Upgrade V8 to version 4.9.385.28
https://chromium.googlesource.com/v8/v8/+/4.9.385.28
FPIIM-449
Change-Id: I4b2e74289d4bf3667f2f3dc8aa2e541f63e26eb4
diff --git a/src/mips/assembler-mips.h b/src/mips/assembler-mips.h
index c6b12b7..0546954 100644
--- a/src/mips/assembler-mips.h
+++ b/src/mips/assembler-mips.h
@@ -38,13 +38,36 @@
#include <stdio.h>
+#include <set>
+
#include "src/assembler.h"
#include "src/mips/constants-mips.h"
-#include "src/serialize.h"
namespace v8 {
namespace internal {
+// clang-format off
+#define GENERAL_REGISTERS(V) \
+ V(zero_reg) V(at) V(v0) V(v1) V(a0) V(a1) V(a2) V(a3) \
+ V(t0) V(t1) V(t2) V(t3) V(t4) V(t5) V(t6) V(t7) \
+ V(s0) V(s1) V(s2) V(s3) V(s4) V(s5) V(s6) V(s7) V(t8) V(t9) \
+ V(k0) V(k1) V(gp) V(sp) V(fp) V(ra)
+
+#define ALLOCATABLE_GENERAL_REGISTERS(V) \
+ V(v0) V(v1) V(a0) V(a1) V(a2) V(a3) \
+ V(t0) V(t1) V(t2) V(t3) V(t4) V(t5) V(t6) V(s7)
+
+#define DOUBLE_REGISTERS(V) \
+ V(f0) V(f1) V(f2) V(f3) V(f4) V(f5) V(f6) V(f7) \
+ V(f8) V(f9) V(f10) V(f11) V(f12) V(f13) V(f14) V(f15) \
+ V(f16) V(f17) V(f18) V(f19) V(f20) V(f21) V(f22) V(f23) \
+ V(f24) V(f25) V(f26) V(f27) V(f28) V(f29) V(f30) V(f31)
+
+#define ALLOCATABLE_DOUBLE_REGISTERS(V) \
+ V(f0) V(f2) V(f4) V(f6) V(f8) V(f10) V(f12) V(f14) \
+ V(f16) V(f18) V(f20) V(f22) V(f24) V(f26)
+// clang-format on
+
// CPU Registers.
//
// 1) We would prefer to use an enum, but enum values are assignment-
@@ -70,13 +93,19 @@
// -----------------------------------------------------------------------------
// Implementation of Register and FPURegister.
-// Core register.
struct Register {
- static const int kNumRegisters = v8::internal::kNumRegisters;
- static const int kMaxNumAllocatableRegisters = 14; // v0 through t6 and cp.
- static const int kSizeInBytes = 4;
static const int kCpRegister = 23; // cp (s7) is the 23rd register.
+ enum Code {
+#define REGISTER_CODE(R) kCode_##R,
+ GENERAL_REGISTERS(REGISTER_CODE)
+#undef REGISTER_CODE
+ kAfterLast,
+ kCode_no_reg = -1
+ };
+
+ static const int kNumRegisters = Code::kAfterLast;
+
#if defined(V8_TARGET_LITTLE_ENDIAN)
static const int kMantissaOffset = 0;
static const int kExponentOffset = 4;
@@ -87,117 +116,37 @@
#error Unknown endianness
#endif
- inline static int NumAllocatableRegisters();
-
- static int ToAllocationIndex(Register reg) {
- DCHECK((reg.code() - 2) < (kMaxNumAllocatableRegisters - 1) ||
- reg.is(from_code(kCpRegister)));
- return reg.is(from_code(kCpRegister)) ?
- kMaxNumAllocatableRegisters - 1 : // Return last index for 'cp'.
- reg.code() - 2; // zero_reg and 'at' are skipped.
- }
-
- static Register FromAllocationIndex(int index) {
- DCHECK(index >= 0 && index < kMaxNumAllocatableRegisters);
- return index == kMaxNumAllocatableRegisters - 1 ?
- from_code(kCpRegister) : // Last index is always the 'cp' register.
- from_code(index + 2); // zero_reg and 'at' are skipped.
- }
-
- static const char* AllocationIndexToString(int index) {
- DCHECK(index >= 0 && index < kMaxNumAllocatableRegisters);
- const char* const names[] = {
- "v0",
- "v1",
- "a0",
- "a1",
- "a2",
- "a3",
- "t0",
- "t1",
- "t2",
- "t3",
- "t4",
- "t5",
- "t6",
- "s7",
- };
- return names[index];
- }
static Register from_code(int code) {
- Register r = { code };
+ DCHECK(code >= 0);
+ DCHECK(code < kNumRegisters);
+ Register r = {code};
return r;
}
-
- bool is_valid() const { return 0 <= code_ && code_ < kNumRegisters; }
- bool is(Register reg) const { return code_ == reg.code_; }
+ const char* ToString();
+ bool IsAllocatable() const;
+ bool is_valid() const { return 0 <= reg_code && reg_code < kNumRegisters; }
+ bool is(Register reg) const { return reg_code == reg.reg_code; }
int code() const {
DCHECK(is_valid());
- return code_;
+ return reg_code;
}
int bit() const {
DCHECK(is_valid());
- return 1 << code_;
+ return 1 << reg_code;
}
// Unfortunately we can't make this private in a struct.
- int code_;
+ int reg_code;
};
-#define REGISTER(N, C) \
- const int kRegister_ ## N ## _Code = C; \
- const Register N = { C }
-
-REGISTER(no_reg, -1);
-// Always zero.
-REGISTER(zero_reg, 0);
-// at: Reserved for synthetic instructions.
-REGISTER(at, 1);
-// v0, v1: Used when returning multiple values from subroutines.
-REGISTER(v0, 2);
-REGISTER(v1, 3);
-// a0 - a4: Used to pass non-FP parameters.
-REGISTER(a0, 4);
-REGISTER(a1, 5);
-REGISTER(a2, 6);
-REGISTER(a3, 7);
-// t0 - t9: Can be used without reservation, act as temporary registers and are
-// allowed to be destroyed by subroutines.
-REGISTER(t0, 8);
-REGISTER(t1, 9);
-REGISTER(t2, 10);
-REGISTER(t3, 11);
-REGISTER(t4, 12);
-REGISTER(t5, 13);
-REGISTER(t6, 14);
-REGISTER(t7, 15);
-// s0 - s7: Subroutine register variables. Subroutines that write to these
-// registers must restore their values before exiting so that the caller can
-// expect the values to be preserved.
-REGISTER(s0, 16);
-REGISTER(s1, 17);
-REGISTER(s2, 18);
-REGISTER(s3, 19);
-REGISTER(s4, 20);
-REGISTER(s5, 21);
-REGISTER(s6, 22);
-REGISTER(s7, 23);
-REGISTER(t8, 24);
-REGISTER(t9, 25);
-// k0, k1: Reserved for system calls and interrupt handlers.
-REGISTER(k0, 26);
-REGISTER(k1, 27);
-// gp: Reserved.
-REGISTER(gp, 28);
-// sp: Stack pointer.
-REGISTER(sp, 29);
-// fp: Frame pointer.
-REGISTER(fp, 30);
-// ra: Return address pointer.
-REGISTER(ra, 31);
-
-#undef REGISTER
+// s7: context register
+// s3: lithium scratch
+// s4: lithium scratch2
+#define DECLARE_REGISTER(R) const Register R = {Register::kCode_##R};
+GENERAL_REGISTERS(DECLARE_REGISTER)
+#undef DECLARE_REGISTER
+const Register no_reg = {Register::kCode_no_reg};
int ToNumber(Register reg);
@@ -205,75 +154,70 @@
Register ToRegister(int num);
// Coprocessor register.
-struct FPURegister {
- static const int kMaxNumRegisters = v8::internal::kNumFPURegisters;
+struct DoubleRegister {
+ enum Code {
+#define REGISTER_CODE(R) kCode_##R,
+ DOUBLE_REGISTERS(REGISTER_CODE)
+#undef REGISTER_CODE
+ kAfterLast,
+ kCode_no_reg = -1
+ };
+
+ static const int kMaxNumRegisters = Code::kAfterLast;
+
+ inline static int NumRegisters();
// TODO(plind): Warning, inconsistent numbering here. kNumFPURegisters refers
// to number of 32-bit FPU regs, but kNumAllocatableRegisters refers to
// number of Double regs (64-bit regs, or FPU-reg-pairs).
- // A few double registers are reserved: one as a scratch register and one to
- // hold 0.0.
- // f28: 0.0
- // f30: scratch register.
- static const int kNumReservedRegisters = 2;
- static const int kMaxNumAllocatableRegisters = kMaxNumRegisters / 2 -
- kNumReservedRegisters;
-
- inline static int NumRegisters();
- inline static int NumAllocatableRegisters();
-
- // TODO(turbofan): Proper support for float32.
- inline static int NumAllocatableAliasedRegisters();
-
- inline static int ToAllocationIndex(FPURegister reg);
- static const char* AllocationIndexToString(int index);
-
- static FPURegister FromAllocationIndex(int index) {
- DCHECK(index >= 0 && index < kMaxNumAllocatableRegisters);
- return from_code(index * 2);
- }
-
- static FPURegister from_code(int code) {
- FPURegister r = { code };
- return r;
- }
-
- bool is_valid() const { return 0 <= code_ && code_ < kMaxNumRegisters ; }
- bool is(FPURegister creg) const { return code_ == creg.code_; }
- FPURegister low() const {
+ const char* ToString();
+ bool IsAllocatable() const;
+ bool is_valid() const { return 0 <= reg_code && reg_code < kMaxNumRegisters; }
+ bool is(DoubleRegister reg) const { return reg_code == reg.reg_code; }
+ DoubleRegister low() const {
// Find low reg of a Double-reg pair, which is the reg itself.
- DCHECK(code_ % 2 == 0); // Specified Double reg must be even.
- FPURegister reg;
- reg.code_ = code_;
+ DCHECK(reg_code % 2 == 0); // Specified Double reg must be even.
+ DoubleRegister reg;
+ reg.reg_code = reg_code;
DCHECK(reg.is_valid());
return reg;
}
- FPURegister high() const {
+ DoubleRegister high() const {
// Find high reg of a Doubel-reg pair, which is reg + 1.
- DCHECK(code_ % 2 == 0); // Specified Double reg must be even.
- FPURegister reg;
- reg.code_ = code_ + 1;
+ DCHECK(reg_code % 2 == 0); // Specified Double reg must be even.
+ DoubleRegister reg;
+ reg.reg_code = reg_code + 1;
DCHECK(reg.is_valid());
return reg;
}
int code() const {
DCHECK(is_valid());
- return code_;
+ return reg_code;
}
int bit() const {
DCHECK(is_valid());
- return 1 << code_;
+ return 1 << reg_code;
+ }
+
+ static DoubleRegister from_code(int code) {
+ DoubleRegister r = {code};
+ return r;
}
void setcode(int f) {
- code_ = f;
+ reg_code = f;
DCHECK(is_valid());
}
// Unfortunately we can't make this private in a struct.
- int code_;
+ int reg_code;
};
+// A few double registers are reserved: one as a scratch register and one to
+// hold 0.0.
+// f28: 0.0
+// f30: scratch register.
+
// V8 now supports the O32 ABI, and the FPU Registers are organized as 32
// 32-bit registers, f0 through f31. When used as 'double' they are used
// in pairs, starting with the even numbered register. So a double operation
@@ -283,43 +227,43 @@
// but it is not in common use. Someday we will want to support this in v8.)
// For O32 ABI, Floats and Doubles refer to same set of 32 32-bit registers.
-typedef FPURegister DoubleRegister;
-typedef FPURegister FloatRegister;
+typedef DoubleRegister FPURegister;
+typedef DoubleRegister FloatRegister;
-const FPURegister no_freg = { -1 };
+const DoubleRegister no_freg = {-1};
-const FPURegister f0 = { 0 }; // Return value in hard float mode.
-const FPURegister f1 = { 1 };
-const FPURegister f2 = { 2 };
-const FPURegister f3 = { 3 };
-const FPURegister f4 = { 4 };
-const FPURegister f5 = { 5 };
-const FPURegister f6 = { 6 };
-const FPURegister f7 = { 7 };
-const FPURegister f8 = { 8 };
-const FPURegister f9 = { 9 };
-const FPURegister f10 = { 10 };
-const FPURegister f11 = { 11 };
-const FPURegister f12 = { 12 }; // Arg 0 in hard float mode.
-const FPURegister f13 = { 13 };
-const FPURegister f14 = { 14 }; // Arg 1 in hard float mode.
-const FPURegister f15 = { 15 };
-const FPURegister f16 = { 16 };
-const FPURegister f17 = { 17 };
-const FPURegister f18 = { 18 };
-const FPURegister f19 = { 19 };
-const FPURegister f20 = { 20 };
-const FPURegister f21 = { 21 };
-const FPURegister f22 = { 22 };
-const FPURegister f23 = { 23 };
-const FPURegister f24 = { 24 };
-const FPURegister f25 = { 25 };
-const FPURegister f26 = { 26 };
-const FPURegister f27 = { 27 };
-const FPURegister f28 = { 28 };
-const FPURegister f29 = { 29 };
-const FPURegister f30 = { 30 };
-const FPURegister f31 = { 31 };
+const DoubleRegister f0 = {0}; // Return value in hard float mode.
+const DoubleRegister f1 = {1};
+const DoubleRegister f2 = {2};
+const DoubleRegister f3 = {3};
+const DoubleRegister f4 = {4};
+const DoubleRegister f5 = {5};
+const DoubleRegister f6 = {6};
+const DoubleRegister f7 = {7};
+const DoubleRegister f8 = {8};
+const DoubleRegister f9 = {9};
+const DoubleRegister f10 = {10};
+const DoubleRegister f11 = {11};
+const DoubleRegister f12 = {12}; // Arg 0 in hard float mode.
+const DoubleRegister f13 = {13};
+const DoubleRegister f14 = {14}; // Arg 1 in hard float mode.
+const DoubleRegister f15 = {15};
+const DoubleRegister f16 = {16};
+const DoubleRegister f17 = {17};
+const DoubleRegister f18 = {18};
+const DoubleRegister f19 = {19};
+const DoubleRegister f20 = {20};
+const DoubleRegister f21 = {21};
+const DoubleRegister f22 = {22};
+const DoubleRegister f23 = {23};
+const DoubleRegister f24 = {24};
+const DoubleRegister f25 = {25};
+const DoubleRegister f26 = {26};
+const DoubleRegister f27 = {27};
+const DoubleRegister f28 = {28};
+const DoubleRegister f29 = {29};
+const DoubleRegister f30 = {30};
+const DoubleRegister f31 = {31};
// Register aliases.
// cp is assumed to be a callee saved register.
@@ -333,27 +277,28 @@
#define kLithiumScratchDouble f30
#define kDoubleRegZero f28
// Used on mips32r6 for compare operations.
-#define kDoubleCompareReg f31
+// We use the last non-callee saved odd register for O32 ABI
+#define kDoubleCompareReg f19
// FPU (coprocessor 1) control registers.
// Currently only FCSR (#31) is implemented.
struct FPUControlRegister {
- bool is_valid() const { return code_ == kFCSRRegister; }
- bool is(FPUControlRegister creg) const { return code_ == creg.code_; }
+ bool is_valid() const { return reg_code == kFCSRRegister; }
+ bool is(FPUControlRegister creg) const { return reg_code == creg.reg_code; }
int code() const {
DCHECK(is_valid());
- return code_;
+ return reg_code;
}
int bit() const {
DCHECK(is_valid());
- return 1 << code_;
+ return 1 << reg_code;
}
void setcode(int f) {
- code_ = f;
+ reg_code = f;
DCHECK(is_valid());
}
// Unfortunately we can't make this private in a struct.
- int code_;
+ int reg_code;
};
const FPUControlRegister no_fpucreg = { kInvalidFPUControlRegister };
@@ -463,27 +408,46 @@
// Note: The same Label can be used for forward and backward branches
// but it may be bound only once.
void bind(Label* L); // Binds an unbound label L to current code position.
+
+ enum OffsetSize : int { kOffset26 = 26, kOffset21 = 21, kOffset16 = 16 };
+
// Determines if Label is bound and near enough so that branch instruction
// can be used to reach it, instead of jump instruction.
bool is_near(Label* L);
+ bool is_near(Label* L, OffsetSize bits);
+ bool is_near_branch(Label* L);
+ inline bool is_near_pre_r6(Label* L) {
+ DCHECK(!IsMipsArchVariant(kMips32r6));
+ return pc_offset() - L->pos() < kMaxBranchOffset - 4 * kInstrSize;
+ }
+ inline bool is_near_r6(Label* L) {
+ DCHECK(IsMipsArchVariant(kMips32r6));
+ return pc_offset() - L->pos() < kMaxCompactBranchOffset - 4 * kInstrSize;
+ }
+
+ int BranchOffset(Instr instr);
// Returns the branch offset to the given label from the current code
// position. Links the label to the current position if it is still unbound.
// Manages the jump elimination optimization if the second parameter is true.
- int32_t branch_offset(Label* L, bool jump_elimination_allowed);
- int32_t branch_offset_compact(Label* L, bool jump_elimination_allowed);
- int32_t branch_offset21(Label* L, bool jump_elimination_allowed);
- int32_t branch_offset21_compact(Label* L, bool jump_elimination_allowed);
- int32_t shifted_branch_offset(Label* L, bool jump_elimination_allowed) {
- int32_t o = branch_offset(L, jump_elimination_allowed);
- DCHECK((o & 3) == 0); // Assert the offset is aligned.
- return o >> 2;
+ int32_t branch_offset_helper(Label* L, OffsetSize bits);
+ inline int32_t branch_offset(Label* L) {
+ return branch_offset_helper(L, OffsetSize::kOffset16);
}
- int32_t shifted_branch_offset_compact(Label* L,
- bool jump_elimination_allowed) {
- int32_t o = branch_offset_compact(L, jump_elimination_allowed);
- DCHECK((o & 3) == 0); // Assert the offset is aligned.
- return o >> 2;
+ inline int32_t branch_offset21(Label* L) {
+ return branch_offset_helper(L, OffsetSize::kOffset21);
+ }
+ inline int32_t branch_offset26(Label* L) {
+ return branch_offset_helper(L, OffsetSize::kOffset26);
+ }
+ inline int32_t shifted_branch_offset(Label* L) {
+ return branch_offset(L) >> 2;
+ }
+ inline int32_t shifted_branch_offset21(Label* L) {
+ return branch_offset21(L) >> 2;
+ }
+ inline int32_t shifted_branch_offset26(Label* L) {
+ return branch_offset26(L) >> 2;
}
uint32_t jump_address(Label* L);
@@ -493,57 +457,53 @@
// Read/Modify the code target address in the branch/call instruction at pc.
static Address target_address_at(Address pc);
- static void set_target_address_at(Address pc,
- Address target,
- ICacheFlushMode icache_flush_mode =
- FLUSH_ICACHE_IF_NEEDED);
+ static void set_target_address_at(
+ Isolate* isolate, Address pc, Address target,
+ ICacheFlushMode icache_flush_mode = FLUSH_ICACHE_IF_NEEDED);
// On MIPS there is no Constant Pool so we skip that parameter.
- INLINE(static Address target_address_at(Address pc,
- ConstantPoolArray* constant_pool)) {
+ INLINE(static Address target_address_at(Address pc, Address constant_pool)) {
return target_address_at(pc);
}
- INLINE(static void set_target_address_at(Address pc,
- ConstantPoolArray* constant_pool,
- Address target,
- ICacheFlushMode icache_flush_mode =
- FLUSH_ICACHE_IF_NEEDED)) {
- set_target_address_at(pc, target, icache_flush_mode);
+ INLINE(static void set_target_address_at(
+ Isolate* isolate, Address pc, Address constant_pool, Address target,
+ ICacheFlushMode icache_flush_mode = FLUSH_ICACHE_IF_NEEDED)) {
+ set_target_address_at(isolate, pc, target, icache_flush_mode);
}
INLINE(static Address target_address_at(Address pc, Code* code)) {
- ConstantPoolArray* constant_pool = code ? code->constant_pool() : NULL;
+ Address constant_pool = code ? code->constant_pool() : NULL;
return target_address_at(pc, constant_pool);
}
- INLINE(static void set_target_address_at(Address pc,
- Code* code,
- Address target,
- ICacheFlushMode icache_flush_mode =
- FLUSH_ICACHE_IF_NEEDED)) {
- ConstantPoolArray* constant_pool = code ? code->constant_pool() : NULL;
- set_target_address_at(pc, constant_pool, target, icache_flush_mode);
+ INLINE(static void set_target_address_at(
+ Isolate* isolate, Address pc, Code* code, Address target,
+ ICacheFlushMode icache_flush_mode = FLUSH_ICACHE_IF_NEEDED)) {
+ Address constant_pool = code ? code->constant_pool() : NULL;
+ set_target_address_at(isolate, pc, constant_pool, target,
+ icache_flush_mode);
}
// Return the code target address at a call site from the return address
// of that call in the instruction stream.
inline static Address target_address_from_return_address(Address pc);
- // Return the code target address of the patch debug break slot
- inline static Address break_address_from_return_address(Address pc);
-
- static void JumpLabelToJumpRegister(Address pc);
-
static void QuietNaN(HeapObject* nan);
// This sets the branch destination (which gets loaded at the call address).
// This is for calls and branches within generated code. The serializer
// has already deserialized the lui/ori instructions etc.
inline static void deserialization_set_special_target_at(
- Address instruction_payload, Code* code, Address target) {
+ Isolate* isolate, Address instruction_payload, Code* code,
+ Address target) {
set_target_address_at(
- instruction_payload - kInstructionsFor32BitConstant * kInstrSize,
- code,
+ isolate,
+ instruction_payload - kInstructionsFor32BitConstant * kInstrSize, code,
target);
}
+ // This sets the internal reference at the pc.
+ inline static void deserialization_set_target_internal_reference_at(
+ Isolate* isolate, Address pc, Address target,
+ RelocInfo::Mode mode = RelocInfo::INTERNAL_REFERENCE);
+
// Size of an instruction.
static const int kInstrSize = sizeof(Instr);
@@ -571,23 +531,14 @@
// target and the return address.
static const int kCallTargetAddressOffset = 4 * kInstrSize;
- // Distance between start of patched return sequence and the emitted address
- // to jump to.
- static const int kPatchReturnSequenceAddressOffset = 0;
-
// Distance between start of patched debug break slot and the emitted address
// to jump to.
- static const int kPatchDebugBreakSlotAddressOffset = 0 * kInstrSize;
+ static const int kPatchDebugBreakSlotAddressOffset = 4 * kInstrSize;
// Difference between address of current opcode and value read from pc
// register.
static const int kPcLoadDelta = 4;
- static const int kPatchDebugBreakSlotReturnOffset = 4 * kInstrSize;
-
- // Number of instructions used for the JS return sequence. The constant is
- // used by the debugger to patch the JS return sequence.
- static const int kJSReturnSequenceInstructions = 7;
static const int kDebugBreakSlotInstructions = 4;
static const int kDebugBreakSlotLength =
kDebugBreakSlotInstructions * kInstrSize;
@@ -600,6 +551,9 @@
// possible to align the pc offset to a multiple
// of m. m must be a power of 2 (>= 4).
void Align(int m);
+ // Insert the smallest number of zero bytes possible to align the pc offset
+ // to a mulitple of m. m must be a power of 2 (>= 2).
+ void DataAlign(int m);
// Aligns code to something that's optimal for a jump target for the platform.
void CodeTargetAlign();
@@ -633,107 +587,111 @@
// --------Branch-and-jump-instructions----------
// We don't use likely variant of instructions.
void b(int16_t offset);
- void b(Label* L) { b(branch_offset(L, false)>>2); }
+ inline void b(Label* L) { b(shifted_branch_offset(L)); }
void bal(int16_t offset);
- void bal(Label* L) { bal(branch_offset(L, false)>>2); }
+ inline void bal(Label* L) { bal(shifted_branch_offset(L)); }
+ void bc(int32_t offset);
+ inline void bc(Label* L) { bc(shifted_branch_offset26(L)); }
+ void balc(int32_t offset);
+ inline void balc(Label* L) { balc(shifted_branch_offset26(L)); }
void beq(Register rs, Register rt, int16_t offset);
- void beq(Register rs, Register rt, Label* L) {
- beq(rs, rt, branch_offset(L, false) >> 2);
+ inline void beq(Register rs, Register rt, Label* L) {
+ beq(rs, rt, shifted_branch_offset(L));
}
void bgez(Register rs, int16_t offset);
void bgezc(Register rt, int16_t offset);
- void bgezc(Register rt, Label* L) {
- bgezc(rt, branch_offset_compact(L, false)>>2);
+ inline void bgezc(Register rt, Label* L) {
+ bgezc(rt, shifted_branch_offset(L));
}
void bgeuc(Register rs, Register rt, int16_t offset);
- void bgeuc(Register rs, Register rt, Label* L) {
- bgeuc(rs, rt, branch_offset_compact(L, false)>>2);
+ inline void bgeuc(Register rs, Register rt, Label* L) {
+ bgeuc(rs, rt, shifted_branch_offset(L));
}
void bgec(Register rs, Register rt, int16_t offset);
- void bgec(Register rs, Register rt, Label* L) {
- bgec(rs, rt, branch_offset_compact(L, false)>>2);
+ inline void bgec(Register rs, Register rt, Label* L) {
+ bgec(rs, rt, shifted_branch_offset(L));
}
void bgezal(Register rs, int16_t offset);
void bgezalc(Register rt, int16_t offset);
- void bgezalc(Register rt, Label* L) {
- bgezalc(rt, branch_offset_compact(L, false)>>2);
+ inline void bgezalc(Register rt, Label* L) {
+ bgezalc(rt, shifted_branch_offset(L));
}
void bgezall(Register rs, int16_t offset);
- void bgezall(Register rs, Label* L) {
- bgezall(rs, branch_offset(L, false)>>2);
+ inline void bgezall(Register rs, Label* L) {
+ bgezall(rs, branch_offset(L) >> 2);
}
void bgtz(Register rs, int16_t offset);
void bgtzc(Register rt, int16_t offset);
- void bgtzc(Register rt, Label* L) {
- bgtzc(rt, branch_offset_compact(L, false)>>2);
+ inline void bgtzc(Register rt, Label* L) {
+ bgtzc(rt, shifted_branch_offset(L));
}
void blez(Register rs, int16_t offset);
void blezc(Register rt, int16_t offset);
- void blezc(Register rt, Label* L) {
- blezc(rt, branch_offset_compact(L, false)>>2);
+ inline void blezc(Register rt, Label* L) {
+ blezc(rt, shifted_branch_offset(L));
}
void bltz(Register rs, int16_t offset);
void bltzc(Register rt, int16_t offset);
- void bltzc(Register rt, Label* L) {
- bltzc(rt, branch_offset_compact(L, false)>>2);
+ inline void bltzc(Register rt, Label* L) {
+ bltzc(rt, shifted_branch_offset(L));
}
void bltuc(Register rs, Register rt, int16_t offset);
- void bltuc(Register rs, Register rt, Label* L) {
- bltuc(rs, rt, branch_offset_compact(L, false)>>2);
+ inline void bltuc(Register rs, Register rt, Label* L) {
+ bltuc(rs, rt, shifted_branch_offset(L));
}
void bltc(Register rs, Register rt, int16_t offset);
- void bltc(Register rs, Register rt, Label* L) {
- bltc(rs, rt, branch_offset_compact(L, false)>>2);
+ inline void bltc(Register rs, Register rt, Label* L) {
+ bltc(rs, rt, shifted_branch_offset(L));
}
void bltzal(Register rs, int16_t offset);
void blezalc(Register rt, int16_t offset);
- void blezalc(Register rt, Label* L) {
- blezalc(rt, branch_offset_compact(L, false)>>2);
+ inline void blezalc(Register rt, Label* L) {
+ blezalc(rt, shifted_branch_offset(L));
}
void bltzalc(Register rt, int16_t offset);
- void bltzalc(Register rt, Label* L) {
- bltzalc(rt, branch_offset_compact(L, false)>>2);
+ inline void bltzalc(Register rt, Label* L) {
+ bltzalc(rt, shifted_branch_offset(L));
}
void bgtzalc(Register rt, int16_t offset);
- void bgtzalc(Register rt, Label* L) {
- bgtzalc(rt, branch_offset_compact(L, false)>>2);
+ inline void bgtzalc(Register rt, Label* L) {
+ bgtzalc(rt, shifted_branch_offset(L));
}
void beqzalc(Register rt, int16_t offset);
- void beqzalc(Register rt, Label* L) {
- beqzalc(rt, branch_offset_compact(L, false)>>2);
+ inline void beqzalc(Register rt, Label* L) {
+ beqzalc(rt, shifted_branch_offset(L));
}
void beqc(Register rs, Register rt, int16_t offset);
- void beqc(Register rs, Register rt, Label* L) {
- beqc(rs, rt, branch_offset_compact(L, false)>>2);
+ inline void beqc(Register rs, Register rt, Label* L) {
+ beqc(rs, rt, shifted_branch_offset(L));
}
void beqzc(Register rs, int32_t offset);
- void beqzc(Register rs, Label* L) {
- beqzc(rs, branch_offset21_compact(L, false)>>2);
+ inline void beqzc(Register rs, Label* L) {
+ beqzc(rs, shifted_branch_offset21(L));
}
void bnezalc(Register rt, int16_t offset);
- void bnezalc(Register rt, Label* L) {
- bnezalc(rt, branch_offset_compact(L, false)>>2);
+ inline void bnezalc(Register rt, Label* L) {
+ bnezalc(rt, shifted_branch_offset(L));
}
void bnec(Register rs, Register rt, int16_t offset);
- void bnec(Register rs, Register rt, Label* L) {
- bnec(rs, rt, branch_offset_compact(L, false)>>2);
+ inline void bnec(Register rs, Register rt, Label* L) {
+ bnec(rs, rt, shifted_branch_offset(L));
}
void bnezc(Register rt, int32_t offset);
- void bnezc(Register rt, Label* L) {
- bnezc(rt, branch_offset21_compact(L, false)>>2);
+ inline void bnezc(Register rt, Label* L) {
+ bnezc(rt, shifted_branch_offset21(L));
}
void bne(Register rs, Register rt, int16_t offset);
- void bne(Register rs, Register rt, Label* L) {
- bne(rs, rt, branch_offset(L, false)>>2);
+ inline void bne(Register rs, Register rt, Label* L) {
+ bne(rs, rt, shifted_branch_offset(L));
}
void bovc(Register rs, Register rt, int16_t offset);
- void bovc(Register rs, Register rt, Label* L) {
- bovc(rs, rt, branch_offset_compact(L, false)>>2);
+ inline void bovc(Register rs, Register rt, Label* L) {
+ bovc(rs, rt, shifted_branch_offset(L));
}
void bnvc(Register rs, Register rt, int16_t offset);
- void bnvc(Register rs, Register rt, Label* L) {
- bnvc(rs, rt, branch_offset_compact(L, false)>>2);
+ inline void bnvc(Register rs, Register rt, Label* L) {
+ bnvc(rs, rt, shifted_branch_offset(L));
}
// Never use the int16_t b(l)cond version with a branch offset
@@ -744,8 +702,8 @@
void jal(int32_t target);
void jalr(Register rs, Register rd = ra);
void jr(Register target);
- void j_or_jr(int32_t target, Register rs);
- void jal_or_jalr(int32_t target, Register rs);
+ void jic(Register rt, int16_t offset);
+ void jialc(Register rt, int16_t offset);
// -------Data-processing-instructions---------
@@ -793,6 +751,8 @@
void rotr(Register rd, Register rt, uint16_t sa);
void rotrv(Register rd, Register rt, Register rs);
+ // Address computing instructions with shift.
+ void lsa(Register rd, Register rt, Register rs, uint8_t sa);
// ------------Memory-instructions-------------
@@ -810,6 +770,14 @@
void swr(Register rd, const MemOperand& rs);
+ // ---------PC-Relative-instructions-----------
+
+ void addiupc(Register rs, int32_t imm19);
+ void lwpc(Register rs, int32_t offset19);
+ void auipc(Register rs, int16_t imm16);
+ void aluipc(Register rs, int16_t imm16);
+
+
// ----------------Prefetch--------------------
void pref(int32_t hint, const MemOperand& rs);
@@ -843,19 +811,34 @@
void movt(Register rd, Register rs, uint16_t cc = 0);
void movf(Register rd, Register rs, uint16_t cc = 0);
- void sel(SecondaryField fmt, FPURegister fd, FPURegister ft,
- FPURegister fs, uint8_t sel);
- void seleqz(Register rs, Register rt, Register rd);
- void seleqz(SecondaryField fmt, FPURegister fd, FPURegister ft,
- FPURegister fs);
- void selnez(Register rs, Register rt, Register rd);
- void selnez(SecondaryField fmt, FPURegister fd, FPURegister ft,
- FPURegister fs);
+ void sel(SecondaryField fmt, FPURegister fd, FPURegister fs, FPURegister ft);
+ void sel_s(FPURegister fd, FPURegister fs, FPURegister ft);
+ void sel_d(FPURegister fd, FPURegister fs, FPURegister ft);
+ void seleqz(Register rd, Register rs, Register rt);
+ void seleqz(SecondaryField fmt, FPURegister fd, FPURegister fs,
+ FPURegister ft);
+ void selnez(Register rd, Register rs, Register rt);
+ void selnez(SecondaryField fmt, FPURegister fd, FPURegister fs,
+ FPURegister ft);
+ void seleqz_d(FPURegister fd, FPURegister fs, FPURegister ft);
+ void seleqz_s(FPURegister fd, FPURegister fs, FPURegister ft);
+ void selnez_d(FPURegister fd, FPURegister fs, FPURegister ft);
+ void selnez_s(FPURegister fd, FPURegister fs, FPURegister ft);
+ void movz_s(FPURegister fd, FPURegister fs, Register rt);
+ void movz_d(FPURegister fd, FPURegister fs, Register rt);
+ void movt_s(FPURegister fd, FPURegister fs, uint16_t cc = 0);
+ void movt_d(FPURegister fd, FPURegister fs, uint16_t cc = 0);
+ void movf_s(FPURegister fd, FPURegister fs, uint16_t cc = 0);
+ void movf_d(FPURegister fd, FPURegister fs, uint16_t cc = 0);
+ void movn_s(FPURegister fd, FPURegister fs, Register rt);
+ void movn_d(FPURegister fd, FPURegister fs, Register rt);
// Bit twiddling.
void clz(Register rd, Register rs);
void ins_(Register rt, Register rs, uint16_t pos, uint16_t size);
void ext_(Register rt, Register rs, uint16_t pos, uint16_t size);
+ void bitswap(Register rd, Register rt);
+ void align(Register rd, Register rs, Register rt, uint8_t bp);
// --------Coprocessor-instructions----------------
@@ -876,15 +859,27 @@
void cfc1(Register rt, FPUControlRegister fs);
// Arithmetic.
+ void add_s(FPURegister fd, FPURegister fs, FPURegister ft);
void add_d(FPURegister fd, FPURegister fs, FPURegister ft);
+ void sub_s(FPURegister fd, FPURegister fs, FPURegister ft);
void sub_d(FPURegister fd, FPURegister fs, FPURegister ft);
+ void mul_s(FPURegister fd, FPURegister fs, FPURegister ft);
void mul_d(FPURegister fd, FPURegister fs, FPURegister ft);
void madd_d(FPURegister fd, FPURegister fr, FPURegister fs, FPURegister ft);
+ void div_s(FPURegister fd, FPURegister fs, FPURegister ft);
void div_d(FPURegister fd, FPURegister fs, FPURegister ft);
+ void abs_s(FPURegister fd, FPURegister fs);
void abs_d(FPURegister fd, FPURegister fs);
void mov_d(FPURegister fd, FPURegister fs);
+ void mov_s(FPURegister fd, FPURegister fs);
+ void neg_s(FPURegister fd, FPURegister fs);
void neg_d(FPURegister fd, FPURegister fs);
+ void sqrt_s(FPURegister fd, FPURegister fs);
void sqrt_d(FPURegister fd, FPURegister fs);
+ void rsqrt_s(FPURegister fd, FPURegister fs);
+ void rsqrt_d(FPURegister fd, FPURegister fs);
+ void recip_d(FPURegister fd, FPURegister fs);
+ void recip_s(FPURegister fd, FPURegister fs);
// Conversion.
void cvt_w_s(FPURegister fd, FPURegister fs);
@@ -897,6 +892,9 @@
void floor_w_d(FPURegister fd, FPURegister fs);
void ceil_w_s(FPURegister fd, FPURegister fs);
void ceil_w_d(FPURegister fd, FPURegister fs);
+ void rint_s(FPURegister fd, FPURegister fs);
+ void rint_d(FPURegister fd, FPURegister fs);
+ void rint(SecondaryField fmt, FPURegister fd, FPURegister fs);
void cvt_l_s(FPURegister fd, FPURegister fs);
void cvt_l_d(FPURegister fd, FPURegister fs);
@@ -909,10 +907,21 @@
void ceil_l_s(FPURegister fd, FPURegister fs);
void ceil_l_d(FPURegister fd, FPURegister fs);
- void min(SecondaryField fmt, FPURegister fd, FPURegister ft, FPURegister fs);
- void mina(SecondaryField fmt, FPURegister fd, FPURegister ft, FPURegister fs);
- void max(SecondaryField fmt, FPURegister fd, FPURegister ft, FPURegister fs);
- void maxa(SecondaryField fmt, FPURegister fd, FPURegister ft, FPURegister fs);
+ void class_s(FPURegister fd, FPURegister fs);
+ void class_d(FPURegister fd, FPURegister fs);
+
+ void min(SecondaryField fmt, FPURegister fd, FPURegister fs, FPURegister ft);
+ void mina(SecondaryField fmt, FPURegister fd, FPURegister fs, FPURegister ft);
+ void max(SecondaryField fmt, FPURegister fd, FPURegister fs, FPURegister ft);
+ void maxa(SecondaryField fmt, FPURegister fd, FPURegister fs, FPURegister ft);
+ void min_s(FPURegister fd, FPURegister fs, FPURegister ft);
+ void min_d(FPURegister fd, FPURegister fs, FPURegister ft);
+ void max_s(FPURegister fd, FPURegister fs, FPURegister ft);
+ void max_d(FPURegister fd, FPURegister fs, FPURegister ft);
+ void mina_s(FPURegister fd, FPURegister fs, FPURegister ft);
+ void mina_d(FPURegister fd, FPURegister fs, FPURegister ft);
+ void maxa_s(FPURegister fd, FPURegister fs, FPURegister ft);
+ void maxa_d(FPURegister fd, FPURegister fs, FPURegister ft);
void cvt_s_w(FPURegister fd, FPURegister fs);
void cvt_s_l(FPURegister fd, FPURegister fs);
@@ -925,24 +934,32 @@
// Conditions and branches for MIPSr6.
void cmp(FPUCondition cond, SecondaryField fmt,
FPURegister fd, FPURegister ft, FPURegister fs);
+ void cmp_s(FPUCondition cond, FPURegister fd, FPURegister fs, FPURegister ft);
+ void cmp_d(FPUCondition cond, FPURegister fd, FPURegister fs, FPURegister ft);
void bc1eqz(int16_t offset, FPURegister ft);
- void bc1eqz(Label* L, FPURegister ft) {
- bc1eqz(branch_offset(L, false)>>2, ft);
+ inline void bc1eqz(Label* L, FPURegister ft) {
+ bc1eqz(shifted_branch_offset(L), ft);
}
void bc1nez(int16_t offset, FPURegister ft);
- void bc1nez(Label* L, FPURegister ft) {
- bc1nez(branch_offset(L, false)>>2, ft);
+ inline void bc1nez(Label* L, FPURegister ft) {
+ bc1nez(shifted_branch_offset(L), ft);
}
// Conditions and branches for non MIPSr6.
void c(FPUCondition cond, SecondaryField fmt,
FPURegister ft, FPURegister fs, uint16_t cc = 0);
+ void c_s(FPUCondition cond, FPURegister ft, FPURegister fs, uint16_t cc = 0);
+ void c_d(FPUCondition cond, FPURegister ft, FPURegister fs, uint16_t cc = 0);
void bc1f(int16_t offset, uint16_t cc = 0);
- void bc1f(Label* L, uint16_t cc = 0) { bc1f(branch_offset(L, false)>>2, cc); }
+ inline void bc1f(Label* L, uint16_t cc = 0) {
+ bc1f(shifted_branch_offset(L), cc);
+ }
void bc1t(int16_t offset, uint16_t cc = 0);
- void bc1t(Label* L, uint16_t cc = 0) { bc1t(branch_offset(L, false)>>2, cc); }
+ inline void bc1t(Label* L, uint16_t cc = 0) {
+ bc1t(shifted_branch_offset(L), cc);
+ }
void fcmp(FPURegister src1, const double src2, FPUCondition cond);
// Check the code size generated from label to here.
@@ -992,11 +1009,11 @@
// Debugging.
- // Mark address of the ExitJSFrame code.
- void RecordJSReturn();
+ // Mark generator continuation.
+ void RecordGeneratorContinuation();
// Mark address of a debug break slot.
- void RecordDebugBreakSlot();
+ void RecordDebugBreakSlot(RelocInfo::Mode mode);
// Record the AST id of the CallIC being compiled, so that it can be placed
// in the relocation information.
@@ -1016,15 +1033,21 @@
// Use --code-comments to enable.
void RecordComment(const char* msg);
- static int RelocateInternalReference(byte* pc, intptr_t pc_delta);
+ // Record a deoptimization reason that can be used by a log or cpu profiler.
+ // Use --trace-deopt to enable.
+ void RecordDeoptReason(const int reason, const SourcePosition position);
+
+
+ static int RelocateInternalReference(RelocInfo::Mode rmode, byte* pc,
+ intptr_t pc_delta);
// Writes a single byte or word of data in the code stream. Used for
// inline tables, e.g., jump-tables.
void db(uint8_t data);
void dd(uint32_t data);
-
- // Emits the address of the code stub's first instruction.
- void emit_code_stub_address(Code* stub);
+ void dq(uint64_t data);
+ void dp(uintptr_t data) { dd(data); }
+ void dd(Label* label);
PositionsRecorder* positions_recorder() { return &positions_recorder_; }
@@ -1052,8 +1075,14 @@
// Check if an instruction is a branch of some kind.
static bool IsBranch(Instr instr);
+ static bool IsBc(Instr instr);
+ static bool IsBzc(Instr instr);
static bool IsBeq(Instr instr);
static bool IsBne(Instr instr);
+ static bool IsBeqzc(Instr instr);
+ static bool IsBnezc(Instr instr);
+ static bool IsBeqc(Instr instr);
+ static bool IsBnec(Instr instr);
static bool IsJump(Instr instr);
static bool IsJ(Instr instr);
@@ -1105,11 +1134,14 @@
void CheckTrampolinePool();
- // Allocate a constant pool of the correct size for the generated code.
- Handle<ConstantPoolArray> NewConstantPool(Isolate* isolate);
+ void PatchConstantPoolAccessInstruction(int pc_offset, int offset,
+ ConstantPoolEntry::Access access,
+ ConstantPoolEntry::Type type) {
+ // No embedded constant pool support.
+ UNREACHABLE();
+ }
- // Generate the constant pool for the generated code.
- void PopulateConstantPool(ConstantPoolArray* constant_pool);
+ bool IsPrevInstrCompactBranch() { return prev_instr_compact_branch_; }
protected:
// Relocation for a type-recording IC has the AST id added to it. This
@@ -1120,10 +1152,10 @@
int32_t buffer_space() const { return reloc_info_writer.pos() - pc_; }
// Decode branch instruction at pos and return branch target pos.
- int target_at(int32_t pos);
+ int target_at(int pos, bool is_internal);
// Patch branch instruction at pos to branch to given branch target pos.
- void target_at_put(int32_t pos, int32_t target_pos);
+ void target_at_put(int pos, int target_pos, bool is_internal);
// Say if we need to relocate with this mode.
bool MustUseReg(RelocInfo::Mode rmode);
@@ -1174,7 +1206,12 @@
return block_buffer_growth_;
}
+ inline void CheckTrampolinePoolQuick(int extra_instructions = 0);
+
private:
+ inline static void set_target_internal_reference_encoded_at(Address pc,
+ Address target);
+
// Buffer size and constant pool distance are checked together at regular
// intervals of kBufferCheckInterval emitted bytes.
static const int kBufferCheckInterval = 1*KB/2;
@@ -1213,11 +1250,19 @@
// The bound position, before this we cannot do instruction elimination.
int last_bound_pos_;
+ // Readable constants for compact branch handling in emit()
+ enum class CompactBranchType : bool { NO = false, COMPACT_BRANCH = true };
+
// Code emission.
inline void CheckBuffer();
void GrowBuffer();
- inline void emit(Instr x);
- inline void CheckTrampolinePoolQuick();
+ inline void emit(Instr x,
+ CompactBranchType is_compact_branch = CompactBranchType::NO);
+ inline void emit(uint64_t x);
+ inline void CheckForEmitInForbiddenSlot();
+ template <typename T>
+ inline void EmitHelper(T x);
+ inline void EmitHelper(Instr x, CompactBranchType is_compact_branch);
// Instruction generation.
// We have 3 different kind of encoding layout on MIPS.
@@ -1268,19 +1313,22 @@
FPUControlRegister fs,
SecondaryField func = NULLSF);
-
- void GenInstrImmediate(Opcode opcode,
- Register rs,
- Register rt,
- int32_t j);
- void GenInstrImmediate(Opcode opcode,
- Register rs,
- SecondaryField SF,
- int32_t j);
- void GenInstrImmediate(Opcode opcode,
- Register r1,
- FPURegister r2,
- int32_t j);
+ void GenInstrImmediate(
+ Opcode opcode, Register rs, Register rt, int32_t j,
+ CompactBranchType is_compact_branch = CompactBranchType::NO);
+ void GenInstrImmediate(
+ Opcode opcode, Register rs, SecondaryField SF, int32_t j,
+ CompactBranchType is_compact_branch = CompactBranchType::NO);
+ void GenInstrImmediate(
+ Opcode opcode, Register r1, FPURegister r2, int32_t j,
+ CompactBranchType is_compact_branch = CompactBranchType::NO);
+ void GenInstrImmediate(
+ Opcode opcode, Register rs, int32_t offset21,
+ CompactBranchType is_compact_branch = CompactBranchType::NO);
+ void GenInstrImmediate(Opcode opcode, Register rs, uint32_t offset21);
+ void GenInstrImmediate(
+ Opcode opcode, int32_t offset26,
+ CompactBranchType is_compact_branch = CompactBranchType::NO);
void GenInstrJump(Opcode opcode,
@@ -1292,7 +1340,7 @@
// Labels.
void print(Label* L);
void bind_to(Label* L, int pos);
- void next(Label* L);
+ void next(Label* L, bool is_internal);
// One trampoline consists of:
// - space for trampoline slots,
@@ -1355,8 +1403,17 @@
bool trampoline_emitted_;
static const int kTrampolineSlotsSize = 4 * kInstrSize;
static const int kMaxBranchOffset = (1 << (18 - 1)) - 1;
+ static const int kMaxCompactBranchOffset = (1 << (28 - 1)) - 1;
static const int kInvalidSlotPos = -1;
+ // Internal reference positions, required for unbounded internal reference
+ // labels.
+ std::set<int> internal_reference_positions_;
+
+ void EmittedCompactBranchInstruction() { prev_instr_compact_branch_ = true; }
+ void ClearCompactBranchState() { prev_instr_compact_branch_ = false; }
+ bool prev_instr_compact_branch_ = false;
+
Trampoline trampoline_;
bool internal_trampoline_exception_;
@@ -1378,6 +1435,7 @@
}
};
-} } // namespace v8::internal
+} // namespace internal
+} // namespace v8
#endif // V8_ARM_ASSEMBLER_MIPS_H_