blob: aaf0105e51e30924ac7801c4448f46c3e1dc0633 [file] [log] [blame]
// Copyright 2018 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.
#ifndef V8_OBJECTS_ALLOCATION_SITE_INL_H_
#define V8_OBJECTS_ALLOCATION_SITE_INL_H_
#include "src/objects/allocation-site.h"
#include "src/heap/heap-write-barrier-inl.h"
#include "src/objects/js-objects-inl.h"
// Has to be the last include (doesn't have include guards):
#include "src/objects/object-macros.h"
namespace v8 {
namespace internal {
OBJECT_CONSTRUCTORS_IMPL(AllocationMemento, Struct)
OBJECT_CONSTRUCTORS_IMPL(AllocationSite, Struct)
NEVER_READ_ONLY_SPACE_IMPL(AllocationSite)
CAST_ACCESSOR(AllocationMemento)
CAST_ACCESSOR(AllocationSite)
ACCESSORS(AllocationSite, transition_info_or_boilerplate, Object,
kTransitionInfoOrBoilerplateOffset)
ACCESSORS(AllocationSite, nested_site, Object, kNestedSiteOffset)
INT32_ACCESSORS(AllocationSite, pretenure_data, kPretenureDataOffset)
INT32_ACCESSORS(AllocationSite, pretenure_create_count,
kPretenureCreateCountOffset)
ACCESSORS(AllocationSite, dependent_code, DependentCode, kDependentCodeOffset)
ACCESSORS_CHECKED(AllocationSite, weak_next, Object, kWeakNextOffset,
HasWeakNext())
ACCESSORS(AllocationMemento, allocation_site, Object, kAllocationSiteOffset)
JSObject AllocationSite::boilerplate() const {
DCHECK(PointsToLiteral());
return JSObject::cast(transition_info_or_boilerplate());
}
void AllocationSite::set_boilerplate(JSObject object, WriteBarrierMode mode) {
set_transition_info_or_boilerplate(object, mode);
}
int AllocationSite::transition_info() const {
DCHECK(!PointsToLiteral());
return Smi::cast(transition_info_or_boilerplate()).value();
}
void AllocationSite::set_transition_info(int value) {
DCHECK(!PointsToLiteral());
set_transition_info_or_boilerplate(Smi::FromInt(value), SKIP_WRITE_BARRIER);
}
bool AllocationSite::HasWeakNext() const {
return map() == GetReadOnlyRoots().allocation_site_map();
}
void AllocationSite::Initialize() {
set_transition_info_or_boilerplate(Smi::kZero);
SetElementsKind(GetInitialFastElementsKind());
set_nested_site(Smi::kZero);
set_pretenure_data(0);
set_pretenure_create_count(0);
set_dependent_code(
DependentCode::cast(GetReadOnlyRoots().empty_weak_fixed_array()),
SKIP_WRITE_BARRIER);
}
bool AllocationSite::IsZombie() const {
return pretenure_decision() == kZombie;
}
bool AllocationSite::IsMaybeTenure() const {
return pretenure_decision() == kMaybeTenure;
}
bool AllocationSite::PretenuringDecisionMade() const {
return pretenure_decision() != kUndecided;
}
void AllocationSite::MarkZombie() {
DCHECK(!IsZombie());
Initialize();
set_pretenure_decision(kZombie);
}
ElementsKind AllocationSite::GetElementsKind() const {
return ElementsKindBits::decode(transition_info());
}
void AllocationSite::SetElementsKind(ElementsKind kind) {
set_transition_info(ElementsKindBits::update(transition_info(), kind));
}
bool AllocationSite::CanInlineCall() const {
return DoNotInlineBit::decode(transition_info()) == 0;
}
void AllocationSite::SetDoNotInlineCall() {
set_transition_info(DoNotInlineBit::update(transition_info(), true));
}
bool AllocationSite::PointsToLiteral() const {
Object raw_value = transition_info_or_boilerplate();
DCHECK_EQ(!raw_value.IsSmi(),
raw_value.IsJSArray() || raw_value.IsJSObject());
return !raw_value.IsSmi();
}
// Heuristic: We only need to create allocation site info if the boilerplate
// elements kind is the initial elements kind.
bool AllocationSite::ShouldTrack(ElementsKind boilerplate_elements_kind) {
return IsSmiElementsKind(boilerplate_elements_kind);
}
inline bool AllocationSite::CanTrack(InstanceType type) {
if (FLAG_allocation_site_pretenuring) {
// TurboFan doesn't care at all about String pretenuring feedback,
// so don't bother even trying to track that.
return type == JS_ARRAY_TYPE || type == JS_OBJECT_TYPE;
}
return type == JS_ARRAY_TYPE;
}
AllocationSite::PretenureDecision AllocationSite::pretenure_decision() const {
return PretenureDecisionBits::decode(pretenure_data());
}
void AllocationSite::set_pretenure_decision(PretenureDecision decision) {
int32_t value = pretenure_data();
set_pretenure_data(PretenureDecisionBits::update(value, decision));
}
bool AllocationSite::deopt_dependent_code() const {
return DeoptDependentCodeBit::decode(pretenure_data());
}
void AllocationSite::set_deopt_dependent_code(bool deopt) {
int32_t value = pretenure_data();
set_pretenure_data(DeoptDependentCodeBit::update(value, deopt));
}
int AllocationSite::memento_found_count() const {
return MementoFoundCountBits::decode(pretenure_data());
}
inline void AllocationSite::set_memento_found_count(int count) {
int32_t value = pretenure_data();
// Verify that we can count more mementos than we can possibly find in one
// new space collection.
DCHECK((GetHeap()->MaxSemiSpaceSize() /
(Heap::kMinObjectSizeInTaggedWords * kTaggedSize +
AllocationMemento::kSize)) < MementoFoundCountBits::kMax);
DCHECK_LT(count, MementoFoundCountBits::kMax);
set_pretenure_data(MementoFoundCountBits::update(value, count));
}
int AllocationSite::memento_create_count() const {
return pretenure_create_count();
}
void AllocationSite::set_memento_create_count(int count) {
set_pretenure_create_count(count);
}
bool AllocationSite::IncrementMementoFoundCount(int increment) {
if (IsZombie()) return false;
int value = memento_found_count();
set_memento_found_count(value + increment);
return memento_found_count() >= kPretenureMinimumCreated;
}
inline void AllocationSite::IncrementMementoCreateCount() {
DCHECK(FLAG_allocation_site_pretenuring);
int value = memento_create_count();
set_memento_create_count(value + 1);
}
bool AllocationMemento::IsValid() const {
return allocation_site().IsAllocationSite() &&
!AllocationSite::cast(allocation_site()).IsZombie();
}
AllocationSite AllocationMemento::GetAllocationSite() const {
DCHECK(IsValid());
return AllocationSite::cast(allocation_site());
}
Address AllocationMemento::GetAllocationSiteUnchecked() const {
return allocation_site().ptr();
}
template <AllocationSiteUpdateMode update_or_check>
bool AllocationSite::DigestTransitionFeedback(Handle<AllocationSite> site,
ElementsKind to_kind) {
Isolate* isolate = site->GetIsolate();
bool result = false;
if (site->PointsToLiteral() && site->boilerplate().IsJSArray()) {
Handle<JSArray> boilerplate(JSArray::cast(site->boilerplate()), isolate);
ElementsKind kind = boilerplate->GetElementsKind();
// if kind is holey ensure that to_kind is as well.
if (IsHoleyElementsKind(kind)) {
to_kind = GetHoleyElementsKind(to_kind);
}
if (IsMoreGeneralElementsKindTransition(kind, to_kind)) {
// If the array is huge, it's not likely to be defined in a local
// function, so we shouldn't make new instances of it very often.
uint32_t length = 0;
CHECK(boilerplate->length().ToArrayLength(&length));
if (length <= kMaximumArrayBytesToPretransition) {
if (update_or_check == AllocationSiteUpdateMode::kCheckOnly) {
return true;
}
if (FLAG_trace_track_allocation_sites) {
bool is_nested = site->IsNested();
PrintF("AllocationSite: JSArray %p boilerplate %supdated %s->%s\n",
reinterpret_cast<void*>(site->ptr()),
is_nested ? "(nested)" : " ", ElementsKindToString(kind),
ElementsKindToString(to_kind));
}
JSObject::TransitionElementsKind(boilerplate, to_kind);
site->dependent_code().DeoptimizeDependentCodeGroup(
isolate, DependentCode::kAllocationSiteTransitionChangedGroup);
result = true;
}
}
} else {
// The AllocationSite is for a constructed Array.
ElementsKind kind = site->GetElementsKind();
// if kind is holey ensure that to_kind is as well.
if (IsHoleyElementsKind(kind)) {
to_kind = GetHoleyElementsKind(to_kind);
}
if (IsMoreGeneralElementsKindTransition(kind, to_kind)) {
if (update_or_check == AllocationSiteUpdateMode::kCheckOnly) return true;
if (FLAG_trace_track_allocation_sites) {
PrintF("AllocationSite: JSArray %p site updated %s->%s\n",
reinterpret_cast<void*>(site->ptr()), ElementsKindToString(kind),
ElementsKindToString(to_kind));
}
site->SetElementsKind(to_kind);
site->dependent_code().DeoptimizeDependentCodeGroup(
isolate, DependentCode::kAllocationSiteTransitionChangedGroup);
result = true;
}
}
return result;
}
} // namespace internal
} // namespace v8
#include "src/objects/object-macros-undef.h"
#endif // V8_OBJECTS_ALLOCATION_SITE_INL_H_