Unify implementations of Map handles vectors and lists
This CL introduces a new type, MapHandles, which is a STL vector of Handle<Map>. It is now used everywhere where lists of Handle<Maps> are required, replacing usages of V8's internal List type. Also-By: franzih@chromium.org BUG=v8:6333,v8:6325 LOG=N Review-Url: https://codereview.chromium.org/2809923002 Cr-Commit-Position: refs/heads/master@{#45211}
This commit is contained in:
parent
a459f188fa
commit
fc274fbe99
@ -232,7 +232,7 @@ void CompilationJob::RegisterWeakObjectsInOptimizedCode(Handle<Code> code) {
|
||||
// TODO(turbofan): Move this to pipeline.cc once Crankshaft dies.
|
||||
Isolate* const isolate = code->GetIsolate();
|
||||
DCHECK(code->is_optimized_code());
|
||||
std::vector<Handle<Map>> maps;
|
||||
MapHandles maps;
|
||||
std::vector<Handle<HeapObject>> objects;
|
||||
{
|
||||
DisallowHeapAllocation no_gc;
|
||||
|
@ -61,26 +61,26 @@ std::ostream& operator<<(std::ostream& os, AccessMode access_mode) {
|
||||
|
||||
ElementAccessInfo::ElementAccessInfo() {}
|
||||
|
||||
ElementAccessInfo::ElementAccessInfo(MapList const& receiver_maps,
|
||||
ElementAccessInfo::ElementAccessInfo(MapHandles const& receiver_maps,
|
||||
ElementsKind elements_kind)
|
||||
: elements_kind_(elements_kind), receiver_maps_(receiver_maps) {}
|
||||
|
||||
// static
|
||||
PropertyAccessInfo PropertyAccessInfo::NotFound(MapList const& receiver_maps,
|
||||
PropertyAccessInfo PropertyAccessInfo::NotFound(MapHandles const& receiver_maps,
|
||||
MaybeHandle<JSObject> holder) {
|
||||
return PropertyAccessInfo(holder, receiver_maps);
|
||||
}
|
||||
|
||||
// static
|
||||
PropertyAccessInfo PropertyAccessInfo::DataConstant(
|
||||
MapList const& receiver_maps, Handle<Object> constant,
|
||||
MapHandles const& receiver_maps, Handle<Object> constant,
|
||||
MaybeHandle<JSObject> holder) {
|
||||
return PropertyAccessInfo(kDataConstant, holder, constant, receiver_maps);
|
||||
}
|
||||
|
||||
// static
|
||||
PropertyAccessInfo PropertyAccessInfo::DataField(
|
||||
PropertyConstness constness, MapList const& receiver_maps,
|
||||
PropertyConstness constness, MapHandles const& receiver_maps,
|
||||
FieldIndex field_index, MachineRepresentation field_representation,
|
||||
Type* field_type, MaybeHandle<Map> field_map, MaybeHandle<JSObject> holder,
|
||||
MaybeHandle<Map> transition_map) {
|
||||
@ -92,7 +92,7 @@ PropertyAccessInfo PropertyAccessInfo::DataField(
|
||||
|
||||
// static
|
||||
PropertyAccessInfo PropertyAccessInfo::AccessorConstant(
|
||||
MapList const& receiver_maps, Handle<Object> constant,
|
||||
MapHandles const& receiver_maps, Handle<Object> constant,
|
||||
MaybeHandle<JSObject> holder) {
|
||||
return PropertyAccessInfo(kAccessorConstant, holder, constant, receiver_maps);
|
||||
}
|
||||
@ -103,7 +103,7 @@ PropertyAccessInfo::PropertyAccessInfo()
|
||||
field_type_(Type::None()) {}
|
||||
|
||||
PropertyAccessInfo::PropertyAccessInfo(MaybeHandle<JSObject> holder,
|
||||
MapList const& receiver_maps)
|
||||
MapHandles const& receiver_maps)
|
||||
: kind_(kNotFound),
|
||||
receiver_maps_(receiver_maps),
|
||||
holder_(holder),
|
||||
@ -112,7 +112,7 @@ PropertyAccessInfo::PropertyAccessInfo(MaybeHandle<JSObject> holder,
|
||||
|
||||
PropertyAccessInfo::PropertyAccessInfo(Kind kind, MaybeHandle<JSObject> holder,
|
||||
Handle<Object> constant,
|
||||
MapList const& receiver_maps)
|
||||
MapHandles const& receiver_maps)
|
||||
: kind_(kind),
|
||||
receiver_maps_(receiver_maps),
|
||||
constant_(constant),
|
||||
@ -123,7 +123,8 @@ PropertyAccessInfo::PropertyAccessInfo(Kind kind, MaybeHandle<JSObject> holder,
|
||||
PropertyAccessInfo::PropertyAccessInfo(
|
||||
Kind kind, MaybeHandle<JSObject> holder, MaybeHandle<Map> transition_map,
|
||||
FieldIndex field_index, MachineRepresentation field_representation,
|
||||
Type* field_type, MaybeHandle<Map> field_map, MapList const& receiver_maps)
|
||||
Type* field_type, MaybeHandle<Map> field_map,
|
||||
MapHandles const& receiver_maps)
|
||||
: kind_(kind),
|
||||
receiver_maps_(receiver_maps),
|
||||
transition_map_(transition_map),
|
||||
@ -228,12 +229,12 @@ bool AccessInfoFactory::ComputeElementAccessInfo(
|
||||
// Check if it is safe to inline element access for the {map}.
|
||||
if (!CanInlineElementAccess(map)) return false;
|
||||
ElementsKind const elements_kind = map->elements_kind();
|
||||
*access_info = ElementAccessInfo(MapList{map}, elements_kind);
|
||||
*access_info = ElementAccessInfo(MapHandles{map}, elements_kind);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AccessInfoFactory::ComputeElementAccessInfos(
|
||||
MapHandleList const& maps, AccessMode access_mode,
|
||||
MapHandles const& maps, AccessMode access_mode,
|
||||
ZoneVector<ElementAccessInfo>* access_infos) {
|
||||
if (access_mode == AccessMode::kLoad) {
|
||||
// For polymorphic loads of similar elements kinds (i.e. all tagged or all
|
||||
@ -248,26 +249,28 @@ bool AccessInfoFactory::ComputeElementAccessInfos(
|
||||
}
|
||||
|
||||
// Collect possible transition targets.
|
||||
MapHandleList possible_transition_targets(maps.length());
|
||||
MapHandles possible_transition_targets;
|
||||
possible_transition_targets.reserve(maps.size());
|
||||
for (Handle<Map> map : maps) {
|
||||
if (Map::TryUpdate(map).ToHandle(&map)) {
|
||||
if (CanInlineElementAccess(map) &&
|
||||
IsFastElementsKind(map->elements_kind()) &&
|
||||
GetInitialFastElementsKind() != map->elements_kind()) {
|
||||
possible_transition_targets.Add(map);
|
||||
possible_transition_targets.push_back(map);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Separate the actual receiver maps and the possible transition sources.
|
||||
MapHandleList receiver_maps(maps.length());
|
||||
MapTransitionList transitions(maps.length());
|
||||
MapHandles receiver_maps;
|
||||
receiver_maps.reserve(maps.size());
|
||||
MapTransitionList transitions(maps.size());
|
||||
for (Handle<Map> map : maps) {
|
||||
if (Map::TryUpdate(map).ToHandle(&map)) {
|
||||
Map* transition_target =
|
||||
map->FindElementsKindTransitionedMap(&possible_transition_targets);
|
||||
map->FindElementsKindTransitionedMap(possible_transition_targets);
|
||||
if (transition_target == nullptr) {
|
||||
receiver_maps.Add(map);
|
||||
receiver_maps.push_back(map);
|
||||
} else {
|
||||
DCHECK(!map->is_stable());
|
||||
transitions.push_back(std::make_pair(map, handle(transition_target)));
|
||||
@ -375,7 +378,7 @@ bool AccessInfoFactory::ComputePropertyAccessInfo(
|
||||
}
|
||||
}
|
||||
*access_info = PropertyAccessInfo::DataField(
|
||||
details.constness(), MapList{receiver_map}, field_index,
|
||||
details.constness(), MapHandles{receiver_map}, field_index,
|
||||
field_representation, field_type, field_map, holder);
|
||||
return true;
|
||||
} else {
|
||||
@ -389,7 +392,7 @@ bool AccessInfoFactory::ComputePropertyAccessInfo(
|
||||
if (details.kind() == kData) {
|
||||
DCHECK(!FLAG_track_constant_fields);
|
||||
*access_info = PropertyAccessInfo::DataConstant(
|
||||
MapList{receiver_map},
|
||||
MapHandles{receiver_map},
|
||||
handle(descriptors->GetValue(number), isolate()), holder);
|
||||
return true;
|
||||
} else {
|
||||
@ -420,7 +423,7 @@ bool AccessInfoFactory::ComputePropertyAccessInfo(
|
||||
}
|
||||
}
|
||||
*access_info = PropertyAccessInfo::AccessorConstant(
|
||||
MapList{receiver_map}, accessor, holder);
|
||||
MapHandles{receiver_map}, accessor, holder);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -463,7 +466,7 @@ bool AccessInfoFactory::ComputePropertyAccessInfo(
|
||||
// on the language mode of the load operation.
|
||||
// Implemented according to ES6 section 9.1.8 [[Get]] (P, Receiver)
|
||||
*access_info =
|
||||
PropertyAccessInfo::NotFound(MapList{receiver_map}, holder);
|
||||
PropertyAccessInfo::NotFound(MapHandles{receiver_map}, holder);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
@ -482,7 +485,7 @@ bool AccessInfoFactory::ComputePropertyAccessInfo(
|
||||
}
|
||||
|
||||
bool AccessInfoFactory::ComputePropertyAccessInfos(
|
||||
MapHandleList const& maps, Handle<Name> name, AccessMode access_mode,
|
||||
MapHandles const& maps, Handle<Name> name, AccessMode access_mode,
|
||||
ZoneVector<PropertyAccessInfo>* access_infos) {
|
||||
for (Handle<Map> map : maps) {
|
||||
if (Map::TryUpdate(map).ToHandle(&map)) {
|
||||
@ -528,14 +531,12 @@ Maybe<ElementsKind> GeneralizeElementsKind(ElementsKind this_kind,
|
||||
|
||||
} // namespace
|
||||
|
||||
bool AccessInfoFactory::ConsolidateElementLoad(MapHandleList const& maps,
|
||||
bool AccessInfoFactory::ConsolidateElementLoad(MapHandles const& maps,
|
||||
ElementAccessInfo* access_info) {
|
||||
if (maps.is_empty()) return false;
|
||||
InstanceType instance_type = maps.first()->instance_type();
|
||||
ElementsKind elements_kind = maps.first()->elements_kind();
|
||||
MapList receiver_maps(maps.length());
|
||||
for (int i = 0; i < maps.length(); ++i) {
|
||||
Handle<Map> map = maps[i];
|
||||
if (maps.empty()) return false;
|
||||
InstanceType instance_type = maps.front()->instance_type();
|
||||
ElementsKind elements_kind = maps.front()->elements_kind();
|
||||
for (Handle<Map> map : maps) {
|
||||
if (!CanInlineElementAccess(map) || map->instance_type() != instance_type) {
|
||||
return false;
|
||||
}
|
||||
@ -543,9 +544,8 @@ bool AccessInfoFactory::ConsolidateElementLoad(MapHandleList const& maps,
|
||||
.To(&elements_kind)) {
|
||||
return false;
|
||||
}
|
||||
receiver_maps[i] = map;
|
||||
}
|
||||
*access_info = ElementAccessInfo(receiver_maps, elements_kind);
|
||||
*access_info = ElementAccessInfo(maps, elements_kind);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -581,8 +581,9 @@ bool AccessInfoFactory::LookupSpecialFieldAccessor(
|
||||
}
|
||||
}
|
||||
// Special fields are always mutable.
|
||||
*access_info = PropertyAccessInfo::DataField(
|
||||
kMutable, MapList{map}, field_index, field_representation, field_type);
|
||||
*access_info =
|
||||
PropertyAccessInfo::DataField(kMutable, MapHandles{map}, field_index,
|
||||
field_representation, field_type);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@ -640,8 +641,8 @@ bool AccessInfoFactory::LookupTransition(Handle<Map> map, Handle<Name> name,
|
||||
dependencies()->AssumeMapNotDeprecated(transition_map);
|
||||
// Transitioning stores are never stores to constant fields.
|
||||
*access_info = PropertyAccessInfo::DataField(
|
||||
kMutable, MapList{map}, field_index, field_representation, field_type,
|
||||
field_map, holder, transition_map);
|
||||
kMutable, MapHandles{map}, field_index, field_representation,
|
||||
field_type, field_map, holder, transition_map);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -31,8 +31,6 @@ enum class AccessMode { kLoad, kStore, kStoreInLiteral };
|
||||
|
||||
std::ostream& operator<<(std::ostream&, AccessMode);
|
||||
|
||||
typedef std::vector<Handle<Map>> MapList;
|
||||
|
||||
// Mapping of transition source to transition target.
|
||||
typedef std::vector<std::pair<Handle<Map>, Handle<Map>>> MapTransitionList;
|
||||
|
||||
@ -40,16 +38,17 @@ typedef std::vector<std::pair<Handle<Map>, Handle<Map>>> MapTransitionList;
|
||||
class ElementAccessInfo final {
|
||||
public:
|
||||
ElementAccessInfo();
|
||||
ElementAccessInfo(MapList const& receiver_maps, ElementsKind elements_kind);
|
||||
ElementAccessInfo(MapHandles const& receiver_maps,
|
||||
ElementsKind elements_kind);
|
||||
|
||||
ElementsKind elements_kind() const { return elements_kind_; }
|
||||
MapList const& receiver_maps() const { return receiver_maps_; }
|
||||
MapHandles const& receiver_maps() const { return receiver_maps_; }
|
||||
MapTransitionList& transitions() { return transitions_; }
|
||||
MapTransitionList const& transitions() const { return transitions_; }
|
||||
|
||||
private:
|
||||
ElementsKind elements_kind_;
|
||||
MapList receiver_maps_;
|
||||
MapHandles receiver_maps_;
|
||||
MapTransitionList transitions_;
|
||||
};
|
||||
|
||||
@ -66,18 +65,18 @@ class PropertyAccessInfo final {
|
||||
kAccessorConstant
|
||||
};
|
||||
|
||||
static PropertyAccessInfo NotFound(MapList const& receiver_maps,
|
||||
static PropertyAccessInfo NotFound(MapHandles const& receiver_maps,
|
||||
MaybeHandle<JSObject> holder);
|
||||
static PropertyAccessInfo DataConstant(MapList const& receiver_maps,
|
||||
static PropertyAccessInfo DataConstant(MapHandles const& receiver_maps,
|
||||
Handle<Object> constant,
|
||||
MaybeHandle<JSObject> holder);
|
||||
static PropertyAccessInfo DataField(
|
||||
PropertyConstness constness, MapList const& receiver_maps,
|
||||
PropertyConstness constness, MapHandles const& receiver_maps,
|
||||
FieldIndex field_index, MachineRepresentation field_representation,
|
||||
Type* field_type, MaybeHandle<Map> field_map = MaybeHandle<Map>(),
|
||||
MaybeHandle<JSObject> holder = MaybeHandle<JSObject>(),
|
||||
MaybeHandle<Map> transition_map = MaybeHandle<Map>());
|
||||
static PropertyAccessInfo AccessorConstant(MapList const& receiver_maps,
|
||||
static PropertyAccessInfo AccessorConstant(MapHandles const& receiver_maps,
|
||||
Handle<Object> constant,
|
||||
MaybeHandle<JSObject> holder);
|
||||
|
||||
@ -106,21 +105,21 @@ class PropertyAccessInfo final {
|
||||
return field_representation_;
|
||||
}
|
||||
MaybeHandle<Map> field_map() const { return field_map_; }
|
||||
MapList const& receiver_maps() const { return receiver_maps_; }
|
||||
MapHandles const& receiver_maps() const { return receiver_maps_; }
|
||||
|
||||
private:
|
||||
PropertyAccessInfo(MaybeHandle<JSObject> holder,
|
||||
MapList const& receiver_maps);
|
||||
MapHandles const& receiver_maps);
|
||||
PropertyAccessInfo(Kind kind, MaybeHandle<JSObject> holder,
|
||||
Handle<Object> constant, MapList const& receiver_maps);
|
||||
Handle<Object> constant, MapHandles const& receiver_maps);
|
||||
PropertyAccessInfo(Kind kind, MaybeHandle<JSObject> holder,
|
||||
MaybeHandle<Map> transition_map, FieldIndex field_index,
|
||||
MachineRepresentation field_representation,
|
||||
Type* field_type, MaybeHandle<Map> field_map,
|
||||
MapList const& receiver_maps);
|
||||
MapHandles const& receiver_maps);
|
||||
|
||||
Kind kind_;
|
||||
MapList receiver_maps_;
|
||||
MapHandles receiver_maps_;
|
||||
Handle<Object> constant_;
|
||||
MaybeHandle<Map> transition_map_;
|
||||
MaybeHandle<JSObject> holder_;
|
||||
@ -139,18 +138,17 @@ class AccessInfoFactory final {
|
||||
|
||||
bool ComputeElementAccessInfo(Handle<Map> map, AccessMode access_mode,
|
||||
ElementAccessInfo* access_info);
|
||||
bool ComputeElementAccessInfos(MapHandleList const& maps,
|
||||
AccessMode access_mode,
|
||||
bool ComputeElementAccessInfos(MapHandles const& maps, AccessMode access_mode,
|
||||
ZoneVector<ElementAccessInfo>* access_infos);
|
||||
bool ComputePropertyAccessInfo(Handle<Map> map, Handle<Name> name,
|
||||
AccessMode access_mode,
|
||||
PropertyAccessInfo* access_info);
|
||||
bool ComputePropertyAccessInfos(MapHandleList const& maps, Handle<Name> name,
|
||||
bool ComputePropertyAccessInfos(MapHandles const& maps, Handle<Name> name,
|
||||
AccessMode access_mode,
|
||||
ZoneVector<PropertyAccessInfo>* access_infos);
|
||||
|
||||
private:
|
||||
bool ConsolidateElementLoad(MapHandleList const& maps,
|
||||
bool ConsolidateElementLoad(MapHandles const& maps,
|
||||
ElementAccessInfo* access_info);
|
||||
bool LookupSpecialFieldAccessor(Handle<Map> map, Handle<Name> name,
|
||||
PropertyAccessInfo* access_info);
|
||||
|
@ -24,21 +24,21 @@ namespace compiler {
|
||||
|
||||
namespace {
|
||||
|
||||
bool HasNumberMaps(MapList const& maps) {
|
||||
bool HasNumberMaps(MapHandles const& maps) {
|
||||
for (auto map : maps) {
|
||||
if (map->instance_type() == HEAP_NUMBER_TYPE) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool HasOnlyJSArrayMaps(MapList const& maps) {
|
||||
bool HasOnlyJSArrayMaps(MapHandles const& maps) {
|
||||
for (auto map : maps) {
|
||||
if (!map->IsJSArrayMap()) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HasOnlyNumberMaps(MapList const& maps) {
|
||||
bool HasOnlyNumberMaps(MapHandles const& maps) {
|
||||
for (auto map : maps) {
|
||||
if (map->instance_type() != HEAP_NUMBER_TYPE) return false;
|
||||
}
|
||||
@ -706,9 +706,8 @@ Reduction JSNativeContextSpecialization::ReduceJSStoreGlobal(Node* node) {
|
||||
}
|
||||
|
||||
Reduction JSNativeContextSpecialization::ReduceNamedAccess(
|
||||
Node* node, Node* value, MapHandleList const& receiver_maps,
|
||||
Handle<Name> name, AccessMode access_mode, LanguageMode language_mode,
|
||||
Node* index) {
|
||||
Node* node, Node* value, MapHandles const& receiver_maps, Handle<Name> name,
|
||||
AccessMode access_mode, LanguageMode language_mode, Node* index) {
|
||||
DCHECK(node->opcode() == IrOpcode::kJSLoadNamed ||
|
||||
node->opcode() == IrOpcode::kJSStoreNamed ||
|
||||
node->opcode() == IrOpcode::kJSLoadProperty ||
|
||||
@ -723,8 +722,8 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccess(
|
||||
// Check if we have an access o.x or o.x=v where o is the current
|
||||
// native contexts' global proxy, and turn that into a direct access
|
||||
// to the current native contexts' global object instead.
|
||||
if (receiver_maps.length() == 1) {
|
||||
Handle<Map> receiver_map = receiver_maps.first();
|
||||
if (receiver_maps.size() == 1) {
|
||||
Handle<Map> receiver_map = receiver_maps.front();
|
||||
if (receiver_map->IsJSGlobalProxyMap()) {
|
||||
Object* maybe_constructor = receiver_map->GetConstructor();
|
||||
// Detached global proxies have |null| as their constructor.
|
||||
@ -841,7 +840,7 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccess(
|
||||
Node* this_control = fallthrough_control;
|
||||
|
||||
// Perform map check on {receiver}.
|
||||
MapList const& receiver_maps = access_info.receiver_maps();
|
||||
MapHandles const& receiver_maps = access_info.receiver_maps();
|
||||
{
|
||||
// Emit a (sequence of) map checks for other {receiver}s.
|
||||
ZoneVector<Node*> this_controls(zone());
|
||||
@ -956,10 +955,10 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccessFromNexus(
|
||||
}
|
||||
|
||||
// Extract receiver maps from the IC using the {nexus}.
|
||||
MapHandleList receiver_maps;
|
||||
MapHandles receiver_maps;
|
||||
if (!ExtractReceiverMaps(receiver, effect, nexus, &receiver_maps)) {
|
||||
return NoChange();
|
||||
} else if (receiver_maps.length() == 0) {
|
||||
} else if (receiver_maps.empty()) {
|
||||
if (flags() & kBailoutOnUninitialized) {
|
||||
return ReduceSoftDeoptimize(
|
||||
node,
|
||||
@ -1047,7 +1046,7 @@ Reduction JSNativeContextSpecialization::ReduceJSStoreNamedOwn(Node* node) {
|
||||
}
|
||||
|
||||
Reduction JSNativeContextSpecialization::ReduceElementAccess(
|
||||
Node* node, Node* index, Node* value, MapHandleList const& receiver_maps,
|
||||
Node* node, Node* index, Node* value, MapHandles const& receiver_maps,
|
||||
AccessMode access_mode, LanguageMode language_mode,
|
||||
KeyedAccessStoreMode store_mode) {
|
||||
DCHECK(node->opcode() == IrOpcode::kJSLoadProperty ||
|
||||
@ -1211,7 +1210,7 @@ Reduction JSNativeContextSpecialization::ReduceElementAccess(
|
||||
receiver, this_effect, this_control);
|
||||
|
||||
// Perform map check(s) on {receiver}.
|
||||
MapList const& receiver_maps = access_info.receiver_maps();
|
||||
MapHandles const& receiver_maps = access_info.receiver_maps();
|
||||
if (j == access_infos.size() - 1) {
|
||||
// Last map check on the fallthrough control path, do a
|
||||
// conditional eager deoptimization exit here.
|
||||
@ -1344,10 +1343,10 @@ Reduction JSNativeContextSpecialization::ReduceKeyedAccess(
|
||||
}
|
||||
|
||||
// Extract receiver maps from the {nexus}.
|
||||
MapHandleList receiver_maps;
|
||||
MapHandles receiver_maps;
|
||||
if (!ExtractReceiverMaps(receiver, effect, nexus, &receiver_maps)) {
|
||||
return NoChange();
|
||||
} else if (receiver_maps.length() == 0) {
|
||||
} else if (receiver_maps.empty()) {
|
||||
if (flags() & kBailoutOnUninitialized) {
|
||||
return ReduceSoftDeoptimize(
|
||||
node,
|
||||
@ -1911,7 +1910,7 @@ JSNativeContextSpecialization::BuildElementAccess(
|
||||
// TODO(bmeurer): We currently specialize based on elements kind. We should
|
||||
// also be able to properly support strings and other JSObjects here.
|
||||
ElementsKind elements_kind = access_info.elements_kind();
|
||||
MapList const& receiver_maps = access_info.receiver_maps();
|
||||
MapHandles const& receiver_maps = access_info.receiver_maps();
|
||||
|
||||
if (IsFixedTypedArrayElementsKind(elements_kind)) {
|
||||
Node* buffer;
|
||||
@ -2282,7 +2281,7 @@ Node* JSNativeContextSpecialization::BuildCheckHeapObject(Node* receiver,
|
||||
|
||||
Node* JSNativeContextSpecialization::BuildCheckMaps(
|
||||
Node* receiver, Node* effect, Node* control,
|
||||
std::vector<Handle<Map>> const& receiver_maps) {
|
||||
MapHandles const& receiver_maps) {
|
||||
HeapObjectMatcher m(receiver);
|
||||
if (m.HasValue()) {
|
||||
Handle<Map> receiver_map(m.Value()->map(), isolate());
|
||||
@ -2356,7 +2355,7 @@ Node* JSNativeContextSpecialization::BuildExtendPropertiesBackingStore(
|
||||
}
|
||||
|
||||
void JSNativeContextSpecialization::AssumePrototypesStable(
|
||||
std::vector<Handle<Map>> const& receiver_maps, Handle<JSObject> holder) {
|
||||
MapHandles const& receiver_maps, Handle<JSObject> holder) {
|
||||
// Determine actual holder and perform prototype chain checks.
|
||||
for (auto map : receiver_maps) {
|
||||
// Perform the implicit ToObject for primitives here.
|
||||
@ -2371,7 +2370,7 @@ void JSNativeContextSpecialization::AssumePrototypesStable(
|
||||
}
|
||||
|
||||
bool JSNativeContextSpecialization::CanTreatHoleAsUndefined(
|
||||
std::vector<Handle<Map>> const& receiver_maps) {
|
||||
MapHandles const& receiver_maps) {
|
||||
// Check if the array prototype chain is intact.
|
||||
if (!isolate()->IsFastArrayConstructorPrototypeChainIntact()) return false;
|
||||
|
||||
@ -2458,8 +2457,8 @@ JSNativeContextSpecialization::InferHasInPrototypeChain(
|
||||
|
||||
bool JSNativeContextSpecialization::ExtractReceiverMaps(
|
||||
Node* receiver, Node* effect, FeedbackNexus const& nexus,
|
||||
MapHandleList* receiver_maps) {
|
||||
DCHECK_EQ(0, receiver_maps->length());
|
||||
MapHandles* receiver_maps) {
|
||||
DCHECK_EQ(0, receiver_maps->size());
|
||||
// See if we can infer a concrete type for the {receiver}.
|
||||
if (InferReceiverMaps(receiver, effect, receiver_maps)) {
|
||||
// We can assume that the {receiver} still has the infered {receiver_maps}.
|
||||
@ -2470,11 +2469,12 @@ bool JSNativeContextSpecialization::ExtractReceiverMaps(
|
||||
// Try to filter impossible candidates based on infered root map.
|
||||
Handle<Map> receiver_map;
|
||||
if (InferReceiverRootMap(receiver).ToHandle(&receiver_map)) {
|
||||
for (int i = receiver_maps->length(); --i >= 0;) {
|
||||
if (receiver_maps->at(i)->FindRootMap() != *receiver_map) {
|
||||
receiver_maps->Remove(i);
|
||||
}
|
||||
}
|
||||
receiver_maps->erase(
|
||||
std::remove_if(receiver_maps->begin(), receiver_maps->end(),
|
||||
[receiver_map](const Handle<Map>& map) {
|
||||
return map->FindRootMap() != *receiver_map;
|
||||
}),
|
||||
receiver_maps->end());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -2482,13 +2482,13 @@ bool JSNativeContextSpecialization::ExtractReceiverMaps(
|
||||
}
|
||||
|
||||
bool JSNativeContextSpecialization::InferReceiverMaps(
|
||||
Node* receiver, Node* effect, MapHandleList* receiver_maps) {
|
||||
Node* receiver, Node* effect, MapHandles* receiver_maps) {
|
||||
ZoneHandleSet<Map> maps;
|
||||
NodeProperties::InferReceiverMapsResult result =
|
||||
NodeProperties::InferReceiverMaps(receiver, effect, &maps);
|
||||
if (result == NodeProperties::kReliableReceiverMaps) {
|
||||
for (size_t i = 0; i < maps.size(); ++i) {
|
||||
receiver_maps->Add(maps[i]);
|
||||
receiver_maps->push_back(maps[i]);
|
||||
}
|
||||
return true;
|
||||
} else if (result == NodeProperties::kUnreliableReceiverMaps) {
|
||||
@ -2498,7 +2498,7 @@ bool JSNativeContextSpecialization::InferReceiverMaps(
|
||||
if (!maps[i]->is_stable()) return false;
|
||||
}
|
||||
for (size_t i = 0; i < maps.size(); ++i) {
|
||||
receiver_maps->Add(maps[i]);
|
||||
receiver_maps->push_back(maps[i]);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -67,7 +67,7 @@ class JSNativeContextSpecialization final : public AdvancedReducer {
|
||||
Reduction ReduceJSStoreDataPropertyInLiteral(Node* node);
|
||||
|
||||
Reduction ReduceElementAccess(Node* node, Node* index, Node* value,
|
||||
MapHandleList const& receiver_maps,
|
||||
MapHandles const& receiver_maps,
|
||||
AccessMode access_mode,
|
||||
LanguageMode language_mode,
|
||||
KeyedAccessStoreMode store_mode);
|
||||
@ -82,7 +82,7 @@ class JSNativeContextSpecialization final : public AdvancedReducer {
|
||||
AccessMode access_mode,
|
||||
LanguageMode language_mode);
|
||||
Reduction ReduceNamedAccess(Node* node, Node* value,
|
||||
MapHandleList const& receiver_maps,
|
||||
MapHandles const& receiver_maps,
|
||||
Handle<Name> name, AccessMode access_mode,
|
||||
LanguageMode language_mode,
|
||||
Node* index = nullptr);
|
||||
@ -130,7 +130,7 @@ class JSNativeContextSpecialization final : public AdvancedReducer {
|
||||
|
||||
// Construct an appropriate map check.
|
||||
Node* BuildCheckMaps(Node* receiver, Node* effect, Node* control,
|
||||
std::vector<Handle<Map>> const& maps);
|
||||
MapHandles const& maps);
|
||||
|
||||
// Construct appropriate subgraph to extend properties backing store.
|
||||
Node* BuildExtendPropertiesBackingStore(Handle<Map> map, Node* properties,
|
||||
@ -138,13 +138,13 @@ class JSNativeContextSpecialization final : public AdvancedReducer {
|
||||
|
||||
// Adds stability dependencies on all prototypes of every class in
|
||||
// {receiver_type} up to (and including) the {holder}.
|
||||
void AssumePrototypesStable(std::vector<Handle<Map>> const& receiver_maps,
|
||||
void AssumePrototypesStable(MapHandles const& receiver_maps,
|
||||
Handle<JSObject> holder);
|
||||
|
||||
// Checks if we can turn the hole into undefined when loading an element
|
||||
// from an object with one of the {receiver_maps}; sets up appropriate
|
||||
// code dependencies and might use the array protector cell.
|
||||
bool CanTreatHoleAsUndefined(std::vector<Handle<Map>> const& receiver_maps);
|
||||
bool CanTreatHoleAsUndefined(MapHandles const& receiver_maps);
|
||||
|
||||
// Checks if we know at compile time that the {receiver} either definitely
|
||||
// has the {prototype} in it's prototype chain, or the {receiver} definitely
|
||||
@ -161,14 +161,14 @@ class JSNativeContextSpecialization final : public AdvancedReducer {
|
||||
// possible.
|
||||
bool ExtractReceiverMaps(Node* receiver, Node* effect,
|
||||
FeedbackNexus const& nexus,
|
||||
MapHandleList* receiver_maps);
|
||||
MapHandles* receiver_maps);
|
||||
|
||||
// Try to infer maps for the given {receiver} at the current {effect}.
|
||||
// If maps are returned then you can be sure that the {receiver} definitely
|
||||
// has one of the returned maps at this point in the program (identified
|
||||
// by {effect}).
|
||||
bool InferReceiverMaps(Node* receiver, Node* effect,
|
||||
MapHandleList* receiver_maps);
|
||||
MapHandles* receiver_maps);
|
||||
// Try to infer a root map for the {receiver} independent of the current
|
||||
// program location.
|
||||
MaybeHandle<Map> InferReceiverRootMap(Node* receiver);
|
||||
|
@ -6914,9 +6914,11 @@ HValue* HOptimizedGraphBuilder::HandlePolymorphicElementAccess(
|
||||
}
|
||||
|
||||
// Elements_kind transition support.
|
||||
MapHandleList transition_target(maps->length());
|
||||
MapHandles transition_target;
|
||||
transition_target.reserve(maps->length());
|
||||
// Collect possible transition targets.
|
||||
MapHandleList possible_transitioned_maps(maps->length());
|
||||
MapHandles possible_transitioned_maps;
|
||||
possible_transitioned_maps.reserve(maps->length());
|
||||
for (int i = 0; i < maps->length(); ++i) {
|
||||
Handle<Map> map = maps->at(i);
|
||||
// Loads from strings or loads with a mix of string and non-string maps
|
||||
@ -6925,7 +6927,7 @@ HValue* HOptimizedGraphBuilder::HandlePolymorphicElementAccess(
|
||||
ElementsKind elements_kind = map->elements_kind();
|
||||
if (CanInlineElementAccess(map) && IsFastElementsKind(elements_kind) &&
|
||||
elements_kind != GetInitialFastElementsKind()) {
|
||||
possible_transitioned_maps.Add(map);
|
||||
possible_transitioned_maps.push_back(map);
|
||||
}
|
||||
if (IsSloppyArgumentsElementsKind(elements_kind)) {
|
||||
HInstruction* result =
|
||||
@ -6938,16 +6940,17 @@ HValue* HOptimizedGraphBuilder::HandlePolymorphicElementAccess(
|
||||
for (int i = 0; i < maps->length(); ++i) {
|
||||
Handle<Map> map = maps->at(i);
|
||||
Map* transitioned_map =
|
||||
map->FindElementsKindTransitionedMap(&possible_transitioned_maps);
|
||||
map->FindElementsKindTransitionedMap(possible_transitioned_maps);
|
||||
if (transitioned_map != nullptr) {
|
||||
DCHECK(!map->is_stable());
|
||||
transition_target.Add(handle(transitioned_map));
|
||||
transition_target.push_back(handle(transitioned_map));
|
||||
} else {
|
||||
transition_target.Add(Handle<Map>());
|
||||
transition_target.push_back(Handle<Map>());
|
||||
}
|
||||
}
|
||||
|
||||
MapHandleList untransitionable_maps(maps->length());
|
||||
MapHandles untransitionable_maps;
|
||||
untransitionable_maps.reserve(maps->length());
|
||||
HTransitionElementsKind* transition = NULL;
|
||||
for (int i = 0; i < maps->length(); ++i) {
|
||||
Handle<Map> map = maps->at(i);
|
||||
@ -6959,14 +6962,14 @@ HValue* HOptimizedGraphBuilder::HandlePolymorphicElementAccess(
|
||||
transition = Add<HTransitionElementsKind>(object, map,
|
||||
transition_target.at(i));
|
||||
} else {
|
||||
untransitionable_maps.Add(map);
|
||||
untransitionable_maps.push_back(map);
|
||||
}
|
||||
}
|
||||
|
||||
// If only one map is left after transitioning, handle this case
|
||||
// monomorphically.
|
||||
DCHECK(untransitionable_maps.length() >= 1);
|
||||
if (untransitionable_maps.length() == 1) {
|
||||
DCHECK(untransitionable_maps.size() >= 1);
|
||||
if (untransitionable_maps.size() == 1) {
|
||||
Handle<Map> untransitionable_map = untransitionable_maps[0];
|
||||
HInstruction* instr = NULL;
|
||||
if (!CanInlineElementAccess(untransitionable_map)) {
|
||||
@ -6983,8 +6986,7 @@ HValue* HOptimizedGraphBuilder::HandlePolymorphicElementAccess(
|
||||
|
||||
HBasicBlock* join = graph()->CreateBasicBlock();
|
||||
|
||||
for (int i = 0; i < untransitionable_maps.length(); ++i) {
|
||||
Handle<Map> map = untransitionable_maps[i];
|
||||
for (Handle<Map> map : untransitionable_maps) {
|
||||
ElementsKind elements_kind = map->elements_kind();
|
||||
HBasicBlock* this_map = graph()->CreateBasicBlock();
|
||||
HBasicBlock* other_map = graph()->CreateBasicBlock();
|
||||
|
@ -646,9 +646,10 @@ void FeedbackNexus::ConfigureMonomorphic(Handle<Name> name,
|
||||
}
|
||||
}
|
||||
|
||||
void FeedbackNexus::ConfigurePolymorphic(Handle<Name> name, MapHandleList* maps,
|
||||
void FeedbackNexus::ConfigurePolymorphic(Handle<Name> name,
|
||||
MapHandles const& maps,
|
||||
List<Handle<Object>>* handlers) {
|
||||
int receiver_count = maps->length();
|
||||
int receiver_count = static_cast<int>(maps.size());
|
||||
DCHECK(receiver_count > 1);
|
||||
Handle<FixedArray> array;
|
||||
if (name.is_null()) {
|
||||
@ -661,14 +662,14 @@ void FeedbackNexus::ConfigurePolymorphic(Handle<Name> name, MapHandleList* maps,
|
||||
}
|
||||
|
||||
for (int current = 0; current < receiver_count; ++current) {
|
||||
Handle<Map> map = maps->at(current);
|
||||
Handle<Map> map = maps[current];
|
||||
Handle<WeakCell> cell = Map::WeakCellForMap(map);
|
||||
array->set(current * 2, *cell);
|
||||
array->set(current * 2 + 1, *handlers->at(current));
|
||||
}
|
||||
}
|
||||
|
||||
int FeedbackNexus::ExtractMaps(MapHandleList* maps) const {
|
||||
int FeedbackNexus::ExtractMaps(MapHandles* maps) const {
|
||||
Isolate* isolate = GetIsolate();
|
||||
Object* feedback = GetFeedback();
|
||||
bool is_named_feedback = IsPropertyNameFeedback(feedback);
|
||||
@ -684,7 +685,7 @@ int FeedbackNexus::ExtractMaps(MapHandleList* maps) const {
|
||||
WeakCell* cell = WeakCell::cast(array->get(i));
|
||||
if (!cell->cleared()) {
|
||||
Map* map = Map::cast(cell->value());
|
||||
maps->Add(handle(map, isolate));
|
||||
maps->push_back(handle(map, isolate));
|
||||
found++;
|
||||
}
|
||||
}
|
||||
@ -693,7 +694,7 @@ int FeedbackNexus::ExtractMaps(MapHandleList* maps) const {
|
||||
WeakCell* cell = WeakCell::cast(feedback);
|
||||
if (!cell->cleared()) {
|
||||
Map* map = Map::cast(cell->value());
|
||||
maps->Add(handle(map, isolate));
|
||||
maps->push_back(handle(map, isolate));
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@ -791,13 +792,13 @@ Name* KeyedStoreICNexus::FindFirstName() const {
|
||||
|
||||
KeyedAccessStoreMode KeyedStoreICNexus::GetKeyedAccessStoreMode() const {
|
||||
KeyedAccessStoreMode mode = STANDARD_STORE;
|
||||
MapHandleList maps;
|
||||
MapHandles maps;
|
||||
List<Handle<Object>> handlers;
|
||||
|
||||
if (GetKeyType() == PROPERTY) return mode;
|
||||
|
||||
ExtractMaps(&maps);
|
||||
FindHandlers(&handlers, maps.length());
|
||||
FindHandlers(&handlers, static_cast<int>(maps.size()));
|
||||
for (int i = 0; i < handlers.length(); i++) {
|
||||
// The first handler that isn't the slow handler will have the bits we need.
|
||||
Handle<Object> maybe_code_handler = handlers.at(i);
|
||||
|
@ -477,14 +477,14 @@ class FeedbackNexus {
|
||||
InlineCacheState ic_state() const { return StateFromFeedback(); }
|
||||
bool IsUninitialized() const { return StateFromFeedback() == UNINITIALIZED; }
|
||||
Map* FindFirstMap() const {
|
||||
MapHandleList maps;
|
||||
MapHandles maps;
|
||||
ExtractMaps(&maps);
|
||||
if (maps.length() > 0) return *maps.at(0);
|
||||
if (maps.size() > 0) return *maps.at(0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
virtual InlineCacheState StateFromFeedback() const = 0;
|
||||
virtual int ExtractMaps(MapHandleList* maps) const;
|
||||
virtual int ExtractMaps(MapHandles* maps) const;
|
||||
virtual MaybeHandle<Object> FindHandlerForMap(Handle<Map> map) const;
|
||||
virtual bool FindHandlers(List<Handle<Object>>* code_list,
|
||||
int length = -1) const;
|
||||
@ -508,7 +508,7 @@ class FeedbackNexus {
|
||||
void ConfigureMonomorphic(Handle<Name> name, Handle<Map> receiver_map,
|
||||
Handle<Object> handler);
|
||||
|
||||
void ConfigurePolymorphic(Handle<Name> name, MapHandleList* maps,
|
||||
void ConfigurePolymorphic(Handle<Name> name, MapHandles const& maps,
|
||||
List<Handle<Object>>* handlers);
|
||||
|
||||
protected:
|
||||
@ -545,7 +545,7 @@ class CallICNexus final : public FeedbackNexus {
|
||||
|
||||
InlineCacheState StateFromFeedback() const final;
|
||||
|
||||
int ExtractMaps(MapHandleList* maps) const final {
|
||||
int ExtractMaps(MapHandles* maps) const final {
|
||||
// CallICs don't record map feedback.
|
||||
return 0;
|
||||
}
|
||||
@ -591,7 +591,7 @@ class LoadGlobalICNexus : public FeedbackNexus {
|
||||
DCHECK(vector->IsLoadGlobalIC(slot));
|
||||
}
|
||||
|
||||
int ExtractMaps(MapHandleList* maps) const final {
|
||||
int ExtractMaps(MapHandles* maps) const final {
|
||||
// LoadGlobalICs don't record map feedback.
|
||||
return 0;
|
||||
}
|
||||
@ -684,7 +684,7 @@ class BinaryOpICNexus final : public FeedbackNexus {
|
||||
InlineCacheState StateFromFeedback() const final;
|
||||
BinaryOperationHint GetBinaryOperationFeedback() const;
|
||||
|
||||
int ExtractMaps(MapHandleList* maps) const final {
|
||||
int ExtractMaps(MapHandles* maps) const final {
|
||||
// BinaryOpICs don't record map feedback.
|
||||
return 0;
|
||||
}
|
||||
@ -711,7 +711,7 @@ class CompareICNexus final : public FeedbackNexus {
|
||||
InlineCacheState StateFromFeedback() const final;
|
||||
CompareOperationHint GetCompareOperationFeedback() const;
|
||||
|
||||
int ExtractMaps(MapHandleList* maps) const final {
|
||||
int ExtractMaps(MapHandles* maps) const final {
|
||||
// BinaryOpICs don't record map feedback.
|
||||
return 0;
|
||||
}
|
||||
|
121
src/ic/ic.cc
121
src/ic/ic.cc
@ -549,7 +549,7 @@ void IC::ConfigureVectorState(Handle<Name> name, Handle<Map> map,
|
||||
OnFeedbackChanged(isolate(), GetHostFunction());
|
||||
}
|
||||
|
||||
void IC::ConfigureVectorState(Handle<Name> name, MapHandleList* maps,
|
||||
void IC::ConfigureVectorState(Handle<Name> name, MapHandles const& maps,
|
||||
List<Handle<Object>>* handlers) {
|
||||
DCHECK(!IsLoadGlobalIC());
|
||||
// Non-keyed ICs don't track the name explicitly.
|
||||
@ -636,16 +636,15 @@ MaybeHandle<Object> LoadGlobalIC::Load(Handle<Name> name) {
|
||||
return LoadIC::Load(global, name);
|
||||
}
|
||||
|
||||
static bool AddOneReceiverMapIfMissing(MapHandleList* receiver_maps,
|
||||
static bool AddOneReceiverMapIfMissing(MapHandles* receiver_maps,
|
||||
Handle<Map> new_receiver_map) {
|
||||
DCHECK(!new_receiver_map.is_null());
|
||||
for (int current = 0; current < receiver_maps->length(); ++current) {
|
||||
if (!receiver_maps->at(current).is_null() &&
|
||||
receiver_maps->at(current).is_identical_to(new_receiver_map)) {
|
||||
for (Handle<Map> map : *receiver_maps) {
|
||||
if (!map.is_null() && map.is_identical_to(new_receiver_map)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
receiver_maps->Add(new_receiver_map);
|
||||
receiver_maps->push_back(new_receiver_map);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -653,11 +652,11 @@ bool IC::UpdatePolymorphicIC(Handle<Name> name, Handle<Object> handler) {
|
||||
DCHECK(IsHandler(*handler));
|
||||
if (is_keyed() && state() != RECOMPUTE_HANDLER) return false;
|
||||
Handle<Map> map = receiver_map();
|
||||
MapHandleList maps;
|
||||
MapHandles maps;
|
||||
List<Handle<Object>> handlers;
|
||||
|
||||
TargetMaps(&maps);
|
||||
int number_of_maps = maps.length();
|
||||
int number_of_maps = static_cast<int>(maps.size());
|
||||
int deprecated_maps = 0;
|
||||
int handler_to_overwrite = -1;
|
||||
|
||||
@ -684,7 +683,9 @@ bool IC::UpdatePolymorphicIC(Handle<Name> name, Handle<Object> handler) {
|
||||
if (number_of_maps == 0 && state() != MONOMORPHIC && state() != POLYMORPHIC) {
|
||||
return false;
|
||||
}
|
||||
if (!nexus()->FindHandlers(&handlers, maps.length())) return false;
|
||||
if (!nexus()->FindHandlers(&handlers, static_cast<int>(maps.size()))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
number_of_valid_maps++;
|
||||
if (number_of_valid_maps > 1 && is_keyed()) return false;
|
||||
@ -694,14 +695,14 @@ bool IC::UpdatePolymorphicIC(Handle<Name> name, Handle<Object> handler) {
|
||||
if (handler_to_overwrite >= 0) {
|
||||
handlers.Set(handler_to_overwrite, handler);
|
||||
if (!map.is_identical_to(maps.at(handler_to_overwrite))) {
|
||||
maps.Set(handler_to_overwrite, map);
|
||||
maps[handler_to_overwrite] = map;
|
||||
}
|
||||
} else {
|
||||
maps.Add(map);
|
||||
maps.push_back(map);
|
||||
handlers.Add(handler);
|
||||
}
|
||||
|
||||
ConfigureVectorState(name, &maps, &handlers);
|
||||
ConfigureVectorState(name, maps, &handlers);
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -714,11 +715,11 @@ void IC::UpdateMonomorphicIC(Handle<Object> handler, Handle<Name> name) {
|
||||
|
||||
|
||||
void IC::CopyICToMegamorphicCache(Handle<Name> name) {
|
||||
MapHandleList maps;
|
||||
MapHandles maps;
|
||||
List<Handle<Object>> handlers;
|
||||
TargetMaps(&maps);
|
||||
if (!nexus()->FindHandlers(&handlers, maps.length())) return;
|
||||
for (int i = 0; i < maps.length(); i++) {
|
||||
if (!nexus()->FindHandlers(&handlers, static_cast<int>(maps.size()))) return;
|
||||
for (int i = 0; i < static_cast<int>(maps.size()); i++) {
|
||||
UpdateMegamorphicCache(*maps.at(i), *name, *handlers.at(i));
|
||||
}
|
||||
}
|
||||
@ -732,9 +733,9 @@ bool IC::IsTransitionOfMonomorphicTarget(Map* source_map, Map* target_map) {
|
||||
source_map->elements_kind(), target_elements_kind);
|
||||
Map* transitioned_map = nullptr;
|
||||
if (more_general_transition) {
|
||||
MapHandleList map_list;
|
||||
map_list.Add(handle(target_map));
|
||||
transitioned_map = source_map->FindElementsKindTransitionedMap(&map_list);
|
||||
MapHandles map_list;
|
||||
map_list.push_back(handle(target_map));
|
||||
transitioned_map = source_map->FindElementsKindTransitionedMap(map_list);
|
||||
}
|
||||
return transitioned_map == target_map;
|
||||
}
|
||||
@ -1323,16 +1324,15 @@ void KeyedLoadIC::UpdateLoadElement(Handle<HeapObject> receiver) {
|
||||
Handle<Map> receiver_map(receiver->map(), isolate());
|
||||
DCHECK(receiver_map->instance_type() != JS_VALUE_TYPE &&
|
||||
receiver_map->instance_type() != JS_PROXY_TYPE); // Checked by caller.
|
||||
MapHandleList target_receiver_maps;
|
||||
MapHandles target_receiver_maps;
|
||||
TargetMaps(&target_receiver_maps);
|
||||
|
||||
if (target_receiver_maps.length() == 0) {
|
||||
if (target_receiver_maps.empty()) {
|
||||
Handle<Object> handler = LoadElementHandler(receiver_map);
|
||||
return ConfigureVectorState(Handle<Name>(), receiver_map, handler);
|
||||
}
|
||||
|
||||
for (int i = 0; i < target_receiver_maps.length(); i++) {
|
||||
Handle<Map> map = target_receiver_maps.at(i);
|
||||
for (Handle<Map> map : target_receiver_maps) {
|
||||
if (map.is_null()) continue;
|
||||
if (map->instance_type() == JS_VALUE_TYPE) {
|
||||
TRACE_GENERIC_IC("JSValue");
|
||||
@ -1372,19 +1372,19 @@ void KeyedLoadIC::UpdateLoadElement(Handle<HeapObject> receiver) {
|
||||
|
||||
// If the maximum number of receiver maps has been exceeded, use the generic
|
||||
// version of the IC.
|
||||
if (target_receiver_maps.length() > kMaxKeyedPolymorphism) {
|
||||
if (target_receiver_maps.size() > kMaxKeyedPolymorphism) {
|
||||
TRACE_GENERIC_IC("max polymorph exceeded");
|
||||
return;
|
||||
}
|
||||
|
||||
List<Handle<Object>> handlers(target_receiver_maps.length());
|
||||
List<Handle<Object>> handlers(static_cast<int>(target_receiver_maps.size()));
|
||||
LoadElementPolymorphicHandlers(&target_receiver_maps, &handlers);
|
||||
DCHECK_LE(1, target_receiver_maps.length());
|
||||
if (target_receiver_maps.length() == 1) {
|
||||
ConfigureVectorState(Handle<Name>(), target_receiver_maps.at(0),
|
||||
DCHECK_LE(1, target_receiver_maps.size());
|
||||
if (target_receiver_maps.size() == 1) {
|
||||
ConfigureVectorState(Handle<Name>(), target_receiver_maps[0],
|
||||
handlers.at(0));
|
||||
} else {
|
||||
ConfigureVectorState(Handle<Name>(), &target_receiver_maps, &handlers);
|
||||
ConfigureVectorState(Handle<Name>(), target_receiver_maps, &handlers);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1429,20 +1429,20 @@ Handle<Object> KeyedLoadIC::LoadElementHandler(Handle<Map> receiver_map) {
|
||||
}
|
||||
|
||||
void KeyedLoadIC::LoadElementPolymorphicHandlers(
|
||||
MapHandleList* receiver_maps, List<Handle<Object>>* handlers) {
|
||||
for (int i = 0; i < receiver_maps->length(); ++i) {
|
||||
Handle<Map> receiver_map(receiver_maps->at(i));
|
||||
if (receiver_map->is_deprecated()) {
|
||||
// Filter out deprecated maps to ensure their instances get migrated.
|
||||
receiver_maps->Remove(i--);
|
||||
continue;
|
||||
}
|
||||
MapHandles* receiver_maps, List<Handle<Object>>* handlers) {
|
||||
// Filter out deprecated maps to ensure their instances get migrated.
|
||||
receiver_maps->erase(
|
||||
std::remove_if(
|
||||
receiver_maps->begin(), receiver_maps->end(),
|
||||
[](const Handle<Map>& map) { return map->is_deprecated(); }),
|
||||
receiver_maps->end());
|
||||
|
||||
for (Handle<Map> receiver_map : *receiver_maps) {
|
||||
// Mark all stable receiver maps that have elements kind transition map
|
||||
// among receiver_maps as unstable because the optimizing compilers may
|
||||
// generate an elements kind transition for this kind of receivers.
|
||||
if (receiver_map->is_stable()) {
|
||||
Map* tmap = receiver_map->FindElementsKindTransitionedMap(receiver_maps);
|
||||
Map* tmap = receiver_map->FindElementsKindTransitionedMap(*receiver_maps);
|
||||
if (tmap != nullptr) {
|
||||
receiver_map->NotifyLeafMapLayoutChange();
|
||||
}
|
||||
@ -1925,9 +1925,9 @@ Handle<Code> StoreIC::CompileHandler(LookupIterator* lookup) {
|
||||
|
||||
void KeyedStoreIC::UpdateStoreElement(Handle<Map> receiver_map,
|
||||
KeyedAccessStoreMode store_mode) {
|
||||
MapHandleList target_receiver_maps;
|
||||
MapHandles target_receiver_maps;
|
||||
TargetMaps(&target_receiver_maps);
|
||||
if (target_receiver_maps.length() == 0) {
|
||||
if (target_receiver_maps.empty()) {
|
||||
Handle<Map> monomorphic_map =
|
||||
ComputeTransitionedMap(receiver_map, store_mode);
|
||||
store_mode = GetNonTransitioningStoreMode(store_mode);
|
||||
@ -1935,9 +1935,8 @@ void KeyedStoreIC::UpdateStoreElement(Handle<Map> receiver_map,
|
||||
return ConfigureVectorState(Handle<Name>(), monomorphic_map, handler);
|
||||
}
|
||||
|
||||
for (int i = 0; i < target_receiver_maps.length(); i++) {
|
||||
if (!target_receiver_maps.at(i).is_null() &&
|
||||
target_receiver_maps.at(i)->instance_type() == JS_VALUE_TYPE) {
|
||||
for (Handle<Map> map : target_receiver_maps) {
|
||||
if (!map.is_null() && map->instance_type() == JS_VALUE_TYPE) {
|
||||
TRACE_GENERIC_IC("JSValue");
|
||||
return;
|
||||
}
|
||||
@ -2002,7 +2001,7 @@ void KeyedStoreIC::UpdateStoreElement(Handle<Map> receiver_map,
|
||||
|
||||
// If the maximum number of receiver maps has been exceeded, use the
|
||||
// megamorphic version of the IC.
|
||||
if (target_receiver_maps.length() > kMaxKeyedPolymorphism) return;
|
||||
if (target_receiver_maps.size() > kMaxKeyedPolymorphism) return;
|
||||
|
||||
// Make sure all polymorphic handlers have the same store mode, otherwise the
|
||||
// megamorphic stub must be used.
|
||||
@ -2020,27 +2019,27 @@ void KeyedStoreIC::UpdateStoreElement(Handle<Map> receiver_map,
|
||||
// receivers are either external arrays, or all "normal" arrays. Otherwise,
|
||||
// use the megamorphic stub.
|
||||
if (store_mode != STANDARD_STORE) {
|
||||
int external_arrays = 0;
|
||||
for (int i = 0; i < target_receiver_maps.length(); ++i) {
|
||||
if (target_receiver_maps[i]->has_fixed_typed_array_elements()) {
|
||||
size_t external_arrays = 0;
|
||||
for (Handle<Map> map : target_receiver_maps) {
|
||||
if (map->has_fixed_typed_array_elements()) {
|
||||
external_arrays++;
|
||||
}
|
||||
}
|
||||
if (external_arrays != 0 &&
|
||||
external_arrays != target_receiver_maps.length()) {
|
||||
external_arrays != target_receiver_maps.size()) {
|
||||
TRACE_GENERIC_IC("unsupported combination of external and normal arrays");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
List<Handle<Object>> handlers(target_receiver_maps.length());
|
||||
List<Handle<Object>> handlers(static_cast<int>(target_receiver_maps.size()));
|
||||
StoreElementPolymorphicHandlers(&target_receiver_maps, &handlers, store_mode);
|
||||
DCHECK_LE(1, target_receiver_maps.length());
|
||||
if (target_receiver_maps.length() == 1) {
|
||||
ConfigureVectorState(Handle<Name>(), target_receiver_maps.at(0),
|
||||
DCHECK_LE(1, target_receiver_maps.size());
|
||||
if (target_receiver_maps.size() == 1) {
|
||||
ConfigureVectorState(Handle<Name>(), target_receiver_maps[0],
|
||||
handlers.at(0));
|
||||
} else {
|
||||
ConfigureVectorState(Handle<Name>(), &target_receiver_maps, &handlers);
|
||||
ConfigureVectorState(Handle<Name>(), target_receiver_maps, &handlers);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2106,21 +2105,21 @@ Handle<Object> KeyedStoreIC::StoreElementHandler(
|
||||
}
|
||||
|
||||
void KeyedStoreIC::StoreElementPolymorphicHandlers(
|
||||
MapHandleList* receiver_maps, List<Handle<Object>>* handlers,
|
||||
MapHandles* receiver_maps, List<Handle<Object>>* handlers,
|
||||
KeyedAccessStoreMode store_mode) {
|
||||
DCHECK(store_mode == STANDARD_STORE ||
|
||||
store_mode == STORE_AND_GROW_NO_TRANSITION ||
|
||||
store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS ||
|
||||
store_mode == STORE_NO_TRANSITION_HANDLE_COW);
|
||||
|
||||
for (int i = 0; i < receiver_maps->length(); ++i) {
|
||||
Handle<Map> receiver_map(receiver_maps->at(i));
|
||||
if (receiver_map->is_deprecated()) {
|
||||
// Filter out deprecated maps to ensure their instances get migrated.
|
||||
receiver_maps->Remove(i--);
|
||||
continue;
|
||||
}
|
||||
// Filter out deprecated maps to ensure their instances get migrated.
|
||||
receiver_maps->erase(
|
||||
std::remove_if(
|
||||
receiver_maps->begin(), receiver_maps->end(),
|
||||
[](const Handle<Map>& map) { return map->is_deprecated(); }),
|
||||
receiver_maps->end());
|
||||
|
||||
for (Handle<Map> receiver_map : *receiver_maps) {
|
||||
Handle<Object> handler;
|
||||
Handle<Map> transitioned_map;
|
||||
|
||||
@ -2134,7 +2133,7 @@ void KeyedStoreIC::StoreElementPolymorphicHandlers(
|
||||
} else {
|
||||
{
|
||||
Map* tmap =
|
||||
receiver_map->FindElementsKindTransitionedMap(receiver_maps);
|
||||
receiver_map->FindElementsKindTransitionedMap(*receiver_maps);
|
||||
if (tmap != nullptr) {
|
||||
if (receiver_map->is_stable()) {
|
||||
receiver_map->NotifyLeafMapLayoutChange();
|
||||
|
16
src/ic/ic.h
16
src/ic/ic.h
@ -96,7 +96,7 @@ class IC {
|
||||
void ConfigureVectorState(Handle<Name> name, Handle<Map> map,
|
||||
Handle<Object> handler);
|
||||
// Configure the vector for POLYMORPHIC.
|
||||
void ConfigureVectorState(Handle<Name> name, MapHandleList* maps,
|
||||
void ConfigureVectorState(Handle<Name> name, MapHandles const& maps,
|
||||
List<Handle<Object>>* handlers);
|
||||
|
||||
char TransitionMarkFromState(IC::State state);
|
||||
@ -164,16 +164,16 @@ class IC {
|
||||
}
|
||||
}
|
||||
|
||||
void TargetMaps(MapHandleList* list) {
|
||||
void TargetMaps(MapHandles* list) {
|
||||
FindTargetMaps();
|
||||
for (int i = 0; i < target_maps_.length(); i++) {
|
||||
list->Add(target_maps_.at(i));
|
||||
for (Handle<Map> map : target_maps_) {
|
||||
list->push_back(map);
|
||||
}
|
||||
}
|
||||
|
||||
Map* FirstTargetMap() {
|
||||
FindTargetMaps();
|
||||
return target_maps_.length() > 0 ? *target_maps_.at(0) : NULL;
|
||||
return !target_maps_.empty() ? *target_maps_[0] : NULL;
|
||||
}
|
||||
|
||||
Handle<FeedbackVector> vector() const { return nexus()->vector_handle(); }
|
||||
@ -223,7 +223,7 @@ class IC {
|
||||
MaybeHandle<Object> maybe_handler_;
|
||||
|
||||
ExtraICState extra_ic_state_;
|
||||
MapHandleList target_maps_;
|
||||
MapHandles target_maps_;
|
||||
bool target_maps_set_;
|
||||
|
||||
const char* slow_stub_reason_;
|
||||
@ -328,7 +328,7 @@ class KeyedLoadIC : public LoadIC {
|
||||
|
||||
Handle<Object> LoadElementHandler(Handle<Map> receiver_map);
|
||||
|
||||
void LoadElementPolymorphicHandlers(MapHandleList* receiver_maps,
|
||||
void LoadElementPolymorphicHandlers(MapHandles* receiver_maps,
|
||||
List<Handle<Object>>* handlers);
|
||||
};
|
||||
|
||||
@ -414,7 +414,7 @@ class KeyedStoreIC : public StoreIC {
|
||||
Handle<Object> StoreElementHandler(Handle<Map> receiver_map,
|
||||
KeyedAccessStoreMode store_mode);
|
||||
|
||||
void StoreElementPolymorphicHandlers(MapHandleList* receiver_maps,
|
||||
void StoreElementPolymorphicHandlers(MapHandles* receiver_maps,
|
||||
List<Handle<Object>>* handlers,
|
||||
KeyedAccessStoreMode store_mode);
|
||||
|
||||
|
@ -4832,16 +4832,15 @@ int AccessorInfo::AppendUnique(Handle<Object> descriptors,
|
||||
valid_descriptors);
|
||||
}
|
||||
|
||||
|
||||
static bool ContainsMap(MapHandleList* maps, Map* map) {
|
||||
static bool ContainsMap(MapHandles const& maps, Map* map) {
|
||||
DCHECK_NOT_NULL(map);
|
||||
for (int i = 0; i < maps->length(); ++i) {
|
||||
if (!maps->at(i).is_null() && *maps->at(i) == map) return true;
|
||||
for (Handle<Map> current : maps) {
|
||||
if (!current.is_null() && *current == map) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Map* Map::FindElementsKindTransitionedMap(MapHandleList* candidates) {
|
||||
Map* Map::FindElementsKindTransitionedMap(MapHandles const& candidates) {
|
||||
DisallowHeapAllocation no_allocation;
|
||||
DisallowDeoptimization no_deoptimization(GetIsolate());
|
||||
|
||||
|
@ -4442,6 +4442,7 @@ class DependentCode: public FixedArray {
|
||||
|
||||
class PrototypeInfo;
|
||||
|
||||
typedef std::vector<Handle<Map>> MapHandles;
|
||||
|
||||
// All heap objects have a Map that describes their structure.
|
||||
// A Map contains information about:
|
||||
@ -4964,7 +4965,7 @@ class Map: public HeapObject {
|
||||
// Returns the transitioned map for this map with the most generic
|
||||
// elements_kind that's found in |candidates|, or |nullptr| if no match is
|
||||
// found at all.
|
||||
Map* FindElementsKindTransitionedMap(MapHandleList* candidates);
|
||||
Map* FindElementsKindTransitionedMap(MapHandles const& candidates);
|
||||
|
||||
inline bool CanTransition();
|
||||
|
||||
|
@ -445,14 +445,14 @@ void TypeFeedbackOracle::CollectReceiverTypes(FeedbackSlot slot,
|
||||
|
||||
void TypeFeedbackOracle::CollectReceiverTypes(FeedbackNexus* nexus,
|
||||
SmallMapList* types) {
|
||||
MapHandleList maps;
|
||||
MapHandles maps;
|
||||
if (nexus->ExtractMaps(&maps) == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
types->Reserve(maps.length(), zone());
|
||||
for (int i = 0; i < maps.length(); i++) {
|
||||
types->AddMapIfMissing(maps.at(i), zone());
|
||||
types->Reserve(static_cast<int>(maps.size()), zone());
|
||||
for (Handle<Map> map : maps) {
|
||||
types->AddMapIfMissing(map, zone());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -349,9 +349,9 @@ TEST(VectorLoadICStates) {
|
||||
|
||||
CompileRun("f({ blarg: 3, torino: 10, foo: 2 })");
|
||||
CHECK_EQ(POLYMORPHIC, nexus.StateFromFeedback());
|
||||
MapHandleList maps;
|
||||
MapHandles maps;
|
||||
nexus.ExtractMaps(&maps);
|
||||
CHECK_EQ(4, maps.length());
|
||||
CHECK_EQ(4, maps.size());
|
||||
|
||||
// Finally driven megamorphic.
|
||||
CompileRun("f({ blarg: 3, gran: 3, torino: 10, foo: 2 })");
|
||||
@ -428,9 +428,9 @@ TEST(VectorLoadICOnSmi) {
|
||||
CompileRun("f(o)");
|
||||
CHECK_EQ(POLYMORPHIC, nexus.StateFromFeedback());
|
||||
|
||||
MapHandleList maps;
|
||||
MapHandles maps;
|
||||
nexus.ExtractMaps(&maps);
|
||||
CHECK_EQ(2, maps.length());
|
||||
CHECK_EQ(2, maps.size());
|
||||
|
||||
// One of the maps should be the o map.
|
||||
v8::MaybeLocal<v8::Value> v8_o =
|
||||
@ -439,8 +439,7 @@ TEST(VectorLoadICOnSmi) {
|
||||
Handle<JSObject>::cast(v8::Utils::OpenHandle(*v8_o.ToLocalChecked()));
|
||||
bool number_map_found = false;
|
||||
bool o_map_found = false;
|
||||
for (int i = 0; i < maps.length(); i++) {
|
||||
Handle<Map> current = maps[i];
|
||||
for (Handle<Map> current : maps) {
|
||||
if (*current == number_map)
|
||||
number_map_found = true;
|
||||
else if (*current == o->map())
|
||||
@ -451,9 +450,9 @@ TEST(VectorLoadICOnSmi) {
|
||||
// The degree of polymorphism doesn't change.
|
||||
CompileRun("f(100)");
|
||||
CHECK_EQ(POLYMORPHIC, nexus.StateFromFeedback());
|
||||
MapHandleList maps2;
|
||||
MapHandles maps2;
|
||||
nexus.ExtractMaps(&maps2);
|
||||
CHECK_EQ(2, maps2.length());
|
||||
CHECK_EQ(2, maps2.size());
|
||||
}
|
||||
|
||||
|
||||
|
@ -1768,9 +1768,9 @@ static void TestReconfigureElementsKind_GeneralizeField(
|
||||
// Ensure Map::FindElementsKindTransitionedMap() is able to find the
|
||||
// transitioned map.
|
||||
{
|
||||
MapHandleList map_list;
|
||||
map_list.Add(updated_map);
|
||||
Map* transitioned_map = map2->FindElementsKindTransitionedMap(&map_list);
|
||||
MapHandles map_list;
|
||||
map_list.push_back(updated_map);
|
||||
Map* transitioned_map = map2->FindElementsKindTransitionedMap(map_list);
|
||||
CHECK_EQ(*updated_map, transitioned_map);
|
||||
}
|
||||
}
|
||||
@ -1863,9 +1863,9 @@ static void TestReconfigureElementsKind_GeneralizeFieldTrivial(
|
||||
// Ensure Map::FindElementsKindTransitionedMap() is able to find the
|
||||
// transitioned map.
|
||||
{
|
||||
MapHandleList map_list;
|
||||
map_list.Add(updated_map);
|
||||
Map* transitioned_map = map2->FindElementsKindTransitionedMap(&map_list);
|
||||
MapHandles map_list;
|
||||
map_list.push_back(updated_map);
|
||||
Map* transitioned_map = map2->FindElementsKindTransitionedMap(map_list);
|
||||
CHECK_EQ(*updated_map, transitioned_map);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user