| Index: src/x64/macro-assembler-x64.h
|
| ===================================================================
|
| --- src/x64/macro-assembler-x64.h (revision 7948)
|
| +++ src/x64/macro-assembler-x64.h (working copy)
|
| @@ -29,6 +29,7 @@
|
| #define V8_X64_MACRO_ASSEMBLER_X64_H_
|
|
|
| #include "assembler.h"
|
| +#include "v8globals.h"
|
|
|
| namespace v8 {
|
| namespace internal {
|
| @@ -44,6 +45,7 @@
|
| RESULT_CONTAINS_TOP = 1 << 1
|
| };
|
|
|
| +
|
| // Default scratch register used by MacroAssembler (and other code that needs
|
| // a spare register). The register isn't callee save, and not used by the
|
| // function calling convention.
|
| @@ -151,11 +153,11 @@
|
| // Check if object is in new space. The condition cc can be equal or
|
| // not_equal. If it is equal a jump will be done if the object is on new
|
| // space. The register scratch can be object itself, but it will be clobbered.
|
| - template <typename LabelType>
|
| void InNewSpace(Register object,
|
| Register scratch,
|
| Condition cc,
|
| - LabelType* branch);
|
| + Label* branch,
|
| + Label::Distance near_jump = Label::kFar);
|
|
|
| // For page containing |object| mark region covering [object+offset]
|
| // dirty. |object| is the object being stored into, |value| is the
|
| @@ -335,11 +337,11 @@
|
| // If either argument is not a smi, jump to on_not_smis and retain
|
| // the original values of source registers. The destination register
|
| // may be changed if it's not one of the source registers.
|
| - template <typename LabelType>
|
| void SmiOrIfSmis(Register dst,
|
| Register src1,
|
| Register src2,
|
| - LabelType* on_not_smis);
|
| + Label* on_not_smis,
|
| + Label::Distance near_jump = Label::kFar);
|
|
|
|
|
| // Simple comparison of smis. Both sides must be known smis to use these,
|
| @@ -397,42 +399,45 @@
|
| // above with a conditional jump.
|
|
|
| // Jump if the value cannot be represented by a smi.
|
| - template <typename LabelType>
|
| - void JumpIfNotValidSmiValue(Register src, LabelType* on_invalid);
|
| + void JumpIfNotValidSmiValue(Register src, Label* on_invalid,
|
| + Label::Distance near_jump = Label::kFar);
|
|
|
| // Jump if the unsigned integer value cannot be represented by a smi.
|
| - template <typename LabelType>
|
| - void JumpIfUIntNotValidSmiValue(Register src, LabelType* on_invalid);
|
| + void JumpIfUIntNotValidSmiValue(Register src, Label* on_invalid,
|
| + Label::Distance near_jump = Label::kFar);
|
|
|
| // Jump to label if the value is a tagged smi.
|
| - template <typename LabelType>
|
| - void JumpIfSmi(Register src, LabelType* on_smi);
|
| + void JumpIfSmi(Register src,
|
| + Label* on_smi,
|
| + Label::Distance near_jump = Label::kFar);
|
|
|
| // Jump to label if the value is not a tagged smi.
|
| - template <typename LabelType>
|
| - void JumpIfNotSmi(Register src, LabelType* on_not_smi);
|
| + void JumpIfNotSmi(Register src,
|
| + Label* on_not_smi,
|
| + Label::Distance near_jump = Label::kFar);
|
|
|
| // Jump to label if the value is not a non-negative tagged smi.
|
| - template <typename LabelType>
|
| - void JumpUnlessNonNegativeSmi(Register src, LabelType* on_not_smi);
|
| + void JumpUnlessNonNegativeSmi(Register src,
|
| + Label* on_not_smi,
|
| + Label::Distance near_jump = Label::kFar);
|
|
|
| // Jump to label if the value, which must be a tagged smi, has value equal
|
| // to the constant.
|
| - template <typename LabelType>
|
| void JumpIfSmiEqualsConstant(Register src,
|
| Smi* constant,
|
| - LabelType* on_equals);
|
| + Label* on_equals,
|
| + Label::Distance near_jump = Label::kFar);
|
|
|
| // Jump if either or both register are not smi values.
|
| - template <typename LabelType>
|
| void JumpIfNotBothSmi(Register src1,
|
| Register src2,
|
| - LabelType* on_not_both_smi);
|
| + Label* on_not_both_smi,
|
| + Label::Distance near_jump = Label::kFar);
|
|
|
| // Jump if either or both register are not non-negative smi values.
|
| - template <typename LabelType>
|
| void JumpUnlessBothNonNegativeSmi(Register src1, Register src2,
|
| - LabelType* on_not_both_smi);
|
| + Label* on_not_both_smi,
|
| + Label::Distance near_jump = Label::kFar);
|
|
|
| // Operations on tagged smi values.
|
|
|
| @@ -442,11 +447,11 @@
|
| // Optimistically adds an integer constant to a supposed smi.
|
| // If the src is not a smi, or the result is not a smi, jump to
|
| // the label.
|
| - template <typename LabelType>
|
| void SmiTryAddConstant(Register dst,
|
| Register src,
|
| Smi* constant,
|
| - LabelType* on_not_smi_result);
|
| + Label* on_not_smi_result,
|
| + Label::Distance near_jump = Label::kFar);
|
|
|
| // Add an integer constant to a tagged smi, giving a tagged smi as result.
|
| // No overflow testing on the result is done.
|
| @@ -458,11 +463,11 @@
|
|
|
| // Add an integer constant to a tagged smi, giving a tagged smi as result,
|
| // or jumping to a label if the result cannot be represented by a smi.
|
| - template <typename LabelType>
|
| void SmiAddConstant(Register dst,
|
| Register src,
|
| Smi* constant,
|
| - LabelType* on_not_smi_result);
|
| + Label* on_not_smi_result,
|
| + Label::Distance near_jump = Label::kFar);
|
|
|
| // Subtract an integer constant from a tagged smi, giving a tagged smi as
|
| // result. No testing on the result is done. Sets the N and Z flags
|
| @@ -471,32 +476,32 @@
|
|
|
| // Subtract an integer constant from a tagged smi, giving a tagged smi as
|
| // result, or jumping to a label if the result cannot be represented by a smi.
|
| - template <typename LabelType>
|
| void SmiSubConstant(Register dst,
|
| Register src,
|
| Smi* constant,
|
| - LabelType* on_not_smi_result);
|
| + Label* on_not_smi_result,
|
| + Label::Distance near_jump = Label::kFar);
|
|
|
| // Negating a smi can give a negative zero or too large positive value.
|
| // NOTICE: This operation jumps on success, not failure!
|
| - template <typename LabelType>
|
| void SmiNeg(Register dst,
|
| Register src,
|
| - LabelType* on_smi_result);
|
| + Label* on_smi_result,
|
| + Label::Distance near_jump = Label::kFar);
|
|
|
| // Adds smi values and return the result as a smi.
|
| // If dst is src1, then src1 will be destroyed, even if
|
| // the operation is unsuccessful.
|
| - template <typename LabelType>
|
| void SmiAdd(Register dst,
|
| Register src1,
|
| Register src2,
|
| - LabelType* on_not_smi_result);
|
| - template <typename LabelType>
|
| + Label* on_not_smi_result,
|
| + Label::Distance near_jump = Label::kFar);
|
| void SmiAdd(Register dst,
|
| Register src1,
|
| const Operand& src2,
|
| - LabelType* on_not_smi_result);
|
| + Label* on_not_smi_result,
|
| + Label::Distance near_jump = Label::kFar);
|
|
|
| void SmiAdd(Register dst,
|
| Register src1,
|
| @@ -505,21 +510,21 @@
|
| // Subtracts smi values and return the result as a smi.
|
| // If dst is src1, then src1 will be destroyed, even if
|
| // the operation is unsuccessful.
|
| - template <typename LabelType>
|
| void SmiSub(Register dst,
|
| Register src1,
|
| Register src2,
|
| - LabelType* on_not_smi_result);
|
| + Label* on_not_smi_result,
|
| + Label::Distance near_jump = Label::kFar);
|
|
|
| void SmiSub(Register dst,
|
| Register src1,
|
| Register src2);
|
|
|
| - template <typename LabelType>
|
| void SmiSub(Register dst,
|
| Register src1,
|
| const Operand& src2,
|
| - LabelType* on_not_smi_result);
|
| + Label* on_not_smi_result,
|
| + Label::Distance near_jump = Label::kFar);
|
|
|
| void SmiSub(Register dst,
|
| Register src1,
|
| @@ -529,27 +534,27 @@
|
| // if possible.
|
| // If dst is src1, then src1 will be destroyed, even if
|
| // the operation is unsuccessful.
|
| - template <typename LabelType>
|
| void SmiMul(Register dst,
|
| Register src1,
|
| Register src2,
|
| - LabelType* on_not_smi_result);
|
| + Label* on_not_smi_result,
|
| + Label::Distance near_jump = Label::kFar);
|
|
|
| // Divides one smi by another and returns the quotient.
|
| // Clobbers rax and rdx registers.
|
| - template <typename LabelType>
|
| void SmiDiv(Register dst,
|
| Register src1,
|
| Register src2,
|
| - LabelType* on_not_smi_result);
|
| + Label* on_not_smi_result,
|
| + Label::Distance near_jump = Label::kFar);
|
|
|
| // Divides one smi by another and returns the remainder.
|
| // Clobbers rax and rdx registers.
|
| - template <typename LabelType>
|
| void SmiMod(Register dst,
|
| Register src1,
|
| Register src2,
|
| - LabelType* on_not_smi_result);
|
| + Label* on_not_smi_result,
|
| + Label::Distance near_jump = Label::kFar);
|
|
|
| // Bitwise operations.
|
| void SmiNot(Register dst, Register src);
|
| @@ -563,11 +568,11 @@
|
| void SmiShiftLeftConstant(Register dst,
|
| Register src,
|
| int shift_value);
|
| - template <typename LabelType>
|
| void SmiShiftLogicalRightConstant(Register dst,
|
| Register src,
|
| int shift_value,
|
| - LabelType* on_not_smi_result);
|
| + Label* on_not_smi_result,
|
| + Label::Distance near_jump = Label::kFar);
|
| void SmiShiftArithmeticRightConstant(Register dst,
|
| Register src,
|
| int shift_value);
|
| @@ -580,11 +585,11 @@
|
| // Shifts a smi value to the right, shifting in zero bits at the top, and
|
| // returns the unsigned intepretation of the result if that is a smi.
|
| // Uses and clobbers rcx, so dst may not be rcx.
|
| - template <typename LabelType>
|
| void SmiShiftLogicalRight(Register dst,
|
| Register src1,
|
| Register src2,
|
| - LabelType* on_not_smi_result);
|
| + Label* on_not_smi_result,
|
| + Label::Distance near_jump = Label::kFar);
|
| // Shifts a smi value to the right, sign extending the top, and
|
| // returns the signed intepretation of the result. That will always
|
| // be a valid smi value, since it's numerically smaller than the
|
| @@ -598,11 +603,11 @@
|
|
|
| // Select the non-smi register of two registers where exactly one is a
|
| // smi. If neither are smis, jump to the failure label.
|
| - template <typename LabelType>
|
| void SelectNonSmi(Register dst,
|
| Register src1,
|
| Register src2,
|
| - LabelType* on_not_smis);
|
| + Label* on_not_smis,
|
| + Label::Distance near_jump = Label::kFar);
|
|
|
| // Converts, if necessary, a smi to a combination of number and
|
| // multiplier to be used as a scaled index.
|
| @@ -638,35 +643,36 @@
|
| // String macros.
|
|
|
| // If object is a string, its map is loaded into object_map.
|
| - template <typename LabelType>
|
| void JumpIfNotString(Register object,
|
| Register object_map,
|
| - LabelType* not_string);
|
| + Label* not_string,
|
| + Label::Distance near_jump = Label::kFar);
|
|
|
|
|
| - template <typename LabelType>
|
| - void JumpIfNotBothSequentialAsciiStrings(Register first_object,
|
| - Register second_object,
|
| - Register scratch1,
|
| - Register scratch2,
|
| - LabelType* on_not_both_flat_ascii);
|
| + void JumpIfNotBothSequentialAsciiStrings(
|
| + Register first_object,
|
| + Register second_object,
|
| + Register scratch1,
|
| + Register scratch2,
|
| + Label* on_not_both_flat_ascii,
|
| + Label::Distance near_jump = Label::kFar);
|
|
|
| // Check whether the instance type represents a flat ascii string. Jump to the
|
| // label if not. If the instance type can be scratched specify same register
|
| // for both instance type and scratch.
|
| - template <typename LabelType>
|
| void JumpIfInstanceTypeIsNotSequentialAscii(
|
| Register instance_type,
|
| Register scratch,
|
| - LabelType *on_not_flat_ascii_string);
|
| + Label*on_not_flat_ascii_string,
|
| + Label::Distance near_jump = Label::kFar);
|
|
|
| - template <typename LabelType>
|
| void JumpIfBothInstanceTypesAreNotSequentialAscii(
|
| Register first_object_instance_type,
|
| Register second_object_instance_type,
|
| Register scratch1,
|
| Register scratch2,
|
| - LabelType* on_fail);
|
| + Label* on_fail,
|
| + Label::Distance near_jump = Label::kFar);
|
|
|
| // ---------------------------------------------------------------------------
|
| // Macro instructions.
|
| @@ -754,8 +760,16 @@
|
| void CheckMap(Register obj,
|
| Handle<Map> map,
|
| Label* fail,
|
| - bool is_heap_object);
|
| + SmiCheckType smi_check_type);
|
|
|
| + // Check if the map of an object is equal to a specified map and branch to a
|
| + // specified target if equal. Skip the smi check if not required (object is
|
| + // known to be a heap object)
|
| + void DispatchMap(Register obj,
|
| + Handle<Map> map,
|
| + Handle<Code> success,
|
| + SmiCheckType smi_check_type);
|
| +
|
| // Check if the object in register heap_object is a string. Afterwards the
|
| // register map contains the object map and the register instance_type
|
| // contains the instance_type. The registers map and instance_type can be the
|
| @@ -770,6 +784,13 @@
|
| // jcc instructions (je, ja, jae, jb, jbe, je, and jz).
|
| void FCmp();
|
|
|
| + void ClampUint8(Register reg);
|
| +
|
| + void ClampDoubleToUint8(XMMRegister input_reg,
|
| + XMMRegister temp_xmm_reg,
|
| + Register result_reg,
|
| + Register temp_reg);
|
| +
|
| // Abort execution if argument is not a number. Used in debug code.
|
| void AbortIfNotNumber(Register object);
|
|
|
| @@ -1112,6 +1133,7 @@
|
| // rax, rcx, rdx, rbx, rsi, rdi, r8, r9, r11, r14, r15.
|
| static int kSafepointPushRegisterIndices[Register::kNumRegisters];
|
| static const int kNumSafepointSavedRegisters = 11;
|
| + static const int kSmiShift = kSmiTagSize + kSmiShiftSize;
|
|
|
| bool generating_stub_;
|
| bool allow_stub_calls_;
|
| @@ -1128,14 +1150,14 @@
|
| Handle<Object> code_object_;
|
|
|
| // Helper functions for generating invokes.
|
| - template <typename LabelType>
|
| void InvokePrologue(const ParameterCount& expected,
|
| const ParameterCount& actual,
|
| Handle<Code> code_constant,
|
| Register code_register,
|
| - LabelType* done,
|
| + Label* done,
|
| InvokeFlag flag,
|
| - const CallWrapper& call_wrapper);
|
| + const CallWrapper& call_wrapper,
|
| + Label::Distance near_jump = Label::kFar);
|
|
|
| // Activation support.
|
| void EnterFrame(StackFrame::Type type);
|
| @@ -1261,751 +1283,6 @@
|
| #define ACCESS_MASM(masm) masm->
|
| #endif
|
|
|
| -// -----------------------------------------------------------------------------
|
| -// Template implementations.
|
| -
|
| -static int kSmiShift = kSmiTagSize + kSmiShiftSize;
|
| -
|
| -
|
| -template <typename LabelType>
|
| -void MacroAssembler::SmiNeg(Register dst,
|
| - Register src,
|
| - LabelType* on_smi_result) {
|
| - if (dst.is(src)) {
|
| - ASSERT(!dst.is(kScratchRegister));
|
| - movq(kScratchRegister, src);
|
| - neg(dst); // Low 32 bits are retained as zero by negation.
|
| - // Test if result is zero or Smi::kMinValue.
|
| - cmpq(dst, kScratchRegister);
|
| - j(not_equal, on_smi_result);
|
| - movq(src, kScratchRegister);
|
| - } else {
|
| - movq(dst, src);
|
| - neg(dst);
|
| - cmpq(dst, src);
|
| - // If the result is zero or Smi::kMinValue, negation failed to create a smi.
|
| - j(not_equal, on_smi_result);
|
| - }
|
| -}
|
| -
|
| -
|
| -template <typename LabelType>
|
| -void MacroAssembler::SmiAdd(Register dst,
|
| - Register src1,
|
| - Register src2,
|
| - LabelType* on_not_smi_result) {
|
| - ASSERT_NOT_NULL(on_not_smi_result);
|
| - ASSERT(!dst.is(src2));
|
| - if (dst.is(src1)) {
|
| - movq(kScratchRegister, src1);
|
| - addq(kScratchRegister, src2);
|
| - j(overflow, on_not_smi_result);
|
| - movq(dst, kScratchRegister);
|
| - } else {
|
| - movq(dst, src1);
|
| - addq(dst, src2);
|
| - j(overflow, on_not_smi_result);
|
| - }
|
| -}
|
| -
|
| -
|
| -template <typename LabelType>
|
| -void MacroAssembler::SmiAdd(Register dst,
|
| - Register src1,
|
| - const Operand& src2,
|
| - LabelType* on_not_smi_result) {
|
| - ASSERT_NOT_NULL(on_not_smi_result);
|
| - if (dst.is(src1)) {
|
| - movq(kScratchRegister, src1);
|
| - addq(kScratchRegister, src2);
|
| - j(overflow, on_not_smi_result);
|
| - movq(dst, kScratchRegister);
|
| - } else {
|
| - ASSERT(!src2.AddressUsesRegister(dst));
|
| - movq(dst, src1);
|
| - addq(dst, src2);
|
| - j(overflow, on_not_smi_result);
|
| - }
|
| -}
|
| -
|
| -
|
| -template <typename LabelType>
|
| -void MacroAssembler::SmiSub(Register dst,
|
| - Register src1,
|
| - Register src2,
|
| - LabelType* on_not_smi_result) {
|
| - ASSERT_NOT_NULL(on_not_smi_result);
|
| - ASSERT(!dst.is(src2));
|
| - if (dst.is(src1)) {
|
| - cmpq(dst, src2);
|
| - j(overflow, on_not_smi_result);
|
| - subq(dst, src2);
|
| - } else {
|
| - movq(dst, src1);
|
| - subq(dst, src2);
|
| - j(overflow, on_not_smi_result);
|
| - }
|
| -}
|
| -
|
| -
|
| -template <typename LabelType>
|
| -void MacroAssembler::SmiSub(Register dst,
|
| - Register src1,
|
| - const Operand& src2,
|
| - LabelType* on_not_smi_result) {
|
| - ASSERT_NOT_NULL(on_not_smi_result);
|
| - if (dst.is(src1)) {
|
| - movq(kScratchRegister, src2);
|
| - cmpq(src1, kScratchRegister);
|
| - j(overflow, on_not_smi_result);
|
| - subq(src1, kScratchRegister);
|
| - } else {
|
| - movq(dst, src1);
|
| - subq(dst, src2);
|
| - j(overflow, on_not_smi_result);
|
| - }
|
| -}
|
| -
|
| -
|
| -template <typename LabelType>
|
| -void MacroAssembler::SmiMul(Register dst,
|
| - Register src1,
|
| - Register src2,
|
| - LabelType* on_not_smi_result) {
|
| - ASSERT(!dst.is(src2));
|
| - ASSERT(!dst.is(kScratchRegister));
|
| - ASSERT(!src1.is(kScratchRegister));
|
| - ASSERT(!src2.is(kScratchRegister));
|
| -
|
| - if (dst.is(src1)) {
|
| - NearLabel failure, zero_correct_result;
|
| - movq(kScratchRegister, src1); // Create backup for later testing.
|
| - SmiToInteger64(dst, src1);
|
| - imul(dst, src2);
|
| - j(overflow, &failure);
|
| -
|
| - // Check for negative zero result. If product is zero, and one
|
| - // argument is negative, go to slow case.
|
| - NearLabel correct_result;
|
| - testq(dst, dst);
|
| - j(not_zero, &correct_result);
|
| -
|
| - movq(dst, kScratchRegister);
|
| - xor_(dst, src2);
|
| - j(positive, &zero_correct_result); // Result was positive zero.
|
| -
|
| - bind(&failure); // Reused failure exit, restores src1.
|
| - movq(src1, kScratchRegister);
|
| - jmp(on_not_smi_result);
|
| -
|
| - bind(&zero_correct_result);
|
| - Set(dst, 0);
|
| -
|
| - bind(&correct_result);
|
| - } else {
|
| - SmiToInteger64(dst, src1);
|
| - imul(dst, src2);
|
| - j(overflow, on_not_smi_result);
|
| - // Check for negative zero result. If product is zero, and one
|
| - // argument is negative, go to slow case.
|
| - NearLabel correct_result;
|
| - testq(dst, dst);
|
| - j(not_zero, &correct_result);
|
| - // One of src1 and src2 is zero, the check whether the other is
|
| - // negative.
|
| - movq(kScratchRegister, src1);
|
| - xor_(kScratchRegister, src2);
|
| - j(negative, on_not_smi_result);
|
| - bind(&correct_result);
|
| - }
|
| -}
|
| -
|
| -
|
| -template <typename LabelType>
|
| -void MacroAssembler::SmiTryAddConstant(Register dst,
|
| - Register src,
|
| - Smi* constant,
|
| - LabelType* on_not_smi_result) {
|
| - // Does not assume that src is a smi.
|
| - ASSERT_EQ(static_cast<int>(1), static_cast<int>(kSmiTagMask));
|
| - ASSERT_EQ(0, kSmiTag);
|
| - ASSERT(!dst.is(kScratchRegister));
|
| - ASSERT(!src.is(kScratchRegister));
|
| -
|
| - JumpIfNotSmi(src, on_not_smi_result);
|
| - Register tmp = (dst.is(src) ? kScratchRegister : dst);
|
| - LoadSmiConstant(tmp, constant);
|
| - addq(tmp, src);
|
| - j(overflow, on_not_smi_result);
|
| - if (dst.is(src)) {
|
| - movq(dst, tmp);
|
| - }
|
| -}
|
| -
|
| -
|
| -template <typename LabelType>
|
| -void MacroAssembler::SmiAddConstant(Register dst,
|
| - Register src,
|
| - Smi* constant,
|
| - LabelType* on_not_smi_result) {
|
| - if (constant->value() == 0) {
|
| - if (!dst.is(src)) {
|
| - movq(dst, src);
|
| - }
|
| - } else if (dst.is(src)) {
|
| - ASSERT(!dst.is(kScratchRegister));
|
| -
|
| - LoadSmiConstant(kScratchRegister, constant);
|
| - addq(kScratchRegister, src);
|
| - j(overflow, on_not_smi_result);
|
| - movq(dst, kScratchRegister);
|
| - } else {
|
| - LoadSmiConstant(dst, constant);
|
| - addq(dst, src);
|
| - j(overflow, on_not_smi_result);
|
| - }
|
| -}
|
| -
|
| -
|
| -template <typename LabelType>
|
| -void MacroAssembler::SmiSubConstant(Register dst,
|
| - Register src,
|
| - Smi* constant,
|
| - LabelType* on_not_smi_result) {
|
| - if (constant->value() == 0) {
|
| - if (!dst.is(src)) {
|
| - movq(dst, src);
|
| - }
|
| - } else if (dst.is(src)) {
|
| - ASSERT(!dst.is(kScratchRegister));
|
| - if (constant->value() == Smi::kMinValue) {
|
| - // Subtracting min-value from any non-negative value will overflow.
|
| - // We test the non-negativeness before doing the subtraction.
|
| - testq(src, src);
|
| - j(not_sign, on_not_smi_result);
|
| - LoadSmiConstant(kScratchRegister, constant);
|
| - subq(dst, kScratchRegister);
|
| - } else {
|
| - // Subtract by adding the negation.
|
| - LoadSmiConstant(kScratchRegister, Smi::FromInt(-constant->value()));
|
| - addq(kScratchRegister, dst);
|
| - j(overflow, on_not_smi_result);
|
| - movq(dst, kScratchRegister);
|
| - }
|
| - } else {
|
| - if (constant->value() == Smi::kMinValue) {
|
| - // Subtracting min-value from any non-negative value will overflow.
|
| - // We test the non-negativeness before doing the subtraction.
|
| - testq(src, src);
|
| - j(not_sign, on_not_smi_result);
|
| - LoadSmiConstant(dst, constant);
|
| - // Adding and subtracting the min-value gives the same result, it only
|
| - // differs on the overflow bit, which we don't check here.
|
| - addq(dst, src);
|
| - } else {
|
| - // Subtract by adding the negation.
|
| - LoadSmiConstant(dst, Smi::FromInt(-(constant->value())));
|
| - addq(dst, src);
|
| - j(overflow, on_not_smi_result);
|
| - }
|
| - }
|
| -}
|
| -
|
| -
|
| -template <typename LabelType>
|
| -void MacroAssembler::SmiDiv(Register dst,
|
| - Register src1,
|
| - Register src2,
|
| - LabelType* on_not_smi_result) {
|
| - ASSERT(!src1.is(kScratchRegister));
|
| - ASSERT(!src2.is(kScratchRegister));
|
| - ASSERT(!dst.is(kScratchRegister));
|
| - ASSERT(!src2.is(rax));
|
| - ASSERT(!src2.is(rdx));
|
| - ASSERT(!src1.is(rdx));
|
| -
|
| - // Check for 0 divisor (result is +/-Infinity).
|
| - NearLabel positive_divisor;
|
| - testq(src2, src2);
|
| - j(zero, on_not_smi_result);
|
| -
|
| - if (src1.is(rax)) {
|
| - movq(kScratchRegister, src1);
|
| - }
|
| - SmiToInteger32(rax, src1);
|
| - // We need to rule out dividing Smi::kMinValue by -1, since that would
|
| - // overflow in idiv and raise an exception.
|
| - // We combine this with negative zero test (negative zero only happens
|
| - // when dividing zero by a negative number).
|
| -
|
| - // We overshoot a little and go to slow case if we divide min-value
|
| - // by any negative value, not just -1.
|
| - NearLabel safe_div;
|
| - testl(rax, Immediate(0x7fffffff));
|
| - j(not_zero, &safe_div);
|
| - testq(src2, src2);
|
| - if (src1.is(rax)) {
|
| - j(positive, &safe_div);
|
| - movq(src1, kScratchRegister);
|
| - jmp(on_not_smi_result);
|
| - } else {
|
| - j(negative, on_not_smi_result);
|
| - }
|
| - bind(&safe_div);
|
| -
|
| - SmiToInteger32(src2, src2);
|
| - // Sign extend src1 into edx:eax.
|
| - cdq();
|
| - idivl(src2);
|
| - Integer32ToSmi(src2, src2);
|
| - // Check that the remainder is zero.
|
| - testl(rdx, rdx);
|
| - if (src1.is(rax)) {
|
| - NearLabel smi_result;
|
| - j(zero, &smi_result);
|
| - movq(src1, kScratchRegister);
|
| - jmp(on_not_smi_result);
|
| - bind(&smi_result);
|
| - } else {
|
| - j(not_zero, on_not_smi_result);
|
| - }
|
| - if (!dst.is(src1) && src1.is(rax)) {
|
| - movq(src1, kScratchRegister);
|
| - }
|
| - Integer32ToSmi(dst, rax);
|
| -}
|
| -
|
| -
|
| -template <typename LabelType>
|
| -void MacroAssembler::SmiMod(Register dst,
|
| - Register src1,
|
| - Register src2,
|
| - LabelType* on_not_smi_result) {
|
| - ASSERT(!dst.is(kScratchRegister));
|
| - ASSERT(!src1.is(kScratchRegister));
|
| - ASSERT(!src2.is(kScratchRegister));
|
| - ASSERT(!src2.is(rax));
|
| - ASSERT(!src2.is(rdx));
|
| - ASSERT(!src1.is(rdx));
|
| - ASSERT(!src1.is(src2));
|
| -
|
| - testq(src2, src2);
|
| - j(zero, on_not_smi_result);
|
| -
|
| - if (src1.is(rax)) {
|
| - movq(kScratchRegister, src1);
|
| - }
|
| - SmiToInteger32(rax, src1);
|
| - SmiToInteger32(src2, src2);
|
| -
|
| - // Test for the edge case of dividing Smi::kMinValue by -1 (will overflow).
|
| - NearLabel safe_div;
|
| - cmpl(rax, Immediate(Smi::kMinValue));
|
| - j(not_equal, &safe_div);
|
| - cmpl(src2, Immediate(-1));
|
| - j(not_equal, &safe_div);
|
| - // Retag inputs and go slow case.
|
| - Integer32ToSmi(src2, src2);
|
| - if (src1.is(rax)) {
|
| - movq(src1, kScratchRegister);
|
| - }
|
| - jmp(on_not_smi_result);
|
| - bind(&safe_div);
|
| -
|
| - // Sign extend eax into edx:eax.
|
| - cdq();
|
| - idivl(src2);
|
| - // Restore smi tags on inputs.
|
| - Integer32ToSmi(src2, src2);
|
| - if (src1.is(rax)) {
|
| - movq(src1, kScratchRegister);
|
| - }
|
| - // Check for a negative zero result. If the result is zero, and the
|
| - // dividend is negative, go slow to return a floating point negative zero.
|
| - NearLabel smi_result;
|
| - testl(rdx, rdx);
|
| - j(not_zero, &smi_result);
|
| - testq(src1, src1);
|
| - j(negative, on_not_smi_result);
|
| - bind(&smi_result);
|
| - Integer32ToSmi(dst, rdx);
|
| -}
|
| -
|
| -
|
| -template <typename LabelType>
|
| -void MacroAssembler::SmiShiftLogicalRightConstant(
|
| - Register dst, Register src, int shift_value, LabelType* on_not_smi_result) {
|
| - // Logic right shift interprets its result as an *unsigned* number.
|
| - if (dst.is(src)) {
|
| - UNIMPLEMENTED(); // Not used.
|
| - } else {
|
| - movq(dst, src);
|
| - if (shift_value == 0) {
|
| - testq(dst, dst);
|
| - j(negative, on_not_smi_result);
|
| - }
|
| - shr(dst, Immediate(shift_value + kSmiShift));
|
| - shl(dst, Immediate(kSmiShift));
|
| - }
|
| -}
|
| -
|
| -
|
| -template <typename LabelType>
|
| -void MacroAssembler::SmiShiftLogicalRight(Register dst,
|
| - Register src1,
|
| - Register src2,
|
| - LabelType* on_not_smi_result) {
|
| - ASSERT(!dst.is(kScratchRegister));
|
| - ASSERT(!src1.is(kScratchRegister));
|
| - ASSERT(!src2.is(kScratchRegister));
|
| - ASSERT(!dst.is(rcx));
|
| - // dst and src1 can be the same, because the one case that bails out
|
| - // is a shift by 0, which leaves dst, and therefore src1, unchanged.
|
| - NearLabel result_ok;
|
| - if (src1.is(rcx) || src2.is(rcx)) {
|
| - movq(kScratchRegister, rcx);
|
| - }
|
| - if (!dst.is(src1)) {
|
| - movq(dst, src1);
|
| - }
|
| - SmiToInteger32(rcx, src2);
|
| - orl(rcx, Immediate(kSmiShift));
|
| - shr_cl(dst); // Shift is rcx modulo 0x1f + 32.
|
| - shl(dst, Immediate(kSmiShift));
|
| - testq(dst, dst);
|
| - if (src1.is(rcx) || src2.is(rcx)) {
|
| - NearLabel positive_result;
|
| - j(positive, &positive_result);
|
| - if (src1.is(rcx)) {
|
| - movq(src1, kScratchRegister);
|
| - } else {
|
| - movq(src2, kScratchRegister);
|
| - }
|
| - jmp(on_not_smi_result);
|
| - bind(&positive_result);
|
| - } else {
|
| - j(negative, on_not_smi_result); // src2 was zero and src1 negative.
|
| - }
|
| -}
|
| -
|
| -
|
| -template <typename LabelType>
|
| -void MacroAssembler::SelectNonSmi(Register dst,
|
| - Register src1,
|
| - Register src2,
|
| - LabelType* on_not_smis) {
|
| - ASSERT(!dst.is(kScratchRegister));
|
| - ASSERT(!src1.is(kScratchRegister));
|
| - ASSERT(!src2.is(kScratchRegister));
|
| - ASSERT(!dst.is(src1));
|
| - ASSERT(!dst.is(src2));
|
| - // Both operands must not be smis.
|
| -#ifdef DEBUG
|
| - if (allow_stub_calls()) { // Check contains a stub call.
|
| - Condition not_both_smis = NegateCondition(CheckBothSmi(src1, src2));
|
| - Check(not_both_smis, "Both registers were smis in SelectNonSmi.");
|
| - }
|
| -#endif
|
| - ASSERT_EQ(0, kSmiTag);
|
| - ASSERT_EQ(0, Smi::FromInt(0));
|
| - movl(kScratchRegister, Immediate(kSmiTagMask));
|
| - and_(kScratchRegister, src1);
|
| - testl(kScratchRegister, src2);
|
| - // If non-zero then both are smis.
|
| - j(not_zero, on_not_smis);
|
| -
|
| - // Exactly one operand is a smi.
|
| - ASSERT_EQ(1, static_cast<int>(kSmiTagMask));
|
| - // kScratchRegister still holds src1 & kSmiTag, which is either zero or one.
|
| - subq(kScratchRegister, Immediate(1));
|
| - // If src1 is a smi, then scratch register all 1s, else it is all 0s.
|
| - movq(dst, src1);
|
| - xor_(dst, src2);
|
| - and_(dst, kScratchRegister);
|
| - // If src1 is a smi, dst holds src1 ^ src2, else it is zero.
|
| - xor_(dst, src1);
|
| - // If src1 is a smi, dst is src2, else it is src1, i.e., the non-smi.
|
| -}
|
| -
|
| -
|
| -template <typename LabelType>
|
| -void MacroAssembler::JumpIfSmi(Register src, LabelType* on_smi) {
|
| - ASSERT_EQ(0, kSmiTag);
|
| - Condition smi = CheckSmi(src);
|
| - j(smi, on_smi);
|
| -}
|
| -
|
| -
|
| -template <typename LabelType>
|
| -void MacroAssembler::JumpIfNotSmi(Register src, LabelType* on_not_smi) {
|
| - Condition smi = CheckSmi(src);
|
| - j(NegateCondition(smi), on_not_smi);
|
| -}
|
| -
|
| -
|
| -template <typename LabelType>
|
| -void MacroAssembler::JumpUnlessNonNegativeSmi(
|
| - Register src, LabelType* on_not_smi_or_negative) {
|
| - Condition non_negative_smi = CheckNonNegativeSmi(src);
|
| - j(NegateCondition(non_negative_smi), on_not_smi_or_negative);
|
| -}
|
| -
|
| -
|
| -template <typename LabelType>
|
| -void MacroAssembler::JumpIfSmiEqualsConstant(Register src,
|
| - Smi* constant,
|
| - LabelType* on_equals) {
|
| - SmiCompare(src, constant);
|
| - j(equal, on_equals);
|
| -}
|
| -
|
| -
|
| -template <typename LabelType>
|
| -void MacroAssembler::JumpIfNotValidSmiValue(Register src,
|
| - LabelType* on_invalid) {
|
| - Condition is_valid = CheckInteger32ValidSmiValue(src);
|
| - j(NegateCondition(is_valid), on_invalid);
|
| -}
|
| -
|
| -
|
| -template <typename LabelType>
|
| -void MacroAssembler::JumpIfUIntNotValidSmiValue(Register src,
|
| - LabelType* on_invalid) {
|
| - Condition is_valid = CheckUInteger32ValidSmiValue(src);
|
| - j(NegateCondition(is_valid), on_invalid);
|
| -}
|
| -
|
| -
|
| -template <typename LabelType>
|
| -void MacroAssembler::JumpIfNotBothSmi(Register src1,
|
| - Register src2,
|
| - LabelType* on_not_both_smi) {
|
| - Condition both_smi = CheckBothSmi(src1, src2);
|
| - j(NegateCondition(both_smi), on_not_both_smi);
|
| -}
|
| -
|
| -
|
| -template <typename LabelType>
|
| -void MacroAssembler::JumpUnlessBothNonNegativeSmi(Register src1,
|
| - Register src2,
|
| - LabelType* on_not_both_smi) {
|
| - Condition both_smi = CheckBothNonNegativeSmi(src1, src2);
|
| - j(NegateCondition(both_smi), on_not_both_smi);
|
| -}
|
| -
|
| -
|
| -template <typename LabelType>
|
| -void MacroAssembler::SmiOrIfSmis(Register dst, Register src1, Register src2,
|
| - LabelType* on_not_smis) {
|
| - if (dst.is(src1) || dst.is(src2)) {
|
| - ASSERT(!src1.is(kScratchRegister));
|
| - ASSERT(!src2.is(kScratchRegister));
|
| - movq(kScratchRegister, src1);
|
| - or_(kScratchRegister, src2);
|
| - JumpIfNotSmi(kScratchRegister, on_not_smis);
|
| - movq(dst, kScratchRegister);
|
| - } else {
|
| - movq(dst, src1);
|
| - or_(dst, src2);
|
| - JumpIfNotSmi(dst, on_not_smis);
|
| - }
|
| -}
|
| -
|
| -
|
| -template <typename LabelType>
|
| -void MacroAssembler::JumpIfNotString(Register object,
|
| - Register object_map,
|
| - LabelType* not_string) {
|
| - Condition is_smi = CheckSmi(object);
|
| - j(is_smi, not_string);
|
| - CmpObjectType(object, FIRST_NONSTRING_TYPE, object_map);
|
| - j(above_equal, not_string);
|
| -}
|
| -
|
| -
|
| -template <typename LabelType>
|
| -void MacroAssembler::JumpIfNotBothSequentialAsciiStrings(Register first_object,
|
| - Register second_object,
|
| - Register scratch1,
|
| - Register scratch2,
|
| - LabelType* on_fail) {
|
| - // Check that both objects are not smis.
|
| - Condition either_smi = CheckEitherSmi(first_object, second_object);
|
| - j(either_smi, on_fail);
|
| -
|
| - // Load instance type for both strings.
|
| - movq(scratch1, FieldOperand(first_object, HeapObject::kMapOffset));
|
| - movq(scratch2, FieldOperand(second_object, HeapObject::kMapOffset));
|
| - movzxbl(scratch1, FieldOperand(scratch1, Map::kInstanceTypeOffset));
|
| - movzxbl(scratch2, FieldOperand(scratch2, Map::kInstanceTypeOffset));
|
| -
|
| - // Check that both are flat ascii strings.
|
| - ASSERT(kNotStringTag != 0);
|
| - const int kFlatAsciiStringMask =
|
| - kIsNotStringMask | kStringRepresentationMask | kStringEncodingMask;
|
| - const int kFlatAsciiStringTag = ASCII_STRING_TYPE;
|
| -
|
| - andl(scratch1, Immediate(kFlatAsciiStringMask));
|
| - andl(scratch2, Immediate(kFlatAsciiStringMask));
|
| - // Interleave the bits to check both scratch1 and scratch2 in one test.
|
| - ASSERT_EQ(0, kFlatAsciiStringMask & (kFlatAsciiStringMask << 3));
|
| - lea(scratch1, Operand(scratch1, scratch2, times_8, 0));
|
| - cmpl(scratch1,
|
| - Immediate(kFlatAsciiStringTag + (kFlatAsciiStringTag << 3)));
|
| - j(not_equal, on_fail);
|
| -}
|
| -
|
| -
|
| -template <typename LabelType>
|
| -void MacroAssembler::JumpIfInstanceTypeIsNotSequentialAscii(
|
| - Register instance_type,
|
| - Register scratch,
|
| - LabelType *failure) {
|
| - if (!scratch.is(instance_type)) {
|
| - movl(scratch, instance_type);
|
| - }
|
| -
|
| - const int kFlatAsciiStringMask =
|
| - kIsNotStringMask | kStringRepresentationMask | kStringEncodingMask;
|
| -
|
| - andl(scratch, Immediate(kFlatAsciiStringMask));
|
| - cmpl(scratch, Immediate(kStringTag | kSeqStringTag | kAsciiStringTag));
|
| - j(not_equal, failure);
|
| -}
|
| -
|
| -
|
| -template <typename LabelType>
|
| -void MacroAssembler::JumpIfBothInstanceTypesAreNotSequentialAscii(
|
| - Register first_object_instance_type,
|
| - Register second_object_instance_type,
|
| - Register scratch1,
|
| - Register scratch2,
|
| - LabelType* on_fail) {
|
| - // Load instance type for both strings.
|
| - movq(scratch1, first_object_instance_type);
|
| - movq(scratch2, second_object_instance_type);
|
| -
|
| - // Check that both are flat ascii strings.
|
| - ASSERT(kNotStringTag != 0);
|
| - const int kFlatAsciiStringMask =
|
| - kIsNotStringMask | kStringRepresentationMask | kStringEncodingMask;
|
| - const int kFlatAsciiStringTag = ASCII_STRING_TYPE;
|
| -
|
| - andl(scratch1, Immediate(kFlatAsciiStringMask));
|
| - andl(scratch2, Immediate(kFlatAsciiStringMask));
|
| - // Interleave the bits to check both scratch1 and scratch2 in one test.
|
| - ASSERT_EQ(0, kFlatAsciiStringMask & (kFlatAsciiStringMask << 3));
|
| - lea(scratch1, Operand(scratch1, scratch2, times_8, 0));
|
| - cmpl(scratch1,
|
| - Immediate(kFlatAsciiStringTag + (kFlatAsciiStringTag << 3)));
|
| - j(not_equal, on_fail);
|
| -}
|
| -
|
| -
|
| -template <typename LabelType>
|
| -void MacroAssembler::InNewSpace(Register object,
|
| - Register scratch,
|
| - Condition cc,
|
| - LabelType* branch) {
|
| - if (Serializer::enabled()) {
|
| - // Can't do arithmetic on external references if it might get serialized.
|
| - // The mask isn't really an address. We load it as an external reference in
|
| - // case the size of the new space is different between the snapshot maker
|
| - // and the running system.
|
| - if (scratch.is(object)) {
|
| - movq(kScratchRegister, ExternalReference::new_space_mask(isolate()));
|
| - and_(scratch, kScratchRegister);
|
| - } else {
|
| - movq(scratch, ExternalReference::new_space_mask(isolate()));
|
| - and_(scratch, object);
|
| - }
|
| - movq(kScratchRegister, ExternalReference::new_space_start(isolate()));
|
| - cmpq(scratch, kScratchRegister);
|
| - j(cc, branch);
|
| - } else {
|
| - ASSERT(is_int32(static_cast<int64_t>(HEAP->NewSpaceMask())));
|
| - intptr_t new_space_start =
|
| - reinterpret_cast<intptr_t>(HEAP->NewSpaceStart());
|
| - movq(kScratchRegister, -new_space_start, RelocInfo::NONE);
|
| - if (scratch.is(object)) {
|
| - addq(scratch, kScratchRegister);
|
| - } else {
|
| - lea(scratch, Operand(object, kScratchRegister, times_1, 0));
|
| - }
|
| - and_(scratch, Immediate(static_cast<int32_t>(HEAP->NewSpaceMask())));
|
| - j(cc, branch);
|
| - }
|
| -}
|
| -
|
| -
|
| -template <typename LabelType>
|
| -void MacroAssembler::InvokePrologue(const ParameterCount& expected,
|
| - const ParameterCount& actual,
|
| - Handle<Code> code_constant,
|
| - Register code_register,
|
| - LabelType* done,
|
| - InvokeFlag flag,
|
| - const CallWrapper& call_wrapper) {
|
| - bool definitely_matches = false;
|
| - NearLabel invoke;
|
| - if (expected.is_immediate()) {
|
| - ASSERT(actual.is_immediate());
|
| - if (expected.immediate() == actual.immediate()) {
|
| - definitely_matches = true;
|
| - } else {
|
| - Set(rax, actual.immediate());
|
| - if (expected.immediate() ==
|
| - SharedFunctionInfo::kDontAdaptArgumentsSentinel) {
|
| - // Don't worry about adapting arguments for built-ins that
|
| - // don't want that done. Skip adaption code by making it look
|
| - // like we have a match between expected and actual number of
|
| - // arguments.
|
| - definitely_matches = true;
|
| - } else {
|
| - Set(rbx, expected.immediate());
|
| - }
|
| - }
|
| - } else {
|
| - if (actual.is_immediate()) {
|
| - // Expected is in register, actual is immediate. This is the
|
| - // case when we invoke function values without going through the
|
| - // IC mechanism.
|
| - cmpq(expected.reg(), Immediate(actual.immediate()));
|
| - j(equal, &invoke);
|
| - ASSERT(expected.reg().is(rbx));
|
| - Set(rax, actual.immediate());
|
| - } else if (!expected.reg().is(actual.reg())) {
|
| - // Both expected and actual are in (different) registers. This
|
| - // is the case when we invoke functions using call and apply.
|
| - cmpq(expected.reg(), actual.reg());
|
| - j(equal, &invoke);
|
| - ASSERT(actual.reg().is(rax));
|
| - ASSERT(expected.reg().is(rbx));
|
| - }
|
| - }
|
| -
|
| - if (!definitely_matches) {
|
| - Handle<Code> adaptor = isolate()->builtins()->ArgumentsAdaptorTrampoline();
|
| - if (!code_constant.is_null()) {
|
| - movq(rdx, code_constant, RelocInfo::EMBEDDED_OBJECT);
|
| - addq(rdx, Immediate(Code::kHeaderSize - kHeapObjectTag));
|
| - } else if (!code_register.is(rdx)) {
|
| - movq(rdx, code_register);
|
| - }
|
| -
|
| - if (flag == CALL_FUNCTION) {
|
| - call_wrapper.BeforeCall(CallSize(adaptor));
|
| - Call(adaptor, RelocInfo::CODE_TARGET);
|
| - call_wrapper.AfterCall();
|
| - jmp(done);
|
| - } else {
|
| - Jump(adaptor, RelocInfo::CODE_TARGET);
|
| - }
|
| - bind(&invoke);
|
| - }
|
| -}
|
| -
|
| -
|
| } } // namespace v8::internal
|
|
|
| #endif // V8_X64_MACRO_ASSEMBLER_X64_H_
|
|
|