• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2015 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include <ostream>
6 
7 #include "src/accessors.h"
8 #include "src/compilation-dependencies.h"
9 #include "src/compiler/access-info.h"
10 #include "src/compiler/type-cache.h"
11 #include "src/field-index-inl.h"
12 #include "src/field-type.h"
13 #include "src/ic/call-optimization.h"
14 #include "src/objects-inl.h"
15 
16 namespace v8 {
17 namespace internal {
18 namespace compiler {
19 
20 namespace {
21 
CanInlineElementAccess(Handle<Map> map)22 bool CanInlineElementAccess(Handle<Map> map) {
23   if (!map->IsJSObjectMap()) return false;
24   if (map->is_access_check_needed()) return false;
25   if (map->has_indexed_interceptor()) return false;
26   ElementsKind const elements_kind = map->elements_kind();
27   if (IsFastElementsKind(elements_kind)) return true;
28   if (IsFixedTypedArrayElementsKind(elements_kind)) return true;
29   return false;
30 }
31 
32 
CanInlinePropertyAccess(Handle<Map> map)33 bool CanInlinePropertyAccess(Handle<Map> map) {
34   // We can inline property access to prototypes of all primitives, except
35   // the special Oddball ones that have no wrapper counterparts (i.e. Null,
36   // Undefined and TheHole).
37   STATIC_ASSERT(ODDBALL_TYPE == LAST_PRIMITIVE_TYPE);
38   if (map->IsBooleanMap()) return true;
39   if (map->instance_type() < LAST_PRIMITIVE_TYPE) return true;
40   return map->IsJSObjectMap() && !map->is_dictionary_map() &&
41          !map->has_named_interceptor() &&
42          // TODO(verwaest): Whitelist contexts to which we have access.
43          !map->is_access_check_needed();
44 }
45 
46 }  // namespace
47 
48 
operator <<(std::ostream & os,AccessMode access_mode)49 std::ostream& operator<<(std::ostream& os, AccessMode access_mode) {
50   switch (access_mode) {
51     case AccessMode::kLoad:
52       return os << "Load";
53     case AccessMode::kStore:
54       return os << "Store";
55     case AccessMode::kStoreInLiteral:
56       return os << "StoreInLiteral";
57   }
58   UNREACHABLE();
59   return os;
60 }
61 
ElementAccessInfo()62 ElementAccessInfo::ElementAccessInfo() {}
63 
ElementAccessInfo(MapList const & receiver_maps,ElementsKind elements_kind)64 ElementAccessInfo::ElementAccessInfo(MapList const& receiver_maps,
65                                      ElementsKind elements_kind)
66     : elements_kind_(elements_kind), receiver_maps_(receiver_maps) {}
67 
68 // static
NotFound(MapList const & receiver_maps,MaybeHandle<JSObject> holder)69 PropertyAccessInfo PropertyAccessInfo::NotFound(MapList const& receiver_maps,
70                                                 MaybeHandle<JSObject> holder) {
71   return PropertyAccessInfo(holder, receiver_maps);
72 }
73 
74 // static
DataConstant(MapList const & receiver_maps,Handle<Object> constant,MaybeHandle<JSObject> holder)75 PropertyAccessInfo PropertyAccessInfo::DataConstant(
76     MapList const& receiver_maps, Handle<Object> constant,
77     MaybeHandle<JSObject> holder) {
78   return PropertyAccessInfo(kDataConstant, holder, constant, receiver_maps);
79 }
80 
81 // static
DataField(PropertyConstness constness,MapList const & receiver_maps,FieldIndex field_index,MachineRepresentation field_representation,Type * field_type,MaybeHandle<Map> field_map,MaybeHandle<JSObject> holder,MaybeHandle<Map> transition_map)82 PropertyAccessInfo PropertyAccessInfo::DataField(
83     PropertyConstness constness, MapList const& receiver_maps,
84     FieldIndex field_index, MachineRepresentation field_representation,
85     Type* field_type, MaybeHandle<Map> field_map, MaybeHandle<JSObject> holder,
86     MaybeHandle<Map> transition_map) {
87   Kind kind = constness == kConst ? kDataConstantField : kDataField;
88   return PropertyAccessInfo(kind, holder, transition_map, field_index,
89                             field_representation, field_type, field_map,
90                             receiver_maps);
91 }
92 
93 // static
AccessorConstant(MapList const & receiver_maps,Handle<Object> constant,MaybeHandle<JSObject> holder)94 PropertyAccessInfo PropertyAccessInfo::AccessorConstant(
95     MapList const& receiver_maps, Handle<Object> constant,
96     MaybeHandle<JSObject> holder) {
97   return PropertyAccessInfo(kAccessorConstant, holder, constant, receiver_maps);
98 }
99 
100 // static
Generic(MapList const & receiver_maps)101 PropertyAccessInfo PropertyAccessInfo::Generic(MapList const& receiver_maps) {
102   return PropertyAccessInfo(kGeneric, MaybeHandle<JSObject>(), Handle<Object>(),
103                             receiver_maps);
104 }
105 
PropertyAccessInfo()106 PropertyAccessInfo::PropertyAccessInfo()
107     : kind_(kInvalid),
108       field_representation_(MachineRepresentation::kNone),
109       field_type_(Type::None()) {}
110 
PropertyAccessInfo(MaybeHandle<JSObject> holder,MapList const & receiver_maps)111 PropertyAccessInfo::PropertyAccessInfo(MaybeHandle<JSObject> holder,
112                                        MapList const& receiver_maps)
113     : kind_(kNotFound),
114       receiver_maps_(receiver_maps),
115       holder_(holder),
116       field_representation_(MachineRepresentation::kNone),
117       field_type_(Type::None()) {}
118 
PropertyAccessInfo(Kind kind,MaybeHandle<JSObject> holder,Handle<Object> constant,MapList const & receiver_maps)119 PropertyAccessInfo::PropertyAccessInfo(Kind kind, MaybeHandle<JSObject> holder,
120                                        Handle<Object> constant,
121                                        MapList const& receiver_maps)
122     : kind_(kind),
123       receiver_maps_(receiver_maps),
124       constant_(constant),
125       holder_(holder),
126       field_representation_(MachineRepresentation::kNone),
127       field_type_(Type::Any()) {}
128 
PropertyAccessInfo(Kind kind,MaybeHandle<JSObject> holder,MaybeHandle<Map> transition_map,FieldIndex field_index,MachineRepresentation field_representation,Type * field_type,MaybeHandle<Map> field_map,MapList const & receiver_maps)129 PropertyAccessInfo::PropertyAccessInfo(
130     Kind kind, MaybeHandle<JSObject> holder, MaybeHandle<Map> transition_map,
131     FieldIndex field_index, MachineRepresentation field_representation,
132     Type* field_type, MaybeHandle<Map> field_map, MapList const& receiver_maps)
133     : kind_(kind),
134       receiver_maps_(receiver_maps),
135       transition_map_(transition_map),
136       holder_(holder),
137       field_index_(field_index),
138       field_representation_(field_representation),
139       field_type_(field_type),
140       field_map_(field_map) {}
141 
Merge(PropertyAccessInfo const * that)142 bool PropertyAccessInfo::Merge(PropertyAccessInfo const* that) {
143   if (this->kind_ != that->kind_) return false;
144   if (this->holder_.address() != that->holder_.address()) return false;
145 
146   switch (this->kind_) {
147     case kInvalid:
148       break;
149 
150     case kDataField:
151     case kDataConstantField: {
152       // Check if we actually access the same field.
153       if (this->kind_ == that->kind_ &&
154           this->transition_map_.address() == that->transition_map_.address() &&
155           this->field_index_ == that->field_index_ &&
156           this->field_map_.address() == that->field_map_.address() &&
157           this->field_type_->Is(that->field_type_) &&
158           that->field_type_->Is(this->field_type_) &&
159           this->field_representation_ == that->field_representation_) {
160         this->receiver_maps_.insert(this->receiver_maps_.end(),
161                                     that->receiver_maps_.begin(),
162                                     that->receiver_maps_.end());
163         return true;
164       }
165       return false;
166     }
167 
168     case kDataConstant:
169     case kAccessorConstant: {
170       // Check if we actually access the same constant.
171       if (this->constant_.address() == that->constant_.address()) {
172         this->receiver_maps_.insert(this->receiver_maps_.end(),
173                                     that->receiver_maps_.begin(),
174                                     that->receiver_maps_.end());
175         return true;
176       }
177       return false;
178     }
179 
180     case kNotFound:
181     case kGeneric: {
182       this->receiver_maps_.insert(this->receiver_maps_.end(),
183                                   that->receiver_maps_.begin(),
184                                   that->receiver_maps_.end());
185       return true;
186     }
187   }
188 
189   UNREACHABLE();
190   return false;
191 }
192 
AccessInfoFactory(CompilationDependencies * dependencies,Handle<Context> native_context,Zone * zone)193 AccessInfoFactory::AccessInfoFactory(CompilationDependencies* dependencies,
194                                      Handle<Context> native_context, Zone* zone)
195     : dependencies_(dependencies),
196       native_context_(native_context),
197       isolate_(native_context->GetIsolate()),
198       type_cache_(TypeCache::Get()),
199       zone_(zone) {
200   DCHECK(native_context->IsNativeContext());
201 }
202 
203 
ComputeElementAccessInfo(Handle<Map> map,AccessMode access_mode,ElementAccessInfo * access_info)204 bool AccessInfoFactory::ComputeElementAccessInfo(
205     Handle<Map> map, AccessMode access_mode, ElementAccessInfo* access_info) {
206   // Check if it is safe to inline element access for the {map}.
207   if (!CanInlineElementAccess(map)) return false;
208   ElementsKind const elements_kind = map->elements_kind();
209   *access_info = ElementAccessInfo(MapList{map}, elements_kind);
210   return true;
211 }
212 
213 
ComputeElementAccessInfos(MapHandleList const & maps,AccessMode access_mode,ZoneVector<ElementAccessInfo> * access_infos)214 bool AccessInfoFactory::ComputeElementAccessInfos(
215     MapHandleList const& maps, AccessMode access_mode,
216     ZoneVector<ElementAccessInfo>* access_infos) {
217   // Collect possible transition targets.
218   MapHandleList possible_transition_targets(maps.length());
219   for (Handle<Map> map : maps) {
220     if (Map::TryUpdate(map).ToHandle(&map)) {
221       if (CanInlineElementAccess(map) &&
222           IsFastElementsKind(map->elements_kind()) &&
223           GetInitialFastElementsKind() != map->elements_kind()) {
224         possible_transition_targets.Add(map);
225       }
226     }
227   }
228 
229   // Separate the actual receiver maps and the possible transition sources.
230   MapHandleList receiver_maps(maps.length());
231   MapTransitionList transitions(maps.length());
232   for (Handle<Map> map : maps) {
233     if (Map::TryUpdate(map).ToHandle(&map)) {
234       Map* transition_target = map->is_stable() ?
235           nullptr :
236           map->FindElementsKindTransitionedMap(&possible_transition_targets);
237       if (transition_target == nullptr) {
238         receiver_maps.Add(map);
239       } else {
240         transitions.push_back(std::make_pair(map, handle(transition_target)));
241       }
242     }
243   }
244 
245   for (Handle<Map> receiver_map : receiver_maps) {
246     // Compute the element access information.
247     ElementAccessInfo access_info;
248     if (!ComputeElementAccessInfo(receiver_map, access_mode, &access_info)) {
249       return false;
250     }
251 
252     // Collect the possible transitions for the {receiver_map}.
253     for (auto transition : transitions) {
254       if (transition.second.is_identical_to(receiver_map)) {
255         access_info.transitions().push_back(transition);
256       }
257     }
258 
259     // Schedule the access information.
260     access_infos->push_back(access_info);
261   }
262   return true;
263 }
264 
265 
ComputePropertyAccessInfo(Handle<Map> map,Handle<Name> name,AccessMode access_mode,PropertyAccessInfo * access_info)266 bool AccessInfoFactory::ComputePropertyAccessInfo(
267     Handle<Map> map, Handle<Name> name, AccessMode access_mode,
268     PropertyAccessInfo* access_info) {
269   // Check if it is safe to inline property access for the {map}.
270   if (!CanInlinePropertyAccess(map)) return false;
271 
272   // Compute the receiver type.
273   Handle<Map> receiver_map = map;
274 
275   // Property lookups require the name to be internalized.
276   name = isolate()->factory()->InternalizeName(name);
277 
278   // We support fast inline cases for certain JSObject getters.
279   if (access_mode == AccessMode::kLoad &&
280       LookupSpecialFieldAccessor(map, name, access_info)) {
281     return true;
282   }
283 
284   MaybeHandle<JSObject> holder;
285   do {
286     // Lookup the named property on the {map}.
287     Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate());
288     int const number = descriptors->SearchWithCache(isolate(), *name, *map);
289     if (number != DescriptorArray::kNotFound) {
290       PropertyDetails const details = descriptors->GetDetails(number);
291       if (access_mode == AccessMode::kStore ||
292           access_mode == AccessMode::kStoreInLiteral) {
293         // Don't bother optimizing stores to read-only properties.
294         if (details.IsReadOnly()) {
295           return false;
296         }
297         // Check for store to data property on a prototype.
298         if (details.kind() == kData && !holder.is_null()) {
299           // Store to property not found on the receiver but on a prototype, we
300           // need to transition to a new data property.
301           // Implemented according to ES6 section 9.1.9 [[Set]] (P, V, Receiver)
302           return LookupTransition(receiver_map, name, holder, access_info);
303         }
304       }
305       if (details.location() == kField) {
306         if (details.kind() == kData) {
307           int index = descriptors->GetFieldIndex(number);
308           Representation details_representation = details.representation();
309           FieldIndex field_index = FieldIndex::ForPropertyIndex(
310               *map, index, details_representation.IsDouble());
311           Type* field_type = Type::NonInternal();
312           MachineRepresentation field_representation =
313               MachineRepresentation::kTagged;
314           MaybeHandle<Map> field_map;
315           if (details_representation.IsSmi()) {
316             field_type = Type::SignedSmall();
317             field_representation = MachineRepresentation::kTaggedSigned;
318           } else if (details_representation.IsDouble()) {
319             field_type = type_cache_.kFloat64;
320             field_representation = MachineRepresentation::kFloat64;
321           } else if (details_representation.IsHeapObject()) {
322             // Extract the field type from the property details (make sure its
323             // representation is TaggedPointer to reflect the heap object case).
324             field_representation = MachineRepresentation::kTaggedPointer;
325             Handle<FieldType> descriptors_field_type(
326                 descriptors->GetFieldType(number), isolate());
327             if (descriptors_field_type->IsNone()) {
328               // Store is not safe if the field type was cleared.
329               if (access_mode == AccessMode::kStore) return false;
330 
331               // The field type was cleared by the GC, so we don't know anything
332               // about the contents now.
333             } else if (descriptors_field_type->IsClass()) {
334               // Add proper code dependencies in case of stable field map(s).
335               Handle<Map> field_owner_map(map->FindFieldOwner(number),
336                                           isolate());
337               dependencies()->AssumeFieldOwner(field_owner_map);
338 
339               // Remember the field map, and try to infer a useful type.
340               field_type = Type::For(descriptors_field_type->AsClass());
341               field_map = descriptors_field_type->AsClass();
342             }
343           }
344           *access_info = PropertyAccessInfo::DataField(
345               details.constness(), MapList{receiver_map}, field_index,
346               field_representation, field_type, field_map, holder);
347           return true;
348         } else {
349           DCHECK_EQ(kAccessor, details.kind());
350           // TODO(turbofan): Add support for general accessors?
351           return false;
352         }
353 
354       } else {
355         DCHECK_EQ(kDescriptor, details.location());
356         if (details.kind() == kData) {
357           DCHECK(!FLAG_track_constant_fields);
358           *access_info = PropertyAccessInfo::DataConstant(
359               MapList{receiver_map},
360               handle(descriptors->GetValue(number), isolate()), holder);
361           return true;
362         } else {
363           DCHECK_EQ(kAccessor, details.kind());
364           Handle<Object> accessors(descriptors->GetValue(number), isolate());
365           if (!accessors->IsAccessorPair()) return false;
366           Handle<Object> accessor(
367               access_mode == AccessMode::kLoad
368                   ? Handle<AccessorPair>::cast(accessors)->getter()
369                   : Handle<AccessorPair>::cast(accessors)->setter(),
370               isolate());
371           if (!accessor->IsJSFunction()) {
372             CallOptimization optimization(accessor);
373             if (!optimization.is_simple_api_call()) {
374               return false;
375             }
376             if (optimization.api_call_info()->fast_handler()->IsCode()) {
377               return false;
378             }
379             if (V8_UNLIKELY(FLAG_runtime_stats)) return false;
380           }
381           if (access_mode == AccessMode::kLoad) {
382             Handle<Name> cached_property_name;
383             if (FunctionTemplateInfo::TryGetCachedPropertyName(isolate(),
384                                                                accessor)
385                     .ToHandle(&cached_property_name)) {
386               if (ComputePropertyAccessInfo(map, cached_property_name,
387                                             access_mode, access_info)) {
388                 return true;
389               }
390             }
391           }
392           *access_info = PropertyAccessInfo::AccessorConstant(
393               MapList{receiver_map}, accessor, holder);
394           return true;
395         }
396       }
397       UNREACHABLE();
398       return false;
399     }
400 
401     // Don't search on the prototype chain for special indices in case of
402     // integer indexed exotic objects (see ES6 section 9.4.5).
403     if (map->IsJSTypedArrayMap() && name->IsString() &&
404         IsSpecialIndex(isolate()->unicode_cache(), String::cast(*name))) {
405       return false;
406     }
407 
408     // Don't search on the prototype when storing in literals
409     if (access_mode == AccessMode::kStoreInLiteral) {
410       return LookupTransition(receiver_map, name, holder, access_info);
411     }
412 
413     // Don't lookup private symbols on the prototype chain.
414     if (name->IsPrivate()) return false;
415 
416     // Walk up the prototype chain.
417     if (!map->prototype()->IsJSObject()) {
418       // Perform the implicit ToObject for primitives here.
419       // Implemented according to ES6 section 7.3.2 GetV (V, P).
420       Handle<JSFunction> constructor;
421       if (Map::GetConstructorFunction(map, native_context())
422               .ToHandle(&constructor)) {
423         map = handle(constructor->initial_map(), isolate());
424         DCHECK(map->prototype()->IsJSObject());
425       } else if (map->prototype()->IsNull(isolate())) {
426         // Store to property not found on the receiver or any prototype, we need
427         // to transition to a new data property.
428         // Implemented according to ES6 section 9.1.9 [[Set]] (P, V, Receiver)
429         if (access_mode == AccessMode::kStore) {
430           return LookupTransition(receiver_map, name, holder, access_info);
431         }
432         // The property was not found, return undefined or throw depending
433         // on the language mode of the load operation.
434         // Implemented according to ES6 section 9.1.8 [[Get]] (P, Receiver)
435         *access_info =
436             PropertyAccessInfo::NotFound(MapList{receiver_map}, holder);
437         return true;
438       } else {
439         return false;
440       }
441     }
442     Handle<JSObject> map_prototype(JSObject::cast(map->prototype()), isolate());
443     if (map_prototype->map()->is_deprecated()) {
444       // Try to migrate the prototype object so we don't embed the deprecated
445       // map into the optimized code.
446       JSObject::TryMigrateInstance(map_prototype);
447     }
448     map = handle(map_prototype->map(), isolate());
449     holder = map_prototype;
450   } while (CanInlinePropertyAccess(map));
451   return false;
452 }
453 
ComputePropertyAccessInfos(MapHandleList const & maps,Handle<Name> name,AccessMode access_mode,ZoneVector<PropertyAccessInfo> * access_infos)454 bool AccessInfoFactory::ComputePropertyAccessInfos(
455     MapHandleList const& maps, Handle<Name> name, AccessMode access_mode,
456     ZoneVector<PropertyAccessInfo>* access_infos) {
457   for (Handle<Map> map : maps) {
458     if (Map::TryUpdate(map).ToHandle(&map)) {
459       PropertyAccessInfo access_info;
460       if (!ComputePropertyAccessInfo(map, name, access_mode, &access_info)) {
461         return false;
462       }
463       // Try to merge the {access_info} with an existing one.
464       bool merged = false;
465       for (PropertyAccessInfo& other_info : *access_infos) {
466         if (other_info.Merge(&access_info)) {
467           merged = true;
468           break;
469         }
470       }
471       if (!merged) access_infos->push_back(access_info);
472     }
473   }
474   return true;
475 }
476 
477 
LookupSpecialFieldAccessor(Handle<Map> map,Handle<Name> name,PropertyAccessInfo * access_info)478 bool AccessInfoFactory::LookupSpecialFieldAccessor(
479     Handle<Map> map, Handle<Name> name, PropertyAccessInfo* access_info) {
480   // Check for special JSObject field accessors.
481   int offset;
482   if (Accessors::IsJSObjectFieldAccessor(map, name, &offset)) {
483     FieldIndex field_index = FieldIndex::ForInObjectOffset(offset);
484     Type* field_type = Type::NonInternal();
485     MachineRepresentation field_representation = MachineRepresentation::kTagged;
486     if (map->IsStringMap()) {
487       DCHECK(Name::Equals(factory()->length_string(), name));
488       // The String::length property is always a smi in the range
489       // [0, String::kMaxLength].
490       field_type = type_cache_.kStringLengthType;
491       field_representation = MachineRepresentation::kTaggedSigned;
492     } else if (map->IsJSArrayMap()) {
493       DCHECK(Name::Equals(factory()->length_string(), name));
494       // The JSArray::length property is a smi in the range
495       // [0, FixedDoubleArray::kMaxLength] in case of fast double
496       // elements, a smi in the range [0, FixedArray::kMaxLength]
497       // in case of other fast elements, and [0, kMaxUInt32] in
498       // case of other arrays.
499       if (IsFastDoubleElementsKind(map->elements_kind())) {
500         field_type = type_cache_.kFixedDoubleArrayLengthType;
501         field_representation = MachineRepresentation::kTaggedSigned;
502       } else if (IsFastElementsKind(map->elements_kind())) {
503         field_type = type_cache_.kFixedArrayLengthType;
504         field_representation = MachineRepresentation::kTaggedSigned;
505       } else {
506         field_type = type_cache_.kJSArrayLengthType;
507       }
508     }
509     // Special fields are always mutable.
510     *access_info = PropertyAccessInfo::DataField(
511         kMutable, MapList{map}, field_index, field_representation, field_type);
512     return true;
513   }
514   return false;
515 }
516 
517 
LookupTransition(Handle<Map> map,Handle<Name> name,MaybeHandle<JSObject> holder,PropertyAccessInfo * access_info)518 bool AccessInfoFactory::LookupTransition(Handle<Map> map, Handle<Name> name,
519                                          MaybeHandle<JSObject> holder,
520                                          PropertyAccessInfo* access_info) {
521   // Check if the {map} has a data transition with the given {name}.
522   if (map->unused_property_fields() == 0) {
523     *access_info = PropertyAccessInfo::Generic(MapList{map});
524     return true;
525   }
526   Handle<Map> transition_map;
527   if (TransitionArray::SearchTransition(map, kData, name, NONE)
528           .ToHandle(&transition_map)) {
529     int const number = transition_map->LastAdded();
530     PropertyDetails const details =
531         transition_map->instance_descriptors()->GetDetails(number);
532     // Don't bother optimizing stores to read-only properties.
533     if (details.IsReadOnly()) return false;
534     // TODO(bmeurer): Handle transition to data constant?
535     if (details.location() != kField) return false;
536     int const index = details.field_index();
537     Representation details_representation = details.representation();
538     FieldIndex field_index = FieldIndex::ForPropertyIndex(
539         *transition_map, index, details_representation.IsDouble());
540     Type* field_type = Type::NonInternal();
541     MaybeHandle<Map> field_map;
542     MachineRepresentation field_representation = MachineRepresentation::kTagged;
543     if (details_representation.IsSmi()) {
544       field_type = Type::SignedSmall();
545       field_representation = MachineRepresentation::kTaggedSigned;
546     } else if (details_representation.IsDouble()) {
547       field_type = type_cache_.kFloat64;
548       field_representation = MachineRepresentation::kFloat64;
549     } else if (details_representation.IsHeapObject()) {
550       // Extract the field type from the property details (make sure its
551       // representation is TaggedPointer to reflect the heap object case).
552       field_representation = MachineRepresentation::kTaggedPointer;
553       Handle<FieldType> descriptors_field_type(
554           transition_map->instance_descriptors()->GetFieldType(number),
555           isolate());
556       if (descriptors_field_type->IsNone()) {
557         // Store is not safe if the field type was cleared.
558         return false;
559       } else if (descriptors_field_type->IsClass()) {
560         // Add proper code dependencies in case of stable field map(s).
561         Handle<Map> field_owner_map(transition_map->FindFieldOwner(number),
562                                     isolate());
563         dependencies()->AssumeFieldOwner(field_owner_map);
564 
565         // Remember the field map, and try to infer a useful type.
566         field_type = Type::For(descriptors_field_type->AsClass());
567         field_map = descriptors_field_type->AsClass();
568       }
569     }
570     dependencies()->AssumeMapNotDeprecated(transition_map);
571     // Transitioning stores are never stores to constant fields.
572     *access_info = PropertyAccessInfo::DataField(
573         kMutable, MapList{map}, field_index, field_representation, field_type,
574         field_map, holder, transition_map);
575     return true;
576   }
577   return false;
578 }
579 
580 
factory() const581 Factory* AccessInfoFactory::factory() const { return isolate()->factory(); }
582 
583 }  // namespace compiler
584 }  // namespace internal
585 }  // namespace v8
586