macro-assembler-arm.h 46 KB
Newer Older
1
// Copyright 2011 the V8 project authors. All rights reserved.
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
//       copyright notice, this list of conditions and the following
//       disclaimer in the documentation and/or other materials provided
//       with the distribution.
//     * Neither the name of Google Inc. nor the names of its
//       contributors may be used to endorse or promote products derived
//       from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

28 29
#ifndef V8_ARM_MACRO_ASSEMBLER_ARM_H_
#define V8_ARM_MACRO_ASSEMBLER_ARM_H_
30 31

#include "assembler.h"
32
#include "v8globals.h"
33

34 35
namespace v8 {
namespace internal {
36

37 38 39 40 41 42 43 44
// ----------------------------------------------------------------------------
// Static helper functions

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

45

46 47 48 49 50 51
static inline Operand SmiUntagOperand(Register object) {
  return Operand(object, ASR, kSmiTagSize);
}



52
// Give alias names to registers
53
const Register cp = { 8 };  // JavaScript context pointer
54
const Register roots = { 10 };  // Roots array pointer.
55

56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
// Flags used for the AllocateInNewSpace functions.
enum AllocationFlags {
  // No special flags.
  NO_ALLOCATION_FLAGS = 0,
  // Return the pointer to the allocated already tagged as a heap object.
  TAG_OBJECT = 1 << 0,
  // The content of the result register already contains the allocation top in
  // new space.
  RESULT_CONTAINS_TOP = 1 << 1,
  // Specify that the requested size of the space to allocate is specified in
  // words instead of bytes.
  SIZE_IN_WORDS = 1 << 2
};


71 72 73 74 75 76 77 78 79 80 81
// Flags used for the ObjectToDoubleVFPRegister function.
enum ObjectToDoubleFlags {
  // No special flags.
  NO_OBJECT_TO_DOUBLE_FLAGS = 0,
  // Object is known to be a non smi.
  OBJECT_NOT_SMI = 1 << 0,
  // Don't load NaNs or infinities, branch to the non number case instead.
  AVOID_NANS_AND_INFINITIES = 1 << 1
};


82 83 84
// MacroAssembler implements a collection of frequently used macros.
class MacroAssembler: public Assembler {
 public:
85 86 87 88 89
  // 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);
90

91
  // Jump, Call, and Ret pseudo instructions implementing inter-working.
92
  void Jump(Register target, Condition cond = al);
93
  void Jump(Address target, RelocInfo::Mode rmode, Condition cond = al);
94
  void Jump(Handle<Code> code, RelocInfo::Mode rmode, Condition cond = al);
95
  static int CallSize(Register target, Condition cond = al);
96
  void Call(Register target, Condition cond = al);
97 98 99
  static int CallSize(Address target,
                      RelocInfo::Mode rmode,
                      Condition cond = al);
100
  void Call(Address target, RelocInfo::Mode rmode, Condition cond = al);
101 102 103 104
  static int CallSize(Handle<Code> code,
                      RelocInfo::Mode rmode = RelocInfo::CODE_TARGET,
                      unsigned ast_id = kNoASTId,
                      Condition cond = al);
105
  void Call(Handle<Code> code,
106 107
            RelocInfo::Mode rmode = RelocInfo::CODE_TARGET,
            unsigned ast_id = kNoASTId,
108
            Condition cond = al);
109
  void Ret(Condition cond = al);
110 111 112 113 114

  // 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);

115
  void Ret(int drop, Condition cond = al);
116 117 118

  // Swap two registers.  If the scratch register is omitted then a slightly
  // less efficient form using xor instead of mov is emitted.
119 120 121 122
  void Swap(Register reg1,
            Register reg2,
            Register scratch = no_reg,
            Condition cond = al);
123

124 125 126 127 128 129 130

  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);
131 132 133 134 135 136 137 138 139
  // 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);
140
  void Bfc(Register dst, int lsb, int width, Condition cond = al);
141 142
  void Usat(Register dst, int satpos, const Operand& src,
            Condition cond = al);
143

144
  void Call(Label* target);
145 146

  // Register move. May do nothing if the registers are identical.
147
  void Move(Register dst, Handle<Object> value);
148
  void Move(Register dst, Register src, Condition cond = al);
149 150
  void Move(DoubleRegister dst, DoubleRegister src);

151 152 153 154
  // Load an object from the root table.
  void LoadRoot(Register destination,
                Heap::RootListIndex index,
                Condition cond = al);
155 156 157 158
  // Store an object to the root table.
  void StoreRoot(Register source,
                 Heap::RootListIndex index,
                 Condition cond = al);
159

160 161 162 163 164

  // Check if object is in new space.
  // scratch can be object itself, but it will be clobbered.
  void InNewSpace(Register object,
                  Register scratch,
165
                  Condition cond,  // eq for new space, ne otherwise
166 167 168
                  Label* branch);


169
  // For the page containing |object| mark the region covering [address]
170
  // dirty. The object address must be in the first 8K of an allocated page.
171
  void RecordWriteHelper(Register object,
172 173 174 175 176 177 178 179 180
                         Register address,
                         Register scratch);

  // For the page containing |object| mark the region covering
  // [object+offset] dirty. The object address must be in the first 8K
  // of an allocated page.  The 'scratch' registers are used in the
  // implementation and all 3 registers are clobbered by the
  // operation, as well as the ip register. RecordWrite updates the
  // write barrier even when storing smis.
181 182 183 184
  void RecordWrite(Register object,
                   Operand offset,
                   Register scratch0,
                   Register scratch1);
185

186 187 188 189 190 191 192 193 194
  // For the page containing |object| mark the region covering
  // [address] dirty. The object address must be in the first 8K of an
  // allocated page.  All 3 registers are clobbered by the operation,
  // as well as the ip register. RecordWrite updates the write barrier
  // even when storing smis.
  void RecordWrite(Register object,
                   Register address,
                   Register scratch);

195 196 197
  // Push a handle.
  void Push(Handle<Object> handle);

198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256
  // Push two registers.  Pushes leftmost register first (to highest address).
  void Push(Register src1, Register src2, Condition cond = al) {
    ASSERT(!src1.is(src2));
    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) {
    ASSERT(!src1.is(src2));
    ASSERT(!src2.is(src3));
    ASSERT(!src1.is(src3));
    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).
  void Push(Register src1, Register src2,
            Register src3, Register src4, Condition cond = al) {
    ASSERT(!src1.is(src2));
    ASSERT(!src2.is(src3));
    ASSERT(!src1.is(src3));
    ASSERT(!src1.is(src4));
    ASSERT(!src2.is(src4));
    ASSERT(!src3.is(src4));
    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);
    }
  }

257 258 259 260 261 262 263 264 265 266 267
  // Pop two registers. Pops rightmost register first (from lower address).
  void Pop(Register src1, Register src2, Condition cond = al) {
    ASSERT(!src1.is(src2));
    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);
    }
  }

268 269 270 271
  // Push and pop the registers that can hold pointers, as defined by the
  // RegList constant kSafepointSavedRegisters.
  void PushSafepointRegisters();
  void PopSafepointRegisters();
272 273
  void PushSafepointRegistersAndDoubles();
  void PopSafepointRegistersAndDoubles();
274 275 276 277 278 279 280
  // Store value in register src in the safepoint stack slot for
  // register dst.
  void StoreToSafepointRegisterSlot(Register src, Register dst);
  void StoreToSafepointRegistersAndDoublesSlot(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);
281

282 283 284 285 286 287 288 289 290 291 292 293
  // 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);

294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316
  // Clear specified FPSCR bits.
  void ClearFPSCRBits(const uint32_t bits_to_clear,
                      const Register scratch,
                      const Condition cond = al);

  // 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);

  // 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);

317 318 319 320
  void Vmov(const DwVfpRegister dst,
            const double imm,
            const Condition cond = al);

321 322 323 324 325 326 327 328 329 330

  // ---------------------------------------------------------------------------
  // Activation frames

  void EnterInternalFrame() { EnterFrame(StackFrame::INTERNAL); }
  void LeaveInternalFrame() { LeaveFrame(StackFrame::INTERNAL); }

  void EnterConstructFrame() { EnterFrame(StackFrame::CONSTRUCT); }
  void LeaveConstructFrame() { LeaveFrame(StackFrame::CONSTRUCT); }

331
  // Enter exit frame.
332 333
  // stack_space - extra stack space, used for alignment before call to C.
  void EnterExitFrame(bool save_doubles, int stack_space = 0);
334 335

  // Leave the current exit frame. Expects the return value in r0.
336 337 338
  // 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).
  void LeaveExitFrame(bool save_doubles, Register argument_count);
339

340 341
  // Get the actual activation frame alignment for target environment.
  static int ActivationFrameAlignment();
342

343 344
  void LoadContext(Register dst, int context_chain_length);

345 346 347 348 349 350 351 352
  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);

353 354 355
  // ---------------------------------------------------------------------------
  // JavaScript invokes

356 357 358 359 360
  // Setup call kind marking in ecx. The method takes ecx as an
  // explicit first parameter to make the code more readable at the
  // call sites.
  void SetCallKind(Register dst, CallKind kind);

361 362 363 364
  // Invoke the JavaScript function code by either calling or jumping.
  void InvokeCode(Register code,
                  const ParameterCount& expected,
                  const ParameterCount& actual,
365
                  InvokeFlag flag,
366 367
                  const CallWrapper& call_wrapper,
                  CallKind call_kind);
368 369 370 371

  void InvokeCode(Handle<Code> code,
                  const ParameterCount& expected,
                  const ParameterCount& actual,
372
                  RelocInfo::Mode rmode,
373
                  InvokeFlag flag,
374
                  CallKind call_kind);
375 376 377 378 379

  // 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,
380
                      InvokeFlag flag,
381 382
                      const CallWrapper& call_wrapper,
                      CallKind call_kind);
383

384 385
  void InvokeFunction(JSFunction* function,
                      const ParameterCount& actual,
386 387
                      InvokeFlag flag,
                      CallKind call_kind);
388

389 390 391 392 393 394 395 396 397 398 399 400
  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);
401

402
#ifdef ENABLE_DEBUGGER_SUPPORT
403 404 405
  // ---------------------------------------------------------------------------
  // Debugger Support

serya@chromium.org's avatar
serya@chromium.org committed
406
  void DebugBreak();
407
#endif
408 409 410 411 412 413 414 415 416

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

  // Push a new try handler and link into try handler chain.
  // The return address must be passed in register lr.
  // On exit, r0 contains TOS (code slot).
  void PushTryHandler(CodeLocation try_location, HandlerType type);

417 418 419
  // Unlink the stack handler on top of the stack from the try handler chain.
  // Must preserve the result register.
  void PopTryHandler();
420

421 422 423 424 425 426 427
  // Passes thrown value (in r0) to the handler of top of the try handler chain.
  void Throw(Register value);

  // Propagates an uncatchable exception to the top of the current JS stack's
  // handler chain.
  void ThrowUncatchable(UncatchableExceptionType type, Register value);

428 429 430 431 432 433
  // ---------------------------------------------------------------------------
  // 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.
434 435 436
  void CheckAccessGlobalProxy(Register holder_reg,
                              Register scratch,
                              Label* miss);
437

438 439 440 441 442 443 444 445 446 447

  void LoadFromNumberDictionary(Label* miss,
                                Register elements,
                                Register key,
                                Register result,
                                Register t0,
                                Register t1,
                                Register t2);


448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481
  inline void MarkCode(NopMarkerTypes type) {
    nop(type);
  }

  // Check if the given instruction is a 'type' marker.
  // ie. check if is is a mov r<type>, r<type> (referenced as nop(type))
  // These instructions are generated to mark special location in the code,
  // like some special IC code.
  static inline bool IsMarkedCode(Instr instr, int type) {
    ASSERT((FIRST_IC_MARKER <= type) && (type < LAST_CODE_MARKER));
    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;
    ASSERT((type == -1) ||
           ((FIRST_IC_MARKER <= type) && (type < LAST_CODE_MARKER)));
    return type;
  }

482

483 484 485
  // ---------------------------------------------------------------------------
  // Allocation support

486 487 488 489 490 491 492
  // Allocate an object in new space. The object_size is specified
  // either in bytes or in words if the allocation flag SIZE_IN_WORDS
  // is passed. If the new 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.
493 494 495 496 497 498 499 500 501 502 503 504
  void AllocateInNewSpace(int object_size,
                          Register result,
                          Register scratch1,
                          Register scratch2,
                          Label* gc_required,
                          AllocationFlags flags);
  void AllocateInNewSpace(Register object_size,
                          Register result,
                          Register scratch1,
                          Register scratch2,
                          Label* gc_required,
                          AllocationFlags flags);
505 506 507 508 509 510

  // Undo allocation in new space. The object passed and objects allocated after
  // it will no longer be allocated. The caller must make sure that no pointers
  // are left to the object(s) no longer allocated as they would be invalid when
  // allocation is undone.
  void UndoAllocationInNewSpace(Register object, Register scratch);
511

512 513 514 515 516 517 518 519 520 521 522 523 524

  void AllocateTwoByteString(Register result,
                             Register length,
                             Register scratch1,
                             Register scratch2,
                             Register scratch3,
                             Label* gc_required);
  void AllocateAsciiString(Register result,
                           Register length,
                           Register scratch1,
                           Register scratch2,
                           Register scratch3,
                           Label* gc_required);
525 526 527 528 529 530 531 532 533 534
  void AllocateTwoByteConsString(Register result,
                                 Register length,
                                 Register scratch1,
                                 Register scratch2,
                                 Label* gc_required);
  void AllocateAsciiConsString(Register result,
                               Register length,
                               Register scratch1,
                               Register scratch2,
                               Label* gc_required);
535 536 537 538 539 540 541 542 543 544
  void AllocateTwoByteSlicedString(Register result,
                                   Register length,
                                   Register scratch1,
                                   Register scratch2,
                                   Label* gc_required);
  void AllocateAsciiSlicedString(Register result,
                                 Register length,
                                 Register scratch1,
                                 Register scratch2,
                                 Label* gc_required);
545

546 547 548
  // 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.
549 550 551
  void AllocateHeapNumber(Register result,
                          Register scratch1,
                          Register scratch2,
552
                          Register heap_number_map,
553
                          Label* gc_required);
554 555 556 557 558 559 560
  void AllocateHeapNumberWithValue(Register result,
                                   DwVfpRegister value,
                                   Register scratch1,
                                   Register scratch2,
                                   Register heap_number_map,
                                   Label* gc_required);

561 562
  // Copies a fixed number of fields of heap objects from src to dst.
  void CopyFields(Register dst, Register src, RegList temps, int field_count);
563

564 565 566 567 568 569 570 571
  // 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);

572 573 574
  // ---------------------------------------------------------------------------
  // Support functions.

575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590
  // 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,
                               Label* miss);

  // 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
591
  // other registers.
592 593 594 595 596
  void CompareObjectType(Register heap_object,
                         Register map,
                         Register type_reg,
                         InstanceType type);

597 598 599 600 601 602 603 604 605
  // Compare instance type in a map.  map contains a valid map object 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 heap object in the heap_object register unless the heap_object
  // register is the same register as type_reg.
  void CompareInstanceType(Register map,
                           Register type_reg,
                           InstanceType type);

606

607 608 609 610 611 612
  // 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);

613 614 615 616
  // Check if the map of an object is equal to a specified map (either
  // given directly or as an index into the root list) and branch to
  // label if not. Skip the smi check if not required (object is known
  // to be a heap object)
617 618 619 620
  void CheckMap(Register obj,
                Register scratch,
                Handle<Map> map,
                Label* fail,
621
                SmiCheckType smi_check_type);
622

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

624 625 626 627
  void CheckMap(Register obj,
                Register scratch,
                Heap::RootListIndex index,
                Label* fail,
628
                SmiCheckType smi_check_type);
629 630


danno@chromium.org's avatar
danno@chromium.org committed
631 632 633 634 635 636 637 638 639 640
  // Check if the map of an object is equal to a specified 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 DispatchMap(Register obj,
                   Register scratch,
                   Handle<Map> map,
                   Handle<Code> success,
                   SmiCheckType smi_check_type);


641 642 643 644 645
  // 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);


646 647 648 649 650 651 652 653 654 655 656 657 658
  // Load and check the instance type of an object for being a string.
  // Loads the type into the second argument register.
  // Returns a condition that will be enabled if the object was a string.
  Condition IsObjectStringType(Register obj,
                               Register type) {
    ldr(type, FieldMemOperand(obj, HeapObject::kMapOffset));
    ldrb(type, FieldMemOperand(type, Map::kInstanceTypeOffset));
    tst(type, Operand(kIsNotStringMask));
    ASSERT_EQ(0, kStringTag);
    return eq;
  }


659 660 661 662
  // Generates code for reporting that an illegal operation has
  // occurred.
  void IllegalOperation(int num_arguments);

663 664 665 666 667 668
  // 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);

669 670
  // Get the number of least significant bits from a register
  void GetLeastBitsFromSmi(Register dst, Register src, int num_least_bits);
671
  void GetLeastBitsFromInt32(Register dst, Register src, int mun_least_bits);
672

673 674 675 676 677
  // Uses VFP instructions to Convert a Smi to a double.
  void IntegerToDoubleConversionWithVFP3(Register inReg,
                                         Register outHighReg,
                                         Register outLowReg);

678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698
  // Load the value of a number object into a VFP double register. If the object
  // is not a number a jump to the label not_number is performed and the VFP
  // double register is unchanged.
  void ObjectToDoubleVFPRegister(
      Register object,
      DwVfpRegister value,
      Register scratch1,
      Register scratch2,
      Register heap_number_map,
      SwVfpRegister scratch3,
      Label* not_number,
      ObjectToDoubleFlags flags = NO_OBJECT_TO_DOUBLE_FLAGS);

  // Load the value of a smi object into a VFP double register. The register
  // scratch1 can be the same register as smi in which case smi will hold the
  // untagged value afterwards.
  void SmiToDoubleVFPRegister(Register smi,
                              DwVfpRegister value,
                              Register scratch1,
                              SwVfpRegister scratch2);

699 700
  // Convert the HeapNumber pointed to by source to a 32bits signed integer
  // dest. If the HeapNumber does not fit into a 32bits signed integer branch
701 702
  // to not_int32 label. If VFP3 is available double_scratch is used but not
  // scratch2.
703 704 705 706
  void ConvertToInt32(Register source,
                      Register dest,
                      Register scratch,
                      Register scratch2,
707
                      DwVfpRegister double_scratch,
708 709
                      Label *not_int32);

710 711 712 713 714
  // Truncates a double using a specific rounding mode.
  // Clears the z flag (ne condition) if an overflow occurs.
  // If exact_conversion is true, the z flag is also cleared if the conversion
  // was inexact, ie. if the double value could not be converted exactly
  // to a 32bit integer.
715 716 717 718 719 720 721 722
  void EmitVFPTruncate(VFPRoundingMode rounding_mode,
                       SwVfpRegister result,
                       DwVfpRegister double_input,
                       Register scratch1,
                       Register scratch2,
                       CheckForInexactConversion check
                           = kDontCheckForInexactConversion);

723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743
  // Helper for EmitECMATruncate.
  // This will truncate a floating-point value outside of the singed 32bit
  // integer range to a 32bit signed integer.
  // Expects the double value loaded in input_high and input_low.
  // Exits with the answer in 'result'.
  // Note that this code does not work for values in the 32bit range!
  void EmitOutOfInt32RangeTruncate(Register result,
                                   Register input_high,
                                   Register input_low,
                                   Register scratch);

  // Performs a truncating conversion of a floating point number as used by
  // the JS bitwise operations. See ECMA-262 9.5: ToInt32.
  // Exits with 'result' holding the answer and all other registers clobbered.
  void EmitECMATruncate(Register result,
                        DwVfpRegister double_input,
                        SwVfpRegister single_scratch,
                        Register scratch,
                        Register scratch2,
                        Register scratch3);

744 745
  // Count leading zeros in a 32 bit word.  On ARM5 and later it uses the clz
  // instruction.  On pre-ARM5 hardware this routine gives the wrong answer
746 747 748 749 750 751
  // for 0 (31 instead of 32).  Source and scratch can be the same in which case
  // the source is clobbered.  Source and zeros can also be the same in which
  // case scratch should be a different register.
  void CountLeadingZeros(Register zeros,
                         Register source,
                         Register scratch);
752

753 754 755 756
  // ---------------------------------------------------------------------------
  // Runtime calls

  // Call a code stub.
757
  void CallStub(CodeStub* stub, Condition cond = al);
758

759 760 761 762 763
  // Call a code stub and return the code object called.  Try to generate
  // the code if necessary.  Do not perform a GC but instead return a retry
  // after GC failure.
  MUST_USE_RESULT MaybeObject* TryCallStub(CodeStub* stub, Condition cond = al);

764 765 766
  // Call a code stub.
  void TailCallStub(CodeStub* stub, Condition cond = al);

767 768 769 770 771 772
  // Tail call a code stub (jump) and return the code object called.  Try to
  // generate the code if necessary.  Do not perform a GC but instead return
  // a retry after GC failure.
  MUST_USE_RESULT MaybeObject* TryTailCallStub(CodeStub* stub,
                                               Condition cond = al);

773
  // Call a runtime routine.
774
  void CallRuntime(const Runtime::Function* f, int num_arguments);
775
  void CallRuntimeSaveDoubles(Runtime::FunctionId id);
776 777 778 779

  // Convenience function: Same as above, but takes the fid instead.
  void CallRuntime(Runtime::FunctionId fid, int num_arguments);

780 781 782 783
  // Convenience function: call an external reference.
  void CallExternalReference(const ExternalReference& ext,
                             int num_arguments);

784
  // Tail call of a runtime routine (jump).
serya@chromium.org's avatar
serya@chromium.org committed
785
  // Like JumpToExternalReference, but also takes care of passing the number
786
  // of parameters.
serya@chromium.org's avatar
serya@chromium.org committed
787 788 789 790
  void TailCallExternalReference(const ExternalReference& ext,
                                 int num_arguments,
                                 int result_size);

791 792 793 794 795 796
  // Tail call of a runtime routine (jump). Try to generate the code if
  // necessary. Do not perform a GC but instead return a retry after GC
  // failure.
  MUST_USE_RESULT MaybeObject* TryTailCallExternalReference(
      const ExternalReference& ext, int num_arguments, int result_size);

serya@chromium.org's avatar
serya@chromium.org committed
797 798
  // Convenience function: tail call a runtime routine (jump).
  void TailCallRuntime(Runtime::FunctionId fid,
799 800
                       int num_arguments,
                       int result_size);
801

802 803 804
  int CalculateStackPassedWords(int num_reg_arguments,
                                int num_double_arguments);

805 806 807
  // 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
808 809 810
  // 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.
811 812 813 814
  // 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.
815 816 817 818 819 820 821 822 823 824 825 826 827
  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.
  void SetCallCDoubleArguments(DoubleRegister dreg);
  void SetCallCDoubleArguments(DoubleRegister dreg1, DoubleRegister dreg2);
  void SetCallCDoubleArguments(DoubleRegister dreg, Register reg);
828 829 830 831 832 833 834

  // 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);
835
  void CallCFunction(Register function, Register scratch, int num_arguments);
836 837 838 839 840 841
  void CallCFunction(ExternalReference function,
                     int num_reg_arguments,
                     int num_double_arguments);
  void CallCFunction(Register function, Register scratch,
                     int num_reg_arguments,
                     int num_double_arguments);
842

843 844
  void GetCFunctionDoubleResult(const DoubleRegister dst);

845 846 847 848
  // Calls an API function. Allocates HandleScope, extracts returned value
  // from handle and propagates exceptions. Restores context.
  // stack_space - space to be unwound on exit (includes the call js
  // arguments space and the additional space allocated for the fast call).
849
  MaybeObject* TryCallApiFunctionAndReturn(ExternalReference function,
850 851
                                           int stack_space);

852
  // Jump to a runtime routine.
serya@chromium.org's avatar
serya@chromium.org committed
853
  void JumpToExternalReference(const ExternalReference& builtin);
854

855 856
  MaybeObject* TryJumpToExternalReference(const ExternalReference& ext);

857 858
  // Invoke specified builtin JavaScript function. Adds an entry to
  // the unresolved list if the name does not resolve.
859
  void InvokeBuiltin(Builtins::JavaScript id,
860
                     InvokeFlag flag,
861
                     const CallWrapper& call_wrapper = NullCallWrapper());
862 863 864 865

  // 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);
866

867 868 869
  // Store the function for the given builtin in the target register.
  void GetBuiltinFunction(Register target, Builtins::JavaScript id);

870 871 872 873
  Handle<Object> CodeObject() {
    ASSERT(!code_object_.is_null());
    return code_object_;
  }
874

875

876 877 878 879 880 881 882 883 884 885 886
  // ---------------------------------------------------------------------------
  // 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);


887 888 889
  // ---------------------------------------------------------------------------
  // Debugging

890
  // Calls Abort(msg) if the condition cond is not satisfied.
891
  // Use --debug_code to enable.
892
  void Assert(Condition cond, const char* msg);
893
  void AssertRegisterIsRoot(Register reg, Heap::RootListIndex index);
894
  void AssertFastElements(Register elements);
895 896

  // Like Assert(), but always enabled.
897
  void Check(Condition cond, const char* msg);
898 899 900 901 902 903 904

  // Print a message to stdout and abort execution.
  void Abort(const char* msg);

  // Verify restrictions about code generated in stubs.
  void set_generating_stub(bool value) { generating_stub_ = value; }
  bool generating_stub() { return generating_stub_; }
905 906
  void set_allow_stub_calls(bool value) { allow_stub_calls_ = value; }
  bool allow_stub_calls() { return allow_stub_calls_; }
907

908 909 910 911 912 913 914 915 916
  // EABI variant for double arguments in use.
  bool use_eabi_hardfloat() {
#if USE_EABI_HARDFLOAT
    return true;
#else
    return false;
#endif
  }

917 918 919 920 921 922 923 924 925 926
  // ---------------------------------------------------------------------------
  // 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);
927 928 929 930 931 932 933 934 935 936
  // 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);
937

938 939 940
  // ---------------------------------------------------------------------------
  // Smi utilities

941 942 943
  void SmiTag(Register reg, SBit s = LeaveCC) {
    add(reg, reg, Operand(reg), s);
  }
944 945 946
  void SmiTag(Register dst, Register src, SBit s = LeaveCC) {
    add(dst, src, Operand(src), s);
  }
947

948 949 950 951 952 953 954 955 956 957
  // 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.
  void TrySmiTag(Register reg, Label* not_a_smi, Register scratch) {
    mov(scratch, reg);
    SmiTag(scratch, SetCC);
    b(vs, not_a_smi);
    mov(reg, scratch);
  }

958 959
  void SmiUntag(Register reg, SBit s = LeaveCC) {
    mov(reg, Operand(reg, ASR, kSmiTagSize), s);
960
  }
961 962
  void SmiUntag(Register dst, Register src, SBit s = LeaveCC) {
    mov(dst, Operand(src, ASR, kSmiTagSize), s);
963
  }
964

965 966 967 968 969 970 971 972 973 974
  // Jump the register contains a smi.
  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);
  }
975 976 977 978 979
  // 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);

980 981
  // Abort execution if argument is a smi. Used in debug code.
  void AbortIfSmi(Register object);
982
  void AbortIfNotSmi(Register object);
983

984 985 986
  // Abort execution if argument is a string. Used in debug code.
  void AbortIfNotString(Register object);

987 988 989 990 991
  // Abort execution if argument is not the root value with the given index.
  void AbortIfNotRootValue(Register src,
                           Heap::RootListIndex root_value_index,
                           const char* message);

992 993 994 995 996 997 998 999
  // ---------------------------------------------------------------------------
  // HeapNumber utilities

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

1000 1001 1002 1003 1004 1005 1006 1007 1008
  // ---------------------------------------------------------------------------
  // String utilities

  // Checks if both objects are sequential ASCII strings and jumps to label
  // if either is not. Assumes that neither object is a smi.
  void JumpIfNonSmisNotBothSequentialAsciiStrings(Register object1,
                                                  Register object2,
                                                  Register scratch1,
                                                  Register scratch2,
1009
                                                  Label* failure);
1010 1011 1012 1013 1014 1015 1016 1017 1018

  // Checks if both objects are sequential ASCII strings and jumps to label
  // if either is not.
  void JumpIfNotBothSequentialAsciiStrings(Register first,
                                           Register second,
                                           Register scratch1,
                                           Register scratch2,
                                           Label* not_flat_ascii_strings);

1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034
  // Checks if both instance types are sequential ASCII strings and jumps to
  // label if either is not.
  void JumpIfBothInstanceTypesAreNotSequentialAscii(
      Register first_object_instance_type,
      Register second_object_instance_type,
      Register scratch1,
      Register scratch2,
      Label* failure);

  // Check if instance type is sequential ASCII string and jump to label if
  // it is not.
  void JumpIfInstanceTypeIsNotSequentialAscii(Register type,
                                              Register scratch,
                                              Label* failure);


1035 1036 1037 1038 1039 1040 1041 1042 1043
  // ---------------------------------------------------------------------------
  // Patching helpers.

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


1044 1045 1046 1047 1048 1049 1050
  void ClampUint8(Register output_reg, Register input_reg);

  void ClampDoubleToUint8(Register result_reg,
                          DoubleRegister input_reg,
                          DoubleRegister temp_double_reg);


1051 1052
  void LoadInstanceDescriptors(Register map, Register descriptors);

1053
 private:
1054 1055 1056
  void CallCFunctionHelper(Register function,
                           ExternalReference function_reference,
                           Register scratch,
1057 1058
                           int num_reg_arguments,
                           int num_double_arguments);
1059

1060
  void Jump(intptr_t target, RelocInfo::Mode rmode, Condition cond = al);
1061 1062 1063 1064 1065 1066 1067

  // Helper functions for generating invokes.
  void InvokePrologue(const ParameterCount& expected,
                      const ParameterCount& actual,
                      Handle<Code> code_constant,
                      Register code_reg,
                      Label* done,
1068
                      InvokeFlag flag,
1069 1070
                      const CallWrapper& call_wrapper,
                      CallKind call_kind);
1071

1072 1073 1074 1075
  // Activation support.
  void EnterFrame(StackFrame::Type type);
  void LeaveFrame(StackFrame::Type type);

1076 1077 1078 1079 1080 1081
  void InitializeNewString(Register string,
                           Register length,
                           Heap::RootListIndex map_index,
                           Register scratch1,
                           Register scratch2);

1082 1083 1084 1085 1086
  // Compute memory operands for safepoint stack slots.
  static int SafepointRegisterStackIndex(int reg_code);
  MemOperand SafepointRegisterSlot(Register reg);
  MemOperand SafepointRegistersAndDoublesSlot(Register reg);

1087 1088 1089 1090
  bool generating_stub_;
  bool allow_stub_calls_;
  // This handle will be patched with the code object on installation.
  Handle<Object> code_object_;
1091 1092 1093 1094

  // Needs access to SafepointRegisterStackIndex for optimized frame
  // traversal.
  friend class OptimizedFrame;
1095 1096 1097
};


1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112
#ifdef ENABLE_DEBUGGER_SUPPORT
// 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:
  CodePatcher(byte* address, int instructions);
  virtual ~CodePatcher();

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

  // Emit an instruction directly.
1113
  void Emit(Instr instr);
1114 1115 1116 1117

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

1118 1119 1120 1121
  // Emit the condition part of an instruction leaving the rest of the current
  // instruction unchanged.
  void EmitCondition(Condition cond);

1122 1123 1124 1125 1126 1127 1128 1129 1130
 private:
  byte* address_;  // The address of the code being patched.
  int instructions_;  // Number of instructions of the expected patch size.
  int size_;  // Number of bytes of the expected patch size.
  MacroAssembler masm_;  // Macro assembler used to generate the code.
};
#endif  // ENABLE_DEBUGGER_SUPPORT


1131 1132 1133
// -----------------------------------------------------------------------------
// Static helper functions.

1134 1135 1136 1137 1138 1139 1140 1141 1142 1143
static MemOperand ContextOperand(Register context, int index) {
  return MemOperand(context, Context::SlotOffset(index));
}


static inline MemOperand GlobalObjectOperand()  {
  return ContextOperand(cp, Context::GLOBAL_INDEX);
}


1144 1145 1146 1147 1148 1149 1150 1151 1152
#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

1153 1154 1155

} }  // namespace v8::internal

1156
#endif  // V8_ARM_MACRO_ASSEMBLER_ARM_H_