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

Side by Side Diff: src/x64/codegen-x64.cc

Issue 545108: X64 implementation of native ascii string compare. (Closed)
Patch Set: Created 10 years, 11 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
« no previous file with comments | « src/x64/codegen-x64.h ('k') | src/x64/macro-assembler-x64.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2009 the V8 project authors. All rights reserved. 1 // Copyright 2009 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 3919 matching lines...) Expand 10 before | Expand all | Expand 10 after
3930 frame_->Push(&answer); 3930 frame_->Push(&answer);
3931 } 3931 }
3932 3932
3933 3933
3934 void CodeGenerator::GenerateStringCompare(ZoneList<Expression*>* args) { 3934 void CodeGenerator::GenerateStringCompare(ZoneList<Expression*>* args) {
3935 ASSERT_EQ(2, args->length()); 3935 ASSERT_EQ(2, args->length());
3936 3936
3937 Load(args->at(0)); 3937 Load(args->at(0));
3938 Load(args->at(1)); 3938 Load(args->at(1));
3939 3939
3940 Result answer = frame_->CallRuntime(Runtime::kStringCompare, 2); 3940 StringCompareStub stub;
3941 Result answer = frame_->CallStub(&stub, 2);
3941 frame_->Push(&answer); 3942 frame_->Push(&answer);
3942 } 3943 }
3943 3944
3944 3945
3945 void CodeGenerator::GenerateClassOf(ZoneList<Expression*>* args) { 3946 void CodeGenerator::GenerateClassOf(ZoneList<Expression*>* args) {
3946 ASSERT(args->length() == 1); 3947 ASSERT(args->length() == 1);
3947 JumpTarget leave, null, function, non_function_constructor; 3948 JumpTarget leave, null, function, non_function_constructor;
3948 Load(args->at(0)); // Load the object. 3949 Load(args->at(0)); // Load the object.
3949 Result obj = frame_->Pop(); 3950 Result obj = frame_->Pop();
3950 obj.ToRegister(); 3951 obj.ToRegister();
(...skipping 2538 matching lines...) Expand 10 before | Expand all | Expand 10 after
6489 __ bind(&below_lbl); 6490 __ bind(&below_lbl);
6490 __ movq(rax, Immediate(-1)); 6491 __ movq(rax, Immediate(-1));
6491 __ ret(2 * kPointerSize); 6492 __ ret(2 * kPointerSize);
6492 6493
6493 __ bind(&above_lbl); 6494 __ bind(&above_lbl);
6494 __ movq(rax, Immediate(1)); 6495 __ movq(rax, Immediate(1));
6495 __ ret(2 * kPointerSize); // rax, rdx were pushed 6496 __ ret(2 * kPointerSize); // rax, rdx were pushed
6496 6497
6497 // Fast negative check for symbol-to-symbol equality. 6498 // Fast negative check for symbol-to-symbol equality.
6498 __ bind(&check_for_symbols); 6499 __ bind(&check_for_symbols);
6500 Label check_for_strings;
6499 if (cc_ == equal) { 6501 if (cc_ == equal) {
6500 BranchIfNonSymbol(masm, &call_builtin, rax, kScratchRegister); 6502 BranchIfNonSymbol(masm, &check_for_strings, rax, kScratchRegister);
6501 BranchIfNonSymbol(masm, &call_builtin, rdx, kScratchRegister); 6503 BranchIfNonSymbol(masm, &check_for_strings, rdx, kScratchRegister);
6502 6504
6503 // We've already checked for object identity, so if both operands 6505 // We've already checked for object identity, so if both operands
6504 // are symbols they aren't equal. Register eax (not rax) already holds a 6506 // are symbols they aren't equal. Register eax (not rax) already holds a
6505 // non-zero value, which indicates not equal, so just return. 6507 // non-zero value, which indicates not equal, so just return.
6506 __ ret(2 * kPointerSize); 6508 __ ret(2 * kPointerSize);
6507 } 6509 }
6508 6510
6511 __ bind(&check_for_strings);
6512 Condition either_smi = masm->CheckEitherSmi(rax, rdx);
6513 __ j(either_smi, &call_builtin);
6514
6515 // Load instance type for both objects to check if they are flat
6516 // ASCII strings.
6517 __ movq(rcx, FieldOperand(rdx, HeapObject::kMapOffset));
6518 __ movq(rbx, FieldOperand(rax, HeapObject::kMapOffset));
6519 __ movzxbl(rcx, FieldOperand(rcx, Map::kInstanceTypeOffset));
6520 __ movzxbl(rbx, FieldOperand(rbx, Map::kInstanceTypeOffset));
6521
6522 Label non_ascii_flat;
6523 ASSERT(kNotStringTag != 0);
6524 const int kFlatAsciiStringMask =
6525 kIsNotStringMask | kStringRepresentationMask | kStringEncodingMask;
6526 const int kFlatAsciiStringBits =
6527 kNotStringTag | kSeqStringTag | kAsciiStringTag;
6528
6529 __ andl(rcx, Immediate(kFlatAsciiStringMask));
6530 __ andl(rbx, Immediate(kFlatAsciiStringMask));
6531 // Interleave the bits to check both rcx and rbx in one test.
6532 ASSERT_EQ(0, kFlatAsciiStringMask & (kFlatAsciiStringMask << 3));
6533 __ lea(rcx, Operand(rcx, rbx, times_8, 0));
6534 __ cmpl(rcx, Immediate(kFlatAsciiStringBits + (kFlatAsciiStringBits << 3)));
6535 __ j(not_equal, &call_builtin);
6536
6537 // Inline comparison of ascii strings.
6538 StringCompareStub::GenerateCompareFlatAsciiStrings(masm,
6539 rdx,
6540 rax,
6541 rcx,
6542 rbx,
6543 rdi,
6544 r8);
6545
6546 #ifdef DEBUG
6547 __ Abort("Unexpected fall-through from string comparison");
6548 #endif
6549
6509 __ bind(&call_builtin); 6550 __ bind(&call_builtin);
6510 // must swap argument order 6551 // must swap argument order
6511 __ pop(rcx); 6552 __ pop(rcx);
6512 __ pop(rdx); 6553 __ pop(rdx);
6513 __ pop(rax); 6554 __ pop(rax);
6514 __ push(rdx); 6555 __ push(rdx);
6515 __ push(rax); 6556 __ push(rax);
6516 6557
6517 // Figure out which native to call and setup the arguments. 6558 // Figure out which native to call and setup the arguments.
6518 Builtins::JavaScript builtin; 6559 Builtins::JavaScript builtin;
(...skipping 1601 matching lines...) Expand 10 before | Expand all | Expand 10 after
8120 __ movzxwl(kScratchRegister, Operand(src, 0)); 8161 __ movzxwl(kScratchRegister, Operand(src, 0));
8121 __ movw(Operand(dest, 0), kScratchRegister); 8162 __ movw(Operand(dest, 0), kScratchRegister);
8122 __ addq(src, Immediate(2)); 8163 __ addq(src, Immediate(2));
8123 __ addq(dest, Immediate(2)); 8164 __ addq(dest, Immediate(2));
8124 } 8165 }
8125 __ subl(count, Immediate(1)); 8166 __ subl(count, Immediate(1));
8126 __ j(not_zero, &loop); 8167 __ j(not_zero, &loop);
8127 } 8168 }
8128 8169
8129 8170
8171
8172 void StringCompareStub::GenerateCompareFlatAsciiStrings(MacroAssembler* masm,
8173 Register left,
8174 Register right,
8175 Register scratch1,
8176 Register scratch2,
8177 Register scratch3,
8178 Register scratch4) {
8179 // Ensure that you can always subtract a string length from a non-negative
8180 // number (e.g. another length).
8181 ASSERT(String::kMaxLength < 0x7fffffff);
8182
8183 // Find minimum length and length difference.
8184 __ movl(scratch1, FieldOperand(left, String::kLengthOffset));
8185 __ movl(scratch4, scratch1);
8186 __ subl(scratch4, FieldOperand(right, String::kLengthOffset));
8187 // Register scratch4 now holds left.length - right.length.
8188 const Register length_difference = scratch4;
8189 Label left_shorter;
8190 __ j(less, &left_shorter);
8191 // The right string isn't longer that the left one.
8192 // Get the right string's length by subtracting the (non-negative) difference
8193 // from the left string's length.
8194 __ subl(scratch1, length_difference);
8195 __ bind(&left_shorter);
8196 // Register scratch1 now holds Min(left.length, right.length).
8197 const Register min_length = scratch1;
8198
8199 Label compare_lengths;
8200 // If min-length is zero, go directly to comparing lengths.
8201 __ testl(min_length, min_length);
8202 __ j(zero, &compare_lengths);
8203
8204 // Registers scratch2 and scratch3 are free.
8205 Label result_not_equal;
8206 Label loop;
8207 {
8208 // Check characters 0 .. min_length - 1 in a loop.
8209 // Use scratch3 as loop index, min_length as limit and scratch2
8210 // for computation.
8211 const Register index = scratch3;
8212 __ movl(index, Immediate(0)); // Index into strings.
8213 __ bind(&loop);
8214 // Compare characters.
8215 // TODO(lrn): Could we load more than one character at a time?
8216 __ movb(scratch2, FieldOperand(left,
8217 index,
8218 times_1,
8219 SeqAsciiString::kHeaderSize));
8220 // Increment index and use -1 modifier on next load to give
8221 // the previous load extra time to complete.
8222 __ addl(index, Immediate(1));
8223 __ cmpb(scratch2, FieldOperand(right,
8224 index,
8225 times_1,
8226 SeqAsciiString::kHeaderSize - 1));
8227 __ j(not_equal, &result_not_equal);
8228 __ cmpl(index, min_length);
8229 __ j(not_equal, &loop);
8230 }
8231 // Completed loop without finding different characters.
8232 // Compare lengths (precomputed).
8233 __ bind(&compare_lengths);
8234 __ testl(length_difference, length_difference);
8235 __ j(not_zero, &result_not_equal);
8236
8237 // Result is EQUAL.
8238 __ Move(rax, Smi::FromInt(EQUAL));
8239 __ IncrementCounter(&Counters::string_compare_native, 1);
8240 __ ret(2 * kPointerSize);
8241
8242 Label result_greater;
8243 __ bind(&result_not_equal);
8244 // Unequal comparison of left to right, either character or length.
8245 __ j(greater, &result_greater);
8246
8247 // Result is LESS.
8248 __ Move(rax, Smi::FromInt(LESS));
8249 __ IncrementCounter(&Counters::string_compare_native, 1);
8250 __ ret(2 * kPointerSize);
8251
8252 // Result is GREATER.
8253 __ bind(&result_greater);
8254 __ Move(rax, Smi::FromInt(GREATER));
8255 __ IncrementCounter(&Counters::string_compare_native, 1);
8256 __ ret(2 * kPointerSize);
8257 }
8258
8259
8260 void StringCompareStub::Generate(MacroAssembler* masm) {
8261 Label runtime;
8262
8263 // Stack frame on entry.
8264 // rsp[0]: return address
8265 // rsp[8]: right string
8266 // rsp[16]: left string
8267
8268 __ movq(rdx, Operand(rsp, 2 * kPointerSize)); // left
8269 __ movq(rax, Operand(rsp, 1 * kPointerSize)); // right
8270
8271 Label not_same;
8272 __ cmpq(rdx, rax);
8273 __ j(not_equal, &not_same);
8274 __ Move(rax, Smi::FromInt(0));
Søren Thygesen Gjesse 2010/01/18 09:58:01 0 -> EQUAL.
Lasse Reichstein 2010/01/18 10:33:02 Fixed
8275 __ IncrementCounter(&Counters::string_compare_native, 1);
8276 __ ret(2 * kPointerSize);
8277
8278 __ bind(&not_same);
8279
8280 // Check that both objects are not smis.
8281 Condition either_smi = masm->CheckEitherSmi(rax, rdx);
8282 __ j(either_smi, &runtime);
8283
8284 // Load instance type for both strings.
8285 __ movq(rcx, FieldOperand(rdx, HeapObject::kMapOffset));
8286 __ movq(rbx, FieldOperand(rax, HeapObject::kMapOffset));
8287 __ movzxbl(rcx, FieldOperand(rcx, Map::kInstanceTypeOffset));
8288 __ movzxbl(rbx, FieldOperand(rbx, Map::kInstanceTypeOffset));
8289
8290 // Check that both are flat ascii strings.
8291 Label non_ascii_flat;
8292 ASSERT(kNotStringTag != 0);
8293 const int kFlatAsciiStringMask =
8294 kIsNotStringMask | kStringRepresentationMask | kStringEncodingMask;
8295 const int kFlatAsciiStringBits =
8296 kNotStringTag | kSeqStringTag | kAsciiStringTag;
8297
8298 __ andl(rcx, Immediate(kFlatAsciiStringMask));
8299 __ andl(rbx, Immediate(kFlatAsciiStringMask));
8300 // Interleave the bits to check both rcx and rbx in one test.
8301 ASSERT_EQ(0, kFlatAsciiStringMask & (kFlatAsciiStringMask << 3));
8302 __ lea(rcx, Operand(rcx, rbx, times_8, 0));
8303 __ cmpl(rcx, Immediate(kFlatAsciiStringBits + (kFlatAsciiStringBits << 3)));
8304 __ j(not_equal, &non_ascii_flat);
8305
8306 // Inline comparison of ascii strings.
8307 GenerateCompareFlatAsciiStrings(masm, rdx, rax, rcx, rbx, rdi, r8);
8308
8309 __ bind(&non_ascii_flat);
8310
8311 // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater)
8312 // tagged as a small integer.
8313 __ bind(&runtime);
8314 __ TailCallRuntime(ExternalReference(Runtime::kStringCompare), 2, 1);
8315 }
8316
8130 #undef __ 8317 #undef __
8131 8318
8132 #define __ masm. 8319 #define __ masm.
8133 8320
8134 #ifdef _WIN64 8321 #ifdef _WIN64
8135 typedef double (*ModuloFunction)(double, double); 8322 typedef double (*ModuloFunction)(double, double);
8136 // Define custom fmod implementation. 8323 // Define custom fmod implementation.
8137 ModuloFunction CreateModuloFunction() { 8324 ModuloFunction CreateModuloFunction() {
8138 size_t actual_size; 8325 size_t actual_size;
8139 byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize, 8326 byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
8213 __ ret(0); 8400 __ ret(0);
8214 8401
8215 CodeDesc desc; 8402 CodeDesc desc;
8216 masm.GetCode(&desc); 8403 masm.GetCode(&desc);
8217 // Call the function from C++. 8404 // Call the function from C++.
8218 return FUNCTION_CAST<ModuloFunction>(buffer); 8405 return FUNCTION_CAST<ModuloFunction>(buffer);
8219 } 8406 }
8220 8407
8221 #endif 8408 #endif
8222 8409
8410
8223 #undef __ 8411 #undef __
8224 8412
8225 } } // namespace v8::internal 8413 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/x64/codegen-x64.h ('k') | src/x64/macro-assembler-x64.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698