@@ -5199,12 +5199,16 @@ void HOptimizedGraphBuilder::VisitConditional(Conditional* expr) {
51995199 }
52005200}
52015201
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+ }
52025207
5203- HOptimizedGraphBuilder::GlobalPropertyAccess
5204- HOptimizedGraphBuilder::LookupGlobalProperty (Variable* var, LookupIterator* it,
5205- PropertyAccessType access_type) {
5206- if (var->is_this () || !current_info ()->has_global_object ()) {
5207- return kUseGeneric ;
5208+ bool HOptimizedGraphBuilder::CanInlineGlobalPropertyAccess (
5209+ LookupIterator* it, PropertyAccessType access_type) {
5210+ if (!current_info ()->has_global_object ()) {
5211+ return false ;
52085212 }
52095213
52105214 switch (it->state ()) {
@@ -5213,17 +5217,17 @@ HOptimizedGraphBuilder::LookupGlobalProperty(Variable* var, LookupIterator* it,
52135217 case LookupIterator::INTERCEPTOR :
52145218 case LookupIterator::INTEGER_INDEXED_EXOTIC :
52155219 case LookupIterator::NOT_FOUND :
5216- return kUseGeneric ;
5220+ return false ;
52175221 case LookupIterator::DATA :
5218- if (access_type == STORE && it->IsReadOnly ()) return kUseGeneric ;
5219- if (!it->GetHolder <JSObject>()->IsJSGlobalObject ()) return kUseGeneric ;
5220- return kUseCell ;
5222+ if (access_type == STORE && it->IsReadOnly ()) return false ;
5223+ if (!it->GetHolder <JSObject>()->IsJSGlobalObject ()) return false ;
5224+ return true ;
52215225 case LookupIterator::JSPROXY :
52225226 case LookupIterator::TRANSITION :
52235227 UNREACHABLE ();
52245228 }
52255229 UNREACHABLE ();
5226- return kUseGeneric ;
5230+ return false ;
52275231}
52285232
52295233
@@ -5239,6 +5243,55 @@ HValue* HOptimizedGraphBuilder::BuildContextChainWalk(Variable* var) {
52395243 return context;
52405244}
52415245
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+ }
52425295
52435296void HOptimizedGraphBuilder::VisitVariableProxy (VariableProxy* expr) {
52445297 DCHECK (!HasStackOverflow ());
@@ -5287,57 +5340,9 @@ void HOptimizedGraphBuilder::VisitVariableProxy(VariableProxy* expr) {
52875340 }
52885341
52895342 LookupIterator it (global, variable->name (), LookupIterator::OWN );
5290- GlobalPropertyAccess type = LookupGlobalProperty (variable, &it, LOAD );
5291-
5292- if (type == kUseCell ) {
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- }
5343+ if (CanInlineGlobalPropertyAccess (variable, &it, LOAD )) {
5344+ InlineGlobalPropertyLoad (&it, expr->id ());
5345+ return ;
53415346 } else {
53425347 Handle<TypeFeedbackVector> vector (current_feedback_vector (), isolate ());
53435348
@@ -6441,6 +6446,67 @@ void HOptimizedGraphBuilder::HandlePropertyAssignment(Assignment* expr) {
64416446 expr->AssignmentId (), expr->IsUninitialized ());
64426447}
64436448
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+ }
64446510
64456511// Because not every expression has a position and there is not common
64466512// superclass of Assignment and CountOperation, we cannot just pass the
@@ -6481,64 +6547,10 @@ void HOptimizedGraphBuilder::HandleGlobalVariableAssignment(
64816547 }
64826548
64836549 LookupIterator it (global, var->name (), LookupIterator::OWN );
6484- GlobalPropertyAccess type = LookupGlobalProperty (var, &it, STORE );
6485- if (type == kUseCell ) {
6486- Handle<PropertyCell> cell = it.GetPropertyCell ();
6487- top_info ()->dependencies ()->AssumePropertyCell (cell);
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 );
6550+ if (CanInlineGlobalPropertyAccess (var, &it, STORE )) {
6551+ HInstruction* instr = InlineGlobalPropertyStore (&it, value, ast_id);
6552+ if (!instr) return ;
6553+ AddInstruction (instr);
65426554 if (instr->HasObservableSideEffects ()) {
65436555 Add<HSimulate>(ast_id, REMOVABLE_SIMULATE );
65446556 }
@@ -7460,7 +7472,35 @@ HValue* HOptimizedGraphBuilder::BuildNamedAccess(
74607472 ComputeReceiverTypes (expr, object, &maps, this );
74617473 DCHECK (maps != NULL );
74627474
7475+ // Check for special case: Access via a single map to the global proxy
7476+ // can also be handled monomorphically.
74637477 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+
74647504 PropertyAccessInfo info (this , access, maps->first (), name);
74657505 if (!info.CanAccessAsMonomorphic (maps)) {
74667506 HandlePolymorphicNamedFieldAccess (access, expr, slot, ast_id, return_id,
0 commit comments