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

#include "src/factory.h"
#include "src/handles-inl.h"
#include "src/isolate.h"
#include "src/objects-inl.h"
#include "src/zone/zone.h"

namespace v8 {
namespace internal {

DependentCode* CompilationDependencies::Get(Handle<Object> object) {
  if (object->IsMap()) {
    return Handle<Map>::cast(object)->dependent_code();
  } else if (object->IsPropertyCell()) {
    return Handle<PropertyCell>::cast(object)->dependent_code();
  } else if (object->IsAllocationSite()) {
    return Handle<AllocationSite>::cast(object)->dependent_code();
  }
  UNREACHABLE();
  return nullptr;
}


void CompilationDependencies::Set(Handle<Object> object,
                                  Handle<DependentCode> dep) {
  if (object->IsMap()) {
    Handle<Map>::cast(object)->set_dependent_code(*dep);
  } else if (object->IsPropertyCell()) {
    Handle<PropertyCell>::cast(object)->set_dependent_code(*dep);
  } else if (object->IsAllocationSite()) {
    Handle<AllocationSite>::cast(object)->set_dependent_code(*dep);
  } else {
    UNREACHABLE();
  }
}


void CompilationDependencies::Insert(DependentCode::DependencyGroup group,
                                     Handle<HeapObject> object) {
  if (groups_[group] == nullptr) {
    groups_[group] = new (zone_) ZoneList<Handle<HeapObject>>(2, zone_);
  }
  groups_[group]->Add(object, zone_);

  if (object_wrapper_.is_null()) {
    // Allocate the wrapper if necessary.
    object_wrapper_ =
        isolate_->factory()->NewForeign(reinterpret_cast<Address>(this));
  }

  // Get the old dependent code list.
  Handle<DependentCode> old_dependent_code =
      Handle<DependentCode>(Get(object), isolate_);
  Handle<DependentCode> new_dependent_code =
      DependentCode::InsertCompilationDependencies(old_dependent_code, group,
                                                   object_wrapper_);

  // Set the new dependent code list if the head of the list changed.
  if (!new_dependent_code.is_identical_to(old_dependent_code)) {
    Set(object, new_dependent_code);
  }
}


void CompilationDependencies::Commit(Handle<Code> code) {
  if (IsEmpty()) return;

  DCHECK(!object_wrapper_.is_null());
  Handle<WeakCell> cell = Code::WeakCellFor(code);
  AllowDeferredHandleDereference get_wrapper;
  for (int i = 0; i < DependentCode::kGroupCount; i++) {
    ZoneList<Handle<HeapObject>>* group_objects = groups_[i];
    if (group_objects == nullptr) continue;
    DependentCode::DependencyGroup group =
        static_cast<DependentCode::DependencyGroup>(i);
    for (int j = 0; j < group_objects->length(); j++) {
      DependentCode* dependent_code = Get(group_objects->at(j));
      dependent_code->UpdateToFinishedCode(group, *object_wrapper_, *cell);
    }
    groups_[i] = nullptr;  // Zone-allocated, no need to delete.
  }
}


void CompilationDependencies::Rollback() {
  if (IsEmpty()) return;

  AllowDeferredHandleDereference get_wrapper;
  // Unregister from all dependent maps if not yet committed.
  for (int i = 0; i < DependentCode::kGroupCount; i++) {
    ZoneList<Handle<HeapObject>>* group_objects = groups_[i];
    if (group_objects == nullptr) continue;
    DependentCode::DependencyGroup group =
        static_cast<DependentCode::DependencyGroup>(i);
    for (int j = 0; j < group_objects->length(); j++) {
      DependentCode* dependent_code = Get(group_objects->at(j));
      dependent_code->RemoveCompilationDependencies(group, *object_wrapper_);
    }
    groups_[i] = nullptr;  // Zone-allocated, no need to delete.
  }
}


void CompilationDependencies::AssumeMapNotDeprecated(Handle<Map> map) {
  DCHECK(!map->is_deprecated());
  // Do nothing if the map cannot be deprecated.
  if (map->CanBeDeprecated()) {
    Insert(DependentCode::kTransitionGroup, map);
  }
}


void CompilationDependencies::AssumeMapStable(Handle<Map> map) {
  DCHECK(map->is_stable());
  // Do nothing if the map cannot transition.
  if (map->CanTransition()) {
    Insert(DependentCode::kPrototypeCheckGroup, map);
  }
}


void CompilationDependencies::AssumePrototypeMapsStable(
    Handle<Map> map, MaybeHandle<JSReceiver> prototype) {
  for (PrototypeIterator i(map); !i.IsAtEnd(); i.Advance()) {
    Handle<JSReceiver> const current =
        PrototypeIterator::GetCurrent<JSReceiver>(i);
    AssumeMapStable(handle(current->map()));
    Handle<JSReceiver> last;
    if (prototype.ToHandle(&last) && last.is_identical_to(current)) {
      break;
    }
  }
}


void CompilationDependencies::AssumeTransitionStable(
    Handle<AllocationSite> site) {
  // Do nothing if the object doesn't have any useful element transitions left.
  ElementsKind kind =
      site->SitePointsToLiteral()
          ? JSObject::cast(site->transition_info())->GetElementsKind()
          : site->GetElementsKind();
  if (AllocationSite::GetMode(kind) == TRACK_ALLOCATION_SITE) {
    Insert(DependentCode::kAllocationSiteTransitionChangedGroup, site);
  }
}

}  // namespace internal
}  // namespace v8
