Line data Source code
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 :
22 35987 : bool CanInlineElementAccess(Handle<Map> map) {
23 35987 : if (!map->IsJSObjectMap()) return false;
24 35727 : if (map->is_access_check_needed()) return false;
25 35727 : if (map->has_indexed_interceptor()) return false;
26 : ElementsKind const elements_kind = map->elements_kind();
27 35715 : if (IsFastElementsKind(elements_kind)) return true;
28 7334 : if (IsFixedTypedArrayElementsKind(elements_kind)) return true;
29 1823 : return false;
30 : }
31 :
32 :
33 122057 : 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 122057 : if (map->IsBooleanMap()) return true;
39 121944 : if (map->instance_type() < LAST_PRIMITIVE_TYPE) return true;
40 236499 : return map->IsJSObjectMap() && !map->is_dictionary_map() &&
41 236486 : !map->has_named_interceptor() &&
42 : // TODO(verwaest): Whitelist contexts to which we have access.
43 118526 : !map->is_access_check_needed();
44 : }
45 :
46 : } // namespace
47 :
48 :
49 0 : std::ostream& operator<<(std::ostream& os, AccessMode access_mode) {
50 0 : switch (access_mode) {
51 : case AccessMode::kLoad:
52 0 : return os << "Load";
53 : case AccessMode::kStore:
54 0 : return os << "Store";
55 : case AccessMode::kStoreInLiteral:
56 0 : return os << "StoreInLiteral";
57 : }
58 0 : UNREACHABLE();
59 : return os;
60 : }
61 :
62 0 : ElementAccessInfo::ElementAccessInfo() {}
63 :
64 0 : ElementAccessInfo::ElementAccessInfo(MapList const& receiver_maps,
65 : ElementsKind elements_kind)
66 26914 : : elements_kind_(elements_kind), receiver_maps_(receiver_maps) {}
67 :
68 : // static
69 0 : PropertyAccessInfo PropertyAccessInfo::NotFound(MapList const& receiver_maps,
70 : MaybeHandle<JSObject> holder) {
71 0 : return PropertyAccessInfo(holder, receiver_maps);
72 : }
73 :
74 : // static
75 0 : PropertyAccessInfo PropertyAccessInfo::DataConstant(
76 : MapList const& receiver_maps, Handle<Object> constant,
77 : MaybeHandle<JSObject> holder) {
78 0 : return PropertyAccessInfo(kDataConstant, holder, constant, receiver_maps);
79 : }
80 :
81 : // static
82 0 : 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 18784 : Kind kind = constness == kConst ? kDataConstantField : kDataField;
88 : return PropertyAccessInfo(kind, holder, transition_map, field_index,
89 : field_representation, field_type, field_map,
90 0 : receiver_maps);
91 : }
92 :
93 : // static
94 0 : PropertyAccessInfo PropertyAccessInfo::AccessorConstant(
95 : MapList const& receiver_maps, Handle<Object> constant,
96 : MaybeHandle<JSObject> holder) {
97 0 : return PropertyAccessInfo(kAccessorConstant, holder, constant, receiver_maps);
98 : }
99 :
100 1371 : PropertyAccessInfo::PropertyAccessInfo()
101 : : kind_(kInvalid),
102 : field_representation_(MachineRepresentation::kNone),
103 191257 : field_type_(Type::None()) {}
104 :
105 0 : PropertyAccessInfo::PropertyAccessInfo(MaybeHandle<JSObject> holder,
106 : MapList const& receiver_maps)
107 : : kind_(kNotFound),
108 : receiver_maps_(receiver_maps),
109 : holder_(holder),
110 : field_representation_(MachineRepresentation::kNone),
111 6915 : field_type_(Type::None()) {}
112 :
113 0 : PropertyAccessInfo::PropertyAccessInfo(Kind kind, MaybeHandle<JSObject> holder,
114 : Handle<Object> constant,
115 : MapList const& receiver_maps)
116 : : kind_(kind),
117 : receiver_maps_(receiver_maps),
118 : constant_(constant),
119 : holder_(holder),
120 : field_representation_(MachineRepresentation::kNone),
121 183786 : field_type_(Type::Any()) {}
122 :
123 0 : PropertyAccessInfo::PropertyAccessInfo(
124 : Kind kind, MaybeHandle<JSObject> holder, MaybeHandle<Map> transition_map,
125 : FieldIndex field_index, MachineRepresentation field_representation,
126 : Type* field_type, MaybeHandle<Map> field_map, MapList const& receiver_maps)
127 : : kind_(kind),
128 : receiver_maps_(receiver_maps),
129 : transition_map_(transition_map),
130 : holder_(holder),
131 : field_index_(field_index),
132 : field_representation_(field_representation),
133 : field_type_(field_type),
134 59782 : field_map_(field_map) {}
135 :
136 6469 : bool PropertyAccessInfo::Merge(PropertyAccessInfo const* that,
137 : AccessMode access_mode, Zone* zone) {
138 6469 : if (this->kind_ != that->kind_) return false;
139 6173 : if (this->holder_.address() != that->holder_.address()) return false;
140 :
141 5686 : switch (this->kind_) {
142 : case kInvalid:
143 : break;
144 :
145 : case kDataField:
146 : case kDataConstantField: {
147 : // Check if we actually access the same field.
148 9518 : if (this->kind_ == that->kind_ &&
149 : this->field_index_ == that->field_index_) {
150 2296 : switch (access_mode) {
151 : case AccessMode::kLoad: {
152 2125 : if (this->field_representation_ != that->field_representation_) {
153 576 : if (!IsAnyTagged(this->field_representation_) ||
154 : !IsAnyTagged(that->field_representation_)) {
155 : return false;
156 : }
157 288 : this->field_representation_ = MachineRepresentation::kTagged;
158 : }
159 2125 : if (this->field_map_.address() != that->field_map_.address()) {
160 8 : this->field_map_ = MaybeHandle<Map>();
161 : }
162 : break;
163 : }
164 : case AccessMode::kStore:
165 : case AccessMode::kStoreInLiteral: {
166 : // For stores, the field map and field representation information
167 : // must match exactly, otherwise we cannot merge the stores. We
168 : // also need to make sure that in case of transitioning stores,
169 : // the transition targets match.
170 342 : if (this->field_map_.address() != that->field_map_.address() ||
171 342 : this->field_representation_ != that->field_representation_ ||
172 : this->transition_map_.address() !=
173 : that->transition_map_.address()) {
174 : return false;
175 : }
176 : break;
177 : }
178 : }
179 : // Merge the field type.
180 : this->field_type_ =
181 2208 : Type::Union(this->field_type_, that->field_type_, zone);
182 : // Merge the receiver maps.
183 : this->receiver_maps_.insert(this->receiver_maps_.end(),
184 : that->receiver_maps_.begin(),
185 5037 : that->receiver_maps_.end());
186 2208 : return true;
187 : }
188 : return false;
189 : }
190 :
191 : case kDataConstant:
192 : case kAccessorConstant: {
193 : // Check if we actually access the same constant.
194 917 : if (this->constant_.address() == that->constant_.address()) {
195 : this->receiver_maps_.insert(this->receiver_maps_.end(),
196 : that->receiver_maps_.begin(),
197 611 : that->receiver_maps_.end());
198 611 : return true;
199 : }
200 : return false;
201 : }
202 :
203 : case kNotFound: {
204 : this->receiver_maps_.insert(this->receiver_maps_.end(),
205 : that->receiver_maps_.begin(),
206 10 : that->receiver_maps_.end());
207 10 : return true;
208 : }
209 : }
210 :
211 0 : UNREACHABLE();
212 : return false;
213 : }
214 :
215 115970 : AccessInfoFactory::AccessInfoFactory(CompilationDependencies* dependencies,
216 : Handle<Context> native_context, Zone* zone)
217 : : dependencies_(dependencies),
218 : native_context_(native_context),
219 : isolate_(native_context->GetIsolate()),
220 115970 : type_cache_(TypeCache::Get()),
221 347910 : zone_(zone) {
222 : DCHECK(native_context->IsNativeContext());
223 115970 : }
224 :
225 :
226 3259 : bool AccessInfoFactory::ComputeElementAccessInfo(
227 : Handle<Map> map, AccessMode access_mode, ElementAccessInfo* access_info) {
228 : // Check if it is safe to inline element access for the {map}.
229 3259 : if (!CanInlineElementAccess(map)) return false;
230 : ElementsKind const elements_kind = map->elements_kind();
231 7692 : *access_info = ElementAccessInfo(MapList{map}, elements_kind);
232 2564 : return true;
233 : }
234 :
235 26415 : bool AccessInfoFactory::ComputeElementAccessInfos(
236 6195 : MapHandleList const& maps, AccessMode access_mode,
237 : ZoneVector<ElementAccessInfo>* access_infos) {
238 : // For polymorphic loads of similar elements kinds (i.e. all tagged or all
239 : // double), always use the "worst case" code without a transition. This is
240 : // much faster than transitioning the elements to the worst case, trading a
241 : // TransitionElementsKind for a CheckMaps, avoiding mutation of the array.
242 : //
243 : // Similarly, for polymorphic stores of compatible elements kind that
244 : // differ only in holeyness, always use the "holey case" code without a
245 : // transition. This is beneficial, because CheckMaps can often be optimized
246 : // whereas TransitionElementsKind can block optimizations. And as above, we
247 : // avoid mutation of the array (we still mutate the array contents).
248 : ElementAccessInfo access_info;
249 26415 : if (ConsolidateElementAccess(maps, access_mode, &access_info)) {
250 24350 : access_infos->push_back(access_info);
251 24350 : return true;
252 : }
253 :
254 : // Collect possible transition targets.
255 : MapHandleList possible_transition_targets(maps.length());
256 7981 : for (Handle<Map> map : maps) {
257 7702 : if (Map::TryUpdate(map).ToHandle(&map)) {
258 10837 : if (CanInlineElementAccess(map) &&
259 6678 : IsFastElementsKind(map->elements_kind()) &&
260 : GetInitialFastElementsKind() != map->elements_kind()) {
261 2125 : possible_transition_targets.Add(map);
262 : }
263 : }
264 : }
265 :
266 : // Separate the actual receiver maps and the possible transition sources.
267 : MapHandleList receiver_maps(maps.length());
268 2065 : MapTransitionList transitions(maps.length());
269 7981 : for (Handle<Map> map : maps) {
270 7702 : if (Map::TryUpdate(map).ToHandle(&map)) {
271 : Map* transition_target =
272 3851 : map->FindElementsKindTransitionedMap(&possible_transition_targets);
273 3851 : if (transition_target == nullptr) {
274 3418 : receiver_maps.Add(map);
275 : } else {
276 : DCHECK(!map->is_stable());
277 866 : transitions.push_back(std::make_pair(map, handle(transition_target)));
278 : }
279 : }
280 : }
281 :
282 6694 : for (Handle<Map> receiver_map : receiver_maps) {
283 : // Compute the element access information.
284 : ElementAccessInfo access_info;
285 3259 : if (!ComputeElementAccessInfo(receiver_map, access_mode, &access_info)) {
286 695 : return false;
287 : }
288 :
289 : // Collect the possible transitions for the {receiver_map}.
290 11287 : for (auto transition : transitions) {
291 6159 : if (transition.second.is_identical_to(receiver_map)) {
292 433 : access_info.transitions().push_back(transition);
293 : }
294 : }
295 :
296 : // Schedule the access information.
297 2564 : access_infos->push_back(access_info);
298 2564 : }
299 27785 : return true;
300 : }
301 :
302 :
303 94951 : bool AccessInfoFactory::ComputePropertyAccessInfo(
304 : Handle<Map> map, Handle<Name> name, AccessMode access_mode,
305 464916 : PropertyAccessInfo* access_info) {
306 : // Check if it is safe to inline property access for the {map}.
307 94951 : if (!CanInlinePropertyAccess(map)) return false;
308 :
309 : // Compute the receiver type.
310 : Handle<Map> receiver_map = map;
311 :
312 : // Property lookups require the name to be internalized.
313 94475 : name = isolate()->factory()->InternalizeName(name);
314 :
315 : // We support fast inline cases for certain JSObject getters.
316 180879 : if (access_mode == AccessMode::kLoad &&
317 86404 : LookupSpecialFieldAccessor(map, name, access_info)) {
318 : return true;
319 : }
320 :
321 : MaybeHandle<JSObject> holder;
322 27106 : do {
323 : // Lookup the named property on the {map}.
324 : Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate());
325 : int const number = descriptors->SearchWithCache(isolate(), *name, *map);
326 114879 : if (number != DescriptorArray::kNotFound) {
327 81012 : PropertyDetails const details = descriptors->GetDetails(number);
328 81012 : if (access_mode == AccessMode::kStore ||
329 : access_mode == AccessMode::kStoreInLiteral) {
330 : // Don't bother optimizing stores to read-only properties.
331 3618 : if (details.IsReadOnly()) {
332 : return false;
333 : }
334 : // Check for store to data property on a prototype.
335 3582 : if (details.kind() == kData && !holder.is_null()) {
336 : // Store to property not found on the receiver but on a prototype, we
337 : // need to transition to a new data property.
338 : // Implemented according to ES6 section 9.1.9 [[Set]] (P, V, Receiver)
339 127 : return LookupTransition(receiver_map, name, holder, access_info);
340 : }
341 : }
342 80849 : if (details.location() == kField) {
343 18784 : if (details.kind() == kData) {
344 : int index = descriptors->GetFieldIndex(number);
345 : Representation details_representation = details.representation();
346 : FieldIndex field_index = FieldIndex::ForPropertyIndex(
347 37568 : *map, index, details_representation.IsDouble());
348 : Type* field_type = Type::NonInternal();
349 : MachineRepresentation field_representation =
350 : MachineRepresentation::kTagged;
351 : MaybeHandle<Map> field_map;
352 18784 : if (details_representation.IsSmi()) {
353 : field_type = Type::SignedSmall();
354 : field_representation = MachineRepresentation::kTaggedSigned;
355 13835 : } else if (details_representation.IsDouble()) {
356 483 : field_type = type_cache_.kFloat64;
357 : field_representation = MachineRepresentation::kFloat64;
358 13352 : } else if (details_representation.IsHeapObject()) {
359 : // Extract the field type from the property details (make sure its
360 : // representation is TaggedPointer to reflect the heap object case).
361 : field_representation = MachineRepresentation::kTaggedPointer;
362 : Handle<FieldType> descriptors_field_type(
363 7298 : descriptors->GetFieldType(number), isolate());
364 7298 : if (descriptors_field_type->IsNone()) {
365 : // Store is not safe if the field type was cleared.
366 0 : if (access_mode == AccessMode::kStore) return false;
367 :
368 : // The field type was cleared by the GC, so we don't know anything
369 : // about the contents now.
370 7298 : } else if (descriptors_field_type->IsClass()) {
371 : // Add proper code dependencies in case of stable field map(s).
372 : Handle<Map> field_owner_map(map->FindFieldOwner(number),
373 2566 : isolate());
374 : dependencies()->AssumeFieldOwner(field_owner_map);
375 :
376 : // Remember the field map, and try to infer a useful type.
377 2566 : field_type = Type::For(descriptors_field_type->AsClass());
378 2566 : field_map = descriptors_field_type->AsClass();
379 : }
380 : }
381 56352 : *access_info = PropertyAccessInfo::DataField(
382 : details.constness(), MapList{receiver_map}, field_index,
383 18784 : field_representation, field_type, field_map, holder);
384 18784 : return true;
385 : } else {
386 : DCHECK_EQ(kAccessor, details.kind());
387 : // TODO(turbofan): Add support for general accessors?
388 : return false;
389 : }
390 :
391 : } else {
392 : DCHECK_EQ(kDescriptor, details.location());
393 62065 : if (details.kind() == kData) {
394 : DCHECK(!FLAG_track_constant_fields);
395 179706 : *access_info = PropertyAccessInfo::DataConstant(
396 : MapList{receiver_map},
397 59902 : handle(descriptors->GetValue(number), isolate()), holder);
398 59902 : return true;
399 : } else {
400 : DCHECK_EQ(kAccessor, details.kind());
401 : Handle<Object> accessors(descriptors->GetValue(number), isolate());
402 2163 : if (!accessors->IsAccessorPair()) return false;
403 : Handle<Object> accessor(
404 : access_mode == AccessMode::kLoad
405 : ? Handle<AccessorPair>::cast(accessors)->getter()
406 : : Handle<AccessorPair>::cast(accessors)->setter(),
407 1423 : isolate());
408 1423 : if (!accessor->IsJSFunction()) {
409 64 : CallOptimization optimization(accessor);
410 64 : if (!optimization.is_simple_api_call()) {
411 55 : return false;
412 : }
413 9 : if (V8_UNLIKELY(FLAG_runtime_stats)) return false;
414 : }
415 1368 : if (access_mode == AccessMode::kLoad) {
416 : Handle<Name> cached_property_name;
417 863 : if (FunctionTemplateInfo::TryGetCachedPropertyName(isolate(),
418 : accessor)
419 1726 : .ToHandle(&cached_property_name)) {
420 8 : if (ComputePropertyAccessInfo(map, cached_property_name,
421 : access_mode, access_info)) {
422 8 : return true;
423 : }
424 : }
425 : }
426 4080 : *access_info = PropertyAccessInfo::AccessorConstant(
427 1360 : MapList{receiver_map}, accessor, holder);
428 1360 : return true;
429 : }
430 : }
431 : UNREACHABLE();
432 : return false;
433 : }
434 :
435 : // Don't search on the prototype chain for special indices in case of
436 : // integer indexed exotic objects (see ES6 section 9.4.5).
437 34702 : if (map->IsJSTypedArrayMap() && name->IsString() &&
438 414 : IsSpecialIndex(isolate()->unicode_cache(), String::cast(*name))) {
439 : return false;
440 : }
441 :
442 : // Don't search on the prototype when storing in literals
443 33860 : if (access_mode == AccessMode::kStoreInLiteral) {
444 123 : return LookupTransition(receiver_map, name, holder, access_info);
445 : }
446 :
447 : // Don't lookup private symbols on the prototype chain.
448 33737 : if (name->IsPrivate()) return false;
449 :
450 : // Walk up the prototype chain.
451 33731 : if (!map->prototype()->IsJSObject()) {
452 : // Perform the implicit ToObject for primitives here.
453 : // Implemented according to ES6 section 7.3.2 GetV (V, P).
454 : Handle<JSFunction> constructor;
455 9276 : if (Map::GetConstructorFunction(map, native_context())
456 18552 : .ToHandle(&constructor)) {
457 : map = handle(constructor->initial_map(), isolate());
458 : DCHECK(map->prototype()->IsJSObject());
459 6625 : } else if (map->prototype()->IsNull(isolate())) {
460 : // Store to property not found on the receiver or any prototype, we need
461 : // to transition to a new data property.
462 : // Implemented according to ES6 section 9.1.9 [[Set]] (P, V, Receiver)
463 6618 : if (access_mode == AccessMode::kStore) {
464 4313 : return LookupTransition(receiver_map, name, holder, access_info);
465 : }
466 : // The property was not found, return undefined or throw depending
467 : // on the language mode of the load operation.
468 : // Implemented according to ES6 section 9.1.8 [[Get]] (P, Receiver)
469 6915 : *access_info =
470 2305 : PropertyAccessInfo::NotFound(MapList{receiver_map}, holder);
471 2305 : return true;
472 : } else {
473 : return false;
474 : }
475 : }
476 : Handle<JSObject> map_prototype(JSObject::cast(map->prototype()), isolate());
477 27106 : if (map_prototype->map()->is_deprecated()) {
478 : // Try to migrate the prototype object so we don't embed the deprecated
479 : // map into the optimized code.
480 0 : JSObject::TryMigrateInstance(map_prototype);
481 : }
482 : map = handle(map_prototype->map(), isolate());
483 : holder = map_prototype;
484 : } while (CanInlinePropertyAccess(map));
485 : return false;
486 : }
487 :
488 88184 : bool AccessInfoFactory::ComputePropertyAccessInfos(
489 : MapHandleList const& maps, Handle<Name> name, AccessMode access_mode,
490 6469 : ZoneVector<PropertyAccessInfo>* access_infos) {
491 268602 : for (Handle<Map> map : maps) {
492 187166 : if (Map::TryUpdate(map).ToHandle(&map)) {
493 : PropertyAccessInfo access_info;
494 93572 : if (!ComputePropertyAccessInfo(map, name, access_mode, &access_info)) {
495 : return false;
496 : }
497 : // Try to merge the {access_info} with an existing one.
498 : bool merged = false;
499 188086 : for (PropertyAccessInfo& other_info : *access_infos) {
500 6469 : if (other_info.Merge(&access_info, access_mode, zone())) {
501 : merged = true;
502 : break;
503 : }
504 : }
505 92223 : if (!merged) access_infos->push_back(access_info);
506 : }
507 : }
508 86835 : return true;
509 : }
510 :
511 26415 : bool AccessInfoFactory::ConsolidateElementAccess(
512 108519 : MapHandleList const& maps, AccessMode access_mode,
513 : ElementAccessInfo* access_info) {
514 26415 : if (maps.is_empty()) return false;
515 : InstanceType instance_type = maps.first()->instance_type();
516 : ElementsKind elements_kind = maps.first()->elements_kind();
517 26415 : MapList receiver_maps(maps.length());
518 106454 : for (int i = 0; i < maps.length(); ++i) {
519 28877 : Handle<Map> map = maps[i];
520 57070 : if (!CanInlineElementAccess(map) || map->instance_type() != instance_type) {
521 : return false;
522 : }
523 : ElementsKind other_kind = map->elements_kind();
524 27908 : if (IsHoleyElementsKind(elements_kind)) {
525 : other_kind = GetHoleyElementsKind(other_kind);
526 20960 : } else if (IsHoleyElementsKind(other_kind)) {
527 : elements_kind = GetHoleyElementsKind(elements_kind);
528 : }
529 27908 : if (elements_kind != other_kind) {
530 1864 : if (access_mode != AccessMode::kLoad) return false;
531 866 : if (IsFastDoubleElementsKind(elements_kind) !=
532 : IsFastDoubleElementsKind(other_kind)) {
533 : return false;
534 : }
535 822 : if (IsMoreGeneralElementsKindTransition(elements_kind, other_kind)) {
536 : elements_kind = other_kind;
537 822 : } else if (!IsMoreGeneralElementsKindTransition(other_kind,
538 822 : elements_kind)) {
539 : return false;
540 : }
541 : }
542 53624 : receiver_maps[i] = map;
543 : }
544 24350 : *access_info = ElementAccessInfo(receiver_maps, elements_kind);
545 24350 : return true;
546 : }
547 :
548 86404 : bool AccessInfoFactory::LookupSpecialFieldAccessor(
549 : Handle<Map> map, Handle<Name> name, PropertyAccessInfo* access_info) {
550 : // Check for special JSObject field accessors.
551 : int offset;
552 86404 : if (Accessors::IsJSObjectFieldAccessor(map, name, &offset)) {
553 6590 : FieldIndex field_index = FieldIndex::ForInObjectOffset(offset);
554 : Type* field_type = Type::NonInternal();
555 : MachineRepresentation field_representation = MachineRepresentation::kTagged;
556 6590 : if (map->IsStringMap()) {
557 : DCHECK(Name::Equals(factory()->length_string(), name));
558 : // The String::length property is always a smi in the range
559 : // [0, String::kMaxLength].
560 880 : field_type = type_cache_.kStringLengthType;
561 : field_representation = MachineRepresentation::kTaggedSigned;
562 5710 : } else if (map->IsJSArrayMap()) {
563 : DCHECK(Name::Equals(factory()->length_string(), name));
564 : // The JSArray::length property is a smi in the range
565 : // [0, FixedDoubleArray::kMaxLength] in case of fast double
566 : // elements, a smi in the range [0, FixedArray::kMaxLength]
567 : // in case of other fast elements, and [0, kMaxUInt32] in
568 : // case of other arrays.
569 5710 : if (IsFastDoubleElementsKind(map->elements_kind())) {
570 179 : field_type = type_cache_.kFixedDoubleArrayLengthType;
571 : field_representation = MachineRepresentation::kTaggedSigned;
572 5531 : } else if (IsFastElementsKind(map->elements_kind())) {
573 5306 : field_type = type_cache_.kFixedArrayLengthType;
574 : field_representation = MachineRepresentation::kTaggedSigned;
575 : } else {
576 225 : field_type = type_cache_.kJSArrayLengthType;
577 : }
578 : }
579 : // Special fields are always mutable.
580 19770 : *access_info = PropertyAccessInfo::DataField(
581 6590 : kMutable, MapList{map}, field_index, field_representation, field_type);
582 : return true;
583 : }
584 : return false;
585 : }
586 :
587 :
588 4563 : bool AccessInfoFactory::LookupTransition(Handle<Map> map, Handle<Name> name,
589 : MaybeHandle<JSObject> holder,
590 6350 : PropertyAccessInfo* access_info) {
591 : // Check if the {map} has a data transition with the given {name}.
592 : Handle<Map> transition_map;
593 4563 : if (TransitionArray::SearchTransition(map, kData, name, NONE)
594 9126 : .ToHandle(&transition_map)) {
595 : int const number = transition_map->LastAdded();
596 : PropertyDetails const details =
597 4532 : transition_map->instance_descriptors()->GetDetails(number);
598 : // Don't bother optimizing stores to read-only properties.
599 4532 : if (details.IsReadOnly()) return false;
600 : // TODO(bmeurer): Handle transition to data constant?
601 4532 : if (details.location() != kField) return false;
602 : int const index = details.field_index();
603 : Representation details_representation = details.representation();
604 : FieldIndex field_index = FieldIndex::ForPropertyIndex(
605 9034 : *transition_map, index, details_representation.IsDouble());
606 : Type* field_type = Type::NonInternal();
607 : MaybeHandle<Map> field_map;
608 : MachineRepresentation field_representation = MachineRepresentation::kTagged;
609 4517 : if (details_representation.IsSmi()) {
610 : field_type = Type::SignedSmall();
611 : field_representation = MachineRepresentation::kTaggedSigned;
612 1604 : } else if (details_representation.IsDouble()) {
613 121 : field_type = type_cache_.kFloat64;
614 : field_representation = MachineRepresentation::kFloat64;
615 1483 : } else if (details_representation.IsHeapObject()) {
616 : // Extract the field type from the property details (make sure its
617 : // representation is TaggedPointer to reflect the heap object case).
618 : field_representation = MachineRepresentation::kTaggedPointer;
619 : Handle<FieldType> descriptors_field_type(
620 : transition_map->instance_descriptors()->GetFieldType(number),
621 1405 : isolate());
622 1405 : if (descriptors_field_type->IsNone()) {
623 : // Store is not safe if the field type was cleared.
624 : return false;
625 1405 : } else if (descriptors_field_type->IsClass()) {
626 : // Add proper code dependencies in case of stable field map(s).
627 : Handle<Map> field_owner_map(transition_map->FindFieldOwner(number),
628 214 : isolate());
629 : dependencies()->AssumeFieldOwner(field_owner_map);
630 :
631 : // Remember the field map, and try to infer a useful type.
632 214 : field_type = Type::For(descriptors_field_type->AsClass());
633 214 : field_map = descriptors_field_type->AsClass();
634 : }
635 : }
636 4517 : dependencies()->AssumeMapNotDeprecated(transition_map);
637 : // Transitioning stores are never stores to constant fields.
638 13551 : *access_info = PropertyAccessInfo::DataField(
639 : kMutable, MapList{map}, field_index, field_representation, field_type,
640 4517 : field_map, holder, transition_map);
641 4517 : return true;
642 : }
643 : return false;
644 : }
645 :
646 :
647 0 : Factory* AccessInfoFactory::factory() const { return isolate()->factory(); }
648 :
649 : } // namespace compiler
650 : } // namespace internal
651 : } // namespace v8
|