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 // Give alias names to registers 48 const Register cp = { 8 }; // JavaScript context pointer 49 const Register kRootRegister = { 10 }; // Roots array pointer. 50 51 // Flags used for AllocateHeapNumber 52 enum TaggingMode { 53 // Tag the result. 54 TAG_RESULT, 55 // Don't tag 56 DONT_TAG_RESULT 57 }; 58 59 60 enum RememberedSetAction { EMIT_REMEMBERED_SET, OMIT_REMEMBERED_SET }; 61 enum SmiCheck { INLINE_SMI_CHECK, OMIT_SMI_CHECK }; 62 enum LinkRegisterStatus { kLRHasNotBeenSaved, kLRHasBeenSaved }; 63 64 65 #ifdef DEBUG 66 bool AreAliased(Register reg1, 67 Register reg2, 68 Register reg3 = no_reg, 69 Register reg4 = no_reg, 70 Register reg5 = no_reg, 71 Register reg6 = no_reg); 72 #endif 73 74 75 enum TargetAddressStorageMode { 76 CAN_INLINE_TARGET_ADDRESS, 77 NEVER_INLINE_TARGET_ADDRESS 78 }; 79 80 // MacroAssembler implements a collection of frequently used macros. 81 class MacroAssembler: public Assembler { 82 public: 83 // The isolate parameter can be NULL if the macro assembler should 84 // not use isolate-dependent functionality. In this case, it's the 85 // responsibility of the caller to never invoke such function on the 86 // macro assembler. 87 MacroAssembler(Isolate* isolate, void* buffer, int size); 88 89 // Jump, Call, and Ret pseudo instructions implementing inter-working. 90 void Jump(Register target, Condition cond = al); 91 void Jump(Address target, RelocInfo::Mode rmode, Condition cond = al); 92 void Jump(Handle<Code> code, RelocInfo::Mode rmode, Condition cond = al); 93 static int CallSize(Register target, Condition cond = al); 94 void Call(Register target, Condition cond = al); 95 int CallSize(Address target, RelocInfo::Mode rmode, Condition cond = al); 96 static int CallSizeNotPredictableCodeSize(Address target, 97 RelocInfo::Mode rmode, 98 Condition cond = al); 99 void Call(Address target, RelocInfo::Mode rmode, 100 Condition cond = al, 101 TargetAddressStorageMode mode = CAN_INLINE_TARGET_ADDRESS); 102 int CallSize(Handle<Code> code, 103 RelocInfo::Mode rmode = RelocInfo::CODE_TARGET, 104 TypeFeedbackId ast_id = TypeFeedbackId::None(), 105 Condition cond = al); 106 void Call(Handle<Code> code, 107 RelocInfo::Mode rmode = RelocInfo::CODE_TARGET, 108 TypeFeedbackId ast_id = TypeFeedbackId::None(), 109 Condition cond = al, 110 TargetAddressStorageMode mode = CAN_INLINE_TARGET_ADDRESS); 111 void Ret(Condition cond = al); 112 113 // Emit code to discard a non-negative number of pointer-sized elements 114 // from the stack, clobbering only the sp register. 115 void Drop(int count, Condition cond = al); 116 117 void Ret(int drop, Condition cond = al); 118 119 // Swap two registers. If the scratch register is omitted then a slightly 120 // less efficient form using xor instead of mov is emitted. 121 void Swap(Register reg1, 122 Register reg2, 123 Register scratch = no_reg, 124 Condition cond = al); 125 126 127 void And(Register dst, Register src1, const Operand& src2, 128 Condition cond = al); 129 void Ubfx(Register dst, Register src, int lsb, int width, 130 Condition cond = al); 131 void Sbfx(Register dst, Register src, int lsb, int width, 132 Condition cond = al); 133 // The scratch register is not used for ARMv7. 134 // scratch can be the same register as src (in which case it is trashed), but 135 // not the same as dst. 136 void Bfi(Register dst, 137 Register src, 138 Register scratch, 139 int lsb, 140 int width, 141 Condition cond = al); 142 void Bfc(Register dst, Register src, int lsb, int width, Condition cond = al); 143 void Usat(Register dst, int satpos, const Operand& src, 144 Condition cond = al); 145 146 void Call(Label* target); 147 void Push(Register src) { push(src); } 148 void Pop(Register dst) { pop(dst); } 149 150 // Register move. May do nothing if the registers are identical. 151 void Move(Register dst, Handle<Object> value); 152 void Move(Register dst, Register src, Condition cond = al); 153 void Move(DwVfpRegister dst, DwVfpRegister src); 154 155 // Load an object from the root table. 156 void LoadRoot(Register destination, 157 Heap::RootListIndex index, 158 Condition cond = al); 159 // Store an object to the root table. 160 void StoreRoot(Register source, 161 Heap::RootListIndex index, 162 Condition cond = al); 163 164 void LoadHeapObject(Register dst, Handle<HeapObject> object); 165 166 void LoadObject(Register result, Handle<Object> object) { 167 AllowDeferredHandleDereference heap_object_check; 168 if (object->IsHeapObject()) { 169 LoadHeapObject(result, Handle<HeapObject>::cast(object)); 170 } else { 171 Move(result, object); 172 } 173 } 174 175 // --------------------------------------------------------------------------- 176 // GC Support 177 178 void IncrementalMarkingRecordWriteHelper(Register object, 179 Register value, 180 Register address); 181 182 enum RememberedSetFinalAction { 183 kReturnAtEnd, 184 kFallThroughAtEnd 185 }; 186 187 // Record in the remembered set the fact that we have a pointer to new space 188 // at the address pointed to by the addr register. Only works if addr is not 189 // in new space. 190 void RememberedSetHelper(Register object, // Used for debug code. 191 Register addr, 192 Register scratch, 193 SaveFPRegsMode save_fp, 194 RememberedSetFinalAction and_then); 195 196 void CheckPageFlag(Register object, 197 Register scratch, 198 int mask, 199 Condition cc, 200 Label* condition_met); 201 202 void CheckMapDeprecated(Handle<Map> map, 203 Register scratch, 204 Label* if_deprecated); 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 void Push(Smi* smi) { Push(Handle<Smi>(smi, isolate())); } 303 304 // Push two registers. Pushes leftmost register first (to highest address). 305 void Push(Register src1, Register src2, Condition cond = al) { 306 ASSERT(!src1.is(src2)); 307 if (src1.code() > src2.code()) { 308 stm(db_w, sp, src1.bit() | src2.bit(), cond); 309 } else { 310 str(src1, MemOperand(sp, 4, NegPreIndex), cond); 311 str(src2, MemOperand(sp, 4, NegPreIndex), cond); 312 } 313 } 314 315 // Push three registers. Pushes leftmost register first (to highest address). 316 void Push(Register src1, Register src2, Register src3, Condition cond = al) { 317 ASSERT(!src1.is(src2)); 318 ASSERT(!src2.is(src3)); 319 ASSERT(!src1.is(src3)); 320 if (src1.code() > src2.code()) { 321 if (src2.code() > src3.code()) { 322 stm(db_w, sp, src1.bit() | src2.bit() | src3.bit(), cond); 323 } else { 324 stm(db_w, sp, src1.bit() | src2.bit(), cond); 325 str(src3, MemOperand(sp, 4, NegPreIndex), cond); 326 } 327 } else { 328 str(src1, MemOperand(sp, 4, NegPreIndex), cond); 329 Push(src2, src3, cond); 330 } 331 } 332 333 // Push four registers. Pushes leftmost register first (to highest address). 334 void Push(Register src1, 335 Register src2, 336 Register src3, 337 Register src4, 338 Condition cond = al) { 339 ASSERT(!src1.is(src2)); 340 ASSERT(!src2.is(src3)); 341 ASSERT(!src1.is(src3)); 342 ASSERT(!src1.is(src4)); 343 ASSERT(!src2.is(src4)); 344 ASSERT(!src3.is(src4)); 345 if (src1.code() > src2.code()) { 346 if (src2.code() > src3.code()) { 347 if (src3.code() > src4.code()) { 348 stm(db_w, 349 sp, 350 src1.bit() | src2.bit() | src3.bit() | src4.bit(), 351 cond); 352 } else { 353 stm(db_w, sp, src1.bit() | src2.bit() | src3.bit(), cond); 354 str(src4, MemOperand(sp, 4, NegPreIndex), cond); 355 } 356 } else { 357 stm(db_w, sp, src1.bit() | src2.bit(), cond); 358 Push(src3, src4, cond); 359 } 360 } else { 361 str(src1, MemOperand(sp, 4, NegPreIndex), cond); 362 Push(src2, src3, src4, cond); 363 } 364 } 365 366 // Pop two registers. Pops rightmost register first (from lower address). 367 void Pop(Register src1, Register src2, Condition cond = al) { 368 ASSERT(!src1.is(src2)); 369 if (src1.code() > src2.code()) { 370 ldm(ia_w, sp, src1.bit() | src2.bit(), cond); 371 } else { 372 ldr(src2, MemOperand(sp, 4, PostIndex), cond); 373 ldr(src1, MemOperand(sp, 4, PostIndex), cond); 374 } 375 } 376 377 // Pop three registers. Pops rightmost register first (from lower address). 378 void Pop(Register src1, Register src2, Register src3, Condition cond = al) { 379 ASSERT(!src1.is(src2)); 380 ASSERT(!src2.is(src3)); 381 ASSERT(!src1.is(src3)); 382 if (src1.code() > src2.code()) { 383 if (src2.code() > src3.code()) { 384 ldm(ia_w, sp, src1.bit() | src2.bit() | src3.bit(), cond); 385 } else { 386 ldr(src3, MemOperand(sp, 4, PostIndex), cond); 387 ldm(ia_w, sp, src1.bit() | src2.bit(), cond); 388 } 389 } else { 390 Pop(src2, src3, cond); 391 str(src1, MemOperand(sp, 4, PostIndex), cond); 392 } 393 } 394 395 // Pop four registers. Pops rightmost register first (from lower address). 396 void Pop(Register src1, 397 Register src2, 398 Register src3, 399 Register src4, 400 Condition cond = al) { 401 ASSERT(!src1.is(src2)); 402 ASSERT(!src2.is(src3)); 403 ASSERT(!src1.is(src3)); 404 ASSERT(!src1.is(src4)); 405 ASSERT(!src2.is(src4)); 406 ASSERT(!src3.is(src4)); 407 if (src1.code() > src2.code()) { 408 if (src2.code() > src3.code()) { 409 if (src3.code() > src4.code()) { 410 ldm(ia_w, 411 sp, 412 src1.bit() | src2.bit() | src3.bit() | src4.bit(), 413 cond); 414 } else { 415 ldr(src4, MemOperand(sp, 4, PostIndex), cond); 416 ldm(ia_w, sp, src1.bit() | src2.bit() | src3.bit(), cond); 417 } 418 } else { 419 Pop(src3, src4, cond); 420 ldm(ia_w, sp, src1.bit() | src2.bit(), cond); 421 } 422 } else { 423 Pop(src2, src3, src4, cond); 424 ldr(src1, MemOperand(sp, 4, PostIndex), cond); 425 } 426 } 427 428 // Push and pop the registers that can hold pointers, as defined by the 429 // RegList constant kSafepointSavedRegisters. 430 void PushSafepointRegisters(); 431 void PopSafepointRegisters(); 432 void PushSafepointRegistersAndDoubles(); 433 void PopSafepointRegistersAndDoubles(); 434 // Store value in register src in the safepoint stack slot for 435 // register dst. 436 void StoreToSafepointRegisterSlot(Register src, Register dst); 437 void StoreToSafepointRegistersAndDoublesSlot(Register src, Register dst); 438 // Load the value of the src register from its safepoint stack slot 439 // into register dst. 440 void LoadFromSafepointRegisterSlot(Register dst, Register src); 441 442 // Load two consecutive registers with two consecutive memory locations. 443 void Ldrd(Register dst1, 444 Register dst2, 445 const MemOperand& src, 446 Condition cond = al); 447 448 // Store two consecutive registers to two consecutive memory locations. 449 void Strd(Register src1, 450 Register src2, 451 const MemOperand& dst, 452 Condition cond = al); 453 454 // Ensure that FPSCR contains values needed by JavaScript. 455 // We need the NaNModeControlBit to be sure that operations like 456 // vadd and vsub generate the Canonical NaN (if a NaN must be generated). 457 // In VFP3 it will be always the Canonical NaN. 458 // In VFP2 it will be either the Canonical NaN or the negative version 459 // of the Canonical NaN. It doesn't matter if we have two values. The aim 460 // is to be sure to never generate the hole NaN. 461 void VFPEnsureFPSCRState(Register scratch); 462 463 // If the value is a NaN, canonicalize the value else, do nothing. 464 void VFPCanonicalizeNaN(const DwVfpRegister value, 465 const Condition cond = al); 466 467 // Compare double values and move the result to the normal condition flags. 468 void VFPCompareAndSetFlags(const DwVfpRegister src1, 469 const DwVfpRegister src2, 470 const Condition cond = al); 471 void VFPCompareAndSetFlags(const DwVfpRegister src1, 472 const double src2, 473 const Condition cond = al); 474 475 // Compare double values and then load the fpscr flags to a register. 476 void VFPCompareAndLoadFlags(const DwVfpRegister src1, 477 const DwVfpRegister src2, 478 const Register fpscr_flags, 479 const Condition cond = al); 480 void VFPCompareAndLoadFlags(const DwVfpRegister src1, 481 const double src2, 482 const Register fpscr_flags, 483 const Condition cond = al); 484 485 void Vmov(const DwVfpRegister dst, 486 const double imm, 487 const Register scratch = no_reg); 488 489 void VmovHigh(Register dst, DwVfpRegister src); 490 void VmovHigh(DwVfpRegister dst, Register src); 491 void VmovLow(Register dst, DwVfpRegister src); 492 void VmovLow(DwVfpRegister dst, Register src); 493 494 // Converts the smi or heap number in object to an int32 using the rules 495 // for ToInt32 as described in ECMAScript 9.5.: the value is truncated 496 // and brought into the range -2^31 .. +2^31 - 1. 497 void ConvertNumberToInt32(Register object, 498 Register dst, 499 Register heap_number_map, 500 Register scratch1, 501 Register scratch2, 502 Register scratch3, 503 DwVfpRegister double_scratch1, 504 LowDwVfpRegister double_scratch2, 505 Label* not_int32); 506 507 // Loads the number from object into dst register. 508 // If |object| is neither smi nor heap number, |not_number| is jumped to 509 // with |object| still intact. 510 void LoadNumber(Register object, 511 LowDwVfpRegister dst, 512 Register heap_number_map, 513 Register scratch, 514 Label* not_number); 515 516 // Loads the number from object into double_dst in the double format. 517 // Control will jump to not_int32 if the value cannot be exactly represented 518 // by a 32-bit integer. 519 // Floating point value in the 32-bit integer range that are not exact integer 520 // won't be loaded. 521 void LoadNumberAsInt32Double(Register object, 522 DwVfpRegister double_dst, 523 Register heap_number_map, 524 Register scratch, 525 LowDwVfpRegister double_scratch, 526 Label* not_int32); 527 528 // Loads the number from object into dst as a 32-bit integer. 529 // Control will jump to not_int32 if the object cannot be exactly represented 530 // by a 32-bit integer. 531 // Floating point value in the 32-bit integer range that are not exact integer 532 // won't be converted. 533 void LoadNumberAsInt32(Register object, 534 Register dst, 535 Register heap_number_map, 536 Register scratch, 537 DwVfpRegister double_scratch0, 538 LowDwVfpRegister double_scratch1, 539 Label* not_int32); 540 541 542 // Enter exit frame. 543 // stack_space - extra stack space, used for alignment before call to C. 544 void EnterExitFrame(bool save_doubles, int stack_space = 0); 545 546 // Leave the current exit frame. Expects the return value in r0. 547 // Expect the number of values, pushed prior to the exit frame, to 548 // remove in a register (or no_reg, if there is nothing to remove). 549 void LeaveExitFrame(bool save_doubles, Register argument_count); 550 551 // Get the actual activation frame alignment for target environment. 552 static int ActivationFrameAlignment(); 553 554 void LoadContext(Register dst, int context_chain_length); 555 556 // Conditionally load the cached Array transitioned map of type 557 // transitioned_kind from the native context if the map in register 558 // map_in_out is the cached Array map in the native context of 559 // expected_kind. 560 void LoadTransitionedArrayMapConditional( 561 ElementsKind expected_kind, 562 ElementsKind transitioned_kind, 563 Register map_in_out, 564 Register scratch, 565 Label* no_map_match); 566 567 // Load the initial map for new Arrays from a JSFunction. 568 void LoadInitialArrayMap(Register function_in, 569 Register scratch, 570 Register map_out, 571 bool can_have_holes); 572 573 void LoadGlobalFunction(int index, Register function); 574 void LoadArrayFunction(Register function); 575 576 // Load the initial map from the global function. The registers 577 // function and map can be the same, function is then overwritten. 578 void LoadGlobalFunctionInitialMap(Register function, 579 Register map, 580 Register scratch); 581 582 void InitializeRootRegister() { 583 ExternalReference roots_array_start = 584 ExternalReference::roots_array_start(isolate()); 585 mov(kRootRegister, Operand(roots_array_start)); 586 } 587 588 // --------------------------------------------------------------------------- 589 // JavaScript invokes 590 591 // Set up call kind marking in ecx. The method takes ecx as an 592 // explicit first parameter to make the code more readable at the 593 // call sites. 594 void SetCallKind(Register dst, CallKind kind); 595 596 // Invoke the JavaScript function code by either calling or jumping. 597 void InvokeCode(Register code, 598 const ParameterCount& expected, 599 const ParameterCount& actual, 600 InvokeFlag flag, 601 const CallWrapper& call_wrapper, 602 CallKind call_kind); 603 604 void InvokeCode(Handle<Code> code, 605 const ParameterCount& expected, 606 const ParameterCount& actual, 607 RelocInfo::Mode rmode, 608 InvokeFlag flag, 609 CallKind call_kind); 610 611 // Invoke the JavaScript function in the given register. Changes the 612 // current context to the context in the function before invoking. 613 void InvokeFunction(Register function, 614 const ParameterCount& actual, 615 InvokeFlag flag, 616 const CallWrapper& call_wrapper, 617 CallKind call_kind); 618 619 void InvokeFunction(Handle<JSFunction> function, 620 const ParameterCount& expected, 621 const ParameterCount& actual, 622 InvokeFlag flag, 623 const CallWrapper& call_wrapper, 624 CallKind call_kind); 625 626 void IsObjectJSObjectType(Register heap_object, 627 Register map, 628 Register scratch, 629 Label* fail); 630 631 void IsInstanceJSObjectType(Register map, 632 Register scratch, 633 Label* fail); 634 635 void IsObjectJSStringType(Register object, 636 Register scratch, 637 Label* fail); 638 639 void IsObjectNameType(Register object, 640 Register scratch, 641 Label* fail); 642 643 #ifdef ENABLE_DEBUGGER_SUPPORT 644 // --------------------------------------------------------------------------- 645 // Debugger Support 646 647 void DebugBreak(); 648 #endif 649 650 // --------------------------------------------------------------------------- 651 // Exception handling 652 653 // Push a new try handler and link into try handler chain. 654 void PushTryHandler(StackHandler::Kind kind, int handler_index); 655 656 // Unlink the stack handler on top of the stack from the try handler chain. 657 // Must preserve the result register. 658 void PopTryHandler(); 659 660 // Passes thrown value to the handler of top of the try handler chain. 661 void Throw(Register value); 662 663 // Propagates an uncatchable exception to the top of the current JS stack's 664 // handler chain. 665 void ThrowUncatchable(Register value); 666 667 // --------------------------------------------------------------------------- 668 // Inline caching support 669 670 // Generate code for checking access rights - used for security checks 671 // on access to global objects across environments. The holder register 672 // is left untouched, whereas both scratch registers are clobbered. 673 void CheckAccessGlobalProxy(Register holder_reg, 674 Register scratch, 675 Label* miss); 676 677 void GetNumberHash(Register t0, Register scratch); 678 679 void LoadFromNumberDictionary(Label* miss, 680 Register elements, 681 Register key, 682 Register result, 683 Register t0, 684 Register t1, 685 Register t2); 686 687 688 inline void MarkCode(NopMarkerTypes type) { 689 nop(type); 690 } 691 692 // Check if the given instruction is a 'type' marker. 693 // i.e. check if is is a mov r<type>, r<type> (referenced as nop(type)) 694 // These instructions are generated to mark special location in the code, 695 // like some special IC code. 696 static inline bool IsMarkedCode(Instr instr, int type) { 697 ASSERT((FIRST_IC_MARKER <= type) && (type < LAST_CODE_MARKER)); 698 return IsNop(instr, type); 699 } 700 701 702 static inline int GetCodeMarker(Instr instr) { 703 int dst_reg_offset = 12; 704 int dst_mask = 0xf << dst_reg_offset; 705 int src_mask = 0xf; 706 int dst_reg = (instr & dst_mask) >> dst_reg_offset; 707 int src_reg = instr & src_mask; 708 uint32_t non_register_mask = ~(dst_mask | src_mask); 709 uint32_t mov_mask = al | 13 << 21; 710 711 // Return <n> if we have a mov rn rn, else return -1. 712 int type = ((instr & non_register_mask) == mov_mask) && 713 (dst_reg == src_reg) && 714 (FIRST_IC_MARKER <= dst_reg) && (dst_reg < LAST_CODE_MARKER) 715 ? src_reg 716 : -1; 717 ASSERT((type == -1) || 718 ((FIRST_IC_MARKER <= type) && (type < LAST_CODE_MARKER))); 719 return type; 720 } 721 722 723 // --------------------------------------------------------------------------- 724 // Allocation support 725 726 // Allocate an object in new space or old pointer space. The object_size is 727 // specified either in bytes or in words if the allocation flag SIZE_IN_WORDS 728 // is passed. If the space is exhausted control continues at the gc_required 729 // label. The allocated object is returned in result. If the flag 730 // tag_allocated_object is true the result is tagged as as a heap object. 731 // All registers are clobbered also when control continues at the gc_required 732 // label. 733 void Allocate(int object_size, 734 Register result, 735 Register scratch1, 736 Register scratch2, 737 Label* gc_required, 738 AllocationFlags flags); 739 740 void Allocate(Register object_size, 741 Register result, 742 Register scratch1, 743 Register scratch2, 744 Label* gc_required, 745 AllocationFlags flags); 746 747 // Undo allocation in new space. The object passed and objects allocated after 748 // it will no longer be allocated. The caller must make sure that no pointers 749 // are left to the object(s) no longer allocated as they would be invalid when 750 // allocation is undone. 751 void UndoAllocationInNewSpace(Register object, Register scratch); 752 753 754 void AllocateTwoByteString(Register result, 755 Register length, 756 Register scratch1, 757 Register scratch2, 758 Register scratch3, 759 Label* gc_required); 760 void AllocateAsciiString(Register result, 761 Register length, 762 Register scratch1, 763 Register scratch2, 764 Register scratch3, 765 Label* gc_required); 766 void AllocateTwoByteConsString(Register result, 767 Register length, 768 Register scratch1, 769 Register scratch2, 770 Label* gc_required); 771 void AllocateAsciiConsString(Register result, 772 Register length, 773 Register scratch1, 774 Register scratch2, 775 Label* gc_required); 776 void AllocateTwoByteSlicedString(Register result, 777 Register length, 778 Register scratch1, 779 Register scratch2, 780 Label* gc_required); 781 void AllocateAsciiSlicedString(Register result, 782 Register length, 783 Register scratch1, 784 Register scratch2, 785 Label* gc_required); 786 787 // Allocates a heap number or jumps to the gc_required label if the young 788 // space is full and a scavenge is needed. All registers are clobbered also 789 // when control continues at the gc_required label. 790 void AllocateHeapNumber(Register result, 791 Register scratch1, 792 Register scratch2, 793 Register heap_number_map, 794 Label* gc_required, 795 TaggingMode tagging_mode = TAG_RESULT); 796 void AllocateHeapNumberWithValue(Register result, 797 DwVfpRegister value, 798 Register scratch1, 799 Register scratch2, 800 Register heap_number_map, 801 Label* gc_required); 802 803 // Copies a fixed number of fields of heap objects from src to dst. 804 void CopyFields(Register dst, 805 Register src, 806 LowDwVfpRegister double_scratch, 807 int field_count); 808 809 // Copies a number of bytes from src to dst. All registers are clobbered. On 810 // exit src and dst will point to the place just after where the last byte was 811 // read or written and length will be zero. 812 void CopyBytes(Register src, 813 Register dst, 814 Register length, 815 Register scratch); 816 817 // Initialize fields with filler values. Fields starting at |start_offset| 818 // not including end_offset are overwritten with the value in |filler|. At 819 // the end the loop, |start_offset| takes the value of |end_offset|. 820 void InitializeFieldsWithFiller(Register start_offset, 821 Register end_offset, 822 Register filler); 823 824 // --------------------------------------------------------------------------- 825 // Support functions. 826 827 // Try to get function prototype of a function and puts the value in 828 // the result register. Checks that the function really is a 829 // function and jumps to the miss label if the fast checks fail. The 830 // function register will be untouched; the other registers may be 831 // clobbered. 832 void TryGetFunctionPrototype(Register function, 833 Register result, 834 Register scratch, 835 Label* miss, 836 bool miss_on_bound_function = false); 837 838 // Compare object type for heap object. heap_object contains a non-Smi 839 // whose object type should be compared with the given type. This both 840 // sets the flags and leaves the object type in the type_reg register. 841 // It leaves the map in the map register (unless the type_reg and map register 842 // are the same register). It leaves the heap object in the heap_object 843 // register unless the heap_object register is the same register as one of the 844 // other registers. 845 void CompareObjectType(Register heap_object, 846 Register map, 847 Register type_reg, 848 InstanceType type); 849 850 // Compare instance type in a map. map contains a valid map object whose 851 // object type should be compared with the given type. This both 852 // sets the flags and leaves the object type in the type_reg register. 853 void CompareInstanceType(Register map, 854 Register type_reg, 855 InstanceType type); 856 857 858 // Check if a map for a JSObject indicates that the object has fast elements. 859 // Jump to the specified label if it does not. 860 void CheckFastElements(Register map, 861 Register scratch, 862 Label* fail); 863 864 // Check if a map for a JSObject indicates that the object can have both smi 865 // and HeapObject elements. Jump to the specified label if it does not. 866 void CheckFastObjectElements(Register map, 867 Register scratch, 868 Label* fail); 869 870 // Check if a map for a JSObject indicates that the object has fast smi only 871 // elements. Jump to the specified label if it does not. 872 void CheckFastSmiElements(Register map, 873 Register scratch, 874 Label* fail); 875 876 // Check to see if maybe_number can be stored as a double in 877 // FastDoubleElements. If it can, store it at the index specified by key in 878 // the FastDoubleElements array elements. Otherwise jump to fail. 879 void StoreNumberToDoubleElements(Register value_reg, 880 Register key_reg, 881 Register elements_reg, 882 Register scratch1, 883 LowDwVfpRegister double_scratch, 884 Label* fail, 885 int elements_offset = 0); 886 887 // Compare an object's map with the specified map and its transitioned 888 // elements maps if mode is ALLOW_ELEMENT_TRANSITION_MAPS. Condition flags are 889 // set with result of map compare. If multiple map compares are required, the 890 // compare sequences branches to early_success. 891 void CompareMap(Register obj, 892 Register scratch, 893 Handle<Map> map, 894 Label* early_success); 895 896 // As above, but the map of the object is already loaded into the register 897 // which is preserved by the code generated. 898 void CompareMap(Register obj_map, 899 Handle<Map> map, 900 Label* early_success); 901 902 // Check if the map of an object is equal to a specified map and branch to 903 // label if not. Skip the smi check if not required (object is known to be a 904 // heap object). If mode is ALLOW_ELEMENT_TRANSITION_MAPS, then also match 905 // against maps that are ElementsKind transition maps of the specified map. 906 void CheckMap(Register obj, 907 Register scratch, 908 Handle<Map> map, 909 Label* fail, 910 SmiCheckType smi_check_type); 911 912 913 void CheckMap(Register obj, 914 Register scratch, 915 Heap::RootListIndex index, 916 Label* fail, 917 SmiCheckType smi_check_type); 918 919 920 // Check if the map of an object is equal to a specified map and branch to a 921 // specified target if equal. Skip the smi check if not required (object is 922 // known to be a heap object) 923 void DispatchMap(Register obj, 924 Register scratch, 925 Handle<Map> map, 926 Handle<Code> success, 927 SmiCheckType smi_check_type); 928 929 930 // Compare the object in a register to a value from the root list. 931 // Uses the ip register as scratch. 932 void CompareRoot(Register obj, Heap::RootListIndex index); 933 934 935 // Load and check the instance type of an object for being a string. 936 // Loads the type into the second argument register. 937 // Returns a condition that will be enabled if the object was a string 938 // and the passed-in condition passed. If the passed-in condition failed 939 // then flags remain unchanged. 940 Condition IsObjectStringType(Register obj, 941 Register type, 942 Condition cond = al) { 943 ldr(type, FieldMemOperand(obj, HeapObject::kMapOffset), cond); 944 ldrb(type, FieldMemOperand(type, Map::kInstanceTypeOffset), cond); 945 tst(type, Operand(kIsNotStringMask), cond); 946 ASSERT_EQ(0, kStringTag); 947 return eq; 948 } 949 950 951 // Generates code for reporting that an illegal operation has 952 // occurred. 953 void IllegalOperation(int num_arguments); 954 955 // Picks out an array index from the hash field. 956 // Register use: 957 // hash - holds the index's hash. Clobbered. 958 // index - holds the overwritten index on exit. 959 void IndexFromHash(Register hash, Register index); 960 961 // Get the number of least significant bits from a register 962 void GetLeastBitsFromSmi(Register dst, Register src, int num_least_bits); 963 void GetLeastBitsFromInt32(Register dst, Register src, int mun_least_bits); 964 965 // Load the value of a smi object into a double register. 966 // The register value must be between d0 and d15. 967 void SmiToDouble(LowDwVfpRegister value, Register smi); 968 969 // Check if a double can be exactly represented as a signed 32-bit integer. 970 // Z flag set to one if true. 971 void TestDoubleIsInt32(DwVfpRegister double_input, 972 LowDwVfpRegister double_scratch); 973 974 // Try to convert a double to a signed 32-bit integer. 975 // Z flag set to one and result assigned if the conversion is exact. 976 void TryDoubleToInt32Exact(Register result, 977 DwVfpRegister double_input, 978 LowDwVfpRegister double_scratch); 979 980 // Floor a double and writes the value to the result register. 981 // Go to exact if the conversion is exact (to be able to test -0), 982 // fall through calling code if an overflow occurred, else go to done. 983 // In return, input_high is loaded with high bits of input. 984 void TryInt32Floor(Register result, 985 DwVfpRegister double_input, 986 Register input_high, 987 LowDwVfpRegister double_scratch, 988 Label* done, 989 Label* exact); 990 991 // Performs a truncating conversion of a floating point number as used by 992 // the JS bitwise operations. See ECMA-262 9.5: ToInt32. 993 // Double_scratch must be between d0 and d15. 994 // Exits with 'result' holding the answer and all other registers clobbered. 995 void ECMAToInt32(Register result, 996 DwVfpRegister double_input, 997 Register scratch, 998 Register scratch_high, 999 Register scratch_low, 1000 LowDwVfpRegister double_scratch); 1001 1002 // Check whether d16-d31 are available on the CPU. The result is given by the 1003 // Z condition flag: Z==0 if d16-d31 available, Z==1 otherwise. 1004 void CheckFor32DRegs(Register scratch); 1005 1006 // Does a runtime check for 16/32 FP registers. Either way, pushes 32 double 1007 // values to location, saving [d0..(d15|d31)]. 1008 void SaveFPRegs(Register location, Register scratch); 1009 1010 // Does a runtime check for 16/32 FP registers. Either way, pops 32 double 1011 // values to location, restoring [d0..(d15|d31)]. 1012 void RestoreFPRegs(Register location, Register scratch); 1013 1014 // --------------------------------------------------------------------------- 1015 // Runtime calls 1016 1017 // Call a code stub. 1018 void CallStub(CodeStub* stub, 1019 TypeFeedbackId ast_id = TypeFeedbackId::None(), 1020 Condition cond = al); 1021 1022 // Call a code stub. 1023 void TailCallStub(CodeStub* stub, Condition cond = al); 1024 1025 // Call a runtime routine. 1026 void CallRuntime(const Runtime::Function* f, int num_arguments); 1027 void CallRuntimeSaveDoubles(Runtime::FunctionId id); 1028 1029 // Convenience function: Same as above, but takes the fid instead. 1030 void CallRuntime(Runtime::FunctionId fid, int num_arguments); 1031 1032 // Convenience function: call an external reference. 1033 void CallExternalReference(const ExternalReference& ext, 1034 int num_arguments); 1035 1036 // Tail call of a runtime routine (jump). 1037 // Like JumpToExternalReference, but also takes care of passing the number 1038 // of parameters. 1039 void TailCallExternalReference(const ExternalReference& ext, 1040 int num_arguments, 1041 int result_size); 1042 1043 // Convenience function: tail call a runtime routine (jump). 1044 void TailCallRuntime(Runtime::FunctionId fid, 1045 int num_arguments, 1046 int result_size); 1047 1048 int CalculateStackPassedWords(int num_reg_arguments, 1049 int num_double_arguments); 1050 1051 // Before calling a C-function from generated code, align arguments on stack. 1052 // After aligning the frame, non-register arguments must be stored in 1053 // sp[0], sp[4], etc., not pushed. The argument count assumes all arguments 1054 // are word sized. If double arguments are used, this function assumes that 1055 // all double arguments are stored before core registers; otherwise the 1056 // correct alignment of the double values is not guaranteed. 1057 // Some compilers/platforms require the stack to be aligned when calling 1058 // C++ code. 1059 // Needs a scratch register to do some arithmetic. This register will be 1060 // trashed. 1061 void PrepareCallCFunction(int num_reg_arguments, 1062 int num_double_registers, 1063 Register scratch); 1064 void PrepareCallCFunction(int num_reg_arguments, 1065 Register scratch); 1066 1067 // There are two ways of passing double arguments on ARM, depending on 1068 // whether soft or hard floating point ABI is used. These functions 1069 // abstract parameter passing for the three different ways we call 1070 // C functions from generated code. 1071 void SetCallCDoubleArguments(DwVfpRegister dreg); 1072 void SetCallCDoubleArguments(DwVfpRegister dreg1, DwVfpRegister dreg2); 1073 void SetCallCDoubleArguments(DwVfpRegister dreg, Register reg); 1074 1075 // Calls a C function and cleans up the space for arguments allocated 1076 // by PrepareCallCFunction. The called function is not allowed to trigger a 1077 // garbage collection, since that might move the code and invalidate the 1078 // return address (unless this is somehow accounted for by the called 1079 // function). 1080 void CallCFunction(ExternalReference function, int num_arguments); 1081 void CallCFunction(Register function, int num_arguments); 1082 void CallCFunction(ExternalReference function, 1083 int num_reg_arguments, 1084 int num_double_arguments); 1085 void CallCFunction(Register function, 1086 int num_reg_arguments, 1087 int num_double_arguments); 1088 1089 void GetCFunctionDoubleResult(const DwVfpRegister dst); 1090 1091 // Calls an API function. Allocates HandleScope, extracts returned value 1092 // from handle and propagates exceptions. Restores context. stack_space 1093 // - space to be unwound on exit (includes the call JS arguments space and 1094 // the additional space allocated for the fast call). 1095 void CallApiFunctionAndReturn(ExternalReference function, 1096 Address function_address, 1097 ExternalReference thunk_ref, 1098 Register thunk_last_arg, 1099 int stack_space, 1100 bool returns_handle, 1101 int return_value_offset_from_fp); 1102 1103 // Jump to a runtime routine. 1104 void JumpToExternalReference(const ExternalReference& builtin); 1105 1106 // Invoke specified builtin JavaScript function. Adds an entry to 1107 // the unresolved list if the name does not resolve. 1108 void InvokeBuiltin(Builtins::JavaScript id, 1109 InvokeFlag flag, 1110 const CallWrapper& call_wrapper = NullCallWrapper()); 1111 1112 // Store the code object for the given builtin in the target register and 1113 // setup the function in r1. 1114 void GetBuiltinEntry(Register target, Builtins::JavaScript id); 1115 1116 // Store the function for the given builtin in the target register. 1117 void GetBuiltinFunction(Register target, Builtins::JavaScript id); 1118 1119 Handle<Object> CodeObject() { 1120 ASSERT(!code_object_.is_null()); 1121 return code_object_; 1122 } 1123 1124 1125 // --------------------------------------------------------------------------- 1126 // StatsCounter support 1127 1128 void SetCounter(StatsCounter* counter, int value, 1129 Register scratch1, Register scratch2); 1130 void IncrementCounter(StatsCounter* counter, int value, 1131 Register scratch1, Register scratch2); 1132 void DecrementCounter(StatsCounter* counter, int value, 1133 Register scratch1, Register scratch2); 1134 1135 1136 // --------------------------------------------------------------------------- 1137 // Debugging 1138 1139 // Calls Abort(msg) if the condition cond is not satisfied. 1140 // Use --debug_code to enable. 1141 void Assert(Condition cond, BailoutReason reason); 1142 void AssertFastElements(Register elements); 1143 1144 // Like Assert(), but always enabled. 1145 void Check(Condition cond, BailoutReason reason); 1146 1147 // Print a message to stdout and abort execution. 1148 void Abort(BailoutReason msg); 1149 1150 // Verify restrictions about code generated in stubs. 1151 void set_generating_stub(bool value) { generating_stub_ = value; } 1152 bool generating_stub() { return generating_stub_; } 1153 void set_allow_stub_calls(bool value) { allow_stub_calls_ = value; } 1154 bool allow_stub_calls() { return allow_stub_calls_; } 1155 void set_has_frame(bool value) { has_frame_ = value; } 1156 bool has_frame() { return has_frame_; } 1157 inline bool AllowThisStubCall(CodeStub* stub); 1158 1159 // EABI variant for double arguments in use. 1160 bool use_eabi_hardfloat() { 1161 #ifdef __arm__ 1162 return OS::ArmUsingHardFloat(); 1163 #elif USE_EABI_HARDFLOAT 1164 return true; 1165 #else 1166 return false; 1167 #endif 1168 } 1169 1170 // --------------------------------------------------------------------------- 1171 // Number utilities 1172 1173 // Check whether the value of reg is a power of two and not zero. If not 1174 // control continues at the label not_power_of_two. If reg is a power of two 1175 // the register scratch contains the value of (reg - 1) when control falls 1176 // through. 1177 void JumpIfNotPowerOfTwoOrZero(Register reg, 1178 Register scratch, 1179 Label* not_power_of_two_or_zero); 1180 // Check whether the value of reg is a power of two and not zero. 1181 // Control falls through if it is, with scratch containing the mask 1182 // value (reg - 1). 1183 // Otherwise control jumps to the 'zero_and_neg' label if the value of reg is 1184 // zero or negative, or jumps to the 'not_power_of_two' label if the value is 1185 // strictly positive but not a power of two. 1186 void JumpIfNotPowerOfTwoOrZeroAndNeg(Register reg, 1187 Register scratch, 1188 Label* zero_and_neg, 1189 Label* not_power_of_two); 1190 1191 // --------------------------------------------------------------------------- 1192 // Smi utilities 1193 1194 void SmiTag(Register reg, SBit s = LeaveCC) { 1195 add(reg, reg, Operand(reg), s); 1196 } 1197 void SmiTag(Register dst, Register src, SBit s = LeaveCC) { 1198 add(dst, src, Operand(src), s); 1199 } 1200 1201 // Try to convert int32 to smi. If the value is to large, preserve 1202 // the original value and jump to not_a_smi. Destroys scratch and 1203 // sets flags. 1204 void TrySmiTag(Register reg, Label* not_a_smi) { 1205 TrySmiTag(reg, reg, not_a_smi); 1206 } 1207 void TrySmiTag(Register reg, Register src, Label* not_a_smi) { 1208 SmiTag(ip, src, SetCC); 1209 b(vs, not_a_smi); 1210 mov(reg, ip); 1211 } 1212 1213 1214 void SmiUntag(Register reg, SBit s = LeaveCC) { 1215 mov(reg, Operand::SmiUntag(reg), s); 1216 } 1217 void SmiUntag(Register dst, Register src, SBit s = LeaveCC) { 1218 mov(dst, Operand::SmiUntag(src), s); 1219 } 1220 1221 // Untag the source value into destination and jump if source is a smi. 1222 // Souce and destination can be the same register. 1223 void UntagAndJumpIfSmi(Register dst, Register src, Label* smi_case); 1224 1225 // Untag the source value into destination and jump if source is not a smi. 1226 // Souce and destination can be the same register. 1227 void UntagAndJumpIfNotSmi(Register dst, Register src, Label* non_smi_case); 1228 1229 // Test if the register contains a smi (Z == 0 (eq) if true). 1230 inline void SmiTst(Register value) { 1231 tst(value, Operand(kSmiTagMask)); 1232 } 1233 inline void NonNegativeSmiTst(Register value) { 1234 tst(value, Operand(kSmiTagMask | kSmiSignMask)); 1235 } 1236 // Jump if the register contains a smi. 1237 inline void JumpIfSmi(Register value, Label* smi_label) { 1238 tst(value, Operand(kSmiTagMask)); 1239 b(eq, smi_label); 1240 } 1241 // Jump if either of the registers contain a non-smi. 1242 inline void JumpIfNotSmi(Register value, Label* not_smi_label) { 1243 tst(value, Operand(kSmiTagMask)); 1244 b(ne, not_smi_label); 1245 } 1246 // Jump if either of the registers contain a non-smi. 1247 void JumpIfNotBothSmi(Register reg1, Register reg2, Label* on_not_both_smi); 1248 // Jump if either of the registers contain a smi. 1249 void JumpIfEitherSmi(Register reg1, Register reg2, Label* on_either_smi); 1250 1251 // Abort execution if argument is a smi, enabled via --debug-code. 1252 void AssertNotSmi(Register object); 1253 void AssertSmi(Register object); 1254 1255 // Abort execution if argument is not a string, enabled via --debug-code. 1256 void AssertString(Register object); 1257 1258 // Abort execution if argument is not a name, enabled via --debug-code. 1259 void AssertName(Register object); 1260 1261 // Abort execution if reg is not the root value with the given index, 1262 // enabled via --debug-code. 1263 void AssertIsRoot(Register reg, Heap::RootListIndex index); 1264 1265 // --------------------------------------------------------------------------- 1266 // HeapNumber utilities 1267 1268 void JumpIfNotHeapNumber(Register object, 1269 Register heap_number_map, 1270 Register scratch, 1271 Label* on_not_heap_number); 1272 1273 // --------------------------------------------------------------------------- 1274 // String utilities 1275 1276 // Checks if both objects are sequential ASCII strings and jumps to label 1277 // if either is not. Assumes that neither object is a smi. 1278 void JumpIfNonSmisNotBothSequentialAsciiStrings(Register object1, 1279 Register object2, 1280 Register scratch1, 1281 Register scratch2, 1282 Label* failure); 1283 1284 // Checks if both objects are sequential ASCII strings and jumps to label 1285 // if either is not. 1286 void JumpIfNotBothSequentialAsciiStrings(Register first, 1287 Register second, 1288 Register scratch1, 1289 Register scratch2, 1290 Label* not_flat_ascii_strings); 1291 1292 // Checks if both instance types are sequential ASCII strings and jumps to 1293 // label if either is not. 1294 void JumpIfBothInstanceTypesAreNotSequentialAscii( 1295 Register first_object_instance_type, 1296 Register second_object_instance_type, 1297 Register scratch1, 1298 Register scratch2, 1299 Label* failure); 1300 1301 // Check if instance type is sequential ASCII string and jump to label if 1302 // it is not. 1303 void JumpIfInstanceTypeIsNotSequentialAscii(Register type, 1304 Register scratch, 1305 Label* failure); 1306 1307 void JumpIfNotUniqueName(Register reg, Label* not_unique_name); 1308 1309 // --------------------------------------------------------------------------- 1310 // Patching helpers. 1311 1312 // Get the location of a relocated constant (its address in the constant pool) 1313 // from its load site. 1314 void GetRelocatedValueLocation(Register ldr_location, 1315 Register result); 1316 1317 1318 void ClampUint8(Register output_reg, Register input_reg); 1319 1320 void ClampDoubleToUint8(Register result_reg, 1321 DwVfpRegister input_reg, 1322 LowDwVfpRegister double_scratch); 1323 1324 1325 void LoadInstanceDescriptors(Register map, Register descriptors); 1326 void EnumLength(Register dst, Register map); 1327 void NumberOfOwnDescriptors(Register dst, Register map); 1328 1329 template<typename Field> 1330 void DecodeField(Register reg) { 1331 static const int shift = Field::kShift; 1332 static const int mask = (Field::kMask >> shift) << kSmiTagSize; 1333 mov(reg, Operand(reg, LSR, shift)); 1334 and_(reg, reg, Operand(mask)); 1335 } 1336 1337 // Activation support. 1338 void EnterFrame(StackFrame::Type type); 1339 void LeaveFrame(StackFrame::Type type); 1340 1341 // Expects object in r0 and returns map with validated enum cache 1342 // in r0. Assumes that any other register can be used as a scratch. 1343 void CheckEnumCache(Register null_value, Label* call_runtime); 1344 1345 // AllocationMemento support. Arrays may have an associated 1346 // AllocationMemento object that can be checked for in order to pretransition 1347 // to another type. 1348 // On entry, receiver_reg should point to the array object. 1349 // scratch_reg gets clobbered. 1350 // If allocation info is present, condition flags are set to eq 1351 void TestJSArrayForAllocationMemento(Register receiver_reg, 1352 Register scratch_reg); 1353 1354 private: 1355 void CallCFunctionHelper(Register function, 1356 int num_reg_arguments, 1357 int num_double_arguments); 1358 1359 void Jump(intptr_t target, RelocInfo::Mode rmode, Condition cond = al); 1360 1361 // Helper functions for generating invokes. 1362 void InvokePrologue(const ParameterCount& expected, 1363 const ParameterCount& actual, 1364 Handle<Code> code_constant, 1365 Register code_reg, 1366 Label* done, 1367 bool* definitely_mismatches, 1368 InvokeFlag flag, 1369 const CallWrapper& call_wrapper, 1370 CallKind call_kind); 1371 1372 void InitializeNewString(Register string, 1373 Register length, 1374 Heap::RootListIndex map_index, 1375 Register scratch1, 1376 Register scratch2); 1377 1378 // Helper for implementing JumpIfNotInNewSpace and JumpIfInNewSpace. 1379 void InNewSpace(Register object, 1380 Register scratch, 1381 Condition cond, // eq for new space, ne otherwise. 1382 Label* branch); 1383 1384 // Helper for finding the mark bits for an address. Afterwards, the 1385 // bitmap register points at the word with the mark bits and the mask 1386 // the position of the first bit. Leaves addr_reg unchanged. 1387 inline void GetMarkBits(Register addr_reg, 1388 Register bitmap_reg, 1389 Register mask_reg); 1390 1391 // Helper for throwing exceptions. Compute a handler address and jump to 1392 // it. See the implementation for register usage. 1393 void JumpToHandlerEntry(); 1394 1395 // Compute memory operands for safepoint stack slots. 1396 static int SafepointRegisterStackIndex(int reg_code); 1397 MemOperand SafepointRegisterSlot(Register reg); 1398 MemOperand SafepointRegistersAndDoublesSlot(Register reg); 1399 1400 bool generating_stub_; 1401 bool allow_stub_calls_; 1402 bool has_frame_; 1403 // This handle will be patched with the code object on installation. 1404 Handle<Object> code_object_; 1405 1406 // Needs access to SafepointRegisterStackIndex for compiled frame 1407 // traversal. 1408 friend class StandardFrame; 1409 }; 1410 1411 1412 // The code patcher is used to patch (typically) small parts of code e.g. for 1413 // debugging and other types of instrumentation. When using the code patcher 1414 // the exact number of bytes specified must be emitted. It is not legal to emit 1415 // relocation information. If any of these constraints are violated it causes 1416 // an assertion to fail. 1417 class CodePatcher { 1418 public: 1419 CodePatcher(byte* address, int instructions); 1420 virtual ~CodePatcher(); 1421 1422 // Macro assembler to emit code. 1423 MacroAssembler* masm() { return &masm_; } 1424 1425 // Emit an instruction directly. 1426 void Emit(Instr instr); 1427 1428 // Emit an address directly. 1429 void Emit(Address addr); 1430 1431 // Emit the condition part of an instruction leaving the rest of the current 1432 // instruction unchanged. 1433 void EmitCondition(Condition cond); 1434 1435 private: 1436 byte* address_; // The address of the code being patched. 1437 int size_; // Number of bytes of the expected patch size. 1438 MacroAssembler masm_; // Macro assembler used to generate the code. 1439 }; 1440 1441 1442 // ----------------------------------------------------------------------------- 1443 // Static helper functions. 1444 1445 inline MemOperand ContextOperand(Register context, int index) { 1446 return MemOperand(context, Context::SlotOffset(index)); 1447 } 1448 1449 1450 inline MemOperand GlobalObjectOperand() { 1451 return ContextOperand(cp, Context::GLOBAL_OBJECT_INDEX); 1452 } 1453 1454 1455 #ifdef GENERATED_CODE_COVERAGE 1456 #define CODE_COVERAGE_STRINGIFY(x) #x 1457 #define CODE_COVERAGE_TOSTRING(x) CODE_COVERAGE_STRINGIFY(x) 1458 #define __FILE_LINE__ __FILE__ ":" CODE_COVERAGE_TOSTRING(__LINE__) 1459 #define ACCESS_MASM(masm) masm->stop(__FILE_LINE__); masm-> 1460 #else 1461 #define ACCESS_MASM(masm) masm-> 1462 #endif 1463 1464 1465 } } // namespace v8::internal 1466 1467 #endif // V8_ARM_MACRO_ASSEMBLER_ARM_H_ 1468