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