OLD | NEW |
1 // Copyright 2016 the V8 project authors. All rights reserved. | 1 // Copyright 2016 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 #include "src/code-stub-assembler.h" | 4 #include "src/code-stub-assembler.h" |
5 #include "src/code-factory.h" | 5 #include "src/code-factory.h" |
6 #include "src/frames-inl.h" | 6 #include "src/frames-inl.h" |
7 #include "src/frames.h" | 7 #include "src/frames.h" |
8 #include "src/ic/handler-configuration.h" | 8 #include "src/ic/handler-configuration.h" |
9 #include "src/ic/stub-cache.h" | 9 #include "src/ic/stub-cache.h" |
10 | 10 |
(...skipping 5617 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5628 Return(value); | 5628 Return(value); |
5629 | 5629 |
5630 Bind(&if_accessor_info); | 5630 Bind(&if_accessor_info); |
5631 Callable callable = CodeFactory::ApiGetter(isolate()); | 5631 Callable callable = CodeFactory::ApiGetter(isolate()); |
5632 TailCallStub(callable, p->context, p->receiver, holder, value); | 5632 TailCallStub(callable, p->context, p->receiver, holder, value); |
5633 } | 5633 } |
5634 } | 5634 } |
5635 | 5635 |
5636 Bind(&try_proto_handler); | 5636 Bind(&try_proto_handler); |
5637 { | 5637 { |
5638 GotoIf(WordEqual(LoadMap(handler), LoadRoot(Heap::kCodeMapRootIndex)), | 5638 GotoIf(IsCodeMap(LoadMap(handler)), &call_handler); |
5639 &call_handler); | |
5640 HandleLoadICProtoHandler(p, handler, &var_holder, &var_smi_handler, | 5639 HandleLoadICProtoHandler(p, handler, &var_holder, &var_smi_handler, |
5641 &if_smi_handler, miss); | 5640 &if_smi_handler, miss); |
5642 } | 5641 } |
5643 | 5642 |
5644 Bind(&call_handler); | 5643 Bind(&call_handler); |
5645 { | 5644 { |
5646 typedef LoadWithVectorDescriptor Descriptor; | 5645 typedef LoadWithVectorDescriptor Descriptor; |
5647 TailCallStub(Descriptor(isolate()), handler, p->context, | 5646 TailCallStub(Descriptor(isolate()), handler, p->context, |
5648 Arg(Descriptor::kReceiver, p->receiver), | 5647 Arg(Descriptor::kReceiver, p->receiver), |
5649 Arg(Descriptor::kName, p->name), | 5648 Arg(Descriptor::kName, p->name), |
(...skipping 429 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6079 Bind(&slow); | 6078 Bind(&slow); |
6080 { | 6079 { |
6081 Comment("KeyedLoadGeneric_slow"); | 6080 Comment("KeyedLoadGeneric_slow"); |
6082 IncrementCounter(isolate()->counters()->ic_keyed_load_generic_slow(), 1); | 6081 IncrementCounter(isolate()->counters()->ic_keyed_load_generic_slow(), 1); |
6083 // TODO(jkummerow): Should we use the GetProperty TF stub instead? | 6082 // TODO(jkummerow): Should we use the GetProperty TF stub instead? |
6084 TailCallRuntime(Runtime::kKeyedGetProperty, p->context, p->receiver, | 6083 TailCallRuntime(Runtime::kKeyedGetProperty, p->context, p->receiver, |
6085 p->name); | 6084 p->name); |
6086 } | 6085 } |
6087 } | 6086 } |
6088 | 6087 |
6089 void CodeStubAssembler::HandleStoreFieldAndReturn( | 6088 void CodeStubAssembler::HandleStoreFieldAndReturn(Node* handler_word, |
6090 Node* handler_word, Node* holder, Representation representation, | 6089 Node* holder, |
6091 Node* value, bool transition_to_field, Label* miss) { | 6090 Representation representation, |
| 6091 Node* value, Node* transition, |
| 6092 Label* miss) { |
| 6093 bool transition_to_field = transition != nullptr; |
6092 Node* prepared_value = PrepareValueForWrite(value, representation, miss); | 6094 Node* prepared_value = PrepareValueForWrite(value, representation, miss); |
6093 | 6095 |
| 6096 if (transition_to_field) { |
| 6097 Label storage_extended(this); |
| 6098 GotoUnless(IsSetWord<StoreHandler::ExtendStorageBits>(handler_word), |
| 6099 &storage_extended); |
| 6100 Comment("[ Extend storage"); |
| 6101 ExtendPropertiesBackingStore(holder); |
| 6102 Comment("] Extend storage"); |
| 6103 Goto(&storage_extended); |
| 6104 |
| 6105 Bind(&storage_extended); |
| 6106 } |
| 6107 |
6094 Node* offset = DecodeWord<StoreHandler::FieldOffsetBits>(handler_word); | 6108 Node* offset = DecodeWord<StoreHandler::FieldOffsetBits>(handler_word); |
6095 Label if_inobject(this), if_out_of_object(this); | 6109 Label if_inobject(this), if_out_of_object(this); |
6096 Branch(IsSetWord<StoreHandler::IsInobjectBits>(handler_word), &if_inobject, | 6110 Branch(IsSetWord<StoreHandler::IsInobjectBits>(handler_word), &if_inobject, |
6097 &if_out_of_object); | 6111 &if_out_of_object); |
6098 | 6112 |
6099 Bind(&if_inobject); | 6113 Bind(&if_inobject); |
6100 { | 6114 { |
6101 StoreNamedField(holder, offset, true, representation, prepared_value, | 6115 StoreNamedField(holder, offset, true, representation, prepared_value, |
6102 transition_to_field); | 6116 transition_to_field); |
| 6117 if (transition_to_field) { |
| 6118 StoreObjectField(holder, JSObject::kMapOffset, transition); |
| 6119 } |
6103 Return(value); | 6120 Return(value); |
6104 } | 6121 } |
6105 | 6122 |
6106 Bind(&if_out_of_object); | 6123 Bind(&if_out_of_object); |
6107 { | 6124 { |
6108 StoreNamedField(holder, offset, false, representation, prepared_value, | 6125 StoreNamedField(holder, offset, false, representation, prepared_value, |
6109 transition_to_field); | 6126 transition_to_field); |
| 6127 if (transition_to_field) { |
| 6128 StoreObjectField(holder, JSObject::kMapOffset, transition); |
| 6129 } |
6110 Return(value); | 6130 Return(value); |
6111 } | 6131 } |
6112 } | 6132 } |
6113 | 6133 |
6114 void CodeStubAssembler::HandleStoreICSmiHandlerCase(Node* handler_word, | 6134 void CodeStubAssembler::HandleStoreICSmiHandlerCase(Node* handler_word, |
6115 Node* holder, Node* value, | 6135 Node* holder, Node* value, |
6116 bool transition_to_field, | 6136 Node* transition, |
6117 Label* miss) { | 6137 Label* miss) { |
6118 Comment(transition_to_field ? "transitioning field store" : "field store"); | 6138 Comment(transition ? "transitioning field store" : "field store"); |
| 6139 |
| 6140 #ifdef DEBUG |
| 6141 Node* handler_kind = DecodeWord<StoreHandler::KindBits>(handler_word); |
| 6142 if (transition) { |
| 6143 CSA_ASSERT( |
| 6144 this, |
| 6145 WordOr(WordEqual(handler_kind, |
| 6146 IntPtrConstant(StoreHandler::kTransitionToField)), |
| 6147 WordEqual(handler_kind, |
| 6148 IntPtrConstant(StoreHandler::kTransitionToConstant)))); |
| 6149 } else { |
| 6150 CSA_ASSERT(this, WordEqual(handler_kind, |
| 6151 IntPtrConstant(StoreHandler::kStoreField))); |
| 6152 } |
| 6153 #endif |
6119 | 6154 |
6120 Node* field_representation = | 6155 Node* field_representation = |
6121 DecodeWord<StoreHandler::FieldRepresentationBits>(handler_word); | 6156 DecodeWord<StoreHandler::FieldRepresentationBits>(handler_word); |
6122 | 6157 |
6123 Label if_smi_field(this), if_double_field(this), if_heap_object_field(this), | 6158 Label if_smi_field(this), if_double_field(this), if_heap_object_field(this), |
6124 if_tagged_field(this); | 6159 if_tagged_field(this); |
6125 | 6160 |
6126 GotoIf(WordEqual(field_representation, IntPtrConstant(StoreHandler::kTagged)), | 6161 GotoIf(WordEqual(field_representation, IntPtrConstant(StoreHandler::kTagged)), |
6127 &if_tagged_field); | 6162 &if_tagged_field); |
6128 GotoIf(WordEqual(field_representation, | 6163 GotoIf(WordEqual(field_representation, |
6129 IntPtrConstant(StoreHandler::kHeapObject)), | 6164 IntPtrConstant(StoreHandler::kHeapObject)), |
6130 &if_heap_object_field); | 6165 &if_heap_object_field); |
6131 GotoIf(WordEqual(field_representation, IntPtrConstant(StoreHandler::kDouble)), | 6166 GotoIf(WordEqual(field_representation, IntPtrConstant(StoreHandler::kDouble)), |
6132 &if_double_field); | 6167 &if_double_field); |
6133 CSA_ASSERT(this, WordEqual(field_representation, | 6168 CSA_ASSERT(this, WordEqual(field_representation, |
6134 IntPtrConstant(StoreHandler::kSmi))); | 6169 IntPtrConstant(StoreHandler::kSmi))); |
6135 Goto(&if_smi_field); | 6170 Goto(&if_smi_field); |
6136 | 6171 |
6137 Bind(&if_tagged_field); | 6172 Bind(&if_tagged_field); |
6138 { | 6173 { |
6139 Comment("store tagged field"); | 6174 Comment("store tagged field"); |
6140 HandleStoreFieldAndReturn(handler_word, holder, Representation::Tagged(), | 6175 HandleStoreFieldAndReturn(handler_word, holder, Representation::Tagged(), |
6141 value, transition_to_field, miss); | 6176 value, transition, miss); |
6142 } | 6177 } |
6143 | 6178 |
6144 Bind(&if_double_field); | 6179 Bind(&if_double_field); |
6145 { | 6180 { |
6146 Comment("store double field"); | 6181 Comment("store double field"); |
6147 HandleStoreFieldAndReturn(handler_word, holder, Representation::Double(), | 6182 HandleStoreFieldAndReturn(handler_word, holder, Representation::Double(), |
6148 value, transition_to_field, miss); | 6183 value, transition, miss); |
6149 } | 6184 } |
6150 | 6185 |
6151 Bind(&if_heap_object_field); | 6186 Bind(&if_heap_object_field); |
6152 { | 6187 { |
6153 Comment("store heap object field"); | 6188 Comment("store heap object field"); |
6154 // Generate full field type check here and then store value as Tagged. | 6189 // Generate full field type check here and then store value as Tagged. |
6155 Node* prepared_value = | 6190 Node* prepared_value = |
6156 PrepareValueForWrite(value, Representation::HeapObject(), miss); | 6191 PrepareValueForWrite(value, Representation::HeapObject(), miss); |
6157 Node* value_index_in_descriptor = | 6192 Node* value_index_in_descriptor = |
6158 DecodeWord<StoreHandler::DescriptorValueIndexBits>(handler_word); | 6193 DecodeWord<StoreHandler::DescriptorValueIndexBits>(handler_word); |
6159 Node* descriptors = LoadMapDescriptors(LoadMap(holder)); | 6194 Node* descriptors = |
| 6195 LoadMapDescriptors(transition ? transition : LoadMap(holder)); |
6160 Node* maybe_field_type = LoadFixedArrayElement( | 6196 Node* maybe_field_type = LoadFixedArrayElement( |
6161 descriptors, value_index_in_descriptor, 0, INTPTR_PARAMETERS); | 6197 descriptors, value_index_in_descriptor, 0, INTPTR_PARAMETERS); |
6162 Label do_store(this); | 6198 Label do_store(this); |
6163 GotoIf(TaggedIsSmi(maybe_field_type), &do_store); | 6199 GotoIf(TaggedIsSmi(maybe_field_type), &do_store); |
6164 // Check that value type matches the field type. | 6200 // Check that value type matches the field type. |
6165 { | 6201 { |
6166 Node* field_type = LoadWeakCellValue(maybe_field_type, miss); | 6202 Node* field_type = LoadWeakCellValue(maybe_field_type, miss); |
6167 Branch(WordEqual(LoadMap(prepared_value), field_type), &do_store, miss); | 6203 Branch(WordEqual(LoadMap(prepared_value), field_type), &do_store, miss); |
6168 } | 6204 } |
6169 Bind(&do_store); | 6205 Bind(&do_store); |
6170 HandleStoreFieldAndReturn(handler_word, holder, Representation::Tagged(), | 6206 HandleStoreFieldAndReturn(handler_word, holder, Representation::Tagged(), |
6171 prepared_value, transition_to_field, miss); | 6207 prepared_value, transition, miss); |
6172 } | 6208 } |
6173 | 6209 |
6174 Bind(&if_smi_field); | 6210 Bind(&if_smi_field); |
6175 { | 6211 { |
6176 Comment("store smi field"); | 6212 Comment("store smi field"); |
6177 HandleStoreFieldAndReturn(handler_word, holder, Representation::Smi(), | 6213 HandleStoreFieldAndReturn(handler_word, holder, Representation::Smi(), |
6178 value, transition_to_field, miss); | 6214 value, transition, miss); |
6179 } | 6215 } |
6180 } | 6216 } |
6181 | 6217 |
6182 void CodeStubAssembler::HandleStoreICHandlerCase(const StoreICParameters* p, | 6218 void CodeStubAssembler::HandleStoreICHandlerCase(const StoreICParameters* p, |
6183 Node* handler, Label* miss) { | 6219 Node* handler, Label* miss) { |
6184 Label if_smi_handler(this), call_handler(this); | 6220 Label if_smi_handler(this); |
| 6221 Label try_proto_handler(this), call_handler(this); |
6185 | 6222 |
6186 Branch(TaggedIsSmi(handler), &if_smi_handler, &call_handler); | 6223 Branch(TaggedIsSmi(handler), &if_smi_handler, &try_proto_handler); |
6187 | 6224 |
6188 // |handler| is a Smi, encoding what to do. See SmiHandler methods | 6225 // |handler| is a Smi, encoding what to do. See SmiHandler methods |
6189 // for the encoding format. | 6226 // for the encoding format. |
6190 Bind(&if_smi_handler); | 6227 Bind(&if_smi_handler); |
6191 { | 6228 { |
6192 Node* holder = p->receiver; | 6229 Node* holder = p->receiver; |
6193 Node* handler_word = SmiUntag(handler); | 6230 Node* handler_word = SmiUntag(handler); |
6194 | 6231 |
6195 // Handle non-transitioning stores. | 6232 // Handle non-transitioning field stores. |
6196 HandleStoreICSmiHandlerCase(handler_word, holder, p->value, false, miss); | 6233 HandleStoreICSmiHandlerCase(handler_word, holder, p->value, nullptr, miss); |
| 6234 } |
| 6235 |
| 6236 Bind(&try_proto_handler); |
| 6237 { |
| 6238 GotoIf(IsCodeMap(LoadMap(handler)), &call_handler); |
| 6239 HandleStoreICProtoHandler(p, handler, miss); |
6197 } | 6240 } |
6198 | 6241 |
6199 // |handler| is a heap object. Must be code, call it. | 6242 // |handler| is a heap object. Must be code, call it. |
6200 Bind(&call_handler); | 6243 Bind(&call_handler); |
6201 { | 6244 { |
6202 StoreWithVectorDescriptor descriptor(isolate()); | 6245 StoreWithVectorDescriptor descriptor(isolate()); |
6203 TailCallStub(descriptor, handler, p->context, p->receiver, p->name, | 6246 TailCallStub(descriptor, handler, p->context, p->receiver, p->name, |
6204 p->value, p->slot, p->vector); | 6247 p->value, p->slot, p->vector); |
6205 } | 6248 } |
6206 } | 6249 } |
6207 | 6250 |
| 6251 void CodeStubAssembler::HandleStoreICProtoHandler(const StoreICParameters* p, |
| 6252 Node* handler, Label* miss) { |
| 6253 // IC dispatchers rely on these assumptions to be held. |
| 6254 STATIC_ASSERT(FixedArray::kLengthOffset == |
| 6255 StoreHandler::kTransitionCellOffset); |
| 6256 DCHECK_EQ(FixedArray::OffsetOfElementAt(StoreHandler::kSmiHandlerIndex), |
| 6257 StoreHandler::kSmiHandlerOffset); |
| 6258 DCHECK_EQ(FixedArray::OffsetOfElementAt(StoreHandler::kValidityCellIndex), |
| 6259 StoreHandler::kValidityCellOffset); |
| 6260 |
| 6261 // Both FixedArray and Tuple3 handlers have validity cell at the same offset. |
| 6262 Label validity_cell_check_done(this); |
| 6263 Node* validity_cell = |
| 6264 LoadObjectField(handler, StoreHandler::kValidityCellOffset); |
| 6265 GotoIf(WordEqual(validity_cell, IntPtrConstant(0)), |
| 6266 &validity_cell_check_done); |
| 6267 Node* cell_value = LoadObjectField(validity_cell, Cell::kValueOffset); |
| 6268 GotoIf(WordNotEqual(cell_value, |
| 6269 SmiConstant(Smi::FromInt(Map::kPrototypeChainValid))), |
| 6270 miss); |
| 6271 Goto(&validity_cell_check_done); |
| 6272 |
| 6273 Bind(&validity_cell_check_done); |
| 6274 Node* smi_handler = LoadObjectField(handler, StoreHandler::kSmiHandlerOffset); |
| 6275 CSA_ASSERT(this, TaggedIsSmi(smi_handler)); |
| 6276 |
| 6277 Node* maybe_transition_cell = |
| 6278 LoadObjectField(handler, StoreHandler::kTransitionCellOffset); |
| 6279 Label array_handler(this), tuple_handler(this); |
| 6280 Branch(TaggedIsSmi(maybe_transition_cell), &array_handler, &tuple_handler); |
| 6281 |
| 6282 Variable var_transition(this, MachineRepresentation::kTagged); |
| 6283 Label if_transition(this), if_transition_to_constant(this); |
| 6284 Bind(&tuple_handler); |
| 6285 { |
| 6286 Node* transition = LoadWeakCellValue(maybe_transition_cell, miss); |
| 6287 var_transition.Bind(transition); |
| 6288 Goto(&if_transition); |
| 6289 } |
| 6290 |
| 6291 Bind(&array_handler); |
| 6292 { |
| 6293 Node* length = SmiUntag(maybe_transition_cell); |
| 6294 BuildFastLoop(MachineType::PointerRepresentation(), |
| 6295 IntPtrConstant(StoreHandler::kFirstPrototypeIndex), length, |
| 6296 [this, p, handler, miss](CodeStubAssembler*, Node* current) { |
| 6297 Node* prototype_cell = LoadFixedArrayElement( |
| 6298 handler, current, 0, INTPTR_PARAMETERS); |
| 6299 CheckPrototype(prototype_cell, p->name, miss); |
| 6300 }, |
| 6301 1, IndexAdvanceMode::kPost); |
| 6302 |
| 6303 Node* maybe_transition_cell = LoadFixedArrayElement( |
| 6304 handler, IntPtrConstant(StoreHandler::kTransitionCellIndex), 0, |
| 6305 INTPTR_PARAMETERS); |
| 6306 Node* transition = LoadWeakCellValue(maybe_transition_cell, miss); |
| 6307 var_transition.Bind(transition); |
| 6308 Goto(&if_transition); |
| 6309 } |
| 6310 |
| 6311 Bind(&if_transition); |
| 6312 { |
| 6313 Node* holder = p->receiver; |
| 6314 Node* transition = var_transition.value(); |
| 6315 Node* handler_word = SmiUntag(smi_handler); |
| 6316 |
| 6317 GotoIf(IsSetWord32<Map::Deprecated>(LoadMapBitField3(transition)), miss); |
| 6318 |
| 6319 Node* handler_kind = DecodeWord<StoreHandler::KindBits>(handler_word); |
| 6320 GotoIf(WordEqual(handler_kind, |
| 6321 IntPtrConstant(StoreHandler::kTransitionToConstant)), |
| 6322 &if_transition_to_constant); |
| 6323 |
| 6324 // Handle transitioning field stores. |
| 6325 HandleStoreICSmiHandlerCase(handler_word, holder, p->value, transition, |
| 6326 miss); |
| 6327 |
| 6328 Bind(&if_transition_to_constant); |
| 6329 { |
| 6330 // Check that constant matches value. |
| 6331 Node* value_index_in_descriptor = |
| 6332 DecodeWord<StoreHandler::DescriptorValueIndexBits>(handler_word); |
| 6333 Node* descriptors = LoadMapDescriptors(transition); |
| 6334 Node* constant = LoadFixedArrayElement( |
| 6335 descriptors, value_index_in_descriptor, 0, INTPTR_PARAMETERS); |
| 6336 GotoIf(WordNotEqual(p->value, constant), miss); |
| 6337 |
| 6338 StoreObjectField(p->receiver, JSObject::kMapOffset, transition); |
| 6339 Return(p->value); |
| 6340 } |
| 6341 } |
| 6342 } |
| 6343 |
6208 void CodeStubAssembler::StoreIC(const StoreICParameters* p) { | 6344 void CodeStubAssembler::StoreIC(const StoreICParameters* p) { |
6209 Variable var_handler(this, MachineRepresentation::kTagged); | 6345 Variable var_handler(this, MachineRepresentation::kTagged); |
6210 // TODO(ishell): defer blocks when it works. | 6346 // TODO(ishell): defer blocks when it works. |
6211 Label if_handler(this, &var_handler), try_polymorphic(this), | 6347 Label if_handler(this, &var_handler), try_polymorphic(this), |
6212 try_megamorphic(this /*, Label::kDeferred*/), | 6348 try_megamorphic(this /*, Label::kDeferred*/), |
6213 miss(this /*, Label::kDeferred*/); | 6349 miss(this /*, Label::kDeferred*/); |
6214 | 6350 |
6215 Node* receiver_map = LoadReceiverMap(p->receiver); | 6351 Node* receiver_map = LoadReceiverMap(p->receiver); |
6216 | 6352 |
6217 // Check monomorphic case. | 6353 // Check monomorphic case. |
(...skipping 2692 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
8910 } | 9046 } |
8911 | 9047 |
8912 void CodeStubArguments::PopAndReturn(compiler::Node* value) { | 9048 void CodeStubArguments::PopAndReturn(compiler::Node* value) { |
8913 assembler_->PopAndReturn( | 9049 assembler_->PopAndReturn( |
8914 assembler_->IntPtrAddFoldConstants(argc_, assembler_->IntPtrConstant(1)), | 9050 assembler_->IntPtrAddFoldConstants(argc_, assembler_->IntPtrConstant(1)), |
8915 value); | 9051 value); |
8916 } | 9052 } |
8917 | 9053 |
8918 } // namespace internal | 9054 } // namespace internal |
8919 } // namespace v8 | 9055 } // namespace v8 |
OLD | NEW |