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 5181 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5192 | 5192 |
5193 if (!ast_context()->IsTest()) { | 5193 if (!ast_context()->IsTest()) { |
5194 HBasicBlock* join = CreateJoin(cond_true, cond_false, expr->id()); | 5194 HBasicBlock* join = CreateJoin(cond_true, cond_false, expr->id()); |
5195 set_current_block(join); | 5195 set_current_block(join); |
5196 if (join != NULL && !ast_context()->IsEffect()) { | 5196 if (join != NULL && !ast_context()->IsEffect()) { |
5197 return ast_context()->ReturnValue(Pop()); | 5197 return ast_context()->ReturnValue(Pop()); |
5198 } | 5198 } |
5199 } | 5199 } |
5200 } | 5200 } |
5201 | 5201 |
| 5202 bool HOptimizedGraphBuilder::CanInlineGlobalPropertyAccess( |
| 5203 Variable* var, LookupIterator* it, PropertyAccessType access_type) { |
| 5204 if (var->is_this()) return false; |
| 5205 return CanInlineGlobalPropertyAccess(it, access_type); |
| 5206 } |
5202 | 5207 |
5203 HOptimizedGraphBuilder::GlobalPropertyAccess | 5208 bool HOptimizedGraphBuilder::CanInlineGlobalPropertyAccess( |
5204 HOptimizedGraphBuilder::LookupGlobalProperty(Variable* var, LookupIterator* it, | 5209 LookupIterator* it, PropertyAccessType access_type) { |
5205 PropertyAccessType access_type) { | 5210 if (!current_info()->has_global_object()) { |
5206 if (var->is_this() || !current_info()->has_global_object()) { | 5211 return false; |
5207 return kUseGeneric; | |
5208 } | 5212 } |
5209 | 5213 |
5210 switch (it->state()) { | 5214 switch (it->state()) { |
5211 case LookupIterator::ACCESSOR: | 5215 case LookupIterator::ACCESSOR: |
5212 case LookupIterator::ACCESS_CHECK: | 5216 case LookupIterator::ACCESS_CHECK: |
5213 case LookupIterator::INTERCEPTOR: | 5217 case LookupIterator::INTERCEPTOR: |
5214 case LookupIterator::INTEGER_INDEXED_EXOTIC: | 5218 case LookupIterator::INTEGER_INDEXED_EXOTIC: |
5215 case LookupIterator::NOT_FOUND: | 5219 case LookupIterator::NOT_FOUND: |
5216 return kUseGeneric; | 5220 return false; |
5217 case LookupIterator::DATA: | 5221 case LookupIterator::DATA: |
5218 if (access_type == STORE && it->IsReadOnly()) return kUseGeneric; | 5222 if (access_type == STORE && it->IsReadOnly()) return false; |
5219 if (!it->GetHolder<JSObject>()->IsJSGlobalObject()) return kUseGeneric; | 5223 if (!it->GetHolder<JSObject>()->IsJSGlobalObject()) return false; |
5220 return kUseCell; | 5224 return true; |
5221 case LookupIterator::JSPROXY: | 5225 case LookupIterator::JSPROXY: |
5222 case LookupIterator::TRANSITION: | 5226 case LookupIterator::TRANSITION: |
5223 UNREACHABLE(); | 5227 UNREACHABLE(); |
5224 } | 5228 } |
5225 UNREACHABLE(); | 5229 UNREACHABLE(); |
5226 return kUseGeneric; | 5230 return false; |
5227 } | 5231 } |
5228 | 5232 |
5229 | 5233 |
5230 HValue* HOptimizedGraphBuilder::BuildContextChainWalk(Variable* var) { | 5234 HValue* HOptimizedGraphBuilder::BuildContextChainWalk(Variable* var) { |
5231 DCHECK(var->IsContextSlot()); | 5235 DCHECK(var->IsContextSlot()); |
5232 HValue* context = environment()->context(); | 5236 HValue* context = environment()->context(); |
5233 int length = scope()->ContextChainLength(var->scope()); | 5237 int length = scope()->ContextChainLength(var->scope()); |
5234 while (length-- > 0) { | 5238 while (length-- > 0) { |
5235 context = Add<HLoadNamedField>( | 5239 context = Add<HLoadNamedField>( |
5236 context, nullptr, | 5240 context, nullptr, |
5237 HObjectAccess::ForContextSlot(Context::PREVIOUS_INDEX)); | 5241 HObjectAccess::ForContextSlot(Context::PREVIOUS_INDEX)); |
5238 } | 5242 } |
5239 return context; | 5243 return context; |
5240 } | 5244 } |
5241 | 5245 |
| 5246 void HOptimizedGraphBuilder::InlineGlobalPropertyLoad(LookupIterator* it, |
| 5247 BailoutId ast_id) { |
| 5248 Handle<PropertyCell> cell = it->GetPropertyCell(); |
| 5249 top_info()->dependencies()->AssumePropertyCell(cell); |
| 5250 auto cell_type = it->property_details().cell_type(); |
| 5251 if (cell_type == PropertyCellType::kConstant || |
| 5252 cell_type == PropertyCellType::kUndefined) { |
| 5253 Handle<Object> constant_object(cell->value(), isolate()); |
| 5254 if (constant_object->IsConsString()) { |
| 5255 constant_object = String::Flatten(Handle<String>::cast(constant_object)); |
| 5256 } |
| 5257 HConstant* constant = New<HConstant>(constant_object); |
| 5258 return ast_context()->ReturnInstruction(constant, ast_id); |
| 5259 } else { |
| 5260 auto access = HObjectAccess::ForPropertyCellValue(); |
| 5261 UniqueSet<Map>* field_maps = nullptr; |
| 5262 if (cell_type == PropertyCellType::kConstantType) { |
| 5263 switch (cell->GetConstantType()) { |
| 5264 case PropertyCellConstantType::kSmi: |
| 5265 access = access.WithRepresentation(Representation::Smi()); |
| 5266 break; |
| 5267 case PropertyCellConstantType::kStableMap: { |
| 5268 // Check that the map really is stable. The heap object could |
| 5269 // have mutated without the cell updating state. In that case, |
| 5270 // make no promises about the loaded value except that it's a |
| 5271 // heap object. |
| 5272 access = access.WithRepresentation(Representation::HeapObject()); |
| 5273 Handle<Map> map(HeapObject::cast(cell->value())->map()); |
| 5274 if (map->is_stable()) { |
| 5275 field_maps = new (zone()) |
| 5276 UniqueSet<Map>(Unique<Map>::CreateImmovable(map), zone()); |
| 5277 } |
| 5278 break; |
| 5279 } |
| 5280 } |
| 5281 } |
| 5282 HConstant* cell_constant = Add<HConstant>(cell); |
| 5283 HLoadNamedField* instr; |
| 5284 if (field_maps == nullptr) { |
| 5285 instr = New<HLoadNamedField>(cell_constant, nullptr, access); |
| 5286 } else { |
| 5287 instr = New<HLoadNamedField>(cell_constant, nullptr, access, field_maps, |
| 5288 HType::HeapObject()); |
| 5289 } |
| 5290 instr->ClearDependsOnFlag(kInobjectFields); |
| 5291 instr->SetDependsOnFlag(kGlobalVars); |
| 5292 return ast_context()->ReturnInstruction(instr, ast_id); |
| 5293 } |
| 5294 } |
5242 | 5295 |
5243 void HOptimizedGraphBuilder::VisitVariableProxy(VariableProxy* expr) { | 5296 void HOptimizedGraphBuilder::VisitVariableProxy(VariableProxy* expr) { |
5244 DCHECK(!HasStackOverflow()); | 5297 DCHECK(!HasStackOverflow()); |
5245 DCHECK(current_block() != NULL); | 5298 DCHECK(current_block() != NULL); |
5246 DCHECK(current_block()->HasPredecessor()); | 5299 DCHECK(current_block()->HasPredecessor()); |
5247 Variable* variable = expr->var(); | 5300 Variable* variable = expr->var(); |
5248 switch (variable->location()) { | 5301 switch (variable->location()) { |
5249 case VariableLocation::UNALLOCATED: { | 5302 case VariableLocation::UNALLOCATED: { |
5250 if (IsLexicalVariableMode(variable->mode())) { | 5303 if (IsLexicalVariableMode(variable->mode())) { |
5251 // TODO(rossberg): should this be an DCHECK? | 5304 // TODO(rossberg): should this be an DCHECK? |
(...skipping 28 matching lines...) Expand all Loading... |
5280 return Bailout(kReferenceToUninitializedVariable); | 5333 return Bailout(kReferenceToUninitializedVariable); |
5281 } | 5334 } |
5282 HInstruction* result = New<HLoadNamedField>( | 5335 HInstruction* result = New<HLoadNamedField>( |
5283 Add<HConstant>(script_context), nullptr, | 5336 Add<HConstant>(script_context), nullptr, |
5284 HObjectAccess::ForContextSlot(lookup.slot_index)); | 5337 HObjectAccess::ForContextSlot(lookup.slot_index)); |
5285 return ast_context()->ReturnInstruction(result, expr->id()); | 5338 return ast_context()->ReturnInstruction(result, expr->id()); |
5286 } | 5339 } |
5287 } | 5340 } |
5288 | 5341 |
5289 LookupIterator it(global, variable->name(), LookupIterator::OWN); | 5342 LookupIterator it(global, variable->name(), LookupIterator::OWN); |
5290 GlobalPropertyAccess type = LookupGlobalProperty(variable, &it, LOAD); | 5343 if (CanInlineGlobalPropertyAccess(variable, &it, LOAD)) { |
5291 | 5344 InlineGlobalPropertyLoad(&it, expr->id()); |
5292 if (type == kUseCell) { | 5345 return; |
5293 Handle<PropertyCell> cell = it.GetPropertyCell(); | |
5294 top_info()->dependencies()->AssumePropertyCell(cell); | |
5295 auto cell_type = it.property_details().cell_type(); | |
5296 if (cell_type == PropertyCellType::kConstant || | |
5297 cell_type == PropertyCellType::kUndefined) { | |
5298 Handle<Object> constant_object(cell->value(), isolate()); | |
5299 if (constant_object->IsConsString()) { | |
5300 constant_object = | |
5301 String::Flatten(Handle<String>::cast(constant_object)); | |
5302 } | |
5303 HConstant* constant = New<HConstant>(constant_object); | |
5304 return ast_context()->ReturnInstruction(constant, expr->id()); | |
5305 } else { | |
5306 auto access = HObjectAccess::ForPropertyCellValue(); | |
5307 UniqueSet<Map>* field_maps = nullptr; | |
5308 if (cell_type == PropertyCellType::kConstantType) { | |
5309 switch (cell->GetConstantType()) { | |
5310 case PropertyCellConstantType::kSmi: | |
5311 access = access.WithRepresentation(Representation::Smi()); | |
5312 break; | |
5313 case PropertyCellConstantType::kStableMap: { | |
5314 // Check that the map really is stable. The heap object could | |
5315 // have mutated without the cell updating state. In that case, | |
5316 // make no promises about the loaded value except that it's a | |
5317 // heap object. | |
5318 access = | |
5319 access.WithRepresentation(Representation::HeapObject()); | |
5320 Handle<Map> map(HeapObject::cast(cell->value())->map()); | |
5321 if (map->is_stable()) { | |
5322 field_maps = new (zone()) | |
5323 UniqueSet<Map>(Unique<Map>::CreateImmovable(map), zone()); | |
5324 } | |
5325 break; | |
5326 } | |
5327 } | |
5328 } | |
5329 HConstant* cell_constant = Add<HConstant>(cell); | |
5330 HLoadNamedField* instr; | |
5331 if (field_maps == nullptr) { | |
5332 instr = New<HLoadNamedField>(cell_constant, nullptr, access); | |
5333 } else { | |
5334 instr = New<HLoadNamedField>(cell_constant, nullptr, access, | |
5335 field_maps, HType::HeapObject()); | |
5336 } | |
5337 instr->ClearDependsOnFlag(kInobjectFields); | |
5338 instr->SetDependsOnFlag(kGlobalVars); | |
5339 return ast_context()->ReturnInstruction(instr, expr->id()); | |
5340 } | |
5341 } else { | 5346 } else { |
5342 Handle<TypeFeedbackVector> vector(current_feedback_vector(), isolate()); | 5347 Handle<TypeFeedbackVector> vector(current_feedback_vector(), isolate()); |
5343 | 5348 |
5344 HValue* vector_value = Add<HConstant>(vector); | 5349 HValue* vector_value = Add<HConstant>(vector); |
5345 HValue* slot_value = | 5350 HValue* slot_value = |
5346 Add<HConstant>(vector->GetIndex(expr->VariableFeedbackSlot())); | 5351 Add<HConstant>(vector->GetIndex(expr->VariableFeedbackSlot())); |
5347 Callable callable = CodeFactory::LoadGlobalICInOptimizedCode( | 5352 Callable callable = CodeFactory::LoadGlobalICInOptimizedCode( |
5348 isolate(), ast_context()->typeof_mode()); | 5353 isolate(), ast_context()->typeof_mode()); |
5349 HValue* stub = Add<HConstant>(callable.code()); | 5354 HValue* stub = Add<HConstant>(callable.code()); |
5350 HValue* values[] = {slot_value, vector_value}; | 5355 HValue* values[] = {slot_value, vector_value}; |
(...skipping 1083 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6434 DCHECK(prop != NULL); | 6439 DCHECK(prop != NULL); |
6435 CHECK_ALIVE(VisitForValue(prop->obj())); | 6440 CHECK_ALIVE(VisitForValue(prop->obj())); |
6436 if (!prop->key()->IsPropertyName()) { | 6441 if (!prop->key()->IsPropertyName()) { |
6437 CHECK_ALIVE(VisitForValue(prop->key())); | 6442 CHECK_ALIVE(VisitForValue(prop->key())); |
6438 } | 6443 } |
6439 CHECK_ALIVE(VisitForValue(expr->value())); | 6444 CHECK_ALIVE(VisitForValue(expr->value())); |
6440 BuildStore(expr, prop, expr->AssignmentSlot(), expr->id(), | 6445 BuildStore(expr, prop, expr->AssignmentSlot(), expr->id(), |
6441 expr->AssignmentId(), expr->IsUninitialized()); | 6446 expr->AssignmentId(), expr->IsUninitialized()); |
6442 } | 6447 } |
6443 | 6448 |
| 6449 HInstruction* HOptimizedGraphBuilder::InlineGlobalPropertyStore( |
| 6450 LookupIterator* it, HValue* value, BailoutId ast_id) { |
| 6451 Handle<PropertyCell> cell = it->GetPropertyCell(); |
| 6452 top_info()->dependencies()->AssumePropertyCell(cell); |
| 6453 auto cell_type = it->property_details().cell_type(); |
| 6454 if (cell_type == PropertyCellType::kConstant || |
| 6455 cell_type == PropertyCellType::kUndefined) { |
| 6456 Handle<Object> constant(cell->value(), isolate()); |
| 6457 if (value->IsConstant()) { |
| 6458 HConstant* c_value = HConstant::cast(value); |
| 6459 if (!constant.is_identical_to(c_value->handle(isolate()))) { |
| 6460 Add<HDeoptimize>(DeoptimizeReason::kConstantGlobalVariableAssignment, |
| 6461 Deoptimizer::EAGER); |
| 6462 } |
| 6463 } else { |
| 6464 HValue* c_constant = Add<HConstant>(constant); |
| 6465 IfBuilder builder(this); |
| 6466 if (constant->IsNumber()) { |
| 6467 builder.If<HCompareNumericAndBranch>(value, c_constant, Token::EQ); |
| 6468 } else { |
| 6469 builder.If<HCompareObjectEqAndBranch>(value, c_constant); |
| 6470 } |
| 6471 builder.Then(); |
| 6472 builder.Else(); |
| 6473 Add<HDeoptimize>(DeoptimizeReason::kConstantGlobalVariableAssignment, |
| 6474 Deoptimizer::EAGER); |
| 6475 builder.End(); |
| 6476 } |
| 6477 } |
| 6478 HConstant* cell_constant = Add<HConstant>(cell); |
| 6479 auto access = HObjectAccess::ForPropertyCellValue(); |
| 6480 if (cell_type == PropertyCellType::kConstantType) { |
| 6481 switch (cell->GetConstantType()) { |
| 6482 case PropertyCellConstantType::kSmi: |
| 6483 access = access.WithRepresentation(Representation::Smi()); |
| 6484 break; |
| 6485 case PropertyCellConstantType::kStableMap: { |
| 6486 // First check that the previous value of the {cell} still has the |
| 6487 // map that we are about to check the new {value} for. If not, then |
| 6488 // the stable map assumption was invalidated and we cannot continue |
| 6489 // with the optimized code. |
| 6490 Handle<HeapObject> cell_value(HeapObject::cast(cell->value())); |
| 6491 Handle<Map> cell_value_map(cell_value->map()); |
| 6492 if (!cell_value_map->is_stable()) { |
| 6493 Bailout(kUnstableConstantTypeHeapObject); |
| 6494 return nullptr; |
| 6495 } |
| 6496 top_info()->dependencies()->AssumeMapStable(cell_value_map); |
| 6497 // Now check that the new {value} is a HeapObject with the same map |
| 6498 Add<HCheckHeapObject>(value); |
| 6499 value = Add<HCheckMaps>(value, cell_value_map); |
| 6500 access = access.WithRepresentation(Representation::HeapObject()); |
| 6501 break; |
| 6502 } |
| 6503 } |
| 6504 } |
| 6505 HInstruction* instr = New<HStoreNamedField>(cell_constant, access, value); |
| 6506 instr->ClearChangesFlag(kInobjectFields); |
| 6507 instr->SetChangesFlag(kGlobalVars); |
| 6508 return instr; |
| 6509 } |
6444 | 6510 |
6445 // Because not every expression has a position and there is not common | 6511 // Because not every expression has a position and there is not common |
6446 // superclass of Assignment and CountOperation, we cannot just pass the | 6512 // superclass of Assignment and CountOperation, we cannot just pass the |
6447 // owning expression instead of position and ast_id separately. | 6513 // owning expression instead of position and ast_id separately. |
6448 void HOptimizedGraphBuilder::HandleGlobalVariableAssignment( | 6514 void HOptimizedGraphBuilder::HandleGlobalVariableAssignment( |
6449 Variable* var, HValue* value, FeedbackVectorSlot slot, BailoutId ast_id) { | 6515 Variable* var, HValue* value, FeedbackVectorSlot slot, BailoutId ast_id) { |
6450 Handle<JSGlobalObject> global(current_info()->global_object()); | 6516 Handle<JSGlobalObject> global(current_info()->global_object()); |
6451 | 6517 |
6452 // Lookup in script contexts. | 6518 // Lookup in script contexts. |
6453 { | 6519 { |
(...skipping 20 matching lines...) Expand all Loading... |
6474 Add<HConstant>(script_context), | 6540 Add<HConstant>(script_context), |
6475 HObjectAccess::ForContextSlot(lookup.slot_index), value); | 6541 HObjectAccess::ForContextSlot(lookup.slot_index), value); |
6476 USE(instr); | 6542 USE(instr); |
6477 DCHECK(instr->HasObservableSideEffects()); | 6543 DCHECK(instr->HasObservableSideEffects()); |
6478 Add<HSimulate>(ast_id, REMOVABLE_SIMULATE); | 6544 Add<HSimulate>(ast_id, REMOVABLE_SIMULATE); |
6479 return; | 6545 return; |
6480 } | 6546 } |
6481 } | 6547 } |
6482 | 6548 |
6483 LookupIterator it(global, var->name(), LookupIterator::OWN); | 6549 LookupIterator it(global, var->name(), LookupIterator::OWN); |
6484 GlobalPropertyAccess type = LookupGlobalProperty(var, &it, STORE); | 6550 if (CanInlineGlobalPropertyAccess(var, &it, STORE)) { |
6485 if (type == kUseCell) { | 6551 HInstruction* instr = InlineGlobalPropertyStore(&it, value, ast_id); |
6486 Handle<PropertyCell> cell = it.GetPropertyCell(); | 6552 if (!instr) return; |
6487 top_info()->dependencies()->AssumePropertyCell(cell); | 6553 AddInstruction(instr); |
6488 auto cell_type = it.property_details().cell_type(); | |
6489 if (cell_type == PropertyCellType::kConstant || | |
6490 cell_type == PropertyCellType::kUndefined) { | |
6491 Handle<Object> constant(cell->value(), isolate()); | |
6492 if (value->IsConstant()) { | |
6493 HConstant* c_value = HConstant::cast(value); | |
6494 if (!constant.is_identical_to(c_value->handle(isolate()))) { | |
6495 Add<HDeoptimize>(DeoptimizeReason::kConstantGlobalVariableAssignment, | |
6496 Deoptimizer::EAGER); | |
6497 } | |
6498 } else { | |
6499 HValue* c_constant = Add<HConstant>(constant); | |
6500 IfBuilder builder(this); | |
6501 if (constant->IsNumber()) { | |
6502 builder.If<HCompareNumericAndBranch>(value, c_constant, Token::EQ); | |
6503 } else { | |
6504 builder.If<HCompareObjectEqAndBranch>(value, c_constant); | |
6505 } | |
6506 builder.Then(); | |
6507 builder.Else(); | |
6508 Add<HDeoptimize>(DeoptimizeReason::kConstantGlobalVariableAssignment, | |
6509 Deoptimizer::EAGER); | |
6510 builder.End(); | |
6511 } | |
6512 } | |
6513 HConstant* cell_constant = Add<HConstant>(cell); | |
6514 auto access = HObjectAccess::ForPropertyCellValue(); | |
6515 if (cell_type == PropertyCellType::kConstantType) { | |
6516 switch (cell->GetConstantType()) { | |
6517 case PropertyCellConstantType::kSmi: | |
6518 access = access.WithRepresentation(Representation::Smi()); | |
6519 break; | |
6520 case PropertyCellConstantType::kStableMap: { | |
6521 // First check that the previous value of the {cell} still has the | |
6522 // map that we are about to check the new {value} for. If not, then | |
6523 // the stable map assumption was invalidated and we cannot continue | |
6524 // with the optimized code. | |
6525 Handle<HeapObject> cell_value(HeapObject::cast(cell->value())); | |
6526 Handle<Map> cell_value_map(cell_value->map()); | |
6527 if (!cell_value_map->is_stable()) { | |
6528 return Bailout(kUnstableConstantTypeHeapObject); | |
6529 } | |
6530 top_info()->dependencies()->AssumeMapStable(cell_value_map); | |
6531 // Now check that the new {value} is a HeapObject with the same map. | |
6532 Add<HCheckHeapObject>(value); | |
6533 value = Add<HCheckMaps>(value, cell_value_map); | |
6534 access = access.WithRepresentation(Representation::HeapObject()); | |
6535 break; | |
6536 } | |
6537 } | |
6538 } | |
6539 HInstruction* instr = Add<HStoreNamedField>(cell_constant, access, value); | |
6540 instr->ClearChangesFlag(kInobjectFields); | |
6541 instr->SetChangesFlag(kGlobalVars); | |
6542 if (instr->HasObservableSideEffects()) { | 6554 if (instr->HasObservableSideEffects()) { |
6543 Add<HSimulate>(ast_id, REMOVABLE_SIMULATE); | 6555 Add<HSimulate>(ast_id, REMOVABLE_SIMULATE); |
6544 } | 6556 } |
6545 } else { | 6557 } else { |
6546 HValue* global_object = Add<HLoadNamedField>( | 6558 HValue* global_object = Add<HLoadNamedField>( |
6547 BuildGetNativeContext(), nullptr, | 6559 BuildGetNativeContext(), nullptr, |
6548 HObjectAccess::ForContextSlot(Context::EXTENSION_INDEX)); | 6560 HObjectAccess::ForContextSlot(Context::EXTENSION_INDEX)); |
6549 Handle<TypeFeedbackVector> vector = | 6561 Handle<TypeFeedbackVector> vector = |
6550 handle(current_feedback_vector(), isolate()); | 6562 handle(current_feedback_vector(), isolate()); |
6551 HValue* name = Add<HConstant>(var->name()); | 6563 HValue* name = Add<HConstant>(var->name()); |
(...skipping 901 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7453 } | 7465 } |
7454 | 7466 |
7455 HValue* HOptimizedGraphBuilder::BuildNamedAccess( | 7467 HValue* HOptimizedGraphBuilder::BuildNamedAccess( |
7456 PropertyAccessType access, BailoutId ast_id, BailoutId return_id, | 7468 PropertyAccessType access, BailoutId ast_id, BailoutId return_id, |
7457 Expression* expr, FeedbackVectorSlot slot, HValue* object, | 7469 Expression* expr, FeedbackVectorSlot slot, HValue* object, |
7458 Handle<Name> name, HValue* value, bool is_uninitialized) { | 7470 Handle<Name> name, HValue* value, bool is_uninitialized) { |
7459 SmallMapList* maps; | 7471 SmallMapList* maps; |
7460 ComputeReceiverTypes(expr, object, &maps, this); | 7472 ComputeReceiverTypes(expr, object, &maps, this); |
7461 DCHECK(maps != NULL); | 7473 DCHECK(maps != NULL); |
7462 | 7474 |
| 7475 // Check for special case: Access via a single map to the global proxy |
| 7476 // can also be handled monomorphically. |
7463 if (maps->length() > 0) { | 7477 if (maps->length() > 0) { |
| 7478 Handle<Object> map_constructor = |
| 7479 handle(maps->first()->GetConstructor(), isolate()); |
| 7480 if (map_constructor->IsJSFunction()) { |
| 7481 Handle<Context> map_context = |
| 7482 handle(Handle<JSFunction>::cast(map_constructor)->context()); |
| 7483 Handle<Context> current_context(current_info()->context()); |
| 7484 bool is_same_context_global_proxy_access = |
| 7485 maps->length() == 1 && // >1 map => fallback to polymorphic |
| 7486 maps->first()->IsJSGlobalProxyMap() && |
| 7487 (*map_context == *current_context); |
| 7488 if (is_same_context_global_proxy_access) { |
| 7489 Handle<JSGlobalObject> global_object(current_info()->global_object()); |
| 7490 LookupIterator it(global_object, name, LookupIterator::OWN); |
| 7491 if (CanInlineGlobalPropertyAccess(&it, access)) { |
| 7492 BuildCheckHeapObject(object); |
| 7493 Add<HCheckMaps>(object, maps); |
| 7494 if (access == LOAD) { |
| 7495 InlineGlobalPropertyLoad(&it, expr->id()); |
| 7496 return nullptr; |
| 7497 } else { |
| 7498 return InlineGlobalPropertyStore(&it, value, expr->id()); |
| 7499 } |
| 7500 } |
| 7501 } |
| 7502 } |
| 7503 |
7464 PropertyAccessInfo info(this, access, maps->first(), name); | 7504 PropertyAccessInfo info(this, access, maps->first(), name); |
7465 if (!info.CanAccessAsMonomorphic(maps)) { | 7505 if (!info.CanAccessAsMonomorphic(maps)) { |
7466 HandlePolymorphicNamedFieldAccess(access, expr, slot, ast_id, return_id, | 7506 HandlePolymorphicNamedFieldAccess(access, expr, slot, ast_id, return_id, |
7467 object, value, maps, name); | 7507 object, value, maps, name); |
7468 return NULL; | 7508 return NULL; |
7469 } | 7509 } |
7470 | 7510 |
7471 HValue* checked_object; | 7511 HValue* checked_object; |
7472 // AstType::Number() is only supported by polymorphic load/call handling. | 7512 // AstType::Number() is only supported by polymorphic load/call handling. |
7473 DCHECK(!info.IsNumberType()); | 7513 DCHECK(!info.IsNumberType()); |
(...skipping 5521 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
12995 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); | 13035 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); |
12996 } | 13036 } |
12997 | 13037 |
12998 #ifdef DEBUG | 13038 #ifdef DEBUG |
12999 graph_->Verify(false); // No full verify. | 13039 graph_->Verify(false); // No full verify. |
13000 #endif | 13040 #endif |
13001 } | 13041 } |
13002 | 13042 |
13003 } // namespace internal | 13043 } // namespace internal |
13004 } // namespace v8 | 13044 } // namespace v8 |
OLD | NEW |