Unify load handling into CanLoad and Load.
authorverwaest@chromium.org <verwaest@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 18 Sep 2013 14:56:18 +0000 (14:56 +0000)
committerverwaest@chromium.org <verwaest@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 18 Sep 2013 14:56:18 +0000 (14:56 +0000)
R=titzer@chromium.org

Review URL: https://chromiumcodereview.appspot.com/24088003

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@16792 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

src/hydrogen.cc
src/hydrogen.h

index cde6b09..8a2af36 100644 (file)
@@ -4065,20 +4065,6 @@ static bool LookupAccessorPair(Handle<Map> map,
 }
 
 
-static bool LookupGetter(Handle<Map> map,
-                         Handle<String> name,
-                         Handle<JSFunction>* getter,
-                         Handle<JSObject>* holder) {
-  Handle<AccessorPair> accessors;
-  if (LookupAccessorPair(map, name, &accessors, holder) &&
-      accessors->getter()->IsJSFunction()) {
-    *getter = Handle<JSFunction>(JSFunction::cast(accessors->getter()));
-    return true;
-  }
-  return false;
-}
-
-
 static bool LookupSetter(Handle<Map> map,
                          Handle<String> name,
                          Handle<JSFunction>* setter,
@@ -4546,140 +4532,179 @@ HInstruction* HOptimizedGraphBuilder::BuildStoreNamedMonomorphic(
 }
 
 
-static bool CanLoadPropertyFromPrototype(Handle<Map> map,
-                                         Handle<Name> name,
-                                         LookupResult* lookup) {
-  if (!CanInlinePropertyAccess(*map)) return false;
-  map->LookupDescriptor(NULL, *name, lookup);
-  if (lookup->IsFound()) return false;
+bool HOptimizedGraphBuilder::PropertyAccessInfo::IsCompatibleForLoad(
+    PropertyAccessInfo* info) {
+  if (!CanInlinePropertyAccess(*map_)) return false;
+
+  if (!LookupDescriptor()) return false;
+
+  if (!lookup_.IsFound()) {
+    return (!info->lookup_.IsFound() || !info->holder_.is_null()) &&
+        map_->prototype() == info->map_->prototype();
+  }
+
+  if (lookup_.IsPropertyCallbacks()) {
+    return accessor_.is_identical_to(info->accessor_);
+  }
+
+  if (lookup_.IsConstant()) {
+    return constant_.is_identical_to(info->constant_);
+  }
+
+  ASSERT(lookup_.IsField());
+  if (!info->lookup_.IsField()) return false;
+
+  Representation r = access_.representation();
+  if (!info->access_.representation().IsCompatibleForLoad(r)) return false;
+  if (info->access_.offset() != access_.offset()) return false;
+  if (info->access_.IsInobject() != access_.IsInobject()) return false;
+  info->GeneralizeRepresentation(r);
   return true;
 }
 
 
-HInstruction* HOptimizedGraphBuilder::TryLoadPolymorphicAsMonomorphic(
-    HValue* object,
-    SmallMapList* types,
-    Handle<String> name) {
-  // Use monomorphic load if property lookup results in the same field index
-  // for all maps. Requires special map check on the set of all handled maps.
-  if (types->length() > kMaxLoadPolymorphism) return NULL;
+bool HOptimizedGraphBuilder::PropertyAccessInfo::LookupDescriptor() {
+  map_->LookupDescriptor(NULL, *name_, &lookup_);
+  return LoadResult(map_);
+}
 
-  LookupResult lookup(isolate());
-  int count;
-  HObjectAccess access = HObjectAccess::ForMap();  // initial value unused.
-  for (count = 0; count < types->length(); ++count) {
-    Handle<Map> map = types->at(count);
-    if (!ComputeLoadStoreField(map, name, &lookup, false)) break;
 
-    HObjectAccess new_access = HObjectAccess::ForField(map, &lookup, name);
+bool HOptimizedGraphBuilder::PropertyAccessInfo::LoadResult(Handle<Map> map) {
+  if (lookup_.IsField()) {
+    access_ = HObjectAccess::ForField(map, &lookup_, name_);
+  } else if (lookup_.IsPropertyCallbacks()) {
+    Handle<Object> callback(lookup_.GetValueFromMap(*map), isolate());
+    if (!callback->IsAccessorPair()) return false;
+    Object* getter = Handle<AccessorPair>::cast(callback)->getter();
+    if (!getter->IsJSFunction()) return false;
+    accessor_ = handle(JSFunction::cast(getter));
+  } else if (lookup_.IsConstant()) {
+    constant_ = handle(lookup_.GetConstantFromMap(*map), isolate());
+  }
 
-    if (count == 0) {
-      // First time through the loop; set access and representation.
-      access = new_access;
-    } else if (!access.representation().IsCompatibleForLoad(
-        new_access.representation())) {
-      // Representations did not match.
-      break;
-    } else if (access.offset() != new_access.offset()) {
-      // Offsets did not match.
-      break;
-    } else if (access.IsInobject() != new_access.IsInobject()) {
-      // In-objectness did not match.
-      break;
+  return true;
+}
+
+
+bool HOptimizedGraphBuilder::PropertyAccessInfo::LookupInPrototypes() {
+  Handle<Map> map = map_;
+  while (map->prototype()->IsJSObject()) {
+    holder_ = handle(JSObject::cast(map->prototype()));
+    map = Handle<Map>(holder_->map());
+    if (!CanInlinePropertyAccess(*map)) {
+      lookup_.NotFound();
+      return false;
     }
-    access = access.WithRepresentation(
-        access.representation().generalize(new_access.representation()));
+    map->LookupDescriptor(*holder_, *name_, &lookup_);
+    if (lookup_.IsFound()) return LoadResult(map);
   }
+  lookup_.NotFound();
+  return true;
+}
 
-  if (count == types->length()) {
-    // Everything matched; can use monomorphic load.
-    BuildCheckHeapObject(object);
-    HCheckMaps* checked_object = Add<HCheckMaps>(object, types);
-    return BuildLoadNamedField(checked_object, access);
-  }
 
-  if (count != 0) return NULL;
+bool HOptimizedGraphBuilder::PropertyAccessInfo::CanLoadMonomorphic() {
+  if (!CanInlinePropertyAccess(*map_)) return IsStringLength();
+  if (IsArrayLength()) return true;
+  if (!LookupDescriptor()) return false;
+  if (lookup_.IsFound()) return true;
+  return LookupInPrototypes();
+}
+
 
-  // Second chance: the property is on the prototype and all maps have the
-  // same prototype.
-  Handle<Map> map(types->at(0));
-  if (!CanLoadPropertyFromPrototype(map, name, &lookup)) return NULL;
+bool HOptimizedGraphBuilder::PropertyAccessInfo::CanLoadAsMonomorphic(
+    SmallMapList* types) {
+  ASSERT(map_.is_identical_to(types->first()));
+  if (!CanLoadMonomorphic()) return false;
+  if (types->length() > kMaxLoadPolymorphism) return false;
 
-  Handle<Object> prototype(map->prototype(), isolate());
-  for (count = 1; count < types->length(); ++count) {
-    Handle<Map> test_map(types->at(count));
-    if (!CanLoadPropertyFromPrototype(test_map, name, &lookup)) return NULL;
-    if (test_map->prototype() != *prototype) return NULL;
+  if (IsStringLength()) {
+    for (int i = 1; i < types->length(); ++i) {
+      if (types->at(i)->instance_type() >= FIRST_NONSTRING_TYPE) return false;
+    }
+    return true;
   }
 
-  LookupInPrototypes(map, name, &lookup);
-  if (!lookup.IsField()) return NULL;
+  if (IsArrayLength()) {
+    bool is_fast = IsFastElementsKind(map_->elements_kind());
+    for (int i = 1; i < types->length(); ++i) {
+      Handle<Map> test_map = types->at(i);
+      if (test_map->instance_type() != JS_ARRAY_TYPE) return false;
+      if (IsFastElementsKind(test_map->elements_kind()) != is_fast) {
+        return false;
+      }
+    }
+    return true;
+  }
 
-  BuildCheckHeapObject(object);
-  Add<HCheckMaps>(object, types);
+  for (int i = 1; i < types->length(); ++i) {
+    PropertyAccessInfo test_info(isolate(), types->at(i), name_);
+    if (!test_info.IsCompatibleForLoad(this)) return false;
+  }
 
-  Handle<JSObject> holder(lookup.holder());
-  Handle<Map> holder_map(holder->map());
-  HValue* checked_holder = BuildCheckPrototypeMaps(
-      Handle<JSObject>::cast(prototype), holder);
-  return BuildLoadNamedField(checked_holder,
-      HObjectAccess::ForField(holder_map, &lookup, name));
+  return true;
 }
 
 
-// Returns true if an instance of this map can never find a property with this
-// name in its prototype chain.  This means all prototypes up to the top are
-// fast and don't have the name in them.  It would be good if we could optimize
-// polymorphic loads where the property is sometimes found in the prototype
-// chain.
-static bool PrototypeChainCanNeverResolve(
-    Handle<Map> map, Handle<String> name) {
-  Isolate* isolate = map->GetIsolate();
-  Object* current = map->prototype();
-  while (current != isolate->heap()->null_value()) {
-    if (current->IsJSGlobalProxy() ||
-        current->IsGlobalObject() ||
-        !current->IsJSObject() ||
-        !CanInlinePropertyAccess(JSObject::cast(current)->map()) ||
-        JSObject::cast(current)->IsAccessCheckNeeded()) {
-      return false;
-    }
+HInstruction* HOptimizedGraphBuilder::BuildLoadMonomorphic(
+    PropertyAccessInfo* info,
+    HValue* object,
+    HInstruction* checked_object,
+    BailoutId ast_id,
+    BailoutId return_id,
+    bool can_inline_accessor) {
+  if (info->IsStringLength()) {
+    return New<HLoadNamedField>(
+        checked_object, HObjectAccess::ForStringLength());
+  }
 
-    LookupResult lookup(isolate);
-    Map* map = JSObject::cast(current)->map();
-    map->LookupDescriptor(NULL, *name, &lookup);
-    if (lookup.IsFound()) return false;
-    if (!lookup.IsCacheable()) return false;
-    current = JSObject::cast(current)->GetPrototype();
+  if (info->IsArrayLength()) {
+    return New<HLoadNamedField>(
+        checked_object, HObjectAccess::ForArrayLength(
+            info->map()->elements_kind()));
   }
-  return true;
+
+  HValue* checked_holder = checked_object;
+  if (info->has_holder()) {
+    Handle<JSObject> prototype(JSObject::cast(info->map()->prototype()));
+    checked_holder = BuildCheckPrototypeMaps(prototype, info->holder());
+  }
+
+  if (!info->lookup()->IsFound()) return graph()->GetConstantUndefined();
+
+  if (info->lookup()->IsField()) {
+    return BuildLoadNamedField(checked_holder, info->access());
+  }
+
+  if (info->lookup()->IsPropertyCallbacks()) {
+    Push(checked_object);
+    if (FLAG_inline_accessors &&
+        can_inline_accessor &&
+        TryInlineGetter(info->accessor(), ast_id, return_id)) {
+      return NULL;
+    }
+    Add<HPushArgument>(Pop());
+    return new(zone()) HCallConstantFunction(info->accessor(), 1);
+  }
+
+  ASSERT(info->lookup()->IsConstant());
+  return New<HConstant>(info->constant());
 }
 
 
 void HOptimizedGraphBuilder::HandlePolymorphicLoadNamedField(
     int position,
     BailoutId ast_id,
+    BailoutId return_id,
     HValue* object,
     SmallMapList* types,
     Handle<String> name) {
-  HInstruction* instr = TryLoadPolymorphicAsMonomorphic(object, types, name);
-  if (instr != NULL) {
-    instr->set_position(position);
-    return ast_context()->ReturnInstruction(instr, ast_id);
-  }
-
   // Something did not match; must use a polymorphic load.
   int count = 0;
   HBasicBlock* join = NULL;
   for (int i = 0; i < types->length() && count < kMaxLoadPolymorphism; ++i) {
-    Handle<Map> map = types->at(i);
-    LookupResult lookup(isolate());
-    if (ComputeLoadStoreField(map, name, &lookup, false) ||
-        (lookup.IsCacheable() &&
-         CanInlinePropertyAccess(*map) &&
-         (lookup.IsConstant() ||
-          (!lookup.IsFound() &&
-           PrototypeChainCanNeverResolve(map, name))))) {
+    PropertyAccessInfo info(isolate(), types->at(i), name);
+    if (info.CanLoadMonomorphic()) {
       if (count == 0) {
         BuildCheckHeapObject(object);
         join = graph()->CreateBasicBlock();
@@ -4687,37 +4712,25 @@ void HOptimizedGraphBuilder::HandlePolymorphicLoadNamedField(
       ++count;
       HBasicBlock* if_true = graph()->CreateBasicBlock();
       HBasicBlock* if_false = graph()->CreateBasicBlock();
-      HCompareMap* compare =
-          new(zone()) HCompareMap(object, map,  if_true, if_false);
+      HCompareMap* compare = new(zone()) HCompareMap(
+          object, info.map(),  if_true, if_false);
       current_block()->Finish(compare);
 
       set_current_block(if_true);
 
-      // TODO(verwaest): Merge logic with BuildLoadNamedMonomorphic.
-      if (lookup.IsField()) {
-        HObjectAccess access = HObjectAccess::ForField(map, &lookup, name);
-        HLoadNamedField* load = BuildLoadNamedField(compare, access);
-        load->set_position(position);
-        AddInstruction(load);
-        if (!ast_context()->IsEffect()) Push(load);
-      } else if (lookup.IsConstant()) {
-        Handle<Object> constant(lookup.GetConstantFromMap(*map), isolate());
-        HConstant* hconstant = Add<HConstant>(constant);
-        if (!ast_context()->IsEffect()) Push(hconstant);
+      HInstruction* load = BuildLoadMonomorphic(
+          &info, object, compare, ast_id, return_id, FLAG_polymorphic_inlining);
+      if (load == NULL) {
+        if (HasStackOverflow()) return;
       } else {
-        ASSERT(!lookup.IsFound());
-        if (map->prototype()->IsJSObject()) {
-          Handle<JSObject> prototype(JSObject::cast(map->prototype()));
-          Handle<JSObject> holder = prototype;
-          while (holder->map()->prototype()->IsJSObject()) {
-            holder = handle(JSObject::cast(holder->map()->prototype()));
-          }
-          BuildCheckPrototypeMaps(prototype, holder);
+        if (!load->IsLinked()) {
+          load->set_position(position);
+          AddInstruction(load);
         }
-        if (!ast_context()->IsEffect()) Push(graph()->GetConstantUndefined());
+        if (!ast_context()->IsEffect()) Push(load);
       }
 
-      current_block()->Goto(join);
+      if (current_block() != NULL) current_block()->Goto(join);
       set_current_block(if_false);
     }
   }
@@ -4761,8 +4774,6 @@ bool HOptimizedGraphBuilder::TryStorePolymorphicAsMonomorphic(
   // for all maps. Requires special map check on the set of all handled maps.
   if (types->length() > kMaxStorePolymorphism) return false;
 
-  // TODO(verwaest): Merge the checking logic with the code in
-  // TryLoadPolymorphicAsMonomorphic.
   LookupResult lookup(isolate());
   int count;
   Representation representation = Representation::None();
@@ -5361,73 +5372,6 @@ HInstruction* HOptimizedGraphBuilder::BuildCallGetter(
 }
 
 
-HInstruction* HOptimizedGraphBuilder::BuildLoadNamedMonomorphic(
-    HValue* object,
-    Handle<String> name,
-    Handle<Map> map) {
-  // Handle a load from a known field.
-  ASSERT(!map->is_dictionary_map());
-
-  // Handle access to various length properties
-  if (name->Equals(isolate()->heap()->length_string())) {
-    if (map->instance_type() == JS_ARRAY_TYPE) {
-      HCheckMaps* checked_object = AddCheckMap(object, map);
-      return New<HLoadNamedField>(
-          checked_object, HObjectAccess::ForArrayLength(map->elements_kind()));
-    }
-  }
-
-  LookupResult lookup(isolate());
-  map->LookupDescriptor(NULL, *name, &lookup);
-  if (lookup.IsField()) {
-    HCheckMaps* checked_object = AddCheckMap(object, map);
-    ASSERT(map->IsJSObjectMap());
-    return BuildLoadNamedField(
-        checked_object, HObjectAccess::ForField(map, &lookup, name));
-  }
-
-  // Handle a load of a constant known function.
-  if (lookup.IsConstant()) {
-    AddCheckMap(object, map);
-    Handle<Object> constant(lookup.GetConstantFromMap(*map), isolate());
-    return New<HConstant>(constant);
-  }
-
-  if (lookup.IsFound()) {
-    // Cannot handle the property, do a generic load instead.
-    HValue* context = environment()->context();
-    return new(zone()) HLoadNamedGeneric(context, object, name);
-  }
-
-  // Handle a load from a known field somewhere in the prototype chain.
-  LookupInPrototypes(map, name, &lookup);
-  if (lookup.IsField()) {
-    Handle<JSObject> prototype(JSObject::cast(map->prototype()));
-    Handle<JSObject> holder(lookup.holder());
-    Handle<Map> holder_map(holder->map());
-    AddCheckMap(object, map);
-    HValue* checked_holder = BuildCheckPrototypeMaps(prototype, holder);
-    return BuildLoadNamedField(
-        checked_holder, HObjectAccess::ForField(holder_map, &lookup, name));
-  }
-
-  // Handle a load of a constant function somewhere in the prototype chain.
-  if (lookup.IsConstant()) {
-    Handle<JSObject> prototype(JSObject::cast(map->prototype()));
-    Handle<JSObject> holder(lookup.holder());
-    Handle<Map> holder_map(holder->map());
-    AddCheckMap(object, map);
-    BuildCheckPrototypeMaps(prototype, holder);
-    Handle<Object> constant(lookup.GetConstantFromMap(*holder_map), isolate());
-    return New<HConstant>(constant);
-  }
-
-  // No luck, do a generic load.
-  HValue* context = environment()->context();
-  return new(zone()) HLoadNamedGeneric(context, object, name);
-}
-
-
 HInstruction* HOptimizedGraphBuilder::BuildLoadKeyedGeneric(HValue* object,
                                                             HValue* key) {
   HValue* context = environment()->context();
@@ -5827,7 +5771,6 @@ void HOptimizedGraphBuilder::PushLoad(Property* expr,
 
 
 static bool AreStringTypes(SmallMapList* types) {
-  if (types == NULL || types->length() == 0) return false;
   for (int i = 0; i < types->length(); i++) {
     if (types->at(i)->instance_type() >= FIRST_NONSTRING_TYPE) return false;
   }
@@ -5855,37 +5798,33 @@ void HOptimizedGraphBuilder::BuildLoad(Property* expr,
 
   } else if (expr->key()->IsPropertyName()) {
     Handle<String> name = expr->key()->AsLiteral()->AsPropertyName();
-    HValue* object = Top();
+    HValue* object = Pop();
 
     SmallMapList* types;
-    bool monomorphic = ComputeReceiverTypes(expr, object, &types);
+    ComputeReceiverTypes(expr, object, &types);
+    ASSERT(types != NULL);
+
+    if (types->length() > 0) {
+      PropertyAccessInfo info(isolate(), types->first(), name);
+      if (!info.CanLoadAsMonomorphic(types)) {
+        return HandlePolymorphicLoadNamedField(
+            position, ast_id, expr->LoadId(), object, types, name);
+      }
 
-    if (monomorphic) {
-      Handle<Map> map = types->first();
-      Handle<JSFunction> getter;
-      Handle<JSObject> holder;
-      if (LookupGetter(map, name, &getter, &holder)) {
-        AddCheckConstantFunction(holder, Top(), map);
-        if (FLAG_inline_accessors &&
-            TryInlineGetter(getter, ast_id, expr->LoadId())) {
-          return;
-        }
-        Add<HPushArgument>(Pop());
-        instr = new(zone()) HCallConstantFunction(getter, 1);
+      BuildCheckHeapObject(object);
+      HInstruction* checked_object;
+      if (AreStringTypes(types)) {
+        checked_object =
+            AddInstruction(HCheckInstanceType::NewIsString(object, zone()));
       } else {
-        instr = BuildLoadNamedMonomorphic(Pop(), name, map);
+        checked_object = Add<HCheckMaps>(object, types);
       }
-    } else if (AreStringTypes(types) &&
-               name->Equals(isolate()->heap()->length_string())) {
-      BuildCheckHeapObject(Pop());
-      HValue* checked_object =
-          AddInstruction(HCheckInstanceType::NewIsString(object, zone()));
-      instr = BuildLoadStringLength(object, checked_object);
-    } else if (types != NULL && types->length() > 1) {
-      return HandlePolymorphicLoadNamedField(
-          position, ast_id, Pop(), types, name);
+      instr = BuildLoadMonomorphic(
+          &info, object, checked_object, ast_id, expr->LoadId());
+      if (instr == NULL) return;
+      if (instr->IsLinked()) return ast_context()->ReturnValue(instr);
     } else {
-      instr = BuildLoadNamedGeneric(Pop(), name, expr);
+      instr = BuildLoadNamedGeneric(object, name, expr);
     }
 
   } else {
@@ -6020,22 +5959,13 @@ bool HOptimizedGraphBuilder::TryCallPolymorphicAsMonomorphic(
     Handle<String> name) {
   if (types->length() > kMaxCallPolymorphism) return false;
 
-  Handle<Map> map(types->at(0));
-  LookupResult lookup(isolate());
-  if (!CanLoadPropertyFromPrototype(map, name, &lookup)) return false;
-
-  Handle<Object> prototype(map->prototype(), isolate());
-  for (int count = 1; count < types->length(); ++count) {
-    Handle<Map> test_map(types->at(count));
-    if (!CanLoadPropertyFromPrototype(test_map, name, &lookup)) return false;
-    if (test_map->prototype() != *prototype) return false;
-  }
-
-  if (!expr->ComputeTarget(map, name)) return false;
+  PropertyAccessInfo info(isolate(), types->at(0), name);
+  if (!info.CanLoadAsMonomorphic(types)) return false;
+  if (!expr->ComputeTarget(info.map(), name)) return false;
 
   BuildCheckHeapObject(receiver);
   Add<HCheckMaps>(receiver, types);
-  AddCheckPrototypeMaps(expr->holder(), map);
+  AddCheckPrototypeMaps(expr->holder(), info.map());
   if (FLAG_trace_inlining) {
     Handle<JSFunction> caller = current_info()->closure();
     SmartArrayPointer<char> caller_name =
index af36c50..c306f80 100644 (file)
@@ -1945,13 +1945,81 @@ class HOptimizedGraphBuilder V8_FINAL
   void HandlePropertyAssignment(Assignment* expr);
   void HandleCompoundAssignment(Assignment* expr);
   void HandlePolymorphicLoadNamedField(int position,
+                                       BailoutId ast_id,
                                        BailoutId return_id,
                                        HValue* object,
                                        SmallMapList* types,
                                        Handle<String> name);
-  HInstruction* TryLoadPolymorphicAsMonomorphic(HValue* object,
-                                                SmallMapList* types,
-                                                Handle<String> name);
+
+  class PropertyAccessInfo {
+   public:
+    PropertyAccessInfo(Isolate* isolate, Handle<Map> map, Handle<String> name)
+        : lookup_(isolate),
+          map_(map),
+          name_(name),
+          access_(HObjectAccess::ForMap()) { }
+
+    // Checkes whether this PropertyAccessInfo can be handled as a monomorphic
+    // load named. It additionally fills in the fields necessary to generate the
+    // lookup code.
+    bool CanLoadMonomorphic();
+
+    // Checks whether all types behave uniform when loading name. If all maps
+    // behave the same, a single monomorphic load instruction can be emitted,
+    // guarded by a single map-checks instruction that whether the receiver is
+    // an instance of any of the types.
+    // This method skips the first type in types, assuming that this
+    // PropertyAccessInfo is built for types->first().
+    bool CanLoadAsMonomorphic(SmallMapList* types);
+
+    bool IsStringLength() {
+      return map_->instance_type() < FIRST_NONSTRING_TYPE &&
+          name_->Equals(isolate()->heap()->length_string());
+    }
+
+    bool IsArrayLength() {
+      return map_->instance_type() == JS_ARRAY_TYPE &&
+          name_->Equals(isolate()->heap()->length_string());
+    }
+
+    bool has_holder() { return !holder_.is_null(); }
+
+    LookupResult* lookup() { return &lookup_; }
+    Handle<Map> map() { return map_; }
+    Handle<JSObject> holder() { return holder_; }
+    Handle<JSFunction> accessor() { return accessor_; }
+    Handle<Object> constant() { return constant_; }
+    HObjectAccess access() { return access_; }
+
+   private:
+    Isolate* isolate() { return lookup_.isolate(); }
+
+    bool LoadResult(Handle<Map> map);
+    bool LookupDescriptor();
+    bool LookupInPrototypes();
+    bool IsCompatibleForLoad(PropertyAccessInfo* other);
+
+    void GeneralizeRepresentation(Representation r) {
+      access_ = access_.WithRepresentation(
+          access_.representation().generalize(r));
+    }
+
+    LookupResult lookup_;
+    Handle<Map> map_;
+    Handle<String> name_;
+    Handle<JSObject> holder_;
+    Handle<JSFunction> accessor_;
+    Handle<Object> constant_;
+    HObjectAccess access_;
+  };
+
+  HInstruction* BuildLoadMonomorphic(PropertyAccessInfo* info,
+                                     HValue* object,
+                                     HInstruction* checked_object,
+                                     BailoutId ast_id,
+                                     BailoutId return_id,
+                                     bool can_inline_accessor = true);
+
   void HandlePolymorphicStoreNamedField(int position,
                                         BailoutId assignment_id,
                                         HValue* object,
@@ -2030,9 +2098,6 @@ class HOptimizedGraphBuilder V8_FINAL
                                 Handle<Map> map,
                                 Handle<JSFunction> getter,
                                 Handle<JSObject> holder);
-  HInstruction* BuildLoadNamedMonomorphic(HValue* object,
-                                          Handle<String> name,
-                                          Handle<Map> map);
 
   HCheckMaps* AddCheckMap(HValue* object, Handle<Map> map);