OLD | NEW |
---|---|
1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 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/crankshaft/hydrogen.h" | 5 #include "src/crankshaft/hydrogen.h" |
6 | 6 |
7 #include <memory> | 7 #include <memory> |
8 #include <sstream> | 8 #include <sstream> |
9 | 9 |
10 #include "src/allocation-site-scopes.h" | 10 #include "src/allocation-site-scopes.h" |
(...skipping 5430 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
5441 | 5441 |
5442 if (!ast_context()->IsTest()) { | 5442 if (!ast_context()->IsTest()) { |
5443 HBasicBlock* join = CreateJoin(cond_true, cond_false, expr->id()); | 5443 HBasicBlock* join = CreateJoin(cond_true, cond_false, expr->id()); |
5444 set_current_block(join); | 5444 set_current_block(join); |
5445 if (join != NULL && !ast_context()->IsEffect()) { | 5445 if (join != NULL && !ast_context()->IsEffect()) { |
5446 return ast_context()->ReturnValue(Pop()); | 5446 return ast_context()->ReturnValue(Pop()); |
5447 } | 5447 } |
5448 } | 5448 } |
5449 } | 5449 } |
5450 | 5450 |
5451 bool HOptimizedGraphBuilder::LookupGlobalPropertyCell( | |
5452 Variable* var, LookupIterator* it, PropertyAccessType access_type) { | |
5453 if (var->is_this()) return false; | |
5454 return LookupGlobalPropertyCell(it, access_type); | |
5455 } | |
5451 | 5456 |
5452 HOptimizedGraphBuilder::GlobalPropertyAccess | 5457 bool HOptimizedGraphBuilder::LookupGlobalPropertyCell( |
Toon Verwaest
2016/09/27 14:57:12
This should probably be called "CanInlineGlobalPro
Alfonso
2016/09/29 09:36:39
Done.
| |
5453 HOptimizedGraphBuilder::LookupGlobalProperty(Variable* var, LookupIterator* it, | 5458 LookupIterator* it, PropertyAccessType access_type) { |
5454 PropertyAccessType access_type) { | 5459 if (!current_info()->has_global_object()) { |
5455 if (var->is_this() || !current_info()->has_global_object()) { | 5460 return false; |
5456 return kUseGeneric; | |
5457 } | 5461 } |
5458 | 5462 |
5459 switch (it->state()) { | 5463 switch (it->state()) { |
5460 case LookupIterator::ACCESSOR: | 5464 case LookupIterator::ACCESSOR: |
5461 case LookupIterator::ACCESS_CHECK: | 5465 case LookupIterator::ACCESS_CHECK: |
5462 case LookupIterator::INTERCEPTOR: | 5466 case LookupIterator::INTERCEPTOR: |
5463 case LookupIterator::INTEGER_INDEXED_EXOTIC: | 5467 case LookupIterator::INTEGER_INDEXED_EXOTIC: |
5464 case LookupIterator::NOT_FOUND: | 5468 case LookupIterator::NOT_FOUND: |
5465 return kUseGeneric; | 5469 return false; |
5466 case LookupIterator::DATA: | 5470 case LookupIterator::DATA: |
5467 if (access_type == STORE && it->IsReadOnly()) return kUseGeneric; | 5471 if (access_type == STORE && it->IsReadOnly()) return false; |
5468 if (!it->GetHolder<JSObject>()->IsJSGlobalObject()) return kUseGeneric; | 5472 if (!it->GetHolder<JSObject>()->IsJSGlobalObject()) return false; |
5469 return kUseCell; | 5473 return true; |
5470 case LookupIterator::JSPROXY: | 5474 case LookupIterator::JSPROXY: |
5471 case LookupIterator::TRANSITION: | 5475 case LookupIterator::TRANSITION: |
5472 UNREACHABLE(); | 5476 UNREACHABLE(); |
5473 } | 5477 } |
5474 UNREACHABLE(); | 5478 UNREACHABLE(); |
5475 return kUseGeneric; | 5479 return false; |
5476 } | 5480 } |
5477 | 5481 |
5478 | |
5479 HValue* HOptimizedGraphBuilder::BuildContextChainWalk(Variable* var) { | 5482 HValue* HOptimizedGraphBuilder::BuildContextChainWalk(Variable* var) { |
5480 DCHECK(var->IsContextSlot()); | 5483 DCHECK(var->IsContextSlot()); |
5481 HValue* context = environment()->context(); | 5484 HValue* context = environment()->context(); |
5482 int length = scope()->ContextChainLength(var->scope()); | 5485 int length = scope()->ContextChainLength(var->scope()); |
5483 while (length-- > 0) { | 5486 while (length-- > 0) { |
5484 context = Add<HLoadNamedField>( | 5487 context = Add<HLoadNamedField>( |
5485 context, nullptr, | 5488 context, nullptr, |
5486 HObjectAccess::ForContextSlot(Context::PREVIOUS_INDEX)); | 5489 HObjectAccess::ForContextSlot(Context::PREVIOUS_INDEX)); |
5487 } | 5490 } |
5488 return context; | 5491 return context; |
5489 } | 5492 } |
5490 | 5493 |
5494 void HOptimizedGraphBuilder::LoadFromCell(LookupIterator* it, | |
Toon Verwaest
2016/09/27 14:57:11
And InlineGlobalPropertyAccess
Alfonso
2016/09/29 09:36:40
Done.
| |
5495 BailoutId ast_id) { | |
5496 Handle<PropertyCell> cell = it->GetPropertyCell(); | |
5497 top_info()->dependencies()->AssumePropertyCell(cell); | |
5498 auto cell_type = it->property_details().cell_type(); | |
5499 if (cell_type == PropertyCellType::kConstant || | |
5500 cell_type == PropertyCellType::kUndefined) { | |
5501 Handle<Object> constant_object(cell->value(), isolate()); | |
5502 if (constant_object->IsConsString()) { | |
5503 constant_object = String::Flatten(Handle<String>::cast(constant_object)); | |
5504 } | |
5505 HConstant* constant = New<HConstant>(constant_object); | |
5506 return ast_context()->ReturnInstruction(constant, ast_id); | |
5507 } else { | |
5508 auto access = HObjectAccess::ForPropertyCellValue(); | |
5509 UniqueSet<Map>* field_maps = nullptr; | |
5510 if (cell_type == PropertyCellType::kConstantType) { | |
5511 switch (cell->GetConstantType()) { | |
5512 case PropertyCellConstantType::kSmi: | |
5513 access = access.WithRepresentation(Representation::Smi()); | |
5514 break; | |
5515 case PropertyCellConstantType::kStableMap: { | |
5516 // Check that the map really is stable. The heap object could | |
5517 // have mutated without the cell updating state. In that case, | |
5518 // make no promises about the loaded value except that it's a | |
5519 // heap object. | |
5520 access = access.WithRepresentation(Representation::HeapObject()); | |
5521 Handle<Map> map(HeapObject::cast(cell->value())->map()); | |
5522 if (map->is_stable()) { | |
5523 field_maps = new (zone()) | |
5524 UniqueSet<Map>(Unique<Map>::CreateImmovable(map), zone()); | |
5525 } | |
5526 break; | |
5527 } | |
5528 } | |
5529 } | |
5530 HConstant* cell_constant = Add<HConstant>(cell); | |
5531 HLoadNamedField* instr; | |
5532 if (field_maps == nullptr) { | |
5533 instr = New<HLoadNamedField>(cell_constant, nullptr, access); | |
5534 } else { | |
5535 instr = New<HLoadNamedField>(cell_constant, nullptr, access, field_maps, | |
5536 HType::HeapObject()); | |
5537 } | |
5538 instr->ClearDependsOnFlag(kInobjectFields); | |
5539 instr->SetDependsOnFlag(kGlobalVars); | |
5540 return ast_context()->ReturnInstruction(instr, ast_id); | |
5541 } | |
5542 } | |
5491 | 5543 |
5492 void HOptimizedGraphBuilder::VisitVariableProxy(VariableProxy* expr) { | 5544 void HOptimizedGraphBuilder::VisitVariableProxy(VariableProxy* expr) { |
5493 DCHECK(!HasStackOverflow()); | 5545 DCHECK(!HasStackOverflow()); |
5494 DCHECK(current_block() != NULL); | 5546 DCHECK(current_block() != NULL); |
5495 DCHECK(current_block()->HasPredecessor()); | 5547 DCHECK(current_block()->HasPredecessor()); |
5496 Variable* variable = expr->var(); | 5548 Variable* variable = expr->var(); |
5497 switch (variable->location()) { | 5549 switch (variable->location()) { |
5498 case VariableLocation::UNALLOCATED: { | 5550 case VariableLocation::UNALLOCATED: { |
5499 if (IsLexicalVariableMode(variable->mode())) { | 5551 if (IsLexicalVariableMode(variable->mode())) { |
5500 // TODO(rossberg): should this be an DCHECK? | 5552 // TODO(rossberg): should this be an DCHECK? |
(...skipping 28 matching lines...) Expand all Loading... | |
5529 return Bailout(kReferenceToUninitializedVariable); | 5581 return Bailout(kReferenceToUninitializedVariable); |
5530 } | 5582 } |
5531 HInstruction* result = New<HLoadNamedField>( | 5583 HInstruction* result = New<HLoadNamedField>( |
5532 Add<HConstant>(script_context), nullptr, | 5584 Add<HConstant>(script_context), nullptr, |
5533 HObjectAccess::ForContextSlot(lookup.slot_index)); | 5585 HObjectAccess::ForContextSlot(lookup.slot_index)); |
5534 return ast_context()->ReturnInstruction(result, expr->id()); | 5586 return ast_context()->ReturnInstruction(result, expr->id()); |
5535 } | 5587 } |
5536 } | 5588 } |
5537 | 5589 |
5538 LookupIterator it(global, variable->name(), LookupIterator::OWN); | 5590 LookupIterator it(global, variable->name(), LookupIterator::OWN); |
5539 GlobalPropertyAccess type = LookupGlobalProperty(variable, &it, LOAD); | 5591 if (LookupGlobalPropertyCell(variable, &it, LOAD)) { |
5540 | 5592 return LoadFromCell(&it, expr->id()); |
vogelheim
2016/09/27 13:36:54
LoadFromCell returns void. You *can* return a void
Alfonso
2016/09/29 09:36:40
Done.
| |
5541 if (type == kUseCell) { | |
5542 Handle<PropertyCell> cell = it.GetPropertyCell(); | |
5543 top_info()->dependencies()->AssumePropertyCell(cell); | |
5544 auto cell_type = it.property_details().cell_type(); | |
5545 if (cell_type == PropertyCellType::kConstant || | |
5546 cell_type == PropertyCellType::kUndefined) { | |
5547 Handle<Object> constant_object(cell->value(), isolate()); | |
5548 if (constant_object->IsConsString()) { | |
5549 constant_object = | |
5550 String::Flatten(Handle<String>::cast(constant_object)); | |
5551 } | |
5552 HConstant* constant = New<HConstant>(constant_object); | |
5553 return ast_context()->ReturnInstruction(constant, expr->id()); | |
5554 } else { | |
5555 auto access = HObjectAccess::ForPropertyCellValue(); | |
5556 UniqueSet<Map>* field_maps = nullptr; | |
5557 if (cell_type == PropertyCellType::kConstantType) { | |
5558 switch (cell->GetConstantType()) { | |
5559 case PropertyCellConstantType::kSmi: | |
5560 access = access.WithRepresentation(Representation::Smi()); | |
5561 break; | |
5562 case PropertyCellConstantType::kStableMap: { | |
5563 // Check that the map really is stable. The heap object could | |
5564 // have mutated without the cell updating state. In that case, | |
5565 // make no promises about the loaded value except that it's a | |
5566 // heap object. | |
5567 access = | |
5568 access.WithRepresentation(Representation::HeapObject()); | |
5569 Handle<Map> map(HeapObject::cast(cell->value())->map()); | |
5570 if (map->is_stable()) { | |
5571 field_maps = new (zone()) | |
5572 UniqueSet<Map>(Unique<Map>::CreateImmovable(map), zone()); | |
5573 } | |
5574 break; | |
5575 } | |
5576 } | |
5577 } | |
5578 HConstant* cell_constant = Add<HConstant>(cell); | |
5579 HLoadNamedField* instr; | |
5580 if (field_maps == nullptr) { | |
5581 instr = New<HLoadNamedField>(cell_constant, nullptr, access); | |
5582 } else { | |
5583 instr = New<HLoadNamedField>(cell_constant, nullptr, access, | |
5584 field_maps, HType::HeapObject()); | |
5585 } | |
5586 instr->ClearDependsOnFlag(kInobjectFields); | |
5587 instr->SetDependsOnFlag(kGlobalVars); | |
5588 return ast_context()->ReturnInstruction(instr, expr->id()); | |
5589 } | |
5590 } else { | 5593 } else { |
5591 Handle<TypeFeedbackVector> vector(current_feedback_vector(), isolate()); | 5594 Handle<TypeFeedbackVector> vector(current_feedback_vector(), isolate()); |
5592 HLoadGlobalGeneric* instr = New<HLoadGlobalGeneric>( | 5595 HLoadGlobalGeneric* instr = New<HLoadGlobalGeneric>( |
5593 variable->name(), ast_context()->typeof_mode(), vector, | 5596 variable->name(), ast_context()->typeof_mode(), vector, |
5594 expr->VariableFeedbackSlot()); | 5597 expr->VariableFeedbackSlot()); |
5595 return ast_context()->ReturnInstruction(instr, expr->id()); | 5598 return ast_context()->ReturnInstruction(instr, expr->id()); |
5596 } | 5599 } |
5597 } | 5600 } |
5598 | 5601 |
5599 case VariableLocation::PARAMETER: | 5602 case VariableLocation::PARAMETER: |
(...skipping 654 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
6254 | 6257 |
6255 | 6258 |
6256 bool HOptimizedGraphBuilder::PropertyAccessInfo::CanAccessMonomorphic() { | 6259 bool HOptimizedGraphBuilder::PropertyAccessInfo::CanAccessMonomorphic() { |
6257 if (!CanInlinePropertyAccess(map_)) return false; | 6260 if (!CanInlinePropertyAccess(map_)) return false; |
6258 if (IsJSObjectFieldAccessor()) return IsLoad(); | 6261 if (IsJSObjectFieldAccessor()) return IsLoad(); |
6259 if (map_->IsJSFunctionMap() && map_->is_constructor() && | 6262 if (map_->IsJSFunctionMap() && map_->is_constructor() && |
6260 !map_->has_non_instance_prototype() && | 6263 !map_->has_non_instance_prototype() && |
6261 name_.is_identical_to(isolate()->factory()->prototype_string())) { | 6264 name_.is_identical_to(isolate()->factory()->prototype_string())) { |
6262 return IsLoad(); | 6265 return IsLoad(); |
6263 } | 6266 } |
6267 | |
6264 if (!LookupDescriptor()) return false; | 6268 if (!LookupDescriptor()) return false; |
6265 if (IsFound()) return IsLoad() || !IsReadOnly(); | 6269 if (IsFound()) return IsLoad() || !IsReadOnly(); |
6266 if (IsIntegerIndexedExotic()) return false; | 6270 if (IsIntegerIndexedExotic()) return false; |
6267 if (!LookupInPrototypes()) return false; | 6271 if (!LookupInPrototypes()) return false; |
6268 if (IsLoad()) return true; | 6272 if (IsLoad()) return true; |
6269 | 6273 |
6270 if (IsAccessorConstant()) return true; | 6274 if (IsAccessorConstant()) return true; |
6271 LookupTransition(*map_, *name_, NONE); | 6275 LookupTransition(*map_, *name_, NONE); |
6272 if (IsTransitionToData() && map_->unused_property_fields() > 0) { | 6276 if (IsTransitionToData() && map_->unused_property_fields() > 0) { |
6273 // Construct the object field access. | 6277 // Construct the object field access. |
(...skipping 441 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
6715 Add<HConstant>(script_context), | 6719 Add<HConstant>(script_context), |
6716 HObjectAccess::ForContextSlot(lookup.slot_index), value); | 6720 HObjectAccess::ForContextSlot(lookup.slot_index), value); |
6717 USE(instr); | 6721 USE(instr); |
6718 DCHECK(instr->HasObservableSideEffects()); | 6722 DCHECK(instr->HasObservableSideEffects()); |
6719 Add<HSimulate>(ast_id, REMOVABLE_SIMULATE); | 6723 Add<HSimulate>(ast_id, REMOVABLE_SIMULATE); |
6720 return; | 6724 return; |
6721 } | 6725 } |
6722 } | 6726 } |
6723 | 6727 |
6724 LookupIterator it(global, var->name(), LookupIterator::OWN); | 6728 LookupIterator it(global, var->name(), LookupIterator::OWN); |
6725 GlobalPropertyAccess type = LookupGlobalProperty(var, &it, STORE); | 6729 if (LookupGlobalPropertyCell(var, &it, STORE)) { |
6726 if (type == kUseCell) { | |
6727 Handle<PropertyCell> cell = it.GetPropertyCell(); | 6730 Handle<PropertyCell> cell = it.GetPropertyCell(); |
6728 top_info()->dependencies()->AssumePropertyCell(cell); | 6731 top_info()->dependencies()->AssumePropertyCell(cell); |
6729 auto cell_type = it.property_details().cell_type(); | 6732 auto cell_type = it.property_details().cell_type(); |
6730 if (cell_type == PropertyCellType::kConstant || | 6733 if (cell_type == PropertyCellType::kConstant || |
6731 cell_type == PropertyCellType::kUndefined) { | 6734 cell_type == PropertyCellType::kUndefined) { |
6732 Handle<Object> constant(cell->value(), isolate()); | 6735 Handle<Object> constant(cell->value(), isolate()); |
6733 if (value->IsConstant()) { | 6736 if (value->IsConstant()) { |
6734 HConstant* c_value = HConstant::cast(value); | 6737 HConstant* c_value = HConstant::cast(value); |
6735 if (!constant.is_identical_to(c_value->handle(isolate()))) { | 6738 if (!constant.is_identical_to(c_value->handle(isolate()))) { |
6736 Add<HDeoptimize>(DeoptimizeReason::kConstantGlobalVariableAssignment, | 6739 Add<HDeoptimize>(DeoptimizeReason::kConstantGlobalVariableAssignment, |
(...skipping 947 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
7684 HValue* HOptimizedGraphBuilder::BuildNamedAccess( | 7687 HValue* HOptimizedGraphBuilder::BuildNamedAccess( |
7685 PropertyAccessType access, BailoutId ast_id, BailoutId return_id, | 7688 PropertyAccessType access, BailoutId ast_id, BailoutId return_id, |
7686 Expression* expr, FeedbackVectorSlot slot, HValue* object, | 7689 Expression* expr, FeedbackVectorSlot slot, HValue* object, |
7687 Handle<Name> name, HValue* value, bool is_uninitialized) { | 7690 Handle<Name> name, HValue* value, bool is_uninitialized) { |
7688 SmallMapList* maps; | 7691 SmallMapList* maps; |
7689 ComputeReceiverTypes(expr, object, &maps, this); | 7692 ComputeReceiverTypes(expr, object, &maps, this); |
7690 DCHECK(maps != NULL); | 7693 DCHECK(maps != NULL); |
7691 | 7694 |
7692 if (maps->length() > 0) { | 7695 if (maps->length() > 0) { |
7693 PropertyAccessInfo info(this, access, maps->first(), name); | 7696 PropertyAccessInfo info(this, access, maps->first(), name); |
7694 if (!info.CanAccessAsMonomorphic(maps)) { | 7697 bool can_access_mono = info.CanAccessAsMonomorphic(maps); |
vogelheim
2016/09/27 13:36:54
can_access_monomorphic
Alfonso
2016/09/29 09:36:40
Done.
| |
7698 // TODO(peterssen): Add context access check. | |
7699 // More than one map? Polymorphic. | |
vogelheim
2016/09/27 13:36:54
This comment comments on one of the sub-clauses in
Alfonso
2016/09/29 09:36:40
Done.
| |
7700 bool is_global_proxy = maps->length() == 1 && !can_access_mono && | |
Toon Verwaest
2016/09/27 14:57:11
Why doesn't CanAccessMonomorphic just return true
Alfonso
2016/09/29 09:36:39
CanAccessMonomorphic has many checks and some of t
| |
7701 maps->first()->IsJSGlobalProxyMap(); | |
7702 if (!can_access_mono && !is_global_proxy) { | |
7695 HandlePolymorphicNamedFieldAccess(access, expr, slot, ast_id, return_id, | 7703 HandlePolymorphicNamedFieldAccess(access, expr, slot, ast_id, return_id, |
7696 object, value, maps, name); | 7704 object, value, maps, name); |
7697 return NULL; | 7705 return NULL; |
7698 } | 7706 } |
7699 | 7707 |
7700 HValue* checked_object; | 7708 HValue* checked_object; |
7701 // AstType::Number() is only supported by polymorphic load/call handling. | 7709 // AstType::Number() is only supported by polymorphic load/call handling. |
7702 DCHECK(!info.IsNumberType()); | 7710 DCHECK(!info.IsNumberType()); |
7703 BuildCheckHeapObject(object); | 7711 BuildCheckHeapObject(object); |
7704 if (AreStringTypes(maps)) { | 7712 if (AreStringTypes(maps)) { |
7705 checked_object = | 7713 checked_object = |
7706 Add<HCheckInstanceType>(object, HCheckInstanceType::IS_STRING); | 7714 Add<HCheckInstanceType>(object, HCheckInstanceType::IS_STRING); |
7707 } else { | 7715 } else { |
7708 checked_object = Add<HCheckMaps>(object, maps); | 7716 checked_object = Add<HCheckMaps>(object, maps); |
7709 } | 7717 } |
7718 | |
7719 if (is_global_proxy) { | |
7720 Handle<JSGlobalObject> global(current_info()->global_object()); | |
7721 LookupIterator it(global, name, LookupIterator::OWN); | |
7722 if (LookupGlobalPropertyCell(&it, LOAD)) { | |
7723 LoadFromCell(&it, expr->id()); | |
7724 return NULL; | |
vogelheim
2016/09/27 13:36:54
[I don't understand Crankshaft at all, and am mere
Alfonso
2016/09/29 09:36:40
To my understanding, returning NULL means that the
| |
7725 } | |
7726 } | |
Toon Verwaest
2016/09/27 14:57:11
Doesn't this fall-through mean that you'll try to
Alfonso
2016/09/29 09:36:40
Done.
| |
7727 | |
7710 return BuildMonomorphicAccess( | 7728 return BuildMonomorphicAccess( |
7711 &info, object, checked_object, value, ast_id, return_id); | 7729 &info, object, checked_object, value, ast_id, return_id); |
7712 } | 7730 } |
7713 | 7731 |
7714 return BuildNamedGeneric(access, expr, slot, object, name, value, | 7732 return BuildNamedGeneric(access, expr, slot, object, name, value, |
7715 is_uninitialized); | 7733 is_uninitialized); |
7716 } | 7734 } |
7717 | 7735 |
7718 | 7736 |
7719 void HOptimizedGraphBuilder::PushLoad(Property* expr, | 7737 void HOptimizedGraphBuilder::PushLoad(Property* expr, |
(...skipping 5568 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
13288 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); | 13306 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); |
13289 } | 13307 } |
13290 | 13308 |
13291 #ifdef DEBUG | 13309 #ifdef DEBUG |
13292 graph_->Verify(false); // No full verify. | 13310 graph_->Verify(false); // No full verify. |
13293 #endif | 13311 #endif |
13294 } | 13312 } |
13295 | 13313 |
13296 } // namespace internal | 13314 } // namespace internal |
13297 } // namespace v8 | 13315 } // namespace v8 |
OLD | NEW |