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 "src/compiler/js-native-context-specialization.h" | 5 #include "src/compiler/js-native-context-specialization.h" |
6 | 6 |
| 7 #include "src/accessors.h" |
7 #include "src/compilation-dependencies.h" | 8 #include "src/compilation-dependencies.h" |
8 #include "src/compiler/access-builder.h" | 9 #include "src/compiler/access-builder.h" |
9 #include "src/compiler/js-graph.h" | 10 #include "src/compiler/js-graph.h" |
10 #include "src/compiler/js-operator.h" | 11 #include "src/compiler/js-operator.h" |
11 #include "src/contexts.h" | 12 #include "src/contexts.h" |
12 #include "src/field-index-inl.h" | 13 #include "src/field-index-inl.h" |
13 #include "src/lookup.h" | 14 #include "src/lookup.h" |
14 #include "src/objects-inl.h" // TODO(mstarzinger): Temporary cycle breaker! | 15 #include "src/objects-inl.h" // TODO(mstarzinger): Temporary cycle breaker! |
15 #include "src/type-feedback-vector.h" | 16 #include "src/type-feedback-vector.h" |
16 | 17 |
(...skipping 225 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
242 public: | 243 public: |
243 enum Kind { kInvalid, kData, kDataConstant }; | 244 enum Kind { kInvalid, kData, kDataConstant }; |
244 | 245 |
245 static PropertyAccessInfo DataConstant(Type* receiver_type, | 246 static PropertyAccessInfo DataConstant(Type* receiver_type, |
246 Handle<Object> constant, | 247 Handle<Object> constant, |
247 MaybeHandle<JSObject> holder) { | 248 MaybeHandle<JSObject> holder) { |
248 return PropertyAccessInfo(holder, constant, receiver_type); | 249 return PropertyAccessInfo(holder, constant, receiver_type); |
249 } | 250 } |
250 static PropertyAccessInfo Data(Type* receiver_type, FieldIndex field_index, | 251 static PropertyAccessInfo Data(Type* receiver_type, FieldIndex field_index, |
251 Representation field_representation, | 252 Representation field_representation, |
| 253 Type* field_type, |
252 MaybeHandle<JSObject> holder) { | 254 MaybeHandle<JSObject> holder) { |
253 return PropertyAccessInfo(holder, field_index, field_representation, | 255 return PropertyAccessInfo(holder, field_index, field_representation, |
254 receiver_type); | 256 field_type, receiver_type); |
255 } | 257 } |
256 | 258 |
257 PropertyAccessInfo() : kind_(kInvalid) {} | 259 PropertyAccessInfo() : kind_(kInvalid) {} |
258 PropertyAccessInfo(MaybeHandle<JSObject> holder, Handle<Object> constant, | 260 PropertyAccessInfo(MaybeHandle<JSObject> holder, Handle<Object> constant, |
259 Type* receiver_type) | 261 Type* receiver_type) |
260 : kind_(kDataConstant), | 262 : kind_(kDataConstant), |
261 receiver_type_(receiver_type), | 263 receiver_type_(receiver_type), |
262 constant_(constant), | 264 constant_(constant), |
263 holder_(holder) {} | 265 holder_(holder) {} |
264 PropertyAccessInfo(MaybeHandle<JSObject> holder, FieldIndex field_index, | 266 PropertyAccessInfo(MaybeHandle<JSObject> holder, FieldIndex field_index, |
265 Representation field_representation, Type* receiver_type) | 267 Representation field_representation, Type* field_type, |
| 268 Type* receiver_type) |
266 : kind_(kData), | 269 : kind_(kData), |
267 receiver_type_(receiver_type), | 270 receiver_type_(receiver_type), |
268 holder_(holder), | 271 holder_(holder), |
269 field_index_(field_index), | 272 field_index_(field_index), |
270 field_representation_(field_representation) {} | 273 field_representation_(field_representation), |
| 274 field_type_(field_type) {} |
271 | 275 |
272 bool IsDataConstant() const { return kind() == kDataConstant; } | 276 bool IsDataConstant() const { return kind() == kDataConstant; } |
273 bool IsData() const { return kind() == kData; } | 277 bool IsData() const { return kind() == kData; } |
274 | 278 |
275 Kind kind() const { return kind_; } | 279 Kind kind() const { return kind_; } |
276 MaybeHandle<JSObject> holder() const { return holder_; } | 280 MaybeHandle<JSObject> holder() const { return holder_; } |
277 Handle<Object> constant() const { return constant_; } | 281 Handle<Object> constant() const { return constant_; } |
278 FieldIndex field_index() const { return field_index_; } | 282 FieldIndex field_index() const { return field_index_; } |
279 Representation field_representation() const { return field_representation_; } | 283 Representation field_representation() const { return field_representation_; } |
| 284 Type* field_type() const { return field_type_; } |
280 Type* receiver_type() const { return receiver_type_; } | 285 Type* receiver_type() const { return receiver_type_; } |
281 | 286 |
282 private: | 287 private: |
283 Kind kind_; | 288 Kind kind_; |
284 Type* receiver_type_; | 289 Type* receiver_type_; |
285 Handle<Object> constant_; | 290 Handle<Object> constant_; |
286 MaybeHandle<JSObject> holder_; | 291 MaybeHandle<JSObject> holder_; |
287 FieldIndex field_index_; | 292 FieldIndex field_index_; |
288 Representation field_representation_; | 293 Representation field_representation_; |
| 294 Type* field_type_ = Type::Any(); |
289 }; | 295 }; |
290 | 296 |
291 | 297 |
292 namespace { | 298 namespace { |
293 | 299 |
294 bool CanInlinePropertyAccess(Handle<Map> map) { | 300 bool CanInlinePropertyAccess(Handle<Map> map) { |
295 // TODO(bmeurer): Do something about the number stuff. | 301 // TODO(bmeurer): Do something about the number stuff. |
296 if (map->instance_type() == HEAP_NUMBER_TYPE) return false; | 302 if (map->instance_type() == HEAP_NUMBER_TYPE) return false; |
297 if (map->instance_type() < FIRST_NONSTRING_TYPE) return true; | 303 if (map->instance_type() < FIRST_NONSTRING_TYPE) return true; |
298 return map->IsJSObjectMap() && !map->is_dictionary_map() && | 304 return map->IsJSObjectMap() && !map->is_dictionary_map() && |
299 !map->has_named_interceptor() && | 305 !map->has_named_interceptor() && |
300 // TODO(verwaest): Whitelist contexts to which we have access. | 306 // TODO(verwaest): Whitelist contexts to which we have access. |
301 !map->is_access_check_needed(); | 307 !map->is_access_check_needed(); |
302 } | 308 } |
303 | 309 |
304 } // namespace | 310 } // namespace |
305 | 311 |
306 | 312 |
307 bool JSNativeContextSpecialization::ComputePropertyAccessInfo( | 313 bool JSNativeContextSpecialization::ComputePropertyAccessInfo( |
308 Handle<Map> map, Handle<Name> name, PropertyAccessInfo* access_info) { | 314 Handle<Map> map, Handle<Name> name, PropertyAccessInfo* access_info) { |
309 MaybeHandle<JSObject> holder; | 315 MaybeHandle<JSObject> holder; |
310 Type* receiver_type = Type::Class(map, graph()->zone()); | 316 Handle<Map> receiver_map = map; |
| 317 Type* receiver_type = Type::Class(receiver_map, graph()->zone()); |
311 while (CanInlinePropertyAccess(map)) { | 318 while (CanInlinePropertyAccess(map)) { |
| 319 // Check for special JSObject field accessors. |
| 320 int offset; |
| 321 if (Accessors::IsJSObjectFieldAccessor(map, name, &offset)) { |
| 322 FieldIndex field_index = FieldIndex::ForInObjectOffset(offset); |
| 323 Representation field_representation = Representation::Tagged(); |
| 324 Type* field_type = Type::Tagged(); |
| 325 if (receiver_type->Is(Type::String())) { |
| 326 DCHECK(Name::Equals(factory()->length_string(), name)); |
| 327 // The String::length property is always a smi in the range |
| 328 // [0, String::kMaxLength]. |
| 329 field_representation = Representation::Smi(); |
| 330 field_type = Type::Intersect( |
| 331 Type::Range(0.0, String::kMaxLength, graph()->zone()), |
| 332 Type::TaggedSigned(), graph()->zone()); |
| 333 } else if (receiver_map->IsJSArrayMap()) { |
| 334 DCHECK(Name::Equals(factory()->length_string(), name)); |
| 335 // The JSArray::length property is a smi in the range |
| 336 // [0, FixedDoubleArray::kMaxLength] in case of fast double |
| 337 // elements, a smi in the range [0, FixedArray::kMaxLength] |
| 338 // in case of other fast elements, and [0, kMaxUInt32-1] in |
| 339 // case of other arrays. |
| 340 double field_type_upper = kMaxUInt32 - 1; |
| 341 if (IsFastElementsKind(receiver_map->elements_kind())) { |
| 342 field_representation = Representation::Smi(); |
| 343 field_type_upper = |
| 344 IsFastDoubleElementsKind(receiver_map->elements_kind()) |
| 345 ? FixedDoubleArray::kMaxLength |
| 346 : FixedArray::kMaxLength; |
| 347 } |
| 348 field_type = |
| 349 Type::Intersect(Type::Range(0.0, field_type_upper, graph()->zone()), |
| 350 Type::TaggedSigned(), graph()->zone()); |
| 351 } |
| 352 *access_info = PropertyAccessInfo::Data( |
| 353 receiver_type, field_index, field_representation, field_type, holder); |
| 354 return true; |
| 355 } |
| 356 |
312 // Lookup the named property on the {map}. | 357 // Lookup the named property on the {map}. |
313 Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate()); | 358 Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate()); |
314 int const number = descriptors->SearchWithCache(*name, *map); | 359 int const number = descriptors->SearchWithCache(*name, *map); |
315 if (number != DescriptorArray::kNotFound) { | 360 if (number != DescriptorArray::kNotFound) { |
316 PropertyDetails const details = descriptors->GetDetails(number); | 361 PropertyDetails const details = descriptors->GetDetails(number); |
317 if (details.type() == DATA_CONSTANT) { | 362 if (details.type() == DATA_CONSTANT) { |
318 *access_info = PropertyAccessInfo::DataConstant( | 363 *access_info = PropertyAccessInfo::DataConstant( |
319 receiver_type, handle(descriptors->GetValue(number), isolate()), | 364 receiver_type, handle(descriptors->GetValue(number), isolate()), |
320 holder); | 365 holder); |
321 return true; | 366 return true; |
322 } else if (details.type() == DATA) { | 367 } else if (details.type() == DATA) { |
323 int index = descriptors->GetFieldIndex(number); | 368 int index = descriptors->GetFieldIndex(number); |
324 Representation field_representation = details.representation(); | 369 Representation field_representation = details.representation(); |
325 FieldIndex field_index = FieldIndex::ForPropertyIndex( | 370 FieldIndex field_index = FieldIndex::ForPropertyIndex( |
326 *map, index, field_representation.IsDouble()); | 371 *map, index, field_representation.IsDouble()); |
327 *access_info = PropertyAccessInfo::Data(receiver_type, field_index, | 372 Type* field_type = Type::Any(); |
328 field_representation, holder); | 373 if (field_representation.IsSmi()) { |
| 374 field_type = Type::Intersect(Type::SignedSmall(), |
| 375 Type::TaggedSigned(), graph()->zone()); |
| 376 } else if (field_representation.IsDouble()) { |
| 377 field_type = Type::Intersect(Type::Number(), Type::UntaggedFloat64(), |
| 378 graph()->zone()); |
| 379 } else if (field_representation.IsHeapObject()) { |
| 380 field_type = Type::TaggedPointer(); |
| 381 } |
| 382 *access_info = |
| 383 PropertyAccessInfo::Data(receiver_type, field_index, |
| 384 field_representation, field_type, holder); |
329 return true; | 385 return true; |
330 } else { | 386 } else { |
331 // TODO(bmeurer): Add support for accessors. | 387 // TODO(bmeurer): Add support for accessors. |
332 break; | 388 break; |
333 } | 389 } |
334 } | 390 } |
335 | 391 |
336 // Don't search on the prototype chain for special indices in case of | 392 // Don't search on the prototype chain for special indices in case of |
337 // integer indexed exotic objects (see ES6 section 9.4.5). | 393 // integer indexed exotic objects (see ES6 section 9.4.5). |
338 if (map->IsJSTypedArrayMap() && name->IsString() && | 394 if (map->IsJSTypedArrayMap() && name->IsString() && |
(...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
503 // Generate the actual property access. | 559 // Generate the actual property access. |
504 if (access_info.IsDataConstant()) { | 560 if (access_info.IsDataConstant()) { |
505 this_value = jsgraph()->Constant(access_info.constant()); | 561 this_value = jsgraph()->Constant(access_info.constant()); |
506 } else { | 562 } else { |
507 // TODO(bmeurer): This is sort of adhoc, and must be refactored into some | 563 // TODO(bmeurer): This is sort of adhoc, and must be refactored into some |
508 // common code once we also have support for stores. | 564 // common code once we also have support for stores. |
509 DCHECK(access_info.IsData()); | 565 DCHECK(access_info.IsData()); |
510 FieldIndex const field_index = access_info.field_index(); | 566 FieldIndex const field_index = access_info.field_index(); |
511 Representation const field_representation = | 567 Representation const field_representation = |
512 access_info.field_representation(); | 568 access_info.field_representation(); |
| 569 Type* const field_type = access_info.field_type(); |
513 if (!field_index.is_inobject()) { | 570 if (!field_index.is_inobject()) { |
514 this_value = this_effect = graph()->NewNode( | 571 this_value = this_effect = graph()->NewNode( |
515 simplified()->LoadField(AccessBuilder::ForJSObjectProperties()), | 572 simplified()->LoadField(AccessBuilder::ForJSObjectProperties()), |
516 this_value, this_effect, this_control); | 573 this_value, this_effect, this_control); |
517 } | 574 } |
518 FieldAccess field_access; | 575 FieldAccess field_access; |
519 field_access.base_is_tagged = kTaggedBase; | 576 field_access.base_is_tagged = kTaggedBase; |
520 field_access.offset = field_index.offset(); | 577 field_access.offset = field_index.offset(); |
521 field_access.name = name; | 578 field_access.name = name; |
522 field_access.type = Type::Any(); | 579 field_access.type = field_type; |
523 field_access.machine_type = kMachAnyTagged; | 580 field_access.machine_type = kMachAnyTagged; |
524 if (field_representation.IsSmi()) { | 581 if (field_representation.IsDouble()) { |
525 field_access.type = Type::Intersect( | |
526 Type::SignedSmall(), Type::TaggedSigned(), graph()->zone()); | |
527 } else if (field_representation.IsDouble()) { | |
528 if (!field_index.is_inobject() || field_index.is_hidden_field() || | 582 if (!field_index.is_inobject() || field_index.is_hidden_field() || |
529 !FLAG_unbox_double_fields) { | 583 !FLAG_unbox_double_fields) { |
530 this_value = this_effect = | 584 this_value = this_effect = |
531 graph()->NewNode(simplified()->LoadField(field_access), | 585 graph()->NewNode(simplified()->LoadField(field_access), |
532 this_value, this_effect, this_control); | 586 this_value, this_effect, this_control); |
533 field_access.offset = HeapNumber::kValueOffset; | 587 field_access.offset = HeapNumber::kValueOffset; |
534 field_access.name = MaybeHandle<Name>(); | 588 field_access.name = MaybeHandle<Name>(); |
535 } | 589 } |
536 field_access.type = Type::Intersect( | |
537 Type::Number(), Type::UntaggedFloat64(), graph()->zone()); | |
538 field_access.machine_type = kMachFloat64; | 590 field_access.machine_type = kMachFloat64; |
539 } else if (field_representation.IsHeapObject()) { | |
540 field_access.type = Type::TaggedPointer(); | |
541 } | 591 } |
542 this_value = this_effect = | 592 this_value = this_effect = |
543 graph()->NewNode(simplified()->LoadField(field_access), this_value, | 593 graph()->NewNode(simplified()->LoadField(field_access), this_value, |
544 this_effect, this_control); | 594 this_effect, this_control); |
545 } | 595 } |
546 | 596 |
547 // Remember the final state for this property access. | 597 // Remember the final state for this property access. |
548 values.push_back(this_value); | 598 values.push_back(this_value); |
549 effects.push_back(this_effect); | 599 effects.push_back(this_effect); |
550 controls.push_back(this_control); | 600 controls.push_back(this_control); |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
633 Graph* JSNativeContextSpecialization::graph() const { | 683 Graph* JSNativeContextSpecialization::graph() const { |
634 return jsgraph()->graph(); | 684 return jsgraph()->graph(); |
635 } | 685 } |
636 | 686 |
637 | 687 |
638 Isolate* JSNativeContextSpecialization::isolate() const { | 688 Isolate* JSNativeContextSpecialization::isolate() const { |
639 return jsgraph()->isolate(); | 689 return jsgraph()->isolate(); |
640 } | 690 } |
641 | 691 |
642 | 692 |
| 693 Factory* JSNativeContextSpecialization::factory() const { |
| 694 return isolate()->factory(); |
| 695 } |
| 696 |
| 697 |
643 MachineOperatorBuilder* JSNativeContextSpecialization::machine() const { | 698 MachineOperatorBuilder* JSNativeContextSpecialization::machine() const { |
644 return jsgraph()->machine(); | 699 return jsgraph()->machine(); |
645 } | 700 } |
646 | 701 |
647 | 702 |
648 CommonOperatorBuilder* JSNativeContextSpecialization::common() const { | 703 CommonOperatorBuilder* JSNativeContextSpecialization::common() const { |
649 return jsgraph()->common(); | 704 return jsgraph()->common(); |
650 } | 705 } |
651 | 706 |
652 | 707 |
653 JSOperatorBuilder* JSNativeContextSpecialization::javascript() const { | 708 JSOperatorBuilder* JSNativeContextSpecialization::javascript() const { |
654 return jsgraph()->javascript(); | 709 return jsgraph()->javascript(); |
655 } | 710 } |
656 | 711 |
657 | 712 |
658 SimplifiedOperatorBuilder* JSNativeContextSpecialization::simplified() const { | 713 SimplifiedOperatorBuilder* JSNativeContextSpecialization::simplified() const { |
659 return jsgraph()->simplified(); | 714 return jsgraph()->simplified(); |
660 } | 715 } |
661 | 716 |
662 } // namespace compiler | 717 } // namespace compiler |
663 } // namespace internal | 718 } // namespace internal |
664 } // namespace v8 | 719 } // namespace v8 |
OLD | NEW |