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 5581 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5592 CSA_ASSERT(UintPtrLessThan( | 5592 CSA_ASSERT(UintPtrLessThan( |
5593 descriptor, LoadAndUntagFixedArrayBaseLength(descriptors))); | 5593 descriptor, LoadAndUntagFixedArrayBaseLength(descriptors))); |
5594 #endif | 5594 #endif |
5595 Return( | 5595 Return( |
5596 LoadFixedArrayElement(descriptors, descriptor, 0, INTPTR_PARAMETERS)); | 5596 LoadFixedArrayElement(descriptors, descriptor, 0, INTPTR_PARAMETERS)); |
5597 } | 5597 } |
5598 } | 5598 } |
5599 | 5599 |
5600 Bind(&try_proto_handler); | 5600 Bind(&try_proto_handler); |
5601 { | 5601 { |
5602 GotoIf(WordEqual(LoadMap(handler), LoadRoot(Heap::kCodeMapRootIndex)), | 5602 GotoIf(IsCodeMap(LoadMap(handler)), &call_handler); |
5603 &call_handler); | |
5604 HandleLoadICProtoHandler(p, handler, &var_holder, &var_smi_handler, | 5603 HandleLoadICProtoHandler(p, handler, &var_holder, &var_smi_handler, |
5605 &if_smi_handler, miss); | 5604 &if_smi_handler, miss); |
5606 } | 5605 } |
5607 | 5606 |
5608 Bind(&call_handler); | 5607 Bind(&call_handler); |
5609 { | 5608 { |
5610 typedef LoadWithVectorDescriptor Descriptor; | 5609 typedef LoadWithVectorDescriptor Descriptor; |
5611 TailCallStub(Descriptor(isolate()), handler, p->context, | 5610 TailCallStub(Descriptor(isolate()), handler, p->context, |
5612 Arg(Descriptor::kReceiver, p->receiver), | 5611 Arg(Descriptor::kReceiver, p->receiver), |
5613 Arg(Descriptor::kName, p->name), | 5612 Arg(Descriptor::kName, p->name), |
(...skipping 395 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6009 Bind(&slow); | 6008 Bind(&slow); |
6010 { | 6009 { |
6011 Comment("KeyedLoadGeneric_slow"); | 6010 Comment("KeyedLoadGeneric_slow"); |
6012 IncrementCounter(isolate()->counters()->ic_keyed_load_generic_slow(), 1); | 6011 IncrementCounter(isolate()->counters()->ic_keyed_load_generic_slow(), 1); |
6013 // TODO(jkummerow): Should we use the GetProperty TF stub instead? | 6012 // TODO(jkummerow): Should we use the GetProperty TF stub instead? |
6014 TailCallRuntime(Runtime::kKeyedGetProperty, p->context, p->receiver, | 6013 TailCallRuntime(Runtime::kKeyedGetProperty, p->context, p->receiver, |
6015 p->name); | 6014 p->name); |
6016 } | 6015 } |
6017 } | 6016 } |
6018 | 6017 |
6019 void CodeStubAssembler::HandleStoreFieldAndReturn( | 6018 void CodeStubAssembler::HandleStoreFieldAndReturn(Node* handler_word, |
6020 Node* handler_word, Node* holder, Representation representation, | 6019 Node* holder, |
6021 Node* value, bool transition_to_field, Label* miss) { | 6020 Representation representation, |
| 6021 Node* value, Node* transition, |
| 6022 Label* miss) { |
| 6023 bool transition_to_field = transition != nullptr; |
6022 Node* prepared_value = PrepareValueForWrite(value, representation, miss); | 6024 Node* prepared_value = PrepareValueForWrite(value, representation, miss); |
6023 | 6025 |
| 6026 if (transition_to_field) { |
| 6027 Label storage_extended(this); |
| 6028 GotoUnless(IsSetWord<StoreHandler::ExtendStorageBits>(handler_word), |
| 6029 &storage_extended); |
| 6030 Comment("[ Extend storage"); |
| 6031 ExtendPropertiesBackingStore(holder); |
| 6032 Comment("] Extend storage"); |
| 6033 Goto(&storage_extended); |
| 6034 |
| 6035 Bind(&storage_extended); |
| 6036 } |
| 6037 |
6024 Node* offset = DecodeWord<StoreHandler::FieldOffsetBits>(handler_word); | 6038 Node* offset = DecodeWord<StoreHandler::FieldOffsetBits>(handler_word); |
6025 Label if_inobject(this), if_out_of_object(this); | 6039 Label if_inobject(this), if_out_of_object(this); |
6026 Branch(IsSetWord<StoreHandler::IsInobjectBits>(handler_word), &if_inobject, | 6040 Branch(IsSetWord<StoreHandler::IsInobjectBits>(handler_word), &if_inobject, |
6027 &if_out_of_object); | 6041 &if_out_of_object); |
6028 | 6042 |
6029 Bind(&if_inobject); | 6043 Bind(&if_inobject); |
6030 { | 6044 { |
6031 StoreNamedField(holder, offset, true, representation, prepared_value, | 6045 StoreNamedField(holder, offset, true, representation, prepared_value, |
6032 transition_to_field); | 6046 transition_to_field); |
| 6047 if (transition_to_field) { |
| 6048 StoreObjectField(holder, JSObject::kMapOffset, transition); |
| 6049 } |
6033 Return(value); | 6050 Return(value); |
6034 } | 6051 } |
6035 | 6052 |
6036 Bind(&if_out_of_object); | 6053 Bind(&if_out_of_object); |
6037 { | 6054 { |
6038 StoreNamedField(holder, offset, false, representation, prepared_value, | 6055 StoreNamedField(holder, offset, false, representation, prepared_value, |
6039 transition_to_field); | 6056 transition_to_field); |
| 6057 if (transition_to_field) { |
| 6058 StoreObjectField(holder, JSObject::kMapOffset, transition); |
| 6059 } |
6040 Return(value); | 6060 Return(value); |
6041 } | 6061 } |
6042 } | 6062 } |
6043 | 6063 |
6044 void CodeStubAssembler::HandleStoreICSmiHandlerCase(Node* handler_word, | 6064 void CodeStubAssembler::HandleStoreICSmiHandlerCase(Node* handler_word, |
6045 Node* holder, Node* value, | 6065 Node* holder, Node* value, |
6046 bool transition_to_field, | 6066 Node* transition, |
6047 Label* miss) { | 6067 Label* miss) { |
6048 Comment(transition_to_field ? "transitioning field store" : "field store"); | 6068 Comment(transition ? "transitioning field store" : "field store"); |
| 6069 |
| 6070 #ifdef DEBUG |
| 6071 Node* handler_kind = DecodeWord<StoreHandler::KindBits>(handler_word); |
| 6072 if (transition) { |
| 6073 CSA_ASSERT( |
| 6074 WordOr(WordEqual(handler_kind, |
| 6075 IntPtrConstant(StoreHandler::kTransitionToField)), |
| 6076 WordEqual(handler_kind, |
| 6077 IntPtrConstant(StoreHandler::kTransitionToConstant)))); |
| 6078 } else { |
| 6079 CSA_ASSERT( |
| 6080 WordEqual(handler_kind, IntPtrConstant(StoreHandler::kStoreField))); |
| 6081 } |
| 6082 #endif |
6049 | 6083 |
6050 Node* field_representation = | 6084 Node* field_representation = |
6051 DecodeWord<StoreHandler::FieldRepresentationBits>(handler_word); | 6085 DecodeWord<StoreHandler::FieldRepresentationBits>(handler_word); |
6052 | 6086 |
6053 Label if_smi_field(this), if_double_field(this), if_heap_object_field(this), | 6087 Label if_smi_field(this), if_double_field(this), if_heap_object_field(this), |
6054 if_tagged_field(this); | 6088 if_tagged_field(this); |
6055 | 6089 |
6056 GotoIf(WordEqual(field_representation, IntPtrConstant(StoreHandler::kTagged)), | 6090 GotoIf(WordEqual(field_representation, IntPtrConstant(StoreHandler::kTagged)), |
6057 &if_tagged_field); | 6091 &if_tagged_field); |
6058 GotoIf(WordEqual(field_representation, | 6092 GotoIf(WordEqual(field_representation, |
6059 IntPtrConstant(StoreHandler::kHeapObject)), | 6093 IntPtrConstant(StoreHandler::kHeapObject)), |
6060 &if_heap_object_field); | 6094 &if_heap_object_field); |
6061 GotoIf(WordEqual(field_representation, IntPtrConstant(StoreHandler::kDouble)), | 6095 GotoIf(WordEqual(field_representation, IntPtrConstant(StoreHandler::kDouble)), |
6062 &if_double_field); | 6096 &if_double_field); |
6063 CSA_ASSERT( | 6097 CSA_ASSERT( |
6064 WordEqual(field_representation, IntPtrConstant(StoreHandler::kSmi))); | 6098 WordEqual(field_representation, IntPtrConstant(StoreHandler::kSmi))); |
6065 Goto(&if_smi_field); | 6099 Goto(&if_smi_field); |
6066 | 6100 |
6067 Bind(&if_tagged_field); | 6101 Bind(&if_tagged_field); |
6068 { | 6102 { |
6069 Comment("store tagged field"); | 6103 Comment("store tagged field"); |
6070 HandleStoreFieldAndReturn(handler_word, holder, Representation::Tagged(), | 6104 HandleStoreFieldAndReturn(handler_word, holder, Representation::Tagged(), |
6071 value, transition_to_field, miss); | 6105 value, transition, miss); |
6072 } | 6106 } |
6073 | 6107 |
6074 Bind(&if_double_field); | 6108 Bind(&if_double_field); |
6075 { | 6109 { |
6076 Comment("store double field"); | 6110 Comment("store double field"); |
6077 HandleStoreFieldAndReturn(handler_word, holder, Representation::Double(), | 6111 HandleStoreFieldAndReturn(handler_word, holder, Representation::Double(), |
6078 value, transition_to_field, miss); | 6112 value, transition, miss); |
6079 } | 6113 } |
6080 | 6114 |
6081 Bind(&if_heap_object_field); | 6115 Bind(&if_heap_object_field); |
6082 { | 6116 { |
6083 Comment("store heap object field"); | 6117 Comment("store heap object field"); |
6084 // Generate full field type check here and then store value as Tagged. | 6118 // Generate full field type check here and then store value as Tagged. |
6085 Node* prepared_value = | 6119 Node* prepared_value = |
6086 PrepareValueForWrite(value, Representation::HeapObject(), miss); | 6120 PrepareValueForWrite(value, Representation::HeapObject(), miss); |
6087 Node* value_index_in_descriptor = | 6121 Node* value_index_in_descriptor = |
6088 DecodeWord<StoreHandler::DescriptorValueIndexBits>(handler_word); | 6122 DecodeWord<StoreHandler::DescriptorValueIndexBits>(handler_word); |
6089 Node* descriptors = LoadMapDescriptors(LoadMap(holder)); | 6123 Node* descriptors = |
| 6124 LoadMapDescriptors(transition ? transition : LoadMap(holder)); |
6090 Node* maybe_field_type = LoadFixedArrayElement( | 6125 Node* maybe_field_type = LoadFixedArrayElement( |
6091 descriptors, value_index_in_descriptor, 0, INTPTR_PARAMETERS); | 6126 descriptors, value_index_in_descriptor, 0, INTPTR_PARAMETERS); |
6092 Label do_store(this); | 6127 Label do_store(this); |
6093 GotoIf(TaggedIsSmi(maybe_field_type), &do_store); | 6128 GotoIf(TaggedIsSmi(maybe_field_type), &do_store); |
6094 // Check that value type matches the field type. | 6129 // Check that value type matches the field type. |
6095 { | 6130 { |
6096 Node* field_type = LoadWeakCellValue(maybe_field_type, miss); | 6131 Node* field_type = LoadWeakCellValue(maybe_field_type, miss); |
6097 Branch(WordEqual(LoadMap(prepared_value), field_type), &do_store, miss); | 6132 Branch(WordEqual(LoadMap(prepared_value), field_type), &do_store, miss); |
6098 } | 6133 } |
6099 Bind(&do_store); | 6134 Bind(&do_store); |
6100 HandleStoreFieldAndReturn(handler_word, holder, Representation::Tagged(), | 6135 HandleStoreFieldAndReturn(handler_word, holder, Representation::Tagged(), |
6101 prepared_value, transition_to_field, miss); | 6136 prepared_value, transition, miss); |
6102 } | 6137 } |
6103 | 6138 |
6104 Bind(&if_smi_field); | 6139 Bind(&if_smi_field); |
6105 { | 6140 { |
6106 Comment("store smi field"); | 6141 Comment("store smi field"); |
6107 HandleStoreFieldAndReturn(handler_word, holder, Representation::Smi(), | 6142 HandleStoreFieldAndReturn(handler_word, holder, Representation::Smi(), |
6108 value, transition_to_field, miss); | 6143 value, transition, miss); |
6109 } | 6144 } |
6110 } | 6145 } |
6111 | 6146 |
6112 void CodeStubAssembler::HandleStoreICHandlerCase(const StoreICParameters* p, | 6147 void CodeStubAssembler::HandleStoreICHandlerCase(const StoreICParameters* p, |
6113 Node* handler, Label* miss) { | 6148 Node* handler, Label* miss) { |
6114 Label if_smi_handler(this), call_handler(this); | 6149 Label if_smi_handler(this); |
| 6150 Label try_proto_handler(this), call_handler(this); |
6115 | 6151 |
6116 Branch(TaggedIsSmi(handler), &if_smi_handler, &call_handler); | 6152 Branch(TaggedIsSmi(handler), &if_smi_handler, &try_proto_handler); |
6117 | 6153 |
6118 // |handler| is a Smi, encoding what to do. See SmiHandler methods | 6154 // |handler| is a Smi, encoding what to do. See SmiHandler methods |
6119 // for the encoding format. | 6155 // for the encoding format. |
6120 Bind(&if_smi_handler); | 6156 Bind(&if_smi_handler); |
6121 { | 6157 { |
6122 Node* holder = p->receiver; | 6158 Node* holder = p->receiver; |
6123 Node* handler_word = SmiUntag(handler); | 6159 Node* handler_word = SmiUntag(handler); |
6124 | 6160 |
6125 // Handle non-transitioning stores. | 6161 // Handle non-transitioning field stores. |
6126 HandleStoreICSmiHandlerCase(handler_word, holder, p->value, false, miss); | 6162 HandleStoreICSmiHandlerCase(handler_word, holder, p->value, nullptr, miss); |
| 6163 } |
| 6164 |
| 6165 Bind(&try_proto_handler); |
| 6166 { |
| 6167 GotoIf(IsCodeMap(LoadMap(handler)), &call_handler); |
| 6168 HandleStoreICProtoHandler(p, handler, miss); |
6127 } | 6169 } |
6128 | 6170 |
6129 // |handler| is a heap object. Must be code, call it. | 6171 // |handler| is a heap object. Must be code, call it. |
6130 Bind(&call_handler); | 6172 Bind(&call_handler); |
6131 { | 6173 { |
6132 StoreWithVectorDescriptor descriptor(isolate()); | 6174 StoreWithVectorDescriptor descriptor(isolate()); |
6133 TailCallStub(descriptor, handler, p->context, p->receiver, p->name, | 6175 TailCallStub(descriptor, handler, p->context, p->receiver, p->name, |
6134 p->value, p->slot, p->vector); | 6176 p->value, p->slot, p->vector); |
6135 } | 6177 } |
6136 } | 6178 } |
6137 | 6179 |
| 6180 void CodeStubAssembler::HandleStoreICProtoHandler(const StoreICParameters* p, |
| 6181 Node* handler, Label* miss) { |
| 6182 // IC dispatchers rely on these assumptions to be held. |
| 6183 STATIC_ASSERT(FixedArray::kLengthOffset == |
| 6184 StoreHandler::kTransitionCellOffset); |
| 6185 DCHECK_EQ(FixedArray::OffsetOfElementAt(StoreHandler::kSmiHandlerIndex), |
| 6186 StoreHandler::kSmiHandlerOffset); |
| 6187 DCHECK_EQ(FixedArray::OffsetOfElementAt(StoreHandler::kValidityCellIndex), |
| 6188 StoreHandler::kValidityCellOffset); |
| 6189 |
| 6190 // Both FixedArray and Tuple3 handlers have validity cell at the same offset. |
| 6191 Label validity_cell_check_done(this); |
| 6192 Node* validity_cell = |
| 6193 LoadObjectField(handler, StoreHandler::kValidityCellOffset); |
| 6194 GotoIf(WordEqual(validity_cell, IntPtrConstant(0)), |
| 6195 &validity_cell_check_done); |
| 6196 Node* cell_value = LoadObjectField(validity_cell, Cell::kValueOffset); |
| 6197 GotoIf(WordNotEqual(cell_value, |
| 6198 SmiConstant(Smi::FromInt(Map::kPrototypeChainValid))), |
| 6199 miss); |
| 6200 Goto(&validity_cell_check_done); |
| 6201 |
| 6202 Bind(&validity_cell_check_done); |
| 6203 Node* smi_handler = LoadObjectField(handler, StoreHandler::kSmiHandlerOffset); |
| 6204 CSA_ASSERT(TaggedIsSmi(smi_handler)); |
| 6205 |
| 6206 Node* maybe_transition_cell = |
| 6207 LoadObjectField(handler, StoreHandler::kTransitionCellOffset); |
| 6208 Label array_handler(this), tuple_handler(this); |
| 6209 Branch(TaggedIsSmi(maybe_transition_cell), &array_handler, &tuple_handler); |
| 6210 |
| 6211 Variable var_transition(this, MachineRepresentation::kTagged); |
| 6212 Label if_transition(this), if_transition_to_constant(this); |
| 6213 Bind(&tuple_handler); |
| 6214 { |
| 6215 Node* transition = LoadWeakCellValue(maybe_transition_cell, miss); |
| 6216 var_transition.Bind(transition); |
| 6217 Goto(&if_transition); |
| 6218 } |
| 6219 |
| 6220 Bind(&array_handler); |
| 6221 { |
| 6222 Node* length = SmiUntag(maybe_transition_cell); |
| 6223 BuildFastLoop(MachineType::PointerRepresentation(), |
| 6224 IntPtrConstant(StoreHandler::kFirstPrototypeIndex), length, |
| 6225 [this, p, handler, miss](CodeStubAssembler*, Node* current) { |
| 6226 Node* prototype_cell = LoadFixedArrayElement( |
| 6227 handler, current, 0, INTPTR_PARAMETERS); |
| 6228 CheckPrototype(prototype_cell, p->name, miss); |
| 6229 }, |
| 6230 1, IndexAdvanceMode::kPost); |
| 6231 |
| 6232 Node* maybe_transition_cell = LoadFixedArrayElement( |
| 6233 handler, IntPtrConstant(StoreHandler::kTransitionCellIndex), 0, |
| 6234 INTPTR_PARAMETERS); |
| 6235 Node* transition = LoadWeakCellValue(maybe_transition_cell, miss); |
| 6236 var_transition.Bind(transition); |
| 6237 Goto(&if_transition); |
| 6238 } |
| 6239 |
| 6240 Bind(&if_transition); |
| 6241 { |
| 6242 Node* holder = p->receiver; |
| 6243 Node* transition = var_transition.value(); |
| 6244 Node* handler_word = SmiUntag(smi_handler); |
| 6245 |
| 6246 GotoIf(IsSetWord32<Map::Deprecated>(LoadMapBitField3(transition)), miss); |
| 6247 |
| 6248 Node* handler_kind = DecodeWord<StoreHandler::KindBits>(handler_word); |
| 6249 GotoIf(WordEqual(handler_kind, |
| 6250 IntPtrConstant(StoreHandler::kTransitionToConstant)), |
| 6251 &if_transition_to_constant); |
| 6252 |
| 6253 // Handle transitioning field stores. |
| 6254 HandleStoreICSmiHandlerCase(handler_word, holder, p->value, transition, |
| 6255 miss); |
| 6256 |
| 6257 Bind(&if_transition_to_constant); |
| 6258 { |
| 6259 // Check that constant matches value. |
| 6260 Node* value_index_in_descriptor = |
| 6261 DecodeWord<StoreHandler::DescriptorValueIndexBits>(handler_word); |
| 6262 Node* descriptors = LoadMapDescriptors(transition); |
| 6263 Node* constant = LoadFixedArrayElement( |
| 6264 descriptors, value_index_in_descriptor, 0, INTPTR_PARAMETERS); |
| 6265 GotoIf(WordNotEqual(p->value, constant), miss); |
| 6266 |
| 6267 StoreObjectField(p->receiver, JSObject::kMapOffset, transition); |
| 6268 Return(p->value); |
| 6269 } |
| 6270 } |
| 6271 } |
| 6272 |
6138 void CodeStubAssembler::StoreIC(const StoreICParameters* p) { | 6273 void CodeStubAssembler::StoreIC(const StoreICParameters* p) { |
6139 Variable var_handler(this, MachineRepresentation::kTagged); | 6274 Variable var_handler(this, MachineRepresentation::kTagged); |
6140 // TODO(ishell): defer blocks when it works. | 6275 // TODO(ishell): defer blocks when it works. |
6141 Label if_handler(this, &var_handler), try_polymorphic(this), | 6276 Label if_handler(this, &var_handler), try_polymorphic(this), |
6142 try_megamorphic(this /*, Label::kDeferred*/), | 6277 try_megamorphic(this /*, Label::kDeferred*/), |
6143 miss(this /*, Label::kDeferred*/); | 6278 miss(this /*, Label::kDeferred*/); |
6144 | 6279 |
6145 Node* receiver_map = LoadReceiverMap(p->receiver); | 6280 Node* receiver_map = LoadReceiverMap(p->receiver); |
6146 | 6281 |
6147 // Check monomorphic case. | 6282 // Check monomorphic case. |
(...skipping 2689 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
8837 } | 8972 } |
8838 | 8973 |
8839 void CodeStubArguments::PopAndReturn(compiler::Node* value) { | 8974 void CodeStubArguments::PopAndReturn(compiler::Node* value) { |
8840 assembler_->PopAndReturn( | 8975 assembler_->PopAndReturn( |
8841 assembler_->IntPtrAddFoldConstants(argc_, assembler_->IntPtrConstant(1)), | 8976 assembler_->IntPtrAddFoldConstants(argc_, assembler_->IntPtrConstant(1)), |
8842 value); | 8977 value); |
8843 } | 8978 } |
8844 | 8979 |
8845 } // namespace internal | 8980 } // namespace internal |
8846 } // namespace v8 | 8981 } // namespace v8 |
OLD | NEW |