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 980 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
991 Label left_not_string, call_runtime; | 991 Label left_not_string, call_runtime; |
992 | 992 |
993 // Registers containing left and right operands respectively. | 993 // Registers containing left and right operands respectively. |
994 Register left = rdx; | 994 Register left = rdx; |
995 Register right = rax; | 995 Register right = rax; |
996 | 996 |
997 // Test if left operand is a string. | 997 // Test if left operand is a string. |
998 __ JumpIfSmi(left, &left_not_string, Label::kNear); | 998 __ JumpIfSmi(left, &left_not_string, Label::kNear); |
999 __ CmpObjectType(left, FIRST_NONSTRING_TYPE, rcx); | 999 __ CmpObjectType(left, FIRST_NONSTRING_TYPE, rcx); |
1000 __ j(above_equal, &left_not_string, Label::kNear); | 1000 __ j(above_equal, &left_not_string, Label::kNear); |
1001 StringAddStub string_add_left_stub((StringAddFlags) | 1001 StringAddStub string_add_left_stub( |
1002 (ERECT_FRAME | NO_STRING_CHECK_LEFT_IN_STUB)); | 1002 (StringAddFlags)(STRING_ADD_CHECK_RIGHT | STRING_ADD_ERECT_FRAME)); |
1003 BinaryOpStub_GenerateRegisterArgsPushUnderReturn(masm); | 1003 BinaryOpStub_GenerateRegisterArgsPushUnderReturn(masm); |
1004 __ TailCallStub(&string_add_left_stub); | 1004 __ TailCallStub(&string_add_left_stub); |
1005 | 1005 |
1006 // Left operand is not a string, test right. | 1006 // Left operand is not a string, test right. |
1007 __ bind(&left_not_string); | 1007 __ bind(&left_not_string); |
1008 __ JumpIfSmi(right, &call_runtime, Label::kNear); | 1008 __ JumpIfSmi(right, &call_runtime, Label::kNear); |
1009 __ CmpObjectType(right, FIRST_NONSTRING_TYPE, rcx); | 1009 __ CmpObjectType(right, FIRST_NONSTRING_TYPE, rcx); |
1010 __ j(above_equal, &call_runtime, Label::kNear); | 1010 __ j(above_equal, &call_runtime, Label::kNear); |
1011 | 1011 |
1012 StringAddStub string_add_right_stub((StringAddFlags) | 1012 StringAddStub string_add_right_stub( |
1013 (ERECT_FRAME | NO_STRING_CHECK_RIGHT_IN_STUB)); | 1013 (StringAddFlags)(STRING_ADD_CHECK_LEFT | STRING_ADD_ERECT_FRAME)); |
1014 BinaryOpStub_GenerateRegisterArgsPushUnderReturn(masm); | 1014 BinaryOpStub_GenerateRegisterArgsPushUnderReturn(masm); |
1015 __ TailCallStub(&string_add_right_stub); | 1015 __ TailCallStub(&string_add_right_stub); |
1016 | 1016 |
1017 // Neither argument is a string. | 1017 // Neither argument is a string. |
1018 __ bind(&call_runtime); | 1018 __ bind(&call_runtime); |
1019 } | 1019 } |
1020 | 1020 |
1021 | 1021 |
1022 void BinaryOpStub::GenerateSmiStub(MacroAssembler* masm) { | 1022 void BinaryOpStub::GenerateSmiStub(MacroAssembler* masm) { |
1023 Label right_arg_changed, call_runtime; | 1023 Label right_arg_changed, call_runtime; |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1078 // Test if left operand is a string. | 1078 // Test if left operand is a string. |
1079 __ JumpIfSmi(left, &call_runtime); | 1079 __ JumpIfSmi(left, &call_runtime); |
1080 __ CmpObjectType(left, FIRST_NONSTRING_TYPE, rcx); | 1080 __ CmpObjectType(left, FIRST_NONSTRING_TYPE, rcx); |
1081 __ j(above_equal, &call_runtime); | 1081 __ j(above_equal, &call_runtime); |
1082 | 1082 |
1083 // Test if right operand is a string. | 1083 // Test if right operand is a string. |
1084 __ JumpIfSmi(right, &call_runtime); | 1084 __ JumpIfSmi(right, &call_runtime); |
1085 __ CmpObjectType(right, FIRST_NONSTRING_TYPE, rcx); | 1085 __ CmpObjectType(right, FIRST_NONSTRING_TYPE, rcx); |
1086 __ j(above_equal, &call_runtime); | 1086 __ j(above_equal, &call_runtime); |
1087 | 1087 |
1088 StringAddStub string_add_stub((StringAddFlags) | 1088 StringAddStub string_add_stub( |
1089 (ERECT_FRAME | NO_STRING_CHECK_IN_STUB)); | 1089 (StringAddFlags)(STRING_ADD_CHECK_NONE | STRING_ADD_ERECT_FRAME)); |
1090 BinaryOpStub_GenerateRegisterArgsPushUnderReturn(masm); | 1090 BinaryOpStub_GenerateRegisterArgsPushUnderReturn(masm); |
1091 __ TailCallStub(&string_add_stub); | 1091 __ TailCallStub(&string_add_stub); |
1092 | 1092 |
1093 __ bind(&call_runtime); | 1093 __ bind(&call_runtime); |
1094 GenerateTypeTransition(masm); | 1094 GenerateTypeTransition(masm); |
1095 } | 1095 } |
1096 | 1096 |
1097 | 1097 |
1098 void BinaryOpStub::GenerateOddballStub(MacroAssembler* masm) { | 1098 void BinaryOpStub::GenerateOddballStub(MacroAssembler* masm) { |
1099 Label call_runtime; | 1099 Label call_runtime; |
(...skipping 3387 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4487 | 4487 |
4488 void StringAddStub::Generate(MacroAssembler* masm) { | 4488 void StringAddStub::Generate(MacroAssembler* masm) { |
4489 Label call_runtime, call_builtin; | 4489 Label call_runtime, call_builtin; |
4490 Builtins::JavaScript builtin_id = Builtins::ADD; | 4490 Builtins::JavaScript builtin_id = Builtins::ADD; |
4491 | 4491 |
4492 // Load the two arguments. | 4492 // Load the two arguments. |
4493 __ movq(rax, Operand(rsp, 2 * kPointerSize)); // First argument (left). | 4493 __ movq(rax, Operand(rsp, 2 * kPointerSize)); // First argument (left). |
4494 __ movq(rdx, Operand(rsp, 1 * kPointerSize)); // Second argument (right). | 4494 __ movq(rdx, Operand(rsp, 1 * kPointerSize)); // Second argument (right). |
4495 | 4495 |
4496 // Make sure that both arguments are strings if not known in advance. | 4496 // Make sure that both arguments are strings if not known in advance. |
4497 if ((flags_ & NO_STRING_ADD_FLAGS) != 0) { | 4497 // Otherwise, at least one of the arguments is definitely a string, |
| 4498 // and we convert the one that is not known to be a string. |
| 4499 if ((flags_ & STRING_ADD_CHECK_BOTH) == STRING_ADD_CHECK_BOTH) { |
4498 __ JumpIfSmi(rax, &call_runtime); | 4500 __ JumpIfSmi(rax, &call_runtime); |
4499 __ CmpObjectType(rax, FIRST_NONSTRING_TYPE, r8); | 4501 __ CmpObjectType(rax, FIRST_NONSTRING_TYPE, r8); |
4500 __ j(above_equal, &call_runtime); | 4502 __ j(above_equal, &call_runtime); |
4501 | 4503 |
4502 // First argument is a a string, test second. | 4504 // First argument is a a string, test second. |
4503 __ JumpIfSmi(rdx, &call_runtime); | 4505 __ JumpIfSmi(rdx, &call_runtime); |
4504 __ CmpObjectType(rdx, FIRST_NONSTRING_TYPE, r9); | 4506 __ CmpObjectType(rdx, FIRST_NONSTRING_TYPE, r9); |
4505 __ j(above_equal, &call_runtime); | 4507 __ j(above_equal, &call_runtime); |
4506 } else { | 4508 } else if ((flags_ & STRING_ADD_CHECK_LEFT) == STRING_ADD_CHECK_LEFT) { |
4507 // Here at least one of the arguments is definitely a string. | 4509 ASSERT((flags_ & STRING_ADD_CHECK_RIGHT) == 0); |
4508 // We convert the one that is not known to be a string. | 4510 GenerateConvertArgument(masm, 2 * kPointerSize, rax, rbx, rcx, rdi, |
4509 if ((flags_ & NO_STRING_CHECK_LEFT_IN_STUB) == 0) { | 4511 &call_builtin); |
4510 ASSERT((flags_ & NO_STRING_CHECK_RIGHT_IN_STUB) != 0); | 4512 builtin_id = Builtins::STRING_ADD_RIGHT; |
4511 GenerateConvertArgument(masm, 2 * kPointerSize, rax, rbx, rcx, rdi, | 4513 } else if ((flags_ & STRING_ADD_CHECK_RIGHT) == STRING_ADD_CHECK_RIGHT) { |
4512 &call_builtin); | 4514 ASSERT((flags_ & STRING_ADD_CHECK_LEFT) == 0); |
4513 builtin_id = Builtins::STRING_ADD_RIGHT; | 4515 GenerateConvertArgument(masm, 1 * kPointerSize, rdx, rbx, rcx, rdi, |
4514 } else if ((flags_ & NO_STRING_CHECK_RIGHT_IN_STUB) == 0) { | 4516 &call_builtin); |
4515 ASSERT((flags_ & NO_STRING_CHECK_LEFT_IN_STUB) != 0); | 4517 builtin_id = Builtins::STRING_ADD_LEFT; |
4516 GenerateConvertArgument(masm, 1 * kPointerSize, rdx, rbx, rcx, rdi, | |
4517 &call_builtin); | |
4518 builtin_id = Builtins::STRING_ADD_LEFT; | |
4519 } | |
4520 } | 4518 } |
4521 | 4519 |
4522 // Both arguments are strings. | 4520 // Both arguments are strings. |
4523 // rax: first string | 4521 // rax: first string |
4524 // rdx: second string | 4522 // rdx: second string |
4525 // Check if either of the strings are empty. In that case return the other. | 4523 // Check if either of the strings are empty. In that case return the other. |
4526 Label second_not_zero_length, both_not_zero_length; | 4524 Label second_not_zero_length, both_not_zero_length; |
4527 __ movq(rcx, FieldOperand(rdx, String::kLengthOffset)); | 4525 __ movq(rcx, FieldOperand(rdx, String::kLengthOffset)); |
4528 __ SmiTest(rcx); | 4526 __ SmiTest(rcx); |
4529 __ j(not_zero, &second_not_zero_length, Label::kNear); | 4527 __ j(not_zero, &second_not_zero_length, Label::kNear); |
(...skipping 15 matching lines...) Expand all Loading... |
4545 // rbx: length of first string | 4543 // rbx: length of first string |
4546 // rcx: length of second string | 4544 // rcx: length of second string |
4547 // rdx: second string | 4545 // rdx: second string |
4548 // r8: map of first string (if flags_ == NO_STRING_ADD_FLAGS) | 4546 // r8: map of first string (if flags_ == NO_STRING_ADD_FLAGS) |
4549 // r9: map of second string (if flags_ == NO_STRING_ADD_FLAGS) | 4547 // r9: map of second string (if flags_ == NO_STRING_ADD_FLAGS) |
4550 Label string_add_flat_result, longer_than_two; | 4548 Label string_add_flat_result, longer_than_two; |
4551 __ bind(&both_not_zero_length); | 4549 __ bind(&both_not_zero_length); |
4552 | 4550 |
4553 // If arguments where known to be strings, maps are not loaded to r8 and r9 | 4551 // If arguments where known to be strings, maps are not loaded to r8 and r9 |
4554 // by the code above. | 4552 // by the code above. |
4555 if (flags_ != NO_STRING_ADD_FLAGS) { | 4553 if ((flags_ & STRING_ADD_CHECK_BOTH) != STRING_ADD_CHECK_BOTH) { |
4556 __ movq(r8, FieldOperand(rax, HeapObject::kMapOffset)); | 4554 __ movq(r8, FieldOperand(rax, HeapObject::kMapOffset)); |
4557 __ movq(r9, FieldOperand(rdx, HeapObject::kMapOffset)); | 4555 __ movq(r9, FieldOperand(rdx, HeapObject::kMapOffset)); |
4558 } | 4556 } |
4559 // Get the instance types of the two strings as they will be needed soon. | 4557 // Get the instance types of the two strings as they will be needed soon. |
4560 __ movzxbl(r8, FieldOperand(r8, Map::kInstanceTypeOffset)); | 4558 __ movzxbl(r8, FieldOperand(r8, Map::kInstanceTypeOffset)); |
4561 __ movzxbl(r9, FieldOperand(r9, Map::kInstanceTypeOffset)); | 4559 __ movzxbl(r9, FieldOperand(r9, Map::kInstanceTypeOffset)); |
4562 | 4560 |
4563 // Look at the length of the result of adding the two strings. | 4561 // Look at the length of the result of adding the two strings. |
4564 STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue / 2); | 4562 STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue / 2); |
4565 __ SmiAdd(rbx, rbx, rcx); | 4563 __ SmiAdd(rbx, rbx, rcx); |
(...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4765 // rbx: next character of result | 4763 // rbx: next character of result |
4766 // rdx: first char of second string | 4764 // rdx: first char of second string |
4767 // r15: length of second string | 4765 // r15: length of second string |
4768 StringHelper::GenerateCopyCharacters(masm, rbx, rdx, r15, false); | 4766 StringHelper::GenerateCopyCharacters(masm, rbx, rdx, r15, false); |
4769 __ IncrementCounter(counters->string_add_native(), 1); | 4767 __ IncrementCounter(counters->string_add_native(), 1); |
4770 __ ret(2 * kPointerSize); | 4768 __ ret(2 * kPointerSize); |
4771 | 4769 |
4772 // Just jump to runtime to add the two strings. | 4770 // Just jump to runtime to add the two strings. |
4773 __ bind(&call_runtime); | 4771 __ bind(&call_runtime); |
4774 | 4772 |
4775 if ((flags_ & ERECT_FRAME) != 0) { | 4773 if ((flags_ & STRING_ADD_ERECT_FRAME) != 0) { |
4776 GenerateRegisterArgsPop(masm, rcx); | 4774 GenerateRegisterArgsPop(masm, rcx); |
4777 // Build a frame | 4775 // Build a frame |
4778 { | 4776 { |
4779 FrameScope scope(masm, StackFrame::INTERNAL); | 4777 FrameScope scope(masm, StackFrame::INTERNAL); |
4780 GenerateRegisterArgsPush(masm); | 4778 GenerateRegisterArgsPush(masm); |
4781 __ CallRuntime(Runtime::kStringAdd, 2); | 4779 __ CallRuntime(Runtime::kStringAdd, 2); |
4782 } | 4780 } |
4783 __ Ret(); | 4781 __ Ret(); |
4784 } else { | 4782 } else { |
4785 __ TailCallRuntime(Runtime::kStringAdd, 2, 1); | 4783 __ TailCallRuntime(Runtime::kStringAdd, 2, 1); |
4786 } | 4784 } |
4787 | 4785 |
4788 if (call_builtin.is_linked()) { | 4786 if (call_builtin.is_linked()) { |
4789 __ bind(&call_builtin); | 4787 __ bind(&call_builtin); |
4790 if ((flags_ & ERECT_FRAME) != 0) { | 4788 if ((flags_ & STRING_ADD_ERECT_FRAME) != 0) { |
4791 GenerateRegisterArgsPop(masm, rcx); | 4789 GenerateRegisterArgsPop(masm, rcx); |
4792 // Build a frame | 4790 // Build a frame |
4793 { | 4791 { |
4794 FrameScope scope(masm, StackFrame::INTERNAL); | 4792 FrameScope scope(masm, StackFrame::INTERNAL); |
4795 GenerateRegisterArgsPush(masm); | 4793 GenerateRegisterArgsPush(masm); |
4796 __ InvokeBuiltin(builtin_id, CALL_FUNCTION); | 4794 __ InvokeBuiltin(builtin_id, CALL_FUNCTION); |
4797 } | 4795 } |
4798 __ Ret(); | 4796 __ Ret(); |
4799 } else { | 4797 } else { |
4800 __ InvokeBuiltin(builtin_id, JUMP_FUNCTION); | 4798 __ InvokeBuiltin(builtin_id, JUMP_FUNCTION); |
(...skipping 2010 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6811 __ bind(&fast_elements_case); | 6809 __ bind(&fast_elements_case); |
6812 GenerateCase(masm, FAST_ELEMENTS); | 6810 GenerateCase(masm, FAST_ELEMENTS); |
6813 } | 6811 } |
6814 | 6812 |
6815 | 6813 |
6816 #undef __ | 6814 #undef __ |
6817 | 6815 |
6818 } } // namespace v8::internal | 6816 } } // namespace v8::internal |
6819 | 6817 |
6820 #endif // V8_TARGET_ARCH_X64 | 6818 #endif // V8_TARGET_ARCH_X64 |
OLD | NEW |