OLD | NEW |
1 // Copyright 2015 the V8 project authors. All rights reserved. | 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 | 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 | 4 |
5 #include <ostream> | 5 #include <ostream> |
6 | 6 |
7 #include "src/accessors.h" | 7 #include "src/accessors.h" |
8 #include "src/compilation-dependencies.h" | 8 #include "src/compilation-dependencies.h" |
9 #include "src/compiler/access-info.h" | 9 #include "src/compiler/access-info.h" |
10 #include "src/field-index-inl.h" | 10 #include "src/field-index-inl.h" |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
49 switch (access_mode) { | 49 switch (access_mode) { |
50 case AccessMode::kLoad: | 50 case AccessMode::kLoad: |
51 return os << "Load"; | 51 return os << "Load"; |
52 case AccessMode::kStore: | 52 case AccessMode::kStore: |
53 return os << "Store"; | 53 return os << "Store"; |
54 } | 54 } |
55 UNREACHABLE(); | 55 UNREACHABLE(); |
56 return os; | 56 return os; |
57 } | 57 } |
58 | 58 |
| 59 ElementAccessInfo::ElementAccessInfo() {} |
59 | 60 |
60 // static | 61 ElementAccessInfo::ElementAccessInfo(MapList const& receiver_maps, |
61 PropertyAccessInfo PropertyAccessInfo::NotFound(Type* receiver_type, | |
62 MaybeHandle<JSObject> holder) { | |
63 return PropertyAccessInfo(holder, receiver_type); | |
64 } | |
65 | |
66 | |
67 // static | |
68 PropertyAccessInfo PropertyAccessInfo::DataConstant( | |
69 Type* receiver_type, Handle<Object> constant, | |
70 MaybeHandle<JSObject> holder) { | |
71 return PropertyAccessInfo(holder, constant, receiver_type); | |
72 } | |
73 | |
74 | |
75 // static | |
76 PropertyAccessInfo PropertyAccessInfo::DataField( | |
77 Type* receiver_type, FieldIndex field_index, Type* field_type, | |
78 MaybeHandle<JSObject> holder, MaybeHandle<Map> transition_map) { | |
79 return PropertyAccessInfo(holder, transition_map, field_index, field_type, | |
80 receiver_type); | |
81 } | |
82 | |
83 | |
84 ElementAccessInfo::ElementAccessInfo() : receiver_type_(Type::None()) {} | |
85 | |
86 | |
87 ElementAccessInfo::ElementAccessInfo(Type* receiver_type, | |
88 ElementsKind elements_kind, | 62 ElementsKind elements_kind, |
89 MaybeHandle<JSObject> holder) | 63 MaybeHandle<JSObject> holder) |
90 : elements_kind_(elements_kind), | 64 : elements_kind_(elements_kind), |
91 holder_(holder), | 65 holder_(holder), |
92 receiver_type_(receiver_type) {} | 66 receiver_maps_(receiver_maps) {} |
93 | 67 |
| 68 // static |
| 69 PropertyAccessInfo PropertyAccessInfo::NotFound(MapList const& receiver_maps, |
| 70 MaybeHandle<JSObject> holder) { |
| 71 return PropertyAccessInfo(holder, receiver_maps); |
| 72 } |
| 73 |
| 74 // static |
| 75 PropertyAccessInfo PropertyAccessInfo::DataConstant( |
| 76 MapList const& receiver_maps, Handle<Object> constant, |
| 77 MaybeHandle<JSObject> holder) { |
| 78 return PropertyAccessInfo(holder, constant, receiver_maps); |
| 79 } |
| 80 |
| 81 // static |
| 82 PropertyAccessInfo PropertyAccessInfo::DataField( |
| 83 MapList const& receiver_maps, FieldIndex field_index, Type* field_type, |
| 84 MaybeHandle<JSObject> holder, MaybeHandle<Map> transition_map) { |
| 85 return PropertyAccessInfo(holder, transition_map, field_index, field_type, |
| 86 receiver_maps); |
| 87 } |
94 | 88 |
95 PropertyAccessInfo::PropertyAccessInfo() | 89 PropertyAccessInfo::PropertyAccessInfo() |
96 : kind_(kInvalid), receiver_type_(Type::None()), field_type_(Type::Any()) {} | 90 : kind_(kInvalid), field_type_(Type::Any()) {} |
97 | |
98 | 91 |
99 PropertyAccessInfo::PropertyAccessInfo(MaybeHandle<JSObject> holder, | 92 PropertyAccessInfo::PropertyAccessInfo(MaybeHandle<JSObject> holder, |
100 Type* receiver_type) | 93 MapList const& receiver_maps) |
101 : kind_(kNotFound), | 94 : kind_(kNotFound), |
102 receiver_type_(receiver_type), | 95 receiver_maps_(receiver_maps), |
103 holder_(holder), | 96 holder_(holder), |
104 field_type_(Type::Any()) {} | 97 field_type_(Type::Any()) {} |
105 | 98 |
106 | |
107 PropertyAccessInfo::PropertyAccessInfo(MaybeHandle<JSObject> holder, | 99 PropertyAccessInfo::PropertyAccessInfo(MaybeHandle<JSObject> holder, |
108 Handle<Object> constant, | 100 Handle<Object> constant, |
109 Type* receiver_type) | 101 MapList const& receiver_maps) |
110 : kind_(kDataConstant), | 102 : kind_(kDataConstant), |
111 receiver_type_(receiver_type), | 103 receiver_maps_(receiver_maps), |
112 constant_(constant), | 104 constant_(constant), |
113 holder_(holder), | 105 holder_(holder), |
114 field_type_(Type::Any()) {} | 106 field_type_(Type::Any()) {} |
115 | 107 |
116 PropertyAccessInfo::PropertyAccessInfo(MaybeHandle<JSObject> holder, | 108 PropertyAccessInfo::PropertyAccessInfo(MaybeHandle<JSObject> holder, |
117 MaybeHandle<Map> transition_map, | 109 MaybeHandle<Map> transition_map, |
118 FieldIndex field_index, Type* field_type, | 110 FieldIndex field_index, Type* field_type, |
119 Type* receiver_type) | 111 MapList const& receiver_maps) |
120 : kind_(kDataField), | 112 : kind_(kDataField), |
121 receiver_type_(receiver_type), | 113 receiver_maps_(receiver_maps), |
122 transition_map_(transition_map), | 114 transition_map_(transition_map), |
123 holder_(holder), | 115 holder_(holder), |
124 field_index_(field_index), | 116 field_index_(field_index), |
125 field_type_(field_type) {} | 117 field_type_(field_type) {} |
126 | 118 |
| 119 bool PropertyAccessInfo::Merge(PropertyAccessInfo const* that) { |
| 120 if (this->kind_ != that->kind_) return false; |
| 121 if (this->holder_.address() != that->holder_.address()) return false; |
| 122 |
| 123 switch (this->kind_) { |
| 124 case kInvalid: |
| 125 break; |
| 126 |
| 127 case kNotFound: |
| 128 return true; |
| 129 |
| 130 case kDataField: { |
| 131 // Check if we actually access the same field. |
| 132 if (this->transition_map_.address() == that->transition_map_.address() && |
| 133 this->field_index_ == that->field_index_ && |
| 134 this->field_type_->Is(that->field_type_) && |
| 135 that->field_type_->Is(this->field_type_)) { |
| 136 this->receiver_maps_.insert(this->receiver_maps_.end(), |
| 137 that->receiver_maps_.begin(), |
| 138 that->receiver_maps_.end()); |
| 139 return true; |
| 140 } |
| 141 return false; |
| 142 } |
| 143 |
| 144 case kDataConstant: { |
| 145 // Check if we actually access the same constant. |
| 146 if (this->constant_.address() == that->constant_.address()) { |
| 147 this->receiver_maps_.insert(this->receiver_maps_.end(), |
| 148 that->receiver_maps_.begin(), |
| 149 that->receiver_maps_.end()); |
| 150 return true; |
| 151 } |
| 152 return false; |
| 153 } |
| 154 } |
| 155 |
| 156 UNREACHABLE(); |
| 157 return false; |
| 158 } |
| 159 |
127 AccessInfoFactory::AccessInfoFactory(CompilationDependencies* dependencies, | 160 AccessInfoFactory::AccessInfoFactory(CompilationDependencies* dependencies, |
128 Handle<Context> native_context, Zone* zone) | 161 Handle<Context> native_context, Zone* zone) |
129 : dependencies_(dependencies), | 162 : dependencies_(dependencies), |
130 native_context_(native_context), | 163 native_context_(native_context), |
131 isolate_(native_context->GetIsolate()), | 164 isolate_(native_context->GetIsolate()), |
132 type_cache_(TypeCache::Get()), | 165 type_cache_(TypeCache::Get()), |
133 zone_(zone) { | 166 zone_(zone) { |
134 DCHECK(native_context->IsNativeContext()); | 167 DCHECK(native_context->IsNativeContext()); |
135 } | 168 } |
136 | 169 |
(...skipping 17 matching lines...) Expand all Loading... |
154 // TODO(bmeurer): We do not currently support unstable prototypes. | 187 // TODO(bmeurer): We do not currently support unstable prototypes. |
155 // We might want to revisit the way we handle certain keyed stores | 188 // We might want to revisit the way we handle certain keyed stores |
156 // because this whole prototype chain check is essential a hack, | 189 // because this whole prototype chain check is essential a hack, |
157 // and I'm not sure that it is correct at all with dictionaries in | 190 // and I'm not sure that it is correct at all with dictionaries in |
158 // the prototype chain. | 191 // the prototype chain. |
159 if (!prototype->map()->is_stable()) return false; | 192 if (!prototype->map()->is_stable()) return false; |
160 holder = Handle<JSObject>::cast(prototype); | 193 holder = Handle<JSObject>::cast(prototype); |
161 } | 194 } |
162 } | 195 } |
163 | 196 |
164 *access_info = | 197 *access_info = ElementAccessInfo(MapList{map}, elements_kind, holder); |
165 ElementAccessInfo(Type::Class(map, zone()), elements_kind, holder); | |
166 return true; | 198 return true; |
167 } | 199 } |
168 | 200 |
169 | 201 |
170 bool AccessInfoFactory::ComputeElementAccessInfos( | 202 bool AccessInfoFactory::ComputeElementAccessInfos( |
171 MapHandleList const& maps, AccessMode access_mode, | 203 MapHandleList const& maps, AccessMode access_mode, |
172 ZoneVector<ElementAccessInfo>* access_infos) { | 204 ZoneVector<ElementAccessInfo>* access_infos) { |
173 // Collect possible transition targets. | 205 // Collect possible transition targets. |
174 MapHandleList possible_transition_targets(maps.length()); | 206 MapHandleList possible_transition_targets(maps.length()); |
175 for (Handle<Map> map : maps) { | 207 for (Handle<Map> map : maps) { |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
251 // Check for store to data property on a prototype. | 283 // Check for store to data property on a prototype. |
252 if (details.kind() == kData && !holder.is_null()) { | 284 if (details.kind() == kData && !holder.is_null()) { |
253 // Store to property not found on the receiver but on a prototype, we | 285 // Store to property not found on the receiver but on a prototype, we |
254 // need to transition to a new data property. | 286 // need to transition to a new data property. |
255 // Implemented according to ES6 section 9.1.9 [[Set]] (P, V, Receiver) | 287 // Implemented according to ES6 section 9.1.9 [[Set]] (P, V, Receiver) |
256 return LookupTransition(receiver_map, name, holder, access_info); | 288 return LookupTransition(receiver_map, name, holder, access_info); |
257 } | 289 } |
258 } | 290 } |
259 if (details.type() == DATA_CONSTANT) { | 291 if (details.type() == DATA_CONSTANT) { |
260 *access_info = PropertyAccessInfo::DataConstant( | 292 *access_info = PropertyAccessInfo::DataConstant( |
261 Type::Class(receiver_map, zone()), | 293 MapList{receiver_map}, |
262 handle(descriptors->GetValue(number), isolate()), holder); | 294 handle(descriptors->GetValue(number), isolate()), holder); |
263 return true; | 295 return true; |
264 } else if (details.type() == DATA) { | 296 } else if (details.type() == DATA) { |
265 int index = descriptors->GetFieldIndex(number); | 297 int index = descriptors->GetFieldIndex(number); |
266 Representation field_representation = details.representation(); | 298 Representation field_representation = details.representation(); |
267 FieldIndex field_index = FieldIndex::ForPropertyIndex( | 299 FieldIndex field_index = FieldIndex::ForPropertyIndex( |
268 *map, index, field_representation.IsDouble()); | 300 *map, index, field_representation.IsDouble()); |
269 Type* field_type = Type::Tagged(); | 301 Type* field_type = Type::Tagged(); |
270 if (field_representation.IsSmi()) { | 302 if (field_representation.IsSmi()) { |
271 field_type = type_cache_.kSmi; | 303 field_type = type_cache_.kSmi; |
(...skipping 15 matching lines...) Expand all Loading... |
287 // runtime/GC interaction. | 319 // runtime/GC interaction. |
288 field_type = Type::TaggedPointer(); | 320 field_type = Type::TaggedPointer(); |
289 } else if (!Type::Any()->Is(field_type)) { | 321 } else if (!Type::Any()->Is(field_type)) { |
290 // Add proper code dependencies in case of stable field map(s). | 322 // Add proper code dependencies in case of stable field map(s). |
291 Handle<Map> field_owner_map(map->FindFieldOwner(number), isolate()); | 323 Handle<Map> field_owner_map(map->FindFieldOwner(number), isolate()); |
292 dependencies()->AssumeFieldType(field_owner_map); | 324 dependencies()->AssumeFieldType(field_owner_map); |
293 } | 325 } |
294 DCHECK(field_type->Is(Type::TaggedPointer())); | 326 DCHECK(field_type->Is(Type::TaggedPointer())); |
295 } | 327 } |
296 *access_info = PropertyAccessInfo::DataField( | 328 *access_info = PropertyAccessInfo::DataField( |
297 Type::Class(receiver_map, zone()), field_index, field_type, holder); | 329 MapList{receiver_map}, field_index, field_type, holder); |
298 return true; | 330 return true; |
299 } else { | 331 } else { |
300 // TODO(bmeurer): Add support for accessors. | 332 // TODO(bmeurer): Add support for accessors. |
301 return false; | 333 return false; |
302 } | 334 } |
303 } | 335 } |
304 | 336 |
305 // Don't search on the prototype chain for special indices in case of | 337 // Don't search on the prototype chain for special indices in case of |
306 // integer indexed exotic objects (see ES6 section 9.4.5). | 338 // integer indexed exotic objects (see ES6 section 9.4.5). |
307 if (map->IsJSTypedArrayMap() && name->IsString() && | 339 if (map->IsJSTypedArrayMap() && name->IsString() && |
(...skipping 16 matching lines...) Expand all Loading... |
324 } else if (map->prototype()->IsNull(isolate())) { | 356 } else if (map->prototype()->IsNull(isolate())) { |
325 // Store to property not found on the receiver or any prototype, we need | 357 // Store to property not found on the receiver or any prototype, we need |
326 // to transition to a new data property. | 358 // to transition to a new data property. |
327 // Implemented according to ES6 section 9.1.9 [[Set]] (P, V, Receiver) | 359 // Implemented according to ES6 section 9.1.9 [[Set]] (P, V, Receiver) |
328 if (access_mode == AccessMode::kStore) { | 360 if (access_mode == AccessMode::kStore) { |
329 return LookupTransition(receiver_map, name, holder, access_info); | 361 return LookupTransition(receiver_map, name, holder, access_info); |
330 } | 362 } |
331 // The property was not found, return undefined or throw depending | 363 // The property was not found, return undefined or throw depending |
332 // on the language mode of the load operation. | 364 // on the language mode of the load operation. |
333 // Implemented according to ES6 section 9.1.8 [[Get]] (P, Receiver) | 365 // Implemented according to ES6 section 9.1.8 [[Get]] (P, Receiver) |
334 *access_info = PropertyAccessInfo::NotFound( | 366 *access_info = |
335 Type::Class(receiver_map, zone()), holder); | 367 PropertyAccessInfo::NotFound(MapList{receiver_map}, holder); |
336 return true; | 368 return true; |
337 } else { | 369 } else { |
338 return false; | 370 return false; |
339 } | 371 } |
340 } | 372 } |
341 Handle<JSObject> map_prototype(JSObject::cast(map->prototype()), isolate()); | 373 Handle<JSObject> map_prototype(JSObject::cast(map->prototype()), isolate()); |
342 if (map_prototype->map()->is_deprecated()) { | 374 if (map_prototype->map()->is_deprecated()) { |
343 // Try to migrate the prototype object so we don't embed the deprecated | 375 // Try to migrate the prototype object so we don't embed the deprecated |
344 // map into the optimized code. | 376 // map into the optimized code. |
345 JSObject::TryMigrateInstance(map_prototype); | 377 JSObject::TryMigrateInstance(map_prototype); |
346 } | 378 } |
347 map = handle(map_prototype->map(), isolate()); | 379 map = handle(map_prototype->map(), isolate()); |
348 holder = map_prototype; | 380 holder = map_prototype; |
349 } while (CanInlinePropertyAccess(map)); | 381 } while (CanInlinePropertyAccess(map)); |
350 return false; | 382 return false; |
351 } | 383 } |
352 | 384 |
353 | |
354 bool AccessInfoFactory::ComputePropertyAccessInfos( | 385 bool AccessInfoFactory::ComputePropertyAccessInfos( |
355 MapHandleList const& maps, Handle<Name> name, AccessMode access_mode, | 386 MapHandleList const& maps, Handle<Name> name, AccessMode access_mode, |
356 ZoneVector<PropertyAccessInfo>* access_infos) { | 387 ZoneVector<PropertyAccessInfo>* access_infos) { |
357 for (Handle<Map> map : maps) { | 388 for (Handle<Map> map : maps) { |
358 if (Map::TryUpdate(map).ToHandle(&map)) { | 389 if (Map::TryUpdate(map).ToHandle(&map)) { |
359 PropertyAccessInfo access_info; | 390 PropertyAccessInfo access_info; |
360 if (!ComputePropertyAccessInfo(map, name, access_mode, &access_info)) { | 391 if (!ComputePropertyAccessInfo(map, name, access_mode, &access_info)) { |
361 return false; | 392 return false; |
362 } | 393 } |
363 access_infos->push_back(access_info); | 394 // Try to merge the {access_info} with an existing one. |
| 395 bool merged = false; |
| 396 for (PropertyAccessInfo& other_info : *access_infos) { |
| 397 if (other_info.Merge(&access_info)) { |
| 398 merged = true; |
| 399 break; |
| 400 } |
| 401 } |
| 402 if (!merged) access_infos->push_back(access_info); |
364 } | 403 } |
365 } | 404 } |
366 return true; | 405 return true; |
367 } | 406 } |
368 | 407 |
369 | 408 |
370 bool AccessInfoFactory::LookupSpecialFieldAccessor( | 409 bool AccessInfoFactory::LookupSpecialFieldAccessor( |
371 Handle<Map> map, Handle<Name> name, PropertyAccessInfo* access_info) { | 410 Handle<Map> map, Handle<Name> name, PropertyAccessInfo* access_info) { |
372 // Check for special JSObject field accessors. | 411 // Check for special JSObject field accessors. |
373 int offset; | 412 int offset; |
(...skipping 13 matching lines...) Expand all Loading... |
387 // in case of other fast elements, and [0, kMaxUInt32] in | 426 // in case of other fast elements, and [0, kMaxUInt32] in |
388 // case of other arrays. | 427 // case of other arrays. |
389 if (IsFastDoubleElementsKind(map->elements_kind())) { | 428 if (IsFastDoubleElementsKind(map->elements_kind())) { |
390 field_type = type_cache_.kFixedDoubleArrayLengthType; | 429 field_type = type_cache_.kFixedDoubleArrayLengthType; |
391 } else if (IsFastElementsKind(map->elements_kind())) { | 430 } else if (IsFastElementsKind(map->elements_kind())) { |
392 field_type = type_cache_.kFixedArrayLengthType; | 431 field_type = type_cache_.kFixedArrayLengthType; |
393 } else { | 432 } else { |
394 field_type = type_cache_.kJSArrayLengthType; | 433 field_type = type_cache_.kJSArrayLengthType; |
395 } | 434 } |
396 } | 435 } |
397 *access_info = PropertyAccessInfo::DataField(Type::Class(map, zone()), | 436 *access_info = |
398 field_index, field_type); | 437 PropertyAccessInfo::DataField(MapList{map}, field_index, field_type); |
399 return true; | 438 return true; |
400 } | 439 } |
401 return false; | 440 return false; |
402 } | 441 } |
403 | 442 |
404 | 443 |
405 bool AccessInfoFactory::LookupTransition(Handle<Map> map, Handle<Name> name, | 444 bool AccessInfoFactory::LookupTransition(Handle<Map> map, Handle<Name> name, |
406 MaybeHandle<JSObject> holder, | 445 MaybeHandle<JSObject> holder, |
407 PropertyAccessInfo* access_info) { | 446 PropertyAccessInfo* access_info) { |
408 // Check if the {map} has a data transition with the given {name}. | 447 // Check if the {map} has a data transition with the given {name}. |
(...skipping 29 matching lines...) Expand all Loading... |
438 return false; | 477 return false; |
439 } else if (!Type::Any()->Is(field_type)) { | 478 } else if (!Type::Any()->Is(field_type)) { |
440 // Add proper code dependencies in case of stable field map(s). | 479 // Add proper code dependencies in case of stable field map(s). |
441 Handle<Map> field_owner_map(transition_map->FindFieldOwner(number), | 480 Handle<Map> field_owner_map(transition_map->FindFieldOwner(number), |
442 isolate()); | 481 isolate()); |
443 dependencies()->AssumeFieldType(field_owner_map); | 482 dependencies()->AssumeFieldType(field_owner_map); |
444 } | 483 } |
445 DCHECK(field_type->Is(Type::TaggedPointer())); | 484 DCHECK(field_type->Is(Type::TaggedPointer())); |
446 } | 485 } |
447 dependencies()->AssumeMapNotDeprecated(transition_map); | 486 dependencies()->AssumeMapNotDeprecated(transition_map); |
448 *access_info = | 487 *access_info = PropertyAccessInfo::DataField( |
449 PropertyAccessInfo::DataField(Type::Class(map, zone()), field_index, | 488 MapList{map}, field_index, field_type, holder, transition_map); |
450 field_type, holder, transition_map); | |
451 return true; | 489 return true; |
452 } | 490 } |
453 return false; | 491 return false; |
454 } | 492 } |
455 | 493 |
456 | 494 |
457 Factory* AccessInfoFactory::factory() const { return isolate()->factory(); } | 495 Factory* AccessInfoFactory::factory() const { return isolate()->factory(); } |
458 | 496 |
459 } // namespace compiler | 497 } // namespace compiler |
460 } // namespace internal | 498 } // namespace internal |
461 } // namespace v8 | 499 } // namespace v8 |
OLD | NEW |