Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(468)

Side by Side Diff: src/compiler/js-native-context-specialization.cc

Issue 1406153010: [turbofan] Initial support for transitioning stores. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Fix non-inobject properties. Created 5 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/compilation-dependencies.cc ('k') | src/type-cache.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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/accessors.h"
8 #include "src/compilation-dependencies.h" 8 #include "src/compilation-dependencies.h"
9 #include "src/compiler/access-builder.h" 9 #include "src/compiler/access-builder.h"
10 #include "src/compiler/js-graph.h" 10 #include "src/compiler/js-graph.h"
(...skipping 230 matching lines...) Expand 10 before | Expand all | Expand 10 after
241 simplified()->StoreField(AccessBuilder::ForPropertyCellValue()), 241 simplified()->StoreField(AccessBuilder::ForPropertyCellValue()),
242 jsgraph()->Constant(property_cell), value, effect, control); 242 jsgraph()->Constant(property_cell), value, effect, control);
243 return Replace(node, value, effect, control); 243 return Replace(node, value, effect, control);
244 } 244 }
245 245
246 246
247 // This class encapsulates all information required to access a certain 247 // This class encapsulates all information required to access a certain
248 // object property, either on the object itself or on the prototype chain. 248 // object property, either on the object itself or on the prototype chain.
249 class JSNativeContextSpecialization::PropertyAccessInfo final { 249 class JSNativeContextSpecialization::PropertyAccessInfo final {
250 public: 250 public:
251 enum Kind { kInvalid, kDataConstant, kDataField }; 251 enum Kind { kInvalid, kDataConstant, kDataField, kTransitionToField };
252 252
253 static PropertyAccessInfo DataConstant(Type* receiver_type, 253 static PropertyAccessInfo DataConstant(Type* receiver_type,
254 Handle<Object> constant, 254 Handle<Object> constant,
255 MaybeHandle<JSObject> holder) { 255 MaybeHandle<JSObject> holder) {
256 return PropertyAccessInfo(holder, constant, receiver_type); 256 return PropertyAccessInfo(holder, constant, receiver_type);
257 } 257 }
258 static PropertyAccessInfo DataField(Type* receiver_type, 258 static PropertyAccessInfo DataField(
259 FieldIndex field_index, Type* field_type, 259 Type* receiver_type, FieldIndex field_index, Type* field_type,
260 MaybeHandle<JSObject> holder) { 260 MaybeHandle<JSObject> holder = MaybeHandle<JSObject>()) {
261 return PropertyAccessInfo(holder, field_index, field_type, receiver_type); 261 return PropertyAccessInfo(holder, field_index, field_type, receiver_type);
262 } 262 }
263 static PropertyAccessInfo TransitionToField(Type* receiver_type,
264 FieldIndex field_index,
265 Type* field_type,
266 Handle<Map> transition_map,
267 MaybeHandle<JSObject> holder) {
268 return PropertyAccessInfo(holder, transition_map, field_index, field_type,
269 receiver_type);
270 }
263 271
264 PropertyAccessInfo() : kind_(kInvalid) {} 272 PropertyAccessInfo() : kind_(kInvalid) {}
265 PropertyAccessInfo(MaybeHandle<JSObject> holder, Handle<Object> constant, 273 PropertyAccessInfo(MaybeHandle<JSObject> holder, Handle<Object> constant,
266 Type* receiver_type) 274 Type* receiver_type)
267 : kind_(kDataConstant), 275 : kind_(kDataConstant),
268 receiver_type_(receiver_type), 276 receiver_type_(receiver_type),
269 constant_(constant), 277 constant_(constant),
270 holder_(holder) {} 278 holder_(holder) {}
271 PropertyAccessInfo(MaybeHandle<JSObject> holder, FieldIndex field_index, 279 PropertyAccessInfo(MaybeHandle<JSObject> holder, FieldIndex field_index,
272 Type* field_type, Type* receiver_type) 280 Type* field_type, Type* receiver_type)
273 : kind_(kDataField), 281 : kind_(kDataField),
274 receiver_type_(receiver_type), 282 receiver_type_(receiver_type),
275 holder_(holder), 283 holder_(holder),
276 field_index_(field_index), 284 field_index_(field_index),
277 field_type_(field_type) {} 285 field_type_(field_type) {}
286 PropertyAccessInfo(MaybeHandle<JSObject> holder, Handle<Map> transition_map,
287 FieldIndex field_index, Type* field_type,
288 Type* receiver_type)
289 : kind_(kTransitionToField),
290 receiver_type_(receiver_type),
291 transition_map_(transition_map),
292 holder_(holder),
293 field_index_(field_index),
294 field_type_(field_type) {}
278 295
279 bool IsDataConstant() const { return kind() == kDataConstant; } 296 bool IsDataConstant() const { return kind() == kDataConstant; }
280 bool IsDataField() const { return kind() == kDataField; } 297 bool IsDataField() const { return kind() == kDataField; }
298 bool IsTransitionToField() const { return kind() == kTransitionToField; }
281 299
282 Kind kind() const { return kind_; } 300 Kind kind() const { return kind_; }
283 MaybeHandle<JSObject> holder() const { return holder_; } 301 MaybeHandle<JSObject> holder() const { return holder_; }
284 Handle<Object> constant() const { return constant_; } 302 Handle<Object> constant() const { return constant_; }
303 Handle<Object> transition_map() const { return transition_map_; }
285 FieldIndex field_index() const { return field_index_; } 304 FieldIndex field_index() const { return field_index_; }
286 Type* field_type() const { return field_type_; } 305 Type* field_type() const { return field_type_; }
287 Type* receiver_type() const { return receiver_type_; } 306 Type* receiver_type() const { return receiver_type_; }
288 307
289 private: 308 private:
290 Kind kind_; 309 Kind kind_;
291 Type* receiver_type_; 310 Type* receiver_type_;
292 Handle<Object> constant_; 311 Handle<Object> constant_;
312 Handle<Map> transition_map_;
293 MaybeHandle<JSObject> holder_; 313 MaybeHandle<JSObject> holder_;
294 FieldIndex field_index_; 314 FieldIndex field_index_;
295 Type* field_type_ = Type::Any(); 315 Type* field_type_ = Type::Any();
296 }; 316 };
297 317
298 318
299 namespace { 319 namespace {
300 320
301 bool CanInlinePropertyAccess(Handle<Map> map) { 321 bool CanInlinePropertyAccess(Handle<Map> map) {
302 // TODO(bmeurer): Do something about the number stuff. 322 // TODO(bmeurer): Do something about the number stuff.
303 if (map->instance_type() == HEAP_NUMBER_TYPE) return false; 323 if (map->instance_type() == HEAP_NUMBER_TYPE) return false;
304 if (map->instance_type() < FIRST_NONSTRING_TYPE) return true; 324 if (map->instance_type() < FIRST_NONSTRING_TYPE) return true;
305 return map->IsJSObjectMap() && !map->is_dictionary_map() && 325 return map->IsJSObjectMap() && !map->is_dictionary_map() &&
306 !map->has_named_interceptor() && 326 !map->has_named_interceptor() &&
307 // TODO(verwaest): Whitelist contexts to which we have access. 327 // TODO(verwaest): Whitelist contexts to which we have access.
308 !map->is_access_check_needed(); 328 !map->is_access_check_needed();
309 } 329 }
310 330
311 } // namespace 331 } // namespace
312 332
313 333
314 bool JSNativeContextSpecialization::ComputePropertyAccessInfo( 334 bool JSNativeContextSpecialization::ComputePropertyAccessInfo(
315 Handle<Map> map, Handle<Name> name, PropertyAccessMode access_mode, 335 Handle<Map> map, Handle<Name> name, PropertyAccessMode access_mode,
316 PropertyAccessInfo* access_info) { 336 PropertyAccessInfo* access_info) {
317 MaybeHandle<JSObject> holder; 337 // Check if it is safe to inline property access for the {map}.
338 if (!CanInlinePropertyAccess(map)) return false;
339
340 // Compute the receiver type.
318 Handle<Map> receiver_map = map; 341 Handle<Map> receiver_map = map;
319 Type* receiver_type = Type::Class(receiver_map, graph()->zone()); 342 Type* receiver_type = Type::Class(receiver_map, graph()->zone());
320 while (CanInlinePropertyAccess(map)) { 343
344 // We support fast inline cases for certain JSObject getters.
345 if (access_mode == kLoad) {
321 // Check for special JSObject field accessors. 346 // Check for special JSObject field accessors.
322 int offset; 347 int offset;
323 if (Accessors::IsJSObjectFieldAccessor(map, name, &offset)) { 348 if (Accessors::IsJSObjectFieldAccessor(map, name, &offset)) {
324 // Don't bother optimizing stores to special JSObject field accessors.
325 if (access_mode == kStore) {
326 break;
327 }
328 FieldIndex field_index = FieldIndex::ForInObjectOffset(offset); 349 FieldIndex field_index = FieldIndex::ForInObjectOffset(offset);
329 Type* field_type = Type::Tagged(); 350 Type* field_type = Type::Tagged();
330 if (map->IsStringMap()) { 351 if (map->IsStringMap()) {
331 DCHECK(Name::Equals(factory()->length_string(), name)); 352 DCHECK(Name::Equals(factory()->length_string(), name));
332 // The String::length property is always a smi in the range 353 // The String::length property is always a smi in the range
333 // [0, String::kMaxLength]. 354 // [0, String::kMaxLength].
334 field_type = type_cache_.kStringLengthType; 355 field_type = type_cache_.kStringLengthType;
335 } else if (map->IsJSArrayMap()) { 356 } else if (map->IsJSArrayMap()) {
336 DCHECK(Name::Equals(factory()->length_string(), name)); 357 DCHECK(Name::Equals(factory()->length_string(), name));
337 // The JSArray::length property is a smi in the range 358 // The JSArray::length property is a smi in the range
338 // [0, FixedDoubleArray::kMaxLength] in case of fast double 359 // [0, FixedDoubleArray::kMaxLength] in case of fast double
339 // elements, a smi in the range [0, FixedArray::kMaxLength] 360 // elements, a smi in the range [0, FixedArray::kMaxLength]
340 // in case of other fast elements, and [0, kMaxUInt32] in 361 // in case of other fast elements, and [0, kMaxUInt32] in
341 // case of other arrays. 362 // case of other arrays.
342 if (IsFastDoubleElementsKind(map->elements_kind())) { 363 if (IsFastDoubleElementsKind(map->elements_kind())) {
343 field_type = type_cache_.kFixedDoubleArrayLengthType; 364 field_type = type_cache_.kFixedDoubleArrayLengthType;
344 } else if (IsFastElementsKind(map->elements_kind())) { 365 } else if (IsFastElementsKind(map->elements_kind())) {
345 field_type = type_cache_.kFixedArrayLengthType; 366 field_type = type_cache_.kFixedArrayLengthType;
346 } else { 367 } else {
347 field_type = type_cache_.kJSArrayLengthType; 368 field_type = type_cache_.kJSArrayLengthType;
348 } 369 }
349 } 370 }
350 *access_info = PropertyAccessInfo::DataField(receiver_type, field_index, 371 *access_info =
351 field_type, holder); 372 PropertyAccessInfo::DataField(receiver_type, field_index, field_type);
352 return true; 373 return true;
353 } 374 }
375 }
354 376
377 MaybeHandle<JSObject> holder;
378 while (true) {
355 // Lookup the named property on the {map}. 379 // Lookup the named property on the {map}.
356 Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate()); 380 Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate());
357 int const number = descriptors->SearchWithCache(*name, *map); 381 int const number = descriptors->SearchWithCache(*name, *map);
358 if (number != DescriptorArray::kNotFound) { 382 if (number != DescriptorArray::kNotFound) {
359 if (access_mode == kStore && !map.is_identical_to(receiver_map)) { 383 PropertyDetails const details = descriptors->GetDetails(number);
360 return false; 384 if (access_mode == kStore) {
385 // Don't bother optimizing stores to read-only properties.
386 if (details.IsReadOnly()) {
387 return false;
388 }
389 // Check for store to data property on a prototype.
390 if (details.kind() == kData && !holder.is_null()) {
391 // We need to add the data field to the receiver. Leave the loop
392 // and check whether we already have a transition for this field.
393 // Implemented according to ES6 section 9.1.9 [[Set]] (P, V, Receiver)
394 break;
395 }
361 } 396 }
362 PropertyDetails const details = descriptors->GetDetails(number);
363 if (details.type() == DATA_CONSTANT) { 397 if (details.type() == DATA_CONSTANT) {
364 *access_info = PropertyAccessInfo::DataConstant( 398 *access_info = PropertyAccessInfo::DataConstant(
365 receiver_type, handle(descriptors->GetValue(number), isolate()), 399 receiver_type, handle(descriptors->GetValue(number), isolate()),
366 holder); 400 holder);
367 return true; 401 return true;
368 } else if (details.type() == DATA) { 402 } else if (details.type() == DATA) {
369 // Don't bother optimizing stores to read-only properties.
370 if (access_mode == kStore && details.IsReadOnly()) {
371 break;
372 }
373 int index = descriptors->GetFieldIndex(number); 403 int index = descriptors->GetFieldIndex(number);
374 Representation field_representation = details.representation(); 404 Representation field_representation = details.representation();
375 FieldIndex field_index = FieldIndex::ForPropertyIndex( 405 FieldIndex field_index = FieldIndex::ForPropertyIndex(
376 *map, index, field_representation.IsDouble()); 406 *map, index, field_representation.IsDouble());
377 Type* field_type = Type::Tagged(); 407 Type* field_type = Type::Tagged();
378 if (field_representation.IsSmi()) { 408 if (field_representation.IsSmi()) {
379 field_type = type_cache_.kSmi; 409 field_type = type_cache_.kSmi;
380 } else if (field_representation.IsDouble()) { 410 } else if (field_representation.IsDouble()) {
381 if (access_mode == kStore) { 411 if (access_mode == kStore) {
382 // TODO(bmeurer): Add support for storing to double fields. 412 // TODO(bmeurer): Add support for storing to double fields.
383 break; 413 return false;
384 } 414 }
385 field_type = type_cache_.kFloat64; 415 field_type = type_cache_.kFloat64;
386 } else if (field_representation.IsHeapObject()) { 416 } else if (field_representation.IsHeapObject()) {
387 // Extract the field type from the property details (make sure its 417 // Extract the field type from the property details (make sure its
388 // representation is TaggedPointer to reflect the heap object case). 418 // representation is TaggedPointer to reflect the heap object case).
389 field_type = Type::Intersect( 419 field_type = Type::Intersect(
390 Type::Convert<HeapType>( 420 Type::Convert<HeapType>(
391 handle(descriptors->GetFieldType(number), isolate()), 421 handle(descriptors->GetFieldType(number), isolate()),
392 graph()->zone()), 422 graph()->zone()),
393 Type::TaggedPointer(), graph()->zone()); 423 Type::TaggedPointer(), graph()->zone());
394 if (field_type->Is(Type::None())) { 424 if (field_type->Is(Type::None())) {
395 if (access_mode == kStore) { 425 // Store is not safe if the field type was cleared.
396 // Store is not safe if the field type was cleared. 426 if (access_mode == kStore) return false;
397 break;
398 }
399 427
400 // The field type was cleared by the GC, so we don't know anything 428 // The field type was cleared by the GC, so we don't know anything
401 // about the contents now. 429 // about the contents now.
402 // TODO(bmeurer): It would be awesome to make this saner in the 430 // TODO(bmeurer): It would be awesome to make this saner in the
403 // runtime/GC interaction. 431 // runtime/GC interaction.
404 field_type = Type::TaggedPointer(); 432 field_type = Type::TaggedPointer();
405 } else if (!Type::Any()->Is(field_type)) { 433 } else if (!Type::Any()->Is(field_type)) {
406 // Add proper code dependencies in case of stable field map(s). 434 // Add proper code dependencies in case of stable field map(s).
407 Handle<Map> field_owner_map(map->FindFieldOwner(number), isolate()); 435 Handle<Map> field_owner_map(map->FindFieldOwner(number), isolate());
408 dependencies()->AssumeFieldType(field_owner_map); 436 dependencies()->AssumeFieldType(field_owner_map);
409 } 437 }
410 DCHECK(field_type->Is(Type::TaggedPointer())); 438 DCHECK(field_type->Is(Type::TaggedPointer()));
411 } 439 }
412 *access_info = PropertyAccessInfo::DataField(receiver_type, field_index, 440 *access_info = PropertyAccessInfo::DataField(receiver_type, field_index,
413 field_type, holder); 441 field_type, holder);
414 return true; 442 return true;
415 } else { 443 } else {
416 // TODO(bmeurer): Add support for accessors. 444 // TODO(bmeurer): Add support for accessors.
417 break; 445 return false;
418 } 446 }
419 } 447 }
420 448
421 // Don't search on the prototype chain for special indices in case of 449 // Don't search on the prototype chain for special indices in case of
422 // integer indexed exotic objects (see ES6 section 9.4.5). 450 // integer indexed exotic objects (see ES6 section 9.4.5).
423 if (map->IsJSTypedArrayMap() && name->IsString() && 451 if (map->IsJSTypedArrayMap() && name->IsString() &&
424 IsSpecialIndex(isolate()->unicode_cache(), String::cast(*name))) { 452 IsSpecialIndex(isolate()->unicode_cache(), String::cast(*name))) {
425 break; 453 return false;
426 } 454 }
427 455
428 // Walk up the prototype chain. 456 // Walk up the prototype chain.
429 if (!map->prototype()->IsJSObject()) { 457 if (!map->prototype()->IsJSObject()) {
430 // Perform the implicit ToObject for primitives here. 458 // Perform the implicit ToObject for primitives here.
431 // Implemented according to ES6 section 7.3.2 GetV (V, P). 459 // Implemented according to ES6 section 7.3.2 GetV (V, P).
432 Handle<JSFunction> constructor; 460 Handle<JSFunction> constructor;
433 if (Map::GetConstructorFunction(map, native_context()) 461 if (Map::GetConstructorFunction(map, native_context())
434 .ToHandle(&constructor)) { 462 .ToHandle(&constructor)) {
435 map = handle(constructor->initial_map(), isolate()); 463 map = handle(constructor->initial_map(), isolate());
436 DCHECK(map->prototype()->IsJSObject()); 464 DCHECK(map->prototype()->IsJSObject());
465 } else if (map->prototype()->IsNull()) {
466 // Store to property not found on the receiver or any prototype, we need
467 // to transition to a new data property.
468 // Implemented according to ES6 section 9.1.9 [[Set]] (P, V, Receiver)
469 if (access_mode == kStore) {
470 break;
471 }
472 // TODO(bmeurer): Handle the not found case if the prototype is null.
473 return false;
437 } else { 474 } else {
438 // TODO(bmeurer): Handle the not found case if the prototype is null. 475 return false;
439 break;
440 } 476 }
441 } 477 }
442 Handle<JSObject> map_prototype(JSObject::cast(map->prototype()), isolate()); 478 Handle<JSObject> map_prototype(JSObject::cast(map->prototype()), isolate());
443 if (map_prototype->map()->is_deprecated()) { 479 if (map_prototype->map()->is_deprecated()) {
444 // Try to migrate the prototype object so we don't embed the deprecated 480 // Try to migrate the prototype object so we don't embed the deprecated
445 // map into the optimized code. 481 // map into the optimized code.
446 JSObject::TryMigrateInstance(map_prototype); 482 JSObject::TryMigrateInstance(map_prototype);
447 } 483 }
448 map = handle(map_prototype->map(), isolate()); 484 map = handle(map_prototype->map(), isolate());
449 holder = map_prototype; 485 holder = map_prototype;
486
487 // Check if it is safe to inline property access for the {map}.
488 if (!CanInlinePropertyAccess(map)) return false;
489 }
490 DCHECK_EQ(kStore, access_mode);
491
492 // Check if the {receiver_map} has a data transition with the given {name}.
Jarin 2015/10/29 09:02:33 The structure of this code is strange. This whole
Benedikt Meurer 2015/10/29 09:03:47 Yes, but currently we have two "break" points. I w
493 if (receiver_map->unused_property_fields() == 0) return false;
494 if (Map* transition = TransitionArray::SearchTransition(*receiver_map, kData,
495 *name, NONE)) {
496 Handle<Map> transition_map(transition, isolate());
497 int const number = transition_map->LastAdded();
498 PropertyDetails const details =
499 transition_map->instance_descriptors()->GetDetails(number);
500 // Don't bother optimizing stores to read-only properties.
501 if (details.IsReadOnly()) return false;
502 // TODO(bmeurer): Handle transition to data constant?
503 if (details.type() != DATA) return false;
504 int const index = details.field_index();
505 Representation field_representation = details.representation();
506 FieldIndex field_index = FieldIndex::ForPropertyIndex(
507 *transition_map, index, field_representation.IsDouble());
508 Type* field_type = Type::Tagged();
509 if (field_representation.IsSmi()) {
510 field_type = type_cache_.kSmi;
511 } else if (field_representation.IsDouble()) {
512 // TODO(bmeurer): Add support for storing to double fields.
513 return false;
514 } else if (field_representation.IsHeapObject()) {
515 // Extract the field type from the property details (make sure its
516 // representation is TaggedPointer to reflect the heap object case).
517 field_type = Type::Intersect(
518 Type::Convert<HeapType>(
519 handle(
520 transition_map->instance_descriptors()->GetFieldType(number),
521 isolate()),
522 graph()->zone()),
523 Type::TaggedPointer(), graph()->zone());
524 if (field_type->Is(Type::None())) {
525 // Store is not safe if the field type was cleared.
526 return false;
527 } else if (!Type::Any()->Is(field_type)) {
528 // Add proper code dependencies in case of stable field map(s).
529 Handle<Map> field_owner_map(transition_map->FindFieldOwner(number),
530 isolate());
531 dependencies()->AssumeFieldType(field_owner_map);
532 }
533 DCHECK(field_type->Is(Type::TaggedPointer()));
534 }
535 dependencies()->AssumeMapNotDeprecated(transition_map);
536 *access_info = PropertyAccessInfo::TransitionToField(
537 receiver_type, field_index, field_type, transition_map, holder);
538 return true;
450 } 539 }
451 return false; 540 return false;
452 } 541 }
453 542
454 543
455 bool JSNativeContextSpecialization::ComputePropertyAccessInfos( 544 bool JSNativeContextSpecialization::ComputePropertyAccessInfos(
456 MapHandleList const& maps, Handle<Name> name, 545 MapHandleList const& maps, Handle<Name> name,
457 PropertyAccessMode access_mode, 546 PropertyAccessMode access_mode,
458 ZoneVector<PropertyAccessInfo>* access_infos) { 547 ZoneVector<PropertyAccessInfo>* access_infos) {
459 for (Handle<Map> map : maps) { 548 for (Handle<Map> map : maps) {
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after
557 (this_control_count == 1) 646 (this_control_count == 1)
558 ? this_controls.front() 647 ? this_controls.front()
559 : graph()->NewNode(common()->Merge(this_control_count), 648 : graph()->NewNode(common()->Merge(this_control_count),
560 this_control_count, &this_controls.front()); 649 this_control_count, &this_controls.front());
561 } 650 }
562 651
563 // Determine actual holder and perform prototype chain checks. 652 // Determine actual holder and perform prototype chain checks.
564 Handle<JSObject> holder; 653 Handle<JSObject> holder;
565 if (access_info.holder().ToHandle(&holder)) { 654 if (access_info.holder().ToHandle(&holder)) {
566 AssumePrototypesStable(receiver_type, holder); 655 AssumePrototypesStable(receiver_type, holder);
567 if (access_mode == kLoad) {
568 this_receiver = jsgraph()->Constant(holder);
569 }
570 } 656 }
571 657
572 // Generate the actual property access. 658 // Generate the actual property access.
573 if (access_info.IsDataConstant()) { 659 if (access_info.IsDataConstant()) {
574 this_value = jsgraph()->Constant(access_info.constant()); 660 this_value = jsgraph()->Constant(access_info.constant());
575 if (access_mode == kStore) { 661 if (access_mode == kStore) {
576 Node* check = graph()->NewNode( 662 Node* check = graph()->NewNode(
577 simplified()->ReferenceEqual(Type::Tagged()), value, this_value); 663 simplified()->ReferenceEqual(Type::Tagged()), value, this_value);
578 Node* branch = graph()->NewNode(common()->Branch(BranchHint::kTrue), 664 Node* branch = graph()->NewNode(common()->Branch(BranchHint::kTrue),
579 check, this_control); 665 check, this_control);
580 exit_controls.push_back(graph()->NewNode(common()->IfFalse(), branch)); 666 exit_controls.push_back(graph()->NewNode(common()->IfFalse(), branch));
581 this_control = graph()->NewNode(common()->IfTrue(), branch); 667 this_control = graph()->NewNode(common()->IfTrue(), branch);
582 } 668 }
583 } else { 669 } else {
584 DCHECK(access_info.IsDataField()); 670 DCHECK(access_info.IsDataField() || access_info.IsTransitionToField());
585 FieldIndex const field_index = access_info.field_index(); 671 FieldIndex const field_index = access_info.field_index();
586 Type* const field_type = access_info.field_type(); 672 Type* const field_type = access_info.field_type();
673 if (access_mode == kLoad && access_info.holder().ToHandle(&holder)) {
674 this_receiver = jsgraph()->Constant(holder);
675 }
676 Node* this_storage = this_receiver;
587 if (!field_index.is_inobject()) { 677 if (!field_index.is_inobject()) {
588 this_receiver = this_effect = graph()->NewNode( 678 this_storage = this_effect = graph()->NewNode(
589 simplified()->LoadField(AccessBuilder::ForJSObjectProperties()), 679 simplified()->LoadField(AccessBuilder::ForJSObjectProperties()),
590 this_receiver, this_effect, this_control); 680 this_storage, this_effect, this_control);
591 } 681 }
592 FieldAccess field_access = {kTaggedBase, field_index.offset(), name, 682 FieldAccess field_access = {kTaggedBase, field_index.offset(), name,
593 field_type, kMachAnyTagged}; 683 field_type, kMachAnyTagged};
594 if (access_mode == kLoad) { 684 if (access_mode == kLoad) {
595 if (field_type->Is(Type::UntaggedFloat64())) { 685 if (field_type->Is(Type::UntaggedFloat64())) {
596 if (!field_index.is_inobject() || field_index.is_hidden_field() || 686 if (!field_index.is_inobject() || field_index.is_hidden_field() ||
597 !FLAG_unbox_double_fields) { 687 !FLAG_unbox_double_fields) {
598 this_receiver = this_effect = 688 this_storage = this_effect =
599 graph()->NewNode(simplified()->LoadField(field_access), 689 graph()->NewNode(simplified()->LoadField(field_access),
600 this_receiver, this_effect, this_control); 690 this_storage, this_effect, this_control);
601 field_access.offset = HeapNumber::kValueOffset; 691 field_access.offset = HeapNumber::kValueOffset;
602 field_access.name = MaybeHandle<Name>(); 692 field_access.name = MaybeHandle<Name>();
603 } 693 }
604 field_access.machine_type = kMachFloat64; 694 field_access.machine_type = kMachFloat64;
605 } 695 }
606 this_value = this_effect = 696 this_value = this_effect =
607 graph()->NewNode(simplified()->LoadField(field_access), 697 graph()->NewNode(simplified()->LoadField(field_access),
608 this_receiver, this_effect, this_control); 698 this_storage, this_effect, this_control);
609 } else { 699 } else {
610 DCHECK_EQ(kStore, access_mode); 700 DCHECK_EQ(kStore, access_mode);
611 if (field_type->Is(Type::TaggedSigned())) { 701 if (field_type->Is(Type::TaggedSigned())) {
612 Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), value); 702 Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), value);
613 Node* branch = graph()->NewNode(common()->Branch(BranchHint::kTrue), 703 Node* branch = graph()->NewNode(common()->Branch(BranchHint::kTrue),
614 check, this_control); 704 check, this_control);
615 exit_controls.push_back( 705 exit_controls.push_back(
616 graph()->NewNode(common()->IfFalse(), branch)); 706 graph()->NewNode(common()->IfFalse(), branch));
617 this_control = graph()->NewNode(common()->IfTrue(), branch); 707 this_control = graph()->NewNode(common()->IfTrue(), branch);
618 } else if (field_type->Is(Type::TaggedPointer())) { 708 } else if (field_type->Is(Type::TaggedPointer())) {
(...skipping 25 matching lines...) Expand all
644 this_control = 734 this_control =
645 (this_control_count == 1) 735 (this_control_count == 1)
646 ? this_controls.front() 736 ? this_controls.front()
647 : graph()->NewNode(common()->Merge(this_control_count), 737 : graph()->NewNode(common()->Merge(this_control_count),
648 this_control_count, 738 this_control_count,
649 &this_controls.front()); 739 &this_controls.front());
650 } 740 }
651 } else { 741 } else {
652 DCHECK(field_type->Is(Type::Tagged())); 742 DCHECK(field_type->Is(Type::Tagged()));
653 } 743 }
744 if (access_info.IsTransitionToField()) {
745 this_effect = graph()->NewNode(common()->BeginRegion(), this_effect);
746 this_effect = graph()->NewNode(
747 simplified()->StoreField(AccessBuilder::ForMap()), this_receiver,
748 jsgraph()->Constant(access_info.transition_map()), this_effect,
749 this_control);
750 }
654 this_effect = graph()->NewNode(simplified()->StoreField(field_access), 751 this_effect = graph()->NewNode(simplified()->StoreField(field_access),
655 this_receiver, this_value, this_effect, 752 this_storage, this_value, this_effect,
656 this_control); 753 this_control);
754 if (access_info.IsTransitionToField()) {
755 this_effect =
756 graph()->NewNode(common()->FinishRegion(),
757 jsgraph()->UndefinedConstant(), this_effect);
758 }
657 } 759 }
658 } 760 }
659 761
660 // Remember the final state for this property access. 762 // Remember the final state for this property access.
661 values.push_back(this_value); 763 values.push_back(this_value);
662 effects.push_back(this_effect); 764 effects.push_back(this_effect);
663 controls.push_back(this_control); 765 controls.push_back(this_control);
664 } 766 }
665 767
666 // Collect the fallthru control as final "exit" control. 768 // Collect the fallthru control as final "exit" control.
(...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after
828 } 930 }
829 931
830 932
831 SimplifiedOperatorBuilder* JSNativeContextSpecialization::simplified() const { 933 SimplifiedOperatorBuilder* JSNativeContextSpecialization::simplified() const {
832 return jsgraph()->simplified(); 934 return jsgraph()->simplified();
833 } 935 }
834 936
835 } // namespace compiler 937 } // namespace compiler
836 } // namespace internal 938 } // namespace internal
837 } // namespace v8 939 } // namespace v8
OLDNEW
« no previous file with comments | « src/compilation-dependencies.cc ('k') | src/type-cache.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698