diff options
Diffstat (limited to 'deps/v8/src/mips/macro-assembler-mips.cc')
-rw-r--r-- | deps/v8/src/mips/macro-assembler-mips.cc | 593 |
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())); } |