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 5115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5126 Result ignored = frame_->CallRuntime(Runtime::kToFastProperties, 1); | 5126 Result ignored = frame_->CallRuntime(Runtime::kToFastProperties, 1); |
5127 } | 5127 } |
5128 | 5128 |
5129 // Stack layout: | 5129 // Stack layout: |
5130 // [tos] : result | 5130 // [tos] : result |
5131 | 5131 |
5132 ASSERT_EQ(frame()->height(), original_height + 1); | 5132 ASSERT_EQ(frame()->height(), original_height + 1); |
5133 } | 5133 } |
5134 | 5134 |
5135 | 5135 |
| 5136 void CodeGenerator::EmitKeyedPropertyAssignment(Assignment* node) { |
| 5137 #ifdef DEBUG |
| 5138 int original_height = frame()->height(); |
| 5139 #endif |
| 5140 Comment cmnt(masm_, "[ Keyed Property Assignment"); |
| 5141 Property* prop = node->target()->AsProperty(); |
| 5142 ASSERT_NOT_NULL(prop); |
| 5143 |
| 5144 // Evaluate the receiver subexpression. |
| 5145 Load(prop->obj()); |
| 5146 |
| 5147 // Change to slow case in the beginning of an initialization block to |
| 5148 // avoid the quadratic behavior of repeatedly adding fast properties. |
| 5149 if (node->starts_initialization_block()) { |
| 5150 frame_->Dup(); |
| 5151 Result ignored = frame_->CallRuntime(Runtime::kToSlowProperties, 1); |
| 5152 } |
| 5153 |
| 5154 // Change to fast case at the end of an initialization block. To prepare for |
| 5155 // that add an extra copy of the receiver to the frame, so that it can be |
| 5156 // converted back to fast case after the assignment. |
| 5157 if (node->ends_initialization_block()) { |
| 5158 frame_->Dup(); |
| 5159 } |
| 5160 |
| 5161 // Evaluate the key subexpression. |
| 5162 Load(prop->key()); |
| 5163 |
| 5164 // Stack layout: |
| 5165 // [tos] : key |
| 5166 // [tos+1] : receiver |
| 5167 // [tos+2] : receiver if at the end of an initialization block |
| 5168 |
| 5169 // Evaluate the right-hand side. |
| 5170 if (node->is_compound()) { |
| 5171 // For a compound assignment the right-hand side is a binary operation |
| 5172 // between the current property value and the actual right-hand side. |
| 5173 // Duplicate receiver and key for loading the current property value. |
| 5174 frame()->PushElementAt(1); |
| 5175 frame()->PushElementAt(1); |
| 5176 Result value = EmitKeyedLoad(); |
| 5177 frame()->Push(&value); |
| 5178 Load(node->value()); |
| 5179 |
| 5180 // Perform the binary operation. |
| 5181 bool overwrite_value = |
| 5182 (node->value()->AsBinaryOperation() != NULL && |
| 5183 node->value()->AsBinaryOperation()->ResultOverwriteAllowed()); |
| 5184 BinaryOperation expr(node, node->binary_op(), node->target(), |
| 5185 node->value()); |
| 5186 GenericBinaryOperation(&expr, |
| 5187 overwrite_value ? OVERWRITE_RIGHT : NO_OVERWRITE); |
| 5188 } else { |
| 5189 // For non-compound assignment just load the right-hand side. |
| 5190 Load(node->value()); |
| 5191 } |
| 5192 |
| 5193 // Stack layout: |
| 5194 // [tos] : value |
| 5195 // [tos+1] : key |
| 5196 // [tos+2] : receiver |
| 5197 // [tos+3] : receiver if at the end of an initialization block |
| 5198 |
| 5199 // Perform the assignment. It is safe to ignore constants here. |
| 5200 ASSERT(node->op() != Token::INIT_CONST); |
| 5201 CodeForSourcePosition(node->position()); |
| 5202 Result answer = EmitKeyedStore(prop->key()->type()); |
| 5203 frame()->Push(&answer); |
| 5204 |
| 5205 // Stack layout: |
| 5206 // [tos] : result |
| 5207 // [tos+1] : receiver if at the end of an initialization block |
| 5208 |
| 5209 // Change to fast case at the end of an initialization block. |
| 5210 if (node->ends_initialization_block()) { |
| 5211 // The argument to the runtime call is the extra copy of the receiver, |
| 5212 // which is below the value of the assignment. Swap the receiver and |
| 5213 // the value of the assignment expression. |
| 5214 Result result = frame()->Pop(); |
| 5215 Result receiver = frame()->Pop(); |
| 5216 frame()->Push(&result); |
| 5217 frame()->Push(&receiver); |
| 5218 Result ignored = frame_->CallRuntime(Runtime::kToFastProperties, 1); |
| 5219 } |
| 5220 |
| 5221 // Stack layout: |
| 5222 // [tos] : result |
| 5223 |
| 5224 ASSERT(frame()->height() == original_height + 1); |
| 5225 } |
| 5226 |
| 5227 |
5136 void CodeGenerator::VisitAssignment(Assignment* node) { | 5228 void CodeGenerator::VisitAssignment(Assignment* node) { |
5137 #ifdef DEBUG | 5229 #ifdef DEBUG |
5138 int original_height = frame()->height(); | 5230 int original_height = frame()->height(); |
5139 #endif | 5231 #endif |
5140 Variable* var = node->target()->AsVariableProxy()->AsVariable(); | 5232 Variable* var = node->target()->AsVariableProxy()->AsVariable(); |
5141 Property* prop = node->target()->AsProperty(); | 5233 Property* prop = node->target()->AsProperty(); |
5142 | 5234 |
5143 if (var != NULL && !var->is_global()) { | 5235 if (var != NULL && !var->is_global()) { |
5144 EmitSlotAssignment(node); | 5236 EmitSlotAssignment(node); |
5145 | 5237 |
5146 } else if ((prop != NULL && prop->key()->IsPropertyName()) || | 5238 } else if ((prop != NULL && prop->key()->IsPropertyName()) || |
5147 (var != NULL && var->is_global())) { | 5239 (var != NULL && var->is_global())) { |
5148 // Properties whose keys are property names and global variables are | 5240 // Properties whose keys are property names and global variables are |
5149 // treated as named property references. We do not need to consider | 5241 // treated as named property references. We do not need to consider |
5150 // global 'this' because it is not a valid left-hand side. | 5242 // global 'this' because it is not a valid left-hand side. |
5151 EmitNamedPropertyAssignment(node); | 5243 EmitNamedPropertyAssignment(node); |
5152 | 5244 |
| 5245 } else if (prop != NULL) { |
| 5246 // Other properties (including rewritten parameters for a function that |
| 5247 // uses arguments) are keyed property assignments. |
| 5248 EmitKeyedPropertyAssignment(node); |
| 5249 |
5153 } else { | 5250 } else { |
5154 Comment cmnt(masm_, "[ Assignment"); | 5251 // Invalid left-hand side. |
5155 | 5252 Load(node->target()); |
5156 { Reference target(this, node->target(), node->is_compound()); | 5253 Result result = frame()->CallRuntime(Runtime::kThrowReferenceError, 1); |
5157 if (target.is_illegal()) { | 5254 // The runtime call doesn't actually return but the code generator will |
5158 // Fool the virtual frame into thinking that we left the assignment's | 5255 // still generate code and expects a certain frame height. |
5159 // value on the frame. | 5256 frame()->Push(&result); |
5160 frame_->Push(Smi::FromInt(0)); | |
5161 return; | |
5162 } | |
5163 | |
5164 if (node->starts_initialization_block()) { | |
5165 ASSERT(target.type() == Reference::NAMED || | |
5166 target.type() == Reference::KEYED); | |
5167 // Change to slow case in the beginning of an initialization | |
5168 // block to avoid the quadratic behavior of repeatedly adding | |
5169 // fast properties. | |
5170 | |
5171 // The receiver is the argument to the runtime call. It is the | |
5172 // first value pushed when the reference was loaded to the | |
5173 // frame. | |
5174 frame_->PushElementAt(target.size() - 1); | |
5175 Result ignored = frame_->CallRuntime(Runtime::kToSlowProperties, 1); | |
5176 } | |
5177 if (node->ends_initialization_block()) { | |
5178 // Add an extra copy of the receiver to the frame, so that it can be | |
5179 // converted back to fast case after the assignment. | |
5180 ASSERT(target.type() == Reference::NAMED || | |
5181 target.type() == Reference::KEYED); | |
5182 if (target.type() == Reference::NAMED) { | |
5183 frame_->Dup(); | |
5184 // Dup target receiver on stack. | |
5185 } else { | |
5186 ASSERT(target.type() == Reference::KEYED); | |
5187 Result temp = frame_->Pop(); | |
5188 frame_->Dup(); | |
5189 frame_->Push(&temp); | |
5190 } | |
5191 } | |
5192 if (node->op() == Token::ASSIGN || | |
5193 node->op() == Token::INIT_VAR || | |
5194 node->op() == Token::INIT_CONST) { | |
5195 Load(node->value()); | |
5196 | |
5197 } else { // Assignment is a compound assignment. | |
5198 Literal* literal = node->value()->AsLiteral(); | |
5199 bool overwrite_value = | |
5200 (node->value()->AsBinaryOperation() != NULL && | |
5201 node->value()->AsBinaryOperation()->ResultOverwriteAllowed()); | |
5202 Variable* right_var = node->value()->AsVariableProxy()->AsVariable(); | |
5203 // There are two cases where the target is not read in the right hand | |
5204 // side, that are easy to test for: the right hand side is a literal, | |
5205 // or the right hand side is a different variable. TakeValue | |
5206 // invalidates the target, with an implicit promise that it will be | |
5207 // written to again | |
5208 // before it is read. | |
5209 if (literal != NULL || (right_var != NULL && right_var != var)) { | |
5210 target.TakeValue(); | |
5211 } else { | |
5212 target.GetValue(); | |
5213 } | |
5214 Load(node->value()); | |
5215 BinaryOperation expr(node, node->binary_op(), node->target(), | |
5216 node->value()); | |
5217 GenericBinaryOperation( | |
5218 &expr, overwrite_value ? OVERWRITE_RIGHT : NO_OVERWRITE); | |
5219 } | |
5220 if (var != NULL && | |
5221 var->mode() == Variable::CONST && | |
5222 node->op() != Token::INIT_VAR && node->op() != Token::INIT_CONST) { | |
5223 // Assignment ignored - leave the value on the stack. | |
5224 UnloadReference(&target); | |
5225 } else { | |
5226 CodeForSourcePosition(node->position()); | |
5227 if (node->op() == Token::INIT_CONST) { | |
5228 // Dynamic constant initializations must use the function context | |
5229 // and initialize the actual constant declared. Dynamic variable | |
5230 // initializations are simply assignments and use SetValue. | |
5231 target.SetValue(CONST_INIT); | |
5232 } else { | |
5233 target.SetValue(NOT_CONST_INIT); | |
5234 } | |
5235 if (node->ends_initialization_block()) { | |
5236 ASSERT(target.type() == Reference::UNLOADED); | |
5237 // End of initialization block. Revert to fast case. The | |
5238 // argument to the runtime call is the extra copy of the receiver, | |
5239 // which is below the value of the assignment. | |
5240 // Swap the receiver and the value of the assignment expression. | |
5241 Result lhs = frame_->Pop(); | |
5242 Result receiver = frame_->Pop(); | |
5243 frame_->Push(&lhs); | |
5244 frame_->Push(&receiver); | |
5245 Result ignored = frame_->CallRuntime(Runtime::kToFastProperties, 1); | |
5246 } | |
5247 } | |
5248 } | |
5249 } | 5257 } |
5250 // Stack layout: | |
5251 // [tos] : result | |
5252 | 5258 |
5253 ASSERT(frame()->height() == original_height + 1); | 5259 ASSERT(frame()->height() == original_height + 1); |
5254 } | 5260 } |
5255 | 5261 |
5256 | 5262 |
5257 void CodeGenerator::VisitThrow(Throw* node) { | 5263 void CodeGenerator::VisitThrow(Throw* node) { |
5258 Comment cmnt(masm_, "[ Throw"); | 5264 Comment cmnt(masm_, "[ Throw"); |
5259 Load(node->exception()); | 5265 Load(node->exception()); |
5260 Result result = frame_->CallRuntime(Runtime::kThrow, 1); | 5266 Result result = frame_->CallRuntime(Runtime::kThrow, 1); |
5261 frame_->Push(&result); | 5267 frame_->Push(&result); |
(...skipping 2828 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
8090 // indicate that we have generated an inline version of the | 8096 // indicate that we have generated an inline version of the |
8091 // keyed load. The explicit nop instruction is here because | 8097 // keyed load. The explicit nop instruction is here because |
8092 // the push that follows might be peep-hole optimized away. | 8098 // the push that follows might be peep-hole optimized away. |
8093 __ nop(); | 8099 __ nop(); |
8094 } | 8100 } |
8095 ASSERT(frame()->height() == original_height - 2); | 8101 ASSERT(frame()->height() == original_height - 2); |
8096 return result; | 8102 return result; |
8097 } | 8103 } |
8098 | 8104 |
8099 | 8105 |
| 8106 Result CodeGenerator::EmitKeyedStore(StaticType* key_type) { |
| 8107 #ifdef DEBUG |
| 8108 int original_height = frame()->height(); |
| 8109 #endif |
| 8110 Result result; |
| 8111 // Generate inlined version of the keyed store if the code is in a loop |
| 8112 // and the key is likely to be a smi. |
| 8113 if (loop_nesting() > 0 && key_type->IsLikelySmi()) { |
| 8114 Comment cmnt(masm(), "[ Inlined store to keyed Property"); |
| 8115 |
| 8116 // Get the receiver, key and value into registers. |
| 8117 result = frame()->Pop(); |
| 8118 Result key = frame()->Pop(); |
| 8119 Result receiver = frame()->Pop(); |
| 8120 |
| 8121 Result tmp = allocator_->Allocate(); |
| 8122 ASSERT(tmp.is_valid()); |
| 8123 Result tmp2 = allocator_->Allocate(); |
| 8124 ASSERT(tmp2.is_valid()); |
| 8125 |
| 8126 // Determine whether the value is a constant before putting it in a |
| 8127 // register. |
| 8128 bool value_is_constant = result.is_constant(); |
| 8129 |
| 8130 // Make sure that value, key and receiver are in registers. |
| 8131 result.ToRegister(); |
| 8132 key.ToRegister(); |
| 8133 receiver.ToRegister(); |
| 8134 |
| 8135 DeferredReferenceSetKeyedValue* deferred = |
| 8136 new DeferredReferenceSetKeyedValue(result.reg(), |
| 8137 key.reg(), |
| 8138 receiver.reg()); |
| 8139 |
| 8140 // Check that the receiver is not a smi. |
| 8141 __ JumpIfSmi(receiver.reg(), deferred->entry_label()); |
| 8142 |
| 8143 // Check that the key is a smi. |
| 8144 if (!key.is_smi()) { |
| 8145 __ JumpIfNotSmi(key.reg(), deferred->entry_label()); |
| 8146 } else if (FLAG_debug_code) { |
| 8147 __ AbortIfNotSmi(key.reg()); |
| 8148 } |
| 8149 |
| 8150 // Check that the receiver is a JSArray. |
| 8151 __ CmpObjectType(receiver.reg(), JS_ARRAY_TYPE, kScratchRegister); |
| 8152 deferred->Branch(not_equal); |
| 8153 |
| 8154 // Check that the key is within bounds. Both the key and the length of |
| 8155 // the JSArray are smis. Use unsigned comparison to handle negative keys. |
| 8156 __ SmiCompare(FieldOperand(receiver.reg(), JSArray::kLengthOffset), |
| 8157 key.reg()); |
| 8158 deferred->Branch(below_equal); |
| 8159 |
| 8160 // Get the elements array from the receiver and check that it is not a |
| 8161 // dictionary. |
| 8162 __ movq(tmp.reg(), |
| 8163 FieldOperand(receiver.reg(), JSArray::kElementsOffset)); |
| 8164 |
| 8165 // Check whether it is possible to omit the write barrier. If the elements |
| 8166 // array is in new space or the value written is a smi we can safely update |
| 8167 // the elements array without write barrier. |
| 8168 Label in_new_space; |
| 8169 __ InNewSpace(tmp.reg(), tmp2.reg(), equal, &in_new_space); |
| 8170 if (!value_is_constant) { |
| 8171 __ JumpIfNotSmi(result.reg(), deferred->entry_label()); |
| 8172 } |
| 8173 |
| 8174 __ bind(&in_new_space); |
| 8175 // Bind the deferred code patch site to be able to locate the fixed |
| 8176 // array map comparison. When debugging, we patch this comparison to |
| 8177 // always fail so that we will hit the IC call in the deferred code |
| 8178 // which will allow the debugger to break for fast case stores. |
| 8179 __ bind(deferred->patch_site()); |
| 8180 // Avoid using __ to ensure the distance from patch_site |
| 8181 // to the map address is always the same. |
| 8182 masm()->movq(kScratchRegister, Factory::fixed_array_map(), |
| 8183 RelocInfo::EMBEDDED_OBJECT); |
| 8184 __ cmpq(FieldOperand(tmp.reg(), HeapObject::kMapOffset), |
| 8185 kScratchRegister); |
| 8186 deferred->Branch(not_equal); |
| 8187 |
| 8188 // Store the value. |
| 8189 SmiIndex index = |
| 8190 masm()->SmiToIndex(kScratchRegister, key.reg(), kPointerSizeLog2); |
| 8191 __ movq(FieldOperand(tmp.reg(), |
| 8192 index.reg, |
| 8193 index.scale, |
| 8194 FixedArray::kHeaderSize), |
| 8195 result.reg()); |
| 8196 __ IncrementCounter(&Counters::keyed_store_inline, 1); |
| 8197 |
| 8198 deferred->BindExit(); |
| 8199 } else { |
| 8200 result = frame()->CallKeyedStoreIC(); |
| 8201 // Make sure that we do not have a test instruction after the |
| 8202 // call. A test instruction after the call is used to |
| 8203 // indicate that we have generated an inline version of the |
| 8204 // keyed store. |
| 8205 __ nop(); |
| 8206 } |
| 8207 ASSERT(frame()->height() == original_height - 3); |
| 8208 return result; |
| 8209 } |
| 8210 |
| 8211 |
8100 #undef __ | 8212 #undef __ |
8101 #define __ ACCESS_MASM(masm) | 8213 #define __ ACCESS_MASM(masm) |
8102 | 8214 |
8103 | 8215 |
8104 Handle<String> Reference::GetName() { | 8216 Handle<String> Reference::GetName() { |
8105 ASSERT(type_ == NAMED); | 8217 ASSERT(type_ == NAMED); |
8106 Property* property = expression_->AsProperty(); | 8218 Property* property = expression_->AsProperty(); |
8107 if (property == NULL) { | 8219 if (property == NULL) { |
8108 // Global variable reference treated as a named property reference. | 8220 // Global variable reference treated as a named property reference. |
8109 VariableProxy* proxy = expression_->AsVariableProxy(); | 8221 VariableProxy* proxy = expression_->AsVariableProxy(); |
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
8215 void Reference::SetValue(InitState init_state) { | 8327 void Reference::SetValue(InitState init_state) { |
8216 ASSERT(cgen_->HasValidEntryRegisters()); | 8328 ASSERT(cgen_->HasValidEntryRegisters()); |
8217 ASSERT(!is_illegal()); | 8329 ASSERT(!is_illegal()); |
8218 MacroAssembler* masm = cgen_->masm(); | 8330 MacroAssembler* masm = cgen_->masm(); |
8219 switch (type_) { | 8331 switch (type_) { |
8220 case SLOT: { | 8332 case SLOT: { |
8221 Comment cmnt(masm, "[ Store to Slot"); | 8333 Comment cmnt(masm, "[ Store to Slot"); |
8222 Slot* slot = expression_->AsVariableProxy()->AsVariable()->slot(); | 8334 Slot* slot = expression_->AsVariableProxy()->AsVariable()->slot(); |
8223 ASSERT(slot != NULL); | 8335 ASSERT(slot != NULL); |
8224 cgen_->StoreToSlot(slot, init_state); | 8336 cgen_->StoreToSlot(slot, init_state); |
8225 cgen_->UnloadReference(this); | 8337 set_unloaded(); |
8226 break; | 8338 break; |
8227 } | 8339 } |
8228 | 8340 |
8229 case NAMED: { | 8341 case NAMED: { |
8230 Comment cmnt(masm, "[ Store to named Property"); | 8342 Comment cmnt(masm, "[ Store to named Property"); |
8231 cgen_->frame()->Push(GetName()); | 8343 Result answer = cgen_->EmitNamedStore(GetName(), false); |
8232 Result answer = cgen_->frame()->CallStoreIC(); | |
8233 cgen_->frame()->Push(&answer); | 8344 cgen_->frame()->Push(&answer); |
8234 set_unloaded(); | 8345 set_unloaded(); |
8235 break; | 8346 break; |
8236 } | 8347 } |
8237 | 8348 |
8238 case KEYED: { | 8349 case KEYED: { |
8239 Comment cmnt(masm, "[ Store to keyed Property"); | 8350 Comment cmnt(masm, "[ Store to keyed Property"); |
8240 | |
8241 // Generate inlined version of the keyed store if the code is in | |
8242 // a loop and the key is likely to be a smi. | |
8243 Property* property = expression()->AsProperty(); | 8351 Property* property = expression()->AsProperty(); |
8244 ASSERT(property != NULL); | 8352 ASSERT(property != NULL); |
8245 StaticType* key_smi_analysis = property->key()->type(); | |
8246 | 8353 |
8247 if (cgen_->loop_nesting() > 0 && key_smi_analysis->IsLikelySmi()) { | 8354 Result answer = cgen_->EmitKeyedStore(property->key()->type()); |
8248 Comment cmnt(masm, "[ Inlined store to keyed Property"); | 8355 cgen_->frame()->Push(&answer); |
8249 | |
8250 // Get the receiver, key and value into registers. | |
8251 Result value = cgen_->frame()->Pop(); | |
8252 Result key = cgen_->frame()->Pop(); | |
8253 Result receiver = cgen_->frame()->Pop(); | |
8254 | |
8255 Result tmp = cgen_->allocator_->Allocate(); | |
8256 ASSERT(tmp.is_valid()); | |
8257 Result tmp2 = cgen_->allocator_->Allocate(); | |
8258 ASSERT(tmp2.is_valid()); | |
8259 | |
8260 // Determine whether the value is a constant before putting it | |
8261 // in a register. | |
8262 bool value_is_constant = value.is_constant(); | |
8263 | |
8264 // Make sure that value, key and receiver are in registers. | |
8265 value.ToRegister(); | |
8266 key.ToRegister(); | |
8267 receiver.ToRegister(); | |
8268 | |
8269 DeferredReferenceSetKeyedValue* deferred = | |
8270 new DeferredReferenceSetKeyedValue(value.reg(), | |
8271 key.reg(), | |
8272 receiver.reg()); | |
8273 | |
8274 // Check that the receiver is not a smi. | |
8275 __ JumpIfSmi(receiver.reg(), deferred->entry_label()); | |
8276 | |
8277 // Check that the key is a smi. | |
8278 if (!key.is_smi()) { | |
8279 __ JumpIfNotSmi(key.reg(), deferred->entry_label()); | |
8280 } else if (FLAG_debug_code) { | |
8281 __ AbortIfNotSmi(key.reg()); | |
8282 } | |
8283 | |
8284 // Check that the receiver is a JSArray. | |
8285 __ CmpObjectType(receiver.reg(), JS_ARRAY_TYPE, kScratchRegister); | |
8286 deferred->Branch(not_equal); | |
8287 | |
8288 // Check that the key is within bounds. Both the key and the | |
8289 // length of the JSArray are smis. Use unsigned comparison to handle | |
8290 // negative keys. | |
8291 __ SmiCompare(FieldOperand(receiver.reg(), JSArray::kLengthOffset), | |
8292 key.reg()); | |
8293 deferred->Branch(below_equal); | |
8294 | |
8295 // Get the elements array from the receiver and check that it | |
8296 // is a flat array (not a dictionary). | |
8297 __ movq(tmp.reg(), | |
8298 FieldOperand(receiver.reg(), JSObject::kElementsOffset)); | |
8299 | |
8300 // Check whether it is possible to omit the write barrier. If the | |
8301 // elements array is in new space or the value written is a smi we can | |
8302 // safely update the elements array without write barrier. | |
8303 Label in_new_space; | |
8304 __ InNewSpace(tmp.reg(), tmp2.reg(), equal, &in_new_space); | |
8305 if (!value_is_constant) { | |
8306 __ JumpIfNotSmi(value.reg(), deferred->entry_label()); | |
8307 } | |
8308 | |
8309 __ bind(&in_new_space); | |
8310 // Bind the deferred code patch site to be able to locate the | |
8311 // fixed array map comparison. When debugging, we patch this | |
8312 // comparison to always fail so that we will hit the IC call | |
8313 // in the deferred code which will allow the debugger to | |
8314 // break for fast case stores. | |
8315 __ bind(deferred->patch_site()); | |
8316 // Avoid using __ to ensure the distance from patch_site | |
8317 // to the map address is always the same. | |
8318 masm->movq(kScratchRegister, Factory::fixed_array_map(), | |
8319 RelocInfo::EMBEDDED_OBJECT); | |
8320 __ cmpq(FieldOperand(tmp.reg(), HeapObject::kMapOffset), | |
8321 kScratchRegister); | |
8322 deferred->Branch(not_equal); | |
8323 | |
8324 // Store the value. | |
8325 SmiIndex index = | |
8326 masm->SmiToIndex(kScratchRegister, key.reg(), kPointerSizeLog2); | |
8327 __ movq(FieldOperand(tmp.reg(), | |
8328 index.reg, | |
8329 index.scale, | |
8330 FixedArray::kHeaderSize), | |
8331 value.reg()); | |
8332 __ IncrementCounter(&Counters::keyed_store_inline, 1); | |
8333 | |
8334 deferred->BindExit(); | |
8335 | |
8336 cgen_->frame()->Push(&value); | |
8337 } else { | |
8338 Result answer = cgen_->frame()->CallKeyedStoreIC(); | |
8339 // Make sure that we do not have a test instruction after the | |
8340 // call. A test instruction after the call is used to | |
8341 // indicate that we have generated an inline version of the | |
8342 // keyed store. | |
8343 masm->nop(); | |
8344 cgen_->frame()->Push(&answer); | |
8345 } | |
8346 set_unloaded(); | 8356 set_unloaded(); |
8347 break; | 8357 break; |
8348 } | 8358 } |
8349 | 8359 |
8350 default: | 8360 case UNLOADED: |
| 8361 case ILLEGAL: |
8351 UNREACHABLE(); | 8362 UNREACHABLE(); |
8352 } | 8363 } |
8353 } | 8364 } |
8354 | 8365 |
8355 | 8366 |
8356 void FastNewClosureStub::Generate(MacroAssembler* masm) { | 8367 void FastNewClosureStub::Generate(MacroAssembler* masm) { |
8357 // Create a new closure from the given function info in new | 8368 // Create a new closure from the given function info in new |
8358 // space. Set the context to the current context in rsi. | 8369 // space. Set the context to the current context in rsi. |
8359 Label gc; | 8370 Label gc; |
8360 __ AllocateInNewSpace(JSFunction::kSize, rax, rbx, rcx, &gc, TAG_OBJECT); | 8371 __ AllocateInNewSpace(JSFunction::kSize, rax, rbx, rcx, &gc, TAG_OBJECT); |
(...skipping 3959 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
12320 #undef __ | 12331 #undef __ |
12321 | 12332 |
12322 void RecordWriteStub::Generate(MacroAssembler* masm) { | 12333 void RecordWriteStub::Generate(MacroAssembler* masm) { |
12323 masm->RecordWriteHelper(object_, addr_, scratch_); | 12334 masm->RecordWriteHelper(object_, addr_, scratch_); |
12324 masm->ret(0); | 12335 masm->ret(0); |
12325 } | 12336 } |
12326 | 12337 |
12327 } } // namespace v8::internal | 12338 } } // namespace v8::internal |
12328 | 12339 |
12329 #endif // V8_TARGET_ARCH_X64 | 12340 #endif // V8_TARGET_ARCH_X64 |
OLD | NEW |