OLD | NEW |
1 // Copyright 2010 the V8 project authors. All rights reserved. | 1 // Copyright 2010 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 677 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
688 if (property->key()->IsPropertyName()) { | 688 if (property->key()->IsPropertyName()) { |
689 ref->set_type(Reference::NAMED); | 689 ref->set_type(Reference::NAMED); |
690 } else { | 690 } else { |
691 Load(property->key()); | 691 Load(property->key()); |
692 ref->set_type(Reference::KEYED); | 692 ref->set_type(Reference::KEYED); |
693 } | 693 } |
694 } else if (var != NULL) { | 694 } else if (var != NULL) { |
695 // The expression is a variable proxy that does not rewrite to a | 695 // The expression is a variable proxy that does not rewrite to a |
696 // property. Global variables are treated as named property references. | 696 // property. Global variables are treated as named property references. |
697 if (var->is_global()) { | 697 if (var->is_global()) { |
698 // Named loads require object in eax. Named stores don't use references. | 698 // If eax is free, the register allocator prefers it. Thus the code |
699 // Spilling eax makes it free, so LoadGlobal loads directly into eax. | 699 // generator will load the global object into eax, which is where |
| 700 // LoadIC wants it. Most uses of Reference call LoadIC directly |
| 701 // after the reference is created. |
700 frame_->Spill(eax); | 702 frame_->Spill(eax); |
701 LoadGlobal(); | 703 LoadGlobal(); |
702 ref->set_type(Reference::NAMED); | 704 ref->set_type(Reference::NAMED); |
703 } else { | 705 } else { |
704 ASSERT(var->slot() != NULL); | 706 ASSERT(var->slot() != NULL); |
705 ref->set_type(Reference::SLOT); | 707 ref->set_type(Reference::SLOT); |
706 } | 708 } |
707 } else { | 709 } else { |
708 // Anything else is a runtime error. | 710 // Anything else is a runtime error. |
709 Load(e); | 711 Load(e); |
(...skipping 3599 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4309 // Load next context in chain. | 4311 // Load next context in chain. |
4310 __ mov(tmp.reg(), ContextOperand(tmp.reg(), Context::CLOSURE_INDEX)); | 4312 __ mov(tmp.reg(), ContextOperand(tmp.reg(), Context::CLOSURE_INDEX)); |
4311 __ mov(tmp.reg(), FieldOperand(tmp.reg(), JSFunction::kContextOffset)); | 4313 __ mov(tmp.reg(), FieldOperand(tmp.reg(), JSFunction::kContextOffset)); |
4312 __ jmp(&next); | 4314 __ jmp(&next); |
4313 __ bind(&fast); | 4315 __ bind(&fast); |
4314 } | 4316 } |
4315 tmp.Unuse(); | 4317 tmp.Unuse(); |
4316 | 4318 |
4317 // All extension objects were empty and it is safe to use a global | 4319 // All extension objects were empty and it is safe to use a global |
4318 // load IC call. | 4320 // load IC call. |
| 4321 // The register allocator prefers eax if it is free, so the code generator |
| 4322 // will load the global object directly into eax, which is where the LoadIC |
| 4323 // expects it. |
| 4324 frame_->Spill(eax); |
4319 LoadGlobal(); | 4325 LoadGlobal(); |
4320 frame_->Push(slot->var()->name()); | 4326 frame_->Push(slot->var()->name()); |
4321 RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF) | 4327 RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF) |
4322 ? RelocInfo::CODE_TARGET | 4328 ? RelocInfo::CODE_TARGET |
4323 : RelocInfo::CODE_TARGET_CONTEXT; | 4329 : RelocInfo::CODE_TARGET_CONTEXT; |
4324 Result answer = frame_->CallLoadIC(mode); | 4330 Result answer = frame_->CallLoadIC(mode); |
4325 // A test eax instruction following the call signals that the inobject | 4331 // A test eax instruction following the call signals that the inobject |
4326 // property case was inlined. Ensure that there is not a test eax | 4332 // property case was inlined. Ensure that there is not a test eax |
4327 // instruction here. | 4333 // instruction here. |
4328 __ nop(); | 4334 __ nop(); |
(...skipping 265 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4594 break; | 4600 break; |
4595 case ObjectLiteral::Property::MATERIALIZED_LITERAL: | 4601 case ObjectLiteral::Property::MATERIALIZED_LITERAL: |
4596 if (CompileTimeValue::IsCompileTimeValue(property->value())) break; | 4602 if (CompileTimeValue::IsCompileTimeValue(property->value())) break; |
4597 // else fall through. | 4603 // else fall through. |
4598 case ObjectLiteral::Property::COMPUTED: { | 4604 case ObjectLiteral::Property::COMPUTED: { |
4599 Handle<Object> key(property->key()->handle()); | 4605 Handle<Object> key(property->key()->handle()); |
4600 if (key->IsSymbol()) { | 4606 if (key->IsSymbol()) { |
4601 // Duplicate the object as the IC receiver. | 4607 // Duplicate the object as the IC receiver. |
4602 frame_->Dup(); | 4608 frame_->Dup(); |
4603 Load(property->value()); | 4609 Load(property->value()); |
4604 frame_->Push(key); | 4610 Result dummy = frame_->CallStoreIC(Handle<String>::cast(key), false); |
4605 Result ignored = frame_->CallStoreIC(); | 4611 dummy.Unuse(); |
4606 break; | 4612 break; |
4607 } | 4613 } |
4608 // Fall through | 4614 // Fall through |
4609 } | 4615 } |
4610 case ObjectLiteral::Property::PROTOTYPE: { | 4616 case ObjectLiteral::Property::PROTOTYPE: { |
4611 // Duplicate the object as an argument to the runtime call. | 4617 // Duplicate the object as an argument to the runtime call. |
4612 frame_->Dup(); | 4618 frame_->Dup(); |
4613 Load(property->key()); | 4619 Load(property->key()); |
4614 Load(property->value()); | 4620 Load(property->value()); |
4615 Result ignored = frame_->CallRuntime(Runtime::kSetProperty, 3); | 4621 Result ignored = frame_->CallRuntime(Runtime::kSetProperty, 3); |
(...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4769 Comment cmnt(masm(), "[ Named Property Assignment"); | 4775 Comment cmnt(masm(), "[ Named Property Assignment"); |
4770 Variable* var = node->target()->AsVariableProxy()->AsVariable(); | 4776 Variable* var = node->target()->AsVariableProxy()->AsVariable(); |
4771 Property* prop = node->target()->AsProperty(); | 4777 Property* prop = node->target()->AsProperty(); |
4772 ASSERT(var == NULL || (prop == NULL && var->is_global())); | 4778 ASSERT(var == NULL || (prop == NULL && var->is_global())); |
4773 | 4779 |
4774 // Initialize name and evaluate the receiver subexpression if necessary. | 4780 // Initialize name and evaluate the receiver subexpression if necessary. |
4775 Handle<String> name; | 4781 Handle<String> name; |
4776 bool is_trivial_receiver = false; | 4782 bool is_trivial_receiver = false; |
4777 if (var != NULL) { | 4783 if (var != NULL) { |
4778 name = var->name(); | 4784 name = var->name(); |
4779 LoadGlobal(); | |
4780 } else { | 4785 } else { |
4781 Literal* lit = prop->key()->AsLiteral(); | 4786 Literal* lit = prop->key()->AsLiteral(); |
4782 ASSERT(lit != NULL); | 4787 ASSERT_NOT_NULL(lit); |
4783 name = Handle<String>::cast(lit->handle()); | 4788 name = Handle<String>::cast(lit->handle()); |
4784 // Do not materialize the receiver on the frame if it is trivial. | 4789 // Do not materialize the receiver on the frame if it is trivial. |
4785 is_trivial_receiver = prop->obj()->IsTrivial(); | 4790 is_trivial_receiver = prop->obj()->IsTrivial(); |
4786 if (!is_trivial_receiver) Load(prop->obj()); | 4791 if (!is_trivial_receiver) Load(prop->obj()); |
4787 } | 4792 } |
4788 | 4793 |
4789 if (node->starts_initialization_block()) { | 4794 if (node->starts_initialization_block()) { |
| 4795 ASSERT_EQ(NULL, var); |
4790 // Change to slow case in the beginning of an initialization block to | 4796 // Change to slow case in the beginning of an initialization block to |
4791 // avoid the quadratic behavior of repeatedly adding fast properties. | 4797 // avoid the quadratic behavior of repeatedly adding fast properties. |
4792 if (is_trivial_receiver) { | 4798 if (is_trivial_receiver) { |
4793 frame()->Push(prop->obj()); | 4799 frame()->Push(prop->obj()); |
4794 } else { | 4800 } else { |
4795 frame()->Dup(); | 4801 frame()->Dup(); |
4796 } | 4802 } |
4797 Result ignored = frame()->CallRuntime(Runtime::kToSlowProperties, 1); | 4803 Result ignored = frame()->CallRuntime(Runtime::kToSlowProperties, 1); |
4798 } | 4804 } |
4799 | 4805 |
4800 if (node->ends_initialization_block() && !is_trivial_receiver) { | 4806 if (node->ends_initialization_block() && !is_trivial_receiver) { |
4801 // Add an extra copy of the receiver to the frame, so that it can be | 4807 // Add an extra copy of the receiver to the frame, so that it can be |
4802 // converted back to fast case after the assignment. | 4808 // converted back to fast case after the assignment. |
4803 frame()->Dup(); | 4809 frame()->Dup(); |
4804 } | 4810 } |
4805 | 4811 |
4806 // Evaluate the right-hand side. | 4812 // Evaluate the right-hand side. |
4807 if (node->is_compound()) { | 4813 if (node->is_compound()) { |
4808 if (is_trivial_receiver) { | 4814 if (is_trivial_receiver) { |
4809 frame()->Push(prop->obj()); | 4815 frame()->Push(prop->obj()); |
| 4816 } else if (var != NULL) { |
| 4817 // The LoadIC stub expects the object in eax. |
| 4818 // Freeing eax causes the code generator to load the global into it. |
| 4819 frame_->Spill(eax); |
| 4820 LoadGlobal(); |
4810 } else { | 4821 } else { |
4811 frame()->Dup(); | 4822 frame()->Dup(); |
4812 } | 4823 } |
4813 Result value = EmitNamedLoad(name, var != NULL); | 4824 Result value = EmitNamedLoad(name, var != NULL); |
4814 frame()->Push(&value); | 4825 frame()->Push(&value); |
4815 Load(node->value()); | 4826 Load(node->value()); |
4816 | 4827 |
4817 bool overwrite_value = | 4828 bool overwrite_value = |
4818 (node->value()->AsBinaryOperation() != NULL && | 4829 (node->value()->AsBinaryOperation() != NULL && |
4819 node->value()->AsBinaryOperation()->ResultOverwriteAllowed()); | 4830 node->value()->AsBinaryOperation()->ResultOverwriteAllowed()); |
4820 GenericBinaryOperation(node->binary_op(), | 4831 GenericBinaryOperation(node->binary_op(), |
4821 node->type(), | 4832 node->type(), |
4822 overwrite_value ? OVERWRITE_RIGHT : NO_OVERWRITE); | 4833 overwrite_value ? OVERWRITE_RIGHT : NO_OVERWRITE); |
4823 } else { | 4834 } else { |
4824 Load(node->value()); | 4835 Load(node->value()); |
4825 } | 4836 } |
4826 | 4837 |
4827 // Perform the assignment. It is safe to ignore constants here. | 4838 // Perform the assignment. It is safe to ignore constants here. |
4828 ASSERT(var == NULL || var->mode() != Variable::CONST); | 4839 ASSERT(var == NULL || var->mode() != Variable::CONST); |
4829 ASSERT(node->op() != Token::INIT_CONST); | 4840 ASSERT_NE(Token::INIT_CONST, node->op()); |
4830 if (is_trivial_receiver) { | 4841 if (is_trivial_receiver) { |
4831 Result value = frame()->Pop(); | 4842 Result value = frame()->Pop(); |
4832 frame()->Push(prop->obj()); | 4843 frame()->Push(prop->obj()); |
4833 frame()->Push(&value); | 4844 frame()->Push(&value); |
4834 } | 4845 } |
4835 CodeForSourcePosition(node->position()); | 4846 CodeForSourcePosition(node->position()); |
4836 Result answer = EmitNamedStore(name); | 4847 bool is_contextual = (var != NULL); |
| 4848 Result answer = EmitNamedStore(name, is_contextual); |
4837 frame()->Push(&answer); | 4849 frame()->Push(&answer); |
4838 | 4850 |
4839 if (node->ends_initialization_block()) { | 4851 if (node->ends_initialization_block()) { |
| 4852 ASSERT_EQ(NULL, var); |
4840 // The argument to the runtime call is the receiver. | 4853 // The argument to the runtime call is the receiver. |
4841 if (is_trivial_receiver) { | 4854 if (is_trivial_receiver) { |
4842 frame()->Push(prop->obj()); | 4855 frame()->Push(prop->obj()); |
4843 } else { | 4856 } else { |
4844 // A copy of the receiver is below the value of the assignment. Swap | 4857 // A copy of the receiver is below the value of the assignment. Swap |
4845 // the receiver and the value of the assignment expression. | 4858 // the receiver and the value of the assignment expression. |
4846 Result result = frame()->Pop(); | 4859 Result result = frame()->Pop(); |
4847 Result receiver = frame()->Pop(); | 4860 Result receiver = frame()->Pop(); |
4848 frame()->Push(&result); | 4861 frame()->Push(&result); |
4849 frame()->Push(&receiver); | 4862 frame()->Push(&receiver); |
4850 } | 4863 } |
4851 Result ignored = frame_->CallRuntime(Runtime::kToFastProperties, 1); | 4864 Result ignored = frame_->CallRuntime(Runtime::kToFastProperties, 1); |
4852 } | 4865 } |
4853 | 4866 |
4854 ASSERT(frame()->height() == original_height + 1); | 4867 ASSERT_EQ(frame()->height(), original_height + 1); |
4855 } | 4868 } |
4856 | 4869 |
4857 | 4870 |
4858 void CodeGenerator::EmitKeyedPropertyAssignment(Assignment* node) { | 4871 void CodeGenerator::EmitKeyedPropertyAssignment(Assignment* node) { |
4859 #ifdef DEBUG | 4872 #ifdef DEBUG |
4860 int original_height = frame()->height(); | 4873 int original_height = frame()->height(); |
4861 #endif | 4874 #endif |
4862 Comment cmnt(masm_, "[ Named Property Assignment"); | 4875 Comment cmnt(masm_, "[ Named Property Assignment"); |
4863 Property* prop = node->target()->AsProperty(); | 4876 Property* prop = node->target()->AsProperty(); |
4864 ASSERT(prop != NULL); | 4877 ASSERT_NOT_NULL(prop); |
4865 | 4878 |
4866 // Evaluate the receiver subexpression. | 4879 // Evaluate the receiver subexpression. |
4867 Load(prop->obj()); | 4880 Load(prop->obj()); |
4868 | 4881 |
4869 if (node->starts_initialization_block()) { | 4882 if (node->starts_initialization_block()) { |
4870 // Change to slow case in the beginning of an initialization block to | 4883 // Change to slow case in the beginning of an initialization block to |
4871 // avoid the quadratic behavior of repeatedly adding fast properties. | 4884 // avoid the quadratic behavior of repeatedly adding fast properties. |
4872 frame_->Dup(); | 4885 frame_->Dup(); |
4873 Result ignored = frame_->CallRuntime(Runtime::kToSlowProperties, 1); | 4886 Result ignored = frame_->CallRuntime(Runtime::kToSlowProperties, 1); |
4874 } | 4887 } |
(...skipping 1897 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6772 masm()->mov(result.reg(), FieldOperand(receiver.reg(), offset)); | 6785 masm()->mov(result.reg(), FieldOperand(receiver.reg(), offset)); |
6773 | 6786 |
6774 __ IncrementCounter(&Counters::named_load_inline, 1); | 6787 __ IncrementCounter(&Counters::named_load_inline, 1); |
6775 deferred->BindExit(); | 6788 deferred->BindExit(); |
6776 } | 6789 } |
6777 ASSERT(frame()->height() == original_height - 1); | 6790 ASSERT(frame()->height() == original_height - 1); |
6778 return result; | 6791 return result; |
6779 } | 6792 } |
6780 | 6793 |
6781 | 6794 |
6782 Result CodeGenerator::EmitNamedStore(Handle<String> name) { | 6795 Result CodeGenerator::EmitNamedStore(Handle<String> name, bool is_contextual) { |
6783 #ifdef DEBUG | 6796 #ifdef DEBUG |
6784 int original_height = frame()->height(); | 6797 int expected_height = frame()->height() - (is_contextual ? 1 : 2); |
6785 #endif | 6798 #endif |
6786 frame()->Push(name); | 6799 Result result = frame()->CallStoreIC(name, is_contextual); |
6787 Result result = frame()->CallStoreIC(); | |
6788 | 6800 |
6789 ASSERT(frame()->height() == original_height - 2); | 6801 ASSERT_EQ(expected_height, frame()->height()); |
6790 return result; | 6802 return result; |
6791 } | 6803 } |
6792 | 6804 |
6793 | 6805 |
6794 Result CodeGenerator::EmitKeyedLoad() { | 6806 Result CodeGenerator::EmitKeyedLoad() { |
6795 #ifdef DEBUG | 6807 #ifdef DEBUG |
6796 int original_height = frame()->height(); | 6808 int original_height = frame()->height(); |
6797 #endif | 6809 #endif |
6798 Result result; | 6810 Result result; |
6799 // Inline array load code if inside of a loop. We do not know the | 6811 // Inline array load code if inside of a loop. We do not know the |
(...skipping 296 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7096 Comment cmnt(masm, "[ Store to Slot"); | 7108 Comment cmnt(masm, "[ Store to Slot"); |
7097 Slot* slot = expression_->AsVariableProxy()->AsVariable()->slot(); | 7109 Slot* slot = expression_->AsVariableProxy()->AsVariable()->slot(); |
7098 ASSERT(slot != NULL); | 7110 ASSERT(slot != NULL); |
7099 cgen_->StoreToSlot(slot, init_state); | 7111 cgen_->StoreToSlot(slot, init_state); |
7100 set_unloaded(); | 7112 set_unloaded(); |
7101 break; | 7113 break; |
7102 } | 7114 } |
7103 | 7115 |
7104 case NAMED: { | 7116 case NAMED: { |
7105 Comment cmnt(masm, "[ Store to named Property"); | 7117 Comment cmnt(masm, "[ Store to named Property"); |
7106 Result answer = cgen_->EmitNamedStore(GetName()); | 7118 Result answer = cgen_->EmitNamedStore(GetName(), false); |
7107 cgen_->frame()->Push(&answer); | 7119 cgen_->frame()->Push(&answer); |
7108 set_unloaded(); | 7120 set_unloaded(); |
7109 break; | 7121 break; |
7110 } | 7122 } |
7111 | 7123 |
7112 case KEYED: { | 7124 case KEYED: { |
7113 Comment cmnt(masm, "[ Store to keyed Property"); | 7125 Comment cmnt(masm, "[ Store to keyed Property"); |
7114 Property* property = expression()->AsProperty(); | 7126 Property* property = expression()->AsProperty(); |
7115 ASSERT(property != NULL); | 7127 ASSERT(property != NULL); |
7116 Result answer = cgen_->EmitKeyedStore(property->key()->type()); | 7128 Result answer = cgen_->EmitKeyedStore(property->key()->type()); |
(...skipping 3664 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
10781 | 10793 |
10782 // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater) | 10794 // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater) |
10783 // tagged as a small integer. | 10795 // tagged as a small integer. |
10784 __ bind(&runtime); | 10796 __ bind(&runtime); |
10785 __ TailCallRuntime(ExternalReference(Runtime::kStringCompare), 2, 1); | 10797 __ TailCallRuntime(ExternalReference(Runtime::kStringCompare), 2, 1); |
10786 } | 10798 } |
10787 | 10799 |
10788 #undef __ | 10800 #undef __ |
10789 | 10801 |
10790 } } // namespace v8::internal | 10802 } } // namespace v8::internal |
OLD | NEW |