blob: 1e1a59d7843e7d1c7fc0cf0a6cab5a95b0194e13 [file] [log] [blame]
// Copyright 2019 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/compiler/map-inference.h"
#include "src/compiler/compilation-dependencies.h"
#include "src/compiler/feedback-source.h"
#include "src/compiler/js-graph.h"
#include "src/compiler/simplified-operator.h"
#include "src/objects/map-inl.h"
#include "src/zone/zone-handle-set.h"
namespace v8 {
namespace internal {
namespace compiler {
MapInference::MapInference(JSHeapBroker* broker, Node* object, Node* effect)
: broker_(broker), object_(object) {
ZoneHandleSet<Map> maps;
auto result =
NodeProperties::InferMapsUnsafe(broker_, object_, effect, &maps);
maps_.insert(maps_.end(), maps.begin(), maps.end());
maps_state_ = (result == NodeProperties::kUnreliableMaps)
? kUnreliableDontNeedGuard
: kReliableOrGuarded;
DCHECK_EQ(maps_.empty(), result == NodeProperties::kNoMaps);
}
MapInference::~MapInference() { CHECK(Safe()); }
bool MapInference::Safe() const { return maps_state_ != kUnreliableNeedGuard; }
void MapInference::SetNeedGuardIfUnreliable() {
CHECK(HaveMaps());
if (maps_state_ == kUnreliableDontNeedGuard) {
maps_state_ = kUnreliableNeedGuard;
}
}
void MapInference::SetGuarded() { maps_state_ = kReliableOrGuarded; }
bool MapInference::HaveMaps() const { return !maps_.empty(); }
bool MapInference::AllOfInstanceTypesAreJSReceiver() const {
return AllOfInstanceTypesUnsafe(InstanceTypeChecker::IsJSReceiver);
}
bool MapInference::AllOfInstanceTypesAre(InstanceType type) const {
CHECK(!InstanceTypeChecker::IsString(type));
return AllOfInstanceTypesUnsafe(
[type](InstanceType other) { return type == other; });
}
bool MapInference::AnyOfInstanceTypesAre(InstanceType type) const {
CHECK(!InstanceTypeChecker::IsString(type));
return AnyOfInstanceTypesUnsafe(
[type](InstanceType other) { return type == other; });
}
bool MapInference::AllOfInstanceTypes(std::function<bool(InstanceType)> f) {
SetNeedGuardIfUnreliable();
return AllOfInstanceTypesUnsafe(f);
}
bool MapInference::AllOfInstanceTypesUnsafe(
std::function<bool(InstanceType)> f) const {
CHECK(HaveMaps());
auto instance_type = [this, f](Handle<Map> map) {
MapRef map_ref(broker_, map);
return f(map_ref.instance_type());
};
return std::all_of(maps_.begin(), maps_.end(), instance_type);
}
bool MapInference::AnyOfInstanceTypesUnsafe(
std::function<bool(InstanceType)> f) const {
CHECK(HaveMaps());
auto instance_type = [this, f](Handle<Map> map) {
MapRef map_ref(broker_, map);
return f(map_ref.instance_type());
};
return std::any_of(maps_.begin(), maps_.end(), instance_type);
}
MapHandles const& MapInference::GetMaps() {
SetNeedGuardIfUnreliable();
return maps_;
}
bool MapInference::Is(Handle<Map> expected_map) {
if (!HaveMaps()) return false;
const MapHandles& maps = GetMaps();
if (maps.size() != 1) return false;
return maps[0].equals(expected_map);
}
void MapInference::InsertMapChecks(JSGraph* jsgraph, Effect* effect,
Control control,
const FeedbackSource& feedback) {
CHECK(HaveMaps());
CHECK(feedback.IsValid());
ZoneHandleSet<Map> maps;
for (Handle<Map> map : maps_) maps.insert(map, jsgraph->graph()->zone());
*effect = jsgraph->graph()->NewNode(
jsgraph->simplified()->CheckMaps(CheckMapsFlag::kNone, maps, feedback),
object_, *effect, control);
SetGuarded();
}
bool MapInference::RelyOnMapsViaStability(
CompilationDependencies* dependencies) {
CHECK(HaveMaps());
return RelyOnMapsHelper(dependencies, nullptr, nullptr, Control{nullptr}, {});
}
bool MapInference::RelyOnMapsPreferStability(
CompilationDependencies* dependencies, JSGraph* jsgraph, Effect* effect,
Control control, const FeedbackSource& feedback) {
CHECK(HaveMaps());
if (Safe()) return false;
if (RelyOnMapsViaStability(dependencies)) return true;
CHECK(RelyOnMapsHelper(nullptr, jsgraph, effect, control, feedback));
return false;
}
bool MapInference::RelyOnMapsHelper(CompilationDependencies* dependencies,
JSGraph* jsgraph, Effect* effect,
Control control,
const FeedbackSource& feedback) {
if (Safe()) return true;
auto is_stable = [this](Handle<Map> map) {
MapRef map_ref(broker_, map);
return map_ref.is_stable();
};
if (dependencies != nullptr &&
std::all_of(maps_.cbegin(), maps_.cend(), is_stable)) {
for (Handle<Map> map : maps_) {
dependencies->DependOnStableMap(MapRef(broker_, map));
}
SetGuarded();
return true;
} else if (feedback.IsValid()) {
InsertMapChecks(jsgraph, effect, control, feedback);
return true;
} else {
return false;
}
}
Reduction MapInference::NoChange() {
SetGuarded();
maps_.clear(); // Just to make some CHECKs fail if {this} gets used after.
return Reducer::NoChange();
}
} // namespace compiler
} // namespace internal
} // namespace v8