09f374ac16
FixedDoubleArrays are a special case: 1 The reads are 64-bit and unaligned, thus use memcpy underneath. 2 The compiler only reads FDArray values for (constant) boilerplate elements. 1) makes proper atomic reads tricky-to-impossible without a lock. Luckily, 2) means we know that the array values are immutable after initialization, thus we can simply do a non-atomic read from the compiler thread. Bug: v8:7790 Change-Id: I39698d867543ce2214a2148511c5d90ced6364b3 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2848410 Commit-Queue: Jakob Gruber <jgruber@chromium.org> Reviewed-by: Santiago Aboy Solanes <solanes@chromium.org> Cr-Commit-Position: refs/heads/master@{#74226}
270 lines
9.1 KiB
C++
270 lines
9.1 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 {
|
|
|
|
#include "torque-generated/src/objects/allocation-site-tq-inl.inc"
|
|
|
|
TQ_OBJECT_CONSTRUCTORS_IMPL(AllocationMemento)
|
|
OBJECT_CONSTRUCTORS_IMPL(AllocationSite, Struct)
|
|
|
|
NEVER_READ_ONLY_SPACE_IMPL(AllocationSite)
|
|
|
|
CAST_ACCESSOR(AllocationSite)
|
|
|
|
ACCESSORS(AllocationSite, transition_info_or_boilerplate, Object,
|
|
kTransitionInfoOrBoilerplateOffset)
|
|
RELEASE_ACQUIRE_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());
|
|
}
|
|
|
|
JSObject AllocationSite::boilerplate(AcquireLoadTag tag) const {
|
|
DCHECK(PointsToLiteral());
|
|
return JSObject::cast(transition_info_or_boilerplate(tag));
|
|
}
|
|
|
|
void AllocationSite::set_boilerplate(JSObject value, ReleaseStoreTag tag,
|
|
WriteBarrierMode mode) {
|
|
set_transition_info_or_boilerplate(value, tag, 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_
|