| 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 |