Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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, ¬_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(¬_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 Loading... | |
| 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 |
| OLD | NEW |