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