OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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, ¬_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(¬_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 Loading... |
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 |
OLD | NEW |