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 1355 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5374 HCheckMaps* checked_object = AddCheckMap(object, map); | 5376 HCheckMaps* checked_object = AddCheckMap(object, map); |
5375 return New<HLoadNamedField>( | 5377 return New<HLoadNamedField>( |
5376 checked_object, HObjectAccess::ForArrayLength(map->elements_kind())); | 5378 checked_object, HObjectAccess::ForArrayLength(map->elements_kind())); |
5377 } | 5379 } |
5378 } | 5380 } |
5379 | 5381 |
5380 LookupResult lookup(isolate()); | 5382 LookupResult lookup(isolate()); |
5381 map->LookupDescriptor(NULL, *name, &lookup); | 5383 map->LookupDescriptor(NULL, *name, &lookup); |
5382 if (lookup.IsField()) { | 5384 if (lookup.IsField()) { |
5383 HCheckMaps* checked_object = AddCheckMap(object, map); | 5385 HCheckMaps* checked_object = AddCheckMap(object, map); |
| 5386 ASSERT(map->IsJSObjectMap()); |
5384 return BuildLoadNamedField( | 5387 return BuildLoadNamedField( |
5385 checked_object, HObjectAccess::ForField(map, &lookup, name)); | 5388 checked_object, HObjectAccess::ForField(map, &lookup, name)); |
5386 } | 5389 } |
5387 | 5390 |
5388 // Handle a load of a constant known function. | 5391 // Handle a load of a constant known function. |
5389 if (lookup.IsConstant()) { | 5392 if (lookup.IsConstant()) { |
5390 AddCheckMap(object, map); | 5393 AddCheckMap(object, map); |
5391 Handle<Object> constant(lookup.GetConstantFromMap(*map), isolate()); | 5394 Handle<Object> constant(lookup.GetConstantFromMap(*map), isolate()); |
5392 return New<HConstant>(constant); | 5395 return New<HConstant>(constant); |
5393 } | 5396 } |
5394 | 5397 |
| 5398 if (lookup.IsFound()) { |
| 5399 // Cannot handle the property, do a generic load instead. |
| 5400 HValue* context = environment()->context(); |
| 5401 return new(zone()) HLoadNamedGeneric(context, object, name); |
| 5402 } |
| 5403 |
5395 // Handle a load from a known field somewhere in the prototype chain. | 5404 // Handle a load from a known field somewhere in the prototype chain. |
5396 LookupInPrototypes(map, name, &lookup); | 5405 LookupInPrototypes(map, name, &lookup); |
5397 if (lookup.IsField()) { | 5406 if (lookup.IsField()) { |
5398 Handle<JSObject> prototype(JSObject::cast(map->prototype())); | 5407 Handle<JSObject> prototype(JSObject::cast(map->prototype())); |
5399 Handle<JSObject> holder(lookup.holder()); | 5408 Handle<JSObject> holder(lookup.holder()); |
5400 Handle<Map> holder_map(holder->map()); | 5409 Handle<Map> holder_map(holder->map()); |
5401 AddCheckMap(object, map); | 5410 AddCheckMap(object, map); |
5402 HValue* checked_holder = BuildCheckPrototypeMaps(prototype, holder); | 5411 HValue* checked_holder = BuildCheckPrototypeMaps(prototype, holder); |
5403 return BuildLoadNamedField( | 5412 return BuildLoadNamedField( |
5404 checked_holder, HObjectAccess::ForField(holder_map, &lookup, name)); | 5413 checked_holder, HObjectAccess::ForField(holder_map, &lookup, name)); |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5477 // much faster than transitioning the elements to the worst case, trading a | 5486 // much faster than transitioning the elements to the worst case, trading a |
5478 // HTransitionElements for a HCheckMaps, and avoiding mutation of the array. | 5487 // HTransitionElements for a HCheckMaps, and avoiding mutation of the array. |
5479 bool has_double_maps = false; | 5488 bool has_double_maps = false; |
5480 bool has_smi_or_object_maps = false; | 5489 bool has_smi_or_object_maps = false; |
5481 bool has_js_array_access = false; | 5490 bool has_js_array_access = false; |
5482 bool has_non_js_array_access = false; | 5491 bool has_non_js_array_access = false; |
5483 bool has_seen_holey_elements = false; | 5492 bool has_seen_holey_elements = false; |
5484 Handle<Map> most_general_consolidated_map; | 5493 Handle<Map> most_general_consolidated_map; |
5485 for (int i = 0; i < maps->length(); ++i) { | 5494 for (int i = 0; i < maps->length(); ++i) { |
5486 Handle<Map> map = maps->at(i); | 5495 Handle<Map> map = maps->at(i); |
| 5496 if (!map->IsJSObjectMap()) return NULL; |
5487 // Don't allow mixing of JSArrays with JSObjects. | 5497 // Don't allow mixing of JSArrays with JSObjects. |
5488 if (map->instance_type() == JS_ARRAY_TYPE) { | 5498 if (map->instance_type() == JS_ARRAY_TYPE) { |
5489 if (has_non_js_array_access) return NULL; | 5499 if (has_non_js_array_access) return NULL; |
5490 has_js_array_access = true; | 5500 has_js_array_access = true; |
5491 } else if (has_js_array_access) { | 5501 } else if (has_js_array_access) { |
5492 return NULL; | 5502 return NULL; |
5493 } else { | 5503 } else { |
5494 has_non_js_array_access = true; | 5504 has_non_js_array_access = true; |
5495 } | 5505 } |
5496 // Don't allow mixed, incompatible elements kinds. | 5506 // Don't allow mixed, incompatible elements kinds. |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5529 consolidated_elements_kind, | 5539 consolidated_elements_kind, |
5530 false, NEVER_RETURN_HOLE, STANDARD_STORE); | 5540 false, NEVER_RETURN_HOLE, STANDARD_STORE); |
5531 return instr; | 5541 return instr; |
5532 } | 5542 } |
5533 | 5543 |
5534 | 5544 |
5535 HValue* HOptimizedGraphBuilder::HandlePolymorphicElementAccess( | 5545 HValue* HOptimizedGraphBuilder::HandlePolymorphicElementAccess( |
5536 HValue* object, | 5546 HValue* object, |
5537 HValue* key, | 5547 HValue* key, |
5538 HValue* val, | 5548 HValue* val, |
5539 Expression* prop, | 5549 SmallMapList* maps, |
5540 BailoutId ast_id, | 5550 BailoutId ast_id, |
5541 int position, | 5551 int position, |
5542 bool is_store, | 5552 bool is_store, |
5543 KeyedAccessStoreMode store_mode, | 5553 KeyedAccessStoreMode store_mode, |
5544 bool* has_side_effects) { | 5554 bool* has_side_effects) { |
5545 *has_side_effects = false; | 5555 *has_side_effects = false; |
5546 BuildCheckHeapObject(object); | 5556 BuildCheckHeapObject(object); |
5547 SmallMapList* maps = prop->GetReceiverTypes(); | |
5548 | 5557 |
5549 if (!is_store) { | 5558 if (!is_store) { |
5550 HInstruction* consolidated_load = | 5559 HInstruction* consolidated_load = |
5551 TryBuildConsolidatedElementLoad(object, key, val, maps); | 5560 TryBuildConsolidatedElementLoad(object, key, val, maps); |
5552 if (consolidated_load != NULL) { | 5561 if (consolidated_load != NULL) { |
5553 *has_side_effects |= consolidated_load->HasObservableSideEffects(); | 5562 *has_side_effects |= consolidated_load->HasObservableSideEffects(); |
5554 if (position != RelocInfo::kNoPosition) { | 5563 if (position != RelocInfo::kNoPosition) { |
5555 consolidated_load->set_position(position); | 5564 consolidated_load->set_position(position); |
5556 } | 5565 } |
5557 return consolidated_load; | 5566 return consolidated_load; |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5593 untransitionable_maps.Add(map); | 5602 untransitionable_maps.Add(map); |
5594 } | 5603 } |
5595 } | 5604 } |
5596 | 5605 |
5597 // If only one map is left after transitioning, handle this case | 5606 // If only one map is left after transitioning, handle this case |
5598 // monomorphically. | 5607 // monomorphically. |
5599 ASSERT(untransitionable_maps.length() >= 1); | 5608 ASSERT(untransitionable_maps.length() >= 1); |
5600 if (untransitionable_maps.length() == 1) { | 5609 if (untransitionable_maps.length() == 1) { |
5601 Handle<Map> untransitionable_map = untransitionable_maps[0]; | 5610 Handle<Map> untransitionable_map = untransitionable_maps[0]; |
5602 HInstruction* instr = NULL; | 5611 HInstruction* instr = NULL; |
5603 if (untransitionable_map->has_slow_elements_kind()) { | 5612 if (untransitionable_map->has_slow_elements_kind() || |
| 5613 !untransitionable_map->IsJSObjectMap()) { |
5604 instr = AddInstruction(is_store ? BuildStoreKeyedGeneric(object, key, val) | 5614 instr = AddInstruction(is_store ? BuildStoreKeyedGeneric(object, key, val) |
5605 : BuildLoadKeyedGeneric(object, key)); | 5615 : BuildLoadKeyedGeneric(object, key)); |
5606 } else { | 5616 } else { |
5607 instr = BuildMonomorphicElementAccess( | 5617 instr = BuildMonomorphicElementAccess( |
5608 object, key, val, transition, untransitionable_map, is_store, | 5618 object, key, val, transition, untransitionable_map, is_store, |
5609 store_mode); | 5619 store_mode); |
5610 } | 5620 } |
5611 *has_side_effects |= instr->HasObservableSideEffects(); | 5621 *has_side_effects |= instr->HasObservableSideEffects(); |
5612 if (position != RelocInfo::kNoPosition) instr->set_position(position); | 5622 if (position != RelocInfo::kNoPosition) instr->set_position(position); |
5613 return is_store ? NULL : instr; | 5623 return is_store ? NULL : instr; |
5614 } | 5624 } |
5615 | 5625 |
5616 HBasicBlock* join = graph()->CreateBasicBlock(); | 5626 HBasicBlock* join = graph()->CreateBasicBlock(); |
5617 | 5627 |
5618 for (int i = 0; i < untransitionable_maps.length(); ++i) { | 5628 for (int i = 0; i < untransitionable_maps.length(); ++i) { |
5619 Handle<Map> map = untransitionable_maps[i]; | 5629 Handle<Map> map = untransitionable_maps[i]; |
| 5630 if (!map->IsJSObjectMap()) continue; |
5620 ElementsKind elements_kind = map->elements_kind(); | 5631 ElementsKind elements_kind = map->elements_kind(); |
5621 HBasicBlock* this_map = graph()->CreateBasicBlock(); | 5632 HBasicBlock* this_map = graph()->CreateBasicBlock(); |
5622 HBasicBlock* other_map = graph()->CreateBasicBlock(); | 5633 HBasicBlock* other_map = graph()->CreateBasicBlock(); |
5623 HCompareMap* mapcompare = | 5634 HCompareMap* mapcompare = |
5624 new(zone()) HCompareMap(object, map, this_map, other_map); | 5635 new(zone()) HCompareMap(object, map, this_map, other_map); |
5625 current_block()->Finish(mapcompare); | 5636 current_block()->Finish(mapcompare); |
5626 | 5637 |
5627 set_current_block(this_map); | 5638 set_current_block(this_map); |
5628 HInstruction* access = NULL; | 5639 HInstruction* access = NULL; |
5629 if (IsDictionaryElementsKind(elements_kind)) { | 5640 if (IsDictionaryElementsKind(elements_kind)) { |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5682 Handle<Map> map = types->first(); | 5693 Handle<Map> map = types->first(); |
5683 if (map->has_slow_elements_kind()) { | 5694 if (map->has_slow_elements_kind()) { |
5684 instr = is_store ? BuildStoreKeyedGeneric(obj, key, val) | 5695 instr = is_store ? BuildStoreKeyedGeneric(obj, key, val) |
5685 : BuildLoadKeyedGeneric(obj, key); | 5696 : BuildLoadKeyedGeneric(obj, key); |
5686 AddInstruction(instr); | 5697 AddInstruction(instr); |
5687 } else { | 5698 } else { |
5688 BuildCheckHeapObject(obj); | 5699 BuildCheckHeapObject(obj); |
5689 instr = BuildMonomorphicElementAccess( | 5700 instr = BuildMonomorphicElementAccess( |
5690 obj, key, val, NULL, map, is_store, expr->GetStoreMode()); | 5701 obj, key, val, NULL, map, is_store, expr->GetStoreMode()); |
5691 } | 5702 } |
5692 } else if (expr->GetReceiverTypes() != NULL && | 5703 } else if (types != NULL && !types->is_empty()) { |
5693 !expr->GetReceiverTypes()->is_empty()) { | |
5694 return HandlePolymorphicElementAccess( | 5704 return HandlePolymorphicElementAccess( |
5695 obj, key, val, expr, ast_id, position, is_store, | 5705 obj, key, val, types, ast_id, position, is_store, |
5696 expr->GetStoreMode(), has_side_effects); | 5706 expr->GetStoreMode(), has_side_effects); |
5697 } else { | 5707 } else { |
5698 if (is_store) { | 5708 if (is_store) { |
5699 if (expr->IsAssignment() && expr->AsAssignment()->IsUninitialized()) { | 5709 if (expr->IsAssignment() && expr->AsAssignment()->IsUninitialized()) { |
5700 Add<HDeoptimize>("Insufficient type feedback for keyed store", | 5710 Add<HDeoptimize>("Insufficient type feedback for keyed store", |
5701 Deoptimizer::SOFT); | 5711 Deoptimizer::SOFT); |
5702 } | 5712 } |
5703 instr = BuildStoreKeyedGeneric(obj, key, val); | 5713 instr = BuildStoreKeyedGeneric(obj, key, val); |
5704 } else { | 5714 } else { |
5705 if (expr->AsProperty()->IsUninitialized()) { | 5715 if (expr->AsProperty()->IsUninitialized()) { |
(...skipping 3974 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
9680 if (ShouldProduceTraceOutput()) { | 9690 if (ShouldProduceTraceOutput()) { |
9681 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); | 9691 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); |
9682 } | 9692 } |
9683 | 9693 |
9684 #ifdef DEBUG | 9694 #ifdef DEBUG |
9685 graph_->Verify(false); // No full verify. | 9695 graph_->Verify(false); // No full verify. |
9686 #endif | 9696 #endif |
9687 } | 9697 } |
9688 | 9698 |
9689 } } // namespace v8::internal | 9699 } } // namespace v8::internal |
OLD | NEW |