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