[turbofan] Move MapInference into its own files
Bug: v8:9197 Change-Id: If72dbf1507f68fa344db389c08ad8614bca6667e Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1593337 Auto-Submit: Georg Neis <neis@chromium.org> Reviewed-by: Jaroslav Sevcik <jarin@chromium.org> Commit-Queue: Georg Neis <neis@chromium.org> Cr-Commit-Position: refs/heads/master@{#61199}
This commit is contained in:
parent
b09146832c
commit
3460e02064
2
BUILD.gn
2
BUILD.gn
@ -1811,6 +1811,8 @@ v8_compiler_sources = [
|
||||
"src/compiler/machine-operator-reducer.h",
|
||||
"src/compiler/machine-operator.cc",
|
||||
"src/compiler/machine-operator.h",
|
||||
"src/compiler/map-inference.cc",
|
||||
"src/compiler/map-inference.h",
|
||||
"src/compiler/memory-optimizer.cc",
|
||||
"src/compiler/memory-optimizer.h",
|
||||
"src/compiler/node-aux-data.h",
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include "src/compiler/compilation-dependencies.h"
|
||||
#include "src/compiler/js-graph.h"
|
||||
#include "src/compiler/linkage.h"
|
||||
#include "src/compiler/map-inference.h"
|
||||
#include "src/compiler/node-matchers.h"
|
||||
#include "src/compiler/property-access-builder.h"
|
||||
#include "src/compiler/simplified-operator.h"
|
||||
@ -35,193 +36,6 @@ namespace v8 {
|
||||
namespace internal {
|
||||
namespace compiler {
|
||||
|
||||
// The MapInference class provides access to the "inferred" maps of an
|
||||
// {object}. This information can be either "reliable", meaning that the object
|
||||
// is guaranteed to have one of these maps at runtime, or "unreliable", meaning
|
||||
// that the object is guaranteed to have HAD one of these maps.
|
||||
//
|
||||
// The MapInference class does not expose whether or not the information is
|
||||
// reliable. A client is expected to eventually make the information reliable by
|
||||
// calling one of several methods that will either insert map checks, or record
|
||||
// stability dependencies (or do nothing if the information was already
|
||||
// reliable).
|
||||
class MapInference {
|
||||
public:
|
||||
MapInference(JSHeapBroker* broker, Node* object, Node* effect);
|
||||
|
||||
// The destructor checks that the information has been made reliable (if
|
||||
// necessary) and force-crashes if not.
|
||||
~MapInference();
|
||||
|
||||
// Is there any information at all?
|
||||
V8_WARN_UNUSED_RESULT bool HaveMaps() const;
|
||||
|
||||
// These queries don't require a guard.
|
||||
//
|
||||
V8_WARN_UNUSED_RESULT bool AllOfInstanceTypesAreJSReceiver() const;
|
||||
// Here, {type} must not be a String type.
|
||||
V8_WARN_UNUSED_RESULT bool AllOfInstanceTypesAre(InstanceType type) const;
|
||||
|
||||
// These queries require a guard. (Even instance types are generally not
|
||||
// reliable because of how the representation of a string can change.)
|
||||
V8_WARN_UNUSED_RESULT MapHandles const& GetMaps();
|
||||
V8_WARN_UNUSED_RESULT bool AllOfInstanceTypes(
|
||||
std::function<bool(InstanceType)> f);
|
||||
|
||||
// These methods provide a guard.
|
||||
//
|
||||
// Returns true iff maps were already reliable or stability dependencies were
|
||||
// successfully recorded.
|
||||
V8_WARN_UNUSED_RESULT bool RelyOnMapsViaStability(
|
||||
CompilationDependencies* dependencies);
|
||||
// Records stability dependencies if possible, otherwise it inserts map
|
||||
// checks. Does nothing if maps were already reliable. Returns true iff
|
||||
// dependencies were taken.
|
||||
bool RelyOnMapsPreferStability(CompilationDependencies* dependencies,
|
||||
JSGraph* jsgraph, Node** effect, Node* control,
|
||||
const VectorSlotPair& feedback);
|
||||
// Inserts map checks even if maps were already reliable.
|
||||
void InsertMapChecks(JSGraph* jsgraph, Node** effect, Node* control,
|
||||
const VectorSlotPair& feedback);
|
||||
|
||||
// Internally marks the maps as reliable (thus bypassing the safety check) and
|
||||
// returns the NoChange reduction. USE THIS ONLY WHEN RETURNING, e.g.:
|
||||
// if (foo) return inference.NoChange();
|
||||
V8_WARN_UNUSED_RESULT Reduction NoChange();
|
||||
|
||||
private:
|
||||
JSHeapBroker* const broker_;
|
||||
Node* const object_;
|
||||
|
||||
MapHandles maps_;
|
||||
enum {
|
||||
kReliableOrGuarded,
|
||||
kUnreliableDontNeedGuard,
|
||||
kUnreliableNeedGuard
|
||||
} maps_state_;
|
||||
|
||||
bool Safe() const;
|
||||
void SetNeedGuardIfUnreliable();
|
||||
void SetGuarded();
|
||||
|
||||
V8_WARN_UNUSED_RESULT bool AllOfInstanceTypesUnsafe(
|
||||
std::function<bool(InstanceType)> f) const;
|
||||
V8_WARN_UNUSED_RESULT bool RelyOnMapsHelper(
|
||||
CompilationDependencies* dependencies, JSGraph* jsgraph, Node** effect,
|
||||
Node* control, const VectorSlotPair& feedback);
|
||||
};
|
||||
|
||||
MapInference::MapInference(JSHeapBroker* broker, Node* object, Node* effect)
|
||||
: broker_(broker), object_(object) {
|
||||
ZoneHandleSet<Map> maps;
|
||||
auto result =
|
||||
NodeProperties::InferReceiverMaps(broker_, object_, effect, &maps);
|
||||
maps_.insert(maps_.end(), maps.begin(), maps.end());
|
||||
maps_state_ = (result == NodeProperties::kUnreliableReceiverMaps)
|
||||
? kUnreliableDontNeedGuard
|
||||
: kReliableOrGuarded;
|
||||
DCHECK_EQ(maps_.empty(), result == NodeProperties::kNoReceiverMaps);
|
||||
}
|
||||
|
||||
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; }
|
||||
|
||||
MapInference::~MapInference() { CHECK(Safe()); }
|
||||
|
||||
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::AllOfInstanceTypes(std::function<bool(InstanceType)> f) {
|
||||
SetNeedGuardIfUnreliable();
|
||||
return AllOfInstanceTypesUnsafe(f);
|
||||
}
|
||||
|
||||
bool MapInference::AllOfInstanceTypesUnsafe(
|
||||
std::function<bool(InstanceType)> f) const {
|
||||
CHECK(HaveMaps());
|
||||
return std::all_of(maps_.begin(), maps_.end(),
|
||||
[f](Handle<Map> map) { return f(map->instance_type()); });
|
||||
}
|
||||
|
||||
MapHandles const& MapInference::GetMaps() {
|
||||
SetNeedGuardIfUnreliable();
|
||||
return maps_;
|
||||
}
|
||||
|
||||
void MapInference::InsertMapChecks(JSGraph* jsgraph, Node** effect,
|
||||
Node* control,
|
||||
const VectorSlotPair& 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, nullptr, {});
|
||||
}
|
||||
|
||||
bool MapInference::RelyOnMapsPreferStability(
|
||||
CompilationDependencies* dependencies, JSGraph* jsgraph, Node** effect,
|
||||
Node* control, const VectorSlotPair& 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, Node** effect,
|
||||
Node* control,
|
||||
const VectorSlotPair& feedback) {
|
||||
if (Safe()) return true;
|
||||
|
||||
auto is_stable = [](Handle<Map> map) { return map->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();
|
||||
}
|
||||
|
||||
Reduction JSCallReducer::ReduceMathUnary(Node* node, const Operator* op) {
|
||||
CallParameters const& p = CallParametersOf(node->op());
|
||||
if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
|
||||
|
131
src/compiler/map-inference.cc
Normal file
131
src/compiler/map-inference.cc
Normal file
@ -0,0 +1,131 @@
|
||||
// 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/js-graph.h"
|
||||
#include "src/compiler/simplified-operator.h"
|
||||
#include "src/objects/map-inl.h"
|
||||
#include "src/vector-slot-pair.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::InferReceiverMaps(broker_, object_, effect, &maps);
|
||||
maps_.insert(maps_.end(), maps.begin(), maps.end());
|
||||
maps_state_ = (result == NodeProperties::kUnreliableReceiverMaps)
|
||||
? kUnreliableDontNeedGuard
|
||||
: kReliableOrGuarded;
|
||||
DCHECK_EQ(maps_.empty(), result == NodeProperties::kNoReceiverMaps);
|
||||
}
|
||||
|
||||
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::AllOfInstanceTypes(std::function<bool(InstanceType)> f) {
|
||||
SetNeedGuardIfUnreliable();
|
||||
return AllOfInstanceTypesUnsafe(f);
|
||||
}
|
||||
|
||||
bool MapInference::AllOfInstanceTypesUnsafe(
|
||||
std::function<bool(InstanceType)> f) const {
|
||||
CHECK(HaveMaps());
|
||||
return std::all_of(maps_.begin(), maps_.end(),
|
||||
[f](Handle<Map> map) { return f(map->instance_type()); });
|
||||
}
|
||||
|
||||
MapHandles const& MapInference::GetMaps() {
|
||||
SetNeedGuardIfUnreliable();
|
||||
return maps_;
|
||||
}
|
||||
|
||||
void MapInference::InsertMapChecks(JSGraph* jsgraph, Node** effect,
|
||||
Node* control,
|
||||
const VectorSlotPair& 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, nullptr, {});
|
||||
}
|
||||
|
||||
bool MapInference::RelyOnMapsPreferStability(
|
||||
CompilationDependencies* dependencies, JSGraph* jsgraph, Node** effect,
|
||||
Node* control, const VectorSlotPair& 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, Node** effect,
|
||||
Node* control,
|
||||
const VectorSlotPair& feedback) {
|
||||
if (Safe()) return true;
|
||||
|
||||
auto is_stable = [](Handle<Map> map) { return map->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
|
105
src/compiler/map-inference.h
Normal file
105
src/compiler/map-inference.h
Normal file
@ -0,0 +1,105 @@
|
||||
// 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.
|
||||
|
||||
#ifndef V8_COMPILER_MAP_INFERENCE_H_
|
||||
#define V8_COMPILER_MAP_INFERENCE_H_
|
||||
|
||||
#include "include/v8config.h"
|
||||
#include "src/compiler/graph-reducer.h"
|
||||
#include "src/objects/instance-type.h"
|
||||
#include "src/objects/map.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
class VectorSlotPair;
|
||||
|
||||
namespace compiler {
|
||||
|
||||
class CompilationDependencies;
|
||||
class JSGraph;
|
||||
class JSHeapBroker;
|
||||
class Node;
|
||||
|
||||
// The MapInference class provides access to the "inferred" maps of an
|
||||
// {object}. This information can be either "reliable", meaning that the object
|
||||
// is guaranteed to have one of these maps at runtime, or "unreliable", meaning
|
||||
// that the object is guaranteed to have HAD one of these maps.
|
||||
//
|
||||
// The MapInference class does not expose whether or not the information is
|
||||
// reliable. A client is expected to eventually make the information reliable by
|
||||
// calling one of several methods that will either insert map checks, or record
|
||||
// stability dependencies (or do nothing if the information was already
|
||||
// reliable).
|
||||
class MapInference {
|
||||
public:
|
||||
MapInference(JSHeapBroker* broker, Node* object, Node* effect);
|
||||
|
||||
// The destructor checks that the information has been made reliable (if
|
||||
// necessary) and force-crashes if not.
|
||||
~MapInference();
|
||||
|
||||
// Is there any information at all?
|
||||
V8_WARN_UNUSED_RESULT bool HaveMaps() const;
|
||||
|
||||
// These queries don't require a guard.
|
||||
//
|
||||
V8_WARN_UNUSED_RESULT bool AllOfInstanceTypesAreJSReceiver() const;
|
||||
// Here, {type} must not be a String type.
|
||||
V8_WARN_UNUSED_RESULT bool AllOfInstanceTypesAre(InstanceType type) const;
|
||||
|
||||
// These queries require a guard. (Even instance types are generally not
|
||||
// reliable because of how the representation of a string can change.)
|
||||
V8_WARN_UNUSED_RESULT MapHandles const& GetMaps();
|
||||
V8_WARN_UNUSED_RESULT bool AllOfInstanceTypes(
|
||||
std::function<bool(InstanceType)> f);
|
||||
|
||||
// These methods provide a guard.
|
||||
//
|
||||
// Returns true iff maps were already reliable or stability dependencies were
|
||||
// successfully recorded.
|
||||
V8_WARN_UNUSED_RESULT bool RelyOnMapsViaStability(
|
||||
CompilationDependencies* dependencies);
|
||||
// Records stability dependencies if possible, otherwise it inserts map
|
||||
// checks. Does nothing if maps were already reliable. Returns true iff
|
||||
// dependencies were taken.
|
||||
bool RelyOnMapsPreferStability(CompilationDependencies* dependencies,
|
||||
JSGraph* jsgraph, Node** effect, Node* control,
|
||||
const VectorSlotPair& feedback);
|
||||
// Inserts map checks even if maps were already reliable.
|
||||
void InsertMapChecks(JSGraph* jsgraph, Node** effect, Node* control,
|
||||
const VectorSlotPair& feedback);
|
||||
|
||||
// Internally marks the maps as reliable (thus bypassing the safety check) and
|
||||
// returns the NoChange reduction. USE THIS ONLY WHEN RETURNING, e.g.:
|
||||
// if (foo) return inference.NoChange();
|
||||
V8_WARN_UNUSED_RESULT Reduction NoChange();
|
||||
|
||||
private:
|
||||
JSHeapBroker* const broker_;
|
||||
Node* const object_;
|
||||
|
||||
MapHandles maps_;
|
||||
enum {
|
||||
kReliableOrGuarded,
|
||||
kUnreliableDontNeedGuard,
|
||||
kUnreliableNeedGuard
|
||||
} maps_state_;
|
||||
|
||||
bool Safe() const;
|
||||
void SetNeedGuardIfUnreliable();
|
||||
void SetGuarded();
|
||||
|
||||
V8_WARN_UNUSED_RESULT bool AllOfInstanceTypesUnsafe(
|
||||
std::function<bool(InstanceType)> f) const;
|
||||
V8_WARN_UNUSED_RESULT bool RelyOnMapsHelper(
|
||||
CompilationDependencies* dependencies, JSGraph* jsgraph, Node** effect,
|
||||
Node* control, const VectorSlotPair& feedback);
|
||||
};
|
||||
|
||||
} // namespace compiler
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
||||
#endif // V8_COMPILER_MAP_INFERENCE_H_
|
Loading…
Reference in New Issue
Block a user