| Index: src/arm/macro-assembler-arm.cc
|
| diff --git a/src/arm/macro-assembler-arm.cc b/src/arm/macro-assembler-arm.cc
|
| index 035b045c6200b08dc81c7f5cd8bfab692587f75e..ce653eaadb854b2dcb085190f1718f37b5b7e82f 100644
|
| --- a/src/arm/macro-assembler-arm.cc
|
| +++ b/src/arm/macro-assembler-arm.cc
|
| @@ -113,6 +113,8 @@ int MacroAssembler::CallSize(Register target, Condition cond) {
|
|
|
|
|
| void MacroAssembler::Call(Register target, Condition cond) {
|
| + // Block constant pool for the call instruction sequence.
|
| + BlockConstPoolScope block_const_pool(this);
|
| #ifdef DEBUG
|
| int pre_position = pc_offset();
|
| #endif
|
| @@ -121,10 +123,8 @@ void MacroAssembler::Call(Register target, Condition cond) {
|
| blx(target, cond);
|
| #else
|
| // set lr for return at current pc + 8
|
| - { BlockConstPoolScope block_const_pool(this);
|
| - mov(lr, Operand(pc), LeaveCC, cond);
|
| - mov(pc, Operand(target), LeaveCC, cond);
|
| - }
|
| + mov(lr, Operand(pc), LeaveCC, cond);
|
| + mov(pc, Operand(target), LeaveCC, cond);
|
| #endif
|
|
|
| #ifdef DEBUG
|
| @@ -147,6 +147,8 @@ int MacroAssembler::CallSize(
|
|
|
| void MacroAssembler::Call(
|
| intptr_t target, RelocInfo::Mode rmode, Condition cond) {
|
| + // Block constant pool for the call instruction sequence.
|
| + BlockConstPoolScope block_const_pool(this);
|
| #ifdef DEBUG
|
| int pre_position = pc_offset();
|
| #endif
|
| @@ -156,28 +158,21 @@ void MacroAssembler::Call(
|
| // ldr ip, [pc, #...]
|
| // blx ip
|
|
|
| - // The two instructions (ldr and blx) could be separated by a constant
|
| - // pool and the code would still work. The issue comes from the
|
| - // patching code which expect the ldr to be just above the blx.
|
| - { BlockConstPoolScope block_const_pool(this);
|
| - // Statement positions are expected to be recorded when the target
|
| - // address is loaded. The mov method will automatically record
|
| - // positions when pc is the target, since this is not the case here
|
| - // we have to do it explicitly.
|
| - positions_recorder()->WriteRecordedPositions();
|
| + // Statement positions are expected to be recorded when the target
|
| + // address is loaded. The mov method will automatically record
|
| + // positions when pc is the target, since this is not the case here
|
| + // we have to do it explicitly.
|
| + positions_recorder()->WriteRecordedPositions();
|
|
|
| - mov(ip, Operand(target, rmode), LeaveCC, cond);
|
| - blx(ip, cond);
|
| - }
|
| + mov(ip, Operand(target, rmode), LeaveCC, cond);
|
| + blx(ip, cond);
|
|
|
| ASSERT(kCallTargetAddressOffset == 2 * kInstrSize);
|
| #else
|
| - { BlockConstPoolScope block_const_pool(this);
|
| - // Set lr for return at current pc + 8.
|
| - mov(lr, Operand(pc), LeaveCC, cond);
|
| - // Emit a ldr<cond> pc, [pc + offset of target in constant pool].
|
| - mov(pc, Operand(target, rmode), LeaveCC, cond);
|
| - }
|
| + // Set lr for return at current pc + 8.
|
| + mov(lr, Operand(pc), LeaveCC, cond);
|
| + // Emit a ldr<cond> pc, [pc + offset of target in constant pool].
|
| + mov(pc, Operand(target, rmode), LeaveCC, cond);
|
| ASSERT(kCallTargetAddressOffset == kInstrSize);
|
| #endif
|
|
|
| @@ -438,7 +433,7 @@ void MacroAssembler::StoreRoot(Register source,
|
| void MacroAssembler::RecordWriteHelper(Register object,
|
| Register address,
|
| Register scratch) {
|
| - if (FLAG_debug_code) {
|
| + if (emit_debug_code()) {
|
| // Check that the object is not in new space.
|
| Label not_in_new_space;
|
| InNewSpace(object, scratch, ne, ¬_in_new_space);
|
| @@ -500,7 +495,7 @@ void MacroAssembler::RecordWrite(Register object,
|
|
|
| // Clobber all input registers when running with the debug-code flag
|
| // turned on to provoke errors.
|
| - if (FLAG_debug_code) {
|
| + if (emit_debug_code()) {
|
| mov(object, Operand(BitCast<int32_t>(kZapValue)));
|
| mov(scratch0, Operand(BitCast<int32_t>(kZapValue)));
|
| mov(scratch1, Operand(BitCast<int32_t>(kZapValue)));
|
| @@ -532,7 +527,7 @@ void MacroAssembler::RecordWrite(Register object,
|
|
|
| // Clobber all input registers when running with the debug-code flag
|
| // turned on to provoke errors.
|
| - if (FLAG_debug_code) {
|
| + if (emit_debug_code()) {
|
| mov(object, Operand(BitCast<int32_t>(kZapValue)));
|
| mov(address, Operand(BitCast<int32_t>(kZapValue)));
|
| mov(scratch, Operand(BitCast<int32_t>(kZapValue)));
|
| @@ -736,7 +731,7 @@ void MacroAssembler::EnterExitFrame(bool save_doubles, int stack_space) {
|
| mov(fp, Operand(sp)); // Setup new frame pointer.
|
| // Reserve room for saved entry sp and code object.
|
| sub(sp, sp, Operand(2 * kPointerSize));
|
| - if (FLAG_debug_code) {
|
| + if (emit_debug_code()) {
|
| mov(ip, Operand(0));
|
| str(ip, MemOperand(fp, ExitFrameConstants::kSPOffset));
|
| }
|
| @@ -1143,7 +1138,7 @@ void MacroAssembler::Throw(Register value) {
|
| // Restore cp otherwise.
|
| ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset), ne);
|
| #ifdef DEBUG
|
| - if (FLAG_debug_code) {
|
| + if (emit_debug_code()) {
|
| mov(lr, Operand(pc));
|
| }
|
| #endif
|
| @@ -1217,7 +1212,7 @@ void MacroAssembler::ThrowUncatchable(UncatchableExceptionType type,
|
| // Restore cp otherwise.
|
| ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset), ne);
|
| #ifdef DEBUG
|
| - if (FLAG_debug_code) {
|
| + if (emit_debug_code()) {
|
| mov(lr, Operand(pc));
|
| }
|
| #endif
|
| @@ -1249,7 +1244,7 @@ void MacroAssembler::CheckAccessGlobalProxy(Register holder_reg,
|
| ldr(scratch, FieldMemOperand(scratch, GlobalObject::kGlobalContextOffset));
|
|
|
| // Check the context is a global context.
|
| - if (FLAG_debug_code) {
|
| + if (emit_debug_code()) {
|
| // TODO(119): avoid push(holder_reg)/pop(holder_reg)
|
| // Cannot use ip as a temporary in this verification code. Due to the fact
|
| // that ip is clobbered as part of cmp with an object Operand.
|
| @@ -1268,7 +1263,7 @@ void MacroAssembler::CheckAccessGlobalProxy(Register holder_reg,
|
| b(eq, &same_contexts);
|
|
|
| // Check the context is a global context.
|
| - if (FLAG_debug_code) {
|
| + if (emit_debug_code()) {
|
| // TODO(119): avoid push(holder_reg)/pop(holder_reg)
|
| // Cannot use ip as a temporary in this verification code. Due to the fact
|
| // that ip is clobbered as part of cmp with an object Operand.
|
| @@ -1310,7 +1305,7 @@ void MacroAssembler::AllocateInNewSpace(int object_size,
|
| Label* gc_required,
|
| AllocationFlags flags) {
|
| if (!FLAG_inline_new) {
|
| - if (FLAG_debug_code) {
|
| + if (emit_debug_code()) {
|
| // Trash the registers to simulate an allocation failure.
|
| mov(result, Operand(0x7091));
|
| mov(scratch1, Operand(0x7191));
|
| @@ -1359,7 +1354,7 @@ void MacroAssembler::AllocateInNewSpace(int object_size,
|
| // Load allocation top into result and allocation limit into ip.
|
| ldm(ia, topaddr, result.bit() | ip.bit());
|
| } else {
|
| - if (FLAG_debug_code) {
|
| + if (emit_debug_code()) {
|
| // Assert that result actually contains top on entry. ip is used
|
| // immediately below so this use of ip does not cause difference with
|
| // respect to register content between debug and release mode.
|
| @@ -1393,7 +1388,7 @@ void MacroAssembler::AllocateInNewSpace(Register object_size,
|
| Label* gc_required,
|
| AllocationFlags flags) {
|
| if (!FLAG_inline_new) {
|
| - if (FLAG_debug_code) {
|
| + if (emit_debug_code()) {
|
| // Trash the registers to simulate an allocation failure.
|
| mov(result, Operand(0x7091));
|
| mov(scratch1, Operand(0x7191));
|
| @@ -1437,7 +1432,7 @@ void MacroAssembler::AllocateInNewSpace(Register object_size,
|
| // Load allocation top into result and allocation limit into ip.
|
| ldm(ia, topaddr, result.bit() | ip.bit());
|
| } else {
|
| - if (FLAG_debug_code) {
|
| + if (emit_debug_code()) {
|
| // Assert that result actually contains top on entry. ip is used
|
| // immediately below so this use of ip does not cause difference with
|
| // respect to register content between debug and release mode.
|
| @@ -1462,7 +1457,7 @@ void MacroAssembler::AllocateInNewSpace(Register object_size,
|
| b(hi, gc_required);
|
|
|
| // Update allocation top. result temporarily holds the new top.
|
| - if (FLAG_debug_code) {
|
| + if (emit_debug_code()) {
|
| tst(scratch2, Operand(kObjectAlignmentMask));
|
| Check(eq, "Unaligned allocation in new space");
|
| }
|
| @@ -1766,7 +1761,7 @@ MaybeObject* MacroAssembler::TryCallApiFunctionAndReturn(
|
| // No more valid handles (the result handle was the last one). Restore
|
| // previous handle scope.
|
| str(r4, MemOperand(r7, kNextOffset));
|
| - if (FLAG_debug_code) {
|
| + if (emit_debug_code()) {
|
| ldr(r1, MemOperand(r7, kLevelOffset));
|
| cmp(r1, r6);
|
| Check(eq, "Unexpected level after return from api call");
|
| @@ -2039,6 +2034,121 @@ void MacroAssembler::EmitVFPTruncate(VFPRoundingMode rounding_mode,
|
| }
|
|
|
|
|
| +void MacroAssembler::EmitOutOfInt32RangeTruncate(Register result,
|
| + Register input_high,
|
| + Register input_low,
|
| + Register scratch) {
|
| + Label done, normal_exponent, restore_sign;
|
| +
|
| + // Extract the biased exponent in result.
|
| + Ubfx(result,
|
| + input_high,
|
| + HeapNumber::kExponentShift,
|
| + HeapNumber::kExponentBits);
|
| +
|
| + // Check for Infinity and NaNs, which should return 0.
|
| + cmp(result, Operand(HeapNumber::kExponentMask));
|
| + mov(result, Operand(0), LeaveCC, eq);
|
| + b(eq, &done);
|
| +
|
| + // Express exponent as delta to (number of mantissa bits + 31).
|
| + sub(result,
|
| + result,
|
| + Operand(HeapNumber::kExponentBias + HeapNumber::kMantissaBits + 31),
|
| + SetCC);
|
| +
|
| + // If the delta is strictly positive, all bits would be shifted away,
|
| + // which means that we can return 0.
|
| + b(le, &normal_exponent);
|
| + mov(result, Operand(0));
|
| + b(&done);
|
| +
|
| + bind(&normal_exponent);
|
| + const int kShiftBase = HeapNumber::kNonMantissaBitsInTopWord - 1;
|
| + // Calculate shift.
|
| + add(scratch, result, Operand(kShiftBase + HeapNumber::kMantissaBits), SetCC);
|
| +
|
| + // Save the sign.
|
| + Register sign = result;
|
| + result = no_reg;
|
| + and_(sign, input_high, Operand(HeapNumber::kSignMask));
|
| +
|
| + // Set the implicit 1 before the mantissa part in input_high.
|
| + orr(input_high,
|
| + input_high,
|
| + Operand(1 << HeapNumber::kMantissaBitsInTopWord));
|
| + // Shift the mantissa bits to the correct position.
|
| + // We don't need to clear non-mantissa bits as they will be shifted away.
|
| + // If they weren't, it would mean that the answer is in the 32bit range.
|
| + mov(input_high, Operand(input_high, LSL, scratch));
|
| +
|
| + // Replace the shifted bits with bits from the lower mantissa word.
|
| + Label pos_shift, shift_done;
|
| + rsb(scratch, scratch, Operand(32), SetCC);
|
| + b(&pos_shift, ge);
|
| +
|
| + // Negate scratch.
|
| + rsb(scratch, scratch, Operand(0));
|
| + mov(input_low, Operand(input_low, LSL, scratch));
|
| + b(&shift_done);
|
| +
|
| + bind(&pos_shift);
|
| + mov(input_low, Operand(input_low, LSR, scratch));
|
| +
|
| + bind(&shift_done);
|
| + orr(input_high, input_high, Operand(input_low));
|
| + // Restore sign if necessary.
|
| + cmp(sign, Operand(0));
|
| + result = sign;
|
| + sign = no_reg;
|
| + rsb(result, input_high, Operand(0), LeaveCC, ne);
|
| + mov(result, input_high, LeaveCC, eq);
|
| + bind(&done);
|
| +}
|
| +
|
| +
|
| +void MacroAssembler::EmitECMATruncate(Register result,
|
| + DwVfpRegister double_input,
|
| + SwVfpRegister single_scratch,
|
| + Register scratch,
|
| + Register input_high,
|
| + Register input_low) {
|
| + CpuFeatures::Scope scope(VFP3);
|
| + ASSERT(!input_high.is(result));
|
| + ASSERT(!input_low.is(result));
|
| + ASSERT(!input_low.is(input_high));
|
| + ASSERT(!scratch.is(result) &&
|
| + !scratch.is(input_high) &&
|
| + !scratch.is(input_low));
|
| + ASSERT(!single_scratch.is(double_input.low()) &&
|
| + !single_scratch.is(double_input.high()));
|
| +
|
| + Label done;
|
| +
|
| + // Clear cumulative exception flags.
|
| + ClearFPSCRBits(kVFPExceptionMask, scratch);
|
| + // Try a conversion to a signed integer.
|
| + vcvt_s32_f64(single_scratch, double_input);
|
| + vmov(result, single_scratch);
|
| + // Retrieve he FPSCR.
|
| + vmrs(scratch);
|
| + // Check for overflow and NaNs.
|
| + tst(scratch, Operand(kVFPOverflowExceptionBit |
|
| + kVFPUnderflowExceptionBit |
|
| + kVFPInvalidOpExceptionBit));
|
| + // If we had no exceptions we are done.
|
| + b(eq, &done);
|
| +
|
| + // Load the double value and perform a manual truncation.
|
| + vmov(input_low, input_high, double_input);
|
| + EmitOutOfInt32RangeTruncate(result,
|
| + input_high,
|
| + input_low,
|
| + scratch);
|
| + bind(&done);
|
| +}
|
| +
|
| +
|
| void MacroAssembler::GetLeastBitsFromSmi(Register dst,
|
| Register src,
|
| int num_least_bits) {
|
| @@ -2228,14 +2338,14 @@ void MacroAssembler::DecrementCounter(StatsCounter* counter, int value,
|
|
|
|
|
| void MacroAssembler::Assert(Condition cond, const char* msg) {
|
| - if (FLAG_debug_code)
|
| + if (emit_debug_code())
|
| Check(cond, msg);
|
| }
|
|
|
|
|
| void MacroAssembler::AssertRegisterIsRoot(Register reg,
|
| Heap::RootListIndex index) {
|
| - if (FLAG_debug_code) {
|
| + if (emit_debug_code()) {
|
| LoadRoot(ip, index);
|
| cmp(reg, ip);
|
| Check(eq, "Register did not match expected root");
|
| @@ -2244,7 +2354,7 @@ void MacroAssembler::AssertRegisterIsRoot(Register reg,
|
|
|
|
|
| void MacroAssembler::AssertFastElements(Register elements) {
|
| - if (FLAG_debug_code) {
|
| + if (emit_debug_code()) {
|
| ASSERT(!elements.is(ip));
|
| Label ok;
|
| push(elements);
|
| @@ -2332,7 +2442,7 @@ void MacroAssembler::LoadContext(Register dst, int context_chain_length) {
|
| // (i.e., the static scope chain and runtime context chain do not agree).
|
| // A variable occurring in such a scope should have slot type LOOKUP and
|
| // not CONTEXT.
|
| - if (FLAG_debug_code) {
|
| + if (emit_debug_code()) {
|
| ldr(ip, MemOperand(dst, Context::SlotOffset(Context::FCONTEXT_INDEX)));
|
| cmp(dst, ip);
|
| Check(eq, "Yo dawg, I heard you liked function contexts "
|
| @@ -2357,7 +2467,7 @@ void MacroAssembler::LoadGlobalFunctionInitialMap(Register function,
|
| Register scratch) {
|
| // Load the initial map. The global functions all have initial maps.
|
| ldr(map, FieldMemOperand(function, JSFunction::kPrototypeOrInitialMapOffset));
|
| - if (FLAG_debug_code) {
|
| + if (emit_debug_code()) {
|
| Label ok, fail;
|
| CheckMap(map, scratch, Heap::kMetaMapRootIndex, &fail, false);
|
| b(&ok);
|
| @@ -2565,7 +2675,7 @@ void MacroAssembler::CopyBytes(Register src,
|
|
|
| // Copy bytes in word size chunks.
|
| bind(&word_loop);
|
| - if (FLAG_debug_code) {
|
| + if (emit_debug_code()) {
|
| tst(src, Operand(kPointerSize - 1));
|
| Assert(eq, "Expecting alignment for CopyBytes");
|
| }
|
| @@ -2725,7 +2835,7 @@ void MacroAssembler::CallCFunctionHelper(Register function,
|
| // running in the simulator. The simulator has its own alignment check which
|
| // provides more information.
|
| #if defined(V8_HOST_ARCH_ARM)
|
| - if (FLAG_debug_code) {
|
| + if (emit_debug_code()) {
|
| int frame_alignment = OS::ActivationFrameAlignment();
|
| int frame_alignment_mask = frame_alignment - 1;
|
| if (frame_alignment > kPointerSize) {
|
| @@ -2764,7 +2874,7 @@ void MacroAssembler::GetRelocatedValueLocation(Register ldr_location,
|
| const uint32_t kLdrOffsetMask = (1 << 12) - 1;
|
| const int32_t kPCRegOffset = 2 * kPointerSize;
|
| ldr(result, MemOperand(ldr_location));
|
| - if (FLAG_debug_code) {
|
| + if (emit_debug_code()) {
|
| // Check that the instruction is a ldr reg, [pc + offset] .
|
| and_(result, result, Operand(kLdrPCPattern));
|
| cmp(result, Operand(kLdrPCPattern));
|
|
|