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 |
11 // with the distribution. | 11 // with the distribution. |
12 // * Neither the name of Google Inc. nor the names of its | 12 // * Neither the name of Google Inc. nor the names of its |
13 // contributors may be used to endorse or promote products derived | 13 // contributors may be used to endorse or promote products derived |
14 // from this software without specific prior written permission. | 14 // from this software without specific prior written permission. |
15 // | 15 // |
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
27 | 27 |
28 #include "v8.h" | 28 #include "v8.h" |
29 | 29 |
| 30 #if defined(V8_TARGET_ARCH_ARM) |
| 31 |
30 #include "bootstrapper.h" | 32 #include "bootstrapper.h" |
31 #include "codegen-inl.h" | 33 #include "codegen-inl.h" |
32 #include "compiler.h" | 34 #include "compiler.h" |
33 #include "debug.h" | 35 #include "debug.h" |
34 #include "ic-inl.h" | 36 #include "ic-inl.h" |
35 #include "jsregexp.h" | 37 #include "jsregexp.h" |
36 #include "jump-target-light-inl.h" | 38 #include "jump-target-light-inl.h" |
37 #include "parser.h" | 39 #include "parser.h" |
38 #include "regexp-macro-assembler.h" | 40 #include "regexp-macro-assembler.h" |
39 #include "regexp-stack.h" | 41 #include "regexp-stack.h" |
(...skipping 1321 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1361 // and y the receiver. | 1363 // and y the receiver. |
1362 VirtualFrame::SpilledScope spilled_scope(frame_); | 1364 VirtualFrame::SpilledScope spilled_scope(frame_); |
1363 | 1365 |
1364 ASSERT(ArgumentsMode() == LAZY_ARGUMENTS_ALLOCATION); | 1366 ASSERT(ArgumentsMode() == LAZY_ARGUMENTS_ALLOCATION); |
1365 ASSERT(arguments->IsArguments()); | 1367 ASSERT(arguments->IsArguments()); |
1366 | 1368 |
1367 // Load applicand.apply onto the stack. This will usually | 1369 // Load applicand.apply onto the stack. This will usually |
1368 // give us a megamorphic load site. Not super, but it works. | 1370 // give us a megamorphic load site. Not super, but it works. |
1369 LoadAndSpill(applicand); | 1371 LoadAndSpill(applicand); |
1370 Handle<String> name = Factory::LookupAsciiSymbol("apply"); | 1372 Handle<String> name = Factory::LookupAsciiSymbol("apply"); |
| 1373 frame_->Dup(); |
1371 frame_->CallLoadIC(name, RelocInfo::CODE_TARGET); | 1374 frame_->CallLoadIC(name, RelocInfo::CODE_TARGET); |
1372 frame_->EmitPush(r0); | 1375 frame_->EmitPush(r0); |
1373 | 1376 |
1374 // Load the receiver and the existing arguments object onto the | 1377 // Load the receiver and the existing arguments object onto the |
1375 // expression stack. Avoid allocating the arguments object here. | 1378 // expression stack. Avoid allocating the arguments object here. |
1376 LoadAndSpill(receiver); | 1379 LoadAndSpill(receiver); |
1377 LoadFromSlot(scope()->arguments()->var()->slot(), NOT_INSIDE_TYPEOF); | 1380 LoadFromSlot(scope()->arguments()->var()->slot(), NOT_INSIDE_TYPEOF); |
1378 | 1381 |
1379 // Emit the source position information after having loaded the | 1382 // Emit the source position information after having loaded the |
1380 // receiver and the arguments. | 1383 // receiver and the arguments. |
(...skipping 1619 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3000 __ bind(&fast); | 3003 __ bind(&fast); |
3001 } | 3004 } |
3002 | 3005 |
3003 // Load the global object. | 3006 // Load the global object. |
3004 LoadGlobal(); | 3007 LoadGlobal(); |
3005 // Setup the name register and call load IC. | 3008 // Setup the name register and call load IC. |
3006 frame_->CallLoadIC(slot->var()->name(), | 3009 frame_->CallLoadIC(slot->var()->name(), |
3007 typeof_state == INSIDE_TYPEOF | 3010 typeof_state == INSIDE_TYPEOF |
3008 ? RelocInfo::CODE_TARGET | 3011 ? RelocInfo::CODE_TARGET |
3009 : RelocInfo::CODE_TARGET_CONTEXT); | 3012 : RelocInfo::CODE_TARGET_CONTEXT); |
3010 // Drop the global object. The result is in r0. | |
3011 frame_->Drop(); | |
3012 } | 3013 } |
3013 | 3014 |
3014 | 3015 |
3015 void CodeGenerator::EmitDynamicLoadFromSlotFastCase(Slot* slot, | 3016 void CodeGenerator::EmitDynamicLoadFromSlotFastCase(Slot* slot, |
3016 TypeofState typeof_state, | 3017 TypeofState typeof_state, |
3017 JumpTarget* slow, | 3018 JumpTarget* slow, |
3018 JumpTarget* done) { | 3019 JumpTarget* done) { |
3019 // Generate fast-case code for variables that might be shadowed by | 3020 // Generate fast-case code for variables that might be shadowed by |
3020 // eval-introduced variables. Eval is used a lot without | 3021 // eval-introduced variables. Eval is used a lot without |
3021 // introducing variables. In those cases, we do not want to | 3022 // introducing variables. In those cases, we do not want to |
(...skipping 393 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3415 // For a compound assignment the right-hand side is a binary operation | 3416 // For a compound assignment the right-hand side is a binary operation |
3416 // between the current property value and the actual right-hand side. | 3417 // between the current property value and the actual right-hand side. |
3417 if (is_trivial_receiver) { | 3418 if (is_trivial_receiver) { |
3418 Load(prop->obj()); | 3419 Load(prop->obj()); |
3419 } else if (var != NULL) { | 3420 } else if (var != NULL) { |
3420 LoadGlobal(); | 3421 LoadGlobal(); |
3421 } else { | 3422 } else { |
3422 frame_->Dup(); | 3423 frame_->Dup(); |
3423 } | 3424 } |
3424 EmitNamedLoad(name, var != NULL); | 3425 EmitNamedLoad(name, var != NULL); |
3425 frame_->Drop(); // Receiver is left on the stack. | |
3426 frame_->EmitPush(r0); | 3426 frame_->EmitPush(r0); |
3427 | 3427 |
3428 // Perform the binary operation. | 3428 // Perform the binary operation. |
3429 Literal* literal = node->value()->AsLiteral(); | 3429 Literal* literal = node->value()->AsLiteral(); |
3430 bool overwrite_value = | 3430 bool overwrite_value = |
3431 (node->value()->AsBinaryOperation() != NULL && | 3431 (node->value()->AsBinaryOperation() != NULL && |
3432 node->value()->AsBinaryOperation()->ResultOverwriteAllowed()); | 3432 node->value()->AsBinaryOperation()->ResultOverwriteAllowed()); |
3433 if (literal != NULL && literal->handle()->IsSmi()) { | 3433 if (literal != NULL && literal->handle()->IsSmi()) { |
3434 SmiOperation(node->binary_op(), | 3434 SmiOperation(node->binary_op(), |
3435 literal->handle(), | 3435 literal->handle(), |
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3554 | 3554 |
3555 // Stack layout: | 3555 // Stack layout: |
3556 // [tos] : value | 3556 // [tos] : value |
3557 // [tos+1] : key | 3557 // [tos+1] : key |
3558 // [tos+2] : receiver | 3558 // [tos+2] : receiver |
3559 // [tos+3] : receiver if at the end of an initialization block | 3559 // [tos+3] : receiver if at the end of an initialization block |
3560 | 3560 |
3561 // Perform the assignment. It is safe to ignore constants here. | 3561 // Perform the assignment. It is safe to ignore constants here. |
3562 ASSERT(node->op() != Token::INIT_CONST); | 3562 ASSERT(node->op() != Token::INIT_CONST); |
3563 CodeForSourcePosition(node->position()); | 3563 CodeForSourcePosition(node->position()); |
3564 frame_->PopToR0(); | |
3565 EmitKeyedStore(prop->key()->type()); | 3564 EmitKeyedStore(prop->key()->type()); |
3566 frame_->Drop(2); // Key and receiver are left on the stack. | |
3567 frame_->EmitPush(r0); | 3565 frame_->EmitPush(r0); |
3568 | 3566 |
3569 // Stack layout: | 3567 // Stack layout: |
3570 // [tos] : result | 3568 // [tos] : result |
3571 // [tos+1] : receiver if at the end of an initialization block | 3569 // [tos+1] : receiver if at the end of an initialization block |
3572 | 3570 |
3573 // Change to fast case at the end of an initialization block. | 3571 // Change to fast case at the end of an initialization block. |
3574 if (node->ends_initialization_block()) { | 3572 if (node->ends_initialization_block()) { |
3575 // The argument to the runtime call is the extra copy of the receiver, | 3573 // The argument to the runtime call is the extra copy of the receiver, |
3576 // which is below the value of the assignment. Swap the receiver and | 3574 // which is below the value of the assignment. Swap the receiver and |
(...skipping 1846 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5423 default: | 5421 default: |
5424 UNREACHABLE(); | 5422 UNREACHABLE(); |
5425 } | 5423 } |
5426 ASSERT((has_cc() && frame_->height() == original_height) || | 5424 ASSERT((has_cc() && frame_->height() == original_height) || |
5427 (!has_cc() && frame_->height() == original_height + 1)); | 5425 (!has_cc() && frame_->height() == original_height + 1)); |
5428 } | 5426 } |
5429 | 5427 |
5430 | 5428 |
5431 class DeferredReferenceGetNamedValue: public DeferredCode { | 5429 class DeferredReferenceGetNamedValue: public DeferredCode { |
5432 public: | 5430 public: |
5433 explicit DeferredReferenceGetNamedValue(Handle<String> name) : name_(name) { | 5431 explicit DeferredReferenceGetNamedValue(Register receiver, |
| 5432 Handle<String> name) |
| 5433 : receiver_(receiver), name_(name) { |
5434 set_comment("[ DeferredReferenceGetNamedValue"); | 5434 set_comment("[ DeferredReferenceGetNamedValue"); |
5435 } | 5435 } |
5436 | 5436 |
5437 virtual void Generate(); | 5437 virtual void Generate(); |
5438 | 5438 |
5439 private: | 5439 private: |
| 5440 Register receiver_; |
5440 Handle<String> name_; | 5441 Handle<String> name_; |
5441 }; | 5442 }; |
5442 | 5443 |
5443 | 5444 |
5444 void DeferredReferenceGetNamedValue::Generate() { | 5445 void DeferredReferenceGetNamedValue::Generate() { |
| 5446 ASSERT(receiver_.is(r0) || receiver_.is(r1)); |
| 5447 |
5445 Register scratch1 = VirtualFrame::scratch0(); | 5448 Register scratch1 = VirtualFrame::scratch0(); |
5446 Register scratch2 = VirtualFrame::scratch1(); | 5449 Register scratch2 = VirtualFrame::scratch1(); |
5447 __ DecrementCounter(&Counters::named_load_inline, 1, scratch1, scratch2); | 5450 __ DecrementCounter(&Counters::named_load_inline, 1, scratch1, scratch2); |
5448 __ IncrementCounter(&Counters::named_load_inline_miss, 1, scratch1, scratch2); | 5451 __ IncrementCounter(&Counters::named_load_inline_miss, 1, scratch1, scratch2); |
5449 | 5452 |
5450 // Setup the registers and call load IC. | 5453 // Ensure receiver in r0 and name in r2 to match load ic calling convention. |
5451 // On entry to this deferred code, r0 is assumed to already contain the | 5454 __ Move(r0, receiver_); |
5452 // receiver from the top of the stack. | |
5453 __ mov(r2, Operand(name_)); | 5455 __ mov(r2, Operand(name_)); |
5454 | 5456 |
5455 // The rest of the instructions in the deferred code must be together. | 5457 // The rest of the instructions in the deferred code must be together. |
5456 { Assembler::BlockConstPoolScope block_const_pool(masm_); | 5458 { Assembler::BlockConstPoolScope block_const_pool(masm_); |
5457 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); | 5459 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); |
5458 __ Call(ic, RelocInfo::CODE_TARGET); | 5460 __ Call(ic, RelocInfo::CODE_TARGET); |
5459 // The call must be followed by a nop(1) instruction to indicate that the | 5461 // The call must be followed by a nop(1) instruction to indicate that the |
5460 // in-object has been inlined. | 5462 // in-object has been inlined. |
5461 __ nop(PROPERTY_ACCESS_INLINED); | 5463 __ nop(PROPERTY_ACCESS_INLINED); |
5462 | 5464 |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5510 // Block the constant pool for one more instruction after leaving this | 5512 // Block the constant pool for one more instruction after leaving this |
5511 // constant pool block scope to include the branch instruction ending the | 5513 // constant pool block scope to include the branch instruction ending the |
5512 // deferred code. | 5514 // deferred code. |
5513 __ BlockConstPoolFor(1); | 5515 __ BlockConstPoolFor(1); |
5514 } | 5516 } |
5515 } | 5517 } |
5516 | 5518 |
5517 | 5519 |
5518 class DeferredReferenceSetKeyedValue: public DeferredCode { | 5520 class DeferredReferenceSetKeyedValue: public DeferredCode { |
5519 public: | 5521 public: |
5520 DeferredReferenceSetKeyedValue() { | 5522 DeferredReferenceSetKeyedValue(Register value, |
| 5523 Register key, |
| 5524 Register receiver) |
| 5525 : value_(value), key_(key), receiver_(receiver) { |
5521 set_comment("[ DeferredReferenceSetKeyedValue"); | 5526 set_comment("[ DeferredReferenceSetKeyedValue"); |
5522 } | 5527 } |
5523 | 5528 |
5524 virtual void Generate(); | 5529 virtual void Generate(); |
| 5530 |
| 5531 private: |
| 5532 Register value_; |
| 5533 Register key_; |
| 5534 Register receiver_; |
5525 }; | 5535 }; |
5526 | 5536 |
5527 | 5537 |
5528 void DeferredReferenceSetKeyedValue::Generate() { | 5538 void DeferredReferenceSetKeyedValue::Generate() { |
5529 Register scratch1 = VirtualFrame::scratch0(); | 5539 Register scratch1 = VirtualFrame::scratch0(); |
5530 Register scratch2 = VirtualFrame::scratch1(); | 5540 Register scratch2 = VirtualFrame::scratch1(); |
5531 __ DecrementCounter(&Counters::keyed_store_inline, 1, scratch1, scratch2); | 5541 __ DecrementCounter(&Counters::keyed_store_inline, 1, scratch1, scratch2); |
5532 __ IncrementCounter( | 5542 __ IncrementCounter( |
5533 &Counters::keyed_store_inline_miss, 1, scratch1, scratch2); | 5543 &Counters::keyed_store_inline_miss, 1, scratch1, scratch2); |
5534 | 5544 |
| 5545 // Ensure value in r0, key in r1 and receiver in r2 to match keyed store ic |
| 5546 // calling convention. |
| 5547 if (value_.is(r1)) { |
| 5548 __ Swap(r0, r1, ip); |
| 5549 } |
| 5550 ASSERT(receiver_.is(r2)); |
| 5551 |
5535 // The rest of the instructions in the deferred code must be together. | 5552 // The rest of the instructions in the deferred code must be together. |
5536 { Assembler::BlockConstPoolScope block_const_pool(masm_); | 5553 { Assembler::BlockConstPoolScope block_const_pool(masm_); |
5537 // Call keyed load IC. It has receiver amd key on the stack and the value to | 5554 // Call keyed store IC. It has the arguments value, key and receiver in r0, |
5538 // store in r0. | 5555 // r1 and r2. |
5539 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); | 5556 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); |
5540 __ Call(ic, RelocInfo::CODE_TARGET); | 5557 __ Call(ic, RelocInfo::CODE_TARGET); |
5541 // The call must be followed by a nop instruction to indicate that the | 5558 // The call must be followed by a nop instruction to indicate that the |
5542 // keyed store has been inlined. | 5559 // keyed store has been inlined. |
5543 __ nop(PROPERTY_ACCESS_INLINED); | 5560 __ nop(PROPERTY_ACCESS_INLINED); |
5544 | 5561 |
5545 // Block the constant pool for one more instruction after leaving this | 5562 // Block the constant pool for one more instruction after leaving this |
5546 // constant pool block scope to include the branch instruction ending the | 5563 // constant pool block scope to include the branch instruction ending the |
5547 // deferred code. | 5564 // deferred code. |
5548 __ BlockConstPoolFor(1); | 5565 __ BlockConstPoolFor(1); |
(...skipping 17 matching lines...) Expand all Loading... |
5566 // having it in the instruction stream below where patching will occur. | 5583 // having it in the instruction stream below where patching will occur. |
5567 __ IncrementCounter(&Counters::named_load_inline, 1, | 5584 __ IncrementCounter(&Counters::named_load_inline, 1, |
5568 frame_->scratch0(), frame_->scratch1()); | 5585 frame_->scratch0(), frame_->scratch1()); |
5569 | 5586 |
5570 // The following instructions are the inlined load of an in-object property. | 5587 // The following instructions are the inlined load of an in-object property. |
5571 // Parts of this code is patched, so the exact instructions generated needs | 5588 // Parts of this code is patched, so the exact instructions generated needs |
5572 // to be fixed. Therefore the instruction pool is blocked when generating | 5589 // to be fixed. Therefore the instruction pool is blocked when generating |
5573 // this code | 5590 // this code |
5574 | 5591 |
5575 // Load the receiver from the stack. | 5592 // Load the receiver from the stack. |
5576 frame_->SpillAllButCopyTOSToR0(); | 5593 Register receiver = frame_->PopToRegister(); |
| 5594 VirtualFrame::SpilledScope spilled(frame_); |
5577 | 5595 |
5578 DeferredReferenceGetNamedValue* deferred = | 5596 DeferredReferenceGetNamedValue* deferred = |
5579 new DeferredReferenceGetNamedValue(name); | 5597 new DeferredReferenceGetNamedValue(receiver, name); |
5580 | 5598 |
5581 #ifdef DEBUG | 5599 #ifdef DEBUG |
5582 int kInlinedNamedLoadInstructions = 7; | 5600 int kInlinedNamedLoadInstructions = 7; |
5583 Label check_inlined_codesize; | 5601 Label check_inlined_codesize; |
5584 masm_->bind(&check_inlined_codesize); | 5602 masm_->bind(&check_inlined_codesize); |
5585 #endif | 5603 #endif |
5586 | 5604 |
5587 { Assembler::BlockConstPoolScope block_const_pool(masm_); | 5605 { Assembler::BlockConstPoolScope block_const_pool(masm_); |
5588 // Check that the receiver is a heap object. | 5606 // Check that the receiver is a heap object. |
5589 __ tst(r0, Operand(kSmiTagMask)); | 5607 __ tst(receiver, Operand(kSmiTagMask)); |
5590 deferred->Branch(eq); | 5608 deferred->Branch(eq); |
5591 | 5609 |
5592 // Check the map. The null map used below is patched by the inline cache | 5610 // Check the map. The null map used below is patched by the inline cache |
5593 // code. | 5611 // code. |
5594 __ ldr(r2, FieldMemOperand(r0, HeapObject::kMapOffset)); | 5612 __ ldr(r2, FieldMemOperand(receiver, HeapObject::kMapOffset)); |
5595 __ mov(r3, Operand(Factory::null_value())); | 5613 __ mov(r3, Operand(Factory::null_value())); |
5596 __ cmp(r2, r3); | 5614 __ cmp(r2, r3); |
5597 deferred->Branch(ne); | 5615 deferred->Branch(ne); |
5598 | 5616 |
5599 // Initially use an invalid index. The index will be patched by the | 5617 // Initially use an invalid index. The index will be patched by the |
5600 // inline cache code. | 5618 // inline cache code. |
5601 __ ldr(r0, MemOperand(r0, 0)); | 5619 __ ldr(r0, MemOperand(receiver, 0)); |
5602 | 5620 |
5603 // Make sure that the expected number of instructions are generated. | 5621 // Make sure that the expected number of instructions are generated. |
5604 ASSERT_EQ(kInlinedNamedLoadInstructions, | 5622 ASSERT_EQ(kInlinedNamedLoadInstructions, |
5605 masm_->InstructionsGeneratedSince(&check_inlined_codesize)); | 5623 masm_->InstructionsGeneratedSince(&check_inlined_codesize)); |
5606 } | 5624 } |
5607 | 5625 |
5608 deferred->BindExit(); | 5626 deferred->BindExit(); |
5609 } | 5627 } |
5610 } | 5628 } |
5611 | 5629 |
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5688 scratch1, | 5706 scratch1, |
5689 Operand(FixedArray::kHeaderSize - kHeapObjectTag)); | 5707 Operand(FixedArray::kHeaderSize - kHeapObjectTag)); |
5690 __ ldr(scratch1, | 5708 __ ldr(scratch1, |
5691 MemOperand(scratch1, key, LSL, | 5709 MemOperand(scratch1, key, LSL, |
5692 kPointerSizeLog2 - (kSmiTagSize + kSmiShiftSize))); | 5710 kPointerSizeLog2 - (kSmiTagSize + kSmiShiftSize))); |
5693 __ cmp(scratch1, scratch2); | 5711 __ cmp(scratch1, scratch2); |
5694 deferred->Branch(eq); | 5712 deferred->Branch(eq); |
5695 | 5713 |
5696 __ mov(r0, scratch1); | 5714 __ mov(r0, scratch1); |
5697 // Make sure that the expected number of instructions are generated. | 5715 // Make sure that the expected number of instructions are generated. |
5698 ASSERT_EQ(kInlinedKeyedLoadInstructionsAfterPatchSize, | 5716 ASSERT_EQ(kInlinedKeyedLoadInstructionsAfterPatch, |
5699 masm_->InstructionsGeneratedSince(&check_inlined_codesize)); | 5717 masm_->InstructionsGeneratedSince(&check_inlined_codesize)); |
5700 } | 5718 } |
5701 | 5719 |
5702 deferred->BindExit(); | 5720 deferred->BindExit(); |
5703 } | 5721 } |
5704 } | 5722 } |
5705 | 5723 |
5706 | 5724 |
5707 void CodeGenerator::EmitKeyedStore(StaticType* key_type) { | 5725 void CodeGenerator::EmitKeyedStore(StaticType* key_type) { |
5708 VirtualFrame::SpilledScope scope(frame_); | |
5709 // Generate inlined version of the keyed store if the code is in a loop | 5726 // Generate inlined version of the keyed store if the code is in a loop |
5710 // and the key is likely to be a smi. | 5727 // and the key is likely to be a smi. |
5711 if (loop_nesting() > 0 && key_type->IsLikelySmi()) { | 5728 if (loop_nesting() > 0 && key_type->IsLikelySmi()) { |
5712 // Inline the keyed store. | 5729 // Inline the keyed store. |
5713 Comment cmnt(masm_, "[ Inlined store to keyed property"); | 5730 Comment cmnt(masm_, "[ Inlined store to keyed property"); |
5714 | 5731 |
5715 DeferredReferenceSetKeyedValue* deferred = | 5732 Register scratch1 = VirtualFrame::scratch0(); |
5716 new DeferredReferenceSetKeyedValue(); | 5733 Register scratch2 = VirtualFrame::scratch1(); |
| 5734 Register scratch3 = r3; |
5717 | 5735 |
5718 // Counter will be decremented in the deferred code. Placed here to avoid | 5736 // Counter will be decremented in the deferred code. Placed here to avoid |
5719 // having it in the instruction stream below where patching will occur. | 5737 // having it in the instruction stream below where patching will occur. |
5720 __ IncrementCounter(&Counters::keyed_store_inline, 1, | 5738 __ IncrementCounter(&Counters::keyed_store_inline, 1, |
5721 frame_->scratch0(), frame_->scratch1()); | 5739 scratch1, scratch2); |
| 5740 |
| 5741 // Load the value, key and receiver from the stack. |
| 5742 Register value = frame_->PopToRegister(); |
| 5743 Register key = frame_->PopToRegister(value); |
| 5744 Register receiver = r2; |
| 5745 frame_->EmitPop(receiver); |
| 5746 VirtualFrame::SpilledScope spilled(frame_); |
| 5747 |
| 5748 // The deferred code expects value, key and receiver in registers. |
| 5749 DeferredReferenceSetKeyedValue* deferred = |
| 5750 new DeferredReferenceSetKeyedValue(value, key, receiver); |
5722 | 5751 |
5723 // Check that the value is a smi. As this inlined code does not set the | 5752 // Check that the value is a smi. As this inlined code does not set the |
5724 // write barrier it is only possible to store smi values. | 5753 // write barrier it is only possible to store smi values. |
5725 __ tst(r0, Operand(kSmiTagMask)); | 5754 __ tst(value, Operand(kSmiTagMask)); |
5726 deferred->Branch(ne); | 5755 deferred->Branch(ne); |
5727 | 5756 |
5728 // Load the key and receiver from the stack. | |
5729 __ ldr(r1, MemOperand(sp, 0)); | |
5730 __ ldr(r2, MemOperand(sp, kPointerSize)); | |
5731 | |
5732 // Check that the key is a smi. | 5757 // Check that the key is a smi. |
5733 __ tst(r1, Operand(kSmiTagMask)); | 5758 __ tst(key, Operand(kSmiTagMask)); |
5734 deferred->Branch(ne); | 5759 deferred->Branch(ne); |
5735 | 5760 |
5736 // Check that the receiver is a heap object. | 5761 // Check that the receiver is a heap object. |
5737 __ tst(r2, Operand(kSmiTagMask)); | 5762 __ tst(receiver, Operand(kSmiTagMask)); |
5738 deferred->Branch(eq); | 5763 deferred->Branch(eq); |
5739 | 5764 |
5740 // Check that the receiver is a JSArray. | 5765 // Check that the receiver is a JSArray. |
5741 __ CompareObjectType(r2, r3, r3, JS_ARRAY_TYPE); | 5766 __ CompareObjectType(receiver, scratch1, scratch1, JS_ARRAY_TYPE); |
5742 deferred->Branch(ne); | 5767 deferred->Branch(ne); |
5743 | 5768 |
5744 // Check that the key is within bounds. Both the key and the length of | 5769 // Check that the key is within bounds. Both the key and the length of |
5745 // the JSArray are smis. Use unsigned comparison to handle negative keys. | 5770 // the JSArray are smis. Use unsigned comparison to handle negative keys. |
5746 __ ldr(r3, FieldMemOperand(r2, JSArray::kLengthOffset)); | 5771 __ ldr(scratch1, FieldMemOperand(receiver, JSArray::kLengthOffset)); |
5747 __ cmp(r3, r1); | 5772 __ cmp(scratch1, key); |
5748 deferred->Branch(ls); // Unsigned less equal. | 5773 deferred->Branch(ls); // Unsigned less equal. |
5749 | 5774 |
5750 // The following instructions are the part of the inlined store keyed | 5775 // The following instructions are the part of the inlined store keyed |
5751 // property code which can be patched. Therefore the exact number of | 5776 // property code which can be patched. Therefore the exact number of |
5752 // instructions generated need to be fixed, so the constant pool is blocked | 5777 // instructions generated need to be fixed, so the constant pool is blocked |
5753 // while generating this code. | 5778 // while generating this code. |
5754 #ifdef DEBUG | |
5755 int kInlinedKeyedStoreInstructions = 7; | |
5756 Label check_inlined_codesize; | |
5757 masm_->bind(&check_inlined_codesize); | |
5758 #endif | |
5759 { Assembler::BlockConstPoolScope block_const_pool(masm_); | 5779 { Assembler::BlockConstPoolScope block_const_pool(masm_); |
5760 // Get the elements array from the receiver and check that it | 5780 // Get the elements array from the receiver and check that it |
5761 // is not a dictionary. | 5781 // is not a dictionary. |
5762 __ ldr(r3, FieldMemOperand(r2, JSObject::kElementsOffset)); | 5782 __ ldr(scratch1, FieldMemOperand(receiver, JSObject::kElementsOffset)); |
5763 __ ldr(r4, FieldMemOperand(r3, JSObject::kMapOffset)); | 5783 __ ldr(scratch2, FieldMemOperand(scratch1, JSObject::kMapOffset)); |
5764 // Read the fixed array map from the constant pool (not from the root | 5784 // Read the fixed array map from the constant pool (not from the root |
5765 // array) so that the value can be patched. When debugging, we patch this | 5785 // array) so that the value can be patched. When debugging, we patch this |
5766 // comparison to always fail so that we will hit the IC call in the | 5786 // comparison to always fail so that we will hit the IC call in the |
5767 // deferred code which will allow the debugger to break for fast case | 5787 // deferred code which will allow the debugger to break for fast case |
5768 // stores. | 5788 // stores. |
5769 __ mov(r5, Operand(Factory::fixed_array_map())); | 5789 #ifdef DEBUG |
5770 __ cmp(r4, r5); | 5790 Label check_inlined_codesize; |
| 5791 masm_->bind(&check_inlined_codesize); |
| 5792 #endif |
| 5793 __ mov(scratch3, Operand(Factory::fixed_array_map())); |
| 5794 __ cmp(scratch2, scratch3); |
5771 deferred->Branch(ne); | 5795 deferred->Branch(ne); |
5772 | 5796 |
5773 // Store the value. | 5797 // Store the value. |
5774 __ add(r3, r3, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); | 5798 __ add(scratch1, scratch1, |
5775 __ str(r0, MemOperand(r3, r1, LSL, | 5799 Operand(FixedArray::kHeaderSize - kHeapObjectTag)); |
5776 kPointerSizeLog2 - (kSmiTagSize + kSmiShiftSize))); | 5800 __ str(value, |
| 5801 MemOperand(scratch1, key, LSL, |
| 5802 kPointerSizeLog2 - (kSmiTagSize + kSmiShiftSize))); |
5777 | 5803 |
5778 // Make sure that the expected number of instructions are generated. | 5804 // Make sure that the expected number of instructions are generated. |
5779 ASSERT_EQ(kInlinedKeyedStoreInstructions, | 5805 ASSERT_EQ(kInlinedKeyedStoreInstructionsAfterPatch, |
5780 masm_->InstructionsGeneratedSince(&check_inlined_codesize)); | 5806 masm_->InstructionsGeneratedSince(&check_inlined_codesize)); |
5781 } | 5807 } |
5782 | 5808 |
5783 deferred->BindExit(); | 5809 deferred->BindExit(); |
5784 } else { | 5810 } else { |
5785 frame()->CallKeyedStoreIC(); | 5811 frame()->CallKeyedStoreIC(); |
5786 } | 5812 } |
5787 } | 5813 } |
5788 | 5814 |
5789 | 5815 |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5832 if (!persist_after_get_) { | 5858 if (!persist_after_get_) { |
5833 cgen_->UnloadReference(this); | 5859 cgen_->UnloadReference(this); |
5834 } | 5860 } |
5835 break; | 5861 break; |
5836 } | 5862 } |
5837 | 5863 |
5838 case NAMED: { | 5864 case NAMED: { |
5839 Variable* var = expression_->AsVariableProxy()->AsVariable(); | 5865 Variable* var = expression_->AsVariableProxy()->AsVariable(); |
5840 bool is_global = var != NULL; | 5866 bool is_global = var != NULL; |
5841 ASSERT(!is_global || var->is_global()); | 5867 ASSERT(!is_global || var->is_global()); |
| 5868 if (persist_after_get_) { |
| 5869 cgen_->frame()->Dup(); |
| 5870 } |
5842 cgen_->EmitNamedLoad(GetName(), is_global); | 5871 cgen_->EmitNamedLoad(GetName(), is_global); |
5843 cgen_->frame()->EmitPush(r0); | 5872 cgen_->frame()->EmitPush(r0); |
5844 if (!persist_after_get_) { | 5873 if (!persist_after_get_) set_unloaded(); |
5845 cgen_->UnloadReference(this); | |
5846 } | |
5847 break; | 5874 break; |
5848 } | 5875 } |
5849 | 5876 |
5850 case KEYED: { | 5877 case KEYED: { |
| 5878 ASSERT(property != NULL); |
5851 if (persist_after_get_) { | 5879 if (persist_after_get_) { |
5852 cgen_->frame()->Dup2(); | 5880 cgen_->frame()->Dup2(); |
5853 } | 5881 } |
5854 ASSERT(property != NULL); | |
5855 cgen_->EmitKeyedLoad(); | 5882 cgen_->EmitKeyedLoad(); |
5856 cgen_->frame()->EmitPush(r0); | 5883 cgen_->frame()->EmitPush(r0); |
5857 if (!persist_after_get_) set_unloaded(); | 5884 if (!persist_after_get_) set_unloaded(); |
5858 break; | 5885 break; |
5859 } | 5886 } |
5860 | 5887 |
5861 default: | 5888 default: |
5862 UNREACHABLE(); | 5889 UNREACHABLE(); |
5863 } | 5890 } |
5864 } | 5891 } |
(...skipping 20 matching lines...) Expand all Loading... |
5885 | 5912 |
5886 case NAMED: { | 5913 case NAMED: { |
5887 Comment cmnt(masm, "[ Store to named Property"); | 5914 Comment cmnt(masm, "[ Store to named Property"); |
5888 cgen_->EmitNamedStore(GetName(), false); | 5915 cgen_->EmitNamedStore(GetName(), false); |
5889 frame->EmitPush(r0); | 5916 frame->EmitPush(r0); |
5890 set_unloaded(); | 5917 set_unloaded(); |
5891 break; | 5918 break; |
5892 } | 5919 } |
5893 | 5920 |
5894 case KEYED: { | 5921 case KEYED: { |
5895 VirtualFrame::SpilledScope scope(frame); | |
5896 Comment cmnt(masm, "[ Store to keyed Property"); | 5922 Comment cmnt(masm, "[ Store to keyed Property"); |
5897 Property* property = expression_->AsProperty(); | 5923 Property* property = expression_->AsProperty(); |
5898 ASSERT(property != NULL); | 5924 ASSERT(property != NULL); |
5899 cgen_->CodeForSourcePosition(property->position()); | 5925 cgen_->CodeForSourcePosition(property->position()); |
5900 | |
5901 frame->EmitPop(r0); // Value. | |
5902 cgen_->EmitKeyedStore(property->key()->type()); | 5926 cgen_->EmitKeyedStore(property->key()->type()); |
5903 frame->EmitPush(r0); | 5927 frame->EmitPush(r0); |
5904 cgen_->UnloadReference(this); | 5928 set_unloaded(); |
5905 break; | 5929 break; |
5906 } | 5930 } |
5907 | 5931 |
5908 default: | 5932 default: |
5909 UNREACHABLE(); | 5933 UNREACHABLE(); |
5910 } | 5934 } |
5911 } | 5935 } |
5912 | 5936 |
5913 | 5937 |
5914 void FastNewClosureStub::Generate(MacroAssembler* masm) { | 5938 void FastNewClosureStub::Generate(MacroAssembler* masm) { |
(...skipping 4098 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
10013 | 10037 |
10014 // Just jump to runtime to add the two strings. | 10038 // Just jump to runtime to add the two strings. |
10015 __ bind(&string_add_runtime); | 10039 __ bind(&string_add_runtime); |
10016 __ TailCallRuntime(Runtime::kStringAdd, 2, 1); | 10040 __ TailCallRuntime(Runtime::kStringAdd, 2, 1); |
10017 } | 10041 } |
10018 | 10042 |
10019 | 10043 |
10020 #undef __ | 10044 #undef __ |
10021 | 10045 |
10022 } } // namespace v8::internal | 10046 } } // namespace v8::internal |
| 10047 |
| 10048 #endif // V8_TARGET_ARCH_ARM |
OLD | NEW |