Commit bba36e19 authored by Jaroslav Sevcik's avatar Jaroslav Sevcik Committed by Commit Bot

[turbofan] Optimistic slack tracking completion.

The idea is to compute the slack before compilation start. Then
we check that the slack tracking decision is the same at the end
of compilation. If it is, we just commit to that slack tracking
(by calling function->CompleteInobjectSlackTrackingIfActive).
If the slack tracking decision changed, we will retry the compilation.

This has several pieces:
- Expose computation of slack and instance size from the object model.
- Add compilation dependency on the slack tracking result.
- Change create lowering to use the dependency.
- Fix array creation to use the slack tracking result's instance
  size.

Bug: v8:7790
Change-Id: Id975300cfd6c1786733cd7cbf55cc507c05738b2
Reviewed-on: https://chromium-review.googlesource.com/1164957Reviewed-by: 's avatarGeorg Neis <neis@chromium.org>
Commit-Queue: Jaroslav Sevcik <jarin@chromium.org>
Cr-Commit-Position: refs/heads/master@{#54982}
parent 0a719469
......@@ -17,7 +17,7 @@ CompilationDependencies::CompilationDependencies(Isolate* isolate, Zone* zone)
class CompilationDependencies::Dependency : public ZoneObject {
public:
virtual bool IsValid() const = 0;
virtual void Install(Isolate* isolate, MaybeObjectHandle code) = 0;
virtual void Install(MaybeObjectHandle code) = 0;
};
class InitialMapDependency final : public CompilationDependencies::Dependency {
......@@ -36,9 +36,10 @@ class InitialMapDependency final : public CompilationDependencies::Dependency {
function->initial_map() == *initial_map_.object<Map>();
}
void Install(Isolate* isolate, MaybeObjectHandle code) override {
void Install(MaybeObjectHandle code) override {
SLOW_DCHECK(IsValid());
DependentCode::InstallDependency(isolate, code, initial_map_.object<Map>(),
DependentCode::InstallDependency(function_.isolate(), code,
initial_map_.object<Map>(),
DependentCode::kInitialMapChangedGroup);
}
......@@ -55,9 +56,9 @@ class StableMapDependency final : public CompilationDependencies::Dependency {
bool IsValid() const override { return map_.object<Map>()->is_stable(); }
void Install(Isolate* isolate, MaybeObjectHandle code) override {
void Install(MaybeObjectHandle code) override {
SLOW_DCHECK(IsValid());
DependentCode::InstallDependency(isolate, code, map_.object<Map>(),
DependentCode::InstallDependency(map_.isolate(), code, map_.object<Map>(),
DependentCode::kPrototypeCheckGroup);
}
......@@ -73,9 +74,9 @@ class TransitionDependency final : public CompilationDependencies::Dependency {
bool IsValid() const override { return !map_.object<Map>()->is_deprecated(); }
void Install(Isolate* isolate, MaybeObjectHandle code) override {
void Install(MaybeObjectHandle code) override {
SLOW_DCHECK(IsValid());
DependentCode::InstallDependency(isolate, code, map_.object<Map>(),
DependentCode::InstallDependency(map_.isolate(), code, map_.object<Map>(),
DependentCode::kTransitionGroup);
}
......@@ -97,10 +98,10 @@ class PretenureModeDependency final
return mode_ == site_.object<AllocationSite>()->GetPretenureMode();
}
void Install(Isolate* isolate, MaybeObjectHandle code) override {
void Install(MaybeObjectHandle code) override {
SLOW_DCHECK(IsValid());
DependentCode::InstallDependency(
isolate, code, site_.object<AllocationSite>(),
site_.isolate(), code, site_.object<AllocationSite>(),
DependentCode::kAllocationSiteTenuringChangedGroup);
}
......@@ -127,9 +128,10 @@ class FieldTypeDependency final : public CompilationDependencies::Dependency {
return *type == owner->instance_descriptors()->GetFieldType(descriptor_);
}
void Install(Isolate* isolate, MaybeObjectHandle code) override {
void Install(MaybeObjectHandle code) override {
SLOW_DCHECK(IsValid());
DependentCode::InstallDependency(isolate, code, owner_.object<Map>(),
DependentCode::InstallDependency(owner_.isolate(), code,
owner_.object<Map>(),
DependentCode::kFieldOwnerGroup);
}
......@@ -157,9 +159,9 @@ class GlobalPropertyDependency final
read_only_ == cell->property_details().IsReadOnly();
}
void Install(Isolate* isolate, MaybeObjectHandle code) override {
void Install(MaybeObjectHandle code) override {
SLOW_DCHECK(IsValid());
DependentCode::InstallDependency(isolate, code,
DependentCode::InstallDependency(cell_.isolate(), code,
cell_.object<PropertyCell>(),
DependentCode::kPropertyCellChangedGroup);
}
......@@ -181,9 +183,9 @@ class ProtectorDependency final : public CompilationDependencies::Dependency {
return cell->value() == Smi::FromInt(Isolate::kProtectorValid);
}
void Install(Isolate* isolate, MaybeObjectHandle code) override {
void Install(MaybeObjectHandle code) override {
SLOW_DCHECK(IsValid());
DependentCode::InstallDependency(isolate, code,
DependentCode::InstallDependency(cell_.isolate(), code,
cell_.object<PropertyCell>(),
DependentCode::kPropertyCellChangedGroup);
}
......@@ -213,10 +215,10 @@ class ElementsKindDependency final
return kind_ == kind;
}
void Install(Isolate* isolate, MaybeObjectHandle code) override {
void Install(MaybeObjectHandle code) override {
SLOW_DCHECK(IsValid());
DependentCode::InstallDependency(
isolate, code, site_.object<AllocationSite>(),
site_.isolate(), code, site_.object<AllocationSite>(),
DependentCode::kAllocationSiteTransitionChangedGroup);
}
......@@ -225,6 +227,33 @@ class ElementsKindDependency final
ElementsKind kind_;
};
class InitialMapInstanceSizePredictionDependency final
: public CompilationDependencies::Dependency {
public:
InitialMapInstanceSizePredictionDependency(const JSFunctionRef& function,
int instance_size)
: function_(function), instance_size_(instance_size) {}
bool IsValid() const override {
// The dependency is valid if the prediction is the same as the current
// slack tracking result.
int instance_size =
function_.object<JSFunction>()->ComputeInstanceSizeWithMinSlack(
function_.isolate());
return instance_size == instance_size_;
}
void Install(MaybeObjectHandle code) override {
DCHECK(IsValid());
// Finish the slack tracking.
function_.object<JSFunction>()->CompleteInobjectSlackTrackingIfActive();
}
private:
JSFunctionRef function_;
int instance_size_;
};
MapRef CompilationDependencies::DependOnInitialMap(
const JSFunctionRef& function) {
MapRef map = function.initial_map();
......@@ -295,8 +324,6 @@ bool CompilationDependencies::AreValid() const {
}
bool CompilationDependencies::Commit(Handle<Code> code) {
Isolate* isolate = code->GetIsolate();
// Check validity of all dependencies first, such that we can avoid installing
// anything when there's already an invalid dependency.
if (!AreValid()) {
......@@ -311,7 +338,7 @@ bool CompilationDependencies::Commit(Handle<Code> code) {
dependencies_.clear();
return false;
}
dep->Install(isolate, MaybeObjectHandle::Weak(code));
dep->Install(MaybeObjectHandle::Weak(code));
}
dependencies_.clear();
return true;
......@@ -363,6 +390,28 @@ void CompilationDependencies::DependOnElementsKinds(
CHECK_EQ(current.nested_site().AsSmi(), 0);
}
SlackTrackingPrediction::SlackTrackingPrediction(MapRef initial_map,
int instance_size)
: instance_size_(instance_size),
inobject_property_count_(
(instance_size >> kPointerSizeLog2) -
initial_map.GetInObjectPropertiesStartInWords()) {}
SlackTrackingPrediction
CompilationDependencies::DependOnInitialMapInstanceSizePrediction(
const JSFunctionRef& function) {
MapRef initial_map = DependOnInitialMap(function);
int instance_size = function.InitialMapInstanceSizeWithMinSlack();
// Currently, we always install the prediction dependency. If this turns out
// to be too expensive, we can only install the dependency if slack
// tracking is active.
dependencies_.push_front(
new (zone_)
InitialMapInstanceSizePredictionDependency(function, instance_size));
DCHECK_LE(instance_size, function.initial_map().instance_size());
return SlackTrackingPrediction(initial_map, instance_size);
}
} // namespace compiler
} // namespace internal
} // namespace v8
......@@ -13,6 +13,18 @@ namespace v8 {
namespace internal {
namespace compiler {
class SlackTrackingPrediction {
public:
SlackTrackingPrediction(MapRef initial_map, int instance_size);
int inobject_property_count() const { return inobject_property_count_; }
int instance_size() const { return instance_size_; }
private:
int instance_size_;
int inobject_property_count_;
};
// Collects and installs dependencies of the code that is being generated.
class V8_EXPORT_PRIVATE CompilationDependencies : public ZoneObject {
public:
......@@ -21,7 +33,7 @@ class V8_EXPORT_PRIVATE CompilationDependencies : public ZoneObject {
V8_WARN_UNUSED_RESULT bool Commit(Handle<Code> code);
// Return the initial map of {function} and record the assumption that it
// stays the intial map.
// stays the initial map.
MapRef DependOnInitialMap(const JSFunctionRef& function);
// Record the assumption that {map} stays stable.
......@@ -59,6 +71,14 @@ class V8_EXPORT_PRIVATE CompilationDependencies : public ZoneObject {
// Like DependOnElementsKind but also applies to all nested allocation sites.
void DependOnElementsKinds(const AllocationSiteRef& site);
// Predict the final instance size for {function}'s initial map and record
// the assumption that this prediction is correct. In addition, register
// the initial map dependency. This method returns the {function}'s the
// predicted minimum slack instance size count (wrapped together with
// the corresponding in-object property count for convenience).
SlackTrackingPrediction DependOnInitialMapInstanceSizePrediction(
const JSFunctionRef& function);
// Exposed only for testing purposes.
bool AreValid() const;
......
......@@ -138,25 +138,22 @@ Reduction JSCreateLowering::ReduceJSCreate(Node* node) {
return NoChange();
}
// Add a dependency on the {initial_map} to make sure that this code is
// deoptimized whenever the {initial_map} changes.
MapRef initial_map = dependencies()->DependOnInitialMap(original_constructor);
// Force completion of inobject slack tracking before
// generating code to finalize the instance size.
SlackTrackingResult slack_tracking_result =
original_constructor.FinishSlackTracking();
SlackTrackingPrediction slack_tracking_prediction =
dependencies()->DependOnInitialMapInstanceSizePrediction(
original_constructor);
MapRef initial_map = original_constructor.initial_map();
// Emit code to allocate the JSObject instance for the
// {original_constructor}.
AllocationBuilder a(jsgraph(), effect, control);
a.Allocate(slack_tracking_result.instance_size);
a.Allocate(slack_tracking_prediction.instance_size());
a.Store(AccessBuilder::ForMap(), initial_map);
a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(),
jsgraph()->EmptyFixedArrayConstant());
a.Store(AccessBuilder::ForJSObjectElements(),
jsgraph()->EmptyFixedArrayConstant());
for (int i = 0; i < slack_tracking_result.inobject_property_count; ++i) {
for (int i = 0; i < slack_tracking_prediction.inobject_property_count();
++i) {
a.Store(AccessBuilder::ForJSObjectInObjectProperty(initial_map, i),
jsgraph()->UndefinedConstant());
}
......@@ -417,14 +414,10 @@ Reduction JSCreateLowering::ReduceJSCreateGeneratorObject(Node* node) {
closure_type.AsHeapConstant()->Ref().AsJSFunction();
js_function.EnsureHasInitialMap();
// Force completion of inobject slack tracking before
// generating code to finalize the instance size.
SlackTrackingResult slack_tracking_result =
js_function.FinishSlackTracking();
SlackTrackingPrediction slack_tracking_prediction =
dependencies()->DependOnInitialMapInstanceSizePrediction(js_function);
// Add a dependency on the {initial_map} to make sure that this code is
// deoptimized whenever the {initial_map} changes.
MapRef initial_map = dependencies()->DependOnInitialMap(js_function);
MapRef initial_map = js_function.initial_map();
DCHECK(initial_map.instance_type() == JS_GENERATOR_OBJECT_TYPE ||
initial_map.instance_type() == JS_ASYNC_GENERATOR_OBJECT_TYPE);
......@@ -444,7 +437,7 @@ Reduction JSCreateLowering::ReduceJSCreateGeneratorObject(Node* node) {
// Emit code to allocate the JS[Async]GeneratorObject instance.
AllocationBuilder a(jsgraph(), effect, control);
a.Allocate(slack_tracking_result.instance_size);
a.Allocate(slack_tracking_prediction.instance_size());
Node* empty_fixed_array = jsgraph()->EmptyFixedArrayConstant();
Node* undefined = jsgraph()->UndefinedConstant();
a.Store(AccessBuilder::ForMap(), initial_map);
......@@ -468,7 +461,8 @@ Reduction JSCreateLowering::ReduceJSCreateGeneratorObject(Node* node) {
}
// Handle in-object properties, too.
for (int i = 0; i < slack_tracking_result.inobject_property_count; ++i) {
for (int i = 0; i < slack_tracking_prediction.inobject_property_count();
++i) {
a.Store(AccessBuilder::ForJSObjectInObjectProperty(initial_map, i),
undefined);
}
......@@ -480,9 +474,9 @@ Reduction JSCreateLowering::ReduceJSCreateGeneratorObject(Node* node) {
// Constructs an array with a variable {length} when no upper bound
// is known for the capacity.
Reduction JSCreateLowering::ReduceNewArray(Node* node, Node* length,
MapRef initial_map,
PretenureFlag pretenure) {
Reduction JSCreateLowering::ReduceNewArray(
Node* node, Node* length, MapRef initial_map, PretenureFlag pretenure,
const SlackTrackingPrediction& slack_tracking_prediction) {
DCHECK_EQ(IrOpcode::kJSCreateArray, node->opcode());
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
......@@ -510,12 +504,13 @@ Reduction JSCreateLowering::ReduceNewArray(Node* node, Node* length,
// Perform the allocation of the actual JSArray object.
AllocationBuilder a(jsgraph(), effect, control);
a.Allocate(initial_map.instance_size(), pretenure);
a.Allocate(slack_tracking_prediction.instance_size(), pretenure);
a.Store(AccessBuilder::ForMap(), initial_map);
a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(), properties);
a.Store(AccessBuilder::ForJSObjectElements(), elements);
a.Store(AccessBuilder::ForJSArrayLength(initial_map.elements_kind()), length);
for (int i = 0; i < initial_map.GetInObjectProperties(); ++i) {
for (int i = 0; i < slack_tracking_prediction.inobject_property_count();
++i) {
a.Store(AccessBuilder::ForJSObjectInObjectProperty(initial_map, i),
jsgraph()->UndefinedConstant());
}
......@@ -526,9 +521,10 @@ Reduction JSCreateLowering::ReduceNewArray(Node* node, Node* length,
// Constructs an array with a variable {length} when an actual
// upper bound is known for the {capacity}.
Reduction JSCreateLowering::ReduceNewArray(Node* node, Node* length,
int capacity, MapRef initial_map,
PretenureFlag pretenure) {
Reduction JSCreateLowering::ReduceNewArray(
Node* node, Node* length, int capacity, MapRef initial_map,
PretenureFlag pretenure,
const SlackTrackingPrediction& slack_tracking_prediction) {
DCHECK(node->opcode() == IrOpcode::kJSCreateArray ||
node->opcode() == IrOpcode::kJSCreateEmptyLiteralArray);
Node* effect = NodeProperties::GetEffectInput(node);
......@@ -554,12 +550,13 @@ Reduction JSCreateLowering::ReduceNewArray(Node* node, Node* length,
// Perform the allocation of the actual JSArray object.
AllocationBuilder a(jsgraph(), effect, control);
a.Allocate(initial_map.instance_size(), pretenure);
a.Allocate(slack_tracking_prediction.instance_size(), pretenure);
a.Store(AccessBuilder::ForMap(), initial_map);
a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(), properties);
a.Store(AccessBuilder::ForJSObjectElements(), elements);
a.Store(AccessBuilder::ForJSArrayLength(elements_kind), length);
for (int i = 0; i < initial_map.GetInObjectProperties(); ++i) {
for (int i = 0; i < slack_tracking_prediction.inobject_property_count();
++i) {
a.Store(AccessBuilder::ForJSObjectInObjectProperty(initial_map, i),
jsgraph()->UndefinedConstant());
}
......@@ -568,10 +565,10 @@ Reduction JSCreateLowering::ReduceNewArray(Node* node, Node* length,
return Changed(node);
}
Reduction JSCreateLowering::ReduceNewArray(Node* node,
std::vector<Node*> values,
MapRef initial_map,
PretenureFlag pretenure) {
Reduction JSCreateLowering::ReduceNewArray(
Node* node, std::vector<Node*> values, MapRef initial_map,
PretenureFlag pretenure,
const SlackTrackingPrediction& slack_tracking_prediction) {
DCHECK_EQ(IrOpcode::kJSCreateArray, node->opcode());
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
......@@ -610,12 +607,13 @@ Reduction JSCreateLowering::ReduceNewArray(Node* node,
// Perform the allocation of the actual JSArray object.
AllocationBuilder a(jsgraph(), effect, control);
a.Allocate(initial_map.instance_size(), pretenure);
a.Allocate(slack_tracking_prediction.instance_size(), pretenure);
a.Store(AccessBuilder::ForMap(), initial_map);
a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(), properties);
a.Store(AccessBuilder::ForJSObjectElements(), elements);
a.Store(AccessBuilder::ForJSArrayLength(elements_kind), length);
for (int i = 0; i < initial_map.GetInObjectProperties(); ++i) {
for (int i = 0; i < slack_tracking_prediction.inobject_property_count();
++i) {
a.Store(AccessBuilder::ForJSObjectInObjectProperty(initial_map, i),
jsgraph()->UndefinedConstant());
}
......@@ -715,14 +713,10 @@ Reduction JSCreateLowering::ReduceJSCreateArray(Node* node) {
// Check if we can inline the allocation.
if (IsAllocationInlineable(constructor, original_constructor)) {
// Force completion of inobject slack tracking before
// generating code to finalize the instance size.
original_constructor.FinishSlackTracking();
// Add a dependency on the {initial_map} to make sure that this code is
// deoptimized whenever the {initial_map} changes.
MapRef initial_map =
dependencies()->DependOnInitialMap(original_constructor);
SlackTrackingPrediction slack_tracking_prediction =
dependencies()->DependOnInitialMapInstanceSizePrediction(
original_constructor);
MapRef initial_map = original_constructor.initial_map();
// Tells whether we are protected by either the {site} or a
// protector cell to do certain speculative optimizations.
......@@ -742,7 +736,8 @@ Reduction JSCreateLowering::ReduceJSCreateArray(Node* node) {
if (arity == 0) {
Node* length = jsgraph()->ZeroConstant();
int capacity = JSArray::kPreallocatedArrayElements;
return ReduceNewArray(node, length, capacity, initial_map, pretenure);
return ReduceNewArray(node, length, capacity, initial_map, pretenure,
slack_tracking_prediction);
} else if (arity == 1) {
Node* length = NodeProperties::GetValueInput(node, 2);
Type length_type = NodeProperties::GetType(length);
......@@ -756,16 +751,18 @@ Reduction JSCreateLowering::ReduceJSCreateArray(Node* node) {
: PACKED_ELEMENTS);
initial_map = initial_map.AsElementsKind(elements_kind);
return ReduceNewArray(node, std::vector<Node*>{length}, initial_map,
pretenure);
pretenure, slack_tracking_prediction);
}
if (length_type.Is(Type::SignedSmall()) && length_type.Min() >= 0 &&
length_type.Max() <= kElementLoopUnrollLimit &&
length_type.Min() == length_type.Max()) {
int capacity = static_cast<int>(length_type.Max());
return ReduceNewArray(node, length, capacity, initial_map, pretenure);
return ReduceNewArray(node, length, capacity, initial_map, pretenure,
slack_tracking_prediction);
}
if (length_type.Maybe(Type::UnsignedSmall()) && can_inline_call) {
return ReduceNewArray(node, length, initial_map, pretenure);
return ReduceNewArray(node, length, initial_map, pretenure,
slack_tracking_prediction);
}
} else if (arity <= JSArray::kInitialMaxFastElementArray) {
// Gather the values to store into the newly created array.
......@@ -812,7 +809,8 @@ Reduction JSCreateLowering::ReduceJSCreateArray(Node* node) {
}
initial_map = initial_map.AsElementsKind(elements_kind);
return ReduceNewArray(node, values, initial_map, pretenure);
return ReduceNewArray(node, values, initial_map, pretenure,
slack_tracking_prediction);
}
}
}
......@@ -1158,7 +1156,11 @@ Reduction JSCreateLowering::ReduceJSCreateEmptyLiteralArray(Node* node) {
PretenureFlag const pretenure = dependencies()->DependOnPretenureMode(site);
dependencies()->DependOnElementsKind(site);
Node* length = jsgraph()->ZeroConstant();
return ReduceNewArray(node, length, 0, initial_map, pretenure);
DCHECK(!initial_map.IsInobjectSlackTrackingInProgress());
SlackTrackingPrediction slack_tracking_prediction(
initial_map, initial_map.instance_size());
return ReduceNewArray(node, length, 0, initial_map, pretenure,
slack_tracking_prediction);
}
return NoChange();
}
......
......@@ -26,7 +26,7 @@ class JSGraph;
class JSOperatorBuilder;
class MachineOperatorBuilder;
class SimplifiedOperatorBuilder;
class SlackTrackingPrediction;
// Lowers JSCreate-level operators to fast (inline) allocations.
class V8_EXPORT_PRIVATE JSCreateLowering final
......@@ -68,12 +68,17 @@ class V8_EXPORT_PRIVATE JSCreateLowering final
Reduction ReduceJSCreateCatchContext(Node* node);
Reduction ReduceJSCreateBlockContext(Node* node);
Reduction ReduceJSCreateGeneratorObject(Node* node);
Reduction ReduceNewArray(Node* node, Node* length, MapRef initial_map,
PretenureFlag pretenure);
Reduction ReduceNewArray(Node* node, Node* length, int capacity,
MapRef initial_map, PretenureFlag pretenure);
Reduction ReduceNewArray(Node* node, std::vector<Node*> values,
MapRef initial_map, PretenureFlag pretenure);
Reduction ReduceNewArray(
Node* node, Node* length, MapRef initial_map, PretenureFlag pretenure,
const SlackTrackingPrediction& slack_tracking_prediction);
Reduction ReduceNewArray(
Node* node, Node* length, int capacity, MapRef initial_map,
PretenureFlag pretenure,
const SlackTrackingPrediction& slack_tracking_prediction);
Reduction ReduceNewArray(
Node* node, std::vector<Node*> values, MapRef initial_map,
PretenureFlag pretenure,
const SlackTrackingPrediction& slack_tracking_prediction);
Reduction ReduceJSCreateObject(Node* node);
Node* AllocateArguments(Node* effect, Node* control, Node* frame_state);
......
......@@ -4,7 +4,6 @@
#include "src/compiler/js-heap-broker.h"
#include "src/compiler/compilation-dependencies.h"
#include "src/objects-inl.h"
#include "src/objects/js-array-inl.h"
#include "src/objects/js-regexp-inl.h"
......@@ -204,6 +203,8 @@ StringRef ObjectRef::TypeOf() const {
Object::TypeOf(broker()->isolate(), object<Object>()));
}
Isolate* ObjectRef::isolate() const { return broker()->isolate(); }
base::Optional<ContextRef> ContextRef::previous() const {
AllowHandleAllocation handle_allocation;
AllowHandleDereference handle_dereference;
......@@ -406,14 +407,12 @@ MapRef MapRef::AsElementsKind(ElementsKind kind) const {
Map::AsElementsKind(broker()->isolate(), object<Map>(), kind));
}
SlackTrackingResult JSFunctionRef::FinishSlackTracking() const {
int JSFunctionRef::InitialMapInstanceSizeWithMinSlack() const {
AllowHandleDereference allow_handle_dereference;
AllowHandleAllocation handle_allocation;
object<JSFunction>()->CompleteInobjectSlackTrackingIfActive();
int instance_size = object<JSFunction>()->initial_map()->instance_size();
int inobject_property_count =
object<JSFunction>()->initial_map()->GetInObjectProperties();
return SlackTrackingResult(instance_size, inobject_property_count);
return object<JSFunction>()->ComputeInstanceSizeWithMinSlack(
broker()->isolate());
}
base::Optional<ScriptContextTableRef::LookupResult>
......@@ -753,6 +752,7 @@ HANDLE_ACCESSOR_C(Map, bool, is_stable)
HANDLE_ACCESSOR_C(Map, ElementsKind, elements_kind)
HANDLE_ACCESSOR_C(Map, InstanceType, instance_type)
HANDLE_ACCESSOR_C(Map, int, GetInObjectProperties)
HANDLE_ACCESSOR_C(Map, int, GetInObjectPropertiesStartInWords)
HANDLE_ACCESSOR_C(Map, int, instance_size)
HANDLE_ACCESSOR_C(Map, int, NumberOfOwnDescriptors)
HANDLE_ACCESSOR(Map, Object, constructor_or_backpointer)
......
......@@ -120,6 +120,8 @@ class ObjectRef {
bool BooleanValue();
double OddballToNumber() const;
Isolate* isolate() const;
protected:
JSHeapBroker* broker() const;
ObjectData* data() const;
......@@ -160,14 +162,6 @@ class JSObjectRef : public HeapObjectRef {
ElementsKind GetElementsKind() const;
};
struct SlackTrackingResult {
SlackTrackingResult(int instance_sizex, int inobject_property_countx)
: instance_size(instance_sizex),
inobject_property_count(inobject_property_countx) {}
int instance_size;
int inobject_property_count;
};
class JSFunctionRef : public JSObjectRef {
public:
using JSObjectRef::JSObjectRef;
......@@ -179,7 +173,7 @@ class JSFunctionRef : public JSObjectRef {
MapRef initial_map() const;
JSGlobalProxyRef global_proxy() const;
SlackTrackingResult FinishSlackTracking() const;
int InitialMapInstanceSizeWithMinSlack() const;
SharedFunctionInfoRef shared() const;
void EnsureHasInitialMap() const;
};
......@@ -288,6 +282,7 @@ class MapRef : public HeapObjectRef {
int instance_size() const;
InstanceType instance_type() const;
int GetInObjectProperties() const;
int GetInObjectPropertiesStartInWords() const;
int NumberOfOwnDescriptors() const;
PropertyDetails GetPropertyDetails(int i) const;
NameRef GetPropertyKey(int i) const;
......
......@@ -12559,6 +12559,9 @@ static void GetMinInobjectSlack(Map* map, void* data) {
}
}
int Map::InstanceSizeFromSlack(int slack) const {
return instance_size() - slack * kPointerSize;
}
static void ShrinkInstanceSize(Map* map, void* data) {
int slack = *reinterpret_cast<int*>(data);
......@@ -12567,7 +12570,7 @@ static void ShrinkInstanceSize(Map* map, void* data) {
int old_visitor_id = Map::GetVisitorId(map);
int new_unused = map->UnusedPropertyFields() - slack;
#endif
map->set_instance_size(map->instance_size() - slack * kPointerSize);
map->set_instance_size(map->InstanceSizeFromSlack(slack));
map->set_construction_counter(Map::kNoSlackTracking);
DCHECK_EQ(old_visitor_id, Map::GetVisitorId(map));
DCHECK_EQ(new_unused, map->UnusedPropertyFields());
......@@ -12577,7 +12580,7 @@ static void StopSlackTracking(Map* map, void* data) {
map->set_construction_counter(Map::kNoSlackTracking);
}
void Map::CompleteInobjectSlackTracking(Isolate* isolate) {
int Map::ComputeMinObjectSlack(Isolate* isolate) {
DisallowHeapAllocation no_gc;
// Has to be an initial map.
DCHECK(GetBackPointer()->IsUndefined(isolate));
......@@ -12585,6 +12588,16 @@ void Map::CompleteInobjectSlackTracking(Isolate* isolate) {
int slack = UnusedPropertyFields();
TransitionsAccessor transitions(isolate, this, &no_gc);
transitions.TraverseTransitionTree(&GetMinInobjectSlack, &slack);
return slack;
}
void Map::CompleteInobjectSlackTracking(Isolate* isolate) {
DisallowHeapAllocation no_gc;
// Has to be an initial map.
DCHECK(GetBackPointer()->IsUndefined(isolate));
int slack = ComputeMinObjectSlack(isolate);
TransitionsAccessor transitions(isolate, this, &no_gc);
if (slack != 0) {
// Resize the initial map and all maps in its transition tree.
transitions.TraverseTransitionTree(&ShrinkInstanceSize, &slack);
......@@ -13353,6 +13366,14 @@ MaybeHandle<Map> JSFunction::GetDerivedMap(Isolate* isolate,
return map;
}
int JSFunction::ComputeInstanceSizeWithMinSlack(Isolate* isolate) {
if (has_prototype_slot() && has_initial_map() &&
initial_map()->IsInobjectSlackTrackingInProgress()) {
int slack = initial_map()->ComputeMinObjectSlack(isolate);
return initial_map()->InstanceSizeFromSlack(slack);
}
return initial_map()->instance_size();
}
void JSFunction::PrintName(FILE* out) {
std::unique_ptr<char[]> name = shared()->DebugName()->ToCString();
......
......@@ -3250,6 +3250,11 @@ class JSFunction: public JSObject {
// Clears the optimization marker in the function's feedback vector.
inline void ClearOptimizationMarker();
// If slack tracking is active, it computes instance size of the initial map
// with minimum permissible object slack. If it is not active, it simply
// returns the initial map's instance size.
int ComputeInstanceSizeWithMinSlack(Isolate* isolate);
// Completes inobject slack tracking on initial map if it is active.
inline void CompleteInobjectSlackTrackingIfActive();
......
......@@ -330,6 +330,11 @@ class Map : public HeapObject {
// Does the tracking step.
inline void InobjectSlackTrackingStep(Isolate* isolate);
// Computes inobject slack for the transition tree starting at this initial
// map.
int ComputeMinObjectSlack(Isolate* isolate);
inline int InstanceSizeFromSlack(int slack) const;
// Completes inobject slack tracking for the transition tree starting at this
// initial map.
void CompleteInobjectSlackTracking(Isolate* isolate);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment