map-inference.cc 4.97 KB
Newer Older
1 2 3 4 5 6 7
// 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"
8
#include "src/compiler/feedback-source.h"
9 10 11 12 13 14 15 16
#include "src/compiler/js-graph.h"
#include "src/compiler/simplified-operator.h"
#include "src/objects/map-inl.h"

namespace v8 {
namespace internal {
namespace compiler {

17 18 19
MapInference::MapInference(JSHeapBroker* broker, Node* object, Effect effect)
    : broker_(broker), object_(object), maps_(broker->zone()) {
  ZoneRefUnorderedSet<MapRef> maps(broker->zone());
20
  auto result =
21
      NodeProperties::InferMapsUnsafe(broker_, object_, effect, &maps);
22
  maps_.insert(maps_.end(), maps.begin(), maps.end());
23
  maps_state_ = (result == NodeProperties::kUnreliableMaps)
24 25
                    ? kUnreliableDontNeedGuard
                    : kReliableOrGuarded;
26
  DCHECK_EQ(maps_.empty(), result == NodeProperties::kNoMaps);
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
}

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; });
}

54 55 56 57 58 59
bool MapInference::AnyOfInstanceTypesAre(InstanceType type) const {
  CHECK(!InstanceTypeChecker::IsString(type));
  return AnyOfInstanceTypesUnsafe(
      [type](InstanceType other) { return type == other; });
}

60 61 62 63 64 65 66 67
bool MapInference::AllOfInstanceTypes(std::function<bool(InstanceType)> f) {
  SetNeedGuardIfUnreliable();
  return AllOfInstanceTypesUnsafe(f);
}

bool MapInference::AllOfInstanceTypesUnsafe(
    std::function<bool(InstanceType)> f) const {
  CHECK(HaveMaps());
68

69 70
  auto instance_type = [f](const MapRef& map) {
    return f(map.instance_type());
71 72
  };
  return std::all_of(maps_.begin(), maps_.end(), instance_type);
73 74
}

75 76 77
bool MapInference::AnyOfInstanceTypesUnsafe(
    std::function<bool(InstanceType)> f) const {
  CHECK(HaveMaps());
78

79 80
  auto instance_type = [f](const MapRef& map) {
    return f(map.instance_type());
81 82 83
  };

  return std::any_of(maps_.begin(), maps_.end(), instance_type);
84 85
}

86
ZoneVector<MapRef> const& MapInference::GetMaps() {
87 88 89 90
  SetNeedGuardIfUnreliable();
  return maps_;
}

91
bool MapInference::Is(const MapRef& expected_map) {
92
  if (!HaveMaps()) return false;
93
  const ZoneVector<MapRef>& maps = GetMaps();
94 95 96 97
  if (maps.size() != 1) return false;
  return maps[0].equals(expected_map);
}

98 99
void MapInference::InsertMapChecks(JSGraph* jsgraph, Effect* effect,
                                   Control control,
100
                                   const FeedbackSource& feedback) {
101 102 103
  CHECK(HaveMaps());
  CHECK(feedback.IsValid());
  ZoneHandleSet<Map> maps;
104 105 106
  for (const MapRef& map : maps_) {
    maps.insert(map.object(), jsgraph->graph()->zone());
  }
107 108 109 110 111 112 113 114 115
  *effect = jsgraph->graph()->NewNode(
      jsgraph->simplified()->CheckMaps(CheckMapsFlag::kNone, maps, feedback),
      object_, *effect, control);
  SetGuarded();
}

bool MapInference::RelyOnMapsViaStability(
    CompilationDependencies* dependencies) {
  CHECK(HaveMaps());
116
  return RelyOnMapsHelper(dependencies, nullptr, nullptr, Control{nullptr}, {});
117 118 119
}

bool MapInference::RelyOnMapsPreferStability(
120 121
    CompilationDependencies* dependencies, JSGraph* jsgraph, Effect* effect,
    Control control, const FeedbackSource& feedback) {
122 123 124
  CHECK(HaveMaps());
  if (Safe()) return false;
  if (RelyOnMapsViaStability(dependencies)) return true;
125
  CHECK(RelyOnMapsHelper(nullptr, jsgraph, effect, control, feedback));
126 127 128 129
  return false;
}

bool MapInference::RelyOnMapsHelper(CompilationDependencies* dependencies,
130 131
                                    JSGraph* jsgraph, Effect* effect,
                                    Control control,
132
                                    const FeedbackSource& feedback) {
133 134
  if (Safe()) return true;

135
  auto is_stable = [](const MapRef& map) { return map.is_stable(); };
136 137
  if (dependencies != nullptr &&
      std::all_of(maps_.cbegin(), maps_.cend(), is_stable)) {
138 139
    for (const MapRef& map : maps_) {
      dependencies->DependOnStableMap(map);
140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
    }
    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