Revert "[turbofan] Rewrite CompilationDependencies"
This reverts commit 52a10e5081
.
Reason for revert: https://test-results.appspot.com/data/layout_results/V8-Blink_Linux_64__dbg_/12434/layout-test-results/results.html
Crash e.g. in http/tests/devtools/oopif/oopif-performance-cpu-profiles.js
crash log for devtools (pid <unknown>):
STDOUT: <empty>
STDERR:
STDERR:
STDERR: #
STDERR: # Fatal error in ../../v8/src/compilation-dependencies.cc, line 281
STDERR: # Debug check failed: descriptor == owner->LastAdded() (10 vs. 22).
STDERR: #
STDERR: #
STDERR: #
STDERR: #FailureMessage Object: 0x7fff86878630#0 0x0000031c642c base::debug::StackTrace::StackTrace()
STDERR: #1 0x0000046a56bb gin::(anonymous namespace)::PrintStackTrace()
STDERR: #2 0x00000469c528 V8_Fatal()
STDERR: #3 0x00000469c285 v8::base::(anonymous namespace)::DefaultDcheckHandler()
STDERR: #4 0x000001cc5253 v8::internal::CompilationDependencies::DependOnFieldType()
STDERR: #5 0x000001cdcc46 v8::internal::compiler::AccessInfoFactory::ComputePropertyAccessInfo()
STDERR: #6 0x000001cde661 v8::internal::compiler::AccessInfoFactory::ComputePropertyAccessInfos()
STDERR: #7 0x000001dd982b v8::internal::compiler::JSNativeContextSpecialization::ReduceNamedAccess()
STDERR: #8 0x000001ddb715 v8::internal::compiler::JSNativeContextSpecialization::ReduceNamedAccessFromNexus()
STDERR: #9 0x000001dd656d v8::internal::compiler::JSNativeContextSpecialization::ReduceJSLoadNamed()
STDERR: #10 0x000001d53872 v8::internal::compiler::GraphReducer::Reduce()
STDERR: #11 0x000001d534a5 v8::internal::compiler::GraphReducer::ReduceTop()
STDERR: #12 0x000001d52e58 v8::internal::compiler::GraphReducer::ReduceNode()
STDERR: #13 0x000001e4c201 v8::internal::compiler::InliningPhase::Run()
STDERR: #14 0x000001e44f79 v8::internal::compiler::PipelineImpl::Run<>()
STDERR: #15 0x000001e41058 v8::internal::compiler::PipelineImpl::CreateGraph()
STDERR: #16 0x000001e40c75 v8::internal::compiler::PipelineCompilationJob::PrepareJobImpl()
STDERR: #17 0x000001ccd437 v8::internal::OptimizedCompilationJob::PrepareJob()
STDERR: #18 0x000001cd071e v8::internal::(anonymous namespace)::GetOptimizedCode()
STDERR: #19 0x000001cd0c6f v8::internal::Compiler::CompileOptimized()
STDERR: #20 0x00000231fb62 v8::internal::__RT_impl_Runtime_CompileOptimized_Concurrent()
STDERR: #21 0x00000288e535 <unknown>
Original change's description:
> [turbofan] Rewrite CompilationDependencies
>
> Instead of installing code dependencies during graph reduction,
> install them after code generation.
>
> Bug: v8:7902, v8:7790
> Change-Id: I8a3798254abb5b9ec7c295a1592aeb6b51f24c7a
> Reviewed-on: https://chromium-review.googlesource.com/1119913
> Commit-Queue: Georg Neis <neis@chromium.org>
> Reviewed-by: Jaroslav Sevcik <jarin@chromium.org>
> Reviewed-by: Michael Starzinger <mstarzinger@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#54170}
TBR=mstarzinger@chromium.org,jarin@chromium.org,neis@chromium.org
Change-Id: Ic58c2bfadbd34bb6ba7dc0d2b74871cc90b0a74f
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: v8:7902, v8:7790
Reviewed-on: https://chromium-review.googlesource.com/1125680
Reviewed-by: Yang Guo <yangguo@chromium.org>
Commit-Queue: Yang Guo <yangguo@chromium.org>
Cr-Commit-Position: refs/heads/master@{#54192}
This commit is contained in:
parent
ade7f55b3a
commit
b1cf1e1e07
@ -5,14 +5,15 @@
|
||||
#include "src/compilation-dependencies.h"
|
||||
|
||||
#include "src/handles-inl.h"
|
||||
#include "src/heap/factory.h"
|
||||
#include "src/isolate.h"
|
||||
#include "src/objects-inl.h"
|
||||
#include "src/zone/zone.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
// TODO(neis): Move these to the DependentCode class.
|
||||
namespace {
|
||||
DependentCode* GetDependentCode(Handle<Object> object) {
|
||||
DependentCode* CompilationDependencies::Get(Handle<Object> object) const {
|
||||
if (object->IsMap()) {
|
||||
return Handle<Map>::cast(object)->dependent_code();
|
||||
} else if (object->IsPropertyCell()) {
|
||||
@ -23,7 +24,9 @@ DependentCode* GetDependentCode(Handle<Object> object) {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
void SetDependentCode(Handle<Object> object, Handle<DependentCode> dep) {
|
||||
|
||||
void CompilationDependencies::Set(Handle<Object> object,
|
||||
Handle<DependentCode> dep) {
|
||||
if (object->IsMap()) {
|
||||
Handle<Map>::cast(object)->set_dependent_code(*dep);
|
||||
} else if (object->IsPropertyCell()) {
|
||||
@ -35,332 +38,106 @@ void SetDependentCode(Handle<Object> object, Handle<DependentCode> dep) {
|
||||
}
|
||||
}
|
||||
|
||||
void InstallDependency(Isolate* isolate, Handle<WeakCell> source,
|
||||
Handle<HeapObject> target,
|
||||
DependentCode::DependencyGroup group) {
|
||||
Handle<DependentCode> old_deps(GetDependentCode(target), isolate);
|
||||
Handle<DependentCode> new_deps =
|
||||
DependentCode::InsertWeakCode(old_deps, group, source);
|
||||
// Update the list head if necessary.
|
||||
if (!new_deps.is_identical_to(old_deps)) SetDependentCode(target, new_deps);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
CompilationDependencies::CompilationDependencies(Isolate* isolate, Zone* zone)
|
||||
: isolate_(isolate), zone_(zone), dependencies_(zone) {}
|
||||
void CompilationDependencies::Insert(DependentCode::DependencyGroup group,
|
||||
Handle<HeapObject> object) {
|
||||
if (groups_[group] == nullptr) {
|
||||
groups_[group] = new (zone_->New(sizeof(ZoneVector<Handle<HeapObject>>)))
|
||||
ZoneVector<Handle<HeapObject>>(zone_);
|
||||
}
|
||||
groups_[group]->push_back(object);
|
||||
|
||||
class CompilationDependencies::Dependency : public ZoneObject {
|
||||
public:
|
||||
virtual bool IsValid() const = 0;
|
||||
virtual void Install(Isolate* isolate, Handle<WeakCell> code) = 0;
|
||||
};
|
||||
|
||||
class InitialMapDependency final : public CompilationDependencies::Dependency {
|
||||
public:
|
||||
InitialMapDependency(Handle<JSFunction> function, Handle<Map> initial_map)
|
||||
: function_(function), initial_map_(initial_map) {
|
||||
DCHECK(IsValid());
|
||||
if (object_wrapper_.is_null()) {
|
||||
// Allocate the wrapper if necessary.
|
||||
object_wrapper_ =
|
||||
isolate_->factory()->NewForeign(reinterpret_cast<Address>(this));
|
||||
}
|
||||
|
||||
bool IsValid() const override {
|
||||
DisallowHeapAllocation no_heap_allocation;
|
||||
DCHECK(function_->has_initial_map());
|
||||
return *initial_map_ == function_->initial_map();
|
||||
}
|
||||
// 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_);
|
||||
|
||||
void Install(Isolate* isolate, Handle<WeakCell> code) override {
|
||||
DCHECK(IsValid());
|
||||
InstallDependency(isolate, code, initial_map_,
|
||||
DependentCode::kInitialMapChangedGroup);
|
||||
}
|
||||
|
||||
private:
|
||||
Handle<JSFunction> function_;
|
||||
Handle<Map> initial_map_;
|
||||
};
|
||||
|
||||
class StableMapDependency final : public CompilationDependencies::Dependency {
|
||||
public:
|
||||
explicit StableMapDependency(Handle<Map> map) : map_(map) {
|
||||
DCHECK(IsValid());
|
||||
}
|
||||
|
||||
bool IsValid() const override {
|
||||
DisallowHeapAllocation no_heap_allocation;
|
||||
return map_->is_stable();
|
||||
}
|
||||
|
||||
void Install(Isolate* isolate, Handle<WeakCell> code) override {
|
||||
DCHECK(IsValid());
|
||||
InstallDependency(isolate, code, map_, DependentCode::kPrototypeCheckGroup);
|
||||
}
|
||||
|
||||
private:
|
||||
Handle<Map> map_;
|
||||
};
|
||||
|
||||
class TransitionDependency final : public CompilationDependencies::Dependency {
|
||||
public:
|
||||
explicit TransitionDependency(Handle<Map> map) : map_(map) {
|
||||
DCHECK(IsValid());
|
||||
}
|
||||
|
||||
bool IsValid() const override {
|
||||
DisallowHeapAllocation no_heap_allocation;
|
||||
return !map_->is_deprecated();
|
||||
}
|
||||
|
||||
void Install(Isolate* isolate, Handle<WeakCell> code) override {
|
||||
DCHECK(IsValid());
|
||||
InstallDependency(isolate, code, map_, DependentCode::kTransitionGroup);
|
||||
}
|
||||
|
||||
private:
|
||||
Handle<Map> map_;
|
||||
};
|
||||
|
||||
class PretenureModeDependency final
|
||||
: public CompilationDependencies::Dependency {
|
||||
public:
|
||||
PretenureModeDependency(Handle<AllocationSite> site, PretenureFlag mode)
|
||||
: site_(site), mode_(mode) {
|
||||
DCHECK(IsValid());
|
||||
}
|
||||
|
||||
bool IsValid() const override {
|
||||
DisallowHeapAllocation no_heap_allocation;
|
||||
return mode_ == site_->GetPretenureMode();
|
||||
}
|
||||
|
||||
void Install(Isolate* isolate, Handle<WeakCell> code) override {
|
||||
DCHECK(IsValid());
|
||||
InstallDependency(isolate, code, site_,
|
||||
DependentCode::kAllocationSiteTenuringChangedGroup);
|
||||
}
|
||||
|
||||
private:
|
||||
Handle<AllocationSite> site_;
|
||||
PretenureFlag mode_;
|
||||
};
|
||||
|
||||
class FieldTypeDependency final : public CompilationDependencies::Dependency {
|
||||
public:
|
||||
FieldTypeDependency(Isolate* isolate, Handle<Map> owner,
|
||||
Handle<FieldType> type)
|
||||
: isolate_(isolate), owner_(owner), type_(type) {
|
||||
DCHECK(IsValid());
|
||||
}
|
||||
|
||||
bool IsValid() const override {
|
||||
DisallowHeapAllocation no_heap_allocation;
|
||||
int descriptor = owner_->LastAdded();
|
||||
CHECK_EQ(*owner_, owner_->FindFieldOwner(isolate_, descriptor));
|
||||
return *type_ == owner_->instance_descriptors()->GetFieldType(descriptor);
|
||||
}
|
||||
|
||||
void Install(Isolate* isolate, Handle<WeakCell> code) override {
|
||||
DCHECK(IsValid());
|
||||
InstallDependency(isolate, code, owner_, DependentCode::kFieldOwnerGroup);
|
||||
}
|
||||
|
||||
private:
|
||||
Isolate* isolate_;
|
||||
Handle<Map> owner_;
|
||||
Handle<FieldType> type_;
|
||||
};
|
||||
|
||||
class GlobalPropertyDependency final
|
||||
: public CompilationDependencies::Dependency {
|
||||
public:
|
||||
GlobalPropertyDependency(Handle<PropertyCell> cell, PropertyCellType type,
|
||||
bool read_only)
|
||||
: cell_(cell), type_(type), read_only_(read_only) {
|
||||
DCHECK(IsValid());
|
||||
}
|
||||
|
||||
bool IsValid() const override {
|
||||
DisallowHeapAllocation no_heap_allocation;
|
||||
return type_ == cell_->property_details().cell_type() &&
|
||||
read_only_ == cell_->property_details().IsReadOnly();
|
||||
}
|
||||
|
||||
void Install(Isolate* isolate, Handle<WeakCell> code) override {
|
||||
DCHECK(IsValid());
|
||||
InstallDependency(isolate, code, cell_,
|
||||
DependentCode::kPropertyCellChangedGroup);
|
||||
}
|
||||
|
||||
private:
|
||||
Handle<PropertyCell> cell_;
|
||||
PropertyCellType type_;
|
||||
bool read_only_;
|
||||
};
|
||||
|
||||
class ProtectorDependency final : public CompilationDependencies::Dependency {
|
||||
public:
|
||||
explicit ProtectorDependency(Handle<PropertyCell> cell) : cell_(cell) {
|
||||
DCHECK(IsValid());
|
||||
}
|
||||
|
||||
bool IsValid() const override {
|
||||
DisallowHeapAllocation no_heap_allocation;
|
||||
return cell_->value() == Smi::FromInt(Isolate::kProtectorValid);
|
||||
}
|
||||
|
||||
void Install(Isolate* isolate, Handle<WeakCell> code) override {
|
||||
DCHECK(IsValid());
|
||||
InstallDependency(isolate, code, cell_,
|
||||
DependentCode::kPropertyCellChangedGroup);
|
||||
}
|
||||
|
||||
private:
|
||||
Handle<PropertyCell> cell_;
|
||||
};
|
||||
|
||||
class ElementsKindDependency final
|
||||
: public CompilationDependencies::Dependency {
|
||||
public:
|
||||
ElementsKindDependency(Handle<AllocationSite> site, ElementsKind kind)
|
||||
: site_(site), kind_(kind) {
|
||||
DCHECK(IsValid());
|
||||
}
|
||||
|
||||
bool IsValid() const override {
|
||||
DisallowHeapAllocation no_heap_allocation;
|
||||
DCHECK(AllocationSite::ShouldTrack(kind_));
|
||||
ElementsKind kind = site_->PointsToLiteral()
|
||||
? site_->boilerplate()->GetElementsKind()
|
||||
: site_->GetElementsKind();
|
||||
return kind_ == kind;
|
||||
}
|
||||
|
||||
void Install(Isolate* isolate, Handle<WeakCell> code) override {
|
||||
DCHECK(IsValid());
|
||||
InstallDependency(isolate, code, site_,
|
||||
DependentCode::kAllocationSiteTransitionChangedGroup);
|
||||
}
|
||||
|
||||
private:
|
||||
Handle<AllocationSite> site_;
|
||||
ElementsKind kind_;
|
||||
};
|
||||
|
||||
Handle<Map> CompilationDependencies::DependOnInitialMap(
|
||||
Handle<JSFunction> function) {
|
||||
Handle<Map> map(function->initial_map(), function->GetIsolate());
|
||||
dependencies_.push_front(new (zone_) InitialMapDependency(function, map));
|
||||
return map;
|
||||
}
|
||||
|
||||
void CompilationDependencies::DependOnStableMap(Handle<Map> map) {
|
||||
if (map->CanTransition()) {
|
||||
dependencies_.push_front(new (zone_) StableMapDependency(map));
|
||||
} else {
|
||||
DCHECK(map->is_stable());
|
||||
// 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::DependOnTransition(Handle<Map> target_map) {
|
||||
if (target_map->CanBeDeprecated()) {
|
||||
dependencies_.push_front(new (zone_) TransitionDependency(target_map));
|
||||
} else {
|
||||
DCHECK(!target_map->is_deprecated());
|
||||
}
|
||||
}
|
||||
|
||||
PretenureFlag CompilationDependencies::DependOnPretenureMode(
|
||||
Handle<AllocationSite> site) {
|
||||
PretenureFlag mode = site->GetPretenureMode();
|
||||
dependencies_.push_front(new (zone_) PretenureModeDependency(site, mode));
|
||||
return mode;
|
||||
}
|
||||
|
||||
void CompilationDependencies::DependOnFieldType(Handle<Map> map,
|
||||
int descriptor) {
|
||||
Handle<Map> owner(map->FindFieldOwner(isolate_, descriptor), isolate_);
|
||||
DCHECK_EQ(descriptor, owner->LastAdded());
|
||||
Handle<FieldType> type(
|
||||
owner->instance_descriptors()->GetFieldType(descriptor), isolate_);
|
||||
DCHECK_EQ(*type, map->instance_descriptors()->GetFieldType(descriptor));
|
||||
dependencies_.push_front(new (zone_)
|
||||
FieldTypeDependency(isolate_, owner, type));
|
||||
}
|
||||
|
||||
void CompilationDependencies::DependOnFieldType(const LookupIterator* it) {
|
||||
Handle<Map> owner = it->GetFieldOwnerMap();
|
||||
int descriptor = it->GetFieldDescriptorIndex();
|
||||
DCHECK_EQ(descriptor, owner->LastAdded());
|
||||
Handle<FieldType> type = it->GetFieldType();
|
||||
CHECK_EQ(*type,
|
||||
it->GetHolder<Map>()->map()->instance_descriptors()->GetFieldType(
|
||||
descriptor));
|
||||
dependencies_.push_front(new (zone_)
|
||||
FieldTypeDependency(isolate_, owner, type));
|
||||
}
|
||||
|
||||
void CompilationDependencies::DependOnGlobalProperty(
|
||||
Handle<PropertyCell> cell) {
|
||||
PropertyCellType type = cell->property_details().cell_type();
|
||||
bool read_only = cell->property_details().IsReadOnly();
|
||||
dependencies_.push_front(new (zone_)
|
||||
GlobalPropertyDependency(cell, type, read_only));
|
||||
}
|
||||
|
||||
void CompilationDependencies::DependOnProtector(Handle<PropertyCell> cell) {
|
||||
dependencies_.push_front(new (zone_) ProtectorDependency(cell));
|
||||
}
|
||||
|
||||
void CompilationDependencies::DependOnElementsKind(
|
||||
Handle<AllocationSite> site) {
|
||||
// Do nothing if the object doesn't have any useful element transitions left.
|
||||
ElementsKind kind = site->PointsToLiteral()
|
||||
? site->boilerplate()->GetElementsKind()
|
||||
: site->GetElementsKind();
|
||||
if (AllocationSite::ShouldTrack(kind)) {
|
||||
dependencies_.push_front(new (zone_) ElementsKindDependency(site, kind));
|
||||
}
|
||||
}
|
||||
|
||||
bool CompilationDependencies::AreValid() const {
|
||||
for (auto dep : dependencies_) {
|
||||
if (!dep->IsValid()) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CompilationDependencies::Commit(Handle<Code> code) {
|
||||
// Check validity of all dependencies first, such that we can abort before
|
||||
// installing anything.
|
||||
if (!AreValid()) {
|
||||
dependencies_.clear();
|
||||
return false;
|
||||
}
|
||||
void CompilationDependencies::Commit(Handle<Code> code) {
|
||||
if (IsEmpty()) return;
|
||||
|
||||
DCHECK(!object_wrapper_.is_null());
|
||||
Handle<WeakCell> cell = Code::WeakCellFor(code);
|
||||
for (auto dep : dependencies_) {
|
||||
dep->Install(isolate_, cell);
|
||||
AllowDeferredHandleDereference get_wrapper;
|
||||
for (int i = 0; i < DependentCode::kGroupCount; i++) {
|
||||
ZoneVector<Handle<HeapObject>>* group_objects = groups_[i];
|
||||
if (group_objects == nullptr) continue;
|
||||
DependentCode::DependencyGroup group =
|
||||
static_cast<DependentCode::DependencyGroup>(i);
|
||||
for (size_t j = 0; j < group_objects->size(); 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.
|
||||
}
|
||||
dependencies_.clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
namespace {
|
||||
void DependOnStablePrototypeChain(CompilationDependencies* deps,
|
||||
Handle<Map> map,
|
||||
MaybeHandle<JSReceiver> last_prototype) {
|
||||
|
||||
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++) {
|
||||
ZoneVector<Handle<HeapObject>>* group_objects = groups_[i];
|
||||
if (group_objects == nullptr) continue;
|
||||
DependentCode::DependencyGroup group =
|
||||
static_cast<DependentCode::DependencyGroup>(i);
|
||||
for (size_t j = 0; j < group_objects->size(); 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);
|
||||
deps->DependOnStableMap(handle(current->map(), current->GetIsolate()));
|
||||
AssumeMapStable(handle(current->map(), isolate_));
|
||||
Handle<JSReceiver> last;
|
||||
if (last_prototype.ToHandle(&last) && last.is_identical_to(current)) {
|
||||
if (prototype.ToHandle(&last) && last.is_identical_to(current)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void CompilationDependencies::DependOnStablePrototypeChains(
|
||||
void CompilationDependencies::AssumePrototypesStable(
|
||||
Handle<Context> native_context,
|
||||
std::vector<Handle<Map>> const& receiver_maps, Handle<JSObject> holder) {
|
||||
// Determine actual holder and perform prototype chain checks.
|
||||
@ -370,20 +147,21 @@ void CompilationDependencies::DependOnStablePrototypeChains(
|
||||
Handle<JSFunction> constructor;
|
||||
if (Map::GetConstructorFunction(map, native_context)
|
||||
.ToHandle(&constructor)) {
|
||||
map = handle(constructor->initial_map(), isolate_);
|
||||
map = handle(constructor->initial_map(), holder->GetIsolate());
|
||||
}
|
||||
DependOnStablePrototypeChain(this, map, holder);
|
||||
AssumePrototypeMapsStable(map, holder);
|
||||
}
|
||||
}
|
||||
|
||||
void CompilationDependencies::DependOnElementsKinds(
|
||||
void CompilationDependencies::AssumeTransitionStable(
|
||||
Handle<AllocationSite> site) {
|
||||
while (true) {
|
||||
DependOnElementsKind(site);
|
||||
if (!site->nested_site()->IsAllocationSite()) break;
|
||||
site = handle(AllocationSite::cast(site->nested_site()), isolate_);
|
||||
// Do nothing if the object doesn't have any useful element transitions left.
|
||||
ElementsKind kind = site->PointsToLiteral()
|
||||
? site->boilerplate()->GetElementsKind()
|
||||
: site->GetElementsKind();
|
||||
if (AllocationSite::ShouldTrack(kind)) {
|
||||
Insert(DependentCode::kAllocationSiteTransitionChangedGroup, site);
|
||||
}
|
||||
CHECK_EQ(site->nested_site(), Smi::kZero);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
@ -5,70 +5,75 @@
|
||||
#ifndef V8_COMPILATION_DEPENDENCIES_H_
|
||||
#define V8_COMPILATION_DEPENDENCIES_H_
|
||||
|
||||
#include "src/handles.h"
|
||||
#include "src/objects.h"
|
||||
#include "src/objects/map.h"
|
||||
#include "src/zone/zone-containers.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
// Collects and installs dependencies of the code that is being generated.
|
||||
// Collects dependencies for this compilation, e.g. assumptions about
|
||||
// stable maps, constant globals, etc.
|
||||
class V8_EXPORT_PRIVATE CompilationDependencies {
|
||||
public:
|
||||
CompilationDependencies(Isolate* isolate, Zone* zone);
|
||||
CompilationDependencies(Isolate* isolate, Zone* zone)
|
||||
: isolate_(isolate),
|
||||
zone_(zone),
|
||||
object_wrapper_(Handle<Foreign>::null()),
|
||||
aborted_(false) {
|
||||
std::fill_n(groups_, DependentCode::kGroupCount, nullptr);
|
||||
}
|
||||
|
||||
V8_WARN_UNUSED_RESULT bool Commit(Handle<Code> code);
|
||||
void Insert(DependentCode::DependencyGroup group, Handle<HeapObject> handle);
|
||||
|
||||
// Return the initial map of {function} and record the assumption that it
|
||||
// stays the intial map.
|
||||
Handle<Map> DependOnInitialMap(Handle<JSFunction> function);
|
||||
void AssumeInitialMapCantChange(Handle<Map> map) {
|
||||
Insert(DependentCode::kInitialMapChangedGroup, map);
|
||||
}
|
||||
void AssumeFieldOwner(Handle<Map> map) {
|
||||
Insert(DependentCode::kFieldOwnerGroup, map);
|
||||
}
|
||||
void AssumeMapStable(Handle<Map> map);
|
||||
void AssumePrototypeMapsStable(
|
||||
Handle<Map> map,
|
||||
MaybeHandle<JSReceiver> prototype = MaybeHandle<JSReceiver>());
|
||||
void AssumeMapNotDeprecated(Handle<Map> map);
|
||||
void AssumePropertyCell(Handle<PropertyCell> cell) {
|
||||
Insert(DependentCode::kPropertyCellChangedGroup, cell);
|
||||
}
|
||||
void AssumeTenuringDecision(Handle<AllocationSite> site) {
|
||||
Insert(DependentCode::kAllocationSiteTenuringChangedGroup, site);
|
||||
}
|
||||
void AssumeTransitionStable(Handle<AllocationSite> site);
|
||||
|
||||
// Record the assumption that {map} stays stable.
|
||||
void DependOnStableMap(Handle<Map> map);
|
||||
|
||||
// Record the assumption that {target_map} can be transitioned to, i.e., that
|
||||
// it does not become deprecated.
|
||||
void DependOnTransition(Handle<Map> target_map);
|
||||
|
||||
// Return the pretenure mode of {site} and record the assumption that it does
|
||||
// not change.
|
||||
PretenureFlag DependOnPretenureMode(Handle<AllocationSite> site);
|
||||
|
||||
// Record the assumption that the field type of a field does not change. The
|
||||
// field is identified by the argument(s).
|
||||
void DependOnFieldType(Handle<Map> map, int descriptor);
|
||||
void DependOnFieldType(const LookupIterator* it);
|
||||
|
||||
// Record the assumption that neither {cell}'s {CellType} changes, nor the
|
||||
// {IsReadOnly()} flag of {cell}'s {PropertyDetails}.
|
||||
void DependOnGlobalProperty(Handle<PropertyCell> cell);
|
||||
|
||||
// Record the assumption that the protector remains valid.
|
||||
void DependOnProtector(Handle<PropertyCell> cell);
|
||||
|
||||
// Record the assumption that {site}'s {ElementsKind} doesn't change.
|
||||
void DependOnElementsKind(Handle<AllocationSite> site);
|
||||
|
||||
// Depend on the stability of (the maps of) all prototypes of every class in
|
||||
// Adds stability dependencies on all prototypes of every class in
|
||||
// {receiver_type} up to (and including) the {holder}.
|
||||
void DependOnStablePrototypeChains(
|
||||
Handle<Context> native_context,
|
||||
std::vector<Handle<Map>> const& receiver_maps, Handle<JSObject> holder);
|
||||
void AssumePrototypesStable(Handle<Context> native_context,
|
||||
std::vector<Handle<Map>> const& receiver_maps,
|
||||
Handle<JSObject> holder);
|
||||
|
||||
// Like DependOnElementsKind but also applies to all nested allocation sites.
|
||||
void DependOnElementsKinds(Handle<AllocationSite> site);
|
||||
void Commit(Handle<Code> code);
|
||||
void Rollback();
|
||||
void Abort() { aborted_ = true; }
|
||||
bool HasAborted() const { return aborted_; }
|
||||
|
||||
// Exposed only for testing purposes.
|
||||
bool AreValid() const;
|
||||
|
||||
// Exposed only because C++.
|
||||
class Dependency;
|
||||
bool IsEmpty() const {
|
||||
for (int i = 0; i < DependentCode::kGroupCount; i++) {
|
||||
if (groups_[i]) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
Isolate* isolate_;
|
||||
Zone* zone_;
|
||||
ZoneForwardList<Dependency*> dependencies_;
|
||||
};
|
||||
Handle<Foreign> object_wrapper_;
|
||||
bool aborted_;
|
||||
ZoneVector<Handle<HeapObject> >* groups_[DependentCode::kGroupCount];
|
||||
|
||||
DependentCode* Get(Handle<Object> object) const;
|
||||
void Set(Handle<Object> object, Handle<DependentCode> dep);
|
||||
};
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
||||
|
@ -227,6 +227,8 @@ CompilationJob::Status OptimizedCompilationJob::FinalizeJob(Isolate* isolate) {
|
||||
DCHECK(ThreadId::Current().Equals(isolate->thread_id()));
|
||||
DisallowCodeDependencyChange no_dependency_change;
|
||||
DisallowJavascriptExecution no_js(isolate);
|
||||
CHECK(!compilation_info()->dependencies() ||
|
||||
!compilation_info()->dependencies()->HasAborted());
|
||||
|
||||
// Delegate to the underlying implementation.
|
||||
DCHECK_EQ(state(), State::kReadyToFinalize);
|
||||
@ -800,6 +802,8 @@ CompilationJob::Status FinalizeOptimizedCompilationJob(
|
||||
if (job->state() == CompilationJob::State::kReadyToFinalize) {
|
||||
if (shared->optimization_disabled()) {
|
||||
job->RetryOptimization(BailoutReason::kOptimizationDisabled);
|
||||
} else if (compilation_info->dependencies()->HasAborted()) {
|
||||
job->RetryOptimization(BailoutReason::kBailedOutDueToDependencyChange);
|
||||
} else if (job->FinalizeJob(isolate) == CompilationJob::SUCCEEDED) {
|
||||
job->RecordCompilationStats();
|
||||
job->RecordFunctionCompilation(CodeEventListener::LAZY_COMPILE_TAG,
|
||||
|
@ -395,7 +395,11 @@ bool AccessInfoFactory::ComputePropertyAccessInfo(
|
||||
// The field type was cleared by the GC, so we don't know anything
|
||||
// about the contents now.
|
||||
} else if (descriptors_field_type->IsClass()) {
|
||||
dependencies()->DependOnFieldType(map, number);
|
||||
// Add proper code dependencies in case of stable field map(s).
|
||||
Handle<Map> field_owner_map(
|
||||
map->FindFieldOwner(isolate(), number), isolate());
|
||||
dependencies()->AssumeFieldOwner(field_owner_map);
|
||||
|
||||
// Remember the field map, and try to infer a useful type.
|
||||
field_type = Type::For(js_heap_broker(),
|
||||
descriptors_field_type->AsClass());
|
||||
@ -697,14 +701,18 @@ bool AccessInfoFactory::LookupTransition(Handle<Map> map, Handle<Name> name,
|
||||
// Store is not safe if the field type was cleared.
|
||||
return false;
|
||||
} else if (descriptors_field_type->IsClass()) {
|
||||
dependencies()->DependOnFieldType(transition_map, number);
|
||||
// Add proper code dependencies in case of stable field map(s).
|
||||
Handle<Map> field_owner_map(
|
||||
transition_map->FindFieldOwner(isolate(), number), isolate());
|
||||
dependencies()->AssumeFieldOwner(field_owner_map);
|
||||
|
||||
// Remember the field map, and try to infer a useful type.
|
||||
field_type =
|
||||
Type::For(js_heap_broker(), descriptors_field_type->AsClass());
|
||||
field_map = descriptors_field_type->AsClass();
|
||||
}
|
||||
}
|
||||
dependencies()->DependOnTransition(transition_map);
|
||||
dependencies()->AssumeMapNotDeprecated(transition_map);
|
||||
// Transitioning stores are never stores to constant fields.
|
||||
*access_info = PropertyAccessInfo::DataField(
|
||||
PropertyConstness::kMutable, MapHandles{map}, field_index,
|
||||
|
@ -594,7 +594,7 @@ Reduction JSCallReducer::ReduceObjectGetPrototype(Node* node, Node* object) {
|
||||
}
|
||||
if (result == NodeProperties::kUnreliableReceiverMaps) {
|
||||
for (size_t i = 0; i < object_maps.size(); ++i) {
|
||||
dependencies()->DependOnStableMap(object_maps[i]);
|
||||
dependencies()->AssumeMapStable(object_maps[i]);
|
||||
}
|
||||
}
|
||||
Node* value = jsgraph()->Constant(candidate_prototype);
|
||||
@ -1050,7 +1050,7 @@ Reduction JSCallReducer::ReduceArrayForEach(Node* node,
|
||||
|
||||
// Install code dependencies on the {receiver} prototype maps and the
|
||||
// global array protector cell.
|
||||
dependencies()->DependOnProtector(factory()->no_elements_protector());
|
||||
dependencies()->AssumePropertyCell(factory()->no_elements_protector());
|
||||
|
||||
// If we have unreliable maps, we need a map check.
|
||||
if (result == NodeProperties::kUnreliableReceiverMaps) {
|
||||
@ -1234,7 +1234,7 @@ Reduction JSCallReducer::ReduceArrayReduce(Node* node,
|
||||
|
||||
// Install code dependencies on the {receiver} prototype maps and the
|
||||
// global array protector cell.
|
||||
dependencies()->DependOnProtector(factory()->no_elements_protector());
|
||||
dependencies()->AssumePropertyCell(factory()->no_elements_protector());
|
||||
|
||||
// If we have unreliable maps, we need a map check.
|
||||
if (result == NodeProperties::kUnreliableReceiverMaps) {
|
||||
@ -1504,7 +1504,7 @@ Reduction JSCallReducer::ReduceArrayMap(Node* node,
|
||||
if (receiver_map->elements_kind() != kind) return NoChange();
|
||||
}
|
||||
|
||||
dependencies()->DependOnProtector(factory()->array_species_protector());
|
||||
dependencies()->AssumePropertyCell(factory()->array_species_protector());
|
||||
|
||||
Handle<JSFunction> handle_constructor(
|
||||
JSFunction::cast(
|
||||
@ -1711,7 +1711,7 @@ Reduction JSCallReducer::ReduceArrayFilter(Node* node,
|
||||
if (receiver_map->elements_kind() != kind) return NoChange();
|
||||
}
|
||||
|
||||
dependencies()->DependOnProtector(factory()->array_species_protector());
|
||||
dependencies()->AssumePropertyCell(factory()->array_species_protector());
|
||||
|
||||
Handle<Map> initial_map(
|
||||
Map::cast(native_context()->GetInitialJSArrayMap(packed_kind)),
|
||||
@ -1988,7 +1988,7 @@ Reduction JSCallReducer::ReduceArrayFind(Node* node, ArrayFindVariant variant,
|
||||
|
||||
// Install code dependencies on the {receiver} prototype maps and the
|
||||
// global array protector cell.
|
||||
dependencies()->DependOnProtector(factory()->no_elements_protector());
|
||||
dependencies()->AssumePropertyCell(factory()->no_elements_protector());
|
||||
|
||||
// If we have unreliable maps, we need a map check.
|
||||
if (result == NodeProperties::kUnreliableReceiverMaps) {
|
||||
@ -2303,7 +2303,7 @@ Reduction JSCallReducer::ReduceArrayEvery(Node* node,
|
||||
if (receiver_map->elements_kind() != kind) return NoChange();
|
||||
}
|
||||
|
||||
dependencies()->DependOnProtector(factory()->array_species_protector());
|
||||
dependencies()->AssumePropertyCell(factory()->array_species_protector());
|
||||
|
||||
// If we have unreliable maps, we need a map check.
|
||||
if (result == NodeProperties::kUnreliableReceiverMaps) {
|
||||
@ -2643,7 +2643,7 @@ Reduction JSCallReducer::ReduceArraySome(Node* node,
|
||||
if (receiver_map->elements_kind() != kind) return NoChange();
|
||||
}
|
||||
|
||||
dependencies()->DependOnProtector(factory()->array_species_protector());
|
||||
dependencies()->AssumePropertyCell(factory()->array_species_protector());
|
||||
|
||||
Node* k = jsgraph()->ZeroConstant();
|
||||
|
||||
@ -2891,7 +2891,7 @@ Reduction JSCallReducer::ReduceCallApiFunction(
|
||||
// Install stability dependencies for unreliable {receiver_maps}.
|
||||
if (result == NodeProperties::kUnreliableReceiverMaps) {
|
||||
for (size_t i = 0; i < receiver_maps.size(); ++i) {
|
||||
dependencies()->DependOnStableMap(receiver_maps[i]);
|
||||
dependencies()->AssumeMapStable(receiver_maps[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -3061,7 +3061,7 @@ Reduction JSCallReducer::ReduceCallOrConstructWithArrayLikeOrSpread(
|
||||
// that no one messed with the %ArrayIteratorPrototype%.next method.
|
||||
if (node->opcode() == IrOpcode::kJSCallWithSpread ||
|
||||
node->opcode() == IrOpcode::kJSConstructWithSpread) {
|
||||
dependencies()->DependOnProtector(factory()->array_iterator_protector());
|
||||
dependencies()->AssumePropertyCell(factory()->array_iterator_protector());
|
||||
}
|
||||
|
||||
// Remove the {arguments_list} input from the {node}.
|
||||
@ -4295,7 +4295,7 @@ Reduction JSCallReducer::ReduceArrayPrototypePush(Node* node) {
|
||||
}
|
||||
|
||||
// Install code dependencies on the {receiver} global array protector cell.
|
||||
dependencies()->DependOnProtector(factory()->no_elements_protector());
|
||||
dependencies()->AssumePropertyCell(factory()->no_elements_protector());
|
||||
|
||||
// If the {receiver_maps} information is not reliable, we need
|
||||
// to check that the {receiver} still has one of these maps.
|
||||
@ -4409,7 +4409,7 @@ Reduction JSCallReducer::ReduceArrayPrototypePop(Node* node) {
|
||||
}
|
||||
|
||||
// Install code dependencies on the {receiver} global array protector cell.
|
||||
dependencies()->DependOnProtector(factory()->no_elements_protector());
|
||||
dependencies()->AssumePropertyCell(factory()->no_elements_protector());
|
||||
|
||||
// If the {receiver_maps} information is not reliable, we need
|
||||
// to check that the {receiver} still has one of these maps.
|
||||
@ -4527,7 +4527,7 @@ Reduction JSCallReducer::ReduceArrayPrototypeShift(Node* node) {
|
||||
}
|
||||
|
||||
// Install code dependencies on the {receiver} global array protector cell.
|
||||
dependencies()->DependOnProtector(factory()->no_elements_protector());
|
||||
dependencies()->AssumePropertyCell(factory()->no_elements_protector());
|
||||
|
||||
// If the {receiver_maps} information is not reliable, we need
|
||||
// to check that the {receiver} still has one of these maps.
|
||||
@ -4808,7 +4808,7 @@ Reduction JSCallReducer::ReduceArrayIteratorPrototypeNext(Node* node) {
|
||||
|
||||
// Install code dependency on the array protector for holey arrays.
|
||||
if (IsHoleyElementsKind(elements_kind)) {
|
||||
dependencies()->DependOnProtector(factory()->no_elements_protector());
|
||||
dependencies()->AssumePropertyCell(factory()->no_elements_protector());
|
||||
}
|
||||
|
||||
// Load the (current) {iterated_object} from the {iterator}; this might be
|
||||
@ -4832,7 +4832,7 @@ Reduction JSCallReducer::ReduceArrayIteratorPrototypeNext(Node* node) {
|
||||
if (isolate()->IsArrayBufferNeuteringIntact()) {
|
||||
// Add a code dependency so we are deoptimized in case an ArrayBuffer
|
||||
// gets neutered.
|
||||
dependencies()->DependOnProtector(
|
||||
dependencies()->AssumePropertyCell(
|
||||
factory()->array_buffer_neutering_protector());
|
||||
} else {
|
||||
// Deoptimize if the array buffer was neutered.
|
||||
@ -5318,7 +5318,7 @@ Reduction JSCallReducer::ReduceAsyncFunctionPromiseCreate(Node* node) {
|
||||
if (!isolate()->IsPromiseHookProtectorIntact()) return NoChange();
|
||||
|
||||
// Install a code dependency on the promise hook protector cell.
|
||||
dependencies()->DependOnProtector(factory()->promise_hook_protector());
|
||||
dependencies()->AssumePropertyCell(factory()->promise_hook_protector());
|
||||
|
||||
// Morph this {node} into a JSCreatePromise node.
|
||||
RelaxControls(node);
|
||||
@ -5333,7 +5333,8 @@ Reduction JSCallReducer::ReduceAsyncFunctionPromiseRelease(Node* node) {
|
||||
DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
|
||||
if (!isolate()->IsPromiseHookProtectorIntact()) return NoChange();
|
||||
|
||||
dependencies()->DependOnProtector(factory()->promise_hook_protector());
|
||||
// Install a code dependency on the promise hook protector cell.
|
||||
dependencies()->AssumePropertyCell(factory()->promise_hook_protector());
|
||||
|
||||
// The AsyncFunctionPromiseRelease builtin is a no-op as long as neither
|
||||
// the debugger is active nor any promise hook has been installed (ever).
|
||||
@ -5502,7 +5503,8 @@ Reduction JSCallReducer::ReducePromiseConstructor(Node* node) {
|
||||
// Only handle builtins Promises, not subclasses.
|
||||
if (target != new_target) return NoChange();
|
||||
|
||||
dependencies()->DependOnProtector(factory()->promise_hook_protector());
|
||||
// Add a code dependency on the promise hook protector.
|
||||
dependencies()->AssumePropertyCell(factory()->promise_hook_protector());
|
||||
|
||||
Handle<SharedFunctionInfo> promise_shared(
|
||||
handle(native_context()->promise_function()->shared(), isolate()));
|
||||
@ -5655,7 +5657,8 @@ Reduction JSCallReducer::ReducePromiseInternalConstructor(Node* node) {
|
||||
// Check that promises aren't being observed through (debug) hooks.
|
||||
if (!isolate()->IsPromiseHookProtectorIntact()) return NoChange();
|
||||
|
||||
dependencies()->DependOnProtector(factory()->promise_hook_protector());
|
||||
// Install a code dependency on the promise hook protector cell.
|
||||
dependencies()->AssumePropertyCell(factory()->promise_hook_protector());
|
||||
|
||||
// Create a new pending promise.
|
||||
Node* value = effect =
|
||||
@ -5747,7 +5750,8 @@ Reduction JSCallReducer::ReducePromisePrototypeCatch(Node* node) {
|
||||
}
|
||||
}
|
||||
|
||||
dependencies()->DependOnProtector(factory()->promise_then_protector());
|
||||
// Add a code dependency on the necessary protectors.
|
||||
dependencies()->AssumePropertyCell(factory()->promise_then_protector());
|
||||
|
||||
// If the {receiver_maps} aren't reliable, we need to repeat the
|
||||
// map check here, guarded by the CALL_IC.
|
||||
@ -5823,9 +5827,10 @@ Reduction JSCallReducer::ReducePromisePrototypeFinally(Node* node) {
|
||||
}
|
||||
}
|
||||
|
||||
dependencies()->DependOnProtector(factory()->promise_hook_protector());
|
||||
dependencies()->DependOnProtector(factory()->promise_then_protector());
|
||||
dependencies()->DependOnProtector(factory()->promise_species_protector());
|
||||
// Add a code dependency on the necessary protectors.
|
||||
dependencies()->AssumePropertyCell(factory()->promise_hook_protector());
|
||||
dependencies()->AssumePropertyCell(factory()->promise_then_protector());
|
||||
dependencies()->AssumePropertyCell(factory()->promise_species_protector());
|
||||
|
||||
// If the {receiver_maps} aren't reliable, we need to repeat the
|
||||
// map check here, guarded by the CALL_IC.
|
||||
@ -5975,8 +5980,9 @@ Reduction JSCallReducer::ReducePromisePrototypeThen(Node* node) {
|
||||
}
|
||||
}
|
||||
|
||||
dependencies()->DependOnProtector(factory()->promise_hook_protector());
|
||||
dependencies()->DependOnProtector(factory()->promise_species_protector());
|
||||
// Add a code dependency on the necessary protectors.
|
||||
dependencies()->AssumePropertyCell(factory()->promise_hook_protector());
|
||||
dependencies()->AssumePropertyCell(factory()->promise_species_protector());
|
||||
|
||||
// If the {receiver_maps} aren't reliable, we need to repeat the
|
||||
// map check here, guarded by the CALL_IC.
|
||||
@ -6653,7 +6659,7 @@ Reduction JSCallReducer::ReduceArrayBufferViewAccessor(
|
||||
if (isolate()->IsArrayBufferNeuteringIntact()) {
|
||||
// Add a code dependency so we are deoptimized in case an ArrayBuffer
|
||||
// gets neutered.
|
||||
dependencies()->DependOnProtector(
|
||||
dependencies()->AssumePropertyCell(
|
||||
factory()->array_buffer_neutering_protector());
|
||||
} else {
|
||||
// Check if the {receiver}s buffer was neutered.
|
||||
@ -6997,8 +7003,8 @@ Reduction JSCallReducer::ReduceRegExpPrototypeTest(Node* node) {
|
||||
// Add proper dependencies on the {regexp}s [[Prototype]]s.
|
||||
Handle<JSObject> holder;
|
||||
if (ai_exec.holder().ToHandle(&holder)) {
|
||||
dependencies()->DependOnStablePrototypeChains(
|
||||
native_context(), ai_exec.receiver_maps(), holder);
|
||||
dependencies()->AssumePrototypesStable(native_context(),
|
||||
ai_exec.receiver_maps(), holder);
|
||||
}
|
||||
|
||||
if (need_map_check) {
|
||||
|
@ -133,12 +133,12 @@ Reduction JSCreateLowering::ReduceJSCreate(Node* node) {
|
||||
// Force completion of inobject slack tracking before
|
||||
// generating code to finalize the instance size.
|
||||
original_constructor->CompleteInobjectSlackTrackingIfActive();
|
||||
Handle<Map> initial_map(original_constructor->initial_map(), isolate());
|
||||
int const instance_size = initial_map->instance_size();
|
||||
|
||||
// Add a dependency on the {initial_map} to make sure that this code is
|
||||
// deoptimized whenever the {initial_map} changes.
|
||||
Handle<Map> initial_map =
|
||||
dependencies()->DependOnInitialMap(original_constructor);
|
||||
int const instance_size = initial_map->instance_size();
|
||||
dependencies()->AssumeInitialMapCantChange(initial_map);
|
||||
|
||||
// Emit code to allocate the JSObject instance for the
|
||||
// {original_constructor}.
|
||||
@ -425,12 +425,13 @@ Reduction JSCreateLowering::ReduceJSCreateGeneratorObject(Node* node) {
|
||||
// Force completion of inobject slack tracking before
|
||||
// generating code to finalize the instance size.
|
||||
js_function->CompleteInobjectSlackTrackingIfActive();
|
||||
Handle<Map> initial_map(js_function->initial_map(), isolate());
|
||||
DCHECK(initial_map->instance_type() == JS_GENERATOR_OBJECT_TYPE ||
|
||||
initial_map->instance_type() == JS_ASYNC_GENERATOR_OBJECT_TYPE);
|
||||
|
||||
// Add a dependency on the {initial_map} to make sure that this code is
|
||||
// deoptimized whenever the {initial_map} changes.
|
||||
Handle<Map> initial_map = dependencies()->DependOnInitialMap(js_function);
|
||||
DCHECK(initial_map->instance_type() == JS_GENERATOR_OBJECT_TYPE ||
|
||||
initial_map->instance_type() == JS_ASYNC_GENERATOR_OBJECT_TYPE);
|
||||
dependencies()->AssumeInitialMapCantChange(initial_map);
|
||||
|
||||
// Allocate a register file.
|
||||
DCHECK(js_function->shared()->HasBytecodeArray());
|
||||
@ -724,11 +725,11 @@ Reduction JSCreateLowering::ReduceJSCreateArray(Node* node) {
|
||||
// Force completion of inobject slack tracking before
|
||||
// generating code to finalize the instance size.
|
||||
original_constructor->CompleteInobjectSlackTrackingIfActive();
|
||||
Handle<Map> initial_map(original_constructor->initial_map(), isolate());
|
||||
|
||||
// Add a dependency on the {initial_map} to make sure that this code is
|
||||
// deoptimized whenever the {initial_map} changes.
|
||||
Handle<Map> initial_map =
|
||||
dependencies()->DependOnInitialMap(original_constructor);
|
||||
dependencies()->AssumeInitialMapCantChange(initial_map);
|
||||
|
||||
// Tells whether we are protected by either the {site} or a
|
||||
// protector cell to do certain speculative optimizations.
|
||||
@ -742,8 +743,10 @@ Reduction JSCreateLowering::ReduceJSCreateArray(Node* node) {
|
||||
Map::AsElementsKind(isolate(), initial_map, elements_kind);
|
||||
}
|
||||
can_inline_call = site->CanInlineCall();
|
||||
pretenure = dependencies()->DependOnPretenureMode(site);
|
||||
dependencies()->DependOnElementsKind(site);
|
||||
pretenure = site->GetPretenureMode();
|
||||
|
||||
dependencies()->AssumeTransitionStable(site);
|
||||
dependencies()->AssumeTenuringDecision(site);
|
||||
} else {
|
||||
can_inline_call = isolate()->IsArrayConstructorIntact();
|
||||
}
|
||||
@ -1133,6 +1136,17 @@ Reduction JSCreateLowering::ReduceJSCreatePromise(Node* node) {
|
||||
return Changed(node);
|
||||
}
|
||||
|
||||
void AssumeAllocationSiteTransitionDeepDependencies(
|
||||
CompilationDependencies* dependencies, Isolate* isolate,
|
||||
Handle<AllocationSite> site) {
|
||||
while (true) {
|
||||
dependencies->AssumeTransitionStable(site);
|
||||
if (!site->nested_site()->IsAllocationSite()) break;
|
||||
site = handle(AllocationSite::cast(site->nested_site()), isolate);
|
||||
}
|
||||
CHECK_EQ(site->nested_site(), Smi::kZero);
|
||||
}
|
||||
|
||||
Reduction JSCreateLowering::ReduceJSCreateLiteralArrayOrObject(Node* node) {
|
||||
DCHECK(node->opcode() == IrOpcode::kJSCreateLiteralArray ||
|
||||
node->opcode() == IrOpcode::kJSCreateLiteralObject);
|
||||
@ -1148,11 +1162,12 @@ Reduction JSCreateLowering::ReduceJSCreateLiteralArrayOrObject(Node* node) {
|
||||
if (site.IsFastLiteral(js_heap_broker())) {
|
||||
PretenureFlag pretenure = NOT_TENURED;
|
||||
if (FLAG_allocation_site_pretenuring) {
|
||||
pretenure = dependencies()->DependOnPretenureMode(
|
||||
site.object<AllocationSite>());
|
||||
pretenure = site.GetPretenureMode();
|
||||
dependencies()->AssumeTenuringDecision(site.object<AllocationSite>());
|
||||
}
|
||||
dependencies()->DependOnElementsKinds(site.object<AllocationSite>());
|
||||
JSObjectRef boilerplate = site.boilerplate(js_heap_broker());
|
||||
AssumeAllocationSiteTransitionDeepDependencies(
|
||||
dependencies(), isolate(), site.object<AllocationSite>());
|
||||
Node* value = effect =
|
||||
AllocateFastLiteral(effect, control, boilerplate, pretenure);
|
||||
ReplaceWithValue(node, value, effect, control);
|
||||
@ -1173,8 +1188,9 @@ Reduction JSCreateLowering::ReduceJSCreateEmptyLiteralArray(Node* node) {
|
||||
Handle<Map> const initial_map(
|
||||
native_context()->GetInitialJSArrayMap(site->GetElementsKind()),
|
||||
isolate());
|
||||
PretenureFlag const pretenure = dependencies()->DependOnPretenureMode(site);
|
||||
dependencies()->DependOnElementsKind(site);
|
||||
PretenureFlag const pretenure = site->GetPretenureMode();
|
||||
dependencies()->AssumeTransitionStable(site);
|
||||
dependencies()->AssumeTenuringDecision(site);
|
||||
Node* length = jsgraph()->ZeroConstant();
|
||||
return ReduceNewArray(node, length, 0, initial_map, pretenure);
|
||||
}
|
||||
|
@ -155,7 +155,7 @@ Reduction JSNativeContextSpecialization::ReduceJSGetSuperConstructor(
|
||||
// {function}s map is stable, i.e. we can use a code dependency
|
||||
// to guard against [[Prototype]] changes of {function}.
|
||||
if (function_map->is_stable() && function_prototype->IsConstructor()) {
|
||||
dependencies()->DependOnStableMap(function_map);
|
||||
dependencies()->AssumeMapStable(function_map);
|
||||
Node* value = jsgraph()->Constant(function_prototype);
|
||||
ReplaceWithValue(node, value);
|
||||
return Replace(value);
|
||||
@ -208,7 +208,7 @@ Reduction JSNativeContextSpecialization::ReduceJSInstanceOf(Node* node) {
|
||||
// Determine actual holder and perform prototype chain checks.
|
||||
Handle<JSObject> holder;
|
||||
if (access_info.holder().ToHandle(&holder)) {
|
||||
dependencies()->DependOnStablePrototypeChains(
|
||||
dependencies()->AssumePrototypesStable(
|
||||
native_context().object<Context>(), access_info.receiver_maps(),
|
||||
holder);
|
||||
}
|
||||
@ -234,9 +234,9 @@ Reduction JSNativeContextSpecialization::ReduceJSInstanceOf(Node* node) {
|
||||
// Determine actual holder and perform prototype chain checks.
|
||||
Handle<JSObject> holder;
|
||||
if (access_info.holder().ToHandle(&holder)) {
|
||||
dependencies()->DependOnStablePrototypeChains(
|
||||
native_context().object<Context>(), access_info.receiver_maps(),
|
||||
holder);
|
||||
dependencies()->AssumePrototypesStable(native_context().object<Context>(),
|
||||
access_info.receiver_maps(),
|
||||
holder);
|
||||
} else {
|
||||
holder = receiver;
|
||||
}
|
||||
@ -411,7 +411,9 @@ Reduction JSNativeContextSpecialization::ReduceJSOrdinaryHasInstance(
|
||||
// depend on that for the prototype constant-folding below.
|
||||
JSFunction::EnsureHasInitialMap(function);
|
||||
|
||||
Handle<Map> initial_map = dependencies()->DependOnInitialMap(function);
|
||||
// Install a code dependency on the {function}s initial map.
|
||||
Handle<Map> initial_map(function->initial_map(), isolate());
|
||||
dependencies()->AssumeInitialMapCantChange(initial_map);
|
||||
Node* prototype =
|
||||
jsgraph()->Constant(handle(initial_map->prototype(), isolate()));
|
||||
|
||||
@ -500,9 +502,8 @@ Reduction JSNativeContextSpecialization::ReduceJSResolvePromise(Node* node) {
|
||||
// Add proper dependencies on the {resolution}s [[Prototype]]s.
|
||||
Handle<JSObject> holder;
|
||||
if (access_info.holder().ToHandle(&holder)) {
|
||||
dependencies()->DependOnStablePrototypeChains(
|
||||
native_context().object<Context>(), access_info.receiver_maps(),
|
||||
holder);
|
||||
dependencies()->AssumePrototypesStable(native_context().object<Context>(),
|
||||
access_info.receiver_maps(), holder);
|
||||
}
|
||||
|
||||
// Simply fulfill the {promise} with the {resolution}.
|
||||
@ -608,7 +609,7 @@ Reduction JSNativeContextSpecialization::ReduceGlobalAccess(
|
||||
// can be deleted or reconfigured to an accessor property).
|
||||
if (property_details.cell_type() != PropertyCellType::kMutable ||
|
||||
property_details.IsConfigurable()) {
|
||||
dependencies()->DependOnGlobalProperty(property_cell);
|
||||
dependencies()->AssumePropertyCell(property_cell);
|
||||
}
|
||||
|
||||
// Load from constant/undefined global property can be constant-folded.
|
||||
@ -640,7 +641,7 @@ Reduction JSNativeContextSpecialization::ReduceGlobalAccess(
|
||||
// elimination if it's stable, i.e. the HeapObject wasn't
|
||||
// mutated without the cell state being updated.
|
||||
if (property_cell_value_map->is_stable()) {
|
||||
dependencies()->DependOnStableMap(property_cell_value_map);
|
||||
dependencies()->AssumeMapStable(property_cell_value_map);
|
||||
map = property_cell_value_map;
|
||||
}
|
||||
}
|
||||
@ -662,7 +663,7 @@ Reduction JSNativeContextSpecialization::ReduceGlobalAccess(
|
||||
case PropertyCellType::kConstant: {
|
||||
// Record a code dependency on the cell, and just deoptimize if the new
|
||||
// value doesn't match the previous value stored inside the cell.
|
||||
dependencies()->DependOnGlobalProperty(property_cell);
|
||||
dependencies()->AssumePropertyCell(property_cell);
|
||||
Node* check =
|
||||
graph()->NewNode(simplified()->ReferenceEqual(), value,
|
||||
jsgraph()->Constant(property_cell_value));
|
||||
@ -675,7 +676,7 @@ Reduction JSNativeContextSpecialization::ReduceGlobalAccess(
|
||||
// Record a code dependency on the cell, and just deoptimize if the new
|
||||
// values' type doesn't match the type of the previous value in the
|
||||
// cell.
|
||||
dependencies()->DependOnGlobalProperty(property_cell);
|
||||
dependencies()->AssumePropertyCell(property_cell);
|
||||
Type property_cell_value_type;
|
||||
MachineRepresentation representation = MachineRepresentation::kTagged;
|
||||
if (property_cell_value->IsHeapObject()) {
|
||||
@ -684,7 +685,7 @@ Reduction JSNativeContextSpecialization::ReduceGlobalAccess(
|
||||
Handle<Map> property_cell_value_map(
|
||||
Handle<HeapObject>::cast(property_cell_value)->map(), isolate());
|
||||
DCHECK(property_cell_value_map->is_stable());
|
||||
dependencies()->DependOnStableMap(property_cell_value_map);
|
||||
dependencies()->AssumeMapStable(property_cell_value_map);
|
||||
|
||||
// Check that the {value} is a HeapObject.
|
||||
value = effect = graph()->NewNode(simplified()->CheckHeapObject(),
|
||||
@ -715,7 +716,7 @@ Reduction JSNativeContextSpecialization::ReduceGlobalAccess(
|
||||
case PropertyCellType::kMutable: {
|
||||
// Record a code dependency on the cell, and just deoptimize if the
|
||||
// property ever becomes read-only.
|
||||
dependencies()->DependOnGlobalProperty(property_cell);
|
||||
dependencies()->AssumePropertyCell(property_cell);
|
||||
effect = graph()->NewNode(
|
||||
simplified()->StoreField(ForPropertyCellValue(
|
||||
MachineRepresentation::kTagged, Type::NonInternal(),
|
||||
@ -1096,7 +1097,8 @@ Reduction JSNativeContextSpecialization::ReduceJSLoadNamed(Node* node) {
|
||||
// {function} in order to be notified about changes to the
|
||||
// "prototype" of {function}.
|
||||
JSFunction::EnsureHasInitialMap(function);
|
||||
dependencies()->DependOnInitialMap(function);
|
||||
Handle<Map> initial_map(function->initial_map(), isolate());
|
||||
dependencies()->AssumeInitialMapCantChange(initial_map);
|
||||
Handle<Object> prototype(function->prototype(), isolate());
|
||||
Node* value = jsgraph()->Constant(prototype);
|
||||
ReplaceWithValue(node, value);
|
||||
@ -1230,7 +1232,7 @@ Reduction JSNativeContextSpecialization::ReduceElementAccess(
|
||||
|
||||
// Install dependencies on the relevant prototype maps.
|
||||
for (Handle<Map> prototype_map : prototype_maps) {
|
||||
dependencies()->DependOnStableMap(prototype_map);
|
||||
dependencies()->AssumeMapStable(prototype_map);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1800,9 +1802,8 @@ JSNativeContextSpecialization::BuildPropertyLoad(
|
||||
Handle<JSObject> holder;
|
||||
PropertyAccessBuilder access_builder(jsgraph(), dependencies());
|
||||
if (access_info.holder().ToHandle(&holder)) {
|
||||
dependencies()->DependOnStablePrototypeChains(
|
||||
native_context().object<Context>(), access_info.receiver_maps(),
|
||||
holder);
|
||||
dependencies()->AssumePrototypesStable(native_context().object<Context>(),
|
||||
access_info.receiver_maps(), holder);
|
||||
}
|
||||
|
||||
// Generate the actual property access.
|
||||
@ -1858,9 +1859,8 @@ JSNativeContextSpecialization::BuildPropertyStore(
|
||||
PropertyAccessBuilder access_builder(jsgraph(), dependencies());
|
||||
if (access_info.holder().ToHandle(&holder)) {
|
||||
DCHECK_NE(AccessMode::kStoreInLiteral, access_mode);
|
||||
dependencies()->DependOnStablePrototypeChains(
|
||||
native_context().object<Context>(), access_info.receiver_maps(),
|
||||
holder);
|
||||
dependencies()->AssumePrototypesStable(native_context().object<Context>(),
|
||||
access_info.receiver_maps(), holder);
|
||||
}
|
||||
|
||||
DCHECK(!access_info.IsNotFound());
|
||||
@ -2258,7 +2258,7 @@ JSNativeContextSpecialization::BuildElementAccess(
|
||||
if (isolate()->IsArrayBufferNeuteringIntact()) {
|
||||
// Add a code dependency so we are deoptimized in case an ArrayBuffer
|
||||
// gets neutered.
|
||||
dependencies()->DependOnProtector(
|
||||
dependencies()->AssumePropertyCell(
|
||||
factory()->array_buffer_neutering_protector());
|
||||
} else {
|
||||
// Default to zero if the {receiver}s buffer was neutered.
|
||||
@ -2661,7 +2661,8 @@ Node* JSNativeContextSpecialization::BuildIndexedStringLoad(
|
||||
KeyedAccessLoadMode load_mode) {
|
||||
if (load_mode == LOAD_IGNORE_OUT_OF_BOUNDS &&
|
||||
isolate()->IsNoElementsProtectorIntact()) {
|
||||
dependencies()->DependOnProtector(factory()->no_elements_protector());
|
||||
// Add a code dependency on the "no elements" protector.
|
||||
dependencies()->AssumePropertyCell(factory()->no_elements_protector());
|
||||
|
||||
// Ensure that the {index} is a valid String length.
|
||||
index = *effect = graph()->NewNode(
|
||||
@ -2810,7 +2811,8 @@ bool JSNativeContextSpecialization::CanTreatHoleAsUndefined(
|
||||
// Check if the array prototype chain is intact.
|
||||
if (!isolate()->IsNoElementsProtectorIntact()) return false;
|
||||
|
||||
dependencies()->DependOnProtector(factory()->no_elements_protector());
|
||||
// Install code dependency on the array protector cell.
|
||||
dependencies()->AssumePropertyCell(factory()->no_elements_protector());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -918,9 +918,7 @@ PipelineCompilationJob::Status PipelineCompilationJob::FinalizeJobImpl(
|
||||
}
|
||||
return FAILED;
|
||||
}
|
||||
if (!compilation_info()->dependencies()->Commit(code)) {
|
||||
return AbortOptimization(BailoutReason::kBailedOutDueToDependencyChange);
|
||||
}
|
||||
compilation_info()->dependencies()->Commit(code);
|
||||
compilation_info()->SetCode(code);
|
||||
|
||||
compilation_info()->context()->native_context()->AddOptimizedCode(*code);
|
||||
|
@ -136,7 +136,7 @@ void PropertyAccessBuilder::BuildCheckMaps(
|
||||
if (receiver_map->is_stable()) {
|
||||
for (Handle<Map> map : receiver_maps) {
|
||||
if (map.is_identical_to(receiver_map)) {
|
||||
dependencies()->DependOnStableMap(receiver_map);
|
||||
dependencies()->AssumeMapStable(receiver_map);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -195,17 +195,18 @@ Node* PropertyAccessBuilder::TryBuildLoadConstantDataField(
|
||||
// but for now let's just do what Crankshaft does.
|
||||
LookupIterator it(m.Value(), name, LookupIterator::OWN_SKIP_INTERCEPTOR);
|
||||
if (it.state() == LookupIterator::DATA) {
|
||||
bool is_readonly_non_configurable =
|
||||
bool is_reaonly_non_configurable =
|
||||
it.IsReadOnly() && !it.IsConfigurable();
|
||||
if (is_readonly_non_configurable ||
|
||||
if (is_reaonly_non_configurable ||
|
||||
(FLAG_track_constant_fields && access_info.IsDataConstantField())) {
|
||||
Node* value = jsgraph()->Constant(JSReceiver::GetDataProperty(&it));
|
||||
if (!is_readonly_non_configurable) {
|
||||
if (!is_reaonly_non_configurable) {
|
||||
// It's necessary to add dependency on the map that introduced
|
||||
// the field.
|
||||
DCHECK(access_info.IsDataConstantField());
|
||||
DCHECK(!it.is_dictionary_holder());
|
||||
dependencies()->DependOnFieldType(&it);
|
||||
Handle<Map> field_owner_map = it.GetFieldOwnerMap();
|
||||
dependencies()->AssumeFieldOwner(field_owner_map);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
@ -263,7 +264,7 @@ Node* PropertyAccessBuilder::BuildLoadDataField(
|
||||
Handle<Map> field_map;
|
||||
if (access_info.field_map().ToHandle(&field_map)) {
|
||||
if (field_map->is_stable()) {
|
||||
dependencies()->DependOnStableMap(field_map);
|
||||
dependencies()->AssumeMapStable(field_map);
|
||||
field_access.map = field_map;
|
||||
}
|
||||
}
|
||||
|
@ -148,7 +148,7 @@ Reduction TypedOptimization::ReduceCheckMaps(Node* node) {
|
||||
if (map_type.IsHeapConstant() &&
|
||||
map_type.AsHeapConstant()->Value().is_identical_to(object_map)) {
|
||||
if (object_map->CanTransition()) {
|
||||
dependencies()->DependOnStableMap(object_map);
|
||||
dependencies()->AssumeMapStable(object_map);
|
||||
}
|
||||
return Replace(effect);
|
||||
}
|
||||
@ -213,7 +213,7 @@ Reduction TypedOptimization::ReduceLoadField(Node* node) {
|
||||
Handle<Map> object_map;
|
||||
if (GetStableMapFromObjectType(object_type).ToHandle(&object_map)) {
|
||||
if (object_map->CanTransition()) {
|
||||
dependencies()->DependOnStableMap(object_map);
|
||||
dependencies()->AssumeMapStable(object_map);
|
||||
}
|
||||
Node* const value = jsgraph()->HeapConstant(object_map);
|
||||
ReplaceWithValue(node, value);
|
||||
|
@ -2553,7 +2553,7 @@ MaybeHandle<Code> Factory::TryNewCode(
|
||||
Heap* heap = isolate()->heap();
|
||||
CodePageCollectionMemoryModificationScope code_allocation(heap);
|
||||
HeapObject* result =
|
||||
heap->AllocateRawWithLightRetry(object_size, CODE_SPACE);
|
||||
heap->AllocateRawWithLigthRetry(object_size, CODE_SPACE);
|
||||
|
||||
// Return an empty handle if we cannot allocate the code object.
|
||||
if (!result) return MaybeHandle<Code>();
|
||||
|
@ -4473,7 +4473,7 @@ HeapObject* Heap::EnsureImmovableCode(HeapObject* heap_object,
|
||||
return heap_object;
|
||||
}
|
||||
|
||||
HeapObject* Heap::AllocateRawWithLightRetry(int size, AllocationSpace space,
|
||||
HeapObject* Heap::AllocateRawWithLigthRetry(int size, AllocationSpace space,
|
||||
AllocationAlignment alignment) {
|
||||
HeapObject* result;
|
||||
AllocationResult alloc = AllocateRaw(size, space, alignment);
|
||||
@ -4497,7 +4497,7 @@ HeapObject* Heap::AllocateRawWithLightRetry(int size, AllocationSpace space,
|
||||
HeapObject* Heap::AllocateRawWithRetryOrFail(int size, AllocationSpace space,
|
||||
AllocationAlignment alignment) {
|
||||
AllocationResult alloc;
|
||||
HeapObject* result = AllocateRawWithLightRetry(size, space, alignment);
|
||||
HeapObject* result = AllocateRawWithLigthRetry(size, space, alignment);
|
||||
if (result) return result;
|
||||
|
||||
isolate()->counters()->gc_last_resort_from_handles()->Increment();
|
||||
|
@ -1910,7 +1910,7 @@ class Heap {
|
||||
// triggered and the allocation is retried. This is performed multiple times.
|
||||
// If after that retry procedure the allocation still fails nullptr is
|
||||
// returned.
|
||||
HeapObject* AllocateRawWithLightRetry(
|
||||
HeapObject* AllocateRawWithLigthRetry(
|
||||
int size, AllocationSpace space,
|
||||
AllocationAlignment alignment = kWordAligned);
|
||||
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "src/bootstrapper.h"
|
||||
#include "src/builtins/builtins.h"
|
||||
#include "src/code-stubs.h"
|
||||
#include "src/compilation-dependencies.h"
|
||||
#include "src/compiler.h"
|
||||
#include "src/counters-inl.h"
|
||||
#include "src/counters.h"
|
||||
@ -15017,6 +15018,34 @@ bool DependentCode::Compact() {
|
||||
}
|
||||
|
||||
|
||||
void DependentCode::UpdateToFinishedCode(DependencyGroup group, Foreign* info,
|
||||
WeakCell* code_cell) {
|
||||
if (this->length() == 0 || this->group() > group) {
|
||||
// There is no such group.
|
||||
return;
|
||||
}
|
||||
if (this->group() < group) {
|
||||
// The group comes later in the list.
|
||||
next_link()->UpdateToFinishedCode(group, info, code_cell);
|
||||
return;
|
||||
}
|
||||
DCHECK_EQ(group, this->group());
|
||||
DisallowHeapAllocation no_gc;
|
||||
int count = this->count();
|
||||
for (int i = 0; i < count; i++) {
|
||||
if (object_at(i) == info) {
|
||||
set_object_at(i, code_cell);
|
||||
break;
|
||||
}
|
||||
}
|
||||
#ifdef DEBUG
|
||||
for (int i = 0; i < count; i++) {
|
||||
DCHECK(object_at(i) != info);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void DependentCode::RemoveCompilationDependencies(
|
||||
DependentCode::DependencyGroup group, Foreign* info) {
|
||||
if (this->length() == 0 || this->group() > group) {
|
||||
@ -15105,12 +15134,20 @@ bool DependentCode::MarkCodeForDeoptimization(
|
||||
int count = this->count();
|
||||
for (int i = 0; i < count; i++) {
|
||||
Object* obj = object_at(i);
|
||||
WeakCell* cell = WeakCell::cast(obj);
|
||||
if (cell->cleared()) continue;
|
||||
Code* code = Code::cast(cell->value());
|
||||
if (!code->marked_for_deoptimization()) {
|
||||
code->SetMarkedForDeoptimization(DependencyGroupName(group));
|
||||
marked = true;
|
||||
if (obj->IsWeakCell()) {
|
||||
WeakCell* cell = WeakCell::cast(obj);
|
||||
if (cell->cleared()) continue;
|
||||
Code* code = Code::cast(cell->value());
|
||||
if (!code->marked_for_deoptimization()) {
|
||||
code->SetMarkedForDeoptimization(DependencyGroupName(group));
|
||||
marked = true;
|
||||
}
|
||||
} else {
|
||||
DCHECK(obj->IsForeign());
|
||||
CompilationDependencies* info =
|
||||
reinterpret_cast<CompilationDependencies*>(
|
||||
Foreign::cast(obj)->foreign_address());
|
||||
info->Abort();
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < count; i++) {
|
||||
|
@ -624,6 +624,9 @@ class DependentCode : public FixedArray {
|
||||
DependencyGroup group,
|
||||
Handle<WeakCell> code_cell);
|
||||
|
||||
void UpdateToFinishedCode(DependencyGroup group, Foreign* info,
|
||||
WeakCell* code_cell);
|
||||
|
||||
void RemoveCompilationDependencies(DependentCode::DependencyGroup group,
|
||||
Foreign* info);
|
||||
|
||||
|
@ -87,6 +87,9 @@ OptimizedCompilationInfo::~OptimizedCompilationInfo() {
|
||||
if (GetFlag(kDisableFutureOptimization) && has_shared_info()) {
|
||||
shared_info()->DisableOptimization(bailout_reason());
|
||||
}
|
||||
if (dependencies()) {
|
||||
dependencies()->Rollback();
|
||||
}
|
||||
}
|
||||
|
||||
void OptimizedCompilationInfo::set_deferred_handles(
|
||||
|
@ -309,7 +309,6 @@ class V8_EXPORT_PRIVATE OptimizedCompilationInfo final {
|
||||
std::shared_ptr<DeferredHandles> deferred_handles_;
|
||||
|
||||
// Dependencies for this compilation, e.g. stable maps.
|
||||
// TODO(neis): Move this to PipelineData.
|
||||
std::unique_ptr<CompilationDependencies> dependencies_;
|
||||
|
||||
BailoutReason bailout_reason_;
|
||||
|
@ -153,7 +153,7 @@ Handle<JSFunction> FunctionTester::Compile(Handle<JSFunction> function) {
|
||||
|
||||
Handle<Code> code =
|
||||
Pipeline::GenerateCodeForTesting(&info, isolate).ToHandleChecked();
|
||||
CHECK(info.dependencies()->Commit(code));
|
||||
info.dependencies()->Commit(code);
|
||||
info.context()->native_context()->AddOptimizedCode(*code);
|
||||
function->set_code(*code);
|
||||
return function;
|
||||
|
@ -477,7 +477,6 @@ TEST(ReconfigureAccessorToNonExistingDataField) {
|
||||
CcTest::InitializeVM();
|
||||
v8::HandleScope scope(CcTest::isolate());
|
||||
Isolate* isolate = CcTest::i_isolate();
|
||||
|
||||
Handle<FieldType> any_type = FieldType::Any(isolate);
|
||||
Handle<FieldType> none_type = FieldType::None(isolate);
|
||||
Handle<AccessorPair> pair = CreateAccessorPair(true, true);
|
||||
@ -541,9 +540,9 @@ TEST(ReconfigureAccessorToNonExistingDataField) {
|
||||
// to a map with a property with None representation.
|
||||
TEST(ReconfigureAccessorToNonExistingDataFieldHeavy) {
|
||||
CcTest::InitializeVM();
|
||||
v8::HandleScope scope(CcTest::isolate());
|
||||
Isolate* isolate = CcTest::i_isolate();
|
||||
Factory* factory = isolate->factory();
|
||||
v8::HandleScope scope(CcTest::isolate());
|
||||
|
||||
CompileRun(
|
||||
"function getter() { return 1; };"
|
||||
@ -654,7 +653,9 @@ static void TestGeneralizeField(int detach_property_at_index,
|
||||
Handle<Map> field_owner(map->FindFieldOwner(isolate, property_index),
|
||||
isolate);
|
||||
CompilationDependencies dependencies(isolate, &zone);
|
||||
dependencies.DependOnFieldType(map, property_index);
|
||||
CHECK(!dependencies.HasAborted());
|
||||
|
||||
dependencies.AssumeFieldOwner(field_owner);
|
||||
|
||||
Handle<Map> new_map = Map::ReconfigureProperty(
|
||||
isolate, map, property_index, kData, NONE, to.representation, to.type);
|
||||
@ -670,21 +671,21 @@ static void TestGeneralizeField(int detach_property_at_index,
|
||||
CHECK(map->is_deprecated());
|
||||
CHECK_NE(*map, *new_map);
|
||||
CHECK_EQ(expected_field_type_dependency && !field_owner->is_deprecated(),
|
||||
!dependencies.AreValid());
|
||||
dependencies.HasAborted());
|
||||
|
||||
} else if (expected_deprecation) {
|
||||
CHECK(!map->is_stable());
|
||||
CHECK(map->is_deprecated());
|
||||
CHECK(field_owner->is_deprecated());
|
||||
CHECK_NE(*map, *new_map);
|
||||
CHECK(dependencies.AreValid());
|
||||
CHECK(!dependencies.HasAborted());
|
||||
|
||||
} else {
|
||||
CHECK(!field_owner->is_deprecated());
|
||||
CHECK(map->is_stable()); // Map did not change, must be left stable.
|
||||
CHECK_EQ(*map, *new_map);
|
||||
|
||||
CHECK_EQ(expected_field_type_dependency, !dependencies.AreValid());
|
||||
CHECK_EQ(expected_field_type_dependency, dependencies.HasAborted());
|
||||
}
|
||||
|
||||
{
|
||||
@ -698,6 +699,8 @@ static void TestGeneralizeField(int detach_property_at_index,
|
||||
}
|
||||
}
|
||||
|
||||
dependencies.Rollback(); // Properly cleanup compilation info.
|
||||
|
||||
// Update all deprecated maps and check that they are now the same.
|
||||
Handle<Map> updated_map = Map::Update(isolate, map);
|
||||
CHECK_EQ(*new_map, *updated_map);
|
||||
@ -754,7 +757,6 @@ TEST(GeneralizeSmiFieldToDouble) {
|
||||
CcTest::InitializeVM();
|
||||
v8::HandleScope scope(CcTest::isolate());
|
||||
Isolate* isolate = CcTest::i_isolate();
|
||||
|
||||
Handle<FieldType> any_type = FieldType::Any(isolate);
|
||||
|
||||
TestGeneralizeField(
|
||||
@ -767,7 +769,6 @@ TEST(GeneralizeSmiFieldToTagged) {
|
||||
CcTest::InitializeVM();
|
||||
v8::HandleScope scope(CcTest::isolate());
|
||||
Isolate* isolate = CcTest::i_isolate();
|
||||
|
||||
Handle<FieldType> any_type = FieldType::Any(isolate);
|
||||
Handle<FieldType> value_type =
|
||||
FieldType::Class(Map::Create(isolate, 0), isolate);
|
||||
@ -782,7 +783,6 @@ TEST(GeneralizeDoubleFieldToTagged) {
|
||||
CcTest::InitializeVM();
|
||||
v8::HandleScope scope(CcTest::isolate());
|
||||
Isolate* isolate = CcTest::i_isolate();
|
||||
|
||||
Handle<FieldType> any_type = FieldType::Any(isolate);
|
||||
Handle<FieldType> value_type =
|
||||
FieldType::Class(Map::Create(isolate, 0), isolate);
|
||||
@ -797,7 +797,6 @@ TEST(GeneralizeHeapObjectFieldToTagged) {
|
||||
CcTest::InitializeVM();
|
||||
v8::HandleScope scope(CcTest::isolate());
|
||||
Isolate* isolate = CcTest::i_isolate();
|
||||
|
||||
Handle<FieldType> any_type = FieldType::Any(isolate);
|
||||
Handle<FieldType> value_type =
|
||||
FieldType::Class(Map::Create(isolate, 0), isolate);
|
||||
@ -812,7 +811,6 @@ TEST(GeneralizeHeapObjectFieldToHeapObject) {
|
||||
CcTest::InitializeVM();
|
||||
v8::HandleScope scope(CcTest::isolate());
|
||||
Isolate* isolate = CcTest::i_isolate();
|
||||
|
||||
Handle<FieldType> any_type = FieldType::Any(isolate);
|
||||
|
||||
Handle<FieldType> current_type =
|
||||
@ -843,7 +841,6 @@ TEST(GeneralizeNoneFieldToSmi) {
|
||||
CcTest::InitializeVM();
|
||||
v8::HandleScope scope(CcTest::isolate());
|
||||
Isolate* isolate = CcTest::i_isolate();
|
||||
|
||||
Handle<FieldType> none_type = FieldType::None(isolate);
|
||||
Handle<FieldType> any_type = FieldType::Any(isolate);
|
||||
|
||||
@ -858,7 +855,6 @@ TEST(GeneralizeNoneFieldToDouble) {
|
||||
CcTest::InitializeVM();
|
||||
v8::HandleScope scope(CcTest::isolate());
|
||||
Isolate* isolate = CcTest::i_isolate();
|
||||
|
||||
Handle<FieldType> none_type = FieldType::None(isolate);
|
||||
Handle<FieldType> any_type = FieldType::Any(isolate);
|
||||
|
||||
@ -873,7 +869,6 @@ TEST(GeneralizeNoneFieldToHeapObject) {
|
||||
CcTest::InitializeVM();
|
||||
v8::HandleScope scope(CcTest::isolate());
|
||||
Isolate* isolate = CcTest::i_isolate();
|
||||
|
||||
Handle<FieldType> none_type = FieldType::None(isolate);
|
||||
Handle<FieldType> value_type =
|
||||
FieldType::Class(Map::Create(isolate, 0), isolate);
|
||||
@ -889,7 +884,6 @@ TEST(GeneralizeNoneFieldToTagged) {
|
||||
CcTest::InitializeVM();
|
||||
v8::HandleScope scope(CcTest::isolate());
|
||||
Isolate* isolate = CcTest::i_isolate();
|
||||
|
||||
Handle<FieldType> none_type = FieldType::None(isolate);
|
||||
Handle<FieldType> any_type = FieldType::Any(isolate);
|
||||
|
||||
@ -909,7 +903,6 @@ TEST(GeneralizeFieldWithAccessorProperties) {
|
||||
CcTest::InitializeVM();
|
||||
v8::HandleScope scope(CcTest::isolate());
|
||||
Isolate* isolate = CcTest::i_isolate();
|
||||
|
||||
Handle<FieldType> any_type = FieldType::Any(isolate);
|
||||
Handle<AccessorPair> pair = CreateAccessorPair(true, true);
|
||||
|
||||
@ -1021,8 +1014,10 @@ static void TestReconfigureDataFieldAttribute_GeneralizeField(
|
||||
CHECK(expectations2.Check(*map2));
|
||||
|
||||
Zone zone(isolate->allocator(), ZONE_NAME);
|
||||
Handle<Map> field_owner(map->FindFieldOwner(isolate, kSplitProp), isolate);
|
||||
CompilationDependencies dependencies(isolate, &zone);
|
||||
dependencies.DependOnFieldType(map, kSplitProp);
|
||||
CHECK(!dependencies.HasAborted());
|
||||
dependencies.AssumeFieldOwner(field_owner);
|
||||
|
||||
// Reconfigure attributes of property |kSplitProp| of |map2| to NONE, which
|
||||
// should generalize representations in |map1|.
|
||||
@ -1041,7 +1036,8 @@ static void TestReconfigureDataFieldAttribute_GeneralizeField(
|
||||
expected.type);
|
||||
}
|
||||
CHECK(map->is_deprecated());
|
||||
CHECK(dependencies.AreValid());
|
||||
CHECK(!dependencies.HasAborted());
|
||||
dependencies.Rollback(); // Properly cleanup compilation info.
|
||||
CHECK_NE(*map, *new_map);
|
||||
|
||||
CHECK(!new_map->is_deprecated());
|
||||
@ -1103,8 +1099,10 @@ static void TestReconfigureDataFieldAttribute_GeneralizeFieldTrivial(
|
||||
CHECK(expectations2.Check(*map2));
|
||||
|
||||
Zone zone(isolate->allocator(), ZONE_NAME);
|
||||
Handle<Map> field_owner(map->FindFieldOwner(isolate, kSplitProp), isolate);
|
||||
CompilationDependencies dependencies(isolate, &zone);
|
||||
dependencies.DependOnFieldType(map, kSplitProp);
|
||||
CHECK(!dependencies.HasAborted());
|
||||
dependencies.AssumeFieldOwner(field_owner);
|
||||
|
||||
// Reconfigure attributes of property |kSplitProp| of |map2| to NONE, which
|
||||
// should generalize representations in |map1|.
|
||||
@ -1127,7 +1125,8 @@ static void TestReconfigureDataFieldAttribute_GeneralizeFieldTrivial(
|
||||
}
|
||||
CHECK(!map->is_deprecated());
|
||||
CHECK_EQ(*map, *new_map);
|
||||
CHECK_EQ(expected_field_type_dependency, !dependencies.AreValid());
|
||||
CHECK_EQ(expected_field_type_dependency, dependencies.HasAborted());
|
||||
dependencies.Rollback(); // Properly cleanup compilation info.
|
||||
|
||||
CHECK(!new_map->is_deprecated());
|
||||
CHECK(expectations.Check(*new_map));
|
||||
@ -1140,7 +1139,6 @@ TEST(ReconfigureDataFieldAttribute_GeneralizeSmiFieldToDouble) {
|
||||
CcTest::InitializeVM();
|
||||
v8::HandleScope scope(CcTest::isolate());
|
||||
Isolate* isolate = CcTest::i_isolate();
|
||||
|
||||
Handle<FieldType> any_type = FieldType::Any(isolate);
|
||||
|
||||
if (FLAG_track_constant_fields) {
|
||||
@ -1170,7 +1168,6 @@ TEST(ReconfigureDataFieldAttribute_GeneralizeSmiFieldToTagged) {
|
||||
CcTest::InitializeVM();
|
||||
v8::HandleScope scope(CcTest::isolate());
|
||||
Isolate* isolate = CcTest::i_isolate();
|
||||
|
||||
Handle<FieldType> any_type = FieldType::Any(isolate);
|
||||
Handle<FieldType> value_type =
|
||||
FieldType::Class(Map::Create(isolate, 0), isolate);
|
||||
@ -1202,7 +1199,6 @@ TEST(ReconfigureDataFieldAttribute_GeneralizeDoubleFieldToTagged) {
|
||||
CcTest::InitializeVM();
|
||||
v8::HandleScope scope(CcTest::isolate());
|
||||
Isolate* isolate = CcTest::i_isolate();
|
||||
|
||||
Handle<FieldType> any_type = FieldType::Any(isolate);
|
||||
Handle<FieldType> value_type =
|
||||
FieldType::Class(Map::Create(isolate, 0), isolate);
|
||||
@ -1234,7 +1230,6 @@ TEST(ReconfigureDataFieldAttribute_GeneralizeHeapObjFieldToHeapObj) {
|
||||
CcTest::InitializeVM();
|
||||
v8::HandleScope scope(CcTest::isolate());
|
||||
Isolate* isolate = CcTest::i_isolate();
|
||||
|
||||
Handle<FieldType> any_type = FieldType::Any(isolate);
|
||||
|
||||
Handle<FieldType> current_type =
|
||||
@ -1330,7 +1325,6 @@ TEST(ReconfigureDataFieldAttribute_GeneralizeHeapObjectFieldToTagged) {
|
||||
CcTest::InitializeVM();
|
||||
v8::HandleScope scope(CcTest::isolate());
|
||||
Isolate* isolate = CcTest::i_isolate();
|
||||
|
||||
Handle<FieldType> any_type = FieldType::Any(isolate);
|
||||
Handle<FieldType> value_type =
|
||||
FieldType::Class(Map::Create(isolate, 0), isolate);
|
||||
@ -1782,8 +1776,10 @@ static void TestReconfigureElementsKind_GeneralizeField(
|
||||
CHECK(expectations2.Check(*map2));
|
||||
|
||||
Zone zone(isolate->allocator(), ZONE_NAME);
|
||||
Handle<Map> field_owner(map->FindFieldOwner(isolate, kDiffProp), isolate);
|
||||
CompilationDependencies dependencies(isolate, &zone);
|
||||
dependencies.DependOnFieldType(map, kDiffProp);
|
||||
CHECK(!dependencies.HasAborted());
|
||||
dependencies.AssumeFieldOwner(field_owner);
|
||||
|
||||
// Reconfigure elements kinds of |map2|, which should generalize
|
||||
// representations in |map|.
|
||||
@ -1801,7 +1797,8 @@ static void TestReconfigureElementsKind_GeneralizeField(
|
||||
expected.representation, expected.type);
|
||||
|
||||
CHECK(map->is_deprecated());
|
||||
CHECK(dependencies.AreValid());
|
||||
CHECK(!dependencies.HasAborted());
|
||||
dependencies.Rollback(); // Properly cleanup compilation info.
|
||||
CHECK_NE(*map, *new_map);
|
||||
|
||||
CHECK(!new_map->is_deprecated());
|
||||
@ -1875,8 +1872,10 @@ static void TestReconfigureElementsKind_GeneralizeFieldTrivial(
|
||||
CHECK(expectations2.Check(*map2));
|
||||
|
||||
Zone zone(isolate->allocator(), ZONE_NAME);
|
||||
Handle<Map> field_owner(map->FindFieldOwner(isolate, kDiffProp), isolate);
|
||||
CompilationDependencies dependencies(isolate, &zone);
|
||||
dependencies.DependOnFieldType(map, kDiffProp);
|
||||
CHECK(!dependencies.HasAborted());
|
||||
dependencies.AssumeFieldOwner(field_owner);
|
||||
|
||||
// Reconfigure elements kinds of |map2|, which should generalize
|
||||
// representations in |map|.
|
||||
@ -1897,7 +1896,8 @@ static void TestReconfigureElementsKind_GeneralizeFieldTrivial(
|
||||
expected.representation, expected.type);
|
||||
CHECK(!map->is_deprecated());
|
||||
CHECK_EQ(*map, *new_map);
|
||||
CHECK(dependencies.AreValid());
|
||||
CHECK(!dependencies.HasAborted());
|
||||
dependencies.Rollback(); // Properly cleanup compilation info.
|
||||
|
||||
CHECK(!new_map->is_deprecated());
|
||||
CHECK(expectations.Check(*new_map));
|
||||
@ -1920,7 +1920,6 @@ TEST(ReconfigureElementsKind_GeneralizeSmiFieldToDouble) {
|
||||
CcTest::InitializeVM();
|
||||
v8::HandleScope scope(CcTest::isolate());
|
||||
Isolate* isolate = CcTest::i_isolate();
|
||||
|
||||
Handle<FieldType> any_type = FieldType::Any(isolate);
|
||||
|
||||
if (FLAG_track_constant_fields) {
|
||||
@ -1949,7 +1948,6 @@ TEST(ReconfigureElementsKind_GeneralizeSmiFieldToTagged) {
|
||||
CcTest::InitializeVM();
|
||||
v8::HandleScope scope(CcTest::isolate());
|
||||
Isolate* isolate = CcTest::i_isolate();
|
||||
|
||||
Handle<FieldType> any_type = FieldType::Any(isolate);
|
||||
Handle<FieldType> value_type =
|
||||
FieldType::Class(Map::Create(isolate, 0), isolate);
|
||||
@ -1980,7 +1978,6 @@ TEST(ReconfigureElementsKind_GeneralizeDoubleFieldToTagged) {
|
||||
CcTest::InitializeVM();
|
||||
v8::HandleScope scope(CcTest::isolate());
|
||||
Isolate* isolate = CcTest::i_isolate();
|
||||
|
||||
Handle<FieldType> any_type = FieldType::Any(isolate);
|
||||
Handle<FieldType> value_type =
|
||||
FieldType::Class(Map::Create(isolate, 0), isolate);
|
||||
@ -2011,7 +2008,6 @@ TEST(ReconfigureElementsKind_GeneralizeHeapObjFieldToHeapObj) {
|
||||
CcTest::InitializeVM();
|
||||
v8::HandleScope scope(CcTest::isolate());
|
||||
Isolate* isolate = CcTest::i_isolate();
|
||||
|
||||
Handle<FieldType> any_type = FieldType::Any(isolate);
|
||||
|
||||
Handle<FieldType> current_type =
|
||||
@ -2104,7 +2100,6 @@ TEST(ReconfigureElementsKind_GeneralizeHeapObjectFieldToTagged) {
|
||||
CcTest::InitializeVM();
|
||||
v8::HandleScope scope(CcTest::isolate());
|
||||
Isolate* isolate = CcTest::i_isolate();
|
||||
|
||||
Handle<FieldType> any_type = FieldType::Any(isolate);
|
||||
Handle<FieldType> value_type =
|
||||
FieldType::Class(Map::Create(isolate, 0), isolate);
|
||||
@ -2139,7 +2134,6 @@ TEST(ReconfigurePropertySplitMapTransitionsOverflow) {
|
||||
CcTest::InitializeVM();
|
||||
v8::HandleScope scope(CcTest::isolate());
|
||||
Isolate* isolate = CcTest::i_isolate();
|
||||
|
||||
Handle<FieldType> any_type = FieldType::Any(isolate);
|
||||
|
||||
Expectations expectations(isolate);
|
||||
@ -2328,7 +2322,6 @@ TEST(ElementsKindTransitionFromMapOwningDescriptor) {
|
||||
CcTest::InitializeVM();
|
||||
v8::HandleScope scope(CcTest::isolate());
|
||||
Isolate* isolate = CcTest::i_isolate();
|
||||
|
||||
Handle<FieldType> any_type = FieldType::Any(isolate);
|
||||
Handle<FieldType> value_type =
|
||||
FieldType::Class(Map::Create(isolate, 0), isolate);
|
||||
@ -2358,7 +2351,6 @@ TEST(ElementsKindTransitionFromMapNotOwningDescriptor) {
|
||||
CcTest::InitializeVM();
|
||||
v8::HandleScope scope(CcTest::isolate());
|
||||
Isolate* isolate = CcTest::i_isolate();
|
||||
|
||||
Handle<FieldType> any_type = FieldType::Any(isolate);
|
||||
Handle<FieldType> value_type =
|
||||
FieldType::Class(Map::Create(isolate, 0), isolate);
|
||||
@ -2680,7 +2672,6 @@ TEST(TransitionDataFieldToDataField) {
|
||||
CcTest::InitializeVM();
|
||||
v8::HandleScope scope(CcTest::isolate());
|
||||
Isolate* isolate = CcTest::i_isolate();
|
||||
|
||||
Handle<FieldType> any_type = FieldType::Any(isolate);
|
||||
|
||||
Handle<Object> value1 = handle(Smi::kZero, isolate);
|
||||
@ -2717,7 +2708,6 @@ TEST(TransitionDataConstantToAnotherDataConstant) {
|
||||
v8::HandleScope scope(CcTest::isolate());
|
||||
Isolate* isolate = CcTest::i_isolate();
|
||||
Factory* factory = isolate->factory();
|
||||
|
||||
Handle<String> name = factory->empty_string();
|
||||
Handle<Map> sloppy_map =
|
||||
Map::CopyInitialMap(isolate, isolate->sloppy_function_map());
|
||||
@ -2752,7 +2742,6 @@ TEST(TransitionDataConstantToDataField) {
|
||||
v8::HandleScope scope(CcTest::isolate());
|
||||
Isolate* isolate = CcTest::i_isolate();
|
||||
Factory* factory = isolate->factory();
|
||||
|
||||
Handle<FieldType> any_type = FieldType::Any(isolate);
|
||||
|
||||
Handle<JSFunction> js_func1 =
|
||||
|
@ -57,6 +57,11 @@ class JSCallReducerTest : public TypedGraphTest {
|
||||
i::FLAG_lazy_handler_deserialization = old_flag_lazy_handler_;
|
||||
}
|
||||
|
||||
// Ensure uncommitted compilation dependencies are discarded after each test.
|
||||
// This prevents use-after-free accesses through invalidation of compilation
|
||||
// dependencies.
|
||||
void TearDown() override { deps_.Rollback(); }
|
||||
|
||||
Node* GlobalFunction(const char* name) {
|
||||
Handle<JSFunction> f = Handle<JSFunction>::cast(
|
||||
Object::GetProperty(
|
||||
|
Loading…
Reference in New Issue
Block a user