1 // Copyright 2012 the V8 project authors. All rights reserved. 2 // Redistribution and use in source and binary forms, with or without 3 // modification, are permitted provided that the following conditions are 4 // met: 5 // 6 // * Redistributions of source code must retain the above copyright 7 // notice, this list of conditions and the following disclaimer. 8 // * Redistributions in binary form must reproduce the above 9 // copyright notice, this list of conditions and the following 10 // disclaimer in the documentation and/or other materials provided 11 // with the distribution. 12 // * Neither the name of Google Inc. nor the names of its 13 // contributors may be used to endorse or promote products derived 14 // from this software without specific prior written permission. 15 // 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28 #ifndef V8_ARM_MACRO_ASSEMBLER_ARM_H_ 29 #define V8_ARM_MACRO_ASSEMBLER_ARM_H_ 30 31 #include "assembler.h" 32 #include "frames.h" 33 #include "v8globals.h" 34 35 namespace v8 { 36 namespace internal { 37 38 // ---------------------------------------------------------------------------- 39 // Static helper functions 40 41 // Generate a MemOperand for loading a field from an object. 42 inline MemOperand FieldMemOperand(Register object, int offset) { 43 return MemOperand(object, offset - kHeapObjectTag); 44 } 45 46 47 inline Operand SmiUntagOperand(Register object) { 48 return Operand(object, ASR, kSmiTagSize); 49 } 50 51 52 53 // Give alias names to registers 54 const Register cp = { 8 }; // JavaScript context pointer 55 const Register kRootRegister = { 10 }; // Roots array pointer. 56 57 // Flags used for the AllocateInNewSpace functions. 58 enum AllocationFlags { 59 // No special flags. 60 NO_ALLOCATION_FLAGS = 0, 61 // Return the pointer to the allocated already tagged as a heap object. 62 TAG_OBJECT = 1 << 0, 63 // The content of the result register already contains the allocation top in 64 // new space. 65 RESULT_CONTAINS_TOP = 1 << 1, 66 // Specify that the requested size of the space to allocate is specified in 67 // words instead of bytes. 68 SIZE_IN_WORDS = 1 << 2 69 }; 70 71 72 // Flags used for the ObjectToDoubleVFPRegister function. 73 enum ObjectToDoubleFlags { 74 // No special flags. 75 NO_OBJECT_TO_DOUBLE_FLAGS = 0, 76 // Object is known to be a non smi. 77 OBJECT_NOT_SMI = 1 << 0, 78 // Don't load NaNs or infinities, branch to the non number case instead. 79 AVOID_NANS_AND_INFINITIES = 1 << 1 80 }; 81 82 83 enum RememberedSetAction { EMIT_REMEMBERED_SET, OMIT_REMEMBERED_SET }; 84 enum SmiCheck { INLINE_SMI_CHECK, OMIT_SMI_CHECK }; 85 enum LinkRegisterStatus { kLRHasNotBeenSaved, kLRHasBeenSaved }; 86 87 88 bool AreAliased(Register r1, Register r2, Register r3, Register r4); 89 90 91 // MacroAssembler implements a collection of frequently used macros. 92 class MacroAssembler: public Assembler { 93 public: 94 // The isolate parameter can be NULL if the macro assembler should 95 // not use isolate-dependent functionality. In this case, it's the 96 // responsibility of the caller to never invoke such function on the 97 // macro assembler. 98 MacroAssembler(Isolate* isolate, void* buffer, int size); 99 100 // Jump, Call, and Ret pseudo instructions implementing inter-working. 101 void Jump(Register target, Condition cond = al); 102 void Jump(Address target, RelocInfo::Mode rmode, Condition cond = al); 103 void Jump(Handle<Code> code, RelocInfo::Mode rmode, Condition cond = al); 104 static int CallSize(Register target, Condition cond = al); 105 void Call(Register target, Condition cond = al); 106 static int CallSize(Address target, 107 RelocInfo::Mode rmode, 108 Condition cond = al); 109 void Call(Address target, RelocInfo::Mode rmode, Condition cond = al); 110 static int CallSize(Handle<Code> code, 111 RelocInfo::Mode rmode = RelocInfo::CODE_TARGET, 112 unsigned ast_id = kNoASTId, 113 Condition cond = al); 114 void Call(Handle<Code> code, 115 RelocInfo::Mode rmode = RelocInfo::CODE_TARGET, 116 unsigned ast_id = kNoASTId, 117 Condition cond = al); 118 void Ret(Condition cond = al); 119 120 // Emit code to discard a non-negative number of pointer-sized elements 121 // from the stack, clobbering only the sp register. 122 void Drop(int count, Condition cond = al); 123 124 void Ret(int drop, Condition cond = al); 125 126 // Swap two registers. If the scratch register is omitted then a slightly 127 // less efficient form using xor instead of mov is emitted. 128 void Swap(Register reg1, 129 Register reg2, 130 Register scratch = no_reg, 131 Condition cond = al); 132 133 134 void And(Register dst, Register src1, const Operand& src2, 135 Condition cond = al); 136 void Ubfx(Register dst, Register src, int lsb, int width, 137 Condition cond = al); 138 void Sbfx(Register dst, Register src, int lsb, int width, 139 Condition cond = al); 140 // The scratch register is not used for ARMv7. 141 // scratch can be the same register as src (in which case it is trashed), but 142 // not the same as dst. 143 void Bfi(Register dst, 144 Register src, 145 Register scratch, 146 int lsb, 147 int width, 148 Condition cond = al); 149 void Bfc(Register dst, int lsb, int width, Condition cond = al); 150 void Usat(Register dst, int satpos, const Operand& src, 151 Condition cond = al); 152 153 void Call(Label* target); 154 155 // Register move. May do nothing if the registers are identical. 156 void Move(Register dst, Handle<Object> value); 157 void Move(Register dst, Register src, Condition cond = al); 158 void Move(DoubleRegister dst, DoubleRegister src); 159 160 // Load an object from the root table. 161 void LoadRoot(Register destination, 162 Heap::RootListIndex index, 163 Condition cond = al); 164 // Store an object to the root table. 165 void StoreRoot(Register source, 166 Heap::RootListIndex index, 167 Condition cond = al); 168 169 void LoadHeapObject(Register dst, Handle<HeapObject> object); 170 171 void LoadObject(Register result, Handle<Object> object) { 172 if (object->IsHeapObject()) { 173 LoadHeapObject(result, Handle<HeapObject>::cast(object)); 174 } else { 175 Move(result, object); 176 } 177 } 178 179 // --------------------------------------------------------------------------- 180 // GC Support 181 182 void IncrementalMarkingRecordWriteHelper(Register object, 183 Register value, 184 Register address); 185 186 enum RememberedSetFinalAction { 187 kReturnAtEnd, 188 kFallThroughAtEnd 189 }; 190 191 // Record in the remembered set the fact that we have a pointer to new space 192 // at the address pointed to by the addr register. Only works if addr is not 193 // in new space. 194 void RememberedSetHelper(Register object, // Used for debug code. 195 Register addr, 196 Register scratch, 197 SaveFPRegsMode save_fp, 198 RememberedSetFinalAction and_then); 199 200 void CheckPageFlag(Register object, 201 Register scratch, 202 int mask, 203 Condition cc, 204 Label* condition_met); 205 206 // Check if object is in new space. Jumps if the object is not in new space. 207 // The register scratch can be object itself, but scratch will be clobbered. 208 void JumpIfNotInNewSpace(Register object, 209 Register scratch, 210 Label* branch) { 211 InNewSpace(object, scratch, ne, branch); 212 } 213 214 // Check if object is in new space. Jumps if the object is in new space. 215 // The register scratch can be object itself, but it will be clobbered. 216 void JumpIfInNewSpace(Register object, 217 Register scratch, 218 Label* branch) { 219 InNewSpace(object, scratch, eq, branch); 220 } 221 222 // Check if an object has a given incremental marking color. 223 void HasColor(Register object, 224 Register scratch0, 225 Register scratch1, 226 Label* has_color, 227 int first_bit, 228 int second_bit); 229 230 void JumpIfBlack(Register object, 231 Register scratch0, 232 Register scratch1, 233 Label* on_black); 234 235 // Checks the color of an object. If the object is already grey or black 236 // then we just fall through, since it is already live. If it is white and 237 // we can determine that it doesn't need to be scanned, then we just mark it 238 // black and fall through. For the rest we jump to the label so the 239 // incremental marker can fix its assumptions. 240 void EnsureNotWhite(Register object, 241 Register scratch1, 242 Register scratch2, 243 Register scratch3, 244 Label* object_is_white_and_not_data); 245 246 // Detects conservatively whether an object is data-only, i.e. it does need to 247 // be scanned by the garbage collector. 248 void JumpIfDataObject(Register value, 249 Register scratch, 250 Label* not_data_object); 251 252 // Notify the garbage collector that we wrote a pointer into an object. 253 // |object| is the object being stored into, |value| is the object being 254 // stored. value and scratch registers are clobbered by the operation. 255 // The offset is the offset from the start of the object, not the offset from 256 // the tagged HeapObject pointer. For use with FieldOperand(reg, off). 257 void RecordWriteField( 258 Register object, 259 int offset, 260 Register value, 261 Register scratch, 262 LinkRegisterStatus lr_status, 263 SaveFPRegsMode save_fp, 264 RememberedSetAction remembered_set_action = EMIT_REMEMBERED_SET, 265 SmiCheck smi_check = INLINE_SMI_CHECK); 266 267 // As above, but the offset has the tag presubtracted. For use with 268 // MemOperand(reg, off). 269 inline void RecordWriteContextSlot( 270 Register context, 271 int offset, 272 Register value, 273 Register scratch, 274 LinkRegisterStatus lr_status, 275 SaveFPRegsMode save_fp, 276 RememberedSetAction remembered_set_action = EMIT_REMEMBERED_SET, 277 SmiCheck smi_check = INLINE_SMI_CHECK) { 278 RecordWriteField(context, 279 offset + kHeapObjectTag, 280 value, 281 scratch, 282 lr_status, 283 save_fp, 284 remembered_set_action, 285 smi_check); 286 } 287 288 // For a given |object| notify the garbage collector that the slot |address| 289 // has been written. |value| is the object being stored. The value and 290 // address registers are clobbered by the operation. 291 void RecordWrite( 292 Register object, 293 Register address, 294 Register value, 295 LinkRegisterStatus lr_status, 296 SaveFPRegsMode save_fp, 297 RememberedSetAction remembered_set_action = EMIT_REMEMBERED_SET, 298 SmiCheck smi_check = INLINE_SMI_CHECK); 299 300 // Push a handle. 301 void Push(Handle<Object> handle); 302 303 // Push two registers. Pushes leftmost register first (to highest address). 304 void Push(Register src1, Register src2, Condition cond = al) { 305 ASSERT(!src1.is(src2)); 306 if (src1.code() > src2.code()) { 307 stm(db_w, sp, src1.bit() | src2.bit(), cond); 308 } else { 309 str(src1, MemOperand(sp, 4, NegPreIndex), cond); 310 str(src2, MemOperand(sp, 4, NegPreIndex), cond); 311 } 312 } 313 314 // Push three registers. Pushes leftmost register first (to highest address). 315 void Push(Register src1, Register src2, Register src3, Condition cond = al) { 316 ASSERT(!src1.is(src2)); 317 ASSERT(!src2.is(src3)); 318 ASSERT(!src1.is(src3)); 319 if (src1.code() > src2.code()) { 320 if (src2.code() > src3.code()) { 321 stm(db_w, sp, src1.bit() | src2.bit() | src3.bit(), cond); 322 } else { 323 stm(db_w, sp, src1.bit() | src2.bit(), cond); 324 str(src3, MemOperand(sp, 4, NegPreIndex), cond); 325 } 326 } else { 327 str(src1, MemOperand(sp, 4, NegPreIndex), cond); 328 Push(src2, src3, cond); 329 } 330 } 331 332 // Push four registers. Pushes leftmost register first (to highest address). 333 void Push(Register src1, 334 Register src2, 335 Register src3, 336 Register src4, 337 Condition cond = al) { 338 ASSERT(!src1.is(src2)); 339 ASSERT(!src2.is(src3)); 340 ASSERT(!src1.is(src3)); 341 ASSERT(!src1.is(src4)); 342 ASSERT(!src2.is(src4)); 343 ASSERT(!src3.is(src4)); 344 if (src1.code() > src2.code()) { 345 if (src2.code() > src3.code()) { 346 if (src3.code() > src4.code()) { 347 stm(db_w, 348 sp, 349 src1.bit() | src2.bit() | src3.bit() | src4.bit(), 350 cond); 351 } else { 352 stm(db_w, sp, src1.bit() | src2.bit() | src3.bit(), cond); 353 str(src4, MemOperand(sp, 4, NegPreIndex), cond); 354 } 355 } else { 356 stm(db_w, sp, src1.bit() | src2.bit(), cond); 357 Push(src3, src4, cond); 358 } 359 } else { 360 str(src1, MemOperand(sp, 4, NegPreIndex), cond); 361 Push(src2, src3, src4, cond); 362 } 363 } 364 365 // Pop two registers. Pops rightmost register first (from lower address). 366 void Pop(Register src1, Register src2, Condition cond = al) { 367 ASSERT(!src1.is(src2)); 368 if (src1.code() > src2.code()) { 369 ldm(ia_w, sp, src1.bit() | src2.bit(), cond); 370 } else { 371 ldr(src2, MemOperand(sp, 4, PostIndex), cond); 372 ldr(src1, MemOperand(sp, 4, PostIndex), cond); 373 } 374 } 375 376 // Pop three registers. Pops rightmost register first (from lower address). 377 void Pop(Register src1, Register src2, Register src3, Condition cond = al) { 378 ASSERT(!src1.is(src2)); 379 ASSERT(!src2.is(src3)); 380 ASSERT(!src1.is(src3)); 381 if (src1.code() > src2.code()) { 382 if (src2.code() > src3.code()) { 383 ldm(ia_w, sp, src1.bit() | src2.bit() | src3.bit(), cond); 384 } else { 385 ldr(src3, MemOperand(sp, 4, PostIndex), cond); 386 ldm(ia_w, sp, src1.bit() | src2.bit(), cond); 387 } 388 } else { 389 Pop(src2, src3, cond); 390 str(src1, MemOperand(sp, 4, PostIndex), cond); 391 } 392 } 393 394 // Pop four registers. Pops rightmost register first (from lower address). 395 void Pop(Register src1, 396 Register src2, 397 Register src3, 398 Register src4, 399 Condition cond = al) { 400 ASSERT(!src1.is(src2)); 401 ASSERT(!src2.is(src3)); 402 ASSERT(!src1.is(src3)); 403 ASSERT(!src1.is(src4)); 404 ASSERT(!src2.is(src4)); 405 ASSERT(!src3.is(src4)); 406 if (src1.code() > src2.code()) { 407 if (src2.code() > src3.code()) { 408 if (src3.code() > src4.code()) { 409 ldm(ia_w, 410 sp, 411 src1.bit() | src2.bit() | src3.bit() | src4.bit(), 412 cond); 413 } else { 414 ldr(src4, MemOperand(sp, 4, PostIndex), cond); 415 ldm(ia_w, sp, src1.bit() | src2.bit() | src3.bit(), cond); 416 } 417 } else { 418 Pop(src3, src4, cond); 419 ldm(ia_w, sp, src1.bit() | src2.bit(), cond); 420 } 421 } else { 422 Pop(src2, src3, src4, cond); 423 ldr(src1, MemOperand(sp, 4, PostIndex), cond); 424 } 425 } 426 427 // Push and pop the registers that can hold pointers, as defined by the 428 // RegList constant kSafepointSavedRegisters. 429 void PushSafepointRegisters(); 430 void PopSafepointRegisters(); 431 void PushSafepointRegistersAndDoubles(); 432 void PopSafepointRegistersAndDoubles(); 433 // Store value in register src in the safepoint stack slot for 434 // register dst. 435 void StoreToSafepointRegisterSlot(Register src, Register dst); 436 void StoreToSafepointRegistersAndDoublesSlot(Register src, Register dst); 437 // Load the value of the src register from its safepoint stack slot 438 // into register dst. 439 void LoadFromSafepointRegisterSlot(Register dst, Register src); 440 441 // Load two consecutive registers with two consecutive memory locations. 442 void Ldrd(Register dst1, 443 Register dst2, 444 const MemOperand& src, 445 Condition cond = al); 446 447 // Store two consecutive registers to two consecutive memory locations. 448 void Strd(Register src1, 449 Register src2, 450 const MemOperand& dst, 451 Condition cond = al); 452 453 // Clear specified FPSCR bits. 454 void ClearFPSCRBits(const uint32_t bits_to_clear, 455 const Register scratch, 456 const Condition cond = al); 457 458 // Compare double values and move the result to the normal condition flags. 459 void VFPCompareAndSetFlags(const DwVfpRegister src1, 460 const DwVfpRegister src2, 461 const Condition cond = al); 462 void VFPCompareAndSetFlags(const DwVfpRegister src1, 463 const double src2, 464 const Condition cond = al); 465 466 // Compare double values and then load the fpscr flags to a register. 467 void VFPCompareAndLoadFlags(const DwVfpRegister src1, 468 const DwVfpRegister src2, 469 const Register fpscr_flags, 470 const Condition cond = al); 471 void VFPCompareAndLoadFlags(const DwVfpRegister src1, 472 const double src2, 473 const Register fpscr_flags, 474 const Condition cond = al); 475 476 void Vmov(const DwVfpRegister dst, 477 const double imm, 478 const Condition cond = al); 479 480 // Enter exit frame. 481 // stack_space - extra stack space, used for alignment before call to C. 482 void EnterExitFrame(bool save_doubles, int stack_space = 0); 483 484 // Leave the current exit frame. Expects the return value in r0. 485 // Expect the number of values, pushed prior to the exit frame, to 486 // remove in a register (or no_reg, if there is nothing to remove). 487 void LeaveExitFrame(bool save_doubles, Register argument_count); 488 489 // Get the actual activation frame alignment for target environment. 490 static int ActivationFrameAlignment(); 491 492 void LoadContext(Register dst, int context_chain_length); 493 494 // Conditionally load the cached Array transitioned map of type 495 // transitioned_kind from the global context if the map in register 496 // map_in_out is the cached Array map in the global context of 497 // expected_kind. 498 void LoadTransitionedArrayMapConditional( 499 ElementsKind expected_kind, 500 ElementsKind transitioned_kind, 501 Register map_in_out, 502 Register scratch, 503 Label* no_map_match); 504 505 // Load the initial map for new Arrays from a JSFunction. 506 void LoadInitialArrayMap(Register function_in, 507 Register scratch, 508 Register map_out); 509 510 void LoadGlobalFunction(int index, Register function); 511 512 // Load the initial map from the global function. The registers 513 // function and map can be the same, function is then overwritten. 514 void LoadGlobalFunctionInitialMap(Register function, 515 Register map, 516 Register scratch); 517 518 void InitializeRootRegister() { 519 ExternalReference roots_array_start = 520 ExternalReference::roots_array_start(isolate()); 521 mov(kRootRegister, Operand(roots_array_start)); 522 } 523 524 // --------------------------------------------------------------------------- 525 // JavaScript invokes 526 527 // Set up call kind marking in ecx. The method takes ecx as an 528 // explicit first parameter to make the code more readable at the 529 // call sites. 530 void SetCallKind(Register dst, CallKind kind); 531 532 // Invoke the JavaScript function code by either calling or jumping. 533 void InvokeCode(Register code, 534 const ParameterCount& expected, 535 const ParameterCount& actual, 536 InvokeFlag flag, 537 const CallWrapper& call_wrapper, 538 CallKind call_kind); 539 540 void InvokeCode(Handle<Code> code, 541 const ParameterCount& expected, 542 const ParameterCount& actual, 543 RelocInfo::Mode rmode, 544 InvokeFlag flag, 545 CallKind call_kind); 546 547 // Invoke the JavaScript function in the given register. Changes the 548 // current context to the context in the function before invoking. 549 void InvokeFunction(Register function, 550 const ParameterCount& actual, 551 InvokeFlag flag, 552 const CallWrapper& call_wrapper, 553 CallKind call_kind); 554 555 void InvokeFunction(Handle<JSFunction> function, 556 const ParameterCount& actual, 557 InvokeFlag flag, 558 const CallWrapper& call_wrapper, 559 CallKind call_kind); 560 561 void IsObjectJSObjectType(Register heap_object, 562 Register map, 563 Register scratch, 564 Label* fail); 565 566 void IsInstanceJSObjectType(Register map, 567 Register scratch, 568 Label* fail); 569 570 void IsObjectJSStringType(Register object, 571 Register scratch, 572 Label* fail); 573 574 #ifdef ENABLE_DEBUGGER_SUPPORT 575 // --------------------------------------------------------------------------- 576 // Debugger Support 577 578 void DebugBreak(); 579 #endif 580 581 // --------------------------------------------------------------------------- 582 // Exception handling 583 584 // Push a new try handler and link into try handler chain. 585 void PushTryHandler(StackHandler::Kind kind, int handler_index); 586 587 // Unlink the stack handler on top of the stack from the try handler chain. 588 // Must preserve the result register. 589 void PopTryHandler(); 590 591 // Passes thrown value to the handler of top of the try handler chain. 592 void Throw(Register value); 593 594 // Propagates an uncatchable exception to the top of the current JS stack's 595 // handler chain. 596 void ThrowUncatchable(Register value); 597 598 // --------------------------------------------------------------------------- 599 // Inline caching support 600 601 // Generate code for checking access rights - used for security checks 602 // on access to global objects across environments. The holder register 603 // is left untouched, whereas both scratch registers are clobbered. 604 void CheckAccessGlobalProxy(Register holder_reg, 605 Register scratch, 606 Label* miss); 607 608 void GetNumberHash(Register t0, Register scratch); 609 610 void LoadFromNumberDictionary(Label* miss, 611 Register elements, 612 Register key, 613 Register result, 614 Register t0, 615 Register t1, 616 Register t2); 617 618 619 inline void MarkCode(NopMarkerTypes type) { 620 nop(type); 621 } 622 623 // Check if the given instruction is a 'type' marker. 624 // i.e. check if is is a mov r<type>, r<type> (referenced as nop(type)) 625 // These instructions are generated to mark special location in the code, 626 // like some special IC code. 627 static inline bool IsMarkedCode(Instr instr, int type) { 628 ASSERT((FIRST_IC_MARKER <= type) && (type < LAST_CODE_MARKER)); 629 return IsNop(instr, type); 630 } 631 632 633 static inline int GetCodeMarker(Instr instr) { 634 int dst_reg_offset = 12; 635 int dst_mask = 0xf << dst_reg_offset; 636 int src_mask = 0xf; 637 int dst_reg = (instr & dst_mask) >> dst_reg_offset; 638 int src_reg = instr & src_mask; 639 uint32_t non_register_mask = ~(dst_mask | src_mask); 640 uint32_t mov_mask = al | 13 << 21; 641 642 // Return <n> if we have a mov rn rn, else return -1. 643 int type = ((instr & non_register_mask) == mov_mask) && 644 (dst_reg == src_reg) && 645 (FIRST_IC_MARKER <= dst_reg) && (dst_reg < LAST_CODE_MARKER) 646 ? src_reg 647 : -1; 648 ASSERT((type == -1) || 649 ((FIRST_IC_MARKER <= type) && (type < LAST_CODE_MARKER))); 650 return type; 651 } 652 653 654 // --------------------------------------------------------------------------- 655 // Allocation support 656 657 // Allocate an object in new space. The object_size is specified 658 // either in bytes or in words if the allocation flag SIZE_IN_WORDS 659 // is passed. If the new space is exhausted control continues at the 660 // gc_required label. The allocated object is returned in result. If 661 // the flag tag_allocated_object is true the result is tagged as as 662 // a heap object. All registers are clobbered also when control 663 // continues at the gc_required label. 664 void AllocateInNewSpace(int object_size, 665 Register result, 666 Register scratch1, 667 Register scratch2, 668 Label* gc_required, 669 AllocationFlags flags); 670 void AllocateInNewSpace(Register object_size, 671 Register result, 672 Register scratch1, 673 Register scratch2, 674 Label* gc_required, 675 AllocationFlags flags); 676 677 // Undo allocation in new space. The object passed and objects allocated after 678 // it will no longer be allocated. The caller must make sure that no pointers 679 // are left to the object(s) no longer allocated as they would be invalid when 680 // allocation is undone. 681 void UndoAllocationInNewSpace(Register object, Register scratch); 682 683 684 void AllocateTwoByteString(Register result, 685 Register length, 686 Register scratch1, 687 Register scratch2, 688 Register scratch3, 689 Label* gc_required); 690 void AllocateAsciiString(Register result, 691 Register length, 692 Register scratch1, 693 Register scratch2, 694 Register scratch3, 695 Label* gc_required); 696 void AllocateTwoByteConsString(Register result, 697 Register length, 698 Register scratch1, 699 Register scratch2, 700 Label* gc_required); 701 void AllocateAsciiConsString(Register result, 702 Register length, 703 Register scratch1, 704 Register scratch2, 705 Label* gc_required); 706 void AllocateTwoByteSlicedString(Register result, 707 Register length, 708 Register scratch1, 709 Register scratch2, 710 Label* gc_required); 711 void AllocateAsciiSlicedString(Register result, 712 Register length, 713 Register scratch1, 714 Register scratch2, 715 Label* gc_required); 716 717 // Allocates a heap number or jumps to the gc_required label if the young 718 // space is full and a scavenge is needed. All registers are clobbered also 719 // when control continues at the gc_required label. 720 void AllocateHeapNumber(Register result, 721 Register scratch1, 722 Register scratch2, 723 Register heap_number_map, 724 Label* gc_required); 725 void AllocateHeapNumberWithValue(Register result, 726 DwVfpRegister value, 727 Register scratch1, 728 Register scratch2, 729 Register heap_number_map, 730 Label* gc_required); 731 732 // Copies a fixed number of fields of heap objects from src to dst. 733 void CopyFields(Register dst, Register src, RegList temps, int field_count); 734 735 // Copies a number of bytes from src to dst. All registers are clobbered. On 736 // exit src and dst will point to the place just after where the last byte was 737 // read or written and length will be zero. 738 void CopyBytes(Register src, 739 Register dst, 740 Register length, 741 Register scratch); 742 743 // Initialize fields with filler values. Fields starting at |start_offset| 744 // not including end_offset are overwritten with the value in |filler|. At 745 // the end the loop, |start_offset| takes the value of |end_offset|. 746 void InitializeFieldsWithFiller(Register start_offset, 747 Register end_offset, 748 Register filler); 749 750 // --------------------------------------------------------------------------- 751 // Support functions. 752 753 // Try to get function prototype of a function and puts the value in 754 // the result register. Checks that the function really is a 755 // function and jumps to the miss label if the fast checks fail. The 756 // function register will be untouched; the other registers may be 757 // clobbered. 758 void TryGetFunctionPrototype(Register function, 759 Register result, 760 Register scratch, 761 Label* miss, 762 bool miss_on_bound_function = false); 763 764 // Compare object type for heap object. heap_object contains a non-Smi 765 // whose object type should be compared with the given type. This both 766 // sets the flags and leaves the object type in the type_reg register. 767 // It leaves the map in the map register (unless the type_reg and map register 768 // are the same register). It leaves the heap object in the heap_object 769 // register unless the heap_object register is the same register as one of the 770 // other registers. 771 void CompareObjectType(Register heap_object, 772 Register map, 773 Register type_reg, 774 InstanceType type); 775 776 // Compare instance type in a map. map contains a valid map object whose 777 // object type should be compared with the given type. This both 778 // sets the flags and leaves the object type in the type_reg register. 779 void CompareInstanceType(Register map, 780 Register type_reg, 781 InstanceType type); 782 783 784 // Check if a map for a JSObject indicates that the object has fast elements. 785 // Jump to the specified label if it does not. 786 void CheckFastElements(Register map, 787 Register scratch, 788 Label* fail); 789 790 // Check if a map for a JSObject indicates that the object can have both smi 791 // and HeapObject elements. Jump to the specified label if it does not. 792 void CheckFastObjectElements(Register map, 793 Register scratch, 794 Label* fail); 795 796 // Check if a map for a JSObject indicates that the object has fast smi only 797 // elements. Jump to the specified label if it does not. 798 void CheckFastSmiOnlyElements(Register map, 799 Register scratch, 800 Label* fail); 801 802 // Check to see if maybe_number can be stored as a double in 803 // FastDoubleElements. If it can, store it at the index specified by key in 804 // the FastDoubleElements array elements. Otherwise jump to fail, in which 805 // case scratch2, scratch3 and scratch4 are unmodified. 806 void StoreNumberToDoubleElements(Register value_reg, 807 Register key_reg, 808 Register receiver_reg, 809 Register elements_reg, 810 Register scratch1, 811 Register scratch2, 812 Register scratch3, 813 Register scratch4, 814 Label* fail); 815 816 // Compare an object's map with the specified map and its transitioned 817 // elements maps if mode is ALLOW_ELEMENT_TRANSITION_MAPS. Condition flags are 818 // set with result of map compare. If multiple map compares are required, the 819 // compare sequences branches to early_success. 820 void CompareMap(Register obj, 821 Register scratch, 822 Handle<Map> map, 823 Label* early_success, 824 CompareMapMode mode = REQUIRE_EXACT_MAP); 825 826 // Check if the map of an object is equal to a specified map and branch to 827 // label if not. Skip the smi check if not required (object is known to be a 828 // heap object). If mode is ALLOW_ELEMENT_TRANSITION_MAPS, then also match 829 // against maps that are ElementsKind transition maps of the specified map. 830 void CheckMap(Register obj, 831 Register scratch, 832 Handle<Map> map, 833 Label* fail, 834 SmiCheckType smi_check_type, 835 CompareMapMode mode = REQUIRE_EXACT_MAP); 836 837 838 void CheckMap(Register obj, 839 Register scratch, 840 Heap::RootListIndex index, 841 Label* fail, 842 SmiCheckType smi_check_type); 843 844 845 // Check if the map of an object is equal to a specified map and branch to a 846 // specified target if equal. Skip the smi check if not required (object is 847 // known to be a heap object) 848 void DispatchMap(Register obj, 849 Register scratch, 850 Handle<Map> map, 851 Handle<Code> success, 852 SmiCheckType smi_check_type); 853 854 855 // Compare the object in a register to a value from the root list. 856 // Uses the ip register as scratch. 857 void CompareRoot(Register obj, Heap::RootListIndex index); 858 859 860 // Load and check the instance type of an object for being a string. 861 // Loads the type into the second argument register. 862 // Returns a condition that will be enabled if the object was a string. 863 Condition IsObjectStringType(Register obj, 864 Register type) { 865 ldr(type, FieldMemOperand(obj, HeapObject::kMapOffset)); 866 ldrb(type, FieldMemOperand(type, Map::kInstanceTypeOffset)); 867 tst(type, Operand(kIsNotStringMask)); 868 ASSERT_EQ(0, kStringTag); 869 return eq; 870 } 871 872 873 // Generates code for reporting that an illegal operation has 874 // occurred. 875 void IllegalOperation(int num_arguments); 876 877 // Picks out an array index from the hash field. 878 // Register use: 879 // hash - holds the index's hash. Clobbered. 880 // index - holds the overwritten index on exit. 881 void IndexFromHash(Register hash, Register index); 882 883 // Get the number of least significant bits from a register 884 void GetLeastBitsFromSmi(Register dst, Register src, int num_least_bits); 885 void GetLeastBitsFromInt32(Register dst, Register src, int mun_least_bits); 886 887 // Uses VFP instructions to Convert a Smi to a double. 888 void IntegerToDoubleConversionWithVFP3(Register inReg, 889 Register outHighReg, 890 Register outLowReg); 891 892 // Load the value of a number object into a VFP double register. If the object 893 // is not a number a jump to the label not_number is performed and the VFP 894 // double register is unchanged. 895 void ObjectToDoubleVFPRegister( 896 Register object, 897 DwVfpRegister value, 898 Register scratch1, 899 Register scratch2, 900 Register heap_number_map, 901 SwVfpRegister scratch3, 902 Label* not_number, 903 ObjectToDoubleFlags flags = NO_OBJECT_TO_DOUBLE_FLAGS); 904 905 // Load the value of a smi object into a VFP double register. The register 906 // scratch1 can be the same register as smi in which case smi will hold the 907 // untagged value afterwards. 908 void SmiToDoubleVFPRegister(Register smi, 909 DwVfpRegister value, 910 Register scratch1, 911 SwVfpRegister scratch2); 912 913 // Convert the HeapNumber pointed to by source to a 32bits signed integer 914 // dest. If the HeapNumber does not fit into a 32bits signed integer branch 915 // to not_int32 label. If VFP3 is available double_scratch is used but not 916 // scratch2. 917 void ConvertToInt32(Register source, 918 Register dest, 919 Register scratch, 920 Register scratch2, 921 DwVfpRegister double_scratch, 922 Label *not_int32); 923 924 // Truncates a double using a specific rounding mode. 925 // Clears the z flag (ne condition) if an overflow occurs. 926 // If exact_conversion is true, the z flag is also cleared if the conversion 927 // was inexact, i.e. if the double value could not be converted exactly 928 // to a 32bit integer. 929 void EmitVFPTruncate(VFPRoundingMode rounding_mode, 930 SwVfpRegister result, 931 DwVfpRegister double_input, 932 Register scratch1, 933 Register scratch2, 934 CheckForInexactConversion check 935 = kDontCheckForInexactConversion); 936 937 // Helper for EmitECMATruncate. 938 // This will truncate a floating-point value outside of the singed 32bit 939 // integer range to a 32bit signed integer. 940 // Expects the double value loaded in input_high and input_low. 941 // Exits with the answer in 'result'. 942 // Note that this code does not work for values in the 32bit range! 943 void EmitOutOfInt32RangeTruncate(Register result, 944 Register input_high, 945 Register input_low, 946 Register scratch); 947 948 // Performs a truncating conversion of a floating point number as used by 949 // the JS bitwise operations. See ECMA-262 9.5: ToInt32. 950 // Exits with 'result' holding the answer and all other registers clobbered. 951 void EmitECMATruncate(Register result, 952 DwVfpRegister double_input, 953 SwVfpRegister single_scratch, 954 Register scratch, 955 Register scratch2, 956 Register scratch3); 957 958 // Count leading zeros in a 32 bit word. On ARM5 and later it uses the clz 959 // instruction. On pre-ARM5 hardware this routine gives the wrong answer 960 // for 0 (31 instead of 32). Source and scratch can be the same in which case 961 // the source is clobbered. Source and zeros can also be the same in which 962 // case scratch should be a different register. 963 void CountLeadingZeros(Register zeros, 964 Register source, 965 Register scratch); 966 967 // --------------------------------------------------------------------------- 968 // Runtime calls 969 970 // Call a code stub. 971 void CallStub(CodeStub* stub, Condition cond = al); 972 973 // Call a code stub. 974 void TailCallStub(CodeStub* stub, Condition cond = al); 975 976 // Call a runtime routine. 977 void CallRuntime(const Runtime::Function* f, int num_arguments); 978 void CallRuntimeSaveDoubles(Runtime::FunctionId id); 979 980 // Convenience function: Same as above, but takes the fid instead. 981 void CallRuntime(Runtime::FunctionId fid, int num_arguments); 982 983 // Convenience function: call an external reference. 984 void CallExternalReference(const ExternalReference& ext, 985 int num_arguments); 986 987 // Tail call of a runtime routine (jump). 988 // Like JumpToExternalReference, but also takes care of passing the number 989 // of parameters. 990 void TailCallExternalReference(const ExternalReference& ext, 991 int num_arguments, 992 int result_size); 993 994 // Convenience function: tail call a runtime routine (jump). 995 void TailCallRuntime(Runtime::FunctionId fid, 996 int num_arguments, 997 int result_size); 998 999 int CalculateStackPassedWords(int num_reg_arguments, 1000 int num_double_arguments); 1001 1002 // Before calling a C-function from generated code, align arguments on stack. 1003 // After aligning the frame, non-register arguments must be stored in 1004 // sp[0], sp[4], etc., not pushed. The argument count assumes all arguments 1005 // are word sized. If double arguments are used, this function assumes that 1006 // all double arguments are stored before core registers; otherwise the 1007 // correct alignment of the double values is not guaranteed. 1008 // Some compilers/platforms require the stack to be aligned when calling 1009 // C++ code. 1010 // Needs a scratch register to do some arithmetic. This register will be 1011 // trashed. 1012 void PrepareCallCFunction(int num_reg_arguments, 1013 int num_double_registers, 1014 Register scratch); 1015 void PrepareCallCFunction(int num_reg_arguments, 1016 Register scratch); 1017 1018 // There are two ways of passing double arguments on ARM, depending on 1019 // whether soft or hard floating point ABI is used. These functions 1020 // abstract parameter passing for the three different ways we call 1021 // C functions from generated code. 1022 void SetCallCDoubleArguments(DoubleRegister dreg); 1023 void SetCallCDoubleArguments(DoubleRegister dreg1, DoubleRegister dreg2); 1024 void SetCallCDoubleArguments(DoubleRegister dreg, Register reg); 1025 1026 // Calls a C function and cleans up the space for arguments allocated 1027 // by PrepareCallCFunction. The called function is not allowed to trigger a 1028 // garbage collection, since that might move the code and invalidate the 1029 // return address (unless this is somehow accounted for by the called 1030 // function). 1031 void CallCFunction(ExternalReference function, int num_arguments); 1032 void CallCFunction(Register function, int num_arguments); 1033 void CallCFunction(ExternalReference function, 1034 int num_reg_arguments, 1035 int num_double_arguments); 1036 void CallCFunction(Register function, 1037 int num_reg_arguments, 1038 int num_double_arguments); 1039 1040 void GetCFunctionDoubleResult(const DoubleRegister dst); 1041 1042 // Calls an API function. Allocates HandleScope, extracts returned value 1043 // from handle and propagates exceptions. Restores context. stack_space 1044 // - space to be unwound on exit (includes the call JS arguments space and 1045 // the additional space allocated for the fast call). 1046 void CallApiFunctionAndReturn(ExternalReference function, int stack_space); 1047 1048 // Jump to a runtime routine. 1049 void JumpToExternalReference(const ExternalReference& builtin); 1050 1051 // Invoke specified builtin JavaScript function. Adds an entry to 1052 // the unresolved list if the name does not resolve. 1053 void InvokeBuiltin(Builtins::JavaScript id, 1054 InvokeFlag flag, 1055 const CallWrapper& call_wrapper = NullCallWrapper()); 1056 1057 // Store the code object for the given builtin in the target register and 1058 // setup the function in r1. 1059 void GetBuiltinEntry(Register target, Builtins::JavaScript id); 1060 1061 // Store the function for the given builtin in the target register. 1062 void GetBuiltinFunction(Register target, Builtins::JavaScript id); 1063 1064 Handle<Object> CodeObject() { 1065 ASSERT(!code_object_.is_null()); 1066 return code_object_; 1067 } 1068 1069 1070 // --------------------------------------------------------------------------- 1071 // StatsCounter support 1072 1073 void SetCounter(StatsCounter* counter, int value, 1074 Register scratch1, Register scratch2); 1075 void IncrementCounter(StatsCounter* counter, int value, 1076 Register scratch1, Register scratch2); 1077 void DecrementCounter(StatsCounter* counter, int value, 1078 Register scratch1, Register scratch2); 1079 1080 1081 // --------------------------------------------------------------------------- 1082 // Debugging 1083 1084 // Calls Abort(msg) if the condition cond is not satisfied. 1085 // Use --debug_code to enable. 1086 void Assert(Condition cond, const char* msg); 1087 void AssertRegisterIsRoot(Register reg, Heap::RootListIndex index); 1088 void AssertFastElements(Register elements); 1089 1090 // Like Assert(), but always enabled. 1091 void Check(Condition cond, const char* msg); 1092 1093 // Print a message to stdout and abort execution. 1094 void Abort(const char* msg); 1095 1096 // Verify restrictions about code generated in stubs. 1097 void set_generating_stub(bool value) { generating_stub_ = value; } 1098 bool generating_stub() { return generating_stub_; } 1099 void set_allow_stub_calls(bool value) { allow_stub_calls_ = value; } 1100 bool allow_stub_calls() { return allow_stub_calls_; } 1101 void set_has_frame(bool value) { has_frame_ = value; } 1102 bool has_frame() { return has_frame_; } 1103 inline bool AllowThisStubCall(CodeStub* stub); 1104 1105 // EABI variant for double arguments in use. 1106 bool use_eabi_hardfloat() { 1107 #if USE_EABI_HARDFLOAT 1108 return true; 1109 #else 1110 return false; 1111 #endif 1112 } 1113 1114 // --------------------------------------------------------------------------- 1115 // Number utilities 1116 1117 // Check whether the value of reg is a power of two and not zero. If not 1118 // control continues at the label not_power_of_two. If reg is a power of two 1119 // the register scratch contains the value of (reg - 1) when control falls 1120 // through. 1121 void JumpIfNotPowerOfTwoOrZero(Register reg, 1122 Register scratch, 1123 Label* not_power_of_two_or_zero); 1124 // Check whether the value of reg is a power of two and not zero. 1125 // Control falls through if it is, with scratch containing the mask 1126 // value (reg - 1). 1127 // Otherwise control jumps to the 'zero_and_neg' label if the value of reg is 1128 // zero or negative, or jumps to the 'not_power_of_two' label if the value is 1129 // strictly positive but not a power of two. 1130 void JumpIfNotPowerOfTwoOrZeroAndNeg(Register reg, 1131 Register scratch, 1132 Label* zero_and_neg, 1133 Label* not_power_of_two); 1134 1135 // --------------------------------------------------------------------------- 1136 // Smi utilities 1137 1138 void SmiTag(Register reg, SBit s = LeaveCC) { 1139 add(reg, reg, Operand(reg), s); 1140 } 1141 void SmiTag(Register dst, Register src, SBit s = LeaveCC) { 1142 add(dst, src, Operand(src), s); 1143 } 1144 1145 // Try to convert int32 to smi. If the value is to large, preserve 1146 // the original value and jump to not_a_smi. Destroys scratch and 1147 // sets flags. 1148 void TrySmiTag(Register reg, Label* not_a_smi, Register scratch) { 1149 mov(scratch, reg); 1150 SmiTag(scratch, SetCC); 1151 b(vs, not_a_smi); 1152 mov(reg, scratch); 1153 } 1154 1155 void SmiUntag(Register reg, SBit s = LeaveCC) { 1156 mov(reg, Operand(reg, ASR, kSmiTagSize), s); 1157 } 1158 void SmiUntag(Register dst, Register src, SBit s = LeaveCC) { 1159 mov(dst, Operand(src, ASR, kSmiTagSize), s); 1160 } 1161 1162 // Untag the source value into destination and jump if source is a smi. 1163 // Souce and destination can be the same register. 1164 void UntagAndJumpIfSmi(Register dst, Register src, Label* smi_case); 1165 1166 // Untag the source value into destination and jump if source is not a smi. 1167 // Souce and destination can be the same register. 1168 void UntagAndJumpIfNotSmi(Register dst, Register src, Label* non_smi_case); 1169 1170 // Jump the register contains a smi. 1171 inline void JumpIfSmi(Register value, Label* smi_label) { 1172 tst(value, Operand(kSmiTagMask)); 1173 b(eq, smi_label); 1174 } 1175 // Jump if either of the registers contain a non-smi. 1176 inline void JumpIfNotSmi(Register value, Label* not_smi_label) { 1177 tst(value, Operand(kSmiTagMask)); 1178 b(ne, not_smi_label); 1179 } 1180 // Jump if either of the registers contain a non-smi. 1181 void JumpIfNotBothSmi(Register reg1, Register reg2, Label* on_not_both_smi); 1182 // Jump if either of the registers contain a smi. 1183 void JumpIfEitherSmi(Register reg1, Register reg2, Label* on_either_smi); 1184 1185 // Abort execution if argument is a smi. Used in debug code. 1186 void AbortIfSmi(Register object); 1187 void AbortIfNotSmi(Register object); 1188 1189 // Abort execution if argument is a string. Used in debug code. 1190 void AbortIfNotString(Register object); 1191 1192 // Abort execution if argument is not the root value with the given index. 1193 void AbortIfNotRootValue(Register src, 1194 Heap::RootListIndex root_value_index, 1195 const char* message); 1196 1197 // --------------------------------------------------------------------------- 1198 // HeapNumber utilities 1199 1200 void JumpIfNotHeapNumber(Register object, 1201 Register heap_number_map, 1202 Register scratch, 1203 Label* on_not_heap_number); 1204 1205 // --------------------------------------------------------------------------- 1206 // String utilities 1207 1208 // Checks if both objects are sequential ASCII strings and jumps to label 1209 // if either is not. Assumes that neither object is a smi. 1210 void JumpIfNonSmisNotBothSequentialAsciiStrings(Register object1, 1211 Register object2, 1212 Register scratch1, 1213 Register scratch2, 1214 Label* failure); 1215 1216 // Checks if both objects are sequential ASCII strings and jumps to label 1217 // if either is not. 1218 void JumpIfNotBothSequentialAsciiStrings(Register first, 1219 Register second, 1220 Register scratch1, 1221 Register scratch2, 1222 Label* not_flat_ascii_strings); 1223 1224 // Checks if both instance types are sequential ASCII strings and jumps to 1225 // label if either is not. 1226 void JumpIfBothInstanceTypesAreNotSequentialAscii( 1227 Register first_object_instance_type, 1228 Register second_object_instance_type, 1229 Register scratch1, 1230 Register scratch2, 1231 Label* failure); 1232 1233 // Check if instance type is sequential ASCII string and jump to label if 1234 // it is not. 1235 void JumpIfInstanceTypeIsNotSequentialAscii(Register type, 1236 Register scratch, 1237 Label* failure); 1238 1239 1240 // --------------------------------------------------------------------------- 1241 // Patching helpers. 1242 1243 // Get the location of a relocated constant (its address in the constant pool) 1244 // from its load site. 1245 void GetRelocatedValueLocation(Register ldr_location, 1246 Register result); 1247 1248 1249 void ClampUint8(Register output_reg, Register input_reg); 1250 1251 void ClampDoubleToUint8(Register result_reg, 1252 DoubleRegister input_reg, 1253 DoubleRegister temp_double_reg); 1254 1255 1256 void LoadInstanceDescriptors(Register map, Register descriptors); 1257 1258 // Activation support. 1259 void EnterFrame(StackFrame::Type type); 1260 void LeaveFrame(StackFrame::Type type); 1261 1262 // Expects object in r0 and returns map with validated enum cache 1263 // in r0. Assumes that any other register can be used as a scratch. 1264 void CheckEnumCache(Register null_value, Label* call_runtime); 1265 1266 private: 1267 void CallCFunctionHelper(Register function, 1268 int num_reg_arguments, 1269 int num_double_arguments); 1270 1271 void Jump(intptr_t target, RelocInfo::Mode rmode, Condition cond = al); 1272 1273 // Helper functions for generating invokes. 1274 void InvokePrologue(const ParameterCount& expected, 1275 const ParameterCount& actual, 1276 Handle<Code> code_constant, 1277 Register code_reg, 1278 Label* done, 1279 bool* definitely_mismatches, 1280 InvokeFlag flag, 1281 const CallWrapper& call_wrapper, 1282 CallKind call_kind); 1283 1284 void InitializeNewString(Register string, 1285 Register length, 1286 Heap::RootListIndex map_index, 1287 Register scratch1, 1288 Register scratch2); 1289 1290 // Helper for implementing JumpIfNotInNewSpace and JumpIfInNewSpace. 1291 void InNewSpace(Register object, 1292 Register scratch, 1293 Condition cond, // eq for new space, ne otherwise. 1294 Label* branch); 1295 1296 // Helper for finding the mark bits for an address. Afterwards, the 1297 // bitmap register points at the word with the mark bits and the mask 1298 // the position of the first bit. Leaves addr_reg unchanged. 1299 inline void GetMarkBits(Register addr_reg, 1300 Register bitmap_reg, 1301 Register mask_reg); 1302 1303 // Helper for throwing exceptions. Compute a handler address and jump to 1304 // it. See the implementation for register usage. 1305 void JumpToHandlerEntry(); 1306 1307 // Compute memory operands for safepoint stack slots. 1308 static int SafepointRegisterStackIndex(int reg_code); 1309 MemOperand SafepointRegisterSlot(Register reg); 1310 MemOperand SafepointRegistersAndDoublesSlot(Register reg); 1311 1312 bool generating_stub_; 1313 bool allow_stub_calls_; 1314 bool has_frame_; 1315 // This handle will be patched with the code object on installation. 1316 Handle<Object> code_object_; 1317 1318 // Needs access to SafepointRegisterStackIndex for optimized frame 1319 // traversal. 1320 friend class OptimizedFrame; 1321 }; 1322 1323 1324 #ifdef ENABLE_DEBUGGER_SUPPORT 1325 // The code patcher is used to patch (typically) small parts of code e.g. for 1326 // debugging and other types of instrumentation. When using the code patcher 1327 // the exact number of bytes specified must be emitted. It is not legal to emit 1328 // relocation information. If any of these constraints are violated it causes 1329 // an assertion to fail. 1330 class CodePatcher { 1331 public: 1332 CodePatcher(byte* address, int instructions); 1333 virtual ~CodePatcher(); 1334 1335 // Macro assembler to emit code. 1336 MacroAssembler* masm() { return &masm_; } 1337 1338 // Emit an instruction directly. 1339 void Emit(Instr instr); 1340 1341 // Emit an address directly. 1342 void Emit(Address addr); 1343 1344 // Emit the condition part of an instruction leaving the rest of the current 1345 // instruction unchanged. 1346 void EmitCondition(Condition cond); 1347 1348 private: 1349 byte* address_; // The address of the code being patched. 1350 int instructions_; // Number of instructions of the expected patch size. 1351 int size_; // Number of bytes of the expected patch size. 1352 MacroAssembler masm_; // Macro assembler used to generate the code. 1353 }; 1354 #endif // ENABLE_DEBUGGER_SUPPORT 1355 1356 1357 // ----------------------------------------------------------------------------- 1358 // Static helper functions. 1359 1360 inline MemOperand ContextOperand(Register context, int index) { 1361 return MemOperand(context, Context::SlotOffset(index)); 1362 } 1363 1364 1365 inline MemOperand GlobalObjectOperand() { 1366 return ContextOperand(cp, Context::GLOBAL_INDEX); 1367 } 1368 1369 1370 #ifdef GENERATED_CODE_COVERAGE 1371 #define CODE_COVERAGE_STRINGIFY(x) #x 1372 #define CODE_COVERAGE_TOSTRING(x) CODE_COVERAGE_STRINGIFY(x) 1373 #define __FILE_LINE__ __FILE__ ":" CODE_COVERAGE_TOSTRING(__LINE__) 1374 #define ACCESS_MASM(masm) masm->stop(__FILE_LINE__); masm-> 1375 #else 1376 #define ACCESS_MASM(masm) masm-> 1377 #endif 1378 1379 1380 } } // namespace v8::internal 1381 1382 #endif // V8_ARM_MACRO_ASSEMBLER_ARM_H_ 1383