From 2c3e6b41ffa283218e5d9a9f3663f75392569cad Mon Sep 17 00:00:00 2001 From: "verwaest@chromium.org" Date: Tue, 4 Feb 2014 22:23:26 +0000 Subject: [PATCH] Use PropertyAccessInfo to compute stores in crankshaft. BUG= R=dcarney@chromium.org Review URL: https://codereview.chromium.org/153933002 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@19085 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/hydrogen-instructions.cc | 3 +- src/hydrogen.cc | 497 ++++++++++++++++--------------------------- src/hydrogen.h | 41 ++-- 3 files changed, 207 insertions(+), 334 deletions(-) diff --git a/src/hydrogen-instructions.cc b/src/hydrogen-instructions.cc index 8fab2bf..8f1c62b 100644 --- a/src/hydrogen-instructions.cc +++ b/src/hydrogen-instructions.cc @@ -4345,7 +4345,8 @@ HObjectAccess HObjectAccess::ForBackingStoreOffset(int offset, HObjectAccess HObjectAccess::ForField(Handle map, - LookupResult *lookup, Handle name) { + LookupResult* lookup, + Handle name) { ASSERT(lookup->IsField() || lookup->IsTransitionToField(*map)); int index; Representation representation; diff --git a/src/hydrogen.cc b/src/hydrogen.cc index a0c9cb8..8185596 100644 --- a/src/hydrogen.cc +++ b/src/hydrogen.cc @@ -4928,80 +4928,6 @@ static bool CanInlinePropertyAccess(Type* type) { } -static void LookupInPrototypes(Handle map, - Handle name, - LookupResult* lookup, - Zone* zone) { - while (map->prototype()->IsJSObject()) { - Handle holder(JSObject::cast(map->prototype())); - map = handle(holder->map()); - if (!CanInlinePropertyAccess(IC::MapToType(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, - Handle name, - Handle* accessors, - Handle* 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 callback(lookup.GetValueFromMap(*map), isolate); - if (!callback->IsAccessorPair()) return false; - *accessors = Handle::cast(callback); - *holder = Handle(); - 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 callback(lookup.GetValue(), isolate); - if (!callback->IsAccessorPair()) return false; - *accessors = Handle::cast(callback); - *holder = Handle(lookup.holder()); - return true; - } - - // We haven't found a JavaScript accessor anywhere. - return false; -} - - -static bool LookupSetter(Handle map, - Handle name, - Handle* setter, - Handle* holder, - Zone* zone) { - Handle accessors; - if (LookupAccessorPair(map, name, &accessors, holder, zone) && - accessors->setter()->IsJSFunction()) { - Handle 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 setter; - Handle 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 name, - HValue* value, - Handle 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::cast(map->prototype())), - Handle(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 transition(lookup->GetTransitionMapFromMap(*map)); - HConstant* transition_constant = Add(transition); + HConstant* transition_constant = Add(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 name, - HValue* value) { + HValue* value, + bool is_uninitialized) { + if (is_uninitialized) { + Add("Insufficient type feedback for property assignment", + Deoptimizer::SOFT); + } + return New( 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 name, - LookupResult* lookup, - bool lookup_transition = true) { - if (!CanInlinePropertyAccess(type) || !type->IsClass()) { - lookup->NotFound(); - return false; - } - Handle 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 name, - HValue* value, - Handle 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) { + if (!IsLoad() && lookup_.IsProperty() && + (lookup_.IsReadOnly() || !lookup_.IsCacheable())) { + return false; + } + if (lookup_.IsField()) { access_ = HObjectAccess::ForField(map, &lookup_, name_); } else if (lookup_.IsPropertyCallbacks()) { Handle callback(lookup_.GetValueFromMap(*map), isolate()); if (!callback->IsAccessorPair()) return false; - Object* getter = Handle::cast(callback)->getter(); - if (!getter->IsJSFunction()) return false; - Handle accessor = handle(JSFunction::cast(getter)); + Object* raw_accessor = IsLoad() + ? Handle::cast(callback)->getter() + : Handle::cast(callback)->setter(); + if (!raw_accessor->IsJSFunction()) return false; + Handle 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 = 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 prototype(JSObject::cast(info->map()->prototype())); + BuildCheckPrototypeMaps(prototype, info->holder()); + } + + if (info->lookup()->IsPropertyCallbacks()) { + if (NeedsWrappingFor(info->type(), info->accessor())) { + HValue* function = Add(info->accessor()); + Add(checked_object); + Add(value); + return New(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(value, Handle::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 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 = 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(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(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 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 = 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(object, map, if_true, if_false); + HCompareMap* compare = New( + 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("Insufficient type feedback for property assignment", - Deoptimizer::SOFT); - } + HValue* value = Pop(); + HValue* object = Pop(); Literal* key = prop->key()->AsLiteral(); Handle name = Handle::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 = types->first(); - Handle setter; - Handle 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(object); - Add(value); - if (needs_wrapping) { - HValue* function = Add(setter); - instr = New(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( + 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(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 target = Handle::cast(info.constant()); expr->set_target(target); @@ -8101,8 +7968,8 @@ void HOptimizedGraphBuilder::VisitCall(Call* expr) { if (prop->key()->IsPropertyName() && types->length() > 0) { Handle 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; } diff --git a/src/hydrogen.h b/src/hydrogen.h index 69753d7..7eb2c84 100644 --- a/src/hydrogen.h +++ b/src/hydrogen.h @@ -2264,13 +2264,16 @@ class HOptimizedGraphBuilder : public HGraphBuilder, public AstVisitor { void VisitDataViewInitialize(CallRuntime* expr); + enum PropertyAccessType { LOAD, STORE }; class PropertyAccessInfo { public: PropertyAccessInfo(HOptimizedGraphBuilder* builder, + PropertyAccessType access_type, Type* type, Handle name) : lookup_(builder->isolate()), builder_(builder), + access_type_(access_type), type_(type), name_(name), access_(HObjectAccess::ForMap()) { } @@ -2278,7 +2281,7 @@ class HOptimizedGraphBuilder : public HGraphBuilder, public AstVisitor { // 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(); + bool CanAccessMonomorphic(); // Checks whether all types behave uniform when loading name. If all maps // behave the same, a single monomorphic load instruction can be emitted, @@ -2286,7 +2289,7 @@ class HOptimizedGraphBuilder : public HGraphBuilder, public AstVisitor { // 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 CanAccessAsMonomorphic(SmallMapList* types); Handle map() { if (type_->Is(Type::Number())) { @@ -2337,6 +2340,7 @@ class HOptimizedGraphBuilder : public HGraphBuilder, public AstVisitor { Handle holder() { return holder_; } Handle accessor() { return accessor_; } Handle constant() { return constant_; } + Handle transition() { return transition_; } HObjectAccess access() { return access_; } private: @@ -2352,7 +2356,8 @@ class HOptimizedGraphBuilder : public HGraphBuilder, public AstVisitor { bool LoadResult(Handle map); bool LookupDescriptor(); bool LookupInPrototypes(); - bool IsCompatibleForLoad(PropertyAccessInfo* other); + bool IsCompatible(PropertyAccessInfo* other); + bool IsLoad() const { return access_type_ == LOAD; } void GeneralizeRepresentation(Representation r) { access_ = access_.WithRepresentation( @@ -2361,11 +2366,13 @@ class HOptimizedGraphBuilder : public HGraphBuilder, public AstVisitor { LookupResult lookup_; HOptimizedGraphBuilder* builder_; + PropertyAccessType access_type_; Type* type_; Handle name_; Handle holder_; Handle accessor_; Handle constant_; + Handle transition_; HObjectAccess access_; }; @@ -2376,12 +2383,15 @@ class HOptimizedGraphBuilder : public HGraphBuilder, public AstVisitor { BailoutId return_id, bool can_inline_accessor = true); + HInstruction* BuildStoreMonomorphic(PropertyAccessInfo* info, + HValue* checked_object, + HValue* value, + BailoutId ast_id, + BailoutId return_id, + bool can_inline_accessor = true); + void HandlePolymorphicStoreNamedField(BailoutId assignment_id, - HValue* object, - HValue* value, - SmallMapList* types, - Handle name); - bool TryStorePolymorphicAsMonomorphic(BailoutId assignment_id, + BailoutId return_id, HValue* object, HValue* value, SmallMapList* types, @@ -2472,18 +2482,13 @@ class HOptimizedGraphBuilder : public HGraphBuilder, public AstVisitor { BailoutId return_id, bool is_uninitialized = false); - HInstruction* BuildStoreNamedField(HValue* object, - Handle name, - HValue* value, - Handle map, - LookupResult* lookup); + HInstruction* BuildStoreNamedField(PropertyAccessInfo* info, + HValue* checked_object, + HValue* value); HInstruction* BuildStoreNamedGeneric(HValue* object, Handle name, - HValue* value); - HInstruction* BuildStoreNamedMonomorphic(HValue* object, - Handle name, - HValue* value, - Handle map); + HValue* value, + bool is_uninitialized = false); HInstruction* BuildStoreKeyedGeneric(HValue* object, HValue* key, HValue* value); -- 2.7.4