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/mips64/macro-assembler-mips64.cc b/src/mips64/macro-assembler-mips64.cc
index 2de1c2a..7b73ac7 100644
--- a/src/mips64/macro-assembler-mips64.cc
+++ b/src/mips64/macro-assembler-mips64.cc
@@ -4,29 +4,28 @@
#include <limits.h> // For LONG_MIN, LONG_MAX.
-#include "src/v8.h"
-
#if V8_TARGET_ARCH_MIPS64
#include "src/base/division-by-constant.h"
#include "src/bootstrapper.h"
#include "src/codegen.h"
-#include "src/cpu-profiler.h"
-#include "src/debug.h"
-#include "src/isolate-inl.h"
+#include "src/debug/debug.h"
+#include "src/mips64/macro-assembler-mips64.h"
+#include "src/register-configuration.h"
#include "src/runtime/runtime.h"
namespace v8 {
namespace internal {
-MacroAssembler::MacroAssembler(Isolate* arg_isolate, void* buffer, int size)
+MacroAssembler::MacroAssembler(Isolate* arg_isolate, void* buffer, int size,
+ CodeObjectRequired create_code_object)
: Assembler(arg_isolate, buffer, size),
generating_stub_(false),
has_frame_(false),
has_double_zero_reg_set_(false) {
- if (isolate() != NULL) {
- code_object_ = Handle<Object>(isolate()->heap()->undefined_value(),
- isolate());
+ if (create_code_object == CodeObjectRequired::kYes) {
+ code_object_ =
+ Handle<Object>::New(isolate()->heap()->undefined_value(), isolate());
}
}
@@ -89,6 +88,7 @@
void MacroAssembler::StoreRoot(Register source,
Heap::RootListIndex index) {
+ DCHECK(Heap::RootCanBeWrittenAfterInitialization(index));
sd(source, MemOperand(s6, index << kPointerSizeLog2));
}
@@ -97,6 +97,7 @@
Heap::RootListIndex index,
Condition cond,
Register src1, const Operand& src2) {
+ DCHECK(Heap::RootCanBeWrittenAfterInitialization(index));
Branch(2, NegateCondition(cond), src1, src2);
sd(source, MemOperand(s6, index << kPointerSizeLog2));
}
@@ -149,7 +150,7 @@
MemOperand MacroAssembler::SafepointRegistersAndDoublesSlot(Register reg) {
UNIMPLEMENTED_MIPS();
// General purpose registers are pushed last on the stack.
- int doubles_size = FPURegister::NumAllocatableRegisters() * kDoubleSize;
+ int doubles_size = DoubleRegister::kMaxNumRegisters * kDoubleSize;
int register_offset = SafepointRegisterStackIndex(reg.code()) * kPointerSize;
return MemOperand(sp, doubles_size + register_offset);
}
@@ -166,6 +167,9 @@
}
+// Clobbers object, dst, value, and ra, if (ra_status == kRAHasBeenSaved)
+// The register 'object' contains a heap object pointer. The heap object
+// tag is shifted away.
void MacroAssembler::RecordWriteField(
Register object,
int offset,
@@ -219,8 +223,7 @@
}
-// Will clobber 4 registers: object, map, dst, ip. The
-// register 'object' contains a heap object pointer.
+// Clobbers object, dst, map, and ra, if (ra_status == kRAHasBeenSaved)
void MacroAssembler::RecordWriteForMap(Register object,
Register map,
Register dst,
@@ -294,8 +297,8 @@
}
-// Will clobber 4 registers: object, address, scratch, ip. The
-// register 'object' contains a heap object pointer. The heap object
+// Clobbers object, address, value, and ra, if (ra_status == kRAHasBeenSaved)
+// The register 'object' contains a heap object pointer. The heap object
// tag is shifted away.
void MacroAssembler::RecordWrite(
Register object,
@@ -434,10 +437,7 @@
#endif
// Load the native context of the current context.
- int offset =
- Context::kHeaderSize + Context::GLOBAL_OBJECT_INDEX * kPointerSize;
- ld(scratch, FieldMemOperand(scratch, offset));
- ld(scratch, FieldMemOperand(scratch, GlobalObject::kNativeContextOffset));
+ ld(scratch, ContextMemOperand(scratch, Context::NATIVE_CONTEXT_INDEX));
// Check the context is a native context.
if (emit_debug_code()) {
@@ -527,6 +527,7 @@
// hash = hash ^ (hash >> 16);
srl(at, reg0, 16);
xor_(reg0, reg0, at);
+ And(reg0, reg0, Operand(0x3fffffff));
}
@@ -601,7 +602,7 @@
const int kDetailsOffset =
SeededNumberDictionary::kElementsStartOffset + 2 * kPointerSize;
ld(reg1, FieldMemOperand(reg2, kDetailsOffset));
- DCHECK_EQ(FIELD, 0);
+ DCHECK_EQ(DATA, 0);
And(at, reg1, Operand(Smi::FromInt(PropertyDetails::TypeField::kMask)));
Branch(miss, ne, at, Operand(zero_reg));
@@ -620,7 +621,7 @@
addu(rd, rs, rt.rm());
} else {
if (is_int16(rt.imm64_) && !MustUseReg(rt.rmode_)) {
- addiu(rd, rs, rt.imm64_);
+ addiu(rd, rs, static_cast<int32_t>(rt.imm64_));
} else {
// li handles the relocation.
DCHECK(!rs.is(at));
@@ -636,7 +637,7 @@
daddu(rd, rs, rt.rm());
} else {
if (is_int16(rt.imm64_) && !MustUseReg(rt.rmode_)) {
- daddiu(rd, rs, rt.imm64_);
+ daddiu(rd, rs, static_cast<int32_t>(rt.imm64_));
} else {
// li handles the relocation.
DCHECK(!rs.is(at));
@@ -652,7 +653,8 @@
subu(rd, rs, rt.rm());
} else {
if (is_int16(rt.imm64_) && !MustUseReg(rt.rmode_)) {
- addiu(rd, rs, -rt.imm64_); // No subiu instr, use addiu(x, y, -imm).
+ addiu(rd, rs, static_cast<int32_t>(
+ -rt.imm64_)); // No subiu instr, use addiu(x, y, -imm).
} else {
// li handles the relocation.
DCHECK(!rs.is(at));
@@ -668,7 +670,9 @@
dsubu(rd, rs, rt.rm());
} else {
if (is_int16(rt.imm64_) && !MustUseReg(rt.rmode_)) {
- daddiu(rd, rs, -rt.imm64_); // No subiu instr, use addiu(x, y, -imm).
+ daddiu(rd, rs,
+ static_cast<int32_t>(
+ -rt.imm64_)); // No subiu instr, use addiu(x, y, -imm).
} else {
// li handles the relocation.
DCHECK(!rs.is(at));
@@ -1065,7 +1069,7 @@
and_(rd, rs, rt.rm());
} else {
if (is_uint16(rt.imm64_) && !MustUseReg(rt.rmode_)) {
- andi(rd, rs, rt.imm64_);
+ andi(rd, rs, static_cast<int32_t>(rt.imm64_));
} else {
// li handles the relocation.
DCHECK(!rs.is(at));
@@ -1081,7 +1085,7 @@
or_(rd, rs, rt.rm());
} else {
if (is_uint16(rt.imm64_) && !MustUseReg(rt.rmode_)) {
- ori(rd, rs, rt.imm64_);
+ ori(rd, rs, static_cast<int32_t>(rt.imm64_));
} else {
// li handles the relocation.
DCHECK(!rs.is(at));
@@ -1097,7 +1101,7 @@
xor_(rd, rs, rt.rm());
} else {
if (is_uint16(rt.imm64_) && !MustUseReg(rt.rmode_)) {
- xori(rd, rs, rt.imm64_);
+ xori(rd, rs, static_cast<int32_t>(rt.imm64_));
} else {
// li handles the relocation.
DCHECK(!rs.is(at));
@@ -1134,7 +1138,7 @@
slt(rd, rs, rt.rm());
} else {
if (is_int16(rt.imm64_) && !MustUseReg(rt.rmode_)) {
- slti(rd, rs, rt.imm64_);
+ slti(rd, rs, static_cast<int32_t>(rt.imm64_));
} else {
// li handles the relocation.
DCHECK(!rs.is(at));
@@ -1150,7 +1154,7 @@
sltu(rd, rs, rt.rm());
} else {
if (is_int16(rt.imm64_) && !MustUseReg(rt.rmode_)) {
- sltiu(rd, rs, rt.imm64_);
+ sltiu(rd, rs, static_cast<int32_t>(rt.imm64_));
} else {
// li handles the relocation.
DCHECK(!rs.is(at));
@@ -1184,6 +1188,32 @@
}
+void MacroAssembler::Lsa(Register rd, Register rt, Register rs, uint8_t sa,
+ Register scratch) {
+ if (kArchVariant == kMips64r6 && sa <= 4) {
+ lsa(rd, rt, rs, sa);
+ } else {
+ Register tmp = rd.is(rt) ? scratch : rd;
+ DCHECK(!tmp.is(rt));
+ sll(tmp, rs, sa);
+ Addu(rd, rt, tmp);
+ }
+}
+
+
+void MacroAssembler::Dlsa(Register rd, Register rt, Register rs, uint8_t sa,
+ Register scratch) {
+ if (kArchVariant == kMips64r6 && sa <= 4) {
+ dlsa(rd, rt, rs, sa);
+ } else {
+ Register tmp = rd.is(rt) ? scratch : rd;
+ DCHECK(!tmp.is(rt));
+ dsll(tmp, rs, sa);
+ Daddu(rd, rt, tmp);
+ }
+}
+
+
// ------------Pseudo-instructions-------------
void MacroAssembler::Ulw(Register rd, const MemOperand& rs) {
@@ -1204,7 +1234,24 @@
// Assert fail if the offset from start of object IS actually aligned.
// ONLY use with known misalignment, since there is performance cost.
DCHECK((rs.offset() + kHeapObjectTag) & (kPointerSize - 1));
- // TODO(plind): endian dependency.
+ if (kArchEndian == kLittle) {
+ lwu(rd, rs);
+ lw(scratch, MemOperand(rs.rm(), rs.offset() + kPointerSize / 2));
+ dsll32(scratch, scratch, 0);
+ } else {
+ lw(rd, rs);
+ lwu(scratch, MemOperand(rs.rm(), rs.offset() + kPointerSize / 2));
+ dsll32(rd, rd, 0);
+ }
+ Daddu(rd, rd, scratch);
+}
+
+
+// Load consequent 32-bit word pair in 64-bit reg. and put first word in low
+// bits,
+// second word in high bits.
+void MacroAssembler::LoadWordPair(Register rd, const MemOperand& rs,
+ Register scratch) {
lwu(rd, rs);
lw(scratch, MemOperand(rs.rm(), rs.offset() + kPointerSize / 2));
dsll32(scratch, scratch, 0);
@@ -1218,7 +1265,21 @@
// Assert fail if the offset from start of object IS actually aligned.
// ONLY use with known misalignment, since there is performance cost.
DCHECK((rs.offset() + kHeapObjectTag) & (kPointerSize - 1));
- // TODO(plind): endian dependency.
+ if (kArchEndian == kLittle) {
+ sw(rd, rs);
+ dsrl32(scratch, rd, 0);
+ sw(scratch, MemOperand(rs.rm(), rs.offset() + kPointerSize / 2));
+ } else {
+ sw(rd, MemOperand(rs.rm(), rs.offset() + kPointerSize / 2));
+ dsrl32(scratch, rd, 0);
+ sw(scratch, rs);
+ }
+}
+
+
+// Do 64-bit store as two consequent 32-bit stores to unaligned address.
+void MacroAssembler::StoreWordPair(Register rd, const MemOperand& rs,
+ Register scratch) {
sw(rd, rs);
dsrl32(scratch, rd, 0);
sw(scratch, MemOperand(rs.rm(), rs.offset() + kPointerSize / 2));
@@ -1259,12 +1320,42 @@
ori(rd, rd, (j.imm64_ & kImm16Mask));
}
} else {
- lui(rd, (j.imm64_ >> 48) & kImm16Mask);
- ori(rd, rd, (j.imm64_ >> 32) & kImm16Mask);
- dsll(rd, rd, 16);
- ori(rd, rd, (j.imm64_ >> 16) & kImm16Mask);
- dsll(rd, rd, 16);
- ori(rd, rd, j.imm64_ & kImm16Mask);
+ if (is_int48(j.imm64_)) {
+ if ((j.imm64_ >> 32) & kImm16Mask) {
+ lui(rd, (j.imm64_ >> 32) & kImm16Mask);
+ if ((j.imm64_ >> 16) & kImm16Mask) {
+ ori(rd, rd, (j.imm64_ >> 16) & kImm16Mask);
+ }
+ } else {
+ ori(rd, zero_reg, (j.imm64_ >> 16) & kImm16Mask);
+ }
+ dsll(rd, rd, 16);
+ if (j.imm64_ & kImm16Mask) {
+ ori(rd, rd, j.imm64_ & kImm16Mask);
+ }
+ } else {
+ lui(rd, (j.imm64_ >> 48) & kImm16Mask);
+ if ((j.imm64_ >> 32) & kImm16Mask) {
+ ori(rd, rd, (j.imm64_ >> 32) & kImm16Mask);
+ }
+ if ((j.imm64_ >> 16) & kImm16Mask) {
+ dsll(rd, rd, 16);
+ ori(rd, rd, (j.imm64_ >> 16) & kImm16Mask);
+ if (j.imm64_ & kImm16Mask) {
+ dsll(rd, rd, 16);
+ ori(rd, rd, j.imm64_ & kImm16Mask);
+ } else {
+ dsll(rd, rd, 16);
+ }
+ } else {
+ if (j.imm64_ & kImm16Mask) {
+ dsll32(rd, rd, 0);
+ ori(rd, rd, j.imm64_ & kImm16Mask);
+ } else {
+ dsll32(rd, rd, 0);
+ }
+ }
+ }
}
} else if (MustUseReg(j.rmode_)) {
RecordRelocInfo(j.rmode_, j.imm64_);
@@ -1398,21 +1489,6 @@
}
-void MacroAssembler::FlushICache(Register address, unsigned instructions) {
- RegList saved_regs = kJSCallerSaved | ra.bit();
- MultiPush(saved_regs);
- AllowExternalCallThatCantCauseGC scope(this);
-
- // Save to a0 in case address == a4.
- Move(a0, address);
- PrepareCallCFunction(2, a4);
-
- li(a1, instructions * kInstrSize);
- CallCFunction(ExternalReference::flush_icache_function(isolate()), 2);
- MultiPop(saved_regs);
-}
-
-
void MacroAssembler::Ext(Register rt,
Register rs,
uint16_t pos,
@@ -1431,6 +1507,31 @@
}
+void MacroAssembler::Dextm(Register rt, Register rs, uint16_t pos,
+ uint16_t size) {
+ DCHECK(pos < 32);
+ DCHECK(size <= 64);
+ dextm(rt, rs, pos, size);
+}
+
+
+void MacroAssembler::Dextu(Register rt, Register rs, uint16_t pos,
+ uint16_t size) {
+ DCHECK(pos >= 32 && pos < 64);
+ DCHECK(size < 33);
+ dextu(rt, rs, pos, size);
+}
+
+
+void MacroAssembler::Dins(Register rt, Register rs, uint16_t pos,
+ uint16_t size) {
+ DCHECK(pos < 32);
+ DCHECK(pos + size <= 32);
+ DCHECK(size != 0);
+ dins_(rt, rs, pos, size);
+}
+
+
void MacroAssembler::Ins(Register rt,
Register rs,
uint16_t pos,
@@ -1442,49 +1543,90 @@
}
-void MacroAssembler::Cvt_d_uw(FPURegister fd,
- FPURegister fs,
- FPURegister scratch) {
+void MacroAssembler::Cvt_d_uw(FPURegister fd, FPURegister fs) {
// Move the data from fs to t8.
mfc1(t8, fs);
- Cvt_d_uw(fd, t8, scratch);
+ Cvt_d_uw(fd, t8);
}
-void MacroAssembler::Cvt_d_uw(FPURegister fd,
- Register rs,
- FPURegister scratch) {
- // Convert rs to a FP value in fd (and fd + 1).
- // We do this by converting rs minus the MSB to avoid sign conversion,
- // then adding 2^31 to the result (if needed).
-
- DCHECK(!fd.is(scratch));
+void MacroAssembler::Cvt_d_uw(FPURegister fd, Register rs) {
+ // Convert rs to a FP value in fd.
DCHECK(!rs.is(t9));
DCHECK(!rs.is(at));
- // Save rs's MSB to t9.
- Ext(t9, rs, 31, 1);
- // Remove rs's MSB.
- Ext(at, rs, 0, 31);
- // Move the result to fd.
- mtc1(at, fd);
- mthc1(zero_reg, fd);
+ // Zero extend int32 in rs.
+ Dext(t9, rs, 0, 32);
+ dmtc1(t9, fd);
+ cvt_d_l(fd, fd);
+}
- // Convert fd to a real FP value.
- cvt_d_w(fd, fd);
- Label conversion_done;
+void MacroAssembler::Cvt_d_ul(FPURegister fd, FPURegister fs) {
+ // Move the data from fs to t8.
+ dmfc1(t8, fs);
+ Cvt_d_ul(fd, t8);
+}
- // If rs's MSB was 0, it's done.
- // Otherwise we need to add that to the FP register.
- Branch(&conversion_done, eq, t9, Operand(zero_reg));
- // Load 2^31 into f20 as its float representation.
- li(at, 0x41E00000);
- mtc1(zero_reg, scratch);
- mthc1(at, scratch);
- // Add it to fd.
- add_d(fd, fd, scratch);
+void MacroAssembler::Cvt_d_ul(FPURegister fd, Register rs) {
+ // Convert rs to a FP value in fd.
+
+ DCHECK(!rs.is(t9));
+ DCHECK(!rs.is(at));
+
+ Label msb_clear, conversion_done;
+
+ Branch(&msb_clear, ge, rs, Operand(zero_reg));
+
+ // Rs >= 2^63
+ andi(t9, rs, 1);
+ dsrl(rs, rs, 1);
+ or_(t9, t9, rs);
+ dmtc1(t9, fd);
+ cvt_d_l(fd, fd);
+ Branch(USE_DELAY_SLOT, &conversion_done);
+ add_d(fd, fd, fd); // In delay slot.
+
+ bind(&msb_clear);
+ // Rs < 2^63, we can do simple conversion.
+ dmtc1(rs, fd);
+ cvt_d_l(fd, fd);
+
+ bind(&conversion_done);
+}
+
+
+void MacroAssembler::Cvt_s_ul(FPURegister fd, FPURegister fs) {
+ // Move the data from fs to t8.
+ dmfc1(t8, fs);
+ Cvt_s_ul(fd, t8);
+}
+
+
+void MacroAssembler::Cvt_s_ul(FPURegister fd, Register rs) {
+ // Convert rs to a FP value in fd.
+
+ DCHECK(!rs.is(t9));
+ DCHECK(!rs.is(at));
+
+ Label positive, conversion_done;
+
+ Branch(&positive, ge, rs, Operand(zero_reg));
+
+ // Rs >= 2^31.
+ andi(t9, rs, 1);
+ dsrl(rs, rs, 1);
+ or_(t9, t9, rs);
+ dmtc1(t9, fd);
+ cvt_s_l(fd, fd);
+ Branch(USE_DELAY_SLOT, &conversion_done);
+ add_s(fd, fd, fd); // In delay slot.
+
+ bind(&positive);
+ // Rs < 2^31, we can do simple conversion.
+ dmtc1(rs, fd);
+ cvt_s_l(fd, fd);
bind(&conversion_done);
}
@@ -1530,6 +1672,19 @@
mtc1(t8, fd);
}
+void MacroAssembler::Trunc_ul_d(FPURegister fd, FPURegister fs,
+ FPURegister scratch, Register result) {
+ Trunc_ul_d(fs, t8, scratch, result);
+ dmtc1(t8, fd);
+}
+
+
+void MacroAssembler::Trunc_ul_s(FPURegister fd, FPURegister fs,
+ FPURegister scratch, Register result) {
+ Trunc_ul_s(fs, t8, scratch, result);
+ dmtc1(t8, fd);
+}
+
void MacroAssembler::Trunc_w_d(FPURegister fd, FPURegister fs) {
trunc_w_d(fd, fs);
@@ -1584,6 +1739,102 @@
}
+void MacroAssembler::Trunc_ul_d(FPURegister fd, Register rs,
+ FPURegister scratch, Register result) {
+ DCHECK(!fd.is(scratch));
+ DCHECK(!AreAliased(rs, result, at));
+
+ Label simple_convert, done, fail;
+ if (result.is_valid()) {
+ mov(result, zero_reg);
+ Move(scratch, -1.0);
+ // If fd =< -1 or unordered, then the conversion fails.
+ BranchF(&fail, &fail, le, fd, scratch);
+ }
+
+ // Load 2^63 into scratch as its double representation.
+ li(at, 0x43e0000000000000);
+ dmtc1(at, scratch);
+
+ // Test if scratch > fd.
+ // If fd < 2^63 we can convert it normally.
+ BranchF(&simple_convert, nullptr, lt, fd, scratch);
+
+ // First we subtract 2^63 from fd, then trunc it to rs
+ // and add 2^63 to rs.
+ sub_d(scratch, fd, scratch);
+ trunc_l_d(scratch, scratch);
+ dmfc1(rs, scratch);
+ Or(rs, rs, Operand(1UL << 63));
+ Branch(&done);
+
+ // Simple conversion.
+ bind(&simple_convert);
+ trunc_l_d(scratch, fd);
+ dmfc1(rs, scratch);
+
+ bind(&done);
+ if (result.is_valid()) {
+ // Conversion is failed if the result is negative.
+ addiu(at, zero_reg, -1);
+ dsrl(at, at, 1); // Load 2^62.
+ dmfc1(result, scratch);
+ xor_(result, result, at);
+ Slt(result, zero_reg, result);
+ }
+
+ bind(&fail);
+}
+
+
+void MacroAssembler::Trunc_ul_s(FPURegister fd, Register rs,
+ FPURegister scratch, Register result) {
+ DCHECK(!fd.is(scratch));
+ DCHECK(!AreAliased(rs, result, at));
+
+ Label simple_convert, done, fail;
+ if (result.is_valid()) {
+ mov(result, zero_reg);
+ Move(scratch, -1.0f);
+ // If fd =< -1 or unordered, then the conversion fails.
+ BranchF32(&fail, &fail, le, fd, scratch);
+ }
+
+ // Load 2^63 into scratch as its float representation.
+ li(at, 0x5f000000);
+ mtc1(at, scratch);
+
+ // Test if scratch > fd.
+ // If fd < 2^63 we can convert it normally.
+ BranchF32(&simple_convert, nullptr, lt, fd, scratch);
+
+ // First we subtract 2^63 from fd, then trunc it to rs
+ // and add 2^63 to rs.
+ sub_s(scratch, fd, scratch);
+ trunc_l_s(scratch, scratch);
+ dmfc1(rs, scratch);
+ Or(rs, rs, Operand(1UL << 63));
+ Branch(&done);
+
+ // Simple conversion.
+ bind(&simple_convert);
+ trunc_l_s(scratch, fd);
+ dmfc1(rs, scratch);
+
+ bind(&done);
+ if (result.is_valid()) {
+ // Conversion is failed if the result is negative or unordered.
+ addiu(at, zero_reg, -1);
+ dsrl(at, at, 1); // Load 2^62.
+ dmfc1(result, scratch);
+ xor_(result, result, at);
+ Slt(result, zero_reg, result);
+ }
+
+ bind(&fail);
+}
+
+
void MacroAssembler::Madd_d(FPURegister fd, FPURegister fr, FPURegister fs,
FPURegister ft, FPURegister scratch) {
if (0) { // TODO(plind): find reasonable arch-variant symbol names.
@@ -1597,68 +1848,131 @@
}
-void MacroAssembler::BranchF(Label* target,
- Label* nan,
- Condition cc,
- FPURegister cmp1,
- FPURegister cmp2,
- BranchDelaySlot bd) {
+void MacroAssembler::BranchFCommon(SecondaryField sizeField, Label* target,
+ Label* nan, Condition cond, FPURegister cmp1,
+ FPURegister cmp2, BranchDelaySlot bd) {
BlockTrampolinePoolScope block_trampoline_pool(this);
- if (cc == al) {
+ if (cond == al) {
Branch(bd, target);
return;
}
+ if (kArchVariant == kMips64r6) {
+ sizeField = sizeField == D ? L : W;
+ }
+
DCHECK(nan || target);
// Check for unordered (NaN) cases.
if (nan) {
+ bool long_branch = nan->is_bound() ? is_near(nan) : is_trampoline_emitted();
if (kArchVariant != kMips64r6) {
- c(UN, D, cmp1, cmp2);
- bc1t(nan);
+ if (long_branch) {
+ Label skip;
+ c(UN, sizeField, cmp1, cmp2);
+ bc1f(&skip);
+ nop();
+ BranchLong(nan, bd);
+ bind(&skip);
+ } else {
+ c(UN, sizeField, cmp1, cmp2);
+ bc1t(nan);
+ if (bd == PROTECT) {
+ nop();
+ }
+ }
} else {
- // Use f31 for comparison result. It has to be unavailable to lithium
+ // Use kDoubleCompareReg for comparison result. It has to be unavailable
+ // to lithium
// register allocator.
- DCHECK(!cmp1.is(f31) && !cmp2.is(f31));
- cmp(UN, L, f31, cmp1, cmp2);
- bc1nez(nan, f31);
+ DCHECK(!cmp1.is(kDoubleCompareReg) && !cmp2.is(kDoubleCompareReg));
+ if (long_branch) {
+ Label skip;
+ cmp(UN, sizeField, kDoubleCompareReg, cmp1, cmp2);
+ bc1eqz(&skip, kDoubleCompareReg);
+ nop();
+ BranchLong(nan, bd);
+ bind(&skip);
+ } else {
+ cmp(UN, sizeField, kDoubleCompareReg, cmp1, cmp2);
+ bc1nez(nan, kDoubleCompareReg);
+ if (bd == PROTECT) {
+ nop();
+ }
+ }
}
}
+ if (target) {
+ bool long_branch =
+ target->is_bound() ? is_near(target) : is_trampoline_emitted();
+ if (long_branch) {
+ Label skip;
+ Condition neg_cond = NegateFpuCondition(cond);
+ BranchShortF(sizeField, &skip, neg_cond, cmp1, cmp2, bd);
+ BranchLong(target, bd);
+ bind(&skip);
+ } else {
+ BranchShortF(sizeField, target, cond, cmp1, cmp2, bd);
+ }
+ }
+}
+
+
+void MacroAssembler::BranchShortF(SecondaryField sizeField, Label* target,
+ Condition cc, FPURegister cmp1,
+ FPURegister cmp2, BranchDelaySlot bd) {
if (kArchVariant != kMips64r6) {
+ BlockTrampolinePoolScope block_trampoline_pool(this);
if (target) {
// Here NaN cases were either handled by this function or are assumed to
// have been handled by the caller.
switch (cc) {
case lt:
- c(OLT, D, cmp1, cmp2);
+ c(OLT, sizeField, cmp1, cmp2);
+ bc1t(target);
+ break;
+ case ult:
+ c(ULT, sizeField, cmp1, cmp2);
bc1t(target);
break;
case gt:
- c(ULE, D, cmp1, cmp2);
+ c(ULE, sizeField, cmp1, cmp2);
+ bc1f(target);
+ break;
+ case ugt:
+ c(OLE, sizeField, cmp1, cmp2);
bc1f(target);
break;
case ge:
- c(ULT, D, cmp1, cmp2);
+ c(ULT, sizeField, cmp1, cmp2);
+ bc1f(target);
+ break;
+ case uge:
+ c(OLT, sizeField, cmp1, cmp2);
bc1f(target);
break;
case le:
- c(OLE, D, cmp1, cmp2);
+ c(OLE, sizeField, cmp1, cmp2);
+ bc1t(target);
+ break;
+ case ule:
+ c(ULE, sizeField, cmp1, cmp2);
bc1t(target);
break;
case eq:
- c(EQ, D, cmp1, cmp2);
+ c(EQ, sizeField, cmp1, cmp2);
bc1t(target);
break;
case ueq:
- c(UEQ, D, cmp1, cmp2);
+ c(UEQ, sizeField, cmp1, cmp2);
bc1t(target);
break;
- case ne:
- c(EQ, D, cmp1, cmp2);
+ case ne: // Unordered or not equal.
+ c(EQ, sizeField, cmp1, cmp2);
bc1f(target);
break;
- case nue:
- c(UEQ, D, cmp1, cmp2);
+ case ogl:
+ c(UEQ, sizeField, cmp1, cmp2);
bc1f(target);
break;
default:
@@ -1666,44 +1980,62 @@
}
}
} else {
+ BlockTrampolinePoolScope block_trampoline_pool(this);
if (target) {
// Here NaN cases were either handled by this function or are assumed to
// have been handled by the caller.
// Unsigned conditions are treated as their signed counterpart.
- // Use f31 for comparison result, it is valid in fp64 (FR = 1) mode.
- DCHECK(!cmp1.is(f31) && !cmp2.is(f31));
+ // Use kDoubleCompareReg for comparison result, it is valid in fp64 (FR =
+ // 1) mode.
+ DCHECK(!cmp1.is(kDoubleCompareReg) && !cmp2.is(kDoubleCompareReg));
switch (cc) {
case lt:
- cmp(OLT, L, f31, cmp1, cmp2);
- bc1nez(target, f31);
+ cmp(OLT, sizeField, kDoubleCompareReg, cmp1, cmp2);
+ bc1nez(target, kDoubleCompareReg);
+ break;
+ case ult:
+ cmp(ULT, sizeField, kDoubleCompareReg, cmp1, cmp2);
+ bc1nez(target, kDoubleCompareReg);
break;
case gt:
- cmp(ULE, L, f31, cmp1, cmp2);
- bc1eqz(target, f31);
+ cmp(ULE, sizeField, kDoubleCompareReg, cmp1, cmp2);
+ bc1eqz(target, kDoubleCompareReg);
+ break;
+ case ugt:
+ cmp(OLE, sizeField, kDoubleCompareReg, cmp1, cmp2);
+ bc1eqz(target, kDoubleCompareReg);
break;
case ge:
- cmp(ULT, L, f31, cmp1, cmp2);
- bc1eqz(target, f31);
+ cmp(ULT, sizeField, kDoubleCompareReg, cmp1, cmp2);
+ bc1eqz(target, kDoubleCompareReg);
+ break;
+ case uge:
+ cmp(OLT, sizeField, kDoubleCompareReg, cmp1, cmp2);
+ bc1eqz(target, kDoubleCompareReg);
break;
case le:
- cmp(OLE, L, f31, cmp1, cmp2);
- bc1nez(target, f31);
+ cmp(OLE, sizeField, kDoubleCompareReg, cmp1, cmp2);
+ bc1nez(target, kDoubleCompareReg);
+ break;
+ case ule:
+ cmp(ULE, sizeField, kDoubleCompareReg, cmp1, cmp2);
+ bc1nez(target, kDoubleCompareReg);
break;
case eq:
- cmp(EQ, L, f31, cmp1, cmp2);
- bc1nez(target, f31);
+ cmp(EQ, sizeField, kDoubleCompareReg, cmp1, cmp2);
+ bc1nez(target, kDoubleCompareReg);
break;
case ueq:
- cmp(UEQ, L, f31, cmp1, cmp2);
- bc1nez(target, f31);
+ cmp(UEQ, sizeField, kDoubleCompareReg, cmp1, cmp2);
+ bc1nez(target, kDoubleCompareReg);
break;
case ne:
- cmp(EQ, L, f31, cmp1, cmp2);
- bc1eqz(target, f31);
+ cmp(EQ, sizeField, kDoubleCompareReg, cmp1, cmp2);
+ bc1eqz(target, kDoubleCompareReg);
break;
- case nue:
- cmp(UEQ, L, f31, cmp1, cmp2);
- bc1eqz(target, f31);
+ case ogl:
+ cmp(UEQ, sizeField, kDoubleCompareReg, cmp1, cmp2);
+ bc1eqz(target, kDoubleCompareReg);
break;
default:
CHECK(0);
@@ -1717,6 +2049,14 @@
}
+void MacroAssembler::FmoveLow(FPURegister dst, Register src_low) {
+ DCHECK(!src_low.is(at));
+ mfhc1(at, dst);
+ mtc1(src_low, dst);
+ mthc1(at, dst);
+}
+
+
void MacroAssembler::Move(FPURegister dst, float imm) {
li(at, Operand(bit_cast<int32_t>(imm)));
mtc1(at, dst);
@@ -1738,16 +2078,34 @@
// Move the low part of the double into the lower bits of the corresponding
// FPU register.
if (lo != 0) {
- li(at, Operand(lo));
- mtc1(at, dst);
+ if (!(lo & kImm16Mask)) {
+ lui(at, (lo >> kLuiShift) & kImm16Mask);
+ mtc1(at, dst);
+ } else if (!(lo & kHiMask)) {
+ ori(at, zero_reg, lo & kImm16Mask);
+ mtc1(at, dst);
+ } else {
+ lui(at, (lo >> kLuiShift) & kImm16Mask);
+ ori(at, at, lo & kImm16Mask);
+ mtc1(at, dst);
+ }
} else {
mtc1(zero_reg, dst);
}
// Move the high part of the double into the high bits of the corresponding
// FPU register.
if (hi != 0) {
- li(at, Operand(hi));
- mthc1(at, dst);
+ if (!(hi & kImm16Mask)) {
+ lui(at, (hi >> kLuiShift) & kImm16Mask);
+ mthc1(at, dst);
+ } else if (!(hi & kHiMask)) {
+ ori(at, zero_reg, hi & kImm16Mask);
+ mthc1(at, dst);
+ } else {
+ lui(at, (hi >> kLuiShift) & kImm16Mask);
+ ori(at, at, hi & kImm16Mask);
+ mthc1(at, dst);
+ }
} else {
mthc1(zero_reg, dst);
}
@@ -1970,28 +2328,30 @@
(cond != cc_always && (!rs.is(zero_reg) || !rt.rm().is(zero_reg))))
-void MacroAssembler::Branch(int16_t offset, BranchDelaySlot bdslot) {
+void MacroAssembler::Branch(int32_t offset, BranchDelaySlot bdslot) {
+ DCHECK(kArchVariant == kMips64r6 ? is_int26(offset) : is_int16(offset));
BranchShort(offset, bdslot);
}
-void MacroAssembler::Branch(int16_t offset, Condition cond, Register rs,
- const Operand& rt,
- BranchDelaySlot bdslot) {
- BranchShort(offset, cond, rs, rt, bdslot);
+void MacroAssembler::Branch(int32_t offset, Condition cond, Register rs,
+ const Operand& rt, BranchDelaySlot bdslot) {
+ bool is_near = BranchShortCheck(offset, nullptr, cond, rs, rt, bdslot);
+ DCHECK(is_near);
+ USE(is_near);
}
void MacroAssembler::Branch(Label* L, BranchDelaySlot bdslot) {
if (L->is_bound()) {
- if (is_near(L)) {
+ if (is_near_branch(L)) {
BranchShort(L, bdslot);
} else {
- Jr(L, bdslot);
+ BranchLong(L, bdslot);
}
} else {
if (is_trampoline_emitted()) {
- Jr(L, bdslot);
+ BranchLong(L, bdslot);
} else {
BranchShort(L, bdslot);
}
@@ -2003,17 +2363,15 @@
const Operand& rt,
BranchDelaySlot bdslot) {
if (L->is_bound()) {
- if (is_near(L)) {
- BranchShort(L, cond, rs, rt, bdslot);
- } else {
+ if (!BranchShortCheck(0, L, cond, rs, rt, bdslot)) {
if (cond != cc_always) {
Label skip;
Condition neg_cond = NegateCondition(cond);
BranchShort(&skip, neg_cond, rs, rt);
- Jr(L, bdslot);
+ BranchLong(L, bdslot);
bind(&skip);
} else {
- Jr(L, bdslot);
+ BranchLong(L, bdslot);
}
}
} else {
@@ -2022,10 +2380,10 @@
Label skip;
Condition neg_cond = NegateCondition(cond);
BranchShort(&skip, neg_cond, rs, rt);
- Jr(L, bdslot);
+ BranchLong(L, bdslot);
bind(&skip);
} else {
- Jr(L, bdslot);
+ BranchLong(L, bdslot);
}
} else {
BranchShort(L, cond, rs, rt, bdslot);
@@ -2044,7 +2402,10 @@
}
-void MacroAssembler::BranchShort(int16_t offset, BranchDelaySlot bdslot) {
+void MacroAssembler::BranchShortHelper(int16_t offset, Label* L,
+ BranchDelaySlot bdslot) {
+ DCHECK(L == nullptr || offset == 0);
+ offset = GetOffset(offset, L, OffsetSize::kOffset16);
b(offset);
// Emit a nop in the branch delay slot if required.
@@ -2053,549 +2414,544 @@
}
-void MacroAssembler::BranchShort(int16_t offset, Condition cond, Register rs,
- const Operand& rt,
- BranchDelaySlot bdslot) {
- BRANCH_ARGS_CHECK(cond, rs, rt);
- DCHECK(!rs.is(zero_reg));
- Register r2 = no_reg;
- Register scratch = at;
+void MacroAssembler::BranchShortHelperR6(int32_t offset, Label* L) {
+ DCHECK(L == nullptr || offset == 0);
+ offset = GetOffset(offset, L, OffsetSize::kOffset26);
+ bc(offset);
+}
- if (rt.is_reg()) {
- // NOTE: 'at' can be clobbered by Branch but it is legal to use it as rs or
- // rt.
- BlockTrampolinePoolScope block_trampoline_pool(this);
- r2 = rt.rm_;
- switch (cond) {
- case cc_always:
- b(offset);
- break;
- case eq:
- beq(rs, r2, offset);
- break;
- case ne:
- bne(rs, r2, offset);
- break;
- // Signed comparison.
- case greater:
- if (r2.is(zero_reg)) {
- bgtz(rs, offset);
- } else {
- slt(scratch, r2, rs);
- bne(scratch, zero_reg, offset);
- }
- break;
- case greater_equal:
- if (r2.is(zero_reg)) {
- bgez(rs, offset);
- } else {
- slt(scratch, rs, r2);
- beq(scratch, zero_reg, offset);
- }
- break;
- case less:
- if (r2.is(zero_reg)) {
- bltz(rs, offset);
- } else {
- slt(scratch, rs, r2);
- bne(scratch, zero_reg, offset);
- }
- break;
- case less_equal:
- if (r2.is(zero_reg)) {
- blez(rs, offset);
- } else {
- slt(scratch, r2, rs);
- beq(scratch, zero_reg, offset);
- }
- break;
- // Unsigned comparison.
- case Ugreater:
- if (r2.is(zero_reg)) {
- bgtz(rs, offset);
- } else {
- sltu(scratch, r2, rs);
- bne(scratch, zero_reg, offset);
- }
- break;
- case Ugreater_equal:
- if (r2.is(zero_reg)) {
- bgez(rs, offset);
- } else {
- sltu(scratch, rs, r2);
- beq(scratch, zero_reg, offset);
- }
- break;
- case Uless:
- if (r2.is(zero_reg)) {
- // No code needs to be emitted.
- return;
- } else {
- sltu(scratch, rs, r2);
- bne(scratch, zero_reg, offset);
- }
- break;
- case Uless_equal:
- if (r2.is(zero_reg)) {
- b(offset);
- } else {
- sltu(scratch, r2, rs);
- beq(scratch, zero_reg, offset);
- }
- break;
- default:
- UNREACHABLE();
- }
+
+void MacroAssembler::BranchShort(int32_t offset, BranchDelaySlot bdslot) {
+ if (kArchVariant == kMips64r6 && bdslot == PROTECT) {
+ DCHECK(is_int26(offset));
+ BranchShortHelperR6(offset, nullptr);
} else {
- // Be careful to always use shifted_branch_offset only just before the
- // branch instruction, as the location will be remember for patching the
- // target.
- BlockTrampolinePoolScope block_trampoline_pool(this);
- switch (cond) {
- case cc_always:
- b(offset);
- break;
- case eq:
- if (rt.imm64_ == 0) {
- beq(rs, zero_reg, offset);
- } else {
- // We don't want any other register but scratch clobbered.
- DCHECK(!scratch.is(rs));
- r2 = scratch;
- li(r2, rt);
- beq(rs, r2, offset);
- }
- break;
- case ne:
- if (rt.imm64_ == 0) {
- bne(rs, zero_reg, offset);
- } else {
- // We don't want any other register but scratch clobbered.
- DCHECK(!scratch.is(rs));
- r2 = scratch;
- li(r2, rt);
- bne(rs, r2, offset);
- }
- break;
- // Signed comparison.
- case greater:
- if (rt.imm64_ == 0) {
- bgtz(rs, offset);
- } else {
- r2 = scratch;
- li(r2, rt);
- slt(scratch, r2, rs);
- bne(scratch, zero_reg, offset);
- }
- break;
- case greater_equal:
- if (rt.imm64_ == 0) {
- bgez(rs, offset);
- } else if (is_int16(rt.imm64_)) {
- slti(scratch, rs, rt.imm64_);
- beq(scratch, zero_reg, offset);
- } else {
- r2 = scratch;
- li(r2, rt);
- slt(scratch, rs, r2);
- beq(scratch, zero_reg, offset);
- }
- break;
- case less:
- if (rt.imm64_ == 0) {
- bltz(rs, offset);
- } else if (is_int16(rt.imm64_)) {
- slti(scratch, rs, rt.imm64_);
- bne(scratch, zero_reg, offset);
- } else {
- r2 = scratch;
- li(r2, rt);
- slt(scratch, rs, r2);
- bne(scratch, zero_reg, offset);
- }
- break;
- case less_equal:
- if (rt.imm64_ == 0) {
- blez(rs, offset);
- } else {
- r2 = scratch;
- li(r2, rt);
- slt(scratch, r2, rs);
- beq(scratch, zero_reg, offset);
- }
- break;
- // Unsigned comparison.
- case Ugreater:
- if (rt.imm64_ == 0) {
- bgtz(rs, offset);
- } else {
- r2 = scratch;
- li(r2, rt);
- sltu(scratch, r2, rs);
- bne(scratch, zero_reg, offset);
- }
- break;
- case Ugreater_equal:
- if (rt.imm64_ == 0) {
- bgez(rs, offset);
- } else if (is_int16(rt.imm64_)) {
- sltiu(scratch, rs, rt.imm64_);
- beq(scratch, zero_reg, offset);
- } else {
- r2 = scratch;
- li(r2, rt);
- sltu(scratch, rs, r2);
- beq(scratch, zero_reg, offset);
- }
- break;
- case Uless:
- if (rt.imm64_ == 0) {
- // No code needs to be emitted.
- return;
- } else if (is_int16(rt.imm64_)) {
- sltiu(scratch, rs, rt.imm64_);
- bne(scratch, zero_reg, offset);
- } else {
- r2 = scratch;
- li(r2, rt);
- sltu(scratch, rs, r2);
- bne(scratch, zero_reg, offset);
- }
- break;
- case Uless_equal:
- if (rt.imm64_ == 0) {
- b(offset);
- } else {
- r2 = scratch;
- li(r2, rt);
- sltu(scratch, r2, rs);
- beq(scratch, zero_reg, offset);
- }
- break;
- default:
- UNREACHABLE();
- }
+ DCHECK(is_int16(offset));
+ BranchShortHelper(offset, nullptr, bdslot);
}
- // Emit a nop in the branch delay slot if required.
- if (bdslot == PROTECT)
- nop();
}
void MacroAssembler::BranchShort(Label* L, BranchDelaySlot bdslot) {
- // We use branch_offset as an argument for the branch instructions to be sure
- // it is called just before generating the branch instruction, as needed.
-
- b(shifted_branch_offset(L, false));
-
- // Emit a nop in the branch delay slot if required.
- if (bdslot == PROTECT)
- nop();
+ if (kArchVariant == kMips64r6 && bdslot == PROTECT) {
+ BranchShortHelperR6(0, L);
+ } else {
+ BranchShortHelper(0, L, bdslot);
+ }
}
-void MacroAssembler::BranchShort(Label* L, Condition cond, Register rs,
- const Operand& rt,
- BranchDelaySlot bdslot) {
- BRANCH_ARGS_CHECK(cond, rs, rt);
-
- int32_t offset = 0;
- Register r2 = no_reg;
- Register scratch = at;
+static inline bool IsZero(const Operand& rt) {
if (rt.is_reg()) {
- BlockTrampolinePoolScope block_trampoline_pool(this);
+ return rt.rm().is(zero_reg);
+ } else {
+ return rt.immediate() == 0;
+ }
+}
+
+
+int32_t MacroAssembler::GetOffset(int32_t offset, Label* L, OffsetSize bits) {
+ if (L) {
+ offset = branch_offset_helper(L, bits) >> 2;
+ } else {
+ DCHECK(is_intn(offset, bits));
+ }
+ return offset;
+}
+
+
+Register MacroAssembler::GetRtAsRegisterHelper(const Operand& rt,
+ Register scratch) {
+ Register r2 = no_reg;
+ if (rt.is_reg()) {
r2 = rt.rm_;
- // Be careful to always use shifted_branch_offset only just before the
- // branch instruction, as the location will be remember for patching the
- // target.
+ } else {
+ r2 = scratch;
+ li(r2, rt);
+ }
+
+ return r2;
+}
+
+
+bool MacroAssembler::BranchShortHelperR6(int32_t offset, Label* L,
+ Condition cond, Register rs,
+ const Operand& rt) {
+ DCHECK(L == nullptr || offset == 0);
+ Register scratch = rs.is(at) ? t8 : at;
+ OffsetSize bits = OffsetSize::kOffset16;
+
+ // Be careful to always use shifted_branch_offset only just before the
+ // branch instruction, as the location will be remember for patching the
+ // target.
+ {
+ BlockTrampolinePoolScope block_trampoline_pool(this);
switch (cond) {
case cc_always:
- offset = shifted_branch_offset(L, false);
- b(offset);
+ bits = OffsetSize::kOffset26;
+ if (!is_near(L, bits)) return false;
+ offset = GetOffset(offset, L, bits);
+ bc(offset);
break;
case eq:
- offset = shifted_branch_offset(L, false);
- beq(rs, r2, offset);
+ if (rs.code() == rt.rm_.reg_code) {
+ // Pre R6 beq is used here to make the code patchable. Otherwise bc
+ // should be used which has no condition field so is not patchable.
+ bits = OffsetSize::kOffset16;
+ if (!is_near(L, bits)) return false;
+ scratch = GetRtAsRegisterHelper(rt, scratch);
+ offset = GetOffset(offset, L, bits);
+ beq(rs, scratch, offset);
+ nop();
+ } else if (IsZero(rt)) {
+ bits = OffsetSize::kOffset21;
+ if (!is_near(L, bits)) return false;
+ offset = GetOffset(offset, L, bits);
+ beqzc(rs, offset);
+ } else {
+ // We don't want any other register but scratch clobbered.
+ bits = OffsetSize::kOffset16;
+ if (!is_near(L, bits)) return false;
+ scratch = GetRtAsRegisterHelper(rt, scratch);
+ offset = GetOffset(offset, L, bits);
+ beqc(rs, scratch, offset);
+ }
break;
case ne:
- offset = shifted_branch_offset(L, false);
- bne(rs, r2, offset);
+ if (rs.code() == rt.rm_.reg_code) {
+ // Pre R6 bne is used here to make the code patchable. Otherwise we
+ // should not generate any instruction.
+ bits = OffsetSize::kOffset16;
+ if (!is_near(L, bits)) return false;
+ scratch = GetRtAsRegisterHelper(rt, scratch);
+ offset = GetOffset(offset, L, bits);
+ bne(rs, scratch, offset);
+ nop();
+ } else if (IsZero(rt)) {
+ bits = OffsetSize::kOffset21;
+ if (!is_near(L, bits)) return false;
+ offset = GetOffset(offset, L, bits);
+ bnezc(rs, offset);
+ } else {
+ // We don't want any other register but scratch clobbered.
+ bits = OffsetSize::kOffset16;
+ if (!is_near(L, bits)) return false;
+ scratch = GetRtAsRegisterHelper(rt, scratch);
+ offset = GetOffset(offset, L, bits);
+ bnec(rs, scratch, offset);
+ }
break;
+
// Signed comparison.
case greater:
- if (r2.is(zero_reg)) {
- offset = shifted_branch_offset(L, false);
- bgtz(rs, offset);
+ // rs > rt
+ if (rs.code() == rt.rm_.reg_code) {
+ break; // No code needs to be emitted.
+ } else if (rs.is(zero_reg)) {
+ bits = OffsetSize::kOffset16;
+ if (!is_near(L, bits)) return false;
+ scratch = GetRtAsRegisterHelper(rt, scratch);
+ offset = GetOffset(offset, L, bits);
+ bltzc(scratch, offset);
+ } else if (IsZero(rt)) {
+ bits = OffsetSize::kOffset16;
+ if (!is_near(L, bits)) return false;
+ offset = GetOffset(offset, L, bits);
+ bgtzc(rs, offset);
} else {
- slt(scratch, r2, rs);
- offset = shifted_branch_offset(L, false);
- bne(scratch, zero_reg, offset);
+ bits = OffsetSize::kOffset16;
+ if (!is_near(L, bits)) return false;
+ scratch = GetRtAsRegisterHelper(rt, scratch);
+ DCHECK(!rs.is(scratch));
+ offset = GetOffset(offset, L, bits);
+ bltc(scratch, rs, offset);
}
break;
case greater_equal:
- if (r2.is(zero_reg)) {
- offset = shifted_branch_offset(L, false);
- bgez(rs, offset);
+ // rs >= rt
+ if (rs.code() == rt.rm_.reg_code) {
+ bits = OffsetSize::kOffset26;
+ if (!is_near(L, bits)) return false;
+ offset = GetOffset(offset, L, bits);
+ bc(offset);
+ } else if (rs.is(zero_reg)) {
+ bits = OffsetSize::kOffset16;
+ if (!is_near(L, bits)) return false;
+ scratch = GetRtAsRegisterHelper(rt, scratch);
+ offset = GetOffset(offset, L, bits);
+ blezc(scratch, offset);
+ } else if (IsZero(rt)) {
+ bits = OffsetSize::kOffset16;
+ if (!is_near(L, bits)) return false;
+ offset = GetOffset(offset, L, bits);
+ bgezc(rs, offset);
} else {
- slt(scratch, rs, r2);
- offset = shifted_branch_offset(L, false);
- beq(scratch, zero_reg, offset);
+ bits = OffsetSize::kOffset16;
+ if (!is_near(L, bits)) return false;
+ scratch = GetRtAsRegisterHelper(rt, scratch);
+ DCHECK(!rs.is(scratch));
+ offset = GetOffset(offset, L, bits);
+ bgec(rs, scratch, offset);
}
break;
case less:
- if (r2.is(zero_reg)) {
- offset = shifted_branch_offset(L, false);
- bltz(rs, offset);
+ // rs < rt
+ if (rs.code() == rt.rm_.reg_code) {
+ break; // No code needs to be emitted.
+ } else if (rs.is(zero_reg)) {
+ bits = OffsetSize::kOffset16;
+ if (!is_near(L, bits)) return false;
+ scratch = GetRtAsRegisterHelper(rt, scratch);
+ offset = GetOffset(offset, L, bits);
+ bgtzc(scratch, offset);
+ } else if (IsZero(rt)) {
+ bits = OffsetSize::kOffset16;
+ if (!is_near(L, bits)) return false;
+ offset = GetOffset(offset, L, bits);
+ bltzc(rs, offset);
} else {
- slt(scratch, rs, r2);
- offset = shifted_branch_offset(L, false);
- bne(scratch, zero_reg, offset);
+ bits = OffsetSize::kOffset16;
+ if (!is_near(L, bits)) return false;
+ scratch = GetRtAsRegisterHelper(rt, scratch);
+ DCHECK(!rs.is(scratch));
+ offset = GetOffset(offset, L, bits);
+ bltc(rs, scratch, offset);
}
break;
case less_equal:
- if (r2.is(zero_reg)) {
- offset = shifted_branch_offset(L, false);
- blez(rs, offset);
+ // rs <= rt
+ if (rs.code() == rt.rm_.reg_code) {
+ bits = OffsetSize::kOffset26;
+ if (!is_near(L, bits)) return false;
+ offset = GetOffset(offset, L, bits);
+ bc(offset);
+ } else if (rs.is(zero_reg)) {
+ bits = OffsetSize::kOffset16;
+ if (!is_near(L, bits)) return false;
+ scratch = GetRtAsRegisterHelper(rt, scratch);
+ offset = GetOffset(offset, L, bits);
+ bgezc(scratch, offset);
+ } else if (IsZero(rt)) {
+ bits = OffsetSize::kOffset16;
+ if (!is_near(L, bits)) return false;
+ offset = GetOffset(offset, L, bits);
+ blezc(rs, offset);
} else {
- slt(scratch, r2, rs);
- offset = shifted_branch_offset(L, false);
- beq(scratch, zero_reg, offset);
+ bits = OffsetSize::kOffset16;
+ if (!is_near(L, bits)) return false;
+ scratch = GetRtAsRegisterHelper(rt, scratch);
+ DCHECK(!rs.is(scratch));
+ offset = GetOffset(offset, L, bits);
+ bgec(scratch, rs, offset);
}
break;
+
// Unsigned comparison.
case Ugreater:
- if (r2.is(zero_reg)) {
- offset = shifted_branch_offset(L, false);
- bgtz(rs, offset);
+ // rs > rt
+ if (rs.code() == rt.rm_.reg_code) {
+ break; // No code needs to be emitted.
+ } else if (rs.is(zero_reg)) {
+ bits = OffsetSize::kOffset21;
+ if (!is_near(L, bits)) return false;
+ scratch = GetRtAsRegisterHelper(rt, scratch);
+ offset = GetOffset(offset, L, bits);
+ bnezc(scratch, offset);
+ } else if (IsZero(rt)) {
+ bits = OffsetSize::kOffset21;
+ if (!is_near(L, bits)) return false;
+ offset = GetOffset(offset, L, bits);
+ bnezc(rs, offset);
} else {
- sltu(scratch, r2, rs);
- offset = shifted_branch_offset(L, false);
- bne(scratch, zero_reg, offset);
+ bits = OffsetSize::kOffset16;
+ if (!is_near(L, bits)) return false;
+ scratch = GetRtAsRegisterHelper(rt, scratch);
+ DCHECK(!rs.is(scratch));
+ offset = GetOffset(offset, L, bits);
+ bltuc(scratch, rs, offset);
}
break;
case Ugreater_equal:
- if (r2.is(zero_reg)) {
- offset = shifted_branch_offset(L, false);
- bgez(rs, offset);
+ // rs >= rt
+ if (rs.code() == rt.rm_.reg_code) {
+ bits = OffsetSize::kOffset26;
+ if (!is_near(L, bits)) return false;
+ offset = GetOffset(offset, L, bits);
+ bc(offset);
+ } else if (rs.is(zero_reg)) {
+ bits = OffsetSize::kOffset21;
+ if (!is_near(L, bits)) return false;
+ scratch = GetRtAsRegisterHelper(rt, scratch);
+ offset = GetOffset(offset, L, bits);
+ beqzc(scratch, offset);
+ } else if (IsZero(rt)) {
+ bits = OffsetSize::kOffset26;
+ if (!is_near(L, bits)) return false;
+ offset = GetOffset(offset, L, bits);
+ bc(offset);
} else {
- sltu(scratch, rs, r2);
- offset = shifted_branch_offset(L, false);
- beq(scratch, zero_reg, offset);
+ bits = OffsetSize::kOffset16;
+ if (!is_near(L, bits)) return false;
+ scratch = GetRtAsRegisterHelper(rt, scratch);
+ DCHECK(!rs.is(scratch));
+ offset = GetOffset(offset, L, bits);
+ bgeuc(rs, scratch, offset);
}
break;
case Uless:
- if (r2.is(zero_reg)) {
- // No code needs to be emitted.
- return;
+ // rs < rt
+ if (rs.code() == rt.rm_.reg_code) {
+ break; // No code needs to be emitted.
+ } else if (rs.is(zero_reg)) {
+ bits = OffsetSize::kOffset21;
+ if (!is_near(L, bits)) return false;
+ scratch = GetRtAsRegisterHelper(rt, scratch);
+ offset = GetOffset(offset, L, bits);
+ bnezc(scratch, offset);
+ } else if (IsZero(rt)) {
+ break; // No code needs to be emitted.
} else {
- sltu(scratch, rs, r2);
- offset = shifted_branch_offset(L, false);
- bne(scratch, zero_reg, offset);
+ bits = OffsetSize::kOffset16;
+ if (!is_near(L, bits)) return false;
+ scratch = GetRtAsRegisterHelper(rt, scratch);
+ DCHECK(!rs.is(scratch));
+ offset = GetOffset(offset, L, bits);
+ bltuc(rs, scratch, offset);
}
break;
case Uless_equal:
- if (r2.is(zero_reg)) {
- offset = shifted_branch_offset(L, false);
- b(offset);
+ // rs <= rt
+ if (rs.code() == rt.rm_.reg_code) {
+ bits = OffsetSize::kOffset26;
+ if (!is_near(L, bits)) return false;
+ offset = GetOffset(offset, L, bits);
+ bc(offset);
+ } else if (rs.is(zero_reg)) {
+ bits = OffsetSize::kOffset26;
+ if (!is_near(L, bits)) return false;
+ scratch = GetRtAsRegisterHelper(rt, scratch);
+ offset = GetOffset(offset, L, bits);
+ bc(offset);
+ } else if (IsZero(rt)) {
+ bits = OffsetSize::kOffset21;
+ if (!is_near(L, bits)) return false;
+ offset = GetOffset(offset, L, bits);
+ beqzc(rs, offset);
} else {
- sltu(scratch, r2, rs);
- offset = shifted_branch_offset(L, false);
- beq(scratch, zero_reg, offset);
- }
- break;
- default:
- UNREACHABLE();
- }
- } else {
- // Be careful to always use shifted_branch_offset only just before the
- // branch instruction, as the location will be remember for patching the
- // target.
- BlockTrampolinePoolScope block_trampoline_pool(this);
- switch (cond) {
- case cc_always:
- offset = shifted_branch_offset(L, false);
- b(offset);
- break;
- case eq:
- if (rt.imm64_ == 0) {
- offset = shifted_branch_offset(L, false);
- beq(rs, zero_reg, offset);
- } else {
- DCHECK(!scratch.is(rs));
- r2 = scratch;
- li(r2, rt);
- offset = shifted_branch_offset(L, false);
- beq(rs, r2, offset);
- }
- break;
- case ne:
- if (rt.imm64_ == 0) {
- offset = shifted_branch_offset(L, false);
- bne(rs, zero_reg, offset);
- } else {
- DCHECK(!scratch.is(rs));
- r2 = scratch;
- li(r2, rt);
- offset = shifted_branch_offset(L, false);
- bne(rs, r2, offset);
- }
- break;
- // Signed comparison.
- case greater:
- if (rt.imm64_ == 0) {
- offset = shifted_branch_offset(L, false);
- bgtz(rs, offset);
- } else {
- DCHECK(!scratch.is(rs));
- r2 = scratch;
- li(r2, rt);
- slt(scratch, r2, rs);
- offset = shifted_branch_offset(L, false);
- bne(scratch, zero_reg, offset);
- }
- break;
- case greater_equal:
- if (rt.imm64_ == 0) {
- offset = shifted_branch_offset(L, false);
- bgez(rs, offset);
- } else if (is_int16(rt.imm64_)) {
- slti(scratch, rs, rt.imm64_);
- offset = shifted_branch_offset(L, false);
- beq(scratch, zero_reg, offset);
- } else {
- DCHECK(!scratch.is(rs));
- r2 = scratch;
- li(r2, rt);
- slt(scratch, rs, r2);
- offset = shifted_branch_offset(L, false);
- beq(scratch, zero_reg, offset);
- }
- break;
- case less:
- if (rt.imm64_ == 0) {
- offset = shifted_branch_offset(L, false);
- bltz(rs, offset);
- } else if (is_int16(rt.imm64_)) {
- slti(scratch, rs, rt.imm64_);
- offset = shifted_branch_offset(L, false);
- bne(scratch, zero_reg, offset);
- } else {
- DCHECK(!scratch.is(rs));
- r2 = scratch;
- li(r2, rt);
- slt(scratch, rs, r2);
- offset = shifted_branch_offset(L, false);
- bne(scratch, zero_reg, offset);
- }
- break;
- case less_equal:
- if (rt.imm64_ == 0) {
- offset = shifted_branch_offset(L, false);
- blez(rs, offset);
- } else {
- DCHECK(!scratch.is(rs));
- r2 = scratch;
- li(r2, rt);
- slt(scratch, r2, rs);
- offset = shifted_branch_offset(L, false);
- beq(scratch, zero_reg, offset);
- }
- break;
- // Unsigned comparison.
- case Ugreater:
- if (rt.imm64_ == 0) {
- offset = shifted_branch_offset(L, false);
- bne(rs, zero_reg, offset);
- } else {
- DCHECK(!scratch.is(rs));
- r2 = scratch;
- li(r2, rt);
- sltu(scratch, r2, rs);
- offset = shifted_branch_offset(L, false);
- bne(scratch, zero_reg, offset);
- }
- break;
- case Ugreater_equal:
- if (rt.imm64_ == 0) {
- offset = shifted_branch_offset(L, false);
- bgez(rs, offset);
- } else if (is_int16(rt.imm64_)) {
- sltiu(scratch, rs, rt.imm64_);
- offset = shifted_branch_offset(L, false);
- beq(scratch, zero_reg, offset);
- } else {
- DCHECK(!scratch.is(rs));
- r2 = scratch;
- li(r2, rt);
- sltu(scratch, rs, r2);
- offset = shifted_branch_offset(L, false);
- beq(scratch, zero_reg, offset);
- }
- break;
- case Uless:
- if (rt.imm64_ == 0) {
- // No code needs to be emitted.
- return;
- } else if (is_int16(rt.imm64_)) {
- sltiu(scratch, rs, rt.imm64_);
- offset = shifted_branch_offset(L, false);
- bne(scratch, zero_reg, offset);
- } else {
- DCHECK(!scratch.is(rs));
- r2 = scratch;
- li(r2, rt);
- sltu(scratch, rs, r2);
- offset = shifted_branch_offset(L, false);
- bne(scratch, zero_reg, offset);
- }
- break;
- case Uless_equal:
- if (rt.imm64_ == 0) {
- offset = shifted_branch_offset(L, false);
- beq(rs, zero_reg, offset);
- } else {
- DCHECK(!scratch.is(rs));
- r2 = scratch;
- li(r2, rt);
- sltu(scratch, r2, rs);
- offset = shifted_branch_offset(L, false);
- beq(scratch, zero_reg, offset);
+ bits = OffsetSize::kOffset16;
+ if (!is_near(L, bits)) return false;
+ scratch = GetRtAsRegisterHelper(rt, scratch);
+ DCHECK(!rs.is(scratch));
+ offset = GetOffset(offset, L, bits);
+ bgeuc(scratch, rs, offset);
}
break;
default:
UNREACHABLE();
}
}
- // Check that offset could actually hold on an int16_t.
- DCHECK(is_int16(offset));
- // Emit a nop in the branch delay slot if required.
- if (bdslot == PROTECT)
- nop();
+ CheckTrampolinePoolQuick(1);
+ return true;
}
-void MacroAssembler::BranchAndLink(int16_t offset, BranchDelaySlot bdslot) {
+bool MacroAssembler::BranchShortHelper(int16_t offset, Label* L, Condition cond,
+ Register rs, const Operand& rt,
+ BranchDelaySlot bdslot) {
+ DCHECK(L == nullptr || offset == 0);
+ if (!is_near(L, OffsetSize::kOffset16)) return false;
+
+ Register scratch = at;
+ int32_t offset32;
+
+ // Be careful to always use shifted_branch_offset only just before the
+ // branch instruction, as the location will be remember for patching the
+ // target.
+ {
+ BlockTrampolinePoolScope block_trampoline_pool(this);
+ switch (cond) {
+ case cc_always:
+ offset32 = GetOffset(offset, L, OffsetSize::kOffset16);
+ b(offset32);
+ break;
+ case eq:
+ if (IsZero(rt)) {
+ offset32 = GetOffset(offset, L, OffsetSize::kOffset16);
+ beq(rs, zero_reg, offset32);
+ } else {
+ // We don't want any other register but scratch clobbered.
+ scratch = GetRtAsRegisterHelper(rt, scratch);
+ offset32 = GetOffset(offset, L, OffsetSize::kOffset16);
+ beq(rs, scratch, offset32);
+ }
+ break;
+ case ne:
+ if (IsZero(rt)) {
+ offset32 = GetOffset(offset, L, OffsetSize::kOffset16);
+ bne(rs, zero_reg, offset32);
+ } else {
+ // We don't want any other register but scratch clobbered.
+ scratch = GetRtAsRegisterHelper(rt, scratch);
+ offset32 = GetOffset(offset, L, OffsetSize::kOffset16);
+ bne(rs, scratch, offset32);
+ }
+ break;
+
+ // Signed comparison.
+ case greater:
+ if (IsZero(rt)) {
+ offset32 = GetOffset(offset, L, OffsetSize::kOffset16);
+ bgtz(rs, offset32);
+ } else {
+ Slt(scratch, GetRtAsRegisterHelper(rt, scratch), rs);
+ offset32 = GetOffset(offset, L, OffsetSize::kOffset16);
+ bne(scratch, zero_reg, offset32);
+ }
+ break;
+ case greater_equal:
+ if (IsZero(rt)) {
+ offset32 = GetOffset(offset, L, OffsetSize::kOffset16);
+ bgez(rs, offset32);
+ } else {
+ Slt(scratch, rs, rt);
+ offset32 = GetOffset(offset, L, OffsetSize::kOffset16);
+ beq(scratch, zero_reg, offset32);
+ }
+ break;
+ case less:
+ if (IsZero(rt)) {
+ offset32 = GetOffset(offset, L, OffsetSize::kOffset16);
+ bltz(rs, offset32);
+ } else {
+ Slt(scratch, rs, rt);
+ offset32 = GetOffset(offset, L, OffsetSize::kOffset16);
+ bne(scratch, zero_reg, offset32);
+ }
+ break;
+ case less_equal:
+ if (IsZero(rt)) {
+ offset32 = GetOffset(offset, L, OffsetSize::kOffset16);
+ blez(rs, offset32);
+ } else {
+ Slt(scratch, GetRtAsRegisterHelper(rt, scratch), rs);
+ offset32 = GetOffset(offset, L, OffsetSize::kOffset16);
+ beq(scratch, zero_reg, offset32);
+ }
+ break;
+
+ // Unsigned comparison.
+ case Ugreater:
+ if (IsZero(rt)) {
+ offset32 = GetOffset(offset, L, OffsetSize::kOffset16);
+ bne(rs, zero_reg, offset32);
+ } else {
+ Sltu(scratch, GetRtAsRegisterHelper(rt, scratch), rs);
+ offset32 = GetOffset(offset, L, OffsetSize::kOffset16);
+ bne(scratch, zero_reg, offset32);
+ }
+ break;
+ case Ugreater_equal:
+ if (IsZero(rt)) {
+ offset32 = GetOffset(offset, L, OffsetSize::kOffset16);
+ b(offset32);
+ } else {
+ Sltu(scratch, rs, rt);
+ offset32 = GetOffset(offset, L, OffsetSize::kOffset16);
+ beq(scratch, zero_reg, offset32);
+ }
+ break;
+ case Uless:
+ if (IsZero(rt)) {
+ return true; // No code needs to be emitted.
+ } else {
+ Sltu(scratch, rs, rt);
+ offset32 = GetOffset(offset, L, OffsetSize::kOffset16);
+ bne(scratch, zero_reg, offset32);
+ }
+ break;
+ case Uless_equal:
+ if (IsZero(rt)) {
+ offset32 = GetOffset(offset, L, OffsetSize::kOffset16);
+ beq(rs, zero_reg, offset32);
+ } else {
+ Sltu(scratch, GetRtAsRegisterHelper(rt, scratch), rs);
+ offset32 = GetOffset(offset, L, OffsetSize::kOffset16);
+ beq(scratch, zero_reg, offset32);
+ }
+ break;
+ default:
+ UNREACHABLE();
+ }
+ }
+
+ // Emit a nop in the branch delay slot if required.
+ if (bdslot == PROTECT)
+ nop();
+
+ return true;
+}
+
+
+bool MacroAssembler::BranchShortCheck(int32_t offset, Label* L, Condition cond,
+ Register rs, const Operand& rt,
+ BranchDelaySlot bdslot) {
+ BRANCH_ARGS_CHECK(cond, rs, rt);
+
+ if (!L) {
+ if (kArchVariant == kMips64r6 && bdslot == PROTECT) {
+ DCHECK(is_int26(offset));
+ return BranchShortHelperR6(offset, nullptr, cond, rs, rt);
+ } else {
+ DCHECK(is_int16(offset));
+ return BranchShortHelper(offset, nullptr, cond, rs, rt, bdslot);
+ }
+ } else {
+ DCHECK(offset == 0);
+ if (kArchVariant == kMips64r6 && bdslot == PROTECT) {
+ return BranchShortHelperR6(0, L, cond, rs, rt);
+ } else {
+ return BranchShortHelper(0, L, cond, rs, rt, bdslot);
+ }
+ }
+ return false;
+}
+
+
+void MacroAssembler::BranchShort(int32_t offset, Condition cond, Register rs,
+ const Operand& rt, BranchDelaySlot bdslot) {
+ BranchShortCheck(offset, nullptr, cond, rs, rt, bdslot);
+}
+
+
+void MacroAssembler::BranchShort(Label* L, Condition cond, Register rs,
+ const Operand& rt, BranchDelaySlot bdslot) {
+ BranchShortCheck(0, L, cond, rs, rt, bdslot);
+}
+
+
+void MacroAssembler::BranchAndLink(int32_t offset, BranchDelaySlot bdslot) {
BranchAndLinkShort(offset, bdslot);
}
-void MacroAssembler::BranchAndLink(int16_t offset, Condition cond, Register rs,
- const Operand& rt,
- BranchDelaySlot bdslot) {
- BranchAndLinkShort(offset, cond, rs, rt, bdslot);
+void MacroAssembler::BranchAndLink(int32_t offset, Condition cond, Register rs,
+ const Operand& rt, BranchDelaySlot bdslot) {
+ bool is_near = BranchAndLinkShortCheck(offset, nullptr, cond, rs, rt, bdslot);
+ DCHECK(is_near);
+ USE(is_near);
}
void MacroAssembler::BranchAndLink(Label* L, BranchDelaySlot bdslot) {
if (L->is_bound()) {
- if (is_near(L)) {
+ if (is_near_branch(L)) {
BranchAndLinkShort(L, bdslot);
} else {
- Jalr(L, bdslot);
+ BranchAndLinkLong(L, bdslot);
}
} else {
if (is_trampoline_emitted()) {
- Jalr(L, bdslot);
+ BranchAndLinkLong(L, bdslot);
} else {
BranchAndLinkShort(L, bdslot);
}
@@ -2607,13 +2963,11 @@
const Operand& rt,
BranchDelaySlot bdslot) {
if (L->is_bound()) {
- if (is_near(L)) {
- BranchAndLinkShort(L, cond, rs, rt, bdslot);
- } else {
+ if (!BranchAndLinkShortCheck(0, L, cond, rs, rt, bdslot)) {
Label skip;
Condition neg_cond = NegateCondition(cond);
BranchShort(&skip, neg_cond, rs, rt);
- Jalr(L, bdslot);
+ BranchAndLinkLong(L, bdslot);
bind(&skip);
}
} else {
@@ -2621,20 +2975,19 @@
Label skip;
Condition neg_cond = NegateCondition(cond);
BranchShort(&skip, neg_cond, rs, rt);
- Jalr(L, bdslot);
+ BranchAndLinkLong(L, bdslot);
bind(&skip);
} else {
- BranchAndLinkShort(L, cond, rs, rt, bdslot);
+ BranchAndLinkShortCheck(0, L, cond, rs, rt, bdslot);
}
}
}
-// We need to use a bgezal or bltzal, but they can't be used directly with the
-// slt instructions. We could use sub or add instead but we would miss overflow
-// cases, so we keep slt and add an intermediate third instruction.
-void MacroAssembler::BranchAndLinkShort(int16_t offset,
- BranchDelaySlot bdslot) {
+void MacroAssembler::BranchAndLinkShortHelper(int16_t offset, Label* L,
+ BranchDelaySlot bdslot) {
+ DCHECK(L == nullptr || offset == 0);
+ offset = GetOffset(offset, L, OffsetSize::kOffset16);
bal(offset);
// Emit a nop in the branch delay slot if required.
@@ -2643,230 +2996,306 @@
}
-void MacroAssembler::BranchAndLinkShort(int16_t offset, Condition cond,
- Register rs, const Operand& rt,
+void MacroAssembler::BranchAndLinkShortHelperR6(int32_t offset, Label* L) {
+ DCHECK(L == nullptr || offset == 0);
+ offset = GetOffset(offset, L, OffsetSize::kOffset26);
+ balc(offset);
+}
+
+
+void MacroAssembler::BranchAndLinkShort(int32_t offset,
BranchDelaySlot bdslot) {
- BRANCH_ARGS_CHECK(cond, rs, rt);
- Register r2 = no_reg;
- Register scratch = at;
-
- if (rt.is_reg()) {
- r2 = rt.rm_;
- } else if (cond != cc_always) {
- r2 = scratch;
- li(r2, rt);
+ if (kArchVariant == kMips64r6 && bdslot == PROTECT) {
+ DCHECK(is_int26(offset));
+ BranchAndLinkShortHelperR6(offset, nullptr);
+ } else {
+ DCHECK(is_int16(offset));
+ BranchAndLinkShortHelper(offset, nullptr, bdslot);
}
-
- {
- BlockTrampolinePoolScope block_trampoline_pool(this);
- switch (cond) {
- case cc_always:
- bal(offset);
- break;
- case eq:
- bne(rs, r2, 2);
- nop();
- bal(offset);
- break;
- case ne:
- beq(rs, r2, 2);
- nop();
- bal(offset);
- break;
-
- // Signed comparison.
- case greater:
- // rs > rt
- slt(scratch, r2, rs);
- beq(scratch, zero_reg, 2);
- nop();
- bal(offset);
- break;
- case greater_equal:
- // rs >= rt
- slt(scratch, rs, r2);
- bne(scratch, zero_reg, 2);
- nop();
- bal(offset);
- break;
- case less:
- // rs < r2
- slt(scratch, rs, r2);
- bne(scratch, zero_reg, 2);
- nop();
- bal(offset);
- break;
- case less_equal:
- // rs <= r2
- slt(scratch, r2, rs);
- bne(scratch, zero_reg, 2);
- nop();
- bal(offset);
- break;
-
-
- // Unsigned comparison.
- case Ugreater:
- // rs > rt
- sltu(scratch, r2, rs);
- beq(scratch, zero_reg, 2);
- nop();
- bal(offset);
- break;
- case Ugreater_equal:
- // rs >= rt
- sltu(scratch, rs, r2);
- bne(scratch, zero_reg, 2);
- nop();
- bal(offset);
- break;
- case Uless:
- // rs < r2
- sltu(scratch, rs, r2);
- bne(scratch, zero_reg, 2);
- nop();
- bal(offset);
- break;
- case Uless_equal:
- // rs <= r2
- sltu(scratch, r2, rs);
- bne(scratch, zero_reg, 2);
- nop();
- bal(offset);
- break;
- default:
- UNREACHABLE();
- }
- }
- // Emit a nop in the branch delay slot if required.
- if (bdslot == PROTECT)
- nop();
}
void MacroAssembler::BranchAndLinkShort(Label* L, BranchDelaySlot bdslot) {
- bal(shifted_branch_offset(L, false));
-
- // Emit a nop in the branch delay slot if required.
- if (bdslot == PROTECT)
- nop();
+ if (kArchVariant == kMips64r6 && bdslot == PROTECT) {
+ BranchAndLinkShortHelperR6(0, L);
+ } else {
+ BranchAndLinkShortHelper(0, L, bdslot);
+ }
}
-void MacroAssembler::BranchAndLinkShort(Label* L, Condition cond, Register rs,
- const Operand& rt,
- BranchDelaySlot bdslot) {
- BRANCH_ARGS_CHECK(cond, rs, rt);
+bool MacroAssembler::BranchAndLinkShortHelperR6(int32_t offset, Label* L,
+ Condition cond, Register rs,
+ const Operand& rt) {
+ DCHECK(L == nullptr || offset == 0);
+ Register scratch = rs.is(at) ? t8 : at;
+ OffsetSize bits = OffsetSize::kOffset16;
- int32_t offset = 0;
- Register r2 = no_reg;
- Register scratch = at;
- if (rt.is_reg()) {
- r2 = rt.rm_;
- } else if (cond != cc_always) {
- r2 = scratch;
- li(r2, rt);
+ BlockTrampolinePoolScope block_trampoline_pool(this);
+ DCHECK((cond == cc_always && is_int26(offset)) || is_int16(offset));
+ switch (cond) {
+ case cc_always:
+ bits = OffsetSize::kOffset26;
+ if (!is_near(L, bits)) return false;
+ offset = GetOffset(offset, L, bits);
+ balc(offset);
+ break;
+ case eq:
+ if (!is_near(L, bits)) return false;
+ Subu(scratch, rs, rt);
+ offset = GetOffset(offset, L, bits);
+ beqzalc(scratch, offset);
+ break;
+ case ne:
+ if (!is_near(L, bits)) return false;
+ Subu(scratch, rs, rt);
+ offset = GetOffset(offset, L, bits);
+ bnezalc(scratch, offset);
+ break;
+
+ // Signed comparison.
+ case greater:
+ // rs > rt
+ if (rs.code() == rt.rm_.reg_code) {
+ break; // No code needs to be emitted.
+ } else if (rs.is(zero_reg)) {
+ if (!is_near(L, bits)) return false;
+ scratch = GetRtAsRegisterHelper(rt, scratch);
+ offset = GetOffset(offset, L, bits);
+ bltzalc(scratch, offset);
+ } else if (IsZero(rt)) {
+ if (!is_near(L, bits)) return false;
+ offset = GetOffset(offset, L, bits);
+ bgtzalc(rs, offset);
+ } else {
+ if (!is_near(L, bits)) return false;
+ Slt(scratch, GetRtAsRegisterHelper(rt, scratch), rs);
+ offset = GetOffset(offset, L, bits);
+ bnezalc(scratch, offset);
+ }
+ break;
+ case greater_equal:
+ // rs >= rt
+ if (rs.code() == rt.rm_.reg_code) {
+ bits = OffsetSize::kOffset26;
+ if (!is_near(L, bits)) return false;
+ offset = GetOffset(offset, L, bits);
+ balc(offset);
+ } else if (rs.is(zero_reg)) {
+ if (!is_near(L, bits)) return false;
+ scratch = GetRtAsRegisterHelper(rt, scratch);
+ offset = GetOffset(offset, L, bits);
+ blezalc(scratch, offset);
+ } else if (IsZero(rt)) {
+ if (!is_near(L, bits)) return false;
+ offset = GetOffset(offset, L, bits);
+ bgezalc(rs, offset);
+ } else {
+ if (!is_near(L, bits)) return false;
+ Slt(scratch, rs, rt);
+ offset = GetOffset(offset, L, bits);
+ beqzalc(scratch, offset);
+ }
+ break;
+ case less:
+ // rs < rt
+ if (rs.code() == rt.rm_.reg_code) {
+ break; // No code needs to be emitted.
+ } else if (rs.is(zero_reg)) {
+ if (!is_near(L, bits)) return false;
+ scratch = GetRtAsRegisterHelper(rt, scratch);
+ offset = GetOffset(offset, L, bits);
+ bgtzalc(scratch, offset);
+ } else if (IsZero(rt)) {
+ if (!is_near(L, bits)) return false;
+ offset = GetOffset(offset, L, bits);
+ bltzalc(rs, offset);
+ } else {
+ if (!is_near(L, bits)) return false;
+ Slt(scratch, rs, rt);
+ offset = GetOffset(offset, L, bits);
+ bnezalc(scratch, offset);
+ }
+ break;
+ case less_equal:
+ // rs <= r2
+ if (rs.code() == rt.rm_.reg_code) {
+ bits = OffsetSize::kOffset26;
+ if (!is_near(L, bits)) return false;
+ offset = GetOffset(offset, L, bits);
+ balc(offset);
+ } else if (rs.is(zero_reg)) {
+ if (!is_near(L, bits)) return false;
+ scratch = GetRtAsRegisterHelper(rt, scratch);
+ offset = GetOffset(offset, L, bits);
+ bgezalc(scratch, offset);
+ } else if (IsZero(rt)) {
+ if (!is_near(L, bits)) return false;
+ offset = GetOffset(offset, L, bits);
+ blezalc(rs, offset);
+ } else {
+ if (!is_near(L, bits)) return false;
+ Slt(scratch, GetRtAsRegisterHelper(rt, scratch), rs);
+ offset = GetOffset(offset, L, bits);
+ beqzalc(scratch, offset);
+ }
+ break;
+
+
+ // Unsigned comparison.
+ case Ugreater:
+ // rs > r2
+ if (!is_near(L, bits)) return false;
+ Sltu(scratch, GetRtAsRegisterHelper(rt, scratch), rs);
+ offset = GetOffset(offset, L, bits);
+ bnezalc(scratch, offset);
+ break;
+ case Ugreater_equal:
+ // rs >= r2
+ if (!is_near(L, bits)) return false;
+ Sltu(scratch, rs, rt);
+ offset = GetOffset(offset, L, bits);
+ beqzalc(scratch, offset);
+ break;
+ case Uless:
+ // rs < r2
+ if (!is_near(L, bits)) return false;
+ Sltu(scratch, rs, rt);
+ offset = GetOffset(offset, L, bits);
+ bnezalc(scratch, offset);
+ break;
+ case Uless_equal:
+ // rs <= r2
+ if (!is_near(L, bits)) return false;
+ Sltu(scratch, GetRtAsRegisterHelper(rt, scratch), rs);
+ offset = GetOffset(offset, L, bits);
+ beqzalc(scratch, offset);
+ break;
+ default:
+ UNREACHABLE();
}
-
- {
- BlockTrampolinePoolScope block_trampoline_pool(this);
- switch (cond) {
- case cc_always:
- offset = shifted_branch_offset(L, false);
- bal(offset);
- break;
- case eq:
- bne(rs, r2, 2);
- nop();
- offset = shifted_branch_offset(L, false);
- bal(offset);
- break;
- case ne:
- beq(rs, r2, 2);
- nop();
- offset = shifted_branch_offset(L, false);
- bal(offset);
- break;
-
- // Signed comparison.
- case greater:
- // rs > rt
- slt(scratch, r2, rs);
- beq(scratch, zero_reg, 2);
- nop();
- offset = shifted_branch_offset(L, false);
- bal(offset);
- break;
- case greater_equal:
- // rs >= rt
- slt(scratch, rs, r2);
- bne(scratch, zero_reg, 2);
- nop();
- offset = shifted_branch_offset(L, false);
- bal(offset);
- break;
- case less:
- // rs < r2
- slt(scratch, rs, r2);
- bne(scratch, zero_reg, 2);
- nop();
- offset = shifted_branch_offset(L, false);
- bal(offset);
- break;
- case less_equal:
- // rs <= r2
- slt(scratch, r2, rs);
- bne(scratch, zero_reg, 2);
- nop();
- offset = shifted_branch_offset(L, false);
- bal(offset);
- break;
+ return true;
+}
- // Unsigned comparison.
- case Ugreater:
- // rs > rt
- sltu(scratch, r2, rs);
- beq(scratch, zero_reg, 2);
- nop();
- offset = shifted_branch_offset(L, false);
- bal(offset);
- break;
- case Ugreater_equal:
- // rs >= rt
- sltu(scratch, rs, r2);
- bne(scratch, zero_reg, 2);
- nop();
- offset = shifted_branch_offset(L, false);
- bal(offset);
- break;
- case Uless:
- // rs < r2
- sltu(scratch, rs, r2);
- bne(scratch, zero_reg, 2);
- nop();
- offset = shifted_branch_offset(L, false);
- bal(offset);
- break;
- case Uless_equal:
- // rs <= r2
- sltu(scratch, r2, rs);
- bne(scratch, zero_reg, 2);
- nop();
- offset = shifted_branch_offset(L, false);
- bal(offset);
- break;
+// Pre r6 we need to use a bgezal or bltzal, but they can't be used directly
+// with the slt instructions. We could use sub or add instead but we would miss
+// overflow cases, so we keep slt and add an intermediate third instruction.
+bool MacroAssembler::BranchAndLinkShortHelper(int16_t offset, Label* L,
+ Condition cond, Register rs,
+ const Operand& rt,
+ BranchDelaySlot bdslot) {
+ DCHECK(L == nullptr || offset == 0);
+ if (!is_near(L, OffsetSize::kOffset16)) return false;
- default:
- UNREACHABLE();
- }
+ Register scratch = t8;
+ BlockTrampolinePoolScope block_trampoline_pool(this);
+
+ switch (cond) {
+ case cc_always:
+ offset = GetOffset(offset, L, OffsetSize::kOffset16);
+ bal(offset);
+ break;
+ case eq:
+ bne(rs, GetRtAsRegisterHelper(rt, scratch), 2);
+ nop();
+ offset = GetOffset(offset, L, OffsetSize::kOffset16);
+ bal(offset);
+ break;
+ case ne:
+ beq(rs, GetRtAsRegisterHelper(rt, scratch), 2);
+ nop();
+ offset = GetOffset(offset, L, OffsetSize::kOffset16);
+ bal(offset);
+ break;
+
+ // Signed comparison.
+ case greater:
+ Slt(scratch, GetRtAsRegisterHelper(rt, scratch), rs);
+ addiu(scratch, scratch, -1);
+ offset = GetOffset(offset, L, OffsetSize::kOffset16);
+ bgezal(scratch, offset);
+ break;
+ case greater_equal:
+ Slt(scratch, rs, rt);
+ addiu(scratch, scratch, -1);
+ offset = GetOffset(offset, L, OffsetSize::kOffset16);
+ bltzal(scratch, offset);
+ break;
+ case less:
+ Slt(scratch, rs, rt);
+ addiu(scratch, scratch, -1);
+ offset = GetOffset(offset, L, OffsetSize::kOffset16);
+ bgezal(scratch, offset);
+ break;
+ case less_equal:
+ Slt(scratch, GetRtAsRegisterHelper(rt, scratch), rs);
+ addiu(scratch, scratch, -1);
+ offset = GetOffset(offset, L, OffsetSize::kOffset16);
+ bltzal(scratch, offset);
+ break;
+
+ // Unsigned comparison.
+ case Ugreater:
+ Sltu(scratch, GetRtAsRegisterHelper(rt, scratch), rs);
+ addiu(scratch, scratch, -1);
+ offset = GetOffset(offset, L, OffsetSize::kOffset16);
+ bgezal(scratch, offset);
+ break;
+ case Ugreater_equal:
+ Sltu(scratch, rs, rt);
+ addiu(scratch, scratch, -1);
+ offset = GetOffset(offset, L, OffsetSize::kOffset16);
+ bltzal(scratch, offset);
+ break;
+ case Uless:
+ Sltu(scratch, rs, rt);
+ addiu(scratch, scratch, -1);
+ offset = GetOffset(offset, L, OffsetSize::kOffset16);
+ bgezal(scratch, offset);
+ break;
+ case Uless_equal:
+ Sltu(scratch, GetRtAsRegisterHelper(rt, scratch), rs);
+ addiu(scratch, scratch, -1);
+ offset = GetOffset(offset, L, OffsetSize::kOffset16);
+ bltzal(scratch, offset);
+ break;
+
+ default:
+ UNREACHABLE();
}
- // Check that offset could actually hold on an int16_t.
- DCHECK(is_int16(offset));
// Emit a nop in the branch delay slot if required.
if (bdslot == PROTECT)
nop();
+
+ return true;
+}
+
+
+bool MacroAssembler::BranchAndLinkShortCheck(int32_t offset, Label* L,
+ Condition cond, Register rs,
+ const Operand& rt,
+ BranchDelaySlot bdslot) {
+ BRANCH_ARGS_CHECK(cond, rs, rt);
+
+ if (!L) {
+ if (kArchVariant == kMips64r6 && bdslot == PROTECT) {
+ DCHECK(is_int26(offset));
+ return BranchAndLinkShortHelperR6(offset, nullptr, cond, rs, rt);
+ } else {
+ DCHECK(is_int16(offset));
+ return BranchAndLinkShortHelper(offset, nullptr, cond, rs, rt, bdslot);
+ }
+ } else {
+ DCHECK(offset == 0);
+ if (kArchVariant == kMips64r6 && bdslot == PROTECT) {
+ return BranchAndLinkShortHelperR6(0, L, cond, rs, rt);
+ } else {
+ return BranchAndLinkShortHelper(0, L, cond, rs, rt, bdslot);
+ }
+ }
+ return false;
}
@@ -2956,6 +3385,10 @@
Register rs,
const Operand& rt,
BranchDelaySlot bd) {
+#ifdef DEBUG
+ int size = IsPrevInstrCompactBranch() ? kInstrSize : 0;
+#endif
+
BlockTrampolinePoolScope block_trampoline_pool(this);
Label start;
bind(&start);
@@ -2970,8 +3403,10 @@
if (bd == PROTECT)
nop();
- DCHECK_EQ(CallSize(target, cond, rs, rt, bd),
- SizeOfCodeGeneratedSince(&start));
+#ifdef DEBUG
+ CHECK_EQ(size + CallSize(target, cond, rs, rt, bd),
+ SizeOfCodeGeneratedSince(&start));
+#endif
}
@@ -3049,21 +3484,43 @@
}
-void MacroAssembler::J(Label* L, BranchDelaySlot bdslot) {
- BlockTrampolinePoolScope block_trampoline_pool(this);
-
- uint64_t imm28;
- imm28 = jump_address(L);
- imm28 &= kImm28Mask;
- { 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);
- j(imm28);
+void MacroAssembler::BranchLong(Label* L, BranchDelaySlot bdslot) {
+ if (kArchVariant == kMips64r6 && bdslot == PROTECT &&
+ (!L->is_bound() || is_near_r6(L))) {
+ BranchShortHelperR6(0, L);
+ } else {
+ EmitForbiddenSlotInstruction();
+ BlockTrampolinePoolScope block_trampoline_pool(this);
+ {
+ 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);
+ j(L);
+ }
+ // Emit a nop in the branch delay slot if required.
+ if (bdslot == PROTECT) nop();
}
- // Emit a nop in the branch delay slot if required.
- if (bdslot == PROTECT)
- nop();
+}
+
+
+void MacroAssembler::BranchAndLinkLong(Label* L, BranchDelaySlot bdslot) {
+ if (kArchVariant == kMips64r6 && bdslot == PROTECT &&
+ (!L->is_bound() || is_near_r6(L))) {
+ BranchAndLinkShortHelperR6(0, L);
+ } else {
+ EmitForbiddenSlotInstruction();
+ BlockTrampolinePoolScope block_trampoline_pool(this);
+ {
+ 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);
+ jal(L);
+ }
+ // Emit a nop in the branch delay slot if required.
+ if (bdslot == PROTECT) nop();
+ }
}
@@ -3075,7 +3532,7 @@
{ 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);
+ RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE_ENCODED);
li(at, Operand(imm64), ADDRESS_LOAD);
}
jr(at);
@@ -3094,7 +3551,7 @@
{ 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);
+ RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE_ENCODED);
li(at, Operand(imm64), ADDRESS_LOAD);
}
jalr(at);
@@ -3106,6 +3563,7 @@
void MacroAssembler::DropAndRet(int drop) {
+ DCHECK(is_int16(drop * kPointerSize));
Ret(USE_DELAY_SLOT);
daddiu(sp, sp, drop * kPointerSize);
}
@@ -3143,7 +3601,7 @@
Branch(&skip, NegateCondition(cond), reg, op);
}
- daddiu(sp, sp, count * kPointerSize);
+ Daddu(sp, sp, Operand(count * kPointerSize));
if (cond != al) {
bind(&skip);
@@ -3202,160 +3660,42 @@
void MacroAssembler::DebugBreak() {
PrepareCEntryArgs(0);
- PrepareCEntryFunction(ExternalReference(Runtime::kDebugBreak, isolate()));
+ PrepareCEntryFunction(
+ ExternalReference(Runtime::kHandleDebuggerStatement, isolate()));
CEntryStub ces(isolate(), 1);
DCHECK(AllowThisStubCall(&ces));
- Call(ces.GetCode(), RelocInfo::DEBUG_BREAK);
+ Call(ces.GetCode(), RelocInfo::DEBUGGER_STATEMENT);
}
// ---------------------------------------------------------------------------
// Exception handling.
-void MacroAssembler::PushTryHandler(StackHandler::Kind kind,
- int handler_index) {
+void MacroAssembler::PushStackHandler() {
// Adjust this code if not the case.
- STATIC_ASSERT(StackHandlerConstants::kSize == 5 * kPointerSize);
+ STATIC_ASSERT(StackHandlerConstants::kSize == 1 * kPointerSize);
STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0 * kPointerSize);
- STATIC_ASSERT(StackHandlerConstants::kCodeOffset == 1 * kPointerSize);
- STATIC_ASSERT(StackHandlerConstants::kStateOffset == 2 * kPointerSize);
- STATIC_ASSERT(StackHandlerConstants::kContextOffset == 3 * kPointerSize);
- STATIC_ASSERT(StackHandlerConstants::kFPOffset == 4 * kPointerSize);
-
- // For the JSEntry handler, we must preserve a0-a3 and s0.
- // a5-a7 are available. We will build up the handler from the bottom by
- // pushing on the stack.
- // Set up the code object (a5) and the state (a6) for pushing.
- unsigned state =
- StackHandler::IndexField::encode(handler_index) |
- StackHandler::KindField::encode(kind);
- li(a5, Operand(CodeObject()), CONSTANT_SIZE);
- li(a6, Operand(state));
-
- // Push the frame pointer, context, state, and code object.
- if (kind == StackHandler::JS_ENTRY) {
- DCHECK_EQ(Smi::FromInt(0), 0);
- // The second zero_reg indicates no context.
- // The first zero_reg is the NULL frame pointer.
- // The operands are reversed to match the order of MultiPush/Pop.
- Push(zero_reg, zero_reg, a6, a5);
- } else {
- MultiPush(a5.bit() | a6.bit() | cp.bit() | fp.bit());
- }
// Link the current handler as the next handler.
li(a6, Operand(ExternalReference(Isolate::kHandlerAddress, isolate())));
ld(a5, MemOperand(a6));
push(a5);
+
// Set this new handler as the current one.
sd(sp, MemOperand(a6));
}
-void MacroAssembler::PopTryHandler() {
+void MacroAssembler::PopStackHandler() {
STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0);
pop(a1);
- Daddu(sp, sp, Operand(StackHandlerConstants::kSize - kPointerSize));
+ Daddu(sp, sp, Operand(static_cast<int64_t>(StackHandlerConstants::kSize -
+ kPointerSize)));
li(at, Operand(ExternalReference(Isolate::kHandlerAddress, isolate())));
sd(a1, MemOperand(at));
}
-void MacroAssembler::JumpToHandlerEntry() {
- // Compute the handler entry address and jump to it. The handler table is
- // a fixed array of (smi-tagged) code offsets.
- // v0 = exception, a1 = code object, a2 = state.
- ld(a3, FieldMemOperand(a1, Code::kHandlerTableOffset));
- Daddu(a3, a3, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
- dsrl(a2, a2, StackHandler::kKindWidth); // Handler index.
- dsll(a2, a2, kPointerSizeLog2);
- Daddu(a2, a3, a2);
- ld(a2, MemOperand(a2)); // Smi-tagged offset.
- Daddu(a1, a1, Operand(Code::kHeaderSize - kHeapObjectTag)); // Code start.
- dsra32(t9, a2, 0);
- Daddu(t9, t9, a1);
- Jump(t9); // Jump.
-}
-
-
-void MacroAssembler::Throw(Register value) {
- // Adjust this code if not the case.
- STATIC_ASSERT(StackHandlerConstants::kSize == 5 * kPointerSize);
- STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0);
- STATIC_ASSERT(StackHandlerConstants::kCodeOffset == 1 * kPointerSize);
- STATIC_ASSERT(StackHandlerConstants::kStateOffset == 2 * kPointerSize);
- STATIC_ASSERT(StackHandlerConstants::kContextOffset == 3 * kPointerSize);
- STATIC_ASSERT(StackHandlerConstants::kFPOffset == 4 * kPointerSize);
-
- // The exception is expected in v0.
- Move(v0, value);
-
- // Drop the stack pointer to the top of the top handler.
- li(a3, Operand(ExternalReference(Isolate::kHandlerAddress,
- isolate())));
- ld(sp, MemOperand(a3));
-
- // Restore the next handler.
- pop(a2);
- sd(a2, MemOperand(a3));
-
- // Get the code object (a1) and state (a2). Restore the context and frame
- // pointer.
- MultiPop(a1.bit() | a2.bit() | cp.bit() | fp.bit());
-
- // If the handler is a JS frame, restore the context to the frame.
- // (kind == ENTRY) == (fp == 0) == (cp == 0), so we could test either fp
- // or cp.
- Label done;
- Branch(&done, eq, cp, Operand(zero_reg));
- sd(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
- bind(&done);
-
- JumpToHandlerEntry();
-}
-
-
-void MacroAssembler::ThrowUncatchable(Register value) {
- // Adjust this code if not the case.
- STATIC_ASSERT(StackHandlerConstants::kSize == 5 * kPointerSize);
- STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0 * kPointerSize);
- STATIC_ASSERT(StackHandlerConstants::kCodeOffset == 1 * kPointerSize);
- STATIC_ASSERT(StackHandlerConstants::kStateOffset == 2 * kPointerSize);
- STATIC_ASSERT(StackHandlerConstants::kContextOffset == 3 * kPointerSize);
- STATIC_ASSERT(StackHandlerConstants::kFPOffset == 4 * kPointerSize);
-
- // The exception is expected in v0.
- if (!value.is(v0)) {
- mov(v0, value);
- }
- // Drop the stack pointer to the top of the top stack handler.
- li(a3, Operand(ExternalReference(Isolate::kHandlerAddress, isolate())));
- ld(sp, MemOperand(a3));
-
- // Unwind the handlers until the ENTRY handler is found.
- Label fetch_next, check_kind;
- jmp(&check_kind);
- bind(&fetch_next);
- ld(sp, MemOperand(sp, StackHandlerConstants::kNextOffset));
-
- bind(&check_kind);
- STATIC_ASSERT(StackHandler::JS_ENTRY == 0);
- ld(a2, MemOperand(sp, StackHandlerConstants::kStateOffset));
- And(a2, a2, Operand(StackHandler::KindField::kMask));
- Branch(&fetch_next, ne, a2, Operand(zero_reg));
-
- // Set the top handler address to next handler past the top ENTRY handler.
- pop(a2);
- sd(a2, MemOperand(a3));
-
- // Get the code object (a1) and state (a2). Clear the context and frame
- // pointer (0 was saved in the handler).
- MultiPop(a1.bit() | a2.bit() | cp.bit() | fp.bit());
-
- JumpToHandlerEntry();
-}
-
-
void MacroAssembler::Allocate(int object_size,
Register result,
Register scratch1,
@@ -3374,12 +3714,7 @@
return;
}
- DCHECK(!result.is(scratch1));
- DCHECK(!result.is(scratch2));
- DCHECK(!scratch1.is(scratch2));
- DCHECK(!scratch1.is(t9));
- DCHECK(!scratch2.is(t9));
- DCHECK(!result.is(t9));
+ DCHECK(!AreAliased(result, scratch1, scratch2, t9));
// Make object size into bytes.
if ((flags & SIZE_IN_WORDS) != 0) {
@@ -3395,34 +3730,35 @@
ExternalReference allocation_limit =
AllocationUtils::GetAllocationLimitReference(isolate(), flags);
- intptr_t top =
- reinterpret_cast<intptr_t>(allocation_top.address());
- intptr_t limit =
- reinterpret_cast<intptr_t>(allocation_limit.address());
+ intptr_t top = reinterpret_cast<intptr_t>(allocation_top.address());
+ intptr_t limit = reinterpret_cast<intptr_t>(allocation_limit.address());
DCHECK((limit - top) == kPointerSize);
- // Set up allocation top address and object size registers.
- Register topaddr = scratch1;
- li(topaddr, Operand(allocation_top));
-
+ // Set up allocation top address and allocation limit registers.
+ Register top_address = scratch1;
// This code stores a temporary value in t9.
+ Register alloc_limit = t9;
+ Register result_end = scratch2;
+ li(top_address, Operand(allocation_top));
+
if ((flags & RESULT_CONTAINS_TOP) == 0) {
- // Load allocation top into result and allocation limit into t9.
- ld(result, MemOperand(topaddr));
- ld(t9, MemOperand(topaddr, kPointerSize));
+ // Load allocation top into result and allocation limit into alloc_limit.
+ ld(result, MemOperand(top_address));
+ ld(alloc_limit, MemOperand(top_address, kPointerSize));
} else {
if (emit_debug_code()) {
- // Assert that result actually contains top on entry. t9 is used
- // immediately below so this use of t9 does not cause difference with
- // respect to register content between debug and release mode.
- ld(t9, MemOperand(topaddr));
- Check(eq, kUnexpectedAllocationTop, result, Operand(t9));
+ // Assert that result actually contains top on entry.
+ ld(alloc_limit, MemOperand(top_address));
+ Check(eq, kUnexpectedAllocationTop, result, Operand(alloc_limit));
}
- // Load allocation limit into t9. Result already contains allocation top.
- ld(t9, MemOperand(topaddr, limit - top));
+ // Load allocation limit. Result already contains allocation top.
+ ld(alloc_limit, MemOperand(top_address, static_cast<int32_t>(limit - top)));
}
- DCHECK(kPointerSize == kDoubleSize);
+ // We can ignore DOUBLE_ALIGNMENT flags here because doubles and pointers have
+ // the same alignment on ARM64.
+ STATIC_ASSERT(kPointerAlignment == kDoubleAlignment);
+
if (emit_debug_code()) {
And(at, result, Operand(kDoubleAlignmentMask));
Check(eq, kAllocationIsNotDoubleAligned, at, Operand(zero_reg));
@@ -3430,9 +3766,9 @@
// Calculate new top and bail out if new space is exhausted. Use result
// to calculate the new top.
- Daddu(scratch2, result, Operand(object_size));
- Branch(gc_required, Ugreater, scratch2, Operand(t9));
- sd(scratch2, MemOperand(topaddr));
+ Daddu(result_end, result, Operand(object_size));
+ Branch(gc_required, Ugreater, result_end, Operand(alloc_limit));
+ sd(result_end, MemOperand(top_address));
// Tag object if requested.
if ((flags & TAG_OBJECT) != 0) {
@@ -3441,28 +3777,23 @@
}
-void MacroAssembler::Allocate(Register object_size,
- Register result,
- Register scratch1,
- Register scratch2,
- Label* gc_required,
- AllocationFlags flags) {
+void MacroAssembler::Allocate(Register object_size, Register result,
+ Register result_end, Register scratch,
+ Label* gc_required, AllocationFlags flags) {
if (!FLAG_inline_new) {
if (emit_debug_code()) {
// Trash the registers to simulate an allocation failure.
li(result, 0x7091);
- li(scratch1, 0x7191);
- li(scratch2, 0x7291);
+ li(scratch, 0x7191);
+ li(result_end, 0x7291);
}
jmp(gc_required);
return;
}
- DCHECK(!result.is(scratch1));
- DCHECK(!result.is(scratch2));
- DCHECK(!scratch1.is(scratch2));
- DCHECK(!object_size.is(t9));
- DCHECK(!scratch1.is(t9) && !scratch2.is(t9) && !result.is(t9));
+ // |object_size| and |result_end| may overlap, other registers must not.
+ DCHECK(!AreAliased(object_size, result, scratch, t9));
+ DCHECK(!AreAliased(result_end, result, scratch, t9));
// Check relative positions of allocation top and limit addresses.
// ARM adds additional checks to make sure the ldm instruction can be
@@ -3471,34 +3802,34 @@
AllocationUtils::GetAllocationTopReference(isolate(), flags);
ExternalReference allocation_limit =
AllocationUtils::GetAllocationLimitReference(isolate(), flags);
- intptr_t top =
- reinterpret_cast<intptr_t>(allocation_top.address());
- intptr_t limit =
- reinterpret_cast<intptr_t>(allocation_limit.address());
+ intptr_t top = reinterpret_cast<intptr_t>(allocation_top.address());
+ intptr_t limit = reinterpret_cast<intptr_t>(allocation_limit.address());
DCHECK((limit - top) == kPointerSize);
// Set up allocation top address and object size registers.
- Register topaddr = scratch1;
- li(topaddr, Operand(allocation_top));
-
+ Register top_address = scratch;
// This code stores a temporary value in t9.
+ Register alloc_limit = t9;
+ li(top_address, Operand(allocation_top));
+
if ((flags & RESULT_CONTAINS_TOP) == 0) {
- // Load allocation top into result and allocation limit into t9.
- ld(result, MemOperand(topaddr));
- ld(t9, MemOperand(topaddr, kPointerSize));
+ // Load allocation top into result and allocation limit into alloc_limit.
+ ld(result, MemOperand(top_address));
+ ld(alloc_limit, MemOperand(top_address, kPointerSize));
} else {
if (emit_debug_code()) {
- // Assert that result actually contains top on entry. t9 is used
- // immediately below so this use of t9 does not cause difference with
- // respect to register content between debug and release mode.
- ld(t9, MemOperand(topaddr));
- Check(eq, kUnexpectedAllocationTop, result, Operand(t9));
+ // Assert that result actually contains top on entry.
+ ld(alloc_limit, MemOperand(top_address));
+ Check(eq, kUnexpectedAllocationTop, result, Operand(alloc_limit));
}
- // Load allocation limit into t9. Result already contains allocation top.
- ld(t9, MemOperand(topaddr, limit - top));
+ // Load allocation limit. Result already contains allocation top.
+ ld(alloc_limit, MemOperand(top_address, static_cast<int32_t>(limit - top)));
}
- DCHECK(kPointerSize == kDoubleSize);
+ // We can ignore DOUBLE_ALIGNMENT flags here because doubles and pointers have
+ // the same alignment on ARM64.
+ STATIC_ASSERT(kPointerAlignment == kDoubleAlignment);
+
if (emit_debug_code()) {
And(at, result, Operand(kDoubleAlignmentMask));
Check(eq, kAllocationIsNotDoubleAligned, at, Operand(zero_reg));
@@ -3508,19 +3839,19 @@
// to calculate the new top. Object size may be in words so a shift is
// required to get the number of bytes.
if ((flags & SIZE_IN_WORDS) != 0) {
- dsll(scratch2, object_size, kPointerSizeLog2);
- Daddu(scratch2, result, scratch2);
+ dsll(result_end, object_size, kPointerSizeLog2);
+ Daddu(result_end, result, result_end);
} else {
- Daddu(scratch2, result, Operand(object_size));
+ Daddu(result_end, result, Operand(object_size));
}
- Branch(gc_required, Ugreater, scratch2, Operand(t9));
+ Branch(gc_required, Ugreater, result_end, Operand(alloc_limit));
// Update allocation top. result temporarily holds the new top.
if (emit_debug_code()) {
- And(t9, scratch2, Operand(kObjectAlignmentMask));
- Check(eq, kUnalignedAllocationInNewSpace, t9, Operand(zero_reg));
+ And(at, result_end, Operand(kObjectAlignmentMask));
+ Check(eq, kUnalignedAllocationInNewSpace, at, Operand(zero_reg));
}
- sd(scratch2, MemOperand(topaddr));
+ sd(result_end, MemOperand(top_address));
// Tag object if requested.
if ((flags & TAG_OBJECT) != 0) {
@@ -3529,26 +3860,6 @@
}
-void MacroAssembler::UndoAllocationInNewSpace(Register object,
- Register scratch) {
- ExternalReference new_space_allocation_top =
- ExternalReference::new_space_allocation_top_address(isolate());
-
- // Make sure the object has no tag before resetting top.
- And(object, object, Operand(~kHeapObjectTagMask));
-#ifdef DEBUG
- // Check that the object un-allocated is below the current top.
- li(scratch, Operand(new_space_allocation_top));
- ld(scratch, MemOperand(scratch));
- Check(less, kUndoAllocationOfNonAllocatedMemory,
- object, Operand(scratch));
-#endif
- // Write the address of the object to un-allocate as the current top.
- li(scratch, Operand(new_space_allocation_top));
- sd(object, MemOperand(scratch));
-}
-
-
void MacroAssembler::AllocateTwoByteString(Register result,
Register length,
Register scratch1,
@@ -3717,29 +4028,25 @@
}
-// Copies a fixed number of fields of heap objects from src to dst.
-void MacroAssembler::CopyFields(Register dst,
- Register src,
- RegList temps,
- int field_count) {
- DCHECK((temps & dst.bit()) == 0);
- DCHECK((temps & src.bit()) == 0);
- // Primitive implementation using only one temporary register.
+void MacroAssembler::AllocateJSValue(Register result, Register constructor,
+ Register value, Register scratch1,
+ Register scratch2, Label* gc_required) {
+ DCHECK(!result.is(constructor));
+ DCHECK(!result.is(scratch1));
+ DCHECK(!result.is(scratch2));
+ DCHECK(!result.is(value));
- Register tmp = no_reg;
- // Find a temp register in temps list.
- for (int i = 0; i < kNumRegisters; i++) {
- if ((temps & (1 << i)) != 0) {
- tmp.code_ = i;
- break;
- }
- }
- DCHECK(!tmp.is(no_reg));
+ // Allocate JSValue in new space.
+ Allocate(JSValue::kSize, result, scratch1, scratch2, gc_required, TAG_OBJECT);
- for (int i = 0; i < field_count; i++) {
- ld(tmp, FieldMemOperand(src, i * kPointerSize));
- sd(tmp, FieldMemOperand(dst, i * kPointerSize));
- }
+ // Initialize the JSValue.
+ LoadGlobalFunctionInitialMap(constructor, scratch1, scratch2);
+ sd(scratch1, FieldMemOperand(result, HeapObject::kMapOffset));
+ LoadRoot(scratch1, Heap::kEmptyFixedArrayRootIndex);
+ sd(scratch1, FieldMemOperand(result, JSObject::kPropertiesOffset));
+ sd(scratch1, FieldMemOperand(result, JSObject::kElementsOffset));
+ sd(value, FieldMemOperand(result, JSValue::kValueOffset));
+ STATIC_ASSERT(JSValue::kSize == 4 * kPointerSize);
}
@@ -3774,21 +4081,39 @@
// TODO(kalmard) check if this can be optimized to use sw in most cases.
// Can't use unaligned access - copy byte by byte.
- sb(scratch, MemOperand(dst, 0));
- dsrl(scratch, scratch, 8);
- sb(scratch, MemOperand(dst, 1));
- dsrl(scratch, scratch, 8);
- sb(scratch, MemOperand(dst, 2));
- dsrl(scratch, scratch, 8);
- sb(scratch, MemOperand(dst, 3));
- dsrl(scratch, scratch, 8);
- sb(scratch, MemOperand(dst, 4));
- dsrl(scratch, scratch, 8);
- sb(scratch, MemOperand(dst, 5));
- dsrl(scratch, scratch, 8);
- sb(scratch, MemOperand(dst, 6));
- dsrl(scratch, scratch, 8);
- sb(scratch, MemOperand(dst, 7));
+ if (kArchEndian == kLittle) {
+ sb(scratch, MemOperand(dst, 0));
+ dsrl(scratch, scratch, 8);
+ sb(scratch, MemOperand(dst, 1));
+ dsrl(scratch, scratch, 8);
+ sb(scratch, MemOperand(dst, 2));
+ dsrl(scratch, scratch, 8);
+ sb(scratch, MemOperand(dst, 3));
+ dsrl(scratch, scratch, 8);
+ sb(scratch, MemOperand(dst, 4));
+ dsrl(scratch, scratch, 8);
+ sb(scratch, MemOperand(dst, 5));
+ dsrl(scratch, scratch, 8);
+ sb(scratch, MemOperand(dst, 6));
+ dsrl(scratch, scratch, 8);
+ sb(scratch, MemOperand(dst, 7));
+ } else {
+ sb(scratch, MemOperand(dst, 7));
+ dsrl(scratch, scratch, 8);
+ sb(scratch, MemOperand(dst, 6));
+ dsrl(scratch, scratch, 8);
+ sb(scratch, MemOperand(dst, 5));
+ dsrl(scratch, scratch, 8);
+ sb(scratch, MemOperand(dst, 4));
+ dsrl(scratch, scratch, 8);
+ sb(scratch, MemOperand(dst, 3));
+ dsrl(scratch, scratch, 8);
+ sb(scratch, MemOperand(dst, 2));
+ dsrl(scratch, scratch, 8);
+ sb(scratch, MemOperand(dst, 1));
+ dsrl(scratch, scratch, 8);
+ sb(scratch, MemOperand(dst, 0));
+ }
Daddu(dst, dst, 8);
Dsubu(length, length, Operand(kPointerSize));
@@ -3808,16 +4133,16 @@
}
-void MacroAssembler::InitializeFieldsWithFiller(Register start_offset,
- Register end_offset,
+void MacroAssembler::InitializeFieldsWithFiller(Register current_address,
+ Register end_address,
Register filler) {
Label loop, entry;
Branch(&entry);
bind(&loop);
- sd(filler, MemOperand(start_offset));
- Daddu(start_offset, start_offset, kPointerSize);
+ sd(filler, MemOperand(current_address));
+ Daddu(current_address, current_address, kPointerSize);
bind(&entry);
- Branch(&loop, lt, start_offset, Operand(end_offset));
+ Branch(&loop, ult, current_address, Operand(end_address));
}
@@ -3865,69 +4190,43 @@
Register elements_reg,
Register scratch1,
Register scratch2,
- Register scratch3,
Label* fail,
int elements_offset) {
- Label smi_value, maybe_nan, have_double_value, is_nan, done;
- Register mantissa_reg = scratch2;
- Register exponent_reg = scratch3;
+ DCHECK(!AreAliased(value_reg, key_reg, elements_reg, scratch1, scratch2));
+ Label smi_value, done;
// Handle smi values specially.
JumpIfSmi(value_reg, &smi_value);
- // Ensure that the object is a heap number
+ // Ensure that the object is a heap number.
CheckMap(value_reg,
scratch1,
Heap::kHeapNumberMapRootIndex,
fail,
DONT_DO_SMI_CHECK);
- // Check for nan: all NaN values have a value greater (signed) than 0x7ff00000
- // in the exponent.
- li(scratch1, Operand(kNaNOrInfinityLowerBoundUpper32));
- lw(exponent_reg, FieldMemOperand(value_reg, HeapNumber::kExponentOffset));
- Branch(&maybe_nan, ge, exponent_reg, Operand(scratch1));
+ // Double value, turn potential sNaN into qNan.
+ DoubleRegister double_result = f0;
+ DoubleRegister double_scratch = f2;
- lwu(mantissa_reg, FieldMemOperand(value_reg, HeapNumber::kMantissaOffset));
-
- bind(&have_double_value);
- // dsll(scratch1, key_reg, kDoubleSizeLog2 - kSmiTagSize);
- dsra(scratch1, key_reg, 32 - kDoubleSizeLog2);
- Daddu(scratch1, scratch1, elements_reg);
- sw(mantissa_reg, FieldMemOperand(
- scratch1, FixedDoubleArray::kHeaderSize - elements_offset));
- uint32_t offset = FixedDoubleArray::kHeaderSize - elements_offset +
- sizeof(kHoleNanLower32);
- sw(exponent_reg, FieldMemOperand(scratch1, offset));
- jmp(&done);
-
- bind(&maybe_nan);
- // Could be NaN, Infinity or -Infinity. If fraction is not zero, it's NaN,
- // otherwise it's Infinity or -Infinity, and the non-NaN code path applies.
- lw(mantissa_reg, FieldMemOperand(value_reg, HeapNumber::kMantissaOffset));
- Branch(&have_double_value, eq, mantissa_reg, Operand(zero_reg));
- bind(&is_nan);
- // Load canonical NaN for storing into the double array.
- LoadRoot(at, Heap::kNanValueRootIndex);
- lw(mantissa_reg, FieldMemOperand(at, HeapNumber::kMantissaOffset));
- lw(exponent_reg, FieldMemOperand(at, HeapNumber::kExponentOffset));
- jmp(&have_double_value);
+ ldc1(double_result, FieldMemOperand(value_reg, HeapNumber::kValueOffset));
+ Branch(USE_DELAY_SLOT, &done); // Canonicalization is one instruction.
+ FPUCanonicalizeNaN(double_result, double_result);
bind(&smi_value);
+ // Untag and transfer.
+ dsrl32(scratch1, value_reg, 0);
+ mtc1(scratch1, double_scratch);
+ cvt_d_w(double_result, double_scratch);
+
+ bind(&done);
Daddu(scratch1, elements_reg,
Operand(FixedDoubleArray::kHeaderSize - kHeapObjectTag -
elements_offset));
- // dsll(scratch2, key_reg, kDoubleSizeLog2 - kSmiTagSize);
dsra(scratch2, key_reg, 32 - kDoubleSizeLog2);
Daddu(scratch1, scratch1, scratch2);
- // scratch1 is now effective address of the double element
-
- Register untagged_value = elements_reg;
- SmiUntag(untagged_value, value_reg);
- mtc1(untagged_value, f2);
- cvt_d_w(f0, f2);
- sdc1(f0, MemOperand(scratch1, 0));
- bind(&done);
+ // scratch1 is now effective address of the double element.
+ sdc1(double_result, MemOperand(scratch1, 0));
}
@@ -3999,6 +4298,10 @@
ld(value, FieldMemOperand(value, WeakCell::kValueOffset));
}
+void MacroAssembler::FPUCanonicalizeNaN(const DoubleRegister dst,
+ const DoubleRegister src) {
+ sub_d(dst, src, kDoubleRegZero);
+}
void MacroAssembler::LoadWeakValue(Register value, Handle<WeakCell> cell,
Label* miss) {
@@ -4009,7 +4312,11 @@
void MacroAssembler::MovFromFloatResult(const DoubleRegister dst) {
if (IsMipsSoftFloatABI) {
- Move(dst, v0, v1);
+ if (kArchEndian == kLittle) {
+ Move(dst, v0, v1);
+ } else {
+ Move(dst, v1, v0);
+ }
} else {
Move(dst, f0); // Reg f0 is o32 ABI FP return value.
}
@@ -4018,9 +4325,13 @@
void MacroAssembler::MovFromFloatParameter(const DoubleRegister dst) {
if (IsMipsSoftFloatABI) {
- Move(dst, a0, a1);
+ if (kArchEndian == kLittle) {
+ Move(dst, a0, a1);
+ } else {
+ Move(dst, a1, a0);
+ }
} else {
- Move(dst, f12); // Reg f12 is o32 ABI FP first argument value.
+ Move(dst, f12); // Reg f12 is n64 ABI FP first argument value.
}
}
@@ -4029,7 +4340,11 @@
if (!IsMipsSoftFloatABI) {
Move(f12, src);
} else {
- Move(a0, a1, src);
+ if (kArchEndian == kLittle) {
+ Move(a0, a1, src);
+ } else {
+ Move(a1, a0, src);
+ }
}
}
@@ -4038,7 +4353,11 @@
if (!IsMipsSoftFloatABI) {
Move(f0, src);
} else {
- Move(v0, v1, src);
+ if (kArchEndian == kLittle) {
+ Move(v0, v1, src);
+ } else {
+ Move(v1, v0, src);
+ }
}
}
@@ -4056,8 +4375,13 @@
Move(fparg2, src2);
}
} else {
- Move(a0, a1, src1);
- Move(a2, a3, src2);
+ if (kArchEndian == kLittle) {
+ Move(a0, a1, src1);
+ Move(a2, a3, src2);
+ } else {
+ Move(a1, a0, src1);
+ Move(a3, a2, src2);
+ }
}
}
@@ -4067,8 +4391,6 @@
void MacroAssembler::InvokePrologue(const ParameterCount& expected,
const ParameterCount& actual,
- Handle<Code> code_constant,
- Register code_reg,
Label* done,
bool* definitely_mismatches,
InvokeFlag flag,
@@ -4088,14 +4410,13 @@
// passed in registers.
DCHECK(actual.is_immediate() || actual.reg().is(a0));
DCHECK(expected.is_immediate() || expected.reg().is(a2));
- DCHECK((!code_constant.is_null() && code_reg.is(no_reg)) || code_reg.is(a3));
if (expected.is_immediate()) {
DCHECK(actual.is_immediate());
+ li(a0, Operand(actual.immediate()));
if (expected.immediate() == actual.immediate()) {
definitely_matches = true;
} else {
- li(a0, Operand(actual.immediate()));
const int sentinel = SharedFunctionInfo::kDontAdaptArgumentsSentinel;
if (expected.immediate() == sentinel) {
// Don't worry about adapting arguments for builtins that
@@ -4109,18 +4430,13 @@
}
}
} else if (actual.is_immediate()) {
- Branch(®ular_invoke, eq, expected.reg(), Operand(actual.immediate()));
li(a0, Operand(actual.immediate()));
+ Branch(®ular_invoke, eq, expected.reg(), Operand(a0));
} else {
Branch(®ular_invoke, eq, expected.reg(), Operand(actual.reg()));
}
if (!definitely_matches) {
- if (!code_constant.is_null()) {
- li(a3, Operand(code_constant));
- daddiu(a3, a3, Code::kHeaderSize - kHeapObjectTag);
- }
-
Handle<Code> adaptor =
isolate()->builtins()->ArgumentsAdaptorTrampoline();
if (flag == CALL_FUNCTION) {
@@ -4138,21 +4454,78 @@
}
-void MacroAssembler::InvokeCode(Register code,
- const ParameterCount& expected,
- const ParameterCount& actual,
- InvokeFlag flag,
- const CallWrapper& call_wrapper) {
+void MacroAssembler::FloodFunctionIfStepping(Register fun, Register new_target,
+ const ParameterCount& expected,
+ const ParameterCount& actual) {
+ Label skip_flooding;
+ ExternalReference step_in_enabled =
+ ExternalReference::debug_step_in_enabled_address(isolate());
+ li(t0, Operand(step_in_enabled));
+ lb(t0, MemOperand(t0));
+ Branch(&skip_flooding, eq, t0, Operand(zero_reg));
+ {
+ FrameScope frame(this,
+ has_frame() ? StackFrame::NONE : StackFrame::INTERNAL);
+ if (expected.is_reg()) {
+ SmiTag(expected.reg());
+ Push(expected.reg());
+ }
+ if (actual.is_reg()) {
+ SmiTag(actual.reg());
+ Push(actual.reg());
+ }
+ if (new_target.is_valid()) {
+ Push(new_target);
+ }
+ Push(fun);
+ Push(fun);
+ CallRuntime(Runtime::kDebugPrepareStepInIfStepping, 1);
+ Pop(fun);
+ if (new_target.is_valid()) {
+ Pop(new_target);
+ }
+ if (actual.is_reg()) {
+ Pop(actual.reg());
+ SmiUntag(actual.reg());
+ }
+ if (expected.is_reg()) {
+ Pop(expected.reg());
+ SmiUntag(expected.reg());
+ }
+ }
+ bind(&skip_flooding);
+}
+
+
+void MacroAssembler::InvokeFunctionCode(Register function, Register new_target,
+ const ParameterCount& expected,
+ const ParameterCount& actual,
+ InvokeFlag flag,
+ const CallWrapper& call_wrapper) {
// You can't call a function without a valid frame.
DCHECK(flag == JUMP_FUNCTION || has_frame());
+ DCHECK(function.is(a1));
+ DCHECK_IMPLIES(new_target.is_valid(), new_target.is(a3));
+
+ if (call_wrapper.NeedsDebugStepCheck()) {
+ FloodFunctionIfStepping(function, new_target, expected, actual);
+ }
+
+ // Clear the new.target register if not given.
+ if (!new_target.is_valid()) {
+ LoadRoot(a3, Heap::kUndefinedValueRootIndex);
+ }
Label done;
-
bool definitely_mismatches = false;
- InvokePrologue(expected, actual, Handle<Code>::null(), code,
- &done, &definitely_mismatches, flag,
+ InvokePrologue(expected, actual, &done, &definitely_mismatches, flag,
call_wrapper);
if (!definitely_mismatches) {
+ // We call indirectly through the code field in the function to
+ // allow recompilation to take effect without changing any of the
+ // call sites.
+ Register code = t0;
+ ld(code, FieldMemOperand(function, JSFunction::kCodeEntryOffset));
if (flag == CALL_FUNCTION) {
call_wrapper.BeforeCall(CallSize(code));
Call(code);
@@ -4169,6 +4542,7 @@
void MacroAssembler::InvokeFunction(Register function,
+ Register new_target,
const ParameterCount& actual,
InvokeFlag flag,
const CallWrapper& call_wrapper) {
@@ -4178,17 +4552,16 @@
// Contract with called JS functions requires that function is passed in a1.
DCHECK(function.is(a1));
Register expected_reg = a2;
- Register code_reg = a3;
- ld(code_reg, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
+ Register temp_reg = t0;
+ ld(temp_reg, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
ld(cp, FieldMemOperand(a1, JSFunction::kContextOffset));
// The argument count is stored as int32_t on 64-bit platforms.
// TODO(plind): Smi on 32-bit platforms.
lw(expected_reg,
- FieldMemOperand(code_reg,
- SharedFunctionInfo::kFormalParameterCountOffset));
- ld(code_reg, FieldMemOperand(a1, JSFunction::kCodeEntryOffset));
+ FieldMemOperand(temp_reg,
+ SharedFunctionInfo::kFormalParameterCountOffset));
ParameterCount expected(expected_reg);
- InvokeCode(code_reg, expected, actual, flag, call_wrapper);
+ InvokeFunctionCode(a1, new_target, expected, actual, flag, call_wrapper);
}
@@ -4206,11 +4579,7 @@
// Get the function and setup the context.
ld(cp, FieldMemOperand(a1, JSFunction::kContextOffset));
- // We call indirectly through the code field in the function to
- // allow recompilation to take effect without changing any of the
- // call sites.
- ld(a3, FieldMemOperand(a1, JSFunction::kCodeEntryOffset));
- InvokeCode(a3, expected, actual, flag, call_wrapper);
+ InvokeFunctionCode(a1, no_reg, expected, actual, flag, call_wrapper);
}
@@ -4224,24 +4593,6 @@
}
-void MacroAssembler::IsObjectJSObjectType(Register heap_object,
- Register map,
- Register scratch,
- Label* fail) {
- ld(map, FieldMemOperand(heap_object, HeapObject::kMapOffset));
- IsInstanceJSObjectType(map, scratch, fail);
-}
-
-
-void MacroAssembler::IsInstanceJSObjectType(Register map,
- Register scratch,
- Label* fail) {
- lbu(scratch, FieldMemOperand(map, Map::kInstanceTypeOffset));
- Branch(fail, lt, scratch, Operand(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
- Branch(fail, gt, scratch, Operand(LAST_NONCALLABLE_SPEC_OBJECT_TYPE));
-}
-
-
void MacroAssembler::IsObjectJSStringType(Register object,
Register scratch,
Label* fail) {
@@ -4267,34 +4618,22 @@
// Support functions.
-void MacroAssembler::TryGetFunctionPrototype(Register function,
- Register result,
- Register scratch,
- Label* miss,
- bool miss_on_bound_function) {
- Label non_instance;
- if (miss_on_bound_function) {
- // Check that the receiver isn't a smi.
- JumpIfSmi(function, miss);
+void MacroAssembler::GetMapConstructor(Register result, Register map,
+ Register temp, Register temp2) {
+ Label done, loop;
+ ld(result, FieldMemOperand(map, Map::kConstructorOrBackPointerOffset));
+ bind(&loop);
+ JumpIfSmi(result, &done);
+ GetObjectType(result, temp, temp2);
+ Branch(&done, ne, temp2, Operand(MAP_TYPE));
+ ld(result, FieldMemOperand(result, Map::kConstructorOrBackPointerOffset));
+ Branch(&loop);
+ bind(&done);
+}
- // Check that the function really is a function. Load map into result reg.
- GetObjectType(function, result, scratch);
- Branch(miss, ne, scratch, Operand(JS_FUNCTION_TYPE));
- ld(scratch,
- FieldMemOperand(function, JSFunction::kSharedFunctionInfoOffset));
- lwu(scratch,
- FieldMemOperand(scratch, SharedFunctionInfo::kCompilerHintsOffset));
- And(scratch, scratch,
- Operand(1 << SharedFunctionInfo::kBoundFunction));
- Branch(miss, ne, scratch, Operand(zero_reg));
-
- // Make sure that the function has an instance prototype.
- lbu(scratch, FieldMemOperand(result, Map::kBitFieldOffset));
- And(scratch, scratch, Operand(1 << Map::kHasNonInstancePrototype));
- Branch(&non_instance, ne, scratch, Operand(zero_reg));
- }
-
+void MacroAssembler::TryGetFunctionPrototype(Register function, Register result,
+ Register scratch, Label* miss) {
// Get the prototype or initial map from the function.
ld(result,
FieldMemOperand(function, JSFunction::kPrototypeOrInitialMapOffset));
@@ -4313,15 +4652,6 @@
// Get the prototype from the initial map.
ld(result, FieldMemOperand(result, Map::kPrototypeOffset));
- if (miss_on_bound_function) {
- jmp(&done);
-
- // Non-instance prototype: Fetch prototype from constructor field
- // in initial map.
- bind(&non_instance);
- ld(result, FieldMemOperand(result, Map::kConstructorOffset));
- }
-
// All done.
bind(&done);
}
@@ -4359,137 +4689,6 @@
}
-static int AddressOffset(ExternalReference ref0, ExternalReference ref1) {
- int64_t offset = (ref0.address() - ref1.address());
- DCHECK(static_cast<int>(offset) == offset);
- return static_cast<int>(offset);
-}
-
-
-void MacroAssembler::CallApiFunctionAndReturn(
- Register function_address,
- ExternalReference thunk_ref,
- int stack_space,
- MemOperand return_value_operand,
- MemOperand* context_restore_operand) {
- ExternalReference next_address =
- ExternalReference::handle_scope_next_address(isolate());
- const int kNextOffset = 0;
- const int kLimitOffset = AddressOffset(
- ExternalReference::handle_scope_limit_address(isolate()),
- next_address);
- const int kLevelOffset = AddressOffset(
- ExternalReference::handle_scope_level_address(isolate()),
- next_address);
-
- DCHECK(function_address.is(a1) || function_address.is(a2));
-
- Label profiler_disabled;
- Label end_profiler_check;
- li(t9, Operand(ExternalReference::is_profiling_address(isolate())));
- lb(t9, MemOperand(t9, 0));
- Branch(&profiler_disabled, eq, t9, Operand(zero_reg));
-
- // Additional parameter is the address of the actual callback.
- li(t9, Operand(thunk_ref));
- jmp(&end_profiler_check);
-
- bind(&profiler_disabled);
- mov(t9, function_address);
- bind(&end_profiler_check);
-
- // Allocate HandleScope in callee-save registers.
- li(s3, Operand(next_address));
- ld(s0, MemOperand(s3, kNextOffset));
- ld(s1, MemOperand(s3, kLimitOffset));
- ld(s2, MemOperand(s3, kLevelOffset));
- Daddu(s2, s2, Operand(1));
- sd(s2, MemOperand(s3, kLevelOffset));
-
- if (FLAG_log_timer_events) {
- FrameScope frame(this, StackFrame::MANUAL);
- PushSafepointRegisters();
- PrepareCallCFunction(1, a0);
- li(a0, Operand(ExternalReference::isolate_address(isolate())));
- CallCFunction(ExternalReference::log_enter_external_function(isolate()), 1);
- PopSafepointRegisters();
- }
-
- // Native call returns to the DirectCEntry stub which redirects to the
- // return address pushed on stack (could have moved after GC).
- // DirectCEntry stub itself is generated early and never moves.
- DirectCEntryStub stub(isolate());
- stub.GenerateCall(this, t9);
-
- if (FLAG_log_timer_events) {
- FrameScope frame(this, StackFrame::MANUAL);
- PushSafepointRegisters();
- PrepareCallCFunction(1, a0);
- li(a0, Operand(ExternalReference::isolate_address(isolate())));
- CallCFunction(ExternalReference::log_leave_external_function(isolate()), 1);
- PopSafepointRegisters();
- }
-
- Label promote_scheduled_exception;
- Label exception_handled;
- Label delete_allocated_handles;
- Label leave_exit_frame;
- Label return_value_loaded;
-
- // Load value from ReturnValue.
- ld(v0, return_value_operand);
- bind(&return_value_loaded);
-
- // No more valid handles (the result handle was the last one). Restore
- // previous handle scope.
- sd(s0, MemOperand(s3, kNextOffset));
- if (emit_debug_code()) {
- ld(a1, MemOperand(s3, kLevelOffset));
- Check(eq, kUnexpectedLevelAfterReturnFromApiCall, a1, Operand(s2));
- }
- Dsubu(s2, s2, Operand(1));
- sd(s2, MemOperand(s3, kLevelOffset));
- ld(at, MemOperand(s3, kLimitOffset));
- Branch(&delete_allocated_handles, ne, s1, Operand(at));
-
- // Check if the function scheduled an exception.
- bind(&leave_exit_frame);
- LoadRoot(a4, Heap::kTheHoleValueRootIndex);
- li(at, Operand(ExternalReference::scheduled_exception_address(isolate())));
- ld(a5, MemOperand(at));
- Branch(&promote_scheduled_exception, ne, a4, Operand(a5));
- bind(&exception_handled);
-
- bool restore_context = context_restore_operand != NULL;
- if (restore_context) {
- ld(cp, *context_restore_operand);
- }
- li(s0, Operand(stack_space));
- LeaveExitFrame(false, s0, !restore_context, EMIT_RETURN);
-
- bind(&promote_scheduled_exception);
- {
- FrameScope frame(this, StackFrame::INTERNAL);
- CallExternalReference(
- ExternalReference(Runtime::kPromoteScheduledException, isolate()),
- 0);
- }
- jmp(&exception_handled);
-
- // HandleScope limit has changed. Delete allocated extensions.
- bind(&delete_allocated_handles);
- sd(s1, MemOperand(s3, kLimitOffset));
- mov(s0, v0);
- mov(a0, v0);
- PrepareCallCFunction(1, s1);
- li(a0, Operand(ExternalReference::isolate_address(isolate())));
- CallCFunction(ExternalReference::delete_handle_scope_extensions(isolate()),
- 1);
- mov(v0, s0);
- jmp(&leave_exit_frame);
-}
-
-
bool MacroAssembler::AllowThisStubCall(CodeStub* stub) {
return has_frame_ || !stub->SometimesSetsUpAFrame();
}
@@ -4547,7 +4746,6 @@
void MacroAssembler::SmiToDoubleFPURegister(Register smi,
FPURegister value,
Register scratch1) {
- // dsra(scratch1, smi, kSmiTagSize);
dsra32(scratch1, smi, 0);
mtc1(scratch1, value);
cvt_d_w(value, value);
@@ -4562,18 +4760,16 @@
AdduAndCheckForOverflow(dst, left, right.rm(), overflow_dst, scratch);
} else {
if (dst.is(left)) {
+ li(t9, right); // Load right.
mov(scratch, left); // Preserve left.
- daddiu(dst, left, right.immediate()); // Left is overwritten.
+ addu(dst, left, t9); // Left is overwritten.
xor_(scratch, dst, scratch); // Original left.
- // Load right since xori takes uint16 as immediate.
- daddiu(t9, zero_reg, right.immediate());
xor_(overflow_dst, dst, t9);
and_(overflow_dst, overflow_dst, scratch);
} else {
- daddiu(dst, left, right.immediate());
+ li(t9, right);
+ addu(dst, left, t9);
xor_(overflow_dst, dst, left);
- // Load right since xori takes uint16 as immediate.
- daddiu(t9, zero_reg, right.immediate());
xor_(scratch, dst, t9);
and_(overflow_dst, scratch, overflow_dst);
}
@@ -4581,8 +4777,7 @@
}
-void MacroAssembler::AdduAndCheckForOverflow(Register dst,
- Register left,
+void MacroAssembler::AdduAndCheckForOverflow(Register dst, Register left,
Register right,
Register overflow_dst,
Register scratch) {
@@ -4603,6 +4798,72 @@
}
if (dst.is(left)) {
+ mov(scratch, left); // Preserve left.
+ addu(dst, left, right); // Left is overwritten.
+ xor_(scratch, dst, scratch); // Original left.
+ xor_(overflow_dst, dst, right);
+ and_(overflow_dst, overflow_dst, scratch);
+ } else if (dst.is(right)) {
+ mov(scratch, right); // Preserve right.
+ addu(dst, left, right); // Right is overwritten.
+ xor_(scratch, dst, scratch); // Original right.
+ xor_(overflow_dst, dst, left);
+ and_(overflow_dst, overflow_dst, scratch);
+ } else {
+ addu(dst, left, right);
+ xor_(overflow_dst, dst, left);
+ xor_(scratch, dst, right);
+ and_(overflow_dst, scratch, overflow_dst);
+ }
+}
+
+
+void MacroAssembler::DadduAndCheckForOverflow(Register dst, Register left,
+ const Operand& right,
+ Register overflow_dst,
+ Register scratch) {
+ if (right.is_reg()) {
+ DadduAndCheckForOverflow(dst, left, right.rm(), overflow_dst, scratch);
+ } else {
+ if (dst.is(left)) {
+ li(t9, right); // Load right.
+ mov(scratch, left); // Preserve left.
+ daddu(dst, left, t9); // Left is overwritten.
+ xor_(scratch, dst, scratch); // Original left.
+ xor_(overflow_dst, dst, t9);
+ and_(overflow_dst, overflow_dst, scratch);
+ } else {
+ li(t9, right); // Load right.
+ Daddu(dst, left, t9);
+ xor_(overflow_dst, dst, left);
+ xor_(scratch, dst, t9);
+ and_(overflow_dst, scratch, overflow_dst);
+ }
+ }
+}
+
+
+void MacroAssembler::DadduAndCheckForOverflow(Register dst, Register left,
+ Register right,
+ Register overflow_dst,
+ Register scratch) {
+ DCHECK(!dst.is(overflow_dst));
+ DCHECK(!dst.is(scratch));
+ DCHECK(!overflow_dst.is(scratch));
+ DCHECK(!overflow_dst.is(left));
+ DCHECK(!overflow_dst.is(right));
+
+ if (left.is(right) && dst.is(left)) {
+ DCHECK(!dst.is(t9));
+ DCHECK(!scratch.is(t9));
+ DCHECK(!left.is(t9));
+ DCHECK(!right.is(t9));
+ DCHECK(!overflow_dst.is(t9));
+ mov(t9, right);
+ right = t9;
+ }
+
+ if (dst.is(left)) {
mov(scratch, left); // Preserve left.
daddu(dst, left, right); // Left is overwritten.
xor_(scratch, dst, scratch); // Original left.
@@ -4623,6 +4884,89 @@
}
+static inline void BranchOvfHelper(MacroAssembler* masm, Register overflow_dst,
+ Label* overflow_label,
+ Label* no_overflow_label) {
+ DCHECK(overflow_label || no_overflow_label);
+ if (!overflow_label) {
+ DCHECK(no_overflow_label);
+ masm->Branch(no_overflow_label, ge, overflow_dst, Operand(zero_reg));
+ } else {
+ masm->Branch(overflow_label, lt, overflow_dst, Operand(zero_reg));
+ if (no_overflow_label) masm->Branch(no_overflow_label);
+ }
+}
+
+
+void MacroAssembler::DaddBranchOvf(Register dst, Register left,
+ const Operand& right, Label* overflow_label,
+ Label* no_overflow_label, Register scratch) {
+ if (right.is_reg()) {
+ DaddBranchOvf(dst, left, right.rm(), overflow_label, no_overflow_label,
+ scratch);
+ } else {
+ Register overflow_dst = t9;
+ DCHECK(!dst.is(scratch));
+ DCHECK(!dst.is(overflow_dst));
+ DCHECK(!scratch.is(overflow_dst));
+ DCHECK(!left.is(overflow_dst));
+ li(overflow_dst, right); // Load right.
+ if (dst.is(left)) {
+ mov(scratch, left); // Preserve left.
+ Daddu(dst, left, overflow_dst); // Left is overwritten.
+ xor_(scratch, dst, scratch); // Original left.
+ xor_(overflow_dst, dst, overflow_dst);
+ and_(overflow_dst, overflow_dst, scratch);
+ } else {
+ Daddu(dst, left, overflow_dst);
+ xor_(scratch, dst, overflow_dst);
+ xor_(overflow_dst, dst, left);
+ and_(overflow_dst, scratch, overflow_dst);
+ }
+ BranchOvfHelper(this, overflow_dst, overflow_label, no_overflow_label);
+ }
+}
+
+
+void MacroAssembler::DaddBranchOvf(Register dst, Register left, Register right,
+ Label* overflow_label,
+ Label* no_overflow_label, Register scratch) {
+ Register overflow_dst = t9;
+ DCHECK(!dst.is(scratch));
+ DCHECK(!dst.is(overflow_dst));
+ DCHECK(!scratch.is(overflow_dst));
+ DCHECK(!left.is(overflow_dst));
+ DCHECK(!right.is(overflow_dst));
+ DCHECK(!left.is(scratch));
+ DCHECK(!right.is(scratch));
+
+ if (left.is(right) && dst.is(left)) {
+ mov(overflow_dst, right);
+ right = overflow_dst;
+ }
+
+ if (dst.is(left)) {
+ mov(scratch, left); // Preserve left.
+ daddu(dst, left, right); // Left is overwritten.
+ xor_(scratch, dst, scratch); // Original left.
+ xor_(overflow_dst, dst, right);
+ and_(overflow_dst, overflow_dst, scratch);
+ } else if (dst.is(right)) {
+ mov(scratch, right); // Preserve right.
+ daddu(dst, left, right); // Right is overwritten.
+ xor_(scratch, dst, scratch); // Original right.
+ xor_(overflow_dst, dst, left);
+ and_(overflow_dst, overflow_dst, scratch);
+ } else {
+ daddu(dst, left, right);
+ xor_(overflow_dst, dst, left);
+ xor_(scratch, dst, right);
+ and_(overflow_dst, scratch, overflow_dst);
+ }
+ BranchOvfHelper(this, overflow_dst, overflow_label, no_overflow_label);
+}
+
+
void MacroAssembler::SubuAndCheckForOverflow(Register dst, Register left,
const Operand& right,
Register overflow_dst,
@@ -4631,18 +4975,16 @@
SubuAndCheckForOverflow(dst, left, right.rm(), overflow_dst, scratch);
} else {
if (dst.is(left)) {
+ li(t9, right); // Load right.
mov(scratch, left); // Preserve left.
- daddiu(dst, left, -(right.immediate())); // Left is overwritten.
+ Subu(dst, left, t9); // Left is overwritten.
xor_(overflow_dst, dst, scratch); // scratch is original left.
- // Load right since xori takes uint16 as immediate.
- daddiu(t9, zero_reg, right.immediate());
xor_(scratch, scratch, t9); // scratch is original left.
and_(overflow_dst, scratch, overflow_dst);
} else {
- daddiu(dst, left, -(right.immediate()));
+ li(t9, right);
+ subu(dst, left, t9);
xor_(overflow_dst, dst, left);
- // Load right since xori takes uint16 as immediate.
- daddiu(t9, zero_reg, right.immediate());
xor_(scratch, left, t9);
and_(overflow_dst, scratch, overflow_dst);
}
@@ -4650,8 +4992,7 @@
}
-void MacroAssembler::SubuAndCheckForOverflow(Register dst,
- Register left,
+void MacroAssembler::SubuAndCheckForOverflow(Register dst, Register left,
Register right,
Register overflow_dst,
Register scratch) {
@@ -4672,6 +5013,72 @@
}
if (dst.is(left)) {
+ mov(scratch, left); // Preserve left.
+ subu(dst, left, right); // Left is overwritten.
+ xor_(overflow_dst, dst, scratch); // scratch is original left.
+ xor_(scratch, scratch, right); // scratch is original left.
+ and_(overflow_dst, scratch, overflow_dst);
+ } else if (dst.is(right)) {
+ mov(scratch, right); // Preserve right.
+ subu(dst, left, right); // Right is overwritten.
+ xor_(overflow_dst, dst, left);
+ xor_(scratch, left, scratch); // Original right.
+ and_(overflow_dst, scratch, overflow_dst);
+ } else {
+ subu(dst, left, right);
+ xor_(overflow_dst, dst, left);
+ xor_(scratch, left, right);
+ and_(overflow_dst, scratch, overflow_dst);
+ }
+}
+
+
+void MacroAssembler::DsubuAndCheckForOverflow(Register dst, Register left,
+ const Operand& right,
+ Register overflow_dst,
+ Register scratch) {
+ if (right.is_reg()) {
+ DsubuAndCheckForOverflow(dst, left, right.rm(), overflow_dst, scratch);
+ } else {
+ if (dst.is(left)) {
+ li(t9, right); // Load right.
+ mov(scratch, left); // Preserve left.
+ dsubu(dst, left, t9); // Left is overwritten.
+ xor_(overflow_dst, dst, scratch); // scratch is original left.
+ xor_(scratch, scratch, t9); // scratch is original left.
+ and_(overflow_dst, scratch, overflow_dst);
+ } else {
+ li(t9, right);
+ dsubu(dst, left, t9);
+ xor_(overflow_dst, dst, left);
+ xor_(scratch, left, t9);
+ and_(overflow_dst, scratch, overflow_dst);
+ }
+ }
+}
+
+
+void MacroAssembler::DsubuAndCheckForOverflow(Register dst, Register left,
+ Register right,
+ Register overflow_dst,
+ Register scratch) {
+ DCHECK(!dst.is(overflow_dst));
+ DCHECK(!dst.is(scratch));
+ DCHECK(!overflow_dst.is(scratch));
+ DCHECK(!overflow_dst.is(left));
+ DCHECK(!overflow_dst.is(right));
+ DCHECK(!scratch.is(left));
+ DCHECK(!scratch.is(right));
+
+ // This happens with some crankshaft code. Since Subu works fine if
+ // left == right, let's not make that restriction here.
+ if (left.is(right)) {
+ mov(dst, zero_reg);
+ mov(overflow_dst, zero_reg);
+ return;
+ }
+
+ if (dst.is(left)) {
mov(scratch, left); // Preserve left.
dsubu(dst, left, right); // Left is overwritten.
xor_(overflow_dst, dst, scratch); // scratch is original left.
@@ -4692,9 +5099,85 @@
}
-void MacroAssembler::CallRuntime(const Runtime::Function* f,
- int num_arguments,
- SaveFPRegsMode save_doubles) {
+void MacroAssembler::DsubBranchOvf(Register dst, Register left,
+ const Operand& right, Label* overflow_label,
+ Label* no_overflow_label, Register scratch) {
+ DCHECK(overflow_label || no_overflow_label);
+ if (right.is_reg()) {
+ DsubBranchOvf(dst, left, right.rm(), overflow_label, no_overflow_label,
+ scratch);
+ } else {
+ Register overflow_dst = t9;
+ DCHECK(!dst.is(scratch));
+ DCHECK(!dst.is(overflow_dst));
+ DCHECK(!scratch.is(overflow_dst));
+ DCHECK(!left.is(overflow_dst));
+ DCHECK(!left.is(scratch));
+ li(overflow_dst, right); // Load right.
+ if (dst.is(left)) {
+ mov(scratch, left); // Preserve left.
+ Dsubu(dst, left, overflow_dst); // Left is overwritten.
+ xor_(overflow_dst, scratch, overflow_dst); // scratch is original left.
+ xor_(scratch, dst, scratch); // scratch is original left.
+ and_(overflow_dst, scratch, overflow_dst);
+ } else {
+ Dsubu(dst, left, overflow_dst);
+ xor_(scratch, left, overflow_dst);
+ xor_(overflow_dst, dst, left);
+ and_(overflow_dst, scratch, overflow_dst);
+ }
+ BranchOvfHelper(this, overflow_dst, overflow_label, no_overflow_label);
+ }
+}
+
+
+void MacroAssembler::DsubBranchOvf(Register dst, Register left, Register right,
+ Label* overflow_label,
+ Label* no_overflow_label, Register scratch) {
+ DCHECK(overflow_label || no_overflow_label);
+ Register overflow_dst = t9;
+ DCHECK(!dst.is(scratch));
+ DCHECK(!dst.is(overflow_dst));
+ DCHECK(!scratch.is(overflow_dst));
+ DCHECK(!overflow_dst.is(left));
+ DCHECK(!overflow_dst.is(right));
+ DCHECK(!scratch.is(left));
+ DCHECK(!scratch.is(right));
+
+ // This happens with some crankshaft code. Since Subu works fine if
+ // left == right, let's not make that restriction here.
+ if (left.is(right)) {
+ mov(dst, zero_reg);
+ if (no_overflow_label) {
+ Branch(no_overflow_label);
+ }
+ }
+
+ if (dst.is(left)) {
+ mov(scratch, left); // Preserve left.
+ dsubu(dst, left, right); // Left is overwritten.
+ xor_(overflow_dst, dst, scratch); // scratch is original left.
+ xor_(scratch, scratch, right); // scratch is original left.
+ and_(overflow_dst, scratch, overflow_dst);
+ } else if (dst.is(right)) {
+ mov(scratch, right); // Preserve right.
+ dsubu(dst, left, right); // Right is overwritten.
+ xor_(overflow_dst, dst, left);
+ xor_(scratch, left, scratch); // Original right.
+ and_(overflow_dst, scratch, overflow_dst);
+ } else {
+ dsubu(dst, left, right);
+ xor_(overflow_dst, dst, left);
+ xor_(scratch, left, right);
+ and_(overflow_dst, scratch, overflow_dst);
+ }
+ BranchOvfHelper(this, overflow_dst, overflow_label, no_overflow_label);
+}
+
+
+void MacroAssembler::CallRuntime(const Runtime::Function* f, int num_arguments,
+ SaveFPRegsMode save_doubles,
+ BranchDelaySlot bd) {
// All parameters are on the stack. v0 has the return value after call.
// If the expected number of arguments of the runtime function is
@@ -4709,7 +5192,7 @@
PrepareCEntryArgs(num_arguments);
PrepareCEntryFunction(ExternalReference(f, isolate()));
CEntryStub stub(isolate(), 1, save_doubles);
- CallStub(&stub);
+ CallStub(&stub, TypeFeedbackId::None(), al, zero_reg, Operand(zero_reg), bd);
}
@@ -4724,24 +5207,13 @@
}
-void MacroAssembler::TailCallExternalReference(const ExternalReference& ext,
- int num_arguments,
- int result_size) {
- // TODO(1236192): Most runtime routines don't need the number of
- // arguments passed in because it is constant. At some point we
- // should remove this need and make the runtime routine entry code
- // smarter.
- PrepareCEntryArgs(num_arguments);
- JumpToExternalReference(ext);
-}
-
-
-void MacroAssembler::TailCallRuntime(Runtime::FunctionId fid,
- int num_arguments,
- int result_size) {
- TailCallExternalReference(ExternalReference(fid, isolate()),
- num_arguments,
- result_size);
+void MacroAssembler::TailCallRuntime(Runtime::FunctionId fid) {
+ const Runtime::Function* function = Runtime::FunctionForId(fid);
+ DCHECK_EQ(1, function->result_size);
+ if (function->nargs >= 0) {
+ PrepareCEntryArgs(function->nargs);
+ }
+ JumpToExternalReference(ExternalReference(fid, isolate()));
}
@@ -4758,40 +5230,15 @@
}
-void MacroAssembler::InvokeBuiltin(Builtins::JavaScript id,
- InvokeFlag flag,
+void MacroAssembler::InvokeBuiltin(int native_context_index, InvokeFlag flag,
const CallWrapper& call_wrapper) {
// You can't call a builtin without a valid frame.
DCHECK(flag == JUMP_FUNCTION || has_frame());
- GetBuiltinEntry(t9, id);
- if (flag == CALL_FUNCTION) {
- call_wrapper.BeforeCall(CallSize(t9));
- Call(t9);
- call_wrapper.AfterCall();
- } else {
- DCHECK(flag == JUMP_FUNCTION);
- Jump(t9);
- }
-}
-
-
-void MacroAssembler::GetBuiltinFunction(Register target,
- Builtins::JavaScript id) {
- // Load the builtins object into target register.
- ld(target, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
- ld(target, FieldMemOperand(target, GlobalObject::kBuiltinsOffset));
- // Load the JavaScript builtin function from the builtins object.
- ld(target, FieldMemOperand(target,
- JSBuiltinsObject::OffsetOfFunctionWithId(id)));
-}
-
-
-void MacroAssembler::GetBuiltinEntry(Register target, Builtins::JavaScript id) {
- DCHECK(!target.is(a1));
- GetBuiltinFunction(a1, id);
- // Load the code entry point from the builtins object.
- ld(target, FieldMemOperand(a1, JSFunction::kCodeEntryOffset));
+ // Fake a parameter count to avoid emitting code to do the check.
+ ParameterCount expected(0);
+ LoadNativeContextSlot(native_context_index, a1);
+ InvokeFunctionCode(a1, no_reg, expected, expected, flag, call_wrapper);
}
@@ -4934,36 +5381,23 @@
Register map_in_out,
Register scratch,
Label* no_map_match) {
- // Load the global or builtins object from the current context.
- ld(scratch,
- MemOperand(cp, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
- ld(scratch, FieldMemOperand(scratch, GlobalObject::kNativeContextOffset));
+ DCHECK(IsFastElementsKind(expected_kind));
+ DCHECK(IsFastElementsKind(transitioned_kind));
// Check that the function's map is the same as the expected cached map.
- ld(scratch,
- MemOperand(scratch,
- Context::SlotOffset(Context::JS_ARRAY_MAPS_INDEX)));
- size_t offset = expected_kind * kPointerSize +
- FixedArrayBase::kHeaderSize;
- ld(at, FieldMemOperand(scratch, offset));
+ ld(scratch, NativeContextMemOperand());
+ ld(at, ContextMemOperand(scratch, Context::ArrayMapIndex(expected_kind)));
Branch(no_map_match, ne, map_in_out, Operand(at));
// Use the transitioned cached map.
- offset = transitioned_kind * kPointerSize +
- FixedArrayBase::kHeaderSize;
- ld(map_in_out, FieldMemOperand(scratch, offset));
+ ld(map_in_out,
+ ContextMemOperand(scratch, Context::ArrayMapIndex(transitioned_kind)));
}
-void MacroAssembler::LoadGlobalFunction(int index, Register function) {
- // Load the global or builtins object from the current context.
- ld(function,
- MemOperand(cp, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
- // Load the native context from the global or builtins object.
- ld(function, FieldMemOperand(function,
- GlobalObject::kNativeContextOffset));
- // Load the function from the native context.
- ld(function, MemOperand(function, Context::SlotOffset(index)));
+void MacroAssembler::LoadNativeContextSlot(int index, Register dst) {
+ ld(dst, NativeContextMemOperand());
+ ld(dst, ContextMemOperand(dst, index));
}
@@ -5020,6 +5454,14 @@
}
+void MacroAssembler::EmitLoadTypeFeedbackVector(Register vector) {
+ ld(vector, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
+ ld(vector, FieldMemOperand(vector, JSFunction::kSharedFunctionInfoOffset));
+ ld(vector,
+ FieldMemOperand(vector, SharedFunctionInfo::kFeedbackVectorOffset));
+}
+
+
void MacroAssembler::EnterFrame(StackFrame::Type type,
bool load_constant_pool_pointer_reg) {
// Out-of-line constant pool not implemented on mips64.
@@ -5090,7 +5532,7 @@
if (save_doubles) {
// The stack is already aligned to 0 modulo 8 for stores with sdc1.
int kNumOfSavedRegisters = FPURegister::kMaxNumRegisters / 2;
- int space = kNumOfSavedRegisters * kDoubleSize ;
+ int space = kNumOfSavedRegisters * kDoubleSize;
Dsubu(sp, sp, Operand(space));
// Remember: we only need to save every 2nd double FPU value.
for (int i = 0; i < kNumOfSavedRegisters; i++) {
@@ -5116,10 +5558,9 @@
}
-void MacroAssembler::LeaveExitFrame(bool save_doubles,
- Register argument_count,
- bool restore_context,
- bool do_return) {
+void MacroAssembler::LeaveExitFrame(bool save_doubles, Register argument_count,
+ bool restore_context, bool do_return,
+ bool argument_count_is_length) {
// Optionally restore all double registers.
if (save_doubles) {
// Remember: we only need to restore every 2nd double FPU value.
@@ -5152,8 +5593,12 @@
ld(ra, MemOperand(sp, ExitFrameConstants::kCallerPCOffset));
if (argument_count.is_valid()) {
- dsll(t8, argument_count, kPointerSizeLog2);
- daddu(sp, sp, t8);
+ if (argument_count_is_length) {
+ daddu(sp, sp, argument_count);
+ } else {
+ dsll(t8, argument_count, kPointerSizeLog2);
+ daddu(sp, sp, t8);
+ }
}
if (do_return) {
@@ -5175,7 +5620,7 @@
sd(scratch1, FieldMemOperand(string, String::kLengthOffset));
li(scratch1, Operand(String::kEmptyHashField));
sd(scratch2, FieldMemOperand(string, HeapObject::kMapOffset));
- sd(scratch1, FieldMemOperand(string, String::kHashFieldOffset));
+ sw(scratch1, FieldMemOperand(string, String::kHashFieldOffset));
}
@@ -5350,7 +5795,7 @@
#if defined(__APPLE__)
DCHECK_EQ(1, kSmiTagMask);
#else
- DCHECK_EQ((uint64_t)1, kSmiTagMask);
+ DCHECK_EQ((int64_t)1, kSmiTagMask);
#endif
or_(at, reg1, reg2);
JumpIfNotSmi(at, on_not_both_smi);
@@ -5365,7 +5810,7 @@
#if defined(__APPLE__)
DCHECK_EQ(1, kSmiTagMask);
#else
- DCHECK_EQ((uint64_t)1, kSmiTagMask);
+ DCHECK_EQ((int64_t)1, kSmiTagMask);
#endif
// Both Smi tags must be 1 (not Smi).
and_(at, reg1, reg2);
@@ -5394,13 +5839,10 @@
void MacroAssembler::AssertString(Register object) {
if (emit_debug_code()) {
STATIC_ASSERT(kSmiTag == 0);
- SmiTst(object, a4);
- Check(ne, kOperandIsASmiAndNotAString, a4, Operand(zero_reg));
- push(object);
- ld(object, FieldMemOperand(object, HeapObject::kMapOffset));
- lbu(object, FieldMemOperand(object, Map::kInstanceTypeOffset));
- Check(lo, kOperandIsNotAString, object, Operand(FIRST_NONSTRING_TYPE));
- pop(object);
+ SmiTst(object, t8);
+ Check(ne, kOperandIsASmiAndNotAString, t8, Operand(zero_reg));
+ GetObjectType(object, t8, t8);
+ Check(lo, kOperandIsNotAString, t8, Operand(FIRST_NONSTRING_TYPE));
}
}
@@ -5408,13 +5850,32 @@
void MacroAssembler::AssertName(Register object) {
if (emit_debug_code()) {
STATIC_ASSERT(kSmiTag == 0);
- SmiTst(object, a4);
- Check(ne, kOperandIsASmiAndNotAName, a4, Operand(zero_reg));
- push(object);
- ld(object, FieldMemOperand(object, HeapObject::kMapOffset));
- lbu(object, FieldMemOperand(object, Map::kInstanceTypeOffset));
- Check(le, kOperandIsNotAName, object, Operand(LAST_NAME_TYPE));
- pop(object);
+ SmiTst(object, t8);
+ Check(ne, kOperandIsASmiAndNotAName, t8, Operand(zero_reg));
+ GetObjectType(object, t8, t8);
+ Check(le, kOperandIsNotAName, t8, Operand(LAST_NAME_TYPE));
+ }
+}
+
+
+void MacroAssembler::AssertFunction(Register object) {
+ if (emit_debug_code()) {
+ STATIC_ASSERT(kSmiTag == 0);
+ SmiTst(object, t8);
+ Check(ne, kOperandIsASmiAndNotAFunction, t8, Operand(zero_reg));
+ GetObjectType(object, t8, t8);
+ Check(eq, kOperandIsNotAFunction, t8, Operand(JS_FUNCTION_TYPE));
+ }
+}
+
+
+void MacroAssembler::AssertBoundFunction(Register object) {
+ if (emit_debug_code()) {
+ STATIC_ASSERT(kSmiTag == 0);
+ SmiTst(object, t8);
+ Check(ne, kOperandIsASmiAndNotABoundFunction, t8, Operand(zero_reg));
+ GetObjectType(object, t8, t8);
+ Check(eq, kOperandIsNotABoundFunction, t8, Operand(JS_BOUND_FUNCTION_TYPE));
}
}
@@ -5426,11 +5887,9 @@
AssertNotSmi(object);
LoadRoot(scratch, Heap::kUndefinedValueRootIndex);
Branch(&done_checking, eq, object, Operand(scratch));
- push(object);
- ld(object, FieldMemOperand(object, HeapObject::kMapOffset));
+ ld(t8, FieldMemOperand(object, HeapObject::kMapOffset));
LoadRoot(scratch, Heap::kAllocationSiteMapRootIndex);
- Assert(eq, kExpectedUndefinedOrCell, object, Operand(scratch));
- pop(object);
+ Assert(eq, kExpectedUndefinedOrCell, t8, Operand(scratch));
bind(&done_checking);
}
}
@@ -5455,88 +5914,6 @@
}
-void MacroAssembler::LookupNumberStringCache(Register object,
- Register result,
- Register scratch1,
- Register scratch2,
- Register scratch3,
- Label* not_found) {
- // Use of registers. Register result is used as a temporary.
- Register number_string_cache = result;
- Register mask = scratch3;
-
- // Load the number string cache.
- LoadRoot(number_string_cache, Heap::kNumberStringCacheRootIndex);
-
- // Make the hash mask from the length of the number string cache. It
- // contains two elements (number and string) for each cache entry.
- ld(mask, FieldMemOperand(number_string_cache, FixedArray::kLengthOffset));
- // Divide length by two (length is a smi).
- // dsra(mask, mask, kSmiTagSize + 1);
- dsra32(mask, mask, 1);
- Daddu(mask, mask, -1); // Make mask.
-
- // Calculate the entry in the number string cache. The hash value in the
- // number string cache for smis is just the smi value, and the hash for
- // doubles is the xor of the upper and lower words. See
- // Heap::GetNumberStringCache.
- Label is_smi;
- Label load_result_from_cache;
- JumpIfSmi(object, &is_smi);
- CheckMap(object,
- scratch1,
- Heap::kHeapNumberMapRootIndex,
- not_found,
- DONT_DO_SMI_CHECK);
-
- STATIC_ASSERT(8 == kDoubleSize);
- Daddu(scratch1,
- object,
- Operand(HeapNumber::kValueOffset - kHeapObjectTag));
- ld(scratch2, MemOperand(scratch1, kPointerSize));
- ld(scratch1, MemOperand(scratch1, 0));
- Xor(scratch1, scratch1, Operand(scratch2));
- And(scratch1, scratch1, Operand(mask));
-
- // Calculate address of entry in string cache: each entry consists
- // of two pointer sized fields.
- dsll(scratch1, scratch1, kPointerSizeLog2 + 1);
- Daddu(scratch1, number_string_cache, scratch1);
-
- Register probe = mask;
- ld(probe, FieldMemOperand(scratch1, FixedArray::kHeaderSize));
- JumpIfSmi(probe, not_found);
- ldc1(f12, FieldMemOperand(object, HeapNumber::kValueOffset));
- ldc1(f14, FieldMemOperand(probe, HeapNumber::kValueOffset));
- BranchF(&load_result_from_cache, NULL, eq, f12, f14);
- Branch(not_found);
-
- bind(&is_smi);
- Register scratch = scratch1;
- // dsra(scratch, object, 1); // Shift away the tag.
- dsra32(scratch, scratch, 0);
- And(scratch, mask, Operand(scratch));
-
- // Calculate address of entry in string cache: each entry consists
- // of two pointer sized fields.
- dsll(scratch, scratch, kPointerSizeLog2 + 1);
- Daddu(scratch, number_string_cache, scratch);
-
- // Check if the entry is the smi we are looking for.
- ld(probe, FieldMemOperand(scratch, FixedArray::kHeaderSize));
- Branch(not_found, ne, object, Operand(probe));
-
- // Get the result from the cache.
- bind(&load_result_from_cache);
- ld(result, FieldMemOperand(scratch, FixedArray::kHeaderSize + kPointerSize));
-
- IncrementCounter(isolate()->counters()->number_to_string_native(),
- 1,
- scratch1,
- scratch2);
-}
-
-
void MacroAssembler::JumpIfNonSmisNotBothSequentialOneByteStrings(
Register first, Register second, Register scratch1, Register scratch2,
Label* failure) {
@@ -5749,94 +6126,6 @@
#undef BRANCH_ARGS_CHECK
-void MacroAssembler::PatchRelocatedValue(Register li_location,
- Register scratch,
- Register new_value) {
- lwu(scratch, MemOperand(li_location));
- // At this point scratch is a lui(at, ...) instruction.
- if (emit_debug_code()) {
- And(scratch, scratch, kOpcodeMask);
- Check(eq, kTheInstructionToPatchShouldBeALui,
- scratch, Operand(LUI));
- lwu(scratch, MemOperand(li_location));
- }
- dsrl32(t9, new_value, 0);
- Ins(scratch, t9, 0, kImm16Bits);
- sw(scratch, MemOperand(li_location));
-
- lwu(scratch, MemOperand(li_location, kInstrSize));
- // scratch is now ori(at, ...).
- if (emit_debug_code()) {
- And(scratch, scratch, kOpcodeMask);
- Check(eq, kTheInstructionToPatchShouldBeAnOri,
- scratch, Operand(ORI));
- lwu(scratch, MemOperand(li_location, kInstrSize));
- }
- dsrl(t9, new_value, kImm16Bits);
- Ins(scratch, t9, 0, kImm16Bits);
- sw(scratch, MemOperand(li_location, kInstrSize));
-
- lwu(scratch, MemOperand(li_location, kInstrSize * 3));
- // scratch is now ori(at, ...).
- if (emit_debug_code()) {
- And(scratch, scratch, kOpcodeMask);
- Check(eq, kTheInstructionToPatchShouldBeAnOri,
- scratch, Operand(ORI));
- lwu(scratch, MemOperand(li_location, kInstrSize * 3));
- }
-
- Ins(scratch, new_value, 0, kImm16Bits);
- sw(scratch, MemOperand(li_location, kInstrSize * 3));
-
- // Update the I-cache so the new lui and ori can be executed.
- FlushICache(li_location, 4);
-}
-
-void MacroAssembler::GetRelocatedValue(Register li_location,
- Register value,
- Register scratch) {
- lwu(value, MemOperand(li_location));
- if (emit_debug_code()) {
- And(value, value, kOpcodeMask);
- Check(eq, kTheInstructionShouldBeALui,
- value, Operand(LUI));
- lwu(value, MemOperand(li_location));
- }
-
- // value now holds a lui instruction. Extract the immediate.
- andi(value, value, kImm16Mask);
- dsll32(value, value, kImm16Bits);
-
- lwu(scratch, MemOperand(li_location, kInstrSize));
- if (emit_debug_code()) {
- And(scratch, scratch, kOpcodeMask);
- Check(eq, kTheInstructionShouldBeAnOri,
- scratch, Operand(ORI));
- lwu(scratch, MemOperand(li_location, kInstrSize));
- }
- // "scratch" now holds an ori instruction. Extract the immediate.
- andi(scratch, scratch, kImm16Mask);
- dsll32(scratch, scratch, 0);
-
- or_(value, value, scratch);
-
- lwu(scratch, MemOperand(li_location, kInstrSize * 3));
- if (emit_debug_code()) {
- And(scratch, scratch, kOpcodeMask);
- Check(eq, kTheInstructionShouldBeAnOri,
- scratch, Operand(ORI));
- lwu(scratch, MemOperand(li_location, kInstrSize * 3));
- }
- // "scratch" now holds an ori instruction. Extract the immediate.
- andi(scratch, scratch, kImm16Mask);
- dsll(scratch, scratch, kImm16Bits);
-
- or_(value, value, scratch);
- // Sign extend extracted address.
- dsra(value, value, kImm16Bits);
-}
-
-
void MacroAssembler::CheckPageFlag(
Register object,
Register scratch,
@@ -5854,8 +6143,8 @@
Register scratch0,
Register scratch1,
Label* on_black) {
- HasColor(object, scratch0, scratch1, on_black, 1, 0); // kBlackBitPattern.
- DCHECK(strcmp(Marking::kBlackBitPattern, "10") == 0);
+ HasColor(object, scratch0, scratch1, on_black, 1, 1); // kBlackBitPattern.
+ DCHECK(strcmp(Marking::kBlackBitPattern, "11") == 0);
}
@@ -5871,8 +6160,8 @@
GetMarkBits(object, bitmap_scratch, mask_scratch);
Label other_color;
- // Note that we are using a 4-byte aligned 8-byte load.
- Uld(t9, MemOperand(bitmap_scratch, MemoryChunk::kHeaderSize));
+ // Note that we are using two 4-byte aligned loads.
+ LoadWordPair(t9, MemOperand(bitmap_scratch, MemoryChunk::kHeaderSize));
And(t8, t9, Operand(mask_scratch));
Branch(&other_color, first_bit == 1 ? eq : ne, t8, Operand(zero_reg));
// Shift left 1 by adding.
@@ -5884,28 +6173,6 @@
}
-// Detect some, but not all, common pointer-free objects. This is used by the
-// incremental write barrier which doesn't care about oddballs (they are always
-// marked black immediately so this code is not hit).
-void MacroAssembler::JumpIfDataObject(Register value,
- Register scratch,
- Label* not_data_object) {
- DCHECK(!AreAliased(value, scratch, t8, no_reg));
- Label is_data_object;
- ld(scratch, FieldMemOperand(value, HeapObject::kMapOffset));
- LoadRoot(t8, Heap::kHeapNumberMapRootIndex);
- Branch(&is_data_object, eq, t8, Operand(scratch));
- DCHECK(kIsIndirectStringTag == 1 && kIsIndirectStringMask == 1);
- DCHECK(kNotStringTag == 0x80 && kIsNotStringMask == 0x80);
- // If it's a string and it's not a cons string then it's an object containing
- // no GC pointers.
- lbu(scratch, FieldMemOperand(scratch, Map::kInstanceTypeOffset));
- And(t8, scratch, Operand(kIsIndirectStringMask | kIsNotStringMask));
- Branch(not_data_object, ne, t8, Operand(zero_reg));
- bind(&is_data_object);
-}
-
-
void MacroAssembler::GetMarkBits(Register addr_reg,
Register bitmap_reg,
Register mask_reg) {
@@ -5925,115 +6192,29 @@
}
-void MacroAssembler::EnsureNotWhite(
- Register value,
- Register bitmap_scratch,
- Register mask_scratch,
- Register load_scratch,
- Label* value_is_white_and_not_data) {
+void MacroAssembler::JumpIfWhite(Register value, Register bitmap_scratch,
+ Register mask_scratch, Register load_scratch,
+ Label* value_is_white) {
DCHECK(!AreAliased(value, bitmap_scratch, mask_scratch, t8));
GetMarkBits(value, bitmap_scratch, mask_scratch);
// If the value is black or grey we don't need to do anything.
DCHECK(strcmp(Marking::kWhiteBitPattern, "00") == 0);
- DCHECK(strcmp(Marking::kBlackBitPattern, "10") == 0);
- DCHECK(strcmp(Marking::kGreyBitPattern, "11") == 0);
+ DCHECK(strcmp(Marking::kBlackBitPattern, "11") == 0);
+ DCHECK(strcmp(Marking::kGreyBitPattern, "10") == 0);
DCHECK(strcmp(Marking::kImpossibleBitPattern, "01") == 0);
- Label done;
-
// Since both black and grey have a 1 in the first position and white does
// not have a 1 there we only need to check one bit.
// Note that we are using a 4-byte aligned 8-byte load.
- Uld(load_scratch, MemOperand(bitmap_scratch, MemoryChunk::kHeaderSize));
- And(t8, mask_scratch, load_scratch);
- Branch(&done, ne, t8, Operand(zero_reg));
-
if (emit_debug_code()) {
- // Check for impossible bit pattern.
- Label ok;
- // sll may overflow, making the check conservative.
- dsll(t8, mask_scratch, 1);
- And(t8, load_scratch, t8);
- Branch(&ok, eq, t8, Operand(zero_reg));
- stop("Impossible marking bit pattern");
- bind(&ok);
+ LoadWordPair(load_scratch,
+ MemOperand(bitmap_scratch, MemoryChunk::kHeaderSize));
+ } else {
+ lwu(load_scratch, MemOperand(bitmap_scratch, MemoryChunk::kHeaderSize));
}
-
- // Value is white. We check whether it is data that doesn't need scanning.
- // Currently only checks for HeapNumber and non-cons strings.
- Register map = load_scratch; // Holds map while checking type.
- Register length = load_scratch; // Holds length of object after testing type.
- Label is_data_object;
-
- // Check for heap-number
- ld(map, FieldMemOperand(value, HeapObject::kMapOffset));
- LoadRoot(t8, Heap::kHeapNumberMapRootIndex);
- {
- Label skip;
- Branch(&skip, ne, t8, Operand(map));
- li(length, HeapNumber::kSize);
- Branch(&is_data_object);
- bind(&skip);
- }
-
- // Check for strings.
- DCHECK(kIsIndirectStringTag == 1 && kIsIndirectStringMask == 1);
- DCHECK(kNotStringTag == 0x80 && kIsNotStringMask == 0x80);
- // If it's a string and it's not a cons string then it's an object containing
- // no GC pointers.
- Register instance_type = load_scratch;
- lbu(instance_type, FieldMemOperand(map, Map::kInstanceTypeOffset));
- And(t8, instance_type, Operand(kIsIndirectStringMask | kIsNotStringMask));
- Branch(value_is_white_and_not_data, ne, t8, Operand(zero_reg));
- // It's a non-indirect (non-cons and non-slice) string.
- // If it's external, the length is just ExternalString::kSize.
- // Otherwise it's String::kHeaderSize + string->length() * (1 or 2).
- // External strings are the only ones with the kExternalStringTag bit
- // set.
- DCHECK_EQ(0, kSeqStringTag & kExternalStringTag);
- DCHECK_EQ(0, kConsStringTag & kExternalStringTag);
- And(t8, instance_type, Operand(kExternalStringTag));
- {
- Label skip;
- Branch(&skip, eq, t8, Operand(zero_reg));
- li(length, ExternalString::kSize);
- Branch(&is_data_object);
- bind(&skip);
- }
-
- // Sequential string, either Latin1 or UC16.
- // For Latin1 (char-size of 1) we shift the smi tag away to get the length.
- // For UC16 (char-size of 2) we just leave the smi tag in place, thereby
- // getting the length multiplied by 2.
- DCHECK(kOneByteStringTag == 4 && kStringEncodingMask == 4);
- DCHECK(kSmiTag == 0 && kSmiTagSize == 1);
- lw(t9, UntagSmiFieldMemOperand(value, String::kLengthOffset));
- And(t8, instance_type, Operand(kStringEncodingMask));
- {
- Label skip;
- Branch(&skip, ne, t8, Operand(zero_reg));
- // Adjust length for UC16.
- dsll(t9, t9, 1);
- bind(&skip);
- }
- Daddu(length, t9, Operand(SeqString::kHeaderSize + kObjectAlignmentMask));
- DCHECK(!length.is(t8));
- And(length, length, Operand(~kObjectAlignmentMask));
-
- bind(&is_data_object);
- // Value is a data object, and it is white. Mark it black. Since we know
- // that the object is white we can make it black by flipping one bit.
- Uld(t8, MemOperand(bitmap_scratch, MemoryChunk::kHeaderSize));
- Or(t8, t8, Operand(mask_scratch));
- Usd(t8, MemOperand(bitmap_scratch, MemoryChunk::kHeaderSize));
-
- And(bitmap_scratch, bitmap_scratch, Operand(~Page::kPageAlignmentMask));
- Uld(t8, MemOperand(bitmap_scratch, MemoryChunk::kLiveBytesOffset));
- Daddu(t8, t8, Operand(length));
- Usd(t8, MemOperand(bitmap_scratch, MemoryChunk::kLiveBytesOffset));
-
- bind(&done);
+ And(t8, mask_scratch, load_scratch);
+ Branch(value_is_white, eq, t8, Operand(zero_reg));
}
@@ -6044,19 +6225,32 @@
void MacroAssembler::NumberOfOwnDescriptors(Register dst, Register map) {
- ld(dst, FieldMemOperand(map, Map::kBitField3Offset));
+ lwu(dst, FieldMemOperand(map, Map::kBitField3Offset));
DecodeField<Map::NumberOfOwnDescriptorsBits>(dst);
}
void MacroAssembler::EnumLength(Register dst, Register map) {
STATIC_ASSERT(Map::EnumLengthBits::kShift == 0);
- ld(dst, FieldMemOperand(map, Map::kBitField3Offset));
+ lwu(dst, FieldMemOperand(map, Map::kBitField3Offset));
And(dst, dst, Operand(Map::EnumLengthBits::kMask));
SmiTag(dst);
}
+void MacroAssembler::LoadAccessor(Register dst, Register holder,
+ int accessor_index,
+ AccessorComponent accessor) {
+ ld(dst, FieldMemOperand(holder, HeapObject::kMapOffset));
+ LoadInstanceDescriptors(dst, dst);
+ ld(dst,
+ FieldMemOperand(dst, DescriptorArray::GetValueOffset(accessor_index)));
+ int offset = accessor == ACCESSOR_GETTER ? AccessorPair::kGetterOffset
+ : AccessorPair::kSetterOffset;
+ ld(dst, FieldMemOperand(dst, offset));
+}
+
+
void MacroAssembler::CheckEnumCache(Register null_value, Label* call_runtime) {
Register empty_fixed_array_value = a6;
LoadRoot(empty_fixed_array_value, Heap::kEmptyFixedArrayRootIndex);
@@ -6179,8 +6373,11 @@
if (reg5.is_valid()) regs |= reg5.bit();
if (reg6.is_valid()) regs |= reg6.bit();
- for (int i = 0; i < Register::NumAllocatableRegisters(); i++) {
- Register candidate = Register::FromAllocationIndex(i);
+ const RegisterConfiguration* config =
+ RegisterConfiguration::ArchDefault(RegisterConfiguration::CRANKSHAFT);
+ for (int i = 0; i < config->num_allocatable_general_registers(); ++i) {
+ int code = config->GetAllocatableGeneralCode(i);
+ Register candidate = Register::from_code(code);
if (regs & candidate.bit()) continue;
return candidate;
}
@@ -6197,33 +6394,38 @@
DCHECK(!scratch1.is(scratch0));
Factory* factory = isolate()->factory();
Register current = scratch0;
- Label loop_again;
+ Label loop_again, end;
// Scratch contained elements pointer.
Move(current, object);
+ ld(current, FieldMemOperand(current, HeapObject::kMapOffset));
+ ld(current, FieldMemOperand(current, Map::kPrototypeOffset));
+ Branch(&end, eq, current, Operand(factory->null_value()));
// Loop based on the map going up the prototype chain.
bind(&loop_again);
ld(current, FieldMemOperand(current, HeapObject::kMapOffset));
+ lbu(scratch1, FieldMemOperand(current, Map::kInstanceTypeOffset));
+ STATIC_ASSERT(JS_VALUE_TYPE < JS_OBJECT_TYPE);
+ STATIC_ASSERT(JS_PROXY_TYPE < JS_OBJECT_TYPE);
+ Branch(found, lo, scratch1, Operand(JS_OBJECT_TYPE));
lb(scratch1, FieldMemOperand(current, Map::kBitField2Offset));
DecodeField<Map::ElementsKindBits>(scratch1);
Branch(found, eq, scratch1, Operand(DICTIONARY_ELEMENTS));
ld(current, FieldMemOperand(current, Map::kPrototypeOffset));
Branch(&loop_again, ne, current, Operand(factory->null_value()));
+
+ bind(&end);
}
-bool AreAliased(Register reg1,
- Register reg2,
- Register reg3,
- Register reg4,
- Register reg5,
- Register reg6,
- Register reg7,
- Register reg8) {
- int n_of_valid_regs = reg1.is_valid() + reg2.is_valid() +
- reg3.is_valid() + reg4.is_valid() + reg5.is_valid() + reg6.is_valid() +
- reg7.is_valid() + reg8.is_valid();
+bool AreAliased(Register reg1, Register reg2, Register reg3, Register reg4,
+ Register reg5, Register reg6, Register reg7, Register reg8,
+ Register reg9, Register reg10) {
+ int n_of_valid_regs = reg1.is_valid() + reg2.is_valid() + reg3.is_valid() +
+ reg4.is_valid() + reg5.is_valid() + reg6.is_valid() +
+ reg7.is_valid() + reg8.is_valid() + reg9.is_valid() +
+ reg10.is_valid();
RegList regs = 0;
if (reg1.is_valid()) regs |= reg1.bit();
@@ -6234,18 +6436,19 @@
if (reg6.is_valid()) regs |= reg6.bit();
if (reg7.is_valid()) regs |= reg7.bit();
if (reg8.is_valid()) regs |= reg8.bit();
+ if (reg9.is_valid()) regs |= reg9.bit();
+ if (reg10.is_valid()) regs |= reg10.bit();
int n_of_non_aliasing_regs = NumRegs(regs);
return n_of_valid_regs != n_of_non_aliasing_regs;
}
-CodePatcher::CodePatcher(byte* address,
- int instructions,
+CodePatcher::CodePatcher(Isolate* isolate, byte* address, int instructions,
FlushICache flush_cache)
: address_(address),
size_(instructions * Assembler::kInstrSize),
- masm_(NULL, address, size_ + Assembler::kGap),
+ masm_(isolate, address, size_ + Assembler::kGap, CodeObjectRequired::kNo),
flush_cache_(flush_cache) {
// Create a new macro assembler pointing to the address of the code to patch.
// The size is adjusted with kGap on order for the assembler to generate size
@@ -6257,7 +6460,7 @@
CodePatcher::~CodePatcher() {
// Indicate that code has changed.
if (flush_cache_ == FLUSH) {
- CpuFeatures::FlushICache(address_, size_);
+ Assembler::FlushICache(masm_.isolate(), address_, size_);
}
// Check that the code was patched as expected.
DCHECK(masm_.pc_ == address_ + size_);
@@ -6275,25 +6478,10 @@
}
-void CodePatcher::ChangeBranchCondition(Condition cond) {
- Instr instr = Assembler::instr_at(masm_.pc_);
- DCHECK(Assembler::IsBranch(instr));
- uint32_t opcode = Assembler::GetOpcodeField(instr);
- // Currently only the 'eq' and 'ne' cond values are supported and the simple
- // branch instructions (with opcode being the branch type).
- // There are some special cases (see Assembler::IsBranch()) so extending this
- // would be tricky.
- DCHECK(opcode == BEQ ||
- opcode == BNE ||
- opcode == BLEZ ||
- opcode == BGTZ ||
- opcode == BEQL ||
- opcode == BNEL ||
- opcode == BLEZL ||
- opcode == BGTZL);
- opcode = (cond == eq) ? BEQ : BNE;
- instr = (instr & ~kOpcodeMask) | opcode;
- masm_.emit(instr);
+void CodePatcher::ChangeBranchCondition(Instr current_instr,
+ uint32_t new_opcode) {
+ current_instr = (current_instr & ~kOpcodeMask) | new_opcode;
+ masm_.emit(current_instr);
}
@@ -6320,6 +6508,7 @@
}
-} } // namespace v8::internal
+} // namespace internal
+} // namespace v8
#endif // V8_TARGET_ARCH_MIPS64