e0c03dc34c
Remove Isolate parameters from some dictionary methods, and change others to use ReadOnlyRoots instead, to prepare for Isolate templatization in a future patch. One small side-effect is that the global dictionary's property cell's dependent code deoptimization has to dynamically get the Isolate when it needs to actually mark code for deoptimization, for method signature consistency. Given that this is the slow path anyway, it shouldn't matter. Bug: chromium:1011762 Change-Id: I707de9a74ca3b30423a1e5830a10729d6a404786 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2080369 Commit-Queue: Ulan Degenbaev <ulan@chromium.org> Auto-Submit: Leszek Swirski <leszeks@chromium.org> Reviewed-by: Ulan Degenbaev <ulan@chromium.org> Reviewed-by: Igor Sheludko <ishell@chromium.org> Reviewed-by: Toon Verwaest <verwaest@chromium.org> Cr-Commit-Position: refs/heads/master@{#66574}
261 lines
8.7 KiB
C++
261 lines
8.7 KiB
C++
// 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::zero());
|
|
SetElementsKind(GetInitialFastElementsKind());
|
|
set_nested_site(Smi::zero());
|
|
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(
|
|
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(
|
|
DependentCode::kAllocationSiteTransitionChangedGroup);
|
|
result = true;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
} // namespace internal
|
|
} // namespace v8
|
|
|
|
#include "src/objects/object-macros-undef.h"
|
|
|
|
#endif // V8_OBJECTS_ALLOCATION_SITE_INL_H_
|