Index: src/x64/macro-assembler-x64.cc |
diff --git a/src/x64/macro-assembler-x64.cc b/src/x64/macro-assembler-x64.cc |
index 104ccb8c155f5e36c04bb550d603fcfcf1c5a6fa..608f49405b5ecf973d64b53800a9699f457907c2 100644 |
--- a/src/x64/macro-assembler-x64.cc |
+++ b/src/x64/macro-assembler-x64.cc |
@@ -412,6 +412,686 @@ void MacroAssembler::Set(const Operand& dst, int64_t x) { |
} |
+// ---------------------------------------------------------------------------- |
+// Smi tagging, untagging and tag detection. |
+ |
+ |
+void MacroAssembler::Integer32ToSmi(Register dst, Register src) { |
+ ASSERT_EQ(1, kSmiTagSize); |
+ ASSERT_EQ(0, kSmiTag); |
+#ifdef DEBUG |
+ cmpq(src, Immediate(0xC0000000u)); |
+ Check(positive, "Smi conversion overflow"); |
+#endif |
+ if (dst.is(src)) { |
+ addl(dst, src); |
+ } else { |
+ lea(dst, Operand(src, src, times_1, 0)); |
+ } |
+} |
+ |
+ |
+void MacroAssembler::Integer32ToSmi(Register dst, |
+ Register src, |
+ Label* on_overflow) { |
+ ASSERT_EQ(1, kSmiTagSize); |
+ ASSERT_EQ(0, kSmiTag); |
+ if (!dst.is(src)) { |
+ movl(dst, src); |
+ } |
+ addl(dst, src); |
+ j(overflow, on_overflow); |
+} |
+ |
+ |
+void MacroAssembler::Integer64AddToSmi(Register dst, |
+ Register src, |
+ int constant) { |
+#ifdef DEBUG |
+ movl(kScratchRegister, src); |
+ addl(kScratchRegister, Immediate(constant)); |
+ Check(no_overflow, "Add-and-smi-convert overflow"); |
+ Condition valid = CheckInteger32ValidSmiValue(kScratchRegister); |
+ Check(valid, "Add-and-smi-convert overflow"); |
+#endif |
+ lea(dst, Operand(src, src, times_1, constant << kSmiTagSize)); |
+} |
+ |
+ |
+void MacroAssembler::SmiToInteger32(Register dst, Register src) { |
+ ASSERT_EQ(1, kSmiTagSize); |
+ ASSERT_EQ(0, kSmiTag); |
+ if (!dst.is(src)) { |
+ movl(dst, src); |
+ } |
+ sarl(dst, Immediate(kSmiTagSize)); |
+} |
+ |
+ |
+void MacroAssembler::SmiToInteger64(Register dst, Register src) { |
+ ASSERT_EQ(1, kSmiTagSize); |
+ ASSERT_EQ(0, kSmiTag); |
+ movsxlq(dst, src); |
+ sar(dst, Immediate(kSmiTagSize)); |
+} |
+ |
+ |
+void MacroAssembler::PositiveSmiTimesPowerOfTwoToInteger64(Register dst, |
+ Register src, |
+ int power) { |
+ ASSERT(power >= 0); |
+ ASSERT(power < 64); |
+ if (power == 0) { |
+ SmiToInteger64(dst, src); |
+ return; |
+ } |
+ shl(dst, Immediate(power - 1)); |
+} |
+ |
+void MacroAssembler::JumpIfSmi(Register src, Label* on_smi) { |
+ ASSERT_EQ(0, kSmiTag); |
+ testl(src, Immediate(kSmiTagMask)); |
+ j(zero, on_smi); |
+} |
+ |
+ |
+void MacroAssembler::JumpIfNotSmi(Register src, Label* on_not_smi) { |
+ Condition not_smi = CheckNotSmi(src); |
+ j(not_smi, on_not_smi); |
+} |
+ |
+ |
+void MacroAssembler::JumpIfNotPositiveSmi(Register src, |
+ Label* on_not_positive_smi) { |
+ Condition not_positive_smi = CheckNotPositiveSmi(src); |
+ j(not_positive_smi, on_not_positive_smi); |
+} |
+ |
+ |
+void MacroAssembler::JumpIfSmiEqualsConstant(Register src, |
+ int constant, |
+ Label* on_equals) { |
+ if (Smi::IsValid(constant)) { |
+ Condition are_equal = CheckSmiEqualsConstant(src, constant); |
+ j(are_equal, on_equals); |
+ } |
+} |
+ |
+ |
+void MacroAssembler::JumpIfNotValidSmiValue(Register src, Label* on_invalid) { |
+ Condition is_valid = CheckInteger32ValidSmiValue(src); |
+ j(ReverseCondition(is_valid), on_invalid); |
+} |
+ |
+ |
+ |
+void MacroAssembler::JumpIfNotBothSmi(Register src1, |
+ Register src2, |
+ Label* on_not_both_smi) { |
+ Condition not_both_smi = CheckNotBothSmi(src1, src2); |
+ j(not_both_smi, on_not_both_smi); |
+} |
+ |
+Condition MacroAssembler::CheckSmi(Register src) { |
+ testb(src, Immediate(kSmiTagMask)); |
+ return zero; |
+} |
+ |
+ |
+Condition MacroAssembler::CheckNotSmi(Register src) { |
+ ASSERT_EQ(0, kSmiTag); |
+ testb(src, Immediate(kSmiTagMask)); |
+ return not_zero; |
+} |
+ |
+ |
+Condition MacroAssembler::CheckPositiveSmi(Register src) { |
+ ASSERT_EQ(0, kSmiTag); |
+ testl(src, Immediate(static_cast<uint32_t>(0x80000000u | kSmiTagMask))); |
+ return zero; |
+} |
+ |
+ |
+Condition MacroAssembler::CheckNotPositiveSmi(Register src) { |
+ ASSERT_EQ(0, kSmiTag); |
+ testl(src, Immediate(static_cast<uint32_t>(0x80000000u | kSmiTagMask))); |
+ return not_zero; |
+} |
+ |
+ |
+Condition MacroAssembler::CheckBothSmi(Register first, Register second) { |
+ if (first.is(second)) { |
+ return CheckSmi(first); |
+ } |
+ movl(kScratchRegister, first); |
+ orl(kScratchRegister, second); |
+ return CheckSmi(kScratchRegister); |
+} |
+ |
+ |
+Condition MacroAssembler::CheckNotBothSmi(Register first, Register second) { |
+ ASSERT_EQ(0, kSmiTag); |
+ if (first.is(second)) { |
+ return CheckNotSmi(first); |
+ } |
+ movl(kScratchRegister, first); |
+ or_(kScratchRegister, second); |
+ return CheckNotSmi(kScratchRegister); |
+} |
+ |
+ |
+Condition MacroAssembler::CheckIsMinSmi(Register src) { |
+ ASSERT(kSmiTag == 0 && kSmiTagSize == 1); |
+ cmpl(src, Immediate(0x40000000)); |
+ return equal; |
+} |
+ |
+Condition MacroAssembler::CheckSmiEqualsConstant(Register src, int constant) { |
+ if (constant == 0) { |
+ testl(src, src); |
+ return zero; |
+ } |
+ if (Smi::IsValid(constant)) { |
+ cmpl(src, Immediate(Smi::FromInt(constant))); |
+ return zero; |
+ } |
+ // Can't be equal. |
+ UNREACHABLE(); |
+ return no_condition; |
+} |
+ |
+ |
+Condition MacroAssembler::CheckInteger32ValidSmiValue(Register src) { |
+ // A 32-bit integer value can be converted to a smi if it is in the |
+ // range [-2^30 .. 2^30-1]. That is equivalent to having its 32-bit |
+ // representation have bits 30 and 31 be equal. |
+ cmpl(src, Immediate(0xC0000000u)); |
+ return positive; |
+} |
+ |
+ |
+void MacroAssembler::SmiNeg(Register dst, |
+ Register src, |
+ Label* on_not_smi_result) { |
+ if (!dst.is(src)) { |
+ movl(dst, src); |
+ } |
+ negl(dst); |
+ testl(dst, Immediate(0x7fffffff)); |
+ // If the result is zero or 0x80000000, negation failed to create a smi. |
+ j(equal, on_not_smi_result); |
+} |
+ |
+ |
+void MacroAssembler::SmiAdd(Register dst, |
+ Register src1, |
+ Register src2, |
+ Label* on_not_smi_result) { |
+ ASSERT(!dst.is(src2)); |
+ if (!dst.is(src1)) { |
+ movl(dst, src1); |
+ } |
+ addl(dst, src2); |
+ if (!dst.is(src1)) { |
+ j(overflow, on_not_smi_result); |
+ } else { |
+ Label smi_result; |
+ j(no_overflow, &smi_result); |
+ // Restore src1. |
+ subl(src1, src2); |
+ jmp(on_not_smi_result); |
+ bind(&smi_result); |
+ } |
+} |
+ |
+ |
+ |
+void MacroAssembler::SmiSub(Register dst, |
+ Register src1, |
+ Register src2, |
+ Label* on_not_smi_result) { |
+ ASSERT(!dst.is(src2)); |
+ if (!dst.is(src1)) { |
+ movl(dst, src1); |
+ } |
+ subl(dst, src2); |
+ if (!dst.is(src1)) { |
+ j(overflow, on_not_smi_result); |
+ } else { |
+ Label smi_result; |
+ j(no_overflow, &smi_result); |
+ // Restore src1. |
+ addl(src1, src2); |
+ jmp(on_not_smi_result); |
+ bind(&smi_result); |
+ } |
+} |
+ |
+ |
+void MacroAssembler::SmiMul(Register dst, |
+ Register src1, |
+ Register src2, |
+ Label* on_not_smi_result) { |
+ ASSERT(!dst.is(src2)); |
+ |
+ if (dst.is(src1)) { |
+ movq(kScratchRegister, src1); |
+ } |
+ SmiToInteger32(dst, src1); |
+ |
+ imull(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. The frame is unchanged |
+ // in this block, so local control flow can use a Label rather |
+ // than a JumpTarget. |
+ Label non_zero_result; |
+ testl(dst, dst); |
+ j(not_zero, &non_zero_result); |
+ |
+ // Test whether either operand is negative (the other must be zero). |
+ orl(kScratchRegister, src2); |
+ j(negative, on_not_smi_result); |
+ bind(&non_zero_result); |
+} |
+ |
+ |
+void MacroAssembler::SmiTryAddConstant(Register dst, |
+ Register src, |
+ int32_t constant, |
+ Label* on_not_smi_result) { |
+ // Does not assume that src is a smi. |
+ ASSERT_EQ(1, kSmiTagMask); |
+ ASSERT_EQ(0, kSmiTag); |
+ ASSERT(Smi::IsValid(constant)); |
+ |
+ Register tmp = (src.is(dst) ? kScratchRegister : dst); |
+ movl(tmp, src); |
+ addl(tmp, Immediate(Smi::FromInt(constant))); |
+ if (tmp.is(kScratchRegister)) { |
+ j(overflow, on_not_smi_result); |
+ testl(tmp, Immediate(kSmiTagMask)); |
+ j(not_zero, on_not_smi_result); |
+ movl(dst, tmp); |
+ } else { |
+ movl(kScratchRegister, Immediate(kSmiTagMask)); |
+ cmovl(overflow, dst, kScratchRegister); |
+ testl(dst, kScratchRegister); |
+ j(not_zero, on_not_smi_result); |
+ } |
+} |
+ |
+ |
+void MacroAssembler::SmiAddConstant(Register dst, |
+ Register src, |
+ int32_t constant, |
+ Label* on_not_smi_result) { |
+ ASSERT(Smi::IsValid(constant)); |
+ if (on_not_smi_result == NULL) { |
+ if (dst.is(src)) { |
+ movl(dst, src); |
+ } else { |
+ lea(dst, Operand(src, constant << kSmiTagSize)); |
+ } |
+ } else { |
+ if (!dst.is(src)) { |
+ movl(dst, src); |
+ } |
+ addl(dst, Immediate(Smi::FromInt(constant))); |
+ if (!dst.is(src)) { |
+ j(overflow, on_not_smi_result); |
+ } else { |
+ Label result_ok; |
+ j(no_overflow, &result_ok); |
+ subl(dst, Immediate(Smi::FromInt(constant))); |
+ jmp(on_not_smi_result); |
+ bind(&result_ok); |
+ } |
+ } |
+} |
+ |
+ |
+void MacroAssembler::SmiSubConstant(Register dst, |
+ Register src, |
+ int32_t constant, |
+ Label* on_not_smi_result) { |
+ ASSERT(Smi::IsValid(constant)); |
+ Smi* smi_value = Smi::FromInt(constant); |
+ if (dst.is(src)) { |
+ // Optimistic subtract - may change value of dst register, |
+ // if it has garbage bits in the higher half, but will not change |
+ // the value as a tagged smi. |
+ subl(dst, Immediate(smi_value)); |
+ if (on_not_smi_result != NULL) { |
+ Label add_success; |
+ j(no_overflow, &add_success); |
+ addl(dst, Immediate(smi_value)); |
+ jmp(on_not_smi_result); |
+ bind(&add_success); |
+ } |
+ } else { |
+ UNIMPLEMENTED(); // Not used yet. |
+ } |
+} |
+ |
+ |
+void MacroAssembler::SmiDiv(Register dst, |
+ Register src1, |
+ Register src2, |
+ Label* on_not_smi_result) { |
+ ASSERT(!src2.is(rax)); |
+ ASSERT(!src2.is(rdx)); |
+ ASSERT(!src1.is(rdx)); |
+ |
+ // Check for 0 divisor (result is +/-Infinity). |
+ Label positive_divisor; |
+ testl(src2, src2); |
+ j(zero, on_not_smi_result); |
+ j(positive, &positive_divisor); |
+ // Check for negative zero result. If the dividend is zero, and the |
+ // divisor is negative, return a floating point negative zero. |
+ testl(src1, src1); |
+ j(zero, on_not_smi_result); |
+ bind (&positive_divisor); |
+ |
+ // Sign extend src1 into edx:eax. |
+ if (!src1.is(rax)) { |
+ movl(rax, src1); |
+ } |
+ cdq(); |
+ |
+ idivl(src2); |
+ // Check for the corner case of dividing the most negative smi by |
+ // -1. We cannot use the overflow flag, since it is not set by |
+ // idiv instruction. |
+ ASSERT(kSmiTag == 0 && kSmiTagSize == 1); |
+ cmpl(rax, Immediate(0x40000000)); |
+ j(equal, on_not_smi_result); |
+ // Check that the remainder is zero. |
+ testl(rdx, rdx); |
+ j(not_zero, on_not_smi_result); |
+ // Tag the result and store it in the destination register. |
+ Integer32ToSmi(dst, rax); |
+} |
+ |
+ |
+void MacroAssembler::SmiMod(Register dst, |
+ Register src1, |
+ Register src2, |
+ Label* 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)); |
+ |
+ testl(src2, src2); |
+ j(zero, on_not_smi_result); |
+ |
+ if (src1.is(rax)) { |
+ // Mist remember the value to see if a zero result should |
+ // be a negative zero. |
+ movl(kScratchRegister, rax); |
+ } else { |
+ movl(rax, src1); |
+ } |
+ // Sign extend eax into edx:eax. |
+ cdq(); |
+ idivl(src2); |
+ // Check for a negative zero result. If the result is zero, and the |
+ // dividend is negative, return a floating point negative zero. |
+ Label non_zero_result; |
+ testl(rdx, rdx); |
+ j(not_zero, &non_zero_result); |
+ if (src1.is(rax)) { |
+ testl(kScratchRegister, kScratchRegister); |
+ } else { |
+ testl(src1, src1); |
+ } |
+ j(negative, on_not_smi_result); |
+ bind(&non_zero_result); |
+ if (!dst.is(rdx)) { |
+ movl(dst, rdx); |
+ } |
+} |
+ |
+ |
+void MacroAssembler::SmiNot(Register dst, Register src) { |
+ if (dst.is(src)) { |
+ not_(dst); |
+ // Remove inverted smi-tag. The mask is sign-extended to 64 bits. |
+ xor_(src, Immediate(kSmiTagMask)); |
+ } else { |
+ ASSERT_EQ(0, kSmiTag); |
+ lea(dst, Operand(src, kSmiTagMask)); |
+ not_(dst); |
+ } |
+} |
+ |
+ |
+void MacroAssembler::SmiAnd(Register dst, Register src1, Register src2) { |
+ if (!dst.is(src1)) { |
+ movl(dst, src1); |
+ } |
+ and_(dst, src2); |
+} |
+ |
+ |
+void MacroAssembler::SmiAndConstant(Register dst, Register src, int constant) { |
+ ASSERT(Smi::IsValid(constant)); |
+ if (!dst.is(src)) { |
+ movl(dst, src); |
+ } |
+ and_(dst, Immediate(Smi::FromInt(constant))); |
+} |
+ |
+ |
+void MacroAssembler::SmiOr(Register dst, Register src1, Register src2) { |
+ if (!dst.is(src1)) { |
+ movl(dst, src1); |
+ } |
+ or_(dst, src2); |
+} |
+ |
+ |
+void MacroAssembler::SmiOrConstant(Register dst, Register src, int constant) { |
+ ASSERT(Smi::IsValid(constant)); |
+ if (!dst.is(src)) { |
+ movl(dst, src); |
+ } |
+ or_(dst, Immediate(Smi::FromInt(constant))); |
+} |
+ |
+void MacroAssembler::SmiXor(Register dst, Register src1, Register src2) { |
+ if (!dst.is(src1)) { |
+ movl(dst, src1); |
+ } |
+ xor_(dst, src2); |
+} |
+ |
+ |
+void MacroAssembler::SmiXorConstant(Register dst, Register src, int constant) { |
+ ASSERT(Smi::IsValid(constant)); |
+ if (!dst.is(src)) { |
+ movl(dst, src); |
+ } |
+ xor_(dst, Immediate(Smi::FromInt(constant))); |
+} |
+ |
+ |
+ |
+void MacroAssembler::SmiShiftArithmeticRightConstant(Register dst, |
+ Register src, |
+ int shift_value) { |
+ if (shift_value > 0) { |
+ if (dst.is(src)) { |
+ sarl(dst, Immediate(shift_value)); |
+ and_(dst, Immediate(~kSmiTagMask)); |
+ } else { |
+ UNIMPLEMENTED(); // Not used. |
+ } |
+ } |
+} |
+ |
+ |
+void MacroAssembler::SmiShiftLogicRightConstant(Register dst, |
+ Register src, |
+ int shift_value, |
+ Label* on_not_smi_result) { |
+ // Logic right shift interprets its result as an *unsigned* number. |
+ if (dst.is(src)) { |
+ UNIMPLEMENTED(); // Not used. |
+ } else { |
+ movl(dst, src); |
+ // Untag the smi. |
+ sarl(dst, Immediate(kSmiTagSize)); |
+ if (shift_value < 2) { |
+ // A negative Smi shifted right two is in the positive Smi range, |
+ // but if shifted only by zero or one, it never is. |
+ j(negative, on_not_smi_result); |
+ } |
+ if (shift_value > 0) { |
+ // Do the right shift on the integer value. |
+ shrl(dst, Immediate(shift_value)); |
+ } |
+ // Re-tag the result. |
+ addl(dst, dst); |
+ } |
+} |
+ |
+ |
+void MacroAssembler::SmiShiftLeftConstant(Register dst, |
+ Register src, |
+ int shift_value, |
+ Label* on_not_smi_result) { |
+ if (dst.is(src)) { |
+ UNIMPLEMENTED(); // Not used. |
+ } else { |
+ movl(dst, src); |
+ if (shift_value > 0) { |
+ // Treat dst as an untagged integer value equal to two times the |
+ // smi value of src, i.e., already shifted left by one. |
+ if (shift_value > 1) { |
+ shll(dst, Immediate(shift_value - 1)); |
+ } |
+ // Convert int result to Smi, checking that it is in smi range. |
+ ASSERT(kSmiTagSize == 1); // adjust code if not the case |
+ Integer32ToSmi(dst, dst, on_not_smi_result); |
+ } |
+ } |
+} |
+ |
+ |
+void MacroAssembler::SmiShiftLeft(Register dst, |
+ Register src1, |
+ Register src2, |
+ Label* on_not_smi_result) { |
+ ASSERT(!dst.is(rcx)); |
+ Label result_ok; |
+ // Untag both operands. |
+ SmiToInteger32(dst, src1); |
+ SmiToInteger32(rcx, src2); |
+ shll(dst); |
+ // Check that the *signed* result fits in a smi. |
+ Condition is_valid = CheckInteger32ValidSmiValue(dst); |
+ j(is_valid, &result_ok); |
+ // Restore the relevant bits of the source registers |
+ // and call the slow version. |
+ if (dst.is(src1)) { |
+ shrl(dst); |
+ Integer32ToSmi(dst, dst); |
+ } |
+ Integer32ToSmi(rcx, rcx); |
+ jmp(on_not_smi_result); |
+ bind(&result_ok); |
+ Integer32ToSmi(dst, dst); |
+} |
+ |
+ |
+void MacroAssembler::SmiShiftLogicRight(Register dst, |
+ Register src1, |
+ Register src2, |
+ Label* on_not_smi_result) { |
+ ASSERT(!dst.is(rcx)); |
+ Label result_ok; |
+ // Untag both operands. |
+ SmiToInteger32(dst, src1); |
+ SmiToInteger32(rcx, src2); |
+ |
+ shrl(dst); |
+ // Check that the *unsigned* result fits in a smi. |
+ // I.e., that it is a valid positive smi value. The positive smi |
+ // values are 0..0x3fffffff, i.e., neither of the top-most two |
+ // bits can be set. |
+ // |
+ // These two cases can only happen with shifts by 0 or 1 when |
+ // handed a valid smi. If the answer cannot be represented by a |
+ // smi, restore the left and right arguments, and jump to slow |
+ // case. The low bit of the left argument may be lost, but only |
+ // in a case where it is dropped anyway. |
+ testl(dst, Immediate(0xc0000000)); |
+ j(zero, &result_ok); |
+ if (dst.is(src1)) { |
+ shll(dst); |
+ Integer32ToSmi(dst, dst); |
+ } |
+ Integer32ToSmi(rcx, rcx); |
+ jmp(on_not_smi_result); |
+ bind(&result_ok); |
+ // Smi-tag the result in answer. |
+ Integer32ToSmi(dst, dst); |
+} |
+ |
+ |
+void MacroAssembler::SmiShiftArithmeticRight(Register dst, |
+ Register src1, |
+ Register src2) { |
+ ASSERT(!dst.is(rcx)); |
+ // Untag both operands. |
+ SmiToInteger32(dst, src1); |
+ SmiToInteger32(rcx, src2); |
+ // Shift as integer. |
+ sarl(dst); |
+ // Retag result. |
+ Integer32ToSmi(dst, dst); |
+} |
+ |
+ |
+void MacroAssembler::SelectNonSmi(Register dst, |
+ Register src1, |
+ Register src2, |
+ Label* on_not_smis) { |
+ ASSERT(!dst.is(src1)); |
+ ASSERT(!dst.is(src2)); |
+ // Both operands must not be smis. |
+#ifdef DEBUG |
+ Condition not_both_smis = CheckNotBothSmi(src1, src2); |
+ Check(not_both_smis, "Both registers were smis."); |
+#endif |
+ ASSERT_EQ(0, kSmiTag); |
+ ASSERT_EQ(0, Smi::FromInt(0)); |
+ movq(kScratchRegister, Immediate(kSmiTagMask)); |
+ and_(kScratchRegister, src1); |
+ testl(kScratchRegister, src2); |
+ j(not_zero, on_not_smis); |
+ // 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., a non-smi. |
+} |
+ |
+ |
+ |
bool MacroAssembler::IsUnsafeSmi(Smi* value) { |
return false; |
} |