OLD | NEW |
1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 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 996 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1007 Label left_not_string, call_runtime; | 1007 Label left_not_string, call_runtime; |
1008 | 1008 |
1009 // Registers containing left and right operands respectively. | 1009 // Registers containing left and right operands respectively. |
1010 Register left = rdx; | 1010 Register left = rdx; |
1011 Register right = rax; | 1011 Register right = rax; |
1012 | 1012 |
1013 // Test if left operand is a string. | 1013 // Test if left operand is a string. |
1014 __ JumpIfSmi(left, &left_not_string, Label::kNear); | 1014 __ JumpIfSmi(left, &left_not_string, Label::kNear); |
1015 __ CmpObjectType(left, FIRST_NONSTRING_TYPE, rcx); | 1015 __ CmpObjectType(left, FIRST_NONSTRING_TYPE, rcx); |
1016 __ j(above_equal, &left_not_string, Label::kNear); | 1016 __ j(above_equal, &left_not_string, Label::kNear); |
1017 StringAddStub string_add_left_stub((StringAddFlags) | 1017 StringAddStub string_add_left_stub( |
1018 (ERECT_FRAME | NO_STRING_CHECK_LEFT_IN_STUB)); | 1018 (StringAddFlags)(STRING_ADD_CHECK_RIGHT | STRING_ADD_ERECT_FRAME)); |
1019 BinaryOpStub_GenerateRegisterArgsPushUnderReturn(masm); | 1019 BinaryOpStub_GenerateRegisterArgsPushUnderReturn(masm); |
1020 __ TailCallStub(&string_add_left_stub); | 1020 __ TailCallStub(&string_add_left_stub); |
1021 | 1021 |
1022 // Left operand is not a string, test right. | 1022 // Left operand is not a string, test right. |
1023 __ bind(&left_not_string); | 1023 __ bind(&left_not_string); |
1024 __ JumpIfSmi(right, &call_runtime, Label::kNear); | 1024 __ JumpIfSmi(right, &call_runtime, Label::kNear); |
1025 __ CmpObjectType(right, FIRST_NONSTRING_TYPE, rcx); | 1025 __ CmpObjectType(right, FIRST_NONSTRING_TYPE, rcx); |
1026 __ j(above_equal, &call_runtime, Label::kNear); | 1026 __ j(above_equal, &call_runtime, Label::kNear); |
1027 | 1027 |
1028 StringAddStub string_add_right_stub((StringAddFlags) | 1028 StringAddStub string_add_right_stub( |
1029 (ERECT_FRAME | NO_STRING_CHECK_RIGHT_IN_STUB)); | 1029 (StringAddFlags)(STRING_ADD_CHECK_LEFT | STRING_ADD_ERECT_FRAME)); |
1030 BinaryOpStub_GenerateRegisterArgsPushUnderReturn(masm); | 1030 BinaryOpStub_GenerateRegisterArgsPushUnderReturn(masm); |
1031 __ TailCallStub(&string_add_right_stub); | 1031 __ TailCallStub(&string_add_right_stub); |
1032 | 1032 |
1033 // Neither argument is a string. | 1033 // Neither argument is a string. |
1034 __ bind(&call_runtime); | 1034 __ bind(&call_runtime); |
1035 } | 1035 } |
1036 | 1036 |
1037 | 1037 |
1038 void BinaryOpStub::GenerateSmiStub(MacroAssembler* masm) { | 1038 void BinaryOpStub::GenerateSmiStub(MacroAssembler* masm) { |
1039 Label right_arg_changed, call_runtime; | 1039 Label right_arg_changed, call_runtime; |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1094 // Test if left operand is a string. | 1094 // Test if left operand is a string. |
1095 __ JumpIfSmi(left, &call_runtime); | 1095 __ JumpIfSmi(left, &call_runtime); |
1096 __ CmpObjectType(left, FIRST_NONSTRING_TYPE, rcx); | 1096 __ CmpObjectType(left, FIRST_NONSTRING_TYPE, rcx); |
1097 __ j(above_equal, &call_runtime); | 1097 __ j(above_equal, &call_runtime); |
1098 | 1098 |
1099 // Test if right operand is a string. | 1099 // Test if right operand is a string. |
1100 __ JumpIfSmi(right, &call_runtime); | 1100 __ JumpIfSmi(right, &call_runtime); |
1101 __ CmpObjectType(right, FIRST_NONSTRING_TYPE, rcx); | 1101 __ CmpObjectType(right, FIRST_NONSTRING_TYPE, rcx); |
1102 __ j(above_equal, &call_runtime); | 1102 __ j(above_equal, &call_runtime); |
1103 | 1103 |
1104 StringAddStub string_add_stub((StringAddFlags) | 1104 StringAddStub string_add_stub( |
1105 (ERECT_FRAME | NO_STRING_CHECK_IN_STUB)); | 1105 (StringAddFlags)(STRING_ADD_CHECK_NONE | STRING_ADD_ERECT_FRAME)); |
1106 BinaryOpStub_GenerateRegisterArgsPushUnderReturn(masm); | 1106 BinaryOpStub_GenerateRegisterArgsPushUnderReturn(masm); |
1107 __ TailCallStub(&string_add_stub); | 1107 __ TailCallStub(&string_add_stub); |
1108 | 1108 |
1109 __ bind(&call_runtime); | 1109 __ bind(&call_runtime); |
1110 GenerateTypeTransition(masm); | 1110 GenerateTypeTransition(masm); |
1111 } | 1111 } |
1112 | 1112 |
1113 | 1113 |
1114 void BinaryOpStub::GenerateOddballStub(MacroAssembler* masm) { | 1114 void BinaryOpStub::GenerateOddballStub(MacroAssembler* masm) { |
1115 Label call_runtime; | 1115 Label call_runtime; |
(...skipping 3393 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4509 | 4509 |
4510 void StringAddStub::Generate(MacroAssembler* masm) { | 4510 void StringAddStub::Generate(MacroAssembler* masm) { |
4511 Label call_runtime, call_builtin; | 4511 Label call_runtime, call_builtin; |
4512 Builtins::JavaScript builtin_id = Builtins::ADD; | 4512 Builtins::JavaScript builtin_id = Builtins::ADD; |
4513 | 4513 |
4514 // Load the two arguments. | 4514 // Load the two arguments. |
4515 __ movq(rax, Operand(rsp, 2 * kPointerSize)); // First argument (left). | 4515 __ movq(rax, Operand(rsp, 2 * kPointerSize)); // First argument (left). |
4516 __ movq(rdx, Operand(rsp, 1 * kPointerSize)); // Second argument (right). | 4516 __ movq(rdx, Operand(rsp, 1 * kPointerSize)); // Second argument (right). |
4517 | 4517 |
4518 // Make sure that both arguments are strings if not known in advance. | 4518 // Make sure that both arguments are strings if not known in advance. |
4519 if ((flags_ & NO_STRING_ADD_FLAGS) != 0) { | 4519 // Otherwise, at least one of the arguments is definitely a string, |
| 4520 // and we convert the one that is not known to be a string. |
| 4521 if ((flags_ & STRING_ADD_CHECK_BOTH) == STRING_ADD_CHECK_BOTH) { |
| 4522 ASSERT((flags_ & STRING_ADD_CHECK_LEFT) == STRING_ADD_CHECK_LEFT); |
| 4523 ASSERT((flags_ & STRING_ADD_CHECK_RIGHT) == STRING_ADD_CHECK_RIGHT); |
4520 __ JumpIfSmi(rax, &call_runtime); | 4524 __ JumpIfSmi(rax, &call_runtime); |
4521 __ CmpObjectType(rax, FIRST_NONSTRING_TYPE, r8); | 4525 __ CmpObjectType(rax, FIRST_NONSTRING_TYPE, r8); |
4522 __ j(above_equal, &call_runtime); | 4526 __ j(above_equal, &call_runtime); |
4523 | 4527 |
4524 // First argument is a a string, test second. | 4528 // First argument is a a string, test second. |
4525 __ JumpIfSmi(rdx, &call_runtime); | 4529 __ JumpIfSmi(rdx, &call_runtime); |
4526 __ CmpObjectType(rdx, FIRST_NONSTRING_TYPE, r9); | 4530 __ CmpObjectType(rdx, FIRST_NONSTRING_TYPE, r9); |
4527 __ j(above_equal, &call_runtime); | 4531 __ j(above_equal, &call_runtime); |
4528 } else { | 4532 } else if ((flags_ & STRING_ADD_CHECK_LEFT) == STRING_ADD_CHECK_LEFT) { |
4529 // Here at least one of the arguments is definitely a string. | 4533 ASSERT((flags_ & STRING_ADD_CHECK_RIGHT) == 0); |
4530 // We convert the one that is not known to be a string. | 4534 GenerateConvertArgument(masm, 2 * kPointerSize, rax, rbx, rcx, rdi, |
4531 if ((flags_ & NO_STRING_CHECK_LEFT_IN_STUB) == 0) { | 4535 &call_builtin); |
4532 ASSERT((flags_ & NO_STRING_CHECK_RIGHT_IN_STUB) != 0); | 4536 builtin_id = Builtins::STRING_ADD_RIGHT; |
4533 GenerateConvertArgument(masm, 2 * kPointerSize, rax, rbx, rcx, rdi, | 4537 } else if ((flags_ & STRING_ADD_CHECK_RIGHT) == STRING_ADD_CHECK_RIGHT) { |
4534 &call_builtin); | 4538 ASSERT((flags_ & STRING_ADD_CHECK_LEFT) == 0); |
4535 builtin_id = Builtins::STRING_ADD_RIGHT; | 4539 GenerateConvertArgument(masm, 1 * kPointerSize, rdx, rbx, rcx, rdi, |
4536 } else if ((flags_ & NO_STRING_CHECK_RIGHT_IN_STUB) == 0) { | 4540 &call_builtin); |
4537 ASSERT((flags_ & NO_STRING_CHECK_LEFT_IN_STUB) != 0); | 4541 builtin_id = Builtins::STRING_ADD_LEFT; |
4538 GenerateConvertArgument(masm, 1 * kPointerSize, rdx, rbx, rcx, rdi, | |
4539 &call_builtin); | |
4540 builtin_id = Builtins::STRING_ADD_LEFT; | |
4541 } | |
4542 } | 4542 } |
4543 | 4543 |
4544 // Both arguments are strings. | 4544 // Both arguments are strings. |
4545 // rax: first string | 4545 // rax: first string |
4546 // rdx: second string | 4546 // rdx: second string |
4547 // Check if either of the strings are empty. In that case return the other. | 4547 // Check if either of the strings are empty. In that case return the other. |
4548 Label second_not_zero_length, both_not_zero_length; | 4548 Label second_not_zero_length, both_not_zero_length; |
4549 __ movq(rcx, FieldOperand(rdx, String::kLengthOffset)); | 4549 __ movq(rcx, FieldOperand(rdx, String::kLengthOffset)); |
4550 __ SmiTest(rcx); | 4550 __ SmiTest(rcx); |
4551 __ j(not_zero, &second_not_zero_length, Label::kNear); | 4551 __ j(not_zero, &second_not_zero_length, Label::kNear); |
(...skipping 15 matching lines...) Expand all Loading... |
4567 // rbx: length of first string | 4567 // rbx: length of first string |
4568 // rcx: length of second string | 4568 // rcx: length of second string |
4569 // rdx: second string | 4569 // rdx: second string |
4570 // r8: map of first string (if flags_ == NO_STRING_ADD_FLAGS) | 4570 // r8: map of first string (if flags_ == NO_STRING_ADD_FLAGS) |
4571 // r9: map of second string (if flags_ == NO_STRING_ADD_FLAGS) | 4571 // r9: map of second string (if flags_ == NO_STRING_ADD_FLAGS) |
4572 Label string_add_flat_result, longer_than_two; | 4572 Label string_add_flat_result, longer_than_two; |
4573 __ bind(&both_not_zero_length); | 4573 __ bind(&both_not_zero_length); |
4574 | 4574 |
4575 // If arguments where known to be strings, maps are not loaded to r8 and r9 | 4575 // If arguments where known to be strings, maps are not loaded to r8 and r9 |
4576 // by the code above. | 4576 // by the code above. |
4577 if (flags_ != NO_STRING_ADD_FLAGS) { | 4577 if ((flags_ & STRING_ADD_CHECK_BOTH) != STRING_ADD_CHECK_BOTH) { |
4578 __ movq(r8, FieldOperand(rax, HeapObject::kMapOffset)); | 4578 __ movq(r8, FieldOperand(rax, HeapObject::kMapOffset)); |
4579 __ movq(r9, FieldOperand(rdx, HeapObject::kMapOffset)); | 4579 __ movq(r9, FieldOperand(rdx, HeapObject::kMapOffset)); |
4580 } | 4580 } |
4581 // Get the instance types of the two strings as they will be needed soon. | 4581 // Get the instance types of the two strings as they will be needed soon. |
4582 __ movzxbl(r8, FieldOperand(r8, Map::kInstanceTypeOffset)); | 4582 __ movzxbl(r8, FieldOperand(r8, Map::kInstanceTypeOffset)); |
4583 __ movzxbl(r9, FieldOperand(r9, Map::kInstanceTypeOffset)); | 4583 __ movzxbl(r9, FieldOperand(r9, Map::kInstanceTypeOffset)); |
4584 | 4584 |
4585 // Look at the length of the result of adding the two strings. | 4585 // Look at the length of the result of adding the two strings. |
4586 STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue / 2); | 4586 STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue / 2); |
4587 __ SmiAdd(rbx, rbx, rcx); | 4587 __ SmiAdd(rbx, rbx, rcx); |
(...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4787 // rbx: next character of result | 4787 // rbx: next character of result |
4788 // rdx: first char of second string | 4788 // rdx: first char of second string |
4789 // r15: length of second string | 4789 // r15: length of second string |
4790 StringHelper::GenerateCopyCharacters(masm, rbx, rdx, r15, false); | 4790 StringHelper::GenerateCopyCharacters(masm, rbx, rdx, r15, false); |
4791 __ IncrementCounter(counters->string_add_native(), 1); | 4791 __ IncrementCounter(counters->string_add_native(), 1); |
4792 __ ret(2 * kPointerSize); | 4792 __ ret(2 * kPointerSize); |
4793 | 4793 |
4794 // Just jump to runtime to add the two strings. | 4794 // Just jump to runtime to add the two strings. |
4795 __ bind(&call_runtime); | 4795 __ bind(&call_runtime); |
4796 | 4796 |
4797 if ((flags_ & ERECT_FRAME) != 0) { | 4797 if ((flags_ & STRING_ADD_ERECT_FRAME) != 0) { |
4798 GenerateRegisterArgsPop(masm, rcx); | 4798 GenerateRegisterArgsPop(masm, rcx); |
4799 // Build a frame | 4799 // Build a frame |
4800 { | 4800 { |
4801 FrameScope scope(masm, StackFrame::INTERNAL); | 4801 FrameScope scope(masm, StackFrame::INTERNAL); |
4802 GenerateRegisterArgsPush(masm); | 4802 GenerateRegisterArgsPush(masm); |
4803 __ CallRuntime(Runtime::kStringAdd, 2); | 4803 __ CallRuntime(Runtime::kStringAdd, 2); |
4804 } | 4804 } |
4805 __ Ret(); | 4805 __ Ret(); |
4806 } else { | 4806 } else { |
4807 __ TailCallRuntime(Runtime::kStringAdd, 2, 1); | 4807 __ TailCallRuntime(Runtime::kStringAdd, 2, 1); |
4808 } | 4808 } |
4809 | 4809 |
4810 if (call_builtin.is_linked()) { | 4810 if (call_builtin.is_linked()) { |
4811 __ bind(&call_builtin); | 4811 __ bind(&call_builtin); |
4812 if ((flags_ & ERECT_FRAME) != 0) { | 4812 if ((flags_ & STRING_ADD_ERECT_FRAME) != 0) { |
4813 GenerateRegisterArgsPop(masm, rcx); | 4813 GenerateRegisterArgsPop(masm, rcx); |
4814 // Build a frame | 4814 // Build a frame |
4815 { | 4815 { |
4816 FrameScope scope(masm, StackFrame::INTERNAL); | 4816 FrameScope scope(masm, StackFrame::INTERNAL); |
4817 GenerateRegisterArgsPush(masm); | 4817 GenerateRegisterArgsPush(masm); |
4818 __ InvokeBuiltin(builtin_id, CALL_FUNCTION); | 4818 __ InvokeBuiltin(builtin_id, CALL_FUNCTION); |
4819 } | 4819 } |
4820 __ Ret(); | 4820 __ Ret(); |
4821 } else { | 4821 } else { |
4822 __ InvokeBuiltin(builtin_id, JUMP_FUNCTION); | 4822 __ InvokeBuiltin(builtin_id, JUMP_FUNCTION); |
(...skipping 2004 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6827 __ bind(&fast_elements_case); | 6827 __ bind(&fast_elements_case); |
6828 GenerateCase(masm, FAST_ELEMENTS); | 6828 GenerateCase(masm, FAST_ELEMENTS); |
6829 } | 6829 } |
6830 | 6830 |
6831 | 6831 |
6832 #undef __ | 6832 #undef __ |
6833 | 6833 |
6834 } } // namespace v8::internal | 6834 } } // namespace v8::internal |
6835 | 6835 |
6836 #endif // V8_TARGET_ARCH_X64 | 6836 #endif // V8_TARGET_ARCH_X64 |
OLD | NEW |