| Index: src/hydrogen.cc
 | 
| diff --git a/src/hydrogen.cc b/src/hydrogen.cc
 | 
| index a0c9cb83a8321669ff222d08c7e3714f270b0855..818559634690f9060ec95b3bb434aed0a92fa790 100644
 | 
| --- a/src/hydrogen.cc
 | 
| +++ b/src/hydrogen.cc
 | 
| @@ -4928,80 +4928,6 @@ static bool CanInlinePropertyAccess(Type* type) {
 | 
|  }
 | 
|  
 | 
|  
 | 
| -static void LookupInPrototypes(Handle<Map> map,
 | 
| -                               Handle<String> name,
 | 
| -                               LookupResult* lookup,
 | 
| -                               Zone* zone) {
 | 
| -  while (map->prototype()->IsJSObject()) {
 | 
| -    Handle<JSObject> holder(JSObject::cast(map->prototype()));
 | 
| -    map = handle(holder->map());
 | 
| -    if (!CanInlinePropertyAccess(IC::MapToType<Type>(map, zone))) break;
 | 
| -    map->LookupDescriptor(*holder, *name, lookup);
 | 
| -    if (lookup->IsFound()) return;
 | 
| -  }
 | 
| -  lookup->NotFound();
 | 
| -}
 | 
| -
 | 
| -
 | 
| -// Tries to find a JavaScript accessor of the given name in the prototype chain
 | 
| -// starting at the given map. Return true iff there is one, including the
 | 
| -// corresponding AccessorPair plus its holder (which could be null when the
 | 
| -// accessor is found directly in the given map).
 | 
| -static bool LookupAccessorPair(Handle<Map> map,
 | 
| -                               Handle<String> name,
 | 
| -                               Handle<AccessorPair>* accessors,
 | 
| -                               Handle<JSObject>* holder,
 | 
| -                               Zone* zone) {
 | 
| -  Isolate* isolate = map->GetIsolate();
 | 
| -  LookupResult lookup(isolate);
 | 
| -
 | 
| -  // Check for a JavaScript accessor directly in the map.
 | 
| -  map->LookupDescriptor(NULL, *name, &lookup);
 | 
| -  if (lookup.IsPropertyCallbacks()) {
 | 
| -    Handle<Object> callback(lookup.GetValueFromMap(*map), isolate);
 | 
| -    if (!callback->IsAccessorPair()) return false;
 | 
| -    *accessors = Handle<AccessorPair>::cast(callback);
 | 
| -    *holder = Handle<JSObject>();
 | 
| -    return true;
 | 
| -  }
 | 
| -
 | 
| -  // Everything else, e.g. a field, can't be an accessor call.
 | 
| -  if (lookup.IsFound()) return false;
 | 
| -
 | 
| -  // Check for a JavaScript accessor somewhere in the proto chain.
 | 
| -  LookupInPrototypes(map, name, &lookup, zone);
 | 
| -  if (lookup.IsPropertyCallbacks()) {
 | 
| -    Handle<Object> callback(lookup.GetValue(), isolate);
 | 
| -    if (!callback->IsAccessorPair()) return false;
 | 
| -    *accessors = Handle<AccessorPair>::cast(callback);
 | 
| -    *holder = Handle<JSObject>(lookup.holder());
 | 
| -    return true;
 | 
| -  }
 | 
| -
 | 
| -  // We haven't found a JavaScript accessor anywhere.
 | 
| -  return false;
 | 
| -}
 | 
| -
 | 
| -
 | 
| -static bool LookupSetter(Handle<Map> map,
 | 
| -                         Handle<String> name,
 | 
| -                         Handle<JSFunction>* setter,
 | 
| -                         Handle<JSObject>* holder,
 | 
| -                         Zone* zone) {
 | 
| -  Handle<AccessorPair> accessors;
 | 
| -  if (LookupAccessorPair(map, name, &accessors, holder, zone) &&
 | 
| -      accessors->setter()->IsJSFunction()) {
 | 
| -    Handle<JSFunction> func(JSFunction::cast(accessors->setter()));
 | 
| -    CallOptimization call_optimization(func);
 | 
| -    // TODO(dcarney): temporary hack unless crankshaft can handle api calls.
 | 
| -    if (call_optimization.is_simple_api_call()) return false;
 | 
| -    *setter = func;
 | 
| -    return true;
 | 
| -  }
 | 
| -  return false;
 | 
| -}
 | 
| -
 | 
| -
 | 
|  // Determines whether the given array or object literal boilerplate satisfies
 | 
|  // all limits to be considered for fast deep-copying and computes the total
 | 
|  // size of all objects that are part of the graph.
 | 
| @@ -5147,15 +5073,17 @@ void HOptimizedGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) {
 | 
|                // If we don't know the monomorphic type, do a generic store.
 | 
|                CHECK_ALIVE(store = BuildStoreNamedGeneric(literal, name, value));
 | 
|              } else {
 | 
| -#if DEBUG
 | 
| -              Handle<JSFunction> setter;
 | 
| -              Handle<JSObject> holder;
 | 
| -              ASSERT(!LookupSetter(map, name, &setter, &holder, zone()));
 | 
| -#endif
 | 
| -              CHECK_ALIVE(store = BuildStoreNamedMonomorphic(literal,
 | 
| -                                                             name,
 | 
| -                                                             value,
 | 
| -                                                             map));
 | 
| +              PropertyAccessInfo info(this, STORE, ToType(map), name);
 | 
| +              if (info.CanAccessMonomorphic()) {
 | 
| +                HValue* checked_literal = BuildCheckMap(literal, map);
 | 
| +                ASSERT(!info.lookup()->IsPropertyCallbacks());
 | 
| +                store = BuildStoreMonomorphic(
 | 
| +                    &info, checked_literal, value,
 | 
| +                    BailoutId::None(), BailoutId::None());
 | 
| +              } else {
 | 
| +                CHECK_ALIVE(
 | 
| +                    store = BuildStoreNamedGeneric(literal, name, value));
 | 
| +              }
 | 
|              }
 | 
|              AddInstruction(store);
 | 
|              if (store->HasObservableSideEffects()) {
 | 
| @@ -5331,43 +5259,13 @@ HCheckMaps* HOptimizedGraphBuilder::AddCheckMap(HValue* object,
 | 
|  
 | 
|  
 | 
|  HInstruction* HOptimizedGraphBuilder::BuildStoreNamedField(
 | 
| +    PropertyAccessInfo* info,
 | 
|      HValue* checked_object,
 | 
| -    Handle<String> name,
 | 
| -    HValue* value,
 | 
| -    Handle<Map> map,
 | 
| -    LookupResult* lookup) {
 | 
| -  ASSERT(lookup->IsFound());
 | 
| -  // If the property does not exist yet, we have to check that it wasn't made
 | 
| -  // readonly or turned into a setter by some meanwhile modifications on the
 | 
| -  // prototype chain.
 | 
| -  if (!lookup->IsProperty() && map->prototype()->IsJSReceiver()) {
 | 
| -    Object* proto = map->prototype();
 | 
| -    // First check that the prototype chain isn't affected already.
 | 
| -    LookupResult proto_result(isolate());
 | 
| -    proto->Lookup(*name, &proto_result);
 | 
| -    if (proto_result.IsProperty()) {
 | 
| -      // If the inherited property could induce readonly-ness, bail out.
 | 
| -      if (proto_result.IsReadOnly() || !proto_result.IsCacheable()) {
 | 
| -        Bailout(kImproperObjectOnPrototypeChainForStore);
 | 
| -        return NULL;
 | 
| -      }
 | 
| -      // We only need to check up to the preexisting property.
 | 
| -      proto = proto_result.holder();
 | 
| -    } else {
 | 
| -      // Otherwise, find the top prototype.
 | 
| -      while (proto->GetPrototype(isolate())->IsJSObject()) {
 | 
| -        proto = proto->GetPrototype(isolate());
 | 
| -      }
 | 
| -      ASSERT(proto->GetPrototype(isolate())->IsNull());
 | 
| -    }
 | 
| -    ASSERT(proto->IsJSObject());
 | 
| -    BuildCheckPrototypeMaps(
 | 
| -        Handle<JSObject>(JSObject::cast(map->prototype())),
 | 
| -        Handle<JSObject>(JSObject::cast(proto)));
 | 
| -  }
 | 
| -
 | 
| -  HObjectAccess field_access = HObjectAccess::ForField(map, lookup, name);
 | 
| -  bool transition_to_field = lookup->IsTransitionToField(*map);
 | 
| +    HValue* value) {
 | 
| +  bool transition_to_field = info->lookup()->IsTransition();
 | 
| +  // TODO(verwaest): Move this logic into PropertyAccessInfo.
 | 
| +  HObjectAccess field_access = HObjectAccess::ForField(
 | 
| +      info->map(), info->lookup(), info->name());
 | 
|  
 | 
|    HStoreNamedField *instr;
 | 
|    if (FLAG_track_double_fields && field_access.representation().IsDouble()) {
 | 
| @@ -5408,11 +5306,8 @@ HInstruction* HOptimizedGraphBuilder::BuildStoreNamedField(
 | 
|    }
 | 
|  
 | 
|    if (transition_to_field) {
 | 
| -    Handle<Map> transition(lookup->GetTransitionMapFromMap(*map));
 | 
| -    HConstant* transition_constant = Add<HConstant>(transition);
 | 
| +    HConstant* transition_constant = Add<HConstant>(info->transition());
 | 
|      instr->SetTransition(transition_constant, top_info());
 | 
| -    // TODO(fschneider): Record the new map type of the object in the IR to
 | 
| -    // enable elimination of redundant checks after the transition store.
 | 
|      instr->SetGVNFlag(kChangesMaps);
 | 
|    }
 | 
|    return instr;
 | 
| @@ -5422,7 +5317,13 @@ HInstruction* HOptimizedGraphBuilder::BuildStoreNamedField(
 | 
|  HInstruction* HOptimizedGraphBuilder::BuildStoreNamedGeneric(
 | 
|      HValue* object,
 | 
|      Handle<String> name,
 | 
| -    HValue* value) {
 | 
| +    HValue* value,
 | 
| +    bool is_uninitialized) {
 | 
| +  if (is_uninitialized) {
 | 
| +    Add<HDeoptimize>("Insufficient type feedback for property assignment",
 | 
| +                     Deoptimizer::SOFT);
 | 
| +  }
 | 
| +
 | 
|    return New<HStoreNamedGeneric>(
 | 
|                           object,
 | 
|                           name,
 | 
| @@ -5431,46 +5332,7 @@ HInstruction* HOptimizedGraphBuilder::BuildStoreNamedGeneric(
 | 
|  }
 | 
|  
 | 
|  
 | 
| -// Sets the lookup result and returns true if the load/store can be inlined.
 | 
| -static bool ComputeStoreField(Type* type,
 | 
| -                              Handle<String> name,
 | 
| -                              LookupResult* lookup,
 | 
| -                              bool lookup_transition = true) {
 | 
| -  if (!CanInlinePropertyAccess(type) || !type->IsClass()) {
 | 
| -    lookup->NotFound();
 | 
| -    return false;
 | 
| -  }
 | 
| -  Handle<Map> map = type->AsClass();
 | 
| -  ASSERT(!map->is_observed());
 | 
| -  // If we directly find a field, the access can be inlined.
 | 
| -  map->LookupDescriptor(NULL, *name, lookup);
 | 
| -  if (lookup->IsField()) return true;
 | 
| -
 | 
| -  if (!lookup_transition) return false;
 | 
| -
 | 
| -  map->LookupTransition(NULL, *name, lookup);
 | 
| -  return lookup->IsTransitionToField(*map) && map->unused_property_fields() > 0;
 | 
| -}
 | 
| -
 | 
| -
 | 
| -HInstruction* HOptimizedGraphBuilder::BuildStoreNamedMonomorphic(
 | 
| -    HValue* object,
 | 
| -    Handle<String> name,
 | 
| -    HValue* value,
 | 
| -    Handle<Map> map) {
 | 
| -  // Handle a store to a known field.
 | 
| -  LookupResult lookup(isolate());
 | 
| -  if (ComputeStoreField(ToType(map), name, &lookup)) {
 | 
| -    HCheckMaps* checked_object = AddCheckMap(object, map);
 | 
| -    return BuildStoreNamedField(checked_object, name, value, map, &lookup);
 | 
| -  }
 | 
| -
 | 
| -  // No luck, do a generic store.
 | 
| -  return BuildStoreNamedGeneric(object, name, value);
 | 
| -}
 | 
| -
 | 
| -
 | 
| -bool HOptimizedGraphBuilder::PropertyAccessInfo::IsCompatibleForLoad(
 | 
| +bool HOptimizedGraphBuilder::PropertyAccessInfo::IsCompatible(
 | 
|      PropertyAccessInfo* info) {
 | 
|    if (!CanInlinePropertyAccess(type_)) return false;
 | 
|  
 | 
| @@ -5510,7 +5372,11 @@ bool HOptimizedGraphBuilder::PropertyAccessInfo::IsCompatibleForLoad(
 | 
|    if (!info->lookup_.IsField()) return false;
 | 
|  
 | 
|    Representation r = access_.representation();
 | 
| -  if (!info->access_.representation().IsCompatibleForLoad(r)) return false;
 | 
| +  if (IsLoad()) {
 | 
| +    if (!info->access_.representation().IsCompatibleForLoad(r)) return false;
 | 
| +  } else {
 | 
| +    if (!info->access_.representation().IsCompatibleForStore(r)) return false;
 | 
| +  }
 | 
|    if (info->access_.offset() != access_.offset()) return false;
 | 
|    if (info->access_.IsInobject() != access_.IsInobject()) return false;
 | 
|    info->GeneralizeRepresentation(r);
 | 
| @@ -5526,14 +5392,21 @@ bool HOptimizedGraphBuilder::PropertyAccessInfo::LookupDescriptor() {
 | 
|  
 | 
|  
 | 
|  bool HOptimizedGraphBuilder::PropertyAccessInfo::LoadResult(Handle<Map> map) {
 | 
| +  if (!IsLoad() && lookup_.IsProperty() &&
 | 
| +      (lookup_.IsReadOnly() || !lookup_.IsCacheable())) {
 | 
| +    return false;
 | 
| +  }
 | 
| +
 | 
|    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;
 | 
| -    Handle<JSFunction> accessor = handle(JSFunction::cast(getter));
 | 
| +    Object* raw_accessor = IsLoad()
 | 
| +        ? Handle<AccessorPair>::cast(callback)->getter()
 | 
| +        : Handle<AccessorPair>::cast(callback)->setter();
 | 
| +    if (!raw_accessor->IsJSFunction()) return false;
 | 
| +    Handle<JSFunction> accessor = handle(JSFunction::cast(raw_accessor));
 | 
|      CallOptimization call_optimization(accessor);
 | 
|      // TODO(dcarney): temporary hack unless crankshaft can handle api calls.
 | 
|      if (call_optimization.is_simple_api_call()) return false;
 | 
| @@ -5567,19 +5440,38 @@ bool HOptimizedGraphBuilder::PropertyAccessInfo::LookupInPrototypes() {
 | 
|  }
 | 
|  
 | 
|  
 | 
| -bool HOptimizedGraphBuilder::PropertyAccessInfo::CanLoadMonomorphic() {
 | 
| +bool HOptimizedGraphBuilder::PropertyAccessInfo::CanAccessMonomorphic() {
 | 
|    if (!CanInlinePropertyAccess(type_)) return false;
 | 
| -  if (IsJSObjectFieldAccessor()) return true;
 | 
| +  if (IsJSObjectFieldAccessor()) {
 | 
| +    // We should never have gathered typefeedback for JSObjectFieldAccessor
 | 
| +    // stores.
 | 
| +    ASSERT(IsLoad());
 | 
| +    return true;
 | 
| +  }
 | 
|    if (!LookupDescriptor()) return false;
 | 
| -  if (lookup_.IsFound()) return true;
 | 
| -  return LookupInPrototypes();
 | 
| +  if (lookup_.IsFound()) {
 | 
| +    if (IsLoad()) return true;
 | 
| +    return !lookup_.IsReadOnly() && lookup_.IsCacheable();
 | 
| +  }
 | 
| +  if (!LookupInPrototypes()) return false;
 | 
| +  if (IsLoad()) return true;
 | 
| +
 | 
| +  if (lookup_.IsPropertyCallbacks()) return true;
 | 
| +  Handle<Map> map = this->map();
 | 
| +  map->LookupTransition(NULL, *name_, &lookup_);
 | 
| +  if (lookup_.IsTransitionToField(*map) && map->unused_property_fields() > 0) {
 | 
| +    transition_ = handle(lookup_.GetTransitionMapFromMap(*map));
 | 
| +    return true;
 | 
| +  }
 | 
| +  return false;
 | 
|  }
 | 
|  
 | 
|  
 | 
| -bool HOptimizedGraphBuilder::PropertyAccessInfo::CanLoadAsMonomorphic(
 | 
| +bool HOptimizedGraphBuilder::PropertyAccessInfo::CanAccessAsMonomorphic(
 | 
|      SmallMapList* types) {
 | 
|    ASSERT(type_->Is(ToType(types->first())));
 | 
| -  if (!CanLoadMonomorphic()) return false;
 | 
| +  if (!CanAccessMonomorphic()) return false;
 | 
| +  STATIC_ASSERT(kMaxLoadPolymorphism == kMaxStorePolymorphism);
 | 
|    if (types->length() > kMaxLoadPolymorphism) return false;
 | 
|  
 | 
|    if (IsArrayLength()) {
 | 
| @@ -5597,7 +5489,8 @@ bool HOptimizedGraphBuilder::PropertyAccessInfo::CanLoadAsMonomorphic(
 | 
|    HObjectAccess access = HObjectAccess::ForMap();  // bogus default
 | 
|    if (GetJSObjectFieldAccess(&access)) {
 | 
|      for (int i = 1; i < types->length(); ++i) {
 | 
| -      PropertyAccessInfo test_info(builder_, ToType(types->at(i)), name_);
 | 
| +      PropertyAccessInfo test_info(
 | 
| +          builder_, access_type_, ToType(types->at(i)), name_);
 | 
|        HObjectAccess test_access = HObjectAccess::ForMap();  // bogus default
 | 
|        if (!test_info.GetJSObjectFieldAccess(&test_access)) return false;
 | 
|        if (!access.Equals(test_access)) return false;
 | 
| @@ -5610,9 +5503,14 @@ bool HOptimizedGraphBuilder::PropertyAccessInfo::CanLoadAsMonomorphic(
 | 
|    // instruction.
 | 
|    if (type_->Is(Type::Number())) return false;
 | 
|  
 | 
| +  // Multiple maps cannot transition to the same target map.
 | 
| +  ASSERT(!IsLoad() || !lookup_.IsTransition());
 | 
| +  if (lookup_.IsTransition() && types->length() > 1) return false;
 | 
| +
 | 
|    for (int i = 1; i < types->length(); ++i) {
 | 
| -    PropertyAccessInfo test_info(builder_, ToType(types->at(i)), name_);
 | 
| -    if (!test_info.IsCompatibleForLoad(this)) return false;
 | 
| +    PropertyAccessInfo test_info(
 | 
| +        builder_, access_type_, ToType(types->at(i)), name_);
 | 
| +    if (!test_info.IsCompatible(this)) return false;
 | 
|    }
 | 
|  
 | 
|    return true;
 | 
| @@ -5674,6 +5572,49 @@ HInstruction* HOptimizedGraphBuilder::BuildLoadMonomorphic(
 | 
|  }
 | 
|  
 | 
|  
 | 
| +HInstruction* HOptimizedGraphBuilder::BuildStoreMonomorphic(
 | 
| +    PropertyAccessInfo* info,
 | 
| +    HValue* checked_object,
 | 
| +    HValue* value,
 | 
| +    BailoutId ast_id,
 | 
| +    BailoutId return_id,
 | 
| +    bool can_inline_accessor) {
 | 
| +  ASSERT(!info->IsJSObjectFieldAccessor());
 | 
| +
 | 
| +  if (info->has_holder()) {
 | 
| +    Handle<JSObject> prototype(JSObject::cast(info->map()->prototype()));
 | 
| +    BuildCheckPrototypeMaps(prototype, info->holder());
 | 
| +  }
 | 
| +
 | 
| +  if (info->lookup()->IsPropertyCallbacks()) {
 | 
| +    if (NeedsWrappingFor(info->type(), info->accessor())) {
 | 
| +      HValue* function = Add<HConstant>(info->accessor());
 | 
| +      Add<HPushArgument>(checked_object);
 | 
| +      Add<HPushArgument>(value);
 | 
| +      return New<HCallFunction>(function, 2, WRAP_AND_CALL);
 | 
| +    } else {
 | 
| +      Push(checked_object);
 | 
| +      Push(value);
 | 
| +      if (FLAG_inline_accessors &&
 | 
| +          can_inline_accessor &&
 | 
| +          TryInlineSetter(info->accessor(), ast_id, return_id, value)) {
 | 
| +        return NULL;
 | 
| +      }
 | 
| +      PushArgumentsFromEnvironment(2);
 | 
| +      return BuildCallConstantFunction(info->accessor(), 2);
 | 
| +    }
 | 
| +  }
 | 
| +
 | 
| +  if (info->lookup()->IsConstant()) {
 | 
| +    // Check whether we are trying to store the same constant.
 | 
| +    return New<HCheckValue>(value, Handle<JSFunction>::cast(info->constant()));
 | 
| +  }
 | 
| +
 | 
| +  ASSERT(info->lookup()->IsField() || info->lookup()->IsTransition());
 | 
| +  return BuildStoreNamedField(info, checked_object, value);
 | 
| +}
 | 
| +
 | 
| +
 | 
|  void HOptimizedGraphBuilder::HandlePolymorphicLoadNamedField(
 | 
|      BailoutId ast_id,
 | 
|      BailoutId return_id,
 | 
| @@ -5688,12 +5629,12 @@ void HOptimizedGraphBuilder::HandlePolymorphicLoadNamedField(
 | 
|  
 | 
|    bool handle_smi = false;
 | 
|    for (int i = 0; i < types->length() && count < kMaxLoadPolymorphism; ++i) {
 | 
| -    PropertyAccessInfo info(this, ToType(types->at(i)), name);
 | 
| +    PropertyAccessInfo info(this, LOAD, ToType(types->at(i)), name);
 | 
|      if (info.type()->Is(Type::String())) {
 | 
|        if (handled_string) continue;
 | 
|        handled_string = true;
 | 
|      }
 | 
| -    if (info.CanLoadMonomorphic()) {
 | 
| +    if (info.CanAccessMonomorphic()) {
 | 
|        count++;
 | 
|        if (info.type()->Is(Type::Number())) {
 | 
|          handle_smi = true;
 | 
| @@ -5707,12 +5648,12 @@ void HOptimizedGraphBuilder::HandlePolymorphicLoadNamedField(
 | 
|    handled_string = false;
 | 
|  
 | 
|    for (int i = 0; i < types->length() && count < kMaxLoadPolymorphism; ++i) {
 | 
| -    PropertyAccessInfo info(this, ToType(types->at(i)), name);
 | 
| +    PropertyAccessInfo info(this, LOAD, ToType(types->at(i)), name);
 | 
|      if (info.type()->Is(Type::String())) {
 | 
|        if (handled_string) continue;
 | 
|        handled_string = true;
 | 
|      }
 | 
| -    if (!info.CanLoadMonomorphic()) continue;
 | 
| +    if (!info.CanAccessMonomorphic()) continue;
 | 
|  
 | 
|      if (count == 0) {
 | 
|        join = graph()->CreateBasicBlock();
 | 
| @@ -5801,84 +5742,19 @@ void HOptimizedGraphBuilder::HandlePolymorphicLoadNamedField(
 | 
|  }
 | 
|  
 | 
|  
 | 
| -bool HOptimizedGraphBuilder::TryStorePolymorphicAsMonomorphic(
 | 
| -    BailoutId assignment_id,
 | 
| -    HValue* object,
 | 
| -    HValue* value,
 | 
| -    SmallMapList* types,
 | 
| -    Handle<String> name) {
 | 
| -  // Use monomorphic store 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() > kMaxStorePolymorphism) return false;
 | 
| -
 | 
| -  LookupResult lookup(isolate());
 | 
| -  int count;
 | 
| -  Representation representation = Representation::None();
 | 
| -  HObjectAccess access = HObjectAccess::ForMap();  // initial value unused.
 | 
| -  for (count = 0; count < types->length(); ++count) {
 | 
| -    Handle<Map> map = types->at(count);
 | 
| -    // Pass false to ignore transitions.
 | 
| -    if (!ComputeStoreField(ToType(map), name, &lookup, false)) break;
 | 
| -    ASSERT(!map->is_observed());
 | 
| -
 | 
| -    HObjectAccess new_access = HObjectAccess::ForField(map, &lookup, name);
 | 
| -    Representation new_representation = new_access.representation();
 | 
| -
 | 
| -    if (count == 0) {
 | 
| -      // First time through the loop; set access and representation.
 | 
| -      access = new_access;
 | 
| -      representation = new_representation;
 | 
| -    } else if (!representation.IsCompatibleForStore(new_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;
 | 
| -    }
 | 
| -  }
 | 
| -
 | 
| -  if (count != types->length()) return false;
 | 
| -
 | 
| -  // Everything matched; can use monomorphic store.
 | 
| -  BuildCheckHeapObject(object);
 | 
| -  HCheckMaps* checked_object = Add<HCheckMaps>(object, types);
 | 
| -  HInstruction* store;
 | 
| -  CHECK_ALIVE_OR_RETURN(
 | 
| -      store = BuildStoreNamedField(
 | 
| -          checked_object, name, value, types->at(count - 1), &lookup),
 | 
| -      true);
 | 
| -  if (!ast_context()->IsEffect()) Push(value);
 | 
| -  AddInstruction(store);
 | 
| -  Add<HSimulate>(assignment_id);
 | 
| -  if (!ast_context()->IsEffect()) Drop(1);
 | 
| -  ast_context()->ReturnValue(value);
 | 
| -  return true;
 | 
| -}
 | 
| -
 | 
| -
 | 
|  void HOptimizedGraphBuilder::HandlePolymorphicStoreNamedField(
 | 
|      BailoutId assignment_id,
 | 
| +    BailoutId return_id,
 | 
|      HValue* object,
 | 
|      HValue* value,
 | 
|      SmallMapList* types,
 | 
|      Handle<String> name) {
 | 
| -  if (TryStorePolymorphicAsMonomorphic(
 | 
| -          assignment_id, object, value, types, name)) {
 | 
| -    return;
 | 
| -  }
 | 
| -
 | 
| -  // TODO(ager): We should recognize when the prototype chains for different
 | 
| -  // maps are identical. In that case we can avoid repeatedly generating the
 | 
| -  // same prototype map checks.
 | 
|    int count = 0;
 | 
|    HBasicBlock* join = NULL;
 | 
| +  // TODO(verwaest): Unify with polymorphic load handling.
 | 
|    for (int i = 0; i < types->length() && count < kMaxStorePolymorphism; ++i) {
 | 
| -    Handle<Map> map = types->at(i);
 | 
| -    LookupResult lookup(isolate());
 | 
| -    if (ComputeStoreField(ToType(map), name, &lookup)) {
 | 
| +    PropertyAccessInfo info(this, STORE, ToType(types->at(i)), name);
 | 
| +    if (info.CanAccessMonomorphic()) {
 | 
|        if (count == 0) {
 | 
|          BuildCheckHeapObject(object);
 | 
|          join = graph()->CreateBasicBlock();
 | 
| @@ -5886,18 +5762,26 @@ void HOptimizedGraphBuilder::HandlePolymorphicStoreNamedField(
 | 
|        ++count;
 | 
|        HBasicBlock* if_true = graph()->CreateBasicBlock();
 | 
|        HBasicBlock* if_false = graph()->CreateBasicBlock();
 | 
| -      HCompareMap* compare = New<HCompareMap>(object, map,  if_true, if_false);
 | 
| +      HCompareMap* compare = New<HCompareMap>(
 | 
| +          object, info.map(),  if_true, if_false);
 | 
|        FinishCurrentBlock(compare);
 | 
|  
 | 
|        set_current_block(if_true);
 | 
| -      HInstruction* instr;
 | 
| -      CHECK_ALIVE(instr = BuildStoreNamedField(
 | 
| -          compare, name, value, map, &lookup));
 | 
| -      // Goto will add the HSimulate for the store.
 | 
| -      AddInstruction(instr);
 | 
| -      if (!ast_context()->IsEffect()) Push(value);
 | 
| -      Goto(join);
 | 
|  
 | 
| +      HInstruction* store;
 | 
| +      store = BuildStoreMonomorphic(
 | 
| +          &info, compare, value, assignment_id, return_id,
 | 
| +          FLAG_polymorphic_inlining);
 | 
| +
 | 
| +      if (store == NULL) {
 | 
| +        if (HasStackOverflow()) return;
 | 
| +      } else {
 | 
| +        ASSERT(!store->IsLinked());
 | 
| +        AddInstruction(store);
 | 
| +        if (!ast_context()->IsEffect()) Push(value);
 | 
| +      }
 | 
| +
 | 
| +      if (current_block() != NULL) Goto(join);
 | 
|        set_current_block(if_false);
 | 
|      }
 | 
|    }
 | 
| @@ -5959,15 +5843,22 @@ static bool ComputeReceiverTypes(Expression* expr,
 | 
|  }
 | 
|  
 | 
|  
 | 
| +static bool AreStringTypes(SmallMapList* types) {
 | 
| +  for (int i = 0; i < types->length(); i++) {
 | 
| +    if (types->at(i)->instance_type() >= FIRST_NONSTRING_TYPE) return false;
 | 
| +  }
 | 
| +  return true;
 | 
| +}
 | 
| +
 | 
| +
 | 
|  void HOptimizedGraphBuilder::BuildStore(Expression* expr,
 | 
|                                          Property* prop,
 | 
|                                          BailoutId ast_id,
 | 
|                                          BailoutId return_id,
 | 
|                                          bool is_uninitialized) {
 | 
| -  HValue* value = environment()->ExpressionStackAt(0);
 | 
| -
 | 
|    if (!prop->key()->IsPropertyName()) {
 | 
|      // Keyed store.
 | 
| +    HValue* value = environment()->ExpressionStackAt(0);
 | 
|      HValue* key = environment()->ExpressionStackAt(1);
 | 
|      HValue* object = environment()->ExpressionStackAt(2);
 | 
|      bool has_side_effects = false;
 | 
| @@ -5981,12 +5872,8 @@ void HOptimizedGraphBuilder::BuildStore(Expression* expr,
 | 
|    }
 | 
|  
 | 
|    // Named store.
 | 
| -  HValue* object = environment()->ExpressionStackAt(1);
 | 
| -
 | 
| -  if (is_uninitialized) {
 | 
| -    Add<HDeoptimize>("Insufficient type feedback for property assignment",
 | 
| -                     Deoptimizer::SOFT);
 | 
| -  }
 | 
| +  HValue* value = Pop();
 | 
| +  HValue* object = Pop();
 | 
|  
 | 
|    Literal* key = prop->key()->AsLiteral();
 | 
|    Handle<String> name = Handle<String>::cast(key->value());
 | 
| @@ -5995,42 +5882,30 @@ void HOptimizedGraphBuilder::BuildStore(Expression* expr,
 | 
|    HInstruction* instr = NULL;
 | 
|  
 | 
|    SmallMapList* types;
 | 
| -  bool monomorphic = ComputeReceiverTypes(expr, object, &types, zone());
 | 
| +  ComputeReceiverTypes(expr, object, &types, zone());
 | 
|  
 | 
| -  if (monomorphic) {
 | 
| -    Handle<Map> map = types->first();
 | 
| -    Handle<JSFunction> setter;
 | 
| -    Handle<JSObject> holder;
 | 
| -    if (LookupSetter(map, name, &setter, &holder, zone())) {
 | 
| -      AddCheckMap(object, map);
 | 
| -      AddCheckPrototypeMaps(holder, map);
 | 
| -      bool needs_wrapping = NeedsWrappingFor(ToType(map), setter);
 | 
| -      bool try_inline = FLAG_inline_accessors && !needs_wrapping;
 | 
| -      if (try_inline && TryInlineSetter(setter, ast_id, return_id, value)) {
 | 
| -        return;
 | 
| -      }
 | 
| -      Drop(2);
 | 
| -      Add<HPushArgument>(object);
 | 
| -      Add<HPushArgument>(value);
 | 
| -      if (needs_wrapping) {
 | 
| -        HValue* function = Add<HConstant>(setter);
 | 
| -        instr = New<HCallFunction>(function, 2, WRAP_AND_CALL);
 | 
| -      } else {
 | 
| -        instr = BuildCallConstantFunction(setter, 2);
 | 
| -      }
 | 
| +  if (types->length() > 0) {
 | 
| +    PropertyAccessInfo info(this, STORE, ToType(types->first()), name);
 | 
| +    if (!info.CanAccessAsMonomorphic(types)) {
 | 
| +      return HandlePolymorphicStoreNamedField(
 | 
| +          ast_id, return_id, object, value, types, name);
 | 
| +    }
 | 
| +
 | 
| +    ASSERT(!info.type()->Is(Type::Number()));
 | 
| +    BuildCheckHeapObject(object);
 | 
| +    HValue* checked_object;
 | 
| +    if (AreStringTypes(types)) {
 | 
| +      checked_object = Add<HCheckInstanceType>(
 | 
| +          object, HCheckInstanceType::IS_STRING);
 | 
|      } else {
 | 
| -      Drop(2);
 | 
| -      CHECK_ALIVE(instr = BuildStoreNamedMonomorphic(object,
 | 
| -                                                     name,
 | 
| -                                                     value,
 | 
| -                                                     map));
 | 
| -    }
 | 
| -  } else if (types != NULL && types->length() > 1) {
 | 
| -    Drop(2);
 | 
| -    return HandlePolymorphicStoreNamedField(ast_id, object, value, types, name);
 | 
| +      checked_object = Add<HCheckMaps>(object, types);
 | 
| +    }
 | 
| +    instr = BuildStoreMonomorphic(
 | 
| +        &info, checked_object, value, ast_id, return_id);
 | 
| +    if (instr == NULL) return;
 | 
| +    ASSERT(!instr->IsLinked());
 | 
|    } else {
 | 
| -    Drop(2);
 | 
| -    instr = BuildStoreNamedGeneric(object, name, value);
 | 
| +    instr = BuildStoreNamedGeneric(object, name, value, is_uninitialized);
 | 
|    }
 | 
|  
 | 
|    if (!ast_context()->IsEffect()) Push(value);
 | 
| @@ -6838,14 +6713,6 @@ void HOptimizedGraphBuilder::PushLoad(Property* expr,
 | 
|  }
 | 
|  
 | 
|  
 | 
| -static bool AreStringTypes(SmallMapList* types) {
 | 
| -  for (int i = 0; i < types->length(); i++) {
 | 
| -    if (types->at(i)->instance_type() >= FIRST_NONSTRING_TYPE) return false;
 | 
| -  }
 | 
| -  return true;
 | 
| -}
 | 
| -
 | 
| -
 | 
|  void HOptimizedGraphBuilder::BuildLoad(Property* expr,
 | 
|                                         BailoutId ast_id) {
 | 
|    HInstruction* instr = NULL;
 | 
| @@ -6870,8 +6737,8 @@ void HOptimizedGraphBuilder::BuildLoad(Property* expr,
 | 
|      ASSERT(types != NULL);
 | 
|  
 | 
|      if (types->length() > 0) {
 | 
| -      PropertyAccessInfo info(this, ToType(types->first()), name);
 | 
| -      if (!info.CanLoadAsMonomorphic(types)) {
 | 
| +      PropertyAccessInfo info(this, LOAD, ToType(types->first()), name);
 | 
| +      if (!info.CanAccessAsMonomorphic(types)) {
 | 
|          return HandlePolymorphicLoadNamedField(
 | 
|              ast_id, expr->LoadId(), object, types, name);
 | 
|        }
 | 
| @@ -7078,8 +6945,8 @@ void HOptimizedGraphBuilder::HandlePolymorphicCallNamed(
 | 
|    for (int i = 0;
 | 
|         i < types->length() && ordered_functions < kMaxCallPolymorphism;
 | 
|         ++i) {
 | 
| -    PropertyAccessInfo info(this, ToType(types->at(i)), name);
 | 
| -    if (info.CanLoadMonomorphic() &&
 | 
| +    PropertyAccessInfo info(this, LOAD, ToType(types->at(i)), name);
 | 
| +    if (info.CanAccessMonomorphic() &&
 | 
|          info.lookup()->IsConstant() &&
 | 
|          info.constant()->IsJSFunction()) {
 | 
|        if (info.type()->Is(Type::String())) {
 | 
| @@ -7108,13 +6975,13 @@ void HOptimizedGraphBuilder::HandlePolymorphicCallNamed(
 | 
|  
 | 
|    for (int fn = 0; fn < ordered_functions; ++fn) {
 | 
|      int i = order[fn].index();
 | 
| -    PropertyAccessInfo info(this, ToType(types->at(i)), name);
 | 
| +    PropertyAccessInfo info(this, LOAD, ToType(types->at(i)), name);
 | 
|      if (info.type()->Is(Type::String())) {
 | 
|        if (handled_string) continue;
 | 
|        handled_string = true;
 | 
|      }
 | 
|      // Reloads the target.
 | 
| -    info.CanLoadMonomorphic();
 | 
| +    info.CanAccessMonomorphic();
 | 
|      Handle<JSFunction> target = Handle<JSFunction>::cast(info.constant());
 | 
|  
 | 
|      expr->set_target(target);
 | 
| @@ -8101,8 +7968,8 @@ void HOptimizedGraphBuilder::VisitCall(Call* expr) {
 | 
|  
 | 
|      if (prop->key()->IsPropertyName() && types->length() > 0) {
 | 
|        Handle<String> name = prop->key()->AsLiteral()->AsPropertyName();
 | 
| -      PropertyAccessInfo info(this, ToType(types->first()), name);
 | 
| -      if (!info.CanLoadAsMonomorphic(types)) {
 | 
| +      PropertyAccessInfo info(this, LOAD, ToType(types->first()), name);
 | 
| +      if (!info.CanAccessAsMonomorphic(types)) {
 | 
|          HandlePolymorphicCallNamed(expr, receiver, types, name);
 | 
|          return;
 | 
|        }
 | 
| 
 |