// 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