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 4988 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4999 // Perform the assignment. | 4999 // Perform the assignment. |
5000 if (var->mode() != Variable::CONST || node->op() == Token::INIT_CONST) { | 5000 if (var->mode() != Variable::CONST || node->op() == Token::INIT_CONST) { |
5001 CodeForSourcePosition(node->position()); | 5001 CodeForSourcePosition(node->position()); |
5002 StoreToSlot(slot, | 5002 StoreToSlot(slot, |
5003 node->op() == Token::INIT_CONST ? CONST_INIT : NOT_CONST_INIT); | 5003 node->op() == Token::INIT_CONST ? CONST_INIT : NOT_CONST_INIT); |
5004 } | 5004 } |
5005 ASSERT(frame()->height() == original_height + 1); | 5005 ASSERT(frame()->height() == original_height + 1); |
5006 } | 5006 } |
5007 | 5007 |
5008 | 5008 |
| 5009 void CodeGenerator::EmitNamedPropertyAssignment(Assignment* node) { |
| 5010 #ifdef DEBUG |
| 5011 int original_height = frame()->height(); |
| 5012 #endif |
| 5013 Comment cmnt(masm(), "[ Named Property Assignment"); |
| 5014 Variable* var = node->target()->AsVariableProxy()->AsVariable(); |
| 5015 Property* prop = node->target()->AsProperty(); |
| 5016 ASSERT(var == NULL || (prop == NULL && var->is_global())); |
| 5017 |
| 5018 // Initialize name and evaluate the receiver sub-expression if necessary. If |
| 5019 // the receiver is trivial it is not placed on the stack at this point, but |
| 5020 // loaded whenever actually needed. |
| 5021 Handle<String> name; |
| 5022 bool is_trivial_receiver = false; |
| 5023 if (var != NULL) { |
| 5024 name = var->name(); |
| 5025 } else { |
| 5026 Literal* lit = prop->key()->AsLiteral(); |
| 5027 ASSERT_NOT_NULL(lit); |
| 5028 name = Handle<String>::cast(lit->handle()); |
| 5029 // Do not materialize the receiver on the frame if it is trivial. |
| 5030 is_trivial_receiver = prop->obj()->IsTrivial(); |
| 5031 if (!is_trivial_receiver) Load(prop->obj()); |
| 5032 } |
| 5033 |
| 5034 // Change to slow case in the beginning of an initialization block to |
| 5035 // avoid the quadratic behavior of repeatedly adding fast properties. |
| 5036 if (node->starts_initialization_block()) { |
| 5037 // Initialization block consists of assignments of the form expr.x = ..., so |
| 5038 // this will never be an assignment to a variable, so there must be a |
| 5039 // receiver object. |
| 5040 ASSERT_EQ(NULL, var); |
| 5041 if (is_trivial_receiver) { |
| 5042 frame()->Push(prop->obj()); |
| 5043 } else { |
| 5044 frame()->Dup(); |
| 5045 } |
| 5046 Result ignored = frame()->CallRuntime(Runtime::kToSlowProperties, 1); |
| 5047 } |
| 5048 |
| 5049 // Change to fast case at the end of an initialization block. To prepare for |
| 5050 // that add an extra copy of the receiver to the frame, so that it can be |
| 5051 // converted back to fast case after the assignment. |
| 5052 if (node->ends_initialization_block() && !is_trivial_receiver) { |
| 5053 frame()->Dup(); |
| 5054 } |
| 5055 |
| 5056 // Stack layout: |
| 5057 // [tos] : receiver (only materialized if non-trivial) |
| 5058 // [tos+1] : receiver if at the end of an initialization block |
| 5059 |
| 5060 // Evaluate the right-hand side. |
| 5061 if (node->is_compound()) { |
| 5062 // For a compound assignment the right-hand side is a binary operation |
| 5063 // between the current property value and the actual right-hand side. |
| 5064 if (is_trivial_receiver) { |
| 5065 frame()->Push(prop->obj()); |
| 5066 } else if (var != NULL) { |
| 5067 // The LoadIC stub expects the object in rax. |
| 5068 // Freeing rax causes the code generator to load the global into it. |
| 5069 frame_->Spill(rax); |
| 5070 LoadGlobal(); |
| 5071 } else { |
| 5072 frame()->Dup(); |
| 5073 } |
| 5074 Result value = EmitNamedLoad(name, var != NULL); |
| 5075 frame()->Push(&value); |
| 5076 Load(node->value()); |
| 5077 |
| 5078 bool overwrite_value = |
| 5079 (node->value()->AsBinaryOperation() != NULL && |
| 5080 node->value()->AsBinaryOperation()->ResultOverwriteAllowed()); |
| 5081 // Construct the implicit binary operation. |
| 5082 BinaryOperation expr(node, node->binary_op(), node->target(), |
| 5083 node->value()); |
| 5084 GenericBinaryOperation(&expr, |
| 5085 overwrite_value ? OVERWRITE_RIGHT : NO_OVERWRITE); |
| 5086 } else { |
| 5087 // For non-compound assignment just load the right-hand side. |
| 5088 Load(node->value()); |
| 5089 } |
| 5090 |
| 5091 // Stack layout: |
| 5092 // [tos] : value |
| 5093 // [tos+1] : receiver (only materialized if non-trivial) |
| 5094 // [tos+2] : receiver if at the end of an initialization block |
| 5095 |
| 5096 // Perform the assignment. It is safe to ignore constants here. |
| 5097 ASSERT(var == NULL || var->mode() != Variable::CONST); |
| 5098 ASSERT_NE(Token::INIT_CONST, node->op()); |
| 5099 if (is_trivial_receiver) { |
| 5100 Result value = frame()->Pop(); |
| 5101 frame()->Push(prop->obj()); |
| 5102 frame()->Push(&value); |
| 5103 } |
| 5104 CodeForSourcePosition(node->position()); |
| 5105 bool is_contextual = (var != NULL); |
| 5106 Result answer = EmitNamedStore(name, is_contextual); |
| 5107 frame()->Push(&answer); |
| 5108 |
| 5109 // Stack layout: |
| 5110 // [tos] : result |
| 5111 // [tos+1] : receiver if at the end of an initialization block |
| 5112 |
| 5113 if (node->ends_initialization_block()) { |
| 5114 ASSERT_EQ(NULL, var); |
| 5115 // The argument to the runtime call is the receiver. |
| 5116 if (is_trivial_receiver) { |
| 5117 frame()->Push(prop->obj()); |
| 5118 } else { |
| 5119 // A copy of the receiver is below the value of the assignment. Swap |
| 5120 // the receiver and the value of the assignment expression. |
| 5121 Result result = frame()->Pop(); |
| 5122 Result receiver = frame()->Pop(); |
| 5123 frame()->Push(&result); |
| 5124 frame()->Push(&receiver); |
| 5125 } |
| 5126 Result ignored = frame_->CallRuntime(Runtime::kToFastProperties, 1); |
| 5127 } |
| 5128 |
| 5129 // Stack layout: |
| 5130 // [tos] : result |
| 5131 |
| 5132 ASSERT_EQ(frame()->height(), original_height + 1); |
| 5133 } |
| 5134 |
| 5135 |
5009 void CodeGenerator::VisitAssignment(Assignment* node) { | 5136 void CodeGenerator::VisitAssignment(Assignment* node) { |
5010 #ifdef DEBUG | 5137 #ifdef DEBUG |
5011 int original_height = frame()->height(); | 5138 int original_height = frame()->height(); |
5012 #endif | 5139 #endif |
5013 Variable* var = node->target()->AsVariableProxy()->AsVariable(); | 5140 Variable* var = node->target()->AsVariableProxy()->AsVariable(); |
5014 // Property* prop = node->target()->AsProperty(); | 5141 Property* prop = node->target()->AsProperty(); |
5015 | 5142 |
5016 if (var != NULL && !var->is_global()) { | 5143 if (var != NULL && !var->is_global()) { |
5017 EmitSlotAssignment(node); | 5144 EmitSlotAssignment(node); |
5018 | 5145 |
| 5146 } else if ((prop != NULL && prop->key()->IsPropertyName()) || |
| 5147 (var != NULL && var->is_global())) { |
| 5148 // Properties whose keys are property names and global variables are |
| 5149 // treated as named property references. We do not need to consider |
| 5150 // global 'this' because it is not a valid left-hand side. |
| 5151 EmitNamedPropertyAssignment(node); |
| 5152 |
5019 } else { | 5153 } else { |
5020 Comment cmnt(masm_, "[ Assignment"); | 5154 Comment cmnt(masm_, "[ Assignment"); |
5021 | 5155 |
5022 { Reference target(this, node->target(), node->is_compound()); | 5156 { Reference target(this, node->target(), node->is_compound()); |
5023 if (target.is_illegal()) { | 5157 if (target.is_illegal()) { |
5024 // Fool the virtual frame into thinking that we left the assignment's | 5158 // Fool the virtual frame into thinking that we left the assignment's |
5025 // value on the frame. | 5159 // value on the frame. |
5026 frame_->Push(Smi::FromInt(0)); | 5160 frame_->Push(Smi::FromInt(0)); |
5027 return; | 5161 return; |
5028 } | 5162 } |
(...skipping 2811 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7840 masm()->movq(result.reg(), FieldOperand(receiver.reg(), offset)); | 7974 masm()->movq(result.reg(), FieldOperand(receiver.reg(), offset)); |
7841 | 7975 |
7842 __ IncrementCounter(&Counters::named_load_inline, 1); | 7976 __ IncrementCounter(&Counters::named_load_inline, 1); |
7843 deferred->BindExit(); | 7977 deferred->BindExit(); |
7844 } | 7978 } |
7845 ASSERT(frame()->height() == original_height - 1); | 7979 ASSERT(frame()->height() == original_height - 1); |
7846 return result; | 7980 return result; |
7847 } | 7981 } |
7848 | 7982 |
7849 | 7983 |
| 7984 Result CodeGenerator::EmitNamedStore(Handle<String> name, bool is_contextual) { |
| 7985 #ifdef DEBUG |
| 7986 int expected_height = frame()->height() - (is_contextual ? 1 : 2); |
| 7987 #endif |
| 7988 |
| 7989 Result result = frame()->CallStoreIC(name, is_contextual); |
| 7990 // A test eax instruction following the call signals that the inobject |
| 7991 // property case was inlined. Ensure that there is not a test eax |
| 7992 // instruction here. |
| 7993 __ nop(); |
| 7994 |
| 7995 ASSERT_EQ(expected_height, frame()->height()); |
| 7996 return result; |
| 7997 } |
| 7998 |
| 7999 |
7850 Result CodeGenerator::EmitKeyedLoad() { | 8000 Result CodeGenerator::EmitKeyedLoad() { |
7851 #ifdef DEBUG | 8001 #ifdef DEBUG |
7852 int original_height = frame()->height(); | 8002 int original_height = frame()->height(); |
7853 #endif | 8003 #endif |
7854 Result result; | 8004 Result result; |
7855 // Inline array load code if inside of a loop. We do not know | 8005 // Inline array load code if inside of a loop. We do not know |
7856 // the receiver map yet, so we initially generate the code with | 8006 // the receiver map yet, so we initially generate the code with |
7857 // a check against an invalid map. In the inline cache code, we | 8007 // a check against an invalid map. In the inline cache code, we |
7858 // patch the map check if appropriate. | 8008 // patch the map check if appropriate. |
7859 if (loop_nesting() > 0) { | 8009 if (loop_nesting() > 0) { |
(...skipping 4310 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
12170 #undef __ | 12320 #undef __ |
12171 | 12321 |
12172 void RecordWriteStub::Generate(MacroAssembler* masm) { | 12322 void RecordWriteStub::Generate(MacroAssembler* masm) { |
12173 masm->RecordWriteHelper(object_, addr_, scratch_); | 12323 masm->RecordWriteHelper(object_, addr_, scratch_); |
12174 masm->ret(0); | 12324 masm->ret(0); |
12175 } | 12325 } |
12176 | 12326 |
12177 } } // namespace v8::internal | 12327 } } // namespace v8::internal |
12178 | 12328 |
12179 #endif // V8_TARGET_ARCH_X64 | 12329 #endif // V8_TARGET_ARCH_X64 |
OLD | NEW |