OLD | NEW |
1 // Copyright 2006-2009 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2009 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
147 #ifdef DEBUG | 147 #ifdef DEBUG |
148 if (strlen(FLAG_stop_at) > 0 && | 148 if (strlen(FLAG_stop_at) > 0 && |
149 fun->name()->IsEqualTo(CStrVector(FLAG_stop_at))) { | 149 fun->name()->IsEqualTo(CStrVector(FLAG_stop_at))) { |
150 frame_->SpillAll(); | 150 frame_->SpillAll(); |
151 __ int3(); | 151 __ int3(); |
152 } | 152 } |
153 #endif | 153 #endif |
154 | 154 |
155 // New scope to get automatic timing calculation. | 155 // New scope to get automatic timing calculation. |
156 { // NOLINT | 156 { // NOLINT |
157 HistogramTimerScope codegen_timer(&Counters::code_generation); | 157 HistogramTimerScope codegen_timer(&COUNTER(code_generation)); |
158 CodeGenState state(this); | 158 CodeGenState state(this); |
159 | 159 |
160 // Entry: | 160 // Entry: |
161 // Stack: receiver, arguments, return address. | 161 // Stack: receiver, arguments, return address. |
162 // ebp: caller's frame pointer | 162 // ebp: caller's frame pointer |
163 // esp: stack pointer | 163 // esp: stack pointer |
164 // edi: called JS function | 164 // edi: called JS function |
165 // esi: callee's context | 165 // esi: callee's context |
166 allocator_->Initialize(); | 166 allocator_->Initialize(); |
167 frame_->Enter(); | 167 frame_->Enter(); |
(...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
309 | 309 |
310 // Code generation state must be reset. | 310 // Code generation state must be reset. |
311 ASSERT(state_ == NULL); | 311 ASSERT(state_ == NULL); |
312 ASSERT(loop_nesting() == 0); | 312 ASSERT(loop_nesting() == 0); |
313 ASSERT(!function_return_is_shadowed_); | 313 ASSERT(!function_return_is_shadowed_); |
314 function_return_.Unuse(); | 314 function_return_.Unuse(); |
315 DeleteFrame(); | 315 DeleteFrame(); |
316 | 316 |
317 // Process any deferred code using the register allocator. | 317 // Process any deferred code using the register allocator. |
318 if (!HasStackOverflow()) { | 318 if (!HasStackOverflow()) { |
319 HistogramTimerScope deferred_timer(&Counters::deferred_code_generation); | 319 HistogramTimerScope deferred_timer(&COUNTER(deferred_code_generation)); |
320 JumpTarget::set_compiling_deferred_code(true); | 320 JumpTarget::set_compiling_deferred_code(true); |
321 ProcessDeferred(); | 321 ProcessDeferred(); |
322 JumpTarget::set_compiling_deferred_code(false); | 322 JumpTarget::set_compiling_deferred_code(false); |
323 } | 323 } |
324 | 324 |
325 // There is no need to delete the register allocator, it is a | 325 // There is no need to delete the register allocator, it is a |
326 // stack-allocated local. | 326 // stack-allocated local. |
327 allocator_ = NULL; | 327 allocator_ = NULL; |
328 scope_ = NULL; | 328 scope_ = NULL; |
329 } | 329 } |
(...skipping 5690 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6020 // The call must be followed by a test eax instruction to indicate | 6020 // The call must be followed by a test eax instruction to indicate |
6021 // that the inobject property case was inlined. | 6021 // that the inobject property case was inlined. |
6022 // | 6022 // |
6023 // Store the delta to the map check instruction here in the test | 6023 // Store the delta to the map check instruction here in the test |
6024 // instruction. Use masm_-> instead of the __ macro since the | 6024 // instruction. Use masm_-> instead of the __ macro since the |
6025 // latter can't return a value. | 6025 // latter can't return a value. |
6026 int delta_to_patch_site = masm_->SizeOfCodeGeneratedSince(patch_site()); | 6026 int delta_to_patch_site = masm_->SizeOfCodeGeneratedSince(patch_site()); |
6027 // Here we use masm_-> instead of the __ macro because this is the | 6027 // Here we use masm_-> instead of the __ macro because this is the |
6028 // instruction that gets patched and coverage code gets in the way. | 6028 // instruction that gets patched and coverage code gets in the way. |
6029 masm_->test(eax, Immediate(-delta_to_patch_site)); | 6029 masm_->test(eax, Immediate(-delta_to_patch_site)); |
6030 __ IncrementCounter(&Counters::named_load_inline_miss, 1); | 6030 __ IncrementCounter(&COUNTER(named_load_inline_miss), 1); |
6031 | 6031 |
6032 if (!dst_.is(eax)) __ mov(dst_, eax); | 6032 if (!dst_.is(eax)) __ mov(dst_, eax); |
6033 __ pop(receiver_); | 6033 __ pop(receiver_); |
6034 } | 6034 } |
6035 | 6035 |
6036 | 6036 |
6037 class DeferredReferenceGetKeyedValue: public DeferredCode { | 6037 class DeferredReferenceGetKeyedValue: public DeferredCode { |
6038 public: | 6038 public: |
6039 explicit DeferredReferenceGetKeyedValue(Register dst, | 6039 explicit DeferredReferenceGetKeyedValue(Register dst, |
6040 Register receiver, | 6040 Register receiver, |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6074 __ call(ic, mode); | 6074 __ call(ic, mode); |
6075 // The delta from the start of the map-compare instruction to the | 6075 // The delta from the start of the map-compare instruction to the |
6076 // test instruction. We use masm_-> directly here instead of the __ | 6076 // test instruction. We use masm_-> directly here instead of the __ |
6077 // macro because the macro sometimes uses macro expansion to turn | 6077 // macro because the macro sometimes uses macro expansion to turn |
6078 // into something that can't return a value. This is encountered | 6078 // into something that can't return a value. This is encountered |
6079 // when doing generated code coverage tests. | 6079 // when doing generated code coverage tests. |
6080 int delta_to_patch_site = masm_->SizeOfCodeGeneratedSince(patch_site()); | 6080 int delta_to_patch_site = masm_->SizeOfCodeGeneratedSince(patch_site()); |
6081 // Here we use masm_-> instead of the __ macro because this is the | 6081 // Here we use masm_-> instead of the __ macro because this is the |
6082 // instruction that gets patched and coverage code gets in the way. | 6082 // instruction that gets patched and coverage code gets in the way. |
6083 masm_->test(eax, Immediate(-delta_to_patch_site)); | 6083 masm_->test(eax, Immediate(-delta_to_patch_site)); |
6084 __ IncrementCounter(&Counters::keyed_load_inline_miss, 1); | 6084 __ IncrementCounter(&COUNTER(keyed_load_inline_miss), 1); |
6085 | 6085 |
6086 if (!dst_.is(eax)) __ mov(dst_, eax); | 6086 if (!dst_.is(eax)) __ mov(dst_, eax); |
6087 __ pop(key_); | 6087 __ pop(key_); |
6088 __ pop(receiver_); | 6088 __ pop(receiver_); |
6089 } | 6089 } |
6090 | 6090 |
6091 | 6091 |
6092 class DeferredReferenceSetKeyedValue: public DeferredCode { | 6092 class DeferredReferenceSetKeyedValue: public DeferredCode { |
6093 public: | 6093 public: |
6094 DeferredReferenceSetKeyedValue(Register value, | 6094 DeferredReferenceSetKeyedValue(Register value, |
6095 Register key, | 6095 Register key, |
6096 Register receiver) | 6096 Register receiver) |
6097 : value_(value), key_(key), receiver_(receiver) { | 6097 : value_(value), key_(key), receiver_(receiver) { |
6098 set_comment("[ DeferredReferenceSetKeyedValue"); | 6098 set_comment("[ DeferredReferenceSetKeyedValue"); |
6099 } | 6099 } |
6100 | 6100 |
6101 virtual void Generate(); | 6101 virtual void Generate(); |
6102 | 6102 |
6103 Label* patch_site() { return &patch_site_; } | 6103 Label* patch_site() { return &patch_site_; } |
6104 | 6104 |
6105 private: | 6105 private: |
6106 Register value_; | 6106 Register value_; |
6107 Register key_; | 6107 Register key_; |
6108 Register receiver_; | 6108 Register receiver_; |
6109 Label patch_site_; | 6109 Label patch_site_; |
6110 }; | 6110 }; |
6111 | 6111 |
6112 | 6112 |
6113 void DeferredReferenceSetKeyedValue::Generate() { | 6113 void DeferredReferenceSetKeyedValue::Generate() { |
6114 __ IncrementCounter(&Counters::keyed_store_inline_miss, 1); | 6114 __ IncrementCounter(&COUNTER(keyed_store_inline_miss), 1); |
6115 // Push receiver and key arguments on the stack. | 6115 // Push receiver and key arguments on the stack. |
6116 __ push(receiver_); | 6116 __ push(receiver_); |
6117 __ push(key_); | 6117 __ push(key_); |
6118 // Move value argument to eax as expected by the IC stub. | 6118 // Move value argument to eax as expected by the IC stub. |
6119 if (!value_.is(eax)) __ mov(eax, value_); | 6119 if (!value_.is(eax)) __ mov(eax, value_); |
6120 // Call the IC stub. | 6120 // Call the IC stub. |
6121 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); | 6121 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); |
6122 __ call(ic, RelocInfo::CODE_TARGET); | 6122 __ call(ic, RelocInfo::CODE_TARGET); |
6123 // The delta from the start of the map-compare instruction to the | 6123 // The delta from the start of the map-compare instruction to the |
6124 // test instruction. We use masm_-> directly here instead of the | 6124 // test instruction. We use masm_-> directly here instead of the |
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6233 // The delta from the patch label to the load offset must be | 6233 // The delta from the patch label to the load offset must be |
6234 // statically known. | 6234 // statically known. |
6235 ASSERT(masm->SizeOfCodeGeneratedSince(deferred->patch_site()) == | 6235 ASSERT(masm->SizeOfCodeGeneratedSince(deferred->patch_site()) == |
6236 LoadIC::kOffsetToLoadInstruction); | 6236 LoadIC::kOffsetToLoadInstruction); |
6237 // The initial (invalid) offset has to be large enough to force | 6237 // The initial (invalid) offset has to be large enough to force |
6238 // a 32-bit instruction encoding to allow patching with an | 6238 // a 32-bit instruction encoding to allow patching with an |
6239 // arbitrary offset. Use kMaxInt (minus kHeapObjectTag). | 6239 // arbitrary offset. Use kMaxInt (minus kHeapObjectTag). |
6240 int offset = kMaxInt; | 6240 int offset = kMaxInt; |
6241 masm->mov(value.reg(), FieldOperand(receiver.reg(), offset)); | 6241 masm->mov(value.reg(), FieldOperand(receiver.reg(), offset)); |
6242 | 6242 |
6243 __ IncrementCounter(&Counters::named_load_inline, 1); | 6243 __ IncrementCounter(&COUNTER(named_load_inline), 1); |
6244 deferred->BindExit(); | 6244 deferred->BindExit(); |
6245 cgen_->frame()->Push(&receiver); | 6245 cgen_->frame()->Push(&receiver); |
6246 cgen_->frame()->Push(&value); | 6246 cgen_->frame()->Push(&value); |
6247 } | 6247 } |
6248 break; | 6248 break; |
6249 } | 6249 } |
6250 | 6250 |
6251 case KEYED: { | 6251 case KEYED: { |
6252 Comment cmnt(masm, "[ Load from keyed Property"); | 6252 Comment cmnt(masm, "[ Load from keyed Property"); |
6253 Variable* var = expression_->AsVariableProxy()->AsVariable(); | 6253 Variable* var = expression_->AsVariableProxy()->AsVariable(); |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6328 // coming from the deferred code will be in eax. | 6328 // coming from the deferred code will be in eax. |
6329 Result value = index; | 6329 Result value = index; |
6330 __ mov(value.reg(), Operand(elements.reg(), | 6330 __ mov(value.reg(), Operand(elements.reg(), |
6331 index.reg(), | 6331 index.reg(), |
6332 times_4, | 6332 times_4, |
6333 FixedArray::kHeaderSize - kHeapObjectTag)); | 6333 FixedArray::kHeaderSize - kHeapObjectTag)); |
6334 elements.Unuse(); | 6334 elements.Unuse(); |
6335 index.Unuse(); | 6335 index.Unuse(); |
6336 __ cmp(Operand(value.reg()), Immediate(Factory::the_hole_value())); | 6336 __ cmp(Operand(value.reg()), Immediate(Factory::the_hole_value())); |
6337 deferred->Branch(equal); | 6337 deferred->Branch(equal); |
6338 __ IncrementCounter(&Counters::keyed_load_inline, 1); | 6338 __ IncrementCounter(&COUNTER(keyed_load_inline), 1); |
6339 | 6339 |
6340 deferred->BindExit(); | 6340 deferred->BindExit(); |
6341 // Restore the receiver and key to the frame and push the | 6341 // Restore the receiver and key to the frame and push the |
6342 // result on top of it. | 6342 // result on top of it. |
6343 cgen_->frame()->Push(&receiver); | 6343 cgen_->frame()->Push(&receiver); |
6344 cgen_->frame()->Push(&key); | 6344 cgen_->frame()->Push(&key); |
6345 cgen_->frame()->Push(&value); | 6345 cgen_->frame()->Push(&value); |
6346 | 6346 |
6347 } else { | 6347 } else { |
6348 Comment cmnt(masm, "[ Load from keyed Property"); | 6348 Comment cmnt(masm, "[ Load from keyed Property"); |
(...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6497 __ cmp(FieldOperand(tmp.reg(), HeapObject::kMapOffset), | 6497 __ cmp(FieldOperand(tmp.reg(), HeapObject::kMapOffset), |
6498 Immediate(Factory::fixed_array_map())); | 6498 Immediate(Factory::fixed_array_map())); |
6499 deferred->Branch(not_equal); | 6499 deferred->Branch(not_equal); |
6500 | 6500 |
6501 // Store the value. | 6501 // Store the value. |
6502 __ mov(Operand(tmp.reg(), | 6502 __ mov(Operand(tmp.reg(), |
6503 key.reg(), | 6503 key.reg(), |
6504 times_2, | 6504 times_2, |
6505 FixedArray::kHeaderSize - kHeapObjectTag), | 6505 FixedArray::kHeaderSize - kHeapObjectTag), |
6506 value.reg()); | 6506 value.reg()); |
6507 __ IncrementCounter(&Counters::keyed_store_inline, 1); | 6507 __ IncrementCounter(&COUNTER(keyed_store_inline), 1); |
6508 | 6508 |
6509 deferred->BindExit(); | 6509 deferred->BindExit(); |
6510 | 6510 |
6511 cgen_->frame()->Push(&receiver); | 6511 cgen_->frame()->Push(&receiver); |
6512 cgen_->frame()->Push(&key); | 6512 cgen_->frame()->Push(&key); |
6513 cgen_->frame()->Push(&value); | 6513 cgen_->frame()->Push(&value); |
6514 } else { | 6514 } else { |
6515 Result answer = cgen_->frame()->CallKeyedStoreIC(); | 6515 Result answer = cgen_->frame()->CallKeyedStoreIC(); |
6516 // Make sure that we do not have a test instruction after the | 6516 // Make sure that we do not have a test instruction after the |
6517 // call. A test instruction after the call is used to | 6517 // call. A test instruction after the call is used to |
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6622 __ mov(left_arg, left); | 6622 __ mov(left_arg, left); |
6623 } else { | 6623 } else { |
6624 // Order of moves is not important. | 6624 // Order of moves is not important. |
6625 __ mov(left_arg, left); | 6625 __ mov(left_arg, left); |
6626 __ mov(right_arg, right); | 6626 __ mov(right_arg, right); |
6627 } | 6627 } |
6628 } | 6628 } |
6629 | 6629 |
6630 // Update flags to indicate that arguments are in registers. | 6630 // Update flags to indicate that arguments are in registers. |
6631 SetArgsInRegisters(); | 6631 SetArgsInRegisters(); |
6632 __ IncrementCounter(&Counters::generic_binary_stub_calls_regs, 1); | 6632 __ IncrementCounter(&COUNTER(generic_binary_stub_calls_regs), 1); |
6633 } | 6633 } |
6634 | 6634 |
6635 // Call the stub. | 6635 // Call the stub. |
6636 __ CallStub(this); | 6636 __ CallStub(this); |
6637 } | 6637 } |
6638 | 6638 |
6639 | 6639 |
6640 void GenericBinaryOpStub::GenerateCall( | 6640 void GenericBinaryOpStub::GenerateCall( |
6641 MacroAssembler* masm, | 6641 MacroAssembler* masm, |
6642 Register left, | 6642 Register left, |
(...skipping 11 matching lines...) Expand all Loading... |
6654 } else if (left.is(right_arg) && IsOperationCommutative()) { | 6654 } else if (left.is(right_arg) && IsOperationCommutative()) { |
6655 __ mov(left_arg, Immediate(right)); | 6655 __ mov(left_arg, Immediate(right)); |
6656 SetArgsReversed(); | 6656 SetArgsReversed(); |
6657 } else { | 6657 } else { |
6658 __ mov(left_arg, left); | 6658 __ mov(left_arg, left); |
6659 __ mov(right_arg, Immediate(right)); | 6659 __ mov(right_arg, Immediate(right)); |
6660 } | 6660 } |
6661 | 6661 |
6662 // Update flags to indicate that arguments are in registers. | 6662 // Update flags to indicate that arguments are in registers. |
6663 SetArgsInRegisters(); | 6663 SetArgsInRegisters(); |
6664 __ IncrementCounter(&Counters::generic_binary_stub_calls_regs, 1); | 6664 __ IncrementCounter(&COUNTER(generic_binary_stub_calls_regs), 1); |
6665 } | 6665 } |
6666 | 6666 |
6667 // Call the stub. | 6667 // Call the stub. |
6668 __ CallStub(this); | 6668 __ CallStub(this); |
6669 } | 6669 } |
6670 | 6670 |
6671 | 6671 |
6672 void GenericBinaryOpStub::GenerateCall( | 6672 void GenericBinaryOpStub::GenerateCall( |
6673 MacroAssembler* masm, | 6673 MacroAssembler* masm, |
6674 Smi* left, | 6674 Smi* left, |
(...skipping 10 matching lines...) Expand all Loading... |
6685 __ mov(left_arg, Immediate(left)); | 6685 __ mov(left_arg, Immediate(left)); |
6686 } else if (right.is(left_arg) && IsOperationCommutative()) { | 6686 } else if (right.is(left_arg) && IsOperationCommutative()) { |
6687 __ mov(right_arg, Immediate(left)); | 6687 __ mov(right_arg, Immediate(left)); |
6688 SetArgsReversed(); | 6688 SetArgsReversed(); |
6689 } else { | 6689 } else { |
6690 __ mov(left_arg, Immediate(left)); | 6690 __ mov(left_arg, Immediate(left)); |
6691 __ mov(right_arg, right); | 6691 __ mov(right_arg, right); |
6692 } | 6692 } |
6693 // Update flags to indicate that arguments are in registers. | 6693 // Update flags to indicate that arguments are in registers. |
6694 SetArgsInRegisters(); | 6694 SetArgsInRegisters(); |
6695 __ IncrementCounter(&Counters::generic_binary_stub_calls_regs, 1); | 6695 __ IncrementCounter(&COUNTER(generic_binary_stub_calls_regs), 1); |
6696 } | 6696 } |
6697 | 6697 |
6698 // Call the stub. | 6698 // Call the stub. |
6699 __ CallStub(this); | 6699 __ CallStub(this); |
6700 } | 6700 } |
6701 | 6701 |
6702 | 6702 |
6703 void GenericBinaryOpStub::GenerateSmiCode(MacroAssembler* masm, Label* slow) { | 6703 void GenericBinaryOpStub::GenerateSmiCode(MacroAssembler* masm, Label* slow) { |
6704 // Perform fast-case smi code for the operation (eax <op> ebx) and | 6704 // Perform fast-case smi code for the operation (eax <op> ebx) and |
6705 // leave result in register eax. | 6705 // leave result in register eax. |
(...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6840 default: | 6840 default: |
6841 UNREACHABLE(); | 6841 UNREACHABLE(); |
6842 break; | 6842 break; |
6843 } | 6843 } |
6844 } | 6844 } |
6845 | 6845 |
6846 | 6846 |
6847 void GenericBinaryOpStub::Generate(MacroAssembler* masm) { | 6847 void GenericBinaryOpStub::Generate(MacroAssembler* masm) { |
6848 Label call_runtime; | 6848 Label call_runtime; |
6849 | 6849 |
6850 __ IncrementCounter(&Counters::generic_binary_stub_calls, 1); | 6850 __ IncrementCounter(&COUNTER(generic_binary_stub_calls), 1); |
6851 | 6851 |
6852 // Generate fast case smi code if requested. This flag is set when the fast | 6852 // Generate fast case smi code if requested. This flag is set when the fast |
6853 // case smi code is not generated by the caller. Generating it here will speed | 6853 // case smi code is not generated by the caller. Generating it here will speed |
6854 // up common operations. | 6854 // up common operations. |
6855 if (HasSmiCodeInStub()) { | 6855 if (HasSmiCodeInStub()) { |
6856 Label slow; | 6856 Label slow; |
6857 __ mov(ebx, Operand(esp, 1 * kPointerSize)); | 6857 __ mov(ebx, Operand(esp, 1 * kPointerSize)); |
6858 __ mov(eax, Operand(esp, 2 * kPointerSize)); | 6858 __ mov(eax, Operand(esp, 2 * kPointerSize)); |
6859 GenerateSmiCode(masm, &slow); | 6859 GenerateSmiCode(masm, &slow); |
6860 GenerateReturn(masm); | 6860 GenerateReturn(masm); |
(...skipping 1398 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
8259 | 8259 |
8260 // Both arguments are strings. | 8260 // Both arguments are strings. |
8261 // eax: first string | 8261 // eax: first string |
8262 // edx: second string | 8262 // edx: second string |
8263 // Check if either of the strings are empty. In that case return the other. | 8263 // Check if either of the strings are empty. In that case return the other. |
8264 Label second_not_zero_length, both_not_zero_length; | 8264 Label second_not_zero_length, both_not_zero_length; |
8265 __ mov(ecx, FieldOperand(edx, String::kLengthOffset)); | 8265 __ mov(ecx, FieldOperand(edx, String::kLengthOffset)); |
8266 __ test(ecx, Operand(ecx)); | 8266 __ test(ecx, Operand(ecx)); |
8267 __ j(not_zero, &second_not_zero_length); | 8267 __ j(not_zero, &second_not_zero_length); |
8268 // Second string is empty, result is first string which is already in eax. | 8268 // Second string is empty, result is first string which is already in eax. |
8269 __ IncrementCounter(&Counters::string_add_native, 1); | 8269 __ IncrementCounter(&COUNTER(string_add_native), 1); |
8270 __ ret(2 * kPointerSize); | 8270 __ ret(2 * kPointerSize); |
8271 __ bind(&second_not_zero_length); | 8271 __ bind(&second_not_zero_length); |
8272 __ mov(ebx, FieldOperand(eax, String::kLengthOffset)); | 8272 __ mov(ebx, FieldOperand(eax, String::kLengthOffset)); |
8273 __ test(ebx, Operand(ebx)); | 8273 __ test(ebx, Operand(ebx)); |
8274 __ j(not_zero, &both_not_zero_length); | 8274 __ j(not_zero, &both_not_zero_length); |
8275 // First string is empty, result is second string which is in edx. | 8275 // First string is empty, result is second string which is in edx. |
8276 __ mov(eax, edx); | 8276 __ mov(eax, edx); |
8277 __ IncrementCounter(&Counters::string_add_native, 1); | 8277 __ IncrementCounter(&COUNTER(string_add_native), 1); |
8278 __ ret(2 * kPointerSize); | 8278 __ ret(2 * kPointerSize); |
8279 | 8279 |
8280 // Both strings are non-empty. | 8280 // Both strings are non-empty. |
8281 // eax: first string | 8281 // eax: first string |
8282 // ebx: length of first string | 8282 // ebx: length of first string |
8283 // ecx: length of second string | 8283 // ecx: length of second string |
8284 // edx: second string | 8284 // edx: second string |
8285 // Look at the length of the result of adding the two strings. | 8285 // Look at the length of the result of adding the two strings. |
8286 Label string_add_flat_result; | 8286 Label string_add_flat_result; |
8287 __ bind(&both_not_zero_length); | 8287 __ bind(&both_not_zero_length); |
(...skipping 23 matching lines...) Expand all Loading... |
8311 // Allocate an acsii cons string. | 8311 // Allocate an acsii cons string. |
8312 __ AllocateAsciiConsString(ecx, edi, no_reg, &string_add_runtime); | 8312 __ AllocateAsciiConsString(ecx, edi, no_reg, &string_add_runtime); |
8313 __ bind(&allocated); | 8313 __ bind(&allocated); |
8314 // Fill the fields of the cons string. | 8314 // Fill the fields of the cons string. |
8315 __ mov(FieldOperand(ecx, ConsString::kLengthOffset), ebx); | 8315 __ mov(FieldOperand(ecx, ConsString::kLengthOffset), ebx); |
8316 __ mov(FieldOperand(ecx, ConsString::kHashFieldOffset), | 8316 __ mov(FieldOperand(ecx, ConsString::kHashFieldOffset), |
8317 Immediate(String::kEmptyHashField)); | 8317 Immediate(String::kEmptyHashField)); |
8318 __ mov(FieldOperand(ecx, ConsString::kFirstOffset), eax); | 8318 __ mov(FieldOperand(ecx, ConsString::kFirstOffset), eax); |
8319 __ mov(FieldOperand(ecx, ConsString::kSecondOffset), edx); | 8319 __ mov(FieldOperand(ecx, ConsString::kSecondOffset), edx); |
8320 __ mov(eax, ecx); | 8320 __ mov(eax, ecx); |
8321 __ IncrementCounter(&Counters::string_add_native, 1); | 8321 __ IncrementCounter(&COUNTER(string_add_native), 1); |
8322 __ ret(2 * kPointerSize); | 8322 __ ret(2 * kPointerSize); |
8323 __ bind(&non_ascii); | 8323 __ bind(&non_ascii); |
8324 // Allocate a two byte cons string. | 8324 // Allocate a two byte cons string. |
8325 __ AllocateConsString(ecx, edi, no_reg, &string_add_runtime); | 8325 __ AllocateConsString(ecx, edi, no_reg, &string_add_runtime); |
8326 __ jmp(&allocated); | 8326 __ jmp(&allocated); |
8327 | 8327 |
8328 // Handle creating a flat result. First check that both strings are not | 8328 // Handle creating a flat result. First check that both strings are not |
8329 // external strings. | 8329 // external strings. |
8330 // eax: first string | 8330 // eax: first string |
8331 // ebx: length of resulting flat string | 8331 // ebx: length of resulting flat string |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
8372 GenerateCopyCharacters(masm, ecx, edx, edi, ebx, true); | 8372 GenerateCopyCharacters(masm, ecx, edx, edi, ebx, true); |
8373 // Load second argument and locate first character. | 8373 // Load second argument and locate first character. |
8374 __ mov(edx, Operand(esp, 1 * kPointerSize)); | 8374 __ mov(edx, Operand(esp, 1 * kPointerSize)); |
8375 __ mov(edi, FieldOperand(edx, String::kLengthOffset)); | 8375 __ mov(edi, FieldOperand(edx, String::kLengthOffset)); |
8376 __ add(Operand(edx), Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); | 8376 __ add(Operand(edx), Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); |
8377 // eax: result string | 8377 // eax: result string |
8378 // ecx: next character of result | 8378 // ecx: next character of result |
8379 // edx: first char of second argument | 8379 // edx: first char of second argument |
8380 // edi: length of second argument | 8380 // edi: length of second argument |
8381 GenerateCopyCharacters(masm, ecx, edx, edi, ebx, true); | 8381 GenerateCopyCharacters(masm, ecx, edx, edi, ebx, true); |
8382 __ IncrementCounter(&Counters::string_add_native, 1); | 8382 __ IncrementCounter(&COUNTER(string_add_native), 1); |
8383 __ ret(2 * kPointerSize); | 8383 __ ret(2 * kPointerSize); |
8384 | 8384 |
8385 // Handle creating a flat two byte result. | 8385 // Handle creating a flat two byte result. |
8386 // eax: first string - known to be two byte | 8386 // eax: first string - known to be two byte |
8387 // ebx: length of resulting flat string | 8387 // ebx: length of resulting flat string |
8388 // edx: second string | 8388 // edx: second string |
8389 __ bind(&non_ascii_string_add_flat_result); | 8389 __ bind(&non_ascii_string_add_flat_result); |
8390 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); | 8390 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); |
8391 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); | 8391 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); |
8392 __ and_(ecx, kAsciiStringTag); | 8392 __ and_(ecx, kAsciiStringTag); |
(...skipping 18 matching lines...) Expand all Loading... |
8411 GenerateCopyCharacters(masm, ecx, edx, edi, ebx, false); | 8411 GenerateCopyCharacters(masm, ecx, edx, edi, ebx, false); |
8412 // Load second argument and locate first character. | 8412 // Load second argument and locate first character. |
8413 __ mov(edx, Operand(esp, 1 * kPointerSize)); | 8413 __ mov(edx, Operand(esp, 1 * kPointerSize)); |
8414 __ mov(edi, FieldOperand(edx, String::kLengthOffset)); | 8414 __ mov(edi, FieldOperand(edx, String::kLengthOffset)); |
8415 __ add(Operand(edx), Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); | 8415 __ add(Operand(edx), Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); |
8416 // eax: result string | 8416 // eax: result string |
8417 // ecx: next character of result | 8417 // ecx: next character of result |
8418 // edx: first char of second argument | 8418 // edx: first char of second argument |
8419 // edi: length of second argument | 8419 // edi: length of second argument |
8420 GenerateCopyCharacters(masm, ecx, edx, edi, ebx, false); | 8420 GenerateCopyCharacters(masm, ecx, edx, edi, ebx, false); |
8421 __ IncrementCounter(&Counters::string_add_native, 1); | 8421 __ IncrementCounter(&COUNTER(string_add_native), 1); |
8422 __ ret(2 * kPointerSize); | 8422 __ ret(2 * kPointerSize); |
8423 | 8423 |
8424 // Just jump to runtime to add the two strings. | 8424 // Just jump to runtime to add the two strings. |
8425 __ bind(&string_add_runtime); | 8425 __ bind(&string_add_runtime); |
8426 __ TailCallRuntime(ExternalReference(Runtime::kStringAdd), 2, 1); | 8426 __ TailCallRuntime(ExternalReference(Runtime::kStringAdd), 2, 1); |
8427 } | 8427 } |
8428 | 8428 |
8429 | 8429 |
8430 void StringAddStub::GenerateCopyCharacters(MacroAssembler* masm, | 8430 void StringAddStub::GenerateCopyCharacters(MacroAssembler* masm, |
8431 Register dest, | 8431 Register dest, |
(...skipping 17 matching lines...) Expand all Loading... |
8449 __ add(Operand(dest), Immediate(2)); | 8449 __ add(Operand(dest), Immediate(2)); |
8450 } | 8450 } |
8451 __ sub(Operand(count), Immediate(1)); | 8451 __ sub(Operand(count), Immediate(1)); |
8452 __ j(not_zero, &loop); | 8452 __ j(not_zero, &loop); |
8453 } | 8453 } |
8454 | 8454 |
8455 | 8455 |
8456 #undef __ | 8456 #undef __ |
8457 | 8457 |
8458 } } // namespace v8::internal | 8458 } } // namespace v8::internal |
OLD | NEW |