OLD | NEW |
1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
138 // For page containing |object| mark region covering |addr| dirty. | 138 // For page containing |object| mark region covering |addr| dirty. |
139 // RecordWriteHelper only works if the object is not in new | 139 // RecordWriteHelper only works if the object is not in new |
140 // space. | 140 // space. |
141 void RecordWriteHelper(Register object, | 141 void RecordWriteHelper(Register object, |
142 Register addr, | 142 Register addr, |
143 Register scratch); | 143 Register scratch); |
144 | 144 |
145 // Check if object is in new space. The condition cc can be equal or | 145 // Check if object is in new space. The condition cc can be equal or |
146 // not_equal. If it is equal a jump will be done if the object is on new | 146 // not_equal. If it is equal a jump will be done if the object is on new |
147 // space. The register scratch can be object itself, but it will be clobbered. | 147 // space. The register scratch can be object itself, but it will be clobbered. |
148 template <typename LabelType> | |
149 void InNewSpace(Register object, | 148 void InNewSpace(Register object, |
150 Register scratch, | 149 Register scratch, |
151 Condition cc, | 150 Condition cc, |
152 LabelType* branch); | 151 Label* branch, |
| 152 Label::Distance near_jump = Label::kFar); |
153 | 153 |
154 // For page containing |object| mark region covering [object+offset] | 154 // For page containing |object| mark region covering [object+offset] |
155 // dirty. |object| is the object being stored into, |value| is the | 155 // dirty. |object| is the object being stored into, |value| is the |
156 // object being stored. If |offset| is zero, then the |scratch| | 156 // object being stored. If |offset| is zero, then the |scratch| |
157 // register contains the array index into the elements array | 157 // register contains the array index into the elements array |
158 // represented as an untagged 32-bit integer. All registers are | 158 // represented as an untagged 32-bit integer. All registers are |
159 // clobbered by the operation. RecordWrite filters out smis so it | 159 // clobbered by the operation. RecordWrite filters out smis so it |
160 // does not update the write barrier if the value is a smi. | 160 // does not update the write barrier if the value is a smi. |
161 void RecordWrite(Register object, | 161 void RecordWrite(Register object, |
162 int offset, | 162 int offset, |
(...skipping 156 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
319 // Divide a positive smi's integer value by a power of two. | 319 // Divide a positive smi's integer value by a power of two. |
320 // Provides result as 32-bit integer value. | 320 // Provides result as 32-bit integer value. |
321 void PositiveSmiDivPowerOfTwoToInteger32(Register dst, | 321 void PositiveSmiDivPowerOfTwoToInteger32(Register dst, |
322 Register src, | 322 Register src, |
323 int power); | 323 int power); |
324 | 324 |
325 // Perform the logical or of two smi values and return a smi value. | 325 // Perform the logical or of two smi values and return a smi value. |
326 // If either argument is not a smi, jump to on_not_smis and retain | 326 // If either argument is not a smi, jump to on_not_smis and retain |
327 // the original values of source registers. The destination register | 327 // the original values of source registers. The destination register |
328 // may be changed if it's not one of the source registers. | 328 // may be changed if it's not one of the source registers. |
329 template <typename LabelType> | |
330 void SmiOrIfSmis(Register dst, | 329 void SmiOrIfSmis(Register dst, |
331 Register src1, | 330 Register src1, |
332 Register src2, | 331 Register src2, |
333 LabelType* on_not_smis); | 332 Label* on_not_smis, |
| 333 Label::Distance near_jump = Label::kFar); |
334 | 334 |
335 | 335 |
336 // Simple comparison of smis. Both sides must be known smis to use these, | 336 // Simple comparison of smis. Both sides must be known smis to use these, |
337 // otherwise use Cmp. | 337 // otherwise use Cmp. |
338 void SmiCompare(Register smi1, Register smi2); | 338 void SmiCompare(Register smi1, Register smi2); |
339 void SmiCompare(Register dst, Smi* src); | 339 void SmiCompare(Register dst, Smi* src); |
340 void SmiCompare(Register dst, const Operand& src); | 340 void SmiCompare(Register dst, const Operand& src); |
341 void SmiCompare(const Operand& dst, Register src); | 341 void SmiCompare(const Operand& dst, Register src); |
342 void SmiCompare(const Operand& dst, Smi* src); | 342 void SmiCompare(const Operand& dst, Smi* src); |
343 // Compare the int32 in src register to the value of the smi stored at dst. | 343 // Compare the int32 in src register to the value of the smi stored at dst. |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
381 | 381 |
382 // Check whether src is a Smi, and set dst to zero if it is a smi, | 382 // Check whether src is a Smi, and set dst to zero if it is a smi, |
383 // and to one if it isn't. | 383 // and to one if it isn't. |
384 void CheckSmiToIndicator(Register dst, Register src); | 384 void CheckSmiToIndicator(Register dst, Register src); |
385 void CheckSmiToIndicator(Register dst, const Operand& src); | 385 void CheckSmiToIndicator(Register dst, const Operand& src); |
386 | 386 |
387 // Test-and-jump functions. Typically combines a check function | 387 // Test-and-jump functions. Typically combines a check function |
388 // above with a conditional jump. | 388 // above with a conditional jump. |
389 | 389 |
390 // Jump if the value cannot be represented by a smi. | 390 // Jump if the value cannot be represented by a smi. |
391 template <typename LabelType> | 391 void JumpIfNotValidSmiValue(Register src, Label* on_invalid, |
392 void JumpIfNotValidSmiValue(Register src, LabelType* on_invalid); | 392 Label::Distance near_jump = Label::kFar); |
393 | 393 |
394 // Jump if the unsigned integer value cannot be represented by a smi. | 394 // Jump if the unsigned integer value cannot be represented by a smi. |
395 template <typename LabelType> | 395 void JumpIfUIntNotValidSmiValue(Register src, Label* on_invalid, |
396 void JumpIfUIntNotValidSmiValue(Register src, LabelType* on_invalid); | 396 Label::Distance near_jump = Label::kFar); |
397 | 397 |
398 // Jump to label if the value is a tagged smi. | 398 // Jump to label if the value is a tagged smi. |
399 template <typename LabelType> | 399 void JumpIfSmi(Register src, |
400 void JumpIfSmi(Register src, LabelType* on_smi); | 400 Label* on_smi, |
| 401 Label::Distance near_jump = Label::kFar); |
401 | 402 |
402 // Jump to label if the value is not a tagged smi. | 403 // Jump to label if the value is not a tagged smi. |
403 template <typename LabelType> | 404 void JumpIfNotSmi(Register src, |
404 void JumpIfNotSmi(Register src, LabelType* on_not_smi); | 405 Label* on_not_smi, |
| 406 Label::Distance near_jump = Label::kFar); |
405 | 407 |
406 // Jump to label if the value is not a non-negative tagged smi. | 408 // Jump to label if the value is not a non-negative tagged smi. |
407 template <typename LabelType> | 409 void JumpUnlessNonNegativeSmi(Register src, |
408 void JumpUnlessNonNegativeSmi(Register src, LabelType* on_not_smi); | 410 Label* on_not_smi, |
| 411 Label::Distance near_jump = Label::kFar); |
409 | 412 |
410 // Jump to label if the value, which must be a tagged smi, has value equal | 413 // Jump to label if the value, which must be a tagged smi, has value equal |
411 // to the constant. | 414 // to the constant. |
412 template <typename LabelType> | |
413 void JumpIfSmiEqualsConstant(Register src, | 415 void JumpIfSmiEqualsConstant(Register src, |
414 Smi* constant, | 416 Smi* constant, |
415 LabelType* on_equals); | 417 Label* on_equals, |
| 418 Label::Distance near_jump = Label::kFar); |
416 | 419 |
417 // Jump if either or both register are not smi values. | 420 // Jump if either or both register are not smi values. |
418 template <typename LabelType> | |
419 void JumpIfNotBothSmi(Register src1, | 421 void JumpIfNotBothSmi(Register src1, |
420 Register src2, | 422 Register src2, |
421 LabelType* on_not_both_smi); | 423 Label* on_not_both_smi, |
| 424 Label::Distance near_jump = Label::kFar); |
422 | 425 |
423 // Jump if either or both register are not non-negative smi values. | 426 // Jump if either or both register are not non-negative smi values. |
424 template <typename LabelType> | |
425 void JumpUnlessBothNonNegativeSmi(Register src1, Register src2, | 427 void JumpUnlessBothNonNegativeSmi(Register src1, Register src2, |
426 LabelType* on_not_both_smi); | 428 Label* on_not_both_smi, |
| 429 Label::Distance near_jump = Label::kFar); |
427 | 430 |
428 // Operations on tagged smi values. | 431 // Operations on tagged smi values. |
429 | 432 |
430 // Smis represent a subset of integers. The subset is always equivalent to | 433 // Smis represent a subset of integers. The subset is always equivalent to |
431 // a two's complement interpretation of a fixed number of bits. | 434 // a two's complement interpretation of a fixed number of bits. |
432 | 435 |
433 // Optimistically adds an integer constant to a supposed smi. | 436 // Optimistically adds an integer constant to a supposed smi. |
434 // If the src is not a smi, or the result is not a smi, jump to | 437 // If the src is not a smi, or the result is not a smi, jump to |
435 // the label. | 438 // the label. |
436 template <typename LabelType> | |
437 void SmiTryAddConstant(Register dst, | 439 void SmiTryAddConstant(Register dst, |
438 Register src, | 440 Register src, |
439 Smi* constant, | 441 Smi* constant, |
440 LabelType* on_not_smi_result); | 442 Label* on_not_smi_result, |
| 443 Label::Distance near_jump = Label::kFar); |
441 | 444 |
442 // Add an integer constant to a tagged smi, giving a tagged smi as result. | 445 // Add an integer constant to a tagged smi, giving a tagged smi as result. |
443 // No overflow testing on the result is done. | 446 // No overflow testing on the result is done. |
444 void SmiAddConstant(Register dst, Register src, Smi* constant); | 447 void SmiAddConstant(Register dst, Register src, Smi* constant); |
445 | 448 |
446 // Add an integer constant to a tagged smi, giving a tagged smi as result. | 449 // Add an integer constant to a tagged smi, giving a tagged smi as result. |
447 // No overflow testing on the result is done. | 450 // No overflow testing on the result is done. |
448 void SmiAddConstant(const Operand& dst, Smi* constant); | 451 void SmiAddConstant(const Operand& dst, Smi* constant); |
449 | 452 |
450 // Add an integer constant to a tagged smi, giving a tagged smi as result, | 453 // Add an integer constant to a tagged smi, giving a tagged smi as result, |
451 // or jumping to a label if the result cannot be represented by a smi. | 454 // or jumping to a label if the result cannot be represented by a smi. |
452 template <typename LabelType> | |
453 void SmiAddConstant(Register dst, | 455 void SmiAddConstant(Register dst, |
454 Register src, | 456 Register src, |
455 Smi* constant, | 457 Smi* constant, |
456 LabelType* on_not_smi_result); | 458 Label* on_not_smi_result, |
| 459 Label::Distance near_jump = Label::kFar); |
457 | 460 |
458 // Subtract an integer constant from a tagged smi, giving a tagged smi as | 461 // Subtract an integer constant from a tagged smi, giving a tagged smi as |
459 // result. No testing on the result is done. Sets the N and Z flags | 462 // result. No testing on the result is done. Sets the N and Z flags |
460 // based on the value of the resulting integer. | 463 // based on the value of the resulting integer. |
461 void SmiSubConstant(Register dst, Register src, Smi* constant); | 464 void SmiSubConstant(Register dst, Register src, Smi* constant); |
462 | 465 |
463 // Subtract an integer constant from a tagged smi, giving a tagged smi as | 466 // Subtract an integer constant from a tagged smi, giving a tagged smi as |
464 // result, or jumping to a label if the result cannot be represented by a smi. | 467 // result, or jumping to a label if the result cannot be represented by a smi. |
465 template <typename LabelType> | |
466 void SmiSubConstant(Register dst, | 468 void SmiSubConstant(Register dst, |
467 Register src, | 469 Register src, |
468 Smi* constant, | 470 Smi* constant, |
469 LabelType* on_not_smi_result); | 471 Label* on_not_smi_result, |
| 472 Label::Distance near_jump = Label::kFar); |
470 | 473 |
471 // Negating a smi can give a negative zero or too large positive value. | 474 // Negating a smi can give a negative zero or too large positive value. |
472 // NOTICE: This operation jumps on success, not failure! | 475 // NOTICE: This operation jumps on success, not failure! |
473 template <typename LabelType> | |
474 void SmiNeg(Register dst, | 476 void SmiNeg(Register dst, |
475 Register src, | 477 Register src, |
476 LabelType* on_smi_result); | 478 Label* on_smi_result, |
| 479 Label::Distance near_jump = Label::kFar); |
477 | 480 |
478 // Adds smi values and return the result as a smi. | 481 // Adds smi values and return the result as a smi. |
479 // If dst is src1, then src1 will be destroyed, even if | 482 // If dst is src1, then src1 will be destroyed, even if |
480 // the operation is unsuccessful. | 483 // the operation is unsuccessful. |
481 template <typename LabelType> | |
482 void SmiAdd(Register dst, | 484 void SmiAdd(Register dst, |
483 Register src1, | 485 Register src1, |
484 Register src2, | 486 Register src2, |
485 LabelType* on_not_smi_result); | 487 Label* on_not_smi_result, |
486 template <typename LabelType> | 488 Label::Distance near_jump = Label::kFar); |
487 void SmiAdd(Register dst, | 489 void SmiAdd(Register dst, |
488 Register src1, | 490 Register src1, |
489 const Operand& src2, | 491 const Operand& src2, |
490 LabelType* on_not_smi_result); | 492 Label* on_not_smi_result, |
| 493 Label::Distance near_jump = Label::kFar); |
491 | 494 |
492 void SmiAdd(Register dst, | 495 void SmiAdd(Register dst, |
493 Register src1, | 496 Register src1, |
494 Register src2); | 497 Register src2); |
495 | 498 |
496 // Subtracts smi values and return the result as a smi. | 499 // Subtracts smi values and return the result as a smi. |
497 // If dst is src1, then src1 will be destroyed, even if | 500 // If dst is src1, then src1 will be destroyed, even if |
498 // the operation is unsuccessful. | 501 // the operation is unsuccessful. |
499 template <typename LabelType> | |
500 void SmiSub(Register dst, | 502 void SmiSub(Register dst, |
501 Register src1, | 503 Register src1, |
502 Register src2, | 504 Register src2, |
503 LabelType* on_not_smi_result); | 505 Label* on_not_smi_result, |
| 506 Label::Distance near_jump = Label::kFar); |
504 | 507 |
505 void SmiSub(Register dst, | 508 void SmiSub(Register dst, |
506 Register src1, | 509 Register src1, |
507 Register src2); | 510 Register src2); |
508 | 511 |
509 template <typename LabelType> | |
510 void SmiSub(Register dst, | 512 void SmiSub(Register dst, |
511 Register src1, | 513 Register src1, |
512 const Operand& src2, | 514 const Operand& src2, |
513 LabelType* on_not_smi_result); | 515 Label* on_not_smi_result, |
| 516 Label::Distance near_jump = Label::kFar); |
514 | 517 |
515 void SmiSub(Register dst, | 518 void SmiSub(Register dst, |
516 Register src1, | 519 Register src1, |
517 const Operand& src2); | 520 const Operand& src2); |
518 | 521 |
519 // Multiplies smi values and return the result as a smi, | 522 // Multiplies smi values and return the result as a smi, |
520 // if possible. | 523 // if possible. |
521 // If dst is src1, then src1 will be destroyed, even if | 524 // If dst is src1, then src1 will be destroyed, even if |
522 // the operation is unsuccessful. | 525 // the operation is unsuccessful. |
523 template <typename LabelType> | |
524 void SmiMul(Register dst, | 526 void SmiMul(Register dst, |
525 Register src1, | 527 Register src1, |
526 Register src2, | 528 Register src2, |
527 LabelType* on_not_smi_result); | 529 Label* on_not_smi_result, |
| 530 Label::Distance near_jump = Label::kFar); |
528 | 531 |
529 // Divides one smi by another and returns the quotient. | 532 // Divides one smi by another and returns the quotient. |
530 // Clobbers rax and rdx registers. | 533 // Clobbers rax and rdx registers. |
531 template <typename LabelType> | |
532 void SmiDiv(Register dst, | 534 void SmiDiv(Register dst, |
533 Register src1, | 535 Register src1, |
534 Register src2, | 536 Register src2, |
535 LabelType* on_not_smi_result); | 537 Label* on_not_smi_result, |
| 538 Label::Distance near_jump = Label::kFar); |
536 | 539 |
537 // Divides one smi by another and returns the remainder. | 540 // Divides one smi by another and returns the remainder. |
538 // Clobbers rax and rdx registers. | 541 // Clobbers rax and rdx registers. |
539 template <typename LabelType> | |
540 void SmiMod(Register dst, | 542 void SmiMod(Register dst, |
541 Register src1, | 543 Register src1, |
542 Register src2, | 544 Register src2, |
543 LabelType* on_not_smi_result); | 545 Label* on_not_smi_result, |
| 546 Label::Distance near_jump = Label::kFar); |
544 | 547 |
545 // Bitwise operations. | 548 // Bitwise operations. |
546 void SmiNot(Register dst, Register src); | 549 void SmiNot(Register dst, Register src); |
547 void SmiAnd(Register dst, Register src1, Register src2); | 550 void SmiAnd(Register dst, Register src1, Register src2); |
548 void SmiOr(Register dst, Register src1, Register src2); | 551 void SmiOr(Register dst, Register src1, Register src2); |
549 void SmiXor(Register dst, Register src1, Register src2); | 552 void SmiXor(Register dst, Register src1, Register src2); |
550 void SmiAndConstant(Register dst, Register src1, Smi* constant); | 553 void SmiAndConstant(Register dst, Register src1, Smi* constant); |
551 void SmiOrConstant(Register dst, Register src1, Smi* constant); | 554 void SmiOrConstant(Register dst, Register src1, Smi* constant); |
552 void SmiXorConstant(Register dst, Register src1, Smi* constant); | 555 void SmiXorConstant(Register dst, Register src1, Smi* constant); |
553 | 556 |
554 void SmiShiftLeftConstant(Register dst, | 557 void SmiShiftLeftConstant(Register dst, |
555 Register src, | 558 Register src, |
556 int shift_value); | 559 int shift_value); |
557 template <typename LabelType> | |
558 void SmiShiftLogicalRightConstant(Register dst, | 560 void SmiShiftLogicalRightConstant(Register dst, |
559 Register src, | 561 Register src, |
560 int shift_value, | 562 int shift_value, |
561 LabelType* on_not_smi_result); | 563 Label* on_not_smi_result, |
| 564 Label::Distance near_jump = Label::kFar); |
562 void SmiShiftArithmeticRightConstant(Register dst, | 565 void SmiShiftArithmeticRightConstant(Register dst, |
563 Register src, | 566 Register src, |
564 int shift_value); | 567 int shift_value); |
565 | 568 |
566 // Shifts a smi value to the left, and returns the result if that is a smi. | 569 // Shifts a smi value to the left, and returns the result if that is a smi. |
567 // Uses and clobbers rcx, so dst may not be rcx. | 570 // Uses and clobbers rcx, so dst may not be rcx. |
568 void SmiShiftLeft(Register dst, | 571 void SmiShiftLeft(Register dst, |
569 Register src1, | 572 Register src1, |
570 Register src2); | 573 Register src2); |
571 // Shifts a smi value to the right, shifting in zero bits at the top, and | 574 // Shifts a smi value to the right, shifting in zero bits at the top, and |
572 // returns the unsigned intepretation of the result if that is a smi. | 575 // returns the unsigned intepretation of the result if that is a smi. |
573 // Uses and clobbers rcx, so dst may not be rcx. | 576 // Uses and clobbers rcx, so dst may not be rcx. |
574 template <typename LabelType> | |
575 void SmiShiftLogicalRight(Register dst, | 577 void SmiShiftLogicalRight(Register dst, |
576 Register src1, | 578 Register src1, |
577 Register src2, | 579 Register src2, |
578 LabelType* on_not_smi_result); | 580 Label* on_not_smi_result, |
| 581 Label::Distance near_jump = Label::kFar); |
579 // Shifts a smi value to the right, sign extending the top, and | 582 // Shifts a smi value to the right, sign extending the top, and |
580 // returns the signed intepretation of the result. That will always | 583 // returns the signed intepretation of the result. That will always |
581 // be a valid smi value, since it's numerically smaller than the | 584 // be a valid smi value, since it's numerically smaller than the |
582 // original. | 585 // original. |
583 // Uses and clobbers rcx, so dst may not be rcx. | 586 // Uses and clobbers rcx, so dst may not be rcx. |
584 void SmiShiftArithmeticRight(Register dst, | 587 void SmiShiftArithmeticRight(Register dst, |
585 Register src1, | 588 Register src1, |
586 Register src2); | 589 Register src2); |
587 | 590 |
588 // Specialized operations | 591 // Specialized operations |
589 | 592 |
590 // Select the non-smi register of two registers where exactly one is a | 593 // Select the non-smi register of two registers where exactly one is a |
591 // smi. If neither are smis, jump to the failure label. | 594 // smi. If neither are smis, jump to the failure label. |
592 template <typename LabelType> | |
593 void SelectNonSmi(Register dst, | 595 void SelectNonSmi(Register dst, |
594 Register src1, | 596 Register src1, |
595 Register src2, | 597 Register src2, |
596 LabelType* on_not_smis); | 598 Label* on_not_smis, |
| 599 Label::Distance near_jump = Label::kFar); |
597 | 600 |
598 // Converts, if necessary, a smi to a combination of number and | 601 // Converts, if necessary, a smi to a combination of number and |
599 // multiplier to be used as a scaled index. | 602 // multiplier to be used as a scaled index. |
600 // The src register contains a *positive* smi value. The shift is the | 603 // The src register contains a *positive* smi value. The shift is the |
601 // power of two to multiply the index value by (e.g. | 604 // power of two to multiply the index value by (e.g. |
602 // to index by smi-value * kPointerSize, pass the smi and kPointerSizeLog2). | 605 // to index by smi-value * kPointerSize, pass the smi and kPointerSizeLog2). |
603 // The returned index register may be either src or dst, depending | 606 // The returned index register may be either src or dst, depending |
604 // on what is most efficient. If src and dst are different registers, | 607 // on what is most efficient. If src and dst are different registers, |
605 // src is always unchanged. | 608 // src is always unchanged. |
606 SmiIndex SmiToIndex(Register dst, Register src, int shift); | 609 SmiIndex SmiToIndex(Register dst, Register src, int shift); |
(...skipping 15 matching lines...) Expand all Loading... |
622 movq(dst, constant); | 625 movq(dst, constant); |
623 } | 626 } |
624 | 627 |
625 void Push(Smi* smi); | 628 void Push(Smi* smi); |
626 void Test(const Operand& dst, Smi* source); | 629 void Test(const Operand& dst, Smi* source); |
627 | 630 |
628 // --------------------------------------------------------------------------- | 631 // --------------------------------------------------------------------------- |
629 // String macros. | 632 // String macros. |
630 | 633 |
631 // If object is a string, its map is loaded into object_map. | 634 // If object is a string, its map is loaded into object_map. |
632 template <typename LabelType> | |
633 void JumpIfNotString(Register object, | 635 void JumpIfNotString(Register object, |
634 Register object_map, | 636 Register object_map, |
635 LabelType* not_string); | 637 Label* not_string, |
| 638 Label::Distance near_jump = Label::kFar); |
636 | 639 |
637 | 640 |
638 template <typename LabelType> | 641 void JumpIfNotBothSequentialAsciiStrings( |
639 void JumpIfNotBothSequentialAsciiStrings(Register first_object, | 642 Register first_object, |
640 Register second_object, | 643 Register second_object, |
641 Register scratch1, | 644 Register scratch1, |
642 Register scratch2, | 645 Register scratch2, |
643 LabelType* on_not_both_flat_ascii); | 646 Label* on_not_both_flat_ascii, |
| 647 Label::Distance near_jump = Label::kFar); |
644 | 648 |
645 // Check whether the instance type represents a flat ascii string. Jump to the | 649 // Check whether the instance type represents a flat ascii string. Jump to the |
646 // label if not. If the instance type can be scratched specify same register | 650 // label if not. If the instance type can be scratched specify same register |
647 // for both instance type and scratch. | 651 // for both instance type and scratch. |
648 template <typename LabelType> | |
649 void JumpIfInstanceTypeIsNotSequentialAscii( | 652 void JumpIfInstanceTypeIsNotSequentialAscii( |
650 Register instance_type, | 653 Register instance_type, |
651 Register scratch, | 654 Register scratch, |
652 LabelType *on_not_flat_ascii_string); | 655 Label*on_not_flat_ascii_string, |
| 656 Label::Distance near_jump = Label::kFar); |
653 | 657 |
654 template <typename LabelType> | |
655 void JumpIfBothInstanceTypesAreNotSequentialAscii( | 658 void JumpIfBothInstanceTypesAreNotSequentialAscii( |
656 Register first_object_instance_type, | 659 Register first_object_instance_type, |
657 Register second_object_instance_type, | 660 Register second_object_instance_type, |
658 Register scratch1, | 661 Register scratch1, |
659 Register scratch2, | 662 Register scratch2, |
660 LabelType* on_fail); | 663 Label* on_fail, |
| 664 Label::Distance near_jump = Label::kFar); |
661 | 665 |
662 // --------------------------------------------------------------------------- | 666 // --------------------------------------------------------------------------- |
663 // Macro instructions. | 667 // Macro instructions. |
664 | 668 |
665 // Load a register with a long value as efficiently as possible. | 669 // Load a register with a long value as efficiently as possible. |
666 void Set(Register dst, int64_t x); | 670 void Set(Register dst, int64_t x); |
667 void Set(const Operand& dst, int64_t x); | 671 void Set(const Operand& dst, int64_t x); |
668 | 672 |
669 // Move if the registers are not identical. | 673 // Move if the registers are not identical. |
670 void Move(Register target, Register source); | 674 void Move(Register target, Register source); |
(...skipping 425 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1096 | 1100 |
1097 static int SafepointRegisterStackIndex(Register reg) { | 1101 static int SafepointRegisterStackIndex(Register reg) { |
1098 return SafepointRegisterStackIndex(reg.code()); | 1102 return SafepointRegisterStackIndex(reg.code()); |
1099 } | 1103 } |
1100 | 1104 |
1101 private: | 1105 private: |
1102 // Order general registers are pushed by Pushad. | 1106 // Order general registers are pushed by Pushad. |
1103 // rax, rcx, rdx, rbx, rsi, rdi, r8, r9, r11, r14, r15. | 1107 // rax, rcx, rdx, rbx, rsi, rdi, r8, r9, r11, r14, r15. |
1104 static int kSafepointPushRegisterIndices[Register::kNumRegisters]; | 1108 static int kSafepointPushRegisterIndices[Register::kNumRegisters]; |
1105 static const int kNumSafepointSavedRegisters = 11; | 1109 static const int kNumSafepointSavedRegisters = 11; |
| 1110 static const int kSmiShift = kSmiTagSize + kSmiShiftSize; |
1106 | 1111 |
1107 bool generating_stub_; | 1112 bool generating_stub_; |
1108 bool allow_stub_calls_; | 1113 bool allow_stub_calls_; |
1109 bool root_array_available_; | 1114 bool root_array_available_; |
1110 | 1115 |
1111 // Returns a register holding the smi value. The register MUST NOT be | 1116 // Returns a register holding the smi value. The register MUST NOT be |
1112 // modified. It may be the "smi 1 constant" register. | 1117 // modified. It may be the "smi 1 constant" register. |
1113 Register GetSmiConstant(Smi* value); | 1118 Register GetSmiConstant(Smi* value); |
1114 | 1119 |
1115 // Moves the smi value to the destination register. | 1120 // Moves the smi value to the destination register. |
1116 void LoadSmiConstant(Register dst, Smi* value); | 1121 void LoadSmiConstant(Register dst, Smi* value); |
1117 | 1122 |
1118 // This handle will be patched with the code object on installation. | 1123 // This handle will be patched with the code object on installation. |
1119 Handle<Object> code_object_; | 1124 Handle<Object> code_object_; |
1120 | 1125 |
1121 // Helper functions for generating invokes. | 1126 // Helper functions for generating invokes. |
1122 template <typename LabelType> | |
1123 void InvokePrologue(const ParameterCount& expected, | 1127 void InvokePrologue(const ParameterCount& expected, |
1124 const ParameterCount& actual, | 1128 const ParameterCount& actual, |
1125 Handle<Code> code_constant, | 1129 Handle<Code> code_constant, |
1126 Register code_register, | 1130 Register code_register, |
1127 LabelType* done, | 1131 Label* done, |
1128 InvokeFlag flag, | 1132 InvokeFlag flag, |
1129 const CallWrapper& call_wrapper); | 1133 const CallWrapper& call_wrapper, |
| 1134 Label::Distance near_jump = Label::kFar); |
1130 | 1135 |
1131 // Activation support. | 1136 // Activation support. |
1132 void EnterFrame(StackFrame::Type type); | 1137 void EnterFrame(StackFrame::Type type); |
1133 void LeaveFrame(StackFrame::Type type); | 1138 void LeaveFrame(StackFrame::Type type); |
1134 | 1139 |
1135 void EnterExitFramePrologue(bool save_rax); | 1140 void EnterExitFramePrologue(bool save_rax); |
1136 | 1141 |
1137 // Allocates arg_stack_space * kPointerSize memory (not GCed) on the stack | 1142 // Allocates arg_stack_space * kPointerSize memory (not GCed) on the stack |
1138 // accessible via StackSpaceOperand. | 1143 // accessible via StackSpaceOperand. |
1139 void EnterExitFrameEpilogue(int arg_stack_space, bool save_doubles); | 1144 void EnterExitFrameEpilogue(int arg_stack_space, bool save_doubles); |
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1245 masm->call(x64_coverage_function, RelocInfo::RUNTIME_ENTRY); \ | 1250 masm->call(x64_coverage_function, RelocInfo::RUNTIME_ENTRY); \ |
1246 masm->pop(rax); \ | 1251 masm->pop(rax); \ |
1247 masm->popad(); \ | 1252 masm->popad(); \ |
1248 masm->popfd(); \ | 1253 masm->popfd(); \ |
1249 } \ | 1254 } \ |
1250 masm-> | 1255 masm-> |
1251 #else | 1256 #else |
1252 #define ACCESS_MASM(masm) masm-> | 1257 #define ACCESS_MASM(masm) masm-> |
1253 #endif | 1258 #endif |
1254 | 1259 |
1255 // ----------------------------------------------------------------------------- | |
1256 // Template implementations. | |
1257 | |
1258 static int kSmiShift = kSmiTagSize + kSmiShiftSize; | |
1259 | |
1260 | |
1261 template <typename LabelType> | |
1262 void MacroAssembler::SmiNeg(Register dst, | |
1263 Register src, | |
1264 LabelType* on_smi_result) { | |
1265 if (dst.is(src)) { | |
1266 ASSERT(!dst.is(kScratchRegister)); | |
1267 movq(kScratchRegister, src); | |
1268 neg(dst); // Low 32 bits are retained as zero by negation. | |
1269 // Test if result is zero or Smi::kMinValue. | |
1270 cmpq(dst, kScratchRegister); | |
1271 j(not_equal, on_smi_result); | |
1272 movq(src, kScratchRegister); | |
1273 } else { | |
1274 movq(dst, src); | |
1275 neg(dst); | |
1276 cmpq(dst, src); | |
1277 // If the result is zero or Smi::kMinValue, negation failed to create a smi. | |
1278 j(not_equal, on_smi_result); | |
1279 } | |
1280 } | |
1281 | |
1282 | |
1283 template <typename LabelType> | |
1284 void MacroAssembler::SmiAdd(Register dst, | |
1285 Register src1, | |
1286 Register src2, | |
1287 LabelType* on_not_smi_result) { | |
1288 ASSERT_NOT_NULL(on_not_smi_result); | |
1289 ASSERT(!dst.is(src2)); | |
1290 if (dst.is(src1)) { | |
1291 movq(kScratchRegister, src1); | |
1292 addq(kScratchRegister, src2); | |
1293 j(overflow, on_not_smi_result); | |
1294 movq(dst, kScratchRegister); | |
1295 } else { | |
1296 movq(dst, src1); | |
1297 addq(dst, src2); | |
1298 j(overflow, on_not_smi_result); | |
1299 } | |
1300 } | |
1301 | |
1302 | |
1303 template <typename LabelType> | |
1304 void MacroAssembler::SmiAdd(Register dst, | |
1305 Register src1, | |
1306 const Operand& src2, | |
1307 LabelType* on_not_smi_result) { | |
1308 ASSERT_NOT_NULL(on_not_smi_result); | |
1309 if (dst.is(src1)) { | |
1310 movq(kScratchRegister, src1); | |
1311 addq(kScratchRegister, src2); | |
1312 j(overflow, on_not_smi_result); | |
1313 movq(dst, kScratchRegister); | |
1314 } else { | |
1315 ASSERT(!src2.AddressUsesRegister(dst)); | |
1316 movq(dst, src1); | |
1317 addq(dst, src2); | |
1318 j(overflow, on_not_smi_result); | |
1319 } | |
1320 } | |
1321 | |
1322 | |
1323 template <typename LabelType> | |
1324 void MacroAssembler::SmiSub(Register dst, | |
1325 Register src1, | |
1326 Register src2, | |
1327 LabelType* on_not_smi_result) { | |
1328 ASSERT_NOT_NULL(on_not_smi_result); | |
1329 ASSERT(!dst.is(src2)); | |
1330 if (dst.is(src1)) { | |
1331 cmpq(dst, src2); | |
1332 j(overflow, on_not_smi_result); | |
1333 subq(dst, src2); | |
1334 } else { | |
1335 movq(dst, src1); | |
1336 subq(dst, src2); | |
1337 j(overflow, on_not_smi_result); | |
1338 } | |
1339 } | |
1340 | |
1341 | |
1342 template <typename LabelType> | |
1343 void MacroAssembler::SmiSub(Register dst, | |
1344 Register src1, | |
1345 const Operand& src2, | |
1346 LabelType* on_not_smi_result) { | |
1347 ASSERT_NOT_NULL(on_not_smi_result); | |
1348 if (dst.is(src1)) { | |
1349 movq(kScratchRegister, src2); | |
1350 cmpq(src1, kScratchRegister); | |
1351 j(overflow, on_not_smi_result); | |
1352 subq(src1, kScratchRegister); | |
1353 } else { | |
1354 movq(dst, src1); | |
1355 subq(dst, src2); | |
1356 j(overflow, on_not_smi_result); | |
1357 } | |
1358 } | |
1359 | |
1360 | |
1361 template <typename LabelType> | |
1362 void MacroAssembler::SmiMul(Register dst, | |
1363 Register src1, | |
1364 Register src2, | |
1365 LabelType* on_not_smi_result) { | |
1366 ASSERT(!dst.is(src2)); | |
1367 ASSERT(!dst.is(kScratchRegister)); | |
1368 ASSERT(!src1.is(kScratchRegister)); | |
1369 ASSERT(!src2.is(kScratchRegister)); | |
1370 | |
1371 if (dst.is(src1)) { | |
1372 Label failure, zero_correct_result; | |
1373 movq(kScratchRegister, src1); // Create backup for later testing. | |
1374 SmiToInteger64(dst, src1); | |
1375 imul(dst, src2); | |
1376 j(overflow, &failure, Label::kNear); | |
1377 | |
1378 // Check for negative zero result. If product is zero, and one | |
1379 // argument is negative, go to slow case. | |
1380 Label correct_result; | |
1381 testq(dst, dst); | |
1382 j(not_zero, &correct_result, Label::kNear); | |
1383 | |
1384 movq(dst, kScratchRegister); | |
1385 xor_(dst, src2); | |
1386 // Result was positive zero. | |
1387 j(positive, &zero_correct_result, Label::kNear); | |
1388 | |
1389 bind(&failure); // Reused failure exit, restores src1. | |
1390 movq(src1, kScratchRegister); | |
1391 jmp(on_not_smi_result); | |
1392 | |
1393 bind(&zero_correct_result); | |
1394 Set(dst, 0); | |
1395 | |
1396 bind(&correct_result); | |
1397 } else { | |
1398 SmiToInteger64(dst, src1); | |
1399 imul(dst, src2); | |
1400 j(overflow, on_not_smi_result); | |
1401 // Check for negative zero result. If product is zero, and one | |
1402 // argument is negative, go to slow case. | |
1403 Label correct_result; | |
1404 testq(dst, dst); | |
1405 j(not_zero, &correct_result, Label::kNear); | |
1406 // One of src1 and src2 is zero, the check whether the other is | |
1407 // negative. | |
1408 movq(kScratchRegister, src1); | |
1409 xor_(kScratchRegister, src2); | |
1410 j(negative, on_not_smi_result); | |
1411 bind(&correct_result); | |
1412 } | |
1413 } | |
1414 | |
1415 | |
1416 template <typename LabelType> | |
1417 void MacroAssembler::SmiTryAddConstant(Register dst, | |
1418 Register src, | |
1419 Smi* constant, | |
1420 LabelType* on_not_smi_result) { | |
1421 // Does not assume that src is a smi. | |
1422 ASSERT_EQ(static_cast<int>(1), static_cast<int>(kSmiTagMask)); | |
1423 ASSERT_EQ(0, kSmiTag); | |
1424 ASSERT(!dst.is(kScratchRegister)); | |
1425 ASSERT(!src.is(kScratchRegister)); | |
1426 | |
1427 JumpIfNotSmi(src, on_not_smi_result); | |
1428 Register tmp = (dst.is(src) ? kScratchRegister : dst); | |
1429 LoadSmiConstant(tmp, constant); | |
1430 addq(tmp, src); | |
1431 j(overflow, on_not_smi_result); | |
1432 if (dst.is(src)) { | |
1433 movq(dst, tmp); | |
1434 } | |
1435 } | |
1436 | |
1437 | |
1438 template <typename LabelType> | |
1439 void MacroAssembler::SmiAddConstant(Register dst, | |
1440 Register src, | |
1441 Smi* constant, | |
1442 LabelType* on_not_smi_result) { | |
1443 if (constant->value() == 0) { | |
1444 if (!dst.is(src)) { | |
1445 movq(dst, src); | |
1446 } | |
1447 } else if (dst.is(src)) { | |
1448 ASSERT(!dst.is(kScratchRegister)); | |
1449 | |
1450 LoadSmiConstant(kScratchRegister, constant); | |
1451 addq(kScratchRegister, src); | |
1452 j(overflow, on_not_smi_result); | |
1453 movq(dst, kScratchRegister); | |
1454 } else { | |
1455 LoadSmiConstant(dst, constant); | |
1456 addq(dst, src); | |
1457 j(overflow, on_not_smi_result); | |
1458 } | |
1459 } | |
1460 | |
1461 | |
1462 template <typename LabelType> | |
1463 void MacroAssembler::SmiSubConstant(Register dst, | |
1464 Register src, | |
1465 Smi* constant, | |
1466 LabelType* on_not_smi_result) { | |
1467 if (constant->value() == 0) { | |
1468 if (!dst.is(src)) { | |
1469 movq(dst, src); | |
1470 } | |
1471 } else if (dst.is(src)) { | |
1472 ASSERT(!dst.is(kScratchRegister)); | |
1473 if (constant->value() == Smi::kMinValue) { | |
1474 // Subtracting min-value from any non-negative value will overflow. | |
1475 // We test the non-negativeness before doing the subtraction. | |
1476 testq(src, src); | |
1477 j(not_sign, on_not_smi_result); | |
1478 LoadSmiConstant(kScratchRegister, constant); | |
1479 subq(dst, kScratchRegister); | |
1480 } else { | |
1481 // Subtract by adding the negation. | |
1482 LoadSmiConstant(kScratchRegister, Smi::FromInt(-constant->value())); | |
1483 addq(kScratchRegister, dst); | |
1484 j(overflow, on_not_smi_result); | |
1485 movq(dst, kScratchRegister); | |
1486 } | |
1487 } else { | |
1488 if (constant->value() == Smi::kMinValue) { | |
1489 // Subtracting min-value from any non-negative value will overflow. | |
1490 // We test the non-negativeness before doing the subtraction. | |
1491 testq(src, src); | |
1492 j(not_sign, on_not_smi_result); | |
1493 LoadSmiConstant(dst, constant); | |
1494 // Adding and subtracting the min-value gives the same result, it only | |
1495 // differs on the overflow bit, which we don't check here. | |
1496 addq(dst, src); | |
1497 } else { | |
1498 // Subtract by adding the negation. | |
1499 LoadSmiConstant(dst, Smi::FromInt(-(constant->value()))); | |
1500 addq(dst, src); | |
1501 j(overflow, on_not_smi_result); | |
1502 } | |
1503 } | |
1504 } | |
1505 | |
1506 | |
1507 template <typename LabelType> | |
1508 void MacroAssembler::SmiDiv(Register dst, | |
1509 Register src1, | |
1510 Register src2, | |
1511 LabelType* on_not_smi_result) { | |
1512 ASSERT(!src1.is(kScratchRegister)); | |
1513 ASSERT(!src2.is(kScratchRegister)); | |
1514 ASSERT(!dst.is(kScratchRegister)); | |
1515 ASSERT(!src2.is(rax)); | |
1516 ASSERT(!src2.is(rdx)); | |
1517 ASSERT(!src1.is(rdx)); | |
1518 | |
1519 // Check for 0 divisor (result is +/-Infinity). | |
1520 testq(src2, src2); | |
1521 j(zero, on_not_smi_result); | |
1522 | |
1523 if (src1.is(rax)) { | |
1524 movq(kScratchRegister, src1); | |
1525 } | |
1526 SmiToInteger32(rax, src1); | |
1527 // We need to rule out dividing Smi::kMinValue by -1, since that would | |
1528 // overflow in idiv and raise an exception. | |
1529 // We combine this with negative zero test (negative zero only happens | |
1530 // when dividing zero by a negative number). | |
1531 | |
1532 // We overshoot a little and go to slow case if we divide min-value | |
1533 // by any negative value, not just -1. | |
1534 Label safe_div; | |
1535 testl(rax, Immediate(0x7fffffff)); | |
1536 j(not_zero, &safe_div, Label::kNear); | |
1537 testq(src2, src2); | |
1538 if (src1.is(rax)) { | |
1539 j(positive, &safe_div, Label::kNear); | |
1540 movq(src1, kScratchRegister); | |
1541 jmp(on_not_smi_result); | |
1542 } else { | |
1543 j(negative, on_not_smi_result); | |
1544 } | |
1545 bind(&safe_div); | |
1546 | |
1547 SmiToInteger32(src2, src2); | |
1548 // Sign extend src1 into edx:eax. | |
1549 cdq(); | |
1550 idivl(src2); | |
1551 Integer32ToSmi(src2, src2); | |
1552 // Check that the remainder is zero. | |
1553 testl(rdx, rdx); | |
1554 if (src1.is(rax)) { | |
1555 Label smi_result; | |
1556 j(zero, &smi_result, Label::kNear); | |
1557 movq(src1, kScratchRegister); | |
1558 jmp(on_not_smi_result); | |
1559 bind(&smi_result); | |
1560 } else { | |
1561 j(not_zero, on_not_smi_result); | |
1562 } | |
1563 if (!dst.is(src1) && src1.is(rax)) { | |
1564 movq(src1, kScratchRegister); | |
1565 } | |
1566 Integer32ToSmi(dst, rax); | |
1567 } | |
1568 | |
1569 | |
1570 template <typename LabelType> | |
1571 void MacroAssembler::SmiMod(Register dst, | |
1572 Register src1, | |
1573 Register src2, | |
1574 LabelType* on_not_smi_result) { | |
1575 ASSERT(!dst.is(kScratchRegister)); | |
1576 ASSERT(!src1.is(kScratchRegister)); | |
1577 ASSERT(!src2.is(kScratchRegister)); | |
1578 ASSERT(!src2.is(rax)); | |
1579 ASSERT(!src2.is(rdx)); | |
1580 ASSERT(!src1.is(rdx)); | |
1581 ASSERT(!src1.is(src2)); | |
1582 | |
1583 testq(src2, src2); | |
1584 j(zero, on_not_smi_result); | |
1585 | |
1586 if (src1.is(rax)) { | |
1587 movq(kScratchRegister, src1); | |
1588 } | |
1589 SmiToInteger32(rax, src1); | |
1590 SmiToInteger32(src2, src2); | |
1591 | |
1592 // Test for the edge case of dividing Smi::kMinValue by -1 (will overflow). | |
1593 Label safe_div; | |
1594 cmpl(rax, Immediate(Smi::kMinValue)); | |
1595 j(not_equal, &safe_div, Label::kNear); | |
1596 cmpl(src2, Immediate(-1)); | |
1597 j(not_equal, &safe_div, Label::kNear); | |
1598 // Retag inputs and go slow case. | |
1599 Integer32ToSmi(src2, src2); | |
1600 if (src1.is(rax)) { | |
1601 movq(src1, kScratchRegister); | |
1602 } | |
1603 jmp(on_not_smi_result); | |
1604 bind(&safe_div); | |
1605 | |
1606 // Sign extend eax into edx:eax. | |
1607 cdq(); | |
1608 idivl(src2); | |
1609 // Restore smi tags on inputs. | |
1610 Integer32ToSmi(src2, src2); | |
1611 if (src1.is(rax)) { | |
1612 movq(src1, kScratchRegister); | |
1613 } | |
1614 // Check for a negative zero result. If the result is zero, and the | |
1615 // dividend is negative, go slow to return a floating point negative zero. | |
1616 Label smi_result; | |
1617 testl(rdx, rdx); | |
1618 j(not_zero, &smi_result, Label::kNear); | |
1619 testq(src1, src1); | |
1620 j(negative, on_not_smi_result); | |
1621 bind(&smi_result); | |
1622 Integer32ToSmi(dst, rdx); | |
1623 } | |
1624 | |
1625 | |
1626 template <typename LabelType> | |
1627 void MacroAssembler::SmiShiftLogicalRightConstant( | |
1628 Register dst, Register src, int shift_value, LabelType* on_not_smi_result) { | |
1629 // Logic right shift interprets its result as an *unsigned* number. | |
1630 if (dst.is(src)) { | |
1631 UNIMPLEMENTED(); // Not used. | |
1632 } else { | |
1633 movq(dst, src); | |
1634 if (shift_value == 0) { | |
1635 testq(dst, dst); | |
1636 j(negative, on_not_smi_result); | |
1637 } | |
1638 shr(dst, Immediate(shift_value + kSmiShift)); | |
1639 shl(dst, Immediate(kSmiShift)); | |
1640 } | |
1641 } | |
1642 | |
1643 | |
1644 template <typename LabelType> | |
1645 void MacroAssembler::SmiShiftLogicalRight(Register dst, | |
1646 Register src1, | |
1647 Register src2, | |
1648 LabelType* on_not_smi_result) { | |
1649 ASSERT(!dst.is(kScratchRegister)); | |
1650 ASSERT(!src1.is(kScratchRegister)); | |
1651 ASSERT(!src2.is(kScratchRegister)); | |
1652 ASSERT(!dst.is(rcx)); | |
1653 // dst and src1 can be the same, because the one case that bails out | |
1654 // is a shift by 0, which leaves dst, and therefore src1, unchanged. | |
1655 if (src1.is(rcx) || src2.is(rcx)) { | |
1656 movq(kScratchRegister, rcx); | |
1657 } | |
1658 if (!dst.is(src1)) { | |
1659 movq(dst, src1); | |
1660 } | |
1661 SmiToInteger32(rcx, src2); | |
1662 orl(rcx, Immediate(kSmiShift)); | |
1663 shr_cl(dst); // Shift is rcx modulo 0x1f + 32. | |
1664 shl(dst, Immediate(kSmiShift)); | |
1665 testq(dst, dst); | |
1666 if (src1.is(rcx) || src2.is(rcx)) { | |
1667 Label positive_result; | |
1668 j(positive, &positive_result, Label::kNear); | |
1669 if (src1.is(rcx)) { | |
1670 movq(src1, kScratchRegister); | |
1671 } else { | |
1672 movq(src2, kScratchRegister); | |
1673 } | |
1674 jmp(on_not_smi_result); | |
1675 bind(&positive_result); | |
1676 } else { | |
1677 j(negative, on_not_smi_result); // src2 was zero and src1 negative. | |
1678 } | |
1679 } | |
1680 | |
1681 | |
1682 template <typename LabelType> | |
1683 void MacroAssembler::SelectNonSmi(Register dst, | |
1684 Register src1, | |
1685 Register src2, | |
1686 LabelType* on_not_smis) { | |
1687 ASSERT(!dst.is(kScratchRegister)); | |
1688 ASSERT(!src1.is(kScratchRegister)); | |
1689 ASSERT(!src2.is(kScratchRegister)); | |
1690 ASSERT(!dst.is(src1)); | |
1691 ASSERT(!dst.is(src2)); | |
1692 // Both operands must not be smis. | |
1693 #ifdef DEBUG | |
1694 if (allow_stub_calls()) { // Check contains a stub call. | |
1695 Condition not_both_smis = NegateCondition(CheckBothSmi(src1, src2)); | |
1696 Check(not_both_smis, "Both registers were smis in SelectNonSmi."); | |
1697 } | |
1698 #endif | |
1699 ASSERT_EQ(0, kSmiTag); | |
1700 ASSERT_EQ(0, Smi::FromInt(0)); | |
1701 movl(kScratchRegister, Immediate(kSmiTagMask)); | |
1702 and_(kScratchRegister, src1); | |
1703 testl(kScratchRegister, src2); | |
1704 // If non-zero then both are smis. | |
1705 j(not_zero, on_not_smis); | |
1706 | |
1707 // Exactly one operand is a smi. | |
1708 ASSERT_EQ(1, static_cast<int>(kSmiTagMask)); | |
1709 // kScratchRegister still holds src1 & kSmiTag, which is either zero or one. | |
1710 subq(kScratchRegister, Immediate(1)); | |
1711 // If src1 is a smi, then scratch register all 1s, else it is all 0s. | |
1712 movq(dst, src1); | |
1713 xor_(dst, src2); | |
1714 and_(dst, kScratchRegister); | |
1715 // If src1 is a smi, dst holds src1 ^ src2, else it is zero. | |
1716 xor_(dst, src1); | |
1717 // If src1 is a smi, dst is src2, else it is src1, i.e., the non-smi. | |
1718 } | |
1719 | |
1720 | |
1721 template <typename LabelType> | |
1722 void MacroAssembler::JumpIfSmi(Register src, LabelType* on_smi) { | |
1723 ASSERT_EQ(0, kSmiTag); | |
1724 Condition smi = CheckSmi(src); | |
1725 j(smi, on_smi); | |
1726 } | |
1727 | |
1728 | |
1729 template <typename LabelType> | |
1730 void MacroAssembler::JumpIfNotSmi(Register src, LabelType* on_not_smi) { | |
1731 Condition smi = CheckSmi(src); | |
1732 j(NegateCondition(smi), on_not_smi); | |
1733 } | |
1734 | |
1735 | |
1736 template <typename LabelType> | |
1737 void MacroAssembler::JumpUnlessNonNegativeSmi( | |
1738 Register src, LabelType* on_not_smi_or_negative) { | |
1739 Condition non_negative_smi = CheckNonNegativeSmi(src); | |
1740 j(NegateCondition(non_negative_smi), on_not_smi_or_negative); | |
1741 } | |
1742 | |
1743 | |
1744 template <typename LabelType> | |
1745 void MacroAssembler::JumpIfSmiEqualsConstant(Register src, | |
1746 Smi* constant, | |
1747 LabelType* on_equals) { | |
1748 SmiCompare(src, constant); | |
1749 j(equal, on_equals); | |
1750 } | |
1751 | |
1752 | |
1753 template <typename LabelType> | |
1754 void MacroAssembler::JumpIfNotValidSmiValue(Register src, | |
1755 LabelType* on_invalid) { | |
1756 Condition is_valid = CheckInteger32ValidSmiValue(src); | |
1757 j(NegateCondition(is_valid), on_invalid); | |
1758 } | |
1759 | |
1760 | |
1761 template <typename LabelType> | |
1762 void MacroAssembler::JumpIfUIntNotValidSmiValue(Register src, | |
1763 LabelType* on_invalid) { | |
1764 Condition is_valid = CheckUInteger32ValidSmiValue(src); | |
1765 j(NegateCondition(is_valid), on_invalid); | |
1766 } | |
1767 | |
1768 | |
1769 template <typename LabelType> | |
1770 void MacroAssembler::JumpIfNotBothSmi(Register src1, | |
1771 Register src2, | |
1772 LabelType* on_not_both_smi) { | |
1773 Condition both_smi = CheckBothSmi(src1, src2); | |
1774 j(NegateCondition(both_smi), on_not_both_smi); | |
1775 } | |
1776 | |
1777 | |
1778 template <typename LabelType> | |
1779 void MacroAssembler::JumpUnlessBothNonNegativeSmi(Register src1, | |
1780 Register src2, | |
1781 LabelType* on_not_both_smi) { | |
1782 Condition both_smi = CheckBothNonNegativeSmi(src1, src2); | |
1783 j(NegateCondition(both_smi), on_not_both_smi); | |
1784 } | |
1785 | |
1786 | |
1787 template <typename LabelType> | |
1788 void MacroAssembler::SmiOrIfSmis(Register dst, Register src1, Register src2, | |
1789 LabelType* on_not_smis) { | |
1790 if (dst.is(src1) || dst.is(src2)) { | |
1791 ASSERT(!src1.is(kScratchRegister)); | |
1792 ASSERT(!src2.is(kScratchRegister)); | |
1793 movq(kScratchRegister, src1); | |
1794 or_(kScratchRegister, src2); | |
1795 JumpIfNotSmi(kScratchRegister, on_not_smis); | |
1796 movq(dst, kScratchRegister); | |
1797 } else { | |
1798 movq(dst, src1); | |
1799 or_(dst, src2); | |
1800 JumpIfNotSmi(dst, on_not_smis); | |
1801 } | |
1802 } | |
1803 | |
1804 | |
1805 template <typename LabelType> | |
1806 void MacroAssembler::JumpIfNotString(Register object, | |
1807 Register object_map, | |
1808 LabelType* not_string) { | |
1809 Condition is_smi = CheckSmi(object); | |
1810 j(is_smi, not_string); | |
1811 CmpObjectType(object, FIRST_NONSTRING_TYPE, object_map); | |
1812 j(above_equal, not_string); | |
1813 } | |
1814 | |
1815 | |
1816 template <typename LabelType> | |
1817 void MacroAssembler::JumpIfNotBothSequentialAsciiStrings(Register first_object, | |
1818 Register second_object, | |
1819 Register scratch1, | |
1820 Register scratch2, | |
1821 LabelType* on_fail) { | |
1822 // Check that both objects are not smis. | |
1823 Condition either_smi = CheckEitherSmi(first_object, second_object); | |
1824 j(either_smi, on_fail); | |
1825 | |
1826 // Load instance type for both strings. | |
1827 movq(scratch1, FieldOperand(first_object, HeapObject::kMapOffset)); | |
1828 movq(scratch2, FieldOperand(second_object, HeapObject::kMapOffset)); | |
1829 movzxbl(scratch1, FieldOperand(scratch1, Map::kInstanceTypeOffset)); | |
1830 movzxbl(scratch2, FieldOperand(scratch2, Map::kInstanceTypeOffset)); | |
1831 | |
1832 // Check that both are flat ascii strings. | |
1833 ASSERT(kNotStringTag != 0); | |
1834 const int kFlatAsciiStringMask = | |
1835 kIsNotStringMask | kStringRepresentationMask | kStringEncodingMask; | |
1836 const int kFlatAsciiStringTag = ASCII_STRING_TYPE; | |
1837 | |
1838 andl(scratch1, Immediate(kFlatAsciiStringMask)); | |
1839 andl(scratch2, Immediate(kFlatAsciiStringMask)); | |
1840 // Interleave the bits to check both scratch1 and scratch2 in one test. | |
1841 ASSERT_EQ(0, kFlatAsciiStringMask & (kFlatAsciiStringMask << 3)); | |
1842 lea(scratch1, Operand(scratch1, scratch2, times_8, 0)); | |
1843 cmpl(scratch1, | |
1844 Immediate(kFlatAsciiStringTag + (kFlatAsciiStringTag << 3))); | |
1845 j(not_equal, on_fail); | |
1846 } | |
1847 | |
1848 | |
1849 template <typename LabelType> | |
1850 void MacroAssembler::JumpIfInstanceTypeIsNotSequentialAscii( | |
1851 Register instance_type, | |
1852 Register scratch, | |
1853 LabelType *failure) { | |
1854 if (!scratch.is(instance_type)) { | |
1855 movl(scratch, instance_type); | |
1856 } | |
1857 | |
1858 const int kFlatAsciiStringMask = | |
1859 kIsNotStringMask | kStringRepresentationMask | kStringEncodingMask; | |
1860 | |
1861 andl(scratch, Immediate(kFlatAsciiStringMask)); | |
1862 cmpl(scratch, Immediate(kStringTag | kSeqStringTag | kAsciiStringTag)); | |
1863 j(not_equal, failure); | |
1864 } | |
1865 | |
1866 | |
1867 template <typename LabelType> | |
1868 void MacroAssembler::JumpIfBothInstanceTypesAreNotSequentialAscii( | |
1869 Register first_object_instance_type, | |
1870 Register second_object_instance_type, | |
1871 Register scratch1, | |
1872 Register scratch2, | |
1873 LabelType* on_fail) { | |
1874 // Load instance type for both strings. | |
1875 movq(scratch1, first_object_instance_type); | |
1876 movq(scratch2, second_object_instance_type); | |
1877 | |
1878 // Check that both are flat ascii strings. | |
1879 ASSERT(kNotStringTag != 0); | |
1880 const int kFlatAsciiStringMask = | |
1881 kIsNotStringMask | kStringRepresentationMask | kStringEncodingMask; | |
1882 const int kFlatAsciiStringTag = ASCII_STRING_TYPE; | |
1883 | |
1884 andl(scratch1, Immediate(kFlatAsciiStringMask)); | |
1885 andl(scratch2, Immediate(kFlatAsciiStringMask)); | |
1886 // Interleave the bits to check both scratch1 and scratch2 in one test. | |
1887 ASSERT_EQ(0, kFlatAsciiStringMask & (kFlatAsciiStringMask << 3)); | |
1888 lea(scratch1, Operand(scratch1, scratch2, times_8, 0)); | |
1889 cmpl(scratch1, | |
1890 Immediate(kFlatAsciiStringTag + (kFlatAsciiStringTag << 3))); | |
1891 j(not_equal, on_fail); | |
1892 } | |
1893 | |
1894 | |
1895 template <typename LabelType> | |
1896 void MacroAssembler::InNewSpace(Register object, | |
1897 Register scratch, | |
1898 Condition cc, | |
1899 LabelType* branch) { | |
1900 if (Serializer::enabled()) { | |
1901 // Can't do arithmetic on external references if it might get serialized. | |
1902 // The mask isn't really an address. We load it as an external reference in | |
1903 // case the size of the new space is different between the snapshot maker | |
1904 // and the running system. | |
1905 if (scratch.is(object)) { | |
1906 movq(kScratchRegister, ExternalReference::new_space_mask(isolate())); | |
1907 and_(scratch, kScratchRegister); | |
1908 } else { | |
1909 movq(scratch, ExternalReference::new_space_mask(isolate())); | |
1910 and_(scratch, object); | |
1911 } | |
1912 movq(kScratchRegister, ExternalReference::new_space_start(isolate())); | |
1913 cmpq(scratch, kScratchRegister); | |
1914 j(cc, branch); | |
1915 } else { | |
1916 ASSERT(is_int32(static_cast<int64_t>(HEAP->NewSpaceMask()))); | |
1917 intptr_t new_space_start = | |
1918 reinterpret_cast<intptr_t>(HEAP->NewSpaceStart()); | |
1919 movq(kScratchRegister, -new_space_start, RelocInfo::NONE); | |
1920 if (scratch.is(object)) { | |
1921 addq(scratch, kScratchRegister); | |
1922 } else { | |
1923 lea(scratch, Operand(object, kScratchRegister, times_1, 0)); | |
1924 } | |
1925 and_(scratch, Immediate(static_cast<int32_t>(HEAP->NewSpaceMask()))); | |
1926 j(cc, branch); | |
1927 } | |
1928 } | |
1929 | |
1930 | |
1931 template <typename LabelType> | |
1932 void MacroAssembler::InvokePrologue(const ParameterCount& expected, | |
1933 const ParameterCount& actual, | |
1934 Handle<Code> code_constant, | |
1935 Register code_register, | |
1936 LabelType* done, | |
1937 InvokeFlag flag, | |
1938 const CallWrapper& call_wrapper) { | |
1939 bool definitely_matches = false; | |
1940 Label invoke; | |
1941 if (expected.is_immediate()) { | |
1942 ASSERT(actual.is_immediate()); | |
1943 if (expected.immediate() == actual.immediate()) { | |
1944 definitely_matches = true; | |
1945 } else { | |
1946 Set(rax, actual.immediate()); | |
1947 if (expected.immediate() == | |
1948 SharedFunctionInfo::kDontAdaptArgumentsSentinel) { | |
1949 // Don't worry about adapting arguments for built-ins that | |
1950 // don't want that done. Skip adaption code by making it look | |
1951 // like we have a match between expected and actual number of | |
1952 // arguments. | |
1953 definitely_matches = true; | |
1954 } else { | |
1955 Set(rbx, expected.immediate()); | |
1956 } | |
1957 } | |
1958 } else { | |
1959 if (actual.is_immediate()) { | |
1960 // Expected is in register, actual is immediate. This is the | |
1961 // case when we invoke function values without going through the | |
1962 // IC mechanism. | |
1963 cmpq(expected.reg(), Immediate(actual.immediate())); | |
1964 j(equal, &invoke, Label::kNear); | |
1965 ASSERT(expected.reg().is(rbx)); | |
1966 Set(rax, actual.immediate()); | |
1967 } else if (!expected.reg().is(actual.reg())) { | |
1968 // Both expected and actual are in (different) registers. This | |
1969 // is the case when we invoke functions using call and apply. | |
1970 cmpq(expected.reg(), actual.reg()); | |
1971 j(equal, &invoke, Label::kNear); | |
1972 ASSERT(actual.reg().is(rax)); | |
1973 ASSERT(expected.reg().is(rbx)); | |
1974 } | |
1975 } | |
1976 | |
1977 if (!definitely_matches) { | |
1978 Handle<Code> adaptor = isolate()->builtins()->ArgumentsAdaptorTrampoline(); | |
1979 if (!code_constant.is_null()) { | |
1980 movq(rdx, code_constant, RelocInfo::EMBEDDED_OBJECT); | |
1981 addq(rdx, Immediate(Code::kHeaderSize - kHeapObjectTag)); | |
1982 } else if (!code_register.is(rdx)) { | |
1983 movq(rdx, code_register); | |
1984 } | |
1985 | |
1986 if (flag == CALL_FUNCTION) { | |
1987 call_wrapper.BeforeCall(CallSize(adaptor)); | |
1988 Call(adaptor, RelocInfo::CODE_TARGET); | |
1989 call_wrapper.AfterCall(); | |
1990 jmp(done); | |
1991 } else { | |
1992 Jump(adaptor, RelocInfo::CODE_TARGET); | |
1993 } | |
1994 bind(&invoke); | |
1995 } | |
1996 } | |
1997 | |
1998 | |
1999 } } // namespace v8::internal | 1260 } } // namespace v8::internal |
2000 | 1261 |
2001 #endif // V8_X64_MACRO_ASSEMBLER_X64_H_ | 1262 #endif // V8_X64_MACRO_ASSEMBLER_X64_H_ |
OLD | NEW |