1// Copyright 2015 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "src/compilation-dependencies.h"
6
7#include "src/factory.h"
8#include "src/handles-inl.h"
9#include "src/isolate.h"
10#include "src/objects-inl.h"
11#include "src/zone/zone.h"
12
13namespace v8 {
14namespace internal {
15
16DependentCode* CompilationDependencies::Get(Handle<Object> object) {
17  if (object->IsMap()) {
18    return Handle<Map>::cast(object)->dependent_code();
19  } else if (object->IsPropertyCell()) {
20    return Handle<PropertyCell>::cast(object)->dependent_code();
21  } else if (object->IsAllocationSite()) {
22    return Handle<AllocationSite>::cast(object)->dependent_code();
23  }
24  UNREACHABLE();
25  return nullptr;
26}
27
28
29void CompilationDependencies::Set(Handle<Object> object,
30                                  Handle<DependentCode> dep) {
31  if (object->IsMap()) {
32    Handle<Map>::cast(object)->set_dependent_code(*dep);
33  } else if (object->IsPropertyCell()) {
34    Handle<PropertyCell>::cast(object)->set_dependent_code(*dep);
35  } else if (object->IsAllocationSite()) {
36    Handle<AllocationSite>::cast(object)->set_dependent_code(*dep);
37  } else {
38    UNREACHABLE();
39  }
40}
41
42
43void CompilationDependencies::Insert(DependentCode::DependencyGroup group,
44                                     Handle<HeapObject> object) {
45  if (groups_[group] == nullptr) {
46    groups_[group] = new (zone_) ZoneList<Handle<HeapObject>>(2, zone_);
47  }
48  groups_[group]->Add(object, zone_);
49
50  if (object_wrapper_.is_null()) {
51    // Allocate the wrapper if necessary.
52    object_wrapper_ =
53        isolate_->factory()->NewForeign(reinterpret_cast<Address>(this));
54  }
55
56  // Get the old dependent code list.
57  Handle<DependentCode> old_dependent_code =
58      Handle<DependentCode>(Get(object), isolate_);
59  Handle<DependentCode> new_dependent_code =
60      DependentCode::InsertCompilationDependencies(old_dependent_code, group,
61                                                   object_wrapper_);
62
63  // Set the new dependent code list if the head of the list changed.
64  if (!new_dependent_code.is_identical_to(old_dependent_code)) {
65    Set(object, new_dependent_code);
66  }
67}
68
69
70void CompilationDependencies::Commit(Handle<Code> code) {
71  if (IsEmpty()) return;
72
73  DCHECK(!object_wrapper_.is_null());
74  Handle<WeakCell> cell = Code::WeakCellFor(code);
75  AllowDeferredHandleDereference get_wrapper;
76  for (int i = 0; i < DependentCode::kGroupCount; i++) {
77    ZoneList<Handle<HeapObject>>* group_objects = groups_[i];
78    if (group_objects == nullptr) continue;
79    DependentCode::DependencyGroup group =
80        static_cast<DependentCode::DependencyGroup>(i);
81    for (int j = 0; j < group_objects->length(); j++) {
82      DependentCode* dependent_code = Get(group_objects->at(j));
83      dependent_code->UpdateToFinishedCode(group, *object_wrapper_, *cell);
84    }
85    groups_[i] = nullptr;  // Zone-allocated, no need to delete.
86  }
87}
88
89
90void CompilationDependencies::Rollback() {
91  if (IsEmpty()) return;
92
93  AllowDeferredHandleDereference get_wrapper;
94  // Unregister from all dependent maps if not yet committed.
95  for (int i = 0; i < DependentCode::kGroupCount; i++) {
96    ZoneList<Handle<HeapObject>>* group_objects = groups_[i];
97    if (group_objects == nullptr) continue;
98    DependentCode::DependencyGroup group =
99        static_cast<DependentCode::DependencyGroup>(i);
100    for (int j = 0; j < group_objects->length(); j++) {
101      DependentCode* dependent_code = Get(group_objects->at(j));
102      dependent_code->RemoveCompilationDependencies(group, *object_wrapper_);
103    }
104    groups_[i] = nullptr;  // Zone-allocated, no need to delete.
105  }
106}
107
108
109void CompilationDependencies::AssumeMapNotDeprecated(Handle<Map> map) {
110  DCHECK(!map->is_deprecated());
111  // Do nothing if the map cannot be deprecated.
112  if (map->CanBeDeprecated()) {
113    Insert(DependentCode::kTransitionGroup, map);
114  }
115}
116
117
118void CompilationDependencies::AssumeMapStable(Handle<Map> map) {
119  DCHECK(map->is_stable());
120  // Do nothing if the map cannot transition.
121  if (map->CanTransition()) {
122    Insert(DependentCode::kPrototypeCheckGroup, map);
123  }
124}
125
126
127void CompilationDependencies::AssumePrototypeMapsStable(
128    Handle<Map> map, MaybeHandle<JSReceiver> prototype) {
129  for (PrototypeIterator i(map); !i.IsAtEnd(); i.Advance()) {
130    Handle<JSReceiver> const current =
131        PrototypeIterator::GetCurrent<JSReceiver>(i);
132    AssumeMapStable(handle(current->map()));
133    Handle<JSReceiver> last;
134    if (prototype.ToHandle(&last) && last.is_identical_to(current)) {
135      break;
136    }
137  }
138}
139
140
141void CompilationDependencies::AssumeTransitionStable(
142    Handle<AllocationSite> site) {
143  // Do nothing if the object doesn't have any useful element transitions left.
144  ElementsKind kind =
145      site->SitePointsToLiteral()
146          ? JSObject::cast(site->transition_info())->GetElementsKind()
147          : site->GetElementsKind();
148  if (AllocationSite::GetMode(kind) == TRACK_ALLOCATION_SITE) {
149    Insert(DependentCode::kAllocationSiteTransitionChangedGroup, site);
150  }
151}
152
153}  // namespace internal
154}  // namespace v8
155