Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(222)

Side by Side Diff: src/x64/code-stubs-x64.cc

Issue 6542060: X64: Refactor the string add in the type recording binary operation stub... (Closed) Base URL: http://v8.googlecode.com/svn/branches/bleeding_edge/
Patch Set: '' Created 9 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/x64/code-stubs-x64.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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, &not_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(&not_string1);
1375 __ JumpIfNotString(rhs, rhs, &not_strings);
1376
1377 // Only second argument is a string.
1378 __ InvokeBuiltin(Builtins::STRING_ADD_RIGHT, JUMP_FUNCTION);
1379
1380 __ bind(&not_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
1433 Label not_smi; 1412 Label not_smi;
1434 1413
1435 GenerateSmiCode(masm, &not_smi, NO_HEAPNUMBER_RESULTS); 1414 GenerateSmiCode(masm, &not_smi, NO_HEAPNUMBER_RESULTS);
1436 1415
1437 __ bind(&not_smi); 1416 __ bind(&not_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, &not_number); 1433 GenerateFloatingPointCode(masm, &gc_required, &not_number);
1453 1434
1454 __ bind(&not_number); 1435 __ bind(&not_number);
1455 GenerateTypeTransition(masm); 1436 GenerateTypeTransition(masm);
(...skipping 2339 matching lines...) Expand 10 before | Expand all | Expand 10 after
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
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, &not_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(&not_string);
4064 // Puts the cached result into scratch1.
4065 NumberToStringStub::GenerateLookupNumberStringCache(masm,
4066 arg,
4067 scratch1,
4068 scratch2,
4069 scratch3,
4070 false,
4071 &not_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(&not_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
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
OLDNEW
« no previous file with comments | « src/x64/code-stubs-x64.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698