| 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 22 matching lines...) Expand all Loading... |
| 33 #include "code-stubs.h" | 33 #include "code-stubs.h" |
| 34 #include "regexp-macro-assembler.h" | 34 #include "regexp-macro-assembler.h" |
| 35 | 35 |
| 36 namespace v8 { | 36 namespace v8 { |
| 37 namespace internal { | 37 namespace internal { |
| 38 | 38 |
| 39 #define __ ACCESS_MASM(masm) | 39 #define __ ACCESS_MASM(masm) |
| 40 | 40 |
| 41 void ToNumberStub::Generate(MacroAssembler* masm) { | 41 void ToNumberStub::Generate(MacroAssembler* masm) { |
| 42 // The ToNumber stub takes one argument in eax. | 42 // The ToNumber stub takes one argument in eax. |
| 43 NearLabel check_heap_number, call_builtin; | 43 Label check_heap_number, call_builtin; |
| 44 __ SmiTest(rax); | 44 __ SmiTest(rax); |
| 45 __ j(not_zero, &check_heap_number); | 45 __ j(not_zero, &check_heap_number, Label::kNear); |
| 46 __ Ret(); | 46 __ Ret(); |
| 47 | 47 |
| 48 __ bind(&check_heap_number); | 48 __ bind(&check_heap_number); |
| 49 __ CompareRoot(FieldOperand(rax, HeapObject::kMapOffset), | 49 __ CompareRoot(FieldOperand(rax, HeapObject::kMapOffset), |
| 50 Heap::kHeapNumberMapRootIndex); | 50 Heap::kHeapNumberMapRootIndex); |
| 51 __ j(not_equal, &call_builtin); | 51 __ j(not_equal, &call_builtin, Label::kNear); |
| 52 __ Ret(); | 52 __ Ret(); |
| 53 | 53 |
| 54 __ bind(&call_builtin); | 54 __ bind(&call_builtin); |
| 55 __ pop(rcx); // Pop return address. | 55 __ pop(rcx); // Pop return address. |
| 56 __ push(rax); | 56 __ push(rax); |
| 57 __ push(rcx); // Push return address. | 57 __ push(rcx); // Push return address. |
| 58 __ InvokeBuiltin(Builtins::TO_NUMBER, JUMP_FUNCTION); | 58 __ InvokeBuiltin(Builtins::TO_NUMBER, JUMP_FUNCTION); |
| 59 } | 59 } |
| 60 | 60 |
| 61 | 61 |
| (...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 225 | 225 |
| 226 // Return and remove the on-stack parameters. | 226 // Return and remove the on-stack parameters. |
| 227 __ ret(3 * kPointerSize); | 227 __ ret(3 * kPointerSize); |
| 228 | 228 |
| 229 __ bind(&slow_case); | 229 __ bind(&slow_case); |
| 230 __ TailCallRuntime(Runtime::kCreateArrayLiteralShallow, 3, 1); | 230 __ TailCallRuntime(Runtime::kCreateArrayLiteralShallow, 3, 1); |
| 231 } | 231 } |
| 232 | 232 |
| 233 | 233 |
| 234 void ToBooleanStub::Generate(MacroAssembler* masm) { | 234 void ToBooleanStub::Generate(MacroAssembler* masm) { |
| 235 NearLabel false_result, true_result, not_string; | 235 Label false_result, true_result, not_string; |
| 236 __ movq(rax, Operand(rsp, 1 * kPointerSize)); | 236 __ movq(rax, Operand(rsp, 1 * kPointerSize)); |
| 237 | 237 |
| 238 // undefined -> false |
| 239 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex); |
| 240 __ j(equal, &false_result); |
| 241 |
| 242 // Boolean -> its value |
| 243 __ CompareRoot(rax, Heap::kFalseValueRootIndex); |
| 244 __ j(equal, &false_result); |
| 245 __ CompareRoot(rax, Heap::kTrueValueRootIndex); |
| 246 __ j(equal, &true_result); |
| 247 |
| 248 // Smis: 0 -> false, all other -> true |
| 249 __ Cmp(rax, Smi::FromInt(0)); |
| 250 __ j(equal, &false_result); |
| 251 Condition is_smi = __ CheckSmi(rax); |
| 252 __ j(is_smi, &true_result); |
| 253 |
| 238 // 'null' => false. | 254 // 'null' => false. |
| 239 __ CompareRoot(rax, Heap::kNullValueRootIndex); | 255 __ CompareRoot(rax, Heap::kNullValueRootIndex); |
| 240 __ j(equal, &false_result); | 256 __ j(equal, &false_result, Label::kNear); |
| 241 | 257 |
| 242 // Get the map and type of the heap object. | 258 // Get the map and type of the heap object. |
| 243 // We don't use CmpObjectType because we manipulate the type field. | 259 // We don't use CmpObjectType because we manipulate the type field. |
| 244 __ movq(rdx, FieldOperand(rax, HeapObject::kMapOffset)); | 260 __ movq(rdx, FieldOperand(rax, HeapObject::kMapOffset)); |
| 245 __ movzxbq(rcx, FieldOperand(rdx, Map::kInstanceTypeOffset)); | 261 __ movzxbq(rcx, FieldOperand(rdx, Map::kInstanceTypeOffset)); |
| 246 | 262 |
| 247 // Undetectable => false. | 263 // Undetectable => false. |
| 248 __ movzxbq(rbx, FieldOperand(rdx, Map::kBitFieldOffset)); | 264 __ movzxbq(rbx, FieldOperand(rdx, Map::kBitFieldOffset)); |
| 249 __ and_(rbx, Immediate(1 << Map::kIsUndetectable)); | 265 __ and_(rbx, Immediate(1 << Map::kIsUndetectable)); |
| 250 __ j(not_zero, &false_result); | 266 __ j(not_zero, &false_result, Label::kNear); |
| 251 | 267 |
| 252 // JavaScript object => true. | 268 // JavaScript object => true. |
| 253 __ cmpq(rcx, Immediate(FIRST_JS_OBJECT_TYPE)); | 269 __ cmpq(rcx, Immediate(FIRST_JS_OBJECT_TYPE)); |
| 254 __ j(above_equal, &true_result); | 270 __ j(above_equal, &true_result, Label::kNear); |
| 255 | 271 |
| 256 // String value => false iff empty. | 272 // String value => false iff empty. |
| 257 __ cmpq(rcx, Immediate(FIRST_NONSTRING_TYPE)); | 273 __ cmpq(rcx, Immediate(FIRST_NONSTRING_TYPE)); |
| 258 __ j(above_equal, ¬_string); | 274 __ j(above_equal, ¬_string, Label::kNear); |
| 259 __ movq(rdx, FieldOperand(rax, String::kLengthOffset)); | 275 __ movq(rdx, FieldOperand(rax, String::kLengthOffset)); |
| 260 __ SmiTest(rdx); | 276 __ SmiTest(rdx); |
| 261 __ j(zero, &false_result); | 277 __ j(zero, &false_result, Label::kNear); |
| 262 __ jmp(&true_result); | 278 __ jmp(&true_result, Label::kNear); |
| 263 | 279 |
| 264 __ bind(¬_string); | 280 __ bind(¬_string); |
| 265 __ CompareRoot(rdx, Heap::kHeapNumberMapRootIndex); | 281 __ CompareRoot(rdx, Heap::kHeapNumberMapRootIndex); |
| 266 __ j(not_equal, &true_result); | 282 __ j(not_equal, &true_result, Label::kNear); |
| 267 // HeapNumber => false iff +0, -0, or NaN. | 283 // HeapNumber => false iff +0, -0, or NaN. |
| 268 // These three cases set the zero flag when compared to zero using ucomisd. | 284 // These three cases set the zero flag when compared to zero using ucomisd. |
| 269 __ xorps(xmm0, xmm0); | 285 __ xorps(xmm0, xmm0); |
| 270 __ ucomisd(xmm0, FieldOperand(rax, HeapNumber::kValueOffset)); | 286 __ ucomisd(xmm0, FieldOperand(rax, HeapNumber::kValueOffset)); |
| 271 __ j(zero, &false_result); | 287 __ j(zero, &false_result, Label::kNear); |
| 272 // Fall through to |true_result|. | 288 // Fall through to |true_result|. |
| 273 | 289 |
| 274 // Return 1/0 for true/false in rax. | 290 // Return 1/0 for true/false in rax. |
| 275 __ bind(&true_result); | 291 __ bind(&true_result); |
| 276 __ Set(rax, 1); | 292 __ Set(rax, 1); |
| 277 __ ret(1 * kPointerSize); | 293 __ ret(1 * kPointerSize); |
| 278 __ bind(&false_result); | 294 __ bind(&false_result); |
| 279 __ Set(rax, 0); | 295 __ Set(rax, 0); |
| 280 __ ret(1 * kPointerSize); | 296 __ ret(1 * kPointerSize); |
| 281 } | 297 } |
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 371 void IntegerConvert(MacroAssembler* masm, | 387 void IntegerConvert(MacroAssembler* masm, |
| 372 Register result, | 388 Register result, |
| 373 Register source) { | 389 Register source) { |
| 374 // Result may be rcx. If result and source are the same register, source will | 390 // Result may be rcx. If result and source are the same register, source will |
| 375 // be overwritten. | 391 // be overwritten. |
| 376 ASSERT(!result.is(rdi) && !result.is(rbx)); | 392 ASSERT(!result.is(rdi) && !result.is(rbx)); |
| 377 // TODO(lrn): When type info reaches here, if value is a 32-bit integer, use | 393 // TODO(lrn): When type info reaches here, if value is a 32-bit integer, use |
| 378 // cvttsd2si (32-bit version) directly. | 394 // cvttsd2si (32-bit version) directly. |
| 379 Register double_exponent = rbx; | 395 Register double_exponent = rbx; |
| 380 Register double_value = rdi; | 396 Register double_value = rdi; |
| 381 NearLabel done, exponent_63_plus; | 397 Label done, exponent_63_plus; |
| 382 // Get double and extract exponent. | 398 // Get double and extract exponent. |
| 383 __ movq(double_value, FieldOperand(source, HeapNumber::kValueOffset)); | 399 __ movq(double_value, FieldOperand(source, HeapNumber::kValueOffset)); |
| 384 // Clear result preemptively, in case we need to return zero. | 400 // Clear result preemptively, in case we need to return zero. |
| 385 __ xorl(result, result); | 401 __ xorl(result, result); |
| 386 __ movq(xmm0, double_value); // Save copy in xmm0 in case we need it there. | 402 __ movq(xmm0, double_value); // Save copy in xmm0 in case we need it there. |
| 387 // Double to remove sign bit, shift exponent down to least significant bits. | 403 // Double to remove sign bit, shift exponent down to least significant bits. |
| 388 // and subtract bias to get the unshifted, unbiased exponent. | 404 // and subtract bias to get the unshifted, unbiased exponent. |
| 389 __ lea(double_exponent, Operand(double_value, double_value, times_1, 0)); | 405 __ lea(double_exponent, Operand(double_value, double_value, times_1, 0)); |
| 390 __ shr(double_exponent, Immediate(64 - HeapNumber::kExponentBits)); | 406 __ shr(double_exponent, Immediate(64 - HeapNumber::kExponentBits)); |
| 391 __ subl(double_exponent, Immediate(HeapNumber::kExponentBias)); | 407 __ subl(double_exponent, Immediate(HeapNumber::kExponentBias)); |
| 392 // Check whether the exponent is too big for a 63 bit unsigned integer. | 408 // Check whether the exponent is too big for a 63 bit unsigned integer. |
| 393 __ cmpl(double_exponent, Immediate(63)); | 409 __ cmpl(double_exponent, Immediate(63)); |
| 394 __ j(above_equal, &exponent_63_plus); | 410 __ j(above_equal, &exponent_63_plus, Label::kNear); |
| 395 // Handle exponent range 0..62. | 411 // Handle exponent range 0..62. |
| 396 __ cvttsd2siq(result, xmm0); | 412 __ cvttsd2siq(result, xmm0); |
| 397 __ jmp(&done); | 413 __ jmp(&done, Label::kNear); |
| 398 | 414 |
| 399 __ bind(&exponent_63_plus); | 415 __ bind(&exponent_63_plus); |
| 400 // Exponent negative or 63+. | 416 // Exponent negative or 63+. |
| 401 __ cmpl(double_exponent, Immediate(83)); | 417 __ cmpl(double_exponent, Immediate(83)); |
| 402 // If exponent negative or above 83, number contains no significant bits in | 418 // If exponent negative or above 83, number contains no significant bits in |
| 403 // the range 0..2^31, so result is zero, and rcx already holds zero. | 419 // the range 0..2^31, so result is zero, and rcx already holds zero. |
| 404 __ j(above, &done); | 420 __ j(above, &done, Label::kNear); |
| 405 | 421 |
| 406 // Exponent in rage 63..83. | 422 // Exponent in rage 63..83. |
| 407 // Mantissa * 2^exponent contains bits in the range 2^0..2^31, namely | 423 // Mantissa * 2^exponent contains bits in the range 2^0..2^31, namely |
| 408 // the least significant exponent-52 bits. | 424 // the least significant exponent-52 bits. |
| 409 | 425 |
| 410 // Negate low bits of mantissa if value is negative. | 426 // Negate low bits of mantissa if value is negative. |
| 411 __ addq(double_value, double_value); // Move sign bit to carry. | 427 __ addq(double_value, double_value); // Move sign bit to carry. |
| 412 __ sbbl(result, result); // And convert carry to -1 in result register. | 428 __ sbbl(result, result); // And convert carry to -1 in result register. |
| 413 // if scratch2 is negative, do (scratch2-1)^-1, otherwise (scratch2-0)^0. | 429 // if scratch2 is negative, do (scratch2-1)^-1, otherwise (scratch2-0)^0. |
| 414 __ addl(double_value, result); | 430 __ addl(double_value, result); |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 490 case Token::BIT_NOT: | 506 case Token::BIT_NOT: |
| 491 GenerateSmiStubBitNot(masm); | 507 GenerateSmiStubBitNot(masm); |
| 492 break; | 508 break; |
| 493 default: | 509 default: |
| 494 UNREACHABLE(); | 510 UNREACHABLE(); |
| 495 } | 511 } |
| 496 } | 512 } |
| 497 | 513 |
| 498 | 514 |
| 499 void TypeRecordingUnaryOpStub::GenerateSmiStubSub(MacroAssembler* masm) { | 515 void TypeRecordingUnaryOpStub::GenerateSmiStubSub(MacroAssembler* masm) { |
| 500 NearLabel non_smi; | |
| 501 Label slow; | 516 Label slow; |
| 502 GenerateSmiCodeSub(masm, &non_smi, &slow); | 517 GenerateSmiCodeSub(masm, &slow, &slow, Label::kNear, Label::kNear); |
| 503 __ bind(&non_smi); | |
| 504 __ bind(&slow); | 518 __ bind(&slow); |
| 505 GenerateTypeTransition(masm); | 519 GenerateTypeTransition(masm); |
| 506 } | 520 } |
| 507 | 521 |
| 508 | 522 |
| 509 void TypeRecordingUnaryOpStub::GenerateSmiStubBitNot(MacroAssembler* masm) { | 523 void TypeRecordingUnaryOpStub::GenerateSmiStubBitNot(MacroAssembler* masm) { |
| 510 NearLabel non_smi; | 524 Label non_smi; |
| 511 GenerateSmiCodeBitNot(masm, &non_smi); | 525 GenerateSmiCodeBitNot(masm, &non_smi, Label::kNear); |
| 512 __ bind(&non_smi); | 526 __ bind(&non_smi); |
| 513 GenerateTypeTransition(masm); | 527 GenerateTypeTransition(masm); |
| 514 } | 528 } |
| 515 | 529 |
| 516 | 530 |
| 517 void TypeRecordingUnaryOpStub::GenerateSmiCodeSub(MacroAssembler* masm, | 531 void TypeRecordingUnaryOpStub::GenerateSmiCodeSub(MacroAssembler* masm, |
| 518 NearLabel* non_smi, | 532 Label* non_smi, |
| 519 Label* slow) { | 533 Label* slow, |
| 520 NearLabel done; | 534 Label::Distance non_smi_near, |
| 521 __ JumpIfNotSmi(rax, non_smi); | 535 Label::Distance slow_near) { |
| 522 __ SmiNeg(rax, rax, &done); | 536 Label done; |
| 523 __ jmp(slow); | 537 __ JumpIfNotSmi(rax, non_smi, non_smi_near); |
| 538 __ SmiNeg(rax, rax, &done, Label::kNear); |
| 539 __ jmp(slow, slow_near); |
| 524 __ bind(&done); | 540 __ bind(&done); |
| 525 __ ret(0); | 541 __ ret(0); |
| 526 } | 542 } |
| 527 | 543 |
| 528 | 544 |
| 529 void TypeRecordingUnaryOpStub::GenerateSmiCodeBitNot(MacroAssembler* masm, | 545 void TypeRecordingUnaryOpStub::GenerateSmiCodeBitNot( |
| 530 NearLabel* non_smi) { | 546 MacroAssembler* masm, |
| 531 __ JumpIfNotSmi(rax, non_smi); | 547 Label* non_smi, |
| 548 Label::Distance non_smi_near) { |
| 549 __ JumpIfNotSmi(rax, non_smi, non_smi_near); |
| 532 __ SmiNot(rax, rax); | 550 __ SmiNot(rax, rax); |
| 533 __ ret(0); | 551 __ ret(0); |
| 534 } | 552 } |
| 535 | 553 |
| 536 | 554 |
| 537 // TODO(svenpanne): Use virtual functions instead of switch. | 555 // TODO(svenpanne): Use virtual functions instead of switch. |
| 538 void TypeRecordingUnaryOpStub::GenerateHeapNumberStub(MacroAssembler* masm) { | 556 void TypeRecordingUnaryOpStub::GenerateHeapNumberStub(MacroAssembler* masm) { |
| 539 switch (op_) { | 557 switch (op_) { |
| 540 case Token::SUB: | 558 case Token::SUB: |
| 541 GenerateHeapNumberStubSub(masm); | 559 GenerateHeapNumberStubSub(masm); |
| 542 break; | 560 break; |
| 543 case Token::BIT_NOT: | 561 case Token::BIT_NOT: |
| 544 GenerateHeapNumberStubBitNot(masm); | 562 GenerateHeapNumberStubBitNot(masm); |
| 545 break; | 563 break; |
| 546 default: | 564 default: |
| 547 UNREACHABLE(); | 565 UNREACHABLE(); |
| 548 } | 566 } |
| 549 } | 567 } |
| 550 | 568 |
| 551 | 569 |
| 552 void TypeRecordingUnaryOpStub::GenerateHeapNumberStubSub(MacroAssembler* masm) { | 570 void TypeRecordingUnaryOpStub::GenerateHeapNumberStubSub(MacroAssembler* masm) { |
| 553 NearLabel non_smi; | 571 Label non_smi, slow, call_builtin; |
| 554 Label slow; | 572 GenerateSmiCodeSub(masm, &non_smi, &call_builtin, Label::kNear); |
| 555 GenerateSmiCodeSub(masm, &non_smi, &slow); | |
| 556 __ bind(&non_smi); | 573 __ bind(&non_smi); |
| 557 GenerateHeapNumberCodeSub(masm, &slow); | 574 GenerateHeapNumberCodeSub(masm, &slow); |
| 558 __ bind(&slow); | 575 __ bind(&slow); |
| 559 GenerateTypeTransition(masm); | 576 GenerateTypeTransition(masm); |
| 577 __ bind(&call_builtin); |
| 578 GenerateGenericCodeFallback(masm); |
| 560 } | 579 } |
| 561 | 580 |
| 562 | 581 |
| 563 void TypeRecordingUnaryOpStub::GenerateHeapNumberStubBitNot( | 582 void TypeRecordingUnaryOpStub::GenerateHeapNumberStubBitNot( |
| 564 MacroAssembler* masm) { | 583 MacroAssembler* masm) { |
| 565 NearLabel non_smi; | 584 Label non_smi, slow; |
| 566 Label slow; | 585 GenerateSmiCodeBitNot(masm, &non_smi, Label::kNear); |
| 567 GenerateSmiCodeBitNot(masm, &non_smi); | |
| 568 __ bind(&non_smi); | 586 __ bind(&non_smi); |
| 569 GenerateHeapNumberCodeBitNot(masm, &slow); | 587 GenerateHeapNumberCodeBitNot(masm, &slow); |
| 570 __ bind(&slow); | 588 __ bind(&slow); |
| 571 GenerateTypeTransition(masm); | 589 GenerateTypeTransition(masm); |
| 572 } | 590 } |
| 573 | 591 |
| 574 | 592 |
| 575 void TypeRecordingUnaryOpStub::GenerateHeapNumberCodeSub(MacroAssembler* masm, | 593 void TypeRecordingUnaryOpStub::GenerateHeapNumberCodeSub(MacroAssembler* masm, |
| 576 Label* slow) { | 594 Label* slow) { |
| 577 // Check if the operand is a heap number. | 595 // Check if the operand is a heap number. |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 640 case Token::BIT_NOT: | 658 case Token::BIT_NOT: |
| 641 GenerateGenericStubBitNot(masm); | 659 GenerateGenericStubBitNot(masm); |
| 642 break; | 660 break; |
| 643 default: | 661 default: |
| 644 UNREACHABLE(); | 662 UNREACHABLE(); |
| 645 } | 663 } |
| 646 } | 664 } |
| 647 | 665 |
| 648 | 666 |
| 649 void TypeRecordingUnaryOpStub::GenerateGenericStubSub(MacroAssembler* masm) { | 667 void TypeRecordingUnaryOpStub::GenerateGenericStubSub(MacroAssembler* masm) { |
| 650 NearLabel non_smi; | 668 Label non_smi, slow; |
| 651 Label slow; | 669 GenerateSmiCodeSub(masm, &non_smi, &slow, Label::kNear); |
| 652 GenerateSmiCodeSub(masm, &non_smi, &slow); | |
| 653 __ bind(&non_smi); | 670 __ bind(&non_smi); |
| 654 GenerateHeapNumberCodeSub(masm, &slow); | 671 GenerateHeapNumberCodeSub(masm, &slow); |
| 655 __ bind(&slow); | 672 __ bind(&slow); |
| 656 GenerateGenericCodeFallback(masm); | 673 GenerateGenericCodeFallback(masm); |
| 657 } | 674 } |
| 658 | 675 |
| 659 | 676 |
| 660 void TypeRecordingUnaryOpStub::GenerateGenericStubBitNot(MacroAssembler* masm) { | 677 void TypeRecordingUnaryOpStub::GenerateGenericStubBitNot(MacroAssembler* masm) { |
| 661 NearLabel non_smi; | 678 Label non_smi, slow; |
| 662 Label slow; | 679 GenerateSmiCodeBitNot(masm, &non_smi, Label::kNear); |
| 663 GenerateSmiCodeBitNot(masm, &non_smi); | |
| 664 __ bind(&non_smi); | 680 __ bind(&non_smi); |
| 665 GenerateHeapNumberCodeBitNot(masm, &slow); | 681 GenerateHeapNumberCodeBitNot(masm, &slow); |
| 666 __ bind(&slow); | 682 __ bind(&slow); |
| 667 GenerateGenericCodeFallback(masm); | 683 GenerateGenericCodeFallback(masm); |
| 668 } | 684 } |
| 669 | 685 |
| 670 | 686 |
| 671 void TypeRecordingUnaryOpStub::GenerateGenericCodeFallback( | 687 void TypeRecordingUnaryOpStub::GenerateGenericCodeFallback( |
| 672 MacroAssembler* masm) { | 688 MacroAssembler* masm) { |
| 673 // Handle the slow case by jumping to the JavaScript builtin. | 689 // Handle the slow case by jumping to the JavaScript builtin. |
| (...skipping 376 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1050 // No fall-through from this generated code. | 1066 // No fall-through from this generated code. |
| 1051 if (FLAG_debug_code) { | 1067 if (FLAG_debug_code) { |
| 1052 __ Abort("Unexpected fall-through in " | 1068 __ Abort("Unexpected fall-through in " |
| 1053 "TypeRecordingBinaryStub::GenerateFloatingPointCode."); | 1069 "TypeRecordingBinaryStub::GenerateFloatingPointCode."); |
| 1054 } | 1070 } |
| 1055 } | 1071 } |
| 1056 | 1072 |
| 1057 | 1073 |
| 1058 void TypeRecordingBinaryOpStub::GenerateStringAddCode(MacroAssembler* masm) { | 1074 void TypeRecordingBinaryOpStub::GenerateStringAddCode(MacroAssembler* masm) { |
| 1059 ASSERT(op_ == Token::ADD); | 1075 ASSERT(op_ == Token::ADD); |
| 1060 NearLabel left_not_string, call_runtime; | 1076 Label left_not_string, call_runtime; |
| 1061 | 1077 |
| 1062 // Registers containing left and right operands respectively. | 1078 // Registers containing left and right operands respectively. |
| 1063 Register left = rdx; | 1079 Register left = rdx; |
| 1064 Register right = rax; | 1080 Register right = rax; |
| 1065 | 1081 |
| 1066 // Test if left operand is a string. | 1082 // Test if left operand is a string. |
| 1067 __ JumpIfSmi(left, &left_not_string); | 1083 __ JumpIfSmi(left, &left_not_string, Label::kNear); |
| 1068 __ CmpObjectType(left, FIRST_NONSTRING_TYPE, rcx); | 1084 __ CmpObjectType(left, FIRST_NONSTRING_TYPE, rcx); |
| 1069 __ j(above_equal, &left_not_string); | 1085 __ j(above_equal, &left_not_string, Label::kNear); |
| 1070 StringAddStub string_add_left_stub(NO_STRING_CHECK_LEFT_IN_STUB); | 1086 StringAddStub string_add_left_stub(NO_STRING_CHECK_LEFT_IN_STUB); |
| 1071 GenerateRegisterArgsPush(masm); | 1087 GenerateRegisterArgsPush(masm); |
| 1072 __ TailCallStub(&string_add_left_stub); | 1088 __ TailCallStub(&string_add_left_stub); |
| 1073 | 1089 |
| 1074 // Left operand is not a string, test right. | 1090 // Left operand is not a string, test right. |
| 1075 __ bind(&left_not_string); | 1091 __ bind(&left_not_string); |
| 1076 __ JumpIfSmi(right, &call_runtime); | 1092 __ JumpIfSmi(right, &call_runtime, Label::kNear); |
| 1077 __ CmpObjectType(right, FIRST_NONSTRING_TYPE, rcx); | 1093 __ CmpObjectType(right, FIRST_NONSTRING_TYPE, rcx); |
| 1078 __ j(above_equal, &call_runtime); | 1094 __ j(above_equal, &call_runtime, Label::kNear); |
| 1079 | 1095 |
| 1080 StringAddStub string_add_right_stub(NO_STRING_CHECK_RIGHT_IN_STUB); | 1096 StringAddStub string_add_right_stub(NO_STRING_CHECK_RIGHT_IN_STUB); |
| 1081 GenerateRegisterArgsPush(masm); | 1097 GenerateRegisterArgsPush(masm); |
| 1082 __ TailCallStub(&string_add_right_stub); | 1098 __ TailCallStub(&string_add_right_stub); |
| 1083 | 1099 |
| 1084 // Neither argument is a string. | 1100 // Neither argument is a string. |
| 1085 __ bind(&call_runtime); | 1101 __ bind(&call_runtime); |
| 1086 } | 1102 } |
| 1087 | 1103 |
| 1088 | 1104 |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1194 void TypeRecordingBinaryOpStub::GenerateOddballStub(MacroAssembler* masm) { | 1210 void TypeRecordingBinaryOpStub::GenerateOddballStub(MacroAssembler* masm) { |
| 1195 Label call_runtime; | 1211 Label call_runtime; |
| 1196 | 1212 |
| 1197 if (op_ == Token::ADD) { | 1213 if (op_ == Token::ADD) { |
| 1198 // Handle string addition here, because it is the only operation | 1214 // Handle string addition here, because it is the only operation |
| 1199 // that does not do a ToNumber conversion on the operands. | 1215 // that does not do a ToNumber conversion on the operands. |
| 1200 GenerateStringAddCode(masm); | 1216 GenerateStringAddCode(masm); |
| 1201 } | 1217 } |
| 1202 | 1218 |
| 1203 // Convert oddball arguments to numbers. | 1219 // Convert oddball arguments to numbers. |
| 1204 NearLabel check, done; | 1220 Label check, done; |
| 1205 __ CompareRoot(rdx, Heap::kUndefinedValueRootIndex); | 1221 __ CompareRoot(rdx, Heap::kUndefinedValueRootIndex); |
| 1206 __ j(not_equal, &check); | 1222 __ j(not_equal, &check, Label::kNear); |
| 1207 if (Token::IsBitOp(op_)) { | 1223 if (Token::IsBitOp(op_)) { |
| 1208 __ xor_(rdx, rdx); | 1224 __ xor_(rdx, rdx); |
| 1209 } else { | 1225 } else { |
| 1210 __ LoadRoot(rdx, Heap::kNanValueRootIndex); | 1226 __ LoadRoot(rdx, Heap::kNanValueRootIndex); |
| 1211 } | 1227 } |
| 1212 __ jmp(&done); | 1228 __ jmp(&done, Label::kNear); |
| 1213 __ bind(&check); | 1229 __ bind(&check); |
| 1214 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex); | 1230 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex); |
| 1215 __ j(not_equal, &done); | 1231 __ j(not_equal, &done, Label::kNear); |
| 1216 if (Token::IsBitOp(op_)) { | 1232 if (Token::IsBitOp(op_)) { |
| 1217 __ xor_(rax, rax); | 1233 __ xor_(rax, rax); |
| 1218 } else { | 1234 } else { |
| 1219 __ LoadRoot(rax, Heap::kNanValueRootIndex); | 1235 __ LoadRoot(rax, Heap::kNanValueRootIndex); |
| 1220 } | 1236 } |
| 1221 __ bind(&done); | 1237 __ bind(&done); |
| 1222 | 1238 |
| 1223 GenerateHeapNumberStub(masm); | 1239 GenerateHeapNumberStub(masm); |
| 1224 } | 1240 } |
| 1225 | 1241 |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1313 // rsp[0]: return address. | 1329 // rsp[0]: return address. |
| 1314 // xmm1: untagged double input argument | 1330 // xmm1: untagged double input argument |
| 1315 // Output: | 1331 // Output: |
| 1316 // xmm1: untagged double result. | 1332 // xmm1: untagged double result. |
| 1317 | 1333 |
| 1318 Label runtime_call; | 1334 Label runtime_call; |
| 1319 Label runtime_call_clear_stack; | 1335 Label runtime_call_clear_stack; |
| 1320 Label skip_cache; | 1336 Label skip_cache; |
| 1321 const bool tagged = (argument_type_ == TAGGED); | 1337 const bool tagged = (argument_type_ == TAGGED); |
| 1322 if (tagged) { | 1338 if (tagged) { |
| 1323 NearLabel input_not_smi; | 1339 Label input_not_smi, loaded; |
| 1324 NearLabel loaded; | |
| 1325 // Test that rax is a number. | 1340 // Test that rax is a number. |
| 1326 __ movq(rax, Operand(rsp, kPointerSize)); | 1341 __ movq(rax, Operand(rsp, kPointerSize)); |
| 1327 __ JumpIfNotSmi(rax, &input_not_smi); | 1342 __ JumpIfNotSmi(rax, &input_not_smi, Label::kNear); |
| 1328 // Input is a smi. Untag and load it onto the FPU stack. | 1343 // Input is a smi. Untag and load it onto the FPU stack. |
| 1329 // Then load the bits of the double into rbx. | 1344 // Then load the bits of the double into rbx. |
| 1330 __ SmiToInteger32(rax, rax); | 1345 __ SmiToInteger32(rax, rax); |
| 1331 __ subq(rsp, Immediate(kDoubleSize)); | 1346 __ subq(rsp, Immediate(kDoubleSize)); |
| 1332 __ cvtlsi2sd(xmm1, rax); | 1347 __ cvtlsi2sd(xmm1, rax); |
| 1333 __ movsd(Operand(rsp, 0), xmm1); | 1348 __ movsd(Operand(rsp, 0), xmm1); |
| 1334 __ movq(rbx, xmm1); | 1349 __ movq(rbx, xmm1); |
| 1335 __ movq(rdx, xmm1); | 1350 __ movq(rdx, xmm1); |
| 1336 __ fld_d(Operand(rsp, 0)); | 1351 __ fld_d(Operand(rsp, 0)); |
| 1337 __ addq(rsp, Immediate(kDoubleSize)); | 1352 __ addq(rsp, Immediate(kDoubleSize)); |
| 1338 __ jmp(&loaded); | 1353 __ jmp(&loaded, Label::kNear); |
| 1339 | 1354 |
| 1340 __ bind(&input_not_smi); | 1355 __ bind(&input_not_smi); |
| 1341 // Check if input is a HeapNumber. | 1356 // Check if input is a HeapNumber. |
| 1342 __ LoadRoot(rbx, Heap::kHeapNumberMapRootIndex); | 1357 __ LoadRoot(rbx, Heap::kHeapNumberMapRootIndex); |
| 1343 __ cmpq(rbx, FieldOperand(rax, HeapObject::kMapOffset)); | 1358 __ cmpq(rbx, FieldOperand(rax, HeapObject::kMapOffset)); |
| 1344 __ j(not_equal, &runtime_call); | 1359 __ j(not_equal, &runtime_call); |
| 1345 // Input is a HeapNumber. Push it on the FPU stack and load its | 1360 // Input is a HeapNumber. Push it on the FPU stack and load its |
| 1346 // bits into rbx. | 1361 // bits into rbx. |
| 1347 __ fld_d(FieldOperand(rax, HeapNumber::kValueOffset)); | 1362 __ fld_d(FieldOperand(rax, HeapNumber::kValueOffset)); |
| 1348 __ movq(rbx, FieldOperand(rax, HeapNumber::kValueOffset)); | 1363 __ movq(rbx, FieldOperand(rax, HeapNumber::kValueOffset)); |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1403 CHECK_EQ(16, static_cast<int>(elem2_start - elem_start)); | 1418 CHECK_EQ(16, static_cast<int>(elem2_start - elem_start)); |
| 1404 CHECK_EQ(0, static_cast<int>(elem_in0 - elem_start)); | 1419 CHECK_EQ(0, static_cast<int>(elem_in0 - elem_start)); |
| 1405 CHECK_EQ(kIntSize, static_cast<int>(elem_in1 - elem_start)); | 1420 CHECK_EQ(kIntSize, static_cast<int>(elem_in1 - elem_start)); |
| 1406 CHECK_EQ(2 * kIntSize, static_cast<int>(elem_out - elem_start)); | 1421 CHECK_EQ(2 * kIntSize, static_cast<int>(elem_out - elem_start)); |
| 1407 } | 1422 } |
| 1408 #endif | 1423 #endif |
| 1409 // Find the address of the rcx'th entry in the cache, i.e., &rax[rcx*16]. | 1424 // Find the address of the rcx'th entry in the cache, i.e., &rax[rcx*16]. |
| 1410 __ addl(rcx, rcx); | 1425 __ addl(rcx, rcx); |
| 1411 __ lea(rcx, Operand(rax, rcx, times_8, 0)); | 1426 __ lea(rcx, Operand(rax, rcx, times_8, 0)); |
| 1412 // Check if cache matches: Double value is stored in uint32_t[2] array. | 1427 // Check if cache matches: Double value is stored in uint32_t[2] array. |
| 1413 NearLabel cache_miss; | 1428 Label cache_miss; |
| 1414 __ cmpq(rbx, Operand(rcx, 0)); | 1429 __ cmpq(rbx, Operand(rcx, 0)); |
| 1415 __ j(not_equal, &cache_miss); | 1430 __ j(not_equal, &cache_miss, Label::kNear); |
| 1416 // Cache hit! | 1431 // Cache hit! |
| 1417 __ movq(rax, Operand(rcx, 2 * kIntSize)); | 1432 __ movq(rax, Operand(rcx, 2 * kIntSize)); |
| 1418 if (tagged) { | 1433 if (tagged) { |
| 1419 __ fstp(0); // Clear FPU stack. | 1434 __ fstp(0); // Clear FPU stack. |
| 1420 __ ret(kPointerSize); | 1435 __ ret(kPointerSize); |
| 1421 } else { // UNTAGGED. | 1436 } else { // UNTAGGED. |
| 1422 __ movsd(xmm1, FieldOperand(rax, HeapNumber::kValueOffset)); | 1437 __ movsd(xmm1, FieldOperand(rax, HeapNumber::kValueOffset)); |
| 1423 __ Ret(); | 1438 __ Ret(); |
| 1424 } | 1439 } |
| 1425 | 1440 |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1513 __ movq(rdi, rbx); | 1528 __ movq(rdi, rbx); |
| 1514 // Move exponent and sign bits to low bits. | 1529 // Move exponent and sign bits to low bits. |
| 1515 __ shr(rdi, Immediate(HeapNumber::kMantissaBits)); | 1530 __ shr(rdi, Immediate(HeapNumber::kMantissaBits)); |
| 1516 // Remove sign bit. | 1531 // Remove sign bit. |
| 1517 __ andl(rdi, Immediate((1 << HeapNumber::kExponentBits) - 1)); | 1532 __ andl(rdi, Immediate((1 << HeapNumber::kExponentBits) - 1)); |
| 1518 int supported_exponent_limit = (63 + HeapNumber::kExponentBias); | 1533 int supported_exponent_limit = (63 + HeapNumber::kExponentBias); |
| 1519 __ cmpl(rdi, Immediate(supported_exponent_limit)); | 1534 __ cmpl(rdi, Immediate(supported_exponent_limit)); |
| 1520 __ j(below, &in_range); | 1535 __ j(below, &in_range); |
| 1521 // Check for infinity and NaN. Both return NaN for sin. | 1536 // Check for infinity and NaN. Both return NaN for sin. |
| 1522 __ cmpl(rdi, Immediate(0x7ff)); | 1537 __ cmpl(rdi, Immediate(0x7ff)); |
| 1523 NearLabel non_nan_result; | 1538 Label non_nan_result; |
| 1524 __ j(not_equal, &non_nan_result); | 1539 __ j(not_equal, &non_nan_result, Label::kNear); |
| 1525 // Input is +/-Infinity or NaN. Result is NaN. | 1540 // Input is +/-Infinity or NaN. Result is NaN. |
| 1526 __ fstp(0); | 1541 __ fstp(0); |
| 1527 __ LoadRoot(kScratchRegister, Heap::kNanValueRootIndex); | 1542 __ LoadRoot(kScratchRegister, Heap::kNanValueRootIndex); |
| 1528 __ fld_d(FieldOperand(kScratchRegister, HeapNumber::kValueOffset)); | 1543 __ fld_d(FieldOperand(kScratchRegister, HeapNumber::kValueOffset)); |
| 1529 __ jmp(&done); | 1544 __ jmp(&done); |
| 1530 | 1545 |
| 1531 __ bind(&non_nan_result); | 1546 __ bind(&non_nan_result); |
| 1532 | 1547 |
| 1533 // Use fpmod to restrict argument to the range +/-2*PI. | 1548 // Use fpmod to restrict argument to the range +/-2*PI. |
| 1534 __ movq(rdi, rax); // Save rax before using fnstsw_ax. | 1549 __ movq(rdi, rax); // Save rax before using fnstsw_ax. |
| 1535 __ fldpi(); | 1550 __ fldpi(); |
| 1536 __ fadd(0); | 1551 __ fadd(0); |
| 1537 __ fld(1); | 1552 __ fld(1); |
| 1538 // FPU Stack: input, 2*pi, input. | 1553 // FPU Stack: input, 2*pi, input. |
| 1539 { | 1554 { |
| 1540 Label no_exceptions; | 1555 Label no_exceptions; |
| 1541 __ fwait(); | 1556 __ fwait(); |
| 1542 __ fnstsw_ax(); | 1557 __ fnstsw_ax(); |
| 1543 // Clear if Illegal Operand or Zero Division exceptions are set. | 1558 // Clear if Illegal Operand or Zero Division exceptions are set. |
| 1544 __ testl(rax, Immediate(5)); // #IO and #ZD flags of FPU status word. | 1559 __ testl(rax, Immediate(5)); // #IO and #ZD flags of FPU status word. |
| 1545 __ j(zero, &no_exceptions); | 1560 __ j(zero, &no_exceptions); |
| 1546 __ fnclex(); | 1561 __ fnclex(); |
| 1547 __ bind(&no_exceptions); | 1562 __ bind(&no_exceptions); |
| 1548 } | 1563 } |
| 1549 | 1564 |
| 1550 // Compute st(0) % st(1) | 1565 // Compute st(0) % st(1) |
| 1551 { | 1566 { |
| 1552 NearLabel partial_remainder_loop; | 1567 Label partial_remainder_loop; |
| 1553 __ bind(&partial_remainder_loop); | 1568 __ bind(&partial_remainder_loop); |
| 1554 __ fprem1(); | 1569 __ fprem1(); |
| 1555 __ fwait(); | 1570 __ fwait(); |
| 1556 __ fnstsw_ax(); | 1571 __ fnstsw_ax(); |
| 1557 __ testl(rax, Immediate(0x400)); // Check C2 bit of FPU status word. | 1572 __ testl(rax, Immediate(0x400)); // Check C2 bit of FPU status word. |
| 1558 // If C2 is set, computation only has partial result. Loop to | 1573 // If C2 is set, computation only has partial result. Loop to |
| 1559 // continue computation. | 1574 // continue computation. |
| 1560 __ j(not_zero, &partial_remainder_loop); | 1575 __ j(not_zero, &partial_remainder_loop); |
| 1561 } | 1576 } |
| 1562 // FPU Stack: input, 2*pi, input % 2*pi | 1577 // FPU Stack: input, 2*pi, input % 2*pi |
| (...skipping 172 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1735 Register scratch2, | 1750 Register scratch2, |
| 1736 Register scratch3, | 1751 Register scratch3, |
| 1737 Label* on_success, | 1752 Label* on_success, |
| 1738 Label* on_not_smis) { | 1753 Label* on_not_smis) { |
| 1739 Register heap_number_map = scratch3; | 1754 Register heap_number_map = scratch3; |
| 1740 Register smi_result = scratch1; | 1755 Register smi_result = scratch1; |
| 1741 Label done; | 1756 Label done; |
| 1742 | 1757 |
| 1743 __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex); | 1758 __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex); |
| 1744 | 1759 |
| 1745 NearLabel first_smi, check_second; | 1760 Label first_smi; |
| 1746 __ JumpIfSmi(first, &first_smi); | 1761 __ JumpIfSmi(first, &first_smi, Label::kNear); |
| 1747 __ cmpq(FieldOperand(first, HeapObject::kMapOffset), heap_number_map); | 1762 __ cmpq(FieldOperand(first, HeapObject::kMapOffset), heap_number_map); |
| 1748 __ j(not_equal, on_not_smis); | 1763 __ j(not_equal, on_not_smis); |
| 1749 // Convert HeapNumber to smi if possible. | 1764 // Convert HeapNumber to smi if possible. |
| 1750 __ movsd(xmm0, FieldOperand(first, HeapNumber::kValueOffset)); | 1765 __ movsd(xmm0, FieldOperand(first, HeapNumber::kValueOffset)); |
| 1751 __ movq(scratch2, xmm0); | 1766 __ movq(scratch2, xmm0); |
| 1752 __ cvttsd2siq(smi_result, xmm0); | 1767 __ cvttsd2siq(smi_result, xmm0); |
| 1753 // Check if conversion was successful by converting back and | 1768 // Check if conversion was successful by converting back and |
| 1754 // comparing to the original double's bits. | 1769 // comparing to the original double's bits. |
| 1755 __ cvtlsi2sd(xmm1, smi_result); | 1770 __ cvtlsi2sd(xmm1, smi_result); |
| 1756 __ movq(kScratchRegister, xmm1); | 1771 __ movq(kScratchRegister, xmm1); |
| 1757 __ cmpq(scratch2, kScratchRegister); | 1772 __ cmpq(scratch2, kScratchRegister); |
| 1758 __ j(not_equal, on_not_smis); | 1773 __ j(not_equal, on_not_smis); |
| 1759 __ Integer32ToSmi(first, smi_result); | 1774 __ Integer32ToSmi(first, smi_result); |
| 1760 | 1775 |
| 1761 __ bind(&check_second); | |
| 1762 __ JumpIfSmi(second, (on_success != NULL) ? on_success : &done); | 1776 __ JumpIfSmi(second, (on_success != NULL) ? on_success : &done); |
| 1763 __ bind(&first_smi); | 1777 __ bind(&first_smi); |
| 1764 if (FLAG_debug_code) { | 1778 if (FLAG_debug_code) { |
| 1765 // Second should be non-smi if we get here. | 1779 // Second should be non-smi if we get here. |
| 1766 __ AbortIfSmi(second); | 1780 __ AbortIfSmi(second); |
| 1767 } | 1781 } |
| 1768 __ cmpq(FieldOperand(second, HeapObject::kMapOffset), heap_number_map); | 1782 __ cmpq(FieldOperand(second, HeapObject::kMapOffset), heap_number_map); |
| 1769 __ j(not_equal, on_not_smis); | 1783 __ j(not_equal, on_not_smis); |
| 1770 // Convert second to smi, if possible. | 1784 // Convert second to smi, if possible. |
| 1771 __ movsd(xmm0, FieldOperand(second, HeapNumber::kValueOffset)); | 1785 __ movsd(xmm0, FieldOperand(second, HeapNumber::kValueOffset)); |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1822 // Optimized version of pow if exponent is a smi. | 1836 // Optimized version of pow if exponent is a smi. |
| 1823 // xmm0 contains the base. | 1837 // xmm0 contains the base. |
| 1824 __ bind(&powi); | 1838 __ bind(&powi); |
| 1825 __ SmiToInteger32(rax, rax); | 1839 __ SmiToInteger32(rax, rax); |
| 1826 | 1840 |
| 1827 // Save exponent in base as we need to check if exponent is negative later. | 1841 // Save exponent in base as we need to check if exponent is negative later. |
| 1828 // We know that base and exponent are in different registers. | 1842 // We know that base and exponent are in different registers. |
| 1829 __ movq(rdx, rax); | 1843 __ movq(rdx, rax); |
| 1830 | 1844 |
| 1831 // Get absolute value of exponent. | 1845 // Get absolute value of exponent. |
| 1832 NearLabel no_neg; | 1846 Label no_neg; |
| 1833 __ cmpl(rax, Immediate(0)); | 1847 __ cmpl(rax, Immediate(0)); |
| 1834 __ j(greater_equal, &no_neg); | 1848 __ j(greater_equal, &no_neg, Label::kNear); |
| 1835 __ negl(rax); | 1849 __ negl(rax); |
| 1836 __ bind(&no_neg); | 1850 __ bind(&no_neg); |
| 1837 | 1851 |
| 1838 // Load xmm1 with 1. | 1852 // Load xmm1 with 1. |
| 1839 __ movaps(xmm1, xmm3); | 1853 __ movaps(xmm1, xmm3); |
| 1840 NearLabel while_true; | 1854 Label while_true; |
| 1841 NearLabel no_multiply; | 1855 Label no_multiply; |
| 1842 | 1856 |
| 1843 __ bind(&while_true); | 1857 __ bind(&while_true); |
| 1844 __ shrl(rax, Immediate(1)); | 1858 __ shrl(rax, Immediate(1)); |
| 1845 __ j(not_carry, &no_multiply); | 1859 __ j(not_carry, &no_multiply, Label::kNear); |
| 1846 __ mulsd(xmm1, xmm0); | 1860 __ mulsd(xmm1, xmm0); |
| 1847 __ bind(&no_multiply); | 1861 __ bind(&no_multiply); |
| 1848 __ mulsd(xmm0, xmm0); | 1862 __ mulsd(xmm0, xmm0); |
| 1849 __ j(not_zero, &while_true); | 1863 __ j(not_zero, &while_true); |
| 1850 | 1864 |
| 1851 // Base has the original value of the exponent - if the exponent is | 1865 // Base has the original value of the exponent - if the exponent is |
| 1852 // negative return 1/result. | 1866 // negative return 1/result. |
| 1853 __ testl(rdx, rdx); | 1867 __ testl(rdx, rdx); |
| 1854 __ j(positive, &allocate_return); | 1868 __ j(positive, &allocate_return); |
| 1855 // Special case if xmm1 has reached infinity. | 1869 // Special case if xmm1 has reached infinity. |
| 1856 __ divsd(xmm3, xmm1); | 1870 __ divsd(xmm3, xmm1); |
| 1857 __ movaps(xmm1, xmm3); | 1871 __ movaps(xmm1, xmm3); |
| 1858 __ xorps(xmm0, xmm0); | 1872 __ xorps(xmm0, xmm0); |
| 1859 __ ucomisd(xmm0, xmm1); | 1873 __ ucomisd(xmm0, xmm1); |
| 1860 __ j(equal, &call_runtime); | 1874 __ j(equal, &call_runtime); |
| 1861 | 1875 |
| 1862 __ jmp(&allocate_return); | 1876 __ jmp(&allocate_return); |
| 1863 | 1877 |
| 1864 // Exponent (or both) is a heapnumber - no matter what we should now work | 1878 // Exponent (or both) is a heapnumber - no matter what we should now work |
| 1865 // on doubles. | 1879 // on doubles. |
| 1866 __ bind(&exponent_nonsmi); | 1880 __ bind(&exponent_nonsmi); |
| 1867 __ CompareRoot(FieldOperand(rax, HeapObject::kMapOffset), | 1881 __ CompareRoot(FieldOperand(rax, HeapObject::kMapOffset), |
| 1868 Heap::kHeapNumberMapRootIndex); | 1882 Heap::kHeapNumberMapRootIndex); |
| 1869 __ j(not_equal, &call_runtime); | 1883 __ j(not_equal, &call_runtime); |
| 1870 __ movsd(xmm1, FieldOperand(rax, HeapNumber::kValueOffset)); | 1884 __ movsd(xmm1, FieldOperand(rax, HeapNumber::kValueOffset)); |
| 1871 // Test if exponent is nan. | 1885 // Test if exponent is nan. |
| 1872 __ ucomisd(xmm1, xmm1); | 1886 __ ucomisd(xmm1, xmm1); |
| 1873 __ j(parity_even, &call_runtime); | 1887 __ j(parity_even, &call_runtime); |
| 1874 | 1888 |
| 1875 NearLabel base_not_smi; | 1889 Label base_not_smi, handle_special_cases; |
| 1876 NearLabel handle_special_cases; | 1890 __ JumpIfNotSmi(rdx, &base_not_smi, Label::kNear); |
| 1877 __ JumpIfNotSmi(rdx, &base_not_smi); | |
| 1878 __ SmiToInteger32(rdx, rdx); | 1891 __ SmiToInteger32(rdx, rdx); |
| 1879 __ cvtlsi2sd(xmm0, rdx); | 1892 __ cvtlsi2sd(xmm0, rdx); |
| 1880 __ jmp(&handle_special_cases); | 1893 __ jmp(&handle_special_cases, Label::kNear); |
| 1881 | 1894 |
| 1882 __ bind(&base_not_smi); | 1895 __ bind(&base_not_smi); |
| 1883 __ CompareRoot(FieldOperand(rdx, HeapObject::kMapOffset), | 1896 __ CompareRoot(FieldOperand(rdx, HeapObject::kMapOffset), |
| 1884 Heap::kHeapNumberMapRootIndex); | 1897 Heap::kHeapNumberMapRootIndex); |
| 1885 __ j(not_equal, &call_runtime); | 1898 __ j(not_equal, &call_runtime); |
| 1886 __ movl(rcx, FieldOperand(rdx, HeapNumber::kExponentOffset)); | 1899 __ movl(rcx, FieldOperand(rdx, HeapNumber::kExponentOffset)); |
| 1887 __ andl(rcx, Immediate(HeapNumber::kExponentMask)); | 1900 __ andl(rcx, Immediate(HeapNumber::kExponentMask)); |
| 1888 __ cmpl(rcx, Immediate(HeapNumber::kExponentMask)); | 1901 __ cmpl(rcx, Immediate(HeapNumber::kExponentMask)); |
| 1889 // base is NaN or +/-Infinity | 1902 // base is NaN or +/-Infinity |
| 1890 __ j(greater_equal, &call_runtime); | 1903 __ j(greater_equal, &call_runtime); |
| 1891 __ movsd(xmm0, FieldOperand(rdx, HeapNumber::kValueOffset)); | 1904 __ movsd(xmm0, FieldOperand(rdx, HeapNumber::kValueOffset)); |
| 1892 | 1905 |
| 1893 // base is in xmm0 and exponent is in xmm1. | 1906 // base is in xmm0 and exponent is in xmm1. |
| 1894 __ bind(&handle_special_cases); | 1907 __ bind(&handle_special_cases); |
| 1895 NearLabel not_minus_half; | 1908 Label not_minus_half; |
| 1896 // Test for -0.5. | 1909 // Test for -0.5. |
| 1897 // Load xmm2 with -0.5. | 1910 // Load xmm2 with -0.5. |
| 1898 __ movq(rcx, V8_UINT64_C(0xBFE0000000000000), RelocInfo::NONE); | 1911 __ movq(rcx, V8_UINT64_C(0xBFE0000000000000), RelocInfo::NONE); |
| 1899 __ movq(xmm2, rcx); | 1912 __ movq(xmm2, rcx); |
| 1900 // xmm2 now has -0.5. | 1913 // xmm2 now has -0.5. |
| 1901 __ ucomisd(xmm2, xmm1); | 1914 __ ucomisd(xmm2, xmm1); |
| 1902 __ j(not_equal, ¬_minus_half); | 1915 __ j(not_equal, ¬_minus_half, Label::kNear); |
| 1903 | 1916 |
| 1904 // Calculates reciprocal of square root. | 1917 // Calculates reciprocal of square root. |
| 1905 // sqrtsd returns -0 when input is -0. ECMA spec requires +0. | 1918 // sqrtsd returns -0 when input is -0. ECMA spec requires +0. |
| 1906 __ xorps(xmm1, xmm1); | 1919 __ xorps(xmm1, xmm1); |
| 1907 __ addsd(xmm1, xmm0); | 1920 __ addsd(xmm1, xmm0); |
| 1908 __ sqrtsd(xmm1, xmm1); | 1921 __ sqrtsd(xmm1, xmm1); |
| 1909 __ divsd(xmm3, xmm1); | 1922 __ divsd(xmm3, xmm1); |
| 1910 __ movaps(xmm1, xmm3); | 1923 __ movaps(xmm1, xmm3); |
| 1911 __ jmp(&allocate_return); | 1924 __ jmp(&allocate_return); |
| 1912 | 1925 |
| (...skipping 298 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2211 // Check that the last match info has space for the capture registers and the | 2224 // Check that the last match info has space for the capture registers and the |
| 2212 // additional information. Ensure no overflow in add. | 2225 // additional information. Ensure no overflow in add. |
| 2213 STATIC_ASSERT(FixedArray::kMaxLength < kMaxInt - FixedArray::kLengthOffset); | 2226 STATIC_ASSERT(FixedArray::kMaxLength < kMaxInt - FixedArray::kLengthOffset); |
| 2214 __ SmiToInteger32(rdi, FieldOperand(rbx, FixedArray::kLengthOffset)); | 2227 __ SmiToInteger32(rdi, FieldOperand(rbx, FixedArray::kLengthOffset)); |
| 2215 __ addl(rdx, Immediate(RegExpImpl::kLastMatchOverhead)); | 2228 __ addl(rdx, Immediate(RegExpImpl::kLastMatchOverhead)); |
| 2216 __ cmpl(rdx, rdi); | 2229 __ cmpl(rdx, rdi); |
| 2217 __ j(greater, &runtime); | 2230 __ j(greater, &runtime); |
| 2218 | 2231 |
| 2219 // rax: RegExp data (FixedArray) | 2232 // rax: RegExp data (FixedArray) |
| 2220 // Check the representation and encoding of the subject string. | 2233 // Check the representation and encoding of the subject string. |
| 2221 NearLabel seq_ascii_string, seq_two_byte_string, check_code; | 2234 Label seq_ascii_string, seq_two_byte_string, check_code; |
| 2222 __ movq(rdi, Operand(rsp, kSubjectOffset)); | 2235 __ movq(rdi, Operand(rsp, kSubjectOffset)); |
| 2223 __ movq(rbx, FieldOperand(rdi, HeapObject::kMapOffset)); | 2236 __ movq(rbx, FieldOperand(rdi, HeapObject::kMapOffset)); |
| 2224 __ movzxbl(rbx, FieldOperand(rbx, Map::kInstanceTypeOffset)); | 2237 __ movzxbl(rbx, FieldOperand(rbx, Map::kInstanceTypeOffset)); |
| 2225 // First check for flat two byte string. | 2238 // First check for flat two byte string. |
| 2226 __ andb(rbx, Immediate( | 2239 __ andb(rbx, Immediate( |
| 2227 kIsNotStringMask | kStringRepresentationMask | kStringEncodingMask)); | 2240 kIsNotStringMask | kStringRepresentationMask | kStringEncodingMask)); |
| 2228 STATIC_ASSERT((kStringTag | kSeqStringTag | kTwoByteStringTag) == 0); | 2241 STATIC_ASSERT((kStringTag | kSeqStringTag | kTwoByteStringTag) == 0); |
| 2229 __ j(zero, &seq_two_byte_string); | 2242 __ j(zero, &seq_two_byte_string, Label::kNear); |
| 2230 // Any other flat string must be a flat ascii string. | 2243 // Any other flat string must be a flat ascii string. |
| 2231 __ testb(rbx, Immediate(kIsNotStringMask | kStringRepresentationMask)); | 2244 __ testb(rbx, Immediate(kIsNotStringMask | kStringRepresentationMask)); |
| 2232 __ j(zero, &seq_ascii_string); | 2245 __ j(zero, &seq_ascii_string, Label::kNear); |
| 2233 | 2246 |
| 2234 // Check for flat cons string. | 2247 // Check for flat cons string. |
| 2235 // A flat cons string is a cons string where the second part is the empty | 2248 // A flat cons string is a cons string where the second part is the empty |
| 2236 // string. In that case the subject string is just the first part of the cons | 2249 // string. In that case the subject string is just the first part of the cons |
| 2237 // string. Also in this case the first part of the cons string is known to be | 2250 // string. Also in this case the first part of the cons string is known to be |
| 2238 // a sequential string or an external string. | 2251 // a sequential string or an external string. |
| 2239 STATIC_ASSERT(kExternalStringTag !=0); | 2252 STATIC_ASSERT(kExternalStringTag !=0); |
| 2240 STATIC_ASSERT((kConsStringTag & kExternalStringTag) == 0); | 2253 STATIC_ASSERT((kConsStringTag & kExternalStringTag) == 0); |
| 2241 __ testb(rbx, Immediate(kIsNotStringMask | kExternalStringTag)); | 2254 __ testb(rbx, Immediate(kIsNotStringMask | kExternalStringTag)); |
| 2242 __ j(not_zero, &runtime); | 2255 __ j(not_zero, &runtime); |
| 2243 // String is a cons string. | 2256 // String is a cons string. |
| 2244 __ CompareRoot(FieldOperand(rdi, ConsString::kSecondOffset), | 2257 __ CompareRoot(FieldOperand(rdi, ConsString::kSecondOffset), |
| 2245 Heap::kEmptyStringRootIndex); | 2258 Heap::kEmptyStringRootIndex); |
| 2246 __ j(not_equal, &runtime); | 2259 __ j(not_equal, &runtime); |
| 2247 __ movq(rdi, FieldOperand(rdi, ConsString::kFirstOffset)); | 2260 __ movq(rdi, FieldOperand(rdi, ConsString::kFirstOffset)); |
| 2248 __ movq(rbx, FieldOperand(rdi, HeapObject::kMapOffset)); | 2261 __ movq(rbx, FieldOperand(rdi, HeapObject::kMapOffset)); |
| 2249 // String is a cons string with empty second part. | 2262 // String is a cons string with empty second part. |
| 2250 // rdi: first part of cons string. | 2263 // rdi: first part of cons string. |
| 2251 // rbx: map of first part of cons string. | 2264 // rbx: map of first part of cons string. |
| 2252 // Is first part a flat two byte string? | 2265 // Is first part a flat two byte string? |
| 2253 __ testb(FieldOperand(rbx, Map::kInstanceTypeOffset), | 2266 __ testb(FieldOperand(rbx, Map::kInstanceTypeOffset), |
| 2254 Immediate(kStringRepresentationMask | kStringEncodingMask)); | 2267 Immediate(kStringRepresentationMask | kStringEncodingMask)); |
| 2255 STATIC_ASSERT((kSeqStringTag | kTwoByteStringTag) == 0); | 2268 STATIC_ASSERT((kSeqStringTag | kTwoByteStringTag) == 0); |
| 2256 __ j(zero, &seq_two_byte_string); | 2269 __ j(zero, &seq_two_byte_string, Label::kNear); |
| 2257 // Any other flat string must be ascii. | 2270 // Any other flat string must be ascii. |
| 2258 __ testb(FieldOperand(rbx, Map::kInstanceTypeOffset), | 2271 __ testb(FieldOperand(rbx, Map::kInstanceTypeOffset), |
| 2259 Immediate(kStringRepresentationMask)); | 2272 Immediate(kStringRepresentationMask)); |
| 2260 __ j(not_zero, &runtime); | 2273 __ j(not_zero, &runtime); |
| 2261 | 2274 |
| 2262 __ bind(&seq_ascii_string); | 2275 __ bind(&seq_ascii_string); |
| 2263 // rdi: subject string (sequential ascii) | 2276 // rdi: subject string (sequential ascii) |
| 2264 // rax: RegExp data (FixedArray) | 2277 // rax: RegExp data (FixedArray) |
| 2265 __ movq(r11, FieldOperand(rax, JSRegExp::kDataAsciiCodeOffset)); | 2278 __ movq(r11, FieldOperand(rax, JSRegExp::kDataAsciiCodeOffset)); |
| 2266 __ Set(rcx, 1); // Type is ascii. | 2279 __ Set(rcx, 1); // Type is ascii. |
| 2267 __ jmp(&check_code); | 2280 __ jmp(&check_code, Label::kNear); |
| 2268 | 2281 |
| 2269 __ bind(&seq_two_byte_string); | 2282 __ bind(&seq_two_byte_string); |
| 2270 // rdi: subject string (flat two-byte) | 2283 // rdi: subject string (flat two-byte) |
| 2271 // rax: RegExp data (FixedArray) | 2284 // rax: RegExp data (FixedArray) |
| 2272 __ movq(r11, FieldOperand(rax, JSRegExp::kDataUC16CodeOffset)); | 2285 __ movq(r11, FieldOperand(rax, JSRegExp::kDataUC16CodeOffset)); |
| 2273 __ Set(rcx, 0); // Type is two byte. | 2286 __ Set(rcx, 0); // Type is two byte. |
| 2274 | 2287 |
| 2275 __ bind(&check_code); | 2288 __ bind(&check_code); |
| 2276 // Check that the irregexp code has been generated for the actual string | 2289 // Check that the irregexp code has been generated for the actual string |
| 2277 // encoding. If it has, the field contains a code object otherwise it contains | 2290 // encoding. If it has, the field contains a code object otherwise it contains |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2343 #endif | 2356 #endif |
| 2344 | 2357 |
| 2345 // Keep track on aliasing between argX defined above and the registers used. | 2358 // Keep track on aliasing between argX defined above and the registers used. |
| 2346 // rdi: subject string | 2359 // rdi: subject string |
| 2347 // rbx: previous index | 2360 // rbx: previous index |
| 2348 // rcx: encoding of subject string (1 if ascii 0 if two_byte); | 2361 // rcx: encoding of subject string (1 if ascii 0 if two_byte); |
| 2349 // r11: code | 2362 // r11: code |
| 2350 | 2363 |
| 2351 // Argument 4: End of string data | 2364 // Argument 4: End of string data |
| 2352 // Argument 3: Start of string data | 2365 // Argument 3: Start of string data |
| 2353 NearLabel setup_two_byte, setup_rest; | 2366 Label setup_two_byte, setup_rest; |
| 2354 __ testb(rcx, rcx); // Last use of rcx as encoding of subject string. | 2367 __ testb(rcx, rcx); // Last use of rcx as encoding of subject string. |
| 2355 __ j(zero, &setup_two_byte); | 2368 __ j(zero, &setup_two_byte, Label::kNear); |
| 2356 __ SmiToInteger32(rcx, FieldOperand(rdi, String::kLengthOffset)); | 2369 __ SmiToInteger32(rcx, FieldOperand(rdi, String::kLengthOffset)); |
| 2357 __ lea(arg4, FieldOperand(rdi, rcx, times_1, SeqAsciiString::kHeaderSize)); | 2370 __ lea(arg4, FieldOperand(rdi, rcx, times_1, SeqAsciiString::kHeaderSize)); |
| 2358 __ lea(arg3, FieldOperand(rdi, rbx, times_1, SeqAsciiString::kHeaderSize)); | 2371 __ lea(arg3, FieldOperand(rdi, rbx, times_1, SeqAsciiString::kHeaderSize)); |
| 2359 __ jmp(&setup_rest); | 2372 __ jmp(&setup_rest, Label::kNear); |
| 2360 __ bind(&setup_two_byte); | 2373 __ bind(&setup_two_byte); |
| 2361 __ SmiToInteger32(rcx, FieldOperand(rdi, String::kLengthOffset)); | 2374 __ SmiToInteger32(rcx, FieldOperand(rdi, String::kLengthOffset)); |
| 2362 __ lea(arg4, FieldOperand(rdi, rcx, times_2, SeqTwoByteString::kHeaderSize)); | 2375 __ lea(arg4, FieldOperand(rdi, rcx, times_2, SeqTwoByteString::kHeaderSize)); |
| 2363 __ lea(arg3, FieldOperand(rdi, rbx, times_2, SeqTwoByteString::kHeaderSize)); | 2376 __ lea(arg3, FieldOperand(rdi, rbx, times_2, SeqTwoByteString::kHeaderSize)); |
| 2364 | 2377 |
| 2365 __ bind(&setup_rest); | 2378 __ bind(&setup_rest); |
| 2366 // Argument 2: Previous index. | 2379 // Argument 2: Previous index. |
| 2367 __ movq(arg2, rbx); | 2380 __ movq(arg2, rbx); |
| 2368 | 2381 |
| 2369 // Argument 1: Subject string. | 2382 // Argument 1: Subject string. |
| 2370 #ifdef _WIN64 | 2383 #ifdef _WIN64 |
| 2371 __ movq(arg1, rdi); | 2384 __ movq(arg1, rdi); |
| 2372 #else | 2385 #else |
| 2373 // Already there in AMD64 calling convention. | 2386 // Already there in AMD64 calling convention. |
| 2374 ASSERT(arg1.is(rdi)); | 2387 ASSERT(arg1.is(rdi)); |
| 2375 #endif | 2388 #endif |
| 2376 | 2389 |
| 2377 // Locate the code entry and call it. | 2390 // Locate the code entry and call it. |
| 2378 __ addq(r11, Immediate(Code::kHeaderSize - kHeapObjectTag)); | 2391 __ addq(r11, Immediate(Code::kHeaderSize - kHeapObjectTag)); |
| 2379 __ call(r11); | 2392 __ call(r11); |
| 2380 | 2393 |
| 2381 __ LeaveApiExitFrame(); | 2394 __ LeaveApiExitFrame(); |
| 2382 | 2395 |
| 2383 // Check the result. | 2396 // Check the result. |
| 2384 NearLabel success; | 2397 Label success; |
| 2385 Label exception; | 2398 Label exception; |
| 2386 __ cmpl(rax, Immediate(NativeRegExpMacroAssembler::SUCCESS)); | 2399 __ cmpl(rax, Immediate(NativeRegExpMacroAssembler::SUCCESS)); |
| 2387 __ j(equal, &success); | 2400 __ j(equal, &success, Label::kNear); |
| 2388 __ cmpl(rax, Immediate(NativeRegExpMacroAssembler::EXCEPTION)); | 2401 __ cmpl(rax, Immediate(NativeRegExpMacroAssembler::EXCEPTION)); |
| 2389 __ j(equal, &exception); | 2402 __ j(equal, &exception); |
| 2390 __ cmpl(rax, Immediate(NativeRegExpMacroAssembler::FAILURE)); | 2403 __ cmpl(rax, Immediate(NativeRegExpMacroAssembler::FAILURE)); |
| 2391 // If none of the above, it can only be retry. | 2404 // If none of the above, it can only be retry. |
| 2392 // Handle that in the runtime system. | 2405 // Handle that in the runtime system. |
| 2393 __ j(not_equal, &runtime); | 2406 __ j(not_equal, &runtime); |
| 2394 | 2407 |
| 2395 // For failure return null. | 2408 // For failure return null. |
| 2396 __ LoadRoot(rax, Heap::kNullValueRootIndex); | 2409 __ LoadRoot(rax, Heap::kNullValueRootIndex); |
| 2397 __ ret(4 * kPointerSize); | 2410 __ ret(4 * kPointerSize); |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2430 __ movq(rcx, rbx); | 2443 __ movq(rcx, rbx); |
| 2431 __ RecordWrite(rcx, RegExpImpl::kLastInputOffset, rax, rdi, kDontSaveFPRegs); | 2444 __ RecordWrite(rcx, RegExpImpl::kLastInputOffset, rax, rdi, kDontSaveFPRegs); |
| 2432 | 2445 |
| 2433 // Get the static offsets vector filled by the native regexp code. | 2446 // Get the static offsets vector filled by the native regexp code. |
| 2434 __ LoadAddress(rcx, | 2447 __ LoadAddress(rcx, |
| 2435 ExternalReference::address_of_static_offsets_vector(isolate)); | 2448 ExternalReference::address_of_static_offsets_vector(isolate)); |
| 2436 | 2449 |
| 2437 // rbx: last_match_info backing store (FixedArray) | 2450 // rbx: last_match_info backing store (FixedArray) |
| 2438 // rcx: offsets vector | 2451 // rcx: offsets vector |
| 2439 // rdx: number of capture registers | 2452 // rdx: number of capture registers |
| 2440 NearLabel next_capture, done; | 2453 Label next_capture, done; |
| 2441 // Capture register counter starts from number of capture registers and | 2454 // Capture register counter starts from number of capture registers and |
| 2442 // counts down until wraping after zero. | 2455 // counts down until wraping after zero. |
| 2443 __ bind(&next_capture); | 2456 __ bind(&next_capture); |
| 2444 __ subq(rdx, Immediate(1)); | 2457 __ subq(rdx, Immediate(1)); |
| 2445 __ j(negative, &done); | 2458 __ j(negative, &done, Label::kNear); |
| 2446 // Read the value from the static offsets vector buffer and make it a smi. | 2459 // Read the value from the static offsets vector buffer and make it a smi. |
| 2447 __ movl(rdi, Operand(rcx, rdx, times_int_size, 0)); | 2460 __ movl(rdi, Operand(rcx, rdx, times_int_size, 0)); |
| 2448 __ Integer32ToSmi(rdi, rdi); | 2461 __ Integer32ToSmi(rdi, rdi); |
| 2449 // Store the smi value in the last match info. | 2462 // Store the smi value in the last match info. |
| 2450 __ movq(FieldOperand(rbx, | 2463 __ movq(FieldOperand(rbx, |
| 2451 rdx, | 2464 rdx, |
| 2452 times_pointer_size, | 2465 times_pointer_size, |
| 2453 RegExpImpl::kFirstCaptureOffset), | 2466 RegExpImpl::kFirstCaptureOffset), |
| 2454 rdi); | 2467 rdi); |
| 2455 __ jmp(&next_capture); | 2468 __ jmp(&next_capture); |
| (...skipping 12 matching lines...) Expand all Loading... |
| 2468 Isolate::k_pending_exception_address, isolate); | 2481 Isolate::k_pending_exception_address, isolate); |
| 2469 Operand pending_exception_operand = | 2482 Operand pending_exception_operand = |
| 2470 masm->ExternalOperand(pending_exception_address, rbx); | 2483 masm->ExternalOperand(pending_exception_address, rbx); |
| 2471 __ movq(rax, pending_exception_operand); | 2484 __ movq(rax, pending_exception_operand); |
| 2472 __ LoadRoot(rdx, Heap::kTheHoleValueRootIndex); | 2485 __ LoadRoot(rdx, Heap::kTheHoleValueRootIndex); |
| 2473 __ cmpq(rax, rdx); | 2486 __ cmpq(rax, rdx); |
| 2474 __ j(equal, &runtime); | 2487 __ j(equal, &runtime); |
| 2475 __ movq(pending_exception_operand, rdx); | 2488 __ movq(pending_exception_operand, rdx); |
| 2476 | 2489 |
| 2477 __ CompareRoot(rax, Heap::kTerminationExceptionRootIndex); | 2490 __ CompareRoot(rax, Heap::kTerminationExceptionRootIndex); |
| 2478 NearLabel termination_exception; | 2491 Label termination_exception; |
| 2479 __ j(equal, &termination_exception); | 2492 __ j(equal, &termination_exception, Label::kNear); |
| 2480 __ Throw(rax); | 2493 __ Throw(rax); |
| 2481 | 2494 |
| 2482 __ bind(&termination_exception); | 2495 __ bind(&termination_exception); |
| 2483 __ ThrowUncatchable(TERMINATION, rax); | 2496 __ ThrowUncatchable(TERMINATION, rax); |
| 2484 | 2497 |
| 2485 // Do the runtime call to execute the regexp. | 2498 // Do the runtime call to execute the regexp. |
| 2486 __ bind(&runtime); | 2499 __ bind(&runtime); |
| 2487 __ TailCallRuntime(Runtime::kRegExpExec, 4, 1); | 2500 __ TailCallRuntime(Runtime::kRegExpExec, 4, 1); |
| 2488 #endif // V8_INTERPRETED_REGEXP | 2501 #endif // V8_INTERPRETED_REGEXP |
| 2489 } | 2502 } |
| (...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2597 | 2610 |
| 2598 // Calculate the entry in the number string cache. The hash value in the | 2611 // Calculate the entry in the number string cache. The hash value in the |
| 2599 // number string cache for smis is just the smi value, and the hash for | 2612 // number string cache for smis is just the smi value, and the hash for |
| 2600 // doubles is the xor of the upper and lower words. See | 2613 // doubles is the xor of the upper and lower words. See |
| 2601 // Heap::GetNumberStringCache. | 2614 // Heap::GetNumberStringCache. |
| 2602 Label is_smi; | 2615 Label is_smi; |
| 2603 Label load_result_from_cache; | 2616 Label load_result_from_cache; |
| 2604 Factory* factory = masm->isolate()->factory(); | 2617 Factory* factory = masm->isolate()->factory(); |
| 2605 if (!object_is_smi) { | 2618 if (!object_is_smi) { |
| 2606 __ JumpIfSmi(object, &is_smi); | 2619 __ JumpIfSmi(object, &is_smi); |
| 2607 __ CheckMap(object, factory->heap_number_map(), not_found, true); | 2620 __ CheckMap(object, |
| 2621 factory->heap_number_map(), |
| 2622 not_found, |
| 2623 DONT_DO_SMI_CHECK); |
| 2608 | 2624 |
| 2609 STATIC_ASSERT(8 == kDoubleSize); | 2625 STATIC_ASSERT(8 == kDoubleSize); |
| 2610 __ movl(scratch, FieldOperand(object, HeapNumber::kValueOffset + 4)); | 2626 __ movl(scratch, FieldOperand(object, HeapNumber::kValueOffset + 4)); |
| 2611 __ xor_(scratch, FieldOperand(object, HeapNumber::kValueOffset)); | 2627 __ xor_(scratch, FieldOperand(object, HeapNumber::kValueOffset)); |
| 2612 GenerateConvertHashCodeToIndex(masm, scratch, mask); | 2628 GenerateConvertHashCodeToIndex(masm, scratch, mask); |
| 2613 | 2629 |
| 2614 Register index = scratch; | 2630 Register index = scratch; |
| 2615 Register probe = mask; | 2631 Register probe = mask; |
| 2616 __ movq(probe, | 2632 __ movq(probe, |
| 2617 FieldOperand(number_string_cache, | 2633 FieldOperand(number_string_cache, |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2712 __ bind(&ok); | 2728 __ bind(&ok); |
| 2713 } | 2729 } |
| 2714 | 2730 |
| 2715 // The compare stub returns a positive, negative, or zero 64-bit integer | 2731 // The compare stub returns a positive, negative, or zero 64-bit integer |
| 2716 // value in rax, corresponding to result of comparing the two inputs. | 2732 // value in rax, corresponding to result of comparing the two inputs. |
| 2717 // NOTICE! This code is only reached after a smi-fast-case check, so | 2733 // NOTICE! This code is only reached after a smi-fast-case check, so |
| 2718 // it is certain that at least one operand isn't a smi. | 2734 // it is certain that at least one operand isn't a smi. |
| 2719 | 2735 |
| 2720 // Two identical objects are equal unless they are both NaN or undefined. | 2736 // Two identical objects are equal unless they are both NaN or undefined. |
| 2721 { | 2737 { |
| 2722 NearLabel not_identical; | 2738 Label not_identical; |
| 2723 __ cmpq(rax, rdx); | 2739 __ cmpq(rax, rdx); |
| 2724 __ j(not_equal, ¬_identical); | 2740 __ j(not_equal, ¬_identical, Label::kNear); |
| 2725 | 2741 |
| 2726 if (cc_ != equal) { | 2742 if (cc_ != equal) { |
| 2727 // Check for undefined. undefined OP undefined is false even though | 2743 // Check for undefined. undefined OP undefined is false even though |
| 2728 // undefined == undefined. | 2744 // undefined == undefined. |
| 2729 NearLabel check_for_nan; | 2745 Label check_for_nan; |
| 2730 __ CompareRoot(rdx, Heap::kUndefinedValueRootIndex); | 2746 __ CompareRoot(rdx, Heap::kUndefinedValueRootIndex); |
| 2731 __ j(not_equal, &check_for_nan); | 2747 __ j(not_equal, &check_for_nan, Label::kNear); |
| 2732 __ Set(rax, NegativeComparisonResult(cc_)); | 2748 __ Set(rax, NegativeComparisonResult(cc_)); |
| 2733 __ ret(0); | 2749 __ ret(0); |
| 2734 __ bind(&check_for_nan); | 2750 __ bind(&check_for_nan); |
| 2735 } | 2751 } |
| 2736 | 2752 |
| 2737 // Test for NaN. Sadly, we can't just compare to FACTORY->nan_value(), | 2753 // Test for NaN. Sadly, we can't just compare to FACTORY->nan_value(), |
| 2738 // so we do the second best thing - test it ourselves. | 2754 // so we do the second best thing - test it ourselves. |
| 2739 // Note: if cc_ != equal, never_nan_nan_ is not used. | 2755 // Note: if cc_ != equal, never_nan_nan_ is not used. |
| 2740 // We cannot set rax to EQUAL until just before return because | 2756 // We cannot set rax to EQUAL until just before return because |
| 2741 // rax must be unchanged on jump to not_identical. | 2757 // rax must be unchanged on jump to not_identical. |
| 2742 if (never_nan_nan_ && (cc_ == equal)) { | 2758 if (never_nan_nan_ && (cc_ == equal)) { |
| 2743 __ Set(rax, EQUAL); | 2759 __ Set(rax, EQUAL); |
| 2744 __ ret(0); | 2760 __ ret(0); |
| 2745 } else { | 2761 } else { |
| 2746 NearLabel heap_number; | 2762 Label heap_number; |
| 2747 // If it's not a heap number, then return equal for (in)equality operator. | 2763 // If it's not a heap number, then return equal for (in)equality operator. |
| 2748 __ Cmp(FieldOperand(rdx, HeapObject::kMapOffset), | 2764 __ Cmp(FieldOperand(rdx, HeapObject::kMapOffset), |
| 2749 factory->heap_number_map()); | 2765 factory->heap_number_map()); |
| 2750 __ j(equal, &heap_number); | 2766 __ j(equal, &heap_number, Label::kNear); |
| 2751 if (cc_ != equal) { | 2767 if (cc_ != equal) { |
| 2752 // Call runtime on identical JSObjects. Otherwise return equal. | 2768 // Call runtime on identical JSObjects. Otherwise return equal. |
| 2753 __ CmpObjectType(rax, FIRST_JS_OBJECT_TYPE, rcx); | 2769 __ CmpObjectType(rax, FIRST_JS_OBJECT_TYPE, rcx); |
| 2754 __ j(above_equal, ¬_identical); | 2770 __ j(above_equal, ¬_identical, Label::kNear); |
| 2755 } | 2771 } |
| 2756 __ Set(rax, EQUAL); | 2772 __ Set(rax, EQUAL); |
| 2757 __ ret(0); | 2773 __ ret(0); |
| 2758 | 2774 |
| 2759 __ bind(&heap_number); | 2775 __ bind(&heap_number); |
| 2760 // It is a heap number, so return equal if it's not NaN. | 2776 // It is a heap number, so return equal if it's not NaN. |
| 2761 // For NaN, return 1 for every condition except greater and | 2777 // For NaN, return 1 for every condition except greater and |
| 2762 // greater-equal. Return -1 for them, so the comparison yields | 2778 // greater-equal. Return -1 for them, so the comparison yields |
| 2763 // false for all conditions except not-equal. | 2779 // false for all conditions except not-equal. |
| 2764 __ Set(rax, EQUAL); | 2780 __ Set(rax, EQUAL); |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2800 | 2816 |
| 2801 __ bind(¬_smis); | 2817 __ bind(¬_smis); |
| 2802 } | 2818 } |
| 2803 | 2819 |
| 2804 // If either operand is a JSObject or an oddball value, then they are not | 2820 // If either operand is a JSObject or an oddball value, then they are not |
| 2805 // equal since their pointers are different | 2821 // equal since their pointers are different |
| 2806 // There is no test for undetectability in strict equality. | 2822 // There is no test for undetectability in strict equality. |
| 2807 | 2823 |
| 2808 // If the first object is a JS object, we have done pointer comparison. | 2824 // If the first object is a JS object, we have done pointer comparison. |
| 2809 STATIC_ASSERT(LAST_TYPE == JS_FUNCTION_TYPE); | 2825 STATIC_ASSERT(LAST_TYPE == JS_FUNCTION_TYPE); |
| 2810 NearLabel first_non_object; | 2826 Label first_non_object; |
| 2811 __ CmpObjectType(rax, FIRST_JS_OBJECT_TYPE, rcx); | 2827 __ CmpObjectType(rax, FIRST_JS_OBJECT_TYPE, rcx); |
| 2812 __ j(below, &first_non_object); | 2828 __ j(below, &first_non_object, Label::kNear); |
| 2813 // Return non-zero (eax (not rax) is not zero) | 2829 // Return non-zero (eax (not rax) is not zero) |
| 2814 Label return_not_equal; | 2830 Label return_not_equal; |
| 2815 STATIC_ASSERT(kHeapObjectTag != 0); | 2831 STATIC_ASSERT(kHeapObjectTag != 0); |
| 2816 __ bind(&return_not_equal); | 2832 __ bind(&return_not_equal); |
| 2817 __ ret(0); | 2833 __ ret(0); |
| 2818 | 2834 |
| 2819 __ bind(&first_non_object); | 2835 __ bind(&first_non_object); |
| 2820 // Check for oddballs: true, false, null, undefined. | 2836 // Check for oddballs: true, false, null, undefined. |
| 2821 __ CmpInstanceType(rcx, ODDBALL_TYPE); | 2837 __ CmpInstanceType(rcx, ODDBALL_TYPE); |
| 2822 __ j(equal, &return_not_equal); | 2838 __ j(equal, &return_not_equal); |
| 2823 | 2839 |
| 2824 __ CmpObjectType(rdx, FIRST_JS_OBJECT_TYPE, rcx); | 2840 __ CmpObjectType(rdx, FIRST_JS_OBJECT_TYPE, rcx); |
| 2825 __ j(above_equal, &return_not_equal); | 2841 __ j(above_equal, &return_not_equal); |
| 2826 | 2842 |
| 2827 // Check for oddballs: true, false, null, undefined. | 2843 // Check for oddballs: true, false, null, undefined. |
| 2828 __ CmpInstanceType(rcx, ODDBALL_TYPE); | 2844 __ CmpInstanceType(rcx, ODDBALL_TYPE); |
| 2829 __ j(equal, &return_not_equal); | 2845 __ j(equal, &return_not_equal); |
| 2830 | 2846 |
| 2831 // Fall through to the general case. | 2847 // Fall through to the general case. |
| 2832 } | 2848 } |
| 2833 __ bind(&slow); | 2849 __ bind(&slow); |
| 2834 } | 2850 } |
| 2835 | 2851 |
| 2836 // Generate the number comparison code. | 2852 // Generate the number comparison code. |
| 2837 if (include_number_compare_) { | 2853 if (include_number_compare_) { |
| 2838 Label non_number_comparison; | 2854 Label non_number_comparison; |
| 2839 NearLabel unordered; | 2855 Label unordered; |
| 2840 FloatingPointHelper::LoadSSE2UnknownOperands(masm, &non_number_comparison); | 2856 FloatingPointHelper::LoadSSE2UnknownOperands(masm, &non_number_comparison); |
| 2841 __ xorl(rax, rax); | 2857 __ xorl(rax, rax); |
| 2842 __ xorl(rcx, rcx); | 2858 __ xorl(rcx, rcx); |
| 2843 __ ucomisd(xmm0, xmm1); | 2859 __ ucomisd(xmm0, xmm1); |
| 2844 | 2860 |
| 2845 // Don't base result on EFLAGS when a NaN is involved. | 2861 // Don't base result on EFLAGS when a NaN is involved. |
| 2846 __ j(parity_even, &unordered); | 2862 __ j(parity_even, &unordered, Label::kNear); |
| 2847 // Return a result of -1, 0, or 1, based on EFLAGS. | 2863 // Return a result of -1, 0, or 1, based on EFLAGS. |
| 2848 __ setcc(above, rax); | 2864 __ setcc(above, rax); |
| 2849 __ setcc(below, rcx); | 2865 __ setcc(below, rcx); |
| 2850 __ subq(rax, rcx); | 2866 __ subq(rax, rcx); |
| 2851 __ ret(0); | 2867 __ ret(0); |
| 2852 | 2868 |
| 2853 // If one of the numbers was NaN, then the result is always false. | 2869 // If one of the numbers was NaN, then the result is always false. |
| 2854 // The cc is never not-equal. | 2870 // The cc is never not-equal. |
| 2855 __ bind(&unordered); | 2871 __ bind(&unordered); |
| 2856 ASSERT(cc_ != not_equal); | 2872 ASSERT(cc_ != not_equal); |
| (...skipping 19 matching lines...) Expand all Loading... |
| 2876 // non-zero value, which indicates not equal, so just return. | 2892 // non-zero value, which indicates not equal, so just return. |
| 2877 __ ret(0); | 2893 __ ret(0); |
| 2878 } | 2894 } |
| 2879 | 2895 |
| 2880 __ bind(&check_for_strings); | 2896 __ bind(&check_for_strings); |
| 2881 | 2897 |
| 2882 __ JumpIfNotBothSequentialAsciiStrings( | 2898 __ JumpIfNotBothSequentialAsciiStrings( |
| 2883 rdx, rax, rcx, rbx, &check_unequal_objects); | 2899 rdx, rax, rcx, rbx, &check_unequal_objects); |
| 2884 | 2900 |
| 2885 // Inline comparison of ascii strings. | 2901 // Inline comparison of ascii strings. |
| 2886 StringCompareStub::GenerateCompareFlatAsciiStrings(masm, | 2902 if (cc_ == equal) { |
| 2903 StringCompareStub::GenerateFlatAsciiStringEquals(masm, |
| 2887 rdx, | 2904 rdx, |
| 2888 rax, | 2905 rax, |
| 2889 rcx, | 2906 rcx, |
| 2890 rbx, | 2907 rbx); |
| 2891 rdi, | 2908 } else { |
| 2892 r8); | 2909 StringCompareStub::GenerateCompareFlatAsciiStrings(masm, |
| 2910 rdx, |
| 2911 rax, |
| 2912 rcx, |
| 2913 rbx, |
| 2914 rdi, |
| 2915 r8); |
| 2916 } |
| 2893 | 2917 |
| 2894 #ifdef DEBUG | 2918 #ifdef DEBUG |
| 2895 __ Abort("Unexpected fall-through from string comparison"); | 2919 __ Abort("Unexpected fall-through from string comparison"); |
| 2896 #endif | 2920 #endif |
| 2897 | 2921 |
| 2898 __ bind(&check_unequal_objects); | 2922 __ bind(&check_unequal_objects); |
| 2899 if (cc_ == equal && !strict_) { | 2923 if (cc_ == equal && !strict_) { |
| 2900 // Not strict equality. Objects are unequal if | 2924 // Not strict equality. Objects are unequal if |
| 2901 // they are both JSObjects and not undetectable, | 2925 // they are both JSObjects and not undetectable, |
| 2902 // and their pointers are different. | 2926 // and their pointers are different. |
| 2903 NearLabel not_both_objects, return_unequal; | 2927 Label not_both_objects, return_unequal; |
| 2904 // At most one is a smi, so we can test for smi by adding the two. | 2928 // At most one is a smi, so we can test for smi by adding the two. |
| 2905 // A smi plus a heap object has the low bit set, a heap object plus | 2929 // A smi plus a heap object has the low bit set, a heap object plus |
| 2906 // a heap object has the low bit clear. | 2930 // a heap object has the low bit clear. |
| 2907 STATIC_ASSERT(kSmiTag == 0); | 2931 STATIC_ASSERT(kSmiTag == 0); |
| 2908 STATIC_ASSERT(kSmiTagMask == 1); | 2932 STATIC_ASSERT(kSmiTagMask == 1); |
| 2909 __ lea(rcx, Operand(rax, rdx, times_1, 0)); | 2933 __ lea(rcx, Operand(rax, rdx, times_1, 0)); |
| 2910 __ testb(rcx, Immediate(kSmiTagMask)); | 2934 __ testb(rcx, Immediate(kSmiTagMask)); |
| 2911 __ j(not_zero, ¬_both_objects); | 2935 __ j(not_zero, ¬_both_objects, Label::kNear); |
| 2912 __ CmpObjectType(rax, FIRST_JS_OBJECT_TYPE, rbx); | 2936 __ CmpObjectType(rax, FIRST_JS_OBJECT_TYPE, rbx); |
| 2913 __ j(below, ¬_both_objects); | 2937 __ j(below, ¬_both_objects, Label::kNear); |
| 2914 __ CmpObjectType(rdx, FIRST_JS_OBJECT_TYPE, rcx); | 2938 __ CmpObjectType(rdx, FIRST_JS_OBJECT_TYPE, rcx); |
| 2915 __ j(below, ¬_both_objects); | 2939 __ j(below, ¬_both_objects, Label::kNear); |
| 2916 __ testb(FieldOperand(rbx, Map::kBitFieldOffset), | 2940 __ testb(FieldOperand(rbx, Map::kBitFieldOffset), |
| 2917 Immediate(1 << Map::kIsUndetectable)); | 2941 Immediate(1 << Map::kIsUndetectable)); |
| 2918 __ j(zero, &return_unequal); | 2942 __ j(zero, &return_unequal, Label::kNear); |
| 2919 __ testb(FieldOperand(rcx, Map::kBitFieldOffset), | 2943 __ testb(FieldOperand(rcx, Map::kBitFieldOffset), |
| 2920 Immediate(1 << Map::kIsUndetectable)); | 2944 Immediate(1 << Map::kIsUndetectable)); |
| 2921 __ j(zero, &return_unequal); | 2945 __ j(zero, &return_unequal, Label::kNear); |
| 2922 // The objects are both undetectable, so they both compare as the value | 2946 // The objects are both undetectable, so they both compare as the value |
| 2923 // undefined, and are equal. | 2947 // undefined, and are equal. |
| 2924 __ Set(rax, EQUAL); | 2948 __ Set(rax, EQUAL); |
| 2925 __ bind(&return_unequal); | 2949 __ bind(&return_unequal); |
| 2926 // Return non-equal by returning the non-zero object pointer in rax, | 2950 // Return non-equal by returning the non-zero object pointer in rax, |
| 2927 // or return equal if we fell through to here. | 2951 // or return equal if we fell through to here. |
| 2928 __ ret(0); | 2952 __ ret(0); |
| 2929 __ bind(¬_both_objects); | 2953 __ bind(¬_both_objects); |
| 2930 } | 2954 } |
| 2931 | 2955 |
| (...skipping 209 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3141 __ testl(rcx, Immediate(kFailureTagMask)); | 3165 __ testl(rcx, Immediate(kFailureTagMask)); |
| 3142 __ j(zero, &failure_returned); | 3166 __ j(zero, &failure_returned); |
| 3143 | 3167 |
| 3144 // Exit the JavaScript to C++ exit frame. | 3168 // Exit the JavaScript to C++ exit frame. |
| 3145 __ LeaveExitFrame(save_doubles_); | 3169 __ LeaveExitFrame(save_doubles_); |
| 3146 __ ret(0); | 3170 __ ret(0); |
| 3147 | 3171 |
| 3148 // Handling of failure. | 3172 // Handling of failure. |
| 3149 __ bind(&failure_returned); | 3173 __ bind(&failure_returned); |
| 3150 | 3174 |
| 3151 NearLabel retry; | 3175 Label retry; |
| 3152 // If the returned exception is RETRY_AFTER_GC continue at retry label | 3176 // If the returned exception is RETRY_AFTER_GC continue at retry label |
| 3153 STATIC_ASSERT(Failure::RETRY_AFTER_GC == 0); | 3177 STATIC_ASSERT(Failure::RETRY_AFTER_GC == 0); |
| 3154 __ testl(rax, Immediate(((1 << kFailureTypeTagSize) - 1) << kFailureTagSize)); | 3178 __ testl(rax, Immediate(((1 << kFailureTypeTagSize) - 1) << kFailureTagSize)); |
| 3155 __ j(zero, &retry); | 3179 __ j(zero, &retry, Label::kNear); |
| 3156 | 3180 |
| 3157 // Special handling of out of memory exceptions. | 3181 // Special handling of out of memory exceptions. |
| 3158 __ movq(kScratchRegister, Failure::OutOfMemoryException(), RelocInfo::NONE); | 3182 __ movq(kScratchRegister, Failure::OutOfMemoryException(), RelocInfo::NONE); |
| 3159 __ cmpq(rax, kScratchRegister); | 3183 __ cmpq(rax, kScratchRegister); |
| 3160 __ j(equal, throw_out_of_memory_exception); | 3184 __ j(equal, throw_out_of_memory_exception); |
| 3161 | 3185 |
| 3162 // Retrieve the pending exception and clear the variable. | 3186 // Retrieve the pending exception and clear the variable. |
| 3163 ExternalReference pending_exception_address( | 3187 ExternalReference pending_exception_address( |
| 3164 Isolate::k_pending_exception_address, masm->isolate()); | 3188 Isolate::k_pending_exception_address, masm->isolate()); |
| 3165 Operand pending_exception_operand = | 3189 Operand pending_exception_operand = |
| (...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3308 Operand c_entry_fp_operand = masm->ExternalOperand(c_entry_fp); | 3332 Operand c_entry_fp_operand = masm->ExternalOperand(c_entry_fp); |
| 3309 __ push(c_entry_fp_operand); | 3333 __ push(c_entry_fp_operand); |
| 3310 } | 3334 } |
| 3311 | 3335 |
| 3312 #ifdef ENABLE_LOGGING_AND_PROFILING | 3336 #ifdef ENABLE_LOGGING_AND_PROFILING |
| 3313 // If this is the outermost JS call, set js_entry_sp value. | 3337 // If this is the outermost JS call, set js_entry_sp value. |
| 3314 ExternalReference js_entry_sp(Isolate::k_js_entry_sp_address, isolate); | 3338 ExternalReference js_entry_sp(Isolate::k_js_entry_sp_address, isolate); |
| 3315 __ Load(rax, js_entry_sp); | 3339 __ Load(rax, js_entry_sp); |
| 3316 __ testq(rax, rax); | 3340 __ testq(rax, rax); |
| 3317 __ j(not_zero, ¬_outermost_js); | 3341 __ j(not_zero, ¬_outermost_js); |
| 3342 __ Push(Smi::FromInt(StackFrame::OUTERMOST_JSENTRY_FRAME)); |
| 3318 __ movq(rax, rbp); | 3343 __ movq(rax, rbp); |
| 3319 __ Store(js_entry_sp, rax); | 3344 __ Store(js_entry_sp, rax); |
| 3345 Label cont; |
| 3346 __ jmp(&cont); |
| 3320 __ bind(¬_outermost_js); | 3347 __ bind(¬_outermost_js); |
| 3348 __ Push(Smi::FromInt(StackFrame::INNER_JSENTRY_FRAME)); |
| 3349 __ bind(&cont); |
| 3321 #endif | 3350 #endif |
| 3322 | 3351 |
| 3323 // Call a faked try-block that does the invoke. | 3352 // Call a faked try-block that does the invoke. |
| 3324 __ call(&invoke); | 3353 __ call(&invoke); |
| 3325 | 3354 |
| 3326 // Caught exception: Store result (exception) in the pending | 3355 // Caught exception: Store result (exception) in the pending |
| 3327 // exception field in the JSEnv and return a failure sentinel. | 3356 // exception field in the JSEnv and return a failure sentinel. |
| 3328 ExternalReference pending_exception(Isolate::k_pending_exception_address, | 3357 ExternalReference pending_exception(Isolate::k_pending_exception_address, |
| 3329 isolate); | 3358 isolate); |
| 3330 __ Store(pending_exception, rax); | 3359 __ Store(pending_exception, rax); |
| (...skipping 21 matching lines...) Expand all Loading... |
| 3352 isolate); | 3381 isolate); |
| 3353 __ Load(rax, construct_entry); | 3382 __ Load(rax, construct_entry); |
| 3354 } else { | 3383 } else { |
| 3355 ExternalReference entry(Builtins::kJSEntryTrampoline, isolate); | 3384 ExternalReference entry(Builtins::kJSEntryTrampoline, isolate); |
| 3356 __ Load(rax, entry); | 3385 __ Load(rax, entry); |
| 3357 } | 3386 } |
| 3358 __ lea(kScratchRegister, FieldOperand(rax, Code::kHeaderSize)); | 3387 __ lea(kScratchRegister, FieldOperand(rax, Code::kHeaderSize)); |
| 3359 __ call(kScratchRegister); | 3388 __ call(kScratchRegister); |
| 3360 | 3389 |
| 3361 // Unlink this frame from the handler chain. | 3390 // Unlink this frame from the handler chain. |
| 3362 Operand handler_operand = | 3391 __ PopTryHandler(); |
| 3363 masm->ExternalOperand(ExternalReference(Isolate::k_handler_address, | |
| 3364 isolate)); | |
| 3365 __ pop(handler_operand); | |
| 3366 // Pop next_sp. | |
| 3367 __ addq(rsp, Immediate(StackHandlerConstants::kSize - kPointerSize)); | |
| 3368 | 3392 |
| 3393 __ bind(&exit); |
| 3369 #ifdef ENABLE_LOGGING_AND_PROFILING | 3394 #ifdef ENABLE_LOGGING_AND_PROFILING |
| 3370 // If current RBP value is the same as js_entry_sp value, it means that | 3395 // Check if the current stack frame is marked as the outermost JS frame. |
| 3371 // the current function is the outermost. | 3396 __ pop(rbx); |
| 3397 __ Cmp(rbx, Smi::FromInt(StackFrame::OUTERMOST_JSENTRY_FRAME)); |
| 3398 __ j(not_equal, ¬_outermost_js_2); |
| 3372 __ movq(kScratchRegister, js_entry_sp); | 3399 __ movq(kScratchRegister, js_entry_sp); |
| 3373 __ cmpq(rbp, Operand(kScratchRegister, 0)); | |
| 3374 __ j(not_equal, ¬_outermost_js_2); | |
| 3375 __ movq(Operand(kScratchRegister, 0), Immediate(0)); | 3400 __ movq(Operand(kScratchRegister, 0), Immediate(0)); |
| 3376 __ bind(¬_outermost_js_2); | 3401 __ bind(¬_outermost_js_2); |
| 3377 #endif | 3402 #endif |
| 3378 | 3403 |
| 3379 // Restore the top frame descriptor from the stack. | 3404 // Restore the top frame descriptor from the stack. |
| 3380 __ bind(&exit); | 3405 { Operand c_entry_fp_operand = masm->ExternalOperand(c_entry_fp); |
| 3381 { | |
| 3382 Operand c_entry_fp_operand = masm->ExternalOperand(c_entry_fp); | |
| 3383 __ pop(c_entry_fp_operand); | 3406 __ pop(c_entry_fp_operand); |
| 3384 } | 3407 } |
| 3385 | 3408 |
| 3386 // Restore callee-saved registers (X64 conventions). | 3409 // Restore callee-saved registers (X64 conventions). |
| 3387 __ pop(rbx); | 3410 __ pop(rbx); |
| 3388 #ifdef _WIN64 | 3411 #ifdef _WIN64 |
| 3389 // Callee save on in Win64 ABI, arguments/volatile in AMD64 ABI. | 3412 // Callee save on in Win64 ABI, arguments/volatile in AMD64 ABI. |
| 3390 __ pop(rsi); | 3413 __ pop(rsi); |
| 3391 __ pop(rdi); | 3414 __ pop(rdi); |
| 3392 #endif | 3415 #endif |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3446 __ j(above, &slow); | 3469 __ j(above, &slow); |
| 3447 | 3470 |
| 3448 // Get the prototype of the function. | 3471 // Get the prototype of the function. |
| 3449 __ movq(rdx, Operand(rsp, 1 * kPointerSize + extra_stack_space)); | 3472 __ movq(rdx, Operand(rsp, 1 * kPointerSize + extra_stack_space)); |
| 3450 // rdx is function, rax is map. | 3473 // rdx is function, rax is map. |
| 3451 | 3474 |
| 3452 // If there is a call site cache don't look in the global cache, but do the | 3475 // If there is a call site cache don't look in the global cache, but do the |
| 3453 // real lookup and update the call site cache. | 3476 // real lookup and update the call site cache. |
| 3454 if (!HasCallSiteInlineCheck()) { | 3477 if (!HasCallSiteInlineCheck()) { |
| 3455 // Look up the function and the map in the instanceof cache. | 3478 // Look up the function and the map in the instanceof cache. |
| 3456 NearLabel miss; | 3479 Label miss; |
| 3457 __ CompareRoot(rdx, Heap::kInstanceofCacheFunctionRootIndex); | 3480 __ CompareRoot(rdx, Heap::kInstanceofCacheFunctionRootIndex); |
| 3458 __ j(not_equal, &miss); | 3481 __ j(not_equal, &miss, Label::kNear); |
| 3459 __ CompareRoot(rax, Heap::kInstanceofCacheMapRootIndex); | 3482 __ CompareRoot(rax, Heap::kInstanceofCacheMapRootIndex); |
| 3460 __ j(not_equal, &miss); | 3483 __ j(not_equal, &miss, Label::kNear); |
| 3461 __ LoadRoot(rax, Heap::kInstanceofCacheAnswerRootIndex); | 3484 __ LoadRoot(rax, Heap::kInstanceofCacheAnswerRootIndex); |
| 3462 __ ret(2 * kPointerSize); | 3485 __ ret(2 * kPointerSize); |
| 3463 __ bind(&miss); | 3486 __ bind(&miss); |
| 3464 } | 3487 } |
| 3465 | 3488 |
| 3466 __ TryGetFunctionPrototype(rdx, rbx, &slow); | 3489 __ TryGetFunctionPrototype(rdx, rbx, &slow); |
| 3467 | 3490 |
| 3468 // Check that the function prototype is a JS object. | 3491 // Check that the function prototype is a JS object. |
| 3469 __ JumpIfSmi(rbx, &slow); | 3492 __ JumpIfSmi(rbx, &slow); |
| 3470 __ CmpObjectType(rbx, FIRST_JS_OBJECT_TYPE, kScratchRegister); | 3493 __ CmpObjectType(rbx, FIRST_JS_OBJECT_TYPE, kScratchRegister); |
| (...skipping 16 matching lines...) Expand all Loading... |
| 3487 if (FLAG_debug_code) { | 3510 if (FLAG_debug_code) { |
| 3488 __ movl(rdi, Immediate(kWordBeforeMapCheckValue)); | 3511 __ movl(rdi, Immediate(kWordBeforeMapCheckValue)); |
| 3489 __ cmpl(Operand(kScratchRegister, kOffsetToMapCheckValue - 4), rdi); | 3512 __ cmpl(Operand(kScratchRegister, kOffsetToMapCheckValue - 4), rdi); |
| 3490 __ Assert(equal, "InstanceofStub unexpected call site cache (check)."); | 3513 __ Assert(equal, "InstanceofStub unexpected call site cache (check)."); |
| 3491 } | 3514 } |
| 3492 } | 3515 } |
| 3493 | 3516 |
| 3494 __ movq(rcx, FieldOperand(rax, Map::kPrototypeOffset)); | 3517 __ movq(rcx, FieldOperand(rax, Map::kPrototypeOffset)); |
| 3495 | 3518 |
| 3496 // Loop through the prototype chain looking for the function prototype. | 3519 // Loop through the prototype chain looking for the function prototype. |
| 3497 NearLabel loop, is_instance, is_not_instance; | 3520 Label loop, is_instance, is_not_instance; |
| 3498 __ LoadRoot(kScratchRegister, Heap::kNullValueRootIndex); | 3521 __ LoadRoot(kScratchRegister, Heap::kNullValueRootIndex); |
| 3499 __ bind(&loop); | 3522 __ bind(&loop); |
| 3500 __ cmpq(rcx, rbx); | 3523 __ cmpq(rcx, rbx); |
| 3501 __ j(equal, &is_instance); | 3524 __ j(equal, &is_instance, Label::kNear); |
| 3502 __ cmpq(rcx, kScratchRegister); | 3525 __ cmpq(rcx, kScratchRegister); |
| 3503 // The code at is_not_instance assumes that kScratchRegister contains a | 3526 // The code at is_not_instance assumes that kScratchRegister contains a |
| 3504 // non-zero GCable value (the null object in this case). | 3527 // non-zero GCable value (the null object in this case). |
| 3505 __ j(equal, &is_not_instance); | 3528 __ j(equal, &is_not_instance, Label::kNear); |
| 3506 __ movq(rcx, FieldOperand(rcx, HeapObject::kMapOffset)); | 3529 __ movq(rcx, FieldOperand(rcx, HeapObject::kMapOffset)); |
| 3507 __ movq(rcx, FieldOperand(rcx, Map::kPrototypeOffset)); | 3530 __ movq(rcx, FieldOperand(rcx, Map::kPrototypeOffset)); |
| 3508 __ jmp(&loop); | 3531 __ jmp(&loop); |
| 3509 | 3532 |
| 3510 __ bind(&is_instance); | 3533 __ bind(&is_instance); |
| 3511 if (!HasCallSiteInlineCheck()) { | 3534 if (!HasCallSiteInlineCheck()) { |
| 3512 __ xorl(rax, rax); | 3535 __ xorl(rax, rax); |
| 3513 // Store bitwise zero in the cache. This is a Smi in GC terms. | 3536 // Store bitwise zero in the cache. This is a Smi in GC terms. |
| 3514 STATIC_ASSERT(kSmiTag == 0); | 3537 STATIC_ASSERT(kSmiTag == 0); |
| 3515 __ StoreRoot(rax, Heap::kInstanceofCacheAnswerRootIndex); | 3538 __ StoreRoot(rax, Heap::kInstanceofCacheAnswerRootIndex); |
| (...skipping 208 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3724 | 3747 |
| 3725 | 3748 |
| 3726 void StringCharCodeAtGenerator::GenerateSlow( | 3749 void StringCharCodeAtGenerator::GenerateSlow( |
| 3727 MacroAssembler* masm, const RuntimeCallHelper& call_helper) { | 3750 MacroAssembler* masm, const RuntimeCallHelper& call_helper) { |
| 3728 __ Abort("Unexpected fallthrough to CharCodeAt slow case"); | 3751 __ Abort("Unexpected fallthrough to CharCodeAt slow case"); |
| 3729 | 3752 |
| 3730 Factory* factory = masm->isolate()->factory(); | 3753 Factory* factory = masm->isolate()->factory(); |
| 3731 // Index is not a smi. | 3754 // Index is not a smi. |
| 3732 __ bind(&index_not_smi_); | 3755 __ bind(&index_not_smi_); |
| 3733 // If index is a heap number, try converting it to an integer. | 3756 // If index is a heap number, try converting it to an integer. |
| 3734 __ CheckMap(index_, factory->heap_number_map(), index_not_number_, true); | 3757 __ CheckMap(index_, |
| 3758 factory->heap_number_map(), |
| 3759 index_not_number_, |
| 3760 DONT_DO_SMI_CHECK); |
| 3735 call_helper.BeforeCall(masm); | 3761 call_helper.BeforeCall(masm); |
| 3736 __ push(object_); | 3762 __ push(object_); |
| 3737 __ push(index_); | 3763 __ push(index_); |
| 3738 __ push(index_); // Consumed by runtime conversion function. | 3764 __ push(index_); // Consumed by runtime conversion function. |
| 3739 if (index_flags_ == STRING_INDEX_IS_NUMBER) { | 3765 if (index_flags_ == STRING_INDEX_IS_NUMBER) { |
| 3740 __ CallRuntime(Runtime::kNumberToIntegerMapMinusZero, 1); | 3766 __ CallRuntime(Runtime::kNumberToIntegerMapMinusZero, 1); |
| 3741 } else { | 3767 } else { |
| 3742 ASSERT(index_flags_ == STRING_INDEX_IS_ARRAY_INDEX); | 3768 ASSERT(index_flags_ == STRING_INDEX_IS_ARRAY_INDEX); |
| 3743 // NumberToSmi discards numbers that are not exact integers. | 3769 // NumberToSmi discards numbers that are not exact integers. |
| 3744 __ CallRuntime(Runtime::kNumberToSmi, 1); | 3770 __ CallRuntime(Runtime::kNumberToSmi, 1); |
| (...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3864 GenerateConvertArgument(masm, 1 * kPointerSize, rdx, rbx, rcx, rdi, | 3890 GenerateConvertArgument(masm, 1 * kPointerSize, rdx, rbx, rcx, rdi, |
| 3865 &call_builtin); | 3891 &call_builtin); |
| 3866 builtin_id = Builtins::STRING_ADD_LEFT; | 3892 builtin_id = Builtins::STRING_ADD_LEFT; |
| 3867 } | 3893 } |
| 3868 } | 3894 } |
| 3869 | 3895 |
| 3870 // Both arguments are strings. | 3896 // Both arguments are strings. |
| 3871 // rax: first string | 3897 // rax: first string |
| 3872 // rdx: second string | 3898 // rdx: second string |
| 3873 // Check if either of the strings are empty. In that case return the other. | 3899 // Check if either of the strings are empty. In that case return the other. |
| 3874 NearLabel second_not_zero_length, both_not_zero_length; | 3900 Label second_not_zero_length, both_not_zero_length; |
| 3875 __ movq(rcx, FieldOperand(rdx, String::kLengthOffset)); | 3901 __ movq(rcx, FieldOperand(rdx, String::kLengthOffset)); |
| 3876 __ SmiTest(rcx); | 3902 __ SmiTest(rcx); |
| 3877 __ j(not_zero, &second_not_zero_length); | 3903 __ j(not_zero, &second_not_zero_length, Label::kNear); |
| 3878 // Second string is empty, result is first string which is already in rax. | 3904 // Second string is empty, result is first string which is already in rax. |
| 3879 Counters* counters = masm->isolate()->counters(); | 3905 Counters* counters = masm->isolate()->counters(); |
| 3880 __ IncrementCounter(counters->string_add_native(), 1); | 3906 __ IncrementCounter(counters->string_add_native(), 1); |
| 3881 __ ret(2 * kPointerSize); | 3907 __ ret(2 * kPointerSize); |
| 3882 __ bind(&second_not_zero_length); | 3908 __ bind(&second_not_zero_length); |
| 3883 __ movq(rbx, FieldOperand(rax, String::kLengthOffset)); | 3909 __ movq(rbx, FieldOperand(rax, String::kLengthOffset)); |
| 3884 __ SmiTest(rbx); | 3910 __ SmiTest(rbx); |
| 3885 __ j(not_zero, &both_not_zero_length); | 3911 __ j(not_zero, &both_not_zero_length, Label::kNear); |
| 3886 // First string is empty, result is second string which is in rdx. | 3912 // First string is empty, result is second string which is in rdx. |
| 3887 __ movq(rax, rdx); | 3913 __ movq(rax, rdx); |
| 3888 __ IncrementCounter(counters->string_add_native(), 1); | 3914 __ IncrementCounter(counters->string_add_native(), 1); |
| 3889 __ ret(2 * kPointerSize); | 3915 __ ret(2 * kPointerSize); |
| 3890 | 3916 |
| 3891 // Both strings are non-empty. | 3917 // Both strings are non-empty. |
| 3892 // rax: first string | 3918 // rax: first string |
| 3893 // rbx: length of first string | 3919 // rbx: length of first string |
| 3894 // rcx: length of second string | 3920 // rcx: length of second string |
| 3895 // rdx: second string | 3921 // rdx: second string |
| (...skipping 273 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4169 bool ascii) { | 4195 bool ascii) { |
| 4170 // Copy characters using rep movs of doublewords. Align destination on 4 byte | 4196 // Copy characters using rep movs of doublewords. Align destination on 4 byte |
| 4171 // boundary before starting rep movs. Copy remaining characters after running | 4197 // boundary before starting rep movs. Copy remaining characters after running |
| 4172 // rep movs. | 4198 // rep movs. |
| 4173 // Count is positive int32, dest and src are character pointers. | 4199 // Count is positive int32, dest and src are character pointers. |
| 4174 ASSERT(dest.is(rdi)); // rep movs destination | 4200 ASSERT(dest.is(rdi)); // rep movs destination |
| 4175 ASSERT(src.is(rsi)); // rep movs source | 4201 ASSERT(src.is(rsi)); // rep movs source |
| 4176 ASSERT(count.is(rcx)); // rep movs count | 4202 ASSERT(count.is(rcx)); // rep movs count |
| 4177 | 4203 |
| 4178 // Nothing to do for zero characters. | 4204 // Nothing to do for zero characters. |
| 4179 NearLabel done; | 4205 Label done; |
| 4180 __ testl(count, count); | 4206 __ testl(count, count); |
| 4181 __ j(zero, &done); | 4207 __ j(zero, &done, Label::kNear); |
| 4182 | 4208 |
| 4183 // Make count the number of bytes to copy. | 4209 // Make count the number of bytes to copy. |
| 4184 if (!ascii) { | 4210 if (!ascii) { |
| 4185 STATIC_ASSERT(2 == sizeof(uc16)); | 4211 STATIC_ASSERT(2 == sizeof(uc16)); |
| 4186 __ addl(count, count); | 4212 __ addl(count, count); |
| 4187 } | 4213 } |
| 4188 | 4214 |
| 4189 // Don't enter the rep movs if there are less than 4 bytes to copy. | 4215 // Don't enter the rep movs if there are less than 4 bytes to copy. |
| 4190 NearLabel last_bytes; | 4216 Label last_bytes; |
| 4191 __ testl(count, Immediate(~7)); | 4217 __ testl(count, Immediate(~7)); |
| 4192 __ j(zero, &last_bytes); | 4218 __ j(zero, &last_bytes, Label::kNear); |
| 4193 | 4219 |
| 4194 // Copy from edi to esi using rep movs instruction. | 4220 // Copy from edi to esi using rep movs instruction. |
| 4195 __ movl(kScratchRegister, count); | 4221 __ movl(kScratchRegister, count); |
| 4196 __ shr(count, Immediate(3)); // Number of doublewords to copy. | 4222 __ shr(count, Immediate(3)); // Number of doublewords to copy. |
| 4197 __ repmovsq(); | 4223 __ repmovsq(); |
| 4198 | 4224 |
| 4199 // Find number of bytes left. | 4225 // Find number of bytes left. |
| 4200 __ movl(count, kScratchRegister); | 4226 __ movl(count, kScratchRegister); |
| 4201 __ and_(count, Immediate(7)); | 4227 __ and_(count, Immediate(7)); |
| 4202 | 4228 |
| 4203 // Check if there are more bytes to copy. | 4229 // Check if there are more bytes to copy. |
| 4204 __ bind(&last_bytes); | 4230 __ bind(&last_bytes); |
| 4205 __ testl(count, count); | 4231 __ testl(count, count); |
| 4206 __ j(zero, &done); | 4232 __ j(zero, &done, Label::kNear); |
| 4207 | 4233 |
| 4208 // Copy remaining characters. | 4234 // Copy remaining characters. |
| 4209 Label loop; | 4235 Label loop; |
| 4210 __ bind(&loop); | 4236 __ bind(&loop); |
| 4211 __ movb(kScratchRegister, Operand(src, 0)); | 4237 __ movb(kScratchRegister, Operand(src, 0)); |
| 4212 __ movb(Operand(dest, 0), kScratchRegister); | 4238 __ movb(Operand(dest, 0), kScratchRegister); |
| 4213 __ incq(src); | 4239 __ incq(src); |
| 4214 __ incq(dest); | 4240 __ incq(dest); |
| 4215 __ decl(count); | 4241 __ decl(count); |
| 4216 __ j(not_zero, &loop); | 4242 __ j(not_zero, &loop); |
| 4217 | 4243 |
| 4218 __ bind(&done); | 4244 __ bind(&done); |
| 4219 } | 4245 } |
| 4220 | 4246 |
| 4221 void StringHelper::GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm, | 4247 void StringHelper::GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm, |
| 4222 Register c1, | 4248 Register c1, |
| 4223 Register c2, | 4249 Register c2, |
| 4224 Register scratch1, | 4250 Register scratch1, |
| 4225 Register scratch2, | 4251 Register scratch2, |
| 4226 Register scratch3, | 4252 Register scratch3, |
| 4227 Register scratch4, | 4253 Register scratch4, |
| 4228 Label* not_found) { | 4254 Label* not_found) { |
| 4229 // Register scratch3 is the general scratch register in this function. | 4255 // Register scratch3 is the general scratch register in this function. |
| 4230 Register scratch = scratch3; | 4256 Register scratch = scratch3; |
| 4231 | 4257 |
| 4232 // Make sure that both characters are not digits as such strings has a | 4258 // Make sure that both characters are not digits as such strings has a |
| 4233 // different hash algorithm. Don't try to look for these in the symbol table. | 4259 // different hash algorithm. Don't try to look for these in the symbol table. |
| 4234 NearLabel not_array_index; | 4260 Label not_array_index; |
| 4235 __ leal(scratch, Operand(c1, -'0')); | 4261 __ leal(scratch, Operand(c1, -'0')); |
| 4236 __ cmpl(scratch, Immediate(static_cast<int>('9' - '0'))); | 4262 __ cmpl(scratch, Immediate(static_cast<int>('9' - '0'))); |
| 4237 __ j(above, ¬_array_index); | 4263 __ j(above, ¬_array_index, Label::kNear); |
| 4238 __ leal(scratch, Operand(c2, -'0')); | 4264 __ leal(scratch, Operand(c2, -'0')); |
| 4239 __ cmpl(scratch, Immediate(static_cast<int>('9' - '0'))); | 4265 __ cmpl(scratch, Immediate(static_cast<int>('9' - '0'))); |
| 4240 __ j(below_equal, not_found); | 4266 __ j(below_equal, not_found); |
| 4241 | 4267 |
| 4242 __ bind(¬_array_index); | 4268 __ bind(¬_array_index); |
| 4243 // Calculate the two character string hash. | 4269 // Calculate the two character string hash. |
| 4244 Register hash = scratch1; | 4270 Register hash = scratch1; |
| 4245 GenerateHashInit(masm, hash, c1, scratch); | 4271 GenerateHashInit(masm, hash, c1, scratch); |
| 4246 GenerateHashAddCharacter(masm, hash, c2, scratch); | 4272 GenerateHashAddCharacter(masm, hash, c2, scratch); |
| 4247 GenerateHashGetHash(masm, hash, scratch); | 4273 GenerateHashGetHash(masm, hash, scratch); |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4289 // Load the entry from the symbol table. | 4315 // Load the entry from the symbol table. |
| 4290 Register candidate = scratch; // Scratch register contains candidate. | 4316 Register candidate = scratch; // Scratch register contains candidate. |
| 4291 STATIC_ASSERT(SymbolTable::kEntrySize == 1); | 4317 STATIC_ASSERT(SymbolTable::kEntrySize == 1); |
| 4292 __ movq(candidate, | 4318 __ movq(candidate, |
| 4293 FieldOperand(symbol_table, | 4319 FieldOperand(symbol_table, |
| 4294 scratch, | 4320 scratch, |
| 4295 times_pointer_size, | 4321 times_pointer_size, |
| 4296 SymbolTable::kElementsStartOffset)); | 4322 SymbolTable::kElementsStartOffset)); |
| 4297 | 4323 |
| 4298 // If entry is undefined no string with this hash can be found. | 4324 // If entry is undefined no string with this hash can be found. |
| 4299 NearLabel is_string; | 4325 Label is_string; |
| 4300 __ CmpObjectType(candidate, ODDBALL_TYPE, map); | 4326 __ CmpObjectType(candidate, ODDBALL_TYPE, map); |
| 4301 __ j(not_equal, &is_string); | 4327 __ j(not_equal, &is_string, Label::kNear); |
| 4302 | 4328 |
| 4303 __ CompareRoot(candidate, Heap::kUndefinedValueRootIndex); | 4329 __ CompareRoot(candidate, Heap::kUndefinedValueRootIndex); |
| 4304 __ j(equal, not_found); | 4330 __ j(equal, not_found); |
| 4305 // Must be null (deleted entry). | 4331 // Must be null (deleted entry). |
| 4306 __ jmp(&next_probe[i]); | 4332 __ jmp(&next_probe[i]); |
| 4307 | 4333 |
| 4308 __ bind(&is_string); | 4334 __ bind(&is_string); |
| 4309 | 4335 |
| 4310 // If length is not 2 the string is not a candidate. | 4336 // If length is not 2 the string is not a candidate. |
| 4311 __ SmiCompare(FieldOperand(candidate, String::kLengthOffset), | 4337 __ SmiCompare(FieldOperand(candidate, String::kLengthOffset), |
| (...skipping 223 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4535 __ bind(&return_rax); | 4561 __ bind(&return_rax); |
| 4536 __ IncrementCounter(counters->sub_string_native(), 1); | 4562 __ IncrementCounter(counters->sub_string_native(), 1); |
| 4537 __ ret(kArgumentsSize); | 4563 __ ret(kArgumentsSize); |
| 4538 | 4564 |
| 4539 // Just jump to runtime to create the sub string. | 4565 // Just jump to runtime to create the sub string. |
| 4540 __ bind(&runtime); | 4566 __ bind(&runtime); |
| 4541 __ TailCallRuntime(Runtime::kSubString, 3, 1); | 4567 __ TailCallRuntime(Runtime::kSubString, 3, 1); |
| 4542 } | 4568 } |
| 4543 | 4569 |
| 4544 | 4570 |
| 4571 void StringCompareStub::GenerateFlatAsciiStringEquals(MacroAssembler* masm, |
| 4572 Register left, |
| 4573 Register right, |
| 4574 Register scratch1, |
| 4575 Register scratch2) { |
| 4576 Register length = scratch1; |
| 4577 |
| 4578 // Compare lengths. |
| 4579 Label check_zero_length; |
| 4580 __ movq(length, FieldOperand(left, String::kLengthOffset)); |
| 4581 __ SmiCompare(length, FieldOperand(right, String::kLengthOffset)); |
| 4582 __ j(equal, &check_zero_length, Label::kNear); |
| 4583 __ Move(rax, Smi::FromInt(NOT_EQUAL)); |
| 4584 __ ret(0); |
| 4585 |
| 4586 // Check if the length is zero. |
| 4587 Label compare_chars; |
| 4588 __ bind(&check_zero_length); |
| 4589 STATIC_ASSERT(kSmiTag == 0); |
| 4590 __ SmiTest(length); |
| 4591 __ j(not_zero, &compare_chars, Label::kNear); |
| 4592 __ Move(rax, Smi::FromInt(EQUAL)); |
| 4593 __ ret(0); |
| 4594 |
| 4595 // Compare characters. |
| 4596 __ bind(&compare_chars); |
| 4597 Label strings_not_equal; |
| 4598 GenerateAsciiCharsCompareLoop(masm, left, right, length, scratch2, |
| 4599 &strings_not_equal, Label::kNear); |
| 4600 |
| 4601 // Characters are equal. |
| 4602 __ Move(rax, Smi::FromInt(EQUAL)); |
| 4603 __ ret(0); |
| 4604 |
| 4605 // Characters are not equal. |
| 4606 __ bind(&strings_not_equal); |
| 4607 __ Move(rax, Smi::FromInt(NOT_EQUAL)); |
| 4608 __ ret(0); |
| 4609 } |
| 4610 |
| 4611 |
| 4545 void StringCompareStub::GenerateCompareFlatAsciiStrings(MacroAssembler* masm, | 4612 void StringCompareStub::GenerateCompareFlatAsciiStrings(MacroAssembler* masm, |
| 4546 Register left, | 4613 Register left, |
| 4547 Register right, | 4614 Register right, |
| 4548 Register scratch1, | 4615 Register scratch1, |
| 4549 Register scratch2, | 4616 Register scratch2, |
| 4550 Register scratch3, | 4617 Register scratch3, |
| 4551 Register scratch4) { | 4618 Register scratch4) { |
| 4552 // Ensure that you can always subtract a string length from a non-negative | 4619 // Ensure that you can always subtract a string length from a non-negative |
| 4553 // number (e.g. another length). | 4620 // number (e.g. another length). |
| 4554 STATIC_ASSERT(String::kMaxLength < 0x7fffffff); | 4621 STATIC_ASSERT(String::kMaxLength < 0x7fffffff); |
| 4555 | 4622 |
| 4556 // Find minimum length and length difference. | 4623 // Find minimum length and length difference. |
| 4557 __ movq(scratch1, FieldOperand(left, String::kLengthOffset)); | 4624 __ movq(scratch1, FieldOperand(left, String::kLengthOffset)); |
| 4558 __ movq(scratch4, scratch1); | 4625 __ movq(scratch4, scratch1); |
| 4559 __ SmiSub(scratch4, | 4626 __ SmiSub(scratch4, |
| 4560 scratch4, | 4627 scratch4, |
| 4561 FieldOperand(right, String::kLengthOffset)); | 4628 FieldOperand(right, String::kLengthOffset)); |
| 4562 // Register scratch4 now holds left.length - right.length. | 4629 // Register scratch4 now holds left.length - right.length. |
| 4563 const Register length_difference = scratch4; | 4630 const Register length_difference = scratch4; |
| 4564 NearLabel left_shorter; | 4631 Label left_shorter; |
| 4565 __ j(less, &left_shorter); | 4632 __ j(less, &left_shorter, Label::kNear); |
| 4566 // The right string isn't longer that the left one. | 4633 // The right string isn't longer that the left one. |
| 4567 // Get the right string's length by subtracting the (non-negative) difference | 4634 // Get the right string's length by subtracting the (non-negative) difference |
| 4568 // from the left string's length. | 4635 // from the left string's length. |
| 4569 __ SmiSub(scratch1, scratch1, length_difference); | 4636 __ SmiSub(scratch1, scratch1, length_difference); |
| 4570 __ bind(&left_shorter); | 4637 __ bind(&left_shorter); |
| 4571 // Register scratch1 now holds Min(left.length, right.length). | 4638 // Register scratch1 now holds Min(left.length, right.length). |
| 4572 const Register min_length = scratch1; | 4639 const Register min_length = scratch1; |
| 4573 | 4640 |
| 4574 NearLabel compare_lengths; | 4641 Label compare_lengths; |
| 4575 // If min-length is zero, go directly to comparing lengths. | 4642 // If min-length is zero, go directly to comparing lengths. |
| 4576 __ SmiTest(min_length); | 4643 __ SmiTest(min_length); |
| 4577 __ j(zero, &compare_lengths); | 4644 __ j(zero, &compare_lengths, Label::kNear); |
| 4578 | 4645 |
| 4579 __ SmiToInteger32(min_length, min_length); | 4646 // Compare loop. |
| 4647 Label result_not_equal; |
| 4648 GenerateAsciiCharsCompareLoop(masm, left, right, min_length, scratch2, |
| 4649 &result_not_equal, Label::kNear); |
| 4580 | 4650 |
| 4581 // Registers scratch2 and scratch3 are free. | |
| 4582 NearLabel result_not_equal; | |
| 4583 Label loop; | |
| 4584 { | |
| 4585 // Check characters 0 .. min_length - 1 in a loop. | |
| 4586 // Use scratch3 as loop index, min_length as limit and scratch2 | |
| 4587 // for computation. | |
| 4588 const Register index = scratch3; | |
| 4589 __ Set(index, 0); // Index into strings. | |
| 4590 __ bind(&loop); | |
| 4591 // Compare characters. | |
| 4592 // TODO(lrn): Could we load more than one character at a time? | |
| 4593 __ movb(scratch2, FieldOperand(left, | |
| 4594 index, | |
| 4595 times_1, | |
| 4596 SeqAsciiString::kHeaderSize)); | |
| 4597 // Increment index and use -1 modifier on next load to give | |
| 4598 // the previous load extra time to complete. | |
| 4599 __ addl(index, Immediate(1)); | |
| 4600 __ cmpb(scratch2, FieldOperand(right, | |
| 4601 index, | |
| 4602 times_1, | |
| 4603 SeqAsciiString::kHeaderSize - 1)); | |
| 4604 __ j(not_equal, &result_not_equal); | |
| 4605 __ cmpl(index, min_length); | |
| 4606 __ j(not_equal, &loop); | |
| 4607 } | |
| 4608 // Completed loop without finding different characters. | 4651 // Completed loop without finding different characters. |
| 4609 // Compare lengths (precomputed). | 4652 // Compare lengths (precomputed). |
| 4610 __ bind(&compare_lengths); | 4653 __ bind(&compare_lengths); |
| 4611 __ SmiTest(length_difference); | 4654 __ SmiTest(length_difference); |
| 4612 __ j(not_zero, &result_not_equal); | 4655 __ j(not_zero, &result_not_equal, Label::kNear); |
| 4613 | 4656 |
| 4614 // Result is EQUAL. | 4657 // Result is EQUAL. |
| 4615 __ Move(rax, Smi::FromInt(EQUAL)); | 4658 __ Move(rax, Smi::FromInt(EQUAL)); |
| 4616 __ ret(0); | 4659 __ ret(0); |
| 4617 | 4660 |
| 4618 NearLabel result_greater; | 4661 Label result_greater; |
| 4619 __ bind(&result_not_equal); | 4662 __ bind(&result_not_equal); |
| 4620 // Unequal comparison of left to right, either character or length. | 4663 // Unequal comparison of left to right, either character or length. |
| 4621 __ j(greater, &result_greater); | 4664 __ j(greater, &result_greater, Label::kNear); |
| 4622 | 4665 |
| 4623 // Result is LESS. | 4666 // Result is LESS. |
| 4624 __ Move(rax, Smi::FromInt(LESS)); | 4667 __ Move(rax, Smi::FromInt(LESS)); |
| 4625 __ ret(0); | 4668 __ ret(0); |
| 4626 | 4669 |
| 4627 // Result is GREATER. | 4670 // Result is GREATER. |
| 4628 __ bind(&result_greater); | 4671 __ bind(&result_greater); |
| 4629 __ Move(rax, Smi::FromInt(GREATER)); | 4672 __ Move(rax, Smi::FromInt(GREATER)); |
| 4630 __ ret(0); | 4673 __ ret(0); |
| 4631 } | 4674 } |
| 4632 | 4675 |
| 4633 | 4676 |
| 4677 void StringCompareStub::GenerateAsciiCharsCompareLoop( |
| 4678 MacroAssembler* masm, |
| 4679 Register left, |
| 4680 Register right, |
| 4681 Register length, |
| 4682 Register scratch, |
| 4683 Label* chars_not_equal, |
| 4684 Label::Distance near_jump) { |
| 4685 // Change index to run from -length to -1 by adding length to string |
| 4686 // start. This means that loop ends when index reaches zero, which |
| 4687 // doesn't need an additional compare. |
| 4688 __ SmiToInteger32(length, length); |
| 4689 __ lea(left, |
| 4690 FieldOperand(left, length, times_1, SeqAsciiString::kHeaderSize)); |
| 4691 __ lea(right, |
| 4692 FieldOperand(right, length, times_1, SeqAsciiString::kHeaderSize)); |
| 4693 __ neg(length); |
| 4694 Register index = length; // index = -length; |
| 4695 |
| 4696 // Compare loop. |
| 4697 Label loop; |
| 4698 __ bind(&loop); |
| 4699 __ movb(scratch, Operand(left, index, times_1, 0)); |
| 4700 __ cmpb(scratch, Operand(right, index, times_1, 0)); |
| 4701 __ j(not_equal, chars_not_equal, near_jump); |
| 4702 __ addq(index, Immediate(1)); |
| 4703 __ j(not_zero, &loop); |
| 4704 } |
| 4705 |
| 4706 |
| 4634 void StringCompareStub::Generate(MacroAssembler* masm) { | 4707 void StringCompareStub::Generate(MacroAssembler* masm) { |
| 4635 Label runtime; | 4708 Label runtime; |
| 4636 | 4709 |
| 4637 // Stack frame on entry. | 4710 // Stack frame on entry. |
| 4638 // rsp[0]: return address | 4711 // rsp[0]: return address |
| 4639 // rsp[8]: right string | 4712 // rsp[8]: right string |
| 4640 // rsp[16]: left string | 4713 // rsp[16]: left string |
| 4641 | 4714 |
| 4642 __ movq(rdx, Operand(rsp, 2 * kPointerSize)); // left | 4715 __ movq(rdx, Operand(rsp, 2 * kPointerSize)); // left |
| 4643 __ movq(rax, Operand(rsp, 1 * kPointerSize)); // right | 4716 __ movq(rax, Operand(rsp, 1 * kPointerSize)); // right |
| 4644 | 4717 |
| 4645 // Check for identity. | 4718 // Check for identity. |
| 4646 NearLabel not_same; | 4719 Label not_same; |
| 4647 __ cmpq(rdx, rax); | 4720 __ cmpq(rdx, rax); |
| 4648 __ j(not_equal, ¬_same); | 4721 __ j(not_equal, ¬_same, Label::kNear); |
| 4649 __ Move(rax, Smi::FromInt(EQUAL)); | 4722 __ Move(rax, Smi::FromInt(EQUAL)); |
| 4650 Counters* counters = masm->isolate()->counters(); | 4723 Counters* counters = masm->isolate()->counters(); |
| 4651 __ IncrementCounter(counters->string_compare_native(), 1); | 4724 __ IncrementCounter(counters->string_compare_native(), 1); |
| 4652 __ ret(2 * kPointerSize); | 4725 __ ret(2 * kPointerSize); |
| 4653 | 4726 |
| 4654 __ bind(¬_same); | 4727 __ bind(¬_same); |
| 4655 | 4728 |
| 4656 // Check that both are sequential ASCII strings. | 4729 // Check that both are sequential ASCII strings. |
| 4657 __ JumpIfNotBothSequentialAsciiStrings(rdx, rax, rcx, rbx, &runtime); | 4730 __ JumpIfNotBothSequentialAsciiStrings(rdx, rax, rcx, rbx, &runtime); |
| 4658 | 4731 |
| 4659 // Inline comparison of ascii strings. | 4732 // Inline comparison of ascii strings. |
| 4660 __ IncrementCounter(counters->string_compare_native(), 1); | 4733 __ IncrementCounter(counters->string_compare_native(), 1); |
| 4661 // Drop arguments from the stack | 4734 // Drop arguments from the stack |
| 4662 __ pop(rcx); | 4735 __ pop(rcx); |
| 4663 __ addq(rsp, Immediate(2 * kPointerSize)); | 4736 __ addq(rsp, Immediate(2 * kPointerSize)); |
| 4664 __ push(rcx); | 4737 __ push(rcx); |
| 4665 GenerateCompareFlatAsciiStrings(masm, rdx, rax, rcx, rbx, rdi, r8); | 4738 GenerateCompareFlatAsciiStrings(masm, rdx, rax, rcx, rbx, rdi, r8); |
| 4666 | 4739 |
| 4667 // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater) | 4740 // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater) |
| 4668 // tagged as a small integer. | 4741 // tagged as a small integer. |
| 4669 __ bind(&runtime); | 4742 __ bind(&runtime); |
| 4670 __ TailCallRuntime(Runtime::kStringCompare, 2, 1); | 4743 __ TailCallRuntime(Runtime::kStringCompare, 2, 1); |
| 4671 } | 4744 } |
| 4672 | 4745 |
| 4673 | 4746 |
| 4674 void ICCompareStub::GenerateSmis(MacroAssembler* masm) { | 4747 void ICCompareStub::GenerateSmis(MacroAssembler* masm) { |
| 4675 ASSERT(state_ == CompareIC::SMIS); | 4748 ASSERT(state_ == CompareIC::SMIS); |
| 4676 NearLabel miss; | 4749 Label miss; |
| 4677 __ JumpIfNotBothSmi(rdx, rax, &miss); | 4750 __ JumpIfNotBothSmi(rdx, rax, &miss, Label::kNear); |
| 4678 | 4751 |
| 4679 if (GetCondition() == equal) { | 4752 if (GetCondition() == equal) { |
| 4680 // For equality we do not care about the sign of the result. | 4753 // For equality we do not care about the sign of the result. |
| 4681 __ subq(rax, rdx); | 4754 __ subq(rax, rdx); |
| 4682 } else { | 4755 } else { |
| 4683 NearLabel done; | 4756 Label done; |
| 4684 __ subq(rdx, rax); | 4757 __ subq(rdx, rax); |
| 4685 __ j(no_overflow, &done); | 4758 __ j(no_overflow, &done, Label::kNear); |
| 4686 // Correct sign of result in case of overflow. | 4759 // Correct sign of result in case of overflow. |
| 4687 __ SmiNot(rdx, rdx); | 4760 __ SmiNot(rdx, rdx); |
| 4688 __ bind(&done); | 4761 __ bind(&done); |
| 4689 __ movq(rax, rdx); | 4762 __ movq(rax, rdx); |
| 4690 } | 4763 } |
| 4691 __ ret(0); | 4764 __ ret(0); |
| 4692 | 4765 |
| 4693 __ bind(&miss); | 4766 __ bind(&miss); |
| 4694 GenerateMiss(masm); | 4767 GenerateMiss(masm); |
| 4695 } | 4768 } |
| 4696 | 4769 |
| 4697 | 4770 |
| 4698 void ICCompareStub::GenerateHeapNumbers(MacroAssembler* masm) { | 4771 void ICCompareStub::GenerateHeapNumbers(MacroAssembler* masm) { |
| 4699 ASSERT(state_ == CompareIC::HEAP_NUMBERS); | 4772 ASSERT(state_ == CompareIC::HEAP_NUMBERS); |
| 4700 | 4773 |
| 4701 NearLabel generic_stub; | 4774 Label generic_stub; |
| 4702 NearLabel unordered; | 4775 Label unordered; |
| 4703 NearLabel miss; | 4776 Label miss; |
| 4704 Condition either_smi = masm->CheckEitherSmi(rax, rdx); | 4777 Condition either_smi = masm->CheckEitherSmi(rax, rdx); |
| 4705 __ j(either_smi, &generic_stub); | 4778 __ j(either_smi, &generic_stub, Label::kNear); |
| 4706 | 4779 |
| 4707 __ CmpObjectType(rax, HEAP_NUMBER_TYPE, rcx); | 4780 __ CmpObjectType(rax, HEAP_NUMBER_TYPE, rcx); |
| 4708 __ j(not_equal, &miss); | 4781 __ j(not_equal, &miss, Label::kNear); |
| 4709 __ CmpObjectType(rdx, HEAP_NUMBER_TYPE, rcx); | 4782 __ CmpObjectType(rdx, HEAP_NUMBER_TYPE, rcx); |
| 4710 __ j(not_equal, &miss); | 4783 __ j(not_equal, &miss, Label::kNear); |
| 4711 | 4784 |
| 4712 // Load left and right operand | 4785 // Load left and right operand |
| 4713 __ movsd(xmm0, FieldOperand(rdx, HeapNumber::kValueOffset)); | 4786 __ movsd(xmm0, FieldOperand(rdx, HeapNumber::kValueOffset)); |
| 4714 __ movsd(xmm1, FieldOperand(rax, HeapNumber::kValueOffset)); | 4787 __ movsd(xmm1, FieldOperand(rax, HeapNumber::kValueOffset)); |
| 4715 | 4788 |
| 4716 // Compare operands | 4789 // Compare operands |
| 4717 __ ucomisd(xmm0, xmm1); | 4790 __ ucomisd(xmm0, xmm1); |
| 4718 | 4791 |
| 4719 // Don't base result on EFLAGS when a NaN is involved. | 4792 // Don't base result on EFLAGS when a NaN is involved. |
| 4720 __ j(parity_even, &unordered); | 4793 __ j(parity_even, &unordered, Label::kNear); |
| 4721 | 4794 |
| 4722 // Return a result of -1, 0, or 1, based on EFLAGS. | 4795 // Return a result of -1, 0, or 1, based on EFLAGS. |
| 4723 // Performing mov, because xor would destroy the flag register. | 4796 // Performing mov, because xor would destroy the flag register. |
| 4724 __ movl(rax, Immediate(0)); | 4797 __ movl(rax, Immediate(0)); |
| 4725 __ movl(rcx, Immediate(0)); | 4798 __ movl(rcx, Immediate(0)); |
| 4726 __ setcc(above, rax); // Add one to zero if carry clear and not equal. | 4799 __ setcc(above, rax); // Add one to zero if carry clear and not equal. |
| 4727 __ sbbq(rax, rcx); // Subtract one if below (aka. carry set). | 4800 __ sbbq(rax, rcx); // Subtract one if below (aka. carry set). |
| 4728 __ ret(0); | 4801 __ ret(0); |
| 4729 | 4802 |
| 4730 __ bind(&unordered); | 4803 __ bind(&unordered); |
| 4731 | 4804 |
| 4732 CompareStub stub(GetCondition(), strict(), NO_COMPARE_FLAGS); | 4805 CompareStub stub(GetCondition(), strict(), NO_COMPARE_FLAGS); |
| 4733 __ bind(&generic_stub); | 4806 __ bind(&generic_stub); |
| 4734 __ jmp(stub.GetCode(), RelocInfo::CODE_TARGET); | 4807 __ jmp(stub.GetCode(), RelocInfo::CODE_TARGET); |
| 4735 | 4808 |
| 4736 __ bind(&miss); | 4809 __ bind(&miss); |
| 4737 GenerateMiss(masm); | 4810 GenerateMiss(masm); |
| 4738 } | 4811 } |
| 4739 | 4812 |
| 4740 | 4813 |
| 4814 void ICCompareStub::GenerateSymbols(MacroAssembler* masm) { |
| 4815 ASSERT(state_ == CompareIC::SYMBOLS); |
| 4816 ASSERT(GetCondition() == equal); |
| 4817 |
| 4818 // Registers containing left and right operands respectively. |
| 4819 Register left = rdx; |
| 4820 Register right = rax; |
| 4821 Register tmp1 = rcx; |
| 4822 Register tmp2 = rbx; |
| 4823 |
| 4824 // Check that both operands are heap objects. |
| 4825 Label miss; |
| 4826 Condition cond = masm->CheckEitherSmi(left, right, tmp1); |
| 4827 __ j(cond, &miss, Label::kNear); |
| 4828 |
| 4829 // Check that both operands are symbols. |
| 4830 __ movq(tmp1, FieldOperand(left, HeapObject::kMapOffset)); |
| 4831 __ movq(tmp2, FieldOperand(right, HeapObject::kMapOffset)); |
| 4832 __ movzxbq(tmp1, FieldOperand(tmp1, Map::kInstanceTypeOffset)); |
| 4833 __ movzxbq(tmp2, FieldOperand(tmp2, Map::kInstanceTypeOffset)); |
| 4834 STATIC_ASSERT(kSymbolTag != 0); |
| 4835 __ and_(tmp1, tmp2); |
| 4836 __ testb(tmp1, Immediate(kIsSymbolMask)); |
| 4837 __ j(zero, &miss, Label::kNear); |
| 4838 |
| 4839 // Symbols are compared by identity. |
| 4840 Label done; |
| 4841 __ cmpq(left, right); |
| 4842 // Make sure rax is non-zero. At this point input operands are |
| 4843 // guaranteed to be non-zero. |
| 4844 ASSERT(right.is(rax)); |
| 4845 __ j(not_equal, &done, Label::kNear); |
| 4846 STATIC_ASSERT(EQUAL == 0); |
| 4847 STATIC_ASSERT(kSmiTag == 0); |
| 4848 __ Move(rax, Smi::FromInt(EQUAL)); |
| 4849 __ bind(&done); |
| 4850 __ ret(0); |
| 4851 |
| 4852 __ bind(&miss); |
| 4853 GenerateMiss(masm); |
| 4854 } |
| 4855 |
| 4856 |
| 4741 void ICCompareStub::GenerateStrings(MacroAssembler* masm) { | 4857 void ICCompareStub::GenerateStrings(MacroAssembler* masm) { |
| 4742 ASSERT(state_ == CompareIC::STRINGS); | 4858 ASSERT(state_ == CompareIC::STRINGS); |
| 4859 ASSERT(GetCondition() == equal); |
| 4743 Label miss; | 4860 Label miss; |
| 4744 | 4861 |
| 4745 // Registers containing left and right operands respectively. | 4862 // Registers containing left and right operands respectively. |
| 4746 Register left = rdx; | 4863 Register left = rdx; |
| 4747 Register right = rax; | 4864 Register right = rax; |
| 4748 Register tmp1 = rcx; | 4865 Register tmp1 = rcx; |
| 4749 Register tmp2 = rbx; | 4866 Register tmp2 = rbx; |
| 4750 Register tmp3 = rdi; | 4867 Register tmp3 = rdi; |
| 4751 Register tmp4 = r8; | |
| 4752 | 4868 |
| 4753 // Check that both operands are heap objects. | 4869 // Check that both operands are heap objects. |
| 4754 Condition cond = masm->CheckEitherSmi(left, right, tmp1); | 4870 Condition cond = masm->CheckEitherSmi(left, right, tmp1); |
| 4755 __ j(cond, &miss); | 4871 __ j(cond, &miss); |
| 4756 | 4872 |
| 4757 // Check that both operands are strings. This leaves the instance | 4873 // Check that both operands are strings. This leaves the instance |
| 4758 // types loaded in tmp1 and tmp2. | 4874 // types loaded in tmp1 and tmp2. |
| 4759 __ movq(tmp1, FieldOperand(left, HeapObject::kMapOffset)); | 4875 __ movq(tmp1, FieldOperand(left, HeapObject::kMapOffset)); |
| 4760 __ movq(tmp2, FieldOperand(right, HeapObject::kMapOffset)); | 4876 __ movq(tmp2, FieldOperand(right, HeapObject::kMapOffset)); |
| 4761 __ movzxbq(tmp1, FieldOperand(tmp1, Map::kInstanceTypeOffset)); | 4877 __ movzxbq(tmp1, FieldOperand(tmp1, Map::kInstanceTypeOffset)); |
| 4762 __ movzxbq(tmp2, FieldOperand(tmp2, Map::kInstanceTypeOffset)); | 4878 __ movzxbq(tmp2, FieldOperand(tmp2, Map::kInstanceTypeOffset)); |
| 4763 __ movq(tmp3, tmp1); | 4879 __ movq(tmp3, tmp1); |
| 4764 STATIC_ASSERT(kNotStringTag != 0); | 4880 STATIC_ASSERT(kNotStringTag != 0); |
| 4765 __ or_(tmp3, tmp2); | 4881 __ or_(tmp3, tmp2); |
| 4766 __ testl(tmp3, Immediate(kIsNotStringMask)); | 4882 __ testb(tmp3, Immediate(kIsNotStringMask)); |
| 4767 __ j(not_zero, &miss); | 4883 __ j(not_zero, &miss); |
| 4768 | 4884 |
| 4769 // Fast check for identical strings. | 4885 // Fast check for identical strings. |
| 4770 NearLabel not_same; | 4886 Label not_same; |
| 4771 __ cmpq(left, right); | 4887 __ cmpq(left, right); |
| 4772 __ j(not_equal, ¬_same); | 4888 __ j(not_equal, ¬_same, Label::kNear); |
| 4773 STATIC_ASSERT(EQUAL == 0); | 4889 STATIC_ASSERT(EQUAL == 0); |
| 4774 STATIC_ASSERT(kSmiTag == 0); | 4890 STATIC_ASSERT(kSmiTag == 0); |
| 4775 __ Move(rax, Smi::FromInt(EQUAL)); | 4891 __ Move(rax, Smi::FromInt(EQUAL)); |
| 4776 __ ret(0); | 4892 __ ret(0); |
| 4777 | 4893 |
| 4778 // Handle not identical strings. | 4894 // Handle not identical strings. |
| 4779 __ bind(¬_same); | 4895 __ bind(¬_same); |
| 4780 | 4896 |
| 4781 // Check that both strings are symbols. If they are, we're done | 4897 // Check that both strings are symbols. If they are, we're done |
| 4782 // because we already know they are not identical. | 4898 // because we already know they are not identical. |
| 4783 NearLabel do_compare; | 4899 Label do_compare; |
| 4784 ASSERT(GetCondition() == equal); | |
| 4785 STATIC_ASSERT(kSymbolTag != 0); | 4900 STATIC_ASSERT(kSymbolTag != 0); |
| 4786 __ and_(tmp1, tmp2); | 4901 __ and_(tmp1, tmp2); |
| 4787 __ testl(tmp1, Immediate(kIsSymbolMask)); | 4902 __ testb(tmp1, Immediate(kIsSymbolMask)); |
| 4788 __ j(zero, &do_compare); | 4903 __ j(zero, &do_compare, Label::kNear); |
| 4789 // Make sure rax is non-zero. At this point input operands are | 4904 // Make sure rax is non-zero. At this point input operands are |
| 4790 // guaranteed to be non-zero. | 4905 // guaranteed to be non-zero. |
| 4791 ASSERT(right.is(rax)); | 4906 ASSERT(right.is(rax)); |
| 4792 __ ret(0); | 4907 __ ret(0); |
| 4793 | 4908 |
| 4794 // Check that both strings are sequential ASCII. | 4909 // Check that both strings are sequential ASCII. |
| 4795 Label runtime; | 4910 Label runtime; |
| 4796 __ bind(&do_compare); | 4911 __ bind(&do_compare); |
| 4797 __ JumpIfNotBothSequentialAsciiStrings(left, right, tmp1, tmp2, &runtime); | 4912 __ JumpIfNotBothSequentialAsciiStrings(left, right, tmp1, tmp2, &runtime); |
| 4798 | 4913 |
| 4799 // Compare flat ASCII strings. Returns when done. | 4914 // Compare flat ASCII strings. Returns when done. |
| 4800 StringCompareStub::GenerateCompareFlatAsciiStrings( | 4915 StringCompareStub::GenerateFlatAsciiStringEquals( |
| 4801 masm, left, right, tmp1, tmp2, tmp3, tmp4); | 4916 masm, left, right, tmp1, tmp2); |
| 4802 | 4917 |
| 4803 // Handle more complex cases in runtime. | 4918 // Handle more complex cases in runtime. |
| 4804 __ bind(&runtime); | 4919 __ bind(&runtime); |
| 4805 __ pop(tmp1); // Return address. | 4920 __ pop(tmp1); // Return address. |
| 4806 __ push(left); | 4921 __ push(left); |
| 4807 __ push(right); | 4922 __ push(right); |
| 4808 __ push(tmp1); | 4923 __ push(tmp1); |
| 4809 __ TailCallRuntime(Runtime::kStringCompare, 2, 1); | 4924 __ TailCallRuntime(Runtime::kStringEquals, 2, 1); |
| 4810 | 4925 |
| 4811 __ bind(&miss); | 4926 __ bind(&miss); |
| 4812 GenerateMiss(masm); | 4927 GenerateMiss(masm); |
| 4813 } | 4928 } |
| 4814 | 4929 |
| 4815 | 4930 |
| 4816 void ICCompareStub::GenerateObjects(MacroAssembler* masm) { | 4931 void ICCompareStub::GenerateObjects(MacroAssembler* masm) { |
| 4817 ASSERT(state_ == CompareIC::OBJECTS); | 4932 ASSERT(state_ == CompareIC::OBJECTS); |
| 4818 NearLabel miss; | 4933 Label miss; |
| 4819 Condition either_smi = masm->CheckEitherSmi(rdx, rax); | 4934 Condition either_smi = masm->CheckEitherSmi(rdx, rax); |
| 4820 __ j(either_smi, &miss); | 4935 __ j(either_smi, &miss, Label::kNear); |
| 4821 | 4936 |
| 4822 __ CmpObjectType(rax, JS_OBJECT_TYPE, rcx); | 4937 __ CmpObjectType(rax, JS_OBJECT_TYPE, rcx); |
| 4823 __ j(not_equal, &miss, not_taken); | 4938 __ j(not_equal, &miss, Label::kNear); |
| 4824 __ CmpObjectType(rdx, JS_OBJECT_TYPE, rcx); | 4939 __ CmpObjectType(rdx, JS_OBJECT_TYPE, rcx); |
| 4825 __ j(not_equal, &miss, not_taken); | 4940 __ j(not_equal, &miss, Label::kNear); |
| 4826 | 4941 |
| 4827 ASSERT(GetCondition() == equal); | 4942 ASSERT(GetCondition() == equal); |
| 4828 __ subq(rax, rdx); | 4943 __ subq(rax, rdx); |
| 4829 __ ret(0); | 4944 __ ret(0); |
| 4830 | 4945 |
| 4831 __ bind(&miss); | 4946 __ bind(&miss); |
| 4832 GenerateMiss(masm); | 4947 GenerateMiss(masm); |
| 4833 } | 4948 } |
| 4834 | 4949 |
| 4835 | 4950 |
| (...skipping 21 matching lines...) Expand all Loading... |
| 4857 __ pop(rcx); | 4972 __ pop(rcx); |
| 4858 __ pop(rax); | 4973 __ pop(rax); |
| 4859 __ pop(rdx); | 4974 __ pop(rdx); |
| 4860 __ push(rcx); | 4975 __ push(rcx); |
| 4861 | 4976 |
| 4862 // Do a tail call to the rewritten stub. | 4977 // Do a tail call to the rewritten stub. |
| 4863 __ jmp(rdi); | 4978 __ jmp(rdi); |
| 4864 } | 4979 } |
| 4865 | 4980 |
| 4866 | 4981 |
| 4982 MaybeObject* StringDictionaryLookupStub::GenerateNegativeLookup( |
| 4983 MacroAssembler* masm, |
| 4984 Label* miss, |
| 4985 Label* done, |
| 4986 Register properties, |
| 4987 String* name, |
| 4988 Register r0) { |
| 4989 // If names of slots in range from 1 to kProbes - 1 for the hash value are |
| 4990 // not equal to the name and kProbes-th slot is not used (its name is the |
| 4991 // undefined value), it guarantees the hash table doesn't contain the |
| 4992 // property. It's true even if some slots represent deleted properties |
| 4993 // (their names are the null value). |
| 4994 for (int i = 0; i < kInlinedProbes; i++) { |
| 4995 // r0 points to properties hash. |
| 4996 // Compute the masked index: (hash + i + i * i) & mask. |
| 4997 Register index = r0; |
| 4998 // Capacity is smi 2^n. |
| 4999 __ SmiToInteger32(index, FieldOperand(properties, kCapacityOffset)); |
| 5000 __ decl(index); |
| 5001 __ and_(index, |
| 5002 Immediate(name->Hash() + StringDictionary::GetProbeOffset(i))); |
| 5003 |
| 5004 // Scale the index by multiplying by the entry size. |
| 5005 ASSERT(StringDictionary::kEntrySize == 3); |
| 5006 __ lea(index, Operand(index, index, times_2, 0)); // index *= 3. |
| 5007 |
| 5008 Register entity_name = r0; |
| 5009 // Having undefined at this place means the name is not contained. |
| 5010 ASSERT_EQ(kSmiTagSize, 1); |
| 5011 __ movq(entity_name, Operand(properties, |
| 5012 index, |
| 5013 times_pointer_size, |
| 5014 kElementsStartOffset - kHeapObjectTag)); |
| 5015 __ Cmp(entity_name, masm->isolate()->factory()->undefined_value()); |
| 5016 __ j(equal, done); |
| 5017 |
| 5018 // Stop if found the property. |
| 5019 __ Cmp(entity_name, Handle<String>(name)); |
| 5020 __ j(equal, miss); |
| 5021 |
| 5022 // Check if the entry name is not a symbol. |
| 5023 __ movq(entity_name, FieldOperand(entity_name, HeapObject::kMapOffset)); |
| 5024 __ testb(FieldOperand(entity_name, Map::kInstanceTypeOffset), |
| 5025 Immediate(kIsSymbolMask)); |
| 5026 __ j(zero, miss); |
| 5027 } |
| 5028 |
| 5029 StringDictionaryLookupStub stub(properties, |
| 5030 r0, |
| 5031 r0, |
| 5032 StringDictionaryLookupStub::NEGATIVE_LOOKUP); |
| 5033 __ Push(Handle<Object>(name)); |
| 5034 __ push(Immediate(name->Hash())); |
| 5035 MaybeObject* result = masm->TryCallStub(&stub); |
| 5036 if (result->IsFailure()) return result; |
| 5037 __ testq(r0, r0); |
| 5038 __ j(not_zero, miss); |
| 5039 __ jmp(done); |
| 5040 return result; |
| 5041 } |
| 5042 |
| 5043 |
| 5044 // Probe the string dictionary in the |elements| register. Jump to the |
| 5045 // |done| label if a property with the given name is found leaving the |
| 5046 // index into the dictionary in |r1|. Jump to the |miss| label |
| 5047 // otherwise. |
| 5048 void StringDictionaryLookupStub::GeneratePositiveLookup(MacroAssembler* masm, |
| 5049 Label* miss, |
| 5050 Label* done, |
| 5051 Register elements, |
| 5052 Register name, |
| 5053 Register r0, |
| 5054 Register r1) { |
| 5055 // Assert that name contains a string. |
| 5056 if (FLAG_debug_code) __ AbortIfNotString(name); |
| 5057 |
| 5058 __ SmiToInteger32(r0, FieldOperand(elements, kCapacityOffset)); |
| 5059 __ decl(r0); |
| 5060 |
| 5061 for (int i = 0; i < kInlinedProbes; i++) { |
| 5062 // Compute the masked index: (hash + i + i * i) & mask. |
| 5063 __ movl(r1, FieldOperand(name, String::kHashFieldOffset)); |
| 5064 __ shrl(r1, Immediate(String::kHashShift)); |
| 5065 if (i > 0) { |
| 5066 __ addl(r1, Immediate(StringDictionary::GetProbeOffset(i))); |
| 5067 } |
| 5068 __ and_(r1, r0); |
| 5069 |
| 5070 // Scale the index by multiplying by the entry size. |
| 5071 ASSERT(StringDictionary::kEntrySize == 3); |
| 5072 __ lea(r1, Operand(r1, r1, times_2, 0)); // r1 = r1 * 3 |
| 5073 |
| 5074 // Check if the key is identical to the name. |
| 5075 __ cmpq(name, Operand(elements, r1, times_pointer_size, |
| 5076 kElementsStartOffset - kHeapObjectTag)); |
| 5077 __ j(equal, done); |
| 5078 } |
| 5079 |
| 5080 StringDictionaryLookupStub stub(elements, |
| 5081 r0, |
| 5082 r1, |
| 5083 POSITIVE_LOOKUP); |
| 5084 __ push(name); |
| 5085 __ movl(r0, FieldOperand(name, String::kHashFieldOffset)); |
| 5086 __ shrl(r0, Immediate(String::kHashShift)); |
| 5087 __ push(r0); |
| 5088 __ CallStub(&stub); |
| 5089 |
| 5090 __ testq(r0, r0); |
| 5091 __ j(zero, miss); |
| 5092 __ jmp(done); |
| 5093 } |
| 5094 |
| 5095 |
| 5096 void StringDictionaryLookupStub::Generate(MacroAssembler* masm) { |
| 5097 // Stack frame on entry: |
| 5098 // esp[0 * kPointerSize]: return address. |
| 5099 // esp[1 * kPointerSize]: key's hash. |
| 5100 // esp[2 * kPointerSize]: key. |
| 5101 // Registers: |
| 5102 // dictionary_: StringDictionary to probe. |
| 5103 // result_: used as scratch. |
| 5104 // index_: will hold an index of entry if lookup is successful. |
| 5105 // might alias with result_. |
| 5106 // Returns: |
| 5107 // result_ is zero if lookup failed, non zero otherwise. |
| 5108 |
| 5109 Label in_dictionary, maybe_in_dictionary, not_in_dictionary; |
| 5110 |
| 5111 Register scratch = result_; |
| 5112 |
| 5113 __ SmiToInteger32(scratch, FieldOperand(dictionary_, kCapacityOffset)); |
| 5114 __ decl(scratch); |
| 5115 __ push(scratch); |
| 5116 |
| 5117 // If names of slots in range from 1 to kProbes - 1 for the hash value are |
| 5118 // not equal to the name and kProbes-th slot is not used (its name is the |
| 5119 // undefined value), it guarantees the hash table doesn't contain the |
| 5120 // property. It's true even if some slots represent deleted properties |
| 5121 // (their names are the null value). |
| 5122 for (int i = kInlinedProbes; i < kTotalProbes; i++) { |
| 5123 // Compute the masked index: (hash + i + i * i) & mask. |
| 5124 __ movq(scratch, Operand(rsp, 2 * kPointerSize)); |
| 5125 if (i > 0) { |
| 5126 __ addl(scratch, Immediate(StringDictionary::GetProbeOffset(i))); |
| 5127 } |
| 5128 __ and_(scratch, Operand(rsp, 0)); |
| 5129 |
| 5130 // Scale the index by multiplying by the entry size. |
| 5131 ASSERT(StringDictionary::kEntrySize == 3); |
| 5132 __ lea(index_, Operand(scratch, scratch, times_2, 0)); // index *= 3. |
| 5133 |
| 5134 // Having undefined at this place means the name is not contained. |
| 5135 __ movq(scratch, Operand(dictionary_, |
| 5136 index_, |
| 5137 times_pointer_size, |
| 5138 kElementsStartOffset - kHeapObjectTag)); |
| 5139 |
| 5140 __ Cmp(scratch, masm->isolate()->factory()->undefined_value()); |
| 5141 __ j(equal, ¬_in_dictionary); |
| 5142 |
| 5143 // Stop if found the property. |
| 5144 __ cmpq(scratch, Operand(rsp, 3 * kPointerSize)); |
| 5145 __ j(equal, &in_dictionary); |
| 5146 |
| 5147 if (i != kTotalProbes - 1 && mode_ == NEGATIVE_LOOKUP) { |
| 5148 // If we hit a non symbol key during negative lookup |
| 5149 // we have to bailout as this key might be equal to the |
| 5150 // key we are looking for. |
| 5151 |
| 5152 // Check if the entry name is not a symbol. |
| 5153 __ movq(scratch, FieldOperand(scratch, HeapObject::kMapOffset)); |
| 5154 __ testb(FieldOperand(scratch, Map::kInstanceTypeOffset), |
| 5155 Immediate(kIsSymbolMask)); |
| 5156 __ j(zero, &maybe_in_dictionary); |
| 5157 } |
| 5158 } |
| 5159 |
| 5160 __ bind(&maybe_in_dictionary); |
| 5161 // If we are doing negative lookup then probing failure should be |
| 5162 // treated as a lookup success. For positive lookup probing failure |
| 5163 // should be treated as lookup failure. |
| 5164 if (mode_ == POSITIVE_LOOKUP) { |
| 5165 __ movq(scratch, Immediate(0)); |
| 5166 __ Drop(1); |
| 5167 __ ret(2 * kPointerSize); |
| 5168 } |
| 5169 |
| 5170 __ bind(&in_dictionary); |
| 5171 __ movq(scratch, Immediate(1)); |
| 5172 __ Drop(1); |
| 5173 __ ret(2 * kPointerSize); |
| 5174 |
| 5175 __ bind(¬_in_dictionary); |
| 5176 __ movq(scratch, Immediate(0)); |
| 5177 __ Drop(1); |
| 5178 __ ret(2 * kPointerSize); |
| 5179 } |
| 5180 |
| 5181 |
| 4867 #undef __ | 5182 #undef __ |
| 4868 | 5183 |
| 4869 } } // namespace v8::internal | 5184 } } // namespace v8::internal |
| 4870 | 5185 |
| 4871 #endif // V8_TARGET_ARCH_X64 | 5186 #endif // V8_TARGET_ARCH_X64 |
| OLD | NEW |