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

Side by Side Diff: src/ia32/codegen-ia32.cc

Issue 2087009: Custom call IC-s for String.prototype.{charAt,charCodeAt}. (Closed)
Patch Set: ARM port. Created 10 years, 7 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
OLDNEW
1 // Copyright 2010 the V8 project authors. All rights reserved. 1 // Copyright 2010 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 28 matching lines...) Expand all
39 #include "regexp-macro-assembler.h" 39 #include "regexp-macro-assembler.h"
40 #include "regexp-stack.h" 40 #include "regexp-stack.h"
41 #include "register-allocator-inl.h" 41 #include "register-allocator-inl.h"
42 #include "runtime.h" 42 #include "runtime.h"
43 #include "scopes.h" 43 #include "scopes.h"
44 #include "virtual-frame-inl.h" 44 #include "virtual-frame-inl.h"
45 45
46 namespace v8 { 46 namespace v8 {
47 namespace internal { 47 namespace internal {
48 48
49 #define __ ACCESS_MASM(masm_) 49 #define __ ACCESS_MASM(masm)
50 50
51 // ------------------------------------------------------------------------- 51 // -------------------------------------------------------------------------
52 // Platform-specific DeferredCode functions. 52 // Platform-specific FrameRegisterState functions.
53 53
54 void DeferredCode::SaveRegisters() { 54 void FrameRegisterState::Save(MacroAssembler* masm) const {
55 for (int i = 0; i < RegisterAllocator::kNumRegisters; i++) { 55 for (int i = 0; i < RegisterAllocator::kNumRegisters; i++) {
56 int action = registers_[i]; 56 int action = registers_[i];
57 if (action == kPush) { 57 if (action == kPush) {
58 __ push(RegisterAllocator::ToRegister(i)); 58 __ push(RegisterAllocator::ToRegister(i));
59 } else if (action != kIgnore && (action & kSyncedFlag) == 0) { 59 } else if (action != kIgnore && (action & kSyncedFlag) == 0) {
60 __ mov(Operand(ebp, action), RegisterAllocator::ToRegister(i)); 60 __ mov(Operand(ebp, action), RegisterAllocator::ToRegister(i));
61 } 61 }
62 } 62 }
63 } 63 }
64 64
65 65
66 void DeferredCode::RestoreRegisters() { 66 void FrameRegisterState::Restore(MacroAssembler* masm) const {
67 // Restore registers in reverse order due to the stack. 67 // Restore registers in reverse order due to the stack.
68 for (int i = RegisterAllocator::kNumRegisters - 1; i >= 0; i--) { 68 for (int i = RegisterAllocator::kNumRegisters - 1; i >= 0; i--) {
69 int action = registers_[i]; 69 int action = registers_[i];
70 if (action == kPush) { 70 if (action == kPush) {
71 __ pop(RegisterAllocator::ToRegister(i)); 71 __ pop(RegisterAllocator::ToRegister(i));
72 } else if (action != kIgnore) { 72 } else if (action != kIgnore) {
73 action &= ~kSyncedFlag; 73 action &= ~kSyncedFlag;
74 __ mov(RegisterAllocator::ToRegister(i), Operand(ebp, action)); 74 __ mov(RegisterAllocator::ToRegister(i), Operand(ebp, action));
75 } 75 }
76 } 76 }
77 } 77 }
78 78
79 79
80 #undef __
81 #define __ ACCESS_MASM(masm_)
82
83 // -------------------------------------------------------------------------
84 // Platform-specific DeferredCode functions.
85
86 void DeferredCode::SaveRegisters() {
87 frame_state_.Save(masm_);
88 }
89
90
91 void DeferredCode::RestoreRegisters() {
92 frame_state_.Restore(masm_);
93 }
94
95
96 // -------------------------------------------------------------------------
97 // Platform-specific RuntimeCallHelper functions.
98
99 void VirtualFrameRuntimeCallHelper::BeforeCall(MacroAssembler* masm) const {
100 frame_state_->Save(masm);
101 }
102
103
104 void VirtualFrameRuntimeCallHelper::AfterCall(MacroAssembler* masm) const {
105 frame_state_->Restore(masm);
106 }
107
108
109 void ICRuntimeCallHelper::BeforeCall(MacroAssembler* masm) const {
110 masm->EnterInternalFrame();
111 }
112
113
114 void ICRuntimeCallHelper::AfterCall(MacroAssembler* masm) const {
115 masm->LeaveInternalFrame();
116 }
117
118
80 // ------------------------------------------------------------------------- 119 // -------------------------------------------------------------------------
81 // CodeGenState implementation. 120 // CodeGenState implementation.
82 121
83 CodeGenState::CodeGenState(CodeGenerator* owner) 122 CodeGenState::CodeGenState(CodeGenerator* owner)
84 : owner_(owner), 123 : owner_(owner),
85 destination_(NULL), 124 destination_(NULL),
86 previous_(NULL) { 125 previous_(NULL) {
87 owner_->set_state(this); 126 owner_->set_state(this);
88 } 127 }
89 128
(...skipping 5921 matching lines...) Expand 10 before | Expand all | Expand 10 after
6011 Load(args->at(0)); 6050 Load(args->at(0));
6012 Result value = frame_->Pop(); 6051 Result value = frame_->Pop();
6013 value.ToRegister(); 6052 value.ToRegister();
6014 ASSERT(value.is_valid()); 6053 ASSERT(value.is_valid());
6015 __ test(value.reg(), Immediate(kSmiTagMask | kSmiSignMask)); 6054 __ test(value.reg(), Immediate(kSmiTagMask | kSmiSignMask));
6016 value.Unuse(); 6055 value.Unuse();
6017 destination()->Split(zero); 6056 destination()->Split(zero);
6018 } 6057 }
6019 6058
6020 6059
6021 // This generates code that performs a charCodeAt() call or returns 6060 class DeferredStringCharCodeAt : public DeferredCode {
6022 // undefined in order to trigger the slow case, Runtime_StringCharCodeAt. 6061 public:
6023 // It can handle flat, 8 and 16 bit characters and cons strings where the 6062 DeferredStringCharCodeAt(Register object,
6024 // answer is found in the left hand branch of the cons. The slow case will 6063 Register index,
6025 // flatten the string, which will ensure that the answer is in the left hand 6064 Register scratch,
6026 // side the next time around. 6065 Register result)
6027 void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) { 6066 : result_(result),
6028 Comment(masm_, "[ GenerateFastCharCodeAt"); 6067 char_code_at_generator_(object,
6068 index,
6069 scratch,
6070 result,
6071 &need_conversion_,
6072 &need_conversion_,
6073 &index_out_of_range_,
6074 STRING_ANY_NUMBER_INDEX) {}
6075
6076 StringCharCodeAtGenerator* fast_case_generator() {
6077 return &char_code_at_generator_;
6078 }
6079
6080 virtual void Generate() {
6081 VirtualFrameRuntimeCallHelper call_helper(frame_state());
6082 char_code_at_generator_.GenerateSlow(masm(), call_helper);
6083
6084 __ bind(&need_conversion_);
6085 // Move the undefined value into the result register, which will
6086 // trigger conversion.
6087 __ Set(result_, Immediate(Factory::undefined_value()));
6088 __ jmp(exit_label());
6089
6090 __ bind(&index_out_of_range_);
6091 // When the index is out of range, the spec requires us to return
6092 // NaN.
6093 __ Set(result_, Immediate(Factory::nan_value()));
6094 __ jmp(exit_label());
6095 }
6096
6097 private:
6098 Register result_;
6099
6100 Label need_conversion_;
6101 Label index_out_of_range_;
6102
6103 StringCharCodeAtGenerator char_code_at_generator_;
6104 };
6105
6106
6107 // This generates code that performs a String.prototype.charCodeAt() call
6108 // or returns a smi in order to trigger conversion.
6109 void CodeGenerator::GenerateStringCharCodeAt(ZoneList<Expression*>* args) {
6110 Comment(masm_, "[ GenerateStringCharCodeAt");
6029 ASSERT(args->length() == 2); 6111 ASSERT(args->length() == 2);
6030 6112
6031 Load(args->at(0)); 6113 Load(args->at(0));
6032 Load(args->at(1)); 6114 Load(args->at(1));
6033 Result index = frame_->Pop(); 6115 Result index = frame_->Pop();
6034 Result object = frame_->Pop(); 6116 Result object = frame_->Pop();
6035
6036 // We will mutate the index register and possibly the object register.
6037 // The case where they are somehow the same register is handled
6038 // because we only mutate them in the case where the receiver is a
6039 // heap object and the index is not.
6040 object.ToRegister(); 6117 object.ToRegister();
6041 index.ToRegister(); 6118 index.ToRegister();
6119 // We might mutate the object register.
6042 frame_->Spill(object.reg()); 6120 frame_->Spill(object.reg());
6043 frame_->Spill(index.reg());
6044 6121
6045 // We need two extra registers. 6122 // We need two extra registers.
6046 Result result = allocator()->Allocate(); 6123 Result result = allocator()->Allocate();
6047 ASSERT(result.is_valid()); 6124 ASSERT(result.is_valid());
6048 Result scratch = allocator()->Allocate(); 6125 Result scratch = allocator()->Allocate();
6049 ASSERT(scratch.is_valid()); 6126 ASSERT(scratch.is_valid());
6050 6127
6051 // There is no virtual frame effect from here up to the final result 6128 DeferredStringCharCodeAt* deferred =
6052 // push. 6129 new DeferredStringCharCodeAt(object.reg(),
6053 Label slow_case; 6130 index.reg(),
6054 Label exit; 6131 scratch.reg(),
6055 StringHelper::GenerateFastCharCodeAt(masm_, 6132 result.reg());
6056 object.reg(), 6133 deferred->fast_case_generator()->GenerateFast(masm_);
6057 index.reg(), 6134 deferred->BindExit();
6058 scratch.reg(),
6059 result.reg(),
6060 &slow_case,
6061 &slow_case,
6062 &slow_case,
6063 &slow_case);
6064 __ jmp(&exit);
6065
6066 __ bind(&slow_case);
6067 // Move the undefined value into the result register, which will
6068 // trigger the slow case.
6069 __ Set(result.reg(), Immediate(Factory::undefined_value()));
6070
6071 __ bind(&exit);
6072 frame_->Push(&result); 6135 frame_->Push(&result);
6073 } 6136 }
6074 6137
6075 6138
6076 void CodeGenerator::GenerateCharFromCode(ZoneList<Expression*>* args) { 6139 class DeferredStringCharFromCode : public DeferredCode {
6077 Comment(masm_, "[ GenerateCharFromCode"); 6140 public:
6141 DeferredStringCharFromCode(Register code,
6142 Register result)
6143 : char_from_code_generator_(code, result) {}
6144
6145 StringCharFromCodeGenerator* fast_case_generator() {
6146 return &char_from_code_generator_;
6147 }
6148
6149 virtual void Generate() {
6150 VirtualFrameRuntimeCallHelper call_helper(frame_state());
6151 char_from_code_generator_.GenerateSlow(masm(), call_helper);
6152 }
6153
6154 private:
6155 StringCharFromCodeGenerator char_from_code_generator_;
6156 };
6157
6158
6159 // Generates code for creating a one-char string from a char code.
6160 void CodeGenerator::GenerateStringCharFromCode(ZoneList<Expression*>* args) {
6161 Comment(masm_, "[ GenerateStringCharFromCode");
6078 ASSERT(args->length() == 1); 6162 ASSERT(args->length() == 1);
6079 6163
6080 Load(args->at(0)); 6164 Load(args->at(0));
6081 6165
6082 Result code = frame_->Pop(); 6166 Result code = frame_->Pop();
6083 code.ToRegister(); 6167 code.ToRegister();
6084 ASSERT(code.is_valid()); 6168 ASSERT(code.is_valid());
6085 6169
6086 // StringHelper::GenerateCharFromCode may do a runtime call.
6087 frame_->SpillAll();
6088
6089 Result result = allocator()->Allocate(); 6170 Result result = allocator()->Allocate();
6090 ASSERT(result.is_valid()); 6171 ASSERT(result.is_valid());
6091 6172
6092 StringHelper::GenerateCharFromCode(masm_, 6173 DeferredStringCharFromCode* deferred = new DeferredStringCharFromCode(
6093 code.reg(), 6174 code.reg(), result.reg());
6094 result.reg(), 6175 deferred->fast_case_generator()->GenerateFast(masm_);
6095 CALL_FUNCTION); 6176 deferred->BindExit();
6096 frame_->Push(&result); 6177 frame_->Push(&result);
6097 } 6178 }
6098 6179
6180
6181 class DeferredStringCharAt : public DeferredCode {
6182 public:
6183 DeferredStringCharAt(Register object,
6184 Register index,
6185 Register scratch1,
6186 Register scratch2,
6187 Register result)
6188 : result_(result),
6189 char_at_generator_(object,
6190 index,
6191 scratch1,
6192 scratch2,
6193 result,
6194 &need_conversion_,
6195 &need_conversion_,
6196 &index_out_of_range_,
6197 STRING_ANY_NUMBER_INDEX) {}
6198
6199 StringCharAtGenerator* fast_case_generator() {
6200 return &char_at_generator_;
6201 }
6202
6203 virtual void Generate() {
6204 VirtualFrameRuntimeCallHelper call_helper(frame_state());
6205 char_at_generator_.GenerateSlow(masm(), call_helper);
6206
6207 __ bind(&need_conversion_);
6208 // Move smi zero into the result register, which will trigger
6209 // conversion.
6210 __ Set(result_, Immediate(Smi::FromInt(0)));
6211 __ jmp(exit_label());
6212
6213 __ bind(&index_out_of_range_);
6214 // When the index is out of range, the spec requires us to return
6215 // the empty string.
6216 __ Set(result_, Immediate(Factory::empty_string()));
6217 __ jmp(exit_label());
6218 }
6219
6220 private:
6221 Register result_;
6222
6223 Label need_conversion_;
6224 Label index_out_of_range_;
6225
6226 StringCharAtGenerator char_at_generator_;
6227 };
6228
6229
6230 // This generates code that performs a String.prototype.charAt() call
6231 // or returns a smi in order to trigger conversion.
6232 void CodeGenerator::GenerateStringCharAt(ZoneList<Expression*>* args) {
6233 Comment(masm_, "[ GenerateStringCharAt");
6234 ASSERT(args->length() == 2);
6235
6236 Load(args->at(0));
6237 Load(args->at(1));
6238 Result index = frame_->Pop();
6239 Result object = frame_->Pop();
6240 object.ToRegister();
6241 index.ToRegister();
6242 // We might mutate the object register.
6243 frame_->Spill(object.reg());
6244
6245 // We need three extra registers.
6246 Result result = allocator()->Allocate();
6247 ASSERT(result.is_valid());
6248 Result scratch1 = allocator()->Allocate();
6249 ASSERT(scratch1.is_valid());
6250 Result scratch2 = allocator()->Allocate();
6251 ASSERT(scratch2.is_valid());
6252
6253 DeferredStringCharAt* deferred =
6254 new DeferredStringCharAt(object.reg(),
6255 index.reg(),
6256 scratch1.reg(),
6257 scratch2.reg(),
6258 result.reg());
6259 deferred->fast_case_generator()->GenerateFast(masm_);
6260 deferred->BindExit();
6261 frame_->Push(&result);
6262 }
6263
6099 6264
6100 void CodeGenerator::GenerateIsArray(ZoneList<Expression*>* args) { 6265 void CodeGenerator::GenerateIsArray(ZoneList<Expression*>* args) {
6101 ASSERT(args->length() == 1); 6266 ASSERT(args->length() == 1);
6102 Load(args->at(0)); 6267 Load(args->at(0));
6103 Result value = frame_->Pop(); 6268 Result value = frame_->Pop();
6104 value.ToRegister(); 6269 value.ToRegister();
6105 ASSERT(value.is_valid()); 6270 ASSERT(value.is_valid());
6106 __ test(value.reg(), Immediate(kSmiTagMask)); 6271 __ test(value.reg(), Immediate(kSmiTagMask));
6107 destination()->false_target()->Branch(equal); 6272 destination()->false_target()->Branch(equal);
6108 // It is a heap object - get map. 6273 // It is a heap object - get map.
(...skipping 6258 matching lines...) Expand 10 before | Expand all | Expand 10 after
12367 OS::SNPrintF(Vector<char>(name_, kMaxNameLength), 12532 OS::SNPrintF(Vector<char>(name_, kMaxNameLength),
12368 "CompareStub_%s%s%s%s", 12533 "CompareStub_%s%s%s%s",
12369 cc_name, 12534 cc_name,
12370 strict_name, 12535 strict_name,
12371 never_nan_nan_name, 12536 never_nan_nan_name,
12372 include_number_compare_name); 12537 include_number_compare_name);
12373 return name_; 12538 return name_;
12374 } 12539 }
12375 12540
12376 12541
12377 void StringHelper::GenerateFastCharCodeAt(MacroAssembler* masm, 12542 // -------------------------------------------------------------------------
12378 Register object, 12543 // StringCharCodeAtGenerator
12379 Register index, 12544
12380 Register scratch, 12545 void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) {
12381 Register result, 12546 Label flat_string;
12382 Label* receiver_not_string,
12383 Label* index_not_smi,
12384 Label* index_out_of_range,
12385 Label* slow_case) {
12386 Label not_a_flat_string;
12387 Label try_again_with_new_string;
12388 Label ascii_string; 12547 Label ascii_string;
12389 Label got_char_code; 12548 Label got_char_code;
12390 12549
12391 // If the receiver is a smi trigger the non-string case. 12550 // If the receiver is a smi trigger the non-string case.
12392 ASSERT(kSmiTag == 0); 12551 ASSERT(kSmiTag == 0);
12393 __ test(object, Immediate(kSmiTagMask)); 12552 __ test(object_, Immediate(kSmiTagMask));
12394 __ j(zero, receiver_not_string); 12553 __ j(zero, receiver_not_string_);
12395 12554
12396 // Fetch the instance type of the receiver into result register. 12555 // Fetch the instance type of the receiver into result register.
12397 __ mov(result, FieldOperand(object, HeapObject::kMapOffset)); 12556 __ mov(result_, FieldOperand(object_, HeapObject::kMapOffset));
12398 __ movzx_b(result, FieldOperand(result, Map::kInstanceTypeOffset)); 12557 __ movzx_b(result_, FieldOperand(result_, Map::kInstanceTypeOffset));
12399 // If the receiver is not a string trigger the non-string case. 12558 // If the receiver is not a string trigger the non-string case.
12400 __ test(result, Immediate(kIsNotStringMask)); 12559 __ test(result_, Immediate(kIsNotStringMask));
12401 __ j(not_zero, receiver_not_string); 12560 __ j(not_zero, receiver_not_string_);
12402 12561
12403 // If the index is non-smi trigger the non-smi case. 12562 // If the index is non-smi trigger the non-smi case.
12404 ASSERT(kSmiTag == 0); 12563 ASSERT(kSmiTag == 0);
12405 __ test(index, Immediate(kSmiTagMask)); 12564 __ test(index_, Immediate(kSmiTagMask));
12406 __ j(not_zero, index_not_smi); 12565 __ j(not_zero, &index_not_smi_);
12566
12567 // Put smi-tagged index into scratch register.
12568 __ mov(scratch_, index_);
12569 __ bind(&got_smi_index_);
12407 12570
12408 // Check for index out of range. 12571 // Check for index out of range.
12409 __ cmp(index, FieldOperand(object, String::kLengthOffset)); 12572 __ cmp(scratch_, FieldOperand(object_, String::kLengthOffset));
12410 __ j(above_equal, index_out_of_range); 12573 __ j(above_equal, index_out_of_range_);
12411
12412 __ bind(&try_again_with_new_string);
12413 // ----------- S t a t e -------------
12414 // -- object : string to access
12415 // -- result : instance type of the string
12416 // -- scratch : non-negative index < length
12417 // -----------------------------------
12418 12574
12419 // We need special handling for non-flat strings. 12575 // We need special handling for non-flat strings.
12420 ASSERT(kSeqStringTag == 0); 12576 ASSERT(kSeqStringTag == 0);
12421 __ test(result, Immediate(kStringRepresentationMask)); 12577 __ test(result_, Immediate(kStringRepresentationMask));
12422 __ j(not_zero, &not_a_flat_string); 12578 __ j(zero, &flat_string);
12423
12424 // Check for 1-byte or 2-byte string.
12425 ASSERT(kAsciiStringTag != 0);
12426 __ test(result, Immediate(kStringEncodingMask));
12427 __ j(not_zero, &ascii_string);
12428
12429 // 2-byte string.
12430 // Load the 2-byte character code into the result register.
12431 ASSERT(kSmiTag == 0 && kSmiTagSize == 1); // index is smi (powered by 2).
12432 __ movzx_w(result, FieldOperand(object,
12433 index, times_1,
12434 SeqTwoByteString::kHeaderSize));
12435 __ jmp(&got_char_code);
12436 12579
12437 // Handle non-flat strings. 12580 // Handle non-flat strings.
12438 __ bind(&not_a_flat_string); 12581 __ test(result_, Immediate(kIsConsStringMask));
12439 __ and_(result, kStringRepresentationMask); 12582 __ j(zero, &call_runtime_);
12440 __ cmp(result, kConsStringTag);
12441 __ j(not_equal, slow_case);
12442 12583
12443 // ConsString. 12584 // ConsString.
12444 // Check whether the right hand side is the empty string (i.e. if 12585 // Check whether the right hand side is the empty string (i.e. if
12445 // this is really a flat string in a cons string). If that is not 12586 // this is really a flat string in a cons string). If that is not
12446 // the case we would rather go to the runtime system now to flatten 12587 // the case we would rather go to the runtime system now to flatten
12447 // the string. 12588 // the string.
12448 __ mov(result, FieldOperand(object, ConsString::kSecondOffset)); 12589 __ cmp(FieldOperand(object_, ConsString::kSecondOffset),
12449 __ cmp(Operand(result), Factory::empty_string()); 12590 Immediate(Factory::empty_string()));
12450 __ j(not_equal, slow_case); 12591 __ j(not_equal, &call_runtime_);
12451 // Get the first of the two strings and load its instance type. 12592 // Get the first of the two strings and load its instance type.
12452 __ mov(object, FieldOperand(object, ConsString::kFirstOffset)); 12593 __ mov(object_, FieldOperand(object_, ConsString::kFirstOffset));
12453 __ mov(result, FieldOperand(object, HeapObject::kMapOffset)); 12594 __ mov(result_, FieldOperand(object_, HeapObject::kMapOffset));
12454 __ movzx_b(result, FieldOperand(result, Map::kInstanceTypeOffset)); 12595 __ movzx_b(result_, FieldOperand(result_, Map::kInstanceTypeOffset));
12455 __ jmp(&try_again_with_new_string); 12596 // If the first cons component is also non-flat, then go to runtime.
12597 ASSERT(kSeqStringTag == 0);
12598 __ test(result_, Immediate(kStringRepresentationMask));
12599 __ j(not_zero, &call_runtime_);
12600
12601 // Check for 1-byte or 2-byte string.
12602 __ bind(&flat_string);
12603 ASSERT(kAsciiStringTag != 0);
12604 __ test(result_, Immediate(kStringEncodingMask));
12605 __ j(not_zero, &ascii_string);
12606
12607 // 2-byte string.
12608 // Load the 2-byte character code into the result register.
12609 ASSERT(kSmiTag == 0 && kSmiTagSize == 1);
12610 __ movzx_w(result_, FieldOperand(object_,
12611 scratch_, times_1, // Scratch is smi-tagged.
12612 SeqTwoByteString::kHeaderSize));
12613 __ jmp(&got_char_code);
12456 12614
12457 // ASCII string. 12615 // ASCII string.
12616 // Load the byte into the result register.
12458 __ bind(&ascii_string); 12617 __ bind(&ascii_string);
12459 // Put untagged index into scratch register. 12618 __ SmiUntag(scratch_);
12460 __ mov(scratch, index); 12619 __ movzx_b(result_, FieldOperand(object_,
12461 __ SmiUntag(scratch); 12620 scratch_, times_1,
12462 12621 SeqAsciiString::kHeaderSize));
12463 // Load the byte into the result register.
12464 __ movzx_b(result, FieldOperand(object,
12465 scratch, times_1,
12466 SeqAsciiString::kHeaderSize));
12467 __ bind(&got_char_code); 12622 __ bind(&got_char_code);
12468 __ SmiTag(result); 12623 __ SmiTag(result_);
12469 } 12624 __ bind(&exit_);
12470 12625 }
12471 12626
12472 void StringHelper::GenerateCharFromCode(MacroAssembler* masm, 12627
12473 Register code, 12628 void StringCharCodeAtGenerator::GenerateSlow(
12474 Register result, 12629 MacroAssembler* masm, const RuntimeCallHelper& call_helper) {
12475 InvokeFlag flag) { 12630 __ Abort("Unexpected fallthrough to CharCodeAt slow case");
12476 ASSERT(!code.is(result)); 12631
12477 12632 // Index is not a smi.
12478 Label slow_case; 12633 __ bind(&index_not_smi_);
12479 Label exit; 12634 // If index is a heap number, try converting it to an integer.
12480 12635 __ CheckMap(index_, Factory::heap_number_map(), index_not_number_, true);
12636 call_helper.BeforeCall(masm);
12637 __ push(object_);
12638 __ push(index_);
12639 __ push(result_);
12640 __ push(index_); // Consumed by runtime conversion function.
12641 if (index_flags_ == STRING_ANY_NUMBER_INDEX) {
12642 // Strictly speaking, NumberToInteger should be called here, but
12643 // our string lengths don't exceed 32 bits and using ToUint32 maps
12644 // -0 to 0, which is what is required by the spec when accessing
12645 // strings.
12646 __ CallRuntime(Runtime::kNumberToJSUint32, 1);
12647 } else {
12648 ASSERT(index_flags_ == STRING_REQUIRE_ARRAY_INDEX);
12649 // NumberToSmi discards numbers that are not exact integers.
12650 __ CallRuntime(Runtime::kNumberToSmi, 1);
12651 }
12652 if (!scratch_.is(eax)) {
12653 // Save the conversion result before the pop instructions below
12654 // have a chance to overwrite it.
12655 __ mov(scratch_, eax);
12656 }
12657 __ pop(result_);
12658 __ pop(index_);
12659 __ pop(object_);
12660 call_helper.AfterCall(masm);
12661 // If index is still not a smi, it must be out of range.
12662 ASSERT(kSmiTag == 0);
12663 __ test(scratch_, Immediate(kSmiTagMask));
12664 __ j(not_zero, index_out_of_range_);
12665 // Otherwise, return to the fast path.
12666 __ jmp(&got_smi_index_);
12667
12668 // Call runtime. We get here when the receiver is a string and the
12669 // index is a number, but the code of getting the actual character
12670 // is too complex (e.g., when the string needs to be flattened).
12671 __ bind(&call_runtime_);
12672 call_helper.BeforeCall(masm);
12673 __ push(object_);
12674 __ push(index_);
12675 __ CallRuntime(Runtime::kStringCharCodeAt, 2);
12676 if (!result_.is(eax)) {
12677 __ mov(result_, eax);
12678 }
12679 call_helper.AfterCall(masm);
12680 __ jmp(&exit_);
12681
12682 __ Abort("Unexpected fallthrough from CharCodeAt slow case");
12683 }
12684
12685
12686 // -------------------------------------------------------------------------
12687 // StringCharFromCodeGenerator
12688
12689 void StringCharFromCodeGenerator::GenerateFast(MacroAssembler* masm) {
12481 // Fast case of Heap::LookupSingleCharacterStringFromCode. 12690 // Fast case of Heap::LookupSingleCharacterStringFromCode.
12482 ASSERT(kSmiTag == 0); 12691 ASSERT(kSmiTag == 0);
12483 ASSERT(kSmiShiftSize == 0); 12692 ASSERT(kSmiShiftSize == 0);
12484 ASSERT(IsPowerOf2(String::kMaxAsciiCharCode + 1)); 12693 ASSERT(IsPowerOf2(String::kMaxAsciiCharCode + 1));
12485 __ test(code, 12694 __ test(code_,
12486 Immediate(kSmiTagMask | 12695 Immediate(kSmiTagMask |
12487 ((~String::kMaxAsciiCharCode) << kSmiTagSize))); 12696 ((~String::kMaxAsciiCharCode) << kSmiTagSize)));
12488 __ j(not_zero, &slow_case, not_taken); 12697 __ j(not_zero, &slow_case_, not_taken);
12489 12698
12490 __ Set(result, Immediate(Factory::single_character_string_cache())); 12699 __ Set(result_, Immediate(Factory::single_character_string_cache()));
12491 ASSERT(kSmiTag == 0); 12700 ASSERT(kSmiTag == 0);
12492 ASSERT(kSmiTagSize == 1); 12701 ASSERT(kSmiTagSize == 1);
12493 ASSERT(kSmiShiftSize == 0); 12702 ASSERT(kSmiShiftSize == 0);
12494 // At this point code register contains smi tagged ascii char code. 12703 // At this point code register contains smi tagged ascii char code.
12495 __ mov(result, FieldOperand(result, 12704 __ mov(result_, FieldOperand(result_,
12496 code, times_half_pointer_size, 12705 code_, times_half_pointer_size,
12497 FixedArray::kHeaderSize)); 12706 FixedArray::kHeaderSize));
12498 __ cmp(result, Factory::undefined_value()); 12707 __ cmp(result_, Factory::undefined_value());
12499 __ j(equal, &slow_case, not_taken); 12708 __ j(equal, &slow_case_, not_taken);
12500 __ jmp(&exit); 12709 __ bind(&exit_);
12501 12710 }
12502 __ bind(&slow_case); 12711
12503 if (flag == CALL_FUNCTION) { 12712
12504 __ push(code); 12713 void StringCharFromCodeGenerator::GenerateSlow(
12505 __ CallRuntime(Runtime::kCharFromCode, 1); 12714 MacroAssembler* masm, const RuntimeCallHelper& call_helper) {
12506 if (!result.is(eax)) { 12715 __ Abort("Unexpected fallthrough to CharFromCode slow case");
12507 __ mov(result, eax); 12716
12508 } 12717 __ bind(&slow_case_);
12509 } else { 12718 call_helper.BeforeCall(masm);
12510 ASSERT(flag == JUMP_FUNCTION); 12719 __ push(code_);
12511 ASSERT(result.is(eax)); 12720 __ CallRuntime(Runtime::kCharFromCode, 1);
12512 __ pop(eax); // Save return address. 12721 if (!result_.is(eax)) {
12513 __ push(code); 12722 __ mov(result_, eax);
12514 __ push(eax); // Restore return address. 12723 }
12515 __ TailCallRuntime(Runtime::kCharFromCode, 1, 1); 12724 call_helper.AfterCall(masm);
12516 } 12725 __ jmp(&exit_);
12517 12726
12518 __ bind(&exit); 12727 __ Abort("Unexpected fallthrough from CharFromCode slow case");
12519 if (flag == JUMP_FUNCTION) { 12728 }
12520 ASSERT(result.is(eax)); 12729
12521 __ ret(0); 12730
12522 } 12731 // -------------------------------------------------------------------------
12523 } 12732 // StringCharAtGenerator
12524 12733
12525 12734 void StringCharAtGenerator::GenerateFast(MacroAssembler* masm) {
12735 char_code_at_generator_.GenerateFast(masm);
12736 char_from_code_generator_.GenerateFast(masm);
12737 }
12738
12739
12740 void StringCharAtGenerator::GenerateSlow(
12741 MacroAssembler* masm, const RuntimeCallHelper& call_helper) {
12742 char_code_at_generator_.GenerateSlow(masm, call_helper);
12743 char_from_code_generator_.GenerateSlow(masm, call_helper);
12744 }
12745
12746
12526 void StringAddStub::Generate(MacroAssembler* masm) { 12747 void StringAddStub::Generate(MacroAssembler* masm) {
12527 Label string_add_runtime; 12748 Label string_add_runtime;
12528 12749
12529 // Load the two arguments. 12750 // Load the two arguments.
12530 __ mov(eax, Operand(esp, 2 * kPointerSize)); // First argument. 12751 __ mov(eax, Operand(esp, 2 * kPointerSize)); // First argument.
12531 __ mov(edx, Operand(esp, 1 * kPointerSize)); // Second argument. 12752 __ mov(edx, Operand(esp, 1 * kPointerSize)); // Second argument.
12532 12753
12533 // Make sure that both arguments are strings if not known in advance. 12754 // Make sure that both arguments are strings if not known in advance.
12534 if (string_check_) { 12755 if (string_check_) {
12535 __ test(eax, Immediate(kSmiTagMask)); 12756 __ test(eax, Immediate(kSmiTagMask));
(...skipping 733 matching lines...) Expand 10 before | Expand all | Expand 10 after
13269 // tagged as a small integer. 13490 // tagged as a small integer.
13270 __ bind(&runtime); 13491 __ bind(&runtime);
13271 __ TailCallRuntime(Runtime::kStringCompare, 2, 1); 13492 __ TailCallRuntime(Runtime::kStringCompare, 2, 1);
13272 } 13493 }
13273 13494
13274 #undef __ 13495 #undef __
13275 13496
13276 } } // namespace v8::internal 13497 } } // namespace v8::internal
13277 13498
13278 #endif // V8_TARGET_ARCH_IA32 13499 #endif // V8_TARGET_ARCH_IA32
OLDNEW
« src/codegen.h ('K') | « src/ia32/codegen-ia32.h ('k') | src/ia32/full-codegen-ia32.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698