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

Unified Diff: src/x64/codegen-x64.cc

Issue 164135: X64: Implement fast charCodeAt. (Closed)
Patch Set: Created 11 years, 4 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/x64/assembler-x64.cc ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/x64/codegen-x64.cc
diff --git a/src/x64/codegen-x64.cc b/src/x64/codegen-x64.cc
index 158dbbaff5f10789eb8ee5b1d7fb821a29f34fa6..b94fab7306bb65c6cbfe1177b02cc5b137db0ed3 100644
--- a/src/x64/codegen-x64.cc
+++ b/src/x64/codegen-x64.cc
@@ -3423,10 +3423,161 @@ void CodeGenerator::GenerateArgumentsLength(ZoneList<Expression*>* args) {
}
-void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* a) {
- // TODO(X64): Implement this function.
- // Ignore arguments and return undefined, to signal failure.
- frame_->Push(Factory::undefined_value());
+void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) {
+ Comment(masm_, "[ GenerateFastCharCodeAt");
+ ASSERT(args->length() == 2);
+
+ Label slow_case;
+ Label end;
+ Label not_a_flat_string;
+ Label a_cons_string;
+ Label try_again_with_new_string;
+ Label ascii_string;
+ Label got_char_code;
+
+ Load(args->at(0));
+ Load(args->at(1));
+ Result index = frame_->Pop();
+ Result object = frame_->Pop();
+
+ // Get register rcx to use as shift amount later.
+ Result shift_amount;
+ if (object.is_register() && object.reg().is(rcx)) {
+ Result fresh = allocator_->Allocate();
+ shift_amount = object;
+ object = fresh;
+ __ movq(object.reg(), rcx);
+ }
+ if (index.is_register() && index.reg().is(rcx)) {
+ Result fresh = allocator_->Allocate();
+ shift_amount = index;
+ index = fresh;
+ __ movq(index.reg(), rcx);
+ }
+ // There could be references to ecx in the frame. Allocating will
+ // spill them, otherwise spill explicitly.
+ if (shift_amount.is_valid()) {
+ frame_->Spill(rcx);
+ } else {
+ shift_amount = allocator()->Allocate(rcx);
+ }
+ ASSERT(shift_amount.is_register());
+ ASSERT(shift_amount.reg().is(rcx));
+ ASSERT(allocator_->count(rcx) == 1);
+
+ // We will mutate the index register and possibly the object register.
+ // The case where they are somehow the same register is handled
+ // because we only mutate them in the case where the receiver is a
+ // heap object and the index is not.
+ object.ToRegister();
+ index.ToRegister();
+ frame_->Spill(object.reg());
+ frame_->Spill(index.reg());
+
+ // We need a single extra temporary register.
+ Result temp = allocator()->Allocate();
+ ASSERT(temp.is_valid());
+
+ // There is no virtual frame effect from here up to the final result
+ // push.
+
+ // If the receiver is a smi trigger the slow case.
+ ASSERT(kSmiTag == 0);
+ __ testl(object.reg(), Immediate(kSmiTagMask));
+ __ j(zero, &slow_case);
+
+ // If the index is negative or non-smi trigger the slow case.
+ ASSERT(kSmiTag == 0);
+ __ testl(index.reg(),
+ Immediate(static_cast<uint32_t>(kSmiTagMask | 0x80000000U)));
William Hesse 2009/08/07 10:27:15 shouldn't this be a static cast to int32_t. I thi
Lasse Reichstein 2009/08/07 10:44:27 Done.
+ __ j(not_zero, &slow_case);
+ // Untag the index.
+ __ sarl(index.reg(), Immediate(kSmiTagSize));
+
+ __ bind(&try_again_with_new_string);
+ // Fetch the instance type of the receiver into rcx.
+ __ movq(rcx, FieldOperand(object.reg(), HeapObject::kMapOffset));
+ __ movzxbl(rcx, FieldOperand(rcx, Map::kInstanceTypeOffset));
+ // If the receiver is not a string trigger the slow case.
+ __ testb(rcx, Immediate(kIsNotStringMask));
+ __ j(not_zero, &slow_case);
+
+ // Here we make assumptions about the tag values and the shifts needed.
+ // See the comment in objects.h.
+ ASSERT(kLongStringTag == 0);
+ ASSERT(kMediumStringTag + String::kLongLengthShift ==
+ String::kMediumLengthShift);
+ ASSERT(kShortStringTag + String::kLongLengthShift ==
+ String::kShortLengthShift);
+ __ and_(rcx, Immediate(kStringSizeMask));
+ __ addq(rcx, Immediate(String::kLongLengthShift));
+ // Fetch the length field into the temporary register.
+ __ movl(temp.reg(), FieldOperand(object.reg(), String::kLengthOffset));
+ __ shrl(temp.reg()); // The shift amount in ecx is implicit operand.
William Hesse 2009/08/07 10:27:15 cl (low byte of rcx), not ecx. Is this a shr or sa
Lasse Reichstein 2009/08/07 10:44:27 Not sure whether high bit can be 1 (would be waste
+ // Check for index out of range.
+ __ cmpl(index.reg(), temp.reg());
+ __ j(greater_equal, &slow_case);
William Hesse 2009/08/07 10:27:15 greater_equal or below_equal? Are either of these
Lasse Reichstein 2009/08/07 10:44:27 The string length is definitly positive, the index
+ // Reload the instance type (into the temp register this time)..
+ __ movq(temp.reg(), FieldOperand(object.reg(), HeapObject::kMapOffset));
+ __ movzxbl(temp.reg(), FieldOperand(temp.reg(), Map::kInstanceTypeOffset));
+
+ // We need special handling for non-flat strings.
+ ASSERT(kSeqStringTag == 0);
+ __ testb(temp.reg(), Immediate(kStringRepresentationMask));
+ __ j(not_zero, &not_a_flat_string);
+ // Check for 1-byte or 2-byte string.
+ __ testb(temp.reg(), Immediate(kStringEncodingMask));
+ __ j(not_zero, &ascii_string);
+
+ // 2-byte string.
+ // Load the 2-byte character code into the temp register.
+ __ movzxwl(temp.reg(), FieldOperand(object.reg(),
William Hesse 2009/08/07 10:27:15 Add the new operations to the disassembler.
Lasse Reichstein 2009/08/07 10:44:27 Already there. It's just a another operand size fo
Lasse Reichstein 2009/08/07 10:44:27 Already there. It's just a another operand size fo
+ index.reg(),
+ times_2,
+ SeqTwoByteString::kHeaderSize));
+ __ jmp(&got_char_code);
+
+ // ASCII string.
+ __ bind(&ascii_string);
+ // Load the byte into the temp register.
+ __ movzxbl(temp.reg(), FieldOperand(object.reg(),
+ index.reg(),
+ times_1,
+ SeqAsciiString::kHeaderSize));
+ __ bind(&got_char_code);
+ ASSERT(kSmiTag == 0);
+ __ shl(temp.reg(), Immediate(kSmiTagSize));
+ __ jmp(&end);
+
+ // Handle non-flat strings.
+ __ bind(&not_a_flat_string);
+ __ and_(temp.reg(), Immediate(kStringRepresentationMask));
+ __ cmpb(temp.reg(), Immediate(kConsStringTag));
+ __ j(equal, &a_cons_string);
+ __ cmpb(temp.reg(), Immediate(kSlicedStringTag));
+ __ j(not_equal, &slow_case);
+
+ // SlicedString.
+ // Add the offset to the index and trigger the slow case on overflow.
+ __ addl(index.reg(), FieldOperand(object.reg(), SlicedString::kStartOffset));
+ __ j(overflow, &slow_case);
+ // Getting the underlying string is done by running the cons string code.
+
+ // ConsString.
+ __ bind(&a_cons_string);
+ // Get the first of the two strings. Both sliced and cons strings
+ // store their source string at the same offset.
+ ASSERT(SlicedString::kBufferOffset == ConsString::kFirstOffset);
+ __ movq(object.reg(), FieldOperand(object.reg(), ConsString::kFirstOffset));
+ __ jmp(&try_again_with_new_string);
+
+ __ bind(&slow_case);
+ // Move the undefined value into the result register, which will
+ // trigger the slow case.
+ __ Move(temp.reg(), Factory::undefined_value());
+
+ __ bind(&end);
+ frame_->Push(&temp);
}
@@ -4152,8 +4303,6 @@ void CodeGenerator::LoadFromSlotCheckForArguments(Slot* slot,
void CodeGenerator::StoreToSlot(Slot* slot, InitState init_state) {
- // TODO(X64): Enable more types of slot.
-
if (slot->type() == Slot::LOOKUP) {
ASSERT(slot->var()->is_dynamic());
« no previous file with comments | « src/x64/assembler-x64.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698