1 // Copyright 2012 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef V8_ARM_MACRO_ASSEMBLER_ARM_H_ 6 #define V8_ARM_MACRO_ASSEMBLER_ARM_H_ 7 8 #include "src/assembler.h" 9 #include "src/bailout-reason.h" 10 #include "src/frames.h" 11 #include "src/globals.h" 12 13 namespace v8 { 14 namespace internal { 15 16 // Give alias names to registers for calling conventions. 17 const Register kReturnRegister0 = {Register::kCode_r0}; 18 const Register kReturnRegister1 = {Register::kCode_r1}; 19 const Register kReturnRegister2 = {Register::kCode_r2}; 20 const Register kJSFunctionRegister = {Register::kCode_r1}; 21 const Register kContextRegister = {Register::kCode_r7}; 22 const Register kAllocateSizeRegister = {Register::kCode_r1}; 23 const Register kInterpreterAccumulatorRegister = {Register::kCode_r0}; 24 const Register kInterpreterBytecodeOffsetRegister = {Register::kCode_r5}; 25 const Register kInterpreterBytecodeArrayRegister = {Register::kCode_r6}; 26 const Register kInterpreterDispatchTableRegister = {Register::kCode_r8}; 27 const Register kJavaScriptCallArgCountRegister = {Register::kCode_r0}; 28 const Register kJavaScriptCallNewTargetRegister = {Register::kCode_r3}; 29 const Register kRuntimeCallFunctionRegister = {Register::kCode_r1}; 30 const Register kRuntimeCallArgCountRegister = {Register::kCode_r0}; 31 32 // ---------------------------------------------------------------------------- 33 // Static helper functions 34 35 // Generate a MemOperand for loading a field from an object. 36 inline MemOperand FieldMemOperand(Register object, int offset) { 37 return MemOperand(object, offset - kHeapObjectTag); 38 } 39 40 41 // Give alias names to registers 42 const Register cp = {Register::kCode_r7}; // JavaScript context pointer. 43 const Register pp = {Register::kCode_r8}; // Constant pool pointer. 44 const Register kRootRegister = {Register::kCode_r10}; // Roots array pointer. 45 46 // Flags used for AllocateHeapNumber 47 enum TaggingMode { 48 // Tag the result. 49 TAG_RESULT, 50 // Don't tag 51 DONT_TAG_RESULT 52 }; 53 54 55 enum RememberedSetAction { EMIT_REMEMBERED_SET, OMIT_REMEMBERED_SET }; 56 enum SmiCheck { INLINE_SMI_CHECK, OMIT_SMI_CHECK }; 57 enum PointersToHereCheck { 58 kPointersToHereMaybeInteresting, 59 kPointersToHereAreAlwaysInteresting 60 }; 61 enum LinkRegisterStatus { kLRHasNotBeenSaved, kLRHasBeenSaved }; 62 63 64 Register GetRegisterThatIsNotOneOf(Register reg1, 65 Register reg2 = no_reg, 66 Register reg3 = no_reg, 67 Register reg4 = no_reg, 68 Register reg5 = no_reg, 69 Register reg6 = no_reg); 70 71 72 #ifdef DEBUG 73 bool AreAliased(Register reg1, 74 Register reg2, 75 Register reg3 = no_reg, 76 Register reg4 = no_reg, 77 Register reg5 = no_reg, 78 Register reg6 = no_reg, 79 Register reg7 = no_reg, 80 Register reg8 = no_reg); 81 #endif 82 83 84 enum TargetAddressStorageMode { 85 CAN_INLINE_TARGET_ADDRESS, 86 NEVER_INLINE_TARGET_ADDRESS 87 }; 88 89 // MacroAssembler implements a collection of frequently used macros. 90 class MacroAssembler: public Assembler { 91 public: 92 MacroAssembler(Isolate* isolate, void* buffer, int size, 93 CodeObjectRequired create_code_object); 94 95 96 // Returns the size of a call in instructions. Note, the value returned is 97 // only valid as long as no entries are added to the constant pool between 98 // checking the call size and emitting the actual call. 99 static int CallSize(Register target, Condition cond = al); 100 int CallSize(Address target, RelocInfo::Mode rmode, Condition cond = al); 101 int CallStubSize(CodeStub* stub, 102 TypeFeedbackId ast_id = TypeFeedbackId::None(), 103 Condition cond = al); 104 105 // Jump, Call, and Ret pseudo instructions implementing inter-working. 106 void Jump(Register target, Condition cond = al); 107 void Jump(Address target, RelocInfo::Mode rmode, Condition cond = al); 108 void Jump(Handle<Code> code, RelocInfo::Mode rmode, Condition cond = al); 109 void Call(Register target, Condition cond = al); 110 void Call(Address target, RelocInfo::Mode rmode, 111 Condition cond = al, 112 TargetAddressStorageMode mode = CAN_INLINE_TARGET_ADDRESS); 113 void Call(Handle<Code> code, RelocInfo::Mode rmode = RelocInfo::CODE_TARGET, 114 TypeFeedbackId ast_id = TypeFeedbackId::None(), Condition cond = al, 115 TargetAddressStorageMode mode = CAN_INLINE_TARGET_ADDRESS); 116 int CallSize(Handle<Code> code, 117 RelocInfo::Mode rmode = RelocInfo::CODE_TARGET, 118 TypeFeedbackId ast_id = TypeFeedbackId::None(), 119 Condition cond = al); 120 void Ret(Condition cond = al); 121 122 // Used for patching in calls to the deoptimizer. 123 void CallDeoptimizer(Address target); 124 static int CallDeoptimizerSize(); 125 126 // Emit code that loads |parameter_index|'th parameter from the stack to 127 // the register according to the CallInterfaceDescriptor definition. 128 // |sp_to_caller_sp_offset_in_words| specifies the number of words pushed 129 // below the caller's sp. 130 template <class Descriptor> 131 void LoadParameterFromStack( 132 Register reg, typename Descriptor::ParameterIndices parameter_index, 133 int sp_to_ra_offset_in_words = 0) { 134 DCHECK(Descriptor::kPassLastArgsOnStack); 135 UNIMPLEMENTED(); 136 } 137 138 // Emit code to discard a non-negative number of pointer-sized elements 139 // from the stack, clobbering only the sp register. 140 void Drop(int count, Condition cond = al); 141 void Drop(Register count, Condition cond = al); 142 143 void Ret(int drop, Condition cond = al); 144 145 // Swap two registers. If the scratch register is omitted then a slightly 146 // less efficient form using xor instead of mov is emitted. 147 void Swap(Register reg1, 148 Register reg2, 149 Register scratch = no_reg, 150 Condition cond = al); 151 152 void Mls(Register dst, Register src1, Register src2, Register srcA, 153 Condition cond = al); 154 void And(Register dst, Register src1, const Operand& src2, 155 Condition cond = al); 156 void Ubfx(Register dst, Register src, int lsb, int width, 157 Condition cond = al); 158 void Sbfx(Register dst, Register src, int lsb, int width, 159 Condition cond = al); 160 // The scratch register is not used for ARMv7. 161 // scratch can be the same register as src (in which case it is trashed), but 162 // not the same as dst. 163 void Bfi(Register dst, 164 Register src, 165 Register scratch, 166 int lsb, 167 int width, 168 Condition cond = al); 169 void Bfc(Register dst, Register src, int lsb, int width, Condition cond = al); 170 171 void Call(Label* target); 172 void Push(Register src) { push(src); } 173 void Pop(Register dst) { pop(dst); } 174 175 // Register move. May do nothing if the registers are identical. 176 void Move(Register dst, Smi* smi) { mov(dst, Operand(smi)); } 177 void Move(Register dst, Handle<Object> value); 178 void Move(Register dst, Register src, Condition cond = al); 179 void Move(Register dst, const Operand& src, SBit sbit = LeaveCC, 180 Condition cond = al) { 181 if (!src.is_reg() || !src.rm().is(dst) || sbit != LeaveCC) { 182 mov(dst, src, sbit, cond); 183 } 184 } 185 void Move(SwVfpRegister dst, SwVfpRegister src, Condition cond = al); 186 void Move(DwVfpRegister dst, DwVfpRegister src, Condition cond = al); 187 void Move(QwNeonRegister dst, QwNeonRegister src); 188 // Register swap. 189 void Swap(DwVfpRegister srcdst0, DwVfpRegister srcdst1); 190 void Swap(QwNeonRegister srcdst0, QwNeonRegister srcdst1); 191 192 void Load(Register dst, const MemOperand& src, Representation r); 193 void Store(Register src, const MemOperand& dst, Representation r); 194 195 // Load an object from the root table. 196 void LoadRoot(Register destination, 197 Heap::RootListIndex index, 198 Condition cond = al); 199 // Store an object to the root table. 200 void StoreRoot(Register source, 201 Heap::RootListIndex index, 202 Condition cond = al); 203 204 // --------------------------------------------------------------------------- 205 // GC Support 206 207 void IncrementalMarkingRecordWriteHelper(Register object, 208 Register value, 209 Register address); 210 211 enum RememberedSetFinalAction { 212 kReturnAtEnd, 213 kFallThroughAtEnd 214 }; 215 216 // Record in the remembered set the fact that we have a pointer to new space 217 // at the address pointed to by the addr register. Only works if addr is not 218 // in new space. 219 void RememberedSetHelper(Register object, // Used for debug code. 220 Register addr, 221 Register scratch, 222 SaveFPRegsMode save_fp, 223 RememberedSetFinalAction and_then); 224 225 void CheckPageFlag(Register object, 226 Register scratch, 227 int mask, 228 Condition cc, 229 Label* condition_met); 230 231 // Check if object is in new space. Jumps if the object is not in new space. 232 // The register scratch can be object itself, but scratch will be clobbered. 233 void JumpIfNotInNewSpace(Register object, 234 Register scratch, 235 Label* branch) { 236 InNewSpace(object, scratch, eq, branch); 237 } 238 239 // Check if object is in new space. Jumps if the object is in new space. 240 // The register scratch can be object itself, but it will be clobbered. 241 void JumpIfInNewSpace(Register object, 242 Register scratch, 243 Label* branch) { 244 InNewSpace(object, scratch, ne, branch); 245 } 246 247 // Check if an object has a given incremental marking color. 248 void HasColor(Register object, 249 Register scratch0, 250 Register scratch1, 251 Label* has_color, 252 int first_bit, 253 int second_bit); 254 255 void JumpIfBlack(Register object, 256 Register scratch0, 257 Register scratch1, 258 Label* on_black); 259 260 // Checks the color of an object. If the object is white we jump to the 261 // incremental marker. 262 void JumpIfWhite(Register value, Register scratch1, Register scratch2, 263 Register scratch3, Label* value_is_white); 264 265 // Notify the garbage collector that we wrote a pointer into an object. 266 // |object| is the object being stored into, |value| is the object being 267 // stored. value and scratch registers are clobbered by the operation. 268 // The offset is the offset from the start of the object, not the offset from 269 // the tagged HeapObject pointer. For use with FieldMemOperand(reg, off). 270 void RecordWriteField( 271 Register object, 272 int offset, 273 Register value, 274 Register scratch, 275 LinkRegisterStatus lr_status, 276 SaveFPRegsMode save_fp, 277 RememberedSetAction remembered_set_action = EMIT_REMEMBERED_SET, 278 SmiCheck smi_check = INLINE_SMI_CHECK, 279 PointersToHereCheck pointers_to_here_check_for_value = 280 kPointersToHereMaybeInteresting); 281 282 // As above, but the offset has the tag presubtracted. For use with 283 // MemOperand(reg, off). 284 inline void RecordWriteContextSlot( 285 Register context, 286 int offset, 287 Register value, 288 Register scratch, 289 LinkRegisterStatus lr_status, 290 SaveFPRegsMode save_fp, 291 RememberedSetAction remembered_set_action = EMIT_REMEMBERED_SET, 292 SmiCheck smi_check = INLINE_SMI_CHECK, 293 PointersToHereCheck pointers_to_here_check_for_value = 294 kPointersToHereMaybeInteresting) { 295 RecordWriteField(context, 296 offset + kHeapObjectTag, 297 value, 298 scratch, 299 lr_status, 300 save_fp, 301 remembered_set_action, 302 smi_check, 303 pointers_to_here_check_for_value); 304 } 305 306 // Notify the garbage collector that we wrote a code entry into a 307 // JSFunction. Only scratch is clobbered by the operation. 308 void RecordWriteCodeEntryField(Register js_function, Register code_entry, 309 Register scratch); 310 311 void RecordWriteForMap( 312 Register object, 313 Register map, 314 Register dst, 315 LinkRegisterStatus lr_status, 316 SaveFPRegsMode save_fp); 317 318 // For a given |object| notify the garbage collector that the slot |address| 319 // has been written. |value| is the object being stored. The value and 320 // address registers are clobbered by the operation. 321 void RecordWrite( 322 Register object, 323 Register address, 324 Register value, 325 LinkRegisterStatus lr_status, 326 SaveFPRegsMode save_fp, 327 RememberedSetAction remembered_set_action = EMIT_REMEMBERED_SET, 328 SmiCheck smi_check = INLINE_SMI_CHECK, 329 PointersToHereCheck pointers_to_here_check_for_value = 330 kPointersToHereMaybeInteresting); 331 332 // Push a handle. 333 void Push(Handle<Object> handle); 334 void Push(Smi* smi) { Push(Handle<Smi>(smi, isolate())); } 335 336 // Push two registers. Pushes leftmost register first (to highest address). 337 void Push(Register src1, Register src2, Condition cond = al) { 338 if (src1.code() > src2.code()) { 339 stm(db_w, sp, src1.bit() | src2.bit(), cond); 340 } else { 341 str(src1, MemOperand(sp, 4, NegPreIndex), cond); 342 str(src2, MemOperand(sp, 4, NegPreIndex), cond); 343 } 344 } 345 346 // Push three registers. Pushes leftmost register first (to highest address). 347 void Push(Register src1, Register src2, Register src3, Condition cond = al) { 348 if (src1.code() > src2.code()) { 349 if (src2.code() > src3.code()) { 350 stm(db_w, sp, src1.bit() | src2.bit() | src3.bit(), cond); 351 } else { 352 stm(db_w, sp, src1.bit() | src2.bit(), cond); 353 str(src3, MemOperand(sp, 4, NegPreIndex), cond); 354 } 355 } else { 356 str(src1, MemOperand(sp, 4, NegPreIndex), cond); 357 Push(src2, src3, cond); 358 } 359 } 360 361 // Push four registers. Pushes leftmost register first (to highest address). 362 void Push(Register src1, 363 Register src2, 364 Register src3, 365 Register src4, 366 Condition cond = al) { 367 if (src1.code() > src2.code()) { 368 if (src2.code() > src3.code()) { 369 if (src3.code() > src4.code()) { 370 stm(db_w, 371 sp, 372 src1.bit() | src2.bit() | src3.bit() | src4.bit(), 373 cond); 374 } else { 375 stm(db_w, sp, src1.bit() | src2.bit() | src3.bit(), cond); 376 str(src4, MemOperand(sp, 4, NegPreIndex), cond); 377 } 378 } else { 379 stm(db_w, sp, src1.bit() | src2.bit(), cond); 380 Push(src3, src4, cond); 381 } 382 } else { 383 str(src1, MemOperand(sp, 4, NegPreIndex), cond); 384 Push(src2, src3, src4, cond); 385 } 386 } 387 388 // Push five registers. Pushes leftmost register first (to highest address). 389 void Push(Register src1, Register src2, Register src3, Register src4, 390 Register src5, Condition cond = al) { 391 if (src1.code() > src2.code()) { 392 if (src2.code() > src3.code()) { 393 if (src3.code() > src4.code()) { 394 if (src4.code() > src5.code()) { 395 stm(db_w, sp, 396 src1.bit() | src2.bit() | src3.bit() | src4.bit() | src5.bit(), 397 cond); 398 } else { 399 stm(db_w, sp, src1.bit() | src2.bit() | src3.bit() | src4.bit(), 400 cond); 401 str(src5, MemOperand(sp, 4, NegPreIndex), cond); 402 } 403 } else { 404 stm(db_w, sp, src1.bit() | src2.bit() | src3.bit(), cond); 405 Push(src4, src5, cond); 406 } 407 } else { 408 stm(db_w, sp, src1.bit() | src2.bit(), cond); 409 Push(src3, src4, src5, cond); 410 } 411 } else { 412 str(src1, MemOperand(sp, 4, NegPreIndex), cond); 413 Push(src2, src3, src4, src5, cond); 414 } 415 } 416 417 // Pop two registers. Pops rightmost register first (from lower address). 418 void Pop(Register src1, Register src2, Condition cond = al) { 419 DCHECK(!src1.is(src2)); 420 if (src1.code() > src2.code()) { 421 ldm(ia_w, sp, src1.bit() | src2.bit(), cond); 422 } else { 423 ldr(src2, MemOperand(sp, 4, PostIndex), cond); 424 ldr(src1, MemOperand(sp, 4, PostIndex), cond); 425 } 426 } 427 428 // Pop three registers. Pops rightmost register first (from lower address). 429 void Pop(Register src1, Register src2, Register src3, Condition cond = al) { 430 DCHECK(!AreAliased(src1, src2, src3)); 431 if (src1.code() > src2.code()) { 432 if (src2.code() > src3.code()) { 433 ldm(ia_w, sp, src1.bit() | src2.bit() | src3.bit(), cond); 434 } else { 435 ldr(src3, MemOperand(sp, 4, PostIndex), cond); 436 ldm(ia_w, sp, src1.bit() | src2.bit(), cond); 437 } 438 } else { 439 Pop(src2, src3, cond); 440 ldr(src1, MemOperand(sp, 4, PostIndex), cond); 441 } 442 } 443 444 // Pop four registers. Pops rightmost register first (from lower address). 445 void Pop(Register src1, 446 Register src2, 447 Register src3, 448 Register src4, 449 Condition cond = al) { 450 DCHECK(!AreAliased(src1, src2, src3, src4)); 451 if (src1.code() > src2.code()) { 452 if (src2.code() > src3.code()) { 453 if (src3.code() > src4.code()) { 454 ldm(ia_w, 455 sp, 456 src1.bit() | src2.bit() | src3.bit() | src4.bit(), 457 cond); 458 } else { 459 ldr(src4, MemOperand(sp, 4, PostIndex), cond); 460 ldm(ia_w, sp, src1.bit() | src2.bit() | src3.bit(), cond); 461 } 462 } else { 463 Pop(src3, src4, cond); 464 ldm(ia_w, sp, src1.bit() | src2.bit(), cond); 465 } 466 } else { 467 Pop(src2, src3, src4, cond); 468 ldr(src1, MemOperand(sp, 4, PostIndex), cond); 469 } 470 } 471 472 // Push a fixed frame, consisting of lr, fp, constant pool (if 473 // FLAG_enable_embedded_constant_pool) 474 void PushCommonFrame(Register marker_reg = no_reg); 475 476 // Push a standard frame, consisting of lr, fp, constant pool (if 477 // FLAG_enable_embedded_constant_pool), context and JS function 478 void PushStandardFrame(Register function_reg); 479 480 void PopCommonFrame(Register marker_reg = no_reg); 481 482 // Push and pop the registers that can hold pointers, as defined by the 483 // RegList constant kSafepointSavedRegisters. 484 void PushSafepointRegisters(); 485 void PopSafepointRegisters(); 486 // Store value in register src in the safepoint stack slot for 487 // register dst. 488 void StoreToSafepointRegisterSlot(Register src, Register dst); 489 // Load the value of the src register from its safepoint stack slot 490 // into register dst. 491 void LoadFromSafepointRegisterSlot(Register dst, Register src); 492 493 // Load two consecutive registers with two consecutive memory locations. 494 void Ldrd(Register dst1, 495 Register dst2, 496 const MemOperand& src, 497 Condition cond = al); 498 499 // Store two consecutive registers to two consecutive memory locations. 500 void Strd(Register src1, 501 Register src2, 502 const MemOperand& dst, 503 Condition cond = al); 504 505 // If the value is a NaN, canonicalize the value else, do nothing. 506 void VFPCanonicalizeNaN(const DwVfpRegister dst, 507 const DwVfpRegister src, 508 const Condition cond = al); 509 void VFPCanonicalizeNaN(const DwVfpRegister value, 510 const Condition cond = al) { 511 VFPCanonicalizeNaN(value, value, cond); 512 } 513 514 // Compare single values and move the result to the normal condition flags. 515 void VFPCompareAndSetFlags(const SwVfpRegister src1, const SwVfpRegister src2, 516 const Condition cond = al); 517 void VFPCompareAndSetFlags(const SwVfpRegister src1, const float src2, 518 const Condition cond = al); 519 520 // Compare double values and move the result to the normal condition flags. 521 void VFPCompareAndSetFlags(const DwVfpRegister src1, 522 const DwVfpRegister src2, 523 const Condition cond = al); 524 void VFPCompareAndSetFlags(const DwVfpRegister src1, 525 const double src2, 526 const Condition cond = al); 527 528 // Compare single values and then load the fpscr flags to a register. 529 void VFPCompareAndLoadFlags(const SwVfpRegister src1, 530 const SwVfpRegister src2, 531 const Register fpscr_flags, 532 const Condition cond = al); 533 void VFPCompareAndLoadFlags(const SwVfpRegister src1, const float src2, 534 const Register fpscr_flags, 535 const Condition cond = al); 536 537 // Compare double values and then load the fpscr flags to a register. 538 void VFPCompareAndLoadFlags(const DwVfpRegister src1, 539 const DwVfpRegister src2, 540 const Register fpscr_flags, 541 const Condition cond = al); 542 void VFPCompareAndLoadFlags(const DwVfpRegister src1, 543 const double src2, 544 const Register fpscr_flags, 545 const Condition cond = al); 546 547 void Vmov(const DwVfpRegister dst, 548 const double imm, 549 const Register scratch = no_reg); 550 551 void VmovHigh(Register dst, DwVfpRegister src); 552 void VmovHigh(DwVfpRegister dst, Register src); 553 void VmovLow(Register dst, DwVfpRegister src); 554 void VmovLow(DwVfpRegister dst, Register src); 555 556 // Simulate s-register moves for imaginary s32 - s63 registers. 557 void VmovExtended(Register dst, int src_code); 558 void VmovExtended(int dst_code, Register src); 559 // Move between s-registers and imaginary s-registers. 560 void VmovExtended(int dst_code, int src_code, Register scratch); 561 void VmovExtended(int dst_code, const MemOperand& src, Register scratch); 562 void VmovExtended(const MemOperand& dst, int src_code, Register scratch); 563 564 void ExtractLane(Register dst, QwNeonRegister src, NeonDataType dt, int lane); 565 void ExtractLane(SwVfpRegister dst, QwNeonRegister src, Register scratch, 566 int lane); 567 void ReplaceLane(QwNeonRegister dst, QwNeonRegister src, Register src_lane, 568 NeonDataType dt, int lane); 569 void ReplaceLane(QwNeonRegister dst, QwNeonRegister src, 570 SwVfpRegister src_lane, Register scratch, int lane); 571 void Swizzle(QwNeonRegister dst, QwNeonRegister src, Register scratch, 572 NeonSize size, uint32_t lanes); 573 574 void LslPair(Register dst_low, Register dst_high, Register src_low, 575 Register src_high, Register scratch, Register shift); 576 void LslPair(Register dst_low, Register dst_high, Register src_low, 577 Register src_high, uint32_t shift); 578 void LsrPair(Register dst_low, Register dst_high, Register src_low, 579 Register src_high, Register scratch, Register shift); 580 void LsrPair(Register dst_low, Register dst_high, Register src_low, 581 Register src_high, uint32_t shift); 582 void AsrPair(Register dst_low, Register dst_high, Register src_low, 583 Register src_high, Register scratch, Register shift); 584 void AsrPair(Register dst_low, Register dst_high, Register src_low, 585 Register src_high, uint32_t shift); 586 587 // Loads the number from object into dst register. 588 // If |object| is neither smi nor heap number, |not_number| is jumped to 589 // with |object| still intact. 590 void LoadNumber(Register object, 591 LowDwVfpRegister dst, 592 Register heap_number_map, 593 Register scratch, 594 Label* not_number); 595 596 // Loads the number from object into double_dst in the double format. 597 // Control will jump to not_int32 if the value cannot be exactly represented 598 // by a 32-bit integer. 599 // Floating point value in the 32-bit integer range that are not exact integer 600 // won't be loaded. 601 void LoadNumberAsInt32Double(Register object, 602 DwVfpRegister double_dst, 603 Register heap_number_map, 604 Register scratch, 605 LowDwVfpRegister double_scratch, 606 Label* not_int32); 607 608 // Loads the number from object into dst as a 32-bit integer. 609 // Control will jump to not_int32 if the object cannot be exactly represented 610 // by a 32-bit integer. 611 // Floating point value in the 32-bit integer range that are not exact integer 612 // won't be converted. 613 void LoadNumberAsInt32(Register object, 614 Register dst, 615 Register heap_number_map, 616 Register scratch, 617 DwVfpRegister double_scratch0, 618 LowDwVfpRegister double_scratch1, 619 Label* not_int32); 620 621 // Generates function and stub prologue code. 622 void StubPrologue(StackFrame::Type type); 623 void Prologue(bool code_pre_aging); 624 625 // Enter exit frame. 626 // stack_space - extra stack space, used for alignment before call to C. 627 void EnterExitFrame(bool save_doubles, int stack_space = 0, 628 StackFrame::Type frame_type = StackFrame::EXIT); 629 630 // Leave the current exit frame. Expects the return value in r0. 631 // Expect the number of values, pushed prior to the exit frame, to 632 // remove in a register (or no_reg, if there is nothing to remove). 633 void LeaveExitFrame(bool save_doubles, Register argument_count, 634 bool restore_context, 635 bool argument_count_is_length = false); 636 637 // Get the actual activation frame alignment for target environment. 638 static int ActivationFrameAlignment(); 639 640 void LoadContext(Register dst, int context_chain_length); 641 642 // Load the global object from the current context. 643 void LoadGlobalObject(Register dst) { 644 LoadNativeContextSlot(Context::EXTENSION_INDEX, dst); 645 } 646 647 // Load the global proxy from the current context. 648 void LoadGlobalProxy(Register dst) { 649 LoadNativeContextSlot(Context::GLOBAL_PROXY_INDEX, dst); 650 } 651 652 void LoadNativeContextSlot(int index, Register dst); 653 654 // Load the initial map from the global function. The registers 655 // function and map can be the same, function is then overwritten. 656 void LoadGlobalFunctionInitialMap(Register function, 657 Register map, 658 Register scratch); 659 660 void InitializeRootRegister() { 661 ExternalReference roots_array_start = 662 ExternalReference::roots_array_start(isolate()); 663 mov(kRootRegister, Operand(roots_array_start)); 664 } 665 666 // --------------------------------------------------------------------------- 667 // JavaScript invokes 668 669 // Removes current frame and its arguments from the stack preserving 670 // the arguments and a return address pushed to the stack for the next call. 671 // Both |callee_args_count| and |caller_args_count_reg| do not include 672 // receiver. |callee_args_count| is not modified, |caller_args_count_reg| 673 // is trashed. 674 void PrepareForTailCall(const ParameterCount& callee_args_count, 675 Register caller_args_count_reg, Register scratch0, 676 Register scratch1); 677 678 // Invoke the JavaScript function code by either calling or jumping. 679 void InvokeFunctionCode(Register function, Register new_target, 680 const ParameterCount& expected, 681 const ParameterCount& actual, InvokeFlag flag, 682 const CallWrapper& call_wrapper); 683 684 // On function call, call into the debugger if necessary. 685 void CheckDebugHook(Register fun, Register new_target, 686 const ParameterCount& expected, 687 const ParameterCount& actual); 688 689 // Invoke the JavaScript function in the given register. Changes the 690 // current context to the context in the function before invoking. 691 void InvokeFunction(Register function, 692 Register new_target, 693 const ParameterCount& actual, 694 InvokeFlag flag, 695 const CallWrapper& call_wrapper); 696 697 void InvokeFunction(Register function, 698 const ParameterCount& expected, 699 const ParameterCount& actual, 700 InvokeFlag flag, 701 const CallWrapper& call_wrapper); 702 703 void InvokeFunction(Handle<JSFunction> function, 704 const ParameterCount& expected, 705 const ParameterCount& actual, 706 InvokeFlag flag, 707 const CallWrapper& call_wrapper); 708 709 void IsObjectJSStringType(Register object, 710 Register scratch, 711 Label* fail); 712 713 void IsObjectNameType(Register object, 714 Register scratch, 715 Label* fail); 716 717 // Frame restart support 718 void MaybeDropFrames(); 719 720 // Exception handling 721 722 // Push a new stack handler and link into stack handler chain. 723 void PushStackHandler(); 724 725 // Unlink the stack handler on top of the stack from the stack handler chain. 726 // Must preserve the result register. 727 void PopStackHandler(); 728 729 // --------------------------------------------------------------------------- 730 // Inline caching support 731 732 void GetNumberHash(Register t0, Register scratch); 733 734 inline void MarkCode(NopMarkerTypes type) { 735 nop(type); 736 } 737 738 // Check if the given instruction is a 'type' marker. 739 // i.e. check if is is a mov r<type>, r<type> (referenced as nop(type)) 740 // These instructions are generated to mark special location in the code, 741 // like some special IC code. 742 static inline bool IsMarkedCode(Instr instr, int type) { 743 DCHECK((FIRST_IC_MARKER <= type) && (type < LAST_CODE_MARKER)); 744 return IsNop(instr, type); 745 } 746 747 748 static inline int GetCodeMarker(Instr instr) { 749 int dst_reg_offset = 12; 750 int dst_mask = 0xf << dst_reg_offset; 751 int src_mask = 0xf; 752 int dst_reg = (instr & dst_mask) >> dst_reg_offset; 753 int src_reg = instr & src_mask; 754 uint32_t non_register_mask = ~(dst_mask | src_mask); 755 uint32_t mov_mask = al | 13 << 21; 756 757 // Return <n> if we have a mov rn rn, else return -1. 758 int type = ((instr & non_register_mask) == mov_mask) && 759 (dst_reg == src_reg) && 760 (FIRST_IC_MARKER <= dst_reg) && (dst_reg < LAST_CODE_MARKER) 761 ? src_reg 762 : -1; 763 DCHECK((type == -1) || 764 ((FIRST_IC_MARKER <= type) && (type < LAST_CODE_MARKER))); 765 return type; 766 } 767 768 769 // --------------------------------------------------------------------------- 770 // Allocation support 771 772 // Allocate an object in new space or old space. The object_size is 773 // specified either in bytes or in words if the allocation flag SIZE_IN_WORDS 774 // is passed. If the space is exhausted control continues at the gc_required 775 // label. The allocated object is returned in result. If the flag 776 // tag_allocated_object is true the result is tagged as as a heap object. 777 // All registers are clobbered also when control continues at the gc_required 778 // label. 779 void Allocate(int object_size, 780 Register result, 781 Register scratch1, 782 Register scratch2, 783 Label* gc_required, 784 AllocationFlags flags); 785 786 void Allocate(Register object_size, Register result, Register result_end, 787 Register scratch, Label* gc_required, AllocationFlags flags); 788 789 // FastAllocate is right now only used for folded allocations. It just 790 // increments the top pointer without checking against limit. This can only 791 // be done if it was proved earlier that the allocation will succeed. 792 void FastAllocate(int object_size, Register result, Register scratch1, 793 Register scratch2, AllocationFlags flags); 794 795 void FastAllocate(Register object_size, Register result, Register result_end, 796 Register scratch, AllocationFlags flags); 797 798 // Allocates a heap number or jumps to the gc_required label if the young 799 // space is full and a scavenge is needed. All registers are clobbered also 800 // when control continues at the gc_required label. 801 void AllocateHeapNumber(Register result, 802 Register scratch1, 803 Register scratch2, 804 Register heap_number_map, 805 Label* gc_required, 806 MutableMode mode = IMMUTABLE); 807 void AllocateHeapNumberWithValue(Register result, 808 DwVfpRegister value, 809 Register scratch1, 810 Register scratch2, 811 Register heap_number_map, 812 Label* gc_required); 813 814 // Allocate and initialize a JSValue wrapper with the specified {constructor} 815 // and {value}. 816 void AllocateJSValue(Register result, Register constructor, Register value, 817 Register scratch1, Register scratch2, 818 Label* gc_required); 819 820 // Initialize fields with filler values. Fields starting at |current_address| 821 // not including |end_address| are overwritten with the value in |filler|. At 822 // the end the loop, |current_address| takes the value of |end_address|. 823 void InitializeFieldsWithFiller(Register current_address, 824 Register end_address, Register filler); 825 826 // --------------------------------------------------------------------------- 827 // Support functions. 828 829 // Machine code version of Map::GetConstructor(). 830 // |temp| holds |result|'s map when done, and |temp2| its instance type. 831 void GetMapConstructor(Register result, Register map, Register temp, 832 Register temp2); 833 834 // Compare object type for heap object. heap_object contains a non-Smi 835 // whose object type should be compared with the given type. This both 836 // sets the flags and leaves the object type in the type_reg register. 837 // It leaves the map in the map register (unless the type_reg and map register 838 // are the same register). It leaves the heap object in the heap_object 839 // register unless the heap_object register is the same register as one of the 840 // other registers. 841 // Type_reg can be no_reg. In that case ip is used. 842 void CompareObjectType(Register heap_object, 843 Register map, 844 Register type_reg, 845 InstanceType type); 846 847 // Compare instance type in a map. map contains a valid map object whose 848 // object type should be compared with the given type. This both 849 // sets the flags and leaves the object type in the type_reg register. 850 void CompareInstanceType(Register map, 851 Register type_reg, 852 InstanceType type); 853 854 // Compare an object's map with the specified map and its transitioned 855 // elements maps if mode is ALLOW_ELEMENT_TRANSITION_MAPS. Condition flags are 856 // set with result of map compare. If multiple map compares are required, the 857 // compare sequences branches to early_success. 858 void CompareMap(Register obj, 859 Register scratch, 860 Handle<Map> map, 861 Label* early_success); 862 863 // As above, but the map of the object is already loaded into the register 864 // which is preserved by the code generated. 865 void CompareMap(Register obj_map, 866 Handle<Map> map, 867 Label* early_success); 868 869 // Check if the map of an object is equal to a specified map and branch to 870 // label if not. Skip the smi check if not required (object is known to be a 871 // heap object). If mode is ALLOW_ELEMENT_TRANSITION_MAPS, then also match 872 // against maps that are ElementsKind transition maps of the specified map. 873 void CheckMap(Register obj, 874 Register scratch, 875 Handle<Map> map, 876 Label* fail, 877 SmiCheckType smi_check_type); 878 879 880 void CheckMap(Register obj, 881 Register scratch, 882 Heap::RootListIndex index, 883 Label* fail, 884 SmiCheckType smi_check_type); 885 886 887 // Check if the map of an object is equal to a specified weak map and branch 888 // to a specified target if equal. Skip the smi check if not required 889 // (object is known to be a heap object) 890 void DispatchWeakMap(Register obj, Register scratch1, Register scratch2, 891 Handle<WeakCell> cell, Handle<Code> success, 892 SmiCheckType smi_check_type); 893 894 // Compare the given value and the value of weak cell. 895 void CmpWeakValue(Register value, Handle<WeakCell> cell, Register scratch); 896 897 void GetWeakValue(Register value, Handle<WeakCell> cell); 898 899 // Load the value of the weak cell in the value register. Branch to the given 900 // miss label if the weak cell was cleared. 901 void LoadWeakValue(Register value, Handle<WeakCell> cell, Label* miss); 902 903 // Compare the object in a register to a value from the root list. 904 // Uses the ip register as scratch. 905 void CompareRoot(Register obj, Heap::RootListIndex index); 906 void PushRoot(Heap::RootListIndex index) { 907 LoadRoot(ip, index); 908 Push(ip); 909 } 910 911 // Compare the object in a register to a value and jump if they are equal. 912 void JumpIfRoot(Register with, Heap::RootListIndex index, Label* if_equal) { 913 CompareRoot(with, index); 914 b(eq, if_equal); 915 } 916 917 // Compare the object in a register to a value and jump if they are not equal. 918 void JumpIfNotRoot(Register with, Heap::RootListIndex index, 919 Label* if_not_equal) { 920 CompareRoot(with, index); 921 b(ne, if_not_equal); 922 } 923 924 // Load and check the instance type of an object for being a string. 925 // Loads the type into the second argument register. 926 // Returns a condition that will be enabled if the object was a string 927 // and the passed-in condition passed. If the passed-in condition failed 928 // then flags remain unchanged. 929 Condition IsObjectStringType(Register obj, 930 Register type, 931 Condition cond = al) { 932 ldr(type, FieldMemOperand(obj, HeapObject::kMapOffset), cond); 933 ldrb(type, FieldMemOperand(type, Map::kInstanceTypeOffset), cond); 934 tst(type, Operand(kIsNotStringMask), cond); 935 DCHECK_EQ(0u, kStringTag); 936 return eq; 937 } 938 939 940 // Get the number of least significant bits from a register 941 void GetLeastBitsFromSmi(Register dst, Register src, int num_least_bits); 942 void GetLeastBitsFromInt32(Register dst, Register src, int mun_least_bits); 943 944 // Load the value of a smi object into a double register. 945 // The register value must be between d0 and d15. 946 void SmiToDouble(LowDwVfpRegister value, Register smi); 947 948 // Check if a double can be exactly represented as a signed 32-bit integer. 949 // Z flag set to one if true. 950 void TestDoubleIsInt32(DwVfpRegister double_input, 951 LowDwVfpRegister double_scratch); 952 953 // Try to convert a double to a signed 32-bit integer. 954 // Z flag set to one and result assigned if the conversion is exact. 955 void TryDoubleToInt32Exact(Register result, 956 DwVfpRegister double_input, 957 LowDwVfpRegister double_scratch); 958 959 // Floor a double and writes the value to the result register. 960 // Go to exact if the conversion is exact (to be able to test -0), 961 // fall through calling code if an overflow occurred, else go to done. 962 // In return, input_high is loaded with high bits of input. 963 void TryInt32Floor(Register result, 964 DwVfpRegister double_input, 965 Register input_high, 966 LowDwVfpRegister double_scratch, 967 Label* done, 968 Label* exact); 969 970 // Performs a truncating conversion of a floating point number as used by 971 // the JS bitwise operations. See ECMA-262 9.5: ToInt32. Goes to 'done' if it 972 // succeeds, otherwise falls through if result is saturated. On return 973 // 'result' either holds answer, or is clobbered on fall through. 974 // 975 // Only public for the test code in test-code-stubs-arm.cc. 976 void TryInlineTruncateDoubleToI(Register result, 977 DwVfpRegister input, 978 Label* done); 979 980 // Performs a truncating conversion of a floating point number as used by 981 // the JS bitwise operations. See ECMA-262 9.5: ToInt32. 982 // Exits with 'result' holding the answer. 983 void TruncateDoubleToI(Register result, DwVfpRegister double_input); 984 985 // Performs a truncating conversion of a heap number as used by 986 // the JS bitwise operations. See ECMA-262 9.5: ToInt32. 'result' and 'input' 987 // must be different registers. Exits with 'result' holding the answer. 988 void TruncateHeapNumberToI(Register result, Register object); 989 990 // Converts the smi or heap number in object to an int32 using the rules 991 // for ToInt32 as described in ECMAScript 9.5.: the value is truncated 992 // and brought into the range -2^31 .. +2^31 - 1. 'result' and 'input' must be 993 // different registers. 994 void TruncateNumberToI(Register object, 995 Register result, 996 Register heap_number_map, 997 Register scratch1, 998 Label* not_int32); 999 1000 // Check whether d16-d31 are available on the CPU. The result is given by the 1001 // Z condition flag: Z==0 if d16-d31 available, Z==1 otherwise. 1002 void CheckFor32DRegs(Register scratch); 1003 1004 // Does a runtime check for 16/32 FP registers. Either way, pushes 32 double 1005 // values to location, saving [d0..(d15|d31)]. 1006 void SaveFPRegs(Register location, Register scratch); 1007 1008 // Does a runtime check for 16/32 FP registers. Either way, pops 32 double 1009 // values to location, restoring [d0..(d15|d31)]. 1010 void RestoreFPRegs(Register location, Register scratch); 1011 1012 // Perform a floating-point min or max operation with the 1013 // (IEEE-754-compatible) semantics of ARM64's fmin/fmax. Some cases, typically 1014 // NaNs or +/-0.0, are expected to be rare and are handled in out-of-line 1015 // code. The specific behaviour depends on supported instructions. 1016 // 1017 // These functions assume (and assert) that !left.is(right). It is permitted 1018 // for the result to alias either input register. 1019 void FloatMax(SwVfpRegister result, SwVfpRegister left, SwVfpRegister right, 1020 Label* out_of_line); 1021 void FloatMin(SwVfpRegister result, SwVfpRegister left, SwVfpRegister right, 1022 Label* out_of_line); 1023 void FloatMax(DwVfpRegister result, DwVfpRegister left, DwVfpRegister right, 1024 Label* out_of_line); 1025 void FloatMin(DwVfpRegister result, DwVfpRegister left, DwVfpRegister right, 1026 Label* out_of_line); 1027 1028 // Generate out-of-line cases for the macros above. 1029 void FloatMaxOutOfLine(SwVfpRegister result, SwVfpRegister left, 1030 SwVfpRegister right); 1031 void FloatMinOutOfLine(SwVfpRegister result, SwVfpRegister left, 1032 SwVfpRegister right); 1033 void FloatMaxOutOfLine(DwVfpRegister result, DwVfpRegister left, 1034 DwVfpRegister right); 1035 void FloatMinOutOfLine(DwVfpRegister result, DwVfpRegister left, 1036 DwVfpRegister right); 1037 1038 // --------------------------------------------------------------------------- 1039 // Runtime calls 1040 1041 // Call a code stub. 1042 void CallStub(CodeStub* stub, 1043 TypeFeedbackId ast_id = TypeFeedbackId::None(), 1044 Condition cond = al); 1045 1046 // Call a code stub. 1047 void TailCallStub(CodeStub* stub, Condition cond = al); 1048 1049 // Call a runtime routine. 1050 void CallRuntime(const Runtime::Function* f, 1051 int num_arguments, 1052 SaveFPRegsMode save_doubles = kDontSaveFPRegs); 1053 void CallRuntimeSaveDoubles(Runtime::FunctionId fid) { 1054 const Runtime::Function* function = Runtime::FunctionForId(fid); 1055 CallRuntime(function, function->nargs, kSaveFPRegs); 1056 } 1057 1058 // Convenience function: Same as above, but takes the fid instead. 1059 void CallRuntime(Runtime::FunctionId fid, 1060 SaveFPRegsMode save_doubles = kDontSaveFPRegs) { 1061 const Runtime::Function* function = Runtime::FunctionForId(fid); 1062 CallRuntime(function, function->nargs, save_doubles); 1063 } 1064 1065 // Convenience function: Same as above, but takes the fid instead. 1066 void CallRuntime(Runtime::FunctionId fid, int num_arguments, 1067 SaveFPRegsMode save_doubles = kDontSaveFPRegs) { 1068 CallRuntime(Runtime::FunctionForId(fid), num_arguments, save_doubles); 1069 } 1070 1071 // Convenience function: call an external reference. 1072 void CallExternalReference(const ExternalReference& ext, 1073 int num_arguments); 1074 1075 // Convenience function: tail call a runtime routine (jump). 1076 void TailCallRuntime(Runtime::FunctionId fid); 1077 1078 int CalculateStackPassedWords(int num_reg_arguments, 1079 int num_double_arguments); 1080 1081 // Before calling a C-function from generated code, align arguments on stack. 1082 // After aligning the frame, non-register arguments must be stored in 1083 // sp[0], sp[4], etc., not pushed. The argument count assumes all arguments 1084 // are word sized. If double arguments are used, this function assumes that 1085 // all double arguments are stored before core registers; otherwise the 1086 // correct alignment of the double values is not guaranteed. 1087 // Some compilers/platforms require the stack to be aligned when calling 1088 // C++ code. 1089 // Needs a scratch register to do some arithmetic. This register will be 1090 // trashed. 1091 void PrepareCallCFunction(int num_reg_arguments, 1092 int num_double_registers, 1093 Register scratch); 1094 void PrepareCallCFunction(int num_reg_arguments, 1095 Register scratch); 1096 1097 // There are two ways of passing double arguments on ARM, depending on 1098 // whether soft or hard floating point ABI is used. These functions 1099 // abstract parameter passing for the three different ways we call 1100 // C functions from generated code. 1101 void MovToFloatParameter(DwVfpRegister src); 1102 void MovToFloatParameters(DwVfpRegister src1, DwVfpRegister src2); 1103 void MovToFloatResult(DwVfpRegister src); 1104 1105 // Calls a C function and cleans up the space for arguments allocated 1106 // by PrepareCallCFunction. The called function is not allowed to trigger a 1107 // garbage collection, since that might move the code and invalidate the 1108 // return address (unless this is somehow accounted for by the called 1109 // function). 1110 void CallCFunction(ExternalReference function, int num_arguments); 1111 void CallCFunction(Register function, int num_arguments); 1112 void CallCFunction(ExternalReference function, 1113 int num_reg_arguments, 1114 int num_double_arguments); 1115 void CallCFunction(Register function, 1116 int num_reg_arguments, 1117 int num_double_arguments); 1118 1119 void MovFromFloatParameter(DwVfpRegister dst); 1120 void MovFromFloatResult(DwVfpRegister dst); 1121 1122 // Jump to a runtime routine. 1123 void JumpToExternalReference(const ExternalReference& builtin, 1124 bool builtin_exit_frame = false); 1125 1126 Handle<Object> CodeObject() { 1127 DCHECK(!code_object_.is_null()); 1128 return code_object_; 1129 } 1130 1131 1132 // Emit code for a truncating division by a constant. The dividend register is 1133 // unchanged and ip gets clobbered. Dividend and result must be different. 1134 void TruncatingDiv(Register result, Register dividend, int32_t divisor); 1135 1136 // --------------------------------------------------------------------------- 1137 // StatsCounter support 1138 1139 void SetCounter(StatsCounter* counter, int value, 1140 Register scratch1, Register scratch2); 1141 void IncrementCounter(StatsCounter* counter, int value, 1142 Register scratch1, Register scratch2); 1143 void DecrementCounter(StatsCounter* counter, int value, 1144 Register scratch1, Register scratch2); 1145 1146 1147 // --------------------------------------------------------------------------- 1148 // Debugging 1149 1150 // Calls Abort(msg) if the condition cond is not satisfied. 1151 // Use --debug_code to enable. 1152 void Assert(Condition cond, BailoutReason reason); 1153 void AssertFastElements(Register elements); 1154 1155 // Like Assert(), but always enabled. 1156 void Check(Condition cond, BailoutReason reason); 1157 1158 // Print a message to stdout and abort execution. 1159 void Abort(BailoutReason msg); 1160 1161 // Verify restrictions about code generated in stubs. 1162 void set_generating_stub(bool value) { generating_stub_ = value; } 1163 bool generating_stub() { return generating_stub_; } 1164 void set_has_frame(bool value) { has_frame_ = value; } 1165 bool has_frame() { return has_frame_; } 1166 inline bool AllowThisStubCall(CodeStub* stub); 1167 1168 // EABI variant for double arguments in use. 1169 bool use_eabi_hardfloat() { 1170 #ifdef __arm__ 1171 return base::OS::ArmUsingHardFloat(); 1172 #elif USE_EABI_HARDFLOAT 1173 return true; 1174 #else 1175 return false; 1176 #endif 1177 } 1178 1179 // --------------------------------------------------------------------------- 1180 // Number utilities 1181 1182 // Check whether the value of reg is a power of two and not zero. If not 1183 // control continues at the label not_power_of_two. If reg is a power of two 1184 // the register scratch contains the value of (reg - 1) when control falls 1185 // through. 1186 void JumpIfNotPowerOfTwoOrZero(Register reg, 1187 Register scratch, 1188 Label* not_power_of_two_or_zero); 1189 // Check whether the value of reg is a power of two and not zero. 1190 // Control falls through if it is, with scratch containing the mask 1191 // value (reg - 1). 1192 // Otherwise control jumps to the 'zero_and_neg' label if the value of reg is 1193 // zero or negative, or jumps to the 'not_power_of_two' label if the value is 1194 // strictly positive but not a power of two. 1195 void JumpIfNotPowerOfTwoOrZeroAndNeg(Register reg, 1196 Register scratch, 1197 Label* zero_and_neg, 1198 Label* not_power_of_two); 1199 1200 // --------------------------------------------------------------------------- 1201 // Smi utilities 1202 1203 void SmiTag(Register reg, SBit s = LeaveCC) { 1204 add(reg, reg, Operand(reg), s); 1205 } 1206 void SmiTag(Register dst, Register src, SBit s = LeaveCC) { 1207 add(dst, src, Operand(src), s); 1208 } 1209 1210 // Try to convert int32 to smi. If the value is to large, preserve 1211 // the original value and jump to not_a_smi. Destroys scratch and 1212 // sets flags. 1213 void TrySmiTag(Register reg, Label* not_a_smi) { 1214 TrySmiTag(reg, reg, not_a_smi); 1215 } 1216 void TrySmiTag(Register reg, Register src, Label* not_a_smi) { 1217 SmiTag(ip, src, SetCC); 1218 b(vs, not_a_smi); 1219 mov(reg, ip); 1220 } 1221 1222 1223 void SmiUntag(Register reg, SBit s = LeaveCC) { 1224 mov(reg, Operand::SmiUntag(reg), s); 1225 } 1226 void SmiUntag(Register dst, Register src, SBit s = LeaveCC) { 1227 mov(dst, Operand::SmiUntag(src), s); 1228 } 1229 1230 // Untag the source value into destination and jump if source is a smi. 1231 // Souce and destination can be the same register. 1232 void UntagAndJumpIfSmi(Register dst, Register src, Label* smi_case); 1233 1234 // Test if the register contains a smi (Z == 0 (eq) if true). 1235 inline void SmiTst(Register value) { 1236 tst(value, Operand(kSmiTagMask)); 1237 } 1238 inline void NonNegativeSmiTst(Register value) { 1239 tst(value, Operand(kSmiTagMask | kSmiSignMask)); 1240 } 1241 // Jump if the register contains a smi. 1242 inline void JumpIfSmi(Register value, Label* smi_label) { 1243 tst(value, Operand(kSmiTagMask)); 1244 b(eq, smi_label); 1245 } 1246 // Jump if either of the registers contain a non-smi. 1247 inline void JumpIfNotSmi(Register value, Label* not_smi_label) { 1248 tst(value, Operand(kSmiTagMask)); 1249 b(ne, not_smi_label); 1250 } 1251 // Jump if either of the registers contain a non-smi. 1252 void JumpIfNotBothSmi(Register reg1, Register reg2, Label* on_not_both_smi); 1253 // Jump if either of the registers contain a smi. 1254 void JumpIfEitherSmi(Register reg1, Register reg2, Label* on_either_smi); 1255 1256 // Abort execution if argument is a number, enabled via --debug-code. 1257 void AssertNotNumber(Register object); 1258 1259 // Abort execution if argument is a smi, enabled via --debug-code. 1260 void AssertNotSmi(Register object); 1261 void AssertSmi(Register object); 1262 1263 // Abort execution if argument is not a string, enabled via --debug-code. 1264 void AssertString(Register object); 1265 1266 // Abort execution if argument is not a name, enabled via --debug-code. 1267 void AssertName(Register object); 1268 1269 // Abort execution if argument is not a JSFunction, enabled via --debug-code. 1270 void AssertFunction(Register object); 1271 1272 // Abort execution if argument is not a JSBoundFunction, 1273 // enabled via --debug-code. 1274 void AssertBoundFunction(Register object); 1275 1276 // Abort execution if argument is not a JSGeneratorObject, 1277 // enabled via --debug-code. 1278 void AssertGeneratorObject(Register object); 1279 1280 // Abort execution if argument is not a JSReceiver, enabled via --debug-code. 1281 void AssertReceiver(Register object); 1282 1283 // Abort execution if argument is not undefined or an AllocationSite, enabled 1284 // via --debug-code. 1285 void AssertUndefinedOrAllocationSite(Register object, Register scratch); 1286 1287 // Abort execution if reg is not the root value with the given index, 1288 // enabled via --debug-code. 1289 void AssertIsRoot(Register reg, Heap::RootListIndex index); 1290 1291 // --------------------------------------------------------------------------- 1292 // HeapNumber utilities 1293 1294 void JumpIfNotHeapNumber(Register object, 1295 Register heap_number_map, 1296 Register scratch, 1297 Label* on_not_heap_number); 1298 1299 // --------------------------------------------------------------------------- 1300 // String utilities 1301 1302 // Checks if both objects are sequential one-byte strings and jumps to label 1303 // if either is not. Assumes that neither object is a smi. 1304 void JumpIfNonSmisNotBothSequentialOneByteStrings(Register object1, 1305 Register object2, 1306 Register scratch1, 1307 Register scratch2, 1308 Label* failure); 1309 1310 // Checks if both objects are sequential one-byte strings and jumps to label 1311 // if either is not. 1312 void JumpIfNotBothSequentialOneByteStrings(Register first, Register second, 1313 Register scratch1, 1314 Register scratch2, 1315 Label* not_flat_one_byte_strings); 1316 1317 // Checks if both instance types are sequential one-byte strings and jumps to 1318 // label if either is not. 1319 void JumpIfBothInstanceTypesAreNotSequentialOneByte( 1320 Register first_object_instance_type, Register second_object_instance_type, 1321 Register scratch1, Register scratch2, Label* failure); 1322 1323 void JumpIfNotUniqueNameInstanceType(Register reg, Label* not_unique_name); 1324 1325 void EmitSeqStringSetCharCheck(Register string, 1326 Register index, 1327 Register value, 1328 uint32_t encoding_mask); 1329 1330 1331 void ClampUint8(Register output_reg, Register input_reg); 1332 1333 void ClampDoubleToUint8(Register result_reg, 1334 DwVfpRegister input_reg, 1335 LowDwVfpRegister double_scratch); 1336 1337 1338 void LoadInstanceDescriptors(Register map, Register descriptors); 1339 void EnumLength(Register dst, Register map); 1340 void NumberOfOwnDescriptors(Register dst, Register map); 1341 void LoadAccessor(Register dst, Register holder, int accessor_index, 1342 AccessorComponent accessor); 1343 1344 template<typename Field> 1345 void DecodeField(Register dst, Register src) { 1346 Ubfx(dst, src, Field::kShift, Field::kSize); 1347 } 1348 1349 template<typename Field> 1350 void DecodeField(Register reg) { 1351 DecodeField<Field>(reg, reg); 1352 } 1353 1354 template<typename Field> 1355 void DecodeFieldToSmi(Register dst, Register src) { 1356 static const int shift = Field::kShift; 1357 static const int mask = Field::kMask >> shift << kSmiTagSize; 1358 STATIC_ASSERT((mask & (0x80000000u >> (kSmiTagSize - 1))) == 0); 1359 STATIC_ASSERT(kSmiTag == 0); 1360 if (shift < kSmiTagSize) { 1361 mov(dst, Operand(src, LSL, kSmiTagSize - shift)); 1362 and_(dst, dst, Operand(mask)); 1363 } else if (shift > kSmiTagSize) { 1364 mov(dst, Operand(src, LSR, shift - kSmiTagSize)); 1365 and_(dst, dst, Operand(mask)); 1366 } else { 1367 and_(dst, src, Operand(mask)); 1368 } 1369 } 1370 1371 template<typename Field> 1372 void DecodeFieldToSmi(Register reg) { 1373 DecodeField<Field>(reg, reg); 1374 } 1375 1376 // Load the type feedback vector from a JavaScript frame. 1377 void EmitLoadFeedbackVector(Register vector); 1378 1379 // Activation support. 1380 void EnterFrame(StackFrame::Type type, 1381 bool load_constant_pool_pointer_reg = false); 1382 // Returns the pc offset at which the frame ends. 1383 int LeaveFrame(StackFrame::Type type); 1384 1385 void EnterBuiltinFrame(Register context, Register target, Register argc); 1386 void LeaveBuiltinFrame(Register context, Register target, Register argc); 1387 1388 // Expects object in r0 and returns map with validated enum cache 1389 // in r0. Assumes that any other register can be used as a scratch. 1390 void CheckEnumCache(Label* call_runtime); 1391 1392 // AllocationMemento support. Arrays may have an associated 1393 // AllocationMemento object that can be checked for in order to pretransition 1394 // to another type. 1395 // On entry, receiver_reg should point to the array object. 1396 // scratch_reg gets clobbered. 1397 // If allocation info is present, condition flags are set to eq. 1398 void TestJSArrayForAllocationMemento(Register receiver_reg, 1399 Register scratch_reg, 1400 Label* no_memento_found); 1401 1402 // Loads the constant pool pointer (pp) register. 1403 void LoadConstantPoolPointerRegisterFromCodeTargetAddress( 1404 Register code_target_address); 1405 void LoadConstantPoolPointerRegister(); 1406 1407 private: 1408 void CallCFunctionHelper(Register function, 1409 int num_reg_arguments, 1410 int num_double_arguments); 1411 1412 void Jump(intptr_t target, RelocInfo::Mode rmode, Condition cond = al); 1413 1414 // Helper functions for generating invokes. 1415 void InvokePrologue(const ParameterCount& expected, 1416 const ParameterCount& actual, 1417 Label* done, 1418 bool* definitely_mismatches, 1419 InvokeFlag flag, 1420 const CallWrapper& call_wrapper); 1421 1422 // Helper for implementing JumpIfNotInNewSpace and JumpIfInNewSpace. 1423 void InNewSpace(Register object, 1424 Register scratch, 1425 Condition cond, // eq for new space, ne otherwise. 1426 Label* branch); 1427 1428 // Helper for finding the mark bits for an address. Afterwards, the 1429 // bitmap register points at the word with the mark bits and the mask 1430 // the position of the first bit. Leaves addr_reg unchanged. 1431 inline void GetMarkBits(Register addr_reg, 1432 Register bitmap_reg, 1433 Register mask_reg); 1434 1435 // Compute memory operands for safepoint stack slots. 1436 static int SafepointRegisterStackIndex(int reg_code); 1437 MemOperand SafepointRegisterSlot(Register reg); 1438 MemOperand SafepointRegistersAndDoublesSlot(Register reg); 1439 1440 // Implementation helpers for FloatMin and FloatMax. 1441 template <typename T> 1442 void FloatMaxHelper(T result, T left, T right, Label* out_of_line); 1443 template <typename T> 1444 void FloatMinHelper(T result, T left, T right, Label* out_of_line); 1445 template <typename T> 1446 void FloatMaxOutOfLineHelper(T result, T left, T right); 1447 template <typename T> 1448 void FloatMinOutOfLineHelper(T result, T left, T right); 1449 1450 bool generating_stub_; 1451 bool has_frame_; 1452 // This handle will be patched with the code object on installation. 1453 Handle<Object> code_object_; 1454 1455 // Needs access to SafepointRegisterStackIndex for compiled frame 1456 // traversal. 1457 friend class StandardFrame; 1458 }; 1459 1460 1461 // The code patcher is used to patch (typically) small parts of code e.g. for 1462 // debugging and other types of instrumentation. When using the code patcher 1463 // the exact number of bytes specified must be emitted. It is not legal to emit 1464 // relocation information. If any of these constraints are violated it causes 1465 // an assertion to fail. 1466 class CodePatcher { 1467 public: 1468 enum FlushICache { 1469 FLUSH, 1470 DONT_FLUSH 1471 }; 1472 1473 CodePatcher(Isolate* isolate, byte* address, int instructions, 1474 FlushICache flush_cache = FLUSH); 1475 ~CodePatcher(); 1476 1477 // Macro assembler to emit code. 1478 MacroAssembler* masm() { return &masm_; } 1479 1480 // Emit an instruction directly. 1481 void Emit(Instr instr); 1482 1483 // Emit an address directly. 1484 void Emit(Address addr); 1485 1486 // Emit the condition part of an instruction leaving the rest of the current 1487 // instruction unchanged. 1488 void EmitCondition(Condition cond); 1489 1490 private: 1491 byte* address_; // The address of the code being patched. 1492 int size_; // Number of bytes of the expected patch size. 1493 MacroAssembler masm_; // Macro assembler used to generate the code. 1494 FlushICache flush_cache_; // Whether to flush the I cache after patching. 1495 }; 1496 1497 1498 // ----------------------------------------------------------------------------- 1499 // Static helper functions. 1500 1501 inline MemOperand ContextMemOperand(Register context, int index = 0) { 1502 return MemOperand(context, Context::SlotOffset(index)); 1503 } 1504 1505 1506 inline MemOperand NativeContextMemOperand() { 1507 return ContextMemOperand(cp, Context::NATIVE_CONTEXT_INDEX); 1508 } 1509 1510 #define ACCESS_MASM(masm) masm-> 1511 1512 } // namespace internal 1513 } // namespace v8 1514 1515 #endif // V8_ARM_MACRO_ASSEMBLER_ARM_H_ 1516