// Copyright 2015 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/compilation-dependencies.h"

#include "src/compiler/compilation-dependency.h"
#include "src/execution/protectors.h"
#include "src/handles/handles-inl.h"
#include "src/objects/allocation-site-inl.h"
#include "src/objects/js-function-inl.h"
#include "src/objects/objects-inl.h"
#include "src/zone/zone-handle-set.h"

namespace v8 {
namespace internal {
namespace compiler {

CompilationDependencies::CompilationDependencies(JSHeapBroker* broker,
                                                 Zone* zone)
    : zone_(zone), broker_(broker), dependencies_(zone) {}

class InitialMapDependency final : public CompilationDependency {
 public:
  // TODO(neis): Once the concurrent compiler frontend is always-on, we no
  // longer need to explicitly store the initial map.
  InitialMapDependency(const JSFunctionRef& function, const MapRef& initial_map)
      : function_(function), initial_map_(initial_map) {
    DCHECK(function_.has_initial_map());
    DCHECK(function_.initial_map().equals(initial_map_));
  }

  bool IsValid() const override {
    Handle<JSFunction> function = function_.object();
    return function->has_initial_map() &&
           function->initial_map() == *initial_map_.object();
  }

  void Install(const MaybeObjectHandle& code) const override {
    SLOW_DCHECK(IsValid());
    DependentCode::InstallDependency(function_.isolate(), code,
                                     initial_map_.object(),
                                     DependentCode::kInitialMapChangedGroup);
  }

 private:
  JSFunctionRef function_;
  MapRef initial_map_;
};

class PrototypePropertyDependency final : public CompilationDependency {
 public:
  // TODO(neis): Once the concurrent compiler frontend is always-on, we no
  // longer need to explicitly store the prototype.
  PrototypePropertyDependency(const JSFunctionRef& function,
                              const ObjectRef& prototype)
      : function_(function), prototype_(prototype) {
    DCHECK(function_.has_prototype());
    DCHECK(!function_.PrototypeRequiresRuntimeLookup());
    DCHECK(function_.prototype().equals(prototype_));
  }

  bool IsValid() const override {
    Handle<JSFunction> function = function_.object();
    return function->has_prototype_slot() && function->has_prototype() &&
           !function->PrototypeRequiresRuntimeLookup() &&
           function->prototype() == *prototype_.object();
  }

  void PrepareInstall() const override {
    SLOW_DCHECK(IsValid());
    Handle<JSFunction> function = function_.object();
    if (!function->has_initial_map()) JSFunction::EnsureHasInitialMap(function);
  }

  void Install(const MaybeObjectHandle& code) const override {
    SLOW_DCHECK(IsValid());
    Handle<JSFunction> function = function_.object();
    DCHECK(function->has_initial_map());
    Handle<Map> initial_map(function->initial_map(), function_.isolate());
    DependentCode::InstallDependency(function_.isolate(), code, initial_map,
                                     DependentCode::kInitialMapChangedGroup);
  }

 private:
  JSFunctionRef function_;
  ObjectRef prototype_;
};

class StableMapDependency final : public CompilationDependency {
 public:
  explicit StableMapDependency(const MapRef& map) : map_(map) {
    DCHECK(map_.is_stable());
  }

  bool IsValid() const override { return map_.object()->is_stable(); }

  void Install(const MaybeObjectHandle& code) const override {
    SLOW_DCHECK(IsValid());
    DependentCode::InstallDependency(map_.isolate(), code, map_.object(),
                                     DependentCode::kPrototypeCheckGroup);
  }

 private:
  MapRef map_;
};

class TransitionDependency final : public CompilationDependency {
 public:
  explicit TransitionDependency(const MapRef& map) : map_(map) {
    DCHECK(!map_.is_deprecated());
  }

  bool IsValid() const override { return !map_.object()->is_deprecated(); }

  void Install(const MaybeObjectHandle& code) const override {
    SLOW_DCHECK(IsValid());
    DependentCode::InstallDependency(map_.isolate(), code, map_.object(),
                                     DependentCode::kTransitionGroup);
  }

 private:
  MapRef map_;
};

class PretenureModeDependency final : public CompilationDependency {
 public:
  // TODO(neis): Once the concurrent compiler frontend is always-on, we no
  // longer need to explicitly store the mode.
  PretenureModeDependency(const AllocationSiteRef& site,
                          AllocationType allocation)
      : site_(site), allocation_(allocation) {
    DCHECK_EQ(allocation, site_.GetAllocationType());
  }

  bool IsValid() const override {
    return allocation_ == site_.object()->GetAllocationType();
  }

  void Install(const MaybeObjectHandle& code) const override {
    SLOW_DCHECK(IsValid());
    DependentCode::InstallDependency(
        site_.isolate(), code, site_.object(),
        DependentCode::kAllocationSiteTenuringChangedGroup);
  }

#ifdef DEBUG
  bool IsPretenureModeDependency() const override { return true; }
#endif

 private:
  AllocationSiteRef site_;
  AllocationType allocation_;
};

class FieldRepresentationDependency final : public CompilationDependency {
 public:
  // TODO(neis): Once the concurrent compiler frontend is always-on, we no
  // longer need to explicitly store the representation.
  FieldRepresentationDependency(const MapRef& owner, InternalIndex descriptor,
                                Representation representation)
      : owner_(owner),
        descriptor_(descriptor),
        representation_(representation) {
    DCHECK(owner_.equals(owner_.FindFieldOwner(descriptor_)));
    DCHECK(representation_.Equals(
        owner_.GetPropertyDetails(descriptor_).representation()));
  }

  bool IsValid() const override {
    DisallowHeapAllocation no_heap_allocation;
    Handle<Map> owner = owner_.object();
    return representation_.Equals(owner->instance_descriptors(kRelaxedLoad)
                                      .GetDetails(descriptor_)
                                      .representation());
  }

  void Install(const MaybeObjectHandle& code) const override {
    SLOW_DCHECK(IsValid());
    DependentCode::InstallDependency(owner_.isolate(), code, owner_.object(),
                                     DependentCode::kFieldRepresentationGroup);
  }

#ifdef DEBUG
  bool IsFieldRepresentationDependencyOnMap(
      Handle<Map> const& receiver_map) const override {
    return owner_.object().equals(receiver_map);
  }
#endif

 private:
  MapRef owner_;
  InternalIndex descriptor_;
  Representation representation_;
};

class FieldTypeDependency final : public CompilationDependency {
 public:
  // TODO(neis): Once the concurrent compiler frontend is always-on, we no
  // longer need to explicitly store the type.
  FieldTypeDependency(const MapRef& owner, InternalIndex descriptor,
                      const ObjectRef& type)
      : owner_(owner), descriptor_(descriptor), type_(type) {
    DCHECK(owner_.equals(owner_.FindFieldOwner(descriptor_)));
    DCHECK(type_.equals(owner_.GetFieldType(descriptor_)));
  }

  bool IsValid() const override {
    DisallowHeapAllocation no_heap_allocation;
    Handle<Map> owner = owner_.object();
    Handle<Object> type = type_.object();
    return *type ==
           owner->instance_descriptors(kRelaxedLoad).GetFieldType(descriptor_);
  }

  void Install(const MaybeObjectHandle& code) const override {
    SLOW_DCHECK(IsValid());
    DependentCode::InstallDependency(owner_.isolate(), code, owner_.object(),
                                     DependentCode::kFieldTypeGroup);
  }

 private:
  MapRef owner_;
  InternalIndex descriptor_;
  ObjectRef type_;
};

class FieldConstnessDependency final : public CompilationDependency {
 public:
  FieldConstnessDependency(const MapRef& owner, InternalIndex descriptor)
      : owner_(owner), descriptor_(descriptor) {
    DCHECK(owner_.equals(owner_.FindFieldOwner(descriptor_)));
    DCHECK_EQ(PropertyConstness::kConst,
              owner_.GetPropertyDetails(descriptor_).constness());
  }

  bool IsValid() const override {
    DisallowHeapAllocation no_heap_allocation;
    Handle<Map> owner = owner_.object();
    return PropertyConstness::kConst ==
           owner->instance_descriptors(kRelaxedLoad)
               .GetDetails(descriptor_)
               .constness();
  }

  void Install(const MaybeObjectHandle& code) const override {
    SLOW_DCHECK(IsValid());
    DependentCode::InstallDependency(owner_.isolate(), code, owner_.object(),
                                     DependentCode::kFieldConstGroup);
  }

 private:
  MapRef owner_;
  InternalIndex descriptor_;
};

class GlobalPropertyDependency final : public CompilationDependency {
 public:
  // TODO(neis): Once the concurrent compiler frontend is always-on, we no
  // longer need to explicitly store the type and the read_only flag.
  GlobalPropertyDependency(const PropertyCellRef& cell, PropertyCellType type,
                           bool read_only)
      : cell_(cell), type_(type), read_only_(read_only) {
    DCHECK_EQ(type_, cell_.property_details().cell_type());
    DCHECK_EQ(read_only_, cell_.property_details().IsReadOnly());
  }

  bool IsValid() const override {
    Handle<PropertyCell> cell = cell_.object();
    // The dependency is never valid if the cell is 'invalidated'. This is
    // marked by setting the value to the hole.
    if (cell->value() == *(cell_.isolate()->factory()->the_hole_value())) {
      DCHECK(cell->property_details().cell_type() ==
                 PropertyCellType::kInvalidated ||
             cell->property_details().cell_type() ==
                 PropertyCellType::kUninitialized);
      return false;
    }
    return type_ == cell->property_details().cell_type() &&
           read_only_ == cell->property_details().IsReadOnly();
  }

  void Install(const MaybeObjectHandle& code) const override {
    SLOW_DCHECK(IsValid());
    DependentCode::InstallDependency(cell_.isolate(), code, cell_.object(),
                                     DependentCode::kPropertyCellChangedGroup);
  }

 private:
  PropertyCellRef cell_;
  PropertyCellType type_;
  bool read_only_;
};

class ProtectorDependency final : public CompilationDependency {
 public:
  explicit ProtectorDependency(const PropertyCellRef& cell) : cell_(cell) {
    DCHECK_EQ(cell_.value().AsSmi(), Protectors::kProtectorValid);
  }

  bool IsValid() const override {
    Handle<PropertyCell> cell = cell_.object();
    return cell->value() == Smi::FromInt(Protectors::kProtectorValid);
  }

  void Install(const MaybeObjectHandle& code) const override {
    SLOW_DCHECK(IsValid());
    DependentCode::InstallDependency(cell_.isolate(), code, cell_.object(),
                                     DependentCode::kPropertyCellChangedGroup);
  }

 private:
  PropertyCellRef cell_;
};

class ElementsKindDependency final : public CompilationDependency {
 public:
  // TODO(neis): Once the concurrent compiler frontend is always-on, we no
  // longer need to explicitly store the elements kind.
  ElementsKindDependency(const AllocationSiteRef& site, ElementsKind kind)
      : site_(site), kind_(kind) {
    DCHECK(AllocationSite::ShouldTrack(kind_));
    DCHECK_EQ(kind_, site_.PointsToLiteral()
                         ? site_.boilerplate().value().GetElementsKind()
                         : site_.GetElementsKind());
  }

  bool IsValid() const override {
    Handle<AllocationSite> site = site_.object();
    ElementsKind kind = site->PointsToLiteral()
                            ? site->boilerplate().GetElementsKind()
                            : site->GetElementsKind();
    return kind_ == kind;
  }

  void Install(const MaybeObjectHandle& code) const override {
    SLOW_DCHECK(IsValid());
    DependentCode::InstallDependency(
        site_.isolate(), code, site_.object(),
        DependentCode::kAllocationSiteTransitionChangedGroup);
  }

 private:
  AllocationSiteRef site_;
  ElementsKind kind_;
};

class InitialMapInstanceSizePredictionDependency final
    : public CompilationDependency {
 public:
  InitialMapInstanceSizePredictionDependency(const JSFunctionRef& function,
                                             int instance_size)
      : function_(function), instance_size_(instance_size) {}

  bool IsValid() const override {
    // The dependency is valid if the prediction is the same as the current
    // slack tracking result.
    if (!function_.object()->has_initial_map()) return false;
    int instance_size = function_.object()->ComputeInstanceSizeWithMinSlack(
        function_.isolate());
    return instance_size == instance_size_;
  }

  void PrepareInstall() const override {
    SLOW_DCHECK(IsValid());
    function_.object()->CompleteInobjectSlackTrackingIfActive();
  }

  void Install(const MaybeObjectHandle& code) const override {
    SLOW_DCHECK(IsValid());
    DCHECK(
        !function_.object()->initial_map().IsInobjectSlackTrackingInProgress());
  }

 private:
  JSFunctionRef function_;
  int instance_size_;
};

void CompilationDependencies::RecordDependency(
    CompilationDependency const* dependency) {
  if (dependency != nullptr) dependencies_.push_front(dependency);
}

MapRef CompilationDependencies::DependOnInitialMap(
    const JSFunctionRef& function) {
  MapRef map = function.initial_map();
  RecordDependency(zone_->New<InitialMapDependency>(function, map));
  return map;
}

ObjectRef CompilationDependencies::DependOnPrototypeProperty(
    const JSFunctionRef& function) {
  ObjectRef prototype = function.prototype();
  RecordDependency(
      zone_->New<PrototypePropertyDependency>(function, prototype));
  return prototype;
}

void CompilationDependencies::DependOnStableMap(const MapRef& map) {
  if (map.CanTransition()) {
    RecordDependency(zone_->New<StableMapDependency>(map));
  } else {
    DCHECK(map.is_stable());
  }
}

void CompilationDependencies::DependOnTransition(const MapRef& target_map) {
  RecordDependency(TransitionDependencyOffTheRecord(target_map));
}

AllocationType CompilationDependencies::DependOnPretenureMode(
    const AllocationSiteRef& site) {
  AllocationType allocation = site.GetAllocationType();
  RecordDependency(zone_->New<PretenureModeDependency>(site, allocation));
  return allocation;
}

PropertyConstness CompilationDependencies::DependOnFieldConstness(
    const MapRef& map, InternalIndex descriptor) {
  MapRef owner = map.FindFieldOwner(descriptor);
  PropertyConstness constness =
      owner.GetPropertyDetails(descriptor).constness();
  if (constness == PropertyConstness::kMutable) return constness;

  // If the map can have fast elements transitions, then the field can be only
  // considered constant if the map does not transition.
  if (Map::CanHaveFastTransitionableElementsKind(map.instance_type())) {
    // If the map can already transition away, let us report the field as
    // mutable.
    if (!map.is_stable()) {
      return PropertyConstness::kMutable;
    }
    DependOnStableMap(map);
  }

  DCHECK_EQ(constness, PropertyConstness::kConst);
  RecordDependency(zone_->New<FieldConstnessDependency>(owner, descriptor));
  return PropertyConstness::kConst;
}

void CompilationDependencies::DependOnFieldRepresentation(
    const MapRef& map, InternalIndex descriptor) {
  RecordDependency(FieldRepresentationDependencyOffTheRecord(map, descriptor));
}

void CompilationDependencies::DependOnFieldType(const MapRef& map,
                                                InternalIndex descriptor) {
  RecordDependency(FieldTypeDependencyOffTheRecord(map, descriptor));
}

void CompilationDependencies::DependOnGlobalProperty(
    const PropertyCellRef& cell) {
  PropertyCellType type = cell.property_details().cell_type();
  bool read_only = cell.property_details().IsReadOnly();
  RecordDependency(zone_->New<GlobalPropertyDependency>(cell, type, read_only));
}

bool CompilationDependencies::DependOnProtector(const PropertyCellRef& cell) {
  if (cell.value().AsSmi() != Protectors::kProtectorValid) return false;
  RecordDependency(zone_->New<ProtectorDependency>(cell));
  return true;
}

bool CompilationDependencies::DependOnArrayBufferDetachingProtector() {
  return DependOnProtector(PropertyCellRef(
      broker_,
      broker_->isolate()->factory()->array_buffer_detaching_protector()));
}

bool CompilationDependencies::DependOnArrayIteratorProtector() {
  return DependOnProtector(PropertyCellRef(
      broker_, broker_->isolate()->factory()->array_iterator_protector()));
}

bool CompilationDependencies::DependOnArraySpeciesProtector() {
  return DependOnProtector(PropertyCellRef(
      broker_, broker_->isolate()->factory()->array_species_protector()));
}

bool CompilationDependencies::DependOnNoElementsProtector() {
  return DependOnProtector(PropertyCellRef(
      broker_, broker_->isolate()->factory()->no_elements_protector()));
}

bool CompilationDependencies::DependOnPromiseHookProtector() {
  return DependOnProtector(PropertyCellRef(
      broker_, broker_->isolate()->factory()->promise_hook_protector()));
}

bool CompilationDependencies::DependOnPromiseSpeciesProtector() {
  return DependOnProtector(PropertyCellRef(
      broker_, broker_->isolate()->factory()->promise_species_protector()));
}

bool CompilationDependencies::DependOnPromiseThenProtector() {
  return DependOnProtector(PropertyCellRef(
      broker_, broker_->isolate()->factory()->promise_then_protector()));
}

void CompilationDependencies::DependOnElementsKind(
    const AllocationSiteRef& site) {
  // Do nothing if the object doesn't have any useful element transitions left.
  ElementsKind kind = site.PointsToLiteral()
                          ? site.boilerplate().value().GetElementsKind()
                          : site.GetElementsKind();
  if (AllocationSite::ShouldTrack(kind)) {
    RecordDependency(zone_->New<ElementsKindDependency>(site, kind));
  }
}

bool CompilationDependencies::AreValid() const {
  for (auto dep : dependencies_) {
    if (!dep->IsValid()) return false;
  }
  return true;
}

bool CompilationDependencies::Commit(Handle<Code> code) {
  // Dependencies are context-dependent. In the future it may be possible to
  // restore them in the consumer native context, but for now they are
  // disabled.
  CHECK_IMPLIES(broker_->is_native_context_independent(),
                dependencies_.empty());

  for (auto dep : dependencies_) {
    if (!dep->IsValid()) {
      dependencies_.clear();
      return false;
    }
    dep->PrepareInstall();
  }

  DisallowCodeDependencyChange no_dependency_change;
  for (auto dep : dependencies_) {
    // Check each dependency's validity again right before installing it,
    // because the first iteration above might have invalidated some
    // dependencies. For example, PrototypePropertyDependency::PrepareInstall
    // can call EnsureHasInitialMap, which can invalidate a StableMapDependency
    // on the prototype object's map.
    if (!dep->IsValid()) {
      dependencies_.clear();
      return false;
    }
    dep->Install(MaybeObjectHandle::Weak(code));
  }

  // It is even possible that a GC during the above installations invalidated
  // one of the dependencies. However, this should only affect pretenure mode
  // dependencies, which we assert below. It is safe to return successfully in
  // these cases, because once the code gets executed it will do a stack check
  // that triggers its deoptimization.
  if (FLAG_stress_gc_during_compilation) {
    broker_->isolate()->heap()->PreciseCollectAllGarbage(
        Heap::kForcedGC, GarbageCollectionReason::kTesting, kNoGCCallbackFlags);
  }
#ifdef DEBUG
  for (auto dep : dependencies_) {
    CHECK_IMPLIES(!dep->IsValid(), dep->IsPretenureModeDependency());
  }
#endif

  dependencies_.clear();
  return true;
}

namespace {
// This function expects to never see a JSProxy.
void DependOnStablePrototypeChain(CompilationDependencies* deps, MapRef map,
                                  base::Optional<JSObjectRef> last_prototype) {
  while (true) {
    HeapObjectRef proto = map.prototype();
    if (!proto.IsJSObject()) {
      CHECK_EQ(proto.map().oddball_type(), OddballType::kNull);
      break;
    }
    map = proto.map();
    deps->DependOnStableMap(map);
    if (last_prototype.has_value() && proto.equals(*last_prototype)) break;
  }
}
}  // namespace

template <class MapContainer>
void CompilationDependencies::DependOnStablePrototypeChains(
    MapContainer const& receiver_maps, WhereToStart start,
    base::Optional<JSObjectRef> last_prototype) {
  for (auto map : receiver_maps) {
    MapRef receiver_map(broker_, map);
    if (start == kStartAtReceiver) DependOnStableMap(receiver_map);
    if (receiver_map.IsPrimitiveMap()) {
      // Perform the implicit ToObject for primitives here.
      // Implemented according to ES6 section 7.3.2 GetV (V, P).
      base::Optional<JSFunctionRef> constructor =
          broker_->target_native_context().GetConstructorFunction(receiver_map);
      if (constructor.has_value()) receiver_map = constructor->initial_map();
    }
    DependOnStablePrototypeChain(this, receiver_map, last_prototype);
  }
}
template void CompilationDependencies::DependOnStablePrototypeChains(
    ZoneVector<Handle<Map>> const& receiver_maps, WhereToStart start,
    base::Optional<JSObjectRef> last_prototype);
template void CompilationDependencies::DependOnStablePrototypeChains(
    ZoneHandleSet<Map> const& receiver_maps, WhereToStart start,
    base::Optional<JSObjectRef> last_prototype);

void CompilationDependencies::DependOnElementsKinds(
    const AllocationSiteRef& site) {
  AllocationSiteRef current = site;
  while (true) {
    DependOnElementsKind(current);
    if (!current.nested_site().IsAllocationSite()) break;
    current = current.nested_site().AsAllocationSite();
  }
  CHECK_EQ(current.nested_site().AsSmi(), 0);
}

SlackTrackingPrediction::SlackTrackingPrediction(MapRef initial_map,
                                                 int instance_size)
    : instance_size_(instance_size),
      inobject_property_count_(
          (instance_size >> kTaggedSizeLog2) -
          initial_map.GetInObjectPropertiesStartInWords()) {}

SlackTrackingPrediction
CompilationDependencies::DependOnInitialMapInstanceSizePrediction(
    const JSFunctionRef& function) {
  MapRef initial_map = DependOnInitialMap(function);
  int instance_size = function.InitialMapInstanceSizeWithMinSlack();
  // Currently, we always install the prediction dependency. If this turns out
  // to be too expensive, we can only install the dependency if slack
  // tracking is active.
  RecordDependency(zone_->New<InitialMapInstanceSizePredictionDependency>(
      function, instance_size));
  DCHECK_LE(instance_size, function.initial_map().instance_size());
  return SlackTrackingPrediction(initial_map, instance_size);
}

CompilationDependency const*
CompilationDependencies::TransitionDependencyOffTheRecord(
    const MapRef& target_map) const {
  if (target_map.CanBeDeprecated()) {
    return zone_->New<TransitionDependency>(target_map);
  } else {
    DCHECK(!target_map.is_deprecated());
    return nullptr;
  }
}

CompilationDependency const*
CompilationDependencies::FieldRepresentationDependencyOffTheRecord(
    const MapRef& map, InternalIndex descriptor) const {
  MapRef owner = map.FindFieldOwner(descriptor);
  PropertyDetails details = owner.GetPropertyDetails(descriptor);
  DCHECK(details.representation().Equals(
      map.GetPropertyDetails(descriptor).representation()));
  return zone_->New<FieldRepresentationDependency>(owner, descriptor,
                                                   details.representation());
}

CompilationDependency const*
CompilationDependencies::FieldTypeDependencyOffTheRecord(
    const MapRef& map, InternalIndex descriptor) const {
  MapRef owner = map.FindFieldOwner(descriptor);
  ObjectRef type = owner.GetFieldType(descriptor);
  DCHECK(type.equals(map.GetFieldType(descriptor)));
  return zone_->New<FieldTypeDependency>(owner, descriptor, type);
}

}  // namespace compiler
}  // namespace internal
}  // namespace v8
