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 1318 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1329 } | 1329 } |
1330 // No fall-through from this generated code. | 1330 // No fall-through from this generated code. |
1331 if (FLAG_debug_code) { | 1331 if (FLAG_debug_code) { |
1332 __ Abort("Unexpected fall-through in " | 1332 __ Abort("Unexpected fall-through in " |
1333 "TypeRecordingBinaryStub::GenerateFloatingPointCode."); | 1333 "TypeRecordingBinaryStub::GenerateFloatingPointCode."); |
1334 } | 1334 } |
1335 } | 1335 } |
1336 | 1336 |
1337 | 1337 |
1338 void TypeRecordingBinaryOpStub::GenerateStringAddCode(MacroAssembler* masm) { | 1338 void TypeRecordingBinaryOpStub::GenerateStringAddCode(MacroAssembler* masm) { |
| 1339 ASSERT(op_ == Token::ADD); |
| 1340 NearLabel left_not_string, call_runtime; |
| 1341 |
| 1342 // Registers containing left and right operands respectively. |
| 1343 Register left = rdx; |
| 1344 Register right = rax; |
| 1345 |
| 1346 // Test if left operand is a string. |
| 1347 __ JumpIfSmi(left, &left_not_string); |
| 1348 __ CmpObjectType(left, FIRST_NONSTRING_TYPE, rcx); |
| 1349 __ j(above_equal, &left_not_string); |
| 1350 StringAddStub string_add_left_stub(NO_STRING_CHECK_LEFT_IN_STUB); |
1339 GenerateRegisterArgsPush(masm); | 1351 GenerateRegisterArgsPush(masm); |
1340 // Registers containing left and right operands respectively. | 1352 __ TailCallStub(&string_add_left_stub); |
1341 Register lhs = rdx; | |
1342 Register rhs = rax; | |
1343 | 1353 |
1344 // Test for string arguments before calling runtime. | 1354 // Left operand is not a string, test right. |
1345 Label not_strings, both_strings, not_string1, string1, string1_smi2; | 1355 __ bind(&left_not_string); |
| 1356 __ JumpIfSmi(right, &call_runtime); |
| 1357 __ CmpObjectType(right, FIRST_NONSTRING_TYPE, rcx); |
| 1358 __ j(above_equal, &call_runtime); |
1346 | 1359 |
1347 __ JumpIfNotString(lhs, r8, ¬_string1); | 1360 StringAddStub string_add_right_stub(NO_STRING_CHECK_RIGHT_IN_STUB); |
| 1361 GenerateRegisterArgsPush(masm); |
| 1362 __ TailCallStub(&string_add_right_stub); |
1348 | 1363 |
1349 // First argument is a a string, test second. | |
1350 __ JumpIfSmi(rhs, &string1_smi2); | |
1351 __ CmpObjectType(rhs, FIRST_NONSTRING_TYPE, r9); | |
1352 __ j(above_equal, &string1); | |
1353 | |
1354 // First and second argument are strings. | |
1355 StringAddStub string_add_stub(NO_STRING_CHECK_IN_STUB); | |
1356 __ TailCallStub(&string_add_stub); | |
1357 | |
1358 __ bind(&string1_smi2); | |
1359 // First argument is a string, second is a smi. Try to lookup the number | |
1360 // string for the smi in the number string cache. | |
1361 NumberToStringStub::GenerateLookupNumberStringCache( | |
1362 masm, rhs, rbx, rcx, r8, true, &string1); | |
1363 | |
1364 // Replace second argument on stack and tailcall string add stub to make | |
1365 // the result. | |
1366 __ movq(Operand(rsp, 1 * kPointerSize), rbx); | |
1367 __ TailCallStub(&string_add_stub); | |
1368 | |
1369 // Only first argument is a string. | |
1370 __ bind(&string1); | |
1371 __ InvokeBuiltin(Builtins::STRING_ADD_LEFT, JUMP_FUNCTION); | |
1372 | |
1373 // First argument was not a string, test second. | |
1374 __ bind(¬_string1); | |
1375 __ JumpIfNotString(rhs, rhs, ¬_strings); | |
1376 | |
1377 // Only second argument is a string. | |
1378 __ InvokeBuiltin(Builtins::STRING_ADD_RIGHT, JUMP_FUNCTION); | |
1379 | |
1380 __ bind(¬_strings); | |
1381 // Neither argument is a string. | 1364 // Neither argument is a string. |
1382 // Pop arguments, because CallRuntimeCode wants to push them again. | 1365 __ bind(&call_runtime); |
1383 __ pop(rcx); | |
1384 __ pop(rax); | |
1385 __ pop(rdx); | |
1386 __ push(rcx); | |
1387 } | 1366 } |
1388 | 1367 |
1389 | 1368 |
1390 void TypeRecordingBinaryOpStub::GenerateCallRuntimeCode(MacroAssembler* masm) { | 1369 void TypeRecordingBinaryOpStub::GenerateCallRuntimeCode(MacroAssembler* masm) { |
1391 GenerateRegisterArgsPush(masm); | 1370 GenerateRegisterArgsPush(masm); |
1392 switch (op_) { | 1371 switch (op_) { |
1393 case Token::ADD: | 1372 case Token::ADD: |
1394 __ InvokeBuiltin(Builtins::ADD, JUMP_FUNCTION); | 1373 __ InvokeBuiltin(Builtins::ADD, JUMP_FUNCTION); |
1395 break; | 1374 break; |
1396 case Token::SUB: | 1375 case Token::SUB: |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1433 Label not_smi; | 1412 Label not_smi; |
1434 | 1413 |
1435 GenerateSmiCode(masm, ¬_smi, NO_HEAPNUMBER_RESULTS); | 1414 GenerateSmiCode(masm, ¬_smi, NO_HEAPNUMBER_RESULTS); |
1436 | 1415 |
1437 __ bind(¬_smi); | 1416 __ bind(¬_smi); |
1438 GenerateTypeTransition(masm); | 1417 GenerateTypeTransition(masm); |
1439 } | 1418 } |
1440 | 1419 |
1441 | 1420 |
1442 void TypeRecordingBinaryOpStub::GenerateStringStub(MacroAssembler* masm) { | 1421 void TypeRecordingBinaryOpStub::GenerateStringStub(MacroAssembler* masm) { |
| 1422 ASSERT(operands_type_ == TRBinaryOpIC::STRING); |
1443 ASSERT(op_ == Token::ADD); | 1423 ASSERT(op_ == Token::ADD); |
1444 GenerateStringAddCode(masm); | 1424 GenerateStringAddCode(masm); |
1445 | 1425 // Try to add arguments as strings, otherwise, transition to the generic |
| 1426 // TRBinaryOpIC type. |
1446 GenerateTypeTransition(masm); | 1427 GenerateTypeTransition(masm); |
1447 } | 1428 } |
1448 | 1429 |
1449 | 1430 |
1450 void TypeRecordingBinaryOpStub::GenerateHeapNumberStub(MacroAssembler* masm) { | 1431 void TypeRecordingBinaryOpStub::GenerateHeapNumberStub(MacroAssembler* masm) { |
1451 Label gc_required, not_number; | 1432 Label gc_required, not_number; |
1452 GenerateFloatingPointCode(masm, &gc_required, ¬_number); | 1433 GenerateFloatingPointCode(masm, &gc_required, ¬_number); |
1453 | 1434 |
1454 __ bind(¬_number); | 1435 __ bind(¬_number); |
1455 GenerateTypeTransition(masm); | 1436 GenerateTypeTransition(masm); |
(...skipping 2339 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3795 | 3776 |
3796 | 3777 |
3797 void StringCharAtGenerator::GenerateSlow( | 3778 void StringCharAtGenerator::GenerateSlow( |
3798 MacroAssembler* masm, const RuntimeCallHelper& call_helper) { | 3779 MacroAssembler* masm, const RuntimeCallHelper& call_helper) { |
3799 char_code_at_generator_.GenerateSlow(masm, call_helper); | 3780 char_code_at_generator_.GenerateSlow(masm, call_helper); |
3800 char_from_code_generator_.GenerateSlow(masm, call_helper); | 3781 char_from_code_generator_.GenerateSlow(masm, call_helper); |
3801 } | 3782 } |
3802 | 3783 |
3803 | 3784 |
3804 void StringAddStub::Generate(MacroAssembler* masm) { | 3785 void StringAddStub::Generate(MacroAssembler* masm) { |
3805 Label string_add_runtime; | 3786 Label string_add_runtime, call_builtin; |
| 3787 Builtins::JavaScript builtin_id = Builtins::ADD; |
3806 | 3788 |
3807 // Load the two arguments. | 3789 // Load the two arguments. |
3808 __ movq(rax, Operand(rsp, 2 * kPointerSize)); // First argument. | 3790 __ movq(rax, Operand(rsp, 2 * kPointerSize)); // First argument (left). |
3809 __ movq(rdx, Operand(rsp, 1 * kPointerSize)); // Second argument. | 3791 __ movq(rdx, Operand(rsp, 1 * kPointerSize)); // Second argument (right). |
3810 | 3792 |
3811 // Make sure that both arguments are strings if not known in advance. | 3793 // Make sure that both arguments are strings if not known in advance. |
3812 if (string_check_) { | 3794 if (flags_ == NO_STRING_ADD_FLAGS) { |
3813 Condition is_smi; | 3795 Condition is_smi; |
3814 is_smi = masm->CheckSmi(rax); | 3796 is_smi = masm->CheckSmi(rax); |
3815 __ j(is_smi, &string_add_runtime); | 3797 __ j(is_smi, &string_add_runtime); |
3816 __ CmpObjectType(rax, FIRST_NONSTRING_TYPE, r8); | 3798 __ CmpObjectType(rax, FIRST_NONSTRING_TYPE, r8); |
3817 __ j(above_equal, &string_add_runtime); | 3799 __ j(above_equal, &string_add_runtime); |
3818 | 3800 |
3819 // First argument is a a string, test second. | 3801 // First argument is a a string, test second. |
3820 is_smi = masm->CheckSmi(rdx); | 3802 is_smi = masm->CheckSmi(rdx); |
3821 __ j(is_smi, &string_add_runtime); | 3803 __ j(is_smi, &string_add_runtime); |
3822 __ CmpObjectType(rdx, FIRST_NONSTRING_TYPE, r9); | 3804 __ CmpObjectType(rdx, FIRST_NONSTRING_TYPE, r9); |
3823 __ j(above_equal, &string_add_runtime); | 3805 __ j(above_equal, &string_add_runtime); |
| 3806 } else { |
| 3807 // Here at least one of the arguments is definitely a string. |
| 3808 // We convert the one that is not known to be a string. |
| 3809 if ((flags_ & NO_STRING_CHECK_LEFT_IN_STUB) == 0) { |
| 3810 ASSERT((flags_ & NO_STRING_CHECK_RIGHT_IN_STUB) != 0); |
| 3811 GenerateConvertArgument(masm, 2 * kPointerSize, rax, rbx, rcx, rdi, |
| 3812 &call_builtin); |
| 3813 builtin_id = Builtins::STRING_ADD_RIGHT; |
| 3814 } else if ((flags_ & NO_STRING_CHECK_RIGHT_IN_STUB) == 0) { |
| 3815 ASSERT((flags_ & NO_STRING_CHECK_LEFT_IN_STUB) != 0); |
| 3816 GenerateConvertArgument(masm, 1 * kPointerSize, rdx, rbx, rcx, rdi, |
| 3817 &call_builtin); |
| 3818 builtin_id = Builtins::STRING_ADD_LEFT; |
| 3819 } |
3824 } | 3820 } |
3825 | 3821 |
3826 // Both arguments are strings. | 3822 // Both arguments are strings. |
3827 // rax: first string | 3823 // rax: first string |
3828 // rdx: second string | 3824 // rdx: second string |
3829 // Check if either of the strings are empty. In that case return the other. | 3825 // Check if either of the strings are empty. In that case return the other. |
3830 NearLabel second_not_zero_length, both_not_zero_length; | 3826 NearLabel second_not_zero_length, both_not_zero_length; |
3831 __ movq(rcx, FieldOperand(rdx, String::kLengthOffset)); | 3827 __ movq(rcx, FieldOperand(rdx, String::kLengthOffset)); |
3832 __ SmiTest(rcx); | 3828 __ SmiTest(rcx); |
3833 __ j(not_zero, &second_not_zero_length); | 3829 __ j(not_zero, &second_not_zero_length); |
3834 // Second string is empty, result is first string which is already in rax. | 3830 // Second string is empty, result is first string which is already in rax. |
3835 __ IncrementCounter(&Counters::string_add_native, 1); | 3831 __ IncrementCounter(&Counters::string_add_native, 1); |
3836 __ ret(2 * kPointerSize); | 3832 __ ret(2 * kPointerSize); |
3837 __ bind(&second_not_zero_length); | 3833 __ bind(&second_not_zero_length); |
3838 __ movq(rbx, FieldOperand(rax, String::kLengthOffset)); | 3834 __ movq(rbx, FieldOperand(rax, String::kLengthOffset)); |
3839 __ SmiTest(rbx); | 3835 __ SmiTest(rbx); |
3840 __ j(not_zero, &both_not_zero_length); | 3836 __ j(not_zero, &both_not_zero_length); |
3841 // First string is empty, result is second string which is in rdx. | 3837 // First string is empty, result is second string which is in rdx. |
3842 __ movq(rax, rdx); | 3838 __ movq(rax, rdx); |
3843 __ IncrementCounter(&Counters::string_add_native, 1); | 3839 __ IncrementCounter(&Counters::string_add_native, 1); |
3844 __ ret(2 * kPointerSize); | 3840 __ ret(2 * kPointerSize); |
3845 | 3841 |
3846 // Both strings are non-empty. | 3842 // Both strings are non-empty. |
3847 // rax: first string | 3843 // rax: first string |
3848 // rbx: length of first string | 3844 // rbx: length of first string |
3849 // rcx: length of second string | 3845 // rcx: length of second string |
3850 // rdx: second string | 3846 // rdx: second string |
3851 // r8: map of first string if string check was performed above | 3847 // r8: map of first string (if flags_ == NO_STRING_ADD_FLAGS) |
3852 // r9: map of second string if string check was performed above | 3848 // r9: map of second string (if flags_ == NO_STRING_ADD_FLAGS) |
3853 Label string_add_flat_result, longer_than_two; | 3849 Label string_add_flat_result, longer_than_two; |
3854 __ bind(&both_not_zero_length); | 3850 __ bind(&both_not_zero_length); |
3855 | 3851 |
3856 // If arguments where known to be strings, maps are not loaded to r8 and r9 | 3852 // If arguments where known to be strings, maps are not loaded to r8 and r9 |
3857 // by the code above. | 3853 // by the code above. |
3858 if (!string_check_) { | 3854 if (flags_ != NO_STRING_ADD_FLAGS) { |
3859 __ movq(r8, FieldOperand(rax, HeapObject::kMapOffset)); | 3855 __ movq(r8, FieldOperand(rax, HeapObject::kMapOffset)); |
3860 __ movq(r9, FieldOperand(rdx, HeapObject::kMapOffset)); | 3856 __ movq(r9, FieldOperand(rdx, HeapObject::kMapOffset)); |
3861 } | 3857 } |
3862 // Get the instance types of the two strings as they will be needed soon. | 3858 // Get the instance types of the two strings as they will be needed soon. |
3863 __ movzxbl(r8, FieldOperand(r8, Map::kInstanceTypeOffset)); | 3859 __ movzxbl(r8, FieldOperand(r8, Map::kInstanceTypeOffset)); |
3864 __ movzxbl(r9, FieldOperand(r9, Map::kInstanceTypeOffset)); | 3860 __ movzxbl(r9, FieldOperand(r9, Map::kInstanceTypeOffset)); |
3865 | 3861 |
3866 // Look at the length of the result of adding the two strings. | 3862 // Look at the length of the result of adding the two strings. |
3867 STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue / 2); | 3863 STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue / 2); |
3868 __ SmiAdd(rbx, rbx, rcx); | 3864 __ SmiAdd(rbx, rbx, rcx); |
(...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4034 // rdx: first char of second argument | 4030 // rdx: first char of second argument |
4035 // rdi: length of second argument | 4031 // rdi: length of second argument |
4036 StringHelper::GenerateCopyCharacters(masm, rcx, rdx, rdi, false); | 4032 StringHelper::GenerateCopyCharacters(masm, rcx, rdx, rdi, false); |
4037 __ movq(rax, rbx); | 4033 __ movq(rax, rbx); |
4038 __ IncrementCounter(&Counters::string_add_native, 1); | 4034 __ IncrementCounter(&Counters::string_add_native, 1); |
4039 __ ret(2 * kPointerSize); | 4035 __ ret(2 * kPointerSize); |
4040 | 4036 |
4041 // Just jump to runtime to add the two strings. | 4037 // Just jump to runtime to add the two strings. |
4042 __ bind(&string_add_runtime); | 4038 __ bind(&string_add_runtime); |
4043 __ TailCallRuntime(Runtime::kStringAdd, 2, 1); | 4039 __ TailCallRuntime(Runtime::kStringAdd, 2, 1); |
| 4040 |
| 4041 if (call_builtin.is_linked()) { |
| 4042 __ bind(&call_builtin); |
| 4043 __ InvokeBuiltin(builtin_id, JUMP_FUNCTION); |
| 4044 } |
| 4045 } |
| 4046 |
| 4047 |
| 4048 void StringAddStub::GenerateConvertArgument(MacroAssembler* masm, |
| 4049 int stack_offset, |
| 4050 Register arg, |
| 4051 Register scratch1, |
| 4052 Register scratch2, |
| 4053 Register scratch3, |
| 4054 Label* slow) { |
| 4055 // First check if the argument is already a string. |
| 4056 Label not_string, done; |
| 4057 __ JumpIfSmi(arg, ¬_string); |
| 4058 __ CmpObjectType(arg, FIRST_NONSTRING_TYPE, scratch1); |
| 4059 __ j(below, &done); |
| 4060 |
| 4061 // Check the number to string cache. |
| 4062 Label not_cached; |
| 4063 __ bind(¬_string); |
| 4064 // Puts the cached result into scratch1. |
| 4065 NumberToStringStub::GenerateLookupNumberStringCache(masm, |
| 4066 arg, |
| 4067 scratch1, |
| 4068 scratch2, |
| 4069 scratch3, |
| 4070 false, |
| 4071 ¬_cached); |
| 4072 __ movq(arg, scratch1); |
| 4073 __ movq(Operand(rsp, stack_offset), arg); |
| 4074 __ jmp(&done); |
| 4075 |
| 4076 // Check if the argument is a safe string wrapper. |
| 4077 __ bind(¬_cached); |
| 4078 __ JumpIfSmi(arg, slow); |
| 4079 __ CmpObjectType(arg, JS_VALUE_TYPE, scratch1); // map -> scratch1. |
| 4080 __ j(not_equal, slow); |
| 4081 __ testb(FieldOperand(scratch1, Map::kBitField2Offset), |
| 4082 Immediate(1 << Map::kStringWrapperSafeForDefaultValueOf)); |
| 4083 __ j(zero, slow); |
| 4084 __ movq(arg, FieldOperand(arg, JSValue::kValueOffset)); |
| 4085 __ movq(Operand(rsp, stack_offset), arg); |
| 4086 |
| 4087 __ bind(&done); |
4044 } | 4088 } |
4045 | 4089 |
4046 | 4090 |
4047 void StringHelper::GenerateCopyCharacters(MacroAssembler* masm, | 4091 void StringHelper::GenerateCopyCharacters(MacroAssembler* masm, |
4048 Register dest, | 4092 Register dest, |
4049 Register src, | 4093 Register src, |
4050 Register count, | 4094 Register count, |
4051 bool ascii) { | 4095 bool ascii) { |
4052 Label loop; | 4096 Label loop; |
4053 __ bind(&loop); | 4097 __ bind(&loop); |
(...skipping 768 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4822 FieldOperand(elements, PixelArray::kExternalPointerOffset)); | 4866 FieldOperand(elements, PixelArray::kExternalPointerOffset)); |
4823 __ movb(Operand(external_pointer, untagged_key, times_1, 0), untagged_value); | 4867 __ movb(Operand(external_pointer, untagged_key, times_1, 0), untagged_value); |
4824 __ ret(0); // Return value in eax. | 4868 __ ret(0); // Return value in eax. |
4825 } | 4869 } |
4826 | 4870 |
4827 #undef __ | 4871 #undef __ |
4828 | 4872 |
4829 } } // namespace v8::internal | 4873 } } // namespace v8::internal |
4830 | 4874 |
4831 #endif // V8_TARGET_ARCH_X64 | 4875 #endif // V8_TARGET_ARCH_X64 |
OLD | NEW |