summaryrefslogtreecommitdiff
path: root/deps/v8/src/mips/macro-assembler-mips.cc
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/mips/macro-assembler-mips.cc')
-rw-r--r--deps/v8/src/mips/macro-assembler-mips.cc593
1 files changed, 493 insertions, 100 deletions
diff --git a/deps/v8/src/mips/macro-assembler-mips.cc b/deps/v8/src/mips/macro-assembler-mips.cc
index e3544c5eec..7cbbd3ae2f 100644
--- a/deps/v8/src/mips/macro-assembler-mips.cc
+++ b/deps/v8/src/mips/macro-assembler-mips.cc
@@ -1,4 +1,3 @@
-
// Copyright 2012 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -100,6 +99,34 @@ void MacroAssembler::StoreRoot(Register source,
sw(source, MemOperand(s6, index << kPointerSizeLog2));
}
+void MacroAssembler::PushCommonFrame(Register marker_reg) {
+ if (marker_reg.is_valid()) {
+ Push(ra, fp, marker_reg);
+ Addu(fp, sp, Operand(kPointerSize));
+ } else {
+ Push(ra, fp);
+ mov(fp, sp);
+ }
+}
+
+void MacroAssembler::PopCommonFrame(Register marker_reg) {
+ if (marker_reg.is_valid()) {
+ Pop(ra, fp, marker_reg);
+ } else {
+ Pop(ra, fp);
+ }
+}
+
+void MacroAssembler::PushStandardFrame(Register function_reg) {
+ int offset = -StandardFrameConstants::kContextOffset;
+ if (function_reg.is_valid()) {
+ Push(ra, fp, cp, function_reg);
+ offset += kPointerSize;
+ } else {
+ Push(ra, fp, cp);
+ }
+ Addu(fp, sp, Operand(offset));
+}
// Push and pop all registers that can hold pointers.
void MacroAssembler::PushSafepointRegisters() {
@@ -455,12 +482,12 @@ void MacroAssembler::RememberedSetHelper(Register object, // For debug tests.
sw(scratch, MemOperand(t8));
// Call stub on end of buffer.
// Check for end of buffer.
- And(t8, scratch, Operand(StoreBuffer::kStoreBufferOverflowBit));
+ And(t8, scratch, Operand(StoreBuffer::kStoreBufferMask));
if (and_then == kFallThroughAtEnd) {
- Branch(&done, eq, t8, Operand(zero_reg));
+ Branch(&done, ne, t8, Operand(zero_reg));
} else {
DCHECK(and_then == kReturnAtEnd);
- Ret(eq, t8, Operand(zero_reg));
+ Ret(ne, t8, Operand(zero_reg));
}
push(ra);
StoreBufferOverflowStub store_buffer_overflow(isolate(), fp_mode);
@@ -481,13 +508,25 @@ void MacroAssembler::CheckAccessGlobalProxy(Register holder_reg,
Register scratch,
Label* miss) {
Label same_contexts;
+ Register temporary = t8;
DCHECK(!holder_reg.is(scratch));
DCHECK(!holder_reg.is(at));
DCHECK(!scratch.is(at));
- // Load current lexical context from the stack frame.
- lw(scratch, MemOperand(fp, StandardFrameConstants::kContextOffset));
+ // Load current lexical context from the active StandardFrame, which
+ // may require crawling past STUB frames.
+ Label load_context;
+ Label has_context;
+ mov(at, fp);
+ bind(&load_context);
+ lw(scratch, MemOperand(at, CommonFrameConstants::kContextOrFrameTypeOffset));
+ // Passing temporary register, otherwise JumpIfNotSmi modifies register at.
+ JumpIfNotSmi(scratch, &has_context, temporary);
+ lw(at, MemOperand(at, CommonFrameConstants::kCallerFPOffset));
+ Branch(&load_context);
+ bind(&has_context);
+
// In debug mode, make sure the lexical context is set.
#ifdef DEBUG
Check(ne, kWeShouldNotHaveAnEmptyLexicalContext,
@@ -764,6 +803,34 @@ void MacroAssembler::Mul(Register rd_hi, Register rd_lo,
}
}
+void MacroAssembler::Mulu(Register rd_hi, Register rd_lo, Register rs,
+ const Operand& rt) {
+ Register reg;
+ if (rt.is_reg()) {
+ reg = rt.rm();
+ } else {
+ DCHECK(!rs.is(at));
+ reg = at;
+ li(reg, rt);
+ }
+
+ if (!IsMipsArchVariant(kMips32r6)) {
+ multu(rs, reg);
+ mflo(rd_lo);
+ mfhi(rd_hi);
+ } else {
+ if (rd_lo.is(rs)) {
+ DCHECK(!rd_hi.is(rs));
+ DCHECK(!rd_hi.is(reg) && !rd_lo.is(reg));
+ muhu(rd_hi, rs, reg);
+ mulu(rd_lo, rs, reg);
+ } else {
+ DCHECK(!rd_hi.is(reg) && !rd_lo.is(reg));
+ mulu(rd_lo, rs, reg);
+ muhu(rd_hi, rs, reg);
+ }
+ }
+}
void MacroAssembler::Mulh(Register rd, Register rs, const Operand& rt) {
if (rt.is_reg()) {
@@ -1078,7 +1145,7 @@ void MacroAssembler::Ror(Register rd, Register rs, const Operand& rt) {
if (rt.is_reg()) {
rotrv(rd, rs, rt.rm());
} else {
- rotr(rd, rs, rt.imm32_);
+ rotr(rd, rs, rt.imm32_ & 0x1f);
}
} else {
if (rt.is_reg()) {
@@ -1090,8 +1157,8 @@ void MacroAssembler::Ror(Register rd, Register rs, const Operand& rt) {
if (rt.imm32_ == 0) {
srl(rd, rs, 0);
} else {
- srl(at, rs, rt.imm32_);
- sll(rd, rs, (0x20 - rt.imm32_) & 0x1f);
+ srl(at, rs, rt.imm32_ & 0x1f);
+ sll(rd, rs, (0x20 - (rt.imm32_ & 0x1f)) & 0x1f);
or_(rd, rd, at);
}
}
@@ -1110,8 +1177,9 @@ void MacroAssembler::Pref(int32_t hint, const MemOperand& rs) {
void MacroAssembler::Lsa(Register rd, Register rt, Register rs, uint8_t sa,
Register scratch) {
+ DCHECK(sa >= 1 && sa <= 31);
if (IsMipsArchVariant(kMips32r6) && sa <= 4) {
- lsa(rd, rt, rs, sa);
+ lsa(rd, rt, rs, sa - 1);
} else {
Register tmp = rd.is(rt) ? scratch : rd;
DCHECK(!tmp.is(rt));
@@ -1840,6 +1908,185 @@ void MacroAssembler::Movf(Register rd, Register rs, uint16_t cc) {
}
}
+#define __ masm->
+
+static bool ZeroHelper_d(MacroAssembler* masm, MaxMinKind kind, FPURegister dst,
+ FPURegister src1, FPURegister src2, Label* equal) {
+ if (src1.is(src2)) {
+ __ Move(dst, src1);
+ return true;
+ }
+
+ Label other, compare_not_equal;
+ FPURegister left, right;
+ if (kind == MaxMinKind::kMin) {
+ left = src1;
+ right = src2;
+ } else {
+ left = src2;
+ right = src1;
+ }
+
+ __ BranchF64(&compare_not_equal, nullptr, ne, src1, src2);
+ // Left and right hand side are equal, check for -0 vs. +0.
+ __ FmoveHigh(t8, src1);
+ __ Branch(&other, eq, t8, Operand(0x80000000));
+ __ Move_d(dst, right);
+ __ Branch(equal);
+ __ bind(&other);
+ __ Move_d(dst, left);
+ __ Branch(equal);
+ __ bind(&compare_not_equal);
+ return false;
+}
+
+static bool ZeroHelper_s(MacroAssembler* masm, MaxMinKind kind, FPURegister dst,
+ FPURegister src1, FPURegister src2, Label* equal) {
+ if (src1.is(src2)) {
+ __ Move(dst, src1);
+ return true;
+ }
+
+ Label other, compare_not_equal;
+ FPURegister left, right;
+ if (kind == MaxMinKind::kMin) {
+ left = src1;
+ right = src2;
+ } else {
+ left = src2;
+ right = src1;
+ }
+
+ __ BranchF32(&compare_not_equal, nullptr, ne, src1, src2);
+ // Left and right hand side are equal, check for -0 vs. +0.
+ __ FmoveLow(t8, src1);
+ __ Branch(&other, eq, t8, Operand(0x80000000));
+ __ Move_s(dst, right);
+ __ Branch(equal);
+ __ bind(&other);
+ __ Move_s(dst, left);
+ __ Branch(equal);
+ __ bind(&compare_not_equal);
+ return false;
+}
+
+#undef __
+
+void MacroAssembler::MinNaNCheck_d(FPURegister dst, FPURegister src1,
+ FPURegister src2, Label* nan) {
+ if (nan) {
+ BranchF64(nullptr, nan, eq, src1, src2);
+ }
+ if (IsMipsArchVariant(kMips32r6)) {
+ min_d(dst, src1, src2);
+ } else {
+ Label skip;
+ if (!ZeroHelper_d(this, MaxMinKind::kMin, dst, src1, src2, &skip)) {
+ if (dst.is(src1)) {
+ BranchF64(&skip, nullptr, le, src1, src2);
+ Move_d(dst, src2);
+ } else if (dst.is(src2)) {
+ BranchF64(&skip, nullptr, ge, src1, src2);
+ Move_d(dst, src1);
+ } else {
+ Label right;
+ BranchF64(&right, nullptr, gt, src1, src2);
+ Move_d(dst, src1);
+ Branch(&skip);
+ bind(&right);
+ Move_d(dst, src2);
+ }
+ }
+ bind(&skip);
+ }
+}
+
+void MacroAssembler::MaxNaNCheck_d(FPURegister dst, FPURegister src1,
+ FPURegister src2, Label* nan) {
+ if (nan) {
+ BranchF64(nullptr, nan, eq, src1, src2);
+ }
+ if (IsMipsArchVariant(kMips32r6)) {
+ max_d(dst, src1, src2);
+ } else {
+ Label skip;
+ if (!ZeroHelper_d(this, MaxMinKind::kMax, dst, src1, src2, &skip)) {
+ if (dst.is(src1)) {
+ BranchF64(&skip, nullptr, ge, src1, src2);
+ Move_d(dst, src2);
+ } else if (dst.is(src2)) {
+ BranchF64(&skip, nullptr, le, src1, src2);
+ Move_d(dst, src1);
+ } else {
+ Label right;
+ BranchF64(&right, nullptr, lt, src1, src2);
+ Move_d(dst, src1);
+ Branch(&skip);
+ bind(&right);
+ Move_d(dst, src2);
+ }
+ }
+ bind(&skip);
+ }
+}
+
+void MacroAssembler::MinNaNCheck_s(FPURegister dst, FPURegister src1,
+ FPURegister src2, Label* nan) {
+ if (nan) {
+ BranchF32(nullptr, nan, eq, src1, src2);
+ }
+ if (IsMipsArchVariant(kMips32r6)) {
+ min_s(dst, src1, src2);
+ } else {
+ Label skip;
+ if (!ZeroHelper_s(this, MaxMinKind::kMin, dst, src1, src2, &skip)) {
+ if (dst.is(src1)) {
+ BranchF32(&skip, nullptr, le, src1, src2);
+ Move_s(dst, src2);
+ } else if (dst.is(src2)) {
+ BranchF32(&skip, nullptr, ge, src1, src2);
+ Move_s(dst, src1);
+ } else {
+ Label right;
+ BranchF32(&right, nullptr, gt, src1, src2);
+ Move_s(dst, src1);
+ Branch(&skip);
+ bind(&right);
+ Move_s(dst, src2);
+ }
+ }
+ bind(&skip);
+ }
+}
+
+void MacroAssembler::MaxNaNCheck_s(FPURegister dst, FPURegister src1,
+ FPURegister src2, Label* nan) {
+ if (nan) {
+ BranchF32(nullptr, nan, eq, src1, src2);
+ }
+ if (IsMipsArchVariant(kMips32r6)) {
+ max_s(dst, src1, src2);
+ } else {
+ Label skip;
+ if (!ZeroHelper_s(this, MaxMinKind::kMax, dst, src1, src2, &skip)) {
+ if (dst.is(src1)) {
+ BranchF32(&skip, nullptr, ge, src1, src2);
+ Move_s(dst, src2);
+ } else if (dst.is(src2)) {
+ BranchF32(&skip, nullptr, le, src1, src2);
+ Move_s(dst, src1);
+ } else {
+ Label right;
+ BranchF32(&right, nullptr, lt, src1, src2);
+ Move_s(dst, src1);
+ Branch(&skip);
+ bind(&right);
+ Move_s(dst, src2);
+ }
+ }
+ bind(&skip);
+ }
+}
void MacroAssembler::Clz(Register rd, Register rs) {
if (IsMipsArchVariant(kLoongson)) {
@@ -3011,16 +3258,25 @@ void MacroAssembler::Jump(Register target,
const Operand& rt,
BranchDelaySlot bd) {
BlockTrampolinePoolScope block_trampoline_pool(this);
- if (cond == cc_always) {
- jr(target);
+ if (IsMipsArchVariant(kMips32r6) && bd == PROTECT) {
+ if (cond == cc_always) {
+ jic(target, 0);
+ } else {
+ BRANCH_ARGS_CHECK(cond, rs, rt);
+ Branch(2, NegateCondition(cond), rs, rt);
+ jic(target, 0);
+ }
} else {
- BRANCH_ARGS_CHECK(cond, rs, rt);
- Branch(2, NegateCondition(cond), rs, rt);
- jr(target);
+ if (cond == cc_always) {
+ jr(target);
+ } else {
+ BRANCH_ARGS_CHECK(cond, rs, rt);
+ Branch(2, NegateCondition(cond), rs, rt);
+ jr(target);
+ }
+ // Emit a nop in the branch delay slot if required.
+ if (bd == PROTECT) nop();
}
- // Emit a nop in the branch delay slot if required.
- if (bd == PROTECT)
- nop();
}
@@ -3078,8 +3334,7 @@ int MacroAssembler::CallSize(Register target,
size += 3;
}
- if (bd == PROTECT)
- size += 1;
+ if (bd == PROTECT && !IsMipsArchVariant(kMips32r6)) size += 1;
return size * kInstrSize;
}
@@ -3098,16 +3353,25 @@ void MacroAssembler::Call(Register target,
BlockTrampolinePoolScope block_trampoline_pool(this);
Label start;
bind(&start);
- if (cond == cc_always) {
- jalr(target);
+ if (IsMipsArchVariant(kMips32r6) && bd == PROTECT) {
+ if (cond == cc_always) {
+ jialc(target, 0);
+ } else {
+ BRANCH_ARGS_CHECK(cond, rs, rt);
+ Branch(2, NegateCondition(cond), rs, rt);
+ jialc(target, 0);
+ }
} else {
- BRANCH_ARGS_CHECK(cond, rs, rt);
- Branch(2, NegateCondition(cond), rs, rt);
- jalr(target);
+ if (cond == cc_always) {
+ jalr(target);
+ } else {
+ BRANCH_ARGS_CHECK(cond, rs, rt);
+ Branch(2, NegateCondition(cond), rs, rt);
+ jalr(target);
+ }
+ // Emit a nop in the branch delay slot if required.
+ if (bd == PROTECT) nop();
}
- // Emit a nop in the branch delay slot if required.
- if (bd == PROTECT)
- nop();
#ifdef DEBUG
CHECK_EQ(size + CallSize(target, cond, rs, rt, bd),
@@ -3198,18 +3462,35 @@ void MacroAssembler::BranchLong(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_ENCODED);
- lui(at, (imm32 & kHiMask) >> kLuiShift);
- ori(at, at, (imm32 & kImm16Mask));
+ if (IsMipsArchVariant(kMips32r6) && bdslot == PROTECT) {
+ uint32_t lui_offset, jic_offset;
+ UnpackTargetAddressUnsigned(imm32, lui_offset, jic_offset);
+ {
+ BlockGrowBufferScope block_buf_growth(this);
+ // Buffer growth (and relocation) must be blocked for internal
+ // references until associated instructions are emitted and
+ // available to be patched.
+ RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE_ENCODED);
+ lui(at, lui_offset);
+ jic(at, jic_offset);
+ }
+ CheckBuffer();
+ } else {
+ {
+ BlockGrowBufferScope block_buf_growth(this);
+ // Buffer growth (and relocation) must be blocked for internal
+ // references
+ // until associated instructions are emitted and available to be
+ // patched.
+ RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE_ENCODED);
+ lui(at, (imm32 & kHiMask) >> kLuiShift);
+ ori(at, at, (imm32 & kImm16Mask));
+ }
+ CheckBuffer();
+ jr(at);
+ // Emit a nop in the branch delay slot if required.
+ if (bdslot == PROTECT) nop();
}
- jr(at);
-
- // Emit a nop in the branch delay slot if required.
- if (bdslot == PROTECT) nop();
}
}
@@ -3222,18 +3503,35 @@ void MacroAssembler::BranchAndLinkLong(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_ENCODED);
- lui(at, (imm32 & kHiMask) >> kLuiShift);
- ori(at, at, (imm32 & kImm16Mask));
+ if (IsMipsArchVariant(kMips32r6) && bdslot == PROTECT) {
+ uint32_t lui_offset, jic_offset;
+ UnpackTargetAddressUnsigned(imm32, lui_offset, jic_offset);
+ {
+ BlockGrowBufferScope block_buf_growth(this);
+ // Buffer growth (and relocation) must be blocked for internal
+ // references until associated instructions are emitted and
+ // available to be patched.
+ RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE_ENCODED);
+ lui(at, lui_offset);
+ jialc(at, jic_offset);
+ }
+ CheckBuffer();
+ } else {
+ {
+ BlockGrowBufferScope block_buf_growth(this);
+ // Buffer growth (and relocation) must be blocked for internal
+ // references
+ // until associated instructions are emitted and available to be
+ // patched.
+ RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE_ENCODED);
+ lui(at, (imm32 & kHiMask) >> kLuiShift);
+ ori(at, at, (imm32 & kImm16Mask));
+ }
+ CheckBuffer();
+ jalr(at);
+ // Emit a nop in the branch delay slot if required.
+ if (bdslot == PROTECT) nop();
}
- jalr(at);
-
- // Emit a nop in the branch delay slot if required.
- if (bdslot == PROTECT) nop();
}
}
@@ -4062,6 +4360,65 @@ void MacroAssembler::MovToFloatParameters(DoubleRegister src1,
// -----------------------------------------------------------------------------
// JavaScript invokes.
+void MacroAssembler::PrepareForTailCall(const ParameterCount& callee_args_count,
+ Register caller_args_count_reg,
+ Register scratch0, Register scratch1) {
+#if DEBUG
+ if (callee_args_count.is_reg()) {
+ DCHECK(!AreAliased(callee_args_count.reg(), caller_args_count_reg, scratch0,
+ scratch1));
+ } else {
+ DCHECK(!AreAliased(caller_args_count_reg, scratch0, scratch1));
+ }
+#endif
+
+ // Calculate the end of destination area where we will put the arguments
+ // after we drop current frame. We add kPointerSize to count the receiver
+ // argument which is not included into formal parameters count.
+ Register dst_reg = scratch0;
+ Lsa(dst_reg, fp, caller_args_count_reg, kPointerSizeLog2);
+ Addu(dst_reg, dst_reg,
+ Operand(StandardFrameConstants::kCallerSPOffset + kPointerSize));
+
+ Register src_reg = caller_args_count_reg;
+ // Calculate the end of source area. +kPointerSize is for the receiver.
+ if (callee_args_count.is_reg()) {
+ Lsa(src_reg, sp, callee_args_count.reg(), kPointerSizeLog2);
+ Addu(src_reg, src_reg, Operand(kPointerSize));
+ } else {
+ Addu(src_reg, sp,
+ Operand((callee_args_count.immediate() + 1) * kPointerSize));
+ }
+
+ if (FLAG_debug_code) {
+ Check(lo, kStackAccessBelowStackPointer, src_reg, Operand(dst_reg));
+ }
+
+ // Restore caller's frame pointer and return address now as they will be
+ // overwritten by the copying loop.
+ lw(ra, MemOperand(fp, StandardFrameConstants::kCallerPCOffset));
+ lw(fp, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
+
+ // Now copy callee arguments to the caller frame going backwards to avoid
+ // callee arguments corruption (source and destination areas could overlap).
+
+ // Both src_reg and dst_reg are pointing to the word after the one to copy,
+ // so they must be pre-decremented in the loop.
+ Register tmp_reg = scratch1;
+ Label loop, entry;
+ Branch(&entry);
+ bind(&loop);
+ Subu(src_reg, src_reg, Operand(kPointerSize));
+ Subu(dst_reg, dst_reg, Operand(kPointerSize));
+ lw(tmp_reg, MemOperand(src_reg));
+ sw(tmp_reg, MemOperand(dst_reg));
+ bind(&entry);
+ Branch(&loop, ne, sp, Operand(src_reg));
+
+ // Leave current frame.
+ mov(sp, dst_reg);
+}
+
void MacroAssembler::InvokePrologue(const ParameterCount& expected,
const ParameterCount& actual,
Label* done,
@@ -4846,12 +5203,9 @@ void MacroAssembler::LoadGlobalFunctionInitialMap(Register function,
}
}
-
-void MacroAssembler::StubPrologue() {
- Push(ra, fp, cp);
- Push(Smi::FromInt(StackFrame::STUB));
- // Adjust FP to point to saved FP.
- Addu(fp, sp, Operand(StandardFrameConstants::kFixedFrameSizeFromFp));
+void MacroAssembler::StubPrologue(StackFrame::Type type) {
+ li(at, Operand(Smi::FromInt(type)));
+ PushCommonFrame(at);
}
@@ -4874,10 +5228,8 @@ void MacroAssembler::Prologue(bool code_pre_aging) {
nop(); // Branch delay slot nop.
nop(); // Pad the empty space.
} else {
- Push(ra, fp, cp, a1);
+ PushStandardFrame(a1);
nop(Assembler::CODE_AGE_SEQUENCE_NOP);
- // Adjust fp to point to caller's fp.
- Addu(fp, sp, Operand(StandardFrameConstants::kFixedFrameSizeFromFp));
}
}
@@ -4898,30 +5250,41 @@ void MacroAssembler::EnterFrame(StackFrame::Type type,
void MacroAssembler::EnterFrame(StackFrame::Type type) {
- addiu(sp, sp, -5 * kPointerSize);
- li(t8, Operand(Smi::FromInt(type)));
- li(t9, Operand(CodeObject()), CONSTANT_SIZE);
- sw(ra, MemOperand(sp, 4 * kPointerSize));
- sw(fp, MemOperand(sp, 3 * kPointerSize));
- sw(cp, MemOperand(sp, 2 * kPointerSize));
- sw(t8, MemOperand(sp, 1 * kPointerSize));
- sw(t9, MemOperand(sp, 0 * kPointerSize));
+ int stack_offset, fp_offset;
+ if (type == StackFrame::INTERNAL) {
+ stack_offset = -4 * kPointerSize;
+ fp_offset = 2 * kPointerSize;
+ } else {
+ stack_offset = -3 * kPointerSize;
+ fp_offset = 1 * kPointerSize;
+ }
+ addiu(sp, sp, stack_offset);
+ stack_offset = -stack_offset - kPointerSize;
+ sw(ra, MemOperand(sp, stack_offset));
+ stack_offset -= kPointerSize;
+ sw(fp, MemOperand(sp, stack_offset));
+ stack_offset -= kPointerSize;
+ li(t9, Operand(Smi::FromInt(type)));
+ sw(t9, MemOperand(sp, stack_offset));
+ if (type == StackFrame::INTERNAL) {
+ DCHECK_EQ(stack_offset, kPointerSize);
+ li(t9, Operand(CodeObject()));
+ sw(t9, MemOperand(sp, 0));
+ } else {
+ DCHECK_EQ(stack_offset, 0);
+ }
// Adjust FP to point to saved FP.
- Addu(fp, sp,
- Operand(StandardFrameConstants::kFixedFrameSizeFromFp + kPointerSize));
+ Addu(fp, sp, Operand(fp_offset));
}
void MacroAssembler::LeaveFrame(StackFrame::Type type) {
- mov(sp, fp);
- lw(fp, MemOperand(sp, 0 * kPointerSize));
- lw(ra, MemOperand(sp, 1 * kPointerSize));
- addiu(sp, sp, 2 * kPointerSize);
+ addiu(sp, fp, 2 * kPointerSize);
+ lw(ra, MemOperand(fp, 1 * kPointerSize));
+ lw(fp, MemOperand(fp, 0 * kPointerSize));
}
-
-void MacroAssembler::EnterExitFrame(bool save_doubles,
- int stack_space) {
+void MacroAssembler::EnterExitFrame(bool save_doubles, int stack_space) {
// Set up the frame structure on the stack.
STATIC_ASSERT(2 * kPointerSize == ExitFrameConstants::kCallerSPDisplacement);
STATIC_ASSERT(1 * kPointerSize == ExitFrameConstants::kCallerPCOffset);
@@ -4931,16 +5294,20 @@ void MacroAssembler::EnterExitFrame(bool save_doubles,
// fp + 2 (==kCallerSPDisplacement) - old stack's end
// [fp + 1 (==kCallerPCOffset)] - saved old ra
// [fp + 0 (==kCallerFPOffset)] - saved old fp
- // [fp - 1 (==kSPOffset)] - sp of the called function
- // [fp - 2 (==kCodeOffset)] - CodeObject
+ // [fp - 1 StackFrame::EXIT Smi
+ // [fp - 2 (==kSPOffset)] - sp of the called function
+ // [fp - 3 (==kCodeOffset)] - CodeObject
// fp - (2 + stack_space + alignment) == sp == [fp - kSPOffset] - top of the
// new stack (will contain saved ra)
- // Save registers.
- addiu(sp, sp, -4 * kPointerSize);
- sw(ra, MemOperand(sp, 3 * kPointerSize));
- sw(fp, MemOperand(sp, 2 * kPointerSize));
- addiu(fp, sp, 2 * kPointerSize); // Set up new frame pointer.
+ // Save registers and reserve room for saved entry sp and code object.
+ addiu(sp, sp, -2 * kPointerSize - ExitFrameConstants::kFixedFrameSizeFromFp);
+ sw(ra, MemOperand(sp, 4 * kPointerSize));
+ sw(fp, MemOperand(sp, 3 * kPointerSize));
+ li(at, Operand(Smi::FromInt(StackFrame::EXIT)));
+ sw(at, MemOperand(sp, 2 * kPointerSize));
+ // Set up new frame pointer.
+ addiu(fp, sp, ExitFrameConstants::kFixedFrameSizeFromFp);
if (emit_debug_code()) {
sw(zero_reg, MemOperand(fp, ExitFrameConstants::kSPOffset));
@@ -5177,6 +5544,15 @@ void MacroAssembler::JumpIfEitherSmi(Register reg1,
JumpIfSmi(at, on_either_smi);
}
+void MacroAssembler::AssertNotNumber(Register object) {
+ if (emit_debug_code()) {
+ STATIC_ASSERT(kSmiTag == 0);
+ andi(at, object, kSmiTagMask);
+ Check(ne, kOperandIsANumber, at, Operand(zero_reg));
+ GetObjectType(object, t8, t8);
+ Check(ne, kOperandIsNotANumber, t8, Operand(HEAP_NUMBER_TYPE));
+ }
+}
void MacroAssembler::AssertNotSmi(Register object) {
if (emit_debug_code()) {
@@ -5708,28 +6084,45 @@ void MacroAssembler::ClampDoubleToUint8(Register result_reg,
bind(&done);
}
-
-void MacroAssembler::TestJSArrayForAllocationMemento(
- Register receiver_reg,
- Register scratch_reg,
- Label* no_memento_found,
- Condition cond,
- Label* allocation_memento_present) {
- ExternalReference new_space_start =
- ExternalReference::new_space_start(isolate());
+void MacroAssembler::TestJSArrayForAllocationMemento(Register receiver_reg,
+ Register scratch_reg,
+ Label* no_memento_found) {
+ Label map_check;
+ Label top_check;
ExternalReference new_space_allocation_top =
ExternalReference::new_space_allocation_top_address(isolate());
- Addu(scratch_reg, receiver_reg,
- Operand(JSArray::kSize + AllocationMemento::kSize - kHeapObjectTag));
- Branch(no_memento_found, lt, scratch_reg, Operand(new_space_start));
+ const int kMementoMapOffset = JSArray::kSize - kHeapObjectTag;
+ const int kMementoEndOffset = kMementoMapOffset + AllocationMemento::kSize;
+
+ // Bail out if the object is not in new space.
+ JumpIfNotInNewSpace(receiver_reg, scratch_reg, no_memento_found);
+ // If the object is in new space, we need to check whether it is on the same
+ // page as the current top.
+ Addu(scratch_reg, receiver_reg, Operand(kMementoEndOffset));
+ Xor(scratch_reg, scratch_reg, Operand(new_space_allocation_top));
+ And(scratch_reg, scratch_reg, Operand(~Page::kPageAlignmentMask));
+ Branch(&top_check, eq, scratch_reg, Operand(zero_reg));
+ // The object is on a different page than allocation top. Bail out if the
+ // object sits on the page boundary as no memento can follow and we cannot
+ // touch the memory following it.
+ Addu(scratch_reg, receiver_reg, Operand(kMementoEndOffset));
+ Xor(scratch_reg, scratch_reg, Operand(receiver_reg));
+ And(scratch_reg, scratch_reg, Operand(~Page::kPageAlignmentMask));
+ Branch(no_memento_found, ne, scratch_reg, Operand(zero_reg));
+ // Continue with the actual map check.
+ jmp(&map_check);
+ // If top is on the same page as the current object, we need to check whether
+ // we are below top.
+ bind(&top_check);
+ Addu(scratch_reg, receiver_reg, Operand(kMementoEndOffset));
li(at, Operand(new_space_allocation_top));
lw(at, MemOperand(at));
Branch(no_memento_found, gt, scratch_reg, Operand(at));
- lw(scratch_reg, MemOperand(scratch_reg, -AllocationMemento::kSize));
- if (allocation_memento_present) {
- Branch(allocation_memento_present, cond, scratch_reg,
- Operand(isolate()->factory()->allocation_memento_map()));
- }
+ // Memento map check.
+ bind(&map_check);
+ lw(scratch_reg, MemOperand(receiver_reg, kMementoMapOffset));
+ Branch(no_memento_found, ne, scratch_reg,
+ Operand(isolate()->factory()->allocation_memento_map()));
}