macro-assembler-arm.h 63.4 KB
Newer Older
1
// Copyright 2012 the V8 project authors. All rights reserved.
2 3
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
4

5 6
#ifndef V8_ARM_MACRO_ASSEMBLER_ARM_H_
#define V8_ARM_MACRO_ASSEMBLER_ARM_H_
7

8
#include "src/assembler.h"
9
#include "src/bailout-reason.h"
10 11
#include "src/frames.h"
#include "src/globals.h"
12

13 14
namespace v8 {
namespace internal {
15

16 17 18 19 20
// Give alias names to registers for calling conventions.
const Register kReturnRegister0 = {kRegister_r0_Code};
const Register kReturnRegister1 = {kRegister_r1_Code};
const Register kJSFunctionRegister = {kRegister_r1_Code};
const Register kContextRegister = {kRegister_r7_Code};
21 22
const Register kInterpreterAccumulatorRegister = {kRegister_r0_Code};
const Register kInterpreterRegisterFileRegister = {kRegister_r4_Code};
23 24 25 26 27 28
const Register kInterpreterBytecodeOffsetRegister = {kRegister_r5_Code};
const Register kInterpreterBytecodeArrayRegister = {kRegister_r6_Code};
const Register kInterpreterDispatchTableRegister = {kRegister_r8_Code};
const Register kRuntimeCallFunctionRegister = {kRegister_r1_Code};
const Register kRuntimeCallArgCountRegister = {kRegister_r0_Code};

29 30 31 32
// ----------------------------------------------------------------------------
// Static helper functions

// Generate a MemOperand for loading a field from an object.
33
inline MemOperand FieldMemOperand(Register object, int offset) {
34 35 36
  return MemOperand(object, offset - kHeapObjectTag);
}

37 38

// Give alias names to registers
39 40
const Register cp = { kRegister_r7_Code };  // JavaScript context pointer.
const Register pp = { kRegister_r8_Code };  // Constant pool pointer.
41
const Register kRootRegister = { kRegister_r10_Code };  // Roots array pointer.
42

43 44 45 46 47 48 49
// Flags used for AllocateHeapNumber
enum TaggingMode {
  // Tag the result.
  TAG_RESULT,
  // Don't tag
  DONT_TAG_RESULT
};
50

51

52 53
enum RememberedSetAction { EMIT_REMEMBERED_SET, OMIT_REMEMBERED_SET };
enum SmiCheck { INLINE_SMI_CHECK, OMIT_SMI_CHECK };
54 55 56 57
enum PointersToHereCheck {
  kPointersToHereMaybeInteresting,
  kPointersToHereAreAlwaysInteresting
};
58 59 60
enum LinkRegisterStatus { kLRHasNotBeenSaved, kLRHasBeenSaved };


61 62 63 64 65 66 67 68
Register GetRegisterThatIsNotOneOf(Register reg1,
                                   Register reg2 = no_reg,
                                   Register reg3 = no_reg,
                                   Register reg4 = no_reg,
                                   Register reg5 = no_reg,
                                   Register reg6 = no_reg);


69 70 71 72 73 74
#ifdef DEBUG
bool AreAliased(Register reg1,
                Register reg2,
                Register reg3 = no_reg,
                Register reg4 = no_reg,
                Register reg5 = no_reg,
75 76 77
                Register reg6 = no_reg,
                Register reg7 = no_reg,
                Register reg8 = no_reg);
78
#endif
79 80


81 82 83 84 85
enum TargetAddressStorageMode {
  CAN_INLINE_TARGET_ADDRESS,
  NEVER_INLINE_TARGET_ADDRESS
};

86 87 88
// MacroAssembler implements a collection of frequently used macros.
class MacroAssembler: public Assembler {
 public:
89 90 91 92 93
  // The isolate parameter can be NULL if the macro assembler should
  // not use isolate-dependent functionality. In this case, it's the
  // responsibility of the caller to never invoke such function on the
  // macro assembler.
  MacroAssembler(Isolate* isolate, void* buffer, int size);
94

95 96 97 98

  // Returns the size of a call in instructions. Note, the value returned is
  // only valid as long as no entries are added to the constant pool between
  // checking the call size and emitting the actual call.
99
  static int CallSize(Register target, Condition cond = al);
100
  int CallSize(Address target, RelocInfo::Mode rmode, Condition cond = al);
101 102 103
  int CallStubSize(CodeStub* stub,
                   TypeFeedbackId ast_id = TypeFeedbackId::None(),
                   Condition cond = al);
104 105
  static int CallSizeNotPredictableCodeSize(Isolate* isolate,
                                            Address target,
106 107
                                            RelocInfo::Mode rmode,
                                            Condition cond = al);
108 109 110 111 112 113

  // Jump, Call, and Ret pseudo instructions implementing inter-working.
  void Jump(Register target, Condition cond = al);
  void Jump(Address target, RelocInfo::Mode rmode, Condition cond = al);
  void Jump(Handle<Code> code, RelocInfo::Mode rmode, Condition cond = al);
  void Call(Register target, Condition cond = al);
114 115 116
  void Call(Address target, RelocInfo::Mode rmode,
            Condition cond = al,
            TargetAddressStorageMode mode = CAN_INLINE_TARGET_ADDRESS);
117 118 119 120
  int CallSize(Handle<Code> code,
               RelocInfo::Mode rmode = RelocInfo::CODE_TARGET,
               TypeFeedbackId ast_id = TypeFeedbackId::None(),
               Condition cond = al);
121
  void Call(Handle<Code> code,
122
            RelocInfo::Mode rmode = RelocInfo::CODE_TARGET,
123
            TypeFeedbackId ast_id = TypeFeedbackId::None(),
124 125
            Condition cond = al,
            TargetAddressStorageMode mode = CAN_INLINE_TARGET_ADDRESS);
126
  void Ret(Condition cond = al);
127 128 129 130 131

  // Emit code to discard a non-negative number of pointer-sized elements
  // from the stack, clobbering only the sp register.
  void Drop(int count, Condition cond = al);

132
  void Ret(int drop, Condition cond = al);
133 134 135

  // Swap two registers.  If the scratch register is omitted then a slightly
  // less efficient form using xor instead of mov is emitted.
136 137 138 139
  void Swap(Register reg1,
            Register reg2,
            Register scratch = no_reg,
            Condition cond = al);
140

141 142
  void Mls(Register dst, Register src1, Register src2, Register srcA,
           Condition cond = al);
143 144 145 146 147 148
  void And(Register dst, Register src1, const Operand& src2,
           Condition cond = al);
  void Ubfx(Register dst, Register src, int lsb, int width,
            Condition cond = al);
  void Sbfx(Register dst, Register src, int lsb, int width,
            Condition cond = al);
149 150 151 152 153 154 155 156 157
  // The scratch register is not used for ARMv7.
  // scratch can be the same register as src (in which case it is trashed), but
  // not the same as dst.
  void Bfi(Register dst,
           Register src,
           Register scratch,
           int lsb,
           int width,
           Condition cond = al);
158
  void Bfc(Register dst, Register src, int lsb, int width, Condition cond = al);
159 160
  void Usat(Register dst, int satpos, const Operand& src,
            Condition cond = al);
161

162
  void Call(Label* target);
163 164
  void Push(Register src) { push(src); }
  void Pop(Register dst) { pop(dst); }
165 166

  // Register move. May do nothing if the registers are identical.
167
  void Move(Register dst, Handle<Object> value);
168
  void Move(Register dst, Register src, Condition cond = al);
169 170 171 172 173
  void Move(Register dst, const Operand& src, SBit sbit = LeaveCC,
            Condition cond = al) {
    if (!src.is_reg() || !src.rm().is(dst) || sbit != LeaveCC) {
      mov(dst, src, sbit, cond);
    }
174
  }
175
  void Move(DwVfpRegister dst, DwVfpRegister src);
176

177 178 179
  void Load(Register dst, const MemOperand& src, Representation r);
  void Store(Register src, const MemOperand& dst, Representation r);

180 181 182 183
  // Load an object from the root table.
  void LoadRoot(Register destination,
                Heap::RootListIndex index,
                Condition cond = al);
184 185 186 187
  // Store an object to the root table.
  void StoreRoot(Register source,
                 Heap::RootListIndex index,
                 Condition cond = al);
188

189 190
  // ---------------------------------------------------------------------------
  // GC Support
191

192 193 194
  void IncrementalMarkingRecordWriteHelper(Register object,
                                           Register value,
                                           Register address);
195

196 197 198 199
  enum RememberedSetFinalAction {
    kReturnAtEnd,
    kFallThroughAtEnd
  };
200

201 202 203
  // Record in the remembered set the fact that we have a pointer to new space
  // at the address pointed to by the addr register.  Only works if addr is not
  // in new space.
204 205
  void RememberedSetHelper(Register object,  // Used for debug code.
                           Register addr,
206 207 208 209 210 211 212 213 214 215 216
                           Register scratch,
                           SaveFPRegsMode save_fp,
                           RememberedSetFinalAction and_then);

  void CheckPageFlag(Register object,
                     Register scratch,
                     int mask,
                     Condition cc,
                     Label* condition_met);

  // Check if object is in new space.  Jumps if the object is not in new space.
217
  // The register scratch can be object itself, but scratch will be clobbered.
218 219 220 221 222
  void JumpIfNotInNewSpace(Register object,
                           Register scratch,
                           Label* branch) {
    InNewSpace(object, scratch, ne, branch);
  }
223

224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240
  // Check if object is in new space.  Jumps if the object is in new space.
  // The register scratch can be object itself, but it will be clobbered.
  void JumpIfInNewSpace(Register object,
                        Register scratch,
                        Label* branch) {
    InNewSpace(object, scratch, eq, branch);
  }

  // Check if an object has a given incremental marking color.
  void HasColor(Register object,
                Register scratch0,
                Register scratch1,
                Label* has_color,
                int first_bit,
                int second_bit);

  void JumpIfBlack(Register object,
241
                   Register scratch0,
242 243 244 245 246 247 248 249 250 251 252 253 254
                   Register scratch1,
                   Label* on_black);

  // Checks the color of an object.  If the object is already grey or black
  // then we just fall through, since it is already live.  If it is white and
  // we can determine that it doesn't need to be scanned, then we just mark it
  // black and fall through.  For the rest we jump to the label so the
  // incremental marker can fix its assumptions.
  void EnsureNotWhite(Register object,
                      Register scratch1,
                      Register scratch2,
                      Register scratch3,
                      Label* object_is_white_and_not_data);
255

256
  // Detects conservatively whether an object is data-only, i.e. it does need to
257 258 259 260 261 262 263 264 265
  // be scanned by the garbage collector.
  void JumpIfDataObject(Register value,
                        Register scratch,
                        Label* not_data_object);

  // Notify the garbage collector that we wrote a pointer into an object.
  // |object| is the object being stored into, |value| is the object being
  // stored.  value and scratch registers are clobbered by the operation.
  // The offset is the offset from the start of the object, not the offset from
266
  // the tagged HeapObject pointer.  For use with FieldMemOperand(reg, off).
267 268 269 270 271 272 273 274
  void RecordWriteField(
      Register object,
      int offset,
      Register value,
      Register scratch,
      LinkRegisterStatus lr_status,
      SaveFPRegsMode save_fp,
      RememberedSetAction remembered_set_action = EMIT_REMEMBERED_SET,
275 276 277
      SmiCheck smi_check = INLINE_SMI_CHECK,
      PointersToHereCheck pointers_to_here_check_for_value =
          kPointersToHereMaybeInteresting);
278 279 280 281 282 283 284 285 286 287 288

  // As above, but the offset has the tag presubtracted.  For use with
  // MemOperand(reg, off).
  inline void RecordWriteContextSlot(
      Register context,
      int offset,
      Register value,
      Register scratch,
      LinkRegisterStatus lr_status,
      SaveFPRegsMode save_fp,
      RememberedSetAction remembered_set_action = EMIT_REMEMBERED_SET,
289 290 291
      SmiCheck smi_check = INLINE_SMI_CHECK,
      PointersToHereCheck pointers_to_here_check_for_value =
          kPointersToHereMaybeInteresting) {
292 293 294 295 296 297 298
    RecordWriteField(context,
                     offset + kHeapObjectTag,
                     value,
                     scratch,
                     lr_status,
                     save_fp,
                     remembered_set_action,
299 300
                     smi_check,
                     pointers_to_here_check_for_value);
301 302
  }

303 304 305 306 307 308 309
  void RecordWriteForMap(
      Register object,
      Register map,
      Register dst,
      LinkRegisterStatus lr_status,
      SaveFPRegsMode save_fp);

310 311 312 313 314 315 316 317 318 319
  // For a given |object| notify the garbage collector that the slot |address|
  // has been written.  |value| is the object being stored. The value and
  // address registers are clobbered by the operation.
  void RecordWrite(
      Register object,
      Register address,
      Register value,
      LinkRegisterStatus lr_status,
      SaveFPRegsMode save_fp,
      RememberedSetAction remembered_set_action = EMIT_REMEMBERED_SET,
320 321 322
      SmiCheck smi_check = INLINE_SMI_CHECK,
      PointersToHereCheck pointers_to_here_check_for_value =
          kPointersToHereMaybeInteresting);
323

324 325
  // Push a handle.
  void Push(Handle<Object> handle);
326
  void Push(Smi* smi) { Push(Handle<Smi>(smi, isolate())); }
327

328 329
  // Push two registers.  Pushes leftmost register first (to highest address).
  void Push(Register src1, Register src2, Condition cond = al) {
330
    DCHECK(!src1.is(src2));
331 332 333 334 335 336 337 338 339 340
    if (src1.code() > src2.code()) {
      stm(db_w, sp, src1.bit() | src2.bit(), cond);
    } else {
      str(src1, MemOperand(sp, 4, NegPreIndex), cond);
      str(src2, MemOperand(sp, 4, NegPreIndex), cond);
    }
  }

  // Push three registers.  Pushes leftmost register first (to highest address).
  void Push(Register src1, Register src2, Register src3, Condition cond = al) {
341
    DCHECK(!AreAliased(src1, src2, src3));
342 343 344 345 346 347 348 349 350 351 352 353 354 355
    if (src1.code() > src2.code()) {
      if (src2.code() > src3.code()) {
        stm(db_w, sp, src1.bit() | src2.bit() | src3.bit(), cond);
      } else {
        stm(db_w, sp, src1.bit() | src2.bit(), cond);
        str(src3, MemOperand(sp, 4, NegPreIndex), cond);
      }
    } else {
      str(src1, MemOperand(sp, 4, NegPreIndex), cond);
      Push(src2, src3, cond);
    }
  }

  // Push four registers.  Pushes leftmost register first (to highest address).
356 357 358 359 360
  void Push(Register src1,
            Register src2,
            Register src3,
            Register src4,
            Condition cond = al) {
361
    DCHECK(!AreAliased(src1, src2, src3, src4));
362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382
    if (src1.code() > src2.code()) {
      if (src2.code() > src3.code()) {
        if (src3.code() > src4.code()) {
          stm(db_w,
              sp,
              src1.bit() | src2.bit() | src3.bit() | src4.bit(),
              cond);
        } else {
          stm(db_w, sp, src1.bit() | src2.bit() | src3.bit(), cond);
          str(src4, MemOperand(sp, 4, NegPreIndex), cond);
        }
      } else {
        stm(db_w, sp, src1.bit() | src2.bit(), cond);
        Push(src3, src4, cond);
      }
    } else {
      str(src1, MemOperand(sp, 4, NegPreIndex), cond);
      Push(src2, src3, src4, cond);
    }
  }

383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412
  // Push five registers.  Pushes leftmost register first (to highest address).
  void Push(Register src1, Register src2, Register src3, Register src4,
            Register src5, Condition cond = al) {
    DCHECK(!AreAliased(src1, src2, src3, src4, src5));
    if (src1.code() > src2.code()) {
      if (src2.code() > src3.code()) {
        if (src3.code() > src4.code()) {
          if (src4.code() > src5.code()) {
            stm(db_w, sp,
                src1.bit() | src2.bit() | src3.bit() | src4.bit() | src5.bit(),
                cond);
          } else {
            stm(db_w, sp, src1.bit() | src2.bit() | src3.bit() | src4.bit(),
                cond);
            str(src5, MemOperand(sp, 4, NegPreIndex), cond);
          }
        } else {
          stm(db_w, sp, src1.bit() | src2.bit() | src3.bit(), cond);
          Push(src4, src5, cond);
        }
      } else {
        stm(db_w, sp, src1.bit() | src2.bit(), cond);
        Push(src3, src4, src5, cond);
      }
    } else {
      str(src1, MemOperand(sp, 4, NegPreIndex), cond);
      Push(src2, src3, src4, src5, cond);
    }
  }

413 414
  // Pop two registers. Pops rightmost register first (from lower address).
  void Pop(Register src1, Register src2, Condition cond = al) {
415
    DCHECK(!src1.is(src2));
416 417 418 419 420 421 422 423
    if (src1.code() > src2.code()) {
      ldm(ia_w, sp, src1.bit() | src2.bit(), cond);
    } else {
      ldr(src2, MemOperand(sp, 4, PostIndex), cond);
      ldr(src1, MemOperand(sp, 4, PostIndex), cond);
    }
  }

424 425
  // Pop three registers.  Pops rightmost register first (from lower address).
  void Pop(Register src1, Register src2, Register src3, Condition cond = al) {
426
    DCHECK(!AreAliased(src1, src2, src3));
427 428 429 430 431 432 433 434 435
    if (src1.code() > src2.code()) {
      if (src2.code() > src3.code()) {
        ldm(ia_w, sp, src1.bit() | src2.bit() | src3.bit(), cond);
      } else {
        ldr(src3, MemOperand(sp, 4, PostIndex), cond);
        ldm(ia_w, sp, src1.bit() | src2.bit(), cond);
      }
    } else {
      Pop(src2, src3, cond);
436
      ldr(src1, MemOperand(sp, 4, PostIndex), cond);
437 438 439 440 441 442 443 444 445
    }
  }

  // Pop four registers.  Pops rightmost register first (from lower address).
  void Pop(Register src1,
           Register src2,
           Register src3,
           Register src4,
           Condition cond = al) {
446
    DCHECK(!AreAliased(src1, src2, src3, src4));
447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467
    if (src1.code() > src2.code()) {
      if (src2.code() > src3.code()) {
        if (src3.code() > src4.code()) {
          ldm(ia_w,
              sp,
              src1.bit() | src2.bit() | src3.bit() | src4.bit(),
              cond);
        } else {
          ldr(src4, MemOperand(sp, 4, PostIndex), cond);
          ldm(ia_w, sp, src1.bit() | src2.bit() | src3.bit(), cond);
        }
      } else {
        Pop(src3, src4, cond);
        ldm(ia_w, sp, src1.bit() | src2.bit(), cond);
      }
    } else {
      Pop(src2, src3, src4, cond);
      ldr(src1, MemOperand(sp, 4, PostIndex), cond);
    }
  }

468
  // Push a fixed frame, consisting of lr, fp, constant pool (if
469
  // FLAG_enable_embedded_constant_pool), context and JS function / marker id if
470 471 472 473
  // marker_reg is a valid register.
  void PushFixedFrame(Register marker_reg = no_reg);
  void PopFixedFrame(Register marker_reg = no_reg);

474 475 476 477
  // Push and pop the registers that can hold pointers, as defined by the
  // RegList constant kSafepointSavedRegisters.
  void PushSafepointRegisters();
  void PopSafepointRegisters();
478 479 480 481 482 483
  // Store value in register src in the safepoint stack slot for
  // register dst.
  void StoreToSafepointRegisterSlot(Register src, Register dst);
  // Load the value of the src register from its safepoint stack slot
  // into register dst.
  void LoadFromSafepointRegisterSlot(Register dst, Register src);
484

485 486 487 488 489 490 491 492 493 494 495 496
  // Load two consecutive registers with two consecutive memory locations.
  void Ldrd(Register dst1,
            Register dst2,
            const MemOperand& src,
            Condition cond = al);

  // Store two consecutive registers to two consecutive memory locations.
  void Strd(Register src1,
            Register src2,
            const MemOperand& dst,
            Condition cond = al);

497 498 499 500 501 502 503 504 505 506
  // Ensure that FPSCR contains values needed by JavaScript.
  // We need the NaNModeControlBit to be sure that operations like
  // vadd and vsub generate the Canonical NaN (if a NaN must be generated).
  // In VFP3 it will be always the Canonical NaN.
  // In VFP2 it will be either the Canonical NaN or the negative version
  // of the Canonical NaN. It doesn't matter if we have two values. The aim
  // is to be sure to never generate the hole NaN.
  void VFPEnsureFPSCRState(Register scratch);

  // If the value is a NaN, canonicalize the value else, do nothing.
507 508
  void VFPCanonicalizeNaN(const DwVfpRegister dst,
                          const DwVfpRegister src,
509
                          const Condition cond = al);
510 511 512 513
  void VFPCanonicalizeNaN(const DwVfpRegister value,
                          const Condition cond = al) {
    VFPCanonicalizeNaN(value, value, cond);
  }
514

515 516 517 518 519 520
  // Compare single values and move the result to the normal condition flags.
  void VFPCompareAndSetFlags(const SwVfpRegister src1, const SwVfpRegister src2,
                             const Condition cond = al);
  void VFPCompareAndSetFlags(const SwVfpRegister src1, const float src2,
                             const Condition cond = al);

521 522 523 524 525 526 527 528
  // Compare double values and move the result to the normal condition flags.
  void VFPCompareAndSetFlags(const DwVfpRegister src1,
                             const DwVfpRegister src2,
                             const Condition cond = al);
  void VFPCompareAndSetFlags(const DwVfpRegister src1,
                             const double src2,
                             const Condition cond = al);

529 530 531 532 533 534 535 536 537
  // Compare single values and then load the fpscr flags to a register.
  void VFPCompareAndLoadFlags(const SwVfpRegister src1,
                              const SwVfpRegister src2,
                              const Register fpscr_flags,
                              const Condition cond = al);
  void VFPCompareAndLoadFlags(const SwVfpRegister src1, const float src2,
                              const Register fpscr_flags,
                              const Condition cond = al);

538 539 540 541 542 543 544 545 546 547
  // Compare double values and then load the fpscr flags to a register.
  void VFPCompareAndLoadFlags(const DwVfpRegister src1,
                              const DwVfpRegister src2,
                              const Register fpscr_flags,
                              const Condition cond = al);
  void VFPCompareAndLoadFlags(const DwVfpRegister src1,
                              const double src2,
                              const Register fpscr_flags,
                              const Condition cond = al);

548 549
  void Vmov(const DwVfpRegister dst,
            const double imm,
550
            const Register scratch = no_reg);
551

552 553 554 555 556
  void VmovHigh(Register dst, DwVfpRegister src);
  void VmovHigh(DwVfpRegister dst, Register src);
  void VmovLow(Register dst, DwVfpRegister src);
  void VmovLow(DwVfpRegister dst, Register src);

557 558 559 560
  // Loads the number from object into dst register.
  // If |object| is neither smi nor heap number, |not_number| is jumped to
  // with |object| still intact.
  void LoadNumber(Register object,
561
                  LowDwVfpRegister dst,
562 563 564 565 566 567 568 569 570 571 572 573 574
                  Register heap_number_map,
                  Register scratch,
                  Label* not_number);

  // Loads the number from object into double_dst in the double format.
  // Control will jump to not_int32 if the value cannot be exactly represented
  // by a 32-bit integer.
  // Floating point value in the 32-bit integer range that are not exact integer
  // won't be loaded.
  void LoadNumberAsInt32Double(Register object,
                               DwVfpRegister double_dst,
                               Register heap_number_map,
                               Register scratch,
575
                               LowDwVfpRegister double_scratch,
576 577 578 579 580 581 582 583 584 585 586 587
                               Label* not_int32);

  // Loads the number from object into dst as a 32-bit integer.
  // Control will jump to not_int32 if the object cannot be exactly represented
  // by a 32-bit integer.
  // Floating point value in the 32-bit integer range that are not exact integer
  // won't be converted.
  void LoadNumberAsInt32(Register object,
                         Register dst,
                         Register heap_number_map,
                         Register scratch,
                         DwVfpRegister double_scratch0,
588
                         LowDwVfpRegister double_scratch1,
589 590
                         Label* not_int32);

591
  // Generates function and stub prologue code.
592 593
  void StubPrologue();
  void Prologue(bool code_pre_aging);
594

595
  // Enter exit frame.
596 597
  // stack_space - extra stack space, used for alignment before call to C.
  void EnterExitFrame(bool save_doubles, int stack_space = 0);
598 599

  // Leave the current exit frame. Expects the return value in r0.
600 601
  // Expect the number of values, pushed prior to the exit frame, to
  // remove in a register (or no_reg, if there is nothing to remove).
602 603 604
  void LeaveExitFrame(bool save_doubles, Register argument_count,
                      bool restore_context,
                      bool argument_count_is_length = false);
605

606 607
  // Get the actual activation frame alignment for target environment.
  static int ActivationFrameAlignment();
608

609 610
  void LoadContext(Register dst, int context_chain_length);

611
  // Conditionally load the cached Array transitioned map of type
612 613
  // transitioned_kind from the native context if the map in register
  // map_in_out is the cached Array map in the native context of
614 615 616 617 618 619 620 621
  // expected_kind.
  void LoadTransitionedArrayMapConditional(
      ElementsKind expected_kind,
      ElementsKind transitioned_kind,
      Register map_in_out,
      Register scratch,
      Label* no_map_match);

622 623 624 625 626 627 628 629
  void LoadGlobalFunction(int index, Register function);

  // Load the initial map from the global function. The registers
  // function and map can be the same, function is then overwritten.
  void LoadGlobalFunctionInitialMap(Register function,
                                    Register map,
                                    Register scratch);

630 631 632 633 634 635
  void InitializeRootRegister() {
    ExternalReference roots_array_start =
        ExternalReference::roots_array_start(isolate());
    mov(kRootRegister, Operand(roots_array_start));
  }

636 637 638 639 640 641 642
  // ---------------------------------------------------------------------------
  // JavaScript invokes

  // Invoke the JavaScript function code by either calling or jumping.
  void InvokeCode(Register code,
                  const ParameterCount& expected,
                  const ParameterCount& actual,
643
                  InvokeFlag flag,
644
                  const CallWrapper& call_wrapper);
645 646 647 648 649

  // Invoke the JavaScript function in the given register. Changes the
  // current context to the context in the function before invoking.
  void InvokeFunction(Register function,
                      const ParameterCount& actual,
650
                      InvokeFlag flag,
651
                      const CallWrapper& call_wrapper);
652 653 654 655 656

  void InvokeFunction(Register function,
                      const ParameterCount& expected,
                      const ParameterCount& actual,
                      InvokeFlag flag,
657
                      const CallWrapper& call_wrapper);
658

659
  void InvokeFunction(Handle<JSFunction> function,
660
                      const ParameterCount& expected,
661
                      const ParameterCount& actual,
662
                      InvokeFlag flag,
663
                      const CallWrapper& call_wrapper);
664

665 666 667 668 669 670 671 672 673 674 675 676
  void IsObjectJSObjectType(Register heap_object,
                            Register map,
                            Register scratch,
                            Label* fail);

  void IsInstanceJSObjectType(Register map,
                              Register scratch,
                              Label* fail);

  void IsObjectJSStringType(Register object,
                            Register scratch,
                            Label* fail);
677

678 679 680 681
  void IsObjectNameType(Register object,
                        Register scratch,
                        Label* fail);

682 683 684
  // ---------------------------------------------------------------------------
  // Debugger Support

serya@chromium.org's avatar
serya@chromium.org committed
685
  void DebugBreak();
686 687 688 689

  // ---------------------------------------------------------------------------
  // Exception handling

690 691
  // Push a new stack handler and link into stack handler chain.
  void PushStackHandler();
692

693
  // Unlink the stack handler on top of the stack from the stack handler chain.
694
  // Must preserve the result register.
695
  void PopStackHandler();
696 697 698 699 700 701 702

  // ---------------------------------------------------------------------------
  // Inline caching support

  // Generate code for checking access rights - used for security checks
  // on access to global objects across environments. The holder register
  // is left untouched, whereas both scratch registers are clobbered.
703 704 705
  void CheckAccessGlobalProxy(Register holder_reg,
                              Register scratch,
                              Label* miss);
706

707 708
  void GetNumberHash(Register t0, Register scratch);

709 710 711 712 713 714 715 716 717
  void LoadFromNumberDictionary(Label* miss,
                                Register elements,
                                Register key,
                                Register result,
                                Register t0,
                                Register t1,
                                Register t2);


718 719 720 721 722
  inline void MarkCode(NopMarkerTypes type) {
    nop(type);
  }

  // Check if the given instruction is a 'type' marker.
723
  // i.e. check if is is a mov r<type>, r<type> (referenced as nop(type))
724 725 726
  // These instructions are generated to mark special location in the code,
  // like some special IC code.
  static inline bool IsMarkedCode(Instr instr, int type) {
727
    DCHECK((FIRST_IC_MARKER <= type) && (type < LAST_CODE_MARKER));
728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746
    return IsNop(instr, type);
  }


  static inline int GetCodeMarker(Instr instr) {
    int dst_reg_offset = 12;
    int dst_mask = 0xf << dst_reg_offset;
    int src_mask = 0xf;
    int dst_reg = (instr & dst_mask) >> dst_reg_offset;
    int src_reg = instr & src_mask;
    uint32_t non_register_mask = ~(dst_mask | src_mask);
    uint32_t mov_mask = al | 13 << 21;

    // Return <n> if we have a mov rn rn, else return -1.
    int type = ((instr & non_register_mask) == mov_mask) &&
               (dst_reg == src_reg) &&
               (FIRST_IC_MARKER <= dst_reg) && (dst_reg < LAST_CODE_MARKER)
                   ? src_reg
                   : -1;
747
    DCHECK((type == -1) ||
748 749 750 751
           ((FIRST_IC_MARKER <= type) && (type < LAST_CODE_MARKER)));
    return type;
  }

752

753 754 755
  // ---------------------------------------------------------------------------
  // Allocation support

756
  // Allocate an object in new space or old space. The object_size is
757 758 759 760 761 762 763 764 765 766 767 768 769
  // specified either in bytes or in words if the allocation flag SIZE_IN_WORDS
  // is passed. If the space is exhausted control continues at the gc_required
  // label. The allocated object is returned in result. If the flag
  // tag_allocated_object is true the result is tagged as as a heap object.
  // All registers are clobbered also when control continues at the gc_required
  // label.
  void Allocate(int object_size,
                Register result,
                Register scratch1,
                Register scratch2,
                Label* gc_required,
                AllocationFlags flags);

770 771 772 773 774 775
  void Allocate(Register object_size,
                Register result,
                Register scratch1,
                Register scratch2,
                Label* gc_required,
                AllocationFlags flags);
776

777 778 779 780 781 782
  void AllocateTwoByteString(Register result,
                             Register length,
                             Register scratch1,
                             Register scratch2,
                             Register scratch3,
                             Label* gc_required);
783 784 785
  void AllocateOneByteString(Register result, Register length,
                             Register scratch1, Register scratch2,
                             Register scratch3, Label* gc_required);
786 787 788 789 790
  void AllocateTwoByteConsString(Register result,
                                 Register length,
                                 Register scratch1,
                                 Register scratch2,
                                 Label* gc_required);
791 792 793
  void AllocateOneByteConsString(Register result, Register length,
                                 Register scratch1, Register scratch2,
                                 Label* gc_required);
794 795 796 797 798
  void AllocateTwoByteSlicedString(Register result,
                                   Register length,
                                   Register scratch1,
                                   Register scratch2,
                                   Label* gc_required);
799 800 801
  void AllocateOneByteSlicedString(Register result, Register length,
                                   Register scratch1, Register scratch2,
                                   Label* gc_required);
802

803 804 805
  // Allocates a heap number or jumps to the gc_required label if the young
  // space is full and a scavenge is needed. All registers are clobbered also
  // when control continues at the gc_required label.
806 807 808
  void AllocateHeapNumber(Register result,
                          Register scratch1,
                          Register scratch2,
809
                          Register heap_number_map,
810
                          Label* gc_required,
811 812
                          TaggingMode tagging_mode = TAG_RESULT,
                          MutableMode mode = IMMUTABLE);
813 814 815 816 817 818 819
  void AllocateHeapNumberWithValue(Register result,
                                   DwVfpRegister value,
                                   Register scratch1,
                                   Register scratch2,
                                   Register heap_number_map,
                                   Label* gc_required);

820
  // Copies a fixed number of fields of heap objects from src to dst.
821 822
  void CopyFields(Register dst,
                  Register src,
823
                  LowDwVfpRegister double_scratch,
824
                  int field_count);
825

826 827 828 829 830 831 832 833
  // Copies a number of bytes from src to dst. All registers are clobbered. On
  // exit src and dst will point to the place just after where the last byte was
  // read or written and length will be zero.
  void CopyBytes(Register src,
                 Register dst,
                 Register length,
                 Register scratch);

834 835 836 837 838 839 840
  // Initialize fields with filler values.  Fields starting at |start_offset|
  // not including end_offset are overwritten with the value in |filler|.  At
  // the end the loop, |start_offset| takes the value of |end_offset|.
  void InitializeFieldsWithFiller(Register start_offset,
                                  Register end_offset,
                                  Register filler);

841 842 843
  // ---------------------------------------------------------------------------
  // Support functions.

844 845 846 847 848
  // Machine code version of Map::GetConstructor().
  // |temp| holds |result|'s map when done, and |temp2| its instance type.
  void GetMapConstructor(Register result, Register map, Register temp,
                         Register temp2);

849 850 851 852 853 854 855 856
  // Try to get function prototype of a function and puts the value in
  // the result register. Checks that the function really is a
  // function and jumps to the miss label if the fast checks fail. The
  // function register will be untouched; the other registers may be
  // clobbered.
  void TryGetFunctionPrototype(Register function,
                               Register result,
                               Register scratch,
857 858
                               Label* miss,
                               bool miss_on_bound_function = false);
859 860 861 862 863 864 865

  // Compare object type for heap object.  heap_object contains a non-Smi
  // whose object type should be compared with the given type.  This both
  // sets the flags and leaves the object type in the type_reg register.
  // It leaves the map in the map register (unless the type_reg and map register
  // are the same register).  It leaves the heap object in the heap_object
  // register unless the heap_object register is the same register as one of the
866
  // other registers.
867
  // Type_reg can be no_reg. In that case ip is used.
868 869 870 871 872
  void CompareObjectType(Register heap_object,
                         Register map,
                         Register type_reg,
                         InstanceType type);

873 874 875 876 877 878 879 880 881
  // Compare object type for heap object. Branch to false_label if type
  // is lower than min_type or greater than max_type.
  // Load map into the register map.
  void CheckObjectTypeRange(Register heap_object,
                            Register map,
                            InstanceType min_type,
                            InstanceType max_type,
                            Label* false_label);

882 883
  // Compare instance type in a map.  map contains a valid map object whose
  // object type should be compared with the given type.  This both
884
  // sets the flags and leaves the object type in the type_reg register.
885 886 887 888
  void CompareInstanceType(Register map,
                           Register type_reg,
                           InstanceType type);

889

890 891 892 893 894 895
  // Check if a map for a JSObject indicates that the object has fast elements.
  // Jump to the specified label if it does not.
  void CheckFastElements(Register map,
                         Register scratch,
                         Label* fail);

896 897 898 899 900 901 902 903
  // Check if a map for a JSObject indicates that the object can have both smi
  // and HeapObject elements.  Jump to the specified label if it does not.
  void CheckFastObjectElements(Register map,
                               Register scratch,
                               Label* fail);

  // Check if a map for a JSObject indicates that the object has fast smi only
  // elements.  Jump to the specified label if it does not.
904 905 906
  void CheckFastSmiElements(Register map,
                            Register scratch,
                            Label* fail);
907

908 909
  // Check to see if maybe_number can be stored as a double in
  // FastDoubleElements. If it can, store it at the index specified by key in
910
  // the FastDoubleElements array elements. Otherwise jump to fail.
911 912 913 914
  void StoreNumberToDoubleElements(Register value_reg,
                                   Register key_reg,
                                   Register elements_reg,
                                   Register scratch1,
915
                                   LowDwVfpRegister double_scratch,
916 917
                                   Label* fail,
                                   int elements_offset = 0);
918

919 920 921 922 923 924 925
  // Compare an object's map with the specified map and its transitioned
  // elements maps if mode is ALLOW_ELEMENT_TRANSITION_MAPS. Condition flags are
  // set with result of map compare. If multiple map compares are required, the
  // compare sequences branches to early_success.
  void CompareMap(Register obj,
                  Register scratch,
                  Handle<Map> map,
926
                  Label* early_success);
927

928 929 930 931
  // As above, but the map of the object is already loaded into the register
  // which is preserved by the code generated.
  void CompareMap(Register obj_map,
                  Handle<Map> map,
932
                  Label* early_success);
933

934 935 936
  // Check if the map of an object is equal to a specified map and branch to
  // label if not. Skip the smi check if not required (object is known to be a
  // heap object). If mode is ALLOW_ELEMENT_TRANSITION_MAPS, then also match
937
  // against maps that are ElementsKind transition maps of the specified map.
938 939 940 941
  void CheckMap(Register obj,
                Register scratch,
                Handle<Map> map,
                Label* fail,
942
                SmiCheckType smi_check_type);
943

danno@chromium.org's avatar
danno@chromium.org committed
944

945 946 947 948
  void CheckMap(Register obj,
                Register scratch,
                Heap::RootListIndex index,
                Label* fail,
949
                SmiCheckType smi_check_type);
950 951


952 953 954 955 956 957
  // Check if the map of an object is equal to a specified weak map and branch
  // to a specified target if equal. Skip the smi check if not required
  // (object is known to be a heap object)
  void DispatchWeakMap(Register obj, Register scratch1, Register scratch2,
                       Handle<WeakCell> cell, Handle<Code> success,
                       SmiCheckType smi_check_type);
danno@chromium.org's avatar
danno@chromium.org committed
958

959 960 961
  // Compare the given value and the value of weak cell.
  void CmpWeakValue(Register value, Handle<WeakCell> cell, Register scratch);

962 963
  void GetWeakValue(Register value, Handle<WeakCell> cell);

964 965 966
  // Load the value of the weak cell in the value register. Branch to the given
  // miss label if the weak cell was cleared.
  void LoadWeakValue(Register value, Handle<WeakCell> cell, Label* miss);
danno@chromium.org's avatar
danno@chromium.org committed
967

968 969 970 971 972
  // Compare the object in a register to a value from the root list.
  // Uses the ip register as scratch.
  void CompareRoot(Register obj, Heap::RootListIndex index);


973 974
  // Load and check the instance type of an object for being a string.
  // Loads the type into the second argument register.
975 976 977
  // Returns a condition that will be enabled if the object was a string
  // and the passed-in condition passed. If the passed-in condition failed
  // then flags remain unchanged.
978
  Condition IsObjectStringType(Register obj,
979 980 981 982 983
                               Register type,
                               Condition cond = al) {
    ldr(type, FieldMemOperand(obj, HeapObject::kMapOffset), cond);
    ldrb(type, FieldMemOperand(type, Map::kInstanceTypeOffset), cond);
    tst(type, Operand(kIsNotStringMask), cond);
984
    DCHECK_EQ(0u, kStringTag);
985 986 987 988
    return eq;
  }


989 990 991 992 993 994
  // Picks out an array index from the hash field.
  // Register use:
  //   hash - holds the index's hash. Clobbered.
  //   index - holds the overwritten index on exit.
  void IndexFromHash(Register hash, Register index);

995 996
  // Get the number of least significant bits from a register
  void GetLeastBitsFromSmi(Register dst, Register src, int num_least_bits);
997
  void GetLeastBitsFromInt32(Register dst, Register src, int mun_least_bits);
998

999 1000
  // Load the value of a smi object into a double register.
  // The register value must be between d0 and d15.
1001
  void SmiToDouble(LowDwVfpRegister value, Register smi);
1002

1003 1004 1005
  // Check if a double can be exactly represented as a signed 32-bit integer.
  // Z flag set to one if true.
  void TestDoubleIsInt32(DwVfpRegister double_input,
1006
                         LowDwVfpRegister double_scratch);
1007 1008 1009 1010 1011

  // Try to convert a double to a signed 32-bit integer.
  // Z flag set to one and result assigned if the conversion is exact.
  void TryDoubleToInt32Exact(Register result,
                             DwVfpRegister double_input,
1012
                             LowDwVfpRegister double_scratch);
1013 1014 1015 1016

  // Floor a double and writes the value to the result register.
  // Go to exact if the conversion is exact (to be able to test -0),
  // fall through calling code if an overflow occurred, else go to done.
1017
  // In return, input_high is loaded with high bits of input.
1018 1019 1020
  void TryInt32Floor(Register result,
                     DwVfpRegister double_input,
                     Register input_high,
1021
                     LowDwVfpRegister double_scratch,
1022 1023
                     Label* done,
                     Label* exact);
1024

1025 1026 1027 1028 1029 1030 1031 1032 1033 1034
  // Performs a truncating conversion of a floating point number as used by
  // the JS bitwise operations. See ECMA-262 9.5: ToInt32. Goes to 'done' if it
  // succeeds, otherwise falls through if result is saturated. On return
  // 'result' either holds answer, or is clobbered on fall through.
  //
  // Only public for the test code in test-code-stubs-arm.cc.
  void TryInlineTruncateDoubleToI(Register result,
                                  DwVfpRegister input,
                                  Label* done);

1035 1036
  // Performs a truncating conversion of a floating point number as used by
  // the JS bitwise operations. See ECMA-262 9.5: ToInt32.
1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053
  // Exits with 'result' holding the answer.
  void TruncateDoubleToI(Register result, DwVfpRegister double_input);

  // Performs a truncating conversion of a heap number as used by
  // the JS bitwise operations. See ECMA-262 9.5: ToInt32. 'result' and 'input'
  // must be different registers.  Exits with 'result' holding the answer.
  void TruncateHeapNumberToI(Register result, Register object);

  // Converts the smi or heap number in object to an int32 using the rules
  // for ToInt32 as described in ECMAScript 9.5.: the value is truncated
  // and brought into the range -2^31 .. +2^31 - 1. 'result' and 'input' must be
  // different registers.
  void TruncateNumberToI(Register object,
                         Register result,
                         Register heap_number_map,
                         Register scratch1,
                         Label* not_int32);
1054

1055 1056 1057 1058
  // Check whether d16-d31 are available on the CPU. The result is given by the
  // Z condition flag: Z==0 if d16-d31 available, Z==1 otherwise.
  void CheckFor32DRegs(Register scratch);

1059 1060 1061 1062 1063 1064 1065
  // Does a runtime check for 16/32 FP registers. Either way, pushes 32 double
  // values to location, saving [d0..(d15|d31)].
  void SaveFPRegs(Register location, Register scratch);

  // Does a runtime check for 16/32 FP registers. Either way, pops 32 double
  // values to location, restoring [d0..(d15|d31)].
  void RestoreFPRegs(Register location, Register scratch);
1066

1067 1068 1069 1070
  // ---------------------------------------------------------------------------
  // Runtime calls

  // Call a code stub.
1071 1072 1073
  void CallStub(CodeStub* stub,
                TypeFeedbackId ast_id = TypeFeedbackId::None(),
                Condition cond = al);
1074

1075 1076 1077
  // Call a code stub.
  void TailCallStub(CodeStub* stub, Condition cond = al);

1078
  // Call a runtime routine.
1079 1080 1081 1082 1083 1084 1085
  void CallRuntime(const Runtime::Function* f,
                   int num_arguments,
                   SaveFPRegsMode save_doubles = kDontSaveFPRegs);
  void CallRuntimeSaveDoubles(Runtime::FunctionId id) {
    const Runtime::Function* function = Runtime::FunctionForId(id);
    CallRuntime(function, function->nargs, kSaveFPRegs);
  }
1086 1087

  // Convenience function: Same as above, but takes the fid instead.
1088 1089 1090 1091
  void CallRuntime(Runtime::FunctionId id,
                   int num_arguments,
                   SaveFPRegsMode save_doubles = kDontSaveFPRegs) {
    CallRuntime(Runtime::FunctionForId(id), num_arguments, save_doubles);
1092
  }
1093

1094 1095 1096 1097
  // Convenience function: call an external reference.
  void CallExternalReference(const ExternalReference& ext,
                             int num_arguments);

1098
  // Tail call of a runtime routine (jump).
serya@chromium.org's avatar
serya@chromium.org committed
1099
  // Like JumpToExternalReference, but also takes care of passing the number
1100
  // of parameters.
serya@chromium.org's avatar
serya@chromium.org committed
1101 1102 1103 1104 1105 1106
  void TailCallExternalReference(const ExternalReference& ext,
                                 int num_arguments,
                                 int result_size);

  // Convenience function: tail call a runtime routine (jump).
  void TailCallRuntime(Runtime::FunctionId fid,
1107 1108
                       int num_arguments,
                       int result_size);
1109

1110 1111 1112
  int CalculateStackPassedWords(int num_reg_arguments,
                                int num_double_arguments);

1113 1114 1115
  // Before calling a C-function from generated code, align arguments on stack.
  // After aligning the frame, non-register arguments must be stored in
  // sp[0], sp[4], etc., not pushed. The argument count assumes all arguments
1116 1117 1118
  // are word sized. If double arguments are used, this function assumes that
  // all double arguments are stored before core registers; otherwise the
  // correct alignment of the double values is not guaranteed.
1119 1120 1121 1122
  // Some compilers/platforms require the stack to be aligned when calling
  // C++ code.
  // Needs a scratch register to do some arithmetic. This register will be
  // trashed.
1123 1124 1125 1126 1127 1128 1129 1130 1131 1132
  void PrepareCallCFunction(int num_reg_arguments,
                            int num_double_registers,
                            Register scratch);
  void PrepareCallCFunction(int num_reg_arguments,
                            Register scratch);

  // There are two ways of passing double arguments on ARM, depending on
  // whether soft or hard floating point ABI is used. These functions
  // abstract parameter passing for the three different ways we call
  // C functions from generated code.
1133 1134 1135
  void MovToFloatParameter(DwVfpRegister src);
  void MovToFloatParameters(DwVfpRegister src1, DwVfpRegister src2);
  void MovToFloatResult(DwVfpRegister src);
1136 1137 1138 1139 1140 1141 1142

  // Calls a C function and cleans up the space for arguments allocated
  // by PrepareCallCFunction. The called function is not allowed to trigger a
  // garbage collection, since that might move the code and invalidate the
  // return address (unless this is somehow accounted for by the called
  // function).
  void CallCFunction(ExternalReference function, int num_arguments);
1143
  void CallCFunction(Register function, int num_arguments);
1144 1145 1146
  void CallCFunction(ExternalReference function,
                     int num_reg_arguments,
                     int num_double_arguments);
1147
  void CallCFunction(Register function,
1148 1149
                     int num_reg_arguments,
                     int num_double_arguments);
1150

1151 1152
  void MovFromFloatParameter(DwVfpRegister dst);
  void MovFromFloatResult(DwVfpRegister dst);
1153

1154
  // Jump to a runtime routine.
serya@chromium.org's avatar
serya@chromium.org committed
1155
  void JumpToExternalReference(const ExternalReference& builtin);
1156 1157 1158

  // Invoke specified builtin JavaScript function. Adds an entry to
  // the unresolved list if the name does not resolve.
1159
  void InvokeBuiltin(Builtins::JavaScript id,
1160
                     InvokeFlag flag,
1161
                     const CallWrapper& call_wrapper = NullCallWrapper());
1162 1163 1164 1165

  // Store the code object for the given builtin in the target register and
  // setup the function in r1.
  void GetBuiltinEntry(Register target, Builtins::JavaScript id);
1166

1167 1168 1169
  // Store the function for the given builtin in the target register.
  void GetBuiltinFunction(Register target, Builtins::JavaScript id);

1170
  Handle<Object> CodeObject() {
1171
    DCHECK(!code_object_.is_null());
1172 1173
    return code_object_;
  }
1174

1175

1176
  // Emit code for a truncating division by a constant. The dividend register is
1177
  // unchanged and ip gets clobbered. Dividend and result must be different.
1178
  void TruncatingDiv(Register result, Register dividend, int32_t divisor);
1179

1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190
  // ---------------------------------------------------------------------------
  // StatsCounter support

  void SetCounter(StatsCounter* counter, int value,
                  Register scratch1, Register scratch2);
  void IncrementCounter(StatsCounter* counter, int value,
                        Register scratch1, Register scratch2);
  void DecrementCounter(StatsCounter* counter, int value,
                        Register scratch1, Register scratch2);


1191 1192 1193
  // ---------------------------------------------------------------------------
  // Debugging

1194
  // Calls Abort(msg) if the condition cond is not satisfied.
1195
  // Use --debug_code to enable.
1196
  void Assert(Condition cond, BailoutReason reason);
1197
  void AssertFastElements(Register elements);
1198 1199

  // Like Assert(), but always enabled.
1200
  void Check(Condition cond, BailoutReason reason);
1201 1202

  // Print a message to stdout and abort execution.
1203
  void Abort(BailoutReason msg);
1204 1205 1206 1207

  // Verify restrictions about code generated in stubs.
  void set_generating_stub(bool value) { generating_stub_ = value; }
  bool generating_stub() { return generating_stub_; }
1208 1209 1210
  void set_has_frame(bool value) { has_frame_ = value; }
  bool has_frame() { return has_frame_; }
  inline bool AllowThisStubCall(CodeStub* stub);
1211

1212 1213
  // EABI variant for double arguments in use.
  bool use_eabi_hardfloat() {
1214
#ifdef __arm__
1215
    return base::OS::ArmUsingHardFloat();
1216
#elif USE_EABI_HARDFLOAT
1217 1218 1219 1220 1221 1222
    return true;
#else
    return false;
#endif
  }

1223 1224 1225 1226 1227 1228 1229 1230 1231 1232
  // ---------------------------------------------------------------------------
  // Number utilities

  // Check whether the value of reg is a power of two and not zero. If not
  // control continues at the label not_power_of_two. If reg is a power of two
  // the register scratch contains the value of (reg - 1) when control falls
  // through.
  void JumpIfNotPowerOfTwoOrZero(Register reg,
                                 Register scratch,
                                 Label* not_power_of_two_or_zero);
1233 1234 1235 1236 1237 1238 1239 1240 1241 1242
  // Check whether the value of reg is a power of two and not zero.
  // Control falls through if it is, with scratch containing the mask
  // value (reg - 1).
  // Otherwise control jumps to the 'zero_and_neg' label if the value of reg is
  // zero or negative, or jumps to the 'not_power_of_two' label if the value is
  // strictly positive but not a power of two.
  void JumpIfNotPowerOfTwoOrZeroAndNeg(Register reg,
                                       Register scratch,
                                       Label* zero_and_neg,
                                       Label* not_power_of_two);
1243

1244 1245 1246
  // ---------------------------------------------------------------------------
  // Smi utilities

1247 1248 1249
  void SmiTag(Register reg, SBit s = LeaveCC) {
    add(reg, reg, Operand(reg), s);
  }
1250 1251 1252
  void SmiTag(Register dst, Register src, SBit s = LeaveCC) {
    add(dst, src, Operand(src), s);
  }
1253

1254 1255 1256
  // Try to convert int32 to smi. If the value is to large, preserve
  // the original value and jump to not_a_smi. Destroys scratch and
  // sets flags.
1257 1258 1259 1260 1261
  void TrySmiTag(Register reg, Label* not_a_smi) {
    TrySmiTag(reg, reg, not_a_smi);
  }
  void TrySmiTag(Register reg, Register src, Label* not_a_smi) {
    SmiTag(ip, src, SetCC);
1262
    b(vs, not_a_smi);
1263
    mov(reg, ip);
1264 1265
  }

1266

1267
  void SmiUntag(Register reg, SBit s = LeaveCC) {
1268
    mov(reg, Operand::SmiUntag(reg), s);
1269
  }
1270
  void SmiUntag(Register dst, Register src, SBit s = LeaveCC) {
1271
    mov(dst, Operand::SmiUntag(src), s);
1272
  }
1273

1274 1275 1276 1277 1278 1279 1280 1281
  // Untag the source value into destination and jump if source is a smi.
  // Souce and destination can be the same register.
  void UntagAndJumpIfSmi(Register dst, Register src, Label* smi_case);

  // Untag the source value into destination and jump if source is not a smi.
  // Souce and destination can be the same register.
  void UntagAndJumpIfNotSmi(Register dst, Register src, Label* non_smi_case);

1282 1283 1284 1285 1286 1287 1288
  // Test if the register contains a smi (Z == 0 (eq) if true).
  inline void SmiTst(Register value) {
    tst(value, Operand(kSmiTagMask));
  }
  inline void NonNegativeSmiTst(Register value) {
    tst(value, Operand(kSmiTagMask | kSmiSignMask));
  }
1289
  // Jump if the register contains a smi.
1290 1291 1292 1293 1294 1295 1296 1297 1298
  inline void JumpIfSmi(Register value, Label* smi_label) {
    tst(value, Operand(kSmiTagMask));
    b(eq, smi_label);
  }
  // Jump if either of the registers contain a non-smi.
  inline void JumpIfNotSmi(Register value, Label* not_smi_label) {
    tst(value, Operand(kSmiTagMask));
    b(ne, not_smi_label);
  }
1299 1300 1301 1302 1303
  // Jump if either of the registers contain a non-smi.
  void JumpIfNotBothSmi(Register reg1, Register reg2, Label* on_not_both_smi);
  // Jump if either of the registers contain a smi.
  void JumpIfEitherSmi(Register reg1, Register reg2, Label* on_either_smi);

1304 1305 1306 1307
  // Abort execution if argument is a smi, enabled via --debug-code.
  void AssertNotSmi(Register object);
  void AssertSmi(Register object);

1308
  // Abort execution if argument is not a string, enabled via --debug-code.
1309 1310
  void AssertString(Register object);

1311 1312 1313
  // Abort execution if argument is not a name, enabled via --debug-code.
  void AssertName(Register object);

1314 1315 1316 1317
  // Abort execution if argument is not undefined or an AllocationSite, enabled
  // via --debug-code.
  void AssertUndefinedOrAllocationSite(Register object, Register scratch);

1318
  // Abort execution if reg is not the root value with the given index,
1319
  // enabled via --debug-code.
1320
  void AssertIsRoot(Register reg, Heap::RootListIndex index);
1321

1322 1323 1324 1325 1326 1327 1328 1329
  // ---------------------------------------------------------------------------
  // HeapNumber utilities

  void JumpIfNotHeapNumber(Register object,
                           Register heap_number_map,
                           Register scratch,
                           Label* on_not_heap_number);

1330 1331 1332
  // ---------------------------------------------------------------------------
  // String utilities

1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344
  // Generate code to do a lookup in the number string cache. If the number in
  // the register object is found in the cache the generated code falls through
  // with the result in the result register. The object and the result register
  // can be the same. If the number is not found in the cache the code jumps to
  // the label not_found with only the content of register object unchanged.
  void LookupNumberStringCache(Register object,
                               Register result,
                               Register scratch1,
                               Register scratch2,
                               Register scratch3,
                               Label* not_found);

1345
  // Checks if both objects are sequential one-byte strings and jumps to label
1346
  // if either is not. Assumes that neither object is a smi.
1347 1348 1349 1350 1351
  void JumpIfNonSmisNotBothSequentialOneByteStrings(Register object1,
                                                    Register object2,
                                                    Register scratch1,
                                                    Register scratch2,
                                                    Label* failure);
1352

1353
  // Checks if both objects are sequential one-byte strings and jumps to label
1354
  // if either is not.
1355 1356 1357 1358
  void JumpIfNotBothSequentialOneByteStrings(Register first, Register second,
                                             Register scratch1,
                                             Register scratch2,
                                             Label* not_flat_one_byte_strings);
1359

1360
  // Checks if both instance types are sequential one-byte strings and jumps to
1361
  // label if either is not.
1362 1363 1364 1365 1366
  void JumpIfBothInstanceTypesAreNotSequentialOneByte(
      Register first_object_instance_type, Register second_object_instance_type,
      Register scratch1, Register scratch2, Label* failure);

  // Check if instance type is sequential one-byte string and jump to label if
1367
  // it is not.
1368 1369
  void JumpIfInstanceTypeIsNotSequentialOneByte(Register type, Register scratch,
                                                Label* failure);
1370

1371
  void JumpIfNotUniqueNameInstanceType(Register reg, Label* not_unique_name);
1372

1373 1374 1375 1376 1377
  void EmitSeqStringSetCharCheck(Register string,
                                 Register index,
                                 Register value,
                                 uint32_t encoding_mask);

1378 1379 1380 1381 1382
  // ---------------------------------------------------------------------------
  // Patching helpers.

  // Get the location of a relocated constant (its address in the constant pool)
  // from its load site.
1383 1384
  void GetRelocatedValueLocation(Register ldr_location, Register result,
                                 Register scratch);
1385 1386


1387 1388 1389
  void ClampUint8(Register output_reg, Register input_reg);

  void ClampDoubleToUint8(Register result_reg,
1390
                          DwVfpRegister input_reg,
1391
                          LowDwVfpRegister double_scratch);
1392 1393


1394
  void LoadInstanceDescriptors(Register map, Register descriptors);
1395
  void EnumLength(Register dst, Register map);
1396
  void NumberOfOwnDescriptors(Register dst, Register map);
1397 1398
  void LoadAccessor(Register dst, Register holder, int accessor_index,
                    AccessorComponent accessor);
1399 1400

  template<typename Field>
1401
  void DecodeField(Register dst, Register src) {
1402 1403 1404 1405 1406 1407 1408 1409 1410 1411
    Ubfx(dst, src, Field::kShift, Field::kSize);
  }

  template<typename Field>
  void DecodeField(Register reg) {
    DecodeField<Field>(reg, reg);
  }

  template<typename Field>
  void DecodeFieldToSmi(Register dst, Register src) {
1412
    static const int shift = Field::kShift;
1413 1414 1415 1416 1417 1418 1419 1420
    static const int mask = Field::kMask >> shift << kSmiTagSize;
    STATIC_ASSERT((mask & (0x80000000u >> (kSmiTagSize - 1))) == 0);
    STATIC_ASSERT(kSmiTag == 0);
    if (shift < kSmiTagSize) {
      mov(dst, Operand(src, LSL, kSmiTagSize - shift));
      and_(dst, dst, Operand(mask));
    } else if (shift > kSmiTagSize) {
      mov(dst, Operand(src, LSR, shift - kSmiTagSize));
1421
      and_(dst, dst, Operand(mask));
1422 1423
    } else {
      and_(dst, src, Operand(mask));
1424 1425 1426 1427
    }
  }

  template<typename Field>
1428
  void DecodeFieldToSmi(Register reg) {
1429
    DecodeField<Field>(reg, reg);
1430
  }
1431

1432
  // Activation support.
1433 1434
  void EnterFrame(StackFrame::Type type,
                  bool load_constant_pool_pointer_reg = false);
1435 1436
  // Returns the pc offset at which the frame ends.
  int LeaveFrame(StackFrame::Type type);
1437

1438 1439 1440 1441
  // Expects object in r0 and returns map with validated enum cache
  // in r0.  Assumes that any other register can be used as a scratch.
  void CheckEnumCache(Register null_value, Label* call_runtime);

1442 1443
  // AllocationMemento support. Arrays may have an associated
  // AllocationMemento object that can be checked for in order to pretransition
1444 1445 1446
  // to another type.
  // On entry, receiver_reg should point to the array object.
  // scratch_reg gets clobbered.
1447
  // If allocation info is present, condition flags are set to eq.
1448
  void TestJSArrayForAllocationMemento(Register receiver_reg,
1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460
                                       Register scratch_reg,
                                       Label* no_memento_found);

  void JumpIfJSArrayHasAllocationMemento(Register receiver_reg,
                                         Register scratch_reg,
                                         Label* memento_found) {
    Label no_memento_found;
    TestJSArrayForAllocationMemento(receiver_reg, scratch_reg,
                                    &no_memento_found);
    b(eq, memento_found);
    bind(&no_memento_found);
  }
1461

1462 1463 1464 1465
  // Jumps to found label if a prototype map has dictionary elements.
  void JumpIfDictionaryInPrototypeChain(Register object, Register scratch0,
                                        Register scratch1, Label* found);

1466 1467 1468 1469 1470
  // Loads the constant pool pointer (pp) register.
  void LoadConstantPoolPointerRegisterFromCodeTargetAddress(
      Register code_target_address);
  void LoadConstantPoolPointerRegister();

1471
 private:
1472
  void CallCFunctionHelper(Register function,
1473 1474
                           int num_reg_arguments,
                           int num_double_arguments);
1475

1476
  void Jump(intptr_t target, RelocInfo::Mode rmode, Condition cond = al);
1477 1478 1479 1480 1481 1482 1483

  // Helper functions for generating invokes.
  void InvokePrologue(const ParameterCount& expected,
                      const ParameterCount& actual,
                      Handle<Code> code_constant,
                      Register code_reg,
                      Label* done,
1484
                      bool* definitely_mismatches,
1485
                      InvokeFlag flag,
1486
                      const CallWrapper& call_wrapper);
1487

1488 1489 1490 1491 1492 1493
  void InitializeNewString(Register string,
                           Register length,
                           Heap::RootListIndex map_index,
                           Register scratch1,
                           Register scratch2);

1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506
  // Helper for implementing JumpIfNotInNewSpace and JumpIfInNewSpace.
  void InNewSpace(Register object,
                  Register scratch,
                  Condition cond,  // eq for new space, ne otherwise.
                  Label* branch);

  // Helper for finding the mark bits for an address.  Afterwards, the
  // bitmap register points at the word with the mark bits and the mask
  // the position of the first bit.  Leaves addr_reg unchanged.
  inline void GetMarkBits(Register addr_reg,
                          Register bitmap_reg,
                          Register mask_reg);

1507 1508 1509 1510 1511
  // Compute memory operands for safepoint stack slots.
  static int SafepointRegisterStackIndex(int reg_code);
  MemOperand SafepointRegisterSlot(Register reg);
  MemOperand SafepointRegistersAndDoublesSlot(Register reg);

1512
  bool generating_stub_;
1513
  bool has_frame_;
1514 1515
  // This handle will be patched with the code object on installation.
  Handle<Object> code_object_;
1516

1517
  // Needs access to SafepointRegisterStackIndex for compiled frame
1518
  // traversal.
1519
  friend class StandardFrame;
1520 1521 1522
};


1523 1524 1525 1526 1527 1528 1529
// The code patcher is used to patch (typically) small parts of code e.g. for
// debugging and other types of instrumentation. When using the code patcher
// the exact number of bytes specified must be emitted. It is not legal to emit
// relocation information. If any of these constraints are violated it causes
// an assertion to fail.
class CodePatcher {
 public:
1530 1531 1532 1533 1534 1535 1536 1537
  enum FlushICache {
    FLUSH,
    DONT_FLUSH
  };

  CodePatcher(byte* address,
              int instructions,
              FlushICache flush_cache = FLUSH);
1538
  ~CodePatcher();
1539 1540 1541 1542 1543

  // Macro assembler to emit code.
  MacroAssembler* masm() { return &masm_; }

  // Emit an instruction directly.
1544
  void Emit(Instr instr);
1545 1546 1547 1548

  // Emit an address directly.
  void Emit(Address addr);

1549 1550 1551 1552
  // Emit the condition part of an instruction leaving the rest of the current
  // instruction unchanged.
  void EmitCondition(Condition cond);

1553 1554 1555 1556
 private:
  byte* address_;  // The address of the code being patched.
  int size_;  // Number of bytes of the expected patch size.
  MacroAssembler masm_;  // Macro assembler used to generate the code.
1557
  FlushICache flush_cache_;  // Whether to flush the I cache after patching.
1558 1559 1560
};


1561 1562 1563
// -----------------------------------------------------------------------------
// Static helper functions.

1564
inline MemOperand ContextOperand(Register context, int index = 0) {
1565 1566 1567 1568
  return MemOperand(context, Context::SlotOffset(index));
}


1569
inline MemOperand GlobalObjectOperand()  {
1570
  return ContextOperand(cp, Context::GLOBAL_OBJECT_INDEX);
1571 1572 1573
}


1574 1575 1576 1577 1578 1579 1580 1581 1582
#ifdef GENERATED_CODE_COVERAGE
#define CODE_COVERAGE_STRINGIFY(x) #x
#define CODE_COVERAGE_TOSTRING(x) CODE_COVERAGE_STRINGIFY(x)
#define __FILE_LINE__ __FILE__ ":" CODE_COVERAGE_TOSTRING(__LINE__)
#define ACCESS_MASM(masm) masm->stop(__FILE_LINE__); masm->
#else
#define ACCESS_MASM(masm) masm->
#endif

1583 1584 1585

} }  // namespace v8::internal

1586
#endif  // V8_ARM_MACRO_ASSEMBLER_ARM_H_