1 // Copyright 2014 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_PPC_MACRO_ASSEMBLER_PPC_H_ 6 #define V8_PPC_MACRO_ASSEMBLER_PPC_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_r3}; 18 const Register kReturnRegister1 = {Register::kCode_r4}; 19 const Register kReturnRegister2 = {Register::kCode_r5}; 20 const Register kJSFunctionRegister = {Register::kCode_r4}; 21 const Register kContextRegister = {Register::kCode_r30}; 22 const Register kAllocateSizeRegister = {Register::kCode_r4}; 23 const Register kInterpreterAccumulatorRegister = {Register::kCode_r3}; 24 const Register kInterpreterBytecodeOffsetRegister = {Register::kCode_r15}; 25 const Register kInterpreterBytecodeArrayRegister = {Register::kCode_r16}; 26 const Register kInterpreterDispatchTableRegister = {Register::kCode_r17}; 27 const Register kJavaScriptCallArgCountRegister = {Register::kCode_r3}; 28 const Register kJavaScriptCallNewTargetRegister = {Register::kCode_r6}; 29 const Register kRuntimeCallFunctionRegister = {Register::kCode_r4}; 30 const Register kRuntimeCallArgCountRegister = {Register::kCode_r3}; 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 // Flags used for AllocateHeapNumber 42 enum TaggingMode { 43 // Tag the result. 44 TAG_RESULT, 45 // Don't tag 46 DONT_TAG_RESULT 47 }; 48 49 50 enum RememberedSetAction { EMIT_REMEMBERED_SET, OMIT_REMEMBERED_SET }; 51 enum SmiCheck { INLINE_SMI_CHECK, OMIT_SMI_CHECK }; 52 enum PointersToHereCheck { 53 kPointersToHereMaybeInteresting, 54 kPointersToHereAreAlwaysInteresting 55 }; 56 enum LinkRegisterStatus { kLRHasNotBeenSaved, kLRHasBeenSaved }; 57 58 59 Register GetRegisterThatIsNotOneOf(Register reg1, Register reg2 = no_reg, 60 Register reg3 = no_reg, 61 Register reg4 = no_reg, 62 Register reg5 = no_reg, 63 Register reg6 = no_reg); 64 65 66 #ifdef DEBUG 67 bool AreAliased(Register reg1, Register reg2, Register reg3 = no_reg, 68 Register reg4 = no_reg, Register reg5 = no_reg, 69 Register reg6 = no_reg, Register reg7 = no_reg, 70 Register reg8 = no_reg, Register reg9 = no_reg, 71 Register reg10 = no_reg); 72 #endif 73 74 // These exist to provide portability between 32 and 64bit 75 #if V8_TARGET_ARCH_PPC64 76 #define LoadPX ldx 77 #define LoadPUX ldux 78 #define StorePX stdx 79 #define StorePUX stdux 80 #define ShiftLeftImm sldi 81 #define ShiftRightImm srdi 82 #define ClearLeftImm clrldi 83 #define ClearRightImm clrrdi 84 #define ShiftRightArithImm sradi 85 #define ShiftLeft_ sld 86 #define ShiftRight_ srd 87 #define ShiftRightArith srad 88 #define Mul mulld 89 #define Div divd 90 #else 91 #define LoadPX lwzx 92 #define LoadPUX lwzux 93 #define StorePX stwx 94 #define StorePUX stwux 95 #define ShiftLeftImm slwi 96 #define ShiftRightImm srwi 97 #define ClearLeftImm clrlwi 98 #define ClearRightImm clrrwi 99 #define ShiftRightArithImm srawi 100 #define ShiftLeft_ slw 101 #define ShiftRight_ srw 102 #define ShiftRightArith sraw 103 #define Mul mullw 104 #define Div divw 105 #endif 106 107 108 // MacroAssembler implements a collection of frequently used macros. 109 class MacroAssembler : public Assembler { 110 public: 111 MacroAssembler(Isolate* isolate, void* buffer, int size, 112 CodeObjectRequired create_code_object); 113 114 115 // Returns the size of a call in instructions. Note, the value returned is 116 // only valid as long as no entries are added to the constant pool between 117 // checking the call size and emitting the actual call. 118 static int CallSize(Register target); 119 int CallSize(Address target, RelocInfo::Mode rmode, Condition cond = al); 120 static int CallSizeNotPredictableCodeSize(Address target, 121 RelocInfo::Mode rmode, 122 Condition cond = al); 123 124 // Jump, Call, and Ret pseudo instructions implementing inter-working. 125 void Jump(Register target); 126 void JumpToJSEntry(Register target); 127 void Jump(Address target, RelocInfo::Mode rmode, Condition cond = al, 128 CRegister cr = cr7); 129 void Jump(Handle<Code> code, RelocInfo::Mode rmode, Condition cond = al); 130 void Call(Register target); 131 void CallJSEntry(Register target); 132 void Call(Address target, RelocInfo::Mode rmode, Condition cond = al); 133 int CallSize(Handle<Code> code, 134 RelocInfo::Mode rmode = RelocInfo::CODE_TARGET, 135 TypeFeedbackId ast_id = TypeFeedbackId::None(), 136 Condition cond = al); 137 void Call(Handle<Code> code, RelocInfo::Mode rmode = RelocInfo::CODE_TARGET, 138 TypeFeedbackId ast_id = TypeFeedbackId::None(), 139 Condition cond = al); 140 void Ret() { blr(); } 141 void Ret(Condition cond, CRegister cr = cr7) { bclr(cond, cr); } 142 143 // Emit code that loads |parameter_index|'th parameter from the stack to 144 // the register according to the CallInterfaceDescriptor definition. 145 // |sp_to_caller_sp_offset_in_words| specifies the number of words pushed 146 // below the caller's sp. 147 template <class Descriptor> 148 void LoadParameterFromStack( 149 Register reg, typename Descriptor::ParameterIndices parameter_index, 150 int sp_to_ra_offset_in_words = 0) { 151 DCHECK(Descriptor::kPassLastArgsOnStack); 152 UNIMPLEMENTED(); 153 } 154 155 // Emit code to discard a non-negative number of pointer-sized elements 156 // from the stack, clobbering only the sp register. 157 void Drop(int count); 158 void Drop(Register count, Register scratch = r0); 159 160 void Ret(int drop) { 161 Drop(drop); 162 blr(); 163 } 164 165 void Call(Label* target); 166 167 // Register move. May do nothing if the registers are identical. 168 void Move(Register dst, Smi* smi) { LoadSmiLiteral(dst, smi); } 169 void Move(Register dst, Handle<Object> value); 170 void Move(Register dst, Register src, Condition cond = al); 171 void Move(DoubleRegister dst, DoubleRegister src); 172 173 void MultiPush(RegList regs, Register location = sp); 174 void MultiPop(RegList regs, Register location = sp); 175 176 void MultiPushDoubles(RegList dregs, Register location = sp); 177 void MultiPopDoubles(RegList dregs, Register location = sp); 178 179 // Load an object from the root table. 180 void LoadRoot(Register destination, Heap::RootListIndex index, 181 Condition cond = al); 182 // Store an object to the root table. 183 void StoreRoot(Register source, Heap::RootListIndex index, 184 Condition cond = al); 185 186 // --------------------------------------------------------------------------- 187 // GC Support 188 189 void IncrementalMarkingRecordWriteHelper(Register object, Register value, 190 Register address); 191 192 enum RememberedSetFinalAction { kReturnAtEnd, kFallThroughAtEnd }; 193 194 // Record in the remembered set the fact that we have a pointer to new space 195 // at the address pointed to by the addr register. Only works if addr is not 196 // in new space. 197 void RememberedSetHelper(Register object, // Used for debug code. 198 Register addr, Register scratch, 199 SaveFPRegsMode save_fp, 200 RememberedSetFinalAction and_then); 201 202 void CheckPageFlag(Register object, Register scratch, int mask, Condition cc, 203 Label* condition_met); 204 205 // Check if object is in new space. Jumps if the object is not in new space. 206 // The register scratch can be object itself, but scratch will be clobbered. 207 void JumpIfNotInNewSpace(Register object, Register scratch, Label* branch) { 208 InNewSpace(object, scratch, eq, branch); 209 } 210 211 // Check if object is in new space. Jumps if the object is in new space. 212 // The register scratch can be object itself, but it will be clobbered. 213 void JumpIfInNewSpace(Register object, Register scratch, Label* branch) { 214 InNewSpace(object, scratch, ne, branch); 215 } 216 217 // Check if an object has a given incremental marking color. 218 void HasColor(Register object, Register scratch0, Register scratch1, 219 Label* has_color, int first_bit, int second_bit); 220 221 void JumpIfBlack(Register object, Register scratch0, Register scratch1, 222 Label* on_black); 223 224 // Checks the color of an object. If the object is white we jump to the 225 // incremental marker. 226 void JumpIfWhite(Register value, Register scratch1, Register scratch2, 227 Register scratch3, Label* value_is_white); 228 229 // Notify the garbage collector that we wrote a pointer into an object. 230 // |object| is the object being stored into, |value| is the object being 231 // stored. value and scratch registers are clobbered by the operation. 232 // The offset is the offset from the start of the object, not the offset from 233 // the tagged HeapObject pointer. For use with FieldMemOperand(reg, off). 234 void RecordWriteField( 235 Register object, int offset, Register value, Register scratch, 236 LinkRegisterStatus lr_status, SaveFPRegsMode save_fp, 237 RememberedSetAction remembered_set_action = EMIT_REMEMBERED_SET, 238 SmiCheck smi_check = INLINE_SMI_CHECK, 239 PointersToHereCheck pointers_to_here_check_for_value = 240 kPointersToHereMaybeInteresting); 241 242 // As above, but the offset has the tag presubtracted. For use with 243 // MemOperand(reg, off). 244 inline void RecordWriteContextSlot( 245 Register context, int offset, Register value, Register scratch, 246 LinkRegisterStatus lr_status, SaveFPRegsMode save_fp, 247 RememberedSetAction remembered_set_action = EMIT_REMEMBERED_SET, 248 SmiCheck smi_check = INLINE_SMI_CHECK, 249 PointersToHereCheck pointers_to_here_check_for_value = 250 kPointersToHereMaybeInteresting) { 251 RecordWriteField(context, offset + kHeapObjectTag, value, scratch, 252 lr_status, save_fp, remembered_set_action, smi_check, 253 pointers_to_here_check_for_value); 254 } 255 256 // Notify the garbage collector that we wrote a code entry into a 257 // JSFunction. Only scratch is clobbered by the operation. 258 void RecordWriteCodeEntryField(Register js_function, Register code_entry, 259 Register scratch); 260 261 void RecordWriteForMap(Register object, Register map, Register dst, 262 LinkRegisterStatus lr_status, SaveFPRegsMode save_fp); 263 264 // For a given |object| notify the garbage collector that the slot |address| 265 // has been written. |value| is the object being stored. The value and 266 // address registers are clobbered by the operation. 267 void RecordWrite( 268 Register object, Register address, Register value, 269 LinkRegisterStatus lr_status, SaveFPRegsMode save_fp, 270 RememberedSetAction remembered_set_action = EMIT_REMEMBERED_SET, 271 SmiCheck smi_check = INLINE_SMI_CHECK, 272 PointersToHereCheck pointers_to_here_check_for_value = 273 kPointersToHereMaybeInteresting); 274 275 void Push(Register src) { push(src); } 276 277 // Push a handle. 278 void Push(Handle<Object> handle); 279 void Push(Smi* smi) { Push(Handle<Smi>(smi, isolate())); } 280 281 // Push two registers. Pushes leftmost register first (to highest address). 282 void Push(Register src1, Register src2) { 283 StorePU(src2, MemOperand(sp, -2 * kPointerSize)); 284 StoreP(src1, MemOperand(sp, kPointerSize)); 285 } 286 287 // Push three registers. Pushes leftmost register first (to highest address). 288 void Push(Register src1, Register src2, Register src3) { 289 StorePU(src3, MemOperand(sp, -3 * kPointerSize)); 290 StoreP(src2, MemOperand(sp, kPointerSize)); 291 StoreP(src1, MemOperand(sp, 2 * kPointerSize)); 292 } 293 294 // Push four registers. Pushes leftmost register first (to highest address). 295 void Push(Register src1, Register src2, Register src3, Register src4) { 296 StorePU(src4, MemOperand(sp, -4 * kPointerSize)); 297 StoreP(src3, MemOperand(sp, kPointerSize)); 298 StoreP(src2, MemOperand(sp, 2 * kPointerSize)); 299 StoreP(src1, MemOperand(sp, 3 * kPointerSize)); 300 } 301 302 // Push five registers. Pushes leftmost register first (to highest address). 303 void Push(Register src1, Register src2, Register src3, Register src4, 304 Register src5) { 305 StorePU(src5, MemOperand(sp, -5 * kPointerSize)); 306 StoreP(src4, MemOperand(sp, kPointerSize)); 307 StoreP(src3, MemOperand(sp, 2 * kPointerSize)); 308 StoreP(src2, MemOperand(sp, 3 * kPointerSize)); 309 StoreP(src1, MemOperand(sp, 4 * kPointerSize)); 310 } 311 312 void Pop(Register dst) { pop(dst); } 313 314 // Pop two registers. Pops rightmost register first (from lower address). 315 void Pop(Register src1, Register src2) { 316 LoadP(src2, MemOperand(sp, 0)); 317 LoadP(src1, MemOperand(sp, kPointerSize)); 318 addi(sp, sp, Operand(2 * kPointerSize)); 319 } 320 321 // Pop three registers. Pops rightmost register first (from lower address). 322 void Pop(Register src1, Register src2, Register src3) { 323 LoadP(src3, MemOperand(sp, 0)); 324 LoadP(src2, MemOperand(sp, kPointerSize)); 325 LoadP(src1, MemOperand(sp, 2 * kPointerSize)); 326 addi(sp, sp, Operand(3 * kPointerSize)); 327 } 328 329 // Pop four registers. Pops rightmost register first (from lower address). 330 void Pop(Register src1, Register src2, Register src3, Register src4) { 331 LoadP(src4, MemOperand(sp, 0)); 332 LoadP(src3, MemOperand(sp, kPointerSize)); 333 LoadP(src2, MemOperand(sp, 2 * kPointerSize)); 334 LoadP(src1, MemOperand(sp, 3 * kPointerSize)); 335 addi(sp, sp, Operand(4 * kPointerSize)); 336 } 337 338 // Pop five registers. Pops rightmost register first (from lower address). 339 void Pop(Register src1, Register src2, Register src3, Register src4, 340 Register src5) { 341 LoadP(src5, MemOperand(sp, 0)); 342 LoadP(src4, MemOperand(sp, kPointerSize)); 343 LoadP(src3, MemOperand(sp, 2 * kPointerSize)); 344 LoadP(src2, MemOperand(sp, 3 * kPointerSize)); 345 LoadP(src1, MemOperand(sp, 4 * kPointerSize)); 346 addi(sp, sp, Operand(5 * kPointerSize)); 347 } 348 349 // Push a fixed frame, consisting of lr, fp, constant pool. 350 void PushCommonFrame(Register marker_reg = no_reg); 351 352 // Push a standard frame, consisting of lr, fp, constant pool, 353 // context and JS function 354 void PushStandardFrame(Register function_reg); 355 356 void PopCommonFrame(Register marker_reg = no_reg); 357 358 // Restore caller's frame pointer and return address prior to being 359 // overwritten by tail call stack preparation. 360 void RestoreFrameStateForTailCall(); 361 362 // Push and pop the registers that can hold pointers, as defined by the 363 // RegList constant kSafepointSavedRegisters. 364 void PushSafepointRegisters(); 365 void PopSafepointRegisters(); 366 // Store value in register src in the safepoint stack slot for 367 // register dst. 368 void StoreToSafepointRegisterSlot(Register src, Register dst); 369 // Load the value of the src register from its safepoint stack slot 370 // into register dst. 371 void LoadFromSafepointRegisterSlot(Register dst, Register src); 372 373 // Flush the I-cache from asm code. You should use CpuFeatures::FlushICache 374 // from C. 375 // Does not handle errors. 376 void FlushICache(Register address, size_t size, Register scratch); 377 378 // If the value is a NaN, canonicalize the value else, do nothing. 379 void CanonicalizeNaN(const DoubleRegister dst, const DoubleRegister src); 380 void CanonicalizeNaN(const DoubleRegister value) { 381 CanonicalizeNaN(value, value); 382 } 383 384 // Converts the integer (untagged smi) in |src| to a double, storing 385 // the result to |dst| 386 void ConvertIntToDouble(Register src, DoubleRegister dst); 387 388 // Converts the unsigned integer (untagged smi) in |src| to 389 // a double, storing the result to |dst| 390 void ConvertUnsignedIntToDouble(Register src, DoubleRegister dst); 391 392 // Converts the integer (untagged smi) in |src| to 393 // a float, storing the result in |dst| 394 void ConvertIntToFloat(Register src, DoubleRegister dst); 395 396 // Converts the unsigned integer (untagged smi) in |src| to 397 // a float, storing the result in |dst| 398 void ConvertUnsignedIntToFloat(Register src, DoubleRegister dst); 399 400 #if V8_TARGET_ARCH_PPC64 401 void ConvertInt64ToFloat(Register src, DoubleRegister double_dst); 402 void ConvertInt64ToDouble(Register src, DoubleRegister double_dst); 403 void ConvertUnsignedInt64ToFloat(Register src, DoubleRegister double_dst); 404 void ConvertUnsignedInt64ToDouble(Register src, DoubleRegister double_dst); 405 #endif 406 407 // Converts the double_input to an integer. Note that, upon return, 408 // the contents of double_dst will also hold the fixed point representation. 409 void ConvertDoubleToInt64(const DoubleRegister double_input, 410 #if !V8_TARGET_ARCH_PPC64 411 const Register dst_hi, 412 #endif 413 const Register dst, const DoubleRegister double_dst, 414 FPRoundingMode rounding_mode = kRoundToZero); 415 416 #if V8_TARGET_ARCH_PPC64 417 // Converts the double_input to an unsigned integer. Note that, upon return, 418 // the contents of double_dst will also hold the fixed point representation. 419 void ConvertDoubleToUnsignedInt64( 420 const DoubleRegister double_input, const Register dst, 421 const DoubleRegister double_dst, 422 FPRoundingMode rounding_mode = kRoundToZero); 423 #endif 424 425 #if !V8_TARGET_ARCH_PPC64 426 void ShiftLeftPair(Register dst_low, Register dst_high, Register src_low, 427 Register src_high, Register scratch, Register shift); 428 void ShiftLeftPair(Register dst_low, Register dst_high, Register src_low, 429 Register src_high, uint32_t shift); 430 void ShiftRightPair(Register dst_low, Register dst_high, Register src_low, 431 Register src_high, Register scratch, Register shift); 432 void ShiftRightPair(Register dst_low, Register dst_high, Register src_low, 433 Register src_high, uint32_t shift); 434 void ShiftRightAlgPair(Register dst_low, Register dst_high, Register src_low, 435 Register src_high, Register scratch, Register shift); 436 void ShiftRightAlgPair(Register dst_low, Register dst_high, Register src_low, 437 Register src_high, uint32_t shift); 438 #endif 439 440 // Generates function and stub prologue code. 441 void StubPrologue(StackFrame::Type type, Register base = no_reg, 442 int prologue_offset = 0); 443 void Prologue(bool code_pre_aging, Register base, int prologue_offset = 0); 444 445 // Enter exit frame. 446 // stack_space - extra stack space, used for parameters before call to C. 447 // At least one slot (for the return address) should be provided. 448 void EnterExitFrame(bool save_doubles, int stack_space = 1, 449 StackFrame::Type frame_type = StackFrame::EXIT); 450 451 // Leave the current exit frame. Expects the return value in r0. 452 // Expect the number of values, pushed prior to the exit frame, to 453 // remove in a register (or no_reg, if there is nothing to remove). 454 void LeaveExitFrame(bool save_doubles, Register argument_count, 455 bool restore_context, 456 bool argument_count_is_length = false); 457 458 // Get the actual activation frame alignment for target environment. 459 static int ActivationFrameAlignment(); 460 461 void LoadContext(Register dst, int context_chain_length); 462 463 // Load the global object from the current context. 464 void LoadGlobalObject(Register dst) { 465 LoadNativeContextSlot(Context::EXTENSION_INDEX, dst); 466 } 467 468 // Load the global proxy from the current context. 469 void LoadGlobalProxy(Register dst) { 470 LoadNativeContextSlot(Context::GLOBAL_PROXY_INDEX, dst); 471 } 472 473 // Conditionally load the cached Array transitioned map of type 474 // transitioned_kind from the native context if the map in register 475 // map_in_out is the cached Array map in the native context of 476 // expected_kind. 477 void LoadTransitionedArrayMapConditional(ElementsKind expected_kind, 478 ElementsKind transitioned_kind, 479 Register map_in_out, 480 Register scratch, 481 Label* no_map_match); 482 483 void LoadNativeContextSlot(int index, Register dst); 484 485 // Load the initial map from the global function. The registers 486 // function and map can be the same, function is then overwritten. 487 void LoadGlobalFunctionInitialMap(Register function, Register map, 488 Register scratch); 489 490 void InitializeRootRegister() { 491 ExternalReference roots_array_start = 492 ExternalReference::roots_array_start(isolate()); 493 mov(kRootRegister, Operand(roots_array_start)); 494 } 495 496 // ---------------------------------------------------------------- 497 // new PPC macro-assembler interfaces that are slightly higher level 498 // than assembler-ppc and may generate variable length sequences 499 500 // load a literal signed int value <value> to GPR <dst> 501 void LoadIntLiteral(Register dst, int value); 502 503 // load an SMI value <value> to GPR <dst> 504 void LoadSmiLiteral(Register dst, Smi* smi); 505 506 // load a literal double value <value> to FPR <result> 507 void LoadDoubleLiteral(DoubleRegister result, double value, Register scratch); 508 509 void LoadWord(Register dst, const MemOperand& mem, Register scratch); 510 void LoadWordArith(Register dst, const MemOperand& mem, 511 Register scratch = no_reg); 512 void StoreWord(Register src, const MemOperand& mem, Register scratch); 513 514 void LoadHalfWord(Register dst, const MemOperand& mem, Register scratch); 515 void LoadHalfWordArith(Register dst, const MemOperand& mem, 516 Register scratch = no_reg); 517 void StoreHalfWord(Register src, const MemOperand& mem, Register scratch); 518 519 void LoadByte(Register dst, const MemOperand& mem, Register scratch); 520 void StoreByte(Register src, const MemOperand& mem, Register scratch); 521 522 void LoadRepresentation(Register dst, const MemOperand& mem, Representation r, 523 Register scratch = no_reg); 524 void StoreRepresentation(Register src, const MemOperand& mem, 525 Representation r, Register scratch = no_reg); 526 527 void LoadDouble(DoubleRegister dst, const MemOperand& mem, 528 Register scratch = no_reg); 529 void LoadDoubleU(DoubleRegister dst, const MemOperand& mem, 530 Register scratch = no_reg); 531 532 void LoadSingle(DoubleRegister dst, const MemOperand& mem, 533 Register scratch = no_reg); 534 void LoadSingleU(DoubleRegister dst, const MemOperand& mem, 535 Register scratch = no_reg); 536 537 void StoreDouble(DoubleRegister src, const MemOperand& mem, 538 Register scratch = no_reg); 539 void StoreDoubleU(DoubleRegister src, const MemOperand& mem, 540 Register scratch = no_reg); 541 542 void StoreSingle(DoubleRegister src, const MemOperand& mem, 543 Register scratch = no_reg); 544 void StoreSingleU(DoubleRegister src, const MemOperand& mem, 545 Register scratch = no_reg); 546 547 // Move values between integer and floating point registers. 548 void MovIntToDouble(DoubleRegister dst, Register src, Register scratch); 549 void MovUnsignedIntToDouble(DoubleRegister dst, Register src, 550 Register scratch); 551 void MovInt64ToDouble(DoubleRegister dst, 552 #if !V8_TARGET_ARCH_PPC64 553 Register src_hi, 554 #endif 555 Register src); 556 #if V8_TARGET_ARCH_PPC64 557 void MovInt64ComponentsToDouble(DoubleRegister dst, Register src_hi, 558 Register src_lo, Register scratch); 559 #endif 560 void InsertDoubleLow(DoubleRegister dst, Register src, Register scratch); 561 void InsertDoubleHigh(DoubleRegister dst, Register src, Register scratch); 562 void MovDoubleLowToInt(Register dst, DoubleRegister src); 563 void MovDoubleHighToInt(Register dst, DoubleRegister src); 564 void MovDoubleToInt64( 565 #if !V8_TARGET_ARCH_PPC64 566 Register dst_hi, 567 #endif 568 Register dst, DoubleRegister src); 569 void MovIntToFloat(DoubleRegister dst, Register src); 570 void MovFloatToInt(Register dst, DoubleRegister src); 571 572 void Add(Register dst, Register src, intptr_t value, Register scratch); 573 void Cmpi(Register src1, const Operand& src2, Register scratch, 574 CRegister cr = cr7); 575 void Cmpli(Register src1, const Operand& src2, Register scratch, 576 CRegister cr = cr7); 577 void Cmpwi(Register src1, const Operand& src2, Register scratch, 578 CRegister cr = cr7); 579 void Cmplwi(Register src1, const Operand& src2, Register scratch, 580 CRegister cr = cr7); 581 void And(Register ra, Register rs, const Operand& rb, RCBit rc = LeaveRC); 582 void Or(Register ra, Register rs, const Operand& rb, RCBit rc = LeaveRC); 583 void Xor(Register ra, Register rs, const Operand& rb, RCBit rc = LeaveRC); 584 585 void AddSmiLiteral(Register dst, Register src, Smi* smi, Register scratch); 586 void SubSmiLiteral(Register dst, Register src, Smi* smi, Register scratch); 587 void CmpSmiLiteral(Register src1, Smi* smi, Register scratch, 588 CRegister cr = cr7); 589 void CmplSmiLiteral(Register src1, Smi* smi, Register scratch, 590 CRegister cr = cr7); 591 void AndSmiLiteral(Register dst, Register src, Smi* smi, Register scratch, 592 RCBit rc = LeaveRC); 593 594 // Set new rounding mode RN to FPSCR 595 void SetRoundingMode(FPRoundingMode RN); 596 597 // reset rounding mode to default (kRoundToNearest) 598 void ResetRoundingMode(); 599 600 // These exist to provide portability between 32 and 64bit 601 void LoadP(Register dst, const MemOperand& mem, Register scratch = no_reg); 602 void LoadPU(Register dst, const MemOperand& mem, Register scratch = no_reg); 603 void StoreP(Register src, const MemOperand& mem, Register scratch = no_reg); 604 void StorePU(Register src, const MemOperand& mem, Register scratch = no_reg); 605 606 // --------------------------------------------------------------------------- 607 // JavaScript invokes 608 609 // Removes current frame and its arguments from the stack preserving 610 // the arguments and a return address pushed to the stack for the next call. 611 // Both |callee_args_count| and |caller_args_count_reg| do not include 612 // receiver. |callee_args_count| is not modified, |caller_args_count_reg| 613 // is trashed. 614 void PrepareForTailCall(const ParameterCount& callee_args_count, 615 Register caller_args_count_reg, Register scratch0, 616 Register scratch1); 617 618 // Invoke the JavaScript function code by either calling or jumping. 619 void InvokeFunctionCode(Register function, Register new_target, 620 const ParameterCount& expected, 621 const ParameterCount& actual, InvokeFlag flag, 622 const CallWrapper& call_wrapper); 623 624 void FloodFunctionIfStepping(Register fun, Register new_target, 625 const ParameterCount& expected, 626 const ParameterCount& actual); 627 628 // Invoke the JavaScript function in the given register. Changes the 629 // current context to the context in the function before invoking. 630 void InvokeFunction(Register function, Register new_target, 631 const ParameterCount& actual, InvokeFlag flag, 632 const CallWrapper& call_wrapper); 633 634 void InvokeFunction(Register function, const ParameterCount& expected, 635 const ParameterCount& actual, InvokeFlag flag, 636 const CallWrapper& call_wrapper); 637 638 void InvokeFunction(Handle<JSFunction> function, 639 const ParameterCount& expected, 640 const ParameterCount& actual, InvokeFlag flag, 641 const CallWrapper& call_wrapper); 642 643 void IsObjectJSStringType(Register object, Register scratch, Label* fail); 644 645 void IsObjectNameType(Register object, Register scratch, Label* fail); 646 647 // --------------------------------------------------------------------------- 648 // Debugger Support 649 650 void DebugBreak(); 651 652 // --------------------------------------------------------------------------- 653 // Exception handling 654 655 // Push a new stack handler and link into stack handler chain. 656 void PushStackHandler(); 657 658 // Unlink the stack handler on top of the stack from the stack handler chain. 659 // Must preserve the result register. 660 void PopStackHandler(); 661 662 // --------------------------------------------------------------------------- 663 // Inline caching support 664 665 void GetNumberHash(Register t0, Register scratch); 666 667 inline void MarkCode(NopMarkerTypes type) { nop(type); } 668 669 // Check if the given instruction is a 'type' marker. 670 // i.e. check if is is a mov r<type>, r<type> (referenced as nop(type)) 671 // These instructions are generated to mark special location in the code, 672 // like some special IC code. 673 static inline bool IsMarkedCode(Instr instr, int type) { 674 DCHECK((FIRST_IC_MARKER <= type) && (type < LAST_CODE_MARKER)); 675 return IsNop(instr, type); 676 } 677 678 679 static inline int GetCodeMarker(Instr instr) { 680 int dst_reg_offset = 12; 681 int dst_mask = 0xf << dst_reg_offset; 682 int src_mask = 0xf; 683 int dst_reg = (instr & dst_mask) >> dst_reg_offset; 684 int src_reg = instr & src_mask; 685 uint32_t non_register_mask = ~(dst_mask | src_mask); 686 uint32_t mov_mask = al | 13 << 21; 687 688 // Return <n> if we have a mov rn rn, else return -1. 689 int type = ((instr & non_register_mask) == mov_mask) && 690 (dst_reg == src_reg) && (FIRST_IC_MARKER <= dst_reg) && 691 (dst_reg < LAST_CODE_MARKER) 692 ? src_reg 693 : -1; 694 DCHECK((type == -1) || 695 ((FIRST_IC_MARKER <= type) && (type < LAST_CODE_MARKER))); 696 return type; 697 } 698 699 700 // --------------------------------------------------------------------------- 701 // Allocation support 702 703 // Allocate an object in new space or old space. The object_size is 704 // specified either in bytes or in words if the allocation flag SIZE_IN_WORDS 705 // is passed. If the space is exhausted control continues at the gc_required 706 // label. The allocated object is returned in result. If the flag 707 // tag_allocated_object is true the result is tagged as as a heap object. 708 // All registers are clobbered also when control continues at the gc_required 709 // label. 710 void Allocate(int object_size, Register result, Register scratch1, 711 Register scratch2, Label* gc_required, AllocationFlags flags); 712 713 void Allocate(Register object_size, Register result, Register result_end, 714 Register scratch, Label* gc_required, AllocationFlags flags); 715 716 // FastAllocate is right now only used for folded allocations. It just 717 // increments the top pointer without checking against limit. This can only 718 // be done if it was proved earlier that the allocation will succeed. 719 void FastAllocate(int object_size, Register result, Register scratch1, 720 Register scratch2, AllocationFlags flags); 721 722 void FastAllocate(Register object_size, Register result, Register result_end, 723 Register scratch, AllocationFlags flags); 724 725 void AllocateTwoByteString(Register result, Register length, 726 Register scratch1, Register scratch2, 727 Register scratch3, Label* gc_required); 728 void AllocateOneByteString(Register result, Register length, 729 Register scratch1, Register scratch2, 730 Register scratch3, Label* gc_required); 731 void AllocateTwoByteConsString(Register result, Register length, 732 Register scratch1, Register scratch2, 733 Label* gc_required); 734 void AllocateOneByteConsString(Register result, Register length, 735 Register scratch1, Register scratch2, 736 Label* gc_required); 737 void AllocateTwoByteSlicedString(Register result, Register length, 738 Register scratch1, Register scratch2, 739 Label* gc_required); 740 void AllocateOneByteSlicedString(Register result, Register length, 741 Register scratch1, Register scratch2, 742 Label* gc_required); 743 744 // Allocates a heap number or jumps to the gc_required label if the young 745 // space is full and a scavenge is needed. All registers are clobbered also 746 // when control continues at the gc_required label. 747 void AllocateHeapNumber(Register result, Register scratch1, Register scratch2, 748 Register heap_number_map, Label* gc_required, 749 MutableMode mode = IMMUTABLE); 750 void AllocateHeapNumberWithValue(Register result, DoubleRegister value, 751 Register scratch1, Register scratch2, 752 Register heap_number_map, 753 Label* gc_required); 754 755 // Allocate and initialize a JSValue wrapper with the specified {constructor} 756 // and {value}. 757 void AllocateJSValue(Register result, Register constructor, Register value, 758 Register scratch1, Register scratch2, 759 Label* gc_required); 760 761 // Initialize fields with filler values. |count| fields starting at 762 // |current_address| are overwritten with the value in |filler|. At the end 763 // the loop, |current_address| points at the next uninitialized field. 764 // |count| is assumed to be non-zero. 765 void InitializeNFieldsWithFiller(Register current_address, Register count, 766 Register filler); 767 768 // Initialize fields with filler values. Fields starting at |current_address| 769 // not including |end_address| are overwritten with the value in |filler|. At 770 // the end the loop, |current_address| takes the value of |end_address|. 771 void InitializeFieldsWithFiller(Register current_address, 772 Register end_address, Register filler); 773 774 // --------------------------------------------------------------------------- 775 // Support functions. 776 777 // Machine code version of Map::GetConstructor(). 778 // |temp| holds |result|'s map when done, and |temp2| its instance type. 779 void GetMapConstructor(Register result, Register map, Register temp, 780 Register temp2); 781 782 // Try to get function prototype of a function and puts the value in 783 // the result register. Checks that the function really is a 784 // function and jumps to the miss label if the fast checks fail. The 785 // function register will be untouched; the other registers may be 786 // clobbered. 787 void TryGetFunctionPrototype(Register function, Register result, 788 Register scratch, Label* miss); 789 790 // Compare object type for heap object. heap_object contains a non-Smi 791 // whose object type should be compared with the given type. This both 792 // sets the flags and leaves the object type in the type_reg register. 793 // It leaves the map in the map register (unless the type_reg and map register 794 // are the same register). It leaves the heap object in the heap_object 795 // register unless the heap_object register is the same register as one of the 796 // other registers. 797 // Type_reg can be no_reg. In that case ip is used. 798 void CompareObjectType(Register heap_object, Register map, Register type_reg, 799 InstanceType type); 800 801 // Compare instance type in a map. map contains a valid map object whose 802 // object type should be compared with the given type. This both 803 // sets the flags and leaves the object type in the type_reg register. 804 void CompareInstanceType(Register map, Register type_reg, InstanceType type); 805 806 // Check if a map for a JSObject indicates that the object can have both smi 807 // and HeapObject elements. Jump to the specified label if it does not. 808 void CheckFastObjectElements(Register map, Register scratch, Label* fail); 809 810 // Check if a map for a JSObject indicates that the object has fast smi only 811 // elements. Jump to the specified label if it does not. 812 void CheckFastSmiElements(Register map, Register scratch, Label* fail); 813 814 // Check to see if maybe_number can be stored as a double in 815 // FastDoubleElements. If it can, store it at the index specified by key in 816 // the FastDoubleElements array elements. Otherwise jump to fail. 817 void StoreNumberToDoubleElements(Register value_reg, Register key_reg, 818 Register elements_reg, Register scratch1, 819 DoubleRegister double_scratch, Label* fail, 820 int elements_offset = 0); 821 822 // Compare an object's map with the specified map and its transitioned 823 // elements maps if mode is ALLOW_ELEMENT_TRANSITION_MAPS. Condition flags are 824 // set with result of map compare. If multiple map compares are required, the 825 // compare sequences branches to early_success. 826 void CompareMap(Register obj, Register scratch, Handle<Map> map, 827 Label* early_success); 828 829 // As above, but the map of the object is already loaded into the register 830 // which is preserved by the code generated. 831 void CompareMap(Register obj_map, Handle<Map> map, Label* early_success); 832 833 // Check if the map of an object is equal to a specified map and branch to 834 // label if not. Skip the smi check if not required (object is known to be a 835 // heap object). If mode is ALLOW_ELEMENT_TRANSITION_MAPS, then also match 836 // against maps that are ElementsKind transition maps of the specified map. 837 void CheckMap(Register obj, Register scratch, Handle<Map> map, Label* fail, 838 SmiCheckType smi_check_type); 839 840 841 void CheckMap(Register obj, Register scratch, Heap::RootListIndex index, 842 Label* fail, SmiCheckType smi_check_type); 843 844 845 // Check if the map of an object is equal to a specified weak map and branch 846 // to a specified target if equal. Skip the smi check if not required 847 // (object is known to be a heap object) 848 void DispatchWeakMap(Register obj, Register scratch1, Register scratch2, 849 Handle<WeakCell> cell, Handle<Code> success, 850 SmiCheckType smi_check_type); 851 852 // Compare the given value and the value of weak cell. 853 void CmpWeakValue(Register value, Handle<WeakCell> cell, Register scratch, 854 CRegister cr = cr7); 855 856 void GetWeakValue(Register value, Handle<WeakCell> cell); 857 858 // Load the value of the weak cell in the value register. Branch to the given 859 // miss label if the weak cell was cleared. 860 void LoadWeakValue(Register value, Handle<WeakCell> cell, Label* miss); 861 862 // Compare the object in a register to a value from the root list. 863 // Uses the ip register as scratch. 864 void CompareRoot(Register obj, Heap::RootListIndex index); 865 void PushRoot(Heap::RootListIndex index) { 866 LoadRoot(r0, index); 867 Push(r0); 868 } 869 870 // Compare the object in a register to a value and jump if they are equal. 871 void JumpIfRoot(Register with, Heap::RootListIndex index, Label* if_equal) { 872 CompareRoot(with, index); 873 beq(if_equal); 874 } 875 876 // Compare the object in a register to a value and jump if they are not equal. 877 void JumpIfNotRoot(Register with, Heap::RootListIndex index, 878 Label* if_not_equal) { 879 CompareRoot(with, index); 880 bne(if_not_equal); 881 } 882 883 // Load and check the instance type of an object for being a string. 884 // Loads the type into the second argument register. 885 // Returns a condition that will be enabled if the object was a string. 886 Condition IsObjectStringType(Register obj, Register type) { 887 LoadP(type, FieldMemOperand(obj, HeapObject::kMapOffset)); 888 lbz(type, FieldMemOperand(type, Map::kInstanceTypeOffset)); 889 andi(r0, type, Operand(kIsNotStringMask)); 890 DCHECK_EQ(0u, kStringTag); 891 return eq; 892 } 893 894 // Get the number of least significant bits from a register 895 void GetLeastBitsFromSmi(Register dst, Register src, int num_least_bits); 896 void GetLeastBitsFromInt32(Register dst, Register src, int mun_least_bits); 897 898 // Load the value of a smi object into a double register. 899 void SmiToDouble(DoubleRegister value, Register smi); 900 901 // Check if a double can be exactly represented as a signed 32-bit integer. 902 // CR_EQ in cr7 is set if true. 903 void TestDoubleIsInt32(DoubleRegister double_input, Register scratch1, 904 Register scratch2, DoubleRegister double_scratch); 905 906 // Check if a double is equal to -0.0. 907 // CR_EQ in cr7 holds the result. 908 void TestDoubleIsMinusZero(DoubleRegister input, Register scratch1, 909 Register scratch2); 910 911 // Check the sign of a double. 912 // CR_LT in cr7 holds the result. 913 void TestDoubleSign(DoubleRegister input, Register scratch); 914 void TestHeapNumberSign(Register input, Register scratch); 915 916 // Try to convert a double to a signed 32-bit integer. 917 // CR_EQ in cr7 is set and result assigned if the conversion is exact. 918 void TryDoubleToInt32Exact(Register result, DoubleRegister double_input, 919 Register scratch, DoubleRegister double_scratch); 920 921 // Floor a double and writes the value to the result register. 922 // Go to exact if the conversion is exact (to be able to test -0), 923 // fall through calling code if an overflow occurred, else go to done. 924 // In return, input_high is loaded with high bits of input. 925 void TryInt32Floor(Register result, DoubleRegister double_input, 926 Register input_high, Register scratch, 927 DoubleRegister double_scratch, Label* done, Label* exact); 928 929 // Performs a truncating conversion of a floating point number as used by 930 // the JS bitwise operations. See ECMA-262 9.5: ToInt32. Goes to 'done' if it 931 // succeeds, otherwise falls through if result is saturated. On return 932 // 'result' either holds answer, or is clobbered on fall through. 933 // 934 // Only public for the test code in test-code-stubs-arm.cc. 935 void TryInlineTruncateDoubleToI(Register result, DoubleRegister input, 936 Label* done); 937 938 // Performs a truncating conversion of a floating point number as used by 939 // the JS bitwise operations. See ECMA-262 9.5: ToInt32. 940 // Exits with 'result' holding the answer. 941 void TruncateDoubleToI(Register result, DoubleRegister double_input); 942 943 // Performs a truncating conversion of a heap number as used by 944 // the JS bitwise operations. See ECMA-262 9.5: ToInt32. 'result' and 'input' 945 // must be different registers. Exits with 'result' holding the answer. 946 void TruncateHeapNumberToI(Register result, Register object); 947 948 // Converts the smi or heap number in object to an int32 using the rules 949 // for ToInt32 as described in ECMAScript 9.5.: the value is truncated 950 // and brought into the range -2^31 .. +2^31 - 1. 'result' and 'input' must be 951 // different registers. 952 void TruncateNumberToI(Register object, Register result, 953 Register heap_number_map, Register scratch1, 954 Label* not_int32); 955 956 // Overflow handling functions. 957 // Usage: call the appropriate arithmetic function and then call one of the 958 // flow control functions with the corresponding label. 959 960 // Compute dst = left + right, setting condition codes. dst may be same as 961 // either left or right (or a unique register). left and right must not be 962 // the same register. 963 void AddAndCheckForOverflow(Register dst, Register left, Register right, 964 Register overflow_dst, Register scratch = r0); 965 void AddAndCheckForOverflow(Register dst, Register left, intptr_t right, 966 Register overflow_dst, Register scratch = r0); 967 968 // Compute dst = left - right, setting condition codes. dst may be same as 969 // either left or right (or a unique register). left and right must not be 970 // the same register. 971 void SubAndCheckForOverflow(Register dst, Register left, Register right, 972 Register overflow_dst, Register scratch = r0); 973 974 void BranchOnOverflow(Label* label) { blt(label, cr0); } 975 976 void BranchOnNoOverflow(Label* label) { bge(label, cr0); } 977 978 void RetOnOverflow(void) { Ret(lt, cr0); } 979 980 void RetOnNoOverflow(void) { Ret(ge, cr0); } 981 982 // --------------------------------------------------------------------------- 983 // Runtime calls 984 985 // Call a code stub. 986 void CallStub(CodeStub* stub, TypeFeedbackId ast_id = TypeFeedbackId::None(), 987 Condition cond = al); 988 989 // Call a code stub. 990 void TailCallStub(CodeStub* stub, Condition cond = al); 991 992 // Call a runtime routine. 993 void CallRuntime(const Runtime::Function* f, int num_arguments, 994 SaveFPRegsMode save_doubles = kDontSaveFPRegs); 995 void CallRuntimeSaveDoubles(Runtime::FunctionId fid) { 996 const Runtime::Function* function = Runtime::FunctionForId(fid); 997 CallRuntime(function, function->nargs, kSaveFPRegs); 998 } 999 1000 // Convenience function: Same as above, but takes the fid instead. 1001 void CallRuntime(Runtime::FunctionId fid, 1002 SaveFPRegsMode save_doubles = kDontSaveFPRegs) { 1003 const Runtime::Function* function = Runtime::FunctionForId(fid); 1004 CallRuntime(function, function->nargs, save_doubles); 1005 } 1006 1007 // Convenience function: Same as above, but takes the fid instead. 1008 void CallRuntime(Runtime::FunctionId fid, int num_arguments, 1009 SaveFPRegsMode save_doubles = kDontSaveFPRegs) { 1010 CallRuntime(Runtime::FunctionForId(fid), num_arguments, save_doubles); 1011 } 1012 1013 // Convenience function: call an external reference. 1014 void CallExternalReference(const ExternalReference& ext, int num_arguments); 1015 1016 // Convenience function: tail call a runtime routine (jump). 1017 void TailCallRuntime(Runtime::FunctionId fid); 1018 1019 int CalculateStackPassedWords(int num_reg_arguments, 1020 int num_double_arguments); 1021 1022 // Before calling a C-function from generated code, align arguments on stack. 1023 // After aligning the frame, non-register arguments must be stored in 1024 // sp[0], sp[4], etc., not pushed. The argument count assumes all arguments 1025 // are word sized. If double arguments are used, this function assumes that 1026 // all double arguments are stored before core registers; otherwise the 1027 // correct alignment of the double values is not guaranteed. 1028 // Some compilers/platforms require the stack to be aligned when calling 1029 // C++ code. 1030 // Needs a scratch register to do some arithmetic. This register will be 1031 // trashed. 1032 void PrepareCallCFunction(int num_reg_arguments, int num_double_registers, 1033 Register scratch); 1034 void PrepareCallCFunction(int num_reg_arguments, Register scratch); 1035 1036 // There are two ways of passing double arguments on ARM, depending on 1037 // whether soft or hard floating point ABI is used. These functions 1038 // abstract parameter passing for the three different ways we call 1039 // C functions from generated code. 1040 void MovToFloatParameter(DoubleRegister src); 1041 void MovToFloatParameters(DoubleRegister src1, DoubleRegister src2); 1042 void MovToFloatResult(DoubleRegister src); 1043 1044 // Calls a C function and cleans up the space for arguments allocated 1045 // by PrepareCallCFunction. The called function is not allowed to trigger a 1046 // garbage collection, since that might move the code and invalidate the 1047 // return address (unless this is somehow accounted for by the called 1048 // function). 1049 void CallCFunction(ExternalReference function, int num_arguments); 1050 void CallCFunction(Register function, int num_arguments); 1051 void CallCFunction(ExternalReference function, int num_reg_arguments, 1052 int num_double_arguments); 1053 void CallCFunction(Register function, int num_reg_arguments, 1054 int num_double_arguments); 1055 1056 void MovFromFloatParameter(DoubleRegister dst); 1057 void MovFromFloatResult(DoubleRegister dst); 1058 1059 // Jump to a runtime routine. 1060 void JumpToExternalReference(const ExternalReference& builtin, 1061 bool builtin_exit_frame = false); 1062 1063 Handle<Object> CodeObject() { 1064 DCHECK(!code_object_.is_null()); 1065 return code_object_; 1066 } 1067 1068 1069 // Emit code for a truncating division by a constant. The dividend register is 1070 // unchanged and ip gets clobbered. Dividend and result must be different. 1071 void TruncatingDiv(Register result, Register dividend, int32_t divisor); 1072 1073 // --------------------------------------------------------------------------- 1074 // StatsCounter support 1075 1076 void SetCounter(StatsCounter* counter, int value, Register scratch1, 1077 Register scratch2); 1078 void IncrementCounter(StatsCounter* counter, int value, Register scratch1, 1079 Register scratch2); 1080 void DecrementCounter(StatsCounter* counter, int value, Register scratch1, 1081 Register scratch2); 1082 1083 1084 // --------------------------------------------------------------------------- 1085 // Debugging 1086 1087 // Calls Abort(msg) if the condition cond is not satisfied. 1088 // Use --debug_code to enable. 1089 void Assert(Condition cond, BailoutReason reason, CRegister cr = cr7); 1090 void AssertFastElements(Register elements); 1091 1092 // Like Assert(), but always enabled. 1093 void Check(Condition cond, BailoutReason reason, CRegister cr = cr7); 1094 1095 // Print a message to stdout and abort execution. 1096 void Abort(BailoutReason reason); 1097 1098 // Verify restrictions about code generated in stubs. 1099 void set_generating_stub(bool value) { generating_stub_ = value; } 1100 bool generating_stub() { return generating_stub_; } 1101 void set_has_frame(bool value) { has_frame_ = value; } 1102 bool has_frame() { return has_frame_; } 1103 inline bool AllowThisStubCall(CodeStub* stub); 1104 1105 // --------------------------------------------------------------------------- 1106 // Number utilities 1107 1108 // Check whether the value of reg is a power of two and not zero. If not 1109 // control continues at the label not_power_of_two. If reg is a power of two 1110 // the register scratch contains the value of (reg - 1) when control falls 1111 // through. 1112 void JumpIfNotPowerOfTwoOrZero(Register reg, Register scratch, 1113 Label* not_power_of_two_or_zero); 1114 // Check whether the value of reg is a power of two and not zero. 1115 // Control falls through if it is, with scratch containing the mask 1116 // value (reg - 1). 1117 // Otherwise control jumps to the 'zero_and_neg' label if the value of reg is 1118 // zero or negative, or jumps to the 'not_power_of_two' label if the value is 1119 // strictly positive but not a power of two. 1120 void JumpIfNotPowerOfTwoOrZeroAndNeg(Register reg, Register scratch, 1121 Label* zero_and_neg, 1122 Label* not_power_of_two); 1123 1124 // --------------------------------------------------------------------------- 1125 // Bit testing/extraction 1126 // 1127 // Bit numbering is such that the least significant bit is bit 0 1128 // (for consistency between 32/64-bit). 1129 1130 // Extract consecutive bits (defined by rangeStart - rangeEnd) from src 1131 // and, if !test, shift them into the least significant bits of dst. 1132 inline void ExtractBitRange(Register dst, Register src, int rangeStart, 1133 int rangeEnd, RCBit rc = LeaveRC, 1134 bool test = false) { 1135 DCHECK(rangeStart >= rangeEnd && rangeStart < kBitsPerPointer); 1136 int rotate = (rangeEnd == 0) ? 0 : kBitsPerPointer - rangeEnd; 1137 int width = rangeStart - rangeEnd + 1; 1138 if (rc == SetRC && rangeStart < 16 && (rangeEnd == 0 || test)) { 1139 // Prefer faster andi when applicable. 1140 andi(dst, src, Operand(((1 << width) - 1) << rangeEnd)); 1141 } else { 1142 #if V8_TARGET_ARCH_PPC64 1143 rldicl(dst, src, rotate, kBitsPerPointer - width, rc); 1144 #else 1145 rlwinm(dst, src, rotate, kBitsPerPointer - width, kBitsPerPointer - 1, 1146 rc); 1147 #endif 1148 } 1149 } 1150 1151 inline void ExtractBit(Register dst, Register src, uint32_t bitNumber, 1152 RCBit rc = LeaveRC, bool test = false) { 1153 ExtractBitRange(dst, src, bitNumber, bitNumber, rc, test); 1154 } 1155 1156 // Extract consecutive bits (defined by mask) from src and place them 1157 // into the least significant bits of dst. 1158 inline void ExtractBitMask(Register dst, Register src, uintptr_t mask, 1159 RCBit rc = LeaveRC, bool test = false) { 1160 int start = kBitsPerPointer - 1; 1161 int end; 1162 uintptr_t bit = (1L << start); 1163 1164 while (bit && (mask & bit) == 0) { 1165 start--; 1166 bit >>= 1; 1167 } 1168 end = start; 1169 bit >>= 1; 1170 1171 while (bit && (mask & bit)) { 1172 end--; 1173 bit >>= 1; 1174 } 1175 1176 // 1-bits in mask must be contiguous 1177 DCHECK(bit == 0 || (mask & ((bit << 1) - 1)) == 0); 1178 1179 ExtractBitRange(dst, src, start, end, rc, test); 1180 } 1181 1182 // Test single bit in value. 1183 inline void TestBit(Register value, int bitNumber, Register scratch = r0) { 1184 ExtractBitRange(scratch, value, bitNumber, bitNumber, SetRC, true); 1185 } 1186 1187 // Test consecutive bit range in value. Range is defined by 1188 // rangeStart - rangeEnd. 1189 inline void TestBitRange(Register value, int rangeStart, int rangeEnd, 1190 Register scratch = r0) { 1191 ExtractBitRange(scratch, value, rangeStart, rangeEnd, SetRC, true); 1192 } 1193 1194 // Test consecutive bit range in value. Range is defined by mask. 1195 inline void TestBitMask(Register value, uintptr_t mask, 1196 Register scratch = r0) { 1197 ExtractBitMask(scratch, value, mask, SetRC, true); 1198 } 1199 1200 1201 // --------------------------------------------------------------------------- 1202 // Smi utilities 1203 1204 // Shift left by kSmiShift 1205 void SmiTag(Register reg, RCBit rc = LeaveRC) { SmiTag(reg, reg, rc); } 1206 void SmiTag(Register dst, Register src, RCBit rc = LeaveRC) { 1207 ShiftLeftImm(dst, src, Operand(kSmiShift), rc); 1208 } 1209 1210 #if !V8_TARGET_ARCH_PPC64 1211 // Test for overflow < 0: use BranchOnOverflow() or BranchOnNoOverflow(). 1212 void SmiTagCheckOverflow(Register reg, Register overflow); 1213 void SmiTagCheckOverflow(Register dst, Register src, Register overflow); 1214 1215 inline void JumpIfNotSmiCandidate(Register value, Register scratch, 1216 Label* not_smi_label) { 1217 // High bits must be identical to fit into an Smi 1218 STATIC_ASSERT(kSmiShift == 1); 1219 addis(scratch, value, Operand(0x40000000u >> 16)); 1220 cmpi(scratch, Operand::Zero()); 1221 blt(not_smi_label); 1222 } 1223 #endif 1224 inline void TestUnsignedSmiCandidate(Register value, Register scratch) { 1225 // The test is different for unsigned int values. Since we need 1226 // the value to be in the range of a positive smi, we can't 1227 // handle any of the high bits being set in the value. 1228 TestBitRange(value, kBitsPerPointer - 1, kBitsPerPointer - 1 - kSmiShift, 1229 scratch); 1230 } 1231 inline void JumpIfNotUnsignedSmiCandidate(Register value, Register scratch, 1232 Label* not_smi_label) { 1233 TestUnsignedSmiCandidate(value, scratch); 1234 bne(not_smi_label, cr0); 1235 } 1236 1237 void SmiUntag(Register reg, RCBit rc = LeaveRC) { SmiUntag(reg, reg, rc); } 1238 1239 void SmiUntag(Register dst, Register src, RCBit rc = LeaveRC) { 1240 ShiftRightArithImm(dst, src, kSmiShift, rc); 1241 } 1242 1243 void SmiToPtrArrayOffset(Register dst, Register src) { 1244 #if V8_TARGET_ARCH_PPC64 1245 STATIC_ASSERT(kSmiTag == 0 && kSmiShift > kPointerSizeLog2); 1246 ShiftRightArithImm(dst, src, kSmiShift - kPointerSizeLog2); 1247 #else 1248 STATIC_ASSERT(kSmiTag == 0 && kSmiShift < kPointerSizeLog2); 1249 ShiftLeftImm(dst, src, Operand(kPointerSizeLog2 - kSmiShift)); 1250 #endif 1251 } 1252 1253 void SmiToByteArrayOffset(Register dst, Register src) { SmiUntag(dst, src); } 1254 1255 void SmiToShortArrayOffset(Register dst, Register src) { 1256 #if V8_TARGET_ARCH_PPC64 1257 STATIC_ASSERT(kSmiTag == 0 && kSmiShift > 1); 1258 ShiftRightArithImm(dst, src, kSmiShift - 1); 1259 #else 1260 STATIC_ASSERT(kSmiTag == 0 && kSmiShift == 1); 1261 if (!dst.is(src)) { 1262 mr(dst, src); 1263 } 1264 #endif 1265 } 1266 1267 void SmiToIntArrayOffset(Register dst, Register src) { 1268 #if V8_TARGET_ARCH_PPC64 1269 STATIC_ASSERT(kSmiTag == 0 && kSmiShift > 2); 1270 ShiftRightArithImm(dst, src, kSmiShift - 2); 1271 #else 1272 STATIC_ASSERT(kSmiTag == 0 && kSmiShift < 2); 1273 ShiftLeftImm(dst, src, Operand(2 - kSmiShift)); 1274 #endif 1275 } 1276 1277 #define SmiToFloatArrayOffset SmiToIntArrayOffset 1278 1279 void SmiToDoubleArrayOffset(Register dst, Register src) { 1280 #if V8_TARGET_ARCH_PPC64 1281 STATIC_ASSERT(kSmiTag == 0 && kSmiShift > kDoubleSizeLog2); 1282 ShiftRightArithImm(dst, src, kSmiShift - kDoubleSizeLog2); 1283 #else 1284 STATIC_ASSERT(kSmiTag == 0 && kSmiShift < kDoubleSizeLog2); 1285 ShiftLeftImm(dst, src, Operand(kDoubleSizeLog2 - kSmiShift)); 1286 #endif 1287 } 1288 1289 void SmiToArrayOffset(Register dst, Register src, int elementSizeLog2) { 1290 if (kSmiShift < elementSizeLog2) { 1291 ShiftLeftImm(dst, src, Operand(elementSizeLog2 - kSmiShift)); 1292 } else if (kSmiShift > elementSizeLog2) { 1293 ShiftRightArithImm(dst, src, kSmiShift - elementSizeLog2); 1294 } else if (!dst.is(src)) { 1295 mr(dst, src); 1296 } 1297 } 1298 1299 void IndexToArrayOffset(Register dst, Register src, int elementSizeLog2, 1300 bool isSmi) { 1301 if (isSmi) { 1302 SmiToArrayOffset(dst, src, elementSizeLog2); 1303 } else { 1304 ShiftLeftImm(dst, src, Operand(elementSizeLog2)); 1305 } 1306 } 1307 1308 // Untag the source value into destination and jump if source is a smi. 1309 // Souce and destination can be the same register. 1310 void UntagAndJumpIfSmi(Register dst, Register src, Label* smi_case); 1311 1312 // Untag the source value into destination and jump if source is not a smi. 1313 // Souce and destination can be the same register. 1314 void UntagAndJumpIfNotSmi(Register dst, Register src, Label* non_smi_case); 1315 1316 inline void TestIfSmi(Register value, Register scratch) { 1317 TestBitRange(value, kSmiTagSize - 1, 0, scratch); 1318 } 1319 1320 inline void TestIfPositiveSmi(Register value, Register scratch) { 1321 #if V8_TARGET_ARCH_PPC64 1322 rldicl(scratch, value, 1, kBitsPerPointer - (1 + kSmiTagSize), SetRC); 1323 #else 1324 rlwinm(scratch, value, 1, kBitsPerPointer - (1 + kSmiTagSize), 1325 kBitsPerPointer - 1, SetRC); 1326 #endif 1327 } 1328 1329 // Jump the register contains a smi. 1330 inline void JumpIfSmi(Register value, Label* smi_label) { 1331 TestIfSmi(value, r0); 1332 beq(smi_label, cr0); // branch if SMI 1333 } 1334 // Jump if either of the registers contain a non-smi. 1335 inline void JumpIfNotSmi(Register value, Label* not_smi_label) { 1336 TestIfSmi(value, r0); 1337 bne(not_smi_label, cr0); 1338 } 1339 // Jump if either of the registers contain a non-smi. 1340 void JumpIfNotBothSmi(Register reg1, Register reg2, Label* on_not_both_smi); 1341 // Jump if either of the registers contain a smi. 1342 void JumpIfEitherSmi(Register reg1, Register reg2, Label* on_either_smi); 1343 1344 // Abort execution if argument is a number, enabled via --debug-code. 1345 void AssertNotNumber(Register object); 1346 1347 // Abort execution if argument is a smi, enabled via --debug-code. 1348 void AssertNotSmi(Register object); 1349 void AssertSmi(Register object); 1350 1351 1352 #if V8_TARGET_ARCH_PPC64 1353 inline void TestIfInt32(Register value, Register scratch, 1354 CRegister cr = cr7) { 1355 // High bits must be identical to fit into an 32-bit integer 1356 extsw(scratch, value); 1357 cmp(scratch, value, cr); 1358 } 1359 #else 1360 inline void TestIfInt32(Register hi_word, Register lo_word, Register scratch, 1361 CRegister cr = cr7) { 1362 // High bits must be identical to fit into an 32-bit integer 1363 srawi(scratch, lo_word, 31); 1364 cmp(scratch, hi_word, cr); 1365 } 1366 #endif 1367 1368 #if V8_TARGET_ARCH_PPC64 1369 // Ensure it is permissable to read/write int value directly from 1370 // upper half of the smi. 1371 STATIC_ASSERT(kSmiTag == 0); 1372 STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 32); 1373 #endif 1374 #if V8_TARGET_ARCH_PPC64 && V8_TARGET_LITTLE_ENDIAN 1375 #define SmiWordOffset(offset) (offset + kPointerSize / 2) 1376 #else 1377 #define SmiWordOffset(offset) offset 1378 #endif 1379 1380 // Abort execution if argument is not a string, enabled via --debug-code. 1381 void AssertString(Register object); 1382 1383 // Abort execution if argument is not a name, enabled via --debug-code. 1384 void AssertName(Register object); 1385 1386 void AssertFunction(Register object); 1387 1388 // Abort execution if argument is not a JSBoundFunction, 1389 // enabled via --debug-code. 1390 void AssertBoundFunction(Register object); 1391 1392 // Abort execution if argument is not a JSGeneratorObject, 1393 // enabled via --debug-code. 1394 void AssertGeneratorObject(Register object); 1395 1396 // Abort execution if argument is not a JSReceiver, enabled via --debug-code. 1397 void AssertReceiver(Register object); 1398 1399 // Abort execution if argument is not undefined or an AllocationSite, enabled 1400 // via --debug-code. 1401 void AssertUndefinedOrAllocationSite(Register object, Register scratch); 1402 1403 // Abort execution if reg is not the root value with the given index, 1404 // enabled via --debug-code. 1405 void AssertIsRoot(Register reg, Heap::RootListIndex index); 1406 1407 // --------------------------------------------------------------------------- 1408 // HeapNumber utilities 1409 1410 void JumpIfNotHeapNumber(Register object, Register heap_number_map, 1411 Register scratch, Label* on_not_heap_number); 1412 1413 // --------------------------------------------------------------------------- 1414 // String utilities 1415 1416 // Checks if both objects are sequential one-byte strings and jumps to label 1417 // if either is not. Assumes that neither object is a smi. 1418 void JumpIfNonSmisNotBothSequentialOneByteStrings(Register object1, 1419 Register object2, 1420 Register scratch1, 1421 Register scratch2, 1422 Label* failure); 1423 1424 // Checks if both objects are sequential one-byte strings and jumps to label 1425 // if either is not. 1426 void JumpIfNotBothSequentialOneByteStrings(Register first, Register second, 1427 Register scratch1, 1428 Register scratch2, 1429 Label* not_flat_one_byte_strings); 1430 1431 // Checks if both instance types are sequential one-byte strings and jumps to 1432 // label if either is not. 1433 void JumpIfBothInstanceTypesAreNotSequentialOneByte( 1434 Register first_object_instance_type, Register second_object_instance_type, 1435 Register scratch1, Register scratch2, Label* failure); 1436 1437 // Check if instance type is sequential one-byte string and jump to label if 1438 // it is not. 1439 void JumpIfInstanceTypeIsNotSequentialOneByte(Register type, Register scratch, 1440 Label* failure); 1441 1442 void JumpIfNotUniqueNameInstanceType(Register reg, Label* not_unique_name); 1443 1444 void EmitSeqStringSetCharCheck(Register string, Register index, 1445 Register value, uint32_t encoding_mask); 1446 1447 // --------------------------------------------------------------------------- 1448 // Patching helpers. 1449 1450 // Decode offset from constant pool load instruction(s). 1451 // Caller must place the instruction word at <location> in <result>. 1452 void DecodeConstantPoolOffset(Register result, Register location); 1453 1454 void ClampUint8(Register output_reg, Register input_reg); 1455 1456 // Saturate a value into 8-bit unsigned integer 1457 // if input_value < 0, output_value is 0 1458 // if input_value > 255, output_value is 255 1459 // otherwise output_value is the (int)input_value (round to nearest) 1460 void ClampDoubleToUint8(Register result_reg, DoubleRegister input_reg, 1461 DoubleRegister temp_double_reg); 1462 1463 1464 void LoadInstanceDescriptors(Register map, Register descriptors); 1465 void EnumLength(Register dst, Register map); 1466 void NumberOfOwnDescriptors(Register dst, Register map); 1467 void LoadAccessor(Register dst, Register holder, int accessor_index, 1468 AccessorComponent accessor); 1469 1470 template <typename Field> 1471 void DecodeField(Register dst, Register src, RCBit rc = LeaveRC) { 1472 ExtractBitRange(dst, src, Field::kShift + Field::kSize - 1, Field::kShift, 1473 rc); 1474 } 1475 1476 template <typename Field> 1477 void DecodeField(Register reg, RCBit rc = LeaveRC) { 1478 DecodeField<Field>(reg, reg, rc); 1479 } 1480 1481 template <typename Field> 1482 void DecodeFieldToSmi(Register dst, Register src) { 1483 #if V8_TARGET_ARCH_PPC64 1484 DecodeField<Field>(dst, src); 1485 SmiTag(dst); 1486 #else 1487 // 32-bit can do this in one instruction: 1488 int start = Field::kSize + kSmiShift - 1; 1489 int end = kSmiShift; 1490 int rotate = kSmiShift - Field::kShift; 1491 if (rotate < 0) { 1492 rotate += kBitsPerPointer; 1493 } 1494 rlwinm(dst, src, rotate, kBitsPerPointer - start - 1, 1495 kBitsPerPointer - end - 1); 1496 #endif 1497 } 1498 1499 template <typename Field> 1500 void DecodeFieldToSmi(Register reg) { 1501 DecodeFieldToSmi<Field>(reg, reg); 1502 } 1503 1504 // Load the type feedback vector from a JavaScript frame. 1505 void EmitLoadTypeFeedbackVector(Register vector); 1506 1507 // Activation support. 1508 void EnterFrame(StackFrame::Type type, 1509 bool load_constant_pool_pointer_reg = false); 1510 // Returns the pc offset at which the frame ends. 1511 int LeaveFrame(StackFrame::Type type, int stack_adjustment = 0); 1512 1513 void EnterBuiltinFrame(Register context, Register target, Register argc); 1514 void LeaveBuiltinFrame(Register context, Register target, Register argc); 1515 1516 // Expects object in r3 and returns map with validated enum cache 1517 // in r3. Assumes that any other register can be used as a scratch. 1518 void CheckEnumCache(Label* call_runtime); 1519 1520 // AllocationMemento support. Arrays may have an associated 1521 // AllocationMemento object that can be checked for in order to pretransition 1522 // to another type. 1523 // On entry, receiver_reg should point to the array object. 1524 // scratch_reg gets clobbered. 1525 // If allocation info is present, condition flags are set to eq. 1526 void TestJSArrayForAllocationMemento(Register receiver_reg, 1527 Register scratch_reg, 1528 Register scratch2_reg, 1529 Label* no_memento_found); 1530 1531 void JumpIfJSArrayHasAllocationMemento(Register receiver_reg, 1532 Register scratch_reg, 1533 Register scratch2_reg, 1534 Label* memento_found) { 1535 Label no_memento_found; 1536 TestJSArrayForAllocationMemento(receiver_reg, scratch_reg, scratch2_reg, 1537 &no_memento_found); 1538 beq(memento_found); 1539 bind(&no_memento_found); 1540 } 1541 1542 // Jumps to found label if a prototype map has dictionary elements. 1543 void JumpIfDictionaryInPrototypeChain(Register object, Register scratch0, 1544 Register scratch1, Label* found); 1545 1546 // Loads the constant pool pointer (kConstantPoolRegister). 1547 void LoadConstantPoolPointerRegisterFromCodeTargetAddress( 1548 Register code_target_address); 1549 void LoadConstantPoolPointerRegister(); 1550 void LoadConstantPoolPointerRegister(Register base, int code_entry_delta = 0); 1551 1552 void AbortConstantPoolBuilding() { 1553 #ifdef DEBUG 1554 // Avoid DCHECK(!is_linked()) failure in ~Label() 1555 bind(ConstantPoolPosition()); 1556 #endif 1557 } 1558 1559 private: 1560 static const int kSmiShift = kSmiTagSize + kSmiShiftSize; 1561 1562 void CallCFunctionHelper(Register function, int num_reg_arguments, 1563 int num_double_arguments); 1564 1565 void Jump(intptr_t target, RelocInfo::Mode rmode, Condition cond = al, 1566 CRegister cr = cr7); 1567 1568 // Helper functions for generating invokes. 1569 void InvokePrologue(const ParameterCount& expected, 1570 const ParameterCount& actual, Label* done, 1571 bool* definitely_mismatches, InvokeFlag flag, 1572 const CallWrapper& call_wrapper); 1573 1574 void InitializeNewString(Register string, Register length, 1575 Heap::RootListIndex map_index, Register scratch1, 1576 Register scratch2); 1577 1578 // Helper for implementing JumpIfNotInNewSpace and JumpIfInNewSpace. 1579 void InNewSpace(Register object, Register scratch, 1580 Condition cond, // eq for new space, ne otherwise. 1581 Label* branch); 1582 1583 // Helper for finding the mark bits for an address. Afterwards, the 1584 // bitmap register points at the word with the mark bits and the mask 1585 // the position of the first bit. Leaves addr_reg unchanged. 1586 inline void GetMarkBits(Register addr_reg, Register bitmap_reg, 1587 Register mask_reg); 1588 1589 static const RegList kSafepointSavedRegisters; 1590 static const int kNumSafepointSavedRegisters; 1591 1592 // Compute memory operands for safepoint stack slots. 1593 static int SafepointRegisterStackIndex(int reg_code); 1594 MemOperand SafepointRegisterSlot(Register reg); 1595 MemOperand SafepointRegistersAndDoublesSlot(Register reg); 1596 1597 bool generating_stub_; 1598 bool has_frame_; 1599 // This handle will be patched with the code object on installation. 1600 Handle<Object> code_object_; 1601 1602 // Needs access to SafepointRegisterStackIndex for compiled frame 1603 // traversal. 1604 friend class StandardFrame; 1605 }; 1606 1607 1608 // The code patcher is used to patch (typically) small parts of code e.g. for 1609 // debugging and other types of instrumentation. When using the code patcher 1610 // the exact number of bytes specified must be emitted. It is not legal to emit 1611 // relocation information. If any of these constraints are violated it causes 1612 // an assertion to fail. 1613 class CodePatcher { 1614 public: 1615 enum FlushICache { FLUSH, DONT_FLUSH }; 1616 1617 CodePatcher(Isolate* isolate, byte* address, int instructions, 1618 FlushICache flush_cache = FLUSH); 1619 ~CodePatcher(); 1620 1621 // Macro assembler to emit code. 1622 MacroAssembler* masm() { return &masm_; } 1623 1624 // Emit an instruction directly. 1625 void Emit(Instr instr); 1626 1627 // Emit the condition part of an instruction leaving the rest of the current 1628 // instruction unchanged. 1629 void EmitCondition(Condition cond); 1630 1631 private: 1632 byte* address_; // The address of the code being patched. 1633 int size_; // Number of bytes of the expected patch size. 1634 MacroAssembler masm_; // Macro assembler used to generate the code. 1635 FlushICache flush_cache_; // Whether to flush the I cache after patching. 1636 }; 1637 1638 1639 // ----------------------------------------------------------------------------- 1640 // Static helper functions. 1641 1642 inline MemOperand ContextMemOperand(Register context, int index = 0) { 1643 return MemOperand(context, Context::SlotOffset(index)); 1644 } 1645 1646 1647 inline MemOperand NativeContextMemOperand() { 1648 return ContextMemOperand(cp, Context::NATIVE_CONTEXT_INDEX); 1649 } 1650 1651 #define ACCESS_MASM(masm) masm-> 1652 1653 } // namespace internal 1654 } // namespace v8 1655 1656 #endif // V8_PPC_MACRO_ASSEMBLER_PPC_H_ 1657