OLD | NEW |
1 // Copyright 2006-2009 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2009 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 4607 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4618 } | 4618 } |
4619 | 4619 |
4620 | 4620 |
4621 // This generates code that performs a charCodeAt() call or returns | 4621 // This generates code that performs a charCodeAt() call or returns |
4622 // undefined in order to trigger the slow case, Runtime_StringCharCodeAt. | 4622 // undefined in order to trigger the slow case, Runtime_StringCharCodeAt. |
4623 // It can handle flat and sliced strings, 8 and 16 bit characters and | 4623 // It can handle flat and sliced strings, 8 and 16 bit characters and |
4624 // cons strings where the answer is found in the left hand branch of the | 4624 // cons strings where the answer is found in the left hand branch of the |
4625 // cons. The slow case will flatten the string, which will ensure that | 4625 // cons. The slow case will flatten the string, which will ensure that |
4626 // the answer is in the left hand side the next time around. | 4626 // the answer is in the left hand side the next time around. |
4627 void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) { | 4627 void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) { |
| 4628 Comment(masm_, "[ GenerateFastCharCodeAt"); |
4628 ASSERT(args->length() == 2); | 4629 ASSERT(args->length() == 2); |
4629 | 4630 |
4630 JumpTarget slow_case; | 4631 Label slow_case; |
4631 JumpTarget end; | 4632 Label end; |
4632 JumpTarget not_a_flat_string; | 4633 Label not_a_flat_string; |
4633 JumpTarget a_cons_string; | 4634 Label a_cons_string; |
4634 JumpTarget try_again_with_new_string(JumpTarget::BIDIRECTIONAL); | 4635 Label try_again_with_new_string; |
4635 JumpTarget ascii_string; | 4636 Label ascii_string; |
4636 JumpTarget got_char_code; | 4637 Label got_char_code; |
4637 | 4638 |
4638 Load(args->at(0)); | 4639 Load(args->at(0)); |
4639 Load(args->at(1)); | 4640 Load(args->at(1)); |
4640 // Reserve register ecx, to use as shift amount later | |
4641 Result shift_amount = allocator()->Allocate(ecx); | |
4642 ASSERT(shift_amount.is_valid()); | |
4643 Result index = frame_->Pop(); | 4641 Result index = frame_->Pop(); |
| 4642 Result object = frame_->Pop(); |
| 4643 |
| 4644 // Get register ecx to use as shift amount later. |
| 4645 Result shift_amount; |
| 4646 if (object.is_register() && object.reg().is(ecx)) { |
| 4647 Result fresh = allocator_->Allocate(); |
| 4648 shift_amount = object; |
| 4649 object = fresh; |
| 4650 __ mov(object.reg(), ecx); |
| 4651 } |
| 4652 if (index.is_register() && index.reg().is(ecx)) { |
| 4653 Result fresh = allocator_->Allocate(); |
| 4654 shift_amount = index; |
| 4655 index = fresh; |
| 4656 __ mov(index.reg(), ecx); |
| 4657 } |
| 4658 // There could be references to ecx in the frame. Allocating will |
| 4659 // spill them, otherwise spill explicitly. |
| 4660 if (shift_amount.is_valid()) { |
| 4661 frame_->Spill(ecx); |
| 4662 } else { |
| 4663 shift_amount = allocator()->Allocate(ecx); |
| 4664 } |
| 4665 ASSERT(shift_amount.is_register()); |
| 4666 ASSERT(shift_amount.reg().is(ecx)); |
| 4667 ASSERT(allocator_->count(ecx) == 1); |
| 4668 |
| 4669 // We will mutate the index register and possibly the object register. |
| 4670 // The case where they are somehow the same register is handled |
| 4671 // because we only mutate them in the case where the receiver is a |
| 4672 // heap object and the index is not. |
| 4673 object.ToRegister(); |
4644 index.ToRegister(); | 4674 index.ToRegister(); |
4645 Result object = frame_->Pop(); | 4675 frame_->Spill(object.reg()); |
4646 object.ToRegister(); | 4676 frame_->Spill(index.reg()); |
4647 // If the receiver is a smi return undefined. | 4677 |
| 4678 // We need a single extra temporary register. |
| 4679 Result temp = allocator()->Allocate(); |
| 4680 ASSERT(temp.is_valid()); |
| 4681 |
| 4682 // There is no virtual frame effect from here up to the final result |
| 4683 // push. |
| 4684 |
| 4685 // If the receiver is a smi trigger the slow case. |
4648 ASSERT(kSmiTag == 0); | 4686 ASSERT(kSmiTag == 0); |
4649 __ test(object.reg(), Immediate(kSmiTagMask)); | 4687 __ test(object.reg(), Immediate(kSmiTagMask)); |
4650 slow_case.Branch(zero, not_taken); | 4688 __ j(zero, &slow_case); |
4651 | 4689 |
4652 // Check for negative or non-smi index. | 4690 // If the index is negative or non-smi trigger the slow case. |
4653 ASSERT(kSmiTag == 0); | 4691 ASSERT(kSmiTag == 0); |
4654 __ test(index.reg(), Immediate(kSmiTagMask | 0x80000000)); | 4692 __ test(index.reg(), Immediate(kSmiTagMask | 0x80000000)); |
4655 slow_case.Branch(not_zero, not_taken); | 4693 __ j(not_zero, &slow_case); |
4656 // Get rid of the smi tag on the index. | 4694 // Untag the index. |
4657 frame_->Spill(index.reg()); | |
4658 __ sar(index.reg(), kSmiTagSize); | 4695 __ sar(index.reg(), kSmiTagSize); |
4659 | 4696 |
4660 try_again_with_new_string.Bind(&object, &index, &shift_amount); | 4697 __ bind(&try_again_with_new_string); |
4661 // Get the type of the heap object. | 4698 // Fetch the instance type of the receiver into ecx. |
4662 Result object_type = allocator()->Allocate(); | 4699 __ mov(ecx, FieldOperand(object.reg(), HeapObject::kMapOffset)); |
4663 ASSERT(object_type.is_valid()); | 4700 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); |
4664 __ mov(object_type.reg(), FieldOperand(object.reg(), HeapObject::kMapOffset)); | 4701 // If the receiver is not a string trigger the slow case. |
4665 __ movzx_b(object_type.reg(), | 4702 __ test(ecx, Immediate(kIsNotStringMask)); |
4666 FieldOperand(object_type.reg(), Map::kInstanceTypeOffset)); | 4703 __ j(not_zero, &slow_case); |
4667 // We don't handle non-strings. | |
4668 __ test(object_type.reg(), Immediate(kIsNotStringMask)); | |
4669 slow_case.Branch(not_zero, not_taken); | |
4670 | 4704 |
4671 // Here we make assumptions about the tag values and the shifts needed. | 4705 // Here we make assumptions about the tag values and the shifts needed. |
4672 // See the comment in objects.h. | 4706 // See the comment in objects.h. |
4673 ASSERT(kLongStringTag == 0); | 4707 ASSERT(kLongStringTag == 0); |
4674 ASSERT(kMediumStringTag + String::kLongLengthShift == | 4708 ASSERT(kMediumStringTag + String::kLongLengthShift == |
4675 String::kMediumLengthShift); | 4709 String::kMediumLengthShift); |
4676 ASSERT(kShortStringTag + String::kLongLengthShift == | 4710 ASSERT(kShortStringTag + String::kLongLengthShift == |
4677 String::kShortLengthShift); | 4711 String::kShortLengthShift); |
4678 __ mov(shift_amount.reg(), Operand(object_type.reg())); | 4712 __ and_(ecx, kStringSizeMask); |
4679 __ and_(shift_amount.reg(), kStringSizeMask); | 4713 __ add(Operand(ecx), Immediate(String::kLongLengthShift)); |
4680 __ add(Operand(shift_amount.reg()), Immediate(String::kLongLengthShift)); | 4714 // Fetch the length field into the temporary register. |
4681 // Get the length field. Temporary register now used for length. | 4715 __ mov(temp.reg(), FieldOperand(object.reg(), String::kLengthOffset)); |
4682 Result length = object_type; | 4716 __ shr(temp.reg()); // The shift amount in ecx is implicit operand. |
4683 __ mov(length.reg(), FieldOperand(object.reg(), String::kLengthOffset)); | |
4684 __ shr(length.reg()); // shift_amount, in ecx, is implicit operand. | |
4685 // Check for index out of range. | 4717 // Check for index out of range. |
4686 __ cmp(index.reg(), Operand(length.reg())); | 4718 __ cmp(index.reg(), Operand(temp.reg())); |
4687 slow_case.Branch(greater_equal, not_taken); | 4719 __ j(greater_equal, &slow_case); |
4688 length.Unuse(); | 4720 // Reload the instance type (into the temp register this time).. |
4689 // Load the object type into object_type again. | 4721 __ mov(temp.reg(), FieldOperand(object.reg(), HeapObject::kMapOffset)); |
4690 // These two instructions are duplicated from above, to save a register. | 4722 __ movzx_b(temp.reg(), FieldOperand(temp.reg(), Map::kInstanceTypeOffset)); |
4691 __ mov(object_type.reg(), FieldOperand(object.reg(), HeapObject::kMapOffset)); | |
4692 __ movzx_b(object_type.reg(), | |
4693 FieldOperand(object_type.reg(), Map::kInstanceTypeOffset)); | |
4694 | 4723 |
4695 // We need special handling for non-flat strings. | 4724 // We need special handling for non-flat strings. |
4696 ASSERT(kSeqStringTag == 0); | 4725 ASSERT(kSeqStringTag == 0); |
4697 __ test(object_type.reg(), Immediate(kStringRepresentationMask)); | 4726 __ test(temp.reg(), Immediate(kStringRepresentationMask)); |
4698 not_a_flat_string.Branch(not_zero, &object, &index, &object_type, | 4727 __ j(not_zero, ¬_a_flat_string); |
4699 &shift_amount, not_taken); | |
4700 shift_amount.Unuse(); | |
4701 // Check for 1-byte or 2-byte string. | 4728 // Check for 1-byte or 2-byte string. |
4702 __ test(object_type.reg(), Immediate(kStringEncodingMask)); | 4729 __ test(temp.reg(), Immediate(kStringEncodingMask)); |
4703 ascii_string.Branch(not_zero, &object, &index, &object_type, taken); | 4730 __ j(not_zero, &ascii_string); |
4704 | 4731 |
4705 // 2-byte string. | 4732 // 2-byte string. |
4706 // Load the 2-byte character code. | 4733 // Load the 2-byte character code into the temp register. |
4707 __ movzx_w(object_type.reg(), FieldOperand(object.reg(), | 4734 __ movzx_w(temp.reg(), FieldOperand(object.reg(), |
4708 index.reg(), | 4735 index.reg(), |
4709 times_2, | 4736 times_2, |
4710 SeqTwoByteString::kHeaderSize)); | 4737 SeqTwoByteString::kHeaderSize)); |
4711 object.Unuse(); | 4738 __ jmp(&got_char_code); |
4712 index.Unuse(); | |
4713 got_char_code.Jump(&object_type); | |
4714 | 4739 |
4715 // ASCII string. | 4740 // ASCII string. |
4716 ascii_string.Bind(&object, &index, &object_type); | 4741 __ bind(&ascii_string); |
4717 // Load the byte. | 4742 // Load the byte into the temp register. |
4718 __ movzx_b(object_type.reg(), FieldOperand(object.reg(), | 4743 __ movzx_b(temp.reg(), FieldOperand(object.reg(), |
4719 index.reg(), | 4744 index.reg(), |
4720 times_1, | 4745 times_1, |
4721 SeqAsciiString::kHeaderSize)); | 4746 SeqAsciiString::kHeaderSize)); |
4722 object.Unuse(); | 4747 __ bind(&got_char_code); |
4723 index.Unuse(); | |
4724 got_char_code.Bind(&object_type); | |
4725 ASSERT(kSmiTag == 0); | 4748 ASSERT(kSmiTag == 0); |
4726 __ shl(object_type.reg(), kSmiTagSize); | 4749 __ shl(temp.reg(), kSmiTagSize); |
4727 frame_->Push(&object_type); | 4750 __ jmp(&end); |
4728 end.Jump(); | |
4729 | 4751 |
4730 // Handle non-flat strings. | 4752 // Handle non-flat strings. |
4731 not_a_flat_string.Bind(&object, &index, &object_type, &shift_amount); | 4753 __ bind(¬_a_flat_string); |
4732 __ and_(object_type.reg(), kStringRepresentationMask); | 4754 __ and_(temp.reg(), kStringRepresentationMask); |
4733 __ cmp(object_type.reg(), kConsStringTag); | 4755 __ cmp(temp.reg(), kConsStringTag); |
4734 a_cons_string.Branch(equal, &object, &index, &shift_amount, taken); | 4756 __ j(equal, &a_cons_string); |
4735 __ cmp(object_type.reg(), kSlicedStringTag); | 4757 __ cmp(temp.reg(), kSlicedStringTag); |
4736 slow_case.Branch(not_equal, not_taken); | 4758 __ j(not_equal, &slow_case); |
4737 object_type.Unuse(); | |
4738 | 4759 |
4739 // SlicedString. | 4760 // SlicedString. |
4740 // Add the offset to the index. | 4761 // Add the offset to the index and trigger the slow case on overflow. |
4741 __ add(index.reg(), FieldOperand(object.reg(), SlicedString::kStartOffset)); | 4762 __ add(index.reg(), FieldOperand(object.reg(), SlicedString::kStartOffset)); |
4742 slow_case.Branch(overflow); | 4763 __ j(overflow, &slow_case); |
4743 // Getting the underlying string is done by running the cons string code. | 4764 // Getting the underlying string is done by running the cons string code. |
4744 | 4765 |
4745 // ConsString. | 4766 // ConsString. |
4746 a_cons_string.Bind(&object, &index, &shift_amount); | 4767 __ bind(&a_cons_string); |
4747 // Get the first of the two strings. | 4768 // Get the first of the two strings. Both sliced and cons strings |
4748 frame_->Spill(object.reg()); | 4769 // store their source string at the same offset. |
4749 // Both sliced and cons strings store their source string at the same place. | |
4750 ASSERT(SlicedString::kBufferOffset == ConsString::kFirstOffset); | 4770 ASSERT(SlicedString::kBufferOffset == ConsString::kFirstOffset); |
4751 __ mov(object.reg(), FieldOperand(object.reg(), ConsString::kFirstOffset)); | 4771 __ mov(object.reg(), FieldOperand(object.reg(), ConsString::kFirstOffset)); |
4752 try_again_with_new_string.Jump(&object, &index, &shift_amount); | 4772 __ jmp(&try_again_with_new_string); |
4753 | 4773 |
4754 // No results live at this point. | 4774 __ bind(&slow_case); |
4755 slow_case.Bind(); | 4775 // Move the undefined value into the result register, which will |
4756 frame_->Push(Factory::undefined_value()); | 4776 // trigger the slow case. |
4757 end.Bind(); | 4777 __ Set(temp.reg(), Immediate(Factory::undefined_value())); |
| 4778 |
| 4779 __ bind(&end); |
| 4780 frame_->Push(&temp); |
4758 } | 4781 } |
4759 | 4782 |
4760 | 4783 |
4761 void CodeGenerator::GenerateIsArray(ZoneList<Expression*>* args) { | 4784 void CodeGenerator::GenerateIsArray(ZoneList<Expression*>* args) { |
4762 ASSERT(args->length() == 1); | 4785 ASSERT(args->length() == 1); |
4763 Load(args->at(0)); | 4786 Load(args->at(0)); |
4764 Result value = frame_->Pop(); | 4787 Result value = frame_->Pop(); |
4765 value.ToRegister(); | 4788 value.ToRegister(); |
4766 ASSERT(value.is_valid()); | 4789 ASSERT(value.is_valid()); |
4767 __ test(value.reg(), Immediate(kSmiTagMask)); | 4790 __ test(value.reg(), Immediate(kSmiTagMask)); |
(...skipping 2543 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7311 | 7334 |
7312 // Slow-case: Go through the JavaScript implementation. | 7335 // Slow-case: Go through the JavaScript implementation. |
7313 __ bind(&slow); | 7336 __ bind(&slow); |
7314 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); | 7337 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); |
7315 } | 7338 } |
7316 | 7339 |
7317 | 7340 |
7318 #undef __ | 7341 #undef __ |
7319 | 7342 |
7320 } } // namespace v8::internal | 7343 } } // namespace v8::internal |
OLD | NEW |