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

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

Issue 8086021: Clean up the x86 assembler API. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Created 9 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright 2011 the V8 project authors. All rights reserved. 1 // Copyright 2011 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without 2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are 3 // modification, are permitted provided that the following conditions are
4 // met: 4 // met:
5 // 5 //
6 // * Redistributions of source code must retain the above copyright 6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer. 7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above 8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following 9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided 10 // disclaimer in the documentation and/or other materials provided
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
42 42
43 void ToNumberStub::Generate(MacroAssembler* masm) { 43 void ToNumberStub::Generate(MacroAssembler* masm) {
44 // The ToNumber stub takes one argument in eax. 44 // The ToNumber stub takes one argument in eax.
45 Label check_heap_number, call_builtin; 45 Label check_heap_number, call_builtin;
46 __ JumpIfNotSmi(eax, &check_heap_number, Label::kNear); 46 __ JumpIfNotSmi(eax, &check_heap_number, Label::kNear);
47 __ ret(0); 47 __ ret(0);
48 48
49 __ bind(&check_heap_number); 49 __ bind(&check_heap_number);
50 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); 50 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
51 Factory* factory = masm->isolate()->factory(); 51 Factory* factory = masm->isolate()->factory();
52 __ cmp(Operand(ebx), Immediate(factory->heap_number_map())); 52 __ cmp(ebx, Immediate(factory->heap_number_map()));
53 __ j(not_equal, &call_builtin, Label::kNear); 53 __ j(not_equal, &call_builtin, Label::kNear);
54 __ ret(0); 54 __ ret(0);
55 55
56 __ bind(&call_builtin); 56 __ bind(&call_builtin);
57 __ pop(ecx); // Pop return address. 57 __ pop(ecx); // Pop return address.
58 __ push(eax); 58 __ push(eax);
59 __ push(ecx); // Push return address. 59 __ push(ecx); // Push return address.
60 __ InvokeBuiltin(Builtins::TO_NUMBER, JUMP_FUNCTION); 60 __ InvokeBuiltin(Builtins::TO_NUMBER, JUMP_FUNCTION);
61 } 61 }
62 62
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after
143 __ mov(ebx, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX))); 143 __ mov(ebx, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX)));
144 __ mov(Operand(eax, Context::SlotOffset(Context::GLOBAL_INDEX)), ebx); 144 __ mov(Operand(eax, Context::SlotOffset(Context::GLOBAL_INDEX)), ebx);
145 145
146 // Initialize the rest of the slots to undefined. 146 // Initialize the rest of the slots to undefined.
147 __ mov(ebx, factory->undefined_value()); 147 __ mov(ebx, factory->undefined_value());
148 for (int i = Context::MIN_CONTEXT_SLOTS; i < length; i++) { 148 for (int i = Context::MIN_CONTEXT_SLOTS; i < length; i++) {
149 __ mov(Operand(eax, Context::SlotOffset(i)), ebx); 149 __ mov(Operand(eax, Context::SlotOffset(i)), ebx);
150 } 150 }
151 151
152 // Return and remove the on-stack parameter. 152 // Return and remove the on-stack parameter.
153 __ mov(esi, Operand(eax)); 153 __ mov(esi, eax);
154 __ ret(1 * kPointerSize); 154 __ ret(1 * kPointerSize);
155 155
156 // Need to collect. Call into runtime system. 156 // Need to collect. Call into runtime system.
157 __ bind(&gc); 157 __ bind(&gc);
158 __ TailCallRuntime(Runtime::kNewFunctionContext, 1, 1); 158 __ TailCallRuntime(Runtime::kNewFunctionContext, 1, 1);
159 } 159 }
160 160
161 161
162 void FastCloneShallowArrayStub::Generate(MacroAssembler* masm) { 162 void FastCloneShallowArrayStub::Generate(MacroAssembler* masm) {
163 // Stack layout on entry: 163 // Stack layout on entry:
(...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after
338 } 338 }
339 339
340 340
341 void StoreBufferOverflowStub::Generate(MacroAssembler* masm) { 341 void StoreBufferOverflowStub::Generate(MacroAssembler* masm) {
342 // We don't allow a GC during a store buffer overflow so there is no need to 342 // We don't allow a GC during a store buffer overflow so there is no need to
343 // store the registers in any particular way, but we do have to store and 343 // store the registers in any particular way, but we do have to store and
344 // restore them. 344 // restore them.
345 __ pushad(); 345 __ pushad();
346 if (save_doubles_ == kSaveFPRegs) { 346 if (save_doubles_ == kSaveFPRegs) {
347 CpuFeatures::Scope scope(SSE2); 347 CpuFeatures::Scope scope(SSE2);
348 __ sub(Operand(esp), Immediate(kDoubleSize * XMMRegister::kNumRegisters)); 348 __ sub(esp, Immediate(kDoubleSize * XMMRegister::kNumRegisters));
349 for (int i = 0; i < XMMRegister::kNumRegisters; i++) { 349 for (int i = 0; i < XMMRegister::kNumRegisters; i++) {
350 XMMRegister reg = XMMRegister::from_code(i); 350 XMMRegister reg = XMMRegister::from_code(i);
351 __ movdbl(Operand(esp, i * kDoubleSize), reg); 351 __ movdbl(Operand(esp, i * kDoubleSize), reg);
352 } 352 }
353 } 353 }
354 const int argument_count = 1; 354 const int argument_count = 1;
355 355
356 AllowExternalCallThatCantCauseGC scope(masm); 356 AllowExternalCallThatCantCauseGC scope(masm);
357 __ PrepareCallCFunction(argument_count, ecx); 357 __ PrepareCallCFunction(argument_count, ecx);
358 __ mov(Operand(esp, 0 * kPointerSize), 358 __ mov(Operand(esp, 0 * kPointerSize),
359 Immediate(ExternalReference::isolate_address())); 359 Immediate(ExternalReference::isolate_address()));
360 __ CallCFunction( 360 __ CallCFunction(
361 ExternalReference::store_buffer_overflow_function(masm->isolate()), 361 ExternalReference::store_buffer_overflow_function(masm->isolate()),
362 argument_count); 362 argument_count);
363 if (save_doubles_ == kSaveFPRegs) { 363 if (save_doubles_ == kSaveFPRegs) {
364 CpuFeatures::Scope scope(SSE2); 364 CpuFeatures::Scope scope(SSE2);
365 for (int i = 0; i < XMMRegister::kNumRegisters; i++) { 365 for (int i = 0; i < XMMRegister::kNumRegisters; i++) {
366 XMMRegister reg = XMMRegister::from_code(i); 366 XMMRegister reg = XMMRegister::from_code(i);
367 __ movdbl(reg, Operand(esp, i * kDoubleSize)); 367 __ movdbl(reg, Operand(esp, i * kDoubleSize));
368 } 368 }
369 __ add(Operand(esp), Immediate(kDoubleSize * XMMRegister::kNumRegisters)); 369 __ add(esp, Immediate(kDoubleSize * XMMRegister::kNumRegisters));
370 } 370 }
371 __ popad(); 371 __ popad();
372 __ ret(0); 372 __ ret(0);
373 } 373 }
374 374
375 375
376 void ToBooleanStub::CheckOddball(MacroAssembler* masm, 376 void ToBooleanStub::CheckOddball(MacroAssembler* masm,
377 Type type, 377 Type type,
378 Heap::RootListIndex value, 378 Heap::RootListIndex value,
379 bool result) { 379 bool result) {
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after
500 // Get exponent word. 500 // Get exponent word.
501 __ mov(scratch, FieldOperand(source, HeapNumber::kExponentOffset)); 501 __ mov(scratch, FieldOperand(source, HeapNumber::kExponentOffset));
502 // Get exponent alone in scratch2. 502 // Get exponent alone in scratch2.
503 __ mov(scratch2, scratch); 503 __ mov(scratch2, scratch);
504 __ and_(scratch2, HeapNumber::kExponentMask); 504 __ and_(scratch2, HeapNumber::kExponentMask);
505 if (use_sse3) { 505 if (use_sse3) {
506 CpuFeatures::Scope scope(SSE3); 506 CpuFeatures::Scope scope(SSE3);
507 // Check whether the exponent is too big for a 64 bit signed integer. 507 // Check whether the exponent is too big for a 64 bit signed integer.
508 static const uint32_t kTooBigExponent = 508 static const uint32_t kTooBigExponent =
509 (HeapNumber::kExponentBias + 63) << HeapNumber::kExponentShift; 509 (HeapNumber::kExponentBias + 63) << HeapNumber::kExponentShift;
510 __ cmp(Operand(scratch2), Immediate(kTooBigExponent)); 510 __ cmp(scratch2, Immediate(kTooBigExponent));
511 __ j(greater_equal, conversion_failure); 511 __ j(greater_equal, conversion_failure);
512 // Load x87 register with heap number. 512 // Load x87 register with heap number.
513 __ fld_d(FieldOperand(source, HeapNumber::kValueOffset)); 513 __ fld_d(FieldOperand(source, HeapNumber::kValueOffset));
514 // Reserve space for 64 bit answer. 514 // Reserve space for 64 bit answer.
515 __ sub(Operand(esp), Immediate(sizeof(uint64_t))); // Nolint. 515 __ sub(esp, Immediate(sizeof(uint64_t))); // Nolint.
516 // Do conversion, which cannot fail because we checked the exponent. 516 // Do conversion, which cannot fail because we checked the exponent.
517 __ fisttp_d(Operand(esp, 0)); 517 __ fisttp_d(Operand(esp, 0));
518 __ mov(ecx, Operand(esp, 0)); // Load low word of answer into ecx. 518 __ mov(ecx, Operand(esp, 0)); // Load low word of answer into ecx.
519 __ add(Operand(esp), Immediate(sizeof(uint64_t))); // Nolint. 519 __ add(esp, Immediate(sizeof(uint64_t))); // Nolint.
520 } else { 520 } else {
521 // Load ecx with zero. We use this either for the final shift or 521 // Load ecx with zero. We use this either for the final shift or
522 // for the answer. 522 // for the answer.
523 __ xor_(ecx, Operand(ecx)); 523 __ xor_(ecx, ecx);
524 // Check whether the exponent matches a 32 bit signed int that cannot be 524 // Check whether the exponent matches a 32 bit signed int that cannot be
525 // represented by a Smi. A non-smi 32 bit integer is 1.xxx * 2^30 so the 525 // represented by a Smi. A non-smi 32 bit integer is 1.xxx * 2^30 so the
526 // exponent is 30 (biased). This is the exponent that we are fastest at and 526 // exponent is 30 (biased). This is the exponent that we are fastest at and
527 // also the highest exponent we can handle here. 527 // also the highest exponent we can handle here.
528 const uint32_t non_smi_exponent = 528 const uint32_t non_smi_exponent =
529 (HeapNumber::kExponentBias + 30) << HeapNumber::kExponentShift; 529 (HeapNumber::kExponentBias + 30) << HeapNumber::kExponentShift;
530 __ cmp(Operand(scratch2), Immediate(non_smi_exponent)); 530 __ cmp(scratch2, Immediate(non_smi_exponent));
531 // If we have a match of the int32-but-not-Smi exponent then skip some 531 // If we have a match of the int32-but-not-Smi exponent then skip some
532 // logic. 532 // logic.
533 __ j(equal, &right_exponent, Label::kNear); 533 __ j(equal, &right_exponent, Label::kNear);
534 // If the exponent is higher than that then go to slow case. This catches 534 // If the exponent is higher than that then go to slow case. This catches
535 // numbers that don't fit in a signed int32, infinities and NaNs. 535 // numbers that don't fit in a signed int32, infinities and NaNs.
536 __ j(less, &normal_exponent, Label::kNear); 536 __ j(less, &normal_exponent, Label::kNear);
537 537
538 { 538 {
539 // Handle a big exponent. The only reason we have this code is that the 539 // Handle a big exponent. The only reason we have this code is that the
540 // >>> operator has a tendency to generate numbers with an exponent of 31. 540 // >>> operator has a tendency to generate numbers with an exponent of 31.
541 const uint32_t big_non_smi_exponent = 541 const uint32_t big_non_smi_exponent =
542 (HeapNumber::kExponentBias + 31) << HeapNumber::kExponentShift; 542 (HeapNumber::kExponentBias + 31) << HeapNumber::kExponentShift;
543 __ cmp(Operand(scratch2), Immediate(big_non_smi_exponent)); 543 __ cmp(scratch2, Immediate(big_non_smi_exponent));
544 __ j(not_equal, conversion_failure); 544 __ j(not_equal, conversion_failure);
545 // We have the big exponent, typically from >>>. This means the number is 545 // We have the big exponent, typically from >>>. This means the number is
546 // in the range 2^31 to 2^32 - 1. Get the top bits of the mantissa. 546 // in the range 2^31 to 2^32 - 1. Get the top bits of the mantissa.
547 __ mov(scratch2, scratch); 547 __ mov(scratch2, scratch);
548 __ and_(scratch2, HeapNumber::kMantissaMask); 548 __ and_(scratch2, HeapNumber::kMantissaMask);
549 // Put back the implicit 1. 549 // Put back the implicit 1.
550 __ or_(scratch2, 1 << HeapNumber::kExponentShift); 550 __ or_(scratch2, 1 << HeapNumber::kExponentShift);
551 // Shift up the mantissa bits to take up the space the exponent used to 551 // Shift up the mantissa bits to take up the space the exponent used to
552 // take. We just orred in the implicit bit so that took care of one and 552 // take. We just orred in the implicit bit so that took care of one and
553 // we want to use the full unsigned range so we subtract 1 bit from the 553 // we want to use the full unsigned range so we subtract 1 bit from the
554 // shift distance. 554 // shift distance.
555 const int big_shift_distance = HeapNumber::kNonMantissaBitsInTopWord - 1; 555 const int big_shift_distance = HeapNumber::kNonMantissaBitsInTopWord - 1;
556 __ shl(scratch2, big_shift_distance); 556 __ shl(scratch2, big_shift_distance);
557 // Get the second half of the double. 557 // Get the second half of the double.
558 __ mov(ecx, FieldOperand(source, HeapNumber::kMantissaOffset)); 558 __ mov(ecx, FieldOperand(source, HeapNumber::kMantissaOffset));
559 // Shift down 21 bits to get the most significant 11 bits or the low 559 // Shift down 21 bits to get the most significant 11 bits or the low
560 // mantissa word. 560 // mantissa word.
561 __ shr(ecx, 32 - big_shift_distance); 561 __ shr(ecx, 32 - big_shift_distance);
562 __ or_(ecx, Operand(scratch2)); 562 __ or_(ecx, scratch2);
563 // We have the answer in ecx, but we may need to negate it. 563 // We have the answer in ecx, but we may need to negate it.
564 __ test(scratch, Operand(scratch)); 564 __ test(scratch, scratch);
565 __ j(positive, &done, Label::kNear); 565 __ j(positive, &done, Label::kNear);
566 __ neg(ecx); 566 __ neg(ecx);
567 __ jmp(&done, Label::kNear); 567 __ jmp(&done, Label::kNear);
568 } 568 }
569 569
570 __ bind(&normal_exponent); 570 __ bind(&normal_exponent);
571 // Exponent word in scratch, exponent part of exponent word in scratch2. 571 // Exponent word in scratch, exponent part of exponent word in scratch2.
572 // Zero in ecx. 572 // Zero in ecx.
573 // We know the exponent is smaller than 30 (biased). If it is less than 573 // We know the exponent is smaller than 30 (biased). If it is less than
574 // 0 (biased) then the number is smaller in magnitude than 1.0 * 2^0, ie 574 // 0 (biased) then the number is smaller in magnitude than 1.0 * 2^0, ie
575 // it rounds to zero. 575 // it rounds to zero.
576 const uint32_t zero_exponent = 576 const uint32_t zero_exponent =
577 (HeapNumber::kExponentBias + 0) << HeapNumber::kExponentShift; 577 (HeapNumber::kExponentBias + 0) << HeapNumber::kExponentShift;
578 __ sub(Operand(scratch2), Immediate(zero_exponent)); 578 __ sub(scratch2, Immediate(zero_exponent));
579 // ecx already has a Smi zero. 579 // ecx already has a Smi zero.
580 __ j(less, &done, Label::kNear); 580 __ j(less, &done, Label::kNear);
581 581
582 // We have a shifted exponent between 0 and 30 in scratch2. 582 // We have a shifted exponent between 0 and 30 in scratch2.
583 __ shr(scratch2, HeapNumber::kExponentShift); 583 __ shr(scratch2, HeapNumber::kExponentShift);
584 __ mov(ecx, Immediate(30)); 584 __ mov(ecx, Immediate(30));
585 __ sub(ecx, Operand(scratch2)); 585 __ sub(ecx, scratch2);
586 586
587 __ bind(&right_exponent); 587 __ bind(&right_exponent);
588 // Here ecx is the shift, scratch is the exponent word. 588 // Here ecx is the shift, scratch is the exponent word.
589 // Get the top bits of the mantissa. 589 // Get the top bits of the mantissa.
590 __ and_(scratch, HeapNumber::kMantissaMask); 590 __ and_(scratch, HeapNumber::kMantissaMask);
591 // Put back the implicit 1. 591 // Put back the implicit 1.
592 __ or_(scratch, 1 << HeapNumber::kExponentShift); 592 __ or_(scratch, 1 << HeapNumber::kExponentShift);
593 // Shift up the mantissa bits to take up the space the exponent used to 593 // Shift up the mantissa bits to take up the space the exponent used to
594 // take. We have kExponentShift + 1 significant bits int he low end of the 594 // take. We have kExponentShift + 1 significant bits int he low end of the
595 // word. Shift them to the top bits. 595 // word. Shift them to the top bits.
596 const int shift_distance = HeapNumber::kNonMantissaBitsInTopWord - 2; 596 const int shift_distance = HeapNumber::kNonMantissaBitsInTopWord - 2;
597 __ shl(scratch, shift_distance); 597 __ shl(scratch, shift_distance);
598 // Get the second half of the double. For some exponents we don't 598 // Get the second half of the double. For some exponents we don't
599 // actually need this because the bits get shifted out again, but 599 // actually need this because the bits get shifted out again, but
600 // it's probably slower to test than just to do it. 600 // it's probably slower to test than just to do it.
601 __ mov(scratch2, FieldOperand(source, HeapNumber::kMantissaOffset)); 601 __ mov(scratch2, FieldOperand(source, HeapNumber::kMantissaOffset));
602 // Shift down 22 bits to get the most significant 10 bits or the low 602 // Shift down 22 bits to get the most significant 10 bits or the low
603 // mantissa word. 603 // mantissa word.
604 __ shr(scratch2, 32 - shift_distance); 604 __ shr(scratch2, 32 - shift_distance);
605 __ or_(scratch2, Operand(scratch)); 605 __ or_(scratch2, scratch);
606 // Move down according to the exponent. 606 // Move down according to the exponent.
607 __ shr_cl(scratch2); 607 __ shr_cl(scratch2);
608 // Now the unsigned answer is in scratch2. We need to move it to ecx and 608 // Now the unsigned answer is in scratch2. We need to move it to ecx and
609 // we may need to fix the sign. 609 // we may need to fix the sign.
610 Label negative; 610 Label negative;
611 __ xor_(ecx, Operand(ecx)); 611 __ xor_(ecx, ecx);
612 __ cmp(ecx, FieldOperand(source, HeapNumber::kExponentOffset)); 612 __ cmp(ecx, FieldOperand(source, HeapNumber::kExponentOffset));
613 __ j(greater, &negative, Label::kNear); 613 __ j(greater, &negative, Label::kNear);
614 __ mov(ecx, scratch2); 614 __ mov(ecx, scratch2);
615 __ jmp(&done, Label::kNear); 615 __ jmp(&done, Label::kNear);
616 __ bind(&negative); 616 __ bind(&negative);
617 __ sub(ecx, Operand(scratch2)); 617 __ sub(ecx, scratch2);
618 __ bind(&done); 618 __ bind(&done);
619 } 619 }
620 } 620 }
621 621
622 622
623 void UnaryOpStub::PrintName(StringStream* stream) { 623 void UnaryOpStub::PrintName(StringStream* stream) {
624 const char* op_name = Token::Name(op_); 624 const char* op_name = Token::Name(op_);
625 const char* overwrite_name = NULL; // Make g++ happy. 625 const char* overwrite_name = NULL; // Make g++ happy.
626 switch (mode_) { 626 switch (mode_) {
627 case UNARY_NO_OVERWRITE: overwrite_name = "Alloc"; break; 627 case UNARY_NO_OVERWRITE: overwrite_name = "Alloc"; break;
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
709 Label* non_smi, 709 Label* non_smi,
710 Label* undo, 710 Label* undo,
711 Label* slow, 711 Label* slow,
712 Label::Distance non_smi_near, 712 Label::Distance non_smi_near,
713 Label::Distance undo_near, 713 Label::Distance undo_near,
714 Label::Distance slow_near) { 714 Label::Distance slow_near) {
715 // Check whether the value is a smi. 715 // Check whether the value is a smi.
716 __ JumpIfNotSmi(eax, non_smi, non_smi_near); 716 __ JumpIfNotSmi(eax, non_smi, non_smi_near);
717 717
718 // We can't handle -0 with smis, so use a type transition for that case. 718 // We can't handle -0 with smis, so use a type transition for that case.
719 __ test(eax, Operand(eax)); 719 __ test(eax, eax);
720 __ j(zero, slow, slow_near); 720 __ j(zero, slow, slow_near);
721 721
722 // Try optimistic subtraction '0 - value', saving operand in eax for undo. 722 // Try optimistic subtraction '0 - value', saving operand in eax for undo.
723 __ mov(edx, Operand(eax)); 723 __ mov(edx, eax);
724 __ Set(eax, Immediate(0)); 724 __ Set(eax, Immediate(0));
725 __ sub(eax, Operand(edx)); 725 __ sub(eax, edx);
726 __ j(overflow, undo, undo_near); 726 __ j(overflow, undo, undo_near);
727 __ ret(0); 727 __ ret(0);
728 } 728 }
729 729
730 730
731 void UnaryOpStub::GenerateSmiCodeBitNot( 731 void UnaryOpStub::GenerateSmiCodeBitNot(
732 MacroAssembler* masm, 732 MacroAssembler* masm,
733 Label* non_smi, 733 Label* non_smi,
734 Label::Distance non_smi_near) { 734 Label::Distance non_smi_near) {
735 // Check whether the value is a smi. 735 // Check whether the value is a smi.
736 __ JumpIfNotSmi(eax, non_smi, non_smi_near); 736 __ JumpIfNotSmi(eax, non_smi, non_smi_near);
737 737
738 // Flip bits and revert inverted smi-tag. 738 // Flip bits and revert inverted smi-tag.
739 __ not_(eax); 739 __ not_(eax);
740 __ and_(eax, ~kSmiTagMask); 740 __ and_(eax, ~kSmiTagMask);
741 __ ret(0); 741 __ ret(0);
742 } 742 }
743 743
744 744
745 void UnaryOpStub::GenerateSmiCodeUndo(MacroAssembler* masm) { 745 void UnaryOpStub::GenerateSmiCodeUndo(MacroAssembler* masm) {
746 __ mov(eax, Operand(edx)); 746 __ mov(eax, edx);
747 } 747 }
748 748
749 749
750 // TODO(svenpanne): Use virtual functions instead of switch. 750 // TODO(svenpanne): Use virtual functions instead of switch.
751 void UnaryOpStub::GenerateHeapNumberStub(MacroAssembler* masm) { 751 void UnaryOpStub::GenerateHeapNumberStub(MacroAssembler* masm) {
752 switch (op_) { 752 switch (op_) {
753 case Token::SUB: 753 case Token::SUB:
754 GenerateHeapNumberStubSub(masm); 754 GenerateHeapNumberStubSub(masm);
755 break; 755 break;
756 case Token::BIT_NOT: 756 case Token::BIT_NOT:
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
790 void UnaryOpStub::GenerateHeapNumberCodeSub(MacroAssembler* masm, 790 void UnaryOpStub::GenerateHeapNumberCodeSub(MacroAssembler* masm,
791 Label* slow) { 791 Label* slow) {
792 __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset)); 792 __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset));
793 __ cmp(edx, masm->isolate()->factory()->heap_number_map()); 793 __ cmp(edx, masm->isolate()->factory()->heap_number_map());
794 __ j(not_equal, slow); 794 __ j(not_equal, slow);
795 795
796 if (mode_ == UNARY_OVERWRITE) { 796 if (mode_ == UNARY_OVERWRITE) {
797 __ xor_(FieldOperand(eax, HeapNumber::kExponentOffset), 797 __ xor_(FieldOperand(eax, HeapNumber::kExponentOffset),
798 Immediate(HeapNumber::kSignMask)); // Flip sign. 798 Immediate(HeapNumber::kSignMask)); // Flip sign.
799 } else { 799 } else {
800 __ mov(edx, Operand(eax)); 800 __ mov(edx, eax);
801 // edx: operand 801 // edx: operand
802 802
803 Label slow_allocate_heapnumber, heapnumber_allocated; 803 Label slow_allocate_heapnumber, heapnumber_allocated;
804 __ AllocateHeapNumber(eax, ebx, ecx, &slow_allocate_heapnumber); 804 __ AllocateHeapNumber(eax, ebx, ecx, &slow_allocate_heapnumber);
805 __ jmp(&heapnumber_allocated, Label::kNear); 805 __ jmp(&heapnumber_allocated, Label::kNear);
806 806
807 __ bind(&slow_allocate_heapnumber); 807 __ bind(&slow_allocate_heapnumber);
808 { 808 {
809 FrameScope scope(masm, StackFrame::INTERNAL); 809 FrameScope scope(masm, StackFrame::INTERNAL);
810 __ push(edx); 810 __ push(edx);
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
865 } 865 }
866 // IntegerConvert uses ebx and edi as scratch registers. 866 // IntegerConvert uses ebx and edi as scratch registers.
867 // This conversion won't go slow-case. 867 // This conversion won't go slow-case.
868 IntegerConvert(masm, edx, CpuFeatures::IsSupported(SSE3), slow); 868 IntegerConvert(masm, edx, CpuFeatures::IsSupported(SSE3), slow);
869 __ not_(ecx); 869 __ not_(ecx);
870 870
871 __ bind(&heapnumber_allocated); 871 __ bind(&heapnumber_allocated);
872 } 872 }
873 if (CpuFeatures::IsSupported(SSE2)) { 873 if (CpuFeatures::IsSupported(SSE2)) {
874 CpuFeatures::Scope use_sse2(SSE2); 874 CpuFeatures::Scope use_sse2(SSE2);
875 __ cvtsi2sd(xmm0, Operand(ecx)); 875 __ cvtsi2sd(xmm0, ecx);
876 __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); 876 __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0);
877 } else { 877 } else {
878 __ push(ecx); 878 __ push(ecx);
879 __ fild_s(Operand(esp, 0)); 879 __ fild_s(Operand(esp, 0));
880 __ pop(ecx); 880 __ pop(ecx);
881 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); 881 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
882 } 882 }
883 __ ret(0); 883 __ ret(0);
884 } 884 }
885 885
(...skipping 172 matching lines...) Expand 10 before | Expand all | Expand 10 after
1058 Comment smi_check_comment(masm, "-- Smi check arguments"); 1058 Comment smi_check_comment(masm, "-- Smi check arguments");
1059 Label not_smis; 1059 Label not_smis;
1060 Register combined = ecx; 1060 Register combined = ecx;
1061 ASSERT(!left.is(combined) && !right.is(combined)); 1061 ASSERT(!left.is(combined) && !right.is(combined));
1062 switch (op_) { 1062 switch (op_) {
1063 case Token::BIT_OR: 1063 case Token::BIT_OR:
1064 // Perform the operation into eax and smi check the result. Preserve 1064 // Perform the operation into eax and smi check the result. Preserve
1065 // eax in case the result is not a smi. 1065 // eax in case the result is not a smi.
1066 ASSERT(!left.is(ecx) && !right.is(ecx)); 1066 ASSERT(!left.is(ecx) && !right.is(ecx));
1067 __ mov(ecx, right); 1067 __ mov(ecx, right);
1068 __ or_(right, Operand(left)); // Bitwise or is commutative. 1068 __ or_(right, left); // Bitwise or is commutative.
1069 combined = right; 1069 combined = right;
1070 break; 1070 break;
1071 1071
1072 case Token::BIT_XOR: 1072 case Token::BIT_XOR:
1073 case Token::BIT_AND: 1073 case Token::BIT_AND:
1074 case Token::ADD: 1074 case Token::ADD:
1075 case Token::SUB: 1075 case Token::SUB:
1076 case Token::MUL: 1076 case Token::MUL:
1077 case Token::DIV: 1077 case Token::DIV:
1078 case Token::MOD: 1078 case Token::MOD:
1079 __ mov(combined, right); 1079 __ mov(combined, right);
1080 __ or_(combined, Operand(left)); 1080 __ or_(combined, left);
1081 break; 1081 break;
1082 1082
1083 case Token::SHL: 1083 case Token::SHL:
1084 case Token::SAR: 1084 case Token::SAR:
1085 case Token::SHR: 1085 case Token::SHR:
1086 // Move the right operand into ecx for the shift operation, use eax 1086 // Move the right operand into ecx for the shift operation, use eax
1087 // for the smi check register. 1087 // for the smi check register.
1088 ASSERT(!left.is(ecx) && !right.is(ecx)); 1088 ASSERT(!left.is(ecx) && !right.is(ecx));
1089 __ mov(ecx, right); 1089 __ mov(ecx, right);
1090 __ or_(right, Operand(left)); 1090 __ or_(right, left);
1091 combined = right; 1091 combined = right;
1092 break; 1092 break;
1093 1093
1094 default: 1094 default:
1095 break; 1095 break;
1096 } 1096 }
1097 1097
1098 // 3. Perform the smi check of the operands. 1098 // 3. Perform the smi check of the operands.
1099 STATIC_ASSERT(kSmiTag == 0); // Adjust zero check if not the case. 1099 STATIC_ASSERT(kSmiTag == 0); // Adjust zero check if not the case.
1100 __ JumpIfNotSmi(combined, &not_smis); 1100 __ JumpIfNotSmi(combined, &not_smis);
1101 1101
1102 // 4. Operands are both smis, perform the operation leaving the result in 1102 // 4. Operands are both smis, perform the operation leaving the result in
1103 // eax and check the result if necessary. 1103 // eax and check the result if necessary.
1104 Comment perform_smi(masm, "-- Perform smi operation"); 1104 Comment perform_smi(masm, "-- Perform smi operation");
1105 Label use_fp_on_smis; 1105 Label use_fp_on_smis;
1106 switch (op_) { 1106 switch (op_) {
1107 case Token::BIT_OR: 1107 case Token::BIT_OR:
1108 // Nothing to do. 1108 // Nothing to do.
1109 break; 1109 break;
1110 1110
1111 case Token::BIT_XOR: 1111 case Token::BIT_XOR:
1112 ASSERT(right.is(eax)); 1112 ASSERT(right.is(eax));
1113 __ xor_(right, Operand(left)); // Bitwise xor is commutative. 1113 __ xor_(right, left); // Bitwise xor is commutative.
1114 break; 1114 break;
1115 1115
1116 case Token::BIT_AND: 1116 case Token::BIT_AND:
1117 ASSERT(right.is(eax)); 1117 ASSERT(right.is(eax));
1118 __ and_(right, Operand(left)); // Bitwise and is commutative. 1118 __ and_(right, left); // Bitwise and is commutative.
1119 break; 1119 break;
1120 1120
1121 case Token::SHL: 1121 case Token::SHL:
1122 // Remove tags from operands (but keep sign). 1122 // Remove tags from operands (but keep sign).
1123 __ SmiUntag(left); 1123 __ SmiUntag(left);
1124 __ SmiUntag(ecx); 1124 __ SmiUntag(ecx);
1125 // Perform the operation. 1125 // Perform the operation.
1126 __ shl_cl(left); 1126 __ shl_cl(left);
1127 // Check that the *signed* result fits in a smi. 1127 // Check that the *signed* result fits in a smi.
1128 __ cmp(left, 0xc0000000); 1128 __ cmp(left, 0xc0000000);
(...skipping 28 matching lines...) Expand all
1157 // by 0 or 1 when handed a valid smi. 1157 // by 0 or 1 when handed a valid smi.
1158 __ test(left, Immediate(0xc0000000)); 1158 __ test(left, Immediate(0xc0000000));
1159 __ j(not_zero, &use_fp_on_smis); 1159 __ j(not_zero, &use_fp_on_smis);
1160 // Tag the result and store it in register eax. 1160 // Tag the result and store it in register eax.
1161 __ SmiTag(left); 1161 __ SmiTag(left);
1162 __ mov(eax, left); 1162 __ mov(eax, left);
1163 break; 1163 break;
1164 1164
1165 case Token::ADD: 1165 case Token::ADD:
1166 ASSERT(right.is(eax)); 1166 ASSERT(right.is(eax));
1167 __ add(right, Operand(left)); // Addition is commutative. 1167 __ add(right, left); // Addition is commutative.
1168 __ j(overflow, &use_fp_on_smis); 1168 __ j(overflow, &use_fp_on_smis);
1169 break; 1169 break;
1170 1170
1171 case Token::SUB: 1171 case Token::SUB:
1172 __ sub(left, Operand(right)); 1172 __ sub(left, right);
1173 __ j(overflow, &use_fp_on_smis); 1173 __ j(overflow, &use_fp_on_smis);
1174 __ mov(eax, left); 1174 __ mov(eax, left);
1175 break; 1175 break;
1176 1176
1177 case Token::MUL: 1177 case Token::MUL:
1178 // If the smi tag is 0 we can just leave the tag on one operand. 1178 // If the smi tag is 0 we can just leave the tag on one operand.
1179 STATIC_ASSERT(kSmiTag == 0); // Adjust code below if not the case. 1179 STATIC_ASSERT(kSmiTag == 0); // Adjust code below if not the case.
1180 // We can't revert the multiplication if the result is not a smi 1180 // We can't revert the multiplication if the result is not a smi
1181 // so save the right operand. 1181 // so save the right operand.
1182 __ mov(ebx, right); 1182 __ mov(ebx, right);
1183 // Remove tag from one of the operands (but keep sign). 1183 // Remove tag from one of the operands (but keep sign).
1184 __ SmiUntag(right); 1184 __ SmiUntag(right);
1185 // Do multiplication. 1185 // Do multiplication.
1186 __ imul(right, Operand(left)); // Multiplication is commutative. 1186 __ imul(right, left); // Multiplication is commutative.
1187 __ j(overflow, &use_fp_on_smis); 1187 __ j(overflow, &use_fp_on_smis);
1188 // Check for negative zero result. Use combined = left | right. 1188 // Check for negative zero result. Use combined = left | right.
1189 __ NegativeZeroTest(right, combined, &use_fp_on_smis); 1189 __ NegativeZeroTest(right, combined, &use_fp_on_smis);
1190 break; 1190 break;
1191 1191
1192 case Token::DIV: 1192 case Token::DIV:
1193 // We can't revert the division if the result is not a smi so 1193 // We can't revert the division if the result is not a smi so
1194 // save the left operand. 1194 // save the left operand.
1195 __ mov(edi, left); 1195 __ mov(edi, left);
1196 // Check for 0 divisor. 1196 // Check for 0 divisor.
1197 __ test(right, Operand(right)); 1197 __ test(right, right);
1198 __ j(zero, &use_fp_on_smis); 1198 __ j(zero, &use_fp_on_smis);
1199 // Sign extend left into edx:eax. 1199 // Sign extend left into edx:eax.
1200 ASSERT(left.is(eax)); 1200 ASSERT(left.is(eax));
1201 __ cdq(); 1201 __ cdq();
1202 // Divide edx:eax by right. 1202 // Divide edx:eax by right.
1203 __ idiv(right); 1203 __ idiv(right);
1204 // Check for the corner case of dividing the most negative smi by 1204 // Check for the corner case of dividing the most negative smi by
1205 // -1. We cannot use the overflow flag, since it is not set by idiv 1205 // -1. We cannot use the overflow flag, since it is not set by idiv
1206 // instruction. 1206 // instruction.
1207 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize == 1); 1207 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize == 1);
1208 __ cmp(eax, 0x40000000); 1208 __ cmp(eax, 0x40000000);
1209 __ j(equal, &use_fp_on_smis); 1209 __ j(equal, &use_fp_on_smis);
1210 // Check for negative zero result. Use combined = left | right. 1210 // Check for negative zero result. Use combined = left | right.
1211 __ NegativeZeroTest(eax, combined, &use_fp_on_smis); 1211 __ NegativeZeroTest(eax, combined, &use_fp_on_smis);
1212 // Check that the remainder is zero. 1212 // Check that the remainder is zero.
1213 __ test(edx, Operand(edx)); 1213 __ test(edx, edx);
1214 __ j(not_zero, &use_fp_on_smis); 1214 __ j(not_zero, &use_fp_on_smis);
1215 // Tag the result and store it in register eax. 1215 // Tag the result and store it in register eax.
1216 __ SmiTag(eax); 1216 __ SmiTag(eax);
1217 break; 1217 break;
1218 1218
1219 case Token::MOD: 1219 case Token::MOD:
1220 // Check for 0 divisor. 1220 // Check for 0 divisor.
1221 __ test(right, Operand(right)); 1221 __ test(right, right);
1222 __ j(zero, &not_smis); 1222 __ j(zero, &not_smis);
1223 1223
1224 // Sign extend left into edx:eax. 1224 // Sign extend left into edx:eax.
1225 ASSERT(left.is(eax)); 1225 ASSERT(left.is(eax));
1226 __ cdq(); 1226 __ cdq();
1227 // Divide edx:eax by right. 1227 // Divide edx:eax by right.
1228 __ idiv(right); 1228 __ idiv(right);
1229 // Check for negative zero result. Use combined = left | right. 1229 // Check for negative zero result. Use combined = left | right.
1230 __ NegativeZeroTest(edx, combined, slow); 1230 __ NegativeZeroTest(edx, combined, slow);
1231 // Move remainder to register eax. 1231 // Move remainder to register eax.
(...skipping 30 matching lines...) Expand all
1262 // overflowed the smi range). 1262 // overflowed the smi range).
1263 if (allow_heapnumber_results == NO_HEAPNUMBER_RESULTS) { 1263 if (allow_heapnumber_results == NO_HEAPNUMBER_RESULTS) {
1264 __ bind(&use_fp_on_smis); 1264 __ bind(&use_fp_on_smis);
1265 switch (op_) { 1265 switch (op_) {
1266 // Undo the effects of some operations, and some register moves. 1266 // Undo the effects of some operations, and some register moves.
1267 case Token::SHL: 1267 case Token::SHL:
1268 // The arguments are saved on the stack, and only used from there. 1268 // The arguments are saved on the stack, and only used from there.
1269 break; 1269 break;
1270 case Token::ADD: 1270 case Token::ADD:
1271 // Revert right = right + left. 1271 // Revert right = right + left.
1272 __ sub(right, Operand(left)); 1272 __ sub(right, left);
1273 break; 1273 break;
1274 case Token::SUB: 1274 case Token::SUB:
1275 // Revert left = left - right. 1275 // Revert left = left - right.
1276 __ add(left, Operand(right)); 1276 __ add(left, right);
1277 break; 1277 break;
1278 case Token::MUL: 1278 case Token::MUL:
1279 // Right was clobbered but a copy is in ebx. 1279 // Right was clobbered but a copy is in ebx.
1280 __ mov(right, ebx); 1280 __ mov(right, ebx);
1281 break; 1281 break;
1282 case Token::DIV: 1282 case Token::DIV:
1283 // Left was clobbered but a copy is in edi. Right is in ebx for 1283 // Left was clobbered but a copy is in edi. Right is in ebx for
1284 // division. They should be in eax, ebx for jump to not_smi. 1284 // division. They should be in eax, ebx for jump to not_smi.
1285 __ mov(eax, edi); 1285 __ mov(eax, edi);
1286 break; 1286 break;
(...skipping 17 matching lines...) Expand all
1304 // are about to return. 1304 // are about to return.
1305 if (op_ == Token::SHR) { 1305 if (op_ == Token::SHR) {
1306 __ mov(Operand(esp, 1 * kPointerSize), left); 1306 __ mov(Operand(esp, 1 * kPointerSize), left);
1307 __ mov(Operand(esp, 2 * kPointerSize), Immediate(0)); 1307 __ mov(Operand(esp, 2 * kPointerSize), Immediate(0));
1308 __ fild_d(Operand(esp, 1 * kPointerSize)); 1308 __ fild_d(Operand(esp, 1 * kPointerSize));
1309 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); 1309 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
1310 } else { 1310 } else {
1311 ASSERT_EQ(Token::SHL, op_); 1311 ASSERT_EQ(Token::SHL, op_);
1312 if (CpuFeatures::IsSupported(SSE2)) { 1312 if (CpuFeatures::IsSupported(SSE2)) {
1313 CpuFeatures::Scope use_sse2(SSE2); 1313 CpuFeatures::Scope use_sse2(SSE2);
1314 __ cvtsi2sd(xmm0, Operand(left)); 1314 __ cvtsi2sd(xmm0, left);
1315 __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); 1315 __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0);
1316 } else { 1316 } else {
1317 __ mov(Operand(esp, 1 * kPointerSize), left); 1317 __ mov(Operand(esp, 1 * kPointerSize), left);
1318 __ fild_s(Operand(esp, 1 * kPointerSize)); 1318 __ fild_s(Operand(esp, 1 * kPointerSize));
1319 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); 1319 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
1320 } 1320 }
1321 } 1321 }
1322 __ ret(2 * kPointerSize); 1322 __ ret(2 * kPointerSize);
1323 break; 1323 break;
1324 } 1324 }
1325 1325
1326 case Token::ADD: 1326 case Token::ADD:
1327 case Token::SUB: 1327 case Token::SUB:
1328 case Token::MUL: 1328 case Token::MUL:
1329 case Token::DIV: { 1329 case Token::DIV: {
1330 Comment perform_float(masm, "-- Perform float operation on smis"); 1330 Comment perform_float(masm, "-- Perform float operation on smis");
1331 __ bind(&use_fp_on_smis); 1331 __ bind(&use_fp_on_smis);
1332 // Restore arguments to edx, eax. 1332 // Restore arguments to edx, eax.
1333 switch (op_) { 1333 switch (op_) {
1334 case Token::ADD: 1334 case Token::ADD:
1335 // Revert right = right + left. 1335 // Revert right = right + left.
1336 __ sub(right, Operand(left)); 1336 __ sub(right, left);
1337 break; 1337 break;
1338 case Token::SUB: 1338 case Token::SUB:
1339 // Revert left = left - right. 1339 // Revert left = left - right.
1340 __ add(left, Operand(right)); 1340 __ add(left, right);
1341 break; 1341 break;
1342 case Token::MUL: 1342 case Token::MUL:
1343 // Right was clobbered but a copy is in ebx. 1343 // Right was clobbered but a copy is in ebx.
1344 __ mov(right, ebx); 1344 __ mov(right, ebx);
1345 break; 1345 break;
1346 case Token::DIV: 1346 case Token::DIV:
1347 // Left was clobbered but a copy is in edi. Right is in ebx for 1347 // Left was clobbered but a copy is in edi. Right is in ebx for
1348 // division. 1348 // division.
1349 __ mov(edx, edi); 1349 __ mov(edx, edi);
1350 __ mov(eax, right); 1350 __ mov(eax, right);
(...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after
1522 switch (op_) { 1522 switch (op_) {
1523 case Token::ADD: __ addsd(xmm0, xmm1); break; 1523 case Token::ADD: __ addsd(xmm0, xmm1); break;
1524 case Token::SUB: __ subsd(xmm0, xmm1); break; 1524 case Token::SUB: __ subsd(xmm0, xmm1); break;
1525 case Token::MUL: __ mulsd(xmm0, xmm1); break; 1525 case Token::MUL: __ mulsd(xmm0, xmm1); break;
1526 case Token::DIV: __ divsd(xmm0, xmm1); break; 1526 case Token::DIV: __ divsd(xmm0, xmm1); break;
1527 default: UNREACHABLE(); 1527 default: UNREACHABLE();
1528 } 1528 }
1529 // Check result type if it is currently Int32. 1529 // Check result type if it is currently Int32.
1530 if (result_type_ <= BinaryOpIC::INT32) { 1530 if (result_type_ <= BinaryOpIC::INT32) {
1531 __ cvttsd2si(ecx, Operand(xmm0)); 1531 __ cvttsd2si(ecx, Operand(xmm0));
1532 __ cvtsi2sd(xmm2, Operand(ecx)); 1532 __ cvtsi2sd(xmm2, ecx);
1533 __ ucomisd(xmm0, xmm2); 1533 __ ucomisd(xmm0, xmm2);
1534 __ j(not_zero, &not_int32); 1534 __ j(not_zero, &not_int32);
1535 __ j(carry, &not_int32); 1535 __ j(carry, &not_int32);
1536 } 1536 }
1537 GenerateHeapResultAllocation(masm, &call_runtime); 1537 GenerateHeapResultAllocation(masm, &call_runtime);
1538 __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); 1538 __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0);
1539 __ ret(0); 1539 __ ret(0);
1540 } else { // SSE2 not available, use FPU. 1540 } else { // SSE2 not available, use FPU.
1541 FloatingPointHelper::CheckFloatOperands(masm, &not_floats, ebx); 1541 FloatingPointHelper::CheckFloatOperands(masm, &not_floats, ebx);
1542 FloatingPointHelper::LoadFloatOperands( 1542 FloatingPointHelper::LoadFloatOperands(
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
1584 CpuFeatures::Scope use_sse2(SSE2); 1584 CpuFeatures::Scope use_sse2(SSE2);
1585 FloatingPointHelper::LoadSSE2Operands(masm, &not_floats); 1585 FloatingPointHelper::LoadSSE2Operands(masm, &not_floats);
1586 FloatingPointHelper::CheckSSE2OperandsAreInt32(masm, &not_int32, ecx); 1586 FloatingPointHelper::CheckSSE2OperandsAreInt32(masm, &not_int32, ecx);
1587 }*/ 1587 }*/
1588 FloatingPointHelper::LoadUnknownsAsIntegers(masm, 1588 FloatingPointHelper::LoadUnknownsAsIntegers(masm,
1589 use_sse3_, 1589 use_sse3_,
1590 &not_floats); 1590 &not_floats);
1591 FloatingPointHelper::CheckLoadedIntegersWereInt32(masm, use_sse3_, 1591 FloatingPointHelper::CheckLoadedIntegersWereInt32(masm, use_sse3_,
1592 &not_int32); 1592 &not_int32);
1593 switch (op_) { 1593 switch (op_) {
1594 case Token::BIT_OR: __ or_(eax, Operand(ecx)); break; 1594 case Token::BIT_OR: __ or_(eax, ecx); break;
1595 case Token::BIT_AND: __ and_(eax, Operand(ecx)); break; 1595 case Token::BIT_AND: __ and_(eax, ecx); break;
1596 case Token::BIT_XOR: __ xor_(eax, Operand(ecx)); break; 1596 case Token::BIT_XOR: __ xor_(eax, ecx); break;
1597 case Token::SAR: __ sar_cl(eax); break; 1597 case Token::SAR: __ sar_cl(eax); break;
1598 case Token::SHL: __ shl_cl(eax); break; 1598 case Token::SHL: __ shl_cl(eax); break;
1599 case Token::SHR: __ shr_cl(eax); break; 1599 case Token::SHR: __ shr_cl(eax); break;
1600 default: UNREACHABLE(); 1600 default: UNREACHABLE();
1601 } 1601 }
1602 if (op_ == Token::SHR) { 1602 if (op_ == Token::SHR) {
1603 // Check if result is non-negative and fits in a smi. 1603 // Check if result is non-negative and fits in a smi.
1604 __ test(eax, Immediate(0xc0000000)); 1604 __ test(eax, Immediate(0xc0000000));
1605 __ j(not_zero, &call_runtime); 1605 __ j(not_zero, &call_runtime);
1606 } else { 1606 } else {
1607 // Check if result fits in a smi. 1607 // Check if result fits in a smi.
1608 __ cmp(eax, 0xc0000000); 1608 __ cmp(eax, 0xc0000000);
1609 __ j(negative, &non_smi_result, Label::kNear); 1609 __ j(negative, &non_smi_result, Label::kNear);
1610 } 1610 }
1611 // Tag smi result and return. 1611 // Tag smi result and return.
1612 __ SmiTag(eax); 1612 __ SmiTag(eax);
1613 __ ret(2 * kPointerSize); // Drop two pushed arguments from the stack. 1613 __ ret(2 * kPointerSize); // Drop two pushed arguments from the stack.
1614 1614
1615 // All ops except SHR return a signed int32 that we load in 1615 // All ops except SHR return a signed int32 that we load in
1616 // a HeapNumber. 1616 // a HeapNumber.
1617 if (op_ != Token::SHR) { 1617 if (op_ != Token::SHR) {
1618 __ bind(&non_smi_result); 1618 __ bind(&non_smi_result);
1619 // Allocate a heap number if needed. 1619 // Allocate a heap number if needed.
1620 __ mov(ebx, Operand(eax)); // ebx: result 1620 __ mov(ebx, eax); // ebx: result
1621 Label skip_allocation; 1621 Label skip_allocation;
1622 switch (mode_) { 1622 switch (mode_) {
1623 case OVERWRITE_LEFT: 1623 case OVERWRITE_LEFT:
1624 case OVERWRITE_RIGHT: 1624 case OVERWRITE_RIGHT:
1625 // If the operand was an object, we skip the 1625 // If the operand was an object, we skip the
1626 // allocation of a heap number. 1626 // allocation of a heap number.
1627 __ mov(eax, Operand(esp, mode_ == OVERWRITE_RIGHT ? 1627 __ mov(eax, Operand(esp, mode_ == OVERWRITE_RIGHT ?
1628 1 * kPointerSize : 2 * kPointerSize)); 1628 1 * kPointerSize : 2 * kPointerSize));
1629 __ JumpIfNotSmi(eax, &skip_allocation, Label::kNear); 1629 __ JumpIfNotSmi(eax, &skip_allocation, Label::kNear);
1630 // Fall through! 1630 // Fall through!
1631 case NO_OVERWRITE: 1631 case NO_OVERWRITE:
1632 __ AllocateHeapNumber(eax, ecx, edx, &call_runtime); 1632 __ AllocateHeapNumber(eax, ecx, edx, &call_runtime);
1633 __ bind(&skip_allocation); 1633 __ bind(&skip_allocation);
1634 break; 1634 break;
1635 default: UNREACHABLE(); 1635 default: UNREACHABLE();
1636 } 1636 }
1637 // Store the result in the HeapNumber and return. 1637 // Store the result in the HeapNumber and return.
1638 if (CpuFeatures::IsSupported(SSE2)) { 1638 if (CpuFeatures::IsSupported(SSE2)) {
1639 CpuFeatures::Scope use_sse2(SSE2); 1639 CpuFeatures::Scope use_sse2(SSE2);
1640 __ cvtsi2sd(xmm0, Operand(ebx)); 1640 __ cvtsi2sd(xmm0, ebx);
1641 __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); 1641 __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0);
1642 } else { 1642 } else {
1643 __ mov(Operand(esp, 1 * kPointerSize), ebx); 1643 __ mov(Operand(esp, 1 * kPointerSize), ebx);
1644 __ fild_s(Operand(esp, 1 * kPointerSize)); 1644 __ fild_s(Operand(esp, 1 * kPointerSize));
1645 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); 1645 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
1646 } 1646 }
1647 __ ret(2 * kPointerSize); // Drop two pushed arguments from the stack. 1647 __ ret(2 * kPointerSize); // Drop two pushed arguments from the stack.
1648 } 1648 }
1649 1649
1650 __ bind(&not_floats); 1650 __ bind(&not_floats);
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
1711 GenerateAddStrings(masm); 1711 GenerateAddStrings(masm);
1712 } 1712 }
1713 1713
1714 Factory* factory = masm->isolate()->factory(); 1714 Factory* factory = masm->isolate()->factory();
1715 1715
1716 // Convert odd ball arguments to numbers. 1716 // Convert odd ball arguments to numbers.
1717 Label check, done; 1717 Label check, done;
1718 __ cmp(edx, factory->undefined_value()); 1718 __ cmp(edx, factory->undefined_value());
1719 __ j(not_equal, &check, Label::kNear); 1719 __ j(not_equal, &check, Label::kNear);
1720 if (Token::IsBitOp(op_)) { 1720 if (Token::IsBitOp(op_)) {
1721 __ xor_(edx, Operand(edx)); 1721 __ xor_(edx, edx);
1722 } else { 1722 } else {
1723 __ mov(edx, Immediate(factory->nan_value())); 1723 __ mov(edx, Immediate(factory->nan_value()));
1724 } 1724 }
1725 __ jmp(&done, Label::kNear); 1725 __ jmp(&done, Label::kNear);
1726 __ bind(&check); 1726 __ bind(&check);
1727 __ cmp(eax, factory->undefined_value()); 1727 __ cmp(eax, factory->undefined_value());
1728 __ j(not_equal, &done, Label::kNear); 1728 __ j(not_equal, &done, Label::kNear);
1729 if (Token::IsBitOp(op_)) { 1729 if (Token::IsBitOp(op_)) {
1730 __ xor_(eax, Operand(eax)); 1730 __ xor_(eax, eax);
1731 } else { 1731 } else {
1732 __ mov(eax, Immediate(factory->nan_value())); 1732 __ mov(eax, Immediate(factory->nan_value()));
1733 } 1733 }
1734 __ bind(&done); 1734 __ bind(&done);
1735 1735
1736 GenerateHeapNumberStub(masm); 1736 GenerateHeapNumberStub(masm);
1737 } 1737 }
1738 1738
1739 1739
1740 void BinaryOpStub::GenerateHeapNumberStub(MacroAssembler* masm) { 1740 void BinaryOpStub::GenerateHeapNumberStub(MacroAssembler* masm) {
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
1798 case Token::SAR: 1798 case Token::SAR:
1799 case Token::SHL: 1799 case Token::SHL:
1800 case Token::SHR: { 1800 case Token::SHR: {
1801 GenerateRegisterArgsPush(masm); 1801 GenerateRegisterArgsPush(masm);
1802 Label not_floats; 1802 Label not_floats;
1803 Label non_smi_result; 1803 Label non_smi_result;
1804 FloatingPointHelper::LoadUnknownsAsIntegers(masm, 1804 FloatingPointHelper::LoadUnknownsAsIntegers(masm,
1805 use_sse3_, 1805 use_sse3_,
1806 &not_floats); 1806 &not_floats);
1807 switch (op_) { 1807 switch (op_) {
1808 case Token::BIT_OR: __ or_(eax, Operand(ecx)); break; 1808 case Token::BIT_OR: __ or_(eax, ecx); break;
1809 case Token::BIT_AND: __ and_(eax, Operand(ecx)); break; 1809 case Token::BIT_AND: __ and_(eax, ecx); break;
1810 case Token::BIT_XOR: __ xor_(eax, Operand(ecx)); break; 1810 case Token::BIT_XOR: __ xor_(eax, ecx); break;
1811 case Token::SAR: __ sar_cl(eax); break; 1811 case Token::SAR: __ sar_cl(eax); break;
1812 case Token::SHL: __ shl_cl(eax); break; 1812 case Token::SHL: __ shl_cl(eax); break;
1813 case Token::SHR: __ shr_cl(eax); break; 1813 case Token::SHR: __ shr_cl(eax); break;
1814 default: UNREACHABLE(); 1814 default: UNREACHABLE();
1815 } 1815 }
1816 if (op_ == Token::SHR) { 1816 if (op_ == Token::SHR) {
1817 // Check if result is non-negative and fits in a smi. 1817 // Check if result is non-negative and fits in a smi.
1818 __ test(eax, Immediate(0xc0000000)); 1818 __ test(eax, Immediate(0xc0000000));
1819 __ j(not_zero, &call_runtime); 1819 __ j(not_zero, &call_runtime);
1820 } else { 1820 } else {
1821 // Check if result fits in a smi. 1821 // Check if result fits in a smi.
1822 __ cmp(eax, 0xc0000000); 1822 __ cmp(eax, 0xc0000000);
1823 __ j(negative, &non_smi_result, Label::kNear); 1823 __ j(negative, &non_smi_result, Label::kNear);
1824 } 1824 }
1825 // Tag smi result and return. 1825 // Tag smi result and return.
1826 __ SmiTag(eax); 1826 __ SmiTag(eax);
1827 __ ret(2 * kPointerSize); // Drop two pushed arguments from the stack. 1827 __ ret(2 * kPointerSize); // Drop two pushed arguments from the stack.
1828 1828
1829 // All ops except SHR return a signed int32 that we load in 1829 // All ops except SHR return a signed int32 that we load in
1830 // a HeapNumber. 1830 // a HeapNumber.
1831 if (op_ != Token::SHR) { 1831 if (op_ != Token::SHR) {
1832 __ bind(&non_smi_result); 1832 __ bind(&non_smi_result);
1833 // Allocate a heap number if needed. 1833 // Allocate a heap number if needed.
1834 __ mov(ebx, Operand(eax)); // ebx: result 1834 __ mov(ebx, eax); // ebx: result
1835 Label skip_allocation; 1835 Label skip_allocation;
1836 switch (mode_) { 1836 switch (mode_) {
1837 case OVERWRITE_LEFT: 1837 case OVERWRITE_LEFT:
1838 case OVERWRITE_RIGHT: 1838 case OVERWRITE_RIGHT:
1839 // If the operand was an object, we skip the 1839 // If the operand was an object, we skip the
1840 // allocation of a heap number. 1840 // allocation of a heap number.
1841 __ mov(eax, Operand(esp, mode_ == OVERWRITE_RIGHT ? 1841 __ mov(eax, Operand(esp, mode_ == OVERWRITE_RIGHT ?
1842 1 * kPointerSize : 2 * kPointerSize)); 1842 1 * kPointerSize : 2 * kPointerSize));
1843 __ JumpIfNotSmi(eax, &skip_allocation, Label::kNear); 1843 __ JumpIfNotSmi(eax, &skip_allocation, Label::kNear);
1844 // Fall through! 1844 // Fall through!
1845 case NO_OVERWRITE: 1845 case NO_OVERWRITE:
1846 __ AllocateHeapNumber(eax, ecx, edx, &call_runtime); 1846 __ AllocateHeapNumber(eax, ecx, edx, &call_runtime);
1847 __ bind(&skip_allocation); 1847 __ bind(&skip_allocation);
1848 break; 1848 break;
1849 default: UNREACHABLE(); 1849 default: UNREACHABLE();
1850 } 1850 }
1851 // Store the result in the HeapNumber and return. 1851 // Store the result in the HeapNumber and return.
1852 if (CpuFeatures::IsSupported(SSE2)) { 1852 if (CpuFeatures::IsSupported(SSE2)) {
1853 CpuFeatures::Scope use_sse2(SSE2); 1853 CpuFeatures::Scope use_sse2(SSE2);
1854 __ cvtsi2sd(xmm0, Operand(ebx)); 1854 __ cvtsi2sd(xmm0, ebx);
1855 __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); 1855 __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0);
1856 } else { 1856 } else {
1857 __ mov(Operand(esp, 1 * kPointerSize), ebx); 1857 __ mov(Operand(esp, 1 * kPointerSize), ebx);
1858 __ fild_s(Operand(esp, 1 * kPointerSize)); 1858 __ fild_s(Operand(esp, 1 * kPointerSize));
1859 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); 1859 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
1860 } 1860 }
1861 __ ret(2 * kPointerSize); // Drop two pushed arguments from the stack. 1861 __ ret(2 * kPointerSize); // Drop two pushed arguments from the stack.
1862 } 1862 }
1863 1863
1864 __ bind(&not_floats); 1864 __ bind(&not_floats);
(...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after
1997 case Token::BIT_AND: 1997 case Token::BIT_AND:
1998 case Token::BIT_XOR: 1998 case Token::BIT_XOR:
1999 case Token::SAR: 1999 case Token::SAR:
2000 case Token::SHL: 2000 case Token::SHL:
2001 case Token::SHR: { 2001 case Token::SHR: {
2002 Label non_smi_result; 2002 Label non_smi_result;
2003 FloatingPointHelper::LoadUnknownsAsIntegers(masm, 2003 FloatingPointHelper::LoadUnknownsAsIntegers(masm,
2004 use_sse3_, 2004 use_sse3_,
2005 &call_runtime); 2005 &call_runtime);
2006 switch (op_) { 2006 switch (op_) {
2007 case Token::BIT_OR: __ or_(eax, Operand(ecx)); break; 2007 case Token::BIT_OR: __ or_(eax, ecx); break;
2008 case Token::BIT_AND: __ and_(eax, Operand(ecx)); break; 2008 case Token::BIT_AND: __ and_(eax, ecx); break;
2009 case Token::BIT_XOR: __ xor_(eax, Operand(ecx)); break; 2009 case Token::BIT_XOR: __ xor_(eax, ecx); break;
2010 case Token::SAR: __ sar_cl(eax); break; 2010 case Token::SAR: __ sar_cl(eax); break;
2011 case Token::SHL: __ shl_cl(eax); break; 2011 case Token::SHL: __ shl_cl(eax); break;
2012 case Token::SHR: __ shr_cl(eax); break; 2012 case Token::SHR: __ shr_cl(eax); break;
2013 default: UNREACHABLE(); 2013 default: UNREACHABLE();
2014 } 2014 }
2015 if (op_ == Token::SHR) { 2015 if (op_ == Token::SHR) {
2016 // Check if result is non-negative and fits in a smi. 2016 // Check if result is non-negative and fits in a smi.
2017 __ test(eax, Immediate(0xc0000000)); 2017 __ test(eax, Immediate(0xc0000000));
2018 __ j(not_zero, &call_runtime); 2018 __ j(not_zero, &call_runtime);
2019 } else { 2019 } else {
2020 // Check if result fits in a smi. 2020 // Check if result fits in a smi.
2021 __ cmp(eax, 0xc0000000); 2021 __ cmp(eax, 0xc0000000);
2022 __ j(negative, &non_smi_result, Label::kNear); 2022 __ j(negative, &non_smi_result, Label::kNear);
2023 } 2023 }
2024 // Tag smi result and return. 2024 // Tag smi result and return.
2025 __ SmiTag(eax); 2025 __ SmiTag(eax);
2026 __ ret(2 * kPointerSize); // Drop the arguments from the stack. 2026 __ ret(2 * kPointerSize); // Drop the arguments from the stack.
2027 2027
2028 // All ops except SHR return a signed int32 that we load in 2028 // All ops except SHR return a signed int32 that we load in
2029 // a HeapNumber. 2029 // a HeapNumber.
2030 if (op_ != Token::SHR) { 2030 if (op_ != Token::SHR) {
2031 __ bind(&non_smi_result); 2031 __ bind(&non_smi_result);
2032 // Allocate a heap number if needed. 2032 // Allocate a heap number if needed.
2033 __ mov(ebx, Operand(eax)); // ebx: result 2033 __ mov(ebx, eax); // ebx: result
2034 Label skip_allocation; 2034 Label skip_allocation;
2035 switch (mode_) { 2035 switch (mode_) {
2036 case OVERWRITE_LEFT: 2036 case OVERWRITE_LEFT:
2037 case OVERWRITE_RIGHT: 2037 case OVERWRITE_RIGHT:
2038 // If the operand was an object, we skip the 2038 // If the operand was an object, we skip the
2039 // allocation of a heap number. 2039 // allocation of a heap number.
2040 __ mov(eax, Operand(esp, mode_ == OVERWRITE_RIGHT ? 2040 __ mov(eax, Operand(esp, mode_ == OVERWRITE_RIGHT ?
2041 1 * kPointerSize : 2 * kPointerSize)); 2041 1 * kPointerSize : 2 * kPointerSize));
2042 __ JumpIfNotSmi(eax, &skip_allocation, Label::kNear); 2042 __ JumpIfNotSmi(eax, &skip_allocation, Label::kNear);
2043 // Fall through! 2043 // Fall through!
2044 case NO_OVERWRITE: 2044 case NO_OVERWRITE:
2045 __ AllocateHeapNumber(eax, ecx, edx, &call_runtime); 2045 __ AllocateHeapNumber(eax, ecx, edx, &call_runtime);
2046 __ bind(&skip_allocation); 2046 __ bind(&skip_allocation);
2047 break; 2047 break;
2048 default: UNREACHABLE(); 2048 default: UNREACHABLE();
2049 } 2049 }
2050 // Store the result in the HeapNumber and return. 2050 // Store the result in the HeapNumber and return.
2051 if (CpuFeatures::IsSupported(SSE2)) { 2051 if (CpuFeatures::IsSupported(SSE2)) {
2052 CpuFeatures::Scope use_sse2(SSE2); 2052 CpuFeatures::Scope use_sse2(SSE2);
2053 __ cvtsi2sd(xmm0, Operand(ebx)); 2053 __ cvtsi2sd(xmm0, ebx);
2054 __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); 2054 __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0);
2055 } else { 2055 } else {
2056 __ mov(Operand(esp, 1 * kPointerSize), ebx); 2056 __ mov(Operand(esp, 1 * kPointerSize), ebx);
2057 __ fild_s(Operand(esp, 1 * kPointerSize)); 2057 __ fild_s(Operand(esp, 1 * kPointerSize));
2058 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); 2058 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
2059 } 2059 }
2060 __ ret(2 * kPointerSize); 2060 __ ret(2 * kPointerSize);
2061 } 2061 }
2062 break; 2062 break;
2063 } 2063 }
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after
2153 switch (mode) { 2153 switch (mode) {
2154 case OVERWRITE_LEFT: { 2154 case OVERWRITE_LEFT: {
2155 // If the argument in edx is already an object, we skip the 2155 // If the argument in edx is already an object, we skip the
2156 // allocation of a heap number. 2156 // allocation of a heap number.
2157 __ JumpIfNotSmi(edx, &skip_allocation, Label::kNear); 2157 __ JumpIfNotSmi(edx, &skip_allocation, Label::kNear);
2158 // Allocate a heap number for the result. Keep eax and edx intact 2158 // Allocate a heap number for the result. Keep eax and edx intact
2159 // for the possible runtime call. 2159 // for the possible runtime call.
2160 __ AllocateHeapNumber(ebx, ecx, no_reg, alloc_failure); 2160 __ AllocateHeapNumber(ebx, ecx, no_reg, alloc_failure);
2161 // Now edx can be overwritten losing one of the arguments as we are 2161 // Now edx can be overwritten losing one of the arguments as we are
2162 // now done and will not need it any more. 2162 // now done and will not need it any more.
2163 __ mov(edx, Operand(ebx)); 2163 __ mov(edx, ebx);
2164 __ bind(&skip_allocation); 2164 __ bind(&skip_allocation);
2165 // Use object in edx as a result holder 2165 // Use object in edx as a result holder
2166 __ mov(eax, Operand(edx)); 2166 __ mov(eax, edx);
2167 break; 2167 break;
2168 } 2168 }
2169 case OVERWRITE_RIGHT: 2169 case OVERWRITE_RIGHT:
2170 // If the argument in eax is already an object, we skip the 2170 // If the argument in eax is already an object, we skip the
2171 // allocation of a heap number. 2171 // allocation of a heap number.
2172 __ JumpIfNotSmi(eax, &skip_allocation, Label::kNear); 2172 __ JumpIfNotSmi(eax, &skip_allocation, Label::kNear);
2173 // Fall through! 2173 // Fall through!
2174 case NO_OVERWRITE: 2174 case NO_OVERWRITE:
2175 // Allocate a heap number for the result. Keep eax and edx intact 2175 // Allocate a heap number for the result. Keep eax and edx intact
2176 // for the possible runtime call. 2176 // for the possible runtime call.
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
2214 if (tagged) { 2214 if (tagged) {
2215 // Test that eax is a number. 2215 // Test that eax is a number.
2216 Label input_not_smi; 2216 Label input_not_smi;
2217 Label loaded; 2217 Label loaded;
2218 __ mov(eax, Operand(esp, kPointerSize)); 2218 __ mov(eax, Operand(esp, kPointerSize));
2219 __ JumpIfNotSmi(eax, &input_not_smi, Label::kNear); 2219 __ JumpIfNotSmi(eax, &input_not_smi, Label::kNear);
2220 // Input is a smi. Untag and load it onto the FPU stack. 2220 // Input is a smi. Untag and load it onto the FPU stack.
2221 // Then load the low and high words of the double into ebx, edx. 2221 // Then load the low and high words of the double into ebx, edx.
2222 STATIC_ASSERT(kSmiTagSize == 1); 2222 STATIC_ASSERT(kSmiTagSize == 1);
2223 __ sar(eax, 1); 2223 __ sar(eax, 1);
2224 __ sub(Operand(esp), Immediate(2 * kPointerSize)); 2224 __ sub(esp, Immediate(2 * kPointerSize));
2225 __ mov(Operand(esp, 0), eax); 2225 __ mov(Operand(esp, 0), eax);
2226 __ fild_s(Operand(esp, 0)); 2226 __ fild_s(Operand(esp, 0));
2227 __ fst_d(Operand(esp, 0)); 2227 __ fst_d(Operand(esp, 0));
2228 __ pop(edx); 2228 __ pop(edx);
2229 __ pop(ebx); 2229 __ pop(ebx);
2230 __ jmp(&loaded, Label::kNear); 2230 __ jmp(&loaded, Label::kNear);
2231 __ bind(&input_not_smi); 2231 __ bind(&input_not_smi);
2232 // Check if input is a HeapNumber. 2232 // Check if input is a HeapNumber.
2233 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); 2233 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
2234 Factory* factory = masm->isolate()->factory(); 2234 Factory* factory = masm->isolate()->factory();
2235 __ cmp(Operand(ebx), Immediate(factory->heap_number_map())); 2235 __ cmp(ebx, Immediate(factory->heap_number_map()));
2236 __ j(not_equal, &runtime_call); 2236 __ j(not_equal, &runtime_call);
2237 // Input is a HeapNumber. Push it on the FPU stack and load its 2237 // Input is a HeapNumber. Push it on the FPU stack and load its
2238 // low and high words into ebx, edx. 2238 // low and high words into ebx, edx.
2239 __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset)); 2239 __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset));
2240 __ mov(edx, FieldOperand(eax, HeapNumber::kExponentOffset)); 2240 __ mov(edx, FieldOperand(eax, HeapNumber::kExponentOffset));
2241 __ mov(ebx, FieldOperand(eax, HeapNumber::kMantissaOffset)); 2241 __ mov(ebx, FieldOperand(eax, HeapNumber::kMantissaOffset));
2242 2242
2243 __ bind(&loaded); 2243 __ bind(&loaded);
2244 } else { // UNTAGGED. 2244 } else { // UNTAGGED.
2245 if (CpuFeatures::IsSupported(SSE4_1)) { 2245 if (CpuFeatures::IsSupported(SSE4_1)) {
2246 CpuFeatures::Scope sse4_scope(SSE4_1); 2246 CpuFeatures::Scope sse4_scope(SSE4_1);
2247 __ pextrd(Operand(edx), xmm1, 0x1); // copy xmm1[63..32] to edx. 2247 __ pextrd(edx, xmm1, 0x1); // copy xmm1[63..32] to edx.
2248 } else { 2248 } else {
2249 __ pshufd(xmm0, xmm1, 0x1); 2249 __ pshufd(xmm0, xmm1, 0x1);
2250 __ movd(Operand(edx), xmm0); 2250 __ movd(edx, xmm0);
2251 } 2251 }
2252 __ movd(Operand(ebx), xmm1); 2252 __ movd(ebx, xmm1);
2253 } 2253 }
2254 2254
2255 // ST[0] or xmm1 == double value 2255 // ST[0] or xmm1 == double value
2256 // ebx = low 32 bits of double value 2256 // ebx = low 32 bits of double value
2257 // edx = high 32 bits of double value 2257 // edx = high 32 bits of double value
2258 // Compute hash (the shifts are arithmetic): 2258 // Compute hash (the shifts are arithmetic):
2259 // h = (low ^ high); h ^= h >> 16; h ^= h >> 8; h = h & (cacheSize - 1); 2259 // h = (low ^ high); h ^= h >> 16; h ^= h >> 8; h = h & (cacheSize - 1);
2260 __ mov(ecx, ebx); 2260 __ mov(ecx, ebx);
2261 __ xor_(ecx, Operand(edx)); 2261 __ xor_(ecx, edx);
2262 __ mov(eax, ecx); 2262 __ mov(eax, ecx);
2263 __ sar(eax, 16); 2263 __ sar(eax, 16);
2264 __ xor_(ecx, Operand(eax)); 2264 __ xor_(ecx, eax);
2265 __ mov(eax, ecx); 2265 __ mov(eax, ecx);
2266 __ sar(eax, 8); 2266 __ sar(eax, 8);
2267 __ xor_(ecx, Operand(eax)); 2267 __ xor_(ecx, eax);
2268 ASSERT(IsPowerOf2(TranscendentalCache::SubCache::kCacheSize)); 2268 ASSERT(IsPowerOf2(TranscendentalCache::SubCache::kCacheSize));
2269 __ and_(Operand(ecx), 2269 __ and_(ecx,
2270 Immediate(TranscendentalCache::SubCache::kCacheSize - 1)); 2270 Immediate(TranscendentalCache::SubCache::kCacheSize - 1));
2271 2271
2272 // ST[0] or xmm1 == double value. 2272 // ST[0] or xmm1 == double value.
2273 // ebx = low 32 bits of double value. 2273 // ebx = low 32 bits of double value.
2274 // edx = high 32 bits of double value. 2274 // edx = high 32 bits of double value.
2275 // ecx = TranscendentalCache::hash(double value). 2275 // ecx = TranscendentalCache::hash(double value).
2276 ExternalReference cache_array = 2276 ExternalReference cache_array =
2277 ExternalReference::transcendental_cache_array_address(masm->isolate()); 2277 ExternalReference::transcendental_cache_array_address(masm->isolate());
2278 __ mov(eax, Immediate(cache_array)); 2278 __ mov(eax, Immediate(cache_array));
2279 int cache_array_index = 2279 int cache_array_index =
2280 type_ * sizeof(masm->isolate()->transcendental_cache()->caches_[0]); 2280 type_ * sizeof(masm->isolate()->transcendental_cache()->caches_[0]);
2281 __ mov(eax, Operand(eax, cache_array_index)); 2281 __ mov(eax, Operand(eax, cache_array_index));
2282 // Eax points to the cache for the type type_. 2282 // Eax points to the cache for the type type_.
2283 // If NULL, the cache hasn't been initialized yet, so go through runtime. 2283 // If NULL, the cache hasn't been initialized yet, so go through runtime.
2284 __ test(eax, Operand(eax)); 2284 __ test(eax, eax);
2285 __ j(zero, &runtime_call_clear_stack); 2285 __ j(zero, &runtime_call_clear_stack);
2286 #ifdef DEBUG 2286 #ifdef DEBUG
2287 // Check that the layout of cache elements match expectations. 2287 // Check that the layout of cache elements match expectations.
2288 { TranscendentalCache::SubCache::Element test_elem[2]; 2288 { TranscendentalCache::SubCache::Element test_elem[2];
2289 char* elem_start = reinterpret_cast<char*>(&test_elem[0]); 2289 char* elem_start = reinterpret_cast<char*>(&test_elem[0]);
2290 char* elem2_start = reinterpret_cast<char*>(&test_elem[1]); 2290 char* elem2_start = reinterpret_cast<char*>(&test_elem[1]);
2291 char* elem_in0 = reinterpret_cast<char*>(&(test_elem[0].in[0])); 2291 char* elem_in0 = reinterpret_cast<char*>(&(test_elem[0].in[0]));
2292 char* elem_in1 = reinterpret_cast<char*>(&(test_elem[0].in[1])); 2292 char* elem_in1 = reinterpret_cast<char*>(&(test_elem[0].in[1]));
2293 char* elem_out = reinterpret_cast<char*>(&(test_elem[0].output)); 2293 char* elem_out = reinterpret_cast<char*>(&(test_elem[0].output));
2294 CHECK_EQ(12, elem2_start - elem_start); // Two uint_32's and a pointer. 2294 CHECK_EQ(12, elem2_start - elem_start); // Two uint_32's and a pointer.
(...skipping 22 matching lines...) Expand all
2317 } 2317 }
2318 2318
2319 __ bind(&cache_miss); 2319 __ bind(&cache_miss);
2320 // Update cache with new value. 2320 // Update cache with new value.
2321 // We are short on registers, so use no_reg as scratch. 2321 // We are short on registers, so use no_reg as scratch.
2322 // This gives slightly larger code. 2322 // This gives slightly larger code.
2323 if (tagged) { 2323 if (tagged) {
2324 __ AllocateHeapNumber(eax, edi, no_reg, &runtime_call_clear_stack); 2324 __ AllocateHeapNumber(eax, edi, no_reg, &runtime_call_clear_stack);
2325 } else { // UNTAGGED. 2325 } else { // UNTAGGED.
2326 __ AllocateHeapNumber(eax, edi, no_reg, &skip_cache); 2326 __ AllocateHeapNumber(eax, edi, no_reg, &skip_cache);
2327 __ sub(Operand(esp), Immediate(kDoubleSize)); 2327 __ sub(esp, Immediate(kDoubleSize));
2328 __ movdbl(Operand(esp, 0), xmm1); 2328 __ movdbl(Operand(esp, 0), xmm1);
2329 __ fld_d(Operand(esp, 0)); 2329 __ fld_d(Operand(esp, 0));
2330 __ add(Operand(esp), Immediate(kDoubleSize)); 2330 __ add(esp, Immediate(kDoubleSize));
2331 } 2331 }
2332 GenerateOperation(masm); 2332 GenerateOperation(masm);
2333 __ mov(Operand(ecx, 0), ebx); 2333 __ mov(Operand(ecx, 0), ebx);
2334 __ mov(Operand(ecx, kIntSize), edx); 2334 __ mov(Operand(ecx, kIntSize), edx);
2335 __ mov(Operand(ecx, 2 * kIntSize), eax); 2335 __ mov(Operand(ecx, 2 * kIntSize), eax);
2336 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); 2336 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
2337 if (tagged) { 2337 if (tagged) {
2338 __ ret(kPointerSize); 2338 __ ret(kPointerSize);
2339 } else { // UNTAGGED. 2339 } else { // UNTAGGED.
2340 __ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset)); 2340 __ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset));
2341 __ Ret(); 2341 __ Ret();
2342 2342
2343 // Skip cache and return answer directly, only in untagged case. 2343 // Skip cache and return answer directly, only in untagged case.
2344 __ bind(&skip_cache); 2344 __ bind(&skip_cache);
2345 __ sub(Operand(esp), Immediate(kDoubleSize)); 2345 __ sub(esp, Immediate(kDoubleSize));
2346 __ movdbl(Operand(esp, 0), xmm1); 2346 __ movdbl(Operand(esp, 0), xmm1);
2347 __ fld_d(Operand(esp, 0)); 2347 __ fld_d(Operand(esp, 0));
2348 GenerateOperation(masm); 2348 GenerateOperation(masm);
2349 __ fstp_d(Operand(esp, 0)); 2349 __ fstp_d(Operand(esp, 0));
2350 __ movdbl(xmm1, Operand(esp, 0)); 2350 __ movdbl(xmm1, Operand(esp, 0));
2351 __ add(Operand(esp), Immediate(kDoubleSize)); 2351 __ add(esp, Immediate(kDoubleSize));
2352 // We return the value in xmm1 without adding it to the cache, but 2352 // We return the value in xmm1 without adding it to the cache, but
2353 // we cause a scavenging GC so that future allocations will succeed. 2353 // we cause a scavenging GC so that future allocations will succeed.
2354 { 2354 {
2355 FrameScope scope(masm, StackFrame::INTERNAL); 2355 FrameScope scope(masm, StackFrame::INTERNAL);
2356 // Allocate an unused object bigger than a HeapNumber. 2356 // Allocate an unused object bigger than a HeapNumber.
2357 __ push(Immediate(Smi::FromInt(2 * kDoubleSize))); 2357 __ push(Immediate(Smi::FromInt(2 * kDoubleSize)));
2358 __ CallRuntimeSaveDoubles(Runtime::kAllocateInNewSpace); 2358 __ CallRuntimeSaveDoubles(Runtime::kAllocateInNewSpace);
2359 } 2359 }
2360 __ Ret(); 2360 __ Ret();
2361 } 2361 }
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
2402 // Input value is possibly in xmm1. 2402 // Input value is possibly in xmm1.
2403 // Address of result (a newly allocated HeapNumber) may be in eax. 2403 // Address of result (a newly allocated HeapNumber) may be in eax.
2404 if (type_ == TranscendentalCache::SIN || type_ == TranscendentalCache::COS) { 2404 if (type_ == TranscendentalCache::SIN || type_ == TranscendentalCache::COS) {
2405 // Both fsin and fcos require arguments in the range +/-2^63 and 2405 // Both fsin and fcos require arguments in the range +/-2^63 and
2406 // return NaN for infinities and NaN. They can share all code except 2406 // return NaN for infinities and NaN. They can share all code except
2407 // the actual fsin/fcos operation. 2407 // the actual fsin/fcos operation.
2408 Label in_range, done; 2408 Label in_range, done;
2409 // If argument is outside the range -2^63..2^63, fsin/cos doesn't 2409 // If argument is outside the range -2^63..2^63, fsin/cos doesn't
2410 // work. We must reduce it to the appropriate range. 2410 // work. We must reduce it to the appropriate range.
2411 __ mov(edi, edx); 2411 __ mov(edi, edx);
2412 __ and_(Operand(edi), Immediate(0x7ff00000)); // Exponent only. 2412 __ and_(edi, Immediate(0x7ff00000)); // Exponent only.
2413 int supported_exponent_limit = 2413 int supported_exponent_limit =
2414 (63 + HeapNumber::kExponentBias) << HeapNumber::kExponentShift; 2414 (63 + HeapNumber::kExponentBias) << HeapNumber::kExponentShift;
2415 __ cmp(Operand(edi), Immediate(supported_exponent_limit)); 2415 __ cmp(edi, Immediate(supported_exponent_limit));
2416 __ j(below, &in_range, Label::kNear); 2416 __ j(below, &in_range, Label::kNear);
2417 // Check for infinity and NaN. Both return NaN for sin. 2417 // Check for infinity and NaN. Both return NaN for sin.
2418 __ cmp(Operand(edi), Immediate(0x7ff00000)); 2418 __ cmp(edi, Immediate(0x7ff00000));
2419 Label non_nan_result; 2419 Label non_nan_result;
2420 __ j(not_equal, &non_nan_result, Label::kNear); 2420 __ j(not_equal, &non_nan_result, Label::kNear);
2421 // Input is +/-Infinity or NaN. Result is NaN. 2421 // Input is +/-Infinity or NaN. Result is NaN.
2422 __ fstp(0); 2422 __ fstp(0);
2423 // NaN is represented by 0x7ff8000000000000. 2423 // NaN is represented by 0x7ff8000000000000.
2424 __ push(Immediate(0x7ff80000)); 2424 __ push(Immediate(0x7ff80000));
2425 __ push(Immediate(0)); 2425 __ push(Immediate(0));
2426 __ fld_d(Operand(esp, 0)); 2426 __ fld_d(Operand(esp, 0));
2427 __ add(Operand(esp), Immediate(2 * kPointerSize)); 2427 __ add(esp, Immediate(2 * kPointerSize));
2428 __ jmp(&done, Label::kNear); 2428 __ jmp(&done, Label::kNear);
2429 2429
2430 __ bind(&non_nan_result); 2430 __ bind(&non_nan_result);
2431 2431
2432 // Use fpmod to restrict argument to the range +/-2*PI. 2432 // Use fpmod to restrict argument to the range +/-2*PI.
2433 __ mov(edi, eax); // Save eax before using fnstsw_ax. 2433 __ mov(edi, eax); // Save eax before using fnstsw_ax.
2434 __ fldpi(); 2434 __ fldpi();
2435 __ fadd(0); 2435 __ fadd(0);
2436 __ fld(1); 2436 __ fld(1);
2437 // FPU Stack: input, 2*pi, input. 2437 // FPU Stack: input, 2*pi, input.
2438 { 2438 {
2439 Label no_exceptions; 2439 Label no_exceptions;
2440 __ fwait(); 2440 __ fwait();
2441 __ fnstsw_ax(); 2441 __ fnstsw_ax();
2442 // Clear if Illegal Operand or Zero Division exceptions are set. 2442 // Clear if Illegal Operand or Zero Division exceptions are set.
2443 __ test(Operand(eax), Immediate(5)); 2443 __ test(eax, Immediate(5));
2444 __ j(zero, &no_exceptions, Label::kNear); 2444 __ j(zero, &no_exceptions, Label::kNear);
2445 __ fnclex(); 2445 __ fnclex();
2446 __ bind(&no_exceptions); 2446 __ bind(&no_exceptions);
2447 } 2447 }
2448 2448
2449 // Compute st(0) % st(1) 2449 // Compute st(0) % st(1)
2450 { 2450 {
2451 Label partial_remainder_loop; 2451 Label partial_remainder_loop;
2452 __ bind(&partial_remainder_loop); 2452 __ bind(&partial_remainder_loop);
2453 __ fprem1(); 2453 __ fprem1();
2454 __ fwait(); 2454 __ fwait();
2455 __ fnstsw_ax(); 2455 __ fnstsw_ax();
2456 __ test(Operand(eax), Immediate(0x400 /* C2 */)); 2456 __ test(eax, Immediate(0x400 /* C2 */));
2457 // If C2 is set, computation only has partial result. Loop to 2457 // If C2 is set, computation only has partial result. Loop to
2458 // continue computation. 2458 // continue computation.
2459 __ j(not_zero, &partial_remainder_loop); 2459 __ j(not_zero, &partial_remainder_loop);
2460 } 2460 }
2461 // FPU Stack: input, 2*pi, input % 2*pi 2461 // FPU Stack: input, 2*pi, input % 2*pi
2462 __ fstp(2); 2462 __ fstp(2);
2463 __ fstp(0); 2463 __ fstp(0);
2464 __ mov(eax, edi); // Restore eax (allocated HeapNumber pointer). 2464 __ mov(eax, edi); // Restore eax (allocated HeapNumber pointer).
2465 2465
2466 // FPU Stack: input % 2*pi 2466 // FPU Stack: input % 2*pi
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after
2579 __ movdbl(xmm0, FieldOperand(edx, HeapNumber::kValueOffset)); 2579 __ movdbl(xmm0, FieldOperand(edx, HeapNumber::kValueOffset));
2580 2580
2581 __ bind(&load_eax); 2581 __ bind(&load_eax);
2582 // Load operand in eax into xmm1. 2582 // Load operand in eax into xmm1.
2583 __ JumpIfSmi(eax, &load_smi_eax, Label::kNear); 2583 __ JumpIfSmi(eax, &load_smi_eax, Label::kNear);
2584 __ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset)); 2584 __ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset));
2585 __ jmp(&done, Label::kNear); 2585 __ jmp(&done, Label::kNear);
2586 2586
2587 __ bind(&load_smi_edx); 2587 __ bind(&load_smi_edx);
2588 __ SmiUntag(edx); // Untag smi before converting to float. 2588 __ SmiUntag(edx); // Untag smi before converting to float.
2589 __ cvtsi2sd(xmm0, Operand(edx)); 2589 __ cvtsi2sd(xmm0, edx);
2590 __ SmiTag(edx); // Retag smi for heap number overwriting test. 2590 __ SmiTag(edx); // Retag smi for heap number overwriting test.
2591 __ jmp(&load_eax); 2591 __ jmp(&load_eax);
2592 2592
2593 __ bind(&load_smi_eax); 2593 __ bind(&load_smi_eax);
2594 __ SmiUntag(eax); // Untag smi before converting to float. 2594 __ SmiUntag(eax); // Untag smi before converting to float.
2595 __ cvtsi2sd(xmm1, Operand(eax)); 2595 __ cvtsi2sd(xmm1, eax);
2596 __ SmiTag(eax); // Retag smi for heap number overwriting test. 2596 __ SmiTag(eax); // Retag smi for heap number overwriting test.
2597 2597
2598 __ bind(&done); 2598 __ bind(&done);
2599 } 2599 }
2600 2600
2601 2601
2602 void FloatingPointHelper::LoadSSE2Operands(MacroAssembler* masm, 2602 void FloatingPointHelper::LoadSSE2Operands(MacroAssembler* masm,
2603 Label* not_numbers) { 2603 Label* not_numbers) {
2604 Label load_smi_edx, load_eax, load_smi_eax, load_float_eax, done; 2604 Label load_smi_edx, load_eax, load_smi_eax, load_float_eax, done;
2605 // Load operand in edx into xmm0, or branch to not_numbers. 2605 // Load operand in edx into xmm0, or branch to not_numbers.
2606 __ JumpIfSmi(edx, &load_smi_edx, Label::kNear); 2606 __ JumpIfSmi(edx, &load_smi_edx, Label::kNear);
2607 Factory* factory = masm->isolate()->factory(); 2607 Factory* factory = masm->isolate()->factory();
2608 __ cmp(FieldOperand(edx, HeapObject::kMapOffset), factory->heap_number_map()); 2608 __ cmp(FieldOperand(edx, HeapObject::kMapOffset), factory->heap_number_map());
2609 __ j(not_equal, not_numbers); // Argument in edx is not a number. 2609 __ j(not_equal, not_numbers); // Argument in edx is not a number.
2610 __ movdbl(xmm0, FieldOperand(edx, HeapNumber::kValueOffset)); 2610 __ movdbl(xmm0, FieldOperand(edx, HeapNumber::kValueOffset));
2611 __ bind(&load_eax); 2611 __ bind(&load_eax);
2612 // Load operand in eax into xmm1, or branch to not_numbers. 2612 // Load operand in eax into xmm1, or branch to not_numbers.
2613 __ JumpIfSmi(eax, &load_smi_eax, Label::kNear); 2613 __ JumpIfSmi(eax, &load_smi_eax, Label::kNear);
2614 __ cmp(FieldOperand(eax, HeapObject::kMapOffset), factory->heap_number_map()); 2614 __ cmp(FieldOperand(eax, HeapObject::kMapOffset), factory->heap_number_map());
2615 __ j(equal, &load_float_eax, Label::kNear); 2615 __ j(equal, &load_float_eax, Label::kNear);
2616 __ jmp(not_numbers); // Argument in eax is not a number. 2616 __ jmp(not_numbers); // Argument in eax is not a number.
2617 __ bind(&load_smi_edx); 2617 __ bind(&load_smi_edx);
2618 __ SmiUntag(edx); // Untag smi before converting to float. 2618 __ SmiUntag(edx); // Untag smi before converting to float.
2619 __ cvtsi2sd(xmm0, Operand(edx)); 2619 __ cvtsi2sd(xmm0, edx);
2620 __ SmiTag(edx); // Retag smi for heap number overwriting test. 2620 __ SmiTag(edx); // Retag smi for heap number overwriting test.
2621 __ jmp(&load_eax); 2621 __ jmp(&load_eax);
2622 __ bind(&load_smi_eax); 2622 __ bind(&load_smi_eax);
2623 __ SmiUntag(eax); // Untag smi before converting to float. 2623 __ SmiUntag(eax); // Untag smi before converting to float.
2624 __ cvtsi2sd(xmm1, Operand(eax)); 2624 __ cvtsi2sd(xmm1, eax);
2625 __ SmiTag(eax); // Retag smi for heap number overwriting test. 2625 __ SmiTag(eax); // Retag smi for heap number overwriting test.
2626 __ jmp(&done, Label::kNear); 2626 __ jmp(&done, Label::kNear);
2627 __ bind(&load_float_eax); 2627 __ bind(&load_float_eax);
2628 __ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset)); 2628 __ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset));
2629 __ bind(&done); 2629 __ bind(&done);
2630 } 2630 }
2631 2631
2632 2632
2633 void FloatingPointHelper::LoadSSE2Smis(MacroAssembler* masm, 2633 void FloatingPointHelper::LoadSSE2Smis(MacroAssembler* masm,
2634 Register scratch) { 2634 Register scratch) {
2635 const Register left = edx; 2635 const Register left = edx;
2636 const Register right = eax; 2636 const Register right = eax;
2637 __ mov(scratch, left); 2637 __ mov(scratch, left);
2638 ASSERT(!scratch.is(right)); // We're about to clobber scratch. 2638 ASSERT(!scratch.is(right)); // We're about to clobber scratch.
2639 __ SmiUntag(scratch); 2639 __ SmiUntag(scratch);
2640 __ cvtsi2sd(xmm0, Operand(scratch)); 2640 __ cvtsi2sd(xmm0, scratch);
2641 2641
2642 __ mov(scratch, right); 2642 __ mov(scratch, right);
2643 __ SmiUntag(scratch); 2643 __ SmiUntag(scratch);
2644 __ cvtsi2sd(xmm1, Operand(scratch)); 2644 __ cvtsi2sd(xmm1, scratch);
2645 } 2645 }
2646 2646
2647 2647
2648 void FloatingPointHelper::CheckSSE2OperandsAreInt32(MacroAssembler* masm, 2648 void FloatingPointHelper::CheckSSE2OperandsAreInt32(MacroAssembler* masm,
2649 Label* non_int32, 2649 Label* non_int32,
2650 Register scratch) { 2650 Register scratch) {
2651 __ cvttsd2si(scratch, Operand(xmm0)); 2651 __ cvttsd2si(scratch, Operand(xmm0));
2652 __ cvtsi2sd(xmm2, Operand(scratch)); 2652 __ cvtsi2sd(xmm2, scratch);
2653 __ ucomisd(xmm0, xmm2); 2653 __ ucomisd(xmm0, xmm2);
2654 __ j(not_zero, non_int32); 2654 __ j(not_zero, non_int32);
2655 __ j(carry, non_int32); 2655 __ j(carry, non_int32);
2656 __ cvttsd2si(scratch, Operand(xmm1)); 2656 __ cvttsd2si(scratch, Operand(xmm1));
2657 __ cvtsi2sd(xmm2, Operand(scratch)); 2657 __ cvtsi2sd(xmm2, scratch);
2658 __ ucomisd(xmm1, xmm2); 2658 __ ucomisd(xmm1, xmm2);
2659 __ j(not_zero, non_int32); 2659 __ j(not_zero, non_int32);
2660 __ j(carry, non_int32); 2660 __ j(carry, non_int32);
2661 } 2661 }
2662 2662
2663 2663
2664 void FloatingPointHelper::LoadFloatOperands(MacroAssembler* masm, 2664 void FloatingPointHelper::LoadFloatOperands(MacroAssembler* masm,
2665 Register scratch, 2665 Register scratch,
2666 ArgLocation arg_location) { 2666 ArgLocation arg_location) {
2667 Label load_smi_1, load_smi_2, done_load_1, done; 2667 Label load_smi_1, load_smi_2, done_load_1, done;
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after
2755 2755
2756 CpuFeatures::Scope use_sse2(SSE2); 2756 CpuFeatures::Scope use_sse2(SSE2);
2757 Label allocate_return, call_runtime; 2757 Label allocate_return, call_runtime;
2758 2758
2759 // Load input parameters. 2759 // Load input parameters.
2760 __ mov(edx, Operand(esp, 2 * kPointerSize)); 2760 __ mov(edx, Operand(esp, 2 * kPointerSize));
2761 __ mov(eax, Operand(esp, 1 * kPointerSize)); 2761 __ mov(eax, Operand(esp, 1 * kPointerSize));
2762 2762
2763 // Save 1 in xmm3 - we need this several times later on. 2763 // Save 1 in xmm3 - we need this several times later on.
2764 __ mov(ecx, Immediate(1)); 2764 __ mov(ecx, Immediate(1));
2765 __ cvtsi2sd(xmm3, Operand(ecx)); 2765 __ cvtsi2sd(xmm3, ecx);
2766 2766
2767 Label exponent_nonsmi; 2767 Label exponent_nonsmi;
2768 Label base_nonsmi; 2768 Label base_nonsmi;
2769 // If the exponent is a heap number go to that specific case. 2769 // If the exponent is a heap number go to that specific case.
2770 __ JumpIfNotSmi(eax, &exponent_nonsmi); 2770 __ JumpIfNotSmi(eax, &exponent_nonsmi);
2771 __ JumpIfNotSmi(edx, &base_nonsmi); 2771 __ JumpIfNotSmi(edx, &base_nonsmi);
2772 2772
2773 // Optimized version when both exponent and base are smis. 2773 // Optimized version when both exponent and base are smis.
2774 Label powi; 2774 Label powi;
2775 __ SmiUntag(edx); 2775 __ SmiUntag(edx);
2776 __ cvtsi2sd(xmm0, Operand(edx)); 2776 __ cvtsi2sd(xmm0, edx);
2777 __ jmp(&powi); 2777 __ jmp(&powi);
2778 // exponent is smi and base is a heapnumber. 2778 // exponent is smi and base is a heapnumber.
2779 __ bind(&base_nonsmi); 2779 __ bind(&base_nonsmi);
2780 Factory* factory = masm->isolate()->factory(); 2780 Factory* factory = masm->isolate()->factory();
2781 __ cmp(FieldOperand(edx, HeapObject::kMapOffset), 2781 __ cmp(FieldOperand(edx, HeapObject::kMapOffset),
2782 factory->heap_number_map()); 2782 factory->heap_number_map());
2783 __ j(not_equal, &call_runtime); 2783 __ j(not_equal, &call_runtime);
2784 2784
2785 __ movdbl(xmm0, FieldOperand(edx, HeapNumber::kValueOffset)); 2785 __ movdbl(xmm0, FieldOperand(edx, HeapNumber::kValueOffset));
2786 2786
(...skipping 21 matching lines...) Expand all
2808 __ bind(&while_true); 2808 __ bind(&while_true);
2809 __ shr(eax, 1); 2809 __ shr(eax, 1);
2810 __ j(not_carry, &no_multiply, Label::kNear); 2810 __ j(not_carry, &no_multiply, Label::kNear);
2811 __ mulsd(xmm1, xmm0); 2811 __ mulsd(xmm1, xmm0);
2812 __ bind(&no_multiply); 2812 __ bind(&no_multiply);
2813 __ mulsd(xmm0, xmm0); 2813 __ mulsd(xmm0, xmm0);
2814 __ j(not_zero, &while_true); 2814 __ j(not_zero, &while_true);
2815 2815
2816 // base has the original value of the exponent - if the exponent is 2816 // base has the original value of the exponent - if the exponent is
2817 // negative return 1/result. 2817 // negative return 1/result.
2818 __ test(edx, Operand(edx)); 2818 __ test(edx, edx);
2819 __ j(positive, &allocate_return); 2819 __ j(positive, &allocate_return);
2820 // Special case if xmm1 has reached infinity. 2820 // Special case if xmm1 has reached infinity.
2821 __ mov(ecx, Immediate(0x7FB00000)); 2821 __ mov(ecx, Immediate(0x7FB00000));
2822 __ movd(xmm0, Operand(ecx)); 2822 __ movd(xmm0, ecx);
2823 __ cvtss2sd(xmm0, xmm0); 2823 __ cvtss2sd(xmm0, xmm0);
2824 __ ucomisd(xmm0, xmm1); 2824 __ ucomisd(xmm0, xmm1);
2825 __ j(equal, &call_runtime); 2825 __ j(equal, &call_runtime);
2826 __ divsd(xmm3, xmm1); 2826 __ divsd(xmm3, xmm1);
2827 __ movsd(xmm1, xmm3); 2827 __ movsd(xmm1, xmm3);
2828 __ jmp(&allocate_return); 2828 __ jmp(&allocate_return);
2829 2829
2830 // exponent (or both) is a heapnumber - no matter what we should now work 2830 // exponent (or both) is a heapnumber - no matter what we should now work
2831 // on doubles. 2831 // on doubles.
2832 __ bind(&exponent_nonsmi); 2832 __ bind(&exponent_nonsmi);
2833 __ cmp(FieldOperand(eax, HeapObject::kMapOffset), 2833 __ cmp(FieldOperand(eax, HeapObject::kMapOffset),
2834 factory->heap_number_map()); 2834 factory->heap_number_map());
2835 __ j(not_equal, &call_runtime); 2835 __ j(not_equal, &call_runtime);
2836 __ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset)); 2836 __ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset));
2837 // Test if exponent is nan. 2837 // Test if exponent is nan.
2838 __ ucomisd(xmm1, xmm1); 2838 __ ucomisd(xmm1, xmm1);
2839 __ j(parity_even, &call_runtime); 2839 __ j(parity_even, &call_runtime);
2840 2840
2841 Label base_not_smi; 2841 Label base_not_smi;
2842 Label handle_special_cases; 2842 Label handle_special_cases;
2843 __ JumpIfNotSmi(edx, &base_not_smi, Label::kNear); 2843 __ JumpIfNotSmi(edx, &base_not_smi, Label::kNear);
2844 __ SmiUntag(edx); 2844 __ SmiUntag(edx);
2845 __ cvtsi2sd(xmm0, Operand(edx)); 2845 __ cvtsi2sd(xmm0, edx);
2846 __ jmp(&handle_special_cases, Label::kNear); 2846 __ jmp(&handle_special_cases, Label::kNear);
2847 2847
2848 __ bind(&base_not_smi); 2848 __ bind(&base_not_smi);
2849 __ cmp(FieldOperand(edx, HeapObject::kMapOffset), 2849 __ cmp(FieldOperand(edx, HeapObject::kMapOffset),
2850 factory->heap_number_map()); 2850 factory->heap_number_map());
2851 __ j(not_equal, &call_runtime); 2851 __ j(not_equal, &call_runtime);
2852 __ mov(ecx, FieldOperand(edx, HeapNumber::kExponentOffset)); 2852 __ mov(ecx, FieldOperand(edx, HeapNumber::kExponentOffset));
2853 __ and_(ecx, HeapNumber::kExponentMask); 2853 __ and_(ecx, HeapNumber::kExponentMask);
2854 __ cmp(Operand(ecx), Immediate(HeapNumber::kExponentMask)); 2854 __ cmp(ecx, Immediate(HeapNumber::kExponentMask));
2855 // base is NaN or +/-Infinity 2855 // base is NaN or +/-Infinity
2856 __ j(greater_equal, &call_runtime); 2856 __ j(greater_equal, &call_runtime);
2857 __ movdbl(xmm0, FieldOperand(edx, HeapNumber::kValueOffset)); 2857 __ movdbl(xmm0, FieldOperand(edx, HeapNumber::kValueOffset));
2858 2858
2859 // base is in xmm0 and exponent is in xmm1. 2859 // base is in xmm0 and exponent is in xmm1.
2860 __ bind(&handle_special_cases); 2860 __ bind(&handle_special_cases);
2861 Label not_minus_half; 2861 Label not_minus_half;
2862 // Test for -0.5. 2862 // Test for -0.5.
2863 // Load xmm2 with -0.5. 2863 // Load xmm2 with -0.5.
2864 __ mov(ecx, Immediate(0xBF000000)); 2864 __ mov(ecx, Immediate(0xBF000000));
2865 __ movd(xmm2, Operand(ecx)); 2865 __ movd(xmm2, ecx);
2866 __ cvtss2sd(xmm2, xmm2); 2866 __ cvtss2sd(xmm2, xmm2);
2867 // xmm2 now has -0.5. 2867 // xmm2 now has -0.5.
2868 __ ucomisd(xmm2, xmm1); 2868 __ ucomisd(xmm2, xmm1);
2869 __ j(not_equal, &not_minus_half, Label::kNear); 2869 __ j(not_equal, &not_minus_half, Label::kNear);
2870 2870
2871 // Calculates reciprocal of square root. 2871 // Calculates reciprocal of square root.
2872 // sqrtsd returns -0 when input is -0. ECMA spec requires +0. 2872 // sqrtsd returns -0 when input is -0. ECMA spec requires +0.
2873 __ xorps(xmm1, xmm1); 2873 __ xorps(xmm1, xmm1);
2874 __ addsd(xmm1, xmm0); 2874 __ addsd(xmm1, xmm0);
2875 __ sqrtsd(xmm1, xmm1); 2875 __ sqrtsd(xmm1, xmm1);
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
2911 static const int kDisplacement = 1 * kPointerSize; 2911 static const int kDisplacement = 1 * kPointerSize;
2912 2912
2913 // Check that the key is a smi. 2913 // Check that the key is a smi.
2914 Label slow; 2914 Label slow;
2915 __ JumpIfNotSmi(edx, &slow, Label::kNear); 2915 __ JumpIfNotSmi(edx, &slow, Label::kNear);
2916 2916
2917 // Check if the calling frame is an arguments adaptor frame. 2917 // Check if the calling frame is an arguments adaptor frame.
2918 Label adaptor; 2918 Label adaptor;
2919 __ mov(ebx, Operand(ebp, StandardFrameConstants::kCallerFPOffset)); 2919 __ mov(ebx, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
2920 __ mov(ecx, Operand(ebx, StandardFrameConstants::kContextOffset)); 2920 __ mov(ecx, Operand(ebx, StandardFrameConstants::kContextOffset));
2921 __ cmp(Operand(ecx), Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); 2921 __ cmp(ecx, Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
2922 __ j(equal, &adaptor, Label::kNear); 2922 __ j(equal, &adaptor, Label::kNear);
2923 2923
2924 // Check index against formal parameters count limit passed in 2924 // Check index against formal parameters count limit passed in
2925 // through register eax. Use unsigned comparison to get negative 2925 // through register eax. Use unsigned comparison to get negative
2926 // check for free. 2926 // check for free.
2927 __ cmp(edx, Operand(eax)); 2927 __ cmp(edx, eax);
2928 __ j(above_equal, &slow, Label::kNear); 2928 __ j(above_equal, &slow, Label::kNear);
2929 2929
2930 // Read the argument from the stack and return it. 2930 // Read the argument from the stack and return it.
2931 STATIC_ASSERT(kSmiTagSize == 1); 2931 STATIC_ASSERT(kSmiTagSize == 1);
2932 STATIC_ASSERT(kSmiTag == 0); // Shifting code depends on these. 2932 STATIC_ASSERT(kSmiTag == 0); // Shifting code depends on these.
2933 __ lea(ebx, Operand(ebp, eax, times_2, 0)); 2933 __ lea(ebx, Operand(ebp, eax, times_2, 0));
2934 __ neg(edx); 2934 __ neg(edx);
2935 __ mov(eax, Operand(ebx, edx, times_2, kDisplacement)); 2935 __ mov(eax, Operand(ebx, edx, times_2, kDisplacement));
2936 __ ret(0); 2936 __ ret(0);
2937 2937
2938 // Arguments adaptor case: Check index against actual arguments 2938 // Arguments adaptor case: Check index against actual arguments
2939 // limit found in the arguments adaptor frame. Use unsigned 2939 // limit found in the arguments adaptor frame. Use unsigned
2940 // comparison to get negative check for free. 2940 // comparison to get negative check for free.
2941 __ bind(&adaptor); 2941 __ bind(&adaptor);
2942 __ mov(ecx, Operand(ebx, ArgumentsAdaptorFrameConstants::kLengthOffset)); 2942 __ mov(ecx, Operand(ebx, ArgumentsAdaptorFrameConstants::kLengthOffset));
2943 __ cmp(edx, Operand(ecx)); 2943 __ cmp(edx, ecx);
2944 __ j(above_equal, &slow, Label::kNear); 2944 __ j(above_equal, &slow, Label::kNear);
2945 2945
2946 // Read the argument from the stack and return it. 2946 // Read the argument from the stack and return it.
2947 STATIC_ASSERT(kSmiTagSize == 1); 2947 STATIC_ASSERT(kSmiTagSize == 1);
2948 STATIC_ASSERT(kSmiTag == 0); // Shifting code depends on these. 2948 STATIC_ASSERT(kSmiTag == 0); // Shifting code depends on these.
2949 __ lea(ebx, Operand(ebx, ecx, times_2, 0)); 2949 __ lea(ebx, Operand(ebx, ecx, times_2, 0));
2950 __ neg(edx); 2950 __ neg(edx);
2951 __ mov(eax, Operand(ebx, edx, times_2, kDisplacement)); 2951 __ mov(eax, Operand(ebx, edx, times_2, kDisplacement));
2952 __ ret(0); 2952 __ ret(0);
2953 2953
(...skipping 10 matching lines...) Expand all
2964 void ArgumentsAccessStub::GenerateNewNonStrictSlow(MacroAssembler* masm) { 2964 void ArgumentsAccessStub::GenerateNewNonStrictSlow(MacroAssembler* masm) {
2965 // esp[0] : return address 2965 // esp[0] : return address
2966 // esp[4] : number of parameters 2966 // esp[4] : number of parameters
2967 // esp[8] : receiver displacement 2967 // esp[8] : receiver displacement
2968 // esp[12] : function 2968 // esp[12] : function
2969 2969
2970 // Check if the calling frame is an arguments adaptor frame. 2970 // Check if the calling frame is an arguments adaptor frame.
2971 Label runtime; 2971 Label runtime;
2972 __ mov(edx, Operand(ebp, StandardFrameConstants::kCallerFPOffset)); 2972 __ mov(edx, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
2973 __ mov(ecx, Operand(edx, StandardFrameConstants::kContextOffset)); 2973 __ mov(ecx, Operand(edx, StandardFrameConstants::kContextOffset));
2974 __ cmp(Operand(ecx), Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); 2974 __ cmp(ecx, Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
2975 __ j(not_equal, &runtime, Label::kNear); 2975 __ j(not_equal, &runtime, Label::kNear);
2976 2976
2977 // Patch the arguments.length and the parameters pointer. 2977 // Patch the arguments.length and the parameters pointer.
2978 __ mov(ecx, Operand(edx, ArgumentsAdaptorFrameConstants::kLengthOffset)); 2978 __ mov(ecx, Operand(edx, ArgumentsAdaptorFrameConstants::kLengthOffset));
2979 __ mov(Operand(esp, 1 * kPointerSize), ecx); 2979 __ mov(Operand(esp, 1 * kPointerSize), ecx);
2980 __ lea(edx, Operand(edx, ecx, times_2, 2980 __ lea(edx, Operand(edx, ecx, times_2,
2981 StandardFrameConstants::kCallerSPOffset)); 2981 StandardFrameConstants::kCallerSPOffset));
2982 __ mov(Operand(esp, 2 * kPointerSize), edx); 2982 __ mov(Operand(esp, 2 * kPointerSize), edx);
2983 2983
2984 __ bind(&runtime); 2984 __ bind(&runtime);
(...skipping 10 matching lines...) Expand all
2995 // ebx = parameter count (tagged) 2995 // ebx = parameter count (tagged)
2996 __ mov(ebx, Operand(esp, 1 * kPointerSize)); 2996 __ mov(ebx, Operand(esp, 1 * kPointerSize));
2997 2997
2998 // Check if the calling frame is an arguments adaptor frame. 2998 // Check if the calling frame is an arguments adaptor frame.
2999 // TODO(rossberg): Factor out some of the bits that are shared with the other 2999 // TODO(rossberg): Factor out some of the bits that are shared with the other
3000 // Generate* functions. 3000 // Generate* functions.
3001 Label runtime; 3001 Label runtime;
3002 Label adaptor_frame, try_allocate; 3002 Label adaptor_frame, try_allocate;
3003 __ mov(edx, Operand(ebp, StandardFrameConstants::kCallerFPOffset)); 3003 __ mov(edx, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
3004 __ mov(ecx, Operand(edx, StandardFrameConstants::kContextOffset)); 3004 __ mov(ecx, Operand(edx, StandardFrameConstants::kContextOffset));
3005 __ cmp(Operand(ecx), Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); 3005 __ cmp(ecx, Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
3006 __ j(equal, &adaptor_frame, Label::kNear); 3006 __ j(equal, &adaptor_frame, Label::kNear);
3007 3007
3008 // No adaptor, parameter count = argument count. 3008 // No adaptor, parameter count = argument count.
3009 __ mov(ecx, ebx); 3009 __ mov(ecx, ebx);
3010 __ jmp(&try_allocate, Label::kNear); 3010 __ jmp(&try_allocate, Label::kNear);
3011 3011
3012 // We have an adaptor frame. Patch the parameters pointer. 3012 // We have an adaptor frame. Patch the parameters pointer.
3013 __ bind(&adaptor_frame); 3013 __ bind(&adaptor_frame);
3014 __ mov(ecx, Operand(edx, ArgumentsAdaptorFrameConstants::kLengthOffset)); 3014 __ mov(ecx, Operand(edx, ArgumentsAdaptorFrameConstants::kLengthOffset));
3015 __ lea(edx, Operand(edx, ecx, times_2, 3015 __ lea(edx, Operand(edx, ecx, times_2,
3016 StandardFrameConstants::kCallerSPOffset)); 3016 StandardFrameConstants::kCallerSPOffset));
3017 __ mov(Operand(esp, 2 * kPointerSize), edx); 3017 __ mov(Operand(esp, 2 * kPointerSize), edx);
3018 3018
3019 // ebx = parameter count (tagged) 3019 // ebx = parameter count (tagged)
3020 // ecx = argument count (tagged) 3020 // ecx = argument count (tagged)
3021 // esp[4] = parameter count (tagged) 3021 // esp[4] = parameter count (tagged)
3022 // esp[8] = address of receiver argument 3022 // esp[8] = address of receiver argument
3023 // Compute the mapped parameter count = min(ebx, ecx) in ebx. 3023 // Compute the mapped parameter count = min(ebx, ecx) in ebx.
3024 __ cmp(ebx, Operand(ecx)); 3024 __ cmp(ebx, ecx);
3025 __ j(less_equal, &try_allocate, Label::kNear); 3025 __ j(less_equal, &try_allocate, Label::kNear);
3026 __ mov(ebx, ecx); 3026 __ mov(ebx, ecx);
3027 3027
3028 __ bind(&try_allocate); 3028 __ bind(&try_allocate);
3029 3029
3030 // Save mapped parameter count. 3030 // Save mapped parameter count.
3031 __ push(ebx); 3031 __ push(ebx);
3032 3032
3033 // Compute the sizes of backing store, parameter map, and arguments object. 3033 // Compute the sizes of backing store, parameter map, and arguments object.
3034 // 1. Parameter map, has 2 extra words containing context and backing store. 3034 // 1. Parameter map, has 2 extra words containing context and backing store.
3035 const int kParameterMapHeaderSize = 3035 const int kParameterMapHeaderSize =
3036 FixedArray::kHeaderSize + 2 * kPointerSize; 3036 FixedArray::kHeaderSize + 2 * kPointerSize;
3037 Label no_parameter_map; 3037 Label no_parameter_map;
3038 __ test(ebx, Operand(ebx)); 3038 __ test(ebx, ebx);
3039 __ j(zero, &no_parameter_map, Label::kNear); 3039 __ j(zero, &no_parameter_map, Label::kNear);
3040 __ lea(ebx, Operand(ebx, times_2, kParameterMapHeaderSize)); 3040 __ lea(ebx, Operand(ebx, times_2, kParameterMapHeaderSize));
3041 __ bind(&no_parameter_map); 3041 __ bind(&no_parameter_map);
3042 3042
3043 // 2. Backing store. 3043 // 2. Backing store.
3044 __ lea(ebx, Operand(ebx, ecx, times_2, FixedArray::kHeaderSize)); 3044 __ lea(ebx, Operand(ebx, ecx, times_2, FixedArray::kHeaderSize));
3045 3045
3046 // 3. Arguments object. 3046 // 3. Arguments object.
3047 __ add(Operand(ebx), Immediate(Heap::kArgumentsObjectSize)); 3047 __ add(ebx, Immediate(Heap::kArgumentsObjectSize));
3048 3048
3049 // Do the allocation of all three objects in one go. 3049 // Do the allocation of all three objects in one go.
3050 __ AllocateInNewSpace(ebx, eax, edx, edi, &runtime, TAG_OBJECT); 3050 __ AllocateInNewSpace(ebx, eax, edx, edi, &runtime, TAG_OBJECT);
3051 3051
3052 // eax = address of new object(s) (tagged) 3052 // eax = address of new object(s) (tagged)
3053 // ecx = argument count (tagged) 3053 // ecx = argument count (tagged)
3054 // esp[0] = mapped parameter count (tagged) 3054 // esp[0] = mapped parameter count (tagged)
3055 // esp[8] = parameter count (tagged) 3055 // esp[8] = parameter count (tagged)
3056 // esp[12] = address of receiver argument 3056 // esp[12] = address of receiver argument
3057 // Get the arguments boilerplate from the current (global) context into edi. 3057 // Get the arguments boilerplate from the current (global) context into edi.
3058 Label has_mapped_parameters, copy; 3058 Label has_mapped_parameters, copy;
3059 __ mov(edi, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX))); 3059 __ mov(edi, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX)));
3060 __ mov(edi, FieldOperand(edi, GlobalObject::kGlobalContextOffset)); 3060 __ mov(edi, FieldOperand(edi, GlobalObject::kGlobalContextOffset));
3061 __ mov(ebx, Operand(esp, 0 * kPointerSize)); 3061 __ mov(ebx, Operand(esp, 0 * kPointerSize));
3062 __ test(ebx, Operand(ebx)); 3062 __ test(ebx, ebx);
3063 __ j(not_zero, &has_mapped_parameters, Label::kNear); 3063 __ j(not_zero, &has_mapped_parameters, Label::kNear);
3064 __ mov(edi, Operand(edi, 3064 __ mov(edi, Operand(edi,
3065 Context::SlotOffset(Context::ARGUMENTS_BOILERPLATE_INDEX))); 3065 Context::SlotOffset(Context::ARGUMENTS_BOILERPLATE_INDEX)));
3066 __ jmp(&copy, Label::kNear); 3066 __ jmp(&copy, Label::kNear);
3067 3067
3068 __ bind(&has_mapped_parameters); 3068 __ bind(&has_mapped_parameters);
3069 __ mov(edi, Operand(edi, 3069 __ mov(edi, Operand(edi,
3070 Context::SlotOffset(Context::ALIASED_ARGUMENTS_BOILERPLATE_INDEX))); 3070 Context::SlotOffset(Context::ALIASED_ARGUMENTS_BOILERPLATE_INDEX)));
3071 __ bind(&copy); 3071 __ bind(&copy);
3072 3072
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
3107 // ecx = argument count (tagged) 3107 // ecx = argument count (tagged)
3108 // edi = address of parameter map or backing store (tagged) 3108 // edi = address of parameter map or backing store (tagged)
3109 // esp[0] = mapped parameter count (tagged) 3109 // esp[0] = mapped parameter count (tagged)
3110 // esp[8] = parameter count (tagged) 3110 // esp[8] = parameter count (tagged)
3111 // esp[12] = address of receiver argument 3111 // esp[12] = address of receiver argument
3112 // Free a register. 3112 // Free a register.
3113 __ push(eax); 3113 __ push(eax);
3114 3114
3115 // Initialize parameter map. If there are no mapped arguments, we're done. 3115 // Initialize parameter map. If there are no mapped arguments, we're done.
3116 Label skip_parameter_map; 3116 Label skip_parameter_map;
3117 __ test(ebx, Operand(ebx)); 3117 __ test(ebx, ebx);
3118 __ j(zero, &skip_parameter_map); 3118 __ j(zero, &skip_parameter_map);
3119 3119
3120 __ mov(FieldOperand(edi, FixedArray::kMapOffset), 3120 __ mov(FieldOperand(edi, FixedArray::kMapOffset),
3121 Immediate(FACTORY->non_strict_arguments_elements_map())); 3121 Immediate(FACTORY->non_strict_arguments_elements_map()));
3122 __ lea(eax, Operand(ebx, reinterpret_cast<intptr_t>(Smi::FromInt(2)))); 3122 __ lea(eax, Operand(ebx, reinterpret_cast<intptr_t>(Smi::FromInt(2))));
3123 __ mov(FieldOperand(edi, FixedArray::kLengthOffset), eax); 3123 __ mov(FieldOperand(edi, FixedArray::kLengthOffset), eax);
3124 __ mov(FieldOperand(edi, FixedArray::kHeaderSize + 0 * kPointerSize), esi); 3124 __ mov(FieldOperand(edi, FixedArray::kHeaderSize + 0 * kPointerSize), esi);
3125 __ lea(eax, Operand(edi, ebx, times_2, kParameterMapHeaderSize)); 3125 __ lea(eax, Operand(edi, ebx, times_2, kParameterMapHeaderSize));
3126 __ mov(FieldOperand(edi, FixedArray::kHeaderSize + 1 * kPointerSize), eax); 3126 __ mov(FieldOperand(edi, FixedArray::kHeaderSize + 1 * kPointerSize), eax);
3127 3127
3128 // Copy the parameter slots and the holes in the arguments. 3128 // Copy the parameter slots and the holes in the arguments.
3129 // We need to fill in mapped_parameter_count slots. They index the context, 3129 // We need to fill in mapped_parameter_count slots. They index the context,
3130 // where parameters are stored in reverse order, at 3130 // where parameters are stored in reverse order, at
3131 // MIN_CONTEXT_SLOTS .. MIN_CONTEXT_SLOTS+parameter_count-1 3131 // MIN_CONTEXT_SLOTS .. MIN_CONTEXT_SLOTS+parameter_count-1
3132 // The mapped parameter thus need to get indices 3132 // The mapped parameter thus need to get indices
3133 // MIN_CONTEXT_SLOTS+parameter_count-1 .. 3133 // MIN_CONTEXT_SLOTS+parameter_count-1 ..
3134 // MIN_CONTEXT_SLOTS+parameter_count-mapped_parameter_count 3134 // MIN_CONTEXT_SLOTS+parameter_count-mapped_parameter_count
3135 // We loop from right to left. 3135 // We loop from right to left.
3136 Label parameters_loop, parameters_test; 3136 Label parameters_loop, parameters_test;
3137 __ push(ecx); 3137 __ push(ecx);
3138 __ mov(eax, Operand(esp, 2 * kPointerSize)); 3138 __ mov(eax, Operand(esp, 2 * kPointerSize));
3139 __ mov(ebx, Immediate(Smi::FromInt(Context::MIN_CONTEXT_SLOTS))); 3139 __ mov(ebx, Immediate(Smi::FromInt(Context::MIN_CONTEXT_SLOTS)));
3140 __ add(ebx, Operand(esp, 4 * kPointerSize)); 3140 __ add(ebx, Operand(esp, 4 * kPointerSize));
3141 __ sub(ebx, Operand(eax)); 3141 __ sub(ebx, eax);
3142 __ mov(ecx, FACTORY->the_hole_value()); 3142 __ mov(ecx, FACTORY->the_hole_value());
3143 __ mov(edx, edi); 3143 __ mov(edx, edi);
3144 __ lea(edi, Operand(edi, eax, times_2, kParameterMapHeaderSize)); 3144 __ lea(edi, Operand(edi, eax, times_2, kParameterMapHeaderSize));
3145 // eax = loop variable (tagged) 3145 // eax = loop variable (tagged)
3146 // ebx = mapping index (tagged) 3146 // ebx = mapping index (tagged)
3147 // ecx = the hole value 3147 // ecx = the hole value
3148 // edx = address of parameter map (tagged) 3148 // edx = address of parameter map (tagged)
3149 // edi = address of backing store (tagged) 3149 // edi = address of backing store (tagged)
3150 // esp[0] = argument count (tagged) 3150 // esp[0] = argument count (tagged)
3151 // esp[4] = address of new object (tagged) 3151 // esp[4] = address of new object (tagged)
3152 // esp[8] = mapped parameter count (tagged) 3152 // esp[8] = mapped parameter count (tagged)
3153 // esp[16] = parameter count (tagged) 3153 // esp[16] = parameter count (tagged)
3154 // esp[20] = address of receiver argument 3154 // esp[20] = address of receiver argument
3155 __ jmp(&parameters_test, Label::kNear); 3155 __ jmp(&parameters_test, Label::kNear);
3156 3156
3157 __ bind(&parameters_loop); 3157 __ bind(&parameters_loop);
3158 __ sub(Operand(eax), Immediate(Smi::FromInt(1))); 3158 __ sub(eax, Immediate(Smi::FromInt(1)));
3159 __ mov(FieldOperand(edx, eax, times_2, kParameterMapHeaderSize), ebx); 3159 __ mov(FieldOperand(edx, eax, times_2, kParameterMapHeaderSize), ebx);
3160 __ mov(FieldOperand(edi, eax, times_2, FixedArray::kHeaderSize), ecx); 3160 __ mov(FieldOperand(edi, eax, times_2, FixedArray::kHeaderSize), ecx);
3161 __ add(Operand(ebx), Immediate(Smi::FromInt(1))); 3161 __ add(ebx, Immediate(Smi::FromInt(1)));
3162 __ bind(&parameters_test); 3162 __ bind(&parameters_test);
3163 __ test(eax, Operand(eax)); 3163 __ test(eax, eax);
3164 __ j(not_zero, &parameters_loop, Label::kNear); 3164 __ j(not_zero, &parameters_loop, Label::kNear);
3165 __ pop(ecx); 3165 __ pop(ecx);
3166 3166
3167 __ bind(&skip_parameter_map); 3167 __ bind(&skip_parameter_map);
3168 3168
3169 // ecx = argument count (tagged) 3169 // ecx = argument count (tagged)
3170 // edi = address of backing store (tagged) 3170 // edi = address of backing store (tagged)
3171 // esp[0] = address of new object (tagged) 3171 // esp[0] = address of new object (tagged)
3172 // esp[4] = mapped parameter count (tagged) 3172 // esp[4] = mapped parameter count (tagged)
3173 // esp[12] = parameter count (tagged) 3173 // esp[12] = parameter count (tagged)
3174 // esp[16] = address of receiver argument 3174 // esp[16] = address of receiver argument
3175 // Copy arguments header and remaining slots (if there are any). 3175 // Copy arguments header and remaining slots (if there are any).
3176 __ mov(FieldOperand(edi, FixedArray::kMapOffset), 3176 __ mov(FieldOperand(edi, FixedArray::kMapOffset),
3177 Immediate(FACTORY->fixed_array_map())); 3177 Immediate(FACTORY->fixed_array_map()));
3178 __ mov(FieldOperand(edi, FixedArray::kLengthOffset), ecx); 3178 __ mov(FieldOperand(edi, FixedArray::kLengthOffset), ecx);
3179 3179
3180 Label arguments_loop, arguments_test; 3180 Label arguments_loop, arguments_test;
3181 __ mov(ebx, Operand(esp, 1 * kPointerSize)); 3181 __ mov(ebx, Operand(esp, 1 * kPointerSize));
3182 __ mov(edx, Operand(esp, 4 * kPointerSize)); 3182 __ mov(edx, Operand(esp, 4 * kPointerSize));
3183 __ sub(Operand(edx), ebx); // Is there a smarter way to do negative scaling? 3183 __ sub(edx, ebx); // Is there a smarter way to do negative scaling?
3184 __ sub(Operand(edx), ebx); 3184 __ sub(edx, ebx);
3185 __ jmp(&arguments_test, Label::kNear); 3185 __ jmp(&arguments_test, Label::kNear);
3186 3186
3187 __ bind(&arguments_loop); 3187 __ bind(&arguments_loop);
3188 __ sub(Operand(edx), Immediate(kPointerSize)); 3188 __ sub(edx, Immediate(kPointerSize));
3189 __ mov(eax, Operand(edx, 0)); 3189 __ mov(eax, Operand(edx, 0));
3190 __ mov(FieldOperand(edi, ebx, times_2, FixedArray::kHeaderSize), eax); 3190 __ mov(FieldOperand(edi, ebx, times_2, FixedArray::kHeaderSize), eax);
3191 __ add(Operand(ebx), Immediate(Smi::FromInt(1))); 3191 __ add(ebx, Immediate(Smi::FromInt(1)));
3192 3192
3193 __ bind(&arguments_test); 3193 __ bind(&arguments_test);
3194 __ cmp(ebx, Operand(ecx)); 3194 __ cmp(ebx, ecx);
3195 __ j(less, &arguments_loop, Label::kNear); 3195 __ j(less, &arguments_loop, Label::kNear);
3196 3196
3197 // Restore. 3197 // Restore.
3198 __ pop(eax); // Address of arguments object. 3198 __ pop(eax); // Address of arguments object.
3199 __ pop(ebx); // Parameter count. 3199 __ pop(ebx); // Parameter count.
3200 3200
3201 // Return and remove the on-stack parameters. 3201 // Return and remove the on-stack parameters.
3202 __ ret(3 * kPointerSize); 3202 __ ret(3 * kPointerSize);
3203 3203
3204 // Do the runtime call to allocate the arguments object. 3204 // Do the runtime call to allocate the arguments object.
3205 __ bind(&runtime); 3205 __ bind(&runtime);
3206 __ pop(eax); // Remove saved parameter count. 3206 __ pop(eax); // Remove saved parameter count.
3207 __ mov(Operand(esp, 1 * kPointerSize), ecx); // Patch argument count. 3207 __ mov(Operand(esp, 1 * kPointerSize), ecx); // Patch argument count.
3208 __ TailCallRuntime(Runtime::kNewStrictArgumentsFast, 3, 1); 3208 __ TailCallRuntime(Runtime::kNewStrictArgumentsFast, 3, 1);
3209 } 3209 }
3210 3210
3211 3211
3212 void ArgumentsAccessStub::GenerateNewStrict(MacroAssembler* masm) { 3212 void ArgumentsAccessStub::GenerateNewStrict(MacroAssembler* masm) {
3213 // esp[0] : return address 3213 // esp[0] : return address
3214 // esp[4] : number of parameters 3214 // esp[4] : number of parameters
3215 // esp[8] : receiver displacement 3215 // esp[8] : receiver displacement
3216 // esp[12] : function 3216 // esp[12] : function
3217 3217
3218 // Check if the calling frame is an arguments adaptor frame. 3218 // Check if the calling frame is an arguments adaptor frame.
3219 Label adaptor_frame, try_allocate, runtime; 3219 Label adaptor_frame, try_allocate, runtime;
3220 __ mov(edx, Operand(ebp, StandardFrameConstants::kCallerFPOffset)); 3220 __ mov(edx, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
3221 __ mov(ecx, Operand(edx, StandardFrameConstants::kContextOffset)); 3221 __ mov(ecx, Operand(edx, StandardFrameConstants::kContextOffset));
3222 __ cmp(Operand(ecx), Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); 3222 __ cmp(ecx, Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
3223 __ j(equal, &adaptor_frame, Label::kNear); 3223 __ j(equal, &adaptor_frame, Label::kNear);
3224 3224
3225 // Get the length from the frame. 3225 // Get the length from the frame.
3226 __ mov(ecx, Operand(esp, 1 * kPointerSize)); 3226 __ mov(ecx, Operand(esp, 1 * kPointerSize));
3227 __ jmp(&try_allocate, Label::kNear); 3227 __ jmp(&try_allocate, Label::kNear);
3228 3228
3229 // Patch the arguments.length and the parameters pointer. 3229 // Patch the arguments.length and the parameters pointer.
3230 __ bind(&adaptor_frame); 3230 __ bind(&adaptor_frame);
3231 __ mov(ecx, Operand(edx, ArgumentsAdaptorFrameConstants::kLengthOffset)); 3231 __ mov(ecx, Operand(edx, ArgumentsAdaptorFrameConstants::kLengthOffset));
3232 __ mov(Operand(esp, 1 * kPointerSize), ecx); 3232 __ mov(Operand(esp, 1 * kPointerSize), ecx);
3233 __ lea(edx, Operand(edx, ecx, times_2, 3233 __ lea(edx, Operand(edx, ecx, times_2,
3234 StandardFrameConstants::kCallerSPOffset)); 3234 StandardFrameConstants::kCallerSPOffset));
3235 __ mov(Operand(esp, 2 * kPointerSize), edx); 3235 __ mov(Operand(esp, 2 * kPointerSize), edx);
3236 3236
3237 // Try the new space allocation. Start out with computing the size of 3237 // Try the new space allocation. Start out with computing the size of
3238 // the arguments object and the elements array. 3238 // the arguments object and the elements array.
3239 Label add_arguments_object; 3239 Label add_arguments_object;
3240 __ bind(&try_allocate); 3240 __ bind(&try_allocate);
3241 __ test(ecx, Operand(ecx)); 3241 __ test(ecx, ecx);
3242 __ j(zero, &add_arguments_object, Label::kNear); 3242 __ j(zero, &add_arguments_object, Label::kNear);
3243 __ lea(ecx, Operand(ecx, times_2, FixedArray::kHeaderSize)); 3243 __ lea(ecx, Operand(ecx, times_2, FixedArray::kHeaderSize));
3244 __ bind(&add_arguments_object); 3244 __ bind(&add_arguments_object);
3245 __ add(Operand(ecx), Immediate(Heap::kArgumentsObjectSizeStrict)); 3245 __ add(ecx, Immediate(Heap::kArgumentsObjectSizeStrict));
3246 3246
3247 // Do the allocation of both objects in one go. 3247 // Do the allocation of both objects in one go.
3248 __ AllocateInNewSpace(ecx, eax, edx, ebx, &runtime, TAG_OBJECT); 3248 __ AllocateInNewSpace(ecx, eax, edx, ebx, &runtime, TAG_OBJECT);
3249 3249
3250 // Get the arguments boilerplate from the current (global) context. 3250 // Get the arguments boilerplate from the current (global) context.
3251 __ mov(edi, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX))); 3251 __ mov(edi, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX)));
3252 __ mov(edi, FieldOperand(edi, GlobalObject::kGlobalContextOffset)); 3252 __ mov(edi, FieldOperand(edi, GlobalObject::kGlobalContextOffset));
3253 const int offset = 3253 const int offset =
3254 Context::SlotOffset(Context::STRICT_MODE_ARGUMENTS_BOILERPLATE_INDEX); 3254 Context::SlotOffset(Context::STRICT_MODE_ARGUMENTS_BOILERPLATE_INDEX);
3255 __ mov(edi, Operand(edi, offset)); 3255 __ mov(edi, Operand(edi, offset));
3256 3256
3257 // Copy the JS object part. 3257 // Copy the JS object part.
3258 for (int i = 0; i < JSObject::kHeaderSize; i += kPointerSize) { 3258 for (int i = 0; i < JSObject::kHeaderSize; i += kPointerSize) {
3259 __ mov(ebx, FieldOperand(edi, i)); 3259 __ mov(ebx, FieldOperand(edi, i));
3260 __ mov(FieldOperand(eax, i), ebx); 3260 __ mov(FieldOperand(eax, i), ebx);
3261 } 3261 }
3262 3262
3263 // Get the length (smi tagged) and set that as an in-object property too. 3263 // Get the length (smi tagged) and set that as an in-object property too.
3264 STATIC_ASSERT(Heap::kArgumentsLengthIndex == 0); 3264 STATIC_ASSERT(Heap::kArgumentsLengthIndex == 0);
3265 __ mov(ecx, Operand(esp, 1 * kPointerSize)); 3265 __ mov(ecx, Operand(esp, 1 * kPointerSize));
3266 __ mov(FieldOperand(eax, JSObject::kHeaderSize + 3266 __ mov(FieldOperand(eax, JSObject::kHeaderSize +
3267 Heap::kArgumentsLengthIndex * kPointerSize), 3267 Heap::kArgumentsLengthIndex * kPointerSize),
3268 ecx); 3268 ecx);
3269 3269
3270 // If there are no actual arguments, we're done. 3270 // If there are no actual arguments, we're done.
3271 Label done; 3271 Label done;
3272 __ test(ecx, Operand(ecx)); 3272 __ test(ecx, ecx);
3273 __ j(zero, &done, Label::kNear); 3273 __ j(zero, &done, Label::kNear);
3274 3274
3275 // Get the parameters pointer from the stack. 3275 // Get the parameters pointer from the stack.
3276 __ mov(edx, Operand(esp, 2 * kPointerSize)); 3276 __ mov(edx, Operand(esp, 2 * kPointerSize));
3277 3277
3278 // Setup the elements pointer in the allocated arguments object and 3278 // Setup the elements pointer in the allocated arguments object and
3279 // initialize the header in the elements fixed array. 3279 // initialize the header in the elements fixed array.
3280 __ lea(edi, Operand(eax, Heap::kArgumentsObjectSizeStrict)); 3280 __ lea(edi, Operand(eax, Heap::kArgumentsObjectSizeStrict));
3281 __ mov(FieldOperand(eax, JSObject::kElementsOffset), edi); 3281 __ mov(FieldOperand(eax, JSObject::kElementsOffset), edi);
3282 __ mov(FieldOperand(edi, FixedArray::kMapOffset), 3282 __ mov(FieldOperand(edi, FixedArray::kMapOffset),
3283 Immediate(FACTORY->fixed_array_map())); 3283 Immediate(FACTORY->fixed_array_map()));
3284 3284
3285 __ mov(FieldOperand(edi, FixedArray::kLengthOffset), ecx); 3285 __ mov(FieldOperand(edi, FixedArray::kLengthOffset), ecx);
3286 // Untag the length for the loop below. 3286 // Untag the length for the loop below.
3287 __ SmiUntag(ecx); 3287 __ SmiUntag(ecx);
3288 3288
3289 // Copy the fixed array slots. 3289 // Copy the fixed array slots.
3290 Label loop; 3290 Label loop;
3291 __ bind(&loop); 3291 __ bind(&loop);
3292 __ mov(ebx, Operand(edx, -1 * kPointerSize)); // Skip receiver. 3292 __ mov(ebx, Operand(edx, -1 * kPointerSize)); // Skip receiver.
3293 __ mov(FieldOperand(edi, FixedArray::kHeaderSize), ebx); 3293 __ mov(FieldOperand(edi, FixedArray::kHeaderSize), ebx);
3294 __ add(Operand(edi), Immediate(kPointerSize)); 3294 __ add(edi, Immediate(kPointerSize));
3295 __ sub(Operand(edx), Immediate(kPointerSize)); 3295 __ sub(edx, Immediate(kPointerSize));
3296 __ dec(ecx); 3296 __ dec(ecx);
3297 __ j(not_zero, &loop); 3297 __ j(not_zero, &loop);
3298 3298
3299 // Return and remove the on-stack parameters. 3299 // Return and remove the on-stack parameters.
3300 __ bind(&done); 3300 __ bind(&done);
3301 __ ret(3 * kPointerSize); 3301 __ ret(3 * kPointerSize);
3302 3302
3303 // Do the runtime call to allocate the arguments object. 3303 // Do the runtime call to allocate the arguments object.
3304 __ bind(&runtime); 3304 __ bind(&runtime);
3305 __ TailCallRuntime(Runtime::kNewStrictArgumentsFast, 3, 1); 3305 __ TailCallRuntime(Runtime::kNewStrictArgumentsFast, 3, 1);
(...skipping 26 matching lines...) Expand all
3332 3332
3333 Label runtime, invoke_regexp; 3333 Label runtime, invoke_regexp;
3334 3334
3335 // Ensure that a RegExp stack is allocated. 3335 // Ensure that a RegExp stack is allocated.
3336 ExternalReference address_of_regexp_stack_memory_address = 3336 ExternalReference address_of_regexp_stack_memory_address =
3337 ExternalReference::address_of_regexp_stack_memory_address( 3337 ExternalReference::address_of_regexp_stack_memory_address(
3338 masm->isolate()); 3338 masm->isolate());
3339 ExternalReference address_of_regexp_stack_memory_size = 3339 ExternalReference address_of_regexp_stack_memory_size =
3340 ExternalReference::address_of_regexp_stack_memory_size(masm->isolate()); 3340 ExternalReference::address_of_regexp_stack_memory_size(masm->isolate());
3341 __ mov(ebx, Operand::StaticVariable(address_of_regexp_stack_memory_size)); 3341 __ mov(ebx, Operand::StaticVariable(address_of_regexp_stack_memory_size));
3342 __ test(ebx, Operand(ebx)); 3342 __ test(ebx, ebx);
3343 __ j(zero, &runtime); 3343 __ j(zero, &runtime);
3344 3344
3345 // Check that the first argument is a JSRegExp object. 3345 // Check that the first argument is a JSRegExp object.
3346 __ mov(eax, Operand(esp, kJSRegExpOffset)); 3346 __ mov(eax, Operand(esp, kJSRegExpOffset));
3347 STATIC_ASSERT(kSmiTag == 0); 3347 STATIC_ASSERT(kSmiTag == 0);
3348 __ JumpIfSmi(eax, &runtime); 3348 __ JumpIfSmi(eax, &runtime);
3349 __ CmpObjectType(eax, JS_REGEXP_TYPE, ecx); 3349 __ CmpObjectType(eax, JS_REGEXP_TYPE, ecx);
3350 __ j(not_equal, &runtime); 3350 __ j(not_equal, &runtime);
3351 // Check that the RegExp has been compiled (data contains a fixed array). 3351 // Check that the RegExp has been compiled (data contains a fixed array).
3352 __ mov(ecx, FieldOperand(eax, JSRegExp::kDataOffset)); 3352 __ mov(ecx, FieldOperand(eax, JSRegExp::kDataOffset));
3353 if (FLAG_debug_code) { 3353 if (FLAG_debug_code) {
3354 __ test(ecx, Immediate(kSmiTagMask)); 3354 __ test(ecx, Immediate(kSmiTagMask));
3355 __ Check(not_zero, "Unexpected type for RegExp data, FixedArray expected"); 3355 __ Check(not_zero, "Unexpected type for RegExp data, FixedArray expected");
3356 __ CmpObjectType(ecx, FIXED_ARRAY_TYPE, ebx); 3356 __ CmpObjectType(ecx, FIXED_ARRAY_TYPE, ebx);
3357 __ Check(equal, "Unexpected type for RegExp data, FixedArray expected"); 3357 __ Check(equal, "Unexpected type for RegExp data, FixedArray expected");
3358 } 3358 }
3359 3359
3360 // ecx: RegExp data (FixedArray) 3360 // ecx: RegExp data (FixedArray)
3361 // Check the type of the RegExp. Only continue if type is JSRegExp::IRREGEXP. 3361 // Check the type of the RegExp. Only continue if type is JSRegExp::IRREGEXP.
3362 __ mov(ebx, FieldOperand(ecx, JSRegExp::kDataTagOffset)); 3362 __ mov(ebx, FieldOperand(ecx, JSRegExp::kDataTagOffset));
3363 __ cmp(Operand(ebx), Immediate(Smi::FromInt(JSRegExp::IRREGEXP))); 3363 __ cmp(ebx, Immediate(Smi::FromInt(JSRegExp::IRREGEXP)));
3364 __ j(not_equal, &runtime); 3364 __ j(not_equal, &runtime);
3365 3365
3366 // ecx: RegExp data (FixedArray) 3366 // ecx: RegExp data (FixedArray)
3367 // Check that the number of captures fit in the static offsets vector buffer. 3367 // Check that the number of captures fit in the static offsets vector buffer.
3368 __ mov(edx, FieldOperand(ecx, JSRegExp::kIrregexpCaptureCountOffset)); 3368 __ mov(edx, FieldOperand(ecx, JSRegExp::kIrregexpCaptureCountOffset));
3369 // Calculate number of capture registers (number_of_captures + 1) * 2. This 3369 // Calculate number of capture registers (number_of_captures + 1) * 2. This
3370 // uses the asumption that smis are 2 * their untagged value. 3370 // uses the asumption that smis are 2 * their untagged value.
3371 STATIC_ASSERT(kSmiTag == 0); 3371 STATIC_ASSERT(kSmiTag == 0);
3372 STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1); 3372 STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1);
3373 __ add(Operand(edx), Immediate(2)); // edx was a smi. 3373 __ add(edx, Immediate(2)); // edx was a smi.
3374 // Check that the static offsets vector buffer is large enough. 3374 // Check that the static offsets vector buffer is large enough.
3375 __ cmp(edx, OffsetsVector::kStaticOffsetsVectorSize); 3375 __ cmp(edx, OffsetsVector::kStaticOffsetsVectorSize);
3376 __ j(above, &runtime); 3376 __ j(above, &runtime);
3377 3377
3378 // ecx: RegExp data (FixedArray) 3378 // ecx: RegExp data (FixedArray)
3379 // edx: Number of capture registers 3379 // edx: Number of capture registers
3380 // Check that the second argument is a string. 3380 // Check that the second argument is a string.
3381 __ mov(eax, Operand(esp, kSubjectOffset)); 3381 __ mov(eax, Operand(esp, kSubjectOffset));
3382 __ JumpIfSmi(eax, &runtime); 3382 __ JumpIfSmi(eax, &runtime);
3383 Condition is_string = masm->IsObjectStringType(eax, ebx, ebx); 3383 Condition is_string = masm->IsObjectStringType(eax, ebx, ebx);
3384 __ j(NegateCondition(is_string), &runtime); 3384 __ j(NegateCondition(is_string), &runtime);
3385 // Get the length of the string to ebx. 3385 // Get the length of the string to ebx.
3386 __ mov(ebx, FieldOperand(eax, String::kLengthOffset)); 3386 __ mov(ebx, FieldOperand(eax, String::kLengthOffset));
3387 3387
3388 // ebx: Length of subject string as a smi 3388 // ebx: Length of subject string as a smi
3389 // ecx: RegExp data (FixedArray) 3389 // ecx: RegExp data (FixedArray)
3390 // edx: Number of capture registers 3390 // edx: Number of capture registers
3391 // Check that the third argument is a positive smi less than the subject 3391 // Check that the third argument is a positive smi less than the subject
3392 // string length. A negative value will be greater (unsigned comparison). 3392 // string length. A negative value will be greater (unsigned comparison).
3393 __ mov(eax, Operand(esp, kPreviousIndexOffset)); 3393 __ mov(eax, Operand(esp, kPreviousIndexOffset));
3394 __ JumpIfNotSmi(eax, &runtime); 3394 __ JumpIfNotSmi(eax, &runtime);
3395 __ cmp(eax, Operand(ebx)); 3395 __ cmp(eax, ebx);
3396 __ j(above_equal, &runtime); 3396 __ j(above_equal, &runtime);
3397 3397
3398 // ecx: RegExp data (FixedArray) 3398 // ecx: RegExp data (FixedArray)
3399 // edx: Number of capture registers 3399 // edx: Number of capture registers
3400 // Check that the fourth object is a JSArray object. 3400 // Check that the fourth object is a JSArray object.
3401 __ mov(eax, Operand(esp, kLastMatchInfoOffset)); 3401 __ mov(eax, Operand(esp, kLastMatchInfoOffset));
3402 __ JumpIfSmi(eax, &runtime); 3402 __ JumpIfSmi(eax, &runtime);
3403 __ CmpObjectType(eax, JS_ARRAY_TYPE, ebx); 3403 __ CmpObjectType(eax, JS_ARRAY_TYPE, ebx);
3404 __ j(not_equal, &runtime); 3404 __ j(not_equal, &runtime);
3405 // Check that the JSArray is in fast case. 3405 // Check that the JSArray is in fast case.
3406 __ mov(ebx, FieldOperand(eax, JSArray::kElementsOffset)); 3406 __ mov(ebx, FieldOperand(eax, JSArray::kElementsOffset));
3407 __ mov(eax, FieldOperand(ebx, HeapObject::kMapOffset)); 3407 __ mov(eax, FieldOperand(ebx, HeapObject::kMapOffset));
3408 Factory* factory = masm->isolate()->factory(); 3408 Factory* factory = masm->isolate()->factory();
3409 __ cmp(eax, factory->fixed_array_map()); 3409 __ cmp(eax, factory->fixed_array_map());
3410 __ j(not_equal, &runtime); 3410 __ j(not_equal, &runtime);
3411 // Check that the last match info has space for the capture registers and the 3411 // Check that the last match info has space for the capture registers and the
3412 // additional information. 3412 // additional information.
3413 __ mov(eax, FieldOperand(ebx, FixedArray::kLengthOffset)); 3413 __ mov(eax, FieldOperand(ebx, FixedArray::kLengthOffset));
3414 __ SmiUntag(eax); 3414 __ SmiUntag(eax);
3415 __ add(Operand(edx), Immediate(RegExpImpl::kLastMatchOverhead)); 3415 __ add(edx, Immediate(RegExpImpl::kLastMatchOverhead));
3416 __ cmp(edx, Operand(eax)); 3416 __ cmp(edx, eax);
3417 __ j(greater, &runtime); 3417 __ j(greater, &runtime);
3418 3418
3419 // Reset offset for possibly sliced string. 3419 // Reset offset for possibly sliced string.
3420 __ Set(edi, Immediate(0)); 3420 __ Set(edi, Immediate(0));
3421 // ecx: RegExp data (FixedArray) 3421 // ecx: RegExp data (FixedArray)
3422 // Check the representation and encoding of the subject string. 3422 // Check the representation and encoding of the subject string.
3423 Label seq_ascii_string, seq_two_byte_string, check_code; 3423 Label seq_ascii_string, seq_two_byte_string, check_code;
3424 __ mov(eax, Operand(esp, kSubjectOffset)); 3424 __ mov(eax, Operand(esp, kSubjectOffset));
3425 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); 3425 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
3426 __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset)); 3426 __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset));
3427 // First check for flat two byte string. 3427 // First check for flat two byte string.
3428 __ and_(ebx, 3428 __ and_(ebx,
3429 kIsNotStringMask | kStringRepresentationMask | kStringEncodingMask); 3429 kIsNotStringMask | kStringRepresentationMask | kStringEncodingMask);
3430 STATIC_ASSERT((kStringTag | kSeqStringTag | kTwoByteStringTag) == 0); 3430 STATIC_ASSERT((kStringTag | kSeqStringTag | kTwoByteStringTag) == 0);
3431 __ j(zero, &seq_two_byte_string, Label::kNear); 3431 __ j(zero, &seq_two_byte_string, Label::kNear);
3432 // Any other flat string must be a flat ascii string. 3432 // Any other flat string must be a flat ascii string.
3433 __ and_(Operand(ebx), 3433 __ and_(ebx, Immediate(kIsNotStringMask | kStringRepresentationMask));
3434 Immediate(kIsNotStringMask | kStringRepresentationMask));
3435 __ j(zero, &seq_ascii_string, Label::kNear); 3434 __ j(zero, &seq_ascii_string, Label::kNear);
3436 3435
3437 // Check for flat cons string or sliced string. 3436 // Check for flat cons string or sliced string.
3438 // A flat cons string is a cons string where the second part is the empty 3437 // A flat cons string is a cons string where the second part is the empty
3439 // string. In that case the subject string is just the first part of the cons 3438 // string. In that case the subject string is just the first part of the cons
3440 // string. Also in this case the first part of the cons string is known to be 3439 // string. Also in this case the first part of the cons string is known to be
3441 // a sequential string or an external string. 3440 // a sequential string or an external string.
3442 // In the case of a sliced string its offset has to be taken into account. 3441 // In the case of a sliced string its offset has to be taken into account.
3443 Label cons_string, check_encoding; 3442 Label cons_string, check_encoding;
3444 STATIC_ASSERT(kConsStringTag < kExternalStringTag); 3443 STATIC_ASSERT(kConsStringTag < kExternalStringTag);
3445 STATIC_ASSERT(kSlicedStringTag > kExternalStringTag); 3444 STATIC_ASSERT(kSlicedStringTag > kExternalStringTag);
3446 __ cmp(Operand(ebx), Immediate(kExternalStringTag)); 3445 __ cmp(ebx, Immediate(kExternalStringTag));
3447 __ j(less, &cons_string); 3446 __ j(less, &cons_string);
3448 __ j(equal, &runtime); 3447 __ j(equal, &runtime);
3449 3448
3450 // String is sliced. 3449 // String is sliced.
3451 __ mov(edi, FieldOperand(eax, SlicedString::kOffsetOffset)); 3450 __ mov(edi, FieldOperand(eax, SlicedString::kOffsetOffset));
3452 __ mov(eax, FieldOperand(eax, SlicedString::kParentOffset)); 3451 __ mov(eax, FieldOperand(eax, SlicedString::kParentOffset));
3453 // edi: offset of sliced string, smi-tagged. 3452 // edi: offset of sliced string, smi-tagged.
3454 // eax: parent string. 3453 // eax: parent string.
3455 __ jmp(&check_encoding, Label::kNear); 3454 __ jmp(&check_encoding, Label::kNear);
3456 // String is a cons string, check whether it is flat. 3455 // String is a cons string, check whether it is flat.
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after
3542 // esi: original subject string 3541 // esi: original subject string
3543 // eax: underlying subject string 3542 // eax: underlying subject string
3544 // ebx: previous index 3543 // ebx: previous index
3545 // ecx: encoding of subject string (1 if ascii 0 if two_byte); 3544 // ecx: encoding of subject string (1 if ascii 0 if two_byte);
3546 // edx: code 3545 // edx: code
3547 // Argument 4: End of string data 3546 // Argument 4: End of string data
3548 // Argument 3: Start of string data 3547 // Argument 3: Start of string data
3549 // Prepare start and end index of the input. 3548 // Prepare start and end index of the input.
3550 // Load the length from the original sliced string if that is the case. 3549 // Load the length from the original sliced string if that is the case.
3551 __ mov(esi, FieldOperand(esi, String::kLengthOffset)); 3550 __ mov(esi, FieldOperand(esi, String::kLengthOffset));
3552 __ add(esi, Operand(edi)); // Calculate input end wrt offset. 3551 __ add(esi, edi); // Calculate input end wrt offset.
3553 __ SmiUntag(edi); 3552 __ SmiUntag(edi);
3554 __ add(ebx, Operand(edi)); // Calculate input start wrt offset. 3553 __ add(ebx, edi); // Calculate input start wrt offset.
3555 3554
3556 // ebx: start index of the input string 3555 // ebx: start index of the input string
3557 // esi: end index of the input string 3556 // esi: end index of the input string
3558 Label setup_two_byte, setup_rest; 3557 Label setup_two_byte, setup_rest;
3559 __ test(ecx, Operand(ecx)); 3558 __ test(ecx, ecx);
3560 __ j(zero, &setup_two_byte, Label::kNear); 3559 __ j(zero, &setup_two_byte, Label::kNear);
3561 __ SmiUntag(esi); 3560 __ SmiUntag(esi);
3562 __ lea(ecx, FieldOperand(eax, esi, times_1, SeqAsciiString::kHeaderSize)); 3561 __ lea(ecx, FieldOperand(eax, esi, times_1, SeqAsciiString::kHeaderSize));
3563 __ mov(Operand(esp, 3 * kPointerSize), ecx); // Argument 4. 3562 __ mov(Operand(esp, 3 * kPointerSize), ecx); // Argument 4.
3564 __ lea(ecx, FieldOperand(eax, ebx, times_1, SeqAsciiString::kHeaderSize)); 3563 __ lea(ecx, FieldOperand(eax, ebx, times_1, SeqAsciiString::kHeaderSize));
3565 __ mov(Operand(esp, 2 * kPointerSize), ecx); // Argument 3. 3564 __ mov(Operand(esp, 2 * kPointerSize), ecx); // Argument 3.
3566 __ jmp(&setup_rest, Label::kNear); 3565 __ jmp(&setup_rest, Label::kNear);
3567 3566
3568 __ bind(&setup_two_byte); 3567 __ bind(&setup_two_byte);
3569 STATIC_ASSERT(kSmiTag == 0); 3568 STATIC_ASSERT(kSmiTag == 0);
3570 STATIC_ASSERT(kSmiTagSize == 1); // esi is smi (powered by 2). 3569 STATIC_ASSERT(kSmiTagSize == 1); // esi is smi (powered by 2).
3571 __ lea(ecx, FieldOperand(eax, esi, times_1, SeqTwoByteString::kHeaderSize)); 3570 __ lea(ecx, FieldOperand(eax, esi, times_1, SeqTwoByteString::kHeaderSize));
3572 __ mov(Operand(esp, 3 * kPointerSize), ecx); // Argument 4. 3571 __ mov(Operand(esp, 3 * kPointerSize), ecx); // Argument 4.
3573 __ lea(ecx, FieldOperand(eax, ebx, times_2, SeqTwoByteString::kHeaderSize)); 3572 __ lea(ecx, FieldOperand(eax, ebx, times_2, SeqTwoByteString::kHeaderSize));
3574 __ mov(Operand(esp, 2 * kPointerSize), ecx); // Argument 3. 3573 __ mov(Operand(esp, 2 * kPointerSize), ecx); // Argument 3.
3575 3574
3576 __ bind(&setup_rest); 3575 __ bind(&setup_rest);
3577 3576
3578 // Locate the code entry and call it. 3577 // Locate the code entry and call it.
3579 __ add(Operand(edx), Immediate(Code::kHeaderSize - kHeapObjectTag)); 3578 __ add(edx, Immediate(Code::kHeaderSize - kHeapObjectTag));
3580 __ call(Operand(edx)); 3579 __ call(edx);
3581 3580
3582 // Drop arguments and come back to JS mode. 3581 // Drop arguments and come back to JS mode.
3583 __ LeaveApiExitFrame(); 3582 __ LeaveApiExitFrame();
3584 3583
3585 // Check the result. 3584 // Check the result.
3586 Label success; 3585 Label success;
3587 __ cmp(eax, NativeRegExpMacroAssembler::SUCCESS); 3586 __ cmp(eax, NativeRegExpMacroAssembler::SUCCESS);
3588 __ j(equal, &success); 3587 __ j(equal, &success);
3589 Label failure; 3588 Label failure;
3590 __ cmp(eax, NativeRegExpMacroAssembler::FAILURE); 3589 __ cmp(eax, NativeRegExpMacroAssembler::FAILURE);
3591 __ j(equal, &failure); 3590 __ j(equal, &failure);
3592 __ cmp(eax, NativeRegExpMacroAssembler::EXCEPTION); 3591 __ cmp(eax, NativeRegExpMacroAssembler::EXCEPTION);
3593 // If not exception it can only be retry. Handle that in the runtime system. 3592 // If not exception it can only be retry. Handle that in the runtime system.
3594 __ j(not_equal, &runtime); 3593 __ j(not_equal, &runtime);
3595 // Result must now be exception. If there is no pending exception already a 3594 // Result must now be exception. If there is no pending exception already a
3596 // stack overflow (on the backtrack stack) was detected in RegExp code but 3595 // stack overflow (on the backtrack stack) was detected in RegExp code but
3597 // haven't created the exception yet. Handle that in the runtime system. 3596 // haven't created the exception yet. Handle that in the runtime system.
3598 // TODO(592): Rerunning the RegExp to get the stack overflow exception. 3597 // TODO(592): Rerunning the RegExp to get the stack overflow exception.
3599 ExternalReference pending_exception(Isolate::kPendingExceptionAddress, 3598 ExternalReference pending_exception(Isolate::kPendingExceptionAddress,
3600 masm->isolate()); 3599 masm->isolate());
3601 __ mov(edx, 3600 __ mov(edx,
3602 Operand::StaticVariable(ExternalReference::the_hole_value_location( 3601 Operand::StaticVariable(ExternalReference::the_hole_value_location(
3603 masm->isolate()))); 3602 masm->isolate())));
3604 __ mov(eax, Operand::StaticVariable(pending_exception)); 3603 __ mov(eax, Operand::StaticVariable(pending_exception));
3605 __ cmp(edx, Operand(eax)); 3604 __ cmp(edx, eax);
3606 __ j(equal, &runtime); 3605 __ j(equal, &runtime);
3607 // For exception, throw the exception again. 3606 // For exception, throw the exception again.
3608 3607
3609 // Clear the pending exception variable. 3608 // Clear the pending exception variable.
3610 __ mov(Operand::StaticVariable(pending_exception), edx); 3609 __ mov(Operand::StaticVariable(pending_exception), edx);
3611 3610
3612 // Special handling of termination exceptions which are uncatchable 3611 // Special handling of termination exceptions which are uncatchable
3613 // by javascript code. 3612 // by javascript code.
3614 __ cmp(eax, factory->termination_exception()); 3613 __ cmp(eax, factory->termination_exception());
3615 Label throw_termination_exception; 3614 Label throw_termination_exception;
3616 __ j(equal, &throw_termination_exception, Label::kNear); 3615 __ j(equal, &throw_termination_exception, Label::kNear);
3617 3616
3618 // Handle normal exception by following handler chain. 3617 // Handle normal exception by following handler chain.
3619 __ Throw(eax); 3618 __ Throw(eax);
3620 3619
3621 __ bind(&throw_termination_exception); 3620 __ bind(&throw_termination_exception);
3622 __ ThrowUncatchable(TERMINATION, eax); 3621 __ ThrowUncatchable(TERMINATION, eax);
3623 3622
3624 __ bind(&failure); 3623 __ bind(&failure);
3625 // For failure to match, return null. 3624 // For failure to match, return null.
3626 __ mov(Operand(eax), factory->null_value()); 3625 __ mov(eax, factory->null_value());
3627 __ ret(4 * kPointerSize); 3626 __ ret(4 * kPointerSize);
3628 3627
3629 // Load RegExp data. 3628 // Load RegExp data.
3630 __ bind(&success); 3629 __ bind(&success);
3631 __ mov(eax, Operand(esp, kJSRegExpOffset)); 3630 __ mov(eax, Operand(esp, kJSRegExpOffset));
3632 __ mov(ecx, FieldOperand(eax, JSRegExp::kDataOffset)); 3631 __ mov(ecx, FieldOperand(eax, JSRegExp::kDataOffset));
3633 __ mov(edx, FieldOperand(ecx, JSRegExp::kIrregexpCaptureCountOffset)); 3632 __ mov(edx, FieldOperand(ecx, JSRegExp::kIrregexpCaptureCountOffset));
3634 // Calculate number of capture registers (number_of_captures + 1) * 2. 3633 // Calculate number of capture registers (number_of_captures + 1) * 2.
3635 STATIC_ASSERT(kSmiTag == 0); 3634 STATIC_ASSERT(kSmiTag == 0);
3636 STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1); 3635 STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1);
3637 __ add(Operand(edx), Immediate(2)); // edx was a smi. 3636 __ add(edx, Immediate(2)); // edx was a smi.
3638 3637
3639 // edx: Number of capture registers 3638 // edx: Number of capture registers
3640 // Load last_match_info which is still known to be a fast case JSArray. 3639 // Load last_match_info which is still known to be a fast case JSArray.
3641 __ mov(eax, Operand(esp, kLastMatchInfoOffset)); 3640 __ mov(eax, Operand(esp, kLastMatchInfoOffset));
3642 __ mov(ebx, FieldOperand(eax, JSArray::kElementsOffset)); 3641 __ mov(ebx, FieldOperand(eax, JSArray::kElementsOffset));
3643 3642
3644 // ebx: last_match_info backing store (FixedArray) 3643 // ebx: last_match_info backing store (FixedArray)
3645 // edx: number of capture registers 3644 // edx: number of capture registers
3646 // Store the capture count. 3645 // Store the capture count.
3647 __ SmiTag(edx); // Number of capture registers to smi. 3646 __ SmiTag(edx); // Number of capture registers to smi.
(...skipping 20 matching lines...) Expand all
3668 ExternalReference::address_of_static_offsets_vector(masm->isolate()); 3667 ExternalReference::address_of_static_offsets_vector(masm->isolate());
3669 __ mov(ecx, Immediate(address_of_static_offsets_vector)); 3668 __ mov(ecx, Immediate(address_of_static_offsets_vector));
3670 3669
3671 // ebx: last_match_info backing store (FixedArray) 3670 // ebx: last_match_info backing store (FixedArray)
3672 // ecx: offsets vector 3671 // ecx: offsets vector
3673 // edx: number of capture registers 3672 // edx: number of capture registers
3674 Label next_capture, done; 3673 Label next_capture, done;
3675 // Capture register counter starts from number of capture registers and 3674 // Capture register counter starts from number of capture registers and
3676 // counts down until wraping after zero. 3675 // counts down until wraping after zero.
3677 __ bind(&next_capture); 3676 __ bind(&next_capture);
3678 __ sub(Operand(edx), Immediate(1)); 3677 __ sub(edx, Immediate(1));
3679 __ j(negative, &done, Label::kNear); 3678 __ j(negative, &done, Label::kNear);
3680 // Read the value from the static offsets vector buffer. 3679 // Read the value from the static offsets vector buffer.
3681 __ mov(edi, Operand(ecx, edx, times_int_size, 0)); 3680 __ mov(edi, Operand(ecx, edx, times_int_size, 0));
3682 __ SmiTag(edi); 3681 __ SmiTag(edi);
3683 // Store the smi value in the last match info. 3682 // Store the smi value in the last match info.
3684 __ mov(FieldOperand(ebx, 3683 __ mov(FieldOperand(ebx,
3685 edx, 3684 edx,
3686 times_pointer_size, 3685 times_pointer_size,
3687 RegExpImpl::kFirstCaptureOffset), 3686 RegExpImpl::kFirstCaptureOffset),
3688 edi); 3687 edi);
(...skipping 10 matching lines...) Expand all
3699 #endif // V8_INTERPRETED_REGEXP 3698 #endif // V8_INTERPRETED_REGEXP
3700 } 3699 }
3701 3700
3702 3701
3703 void RegExpConstructResultStub::Generate(MacroAssembler* masm) { 3702 void RegExpConstructResultStub::Generate(MacroAssembler* masm) {
3704 const int kMaxInlineLength = 100; 3703 const int kMaxInlineLength = 100;
3705 Label slowcase; 3704 Label slowcase;
3706 Label done; 3705 Label done;
3707 __ mov(ebx, Operand(esp, kPointerSize * 3)); 3706 __ mov(ebx, Operand(esp, kPointerSize * 3));
3708 __ JumpIfNotSmi(ebx, &slowcase); 3707 __ JumpIfNotSmi(ebx, &slowcase);
3709 __ cmp(Operand(ebx), Immediate(Smi::FromInt(kMaxInlineLength))); 3708 __ cmp(ebx, Immediate(Smi::FromInt(kMaxInlineLength)));
3710 __ j(above, &slowcase); 3709 __ j(above, &slowcase);
3711 // Smi-tagging is equivalent to multiplying by 2. 3710 // Smi-tagging is equivalent to multiplying by 2.
3712 STATIC_ASSERT(kSmiTag == 0); 3711 STATIC_ASSERT(kSmiTag == 0);
3713 STATIC_ASSERT(kSmiTagSize == 1); 3712 STATIC_ASSERT(kSmiTagSize == 1);
3714 // Allocate RegExpResult followed by FixedArray with size in ebx. 3713 // Allocate RegExpResult followed by FixedArray with size in ebx.
3715 // JSArray: [Map][empty properties][Elements][Length-smi][index][input] 3714 // JSArray: [Map][empty properties][Elements][Length-smi][index][input]
3716 // Elements: [Map][Length][..elements..] 3715 // Elements: [Map][Length][..elements..]
3717 __ AllocateInNewSpace(JSRegExpResult::kSize + FixedArray::kHeaderSize, 3716 __ AllocateInNewSpace(JSRegExpResult::kSize + FixedArray::kHeaderSize,
3718 times_half_pointer_size, 3717 times_half_pointer_size,
3719 ebx, // In: Number of elements (times 2, being a smi) 3718 ebx, // In: Number of elements (times 2, being a smi)
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
3759 // Fill contents of fixed-array with the-hole. 3758 // Fill contents of fixed-array with the-hole.
3760 __ SmiUntag(ecx); 3759 __ SmiUntag(ecx);
3761 __ mov(edx, Immediate(factory->the_hole_value())); 3760 __ mov(edx, Immediate(factory->the_hole_value()));
3762 __ lea(ebx, FieldOperand(ebx, FixedArray::kHeaderSize)); 3761 __ lea(ebx, FieldOperand(ebx, FixedArray::kHeaderSize));
3763 // Fill fixed array elements with hole. 3762 // Fill fixed array elements with hole.
3764 // eax: JSArray. 3763 // eax: JSArray.
3765 // ecx: Number of elements to fill. 3764 // ecx: Number of elements to fill.
3766 // ebx: Start of elements in FixedArray. 3765 // ebx: Start of elements in FixedArray.
3767 // edx: the hole. 3766 // edx: the hole.
3768 Label loop; 3767 Label loop;
3769 __ test(ecx, Operand(ecx)); 3768 __ test(ecx, ecx);
3770 __ bind(&loop); 3769 __ bind(&loop);
3771 __ j(less_equal, &done, Label::kNear); // Jump if ecx is negative or zero. 3770 __ j(less_equal, &done, Label::kNear); // Jump if ecx is negative or zero.
3772 __ sub(Operand(ecx), Immediate(1)); 3771 __ sub(ecx, Immediate(1));
3773 __ mov(Operand(ebx, ecx, times_pointer_size, 0), edx); 3772 __ mov(Operand(ebx, ecx, times_pointer_size, 0), edx);
3774 __ jmp(&loop); 3773 __ jmp(&loop);
3775 3774
3776 __ bind(&done); 3775 __ bind(&done);
3777 __ ret(3 * kPointerSize); 3776 __ ret(3 * kPointerSize);
3778 3777
3779 __ bind(&slowcase); 3778 __ bind(&slowcase);
3780 __ TailCallRuntime(Runtime::kRegExpConstructResult, 3, 1); 3779 __ TailCallRuntime(Runtime::kRegExpConstructResult, 3, 1);
3781 } 3780 }
3782 3781
(...skipping 13 matching lines...) Expand all
3796 // Load the number string cache. 3795 // Load the number string cache.
3797 ExternalReference roots_address = 3796 ExternalReference roots_address =
3798 ExternalReference::roots_address(masm->isolate()); 3797 ExternalReference::roots_address(masm->isolate());
3799 __ mov(scratch, Immediate(Heap::kNumberStringCacheRootIndex)); 3798 __ mov(scratch, Immediate(Heap::kNumberStringCacheRootIndex));
3800 __ mov(number_string_cache, 3799 __ mov(number_string_cache,
3801 Operand::StaticArray(scratch, times_pointer_size, roots_address)); 3800 Operand::StaticArray(scratch, times_pointer_size, roots_address));
3802 // Make the hash mask from the length of the number string cache. It 3801 // Make the hash mask from the length of the number string cache. It
3803 // contains two elements (number and string) for each cache entry. 3802 // contains two elements (number and string) for each cache entry.
3804 __ mov(mask, FieldOperand(number_string_cache, FixedArray::kLengthOffset)); 3803 __ mov(mask, FieldOperand(number_string_cache, FixedArray::kLengthOffset));
3805 __ shr(mask, kSmiTagSize + 1); // Untag length and divide it by two. 3804 __ shr(mask, kSmiTagSize + 1); // Untag length and divide it by two.
3806 __ sub(Operand(mask), Immediate(1)); // Make mask. 3805 __ sub(mask, Immediate(1)); // Make mask.
3807 3806
3808 // Calculate the entry in the number string cache. The hash value in the 3807 // Calculate the entry in the number string cache. The hash value in the
3809 // number string cache for smis is just the smi value, and the hash for 3808 // number string cache for smis is just the smi value, and the hash for
3810 // doubles is the xor of the upper and lower words. See 3809 // doubles is the xor of the upper and lower words. See
3811 // Heap::GetNumberStringCache. 3810 // Heap::GetNumberStringCache.
3812 Label smi_hash_calculated; 3811 Label smi_hash_calculated;
3813 Label load_result_from_cache; 3812 Label load_result_from_cache;
3814 if (object_is_smi) { 3813 if (object_is_smi) {
3815 __ mov(scratch, object); 3814 __ mov(scratch, object);
3816 __ SmiUntag(scratch); 3815 __ SmiUntag(scratch);
3817 } else { 3816 } else {
3818 Label not_smi; 3817 Label not_smi;
3819 STATIC_ASSERT(kSmiTag == 0); 3818 STATIC_ASSERT(kSmiTag == 0);
3820 __ JumpIfNotSmi(object, &not_smi, Label::kNear); 3819 __ JumpIfNotSmi(object, &not_smi, Label::kNear);
3821 __ mov(scratch, object); 3820 __ mov(scratch, object);
3822 __ SmiUntag(scratch); 3821 __ SmiUntag(scratch);
3823 __ jmp(&smi_hash_calculated, Label::kNear); 3822 __ jmp(&smi_hash_calculated, Label::kNear);
3824 __ bind(&not_smi); 3823 __ bind(&not_smi);
3825 __ cmp(FieldOperand(object, HeapObject::kMapOffset), 3824 __ cmp(FieldOperand(object, HeapObject::kMapOffset),
3826 masm->isolate()->factory()->heap_number_map()); 3825 masm->isolate()->factory()->heap_number_map());
3827 __ j(not_equal, not_found); 3826 __ j(not_equal, not_found);
3828 STATIC_ASSERT(8 == kDoubleSize); 3827 STATIC_ASSERT(8 == kDoubleSize);
3829 __ mov(scratch, FieldOperand(object, HeapNumber::kValueOffset)); 3828 __ mov(scratch, FieldOperand(object, HeapNumber::kValueOffset));
3830 __ xor_(scratch, FieldOperand(object, HeapNumber::kValueOffset + 4)); 3829 __ xor_(scratch, FieldOperand(object, HeapNumber::kValueOffset + 4));
3831 // Object is heap number and hash is now in scratch. Calculate cache index. 3830 // Object is heap number and hash is now in scratch. Calculate cache index.
3832 __ and_(scratch, Operand(mask)); 3831 __ and_(scratch, mask);
3833 Register index = scratch; 3832 Register index = scratch;
3834 Register probe = mask; 3833 Register probe = mask;
3835 __ mov(probe, 3834 __ mov(probe,
3836 FieldOperand(number_string_cache, 3835 FieldOperand(number_string_cache,
3837 index, 3836 index,
3838 times_twice_pointer_size, 3837 times_twice_pointer_size,
3839 FixedArray::kHeaderSize)); 3838 FixedArray::kHeaderSize));
3840 __ JumpIfSmi(probe, not_found); 3839 __ JumpIfSmi(probe, not_found);
3841 if (CpuFeatures::IsSupported(SSE2)) { 3840 if (CpuFeatures::IsSupported(SSE2)) {
3842 CpuFeatures::Scope fscope(SSE2); 3841 CpuFeatures::Scope fscope(SSE2);
3843 __ movdbl(xmm0, FieldOperand(object, HeapNumber::kValueOffset)); 3842 __ movdbl(xmm0, FieldOperand(object, HeapNumber::kValueOffset));
3844 __ movdbl(xmm1, FieldOperand(probe, HeapNumber::kValueOffset)); 3843 __ movdbl(xmm1, FieldOperand(probe, HeapNumber::kValueOffset));
3845 __ ucomisd(xmm0, xmm1); 3844 __ ucomisd(xmm0, xmm1);
3846 } else { 3845 } else {
3847 __ fld_d(FieldOperand(object, HeapNumber::kValueOffset)); 3846 __ fld_d(FieldOperand(object, HeapNumber::kValueOffset));
3848 __ fld_d(FieldOperand(probe, HeapNumber::kValueOffset)); 3847 __ fld_d(FieldOperand(probe, HeapNumber::kValueOffset));
3849 __ FCmp(); 3848 __ FCmp();
3850 } 3849 }
3851 __ j(parity_even, not_found); // Bail out if NaN is involved. 3850 __ j(parity_even, not_found); // Bail out if NaN is involved.
3852 __ j(not_equal, not_found); // The cache did not contain this value. 3851 __ j(not_equal, not_found); // The cache did not contain this value.
3853 __ jmp(&load_result_from_cache, Label::kNear); 3852 __ jmp(&load_result_from_cache, Label::kNear);
3854 } 3853 }
3855 3854
3856 __ bind(&smi_hash_calculated); 3855 __ bind(&smi_hash_calculated);
3857 // Object is smi and hash is now in scratch. Calculate cache index. 3856 // Object is smi and hash is now in scratch. Calculate cache index.
3858 __ and_(scratch, Operand(mask)); 3857 __ and_(scratch, mask);
3859 Register index = scratch; 3858 Register index = scratch;
3860 // Check if the entry is the smi we are looking for. 3859 // Check if the entry is the smi we are looking for.
3861 __ cmp(object, 3860 __ cmp(object,
3862 FieldOperand(number_string_cache, 3861 FieldOperand(number_string_cache,
3863 index, 3862 index,
3864 times_twice_pointer_size, 3863 times_twice_pointer_size,
3865 FixedArray::kHeaderSize)); 3864 FixedArray::kHeaderSize));
3866 __ j(not_equal, not_found); 3865 __ j(not_equal, not_found);
3867 3866
3868 // Get the result from the cache. 3867 // Get the result from the cache.
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
3900 } 3899 }
3901 3900
3902 void CompareStub::Generate(MacroAssembler* masm) { 3901 void CompareStub::Generate(MacroAssembler* masm) {
3903 ASSERT(lhs_.is(no_reg) && rhs_.is(no_reg)); 3902 ASSERT(lhs_.is(no_reg) && rhs_.is(no_reg));
3904 3903
3905 Label check_unequal_objects; 3904 Label check_unequal_objects;
3906 3905
3907 // Compare two smis if required. 3906 // Compare two smis if required.
3908 if (include_smi_compare_) { 3907 if (include_smi_compare_) {
3909 Label non_smi, smi_done; 3908 Label non_smi, smi_done;
3910 __ mov(ecx, Operand(edx)); 3909 __ mov(ecx, edx);
3911 __ or_(ecx, Operand(eax)); 3910 __ or_(ecx, eax);
3912 __ JumpIfNotSmi(ecx, &non_smi, Label::kNear); 3911 __ JumpIfNotSmi(ecx, &non_smi, Label::kNear);
3913 __ sub(edx, Operand(eax)); // Return on the result of the subtraction. 3912 __ sub(edx, eax); // Return on the result of the subtraction.
3914 __ j(no_overflow, &smi_done, Label::kNear); 3913 __ j(no_overflow, &smi_done, Label::kNear);
3915 __ not_(edx); // Correct sign in case of overflow. edx is never 0 here. 3914 __ not_(edx); // Correct sign in case of overflow. edx is never 0 here.
3916 __ bind(&smi_done); 3915 __ bind(&smi_done);
3917 __ mov(eax, edx); 3916 __ mov(eax, edx);
3918 __ ret(0); 3917 __ ret(0);
3919 __ bind(&non_smi); 3918 __ bind(&non_smi);
3920 } else if (FLAG_debug_code) { 3919 } else if (FLAG_debug_code) {
3921 __ mov(ecx, Operand(edx)); 3920 __ mov(ecx, edx);
3922 __ or_(ecx, Operand(eax)); 3921 __ or_(ecx, eax);
3923 __ test(ecx, Immediate(kSmiTagMask)); 3922 __ test(ecx, Immediate(kSmiTagMask));
3924 __ Assert(not_zero, "Unexpected smi operands."); 3923 __ Assert(not_zero, "Unexpected smi operands.");
3925 } 3924 }
3926 3925
3927 // NOTICE! This code is only reached after a smi-fast-case check, so 3926 // NOTICE! This code is only reached after a smi-fast-case check, so
3928 // it is certain that at least one operand isn't a smi. 3927 // it is certain that at least one operand isn't a smi.
3929 3928
3930 // Identical objects can be compared fast, but there are some tricky cases 3929 // Identical objects can be compared fast, but there are some tricky cases
3931 // for NaN and undefined. 3930 // for NaN and undefined.
3932 { 3931 {
3933 Label not_identical; 3932 Label not_identical;
3934 __ cmp(eax, Operand(edx)); 3933 __ cmp(eax, edx);
3935 __ j(not_equal, &not_identical); 3934 __ j(not_equal, &not_identical);
3936 3935
3937 if (cc_ != equal) { 3936 if (cc_ != equal) {
3938 // Check for undefined. undefined OP undefined is false even though 3937 // Check for undefined. undefined OP undefined is false even though
3939 // undefined == undefined. 3938 // undefined == undefined.
3940 Label check_for_nan; 3939 Label check_for_nan;
3941 __ cmp(edx, masm->isolate()->factory()->undefined_value()); 3940 __ cmp(edx, masm->isolate()->factory()->undefined_value());
3942 __ j(not_equal, &check_for_nan, Label::kNear); 3941 __ j(not_equal, &check_for_nan, Label::kNear);
3943 __ Set(eax, Immediate(Smi::FromInt(NegativeComparisonResult(cc_)))); 3942 __ Set(eax, Immediate(Smi::FromInt(NegativeComparisonResult(cc_))));
3944 __ ret(0); 3943 __ ret(0);
(...skipping 28 matching lines...) Expand all
3973 // Read top bits of double representation (second word of value). 3972 // Read top bits of double representation (second word of value).
3974 3973
3975 // Value is a QNaN if value & kQuietNaNMask == kQuietNaNMask, i.e., 3974 // Value is a QNaN if value & kQuietNaNMask == kQuietNaNMask, i.e.,
3976 // all bits in the mask are set. We only need to check the word 3975 // all bits in the mask are set. We only need to check the word
3977 // that contains the exponent and high bit of the mantissa. 3976 // that contains the exponent and high bit of the mantissa.
3978 STATIC_ASSERT(((kQuietNaNHighBitsMask << 1) & 0x80000000u) != 0); 3977 STATIC_ASSERT(((kQuietNaNHighBitsMask << 1) & 0x80000000u) != 0);
3979 __ mov(edx, FieldOperand(edx, HeapNumber::kExponentOffset)); 3978 __ mov(edx, FieldOperand(edx, HeapNumber::kExponentOffset));
3980 __ Set(eax, Immediate(0)); 3979 __ Set(eax, Immediate(0));
3981 // Shift value and mask so kQuietNaNHighBitsMask applies to topmost 3980 // Shift value and mask so kQuietNaNHighBitsMask applies to topmost
3982 // bits. 3981 // bits.
3983 __ add(edx, Operand(edx)); 3982 __ add(edx, edx);
3984 __ cmp(edx, kQuietNaNHighBitsMask << 1); 3983 __ cmp(edx, kQuietNaNHighBitsMask << 1);
3985 if (cc_ == equal) { 3984 if (cc_ == equal) {
3986 STATIC_ASSERT(EQUAL != 1); 3985 STATIC_ASSERT(EQUAL != 1);
3987 __ setcc(above_equal, eax); 3986 __ setcc(above_equal, eax);
3988 __ ret(0); 3987 __ ret(0);
3989 } else { 3988 } else {
3990 Label nan; 3989 Label nan;
3991 __ j(above_equal, &nan, Label::kNear); 3990 __ j(above_equal, &nan, Label::kNear);
3992 __ Set(eax, Immediate(Smi::FromInt(EQUAL))); 3991 __ Set(eax, Immediate(Smi::FromInt(EQUAL)));
3993 __ ret(0); 3992 __ ret(0);
(...skipping 13 matching lines...) Expand all
4007 Label not_smis; 4006 Label not_smis;
4008 // If we're doing a strict equality comparison, we don't have to do 4007 // If we're doing a strict equality comparison, we don't have to do
4009 // type conversion, so we generate code to do fast comparison for objects 4008 // type conversion, so we generate code to do fast comparison for objects
4010 // and oddballs. Non-smi numbers and strings still go through the usual 4009 // and oddballs. Non-smi numbers and strings still go through the usual
4011 // slow-case code. 4010 // slow-case code.
4012 // If either is a Smi (we know that not both are), then they can only 4011 // If either is a Smi (we know that not both are), then they can only
4013 // be equal if the other is a HeapNumber. If so, use the slow case. 4012 // be equal if the other is a HeapNumber. If so, use the slow case.
4014 STATIC_ASSERT(kSmiTag == 0); 4013 STATIC_ASSERT(kSmiTag == 0);
4015 ASSERT_EQ(0, Smi::FromInt(0)); 4014 ASSERT_EQ(0, Smi::FromInt(0));
4016 __ mov(ecx, Immediate(kSmiTagMask)); 4015 __ mov(ecx, Immediate(kSmiTagMask));
4017 __ and_(ecx, Operand(eax)); 4016 __ and_(ecx, eax);
4018 __ test(ecx, Operand(edx)); 4017 __ test(ecx, edx);
4019 __ j(not_zero, &not_smis, Label::kNear); 4018 __ j(not_zero, &not_smis, Label::kNear);
4020 // One operand is a smi. 4019 // One operand is a smi.
4021 4020
4022 // Check whether the non-smi is a heap number. 4021 // Check whether the non-smi is a heap number.
4023 STATIC_ASSERT(kSmiTagMask == 1); 4022 STATIC_ASSERT(kSmiTagMask == 1);
4024 // ecx still holds eax & kSmiTag, which is either zero or one. 4023 // ecx still holds eax & kSmiTag, which is either zero or one.
4025 __ sub(Operand(ecx), Immediate(0x01)); 4024 __ sub(ecx, Immediate(0x01));
4026 __ mov(ebx, edx); 4025 __ mov(ebx, edx);
4027 __ xor_(ebx, Operand(eax)); 4026 __ xor_(ebx, eax);
4028 __ and_(ebx, Operand(ecx)); // ebx holds either 0 or eax ^ edx. 4027 __ and_(ebx, ecx); // ebx holds either 0 or eax ^ edx.
4029 __ xor_(ebx, Operand(eax)); 4028 __ xor_(ebx, eax);
4030 // if eax was smi, ebx is now edx, else eax. 4029 // if eax was smi, ebx is now edx, else eax.
4031 4030
4032 // Check if the non-smi operand is a heap number. 4031 // Check if the non-smi operand is a heap number.
4033 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset), 4032 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
4034 Immediate(masm->isolate()->factory()->heap_number_map())); 4033 Immediate(masm->isolate()->factory()->heap_number_map()));
4035 // If heap number, handle it in the slow case. 4034 // If heap number, handle it in the slow case.
4036 __ j(equal, &slow, Label::kNear); 4035 __ j(equal, &slow, Label::kNear);
4037 // Return non-equal (ebx is not zero) 4036 // Return non-equal (ebx is not zero)
4038 __ mov(eax, ebx); 4037 __ mov(eax, ebx);
4039 __ ret(0); 4038 __ ret(0);
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
4081 CpuFeatures::Scope use_cmov(CMOV); 4080 CpuFeatures::Scope use_cmov(CMOV);
4082 4081
4083 FloatingPointHelper::LoadSSE2Operands(masm, &non_number_comparison); 4082 FloatingPointHelper::LoadSSE2Operands(masm, &non_number_comparison);
4084 __ ucomisd(xmm0, xmm1); 4083 __ ucomisd(xmm0, xmm1);
4085 4084
4086 // Don't base result on EFLAGS when a NaN is involved. 4085 // Don't base result on EFLAGS when a NaN is involved.
4087 __ j(parity_even, &unordered, Label::kNear); 4086 __ j(parity_even, &unordered, Label::kNear);
4088 // Return a result of -1, 0, or 1, based on EFLAGS. 4087 // Return a result of -1, 0, or 1, based on EFLAGS.
4089 __ mov(eax, 0); // equal 4088 __ mov(eax, 0); // equal
4090 __ mov(ecx, Immediate(Smi::FromInt(1))); 4089 __ mov(ecx, Immediate(Smi::FromInt(1)));
4091 __ cmov(above, eax, Operand(ecx)); 4090 __ cmov(above, eax, ecx);
4092 __ mov(ecx, Immediate(Smi::FromInt(-1))); 4091 __ mov(ecx, Immediate(Smi::FromInt(-1)));
4093 __ cmov(below, eax, Operand(ecx)); 4092 __ cmov(below, eax, ecx);
4094 __ ret(0); 4093 __ ret(0);
4095 } else { 4094 } else {
4096 FloatingPointHelper::CheckFloatOperands( 4095 FloatingPointHelper::CheckFloatOperands(
4097 masm, &non_number_comparison, ebx); 4096 masm, &non_number_comparison, ebx);
4098 FloatingPointHelper::LoadFloatOperand(masm, eax); 4097 FloatingPointHelper::LoadFloatOperand(masm, eax);
4099 FloatingPointHelper::LoadFloatOperand(masm, edx); 4098 FloatingPointHelper::LoadFloatOperand(masm, edx);
4100 __ FCmp(); 4099 __ FCmp();
4101 4100
4102 // Don't base result on EFLAGS when a NaN is involved. 4101 // Don't base result on EFLAGS when a NaN is involved.
4103 __ j(parity_even, &unordered, Label::kNear); 4102 __ j(parity_even, &unordered, Label::kNear);
(...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after
4309 // instruction stream after the call. Cache states are uninitialized, 4308 // instruction stream after the call. Cache states are uninitialized,
4310 // monomorphic (indicated by a JSFunction), and megamorphic. 4309 // monomorphic (indicated by a JSFunction), and megamorphic.
4311 Label initialize, call; 4310 Label initialize, call;
4312 // Load the cache cell address into ebx and the cache state into ecx. 4311 // Load the cache cell address into ebx and the cache state into ecx.
4313 __ mov(ebx, Operand(esp, 0)); // Return address. 4312 __ mov(ebx, Operand(esp, 0)); // Return address.
4314 __ mov(ebx, Operand(ebx, 1)); // 1 ~ sizeof 'test eax' opcode in bytes. 4313 __ mov(ebx, Operand(ebx, 1)); // 1 ~ sizeof 'test eax' opcode in bytes.
4315 __ mov(ecx, FieldOperand(ebx, JSGlobalPropertyCell::kValueOffset)); 4314 __ mov(ecx, FieldOperand(ebx, JSGlobalPropertyCell::kValueOffset));
4316 4315
4317 // A monomorphic cache hit or an already megamorphic state: invoke the 4316 // A monomorphic cache hit or an already megamorphic state: invoke the
4318 // function without changing the state. 4317 // function without changing the state.
4319 __ cmp(ecx, Operand(edi)); 4318 __ cmp(ecx, edi);
4320 __ j(equal, &call, Label::kNear); 4319 __ j(equal, &call, Label::kNear);
4321 __ cmp(Operand(ecx), Immediate(MegamorphicSentinel(isolate))); 4320 __ cmp(ecx, Immediate(MegamorphicSentinel(isolate)));
4322 __ j(equal, &call, Label::kNear); 4321 __ j(equal, &call, Label::kNear);
4323 4322
4324 // A monomorphic miss (i.e, here the cache is not uninitialized) goes 4323 // A monomorphic miss (i.e, here the cache is not uninitialized) goes
4325 // megamorphic. 4324 // megamorphic.
4326 __ cmp(Operand(ecx), Immediate(UninitializedSentinel(isolate))); 4325 __ cmp(ecx, Immediate(UninitializedSentinel(isolate)));
4327 __ j(equal, &initialize, Label::kNear); 4326 __ j(equal, &initialize, Label::kNear);
4328 // MegamorphicSentinel is a root so no write-barrier is needed. 4327 // MegamorphicSentinel is a root so no write-barrier is needed.
4329 __ mov(FieldOperand(ebx, JSGlobalPropertyCell::kValueOffset), 4328 __ mov(FieldOperand(ebx, JSGlobalPropertyCell::kValueOffset),
4330 Immediate(MegamorphicSentinel(isolate))); 4329 Immediate(MegamorphicSentinel(isolate)));
4331 __ jmp(&call, Label::kNear); 4330 __ jmp(&call, Label::kNear);
4332 4331
4333 // An uninitialized cache is patched with the function. 4332 // An uninitialized cache is patched with the function.
4334 __ bind(&initialize); 4333 __ bind(&initialize);
4335 __ mov(FieldOperand(ebx, JSGlobalPropertyCell::kValueOffset), edi); 4334 __ mov(FieldOperand(ebx, JSGlobalPropertyCell::kValueOffset), edi);
4336 __ mov(ecx, edi); 4335 __ mov(ecx, edi);
(...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after
4476 ExternalReference::heap_always_allocate_scope_depth(masm->isolate()); 4475 ExternalReference::heap_always_allocate_scope_depth(masm->isolate());
4477 if (always_allocate_scope) { 4476 if (always_allocate_scope) {
4478 __ inc(Operand::StaticVariable(scope_depth)); 4477 __ inc(Operand::StaticVariable(scope_depth));
4479 } 4478 }
4480 4479
4481 // Call C function. 4480 // Call C function.
4482 __ mov(Operand(esp, 0 * kPointerSize), edi); // argc. 4481 __ mov(Operand(esp, 0 * kPointerSize), edi); // argc.
4483 __ mov(Operand(esp, 1 * kPointerSize), esi); // argv. 4482 __ mov(Operand(esp, 1 * kPointerSize), esi); // argv.
4484 __ mov(Operand(esp, 2 * kPointerSize), 4483 __ mov(Operand(esp, 2 * kPointerSize),
4485 Immediate(ExternalReference::isolate_address())); 4484 Immediate(ExternalReference::isolate_address()));
4486 __ call(Operand(ebx)); 4485 __ call(ebx);
4487 // Result is in eax or edx:eax - do not destroy these registers! 4486 // Result is in eax or edx:eax - do not destroy these registers!
4488 4487
4489 if (always_allocate_scope) { 4488 if (always_allocate_scope) {
4490 __ dec(Operand::StaticVariable(scope_depth)); 4489 __ dec(Operand::StaticVariable(scope_depth));
4491 } 4490 }
4492 4491
4493 // Make sure we're not trying to return 'the hole' from the runtime 4492 // Make sure we're not trying to return 'the hole' from the runtime
4494 // call as this may lead to crashes in the IC code later. 4493 // call as this may lead to crashes in the IC code later.
4495 if (FLAG_debug_code) { 4494 if (FLAG_debug_code) {
4496 Label okay; 4495 Label okay;
(...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after
4631 GenerateThrowTOS(masm); 4630 GenerateThrowTOS(masm);
4632 } 4631 }
4633 4632
4634 4633
4635 void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) { 4634 void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) {
4636 Label invoke, exit; 4635 Label invoke, exit;
4637 Label not_outermost_js, not_outermost_js_2; 4636 Label not_outermost_js, not_outermost_js_2;
4638 4637
4639 // Setup frame. 4638 // Setup frame.
4640 __ push(ebp); 4639 __ push(ebp);
4641 __ mov(ebp, Operand(esp)); 4640 __ mov(ebp, esp);
4642 4641
4643 // Push marker in two places. 4642 // Push marker in two places.
4644 int marker = is_construct ? StackFrame::ENTRY_CONSTRUCT : StackFrame::ENTRY; 4643 int marker = is_construct ? StackFrame::ENTRY_CONSTRUCT : StackFrame::ENTRY;
4645 __ push(Immediate(Smi::FromInt(marker))); // context slot 4644 __ push(Immediate(Smi::FromInt(marker))); // context slot
4646 __ push(Immediate(Smi::FromInt(marker))); // function slot 4645 __ push(Immediate(Smi::FromInt(marker))); // function slot
4647 // Save callee-saved registers (C calling conventions). 4646 // Save callee-saved registers (C calling conventions).
4648 __ push(edi); 4647 __ push(edi);
4649 __ push(esi); 4648 __ push(esi);
4650 __ push(ebx); 4649 __ push(ebx);
4651 4650
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
4699 Builtins::kJSConstructEntryTrampoline, 4698 Builtins::kJSConstructEntryTrampoline,
4700 masm->isolate()); 4699 masm->isolate());
4701 __ mov(edx, Immediate(construct_entry)); 4700 __ mov(edx, Immediate(construct_entry));
4702 } else { 4701 } else {
4703 ExternalReference entry(Builtins::kJSEntryTrampoline, 4702 ExternalReference entry(Builtins::kJSEntryTrampoline,
4704 masm->isolate()); 4703 masm->isolate());
4705 __ mov(edx, Immediate(entry)); 4704 __ mov(edx, Immediate(entry));
4706 } 4705 }
4707 __ mov(edx, Operand(edx, 0)); // deref address 4706 __ mov(edx, Operand(edx, 0)); // deref address
4708 __ lea(edx, FieldOperand(edx, Code::kHeaderSize)); 4707 __ lea(edx, FieldOperand(edx, Code::kHeaderSize));
4709 __ call(Operand(edx)); 4708 __ call(edx);
4710 4709
4711 // Unlink this frame from the handler chain. 4710 // Unlink this frame from the handler chain.
4712 __ PopTryHandler(); 4711 __ PopTryHandler();
4713 4712
4714 __ bind(&exit); 4713 __ bind(&exit);
4715 // Check if the current stack frame is marked as the outermost JS frame. 4714 // Check if the current stack frame is marked as the outermost JS frame.
4716 __ pop(ebx); 4715 __ pop(ebx);
4717 __ cmp(Operand(ebx), 4716 __ cmp(ebx, Immediate(Smi::FromInt(StackFrame::OUTERMOST_JSENTRY_FRAME)));
4718 Immediate(Smi::FromInt(StackFrame::OUTERMOST_JSENTRY_FRAME)));
4719 __ j(not_equal, &not_outermost_js_2); 4717 __ j(not_equal, &not_outermost_js_2);
4720 __ mov(Operand::StaticVariable(js_entry_sp), Immediate(0)); 4718 __ mov(Operand::StaticVariable(js_entry_sp), Immediate(0));
4721 __ bind(&not_outermost_js_2); 4719 __ bind(&not_outermost_js_2);
4722 4720
4723 // Restore the top frame descriptor from the stack. 4721 // Restore the top frame descriptor from the stack.
4724 __ pop(Operand::StaticVariable(ExternalReference( 4722 __ pop(Operand::StaticVariable(ExternalReference(
4725 Isolate::kCEntryFPAddress, 4723 Isolate::kCEntryFPAddress,
4726 masm->isolate()))); 4724 masm->isolate())));
4727 4725
4728 // Restore callee-saved registers (C calling conventions). 4726 // Restore callee-saved registers (C calling conventions).
4729 __ pop(ebx); 4727 __ pop(ebx);
4730 __ pop(esi); 4728 __ pop(esi);
4731 __ pop(edi); 4729 __ pop(edi);
4732 __ add(Operand(esp), Immediate(2 * kPointerSize)); // remove markers 4730 __ add(esp, Immediate(2 * kPointerSize)); // remove markers
4733 4731
4734 // Restore frame pointer and return. 4732 // Restore frame pointer and return.
4735 __ pop(ebp); 4733 __ pop(ebp);
4736 __ ret(0); 4734 __ ret(0);
4737 } 4735 }
4738 4736
4739 4737
4740 // Generate stub code for instanceof. 4738 // Generate stub code for instanceof.
4741 // This code can patch a call site inlined cache of the instance of check, 4739 // This code can patch a call site inlined cache of the instance of check,
4742 // which looks like this. 4740 // which looks like this.
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after
4838 __ Assert(equal, "InstanceofStub unexpected call site cache (cmp 2)"); 4836 __ Assert(equal, "InstanceofStub unexpected call site cache (cmp 2)");
4839 } 4837 }
4840 __ mov(Operand(scratch, kDeltaToCmpImmediate), map); 4838 __ mov(Operand(scratch, kDeltaToCmpImmediate), map);
4841 } 4839 }
4842 4840
4843 // Loop through the prototype chain of the object looking for the function 4841 // Loop through the prototype chain of the object looking for the function
4844 // prototype. 4842 // prototype.
4845 __ mov(scratch, FieldOperand(map, Map::kPrototypeOffset)); 4843 __ mov(scratch, FieldOperand(map, Map::kPrototypeOffset));
4846 Label loop, is_instance, is_not_instance; 4844 Label loop, is_instance, is_not_instance;
4847 __ bind(&loop); 4845 __ bind(&loop);
4848 __ cmp(scratch, Operand(prototype)); 4846 __ cmp(scratch, prototype);
4849 __ j(equal, &is_instance, Label::kNear); 4847 __ j(equal, &is_instance, Label::kNear);
4850 Factory* factory = masm->isolate()->factory(); 4848 Factory* factory = masm->isolate()->factory();
4851 __ cmp(Operand(scratch), Immediate(factory->null_value())); 4849 __ cmp(scratch, Immediate(factory->null_value()));
4852 __ j(equal, &is_not_instance, Label::kNear); 4850 __ j(equal, &is_not_instance, Label::kNear);
4853 __ mov(scratch, FieldOperand(scratch, HeapObject::kMapOffset)); 4851 __ mov(scratch, FieldOperand(scratch, HeapObject::kMapOffset));
4854 __ mov(scratch, FieldOperand(scratch, Map::kPrototypeOffset)); 4852 __ mov(scratch, FieldOperand(scratch, Map::kPrototypeOffset));
4855 __ jmp(&loop); 4853 __ jmp(&loop);
4856 4854
4857 __ bind(&is_instance); 4855 __ bind(&is_instance);
4858 if (!HasCallSiteInlineCheck()) { 4856 if (!HasCallSiteInlineCheck()) {
4859 __ Set(eax, Immediate(0)); 4857 __ Set(eax, Immediate(0));
4860 __ mov(scratch, Immediate(Heap::kInstanceofCacheAnswerRootIndex)); 4858 __ mov(scratch, Immediate(Heap::kInstanceofCacheAnswerRootIndex));
4861 __ mov(Operand::StaticArray(scratch, 4859 __ mov(Operand::StaticArray(scratch,
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
4939 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); 4937 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION);
4940 } else { 4938 } else {
4941 // Call the builtin and convert 0/1 to true/false. 4939 // Call the builtin and convert 0/1 to true/false.
4942 { 4940 {
4943 FrameScope scope(masm, StackFrame::INTERNAL); 4941 FrameScope scope(masm, StackFrame::INTERNAL);
4944 __ push(object); 4942 __ push(object);
4945 __ push(function); 4943 __ push(function);
4946 __ InvokeBuiltin(Builtins::INSTANCE_OF, CALL_FUNCTION); 4944 __ InvokeBuiltin(Builtins::INSTANCE_OF, CALL_FUNCTION);
4947 } 4945 }
4948 Label true_value, done; 4946 Label true_value, done;
4949 __ test(eax, Operand(eax)); 4947 __ test(eax, eax);
4950 __ j(zero, &true_value, Label::kNear); 4948 __ j(zero, &true_value, Label::kNear);
4951 __ mov(eax, factory->false_value()); 4949 __ mov(eax, factory->false_value());
4952 __ jmp(&done, Label::kNear); 4950 __ jmp(&done, Label::kNear);
4953 __ bind(&true_value); 4951 __ bind(&true_value);
4954 __ mov(eax, factory->true_value()); 4952 __ mov(eax, factory->true_value());
4955 __ bind(&done); 4953 __ bind(&done);
4956 __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize); 4954 __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize);
4957 } 4955 }
4958 } 4956 }
4959 4957
(...skipping 295 matching lines...) Expand 10 before | Expand all | Expand 10 after
5255 } 5253 }
5256 } 5254 }
5257 5255
5258 // Both arguments are strings. 5256 // Both arguments are strings.
5259 // eax: first string 5257 // eax: first string
5260 // edx: second string 5258 // edx: second string
5261 // Check if either of the strings are empty. In that case return the other. 5259 // Check if either of the strings are empty. In that case return the other.
5262 Label second_not_zero_length, both_not_zero_length; 5260 Label second_not_zero_length, both_not_zero_length;
5263 __ mov(ecx, FieldOperand(edx, String::kLengthOffset)); 5261 __ mov(ecx, FieldOperand(edx, String::kLengthOffset));
5264 STATIC_ASSERT(kSmiTag == 0); 5262 STATIC_ASSERT(kSmiTag == 0);
5265 __ test(ecx, Operand(ecx)); 5263 __ test(ecx, ecx);
5266 __ j(not_zero, &second_not_zero_length, Label::kNear); 5264 __ j(not_zero, &second_not_zero_length, Label::kNear);
5267 // Second string is empty, result is first string which is already in eax. 5265 // Second string is empty, result is first string which is already in eax.
5268 Counters* counters = masm->isolate()->counters(); 5266 Counters* counters = masm->isolate()->counters();
5269 __ IncrementCounter(counters->string_add_native(), 1); 5267 __ IncrementCounter(counters->string_add_native(), 1);
5270 __ ret(2 * kPointerSize); 5268 __ ret(2 * kPointerSize);
5271 __ bind(&second_not_zero_length); 5269 __ bind(&second_not_zero_length);
5272 __ mov(ebx, FieldOperand(eax, String::kLengthOffset)); 5270 __ mov(ebx, FieldOperand(eax, String::kLengthOffset));
5273 STATIC_ASSERT(kSmiTag == 0); 5271 STATIC_ASSERT(kSmiTag == 0);
5274 __ test(ebx, Operand(ebx)); 5272 __ test(ebx, ebx);
5275 __ j(not_zero, &both_not_zero_length, Label::kNear); 5273 __ j(not_zero, &both_not_zero_length, Label::kNear);
5276 // First string is empty, result is second string which is in edx. 5274 // First string is empty, result is second string which is in edx.
5277 __ mov(eax, edx); 5275 __ mov(eax, edx);
5278 __ IncrementCounter(counters->string_add_native(), 1); 5276 __ IncrementCounter(counters->string_add_native(), 1);
5279 __ ret(2 * kPointerSize); 5277 __ ret(2 * kPointerSize);
5280 5278
5281 // Both strings are non-empty. 5279 // Both strings are non-empty.
5282 // eax: first string 5280 // eax: first string
5283 // ebx: length of first string as a smi 5281 // ebx: length of first string as a smi
5284 // ecx: length of second string as a smi 5282 // ecx: length of second string as a smi
5285 // edx: second string 5283 // edx: second string
5286 // Look at the length of the result of adding the two strings. 5284 // Look at the length of the result of adding the two strings.
5287 Label string_add_flat_result, longer_than_two; 5285 Label string_add_flat_result, longer_than_two;
5288 __ bind(&both_not_zero_length); 5286 __ bind(&both_not_zero_length);
5289 __ add(ebx, Operand(ecx)); 5287 __ add(ebx, ecx);
5290 STATIC_ASSERT(Smi::kMaxValue == String::kMaxLength); 5288 STATIC_ASSERT(Smi::kMaxValue == String::kMaxLength);
5291 // Handle exceptionally long strings in the runtime system. 5289 // Handle exceptionally long strings in the runtime system.
5292 __ j(overflow, &string_add_runtime); 5290 __ j(overflow, &string_add_runtime);
5293 // Use the symbol table when adding two one character strings, as it 5291 // Use the symbol table when adding two one character strings, as it
5294 // helps later optimizations to return a symbol here. 5292 // helps later optimizations to return a symbol here.
5295 __ cmp(Operand(ebx), Immediate(Smi::FromInt(2))); 5293 __ cmp(ebx, Immediate(Smi::FromInt(2)));
5296 __ j(not_equal, &longer_than_two); 5294 __ j(not_equal, &longer_than_two);
5297 5295
5298 // Check that both strings are non-external ascii strings. 5296 // Check that both strings are non-external ascii strings.
5299 __ JumpIfNotBothSequentialAsciiStrings(eax, edx, ebx, ecx, 5297 __ JumpIfNotBothSequentialAsciiStrings(eax, edx, ebx, ecx,
5300 &string_add_runtime); 5298 &string_add_runtime);
5301 5299
5302 // Get the two characters forming the new string. 5300 // Get the two characters forming the new string.
5303 __ movzx_b(ebx, FieldOperand(eax, SeqAsciiString::kHeaderSize)); 5301 __ movzx_b(ebx, FieldOperand(eax, SeqAsciiString::kHeaderSize));
5304 __ movzx_b(ecx, FieldOperand(edx, SeqAsciiString::kHeaderSize)); 5302 __ movzx_b(ecx, FieldOperand(edx, SeqAsciiString::kHeaderSize));
5305 5303
(...skipping 16 matching lines...) Expand all
5322 __ movzx_b(ecx, FieldOperand(edx, SeqAsciiString::kHeaderSize)); 5320 __ movzx_b(ecx, FieldOperand(edx, SeqAsciiString::kHeaderSize));
5323 __ bind(&make_two_character_string_no_reload); 5321 __ bind(&make_two_character_string_no_reload);
5324 __ IncrementCounter(counters->string_add_make_two_char(), 1); 5322 __ IncrementCounter(counters->string_add_make_two_char(), 1);
5325 __ AllocateAsciiString(eax, // Result. 5323 __ AllocateAsciiString(eax, // Result.
5326 2, // Length. 5324 2, // Length.
5327 edi, // Scratch 1. 5325 edi, // Scratch 1.
5328 edx, // Scratch 2. 5326 edx, // Scratch 2.
5329 &string_add_runtime); 5327 &string_add_runtime);
5330 // Pack both characters in ebx. 5328 // Pack both characters in ebx.
5331 __ shl(ecx, kBitsPerByte); 5329 __ shl(ecx, kBitsPerByte);
5332 __ or_(ebx, Operand(ecx)); 5330 __ or_(ebx, ecx);
5333 // Set the characters in the new string. 5331 // Set the characters in the new string.
5334 __ mov_w(FieldOperand(eax, SeqAsciiString::kHeaderSize), ebx); 5332 __ mov_w(FieldOperand(eax, SeqAsciiString::kHeaderSize), ebx);
5335 __ IncrementCounter(counters->string_add_native(), 1); 5333 __ IncrementCounter(counters->string_add_native(), 1);
5336 __ ret(2 * kPointerSize); 5334 __ ret(2 * kPointerSize);
5337 5335
5338 __ bind(&longer_than_two); 5336 __ bind(&longer_than_two);
5339 // Check if resulting string will be flat. 5337 // Check if resulting string will be flat.
5340 __ cmp(Operand(ebx), Immediate(Smi::FromInt(String::kMinNonFlatLength))); 5338 __ cmp(ebx, Immediate(Smi::FromInt(String::kMinNonFlatLength)));
5341 __ j(below, &string_add_flat_result); 5339 __ j(below, &string_add_flat_result);
5342 5340
5343 // If result is not supposed to be flat allocate a cons string object. If both 5341 // If result is not supposed to be flat allocate a cons string object. If both
5344 // strings are ascii the result is an ascii cons string. 5342 // strings are ascii the result is an ascii cons string.
5345 Label non_ascii, allocated, ascii_data; 5343 Label non_ascii, allocated, ascii_data;
5346 __ mov(edi, FieldOperand(eax, HeapObject::kMapOffset)); 5344 __ mov(edi, FieldOperand(eax, HeapObject::kMapOffset));
5347 __ movzx_b(ecx, FieldOperand(edi, Map::kInstanceTypeOffset)); 5345 __ movzx_b(ecx, FieldOperand(edi, Map::kInstanceTypeOffset));
5348 __ mov(edi, FieldOperand(edx, HeapObject::kMapOffset)); 5346 __ mov(edi, FieldOperand(edx, HeapObject::kMapOffset));
5349 __ movzx_b(edi, FieldOperand(edi, Map::kInstanceTypeOffset)); 5347 __ movzx_b(edi, FieldOperand(edi, Map::kInstanceTypeOffset));
5350 __ and_(ecx, Operand(edi)); 5348 __ and_(ecx, edi);
5351 STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0); 5349 STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0);
5352 STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); 5350 STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0);
5353 __ test(ecx, Immediate(kStringEncodingMask)); 5351 __ test(ecx, Immediate(kStringEncodingMask));
5354 __ j(zero, &non_ascii); 5352 __ j(zero, &non_ascii);
5355 __ bind(&ascii_data); 5353 __ bind(&ascii_data);
5356 // Allocate an acsii cons string. 5354 // Allocate an acsii cons string.
5357 __ AllocateAsciiConsString(ecx, edi, no_reg, &string_add_runtime); 5355 __ AllocateAsciiConsString(ecx, edi, no_reg, &string_add_runtime);
5358 __ bind(&allocated); 5356 __ bind(&allocated);
5359 // Fill the fields of the cons string. 5357 // Fill the fields of the cons string.
5360 if (FLAG_debug_code) __ AbortIfNotSmi(ebx); 5358 if (FLAG_debug_code) __ AbortIfNotSmi(ebx);
5361 __ mov(FieldOperand(ecx, ConsString::kLengthOffset), ebx); 5359 __ mov(FieldOperand(ecx, ConsString::kLengthOffset), ebx);
5362 __ mov(FieldOperand(ecx, ConsString::kHashFieldOffset), 5360 __ mov(FieldOperand(ecx, ConsString::kHashFieldOffset),
5363 Immediate(String::kEmptyHashField)); 5361 Immediate(String::kEmptyHashField));
5364 __ mov(FieldOperand(ecx, ConsString::kFirstOffset), eax); 5362 __ mov(FieldOperand(ecx, ConsString::kFirstOffset), eax);
5365 __ mov(FieldOperand(ecx, ConsString::kSecondOffset), edx); 5363 __ mov(FieldOperand(ecx, ConsString::kSecondOffset), edx);
5366 __ mov(eax, ecx); 5364 __ mov(eax, ecx);
5367 __ IncrementCounter(counters->string_add_native(), 1); 5365 __ IncrementCounter(counters->string_add_native(), 1);
5368 __ ret(2 * kPointerSize); 5366 __ ret(2 * kPointerSize);
5369 __ bind(&non_ascii); 5367 __ bind(&non_ascii);
5370 // At least one of the strings is two-byte. Check whether it happens 5368 // At least one of the strings is two-byte. Check whether it happens
5371 // to contain only ascii characters. 5369 // to contain only ascii characters.
5372 // ecx: first instance type AND second instance type. 5370 // ecx: first instance type AND second instance type.
5373 // edi: second instance type. 5371 // edi: second instance type.
5374 __ test(ecx, Immediate(kAsciiDataHintMask)); 5372 __ test(ecx, Immediate(kAsciiDataHintMask));
5375 __ j(not_zero, &ascii_data); 5373 __ j(not_zero, &ascii_data);
5376 __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset)); 5374 __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset));
5377 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); 5375 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
5378 __ xor_(edi, Operand(ecx)); 5376 __ xor_(edi, ecx);
5379 STATIC_ASSERT(kAsciiStringTag != 0 && kAsciiDataHintTag != 0); 5377 STATIC_ASSERT(kAsciiStringTag != 0 && kAsciiDataHintTag != 0);
5380 __ and_(edi, kAsciiStringTag | kAsciiDataHintTag); 5378 __ and_(edi, kAsciiStringTag | kAsciiDataHintTag);
5381 __ cmp(edi, kAsciiStringTag | kAsciiDataHintTag); 5379 __ cmp(edi, kAsciiStringTag | kAsciiDataHintTag);
5382 __ j(equal, &ascii_data); 5380 __ j(equal, &ascii_data);
5383 // Allocate a two byte cons string. 5381 // Allocate a two byte cons string.
5384 __ AllocateTwoByteConsString(ecx, edi, no_reg, &string_add_runtime); 5382 __ AllocateTwoByteConsString(ecx, edi, no_reg, &string_add_runtime);
5385 __ jmp(&allocated); 5383 __ jmp(&allocated);
5386 5384
5387 // Handle creating a flat result. First check that both strings are not 5385 // Handle creating a flat result. First check that both strings are not
5388 // external strings. 5386 // external strings.
(...skipping 27 matching lines...) Expand all
5416 __ test_b(FieldOperand(ecx, Map::kInstanceTypeOffset), kStringEncodingMask); 5414 __ test_b(FieldOperand(ecx, Map::kInstanceTypeOffset), kStringEncodingMask);
5417 __ j(zero, &string_add_runtime); 5415 __ j(zero, &string_add_runtime);
5418 5416
5419 // Both strings are ascii strings. As they are short they are both flat. 5417 // Both strings are ascii strings. As they are short they are both flat.
5420 // ebx: length of resulting flat string as a smi 5418 // ebx: length of resulting flat string as a smi
5421 __ SmiUntag(ebx); 5419 __ SmiUntag(ebx);
5422 __ AllocateAsciiString(eax, ebx, ecx, edx, edi, &string_add_runtime); 5420 __ AllocateAsciiString(eax, ebx, ecx, edx, edi, &string_add_runtime);
5423 // eax: result string 5421 // eax: result string
5424 __ mov(ecx, eax); 5422 __ mov(ecx, eax);
5425 // Locate first character of result. 5423 // Locate first character of result.
5426 __ add(Operand(ecx), Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); 5424 __ add(ecx, Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag));
5427 // Load first argument and locate first character. 5425 // Load first argument and locate first character.
5428 __ mov(edx, Operand(esp, 2 * kPointerSize)); 5426 __ mov(edx, Operand(esp, 2 * kPointerSize));
5429 __ mov(edi, FieldOperand(edx, String::kLengthOffset)); 5427 __ mov(edi, FieldOperand(edx, String::kLengthOffset));
5430 __ SmiUntag(edi); 5428 __ SmiUntag(edi);
5431 __ add(Operand(edx), Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); 5429 __ add(edx, Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag));
5432 // eax: result string 5430 // eax: result string
5433 // ecx: first character of result 5431 // ecx: first character of result
5434 // edx: first char of first argument 5432 // edx: first char of first argument
5435 // edi: length of first argument 5433 // edi: length of first argument
5436 StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, true); 5434 StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, true);
5437 // Load second argument and locate first character. 5435 // Load second argument and locate first character.
5438 __ mov(edx, Operand(esp, 1 * kPointerSize)); 5436 __ mov(edx, Operand(esp, 1 * kPointerSize));
5439 __ mov(edi, FieldOperand(edx, String::kLengthOffset)); 5437 __ mov(edi, FieldOperand(edx, String::kLengthOffset));
5440 __ SmiUntag(edi); 5438 __ SmiUntag(edi);
5441 __ add(Operand(edx), Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); 5439 __ add(edx, Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag));
5442 // eax: result string 5440 // eax: result string
5443 // ecx: next character of result 5441 // ecx: next character of result
5444 // edx: first char of second argument 5442 // edx: first char of second argument
5445 // edi: length of second argument 5443 // edi: length of second argument
5446 StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, true); 5444 StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, true);
5447 __ IncrementCounter(counters->string_add_native(), 1); 5445 __ IncrementCounter(counters->string_add_native(), 1);
5448 __ ret(2 * kPointerSize); 5446 __ ret(2 * kPointerSize);
5449 5447
5450 // Handle creating a flat two byte result. 5448 // Handle creating a flat two byte result.
5451 // eax: first string - known to be two byte 5449 // eax: first string - known to be two byte
5452 // ebx: length of resulting flat string as a smi 5450 // ebx: length of resulting flat string as a smi
5453 // edx: second string 5451 // edx: second string
5454 __ bind(&non_ascii_string_add_flat_result); 5452 __ bind(&non_ascii_string_add_flat_result);
5455 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); 5453 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
5456 __ test_b(FieldOperand(ecx, Map::kInstanceTypeOffset), kStringEncodingMask); 5454 __ test_b(FieldOperand(ecx, Map::kInstanceTypeOffset), kStringEncodingMask);
5457 __ j(not_zero, &string_add_runtime); 5455 __ j(not_zero, &string_add_runtime);
5458 // Both strings are two byte strings. As they are short they are both 5456 // Both strings are two byte strings. As they are short they are both
5459 // flat. 5457 // flat.
5460 __ SmiUntag(ebx); 5458 __ SmiUntag(ebx);
5461 __ AllocateTwoByteString(eax, ebx, ecx, edx, edi, &string_add_runtime); 5459 __ AllocateTwoByteString(eax, ebx, ecx, edx, edi, &string_add_runtime);
5462 // eax: result string 5460 // eax: result string
5463 __ mov(ecx, eax); 5461 __ mov(ecx, eax);
5464 // Locate first character of result. 5462 // Locate first character of result.
5465 __ add(Operand(ecx), 5463 __ add(ecx,
5466 Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); 5464 Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
5467 // Load first argument and locate first character. 5465 // Load first argument and locate first character.
5468 __ mov(edx, Operand(esp, 2 * kPointerSize)); 5466 __ mov(edx, Operand(esp, 2 * kPointerSize));
5469 __ mov(edi, FieldOperand(edx, String::kLengthOffset)); 5467 __ mov(edi, FieldOperand(edx, String::kLengthOffset));
5470 __ SmiUntag(edi); 5468 __ SmiUntag(edi);
5471 __ add(Operand(edx), 5469 __ add(edx,
5472 Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); 5470 Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
5473 // eax: result string 5471 // eax: result string
5474 // ecx: first character of result 5472 // ecx: first character of result
5475 // edx: first char of first argument 5473 // edx: first char of first argument
5476 // edi: length of first argument 5474 // edi: length of first argument
5477 StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, false); 5475 StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, false);
5478 // Load second argument and locate first character. 5476 // Load second argument and locate first character.
5479 __ mov(edx, Operand(esp, 1 * kPointerSize)); 5477 __ mov(edx, Operand(esp, 1 * kPointerSize));
5480 __ mov(edi, FieldOperand(edx, String::kLengthOffset)); 5478 __ mov(edi, FieldOperand(edx, String::kLengthOffset));
5481 __ SmiUntag(edi); 5479 __ SmiUntag(edi);
5482 __ add(Operand(edx), Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); 5480 __ add(edx, Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag));
5483 // eax: result string 5481 // eax: result string
5484 // ecx: next character of result 5482 // ecx: next character of result
5485 // edx: first char of second argument 5483 // edx: first char of second argument
5486 // edi: length of second argument 5484 // edi: length of second argument
5487 StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, false); 5485 StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, false);
5488 __ IncrementCounter(counters->string_add_native(), 1); 5486 __ IncrementCounter(counters->string_add_native(), 1);
5489 __ ret(2 * kPointerSize); 5487 __ ret(2 * kPointerSize);
5490 5488
5491 // Just jump to runtime to add the two strings. 5489 // Just jump to runtime to add the two strings.
5492 __ bind(&string_add_runtime); 5490 __ bind(&string_add_runtime);
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
5548 Register count, 5546 Register count,
5549 Register scratch, 5547 Register scratch,
5550 bool ascii) { 5548 bool ascii) {
5551 Label loop; 5549 Label loop;
5552 __ bind(&loop); 5550 __ bind(&loop);
5553 // This loop just copies one character at a time, as it is only used for very 5551 // This loop just copies one character at a time, as it is only used for very
5554 // short strings. 5552 // short strings.
5555 if (ascii) { 5553 if (ascii) {
5556 __ mov_b(scratch, Operand(src, 0)); 5554 __ mov_b(scratch, Operand(src, 0));
5557 __ mov_b(Operand(dest, 0), scratch); 5555 __ mov_b(Operand(dest, 0), scratch);
5558 __ add(Operand(src), Immediate(1)); 5556 __ add(src, Immediate(1));
5559 __ add(Operand(dest), Immediate(1)); 5557 __ add(dest, Immediate(1));
5560 } else { 5558 } else {
5561 __ mov_w(scratch, Operand(src, 0)); 5559 __ mov_w(scratch, Operand(src, 0));
5562 __ mov_w(Operand(dest, 0), scratch); 5560 __ mov_w(Operand(dest, 0), scratch);
5563 __ add(Operand(src), Immediate(2)); 5561 __ add(src, Immediate(2));
5564 __ add(Operand(dest), Immediate(2)); 5562 __ add(dest, Immediate(2));
5565 } 5563 }
5566 __ sub(Operand(count), Immediate(1)); 5564 __ sub(count, Immediate(1));
5567 __ j(not_zero, &loop); 5565 __ j(not_zero, &loop);
5568 } 5566 }
5569 5567
5570 5568
5571 void StringHelper::GenerateCopyCharactersREP(MacroAssembler* masm, 5569 void StringHelper::GenerateCopyCharactersREP(MacroAssembler* masm,
5572 Register dest, 5570 Register dest,
5573 Register src, 5571 Register src,
5574 Register count, 5572 Register count,
5575 Register scratch, 5573 Register scratch,
5576 bool ascii) { 5574 bool ascii) {
5577 // Copy characters using rep movs of doublewords. 5575 // Copy characters using rep movs of doublewords.
5578 // The destination is aligned on a 4 byte boundary because we are 5576 // The destination is aligned on a 4 byte boundary because we are
5579 // copying to the beginning of a newly allocated string. 5577 // copying to the beginning of a newly allocated string.
5580 ASSERT(dest.is(edi)); // rep movs destination 5578 ASSERT(dest.is(edi)); // rep movs destination
5581 ASSERT(src.is(esi)); // rep movs source 5579 ASSERT(src.is(esi)); // rep movs source
5582 ASSERT(count.is(ecx)); // rep movs count 5580 ASSERT(count.is(ecx)); // rep movs count
5583 ASSERT(!scratch.is(dest)); 5581 ASSERT(!scratch.is(dest));
5584 ASSERT(!scratch.is(src)); 5582 ASSERT(!scratch.is(src));
5585 ASSERT(!scratch.is(count)); 5583 ASSERT(!scratch.is(count));
5586 5584
5587 // Nothing to do for zero characters. 5585 // Nothing to do for zero characters.
5588 Label done; 5586 Label done;
5589 __ test(count, Operand(count)); 5587 __ test(count, count);
5590 __ j(zero, &done); 5588 __ j(zero, &done);
5591 5589
5592 // Make count the number of bytes to copy. 5590 // Make count the number of bytes to copy.
5593 if (!ascii) { 5591 if (!ascii) {
5594 __ shl(count, 1); 5592 __ shl(count, 1);
5595 } 5593 }
5596 5594
5597 // Don't enter the rep movs if there are less than 4 bytes to copy. 5595 // Don't enter the rep movs if there are less than 4 bytes to copy.
5598 Label last_bytes; 5596 Label last_bytes;
5599 __ test(count, Immediate(~3)); 5597 __ test(count, Immediate(~3));
5600 __ j(zero, &last_bytes, Label::kNear); 5598 __ j(zero, &last_bytes, Label::kNear);
5601 5599
5602 // Copy from edi to esi using rep movs instruction. 5600 // Copy from edi to esi using rep movs instruction.
5603 __ mov(scratch, count); 5601 __ mov(scratch, count);
5604 __ sar(count, 2); // Number of doublewords to copy. 5602 __ sar(count, 2); // Number of doublewords to copy.
5605 __ cld(); 5603 __ cld();
5606 __ rep_movs(); 5604 __ rep_movs();
5607 5605
5608 // Find number of bytes left. 5606 // Find number of bytes left.
5609 __ mov(count, scratch); 5607 __ mov(count, scratch);
5610 __ and_(count, 3); 5608 __ and_(count, 3);
5611 5609
5612 // Check if there are more bytes to copy. 5610 // Check if there are more bytes to copy.
5613 __ bind(&last_bytes); 5611 __ bind(&last_bytes);
5614 __ test(count, Operand(count)); 5612 __ test(count, count);
5615 __ j(zero, &done); 5613 __ j(zero, &done);
5616 5614
5617 // Copy remaining characters. 5615 // Copy remaining characters.
5618 Label loop; 5616 Label loop;
5619 __ bind(&loop); 5617 __ bind(&loop);
5620 __ mov_b(scratch, Operand(src, 0)); 5618 __ mov_b(scratch, Operand(src, 0));
5621 __ mov_b(Operand(dest, 0), scratch); 5619 __ mov_b(Operand(dest, 0), scratch);
5622 __ add(Operand(src), Immediate(1)); 5620 __ add(src, Immediate(1));
5623 __ add(Operand(dest), Immediate(1)); 5621 __ add(dest, Immediate(1));
5624 __ sub(Operand(count), Immediate(1)); 5622 __ sub(count, Immediate(1));
5625 __ j(not_zero, &loop); 5623 __ j(not_zero, &loop);
5626 5624
5627 __ bind(&done); 5625 __ bind(&done);
5628 } 5626 }
5629 5627
5630 5628
5631 void StringHelper::GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm, 5629 void StringHelper::GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm,
5632 Register c1, 5630 Register c1,
5633 Register c2, 5631 Register c2,
5634 Register scratch1, 5632 Register scratch1,
5635 Register scratch2, 5633 Register scratch2,
5636 Register scratch3, 5634 Register scratch3,
5637 Label* not_probed, 5635 Label* not_probed,
5638 Label* not_found) { 5636 Label* not_found) {
5639 // Register scratch3 is the general scratch register in this function. 5637 // Register scratch3 is the general scratch register in this function.
5640 Register scratch = scratch3; 5638 Register scratch = scratch3;
5641 5639
5642 // Make sure that both characters are not digits as such strings has a 5640 // Make sure that both characters are not digits as such strings has a
5643 // different hash algorithm. Don't try to look for these in the symbol table. 5641 // different hash algorithm. Don't try to look for these in the symbol table.
5644 Label not_array_index; 5642 Label not_array_index;
5645 __ mov(scratch, c1); 5643 __ mov(scratch, c1);
5646 __ sub(Operand(scratch), Immediate(static_cast<int>('0'))); 5644 __ sub(scratch, Immediate(static_cast<int>('0')));
5647 __ cmp(Operand(scratch), Immediate(static_cast<int>('9' - '0'))); 5645 __ cmp(scratch, Immediate(static_cast<int>('9' - '0')));
5648 __ j(above, &not_array_index, Label::kNear); 5646 __ j(above, &not_array_index, Label::kNear);
5649 __ mov(scratch, c2); 5647 __ mov(scratch, c2);
5650 __ sub(Operand(scratch), Immediate(static_cast<int>('0'))); 5648 __ sub(scratch, Immediate(static_cast<int>('0')));
5651 __ cmp(Operand(scratch), Immediate(static_cast<int>('9' - '0'))); 5649 __ cmp(scratch, Immediate(static_cast<int>('9' - '0')));
5652 __ j(below_equal, not_probed); 5650 __ j(below_equal, not_probed);
5653 5651
5654 __ bind(&not_array_index); 5652 __ bind(&not_array_index);
5655 // Calculate the two character string hash. 5653 // Calculate the two character string hash.
5656 Register hash = scratch1; 5654 Register hash = scratch1;
5657 GenerateHashInit(masm, hash, c1, scratch); 5655 GenerateHashInit(masm, hash, c1, scratch);
5658 GenerateHashAddCharacter(masm, hash, c2, scratch); 5656 GenerateHashAddCharacter(masm, hash, c2, scratch);
5659 GenerateHashGetHash(masm, hash, scratch); 5657 GenerateHashGetHash(masm, hash, scratch);
5660 5658
5661 // Collect the two characters in a register. 5659 // Collect the two characters in a register.
5662 Register chars = c1; 5660 Register chars = c1;
5663 __ shl(c2, kBitsPerByte); 5661 __ shl(c2, kBitsPerByte);
5664 __ or_(chars, Operand(c2)); 5662 __ or_(chars, c2);
5665 5663
5666 // chars: two character string, char 1 in byte 0 and char 2 in byte 1. 5664 // chars: two character string, char 1 in byte 0 and char 2 in byte 1.
5667 // hash: hash of two character string. 5665 // hash: hash of two character string.
5668 5666
5669 // Load the symbol table. 5667 // Load the symbol table.
5670 Register symbol_table = c2; 5668 Register symbol_table = c2;
5671 ExternalReference roots_address = 5669 ExternalReference roots_address =
5672 ExternalReference::roots_address(masm->isolate()); 5670 ExternalReference::roots_address(masm->isolate());
5673 __ mov(scratch, Immediate(Heap::kSymbolTableRootIndex)); 5671 __ mov(scratch, Immediate(Heap::kSymbolTableRootIndex));
5674 __ mov(symbol_table, 5672 __ mov(symbol_table,
5675 Operand::StaticArray(scratch, times_pointer_size, roots_address)); 5673 Operand::StaticArray(scratch, times_pointer_size, roots_address));
5676 5674
5677 // Calculate capacity mask from the symbol table capacity. 5675 // Calculate capacity mask from the symbol table capacity.
5678 Register mask = scratch2; 5676 Register mask = scratch2;
5679 __ mov(mask, FieldOperand(symbol_table, SymbolTable::kCapacityOffset)); 5677 __ mov(mask, FieldOperand(symbol_table, SymbolTable::kCapacityOffset));
5680 __ SmiUntag(mask); 5678 __ SmiUntag(mask);
5681 __ sub(Operand(mask), Immediate(1)); 5679 __ sub(mask, Immediate(1));
5682 5680
5683 // Registers 5681 // Registers
5684 // chars: two character string, char 1 in byte 0 and char 2 in byte 1. 5682 // chars: two character string, char 1 in byte 0 and char 2 in byte 1.
5685 // hash: hash of two character string 5683 // hash: hash of two character string
5686 // symbol_table: symbol table 5684 // symbol_table: symbol table
5687 // mask: capacity mask 5685 // mask: capacity mask
5688 // scratch: - 5686 // scratch: -
5689 5687
5690 // Perform a number of probes in the symbol table. 5688 // Perform a number of probes in the symbol table.
5691 static const int kProbes = 4; 5689 static const int kProbes = 4;
5692 Label found_in_symbol_table; 5690 Label found_in_symbol_table;
5693 Label next_probe[kProbes], next_probe_pop_mask[kProbes]; 5691 Label next_probe[kProbes], next_probe_pop_mask[kProbes];
5694 for (int i = 0; i < kProbes; i++) { 5692 for (int i = 0; i < kProbes; i++) {
5695 // Calculate entry in symbol table. 5693 // Calculate entry in symbol table.
5696 __ mov(scratch, hash); 5694 __ mov(scratch, hash);
5697 if (i > 0) { 5695 if (i > 0) {
5698 __ add(Operand(scratch), Immediate(SymbolTable::GetProbeOffset(i))); 5696 __ add(scratch, Immediate(SymbolTable::GetProbeOffset(i)));
5699 } 5697 }
5700 __ and_(scratch, Operand(mask)); 5698 __ and_(scratch, mask);
5701 5699
5702 // Load the entry from the symbol table. 5700 // Load the entry from the symbol table.
5703 Register candidate = scratch; // Scratch register contains candidate. 5701 Register candidate = scratch; // Scratch register contains candidate.
5704 STATIC_ASSERT(SymbolTable::kEntrySize == 1); 5702 STATIC_ASSERT(SymbolTable::kEntrySize == 1);
5705 __ mov(candidate, 5703 __ mov(candidate,
5706 FieldOperand(symbol_table, 5704 FieldOperand(symbol_table,
5707 scratch, 5705 scratch,
5708 times_pointer_size, 5706 times_pointer_size,
5709 SymbolTable::kElementsStartOffset)); 5707 SymbolTable::kElementsStartOffset));
5710 5708
(...skipping 16 matching lines...) Expand all
5727 5725
5728 // Check that the candidate is a non-external ascii string. 5726 // Check that the candidate is a non-external ascii string.
5729 __ mov(temp, FieldOperand(candidate, HeapObject::kMapOffset)); 5727 __ mov(temp, FieldOperand(candidate, HeapObject::kMapOffset));
5730 __ movzx_b(temp, FieldOperand(temp, Map::kInstanceTypeOffset)); 5728 __ movzx_b(temp, FieldOperand(temp, Map::kInstanceTypeOffset));
5731 __ JumpIfInstanceTypeIsNotSequentialAscii( 5729 __ JumpIfInstanceTypeIsNotSequentialAscii(
5732 temp, temp, &next_probe_pop_mask[i]); 5730 temp, temp, &next_probe_pop_mask[i]);
5733 5731
5734 // Check if the two characters match. 5732 // Check if the two characters match.
5735 __ mov(temp, FieldOperand(candidate, SeqAsciiString::kHeaderSize)); 5733 __ mov(temp, FieldOperand(candidate, SeqAsciiString::kHeaderSize));
5736 __ and_(temp, 0x0000ffff); 5734 __ and_(temp, 0x0000ffff);
5737 __ cmp(chars, Operand(temp)); 5735 __ cmp(chars, temp);
5738 __ j(equal, &found_in_symbol_table); 5736 __ j(equal, &found_in_symbol_table);
5739 __ bind(&next_probe_pop_mask[i]); 5737 __ bind(&next_probe_pop_mask[i]);
5740 __ pop(mask); 5738 __ pop(mask);
5741 __ bind(&next_probe[i]); 5739 __ bind(&next_probe[i]);
5742 } 5740 }
5743 5741
5744 // No matching 2 character string found by probing. 5742 // No matching 2 character string found by probing.
5745 __ jmp(not_found); 5743 __ jmp(not_found);
5746 5744
5747 // Scratch register contains result when we fall through to here. 5745 // Scratch register contains result when we fall through to here.
5748 Register result = scratch; 5746 Register result = scratch;
5749 __ bind(&found_in_symbol_table); 5747 __ bind(&found_in_symbol_table);
5750 __ pop(mask); // Pop saved mask from the stack. 5748 __ pop(mask); // Pop saved mask from the stack.
5751 if (!result.is(eax)) { 5749 if (!result.is(eax)) {
5752 __ mov(eax, result); 5750 __ mov(eax, result);
5753 } 5751 }
5754 } 5752 }
5755 5753
5756 5754
5757 void StringHelper::GenerateHashInit(MacroAssembler* masm, 5755 void StringHelper::GenerateHashInit(MacroAssembler* masm,
5758 Register hash, 5756 Register hash,
5759 Register character, 5757 Register character,
5760 Register scratch) { 5758 Register scratch) {
5761 // hash = character + (character << 10); 5759 // hash = character + (character << 10);
5762 __ mov(hash, character); 5760 __ mov(hash, character);
5763 __ shl(hash, 10); 5761 __ shl(hash, 10);
5764 __ add(hash, Operand(character)); 5762 __ add(hash, character);
5765 // hash ^= hash >> 6; 5763 // hash ^= hash >> 6;
5766 __ mov(scratch, hash); 5764 __ mov(scratch, hash);
5767 __ sar(scratch, 6); 5765 __ sar(scratch, 6);
5768 __ xor_(hash, Operand(scratch)); 5766 __ xor_(hash, scratch);
5769 } 5767 }
5770 5768
5771 5769
5772 void StringHelper::GenerateHashAddCharacter(MacroAssembler* masm, 5770 void StringHelper::GenerateHashAddCharacter(MacroAssembler* masm,
5773 Register hash, 5771 Register hash,
5774 Register character, 5772 Register character,
5775 Register scratch) { 5773 Register scratch) {
5776 // hash += character; 5774 // hash += character;
5777 __ add(hash, Operand(character)); 5775 __ add(hash, character);
5778 // hash += hash << 10; 5776 // hash += hash << 10;
5779 __ mov(scratch, hash); 5777 __ mov(scratch, hash);
5780 __ shl(scratch, 10); 5778 __ shl(scratch, 10);
5781 __ add(hash, Operand(scratch)); 5779 __ add(hash, scratch);
5782 // hash ^= hash >> 6; 5780 // hash ^= hash >> 6;
5783 __ mov(scratch, hash); 5781 __ mov(scratch, hash);
5784 __ sar(scratch, 6); 5782 __ sar(scratch, 6);
5785 __ xor_(hash, Operand(scratch)); 5783 __ xor_(hash, scratch);
5786 } 5784 }
5787 5785
5788 5786
5789 void StringHelper::GenerateHashGetHash(MacroAssembler* masm, 5787 void StringHelper::GenerateHashGetHash(MacroAssembler* masm,
5790 Register hash, 5788 Register hash,
5791 Register scratch) { 5789 Register scratch) {
5792 // hash += hash << 3; 5790 // hash += hash << 3;
5793 __ mov(scratch, hash); 5791 __ mov(scratch, hash);
5794 __ shl(scratch, 3); 5792 __ shl(scratch, 3);
5795 __ add(hash, Operand(scratch)); 5793 __ add(hash, scratch);
5796 // hash ^= hash >> 11; 5794 // hash ^= hash >> 11;
5797 __ mov(scratch, hash); 5795 __ mov(scratch, hash);
5798 __ sar(scratch, 11); 5796 __ sar(scratch, 11);
5799 __ xor_(hash, Operand(scratch)); 5797 __ xor_(hash, scratch);
5800 // hash += hash << 15; 5798 // hash += hash << 15;
5801 __ mov(scratch, hash); 5799 __ mov(scratch, hash);
5802 __ shl(scratch, 15); 5800 __ shl(scratch, 15);
5803 __ add(hash, Operand(scratch)); 5801 __ add(hash, scratch);
5804 5802
5805 // if (hash == 0) hash = 27; 5803 // if (hash == 0) hash = 27;
5806 Label hash_not_zero; 5804 Label hash_not_zero;
5807 __ test(hash, Operand(hash)); 5805 __ test(hash, hash);
5808 __ j(not_zero, &hash_not_zero, Label::kNear); 5806 __ j(not_zero, &hash_not_zero, Label::kNear);
5809 __ mov(hash, Immediate(27)); 5807 __ mov(hash, Immediate(27));
5810 __ bind(&hash_not_zero); 5808 __ bind(&hash_not_zero);
5811 } 5809 }
5812 5810
5813 5811
5814 void SubStringStub::Generate(MacroAssembler* masm) { 5812 void SubStringStub::Generate(MacroAssembler* masm) {
5815 Label runtime; 5813 Label runtime;
5816 5814
5817 // Stack frame on entry. 5815 // Stack frame on entry.
(...skipping 11 matching lines...) Expand all
5829 5827
5830 // eax: string 5828 // eax: string
5831 // ebx: instance type 5829 // ebx: instance type
5832 5830
5833 // Calculate length of sub string using the smi values. 5831 // Calculate length of sub string using the smi values.
5834 Label result_longer_than_two; 5832 Label result_longer_than_two;
5835 __ mov(ecx, Operand(esp, 1 * kPointerSize)); // To index. 5833 __ mov(ecx, Operand(esp, 1 * kPointerSize)); // To index.
5836 __ JumpIfNotSmi(ecx, &runtime); 5834 __ JumpIfNotSmi(ecx, &runtime);
5837 __ mov(edx, Operand(esp, 2 * kPointerSize)); // From index. 5835 __ mov(edx, Operand(esp, 2 * kPointerSize)); // From index.
5838 __ JumpIfNotSmi(edx, &runtime); 5836 __ JumpIfNotSmi(edx, &runtime);
5839 __ sub(ecx, Operand(edx)); 5837 __ sub(ecx, edx);
5840 __ cmp(ecx, FieldOperand(eax, String::kLengthOffset)); 5838 __ cmp(ecx, FieldOperand(eax, String::kLengthOffset));
5841 Label return_eax; 5839 Label return_eax;
5842 __ j(equal, &return_eax); 5840 __ j(equal, &return_eax);
5843 // Special handling of sub-strings of length 1 and 2. One character strings 5841 // Special handling of sub-strings of length 1 and 2. One character strings
5844 // are handled in the runtime system (looked up in the single character 5842 // are handled in the runtime system (looked up in the single character
5845 // cache). Two character strings are looked for in the symbol cache. 5843 // cache). Two character strings are looked for in the symbol cache.
5846 __ SmiUntag(ecx); // Result length is no longer smi. 5844 __ SmiUntag(ecx); // Result length is no longer smi.
5847 __ cmp(ecx, 2); 5845 __ cmp(ecx, 2);
5848 __ j(greater, &result_longer_than_two); 5846 __ j(greater, &result_longer_than_two);
5849 __ j(less, &runtime); 5847 __ j(less, &runtime);
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after
5961 __ JumpIfInstanceTypeIsNotSequentialAscii(ebx, ebx, &non_ascii_flat); 5959 __ JumpIfInstanceTypeIsNotSequentialAscii(ebx, ebx, &non_ascii_flat);
5962 5960
5963 // Allocate the result. 5961 // Allocate the result.
5964 __ AllocateAsciiString(eax, ecx, ebx, edx, edi, &runtime); 5962 __ AllocateAsciiString(eax, ecx, ebx, edx, edi, &runtime);
5965 5963
5966 // eax: result string 5964 // eax: result string
5967 // ecx: result string length 5965 // ecx: result string length
5968 __ mov(edx, esi); // esi used by following code. 5966 __ mov(edx, esi); // esi used by following code.
5969 // Locate first character of result. 5967 // Locate first character of result.
5970 __ mov(edi, eax); 5968 __ mov(edi, eax);
5971 __ add(Operand(edi), Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); 5969 __ add(edi, Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag));
5972 // Load string argument and locate character of sub string start. 5970 // Load string argument and locate character of sub string start.
5973 __ mov(esi, Operand(esp, 3 * kPointerSize)); 5971 __ mov(esi, Operand(esp, 3 * kPointerSize));
5974 __ add(Operand(esi), Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); 5972 __ add(esi, Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag));
5975 __ mov(ebx, Operand(esp, 2 * kPointerSize)); // from 5973 __ mov(ebx, Operand(esp, 2 * kPointerSize)); // from
5976 __ SmiUntag(ebx); 5974 __ SmiUntag(ebx);
5977 __ add(esi, Operand(ebx)); 5975 __ add(esi, ebx);
5978 5976
5979 // eax: result string 5977 // eax: result string
5980 // ecx: result length 5978 // ecx: result length
5981 // edx: original value of esi 5979 // edx: original value of esi
5982 // edi: first character of result 5980 // edi: first character of result
5983 // esi: character of sub string start 5981 // esi: character of sub string start
5984 StringHelper::GenerateCopyCharactersREP(masm, edi, esi, ecx, ebx, true); 5982 StringHelper::GenerateCopyCharactersREP(masm, edi, esi, ecx, ebx, true);
5985 __ mov(esi, edx); // Restore esi. 5983 __ mov(esi, edx); // Restore esi.
5986 Counters* counters = masm->isolate()->counters(); 5984 Counters* counters = masm->isolate()->counters();
5987 __ IncrementCounter(counters->sub_string_native(), 1); 5985 __ IncrementCounter(counters->sub_string_native(), 1);
5988 __ ret(3 * kPointerSize); 5986 __ ret(3 * kPointerSize);
5989 5987
5990 __ bind(&non_ascii_flat); 5988 __ bind(&non_ascii_flat);
5991 // eax: string 5989 // eax: string
5992 // ebx: instance type & kStringRepresentationMask | kStringEncodingMask 5990 // ebx: instance type & kStringRepresentationMask | kStringEncodingMask
5993 // ecx: result string length 5991 // ecx: result string length
5994 // Check for flat two byte string 5992 // Check for flat two byte string
5995 __ cmp(ebx, kSeqStringTag | kTwoByteStringTag); 5993 __ cmp(ebx, kSeqStringTag | kTwoByteStringTag);
5996 __ j(not_equal, &runtime); 5994 __ j(not_equal, &runtime);
5997 5995
5998 // Allocate the result. 5996 // Allocate the result.
5999 __ AllocateTwoByteString(eax, ecx, ebx, edx, edi, &runtime); 5997 __ AllocateTwoByteString(eax, ecx, ebx, edx, edi, &runtime);
6000 5998
6001 // eax: result string 5999 // eax: result string
6002 // ecx: result string length 6000 // ecx: result string length
6003 __ mov(edx, esi); // esi used by following code. 6001 __ mov(edx, esi); // esi used by following code.
6004 // Locate first character of result. 6002 // Locate first character of result.
6005 __ mov(edi, eax); 6003 __ mov(edi, eax);
6006 __ add(Operand(edi), 6004 __ add(edi,
6007 Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); 6005 Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
6008 // Load string argument and locate character of sub string start. 6006 // Load string argument and locate character of sub string start.
6009 __ mov(esi, Operand(esp, 3 * kPointerSize)); 6007 __ mov(esi, Operand(esp, 3 * kPointerSize));
6010 __ add(Operand(esi), 6008 __ add(esi, Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
6011 Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
6012 __ mov(ebx, Operand(esp, 2 * kPointerSize)); // from 6009 __ mov(ebx, Operand(esp, 2 * kPointerSize)); // from
6013 // As from is a smi it is 2 times the value which matches the size of a two 6010 // As from is a smi it is 2 times the value which matches the size of a two
6014 // byte character. 6011 // byte character.
6015 STATIC_ASSERT(kSmiTag == 0); 6012 STATIC_ASSERT(kSmiTag == 0);
6016 STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1); 6013 STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1);
6017 __ add(esi, Operand(ebx)); 6014 __ add(esi, ebx);
6018 6015
6019 // eax: result string 6016 // eax: result string
6020 // ecx: result length 6017 // ecx: result length
6021 // edx: original value of esi 6018 // edx: original value of esi
6022 // edi: first character of result 6019 // edi: first character of result
6023 // esi: character of sub string start 6020 // esi: character of sub string start
6024 StringHelper::GenerateCopyCharactersREP(masm, edi, esi, ecx, ebx, false); 6021 StringHelper::GenerateCopyCharactersREP(masm, edi, esi, ecx, ebx, false);
6025 __ mov(esi, edx); // Restore esi. 6022 __ mov(esi, edx); // Restore esi.
6026 6023
6027 __ bind(&return_eax); 6024 __ bind(&return_eax);
(...skipping 19 matching lines...) Expand all
6047 __ cmp(length, FieldOperand(right, String::kLengthOffset)); 6044 __ cmp(length, FieldOperand(right, String::kLengthOffset));
6048 __ j(equal, &check_zero_length, Label::kNear); 6045 __ j(equal, &check_zero_length, Label::kNear);
6049 __ bind(&strings_not_equal); 6046 __ bind(&strings_not_equal);
6050 __ Set(eax, Immediate(Smi::FromInt(NOT_EQUAL))); 6047 __ Set(eax, Immediate(Smi::FromInt(NOT_EQUAL)));
6051 __ ret(0); 6048 __ ret(0);
6052 6049
6053 // Check if the length is zero. 6050 // Check if the length is zero.
6054 Label compare_chars; 6051 Label compare_chars;
6055 __ bind(&check_zero_length); 6052 __ bind(&check_zero_length);
6056 STATIC_ASSERT(kSmiTag == 0); 6053 STATIC_ASSERT(kSmiTag == 0);
6057 __ test(length, Operand(length)); 6054 __ test(length, length);
6058 __ j(not_zero, &compare_chars, Label::kNear); 6055 __ j(not_zero, &compare_chars, Label::kNear);
6059 __ Set(eax, Immediate(Smi::FromInt(EQUAL))); 6056 __ Set(eax, Immediate(Smi::FromInt(EQUAL)));
6060 __ ret(0); 6057 __ ret(0);
6061 6058
6062 // Compare characters. 6059 // Compare characters.
6063 __ bind(&compare_chars); 6060 __ bind(&compare_chars);
6064 GenerateAsciiCharsCompareLoop(masm, left, right, length, scratch2, 6061 GenerateAsciiCharsCompareLoop(masm, left, right, length, scratch2,
6065 &strings_not_equal, Label::kNear); 6062 &strings_not_equal, Label::kNear);
6066 6063
6067 // Characters are equal. 6064 // Characters are equal.
(...skipping 14 matching lines...) Expand all
6082 // Find minimum length. 6079 // Find minimum length.
6083 Label left_shorter; 6080 Label left_shorter;
6084 __ mov(scratch1, FieldOperand(left, String::kLengthOffset)); 6081 __ mov(scratch1, FieldOperand(left, String::kLengthOffset));
6085 __ mov(scratch3, scratch1); 6082 __ mov(scratch3, scratch1);
6086 __ sub(scratch3, FieldOperand(right, String::kLengthOffset)); 6083 __ sub(scratch3, FieldOperand(right, String::kLengthOffset));
6087 6084
6088 Register length_delta = scratch3; 6085 Register length_delta = scratch3;
6089 6086
6090 __ j(less_equal, &left_shorter, Label::kNear); 6087 __ j(less_equal, &left_shorter, Label::kNear);
6091 // Right string is shorter. Change scratch1 to be length of right string. 6088 // Right string is shorter. Change scratch1 to be length of right string.
6092 __ sub(scratch1, Operand(length_delta)); 6089 __ sub(scratch1, length_delta);
6093 __ bind(&left_shorter); 6090 __ bind(&left_shorter);
6094 6091
6095 Register min_length = scratch1; 6092 Register min_length = scratch1;
6096 6093
6097 // If either length is zero, just compare lengths. 6094 // If either length is zero, just compare lengths.
6098 Label compare_lengths; 6095 Label compare_lengths;
6099 __ test(min_length, Operand(min_length)); 6096 __ test(min_length, min_length);
6100 __ j(zero, &compare_lengths, Label::kNear); 6097 __ j(zero, &compare_lengths, Label::kNear);
6101 6098
6102 // Compare characters. 6099 // Compare characters.
6103 Label result_not_equal; 6100 Label result_not_equal;
6104 GenerateAsciiCharsCompareLoop(masm, left, right, min_length, scratch2, 6101 GenerateAsciiCharsCompareLoop(masm, left, right, min_length, scratch2,
6105 &result_not_equal, Label::kNear); 6102 &result_not_equal, Label::kNear);
6106 6103
6107 // Compare lengths - strings up to min-length are equal. 6104 // Compare lengths - strings up to min-length are equal.
6108 __ bind(&compare_lengths); 6105 __ bind(&compare_lengths);
6109 __ test(length_delta, Operand(length_delta)); 6106 __ test(length_delta, length_delta);
6110 __ j(not_zero, &result_not_equal, Label::kNear); 6107 __ j(not_zero, &result_not_equal, Label::kNear);
6111 6108
6112 // Result is EQUAL. 6109 // Result is EQUAL.
6113 STATIC_ASSERT(EQUAL == 0); 6110 STATIC_ASSERT(EQUAL == 0);
6114 STATIC_ASSERT(kSmiTag == 0); 6111 STATIC_ASSERT(kSmiTag == 0);
6115 __ Set(eax, Immediate(Smi::FromInt(EQUAL))); 6112 __ Set(eax, Immediate(Smi::FromInt(EQUAL)));
6116 __ ret(0); 6113 __ ret(0);
6117 6114
6118 Label result_greater; 6115 Label result_greater;
6119 __ bind(&result_not_equal); 6116 __ bind(&result_not_equal);
(...skipping 28 matching lines...) Expand all
6148 FieldOperand(right, length, times_1, SeqAsciiString::kHeaderSize)); 6145 FieldOperand(right, length, times_1, SeqAsciiString::kHeaderSize));
6149 __ neg(length); 6146 __ neg(length);
6150 Register index = length; // index = -length; 6147 Register index = length; // index = -length;
6151 6148
6152 // Compare loop. 6149 // Compare loop.
6153 Label loop; 6150 Label loop;
6154 __ bind(&loop); 6151 __ bind(&loop);
6155 __ mov_b(scratch, Operand(left, index, times_1, 0)); 6152 __ mov_b(scratch, Operand(left, index, times_1, 0));
6156 __ cmpb(scratch, Operand(right, index, times_1, 0)); 6153 __ cmpb(scratch, Operand(right, index, times_1, 0));
6157 __ j(not_equal, chars_not_equal, chars_not_equal_near); 6154 __ j(not_equal, chars_not_equal, chars_not_equal_near);
6158 __ add(Operand(index), Immediate(1)); 6155 __ add(index, Immediate(1));
6159 __ j(not_zero, &loop); 6156 __ j(not_zero, &loop);
6160 } 6157 }
6161 6158
6162 6159
6163 void StringCompareStub::Generate(MacroAssembler* masm) { 6160 void StringCompareStub::Generate(MacroAssembler* masm) {
6164 Label runtime; 6161 Label runtime;
6165 6162
6166 // Stack frame on entry. 6163 // Stack frame on entry.
6167 // esp[0]: return address 6164 // esp[0]: return address
6168 // esp[4]: right string 6165 // esp[4]: right string
6169 // esp[8]: left string 6166 // esp[8]: left string
6170 6167
6171 __ mov(edx, Operand(esp, 2 * kPointerSize)); // left 6168 __ mov(edx, Operand(esp, 2 * kPointerSize)); // left
6172 __ mov(eax, Operand(esp, 1 * kPointerSize)); // right 6169 __ mov(eax, Operand(esp, 1 * kPointerSize)); // right
6173 6170
6174 Label not_same; 6171 Label not_same;
6175 __ cmp(edx, Operand(eax)); 6172 __ cmp(edx, eax);
6176 __ j(not_equal, &not_same, Label::kNear); 6173 __ j(not_equal, &not_same, Label::kNear);
6177 STATIC_ASSERT(EQUAL == 0); 6174 STATIC_ASSERT(EQUAL == 0);
6178 STATIC_ASSERT(kSmiTag == 0); 6175 STATIC_ASSERT(kSmiTag == 0);
6179 __ Set(eax, Immediate(Smi::FromInt(EQUAL))); 6176 __ Set(eax, Immediate(Smi::FromInt(EQUAL)));
6180 __ IncrementCounter(masm->isolate()->counters()->string_compare_native(), 1); 6177 __ IncrementCounter(masm->isolate()->counters()->string_compare_native(), 1);
6181 __ ret(2 * kPointerSize); 6178 __ ret(2 * kPointerSize);
6182 6179
6183 __ bind(&not_same); 6180 __ bind(&not_same);
6184 6181
6185 // Check that both objects are sequential ascii strings. 6182 // Check that both objects are sequential ascii strings.
6186 __ JumpIfNotBothSequentialAsciiStrings(edx, eax, ecx, ebx, &runtime); 6183 __ JumpIfNotBothSequentialAsciiStrings(edx, eax, ecx, ebx, &runtime);
6187 6184
6188 // Compare flat ascii strings. 6185 // Compare flat ascii strings.
6189 // Drop arguments from the stack. 6186 // Drop arguments from the stack.
6190 __ pop(ecx); 6187 __ pop(ecx);
6191 __ add(Operand(esp), Immediate(2 * kPointerSize)); 6188 __ add(esp, Immediate(2 * kPointerSize));
6192 __ push(ecx); 6189 __ push(ecx);
6193 GenerateCompareFlatAsciiStrings(masm, edx, eax, ecx, ebx, edi); 6190 GenerateCompareFlatAsciiStrings(masm, edx, eax, ecx, ebx, edi);
6194 6191
6195 // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater) 6192 // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater)
6196 // tagged as a small integer. 6193 // tagged as a small integer.
6197 __ bind(&runtime); 6194 __ bind(&runtime);
6198 __ TailCallRuntime(Runtime::kStringCompare, 2, 1); 6195 __ TailCallRuntime(Runtime::kStringCompare, 2, 1);
6199 } 6196 }
6200 6197
6201 6198
6202 void ICCompareStub::GenerateSmis(MacroAssembler* masm) { 6199 void ICCompareStub::GenerateSmis(MacroAssembler* masm) {
6203 ASSERT(state_ == CompareIC::SMIS); 6200 ASSERT(state_ == CompareIC::SMIS);
6204 Label miss; 6201 Label miss;
6205 __ mov(ecx, Operand(edx)); 6202 __ mov(ecx, edx);
6206 __ or_(ecx, Operand(eax)); 6203 __ or_(ecx, eax);
6207 __ JumpIfNotSmi(ecx, &miss, Label::kNear); 6204 __ JumpIfNotSmi(ecx, &miss, Label::kNear);
6208 6205
6209 if (GetCondition() == equal) { 6206 if (GetCondition() == equal) {
6210 // For equality we do not care about the sign of the result. 6207 // For equality we do not care about the sign of the result.
6211 __ sub(eax, Operand(edx)); 6208 __ sub(eax, edx);
6212 } else { 6209 } else {
6213 Label done; 6210 Label done;
6214 __ sub(edx, Operand(eax)); 6211 __ sub(edx, eax);
6215 __ j(no_overflow, &done, Label::kNear); 6212 __ j(no_overflow, &done, Label::kNear);
6216 // Correct sign of result in case of overflow. 6213 // Correct sign of result in case of overflow.
6217 __ not_(edx); 6214 __ not_(edx);
6218 __ bind(&done); 6215 __ bind(&done);
6219 __ mov(eax, edx); 6216 __ mov(eax, edx);
6220 } 6217 }
6221 __ ret(0); 6218 __ ret(0);
6222 6219
6223 __ bind(&miss); 6220 __ bind(&miss);
6224 GenerateMiss(masm); 6221 GenerateMiss(masm);
6225 } 6222 }
6226 6223
6227 6224
6228 void ICCompareStub::GenerateHeapNumbers(MacroAssembler* masm) { 6225 void ICCompareStub::GenerateHeapNumbers(MacroAssembler* masm) {
6229 ASSERT(state_ == CompareIC::HEAP_NUMBERS); 6226 ASSERT(state_ == CompareIC::HEAP_NUMBERS);
6230 6227
6231 Label generic_stub; 6228 Label generic_stub;
6232 Label unordered; 6229 Label unordered;
6233 Label miss; 6230 Label miss;
6234 __ mov(ecx, Operand(edx)); 6231 __ mov(ecx, edx);
6235 __ and_(ecx, Operand(eax)); 6232 __ and_(ecx, eax);
6236 __ JumpIfSmi(ecx, &generic_stub, Label::kNear); 6233 __ JumpIfSmi(ecx, &generic_stub, Label::kNear);
6237 6234
6238 __ CmpObjectType(eax, HEAP_NUMBER_TYPE, ecx); 6235 __ CmpObjectType(eax, HEAP_NUMBER_TYPE, ecx);
6239 __ j(not_equal, &miss, Label::kNear); 6236 __ j(not_equal, &miss, Label::kNear);
6240 __ CmpObjectType(edx, HEAP_NUMBER_TYPE, ecx); 6237 __ CmpObjectType(edx, HEAP_NUMBER_TYPE, ecx);
6241 __ j(not_equal, &miss, Label::kNear); 6238 __ j(not_equal, &miss, Label::kNear);
6242 6239
6243 // Inlining the double comparison and falling back to the general compare 6240 // Inlining the double comparison and falling back to the general compare
6244 // stub if NaN is involved or SS2 or CMOV is unsupported. 6241 // stub if NaN is involved or SS2 or CMOV is unsupported.
6245 if (CpuFeatures::IsSupported(SSE2) && CpuFeatures::IsSupported(CMOV)) { 6242 if (CpuFeatures::IsSupported(SSE2) && CpuFeatures::IsSupported(CMOV)) {
6246 CpuFeatures::Scope scope1(SSE2); 6243 CpuFeatures::Scope scope1(SSE2);
6247 CpuFeatures::Scope scope2(CMOV); 6244 CpuFeatures::Scope scope2(CMOV);
6248 6245
6249 // Load left and right operand 6246 // Load left and right operand
6250 __ movdbl(xmm0, FieldOperand(edx, HeapNumber::kValueOffset)); 6247 __ movdbl(xmm0, FieldOperand(edx, HeapNumber::kValueOffset));
6251 __ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset)); 6248 __ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset));
6252 6249
6253 // Compare operands 6250 // Compare operands
6254 __ ucomisd(xmm0, xmm1); 6251 __ ucomisd(xmm0, xmm1);
6255 6252
6256 // Don't base result on EFLAGS when a NaN is involved. 6253 // Don't base result on EFLAGS when a NaN is involved.
6257 __ j(parity_even, &unordered, Label::kNear); 6254 __ j(parity_even, &unordered, Label::kNear);
6258 6255
6259 // Return a result of -1, 0, or 1, based on EFLAGS. 6256 // Return a result of -1, 0, or 1, based on EFLAGS.
6260 // Performing mov, because xor would destroy the flag register. 6257 // Performing mov, because xor would destroy the flag register.
6261 __ mov(eax, 0); // equal 6258 __ mov(eax, 0); // equal
6262 __ mov(ecx, Immediate(Smi::FromInt(1))); 6259 __ mov(ecx, Immediate(Smi::FromInt(1)));
6263 __ cmov(above, eax, Operand(ecx)); 6260 __ cmov(above, eax, ecx);
6264 __ mov(ecx, Immediate(Smi::FromInt(-1))); 6261 __ mov(ecx, Immediate(Smi::FromInt(-1)));
6265 __ cmov(below, eax, Operand(ecx)); 6262 __ cmov(below, eax, ecx);
6266 __ ret(0); 6263 __ ret(0);
6267 6264
6268 __ bind(&unordered); 6265 __ bind(&unordered);
6269 } 6266 }
6270 6267
6271 CompareStub stub(GetCondition(), strict(), NO_COMPARE_FLAGS); 6268 CompareStub stub(GetCondition(), strict(), NO_COMPARE_FLAGS);
6272 __ bind(&generic_stub); 6269 __ bind(&generic_stub);
6273 __ jmp(stub.GetCode(), RelocInfo::CODE_TARGET); 6270 __ jmp(stub.GetCode(), RelocInfo::CODE_TARGET);
6274 6271
6275 __ bind(&miss); 6272 __ bind(&miss);
6276 GenerateMiss(masm); 6273 GenerateMiss(masm);
6277 } 6274 }
6278 6275
6279 6276
6280 void ICCompareStub::GenerateSymbols(MacroAssembler* masm) { 6277 void ICCompareStub::GenerateSymbols(MacroAssembler* masm) {
6281 ASSERT(state_ == CompareIC::SYMBOLS); 6278 ASSERT(state_ == CompareIC::SYMBOLS);
6282 ASSERT(GetCondition() == equal); 6279 ASSERT(GetCondition() == equal);
6283 6280
6284 // Registers containing left and right operands respectively. 6281 // Registers containing left and right operands respectively.
6285 Register left = edx; 6282 Register left = edx;
6286 Register right = eax; 6283 Register right = eax;
6287 Register tmp1 = ecx; 6284 Register tmp1 = ecx;
6288 Register tmp2 = ebx; 6285 Register tmp2 = ebx;
6289 6286
6290 // Check that both operands are heap objects. 6287 // Check that both operands are heap objects.
6291 Label miss; 6288 Label miss;
6292 __ mov(tmp1, Operand(left)); 6289 __ mov(tmp1, left);
6293 STATIC_ASSERT(kSmiTag == 0); 6290 STATIC_ASSERT(kSmiTag == 0);
6294 __ and_(tmp1, Operand(right)); 6291 __ and_(tmp1, right);
6295 __ JumpIfSmi(tmp1, &miss, Label::kNear); 6292 __ JumpIfSmi(tmp1, &miss, Label::kNear);
6296 6293
6297 // Check that both operands are symbols. 6294 // Check that both operands are symbols.
6298 __ mov(tmp1, FieldOperand(left, HeapObject::kMapOffset)); 6295 __ mov(tmp1, FieldOperand(left, HeapObject::kMapOffset));
6299 __ mov(tmp2, FieldOperand(right, HeapObject::kMapOffset)); 6296 __ mov(tmp2, FieldOperand(right, HeapObject::kMapOffset));
6300 __ movzx_b(tmp1, FieldOperand(tmp1, Map::kInstanceTypeOffset)); 6297 __ movzx_b(tmp1, FieldOperand(tmp1, Map::kInstanceTypeOffset));
6301 __ movzx_b(tmp2, FieldOperand(tmp2, Map::kInstanceTypeOffset)); 6298 __ movzx_b(tmp2, FieldOperand(tmp2, Map::kInstanceTypeOffset));
6302 STATIC_ASSERT(kSymbolTag != 0); 6299 STATIC_ASSERT(kSymbolTag != 0);
6303 __ and_(tmp1, Operand(tmp2)); 6300 __ and_(tmp1, tmp2);
6304 __ test(tmp1, Immediate(kIsSymbolMask)); 6301 __ test(tmp1, Immediate(kIsSymbolMask));
6305 __ j(zero, &miss, Label::kNear); 6302 __ j(zero, &miss, Label::kNear);
6306 6303
6307 // Symbols are compared by identity. 6304 // Symbols are compared by identity.
6308 Label done; 6305 Label done;
6309 __ cmp(left, Operand(right)); 6306 __ cmp(left, right);
6310 // Make sure eax is non-zero. At this point input operands are 6307 // Make sure eax is non-zero. At this point input operands are
6311 // guaranteed to be non-zero. 6308 // guaranteed to be non-zero.
6312 ASSERT(right.is(eax)); 6309 ASSERT(right.is(eax));
6313 __ j(not_equal, &done, Label::kNear); 6310 __ j(not_equal, &done, Label::kNear);
6314 STATIC_ASSERT(EQUAL == 0); 6311 STATIC_ASSERT(EQUAL == 0);
6315 STATIC_ASSERT(kSmiTag == 0); 6312 STATIC_ASSERT(kSmiTag == 0);
6316 __ Set(eax, Immediate(Smi::FromInt(EQUAL))); 6313 __ Set(eax, Immediate(Smi::FromInt(EQUAL)));
6317 __ bind(&done); 6314 __ bind(&done);
6318 __ ret(0); 6315 __ ret(0);
6319 6316
6320 __ bind(&miss); 6317 __ bind(&miss);
6321 GenerateMiss(masm); 6318 GenerateMiss(masm);
6322 } 6319 }
6323 6320
6324 6321
6325 void ICCompareStub::GenerateStrings(MacroAssembler* masm) { 6322 void ICCompareStub::GenerateStrings(MacroAssembler* masm) {
6326 ASSERT(state_ == CompareIC::STRINGS); 6323 ASSERT(state_ == CompareIC::STRINGS);
6327 ASSERT(GetCondition() == equal); 6324 ASSERT(GetCondition() == equal);
6328 Label miss; 6325 Label miss;
6329 6326
6330 // Registers containing left and right operands respectively. 6327 // Registers containing left and right operands respectively.
6331 Register left = edx; 6328 Register left = edx;
6332 Register right = eax; 6329 Register right = eax;
6333 Register tmp1 = ecx; 6330 Register tmp1 = ecx;
6334 Register tmp2 = ebx; 6331 Register tmp2 = ebx;
6335 Register tmp3 = edi; 6332 Register tmp3 = edi;
6336 6333
6337 // Check that both operands are heap objects. 6334 // Check that both operands are heap objects.
6338 __ mov(tmp1, Operand(left)); 6335 __ mov(tmp1, left);
6339 STATIC_ASSERT(kSmiTag == 0); 6336 STATIC_ASSERT(kSmiTag == 0);
6340 __ and_(tmp1, Operand(right)); 6337 __ and_(tmp1, right);
6341 __ JumpIfSmi(tmp1, &miss); 6338 __ JumpIfSmi(tmp1, &miss);
6342 6339
6343 // Check that both operands are strings. This leaves the instance 6340 // Check that both operands are strings. This leaves the instance
6344 // types loaded in tmp1 and tmp2. 6341 // types loaded in tmp1 and tmp2.
6345 __ mov(tmp1, FieldOperand(left, HeapObject::kMapOffset)); 6342 __ mov(tmp1, FieldOperand(left, HeapObject::kMapOffset));
6346 __ mov(tmp2, FieldOperand(right, HeapObject::kMapOffset)); 6343 __ mov(tmp2, FieldOperand(right, HeapObject::kMapOffset));
6347 __ movzx_b(tmp1, FieldOperand(tmp1, Map::kInstanceTypeOffset)); 6344 __ movzx_b(tmp1, FieldOperand(tmp1, Map::kInstanceTypeOffset));
6348 __ movzx_b(tmp2, FieldOperand(tmp2, Map::kInstanceTypeOffset)); 6345 __ movzx_b(tmp2, FieldOperand(tmp2, Map::kInstanceTypeOffset));
6349 __ mov(tmp3, tmp1); 6346 __ mov(tmp3, tmp1);
6350 STATIC_ASSERT(kNotStringTag != 0); 6347 STATIC_ASSERT(kNotStringTag != 0);
6351 __ or_(tmp3, Operand(tmp2)); 6348 __ or_(tmp3, tmp2);
6352 __ test(tmp3, Immediate(kIsNotStringMask)); 6349 __ test(tmp3, Immediate(kIsNotStringMask));
6353 __ j(not_zero, &miss); 6350 __ j(not_zero, &miss);
6354 6351
6355 // Fast check for identical strings. 6352 // Fast check for identical strings.
6356 Label not_same; 6353 Label not_same;
6357 __ cmp(left, Operand(right)); 6354 __ cmp(left, right);
6358 __ j(not_equal, &not_same, Label::kNear); 6355 __ j(not_equal, &not_same, Label::kNear);
6359 STATIC_ASSERT(EQUAL == 0); 6356 STATIC_ASSERT(EQUAL == 0);
6360 STATIC_ASSERT(kSmiTag == 0); 6357 STATIC_ASSERT(kSmiTag == 0);
6361 __ Set(eax, Immediate(Smi::FromInt(EQUAL))); 6358 __ Set(eax, Immediate(Smi::FromInt(EQUAL)));
6362 __ ret(0); 6359 __ ret(0);
6363 6360
6364 // Handle not identical strings. 6361 // Handle not identical strings.
6365 __ bind(&not_same); 6362 __ bind(&not_same);
6366 6363
6367 // Check that both strings are symbols. If they are, we're done 6364 // Check that both strings are symbols. If they are, we're done
6368 // because we already know they are not identical. 6365 // because we already know they are not identical.
6369 Label do_compare; 6366 Label do_compare;
6370 STATIC_ASSERT(kSymbolTag != 0); 6367 STATIC_ASSERT(kSymbolTag != 0);
6371 __ and_(tmp1, Operand(tmp2)); 6368 __ and_(tmp1, tmp2);
6372 __ test(tmp1, Immediate(kIsSymbolMask)); 6369 __ test(tmp1, Immediate(kIsSymbolMask));
6373 __ j(zero, &do_compare, Label::kNear); 6370 __ j(zero, &do_compare, Label::kNear);
6374 // Make sure eax is non-zero. At this point input operands are 6371 // Make sure eax is non-zero. At this point input operands are
6375 // guaranteed to be non-zero. 6372 // guaranteed to be non-zero.
6376 ASSERT(right.is(eax)); 6373 ASSERT(right.is(eax));
6377 __ ret(0); 6374 __ ret(0);
6378 6375
6379 // Check that both strings are sequential ASCII. 6376 // Check that both strings are sequential ASCII.
6380 Label runtime; 6377 Label runtime;
6381 __ bind(&do_compare); 6378 __ bind(&do_compare);
(...skipping 12 matching lines...) Expand all
6394 __ TailCallRuntime(Runtime::kStringEquals, 2, 1); 6391 __ TailCallRuntime(Runtime::kStringEquals, 2, 1);
6395 6392
6396 __ bind(&miss); 6393 __ bind(&miss);
6397 GenerateMiss(masm); 6394 GenerateMiss(masm);
6398 } 6395 }
6399 6396
6400 6397
6401 void ICCompareStub::GenerateObjects(MacroAssembler* masm) { 6398 void ICCompareStub::GenerateObjects(MacroAssembler* masm) {
6402 ASSERT(state_ == CompareIC::OBJECTS); 6399 ASSERT(state_ == CompareIC::OBJECTS);
6403 Label miss; 6400 Label miss;
6404 __ mov(ecx, Operand(edx)); 6401 __ mov(ecx, edx);
6405 __ and_(ecx, Operand(eax)); 6402 __ and_(ecx, eax);
6406 __ JumpIfSmi(ecx, &miss, Label::kNear); 6403 __ JumpIfSmi(ecx, &miss, Label::kNear);
6407 6404
6408 __ CmpObjectType(eax, JS_OBJECT_TYPE, ecx); 6405 __ CmpObjectType(eax, JS_OBJECT_TYPE, ecx);
6409 __ j(not_equal, &miss, Label::kNear); 6406 __ j(not_equal, &miss, Label::kNear);
6410 __ CmpObjectType(edx, JS_OBJECT_TYPE, ecx); 6407 __ CmpObjectType(edx, JS_OBJECT_TYPE, ecx);
6411 __ j(not_equal, &miss, Label::kNear); 6408 __ j(not_equal, &miss, Label::kNear);
6412 6409
6413 ASSERT(GetCondition() == equal); 6410 ASSERT(GetCondition() == equal);
6414 __ sub(eax, Operand(edx)); 6411 __ sub(eax, edx);
6415 __ ret(0); 6412 __ ret(0);
6416 6413
6417 __ bind(&miss); 6414 __ bind(&miss);
6418 GenerateMiss(masm); 6415 GenerateMiss(masm);
6419 } 6416 }
6420 6417
6421 6418
6422 void ICCompareStub::GenerateMiss(MacroAssembler* masm) { 6419 void ICCompareStub::GenerateMiss(MacroAssembler* masm) {
6423 // Save the registers. 6420 // Save the registers.
6424 __ pop(ecx); 6421 __ pop(ecx);
(...skipping 15 matching lines...) Expand all
6440 // Compute the entry point of the rewritten stub. 6437 // Compute the entry point of the rewritten stub.
6441 __ lea(edi, FieldOperand(eax, Code::kHeaderSize)); 6438 __ lea(edi, FieldOperand(eax, Code::kHeaderSize));
6442 6439
6443 // Restore registers. 6440 // Restore registers.
6444 __ pop(ecx); 6441 __ pop(ecx);
6445 __ pop(eax); 6442 __ pop(eax);
6446 __ pop(edx); 6443 __ pop(edx);
6447 __ push(ecx); 6444 __ push(ecx);
6448 6445
6449 // Do a tail call to the rewritten stub. 6446 // Do a tail call to the rewritten stub.
6450 __ jmp(Operand(edi)); 6447 __ jmp(edi);
6451 } 6448 }
6452 6449
6453 6450
6454 // Helper function used to check that the dictionary doesn't contain 6451 // Helper function used to check that the dictionary doesn't contain
6455 // the property. This function may return false negatives, so miss_label 6452 // the property. This function may return false negatives, so miss_label
6456 // must always call a backup property check that is complete. 6453 // must always call a backup property check that is complete.
6457 // This function is safe to call if the receiver has fast properties. 6454 // This function is safe to call if the receiver has fast properties.
6458 // Name must be a symbol and receiver must be a heap object. 6455 // Name must be a symbol and receiver must be a heap object.
6459 MaybeObject* StringDictionaryLookupStub::GenerateNegativeLookup( 6456 MaybeObject* StringDictionaryLookupStub::GenerateNegativeLookup(
6460 MacroAssembler* masm, 6457 MacroAssembler* masm,
6461 Label* miss, 6458 Label* miss,
6462 Label* done, 6459 Label* done,
6463 Register properties, 6460 Register properties,
6464 String* name, 6461 String* name,
6465 Register r0) { 6462 Register r0) {
6466 ASSERT(name->IsSymbol()); 6463 ASSERT(name->IsSymbol());
6467 6464
6468 // If names of slots in range from 1 to kProbes - 1 for the hash value are 6465 // If names of slots in range from 1 to kProbes - 1 for the hash value are
6469 // not equal to the name and kProbes-th slot is not used (its name is the 6466 // not equal to the name and kProbes-th slot is not used (its name is the
6470 // undefined value), it guarantees the hash table doesn't contain the 6467 // undefined value), it guarantees the hash table doesn't contain the
6471 // property. It's true even if some slots represent deleted properties 6468 // property. It's true even if some slots represent deleted properties
6472 // (their names are the null value). 6469 // (their names are the null value).
6473 for (int i = 0; i < kInlinedProbes; i++) { 6470 for (int i = 0; i < kInlinedProbes; i++) {
6474 // Compute the masked index: (hash + i + i * i) & mask. 6471 // Compute the masked index: (hash + i + i * i) & mask.
6475 Register index = r0; 6472 Register index = r0;
6476 // Capacity is smi 2^n. 6473 // Capacity is smi 2^n.
6477 __ mov(index, FieldOperand(properties, kCapacityOffset)); 6474 __ mov(index, FieldOperand(properties, kCapacityOffset));
6478 __ dec(index); 6475 __ dec(index);
6479 __ and_(Operand(index), 6476 __ and_(index,
6480 Immediate(Smi::FromInt(name->Hash() + 6477 Immediate(Smi::FromInt(name->Hash() +
6481 StringDictionary::GetProbeOffset(i)))); 6478 StringDictionary::GetProbeOffset(i))));
6482 6479
6483 // Scale the index by multiplying by the entry size. 6480 // Scale the index by multiplying by the entry size.
6484 ASSERT(StringDictionary::kEntrySize == 3); 6481 ASSERT(StringDictionary::kEntrySize == 3);
6485 __ lea(index, Operand(index, index, times_2, 0)); // index *= 3. 6482 __ lea(index, Operand(index, index, times_2, 0)); // index *= 3.
6486 Register entity_name = r0; 6483 Register entity_name = r0;
6487 // Having undefined at this place means the name is not contained. 6484 // Having undefined at this place means the name is not contained.
6488 ASSERT_EQ(kSmiTagSize, 1); 6485 ASSERT_EQ(kSmiTagSize, 1);
6489 __ mov(entity_name, Operand(properties, index, times_half_pointer_size, 6486 __ mov(entity_name, Operand(properties, index, times_half_pointer_size,
6490 kElementsStartOffset - kHeapObjectTag)); 6487 kElementsStartOffset - kHeapObjectTag));
(...skipping 12 matching lines...) Expand all
6503 } 6500 }
6504 6501
6505 StringDictionaryLookupStub stub(properties, 6502 StringDictionaryLookupStub stub(properties,
6506 r0, 6503 r0,
6507 r0, 6504 r0,
6508 StringDictionaryLookupStub::NEGATIVE_LOOKUP); 6505 StringDictionaryLookupStub::NEGATIVE_LOOKUP);
6509 __ push(Immediate(Handle<Object>(name))); 6506 __ push(Immediate(Handle<Object>(name)));
6510 __ push(Immediate(name->Hash())); 6507 __ push(Immediate(name->Hash()));
6511 MaybeObject* result = masm->TryCallStub(&stub); 6508 MaybeObject* result = masm->TryCallStub(&stub);
6512 if (result->IsFailure()) return result; 6509 if (result->IsFailure()) return result;
6513 __ test(r0, Operand(r0)); 6510 __ test(r0, r0);
6514 __ j(not_zero, miss); 6511 __ j(not_zero, miss);
6515 __ jmp(done); 6512 __ jmp(done);
6516 return result; 6513 return result;
6517 } 6514 }
6518 6515
6519 6516
6520 // Probe the string dictionary in the |elements| register. Jump to the 6517 // Probe the string dictionary in the |elements| register. Jump to the
6521 // |done| label if a property with the given name is found leaving the 6518 // |done| label if a property with the given name is found leaving the
6522 // index into the dictionary in |r0|. Jump to the |miss| label 6519 // index into the dictionary in |r0|. Jump to the |miss| label
6523 // otherwise. 6520 // otherwise.
(...skipping 12 matching lines...) Expand all
6536 __ dec(r1); 6533 __ dec(r1);
6537 6534
6538 // Generate an unrolled loop that performs a few probes before 6535 // Generate an unrolled loop that performs a few probes before
6539 // giving up. Measurements done on Gmail indicate that 2 probes 6536 // giving up. Measurements done on Gmail indicate that 2 probes
6540 // cover ~93% of loads from dictionaries. 6537 // cover ~93% of loads from dictionaries.
6541 for (int i = 0; i < kInlinedProbes; i++) { 6538 for (int i = 0; i < kInlinedProbes; i++) {
6542 // Compute the masked index: (hash + i + i * i) & mask. 6539 // Compute the masked index: (hash + i + i * i) & mask.
6543 __ mov(r0, FieldOperand(name, String::kHashFieldOffset)); 6540 __ mov(r0, FieldOperand(name, String::kHashFieldOffset));
6544 __ shr(r0, String::kHashShift); 6541 __ shr(r0, String::kHashShift);
6545 if (i > 0) { 6542 if (i > 0) {
6546 __ add(Operand(r0), Immediate(StringDictionary::GetProbeOffset(i))); 6543 __ add(r0, Immediate(StringDictionary::GetProbeOffset(i)));
6547 } 6544 }
6548 __ and_(r0, Operand(r1)); 6545 __ and_(r0, r1);
6549 6546
6550 // Scale the index by multiplying by the entry size. 6547 // Scale the index by multiplying by the entry size.
6551 ASSERT(StringDictionary::kEntrySize == 3); 6548 ASSERT(StringDictionary::kEntrySize == 3);
6552 __ lea(r0, Operand(r0, r0, times_2, 0)); // r0 = r0 * 3 6549 __ lea(r0, Operand(r0, r0, times_2, 0)); // r0 = r0 * 3
6553 6550
6554 // Check if the key is identical to the name. 6551 // Check if the key is identical to the name.
6555 __ cmp(name, Operand(elements, 6552 __ cmp(name, Operand(elements,
6556 r0, 6553 r0,
6557 times_4, 6554 times_4,
6558 kElementsStartOffset - kHeapObjectTag)); 6555 kElementsStartOffset - kHeapObjectTag));
6559 __ j(equal, done); 6556 __ j(equal, done);
6560 } 6557 }
6561 6558
6562 StringDictionaryLookupStub stub(elements, 6559 StringDictionaryLookupStub stub(elements,
6563 r1, 6560 r1,
6564 r0, 6561 r0,
6565 POSITIVE_LOOKUP); 6562 POSITIVE_LOOKUP);
6566 __ push(name); 6563 __ push(name);
6567 __ mov(r0, FieldOperand(name, String::kHashFieldOffset)); 6564 __ mov(r0, FieldOperand(name, String::kHashFieldOffset));
6568 __ shr(r0, String::kHashShift); 6565 __ shr(r0, String::kHashShift);
6569 __ push(r0); 6566 __ push(r0);
6570 __ CallStub(&stub); 6567 __ CallStub(&stub);
6571 6568
6572 __ test(r1, Operand(r1)); 6569 __ test(r1, r1);
6573 __ j(zero, miss); 6570 __ j(zero, miss);
6574 __ jmp(done); 6571 __ jmp(done);
6575 } 6572 }
6576 6573
6577 6574
6578 void StringDictionaryLookupStub::Generate(MacroAssembler* masm) { 6575 void StringDictionaryLookupStub::Generate(MacroAssembler* masm) {
6579 // This stub overrides SometimesSetsUpAFrame() to return false. That means 6576 // This stub overrides SometimesSetsUpAFrame() to return false. That means
6580 // we cannot call anything that could cause a GC from this stub. 6577 // we cannot call anything that could cause a GC from this stub.
6581 // Stack frame on entry: 6578 // Stack frame on entry:
6582 // esp[0 * kPointerSize]: return address. 6579 // esp[0 * kPointerSize]: return address.
(...skipping 18 matching lines...) Expand all
6601 6598
6602 // If names of slots in range from 1 to kProbes - 1 for the hash value are 6599 // If names of slots in range from 1 to kProbes - 1 for the hash value are
6603 // not equal to the name and kProbes-th slot is not used (its name is the 6600 // not equal to the name and kProbes-th slot is not used (its name is the
6604 // undefined value), it guarantees the hash table doesn't contain the 6601 // undefined value), it guarantees the hash table doesn't contain the
6605 // property. It's true even if some slots represent deleted properties 6602 // property. It's true even if some slots represent deleted properties
6606 // (their names are the null value). 6603 // (their names are the null value).
6607 for (int i = kInlinedProbes; i < kTotalProbes; i++) { 6604 for (int i = kInlinedProbes; i < kTotalProbes; i++) {
6608 // Compute the masked index: (hash + i + i * i) & mask. 6605 // Compute the masked index: (hash + i + i * i) & mask.
6609 __ mov(scratch, Operand(esp, 2 * kPointerSize)); 6606 __ mov(scratch, Operand(esp, 2 * kPointerSize));
6610 if (i > 0) { 6607 if (i > 0) {
6611 __ add(Operand(scratch), 6608 __ add(scratch, Immediate(StringDictionary::GetProbeOffset(i)));
6612 Immediate(StringDictionary::GetProbeOffset(i)));
6613 } 6609 }
6614 __ and_(scratch, Operand(esp, 0)); 6610 __ and_(scratch, Operand(esp, 0));
6615 6611
6616 // Scale the index by multiplying by the entry size. 6612 // Scale the index by multiplying by the entry size.
6617 ASSERT(StringDictionary::kEntrySize == 3); 6613 ASSERT(StringDictionary::kEntrySize == 3);
6618 __ lea(index_, Operand(scratch, scratch, times_2, 0)); // index *= 3. 6614 __ lea(index_, Operand(scratch, scratch, times_2, 0)); // index *= 3.
6619 6615
6620 // Having undefined at this place means the name is not contained. 6616 // Having undefined at this place means the name is not contained.
6621 ASSERT_EQ(kSmiTagSize, 1); 6617 ASSERT_EQ(kSmiTagSize, 1);
6622 __ mov(scratch, Operand(dictionary_, 6618 __ mov(scratch, Operand(dictionary_,
(...skipping 308 matching lines...) Expand 10 before | Expand all | Expand 10 after
6931 6927
6932 // Fall through when we need to inform the incremental marker. 6928 // Fall through when we need to inform the incremental marker.
6933 } 6929 }
6934 6930
6935 6931
6936 #undef __ 6932 #undef __
6937 6933
6938 } } // namespace v8::internal 6934 } } // namespace v8::internal
6939 6935
6940 #endif // V8_TARGET_ARCH_IA32 6936 #endif // V8_TARGET_ARCH_IA32
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698