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