Upgrade V8 to version 4.9.385.28
https://chromium.googlesource.com/v8/v8/+/4.9.385.28
FPIIM-449
Change-Id: I4b2e74289d4bf3667f2f3dc8aa2e541f63e26eb4
diff --git a/src/mips/macro-assembler-mips.cc b/src/mips/macro-assembler-mips.cc
index 90c3499..3c866ac 100644
--- a/src/mips/macro-assembler-mips.cc
+++ b/src/mips/macro-assembler-mips.cc
@@ -1,33 +1,33 @@
+
// Copyright 2012 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <limits.h> // For LONG_MIN, LONG_MAX.
-#include "src/v8.h"
-
#if V8_TARGET_ARCH_MIPS
#include "src/base/bits.h"
#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/mips/macro-assembler-mips.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());
}
}
@@ -86,6 +86,7 @@
void MacroAssembler::StoreRoot(Register source,
Heap::RootListIndex index) {
+ DCHECK(Heap::RootCanBeWrittenAfterInitialization(index));
sw(source, MemOperand(s6, index << kPointerSizeLog2));
}
@@ -94,6 +95,7 @@
Heap::RootListIndex index,
Condition cond,
Register src1, const Operand& src2) {
+ DCHECK(Heap::RootCanBeWrittenAfterInitialization(index));
Branch(2, NegateCondition(cond), src1, src2);
sw(source, MemOperand(s6, index << kPointerSizeLog2));
}
@@ -146,7 +148,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);
}
@@ -163,6 +165,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,
@@ -216,8 +221,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,
@@ -291,8 +295,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,
@@ -430,10 +434,7 @@
#endif
// Load the native context of the current context.
- int offset =
- Context::kHeaderSize + Context::GLOBAL_OBJECT_INDEX * kPointerSize;
- lw(scratch, FieldMemOperand(scratch, offset));
- lw(scratch, FieldMemOperand(scratch, GlobalObject::kNativeContextOffset));
+ lw(scratch, ContextMemOperand(scratch, Context::NATIVE_CONTEXT_INDEX));
// Check the context is a native context.
if (emit_debug_code()) {
@@ -522,6 +523,7 @@
// hash = hash ^ (hash >> 16);
srl(at, reg0, 16);
xor_(reg0, reg0, at);
+ And(reg0, reg0, Operand(0x3fffffff));
}
@@ -596,7 +598,7 @@
const int kDetailsOffset =
SeededNumberDictionary::kElementsStartOffset + 2 * kPointerSize;
lw(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));
@@ -1050,6 +1052,19 @@
}
+void MacroAssembler::Lsa(Register rd, Register rt, Register rs, uint8_t sa,
+ Register scratch) {
+ if (IsMipsArchVariant(kMips32r6) && 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);
+ }
+}
+
+
// ------------Pseudo-instructions-------------
void MacroAssembler::Ulw(Register rd, const MemOperand& rs) {
@@ -1216,21 +1231,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 == t0.
- Move(a0, address);
- PrepareCallCFunction(2, t0);
-
- li(a1, instructions * kInstrSize);
- CallCFunction(ExternalReference::flush_icache_function(isolate()), 2);
- MultiPop(saved_regs);
-}
-
-
void MacroAssembler::Ext(Register rt,
Register rs,
uint16_t pos,
@@ -1278,50 +1278,40 @@
}
-void MacroAssembler::Cvt_d_uw(FPURegister fd,
- FPURegister fs,
+void MacroAssembler::Cvt_d_uw(FPURegister fd, Register rs,
FPURegister scratch) {
- // Move the data from fs to t8.
- mfc1(t8, fs);
- Cvt_d_uw(fd, t8, scratch);
-}
+ // In FP64Mode we do convertion from long.
+ if (IsFp64Mode()) {
+ mtc1(rs, scratch);
+ Mthc1(zero_reg, scratch);
+ cvt_d_l(fd, scratch);
+ } else {
+ // Convert rs to a FP value in fd.
+ DCHECK(!fd.is(scratch));
+ DCHECK(!rs.is(at));
+ Label msb_clear, conversion_done;
+ // For a value which is < 2^31, regard it as a signed positve word.
+ Branch(&msb_clear, ge, rs, Operand(zero_reg), USE_DELAY_SLOT);
+ mtc1(rs, fd);
-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).
+ li(at, 0x41F00000); // FP value: 2^32.
- DCHECK(!fd.is(scratch));
- DCHECK(!rs.is(t9));
- DCHECK(!rs.is(at));
+ // For unsigned inputs > 2^31, we convert to double as a signed int32,
+ // then add 2^32 to move it back to unsigned value in range 2^31..2^31-1.
+ mtc1(zero_reg, scratch);
+ Mthc1(at, scratch);
- // 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);
+ cvt_d_w(fd, fd);
- // Convert fd to a real FP value.
- cvt_d_w(fd, fd);
+ Branch(USE_DELAY_SLOT, &conversion_done);
+ add_d(fd, fd, scratch);
- Label conversion_done;
+ bind(&msb_clear);
+ cvt_d_w(fd, fd);
- // 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);
-
- bind(&conversion_done);
+ bind(&conversion_done);
+ }
}
@@ -1428,68 +1418,131 @@
}
-void MacroAssembler::BranchF(Label* target,
- Label* nan,
- Condition cc,
- FPURegister cmp1,
- FPURegister cmp2,
- BranchDelaySlot bd) {
- BlockTrampolinePoolScope block_trampoline_pool(this);
- if (cc == al) {
- Branch(bd, target);
- return;
- }
+void MacroAssembler::BranchFCommon(SecondaryField sizeField, Label* target,
+ Label* nan, Condition cond, FPURegister cmp1,
+ FPURegister cmp2, BranchDelaySlot bd) {
+ {
+ BlockTrampolinePoolScope block_trampoline_pool(this);
+ if (cond == al) {
+ Branch(bd, target);
+ return;
+ }
- DCHECK(nan || target);
- // Check for unordered (NaN) cases.
- if (nan) {
- if (!IsMipsArchVariant(kMips32r6)) {
- c(UN, D, cmp1, cmp2);
- bc1t(nan);
- } else {
- // Use kDoubleCompareReg for comparison result. It has to be unavailable
- // to lithium register allocator.
- DCHECK(!cmp1.is(kDoubleCompareReg) && !cmp2.is(kDoubleCompareReg));
- cmp(UN, L, kDoubleCompareReg, cmp1, cmp2);
- bc1nez(nan, kDoubleCompareReg);
+ if (IsMipsArchVariant(kMips32r6)) {
+ 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 (!IsMipsArchVariant(kMips32r6)) {
+ 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 kDoubleCompareReg for comparison result. It has to be unavailable
+ // to lithium register allocator.
+ 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 (!IsMipsArchVariant(kMips32r6)) {
+ 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:
@@ -1497,6 +1550,7 @@
}
}
} 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.
@@ -1506,35 +1560,51 @@
DCHECK(!cmp1.is(kDoubleCompareReg) && !cmp2.is(kDoubleCompareReg));
switch (cc) {
case lt:
- cmp(OLT, L, kDoubleCompareReg, cmp1, cmp2);
+ 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, kDoubleCompareReg, cmp1, cmp2);
+ 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, kDoubleCompareReg, cmp1, cmp2);
+ 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, kDoubleCompareReg, cmp1, cmp2);
+ 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, kDoubleCompareReg, cmp1, cmp2);
+ cmp(EQ, sizeField, kDoubleCompareReg, cmp1, cmp2);
bc1nez(target, kDoubleCompareReg);
break;
case ueq:
- cmp(UEQ, L, kDoubleCompareReg, cmp1, cmp2);
+ cmp(UEQ, sizeField, kDoubleCompareReg, cmp1, cmp2);
bc1nez(target, kDoubleCompareReg);
break;
case ne:
- cmp(EQ, L, kDoubleCompareReg, cmp1, cmp2);
+ cmp(EQ, sizeField, kDoubleCompareReg, cmp1, cmp2);
bc1eqz(target, kDoubleCompareReg);
break;
- case nue:
- cmp(UEQ, L, kDoubleCompareReg, cmp1, cmp2);
+ case ogl:
+ cmp(UEQ, sizeField, kDoubleCompareReg, cmp1, cmp2);
bc1eqz(target, kDoubleCompareReg);
break;
default:
@@ -1542,13 +1612,24 @@
}
}
}
-
if (bd == PROTECT) {
nop();
}
}
+void MacroAssembler::FmoveLow(FPURegister dst, Register src_low) {
+ if (IsFp64Mode()) {
+ DCHECK(!src_low.is(at));
+ mfhc1(at, dst);
+ mtc1(src_low, dst);
+ mthc1(at, dst);
+ } else {
+ mtc1(src_low, dst);
+ }
+}
+
+
void MacroAssembler::Move(FPURegister dst, float imm) {
li(at, Operand(bit_cast<int32_t>(imm)));
mtc1(at, dst);
@@ -1858,28 +1939,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(IsMipsArchVariant(kMips32r6) ? 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);
}
@@ -1891,17 +1974,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 {
@@ -1910,10 +1991,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);
@@ -1932,7 +2013,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.
@@ -1941,549 +2025,543 @@
}
-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)) {
- bne(rs, zero_reg, offset);
- } else {
- sltu(scratch, r2, rs);
- bne(scratch, zero_reg, offset);
- }
- break;
- case Ugreater_equal:
- if (r2.is(zero_reg)) {
- b(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)) {
- beq(rs, zero_reg, offset);
- } else {
- sltu(scratch, r2, rs);
- beq(scratch, zero_reg, offset);
- }
- break;
- default:
- UNREACHABLE();
- }
+
+void MacroAssembler::BranchShort(int32_t offset, BranchDelaySlot bdslot) {
+ if (IsMipsArchVariant(kMips32r6) && 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.imm32_ == 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.imm32_ == 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.imm32_ == 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.imm32_ == 0) {
- bgez(rs, offset);
- } else if (is_int16(rt.imm32_)) {
- slti(scratch, rs, rt.imm32_);
- 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.imm32_ == 0) {
- bltz(rs, offset);
- } else if (is_int16(rt.imm32_)) {
- slti(scratch, rs, rt.imm32_);
- 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.imm32_ == 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.imm32_ == 0) {
- bne(rs, zero_reg, offset);
- } else {
- r2 = scratch;
- li(r2, rt);
- sltu(scratch, r2, rs);
- bne(scratch, zero_reg, offset);
- }
- break;
- case Ugreater_equal:
- if (rt.imm32_ == 0) {
- b(offset);
- } else if (is_int16(rt.imm32_)) {
- sltiu(scratch, rs, rt.imm32_);
- 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.imm32_ == 0) {
- // No code needs to be emitted.
- return;
- } else if (is_int16(rt.imm32_)) {
- sltiu(scratch, rs, rt.imm32_);
- 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.imm32_ == 0) {
- beq(rs, zero_reg, 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 (IsMipsArchVariant(kMips32r6) && 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);
- bne(rs, zero_reg, 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);
- 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::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);
- beq(rs, zero_reg, 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.imm32_ == 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.imm32_ == 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.imm32_ == 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.imm32_ == 0) {
- offset = shifted_branch_offset(L, false);
- bgez(rs, offset);
- } else if (is_int16(rt.imm32_)) {
- slti(scratch, rs, rt.imm32_);
- 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.imm32_ == 0) {
- offset = shifted_branch_offset(L, false);
- bltz(rs, offset);
- } else if (is_int16(rt.imm32_)) {
- slti(scratch, rs, rt.imm32_);
- 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.imm32_ == 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.imm32_ == 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.imm32_ == 0) {
- offset = shifted_branch_offset(L, false);
- b(offset);
- } else if (is_int16(rt.imm32_)) {
- sltiu(scratch, rs, rt.imm32_);
- 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.imm32_ == 0) {
- // No code needs to be emitted.
- return;
- } else if (is_int16(rt.imm32_)) {
- sltiu(scratch, rs, rt.imm32_);
- 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.imm32_ == 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 (IsMipsArchVariant(kMips32r6) && 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 (IsMipsArchVariant(kMips32r6) && 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);
}
@@ -2495,13 +2573,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 {
@@ -2509,20 +2585,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.
@@ -2531,371 +2606,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 (!IsMipsArchVariant(kMips32r6)) {
- 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:
- slt(scratch, r2, rs);
- addiu(scratch, scratch, -1);
- bgezal(scratch, offset);
- break;
- case greater_equal:
- slt(scratch, rs, r2);
- addiu(scratch, scratch, -1);
- bltzal(scratch, offset);
- break;
- case less:
- slt(scratch, rs, r2);
- addiu(scratch, scratch, -1);
- bgezal(scratch, offset);
- break;
- case less_equal:
- slt(scratch, r2, rs);
- addiu(scratch, scratch, -1);
- bltzal(scratch, offset);
- break;
-
- // Unsigned comparison.
- case Ugreater:
- sltu(scratch, r2, rs);
- addiu(scratch, scratch, -1);
- bgezal(scratch, offset);
- break;
- case Ugreater_equal:
- sltu(scratch, rs, r2);
- addiu(scratch, scratch, -1);
- bltzal(scratch, offset);
- break;
- case Uless:
- sltu(scratch, rs, r2);
- addiu(scratch, scratch, -1);
- bgezal(scratch, offset);
- break;
- case Uless_equal:
- sltu(scratch, r2, rs);
- addiu(scratch, scratch, -1);
- bltzal(scratch, offset);
- break;
-
- default:
- UNREACHABLE();
- }
+ if (IsMipsArchVariant(kMips32r6) && bdslot == PROTECT) {
+ DCHECK(is_int26(offset));
+ BranchAndLinkShortHelperR6(offset, nullptr);
} else {
- 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();
- }
+ DCHECK(is_int16(offset));
+ BranchAndLinkShortHelper(offset, nullptr, bdslot);
}
-
- // 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 (IsMipsArchVariant(kMips32r6) && 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();
}
-
- if (!IsMipsArchVariant(kMips32r6)) {
- 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:
- slt(scratch, r2, rs);
- addiu(scratch, scratch, -1);
- offset = shifted_branch_offset(L, false);
- bgezal(scratch, offset);
- break;
- case greater_equal:
- slt(scratch, rs, r2);
- addiu(scratch, scratch, -1);
- offset = shifted_branch_offset(L, false);
- bltzal(scratch, offset);
- break;
- case less:
- slt(scratch, rs, r2);
- addiu(scratch, scratch, -1);
- offset = shifted_branch_offset(L, false);
- bgezal(scratch, offset);
- break;
- case less_equal:
- slt(scratch, r2, rs);
- addiu(scratch, scratch, -1);
- offset = shifted_branch_offset(L, false);
- bltzal(scratch, offset);
- break;
-
- // Unsigned comparison.
- case Ugreater:
- sltu(scratch, r2, rs);
- addiu(scratch, scratch, -1);
- offset = shifted_branch_offset(L, false);
- bgezal(scratch, offset);
- break;
- case Ugreater_equal:
- sltu(scratch, rs, r2);
- addiu(scratch, scratch, -1);
- offset = shifted_branch_offset(L, false);
- bltzal(scratch, offset);
- break;
- case Uless:
- sltu(scratch, rs, r2);
- addiu(scratch, scratch, -1);
- offset = shifted_branch_offset(L, false);
- bgezal(scratch, offset);
- break;
- case Uless_equal:
- sltu(scratch, r2, rs);
- addiu(scratch, scratch, -1);
- offset = shifted_branch_offset(L, false);
- bltzal(scratch, offset);
- break;
-
- default:
- UNREACHABLE();
- }
- } else {
- 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 (IsMipsArchVariant(kMips32r6) && 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 (IsMipsArchVariant(kMips32r6) && bdslot == PROTECT) {
+ return BranchAndLinkShortHelperR6(0, L, cond, rs, rt);
+ } else {
+ return BranchAndLinkShortHelper(0, L, cond, rs, rt, bdslot);
+ }
+ }
+ return false;
}
@@ -2985,6 +2995,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);
@@ -2999,8 +3013,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
}
@@ -3078,65 +3094,56 @@
}
-void MacroAssembler::J(Label* L, BranchDelaySlot bdslot) {
- BlockTrampolinePoolScope block_trampoline_pool(this);
+void MacroAssembler::BranchLong(Label* L, BranchDelaySlot bdslot) {
+ if (IsMipsArchVariant(kMips32r6) && bdslot == PROTECT &&
+ (!L->is_bound() || is_near_r6(L))) {
+ BranchShortHelperR6(0, L);
+ } else {
+ BlockTrampolinePoolScope block_trampoline_pool(this);
+ uint32_t imm32;
+ imm32 = jump_address(L);
+ {
+ BlockGrowBufferScope block_buf_growth(this);
+ // Buffer growth (and relocation) must be blocked for internal references
+ // until associated instructions are emitted and available to be patched.
+ RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE_ENCODED);
+ lui(at, (imm32 & kHiMask) >> kLuiShift);
+ ori(at, at, (imm32 & kImm16Mask));
+ }
+ jr(at);
- uint32_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);
+ // 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::Jr(Label* L, BranchDelaySlot bdslot) {
- BlockTrampolinePoolScope block_trampoline_pool(this);
+void MacroAssembler::BranchAndLinkLong(Label* L, BranchDelaySlot bdslot) {
+ if (IsMipsArchVariant(kMips32r6) && bdslot == PROTECT &&
+ (!L->is_bound() || is_near_r6(L))) {
+ BranchAndLinkShortHelperR6(0, L);
+ } else {
+ BlockTrampolinePoolScope block_trampoline_pool(this);
+ uint32_t imm32;
+ imm32 = jump_address(L);
+ {
+ BlockGrowBufferScope block_buf_growth(this);
+ // Buffer growth (and relocation) must be blocked for internal references
+ // until associated instructions are emitted and available to be patched.
+ RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE_ENCODED);
+ lui(at, (imm32 & kHiMask) >> kLuiShift);
+ ori(at, at, (imm32 & kImm16Mask));
+ }
+ jalr(at);
- uint32_t imm32;
- imm32 = jump_address(L);
- { BlockGrowBufferScope block_buf_growth(this);
- // Buffer growth (and relocation) must be blocked for internal references
- // until associated instructions are emitted and available to be patched.
- RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE);
- lui(at, (imm32 & kHiMask) >> kLuiShift);
- ori(at, at, (imm32 & kImm16Mask));
+ // Emit a nop in the branch delay slot if required.
+ if (bdslot == PROTECT) nop();
}
- jr(at);
-
- // Emit a nop in the branch delay slot if required.
- if (bdslot == PROTECT)
- nop();
-}
-
-
-void MacroAssembler::Jalr(Label* L, BranchDelaySlot bdslot) {
- BlockTrampolinePoolScope block_trampoline_pool(this);
-
- uint32_t imm32;
- imm32 = jump_address(L);
- { BlockGrowBufferScope block_buf_growth(this);
- // Buffer growth (and relocation) must be blocked for internal references
- // until associated instructions are emitted and available to be patched.
- RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE);
- lui(at, (imm32 & kHiMask) >> kLuiShift);
- ori(at, at, (imm32 & kImm16Mask));
- }
- jalr(at);
-
- // Emit a nop in the branch delay slot if required.
- if (bdslot == PROTECT)
- nop();
}
void MacroAssembler::DropAndRet(int drop) {
+ DCHECK(is_int16(drop * kPointerSize));
Ret(USE_DELAY_SLOT);
addiu(sp, sp, drop * kPointerSize);
}
@@ -3174,7 +3181,7 @@
Branch(&skip, NegateCondition(cond), reg, op);
}
- addiu(sp, sp, count * kPointerSize);
+ Addu(sp, sp, Operand(count * kPointerSize));
if (cond != al) {
bind(&skip);
@@ -3211,57 +3218,33 @@
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.
- // t1-t3 are available. We will build up the handler from the bottom by
- // pushing on the stack.
- // Set up the code object (t1) and the state (t2) for pushing.
- unsigned state =
- StackHandler::IndexField::encode(handler_index) |
- StackHandler::KindField::encode(kind);
- li(t1, Operand(CodeObject()), CONSTANT_SIZE);
- li(t2, 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, t2, t1);
- } else {
- MultiPush(t1.bit() | t2.bit() | cp.bit() | fp.bit());
- }
// Link the current handler as the next handler.
li(t2, Operand(ExternalReference(Isolate::kHandlerAddress, isolate())));
lw(t1, MemOperand(t2));
push(t1);
+
// Set this new handler as the current one.
sw(sp, MemOperand(t2));
}
-void MacroAssembler::PopTryHandler() {
+void MacroAssembler::PopStackHandler() {
STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0);
pop(a1);
Addu(sp, sp, Operand(StackHandlerConstants::kSize - kPointerSize));
@@ -3270,101 +3253,6 @@
}
-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.
- lw(a3, FieldMemOperand(a1, Code::kHandlerTableOffset)); // Handler table.
- Addu(a3, a3, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
- srl(a2, a2, StackHandler::kKindWidth); // Handler index.
- sll(a2, a2, kPointerSizeLog2);
- Addu(a2, a3, a2);
- lw(a2, MemOperand(a2)); // Smi-tagged offset.
- Addu(a1, a1, Operand(Code::kHeaderSize - kHeapObjectTag)); // Code start.
- sra(t9, a2, kSmiTagSize);
- Addu(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())));
- lw(sp, MemOperand(a3));
-
- // Restore the next handler.
- pop(a2);
- sw(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));
- sw(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())));
- lw(sp, MemOperand(a3));
-
- // Unwind the handlers until the ENTRY handler is found.
- Label fetch_next, check_kind;
- jmp(&check_kind);
- bind(&fetch_next);
- lw(sp, MemOperand(sp, StackHandlerConstants::kNextOffset));
-
- bind(&check_kind);
- STATIC_ASSERT(StackHandler::JS_ENTRY == 0);
- lw(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);
- sw(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,
@@ -3383,12 +3271,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) {
@@ -3404,55 +3287,52 @@
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.
- lw(result, MemOperand(topaddr));
- lw(t9, MemOperand(topaddr, kPointerSize));
+ // Load allocation top into result and allocation limit into alloc_limit.
+ lw(result, MemOperand(top_address));
+ lw(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.
- lw(t9, MemOperand(topaddr));
- Check(eq, kUnexpectedAllocationTop, result, Operand(t9));
+ // Assert that result actually contains top on entry.
+ lw(alloc_limit, MemOperand(top_address));
+ Check(eq, kUnexpectedAllocationTop, result, Operand(alloc_limit));
}
- // Load allocation limit into t9. Result already contains allocation top.
- lw(t9, MemOperand(topaddr, limit - top));
+ // Load allocation limit. Result already contains allocation top.
+ lw(alloc_limit, MemOperand(top_address, limit - top));
}
if ((flags & DOUBLE_ALIGNMENT) != 0) {
// Align the next allocation. Storing the filler map without checking top is
// safe in new-space because the limit of the heap is aligned there.
- DCHECK((flags & PRETENURE_OLD_POINTER_SPACE) == 0);
DCHECK(kPointerAlignment * 2 == kDoubleAlignment);
- And(scratch2, result, Operand(kDoubleAlignmentMask));
+ And(result_end, result, Operand(kDoubleAlignmentMask));
Label aligned;
- Branch(&aligned, eq, scratch2, Operand(zero_reg));
- if ((flags & PRETENURE_OLD_DATA_SPACE) != 0) {
- Branch(gc_required, Ugreater_equal, result, Operand(t9));
+ Branch(&aligned, eq, result_end, Operand(zero_reg));
+ if ((flags & PRETENURE) != 0) {
+ Branch(gc_required, Ugreater_equal, result, Operand(alloc_limit));
}
- li(scratch2, Operand(isolate()->factory()->one_pointer_filler_map()));
- sw(scratch2, MemOperand(result));
+ li(result_end, Operand(isolate()->factory()->one_pointer_filler_map()));
+ sw(result_end, MemOperand(result));
Addu(result, result, Operand(kDoubleSize / 2));
bind(&aligned);
}
// Calculate new top and bail out if new space is exhausted. Use result
// to calculate the new top.
- Addu(scratch2, result, Operand(object_size));
- Branch(gc_required, Ugreater, scratch2, Operand(t9));
- sw(scratch2, MemOperand(topaddr));
+ Addu(result_end, result, Operand(object_size));
+ Branch(gc_required, Ugreater, result_end, Operand(alloc_limit));
+ sw(result_end, MemOperand(top_address));
// Tag object if requested.
if ((flags & TAG_OBJECT) != 0) {
@@ -3461,28 +3341,25 @@
}
-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 if the DOUBLE_ALIGNMENT flag
+ // is not specified. Other registers must not overlap.
+ DCHECK(!AreAliased(object_size, result, scratch, t9));
+ DCHECK(!AreAliased(result_end, result, scratch, t9));
+ DCHECK((flags & DOUBLE_ALIGNMENT) == 0 || !object_size.is(result_end));
// Check relative positions of allocation top and limit addresses.
// ARM adds additional checks to make sure the ldm instruction can be
@@ -3491,46 +3368,42 @@
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));
-
+ // Set up allocation top address and allocation limit registers.
+ 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.
- lw(result, MemOperand(topaddr));
- lw(t9, MemOperand(topaddr, kPointerSize));
+ // Load allocation top into result and allocation limit into alloc_limit.
+ lw(result, MemOperand(top_address));
+ lw(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.
- lw(t9, MemOperand(topaddr));
- Check(eq, kUnexpectedAllocationTop, result, Operand(t9));
+ // Assert that result actually contains top on entry.
+ lw(alloc_limit, MemOperand(top_address));
+ Check(eq, kUnexpectedAllocationTop, result, Operand(alloc_limit));
}
- // Load allocation limit into t9. Result already contains allocation top.
- lw(t9, MemOperand(topaddr, limit - top));
+ // Load allocation limit. Result already contains allocation top.
+ lw(alloc_limit, MemOperand(top_address, limit - top));
}
if ((flags & DOUBLE_ALIGNMENT) != 0) {
// Align the next allocation. Storing the filler map without checking top is
// safe in new-space because the limit of the heap is aligned there.
- DCHECK((flags & PRETENURE_OLD_POINTER_SPACE) == 0);
DCHECK(kPointerAlignment * 2 == kDoubleAlignment);
- And(scratch2, result, Operand(kDoubleAlignmentMask));
+ And(result_end, result, Operand(kDoubleAlignmentMask));
Label aligned;
- Branch(&aligned, eq, scratch2, Operand(zero_reg));
- if ((flags & PRETENURE_OLD_DATA_SPACE) != 0) {
- Branch(gc_required, Ugreater_equal, result, Operand(t9));
+ Branch(&aligned, eq, result_end, Operand(zero_reg));
+ if ((flags & PRETENURE) != 0) {
+ Branch(gc_required, Ugreater_equal, result, Operand(alloc_limit));
}
- li(scratch2, Operand(isolate()->factory()->one_pointer_filler_map()));
- sw(scratch2, MemOperand(result));
+ li(result_end, Operand(isolate()->factory()->one_pointer_filler_map()));
+ sw(result_end, MemOperand(result));
Addu(result, result, Operand(kDoubleSize / 2));
bind(&aligned);
}
@@ -3539,19 +3412,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) {
- sll(scratch2, object_size, kPointerSizeLog2);
- Addu(scratch2, result, scratch2);
+ sll(result_end, object_size, kPointerSizeLog2);
+ Addu(result_end, result, result_end);
} else {
- Addu(scratch2, result, Operand(object_size));
+ Addu(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(alloc_limit, result_end, Operand(kObjectAlignmentMask));
+ Check(eq, kUnalignedAllocationInNewSpace, alloc_limit, Operand(zero_reg));
}
- sw(scratch2, MemOperand(topaddr));
+ sw(result_end, MemOperand(top_address));
// Tag object if requested.
if ((flags & TAG_OBJECT) != 0) {
@@ -3560,26 +3433,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));
- lw(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));
- sw(object, MemOperand(scratch));
-}
-
-
void MacroAssembler::AllocateTwoByteString(Register result,
Register length,
Register scratch1,
@@ -3747,29 +3600,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++) {
- lw(tmp, FieldMemOperand(src, i * kPointerSize));
- sw(tmp, FieldMemOperand(dst, i * kPointerSize));
- }
+ // Initialize the JSValue.
+ LoadGlobalFunctionInitialMap(constructor, scratch1, scratch2);
+ sw(scratch1, FieldMemOperand(result, HeapObject::kMapOffset));
+ LoadRoot(scratch1, Heap::kEmptyFixedArrayRootIndex);
+ sw(scratch1, FieldMemOperand(result, JSObject::kPropertiesOffset));
+ sw(scratch1, FieldMemOperand(result, JSObject::kElementsOffset));
+ sw(value, FieldMemOperand(result, JSValue::kValueOffset));
+ STATIC_ASSERT(JSValue::kSize == 4 * kPointerSize);
}
@@ -3841,16 +3690,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);
- sw(filler, MemOperand(start_offset));
- Addu(start_offset, start_offset, kPointerSize);
+ sw(filler, MemOperand(current_address));
+ Addu(current_address, current_address, kPointerSize);
bind(&entry);
- Branch(&loop, lt, start_offset, Operand(end_offset));
+ Branch(&loop, ult, current_address, Operand(end_address));
}
@@ -3901,6 +3750,8 @@
Register scratch3,
Label* fail,
int elements_offset) {
+ DCHECK(!AreAliased(value_reg, key_reg, elements_reg, scratch1, scratch2,
+ scratch3));
Label smi_value, maybe_nan, have_double_value, is_nan, done;
Register mantissa_reg = scratch2;
Register exponent_reg = scratch3;
@@ -3917,7 +3768,7 @@
// Check for nan: all NaN values have a value greater (signed) than 0x7ff00000
// in the exponent.
- li(scratch1, Operand(kNaNOrInfinityLowerBoundUpper32));
+ li(scratch1, Operand(kHoleNanUpper32 & HeapNumber::kExponentMask));
lw(exponent_reg, FieldMemOperand(value_reg, HeapNumber::kExponentOffset));
Branch(&maybe_nan, ge, exponent_reg, Operand(scratch1));
@@ -3955,7 +3806,7 @@
Addu(scratch1, scratch1, scratch2);
// scratch1 is now effective address of the double element
- Register untagged_value = elements_reg;
+ Register untagged_value = scratch2;
SmiUntag(untagged_value, value_reg);
mtc1(untagged_value, f2);
cvt_d_w(f0, f2);
@@ -4120,8 +3971,6 @@
void MacroAssembler::InvokePrologue(const ParameterCount& expected,
const ParameterCount& actual,
- Handle<Code> code_constant,
- Register code_reg,
Label* done,
bool* definitely_mismatches,
InvokeFlag flag,
@@ -4141,14 +3990,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
@@ -4162,18 +4010,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));
- addiu(a3, a3, Code::kHeaderSize - kHeapObjectTag);
- }
-
Handle<Code> adaptor =
isolate()->builtins()->ArgumentsAdaptorTrampoline();
if (flag == CALL_FUNCTION) {
@@ -4191,21 +4034,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;
+ lw(code, FieldMemOperand(function, JSFunction::kCodeEntryOffset));
if (flag == CALL_FUNCTION) {
call_wrapper.BeforeCall(CallSize(code));
Call(code);
@@ -4222,6 +4122,7 @@
void MacroAssembler::InvokeFunction(Register function,
+ Register new_target,
const ParameterCount& actual,
InvokeFlag flag,
const CallWrapper& call_wrapper) {
@@ -4231,18 +4132,18 @@
// Contract with called JS functions requires that function is passed in a1.
DCHECK(function.is(a1));
Register expected_reg = a2;
- Register code_reg = a3;
+ Register temp_reg = t0;
- lw(code_reg, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
+ lw(temp_reg, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
lw(cp, FieldMemOperand(a1, JSFunction::kContextOffset));
lw(expected_reg,
- FieldMemOperand(code_reg,
- SharedFunctionInfo::kFormalParameterCountOffset));
+ FieldMemOperand(temp_reg,
+ SharedFunctionInfo::kFormalParameterCountOffset));
sra(expected_reg, expected_reg, kSmiTagSize);
- lw(code_reg, FieldMemOperand(a1, JSFunction::kCodeEntryOffset));
ParameterCount expected(expected_reg);
- InvokeCode(code_reg, expected, actual, flag, call_wrapper);
+ InvokeFunctionCode(function, new_target, expected, actual, flag,
+ call_wrapper);
}
@@ -4260,11 +4161,7 @@
// Get the function and setup the context.
lw(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.
- lw(a3, FieldMemOperand(a1, JSFunction::kCodeEntryOffset));
- InvokeCode(a3, expected, actual, flag, call_wrapper);
+ InvokeFunctionCode(a1, no_reg, expected, actual, flag, call_wrapper);
}
@@ -4278,24 +4175,6 @@
}
-void MacroAssembler::IsObjectJSObjectType(Register heap_object,
- Register map,
- Register scratch,
- Label* fail) {
- lw(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) {
@@ -4321,34 +4200,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;
+ lw(result, FieldMemOperand(map, Map::kConstructorOrBackPointerOffset));
+ bind(&loop);
+ JumpIfSmi(result, &done);
+ GetObjectType(result, temp, temp2);
+ Branch(&done, ne, temp2, Operand(MAP_TYPE));
+ lw(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));
- lw(scratch,
- FieldMemOperand(function, JSFunction::kSharedFunctionInfoOffset));
- lw(scratch,
- FieldMemOperand(scratch, SharedFunctionInfo::kCompilerHintsOffset));
- And(scratch, scratch,
- Operand(Smi::FromInt(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.
lw(result,
FieldMemOperand(function, JSFunction::kPrototypeOrInitialMapOffset));
@@ -4367,15 +4234,6 @@
// Get the prototype from the initial map.
lw(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);
- lw(result, FieldMemOperand(result, Map::kConstructorOffset));
- }
-
// All done.
bind(&done);
}
@@ -4413,135 +4271,6 @@
}
-static int AddressOffset(ExternalReference ref0, ExternalReference ref1) {
- return ref0.address() - ref1.address();
-}
-
-
-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));
- lw(s0, MemOperand(s3, kNextOffset));
- lw(s1, MemOperand(s3, kLimitOffset));
- lw(s2, MemOperand(s3, kLevelOffset));
- Addu(s2, s2, Operand(1));
- sw(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.
- lw(v0, return_value_operand);
- bind(&return_value_loaded);
-
- // No more valid handles (the result handle was the last one). Restore
- // previous handle scope.
- sw(s0, MemOperand(s3, kNextOffset));
- if (emit_debug_code()) {
- lw(a1, MemOperand(s3, kLevelOffset));
- Check(eq, kUnexpectedLevelAfterReturnFromApiCall, a1, Operand(s2));
- }
- Subu(s2, s2, Operand(1));
- sw(s2, MemOperand(s3, kLevelOffset));
- lw(at, MemOperand(s3, kLimitOffset));
- Branch(&delete_allocated_handles, ne, s1, Operand(at));
-
- // Check if the function scheduled an exception.
- bind(&leave_exit_frame);
- LoadRoot(t0, Heap::kTheHoleValueRootIndex);
- li(at, Operand(ExternalReference::scheduled_exception_address(isolate())));
- lw(t1, MemOperand(at));
- Branch(&promote_scheduled_exception, ne, t0, Operand(t1));
- bind(&exception_handled);
-
- bool restore_context = context_restore_operand != NULL;
- if (restore_context) {
- lw(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);
- sw(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();
}
@@ -4604,108 +4333,161 @@
}
-void MacroAssembler::AdduAndCheckForOverflow(Register dst, Register left,
- const Operand& right,
- Register overflow_dst,
- Register scratch) {
- if (right.is_reg()) {
- AdduAndCheckForOverflow(dst, left, right.rm(), overflow_dst, scratch);
+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::AddBranchOvf(Register dst, Register left,
+ const Operand& right, Label* overflow_label,
+ Label* no_overflow_label, Register scratch) {
+ if (right.is_reg()) {
+ AddBranchOvf(dst, left, right.rm(), overflow_label, no_overflow_label,
+ scratch);
+ } else {
+ if (IsMipsArchVariant(kMips32r6)) {
+ Register right_reg = t9;
+ DCHECK(!left.is(right_reg));
+ li(right_reg, Operand(right));
+ AddBranchOvf(dst, left, right_reg, overflow_label, no_overflow_label);
+ } else {
+ Register overflow_dst = t9;
+ DCHECK(!dst.is(scratch));
+ DCHECK(!dst.is(overflow_dst));
+ DCHECK(!scratch.is(overflow_dst));
+ DCHECK(!left.is(overflow_dst));
+ if (dst.is(left)) {
+ mov(scratch, left); // Preserve left.
+ Addu(dst, left, right.immediate()); // Left is overwritten.
+ xor_(scratch, dst, scratch); // Original left.
+ // Load right since xori takes uint16 as immediate.
+ Addu(overflow_dst, zero_reg, right);
+ xor_(overflow_dst, dst, overflow_dst);
+ and_(overflow_dst, overflow_dst, scratch);
+ } else {
+ Addu(dst, left, right.immediate());
+ xor_(overflow_dst, dst, left);
+ // Load right since xori takes uint16 as immediate.
+ Addu(scratch, zero_reg, right);
+ xor_(scratch, dst, scratch);
+ and_(overflow_dst, scratch, overflow_dst);
+ }
+ BranchOvfHelper(this, overflow_dst, overflow_label, no_overflow_label);
+ }
+ }
+}
+
+
+void MacroAssembler::AddBranchOvf(Register dst, Register left, Register right,
+ Label* overflow_label,
+ Label* no_overflow_label, Register scratch) {
+ if (IsMipsArchVariant(kMips32r6)) {
+ if (!overflow_label) {
+ DCHECK(no_overflow_label);
+ DCHECK(!dst.is(scratch));
+ Register left_reg = left.is(dst) ? scratch : left;
+ Register right_reg = right.is(dst) ? t9 : right;
+ DCHECK(!dst.is(left_reg));
+ DCHECK(!dst.is(right_reg));
+ Move(left_reg, left);
+ Move(right_reg, right);
+ addu(dst, left, right);
+ bnvc(left_reg, right_reg, no_overflow_label);
+ } else {
+ bovc(left, right, overflow_label);
+ addu(dst, left, right);
+ if (no_overflow_label) bc(no_overflow_label);
+ }
+ } 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(!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.
- addiu(dst, left, right.immediate()); // Left is overwritten.
- xor_(scratch, dst, scratch); // Original left.
- // Load right since xori takes uint16 as immediate.
- addiu(t9, zero_reg, right.immediate());
- xor_(overflow_dst, dst, t9);
+ 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 {
- addiu(dst, left, right.immediate());
+ addu(dst, left, right);
xor_(overflow_dst, dst, left);
- // Load right since xori takes uint16 as immediate.
- addiu(t9, zero_reg, right.immediate());
- xor_(scratch, dst, t9);
+ xor_(scratch, dst, right);
and_(overflow_dst, scratch, overflow_dst);
}
+ BranchOvfHelper(this, overflow_dst, overflow_label, no_overflow_label);
}
}
-void MacroAssembler::AdduAndCheckForOverflow(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.
- 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::SubuAndCheckForOverflow(Register dst, Register left,
- const Operand& right,
- Register overflow_dst,
- Register scratch) {
+void MacroAssembler::SubBranchOvf(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()) {
- SubuAndCheckForOverflow(dst, left, right.rm(), overflow_dst, scratch);
+ SubBranchOvf(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));
if (dst.is(left)) {
mov(scratch, left); // Preserve left.
- addiu(dst, left, -(right.immediate())); // Left is overwritten.
- xor_(overflow_dst, dst, scratch); // scratch is original left.
+ Subu(dst, left, right.immediate()); // Left is overwritten.
// Load right since xori takes uint16 as immediate.
- addiu(t9, zero_reg, right.immediate());
- xor_(scratch, scratch, t9); // scratch is original left.
+ Addu(overflow_dst, zero_reg, right);
+ 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 {
- addiu(dst, left, -(right.immediate()));
+ Subu(dst, left, right);
xor_(overflow_dst, dst, left);
// Load right since xori takes uint16 as immediate.
- addiu(t9, zero_reg, right.immediate());
- xor_(scratch, left, t9);
+ Addu(scratch, zero_reg, right);
+ xor_(scratch, left, scratch);
and_(overflow_dst, scratch, overflow_dst);
}
+ BranchOvfHelper(this, overflow_dst, overflow_label, no_overflow_label);
}
}
-void MacroAssembler::SubuAndCheckForOverflow(Register dst, Register left,
- Register right,
- Register overflow_dst,
- Register scratch) {
- DCHECK(!dst.is(overflow_dst));
+void MacroAssembler::SubBranchOvf(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(!overflow_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));
@@ -4715,8 +4497,9 @@
// left == right, let's not make that restriction here.
if (left.is(right)) {
mov(dst, zero_reg);
- mov(overflow_dst, zero_reg);
- return;
+ if (no_overflow_label) {
+ Branch(no_overflow_label);
+ }
}
if (dst.is(left)) {
@@ -4737,12 +4520,13 @@
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) {
+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
@@ -4757,7 +4541,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);
}
@@ -4772,24 +4556,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()));
}
@@ -4806,40 +4579,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.
- lw(target, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
- lw(target, FieldMemOperand(target, GlobalObject::kBuiltinsOffset));
- // Load the JavaScript builtin function from the builtins object.
- lw(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.
- lw(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);
}
@@ -4982,36 +4730,23 @@
Register map_in_out,
Register scratch,
Label* no_map_match) {
- // Load the global or builtins object from the current context.
- lw(scratch,
- MemOperand(cp, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
- lw(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.
- lw(scratch,
- MemOperand(scratch,
- Context::SlotOffset(Context::JS_ARRAY_MAPS_INDEX)));
- size_t offset = expected_kind * kPointerSize +
- FixedArrayBase::kHeaderSize;
- lw(at, FieldMemOperand(scratch, offset));
+ lw(scratch, NativeContextMemOperand());
+ lw(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;
- lw(map_in_out, FieldMemOperand(scratch, offset));
+ lw(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.
- lw(function,
- MemOperand(cp, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
- // Load the native context from the global or builtins object.
- lw(function, FieldMemOperand(function,
- GlobalObject::kNativeContextOffset));
- // Load the function from the native context.
- lw(function, MemOperand(function, Context::SlotOffset(index)));
+void MacroAssembler::LoadNativeContextSlot(int index, Register dst) {
+ lw(dst, NativeContextMemOperand());
+ lw(dst, ContextMemOperand(dst, index));
}
@@ -5066,6 +4801,14 @@
}
+void MacroAssembler::EmitLoadTypeFeedbackVector(Register vector) {
+ lw(vector, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
+ lw(vector, FieldMemOperand(vector, JSFunction::kSharedFunctionInfoOffset));
+ lw(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 mips.
@@ -5166,17 +4909,16 @@
}
-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.
lw(t8, MemOperand(fp, ExitFrameConstants::kSPOffset));
for (int i = 0; i < FPURegister::kMaxNumRegisters; i+=2) {
FPURegister reg = FPURegister::from_code(i);
- ldc1(reg, MemOperand(t8, i * kDoubleSize + kPointerSize));
+ ldc1(reg, MemOperand(t8, i * kDoubleSize + kPointerSize));
}
}
@@ -5200,8 +4942,12 @@
lw(ra, MemOperand(sp, ExitFrameConstants::kCallerPCOffset));
if (argument_count.is_valid()) {
- sll(t8, argument_count, kPointerSizeLog2);
- addu(sp, sp, t8);
+ if (argument_count_is_length) {
+ addu(sp, sp, argument_count);
+ } else {
+ sll(t8, argument_count, kPointerSizeLog2);
+ addu(sp, sp, t8);
+ }
}
if (do_return) {
@@ -5373,13 +5119,10 @@
void MacroAssembler::AssertString(Register object) {
if (emit_debug_code()) {
STATIC_ASSERT(kSmiTag == 0);
- SmiTst(object, t0);
- Check(ne, kOperandIsASmiAndNotAString, t0, Operand(zero_reg));
- push(object);
- lw(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));
}
}
@@ -5387,13 +5130,32 @@
void MacroAssembler::AssertName(Register object) {
if (emit_debug_code()) {
STATIC_ASSERT(kSmiTag == 0);
- SmiTst(object, t0);
- Check(ne, kOperandIsASmiAndNotAName, t0, Operand(zero_reg));
- push(object);
- lw(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));
}
}
@@ -5405,11 +5167,9 @@
AssertNotSmi(object);
LoadRoot(scratch, Heap::kUndefinedValueRootIndex);
Branch(&done_checking, eq, object, Operand(scratch));
- push(object);
- lw(object, FieldMemOperand(object, HeapObject::kMapOffset));
+ lw(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);
}
}
@@ -5434,86 +5194,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.
- lw(mask, FieldMemOperand(number_string_cache, FixedArray::kLengthOffset));
- // Divide length by two (length is a smi).
- sra(mask, mask, kSmiTagSize + 1);
- Addu(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);
- Addu(scratch1,
- object,
- Operand(HeapNumber::kValueOffset - kHeapObjectTag));
- lw(scratch2, MemOperand(scratch1, kPointerSize));
- lw(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.
- sll(scratch1, scratch1, kPointerSizeLog2 + 1);
- Addu(scratch1, number_string_cache, scratch1);
-
- Register probe = mask;
- lw(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;
- sra(scratch, object, 1); // Shift away the tag.
- And(scratch, mask, Operand(scratch));
-
- // Calculate address of entry in string cache: each entry consists
- // of two pointer sized fields.
- sll(scratch, scratch, kPointerSizeLog2 + 1);
- Addu(scratch, number_string_cache, scratch);
-
- // Check if the entry is the smi we are looking for.
- lw(probe, FieldMemOperand(scratch, FixedArray::kHeaderSize));
- Branch(not_found, ne, object, Operand(probe));
-
- // Get the result from the cache.
- bind(&load_result_from_cache);
- lw(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) {
@@ -5725,7 +5405,7 @@
if (base::OS::ActivationFrameAlignment() > kPointerSize) {
lw(sp, MemOperand(sp, stack_passed_arguments * kPointerSize));
} else {
- Addu(sp, sp, Operand(stack_passed_arguments * sizeof(kPointerSize)));
+ Addu(sp, sp, Operand(stack_passed_arguments * kPointerSize));
}
}
@@ -5733,65 +5413,6 @@
#undef BRANCH_ARGS_CHECK
-void MacroAssembler::PatchRelocatedValue(Register li_location,
- Register scratch,
- Register new_value) {
- lw(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));
- lw(scratch, MemOperand(li_location));
- }
- srl(t9, new_value, kImm16Bits);
- Ins(scratch, t9, 0, kImm16Bits);
- sw(scratch, MemOperand(li_location));
-
- lw(scratch, MemOperand(li_location, kInstrSize));
- // scratch is now ori(at, ...).
- if (emit_debug_code()) {
- And(scratch, scratch, kOpcodeMask);
- Check(eq, kTheInstructionToPatchShouldBeAnOri,
- scratch, Operand(ORI));
- lw(scratch, MemOperand(li_location, kInstrSize));
- }
- Ins(scratch, new_value, 0, kImm16Bits);
- sw(scratch, MemOperand(li_location, kInstrSize));
-
- // Update the I-cache so the new lui and ori can be executed.
- FlushICache(li_location, 2);
-}
-
-void MacroAssembler::GetRelocatedValue(Register li_location,
- Register value,
- Register scratch) {
- lw(value, MemOperand(li_location));
- if (emit_debug_code()) {
- And(value, value, kOpcodeMask);
- Check(eq, kTheInstructionShouldBeALui,
- value, Operand(LUI));
- lw(value, MemOperand(li_location));
- }
-
- // value now holds a lui instruction. Extract the immediate.
- sll(value, value, kImm16Bits);
-
- lw(scratch, MemOperand(li_location, kInstrSize));
- if (emit_debug_code()) {
- And(scratch, scratch, kOpcodeMask);
- Check(eq, kTheInstructionShouldBeAnOri,
- scratch, Operand(ORI));
- lw(scratch, MemOperand(li_location, kInstrSize));
- }
- // "scratch" now holds an ori instruction. Extract the immediate.
- andi(scratch, scratch, kImm16Mask);
-
- // Merge the results.
- or_(value, value, scratch);
-}
-
-
void MacroAssembler::CheckPageFlag(
Register object,
Register scratch,
@@ -5809,8 +5430,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);
}
@@ -5844,28 +5465,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;
- lw(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) {
@@ -5881,112 +5480,23 @@
}
-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.
lw(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.
- sll(t8, mask_scratch, 1);
- And(t8, load_scratch, t8);
- Branch(&ok, eq, t8, Operand(zero_reg));
- stop("Impossible marking bit pattern");
- bind(&ok);
- }
-
- // 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
- lw(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, FieldMemOperand(value, String::kLengthOffset));
- And(t8, instance_type, Operand(kStringEncodingMask));
- {
- Label skip;
- Branch(&skip, eq, t8, Operand(zero_reg));
- srl(t9, t9, 1);
- bind(&skip);
- }
- Addu(length, t9, Operand(SeqString::kHeaderSize + kObjectAlignmentMask));
- 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.
- lw(t8, MemOperand(bitmap_scratch, MemoryChunk::kHeaderSize));
- Or(t8, t8, Operand(mask_scratch));
- sw(t8, MemOperand(bitmap_scratch, MemoryChunk::kHeaderSize));
-
- And(bitmap_scratch, bitmap_scratch, Operand(~Page::kPageAlignmentMask));
- lw(t8, MemOperand(bitmap_scratch, MemoryChunk::kLiveBytesOffset));
- Addu(t8, t8, Operand(length));
- sw(t8, MemOperand(bitmap_scratch, MemoryChunk::kLiveBytesOffset));
-
- bind(&done);
+ Branch(value_is_white, eq, t8, Operand(zero_reg));
}
@@ -6010,6 +5520,19 @@
}
+void MacroAssembler::LoadAccessor(Register dst, Register holder,
+ int accessor_index,
+ AccessorComponent accessor) {
+ lw(dst, FieldMemOperand(holder, HeapObject::kMapOffset));
+ LoadInstanceDescriptors(dst, dst);
+ lw(dst,
+ FieldMemOperand(dst, DescriptorArray::GetValueOffset(accessor_index)));
+ int offset = accessor == ACCESSOR_GETTER ? AccessorPair::kGetterOffset
+ : AccessorPair::kSetterOffset;
+ lw(dst, FieldMemOperand(dst, offset));
+}
+
+
void MacroAssembler::CheckEnumCache(Register null_value, Label* call_runtime) {
Register empty_fixed_array_value = t2;
LoadRoot(empty_fixed_array_value, Heap::kEmptyFixedArrayRootIndex);
@@ -6132,8 +5655,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;
}
@@ -6150,33 +5676,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);
+ lw(current, FieldMemOperand(current, HeapObject::kMapOffset));
+ lw(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);
lw(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));
lw(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();
@@ -6187,18 +5718,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
@@ -6210,7 +5742,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.
@@ -6229,25 +5761,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);
}
@@ -6274,6 +5791,7 @@
}
-} } // namespace v8::internal
+} // namespace internal
+} // namespace v8
#endif // V8_TARGET_ARCH_MIPS