Upgrade V8 to 5.1.281.57 DO NOT MERGE
FPIIM-449
Change-Id: Id981b686b4d587ac31697662eb98bb34be42ad90
(cherry picked from commit 3b9bc31999c9787eb726ecdbfd5796bfdec32a18)
diff --git a/src/mips/assembler-mips-inl.h b/src/mips/assembler-mips-inl.h
index 5e27f45..517d4ad 100644
--- a/src/mips/assembler-mips-inl.h
+++ b/src/mips/assembler-mips-inl.h
@@ -102,6 +102,10 @@
return Assembler::target_address_at(pc_, host_);
}
+Address RelocInfo::wasm_memory_reference() {
+ DCHECK(IsWasmMemoryReference(rmode_));
+ return Assembler::target_address_at(pc_, host_);
+}
Address RelocInfo::target_address_address() {
DCHECK(IsCodeTarget(rmode_) ||
@@ -152,6 +156,18 @@
}
}
+void RelocInfo::update_wasm_memory_reference(
+ Address old_base, Address new_base, size_t old_size, size_t new_size,
+ ICacheFlushMode icache_flush_mode) {
+ DCHECK(IsWasmMemoryReference(rmode_));
+ DCHECK(old_base <= wasm_memory_reference() &&
+ wasm_memory_reference() < old_base + old_size);
+ Address updated_reference = new_base + (wasm_memory_reference() - old_base);
+ DCHECK(new_base <= updated_reference &&
+ updated_reference < new_base + new_size);
+ Assembler::set_target_address_at(isolate_, pc_, host_, updated_reference,
+ icache_flush_mode);
+}
Address Assembler::target_address_from_return_address(Address pc) {
return pc - kCallTargetAddressOffset;
@@ -160,19 +176,30 @@
void Assembler::set_target_internal_reference_encoded_at(Address pc,
Address target) {
- // Encoded internal references are lui/ori load of 32-bit abolute address.
- Instr instr_lui = Assembler::instr_at(pc + 0 * Assembler::kInstrSize);
- Instr instr_ori = Assembler::instr_at(pc + 1 * Assembler::kInstrSize);
- DCHECK(Assembler::IsLui(instr_lui));
- DCHECK(Assembler::IsOri(instr_ori));
- instr_lui &= ~kImm16Mask;
- instr_ori &= ~kImm16Mask;
+ Instr instr1 = Assembler::instr_at(pc + 0 * Assembler::kInstrSize);
+ Instr instr2 = Assembler::instr_at(pc + 1 * Assembler::kInstrSize);
+ DCHECK(Assembler::IsLui(instr1));
+ DCHECK(Assembler::IsOri(instr2) || Assembler::IsJicOrJialc(instr2));
+ instr1 &= ~kImm16Mask;
+ instr2 &= ~kImm16Mask;
int32_t imm = reinterpret_cast<int32_t>(target);
DCHECK((imm & 3) == 0);
- Assembler::instr_at_put(pc + 0 * Assembler::kInstrSize,
- instr_lui | ((imm >> kLuiShift) & kImm16Mask));
- Assembler::instr_at_put(pc + 1 * Assembler::kInstrSize,
- instr_ori | (imm & kImm16Mask));
+ if (Assembler::IsJicOrJialc(instr2)) {
+ // Encoded internal references are lui/jic load of 32-bit absolute address.
+ uint32_t lui_offset_u, jic_offset_u;
+ Assembler::UnpackTargetAddressUnsigned(imm, lui_offset_u, jic_offset_u);
+
+ Assembler::instr_at_put(pc + 0 * Assembler::kInstrSize,
+ instr1 | lui_offset_u);
+ Assembler::instr_at_put(pc + 1 * Assembler::kInstrSize,
+ instr2 | jic_offset_u);
+ } else {
+ // Encoded internal references are lui/ori load of 32-bit absolute address.
+ Assembler::instr_at_put(pc + 0 * Assembler::kInstrSize,
+ instr1 | ((imm >> kLuiShift) & kImm16Mask));
+ Assembler::instr_at_put(pc + 1 * Assembler::kInstrSize,
+ instr2 | (imm & kImm16Mask));
+ }
// Currently used only by deserializer, and all code will be flushed
// after complete deserialization, no need to flush on each reference.
@@ -230,14 +257,19 @@
if (rmode_ == INTERNAL_REFERENCE) {
return Memory::Address_at(pc_);
} else {
- // Encoded internal references are lui/ori load of 32-bit abolute address.
+ // Encoded internal references are lui/ori or lui/jic load of 32-bit
+ // absolute address.
DCHECK(rmode_ == INTERNAL_REFERENCE_ENCODED);
- Instr instr_lui = Assembler::instr_at(pc_ + 0 * Assembler::kInstrSize);
- Instr instr_ori = Assembler::instr_at(pc_ + 1 * Assembler::kInstrSize);
- DCHECK(Assembler::IsLui(instr_lui));
- DCHECK(Assembler::IsOri(instr_ori));
- int32_t imm = (instr_lui & static_cast<int32_t>(kImm16Mask)) << kLuiShift;
- imm |= (instr_ori & static_cast<int32_t>(kImm16Mask));
+ Instr instr1 = Assembler::instr_at(pc_ + 0 * Assembler::kInstrSize);
+ Instr instr2 = Assembler::instr_at(pc_ + 1 * Assembler::kInstrSize);
+ DCHECK(Assembler::IsLui(instr1));
+ DCHECK(Assembler::IsOri(instr2) || Assembler::IsJicOrJialc(instr2));
+ if (Assembler::IsJicOrJialc(instr2)) {
+ return reinterpret_cast<Address>(
+ Assembler::CreateTargetAddress(instr1, instr2));
+ }
+ int32_t imm = (instr1 & static_cast<int32_t>(kImm16Mask)) << kLuiShift;
+ imm |= (instr2 & static_cast<int32_t>(kImm16Mask));
return reinterpret_cast<Address>(imm);
}
}
diff --git a/src/mips/assembler-mips.cc b/src/mips/assembler-mips.cc
index e50a239..bfa2328 100644
--- a/src/mips/assembler-mips.cc
+++ b/src/mips/assembler-mips.cc
@@ -534,6 +534,11 @@
return opcode == POP30 && rs != 0 && rs < rt; // && rt != 0
}
+bool Assembler::IsJicOrJialc(Instr instr) {
+ uint32_t opcode = GetOpcodeField(instr);
+ uint32_t rs = GetRsField(instr);
+ return (opcode == POP66 || opcode == POP76) && rs == 0;
+}
bool Assembler::IsJump(Instr instr) {
uint32_t opcode = GetOpcodeField(instr);
@@ -546,7 +551,6 @@
((function_field == JALR) || (rd_field == 0 && (function_field == JR))));
}
-
bool Assembler::IsJ(Instr instr) {
uint32_t opcode = GetOpcodeField(instr);
// Checks if the instruction is a jump.
@@ -697,6 +701,47 @@
}
}
+uint32_t Assembler::CreateTargetAddress(Instr instr_lui, Instr instr_jic) {
+ DCHECK(IsLui(instr_lui) && IsJicOrJialc(instr_jic));
+ int16_t jic_offset = GetImmediate16(instr_jic);
+ int16_t lui_offset = GetImmediate16(instr_lui);
+
+ if (jic_offset < 0) {
+ lui_offset += kImm16Mask;
+ }
+ uint32_t lui_offset_u = (static_cast<uint32_t>(lui_offset)) << kLuiShift;
+ uint32_t jic_offset_u = static_cast<uint32_t>(jic_offset) & kImm16Mask;
+
+ return lui_offset_u | jic_offset_u;
+}
+
+// Use just lui and jic instructions. Insert lower part of the target address in
+// jic offset part. Since jic sign-extends offset and then add it with register,
+// before that addition, difference between upper part of the target address and
+// upper part of the sign-extended offset (0xffff or 0x0000), will be inserted
+// in jic register with lui instruction.
+void Assembler::UnpackTargetAddress(uint32_t address, int16_t& lui_offset,
+ int16_t& jic_offset) {
+ lui_offset = (address & kHiMask) >> kLuiShift;
+ jic_offset = address & kLoMask;
+
+ if (jic_offset < 0) {
+ lui_offset -= kImm16Mask;
+ }
+}
+
+void Assembler::UnpackTargetAddressUnsigned(uint32_t address,
+ uint32_t& lui_offset,
+ uint32_t& jic_offset) {
+ int16_t lui_offset16 = (address & kHiMask) >> kLuiShift;
+ int16_t jic_offset16 = address & kLoMask;
+
+ if (jic_offset16 < 0) {
+ lui_offset16 -= kImm16Mask;
+ }
+ lui_offset = static_cast<uint32_t>(lui_offset16) & kImm16Mask;
+ jic_offset = static_cast<uint32_t>(jic_offset16) & kImm16Mask;
+}
int Assembler::target_at(int pos, bool is_internal) {
Instr instr = instr_at(pos);
@@ -724,11 +769,16 @@
if (IsBranch(instr)) {
return AddBranchOffset(pos, instr);
} else {
- Instr instr_lui = instr_at(pos + 0 * Assembler::kInstrSize);
- Instr instr_ori = instr_at(pos + 1 * Assembler::kInstrSize);
- DCHECK(IsOri(instr_ori));
- int32_t imm = (instr_lui & static_cast<int32_t>(kImm16Mask)) << kLuiShift;
- imm |= (instr_ori & static_cast<int32_t>(kImm16Mask));
+ Instr instr1 = instr_at(pos + 0 * Assembler::kInstrSize);
+ Instr instr2 = instr_at(pos + 1 * Assembler::kInstrSize);
+ DCHECK(IsOri(instr2) || IsJicOrJialc(instr2));
+ int32_t imm;
+ if (IsJicOrJialc(instr2)) {
+ imm = CreateTargetAddress(instr1, instr2);
+ } else {
+ imm = (instr1 & static_cast<int32_t>(kImm16Mask)) << kLuiShift;
+ imm |= (instr2 & static_cast<int32_t>(kImm16Mask));
+ }
if (imm == kEndOfJumpChain) {
// EndOfChain sentinel is returned directly, not relative to pc or pos.
@@ -781,19 +831,26 @@
instr = SetBranchOffset(pos, target_pos, instr);
instr_at_put(pos, instr);
} else {
- Instr instr_lui = instr_at(pos + 0 * Assembler::kInstrSize);
- Instr instr_ori = instr_at(pos + 1 * Assembler::kInstrSize);
- DCHECK(IsOri(instr_ori));
+ Instr instr1 = instr_at(pos + 0 * Assembler::kInstrSize);
+ Instr instr2 = instr_at(pos + 1 * Assembler::kInstrSize);
+ DCHECK(IsOri(instr2) || IsJicOrJialc(instr2));
uint32_t imm = reinterpret_cast<uint32_t>(buffer_) + target_pos;
DCHECK((imm & 3) == 0);
+ DCHECK(IsLui(instr1) && (IsJicOrJialc(instr2) || IsOri(instr2)));
+ instr1 &= ~kImm16Mask;
+ instr2 &= ~kImm16Mask;
- instr_lui &= ~kImm16Mask;
- instr_ori &= ~kImm16Mask;
-
- instr_at_put(pos + 0 * Assembler::kInstrSize,
- instr_lui | ((imm & kHiMask) >> kLuiShift));
- instr_at_put(pos + 1 * Assembler::kInstrSize,
- instr_ori | (imm & kImm16Mask));
+ if (IsJicOrJialc(instr2)) {
+ uint32_t lui_offset_u, jic_offset_u;
+ UnpackTargetAddressUnsigned(imm, lui_offset_u, jic_offset_u);
+ instr_at_put(pos + 0 * Assembler::kInstrSize, instr1 | lui_offset_u);
+ instr_at_put(pos + 1 * Assembler::kInstrSize, instr2 | jic_offset_u);
+ } else {
+ instr_at_put(pos + 0 * Assembler::kInstrSize,
+ instr1 | ((imm & kHiMask) >> kLuiShift));
+ instr_at_put(pos + 1 * Assembler::kInstrSize,
+ instr2 | (imm & kImm16Mask));
+ }
}
}
@@ -1330,7 +1387,6 @@
void Assembler::bovc(Register rs, Register rt, int16_t offset) {
DCHECK(IsMipsArchVariant(kMips32r6));
- DCHECK(!rs.is(zero_reg));
if (rs.code() >= rt.code()) {
GenInstrImmediate(ADDI, rs, rt, offset, CompactBranchType::COMPACT_BRANCH);
} else {
@@ -1341,7 +1397,6 @@
void Assembler::bnvc(Register rs, Register rt, int16_t offset) {
DCHECK(IsMipsArchVariant(kMips32r6));
- DCHECK(!rs.is(zero_reg));
if (rs.code() >= rt.code()) {
GenInstrImmediate(DADDI, rs, rt, offset, CompactBranchType::COMPACT_BRANCH);
} else {
@@ -1704,10 +1759,10 @@
void Assembler::lsa(Register rd, Register rt, Register rs, uint8_t sa) {
DCHECK(rd.is_valid() && rt.is_valid() && rs.is_valid());
- DCHECK(sa < 5 && sa > 0);
+ DCHECK(sa <= 3);
DCHECK(IsMipsArchVariant(kMips32r6));
- Instr instr = SPECIAL | (rs.code() << kRsShift) | (rt.code() << kRtShift) |
- (rd.code() << kRdShift) | (sa - 1) << kSaShift | LSA;
+ Instr instr = SPECIAL | rs.code() << kRsShift | rt.code() << kRtShift |
+ rd.code() << kRdShift | sa << kSaShift | LSA;
emit(instr);
}
@@ -2085,7 +2140,6 @@
void Assembler::ldc1(FPURegister fd, const MemOperand& src) {
// Workaround for non-8-byte alignment of HeapNumber, convert 64-bit
// load to two 32-bit loads.
- DCHECK(!src.rm().is(at));
if (IsFp32Mode()) { // fp32 mode.
if (is_int16(src.offset_) && is_int16(src.offset_ + kIntSize)) {
GenInstrImmediate(LWC1, src.rm(), fd,
@@ -2790,24 +2844,36 @@
} else {
DCHECK(RelocInfo::IsInternalReferenceEncoded(rmode));
if (IsLui(instr)) {
- Instr instr_lui = instr_at(pc + 0 * Assembler::kInstrSize);
- Instr instr_ori = instr_at(pc + 1 * Assembler::kInstrSize);
- DCHECK(IsOri(instr_ori));
- int32_t imm = (instr_lui & static_cast<int32_t>(kImm16Mask)) << kLuiShift;
- imm |= (instr_ori & static_cast<int32_t>(kImm16Mask));
+ Instr instr1 = instr_at(pc + 0 * Assembler::kInstrSize);
+ Instr instr2 = instr_at(pc + 1 * Assembler::kInstrSize);
+ DCHECK(IsOri(instr2) || IsJicOrJialc(instr2));
+ int32_t imm;
+ if (IsJicOrJialc(instr2)) {
+ imm = CreateTargetAddress(instr1, instr2);
+ } else {
+ imm = (instr1 & static_cast<int32_t>(kImm16Mask)) << kLuiShift;
+ imm |= (instr2 & static_cast<int32_t>(kImm16Mask));
+ }
+
if (imm == kEndOfJumpChain) {
return 0; // Number of instructions patched.
}
imm += pc_delta;
DCHECK((imm & 3) == 0);
+ instr1 &= ~kImm16Mask;
+ instr2 &= ~kImm16Mask;
- instr_lui &= ~kImm16Mask;
- instr_ori &= ~kImm16Mask;
-
- instr_at_put(pc + 0 * Assembler::kInstrSize,
- instr_lui | ((imm >> kLuiShift) & kImm16Mask));
- instr_at_put(pc + 1 * Assembler::kInstrSize,
- instr_ori | (imm & kImm16Mask));
+ if (IsJicOrJialc(instr2)) {
+ uint32_t lui_offset_u, jic_offset_u;
+ Assembler::UnpackTargetAddressUnsigned(imm, lui_offset_u, jic_offset_u);
+ instr_at_put(pc + 0 * Assembler::kInstrSize, instr1 | lui_offset_u);
+ instr_at_put(pc + 1 * Assembler::kInstrSize, instr2 | jic_offset_u);
+ } else {
+ instr_at_put(pc + 0 * Assembler::kInstrSize,
+ instr1 | ((imm >> kLuiShift) & kImm16Mask));
+ instr_at_put(pc + 1 * Assembler::kInstrSize,
+ instr2 | (imm & kImm16Mask));
+ }
return 2; // Number of instructions patched.
} else {
UNREACHABLE();
@@ -2900,7 +2966,7 @@
// We do not try to reuse pool constants.
RelocInfo rinfo(isolate(), pc_, rmode, data, NULL);
if (rmode >= RelocInfo::COMMENT &&
- rmode <= RelocInfo::DEBUG_BREAK_SLOT_AT_CALL) {
+ rmode <= RelocInfo::DEBUG_BREAK_SLOT_AT_TAIL_CALL) {
// Adjust code for new modes.
DCHECK(RelocInfo::IsDebugBreakSlot(rmode)
|| RelocInfo::IsComment(rmode)
@@ -2964,19 +3030,40 @@
}
int pool_start = pc_offset();
- for (int i = 0; i < unbound_labels_count_; i++) {
- uint32_t imm32;
- imm32 = jump_address(&after_pool);
- { BlockGrowBufferScope block_buf_growth(this);
- // Buffer growth (and relocation) must be blocked for internal
- // references until associated instructions are emitted and available
- // to be patched.
- RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE_ENCODED);
- lui(at, (imm32 & kHiMask) >> kLuiShift);
- ori(at, at, (imm32 & kImm16Mask));
+ if (IsMipsArchVariant(kMips32r6)) {
+ for (int i = 0; i < unbound_labels_count_; i++) {
+ uint32_t imm32;
+ imm32 = jump_address(&after_pool);
+ uint32_t lui_offset, jic_offset;
+ UnpackTargetAddressUnsigned(imm32, lui_offset, jic_offset);
+ {
+ BlockGrowBufferScope block_buf_growth(this);
+ // Buffer growth (and relocation) must be blocked for internal
+ // references until associated instructions are emitted and
+ // available to be patched.
+ RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE_ENCODED);
+ lui(at, lui_offset);
+ jic(at, jic_offset);
+ }
+ CheckBuffer();
}
- jr(at);
- nop();
+ } else {
+ for (int i = 0; i < unbound_labels_count_; i++) {
+ uint32_t imm32;
+ imm32 = jump_address(&after_pool);
+ {
+ BlockGrowBufferScope block_buf_growth(this);
+ // Buffer growth (and relocation) must be blocked for internal
+ // references until associated instructions are emitted and
+ // available to be patched.
+ RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE_ENCODED);
+ lui(at, (imm32 & kHiMask) >> kLuiShift);
+ ori(at, at, (imm32 & kImm16Mask));
+ }
+ CheckBuffer();
+ jr(at);
+ nop();
+ }
}
bind(&after_pool);
trampoline_ = Trampoline(pool_start, unbound_labels_count_);
@@ -3000,10 +3087,10 @@
Instr instr1 = instr_at(pc);
Instr instr2 = instr_at(pc + kInstrSize);
// Interpret 2 instructions generated by li: lui/ori
- if ((GetOpcodeField(instr1) == LUI) && (GetOpcodeField(instr2) == ORI)) {
+ if (IsLui(instr1) && IsOri(instr2)) {
// Assemble the 32 bit value.
- return reinterpret_cast<Address>(
- (GetImmediate16(instr1) << 16) | GetImmediate16(instr2));
+ return reinterpret_cast<Address>((GetImmediate16(instr1) << kLuiShift) |
+ GetImmediate16(instr2));
}
// We should never get here, force a bad address if we do.
@@ -3024,6 +3111,8 @@
// On Mips, a target address is stored in a lui/ori instruction pair, each
// of which load 16 bits of the 32-bit address to a register.
// Patching the address must replace both instr, and flush the i-cache.
+// On r6, target address is stored in a lui/jic pair, and both instr have to be
+// patched.
//
// There is an optimization below, which emits a nop when the address
// fits in just 16 bits. This is unlikely to help, and should be benchmarked,
@@ -3039,15 +3128,27 @@
#ifdef DEBUG
// Check we have the result from a li macro-instruction, using instr pair.
Instr instr1 = instr_at(pc);
- CHECK((GetOpcodeField(instr1) == LUI && GetOpcodeField(instr2) == ORI));
+ CHECK(IsLui(instr1) && (IsOri(instr2) || IsJicOrJialc(instr2)));
#endif
- // Must use 2 instructions to insure patchable code => just use lui and ori.
- // lui rt, upper-16.
- // ori rt rt, lower-16.
- *p = LUI | rt_code | ((itarget & kHiMask) >> kLuiShift);
- *(p + 1) = ORI | rt_code | (rt_code << 5) | (itarget & kImm16Mask);
+ if (IsJicOrJialc(instr2)) {
+ // Must use 2 instructions to insure patchable code => use lui and jic
+ uint32_t lui_offset, jic_offset;
+ Assembler::UnpackTargetAddressUnsigned(itarget, lui_offset, jic_offset);
+ *p &= ~kImm16Mask;
+ *(p + 1) &= ~kImm16Mask;
+
+ *p |= lui_offset;
+ *(p + 1) |= jic_offset;
+
+ } else {
+ // Must use 2 instructions to insure patchable code => just use lui and ori.
+ // lui rt, upper-16.
+ // ori rt rt, lower-16.
+ *p = LUI | rt_code | ((itarget & kHiMask) >> kLuiShift);
+ *(p + 1) = ORI | rt_code | (rt_code << 5) | (itarget & kImm16Mask);
+ }
if (icache_flush_mode != SKIP_ICACHE_FLUSH) {
Assembler::FlushICache(isolate, pc, 2 * sizeof(int32_t));
diff --git a/src/mips/assembler-mips.h b/src/mips/assembler-mips.h
index b708ef7..886ac6c 100644
--- a/src/mips/assembler-mips.h
+++ b/src/mips/assembler-mips.h
@@ -528,7 +528,11 @@
// Distance between the instruction referring to the address of the call
// target and the return address.
+#ifdef _MIPS_ARCH_MIPS32R6
+ static const int kCallTargetAddressOffset = 3 * kInstrSize;
+#else
static const int kCallTargetAddressOffset = 4 * kInstrSize;
+#endif
// Distance between start of patched debug break slot and the emitted address
// to jump to.
@@ -538,7 +542,11 @@
// register.
static const int kPcLoadDelta = 4;
+#ifdef _MIPS_ARCH_MIPS32R6
+ static const int kDebugBreakSlotInstructions = 3;
+#else
static const int kDebugBreakSlotInstructions = 4;
+#endif
static const int kDebugBreakSlotLength =
kDebugBreakSlotInstructions * kInstrSize;
@@ -750,9 +758,6 @@
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-------------
void lb(Register rd, const MemOperand& rs);
@@ -1048,7 +1053,9 @@
void dp(uintptr_t data) { dd(data); }
void dd(Label* label);
- PositionsRecorder* positions_recorder() { return &positions_recorder_; }
+ AssemblerPositionsRecorder* positions_recorder() {
+ return &positions_recorder_;
+ }
// Postpone the generation of the trampoline pool for the specified number of
// instructions.
@@ -1082,6 +1089,7 @@
static bool IsBnezc(Instr instr);
static bool IsBeqc(Instr instr);
static bool IsBnec(Instr instr);
+ static bool IsJicOrJialc(Instr instr);
static bool IsJump(Instr instr);
static bool IsJ(Instr instr);
@@ -1121,12 +1129,20 @@
static int32_t GetBranchOffset(Instr instr);
static bool IsLw(Instr instr);
static int16_t GetLwOffset(Instr instr);
+ static int16_t GetJicOrJialcOffset(Instr instr);
+ static int16_t GetLuiOffset(Instr instr);
static Instr SetLwOffset(Instr instr, int16_t offset);
static bool IsSw(Instr instr);
static Instr SetSwOffset(Instr instr, int16_t offset);
static bool IsAddImmediate(Instr instr);
static Instr SetAddImmediateOffset(Instr instr, int16_t offset);
+ static uint32_t CreateTargetAddress(Instr instr_lui, Instr instr_jic);
+ static void UnpackTargetAddress(uint32_t address, int16_t& lui_offset,
+ int16_t& jic_offset);
+ static void UnpackTargetAddressUnsigned(uint32_t address,
+ uint32_t& lui_offset,
+ uint32_t& jic_offset);
static bool IsAndImmediate(Instr instr);
static bool IsEmittedConstant(Instr instr);
@@ -1143,6 +1159,9 @@
bool IsPrevInstrCompactBranch() { return prev_instr_compact_branch_; }
protected:
+ // Load Scaled Address instruction.
+ void lsa(Register rd, Register rt, Register rs, uint8_t sa);
+
// 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
// the relocation info.
@@ -1213,6 +1232,8 @@
inline void CheckTrampolinePoolQuick(int extra_instructions = 0);
+ inline void CheckBuffer();
+
private:
inline static void set_target_internal_reference_encoded_at(Address pc,
Address target);
@@ -1259,7 +1280,6 @@
enum class CompactBranchType : bool { NO = false, COMPACT_BRANCH = true };
// Code emission.
- inline void CheckBuffer();
void GrowBuffer();
inline void emit(Instr x,
CompactBranchType is_compact_branch = CompactBranchType::NO);
@@ -1406,7 +1426,11 @@
// branch instruction generation, where we use jump instructions rather
// than regular branch instructions.
bool trampoline_emitted_;
+#ifdef _MIPS_ARCH_MIPS32R6
+ static const int kTrampolineSlotsSize = 2 * kInstrSize;
+#else
static const int kTrampolineSlotsSize = 4 * kInstrSize;
+#endif
static const int kMaxBranchOffset = (1 << (18 - 1)) - 1;
static const int kMaxCompactBranchOffset = (1 << (28 - 1)) - 1;
static const int kInvalidSlotPos = -1;
@@ -1427,8 +1451,8 @@
friend class CodePatcher;
friend class BlockTrampolinePoolScope;
- PositionsRecorder positions_recorder_;
- friend class PositionsRecorder;
+ AssemblerPositionsRecorder positions_recorder_;
+ friend class AssemblerPositionsRecorder;
friend class EnsureSpace;
};
diff --git a/src/mips/builtins-mips.cc b/src/mips/builtins-mips.cc
index 09f4d59..9693a52 100644
--- a/src/mips/builtins-mips.cc
+++ b/src/mips/builtins-mips.cc
@@ -149,17 +149,15 @@
// -- sp[(argc - n) * 8] : arg[n] (zero-based)
// -- sp[(argc + 1) * 8] : receiver
// -----------------------------------
- Condition const cc = (kind == MathMaxMinKind::kMin) ? ge : le;
Heap::RootListIndex const root_index =
(kind == MathMaxMinKind::kMin) ? Heap::kInfinityValueRootIndex
: Heap::kMinusInfinityValueRootIndex;
- DoubleRegister const reg = (kind == MathMaxMinKind::kMin) ? f2 : f0;
// Load the accumulator with the default return value (either -Infinity or
// +Infinity), with the tagged value in a1 and the double value in f0.
__ LoadRoot(a1, root_index);
__ ldc1(f0, FieldMemOperand(a1, HeapNumber::kValueOffset));
- __ mov(a3, a0);
+ __ Addu(a3, a0, Operand(1));
Label done_loop, loop;
__ bind(&loop);
@@ -211,21 +209,24 @@
__ SmiToDoubleFPURegister(a2, f2, t0);
__ bind(&done_convert);
- // Perform the actual comparison with the accumulator value on the left hand
- // side (f0) and the next parameter value on the right hand side (f2).
- Label compare_equal, compare_nan, compare_swap;
- __ BranchF(&compare_equal, &compare_nan, eq, f0, f2);
- __ BranchF(&compare_swap, nullptr, cc, f0, f2);
- __ Branch(&loop);
-
- // Left and right hand side are equal, check for -0 vs. +0.
- __ bind(&compare_equal);
- __ FmoveHigh(t0, reg);
- __ Branch(&loop, ne, t0, Operand(0x80000000));
-
- // Result is on the right hand side.
- __ bind(&compare_swap);
- __ mov_d(f0, f2);
+ // Perform the actual comparison with using Min/Max macro instructions the
+ // accumulator value on the left hand side (f0) and the next parameter value
+ // on the right hand side (f2).
+ // We need to work out which HeapNumber (or smi) the result came from.
+ Label compare_nan, set_value;
+ __ BranchF(nullptr, &compare_nan, eq, f0, f2);
+ __ Move(t0, t1, f0);
+ if (kind == MathMaxMinKind::kMin) {
+ __ MinNaNCheck_d(f0, f0, f2);
+ } else {
+ DCHECK(kind == MathMaxMinKind::kMax);
+ __ MaxNaNCheck_d(f0, f0, f2);
+ }
+ __ Move(at, t8, f0);
+ __ Branch(&set_value, ne, t0, Operand(at));
+ __ Branch(&set_value, ne, t1, Operand(t8));
+ __ jmp(&loop);
+ __ bind(&set_value);
__ mov(a1, a2);
__ jmp(&loop);
@@ -238,8 +239,8 @@
__ bind(&done_loop);
__ Lsa(sp, sp, a3, kPointerSizeLog2);
- __ mov(v0, a1);
- __ DropAndRet(1);
+ __ Ret(USE_DELAY_SLOT);
+ __ mov(v0, a1); // In delay slot.
}
// static
@@ -530,6 +531,7 @@
// -- a1 : constructor function
// -- a2 : allocation site or undefined
// -- a3 : new target
+ // -- cp : context
// -- ra : return address
// -- sp[...]: constructor arguments
// -----------------------------------
@@ -543,7 +545,7 @@
// Preserve the incoming parameters on the stack.
__ AssertUndefinedOrAllocationSite(a2, t0);
__ SmiTag(a0);
- __ Push(a2, a0);
+ __ Push(cp, a2, a0);
if (create_implicit_receiver) {
// Allocate the new receiver object.
@@ -618,7 +620,7 @@
}
// Restore context from the frame.
- __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
+ __ lw(cp, MemOperand(fp, ConstructFrameConstants::kContextOffset));
if (create_implicit_receiver) {
// If the result is an object (in the ECMA sense), we should get rid
@@ -750,9 +752,6 @@
// -----------------------------------
ProfileEntryHookStub::MaybeCallEntryHook(masm);
- // Clear the context before we push it when entering the JS frame.
- __ mov(cp, zero_reg);
-
// Enter an internal frame.
{
FrameScope scope(masm, StackFrame::INTERNAL);
@@ -847,9 +846,7 @@
// MANUAL indicates that the scope shouldn't actually generate code to set up
// the frame (that is done below).
FrameScope frame_scope(masm, StackFrame::MANUAL);
-
- __ Push(ra, fp, cp, a1);
- __ Addu(fp, sp, Operand(StandardFrameConstants::kFixedFrameSizeFromFp));
+ __ PushStandardFrame(a1);
// Get the bytecode array from the function object and load the pointer to the
// first entry into kInterpreterBytecodeRegister.
@@ -1205,8 +1202,7 @@
__ MultiPop(saved_regs);
// Perform prologue operations usually performed by the young code stub.
- __ Push(ra, fp, cp, a1);
- __ Addu(fp, sp, Operand(StandardFrameConstants::kFixedFrameSizeFromFp));
+ __ PushStandardFrame(a1);
// Jump to point after the code-age stub.
__ Addu(a0, a0, Operand(kNoCodeAgeSequenceLength));
@@ -1435,23 +1431,6 @@
}
-void Builtins::Generate_OsrAfterStackCheck(MacroAssembler* masm) {
- // We check the stack limit as indicator that recompilation might be done.
- Label ok;
- __ LoadRoot(at, Heap::kStackLimitRootIndex);
- __ Branch(&ok, hs, sp, Operand(at));
- {
- FrameScope scope(masm, StackFrame::INTERNAL);
- __ CallRuntime(Runtime::kStackGuard);
- }
- __ Jump(masm->isolate()->builtins()->OnStackReplacement(),
- RelocInfo::CODE_TARGET);
-
- __ bind(&ok);
- __ Ret();
-}
-
-
// static
void Builtins::Generate_DatePrototype_GetField(MacroAssembler* masm,
int field_index) {
@@ -1498,6 +1477,27 @@
__ TailCallRuntime(Runtime::kThrowNotDateError);
}
+// static
+void Builtins::Generate_FunctionHasInstance(MacroAssembler* masm) {
+ // ----------- S t a t e -------------
+ // -- a0 : argc
+ // -- sp[0] : first argument (left-hand side)
+ // -- sp[4] : receiver (right-hand side)
+ // -----------------------------------
+
+ {
+ FrameScope scope(masm, StackFrame::INTERNAL);
+ __ lw(InstanceOfDescriptor::LeftRegister(),
+ MemOperand(fp, 2 * kPointerSize)); // Load left-hand side.
+ __ lw(InstanceOfDescriptor::RightRegister(),
+ MemOperand(fp, 3 * kPointerSize)); // Load right-hand side.
+ InstanceOfStub stub(masm->isolate(), true);
+ __ CallStub(&stub);
+ }
+
+ // Pop the argument and the receiver.
+ __ DropAndRet(2);
+}
// static
void Builtins::Generate_FunctionPrototypeApply(MacroAssembler* masm) {
@@ -1961,18 +1961,20 @@
DCHECK(!AreAliased(args_reg, scratch1, scratch2, scratch3));
Comment cmnt(masm, "[ PrepareForTailCall");
- // Prepare for tail call only if the debugger is not active.
+ // Prepare for tail call only if ES2015 tail call elimination is enabled.
Label done;
- ExternalReference debug_is_active =
- ExternalReference::debug_is_active_address(masm->isolate());
- __ li(at, Operand(debug_is_active));
+ ExternalReference is_tail_call_elimination_enabled =
+ ExternalReference::is_tail_call_elimination_enabled_address(
+ masm->isolate());
+ __ li(at, Operand(is_tail_call_elimination_enabled));
__ lb(scratch1, MemOperand(at));
- __ Branch(&done, ne, scratch1, Operand(zero_reg));
+ __ Branch(&done, eq, scratch1, Operand(zero_reg));
// Drop possible interpreter handler/stub frame.
{
Label no_interpreter_frame;
- __ lw(scratch3, MemOperand(fp, StandardFrameConstants::kMarkerOffset));
+ __ lw(scratch3,
+ MemOperand(fp, CommonFrameConstants::kContextOrFrameTypeOffset));
__ Branch(&no_interpreter_frame, ne, scratch3,
Operand(Smi::FromInt(StackFrame::STUB)));
__ lw(fp, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
@@ -1980,72 +1982,37 @@
}
// Check if next frame is an arguments adaptor frame.
+ Register caller_args_count_reg = scratch1;
Label no_arguments_adaptor, formal_parameter_count_loaded;
__ lw(scratch2, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
- __ lw(scratch3, MemOperand(scratch2, StandardFrameConstants::kContextOffset));
+ __ lw(scratch3,
+ MemOperand(scratch2, CommonFrameConstants::kContextOrFrameTypeOffset));
__ Branch(&no_arguments_adaptor, ne, scratch3,
Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
- // Drop arguments adaptor frame and load arguments count.
+ // Drop current frame and load arguments count from arguments adaptor frame.
__ mov(fp, scratch2);
- __ lw(scratch1,
+ __ lw(caller_args_count_reg,
MemOperand(fp, ArgumentsAdaptorFrameConstants::kLengthOffset));
- __ SmiUntag(scratch1);
+ __ SmiUntag(caller_args_count_reg);
__ Branch(&formal_parameter_count_loaded);
__ bind(&no_arguments_adaptor);
// Load caller's formal parameter count
- __ lw(scratch1, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
+ __ lw(scratch1,
+ MemOperand(fp, ArgumentsAdaptorFrameConstants::kFunctionOffset));
__ lw(scratch1,
FieldMemOperand(scratch1, JSFunction::kSharedFunctionInfoOffset));
- __ lw(scratch1,
+ __ lw(caller_args_count_reg,
FieldMemOperand(scratch1,
SharedFunctionInfo::kFormalParameterCountOffset));
- __ SmiUntag(scratch1);
+ __ SmiUntag(caller_args_count_reg);
__ bind(&formal_parameter_count_loaded);
- // Calculate the end of destination area where we will put the arguments
- // after we drop current frame. We add kPointerSize to count the receiver
- // argument which is not included into formal parameters count.
- Register dst_reg = scratch2;
- __ Lsa(dst_reg, fp, scratch1, kPointerSizeLog2);
- __ Addu(dst_reg, dst_reg,
- Operand(StandardFrameConstants::kCallerSPOffset + kPointerSize));
-
- Register src_reg = scratch1;
- __ Lsa(src_reg, sp, args_reg, kPointerSizeLog2);
- // Count receiver argument as well (not included in args_reg).
- __ Addu(src_reg, src_reg, Operand(kPointerSize));
-
- if (FLAG_debug_code) {
- __ Check(lo, kStackAccessBelowStackPointer, src_reg, Operand(dst_reg));
- }
-
- // Restore caller's frame pointer and return address now as they will be
- // overwritten by the copying loop.
- __ lw(ra, MemOperand(fp, StandardFrameConstants::kCallerPCOffset));
- __ lw(fp, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
-
- // Now copy callee arguments to the caller frame going backwards to avoid
- // callee arguments corruption (source and destination areas could overlap).
-
- // Both src_reg and dst_reg are pointing to the word after the one to copy,
- // so they must be pre-decremented in the loop.
- Register tmp_reg = scratch3;
- Label loop, entry;
- __ Branch(&entry);
- __ bind(&loop);
- __ Subu(src_reg, src_reg, Operand(kPointerSize));
- __ Subu(dst_reg, dst_reg, Operand(kPointerSize));
- __ lw(tmp_reg, MemOperand(src_reg));
- __ sw(tmp_reg, MemOperand(dst_reg));
- __ bind(&entry);
- __ Branch(&loop, ne, sp, Operand(src_reg));
-
- // Leave current frame.
- __ mov(sp, dst_reg);
-
+ ParameterCount callee_args_count(args_reg);
+ __ PrepareForTailCall(callee_args_count, caller_args_count_reg, scratch2,
+ scratch3);
__ bind(&done);
}
} // namespace
@@ -2556,27 +2523,6 @@
{ // Too few parameters: Actual < expected.
__ bind(&too_few);
-
- // If the function is strong we need to throw an error.
- Label no_strong_error;
- __ lw(t1, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
- __ lw(t2, FieldMemOperand(t1, SharedFunctionInfo::kCompilerHintsOffset));
- __ And(t3, t2, Operand(1 << (SharedFunctionInfo::kStrongModeFunction +
- kSmiTagSize)));
- __ Branch(&no_strong_error, eq, t3, Operand(zero_reg));
-
- // What we really care about is the required number of arguments.
- __ lw(t2, FieldMemOperand(t1, SharedFunctionInfo::kLengthOffset));
- __ SmiUntag(t2);
- __ Branch(&no_strong_error, ge, a0, Operand(t2));
-
- {
- FrameScope frame(masm, StackFrame::MANUAL);
- EnterArgumentsAdaptorFrame(masm);
- __ CallRuntime(Runtime::kThrowStrongModeTooFewArguments);
- }
-
- __ bind(&no_strong_error);
EnterArgumentsAdaptorFrame(masm);
ArgumentAdaptorStackCheck(masm, &stack_overflow);
diff --git a/src/mips/code-stubs-mips.cc b/src/mips/code-stubs-mips.cc
index 541e73e..fd286fb 100644
--- a/src/mips/code-stubs-mips.cc
+++ b/src/mips/code-stubs-mips.cc
@@ -4,9 +4,10 @@
#if V8_TARGET_ARCH_MIPS
+#include "src/code-stubs.h"
+#include "src/api-arguments.h"
#include "src/base/bits.h"
#include "src/bootstrapper.h"
-#include "src/code-stubs.h"
#include "src/codegen.h"
#include "src/ic/handler-compiler.h"
#include "src/ic/ic.h"
@@ -76,6 +77,10 @@
InitializeInternalArrayConstructorDescriptor(isolate(), descriptor, 0);
}
+void FastArrayPushStub::InitializeDescriptor(CodeStubDescriptor* descriptor) {
+ Address deopt_handler = Runtime::FunctionForId(Runtime::kArrayPush)->entry;
+ descriptor->Initialize(a0, deopt_handler, -1, JS_FUNCTION_STUB_MODE);
+}
void InternalArraySingleArgumentConstructorStub::InitializeDescriptor(
CodeStubDescriptor* descriptor) {
@@ -506,7 +511,7 @@
(lhs.is(a1) && rhs.is(a0)));
// a2 is object type of rhs.
- Label object_test, return_unequal, undetectable;
+ Label object_test, return_equal, return_unequal, undetectable;
STATIC_ASSERT(kInternalizedTag == 0 && kStringTag == 0);
__ And(at, a2, Operand(kIsNotStringMask));
__ Branch(&object_test, ne, at, Operand(zero_reg));
@@ -546,6 +551,16 @@
__ bind(&undetectable);
__ And(at, t1, Operand(1 << Map::kIsUndetectable));
__ Branch(&return_unequal, eq, at, Operand(zero_reg));
+
+ // If both sides are JSReceivers, then the result is false according to
+ // the HTML specification, which says that only comparisons with null or
+ // undefined are affected by special casing for document.all.
+ __ GetInstanceType(a2, a2);
+ __ Branch(&return_equal, eq, a2, Operand(ODDBALL_TYPE));
+ __ GetInstanceType(a3, a3);
+ __ Branch(&return_unequal, ne, a3, Operand(ODDBALL_TYPE));
+
+ __ bind(&return_equal);
__ Ret(USE_DELAY_SLOT);
__ li(v0, Operand(EQUAL)); // In delay slot.
}
@@ -1492,8 +1507,12 @@
__ GetObjectType(function, function_map, scratch);
__ Branch(&slow_case, ne, scratch, Operand(JS_FUNCTION_TYPE));
- // Ensure that {function} has an instance prototype.
+ // Go to the runtime if the function is not a constructor.
__ lbu(scratch, FieldMemOperand(function_map, Map::kBitFieldOffset));
+ __ And(at, scratch, Operand(1 << Map::kIsConstructor));
+ __ Branch(&slow_case, eq, at, Operand(zero_reg));
+
+ // Ensure that {function} has an instance prototype.
__ And(at, scratch, Operand(1 << Map::kHasNonInstancePrototype));
__ Branch(&slow_case, ne, at, Operand(zero_reg));
@@ -1563,7 +1582,8 @@
// Slow-case: Call the %InstanceOf runtime function.
__ bind(&slow_case);
__ Push(object, function);
- __ TailCallRuntime(Runtime::kInstanceOf);
+ __ TailCallRuntime(is_es6_instanceof() ? Runtime::kOrdinaryHasInstance
+ : Runtime::kInstanceOf);
}
@@ -1582,29 +1602,6 @@
masm, PropertyAccessCompiler::MissBuiltin(Code::LOAD_IC));
}
-
-void LoadIndexedInterceptorStub::Generate(MacroAssembler* masm) {
- // Return address is in ra.
- Label slow;
-
- Register receiver = LoadDescriptor::ReceiverRegister();
- Register key = LoadDescriptor::NameRegister();
-
- // Check that the key is an array index, that is Uint32.
- __ And(t0, key, Operand(kSmiTagMask | kSmiSignMask));
- __ Branch(&slow, ne, t0, Operand(zero_reg));
-
- // Everything is fine, call runtime.
- __ Push(receiver, key); // Receiver, key.
-
- // Perform tail call to the entry.
- __ TailCallRuntime(Runtime::kLoadElementWithInterceptor);
-
- __ bind(&slow);
- PropertyAccessCompiler::TailCallBuiltin(
- masm, PropertyAccessCompiler::MissBuiltin(Code::KEYED_LOAD_IC));
-}
-
void RegExpExecStub::Generate(MacroAssembler* masm) {
// Just jump directly to runtime if native RegExp is not selected at compile
// time or if regexp entry in generated code is turned off runtime switch or
@@ -2769,57 +2766,58 @@
__ bind(¬_smi);
Label not_heap_number;
- __ lw(a1, FieldMemOperand(a0, HeapObject::kMapOffset));
- __ lbu(a1, FieldMemOperand(a1, Map::kInstanceTypeOffset));
- // a0: object
- // a1: instance type.
+ __ GetObjectType(a0, a1, a1);
+ // a0: receiver
+ // a1: receiver instance type
__ Branch(¬_heap_number, ne, a1, Operand(HEAP_NUMBER_TYPE));
__ Ret(USE_DELAY_SLOT);
__ mov(v0, a0);
__ bind(¬_heap_number);
- Label not_string, slow_string;
+ NonNumberToNumberStub stub(masm->isolate());
+ __ TailCallStub(&stub);
+}
+
+void NonNumberToNumberStub::Generate(MacroAssembler* masm) {
+ // The NonNumberToNumber stub takes on argument in a0.
+ __ AssertNotNumber(a0);
+
+ Label not_string;
+ __ GetObjectType(a0, a1, a1);
+ // a0: receiver
+ // a1: receiver instance type
__ Branch(¬_string, hs, a1, Operand(FIRST_NONSTRING_TYPE));
- // Check if string has a cached array index.
- __ lw(a2, FieldMemOperand(a0, String::kHashFieldOffset));
- __ And(at, a2, Operand(String::kContainsCachedArrayIndexMask));
- __ Branch(&slow_string, ne, at, Operand(zero_reg));
- __ IndexFromHash(a2, a0);
- __ Ret(USE_DELAY_SLOT);
- __ mov(v0, a0);
- __ bind(&slow_string);
- __ push(a0); // Push argument.
- __ TailCallRuntime(Runtime::kStringToNumber);
+ StringToNumberStub stub(masm->isolate());
+ __ TailCallStub(&stub);
__ bind(¬_string);
Label not_oddball;
__ Branch(¬_oddball, ne, a1, Operand(ODDBALL_TYPE));
__ Ret(USE_DELAY_SLOT);
- __ lw(v0, FieldMemOperand(a0, Oddball::kToNumberOffset));
+ __ lw(v0, FieldMemOperand(a0, Oddball::kToNumberOffset)); // In delay slot.
__ bind(¬_oddball);
- __ push(a0); // Push argument.
+ __ Push(a0); // Push argument.
__ TailCallRuntime(Runtime::kToNumber);
}
+void StringToNumberStub::Generate(MacroAssembler* masm) {
+ // The StringToNumber stub takes on argument in a0.
+ __ AssertString(a0);
-void ToLengthStub::Generate(MacroAssembler* masm) {
- // The ToLength stub takes on argument in a0.
- Label not_smi, positive_smi;
- __ JumpIfNotSmi(a0, ¬_smi);
- STATIC_ASSERT(kSmiTag == 0);
- __ Branch(&positive_smi, ge, a0, Operand(zero_reg));
- __ mov(a0, zero_reg);
- __ bind(&positive_smi);
- __ Ret(USE_DELAY_SLOT);
- __ mov(v0, a0);
- __ bind(¬_smi);
+ // Check if string has a cached array index.
+ Label runtime;
+ __ lw(a2, FieldMemOperand(a0, String::kHashFieldOffset));
+ __ And(at, a2, Operand(String::kContainsCachedArrayIndexMask));
+ __ Branch(&runtime, ne, at, Operand(zero_reg));
+ __ IndexFromHash(a2, v0);
+ __ Ret();
- __ push(a0); // Push argument.
- __ TailCallRuntime(Runtime::kToLength);
+ __ bind(&runtime);
+ __ Push(a0); // Push argument.
+ __ TailCallRuntime(Runtime::kStringToNumber);
}
-
void ToStringStub::Generate(MacroAssembler* masm) {
// The ToString stub takes on argument in a0.
Label is_number;
@@ -2990,39 +2988,6 @@
}
-void StringCompareStub::Generate(MacroAssembler* masm) {
- // ----------- S t a t e -------------
- // -- a1 : left
- // -- a0 : right
- // -- ra : return address
- // -----------------------------------
- __ AssertString(a1);
- __ AssertString(a0);
-
- Label not_same;
- __ Branch(¬_same, ne, a0, Operand(a1));
- __ li(v0, Operand(Smi::FromInt(EQUAL)));
- __ IncrementCounter(isolate()->counters()->string_compare_native(), 1, a1,
- a2);
- __ Ret();
-
- __ bind(¬_same);
-
- // Check that both objects are sequential one-byte strings.
- Label runtime;
- __ JumpIfNotBothSequentialOneByteStrings(a1, a0, a2, a3, &runtime);
-
- // Compare flat ASCII strings natively.
- __ IncrementCounter(isolate()->counters()->string_compare_native(), 1, a2,
- a3);
- StringHelper::GenerateCompareFlatOneByteStrings(masm, a1, a0, a2, a3, t0, t1);
-
- __ bind(&runtime);
- __ Push(a1, a0);
- __ TailCallRuntime(Runtime::kStringCompare);
-}
-
-
void BinaryOpICWithAllocationSiteStub::Generate(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- a1 : left
@@ -3345,10 +3310,17 @@
// Handle more complex cases in runtime.
__ bind(&runtime);
- __ Push(left, right);
if (equality) {
- __ TailCallRuntime(Runtime::kStringEquals);
+ {
+ FrameScope scope(masm, StackFrame::INTERNAL);
+ __ Push(left, right);
+ __ CallRuntime(Runtime::kStringEqual);
+ }
+ __ LoadRoot(a0, Heap::kTrueValueRootIndex);
+ __ Ret(USE_DELAY_SLOT);
+ __ Subu(v0, v0, a0); // In delay slot.
} else {
+ __ Push(left, right);
__ TailCallRuntime(Runtime::kStringCompare);
}
@@ -3907,7 +3879,7 @@
CEntryStub ces(isolate(), 1, kSaveFPRegs);
__ Call(ces.GetCode(), RelocInfo::CODE_TARGET);
int parameter_count_offset =
- StubFailureTrampolineFrame::kCallerStackParameterCountFrameOffset;
+ StubFailureTrampolineFrameConstants::kArgumentsLengthOffset;
__ lw(a1, MemOperand(fp, parameter_count_offset));
if (function_mode() == JS_FUNCTION_STUB_MODE) {
__ Addu(a1, a1, Operand(1));
@@ -4889,7 +4861,7 @@
__ bind(&loop);
__ lw(a2, MemOperand(a2, StandardFrameConstants::kCallerFPOffset));
__ bind(&loop_entry);
- __ lw(a3, MemOperand(a2, StandardFrameConstants::kMarkerOffset));
+ __ lw(a3, MemOperand(a2, StandardFrameConstants::kFunctionOffset));
__ Branch(&loop, ne, a1, Operand(a3));
}
@@ -4897,7 +4869,7 @@
// arguments adaptor frame below the function frame).
Label no_rest_parameters;
__ lw(a2, MemOperand(a2, StandardFrameConstants::kCallerFPOffset));
- __ lw(a3, MemOperand(a2, StandardFrameConstants::kContextOffset));
+ __ lw(a3, MemOperand(a2, CommonFrameConstants::kContextOrFrameTypeOffset));
__ Branch(&no_rest_parameters, ne, a3,
Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
@@ -5036,7 +5008,7 @@
// Check if the calling frame is an arguments adaptor frame.
Label adaptor_frame, try_allocate, runtime;
__ lw(t0, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
- __ lw(a0, MemOperand(t0, StandardFrameConstants::kContextOffset));
+ __ lw(a0, MemOperand(t0, CommonFrameConstants::kContextOrFrameTypeOffset));
__ Branch(&adaptor_frame, eq, a0,
Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
@@ -5244,14 +5216,14 @@
__ bind(&loop);
__ lw(a2, MemOperand(a2, StandardFrameConstants::kCallerFPOffset));
__ bind(&loop_entry);
- __ lw(a3, MemOperand(a2, StandardFrameConstants::kMarkerOffset));
+ __ lw(a3, MemOperand(a2, StandardFrameConstants::kFunctionOffset));
__ Branch(&loop, ne, a1, Operand(a3));
}
// Check if we have an arguments adaptor frame below the function frame.
Label arguments_adaptor, arguments_done;
__ lw(a3, MemOperand(a2, StandardFrameConstants::kCallerFPOffset));
- __ lw(a0, MemOperand(a3, StandardFrameConstants::kContextOffset));
+ __ lw(a0, MemOperand(a3, CommonFrameConstants::kContextOrFrameTypeOffset));
__ Branch(&arguments_adaptor, eq, a0,
Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
{
@@ -5607,16 +5579,12 @@
__ jmp(&leave_exit_frame);
}
-static void CallApiFunctionStubHelper(MacroAssembler* masm,
- const ParameterCount& argc,
- bool return_first_arg,
- bool call_data_undefined, bool is_lazy) {
+void CallApiCallbackStub::Generate(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- a0 : callee
// -- t0 : call_data
// -- a2 : holder
// -- a1 : api_function_address
- // -- a3 : number of arguments if argc is a register
// -- cp : context
// --
// -- sp[0] : last argument
@@ -5642,17 +5610,15 @@
STATIC_ASSERT(FCA::kHolderIndex == 0);
STATIC_ASSERT(FCA::kArgsLength == 7);
- DCHECK(argc.is_immediate() || a3.is(argc.reg()));
-
// Save context, callee and call data.
__ Push(context, callee, call_data);
- if (!is_lazy) {
+ if (!is_lazy()) {
// Load context from callee.
__ lw(context, FieldMemOperand(callee, JSFunction::kContextOffset));
}
Register scratch = call_data;
- if (!call_data_undefined) {
+ if (!call_data_undefined()) {
__ LoadRoot(scratch, Heap::kUndefinedValueRootIndex);
}
// Push return value and default return value.
@@ -5677,29 +5643,14 @@
__ Addu(a0, sp, Operand(1 * kPointerSize));
// FunctionCallbackInfo::implicit_args_
__ sw(scratch, MemOperand(a0, 0 * kPointerSize));
- if (argc.is_immediate()) {
- // FunctionCallbackInfo::values_
- __ Addu(at, scratch,
- Operand((FCA::kArgsLength - 1 + argc.immediate()) * kPointerSize));
- __ sw(at, MemOperand(a0, 1 * kPointerSize));
- // FunctionCallbackInfo::length_ = argc
- __ li(at, Operand(argc.immediate()));
- __ sw(at, MemOperand(a0, 2 * kPointerSize));
- // FunctionCallbackInfo::is_construct_call_ = 0
- __ sw(zero_reg, MemOperand(a0, 3 * kPointerSize));
- } else {
- // FunctionCallbackInfo::values_
- __ sll(at, argc.reg(), kPointerSizeLog2);
- __ Addu(at, at, scratch);
- __ Addu(at, at, Operand((FCA::kArgsLength - 1) * kPointerSize));
- __ sw(at, MemOperand(a0, 1 * kPointerSize));
- // FunctionCallbackInfo::length_ = argc
- __ sw(argc.reg(), MemOperand(a0, 2 * kPointerSize));
- // FunctionCallbackInfo::is_construct_call_
- __ Addu(argc.reg(), argc.reg(), Operand(FCA::kArgsLength + 1));
- __ sll(at, argc.reg(), kPointerSizeLog2);
- __ sw(at, MemOperand(a0, 3 * kPointerSize));
- }
+ // FunctionCallbackInfo::values_
+ __ Addu(at, scratch, Operand((FCA::kArgsLength - 1 + argc()) * kPointerSize));
+ __ sw(at, MemOperand(a0, 1 * kPointerSize));
+ // FunctionCallbackInfo::length_ = argc
+ __ li(at, Operand(argc()));
+ __ sw(at, MemOperand(a0, 2 * kPointerSize));
+ // FunctionCallbackInfo::is_construct_call_ = 0
+ __ sw(zero_reg, MemOperand(a0, 3 * kPointerSize));
ExternalReference thunk_ref =
ExternalReference::invoke_function_callback(masm->isolate());
@@ -5709,7 +5660,7 @@
fp, (2 + FCA::kContextSaveIndex) * kPointerSize);
// Stores return the first js argument.
int return_value_offset = 0;
- if (return_first_arg) {
+ if (is_store()) {
return_value_offset = 2 + FCA::kArgsLength;
} else {
return_value_offset = 2 + FCA::kReturnValueOffset;
@@ -5717,33 +5668,14 @@
MemOperand return_value_operand(fp, return_value_offset * kPointerSize);
int stack_space = 0;
int32_t stack_space_offset = 4 * kPointerSize;
- if (argc.is_immediate()) {
- stack_space = argc.immediate() + FCA::kArgsLength + 1;
- stack_space_offset = kInvalidStackOffset;
- }
+ stack_space = argc() + FCA::kArgsLength + 1;
+ stack_space_offset = kInvalidStackOffset;
CallApiFunctionAndReturn(masm, api_function_address, thunk_ref, stack_space,
stack_space_offset, return_value_operand,
&context_restore_operand);
}
-void CallApiFunctionStub::Generate(MacroAssembler* masm) {
- bool call_data_undefined = this->call_data_undefined();
- CallApiFunctionStubHelper(masm, ParameterCount(a3), false,
- call_data_undefined, false);
-}
-
-
-void CallApiAccessorStub::Generate(MacroAssembler* masm) {
- bool is_store = this->is_store();
- int argc = this->argc();
- bool call_data_undefined = this->call_data_undefined();
- bool is_lazy = this->is_lazy();
- CallApiFunctionStubHelper(masm, ParameterCount(argc), is_store,
- call_data_undefined, is_lazy);
-}
-
-
void CallApiGetterStub::Generate(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- sp[0] : name
diff --git a/src/mips/codegen-mips.cc b/src/mips/codegen-mips.cc
index 878ba34..1c6c169 100644
--- a/src/mips/codegen-mips.cc
+++ b/src/mips/codegen-mips.cc
@@ -1197,10 +1197,8 @@
young_sequence_.length() / Assembler::kInstrSize,
CodePatcher::DONT_FLUSH));
PredictableCodeSizeScope scope(patcher->masm(), young_sequence_.length());
- patcher->masm()->Push(ra, fp, cp, a1);
+ patcher->masm()->PushStandardFrame(a1);
patcher->masm()->nop(Assembler::CODE_AGE_SEQUENCE_NOP);
- patcher->masm()->Addu(
- fp, sp, Operand(StandardFrameConstants::kFixedFrameSizeFromFp));
}
diff --git a/src/mips/deoptimizer-mips.cc b/src/mips/deoptimizer-mips.cc
index 0caaa4c..e9caaad 100644
--- a/src/mips/deoptimizer-mips.cc
+++ b/src/mips/deoptimizer-mips.cc
@@ -98,12 +98,6 @@
}
}
-bool Deoptimizer::HasAlignmentPadding(SharedFunctionInfo* shared) {
- // There is no dynamic alignment padding on MIPS in the input frame.
- return false;
-}
-
-
#define __ masm()->
@@ -160,10 +154,15 @@
__ Subu(t0, fp, t0);
// Allocate a new deoptimizer object.
- // Pass four arguments in a0 to a3 and fifth & sixth arguments on stack.
__ PrepareCallCFunction(6, t1);
+ // Pass four arguments in a0 to a3 and fifth & sixth arguments on stack.
+ __ mov(a0, zero_reg);
+ Label context_check;
+ __ lw(a1, MemOperand(fp, CommonFrameConstants::kContextOrFrameTypeOffset));
+ __ JumpIfSmi(a1, &context_check);
__ lw(a0, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
- __ li(a1, Operand(type())); // bailout type,
+ __ bind(&context_check);
+ __ li(a1, Operand(type())); // Bailout type.
// a2: bailout id already loaded.
// a3: code address or 0 already loaded.
__ sw(t0, CFunctionArgumentOperand(5)); // Fp-to-sp delta.
@@ -239,6 +238,8 @@
}
__ pop(a0); // Restore deoptimizer object (class Deoptimizer).
+ __ lw(sp, MemOperand(a0, Deoptimizer::caller_frame_top_offset()));
+
// Replace the current (input) frame with the output frames.
Label outer_push_loop, inner_push_loop,
outer_loop_header, inner_loop_header;
diff --git a/src/mips/frames-mips.h b/src/mips/frames-mips.h
index 849dea2..3511679 100644
--- a/src/mips/frames-mips.h
+++ b/src/mips/frames-mips.h
@@ -133,13 +133,11 @@
-(StandardFrameConstants::kFixedFrameSizeFromFp + kPointerSize);
};
-
-class ExitFrameConstants : public AllStatic {
+class ExitFrameConstants : public TypedFrameConstants {
public:
- static const int kFrameSize = 2 * kPointerSize;
-
- static const int kCodeOffset = -2 * kPointerSize;
- static const int kSPOffset = -1 * kPointerSize;
+ static const int kSPOffset = TYPED_FRAME_PUSHED_VALUE_OFFSET(0);
+ static const int kCodeOffset = TYPED_FRAME_PUSHED_VALUE_OFFSET(1);
+ DEFINE_TYPED_FRAME_SIZES(2);
// The caller fields are below the frame pointer on the stack.
static const int kCallerFPOffset = +0 * kPointerSize;
@@ -161,7 +159,7 @@
// FP-relative.
static const int kLocal0Offset = StandardFrameConstants::kExpressionsOffset;
static const int kLastParameterOffset = +2 * kPointerSize;
- static const int kFunctionOffset = StandardFrameConstants::kMarkerOffset;
+ static const int kFunctionOffset = StandardFrameConstants::kFunctionOffset;
// Caller SP-relative.
static const int kParam0Offset = -2 * kPointerSize;
diff --git a/src/mips/interface-descriptors-mips.cc b/src/mips/interface-descriptors-mips.cc
index fdb43f3..06e3b77 100644
--- a/src/mips/interface-descriptors-mips.cc
+++ b/src/mips/interface-descriptors-mips.cc
@@ -109,35 +109,8 @@
}
-void ToNumberDescriptor::InitializePlatformSpecific(
- CallInterfaceDescriptorData* data) {
- Register registers[] = {a0};
- data->InitializePlatformSpecific(arraysize(registers), registers, NULL);
-}
-
-
// static
-const Register ToLengthDescriptor::ReceiverRegister() { return a0; }
-
-
-// static
-const Register ToStringDescriptor::ReceiverRegister() { return a0; }
-
-
-// static
-const Register ToNameDescriptor::ReceiverRegister() { return a0; }
-
-
-// static
-const Register ToObjectDescriptor::ReceiverRegister() { return a0; }
-
-
-void NumberToStringDescriptor::InitializePlatformSpecific(
- CallInterfaceDescriptorData* data) {
- Register registers[] = {a0};
- data->InitializePlatformSpecific(arraysize(registers), registers, NULL);
-}
-
+const Register TypeConversionDescriptor::ArgumentRegister() { return a0; }
void TypeofDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
@@ -266,6 +239,13 @@
data->InitializePlatformSpecific(0, nullptr, nullptr);
}
+#define SIMD128_ALLOC_DESC(TYPE, Type, type, lane_count, lane_type) \
+ void Allocate##Type##Descriptor::InitializePlatformSpecific( \
+ CallInterfaceDescriptorData* data) { \
+ data->InitializePlatformSpecific(0, nullptr, nullptr); \
+ }
+SIMD128_TYPES(SIMD128_ALLOC_DESC)
+#undef SIMD128_ALLOC_DESC
void AllocateInNewSpaceDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
@@ -310,6 +290,12 @@
data->InitializePlatformSpecific(arraysize(registers), registers);
}
+void FastArrayPushDescriptor::InitializePlatformSpecific(
+ CallInterfaceDescriptorData* data) {
+ // stack param count needs (arg count)
+ Register registers[] = {a0};
+ data->InitializePlatformSpecific(arraysize(registers), registers);
+}
void CompareDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
@@ -318,20 +304,6 @@
}
-void CompareNilDescriptor::InitializePlatformSpecific(
- CallInterfaceDescriptorData* data) {
- Register registers[] = {a0};
- data->InitializePlatformSpecific(arraysize(registers), registers, NULL);
-}
-
-
-void ToBooleanDescriptor::InitializePlatformSpecific(
- CallInterfaceDescriptorData* data) {
- Register registers[] = {a0};
- data->InitializePlatformSpecific(arraysize(registers), registers, NULL);
-}
-
-
void BinaryOpDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
Register registers[] = {a1, a0};
@@ -391,21 +363,7 @@
data->InitializePlatformSpecific(arraysize(registers), registers);
}
-
-void ApiFunctionDescriptor::InitializePlatformSpecific(
- CallInterfaceDescriptorData* data) {
- Register registers[] = {
- a0, // callee
- t0, // call_data
- a2, // holder
- a1, // api_function_address
- a3, // actual number of arguments
- };
- data->InitializePlatformSpecific(arraysize(registers), registers);
-}
-
-
-void ApiAccessorDescriptor::InitializePlatformSpecific(
+void ApiCallbackDescriptorBase::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
Register registers[] = {
a0, // callee
diff --git a/src/mips/macro-assembler-mips.cc b/src/mips/macro-assembler-mips.cc
index e3544c5..7cbbd3a 100644
--- a/src/mips/macro-assembler-mips.cc
+++ b/src/mips/macro-assembler-mips.cc
@@ -1,4 +1,3 @@
-
// Copyright 2012 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -100,6 +99,34 @@
sw(source, MemOperand(s6, index << kPointerSizeLog2));
}
+void MacroAssembler::PushCommonFrame(Register marker_reg) {
+ if (marker_reg.is_valid()) {
+ Push(ra, fp, marker_reg);
+ Addu(fp, sp, Operand(kPointerSize));
+ } else {
+ Push(ra, fp);
+ mov(fp, sp);
+ }
+}
+
+void MacroAssembler::PopCommonFrame(Register marker_reg) {
+ if (marker_reg.is_valid()) {
+ Pop(ra, fp, marker_reg);
+ } else {
+ Pop(ra, fp);
+ }
+}
+
+void MacroAssembler::PushStandardFrame(Register function_reg) {
+ int offset = -StandardFrameConstants::kContextOffset;
+ if (function_reg.is_valid()) {
+ Push(ra, fp, cp, function_reg);
+ offset += kPointerSize;
+ } else {
+ Push(ra, fp, cp);
+ }
+ Addu(fp, sp, Operand(offset));
+}
// Push and pop all registers that can hold pointers.
void MacroAssembler::PushSafepointRegisters() {
@@ -455,12 +482,12 @@
sw(scratch, MemOperand(t8));
// Call stub on end of buffer.
// Check for end of buffer.
- And(t8, scratch, Operand(StoreBuffer::kStoreBufferOverflowBit));
+ And(t8, scratch, Operand(StoreBuffer::kStoreBufferMask));
if (and_then == kFallThroughAtEnd) {
- Branch(&done, eq, t8, Operand(zero_reg));
+ Branch(&done, ne, t8, Operand(zero_reg));
} else {
DCHECK(and_then == kReturnAtEnd);
- Ret(eq, t8, Operand(zero_reg));
+ Ret(ne, t8, Operand(zero_reg));
}
push(ra);
StoreBufferOverflowStub store_buffer_overflow(isolate(), fp_mode);
@@ -481,13 +508,25 @@
Register scratch,
Label* miss) {
Label same_contexts;
+ Register temporary = t8;
DCHECK(!holder_reg.is(scratch));
DCHECK(!holder_reg.is(at));
DCHECK(!scratch.is(at));
- // Load current lexical context from the stack frame.
- lw(scratch, MemOperand(fp, StandardFrameConstants::kContextOffset));
+ // Load current lexical context from the active StandardFrame, which
+ // may require crawling past STUB frames.
+ Label load_context;
+ Label has_context;
+ mov(at, fp);
+ bind(&load_context);
+ lw(scratch, MemOperand(at, CommonFrameConstants::kContextOrFrameTypeOffset));
+ // Passing temporary register, otherwise JumpIfNotSmi modifies register at.
+ JumpIfNotSmi(scratch, &has_context, temporary);
+ lw(at, MemOperand(at, CommonFrameConstants::kCallerFPOffset));
+ Branch(&load_context);
+ bind(&has_context);
+
// In debug mode, make sure the lexical context is set.
#ifdef DEBUG
Check(ne, kWeShouldNotHaveAnEmptyLexicalContext,
@@ -764,6 +803,34 @@
}
}
+void MacroAssembler::Mulu(Register rd_hi, Register rd_lo, Register rs,
+ const Operand& rt) {
+ Register reg;
+ if (rt.is_reg()) {
+ reg = rt.rm();
+ } else {
+ DCHECK(!rs.is(at));
+ reg = at;
+ li(reg, rt);
+ }
+
+ if (!IsMipsArchVariant(kMips32r6)) {
+ multu(rs, reg);
+ mflo(rd_lo);
+ mfhi(rd_hi);
+ } else {
+ if (rd_lo.is(rs)) {
+ DCHECK(!rd_hi.is(rs));
+ DCHECK(!rd_hi.is(reg) && !rd_lo.is(reg));
+ muhu(rd_hi, rs, reg);
+ mulu(rd_lo, rs, reg);
+ } else {
+ DCHECK(!rd_hi.is(reg) && !rd_lo.is(reg));
+ mulu(rd_lo, rs, reg);
+ muhu(rd_hi, rs, reg);
+ }
+ }
+}
void MacroAssembler::Mulh(Register rd, Register rs, const Operand& rt) {
if (rt.is_reg()) {
@@ -1078,7 +1145,7 @@
if (rt.is_reg()) {
rotrv(rd, rs, rt.rm());
} else {
- rotr(rd, rs, rt.imm32_);
+ rotr(rd, rs, rt.imm32_ & 0x1f);
}
} else {
if (rt.is_reg()) {
@@ -1090,8 +1157,8 @@
if (rt.imm32_ == 0) {
srl(rd, rs, 0);
} else {
- srl(at, rs, rt.imm32_);
- sll(rd, rs, (0x20 - rt.imm32_) & 0x1f);
+ srl(at, rs, rt.imm32_ & 0x1f);
+ sll(rd, rs, (0x20 - (rt.imm32_ & 0x1f)) & 0x1f);
or_(rd, rd, at);
}
}
@@ -1110,8 +1177,9 @@
void MacroAssembler::Lsa(Register rd, Register rt, Register rs, uint8_t sa,
Register scratch) {
+ DCHECK(sa >= 1 && sa <= 31);
if (IsMipsArchVariant(kMips32r6) && sa <= 4) {
- lsa(rd, rt, rs, sa);
+ lsa(rd, rt, rs, sa - 1);
} else {
Register tmp = rd.is(rt) ? scratch : rd;
DCHECK(!tmp.is(rt));
@@ -1840,6 +1908,185 @@
}
}
+#define __ masm->
+
+static bool ZeroHelper_d(MacroAssembler* masm, MaxMinKind kind, FPURegister dst,
+ FPURegister src1, FPURegister src2, Label* equal) {
+ if (src1.is(src2)) {
+ __ Move(dst, src1);
+ return true;
+ }
+
+ Label other, compare_not_equal;
+ FPURegister left, right;
+ if (kind == MaxMinKind::kMin) {
+ left = src1;
+ right = src2;
+ } else {
+ left = src2;
+ right = src1;
+ }
+
+ __ BranchF64(&compare_not_equal, nullptr, ne, src1, src2);
+ // Left and right hand side are equal, check for -0 vs. +0.
+ __ FmoveHigh(t8, src1);
+ __ Branch(&other, eq, t8, Operand(0x80000000));
+ __ Move_d(dst, right);
+ __ Branch(equal);
+ __ bind(&other);
+ __ Move_d(dst, left);
+ __ Branch(equal);
+ __ bind(&compare_not_equal);
+ return false;
+}
+
+static bool ZeroHelper_s(MacroAssembler* masm, MaxMinKind kind, FPURegister dst,
+ FPURegister src1, FPURegister src2, Label* equal) {
+ if (src1.is(src2)) {
+ __ Move(dst, src1);
+ return true;
+ }
+
+ Label other, compare_not_equal;
+ FPURegister left, right;
+ if (kind == MaxMinKind::kMin) {
+ left = src1;
+ right = src2;
+ } else {
+ left = src2;
+ right = src1;
+ }
+
+ __ BranchF32(&compare_not_equal, nullptr, ne, src1, src2);
+ // Left and right hand side are equal, check for -0 vs. +0.
+ __ FmoveLow(t8, src1);
+ __ Branch(&other, eq, t8, Operand(0x80000000));
+ __ Move_s(dst, right);
+ __ Branch(equal);
+ __ bind(&other);
+ __ Move_s(dst, left);
+ __ Branch(equal);
+ __ bind(&compare_not_equal);
+ return false;
+}
+
+#undef __
+
+void MacroAssembler::MinNaNCheck_d(FPURegister dst, FPURegister src1,
+ FPURegister src2, Label* nan) {
+ if (nan) {
+ BranchF64(nullptr, nan, eq, src1, src2);
+ }
+ if (IsMipsArchVariant(kMips32r6)) {
+ min_d(dst, src1, src2);
+ } else {
+ Label skip;
+ if (!ZeroHelper_d(this, MaxMinKind::kMin, dst, src1, src2, &skip)) {
+ if (dst.is(src1)) {
+ BranchF64(&skip, nullptr, le, src1, src2);
+ Move_d(dst, src2);
+ } else if (dst.is(src2)) {
+ BranchF64(&skip, nullptr, ge, src1, src2);
+ Move_d(dst, src1);
+ } else {
+ Label right;
+ BranchF64(&right, nullptr, gt, src1, src2);
+ Move_d(dst, src1);
+ Branch(&skip);
+ bind(&right);
+ Move_d(dst, src2);
+ }
+ }
+ bind(&skip);
+ }
+}
+
+void MacroAssembler::MaxNaNCheck_d(FPURegister dst, FPURegister src1,
+ FPURegister src2, Label* nan) {
+ if (nan) {
+ BranchF64(nullptr, nan, eq, src1, src2);
+ }
+ if (IsMipsArchVariant(kMips32r6)) {
+ max_d(dst, src1, src2);
+ } else {
+ Label skip;
+ if (!ZeroHelper_d(this, MaxMinKind::kMax, dst, src1, src2, &skip)) {
+ if (dst.is(src1)) {
+ BranchF64(&skip, nullptr, ge, src1, src2);
+ Move_d(dst, src2);
+ } else if (dst.is(src2)) {
+ BranchF64(&skip, nullptr, le, src1, src2);
+ Move_d(dst, src1);
+ } else {
+ Label right;
+ BranchF64(&right, nullptr, lt, src1, src2);
+ Move_d(dst, src1);
+ Branch(&skip);
+ bind(&right);
+ Move_d(dst, src2);
+ }
+ }
+ bind(&skip);
+ }
+}
+
+void MacroAssembler::MinNaNCheck_s(FPURegister dst, FPURegister src1,
+ FPURegister src2, Label* nan) {
+ if (nan) {
+ BranchF32(nullptr, nan, eq, src1, src2);
+ }
+ if (IsMipsArchVariant(kMips32r6)) {
+ min_s(dst, src1, src2);
+ } else {
+ Label skip;
+ if (!ZeroHelper_s(this, MaxMinKind::kMin, dst, src1, src2, &skip)) {
+ if (dst.is(src1)) {
+ BranchF32(&skip, nullptr, le, src1, src2);
+ Move_s(dst, src2);
+ } else if (dst.is(src2)) {
+ BranchF32(&skip, nullptr, ge, src1, src2);
+ Move_s(dst, src1);
+ } else {
+ Label right;
+ BranchF32(&right, nullptr, gt, src1, src2);
+ Move_s(dst, src1);
+ Branch(&skip);
+ bind(&right);
+ Move_s(dst, src2);
+ }
+ }
+ bind(&skip);
+ }
+}
+
+void MacroAssembler::MaxNaNCheck_s(FPURegister dst, FPURegister src1,
+ FPURegister src2, Label* nan) {
+ if (nan) {
+ BranchF32(nullptr, nan, eq, src1, src2);
+ }
+ if (IsMipsArchVariant(kMips32r6)) {
+ max_s(dst, src1, src2);
+ } else {
+ Label skip;
+ if (!ZeroHelper_s(this, MaxMinKind::kMax, dst, src1, src2, &skip)) {
+ if (dst.is(src1)) {
+ BranchF32(&skip, nullptr, ge, src1, src2);
+ Move_s(dst, src2);
+ } else if (dst.is(src2)) {
+ BranchF32(&skip, nullptr, le, src1, src2);
+ Move_s(dst, src1);
+ } else {
+ Label right;
+ BranchF32(&right, nullptr, lt, src1, src2);
+ Move_s(dst, src1);
+ Branch(&skip);
+ bind(&right);
+ Move_s(dst, src2);
+ }
+ }
+ bind(&skip);
+ }
+}
void MacroAssembler::Clz(Register rd, Register rs) {
if (IsMipsArchVariant(kLoongson)) {
@@ -3011,16 +3258,25 @@
const Operand& rt,
BranchDelaySlot bd) {
BlockTrampolinePoolScope block_trampoline_pool(this);
- if (cond == cc_always) {
- jr(target);
+ if (IsMipsArchVariant(kMips32r6) && bd == PROTECT) {
+ if (cond == cc_always) {
+ jic(target, 0);
+ } else {
+ BRANCH_ARGS_CHECK(cond, rs, rt);
+ Branch(2, NegateCondition(cond), rs, rt);
+ jic(target, 0);
+ }
} else {
- BRANCH_ARGS_CHECK(cond, rs, rt);
- Branch(2, NegateCondition(cond), rs, rt);
- jr(target);
+ if (cond == cc_always) {
+ jr(target);
+ } else {
+ BRANCH_ARGS_CHECK(cond, rs, rt);
+ Branch(2, NegateCondition(cond), rs, rt);
+ jr(target);
+ }
+ // Emit a nop in the branch delay slot if required.
+ if (bd == PROTECT) nop();
}
- // Emit a nop in the branch delay slot if required.
- if (bd == PROTECT)
- nop();
}
@@ -3078,8 +3334,7 @@
size += 3;
}
- if (bd == PROTECT)
- size += 1;
+ if (bd == PROTECT && !IsMipsArchVariant(kMips32r6)) size += 1;
return size * kInstrSize;
}
@@ -3098,16 +3353,25 @@
BlockTrampolinePoolScope block_trampoline_pool(this);
Label start;
bind(&start);
- if (cond == cc_always) {
- jalr(target);
+ if (IsMipsArchVariant(kMips32r6) && bd == PROTECT) {
+ if (cond == cc_always) {
+ jialc(target, 0);
+ } else {
+ BRANCH_ARGS_CHECK(cond, rs, rt);
+ Branch(2, NegateCondition(cond), rs, rt);
+ jialc(target, 0);
+ }
} else {
- BRANCH_ARGS_CHECK(cond, rs, rt);
- Branch(2, NegateCondition(cond), rs, rt);
- jalr(target);
+ if (cond == cc_always) {
+ jalr(target);
+ } else {
+ BRANCH_ARGS_CHECK(cond, rs, rt);
+ Branch(2, NegateCondition(cond), rs, rt);
+ jalr(target);
+ }
+ // Emit a nop in the branch delay slot if required.
+ if (bd == PROTECT) nop();
}
- // Emit a nop in the branch delay slot if required.
- if (bd == PROTECT)
- nop();
#ifdef DEBUG
CHECK_EQ(size + CallSize(target, cond, rs, rt, bd),
@@ -3198,18 +3462,35 @@
BlockTrampolinePoolScope block_trampoline_pool(this);
uint32_t imm32;
imm32 = jump_address(L);
- {
- BlockGrowBufferScope block_buf_growth(this);
- // Buffer growth (and relocation) must be blocked for internal references
- // until associated instructions are emitted and available to be patched.
- RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE_ENCODED);
- lui(at, (imm32 & kHiMask) >> kLuiShift);
- ori(at, at, (imm32 & kImm16Mask));
+ if (IsMipsArchVariant(kMips32r6) && bdslot == PROTECT) {
+ uint32_t lui_offset, jic_offset;
+ UnpackTargetAddressUnsigned(imm32, lui_offset, jic_offset);
+ {
+ BlockGrowBufferScope block_buf_growth(this);
+ // Buffer growth (and relocation) must be blocked for internal
+ // references until associated instructions are emitted and
+ // available to be patched.
+ RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE_ENCODED);
+ lui(at, lui_offset);
+ jic(at, jic_offset);
+ }
+ CheckBuffer();
+ } else {
+ {
+ BlockGrowBufferScope block_buf_growth(this);
+ // Buffer growth (and relocation) must be blocked for internal
+ // references
+ // until associated instructions are emitted and available to be
+ // patched.
+ RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE_ENCODED);
+ lui(at, (imm32 & kHiMask) >> kLuiShift);
+ ori(at, at, (imm32 & kImm16Mask));
+ }
+ CheckBuffer();
+ jr(at);
+ // Emit a nop in the branch delay slot if required.
+ if (bdslot == PROTECT) nop();
}
- jr(at);
-
- // Emit a nop in the branch delay slot if required.
- if (bdslot == PROTECT) nop();
}
}
@@ -3222,18 +3503,35 @@
BlockTrampolinePoolScope block_trampoline_pool(this);
uint32_t imm32;
imm32 = jump_address(L);
- {
- BlockGrowBufferScope block_buf_growth(this);
- // Buffer growth (and relocation) must be blocked for internal references
- // until associated instructions are emitted and available to be patched.
- RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE_ENCODED);
- lui(at, (imm32 & kHiMask) >> kLuiShift);
- ori(at, at, (imm32 & kImm16Mask));
+ if (IsMipsArchVariant(kMips32r6) && bdslot == PROTECT) {
+ uint32_t lui_offset, jic_offset;
+ UnpackTargetAddressUnsigned(imm32, lui_offset, jic_offset);
+ {
+ BlockGrowBufferScope block_buf_growth(this);
+ // Buffer growth (and relocation) must be blocked for internal
+ // references until associated instructions are emitted and
+ // available to be patched.
+ RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE_ENCODED);
+ lui(at, lui_offset);
+ jialc(at, jic_offset);
+ }
+ CheckBuffer();
+ } else {
+ {
+ BlockGrowBufferScope block_buf_growth(this);
+ // Buffer growth (and relocation) must be blocked for internal
+ // references
+ // until associated instructions are emitted and available to be
+ // patched.
+ RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE_ENCODED);
+ lui(at, (imm32 & kHiMask) >> kLuiShift);
+ ori(at, at, (imm32 & kImm16Mask));
+ }
+ CheckBuffer();
+ jalr(at);
+ // Emit a nop in the branch delay slot if required.
+ if (bdslot == PROTECT) nop();
}
- jalr(at);
-
- // Emit a nop in the branch delay slot if required.
- if (bdslot == PROTECT) nop();
}
}
@@ -4062,6 +4360,65 @@
// -----------------------------------------------------------------------------
// JavaScript invokes.
+void MacroAssembler::PrepareForTailCall(const ParameterCount& callee_args_count,
+ Register caller_args_count_reg,
+ Register scratch0, Register scratch1) {
+#if DEBUG
+ if (callee_args_count.is_reg()) {
+ DCHECK(!AreAliased(callee_args_count.reg(), caller_args_count_reg, scratch0,
+ scratch1));
+ } else {
+ DCHECK(!AreAliased(caller_args_count_reg, scratch0, scratch1));
+ }
+#endif
+
+ // Calculate the end of destination area where we will put the arguments
+ // after we drop current frame. We add kPointerSize to count the receiver
+ // argument which is not included into formal parameters count.
+ Register dst_reg = scratch0;
+ Lsa(dst_reg, fp, caller_args_count_reg, kPointerSizeLog2);
+ Addu(dst_reg, dst_reg,
+ Operand(StandardFrameConstants::kCallerSPOffset + kPointerSize));
+
+ Register src_reg = caller_args_count_reg;
+ // Calculate the end of source area. +kPointerSize is for the receiver.
+ if (callee_args_count.is_reg()) {
+ Lsa(src_reg, sp, callee_args_count.reg(), kPointerSizeLog2);
+ Addu(src_reg, src_reg, Operand(kPointerSize));
+ } else {
+ Addu(src_reg, sp,
+ Operand((callee_args_count.immediate() + 1) * kPointerSize));
+ }
+
+ if (FLAG_debug_code) {
+ Check(lo, kStackAccessBelowStackPointer, src_reg, Operand(dst_reg));
+ }
+
+ // Restore caller's frame pointer and return address now as they will be
+ // overwritten by the copying loop.
+ lw(ra, MemOperand(fp, StandardFrameConstants::kCallerPCOffset));
+ lw(fp, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
+
+ // Now copy callee arguments to the caller frame going backwards to avoid
+ // callee arguments corruption (source and destination areas could overlap).
+
+ // Both src_reg and dst_reg are pointing to the word after the one to copy,
+ // so they must be pre-decremented in the loop.
+ Register tmp_reg = scratch1;
+ Label loop, entry;
+ Branch(&entry);
+ bind(&loop);
+ Subu(src_reg, src_reg, Operand(kPointerSize));
+ Subu(dst_reg, dst_reg, Operand(kPointerSize));
+ lw(tmp_reg, MemOperand(src_reg));
+ sw(tmp_reg, MemOperand(dst_reg));
+ bind(&entry);
+ Branch(&loop, ne, sp, Operand(src_reg));
+
+ // Leave current frame.
+ mov(sp, dst_reg);
+}
+
void MacroAssembler::InvokePrologue(const ParameterCount& expected,
const ParameterCount& actual,
Label* done,
@@ -4846,12 +5203,9 @@
}
}
-
-void MacroAssembler::StubPrologue() {
- Push(ra, fp, cp);
- Push(Smi::FromInt(StackFrame::STUB));
- // Adjust FP to point to saved FP.
- Addu(fp, sp, Operand(StandardFrameConstants::kFixedFrameSizeFromFp));
+void MacroAssembler::StubPrologue(StackFrame::Type type) {
+ li(at, Operand(Smi::FromInt(type)));
+ PushCommonFrame(at);
}
@@ -4874,10 +5228,8 @@
nop(); // Branch delay slot nop.
nop(); // Pad the empty space.
} else {
- Push(ra, fp, cp, a1);
+ PushStandardFrame(a1);
nop(Assembler::CODE_AGE_SEQUENCE_NOP);
- // Adjust fp to point to caller's fp.
- Addu(fp, sp, Operand(StandardFrameConstants::kFixedFrameSizeFromFp));
}
}
@@ -4898,30 +5250,41 @@
void MacroAssembler::EnterFrame(StackFrame::Type type) {
- addiu(sp, sp, -5 * kPointerSize);
- li(t8, Operand(Smi::FromInt(type)));
- li(t9, Operand(CodeObject()), CONSTANT_SIZE);
- sw(ra, MemOperand(sp, 4 * kPointerSize));
- sw(fp, MemOperand(sp, 3 * kPointerSize));
- sw(cp, MemOperand(sp, 2 * kPointerSize));
- sw(t8, MemOperand(sp, 1 * kPointerSize));
- sw(t9, MemOperand(sp, 0 * kPointerSize));
+ int stack_offset, fp_offset;
+ if (type == StackFrame::INTERNAL) {
+ stack_offset = -4 * kPointerSize;
+ fp_offset = 2 * kPointerSize;
+ } else {
+ stack_offset = -3 * kPointerSize;
+ fp_offset = 1 * kPointerSize;
+ }
+ addiu(sp, sp, stack_offset);
+ stack_offset = -stack_offset - kPointerSize;
+ sw(ra, MemOperand(sp, stack_offset));
+ stack_offset -= kPointerSize;
+ sw(fp, MemOperand(sp, stack_offset));
+ stack_offset -= kPointerSize;
+ li(t9, Operand(Smi::FromInt(type)));
+ sw(t9, MemOperand(sp, stack_offset));
+ if (type == StackFrame::INTERNAL) {
+ DCHECK_EQ(stack_offset, kPointerSize);
+ li(t9, Operand(CodeObject()));
+ sw(t9, MemOperand(sp, 0));
+ } else {
+ DCHECK_EQ(stack_offset, 0);
+ }
// Adjust FP to point to saved FP.
- Addu(fp, sp,
- Operand(StandardFrameConstants::kFixedFrameSizeFromFp + kPointerSize));
+ Addu(fp, sp, Operand(fp_offset));
}
void MacroAssembler::LeaveFrame(StackFrame::Type type) {
- mov(sp, fp);
- lw(fp, MemOperand(sp, 0 * kPointerSize));
- lw(ra, MemOperand(sp, 1 * kPointerSize));
- addiu(sp, sp, 2 * kPointerSize);
+ addiu(sp, fp, 2 * kPointerSize);
+ lw(ra, MemOperand(fp, 1 * kPointerSize));
+ lw(fp, MemOperand(fp, 0 * kPointerSize));
}
-
-void MacroAssembler::EnterExitFrame(bool save_doubles,
- int stack_space) {
+void MacroAssembler::EnterExitFrame(bool save_doubles, int stack_space) {
// Set up the frame structure on the stack.
STATIC_ASSERT(2 * kPointerSize == ExitFrameConstants::kCallerSPDisplacement);
STATIC_ASSERT(1 * kPointerSize == ExitFrameConstants::kCallerPCOffset);
@@ -4931,16 +5294,20 @@
// fp + 2 (==kCallerSPDisplacement) - old stack's end
// [fp + 1 (==kCallerPCOffset)] - saved old ra
// [fp + 0 (==kCallerFPOffset)] - saved old fp
- // [fp - 1 (==kSPOffset)] - sp of the called function
- // [fp - 2 (==kCodeOffset)] - CodeObject
+ // [fp - 1 StackFrame::EXIT Smi
+ // [fp - 2 (==kSPOffset)] - sp of the called function
+ // [fp - 3 (==kCodeOffset)] - CodeObject
// fp - (2 + stack_space + alignment) == sp == [fp - kSPOffset] - top of the
// new stack (will contain saved ra)
- // Save registers.
- addiu(sp, sp, -4 * kPointerSize);
- sw(ra, MemOperand(sp, 3 * kPointerSize));
- sw(fp, MemOperand(sp, 2 * kPointerSize));
- addiu(fp, sp, 2 * kPointerSize); // Set up new frame pointer.
+ // Save registers and reserve room for saved entry sp and code object.
+ addiu(sp, sp, -2 * kPointerSize - ExitFrameConstants::kFixedFrameSizeFromFp);
+ sw(ra, MemOperand(sp, 4 * kPointerSize));
+ sw(fp, MemOperand(sp, 3 * kPointerSize));
+ li(at, Operand(Smi::FromInt(StackFrame::EXIT)));
+ sw(at, MemOperand(sp, 2 * kPointerSize));
+ // Set up new frame pointer.
+ addiu(fp, sp, ExitFrameConstants::kFixedFrameSizeFromFp);
if (emit_debug_code()) {
sw(zero_reg, MemOperand(fp, ExitFrameConstants::kSPOffset));
@@ -5177,6 +5544,15 @@
JumpIfSmi(at, on_either_smi);
}
+void MacroAssembler::AssertNotNumber(Register object) {
+ if (emit_debug_code()) {
+ STATIC_ASSERT(kSmiTag == 0);
+ andi(at, object, kSmiTagMask);
+ Check(ne, kOperandIsANumber, at, Operand(zero_reg));
+ GetObjectType(object, t8, t8);
+ Check(ne, kOperandIsNotANumber, t8, Operand(HEAP_NUMBER_TYPE));
+ }
+}
void MacroAssembler::AssertNotSmi(Register object) {
if (emit_debug_code()) {
@@ -5708,28 +6084,45 @@
bind(&done);
}
-
-void MacroAssembler::TestJSArrayForAllocationMemento(
- Register receiver_reg,
- Register scratch_reg,
- Label* no_memento_found,
- Condition cond,
- Label* allocation_memento_present) {
- ExternalReference new_space_start =
- ExternalReference::new_space_start(isolate());
+void MacroAssembler::TestJSArrayForAllocationMemento(Register receiver_reg,
+ Register scratch_reg,
+ Label* no_memento_found) {
+ Label map_check;
+ Label top_check;
ExternalReference new_space_allocation_top =
ExternalReference::new_space_allocation_top_address(isolate());
- Addu(scratch_reg, receiver_reg,
- Operand(JSArray::kSize + AllocationMemento::kSize - kHeapObjectTag));
- Branch(no_memento_found, lt, scratch_reg, Operand(new_space_start));
+ const int kMementoMapOffset = JSArray::kSize - kHeapObjectTag;
+ const int kMementoEndOffset = kMementoMapOffset + AllocationMemento::kSize;
+
+ // Bail out if the object is not in new space.
+ JumpIfNotInNewSpace(receiver_reg, scratch_reg, no_memento_found);
+ // If the object is in new space, we need to check whether it is on the same
+ // page as the current top.
+ Addu(scratch_reg, receiver_reg, Operand(kMementoEndOffset));
+ Xor(scratch_reg, scratch_reg, Operand(new_space_allocation_top));
+ And(scratch_reg, scratch_reg, Operand(~Page::kPageAlignmentMask));
+ Branch(&top_check, eq, scratch_reg, Operand(zero_reg));
+ // The object is on a different page than allocation top. Bail out if the
+ // object sits on the page boundary as no memento can follow and we cannot
+ // touch the memory following it.
+ Addu(scratch_reg, receiver_reg, Operand(kMementoEndOffset));
+ Xor(scratch_reg, scratch_reg, Operand(receiver_reg));
+ And(scratch_reg, scratch_reg, Operand(~Page::kPageAlignmentMask));
+ Branch(no_memento_found, ne, scratch_reg, Operand(zero_reg));
+ // Continue with the actual map check.
+ jmp(&map_check);
+ // If top is on the same page as the current object, we need to check whether
+ // we are below top.
+ bind(&top_check);
+ Addu(scratch_reg, receiver_reg, Operand(kMementoEndOffset));
li(at, Operand(new_space_allocation_top));
lw(at, MemOperand(at));
Branch(no_memento_found, gt, scratch_reg, Operand(at));
- lw(scratch_reg, MemOperand(scratch_reg, -AllocationMemento::kSize));
- if (allocation_memento_present) {
- Branch(allocation_memento_present, cond, scratch_reg,
- Operand(isolate()->factory()->allocation_memento_map()));
- }
+ // Memento map check.
+ bind(&map_check);
+ lw(scratch_reg, MemOperand(receiver_reg, kMementoMapOffset));
+ Branch(no_memento_found, ne, scratch_reg,
+ Operand(isolate()->factory()->allocation_memento_map()));
}
diff --git a/src/mips/macro-assembler-mips.h b/src/mips/macro-assembler-mips.h
index 05a8fec..2f02865 100644
--- a/src/mips/macro-assembler-mips.h
+++ b/src/mips/macro-assembler-mips.h
@@ -237,7 +237,8 @@
void Call(Label* target);
- void Move(Register dst, Smi* smi) { li(dst, Operand(smi)); }
+ inline void Move(Register dst, Handle<Object> handle) { li(dst, handle); }
+ inline void Move(Register dst, Smi* smi) { li(dst, Operand(smi)); }
inline void Move(Register dst, Register src) {
if (!dst.is(src)) {
@@ -245,12 +246,20 @@
}
}
- inline void Move(FPURegister dst, FPURegister src) {
+ inline void Move_d(FPURegister dst, FPURegister src) {
if (!dst.is(src)) {
mov_d(dst, src);
}
}
+ inline void Move_s(FPURegister dst, FPURegister src) {
+ if (!dst.is(src)) {
+ mov_s(dst, src);
+ }
+ }
+
+ inline void Move(FPURegister dst, FPURegister src) { Move_d(dst, src); }
+
inline void Move(Register dst_low, Register dst_high, FPURegister src) {
mfc1(dst_low, src);
Mfhc1(dst_high, src);
@@ -284,6 +293,17 @@
void Movt(Register rd, Register rs, uint16_t cc = 0);
void Movf(Register rd, Register rs, uint16_t cc = 0);
+ // Min, Max macros.
+ // On pre-r6 these functions may modify at and t8 registers.
+ void MinNaNCheck_d(FPURegister dst, FPURegister src1, FPURegister src2,
+ Label* nan = nullptr);
+ void MaxNaNCheck_d(FPURegister dst, FPURegister src1, FPURegister src2,
+ Label* nan = nullptr);
+ void MinNaNCheck_s(FPURegister dst, FPURegister src1, FPURegister src2,
+ Label* nan = nullptr);
+ void MaxNaNCheck_s(FPURegister dst, FPURegister src1, FPURegister src2,
+ Label* nan = nullptr);
+
void Clz(Register rd, Register rs);
// Jump unconditionally to given label.
@@ -629,6 +649,7 @@
DEFINE_INSTRUCTION3(Div);
DEFINE_INSTRUCTION3(Mul);
+ DEFINE_INSTRUCTION3(Mulu);
DEFINE_INSTRUCTION(And);
DEFINE_INSTRUCTION(Or);
@@ -646,8 +667,12 @@
#undef DEFINE_INSTRUCTION2
#undef DEFINE_INSTRUCTION3
+ // Load Scaled Address instructions. Parameter sa (shift argument) must be
+ // between [1, 31] (inclusive). On pre-r6 architectures the scratch register
+ // may be clobbered.
void Lsa(Register rd, Register rs, Register rt, uint8_t sa,
Register scratch = at);
+
void Pref(int32_t hint, const MemOperand& rs);
@@ -761,6 +786,14 @@
Addu(sp, sp, Operand(count * kPointerSize));
}
+ // Push a fixed frame, consisting of ra, fp.
+ void PushCommonFrame(Register marker_reg = no_reg);
+
+ // Push a standard frame, consisting of ra, fp, context and JS function.
+ void PushStandardFrame(Register function_reg);
+
+ void PopCommonFrame(Register marker_reg = no_reg);
+
// Push and pop the registers that can hold pointers, as defined by the
// RegList constant kSafepointSavedRegisters.
void PushSafepointRegisters();
@@ -981,8 +1014,16 @@
// -------------------------------------------------------------------------
// JavaScript invokes.
- // Invoke the JavaScript function code by either calling or jumping.
+ // Removes current frame and its arguments from the stack preserving
+ // the arguments and a return address pushed to the stack for the next call.
+ // Both |callee_args_count| and |caller_args_count_reg| do not include
+ // receiver. |callee_args_count| is not modified, |caller_args_count_reg|
+ // is trashed.
+ void PrepareForTailCall(const ParameterCount& callee_args_count,
+ Register caller_args_count_reg, Register scratch0,
+ Register scratch1);
+ // Invoke the JavaScript function code by either calling or jumping.
void InvokeFunctionCode(Register function, Register new_target,
const ParameterCount& expected,
const ParameterCount& actual, InvokeFlag flag,
@@ -1485,6 +1526,9 @@
// Jump if either of the registers contain a smi.
void JumpIfEitherSmi(Register reg1, Register reg2, Label* on_either_smi);
+ // Abort execution if argument is a number, enabled via --debug-code.
+ void AssertNotNumber(Register object);
+
// Abort execution if argument is a smi, enabled via --debug-code.
void AssertNotSmi(Register object);
void AssertSmi(Register object);
@@ -1604,7 +1648,7 @@
}
// Generates function and stub prologue code.
- void StubPrologue();
+ void StubPrologue(StackFrame::Type type);
void Prologue(bool code_pre_aging);
// Load the type feedback vector from a JavaScript frame.
@@ -1619,25 +1663,22 @@
// in a0. Assumes that any other register can be used as a scratch.
void CheckEnumCache(Label* call_runtime);
- // AllocationMemento support. Arrays may have an associated
- // AllocationMemento object that can be checked for in order to pretransition
- // to another type.
- // On entry, receiver_reg should point to the array object.
- // scratch_reg gets clobbered.
- // If allocation info is present, jump to allocation_memento_present.
- void TestJSArrayForAllocationMemento(
- Register receiver_reg,
- Register scratch_reg,
- Label* no_memento_found,
- Condition cond = al,
- Label* allocation_memento_present = NULL);
+ // AllocationMemento support. Arrays may have an associated AllocationMemento
+ // object that can be checked for in order to pretransition to another type.
+ // On entry, receiver_reg should point to the array object. scratch_reg gets
+ // clobbered. If no info is present jump to no_memento_found, otherwise fall
+ // through.
+ void TestJSArrayForAllocationMemento(Register receiver_reg,
+ Register scratch_reg,
+ Label* no_memento_found);
void JumpIfJSArrayHasAllocationMemento(Register receiver_reg,
Register scratch_reg,
Label* memento_found) {
Label no_memento_found;
TestJSArrayForAllocationMemento(receiver_reg, scratch_reg,
- &no_memento_found, eq, memento_found);
+ &no_memento_found);
+ Branch(memento_found);
bind(&no_memento_found);
}
@@ -1773,16 +1814,18 @@
if (kArchVariant >= kMips32r6) {
BlockTrampolinePoolFor(case_count + 5);
addiupc(at, 5);
- lsa(at, at, index, kPointerSizeLog2);
+ Lsa(at, at, index, kPointerSizeLog2);
lw(at, MemOperand(at));
} else {
Label here;
- BlockTrampolinePoolFor(case_count + 6);
+ BlockTrampolinePoolFor(case_count + 10);
+ push(ra);
bal(&here);
sll(at, index, kPointerSizeLog2); // Branch delay slot.
bind(&here);
addu(at, at, ra);
- lw(at, MemOperand(at, 4 * v8::internal::Assembler::kInstrSize));
+ pop(ra);
+ lw(at, MemOperand(at, 6 * v8::internal::Assembler::kInstrSize));
}
jr(at);
nop(); // Branch delay slot nop.
diff --git a/src/mips/simulator-mips.cc b/src/mips/simulator-mips.cc
index 0c91cb5..e37b6e1 100644
--- a/src/mips/simulator-mips.cc
+++ b/src/mips/simulator-mips.cc
@@ -4483,7 +4483,7 @@
// Set up the callee-saved registers with a known value. To be able to check
// that they are preserved properly across JS execution.
- int32_t callee_saved_value = icount_;
+ int32_t callee_saved_value = static_cast<int32_t>(icount_);
set_register(s0, callee_saved_value);
set_register(s1, callee_saved_value);
set_register(s2, callee_saved_value);