 Chromium Code Reviews
 Chromium Code Reviews Issue 23578030:
  Reland Handle non-JSObject heap objects using slow-path IC stub guarded by the map.  (Closed) 
  Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
    
  
    Issue 23578030:
  Reland Handle non-JSObject heap objects using slow-path IC stub guarded by the map.  (Closed) 
  Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge| OLD | NEW | 
|---|---|
| 1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 the V8 project authors. All rights reserved. | 
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without | 
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are | 
| 4 // met: | 4 // met: | 
| 5 // | 5 // | 
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright | 
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. | 
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above | 
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following | 
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided | 
| (...skipping 3987 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3998 HRegExpLiteral* instr = new(zone()) HRegExpLiteral(context, | 3998 HRegExpLiteral* instr = new(zone()) HRegExpLiteral(context, | 
| 3999 literals, | 3999 literals, | 
| 4000 expr->pattern(), | 4000 expr->pattern(), | 
| 4001 expr->flags(), | 4001 expr->flags(), | 
| 4002 expr->literal_index()); | 4002 expr->literal_index()); | 
| 4003 return ast_context()->ReturnInstruction(instr, expr->id()); | 4003 return ast_context()->ReturnInstruction(instr, expr->id()); | 
| 4004 } | 4004 } | 
| 4005 | 4005 | 
| 4006 | 4006 | 
| 4007 static bool CanInlinePropertyAccess(Map* type) { | 4007 static bool CanInlinePropertyAccess(Map* type) { | 
| 4008 return !type->is_dictionary_map() && !type->has_named_interceptor(); | 4008 return type->IsJSObjectMap() && | 
| 4009 !type->is_dictionary_map() && | |
| 4010 !type->has_named_interceptor(); | |
| 4009 } | 4011 } | 
| 4010 | 4012 | 
| 4011 | 4013 | 
| 4012 static void LookupInPrototypes(Handle<Map> map, | 4014 static void LookupInPrototypes(Handle<Map> map, | 
| 4013 Handle<String> name, | 4015 Handle<String> name, | 
| 4014 LookupResult* lookup) { | 4016 LookupResult* lookup) { | 
| 4015 while (map->prototype()->IsJSObject()) { | 4017 while (map->prototype()->IsJSObject()) { | 
| 4016 Handle<JSObject> holder(JSObject::cast(map->prototype())); | 4018 Handle<JSObject> holder(JSObject::cast(map->prototype())); | 
| 4017 map = Handle<Map>(holder->map()); | 4019 map = Handle<Map>(holder->map()); | 
| 4018 if (!CanInlinePropertyAccess(*map)) break; | 4020 if (!CanInlinePropertyAccess(*map)) break; | 
| (...skipping 594 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4613 LookupInPrototypes(map, name, &lookup); | 4615 LookupInPrototypes(map, name, &lookup); | 
| 4614 if (!lookup.IsField()) return NULL; | 4616 if (!lookup.IsField()) return NULL; | 
| 4615 | 4617 | 
| 4616 BuildCheckHeapObject(object); | 4618 BuildCheckHeapObject(object); | 
| 4617 Add<HCheckMaps>(object, types); | 4619 Add<HCheckMaps>(object, types); | 
| 4618 | 4620 | 
| 4619 Handle<JSObject> holder(lookup.holder()); | 4621 Handle<JSObject> holder(lookup.holder()); | 
| 4620 Handle<Map> holder_map(holder->map()); | 4622 Handle<Map> holder_map(holder->map()); | 
| 4621 HValue* checked_holder = BuildCheckPrototypeMaps( | 4623 HValue* checked_holder = BuildCheckPrototypeMaps( | 
| 4622 Handle<JSObject>::cast(prototype), holder); | 4624 Handle<JSObject>::cast(prototype), holder); | 
| 4625 ASSERT(holder_map->IsJSObjectMap()); | |
| 
Michael Starzinger
2013/09/12 21:41:38
This is virtually guaranteed, as we are loading th
 | |
| 4623 return BuildLoadNamedField(checked_holder, | 4626 return BuildLoadNamedField(checked_holder, | 
| 4624 HObjectAccess::ForField(holder_map, &lookup, name)); | 4627 HObjectAccess::ForField(holder_map, &lookup, name)); | 
| 4625 } | 4628 } | 
| 4626 | 4629 | 
| 4627 | 4630 | 
| 4628 // Returns true if an instance of this map can never find a property with this | 4631 // Returns true if an instance of this map can never find a property with this | 
| 4629 // name in its prototype chain. This means all prototypes up to the top are | 4632 // name in its prototype chain. This means all prototypes up to the top are | 
| 4630 // fast and don't have the name in them. It would be good if we could optimize | 4633 // fast and don't have the name in them. It would be good if we could optimize | 
| 4631 // polymorphic loads where the property is sometimes found in the prototype | 4634 // polymorphic loads where the property is sometimes found in the prototype | 
| 4632 // chain. | 4635 // chain. | 
| (...skipping 741 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 5374 HCheckMaps* checked_object = AddCheckMap(object, map); | 5377 HCheckMaps* checked_object = AddCheckMap(object, map); | 
| 5375 return New<HLoadNamedField>( | 5378 return New<HLoadNamedField>( | 
| 5376 checked_object, HObjectAccess::ForArrayLength(map->elements_kind())); | 5379 checked_object, HObjectAccess::ForArrayLength(map->elements_kind())); | 
| 5377 } | 5380 } | 
| 5378 } | 5381 } | 
| 5379 | 5382 | 
| 5380 LookupResult lookup(isolate()); | 5383 LookupResult lookup(isolate()); | 
| 5381 map->LookupDescriptor(NULL, *name, &lookup); | 5384 map->LookupDescriptor(NULL, *name, &lookup); | 
| 5382 if (lookup.IsField()) { | 5385 if (lookup.IsField()) { | 
| 5383 HCheckMaps* checked_object = AddCheckMap(object, map); | 5386 HCheckMaps* checked_object = AddCheckMap(object, map); | 
| 5387 ASSERT(map->IsJSObjectMap()); | |
| 5384 return BuildLoadNamedField( | 5388 return BuildLoadNamedField( | 
| 5385 checked_object, HObjectAccess::ForField(map, &lookup, name)); | 5389 checked_object, HObjectAccess::ForField(map, &lookup, name)); | 
| 5386 } | 5390 } | 
| 5387 | 5391 | 
| 5388 // Handle a load of a constant known function. | 5392 // Handle a load of a constant known function. | 
| 5389 if (lookup.IsConstant()) { | 5393 if (lookup.IsConstant()) { | 
| 5390 AddCheckMap(object, map); | 5394 AddCheckMap(object, map); | 
| 5391 Handle<Object> constant(lookup.GetConstantFromMap(*map), isolate()); | 5395 Handle<Object> constant(lookup.GetConstantFromMap(*map), isolate()); | 
| 5392 return New<HConstant>(constant); | 5396 return New<HConstant>(constant); | 
| 5393 } | 5397 } | 
| 5394 | 5398 | 
| 5399 if (lookup.IsFound()) { | |
| 5400 // Cannot handle the property, do a generic load instead. | |
| 5401 HValue* context = environment()->context(); | |
| 5402 return new(zone()) HLoadNamedGeneric(context, object, name); | |
| 5403 } | |
| 5404 | |
| 5395 // Handle a load from a known field somewhere in the prototype chain. | 5405 // Handle a load from a known field somewhere in the prototype chain. | 
| 5396 LookupInPrototypes(map, name, &lookup); | 5406 LookupInPrototypes(map, name, &lookup); | 
| 5397 if (lookup.IsField()) { | 5407 if (lookup.IsField()) { | 
| 5398 Handle<JSObject> prototype(JSObject::cast(map->prototype())); | 5408 Handle<JSObject> prototype(JSObject::cast(map->prototype())); | 
| 5399 Handle<JSObject> holder(lookup.holder()); | 5409 Handle<JSObject> holder(lookup.holder()); | 
| 5400 Handle<Map> holder_map(holder->map()); | 5410 Handle<Map> holder_map(holder->map()); | 
| 5401 AddCheckMap(object, map); | 5411 AddCheckMap(object, map); | 
| 5402 HValue* checked_holder = BuildCheckPrototypeMaps(prototype, holder); | 5412 HValue* checked_holder = BuildCheckPrototypeMaps(prototype, holder); | 
| 5413 ASSERT(holder_map->IsJSObjectMap()); | |
| 
Michael Starzinger
2013/09/12 21:41:38
Likewise.
 | |
| 5403 return BuildLoadNamedField( | 5414 return BuildLoadNamedField( | 
| 5404 checked_holder, HObjectAccess::ForField(holder_map, &lookup, name)); | 5415 checked_holder, HObjectAccess::ForField(holder_map, &lookup, name)); | 
| 5405 } | 5416 } | 
| 5406 | 5417 | 
| 5407 // Handle a load of a constant function somewhere in the prototype chain. | 5418 // Handle a load of a constant function somewhere in the prototype chain. | 
| 5408 if (lookup.IsConstant()) { | 5419 if (lookup.IsConstant()) { | 
| 5409 Handle<JSObject> prototype(JSObject::cast(map->prototype())); | 5420 Handle<JSObject> prototype(JSObject::cast(map->prototype())); | 
| 5410 Handle<JSObject> holder(lookup.holder()); | 5421 Handle<JSObject> holder(lookup.holder()); | 
| 5411 Handle<Map> holder_map(holder->map()); | 5422 Handle<Map> holder_map(holder->map()); | 
| 5412 AddCheckMap(object, map); | 5423 AddCheckMap(object, map); | 
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 5477 // much faster than transitioning the elements to the worst case, trading a | 5488 // much faster than transitioning the elements to the worst case, trading a | 
| 5478 // HTransitionElements for a HCheckMaps, and avoiding mutation of the array. | 5489 // HTransitionElements for a HCheckMaps, and avoiding mutation of the array. | 
| 5479 bool has_double_maps = false; | 5490 bool has_double_maps = false; | 
| 5480 bool has_smi_or_object_maps = false; | 5491 bool has_smi_or_object_maps = false; | 
| 5481 bool has_js_array_access = false; | 5492 bool has_js_array_access = false; | 
| 5482 bool has_non_js_array_access = false; | 5493 bool has_non_js_array_access = false; | 
| 5483 bool has_seen_holey_elements = false; | 5494 bool has_seen_holey_elements = false; | 
| 5484 Handle<Map> most_general_consolidated_map; | 5495 Handle<Map> most_general_consolidated_map; | 
| 5485 for (int i = 0; i < maps->length(); ++i) { | 5496 for (int i = 0; i < maps->length(); ++i) { | 
| 5486 Handle<Map> map = maps->at(i); | 5497 Handle<Map> map = maps->at(i); | 
| 5498 if (!map->IsJSObjectMap()) return NULL; | |
| 5487 // Don't allow mixing of JSArrays with JSObjects. | 5499 // Don't allow mixing of JSArrays with JSObjects. | 
| 5488 if (map->instance_type() == JS_ARRAY_TYPE) { | 5500 if (map->instance_type() == JS_ARRAY_TYPE) { | 
| 5489 if (has_non_js_array_access) return NULL; | 5501 if (has_non_js_array_access) return NULL; | 
| 5490 has_js_array_access = true; | 5502 has_js_array_access = true; | 
| 5491 } else if (has_js_array_access) { | 5503 } else if (has_js_array_access) { | 
| 5492 return NULL; | 5504 return NULL; | 
| 5493 } else { | 5505 } else { | 
| 5494 has_non_js_array_access = true; | 5506 has_non_js_array_access = true; | 
| 5495 } | 5507 } | 
| 5496 // Don't allow mixed, incompatible elements kinds. | 5508 // Don't allow mixed, incompatible elements kinds. | 
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 5529 consolidated_elements_kind, | 5541 consolidated_elements_kind, | 
| 5530 false, NEVER_RETURN_HOLE, STANDARD_STORE); | 5542 false, NEVER_RETURN_HOLE, STANDARD_STORE); | 
| 5531 return instr; | 5543 return instr; | 
| 5532 } | 5544 } | 
| 5533 | 5545 | 
| 5534 | 5546 | 
| 5535 HValue* HOptimizedGraphBuilder::HandlePolymorphicElementAccess( | 5547 HValue* HOptimizedGraphBuilder::HandlePolymorphicElementAccess( | 
| 5536 HValue* object, | 5548 HValue* object, | 
| 5537 HValue* key, | 5549 HValue* key, | 
| 5538 HValue* val, | 5550 HValue* val, | 
| 5539 Expression* prop, | 5551 SmallMapList* maps, | 
| 5540 BailoutId ast_id, | 5552 BailoutId ast_id, | 
| 5541 int position, | 5553 int position, | 
| 5542 bool is_store, | 5554 bool is_store, | 
| 5543 KeyedAccessStoreMode store_mode, | 5555 KeyedAccessStoreMode store_mode, | 
| 5544 bool* has_side_effects) { | 5556 bool* has_side_effects) { | 
| 5545 *has_side_effects = false; | 5557 *has_side_effects = false; | 
| 5546 BuildCheckHeapObject(object); | 5558 BuildCheckHeapObject(object); | 
| 5547 SmallMapList* maps = prop->GetReceiverTypes(); | |
| 5548 | 5559 | 
| 5549 if (!is_store) { | 5560 if (!is_store) { | 
| 5550 HInstruction* consolidated_load = | 5561 HInstruction* consolidated_load = | 
| 5551 TryBuildConsolidatedElementLoad(object, key, val, maps); | 5562 TryBuildConsolidatedElementLoad(object, key, val, maps); | 
| 5552 if (consolidated_load != NULL) { | 5563 if (consolidated_load != NULL) { | 
| 5553 *has_side_effects |= consolidated_load->HasObservableSideEffects(); | 5564 *has_side_effects |= consolidated_load->HasObservableSideEffects(); | 
| 5554 if (position != RelocInfo::kNoPosition) { | 5565 if (position != RelocInfo::kNoPosition) { | 
| 5555 consolidated_load->set_position(position); | 5566 consolidated_load->set_position(position); | 
| 5556 } | 5567 } | 
| 5557 return consolidated_load; | 5568 return consolidated_load; | 
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 5593 untransitionable_maps.Add(map); | 5604 untransitionable_maps.Add(map); | 
| 5594 } | 5605 } | 
| 5595 } | 5606 } | 
| 5596 | 5607 | 
| 5597 // If only one map is left after transitioning, handle this case | 5608 // If only one map is left after transitioning, handle this case | 
| 5598 // monomorphically. | 5609 // monomorphically. | 
| 5599 ASSERT(untransitionable_maps.length() >= 1); | 5610 ASSERT(untransitionable_maps.length() >= 1); | 
| 5600 if (untransitionable_maps.length() == 1) { | 5611 if (untransitionable_maps.length() == 1) { | 
| 5601 Handle<Map> untransitionable_map = untransitionable_maps[0]; | 5612 Handle<Map> untransitionable_map = untransitionable_maps[0]; | 
| 5602 HInstruction* instr = NULL; | 5613 HInstruction* instr = NULL; | 
| 5603 if (untransitionable_map->has_slow_elements_kind()) { | 5614 if (untransitionable_map->has_slow_elements_kind() || | 
| 5615 !untransitionable_map->IsJSObjectMap()) { | |
| 5604 instr = AddInstruction(is_store ? BuildStoreKeyedGeneric(object, key, val) | 5616 instr = AddInstruction(is_store ? BuildStoreKeyedGeneric(object, key, val) | 
| 5605 : BuildLoadKeyedGeneric(object, key)); | 5617 : BuildLoadKeyedGeneric(object, key)); | 
| 5606 } else { | 5618 } else { | 
| 5607 instr = BuildMonomorphicElementAccess( | 5619 instr = BuildMonomorphicElementAccess( | 
| 5608 object, key, val, transition, untransitionable_map, is_store, | 5620 object, key, val, transition, untransitionable_map, is_store, | 
| 5609 store_mode); | 5621 store_mode); | 
| 5610 } | 5622 } | 
| 5611 *has_side_effects |= instr->HasObservableSideEffects(); | 5623 *has_side_effects |= instr->HasObservableSideEffects(); | 
| 5612 if (position != RelocInfo::kNoPosition) instr->set_position(position); | 5624 if (position != RelocInfo::kNoPosition) instr->set_position(position); | 
| 5613 return is_store ? NULL : instr; | 5625 return is_store ? NULL : instr; | 
| 5614 } | 5626 } | 
| 5615 | 5627 | 
| 5616 HBasicBlock* join = graph()->CreateBasicBlock(); | 5628 HBasicBlock* join = graph()->CreateBasicBlock(); | 
| 5617 | 5629 | 
| 5618 for (int i = 0; i < untransitionable_maps.length(); ++i) { | 5630 for (int i = 0; i < untransitionable_maps.length(); ++i) { | 
| 5619 Handle<Map> map = untransitionable_maps[i]; | 5631 Handle<Map> map = untransitionable_maps[i]; | 
| 5632 if (!map->IsJSObjectMap()) continue; | |
| 5620 ElementsKind elements_kind = map->elements_kind(); | 5633 ElementsKind elements_kind = map->elements_kind(); | 
| 5621 HBasicBlock* this_map = graph()->CreateBasicBlock(); | 5634 HBasicBlock* this_map = graph()->CreateBasicBlock(); | 
| 5622 HBasicBlock* other_map = graph()->CreateBasicBlock(); | 5635 HBasicBlock* other_map = graph()->CreateBasicBlock(); | 
| 5623 HCompareMap* mapcompare = | 5636 HCompareMap* mapcompare = | 
| 5624 new(zone()) HCompareMap(object, map, this_map, other_map); | 5637 new(zone()) HCompareMap(object, map, this_map, other_map); | 
| 5625 current_block()->Finish(mapcompare); | 5638 current_block()->Finish(mapcompare); | 
| 5626 | 5639 | 
| 5627 set_current_block(this_map); | 5640 set_current_block(this_map); | 
| 5628 HInstruction* access = NULL; | 5641 HInstruction* access = NULL; | 
| 5629 if (IsDictionaryElementsKind(elements_kind)) { | 5642 if (IsDictionaryElementsKind(elements_kind)) { | 
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 5682 Handle<Map> map = types->first(); | 5695 Handle<Map> map = types->first(); | 
| 5683 if (map->has_slow_elements_kind()) { | 5696 if (map->has_slow_elements_kind()) { | 
| 5684 instr = is_store ? BuildStoreKeyedGeneric(obj, key, val) | 5697 instr = is_store ? BuildStoreKeyedGeneric(obj, key, val) | 
| 5685 : BuildLoadKeyedGeneric(obj, key); | 5698 : BuildLoadKeyedGeneric(obj, key); | 
| 5686 AddInstruction(instr); | 5699 AddInstruction(instr); | 
| 5687 } else { | 5700 } else { | 
| 5688 BuildCheckHeapObject(obj); | 5701 BuildCheckHeapObject(obj); | 
| 5689 instr = BuildMonomorphicElementAccess( | 5702 instr = BuildMonomorphicElementAccess( | 
| 5690 obj, key, val, NULL, map, is_store, expr->GetStoreMode()); | 5703 obj, key, val, NULL, map, is_store, expr->GetStoreMode()); | 
| 5691 } | 5704 } | 
| 5692 } else if (expr->GetReceiverTypes() != NULL && | 5705 } else if (types != NULL && !types->is_empty()) { | 
| 5693 !expr->GetReceiverTypes()->is_empty()) { | |
| 5694 return HandlePolymorphicElementAccess( | 5706 return HandlePolymorphicElementAccess( | 
| 5695 obj, key, val, expr, ast_id, position, is_store, | 5707 obj, key, val, types, ast_id, position, is_store, | 
| 5696 expr->GetStoreMode(), has_side_effects); | 5708 expr->GetStoreMode(), has_side_effects); | 
| 5697 } else { | 5709 } else { | 
| 5698 if (is_store) { | 5710 if (is_store) { | 
| 5699 if (expr->IsAssignment() && expr->AsAssignment()->IsUninitialized()) { | 5711 if (expr->IsAssignment() && expr->AsAssignment()->IsUninitialized()) { | 
| 5700 Add<HDeoptimize>("Insufficient type feedback for keyed store", | 5712 Add<HDeoptimize>("Insufficient type feedback for keyed store", | 
| 5701 Deoptimizer::SOFT); | 5713 Deoptimizer::SOFT); | 
| 5702 } | 5714 } | 
| 5703 instr = BuildStoreKeyedGeneric(obj, key, val); | 5715 instr = BuildStoreKeyedGeneric(obj, key, val); | 
| 5704 } else { | 5716 } else { | 
| 5705 if (expr->AsProperty()->IsUninitialized()) { | 5717 if (expr->AsProperty()->IsUninitialized()) { | 
| (...skipping 3974 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 9680 if (ShouldProduceTraceOutput()) { | 9692 if (ShouldProduceTraceOutput()) { | 
| 9681 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); | 9693 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); | 
| 9682 } | 9694 } | 
| 9683 | 9695 | 
| 9684 #ifdef DEBUG | 9696 #ifdef DEBUG | 
| 9685 graph_->Verify(false); // No full verify. | 9697 graph_->Verify(false); // No full verify. | 
| 9686 #endif | 9698 #endif | 
| 9687 } | 9699 } | 
| 9688 | 9700 | 
| 9689 } } // namespace v8::internal | 9701 } } // namespace v8::internal | 
| OLD | NEW |