[turbofan] Allow for multiple re-serializations of a function
Implement the possibility to revisit the same function in the serializer using equality of its arguments. Bug: v8:7790 Change-Id: I609a6009bf503e378e50d0b32c6f1c13721d2557 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1863198 Commit-Queue: Maya Lekova <mslekova@chromium.org> Reviewed-by: Georg Neis <neis@chromium.org> Cr-Commit-Position: refs/heads/master@{#64683}
This commit is contained in:
parent
35b5ada087
commit
45a2058b48
1
BUILD.gn
1
BUILD.gn
@ -1820,6 +1820,7 @@ v8_compiler_sources = [
|
||||
"src/compiler/select-lowering.h",
|
||||
"src/compiler/serializer-for-background-compilation.cc",
|
||||
"src/compiler/serializer-for-background-compilation.h",
|
||||
"src/compiler/serializer-hints.h",
|
||||
"src/compiler/simd-scalar-lowering.cc",
|
||||
"src/compiler/simd-scalar-lowering.h",
|
||||
"src/compiler/simplified-lowering.cc",
|
||||
|
@ -4168,7 +4168,7 @@ void BuildGraphFromBytecode(JSHeapBroker* broker, Zone* local_zone,
|
||||
SourcePositionTable* source_positions,
|
||||
int inlining_id, BytecodeGraphBuilderFlags flags,
|
||||
TickCounter* tick_counter) {
|
||||
DCHECK(shared_info.IsSerializedForCompilation(feedback_vector));
|
||||
DCHECK(broker->IsSerializedForCompilation(shared_info, feedback_vector));
|
||||
BytecodeGraphBuilder builder(
|
||||
broker, local_zone, broker->target_native_context(), shared_info,
|
||||
feedback_vector, osr_offset, jsgraph, invocation_frequency,
|
||||
|
@ -803,9 +803,6 @@ class V8_EXPORT_PRIVATE SharedFunctionInfoRef : public HeapObjectRef {
|
||||
return GetInlineability() == SharedFunctionInfo::kIsInlineable;
|
||||
}
|
||||
|
||||
bool IsSerializedForCompilation(FeedbackVectorRef feedback) const;
|
||||
void SetSerializedForCompilation(FeedbackVectorRef feedback);
|
||||
|
||||
// Template objects may not be created at compilation time. This method
|
||||
// wraps the retrieval of the template object and creates it if
|
||||
// necessary.
|
||||
|
@ -1645,9 +1645,6 @@ class SharedFunctionInfoData : public HeapObjectData {
|
||||
int builtin_id() const { return builtin_id_; }
|
||||
int context_header_size() const { return context_header_size_; }
|
||||
BytecodeArrayData* GetBytecodeArray() const { return GetBytecodeArray_; }
|
||||
void SetSerializedForCompilation(JSHeapBroker* broker,
|
||||
FeedbackVectorRef feedback);
|
||||
bool IsSerializedForCompilation(FeedbackVectorRef feedback) const;
|
||||
void SerializeFunctionTemplateInfo(JSHeapBroker* broker);
|
||||
ScopeInfoData* scope_info() const { return scope_info_; }
|
||||
void SerializeScopeInfoChain(JSHeapBroker* broker);
|
||||
@ -1675,9 +1672,6 @@ class SharedFunctionInfoData : public HeapObjectData {
|
||||
int const builtin_id_;
|
||||
int context_header_size_;
|
||||
BytecodeArrayData* const GetBytecodeArray_;
|
||||
ZoneUnorderedSet<Handle<FeedbackVector>, Handle<FeedbackVector>::hash,
|
||||
Handle<FeedbackVector>::equal_to>
|
||||
serialized_for_compilation_;
|
||||
#define DECL_MEMBER(type, name) type const name##_;
|
||||
BROKER_SFI_FIELDS(DECL_MEMBER)
|
||||
#undef DECL_MEMBER
|
||||
@ -1697,8 +1691,7 @@ SharedFunctionInfoData::SharedFunctionInfoData(
|
||||
object->HasBytecodeArray()
|
||||
? broker->GetOrCreateData(object->GetBytecodeArray())
|
||||
->AsBytecodeArray()
|
||||
: nullptr),
|
||||
serialized_for_compilation_(broker->zone())
|
||||
: nullptr)
|
||||
#define INIT_MEMBER(type, name) , name##_(object->name())
|
||||
BROKER_SFI_FIELDS(INIT_MEMBER)
|
||||
#undef INIT_MEMBER
|
||||
@ -1710,13 +1703,6 @@ SharedFunctionInfoData::SharedFunctionInfoData(
|
||||
DCHECK_EQ(HasBytecodeArray_, GetBytecodeArray_ != nullptr);
|
||||
}
|
||||
|
||||
void SharedFunctionInfoData::SetSerializedForCompilation(
|
||||
JSHeapBroker* broker, FeedbackVectorRef feedback) {
|
||||
CHECK(serialized_for_compilation_.insert(feedback.object()).second);
|
||||
TRACE(broker, "Set function " << this << " with " << feedback
|
||||
<< " as serialized for compilation");
|
||||
}
|
||||
|
||||
void SharedFunctionInfoData::SerializeFunctionTemplateInfo(
|
||||
JSHeapBroker* broker) {
|
||||
if (function_template_info_) return;
|
||||
@ -1739,12 +1725,6 @@ void SharedFunctionInfoData::SerializeScopeInfoChain(JSHeapBroker* broker) {
|
||||
scope_info_->SerializeScopeInfoChain(broker);
|
||||
}
|
||||
|
||||
bool SharedFunctionInfoData::IsSerializedForCompilation(
|
||||
FeedbackVectorRef feedback) const {
|
||||
return serialized_for_compilation_.find(feedback.object()) !=
|
||||
serialized_for_compilation_.end();
|
||||
}
|
||||
|
||||
class SourceTextModuleData : public HeapObjectData {
|
||||
public:
|
||||
SourceTextModuleData(JSHeapBroker* broker, ObjectData** storage,
|
||||
@ -2280,7 +2260,8 @@ JSHeapBroker::JSHeapBroker(Isolate* isolate, Zone* broker_zone,
|
||||
feedback_(zone()),
|
||||
bytecode_analyses_(zone()),
|
||||
property_access_infos_(zone()),
|
||||
typed_array_string_tags_(zone()) {
|
||||
typed_array_string_tags_(zone()),
|
||||
serialized_functions_(zone()) {
|
||||
// Note that this initialization of {refs_} with the minimal initial capacity
|
||||
// is redundant in the normal use case (concurrent compilation enabled,
|
||||
// standard objects to be serialized), as the map is going to be replaced
|
||||
@ -2531,6 +2512,42 @@ StringRef JSHeapBroker::GetTypedArrayStringTag(ElementsKind kind) {
|
||||
return StringRef(this, typed_array_string_tags_[idx]);
|
||||
}
|
||||
|
||||
bool JSHeapBroker::ShouldBeSerializedForCompilation(
|
||||
const SharedFunctionInfoRef& shared, const FeedbackVectorRef& feedback,
|
||||
const HintsVector& arguments) const {
|
||||
SerializedFunction function{shared, feedback};
|
||||
auto matching_functions = serialized_functions_.equal_range(function);
|
||||
return std::find_if(matching_functions.first, matching_functions.second,
|
||||
[&arguments](const auto& entry) {
|
||||
return entry.second == arguments;
|
||||
}) == matching_functions.second;
|
||||
}
|
||||
|
||||
void JSHeapBroker::SetSerializedForCompilation(
|
||||
const SharedFunctionInfoRef& shared, const FeedbackVectorRef& feedback,
|
||||
const HintsVector& arguments) {
|
||||
HintsVector arguments_copy_in_broker_zone(zone());
|
||||
for (auto const& hints : arguments) {
|
||||
Hints hint_copy_in_broker_zone;
|
||||
hint_copy_in_broker_zone.AddFromChildSerializer(hints, zone());
|
||||
arguments_copy_in_broker_zone.push_back(hint_copy_in_broker_zone);
|
||||
}
|
||||
|
||||
SerializedFunction function = {shared, feedback};
|
||||
serialized_functions_.insert({function, arguments_copy_in_broker_zone});
|
||||
TRACE(this, "Set function " << shared << " with " << feedback
|
||||
<< " as serialized for compilation");
|
||||
}
|
||||
|
||||
bool JSHeapBroker::IsSerializedForCompilation(
|
||||
const SharedFunctionInfoRef& shared,
|
||||
const FeedbackVectorRef& feedback) const {
|
||||
if (mode() == kDisabled) return true;
|
||||
|
||||
SerializedFunction function = {shared, feedback};
|
||||
return serialized_functions_.find(function) != serialized_functions_.end();
|
||||
}
|
||||
|
||||
bool JSHeapBroker::IsArrayOrObjectPrototype(const JSObjectRef& object) const {
|
||||
if (mode() == kDisabled) {
|
||||
return isolate()->IsInAnyContext(*object.object(),
|
||||
@ -4051,14 +4068,6 @@ JSArrayRef SharedFunctionInfoRef::GetTemplateObject(
|
||||
return JSArrayRef(broker(), array);
|
||||
}
|
||||
|
||||
void SharedFunctionInfoRef::SetSerializedForCompilation(
|
||||
FeedbackVectorRef feedback) {
|
||||
CHECK_EQ(broker()->mode(), JSHeapBroker::kSerializing);
|
||||
CHECK(HasBytecodeArray());
|
||||
data()->AsSharedFunctionInfo()->SetSerializedForCompilation(broker(),
|
||||
feedback);
|
||||
}
|
||||
|
||||
void SharedFunctionInfoRef::SerializeFunctionTemplateInfo() {
|
||||
CHECK_EQ(broker()->mode(), JSHeapBroker::kSerializing);
|
||||
data()->AsSharedFunctionInfo()->SerializeFunctionTemplateInfo(broker());
|
||||
@ -4084,12 +4093,6 @@ SharedFunctionInfoRef::function_template_info() const {
|
||||
return FunctionTemplateInfoRef(broker(), function_template_info);
|
||||
}
|
||||
|
||||
bool SharedFunctionInfoRef::IsSerializedForCompilation(
|
||||
FeedbackVectorRef feedback) const {
|
||||
if (broker()->mode() == JSHeapBroker::kDisabled) return HasBytecodeArray();
|
||||
return data()->AsSharedFunctionInfo()->IsSerializedForCompilation(feedback);
|
||||
}
|
||||
|
||||
int SharedFunctionInfoRef::context_header_size() const {
|
||||
IF_BROKER_DISABLED_ACCESS_HANDLE_C(SharedFunctionInfo,
|
||||
scope_info().ContextHeaderLength);
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "src/compiler/feedback-source.h"
|
||||
#include "src/compiler/processed-feedback.h"
|
||||
#include "src/compiler/refs-map.h"
|
||||
#include "src/compiler/serializer-hints.h"
|
||||
#include "src/handles/handles.h"
|
||||
#include "src/interpreter/bytecode-array-accessor.h"
|
||||
#include "src/objects/feedback-vector.h"
|
||||
@ -179,6 +180,15 @@ class V8_EXPORT_PRIVATE JSHeapBroker {
|
||||
|
||||
StringRef GetTypedArrayStringTag(ElementsKind kind);
|
||||
|
||||
bool ShouldBeSerializedForCompilation(const SharedFunctionInfoRef& shared,
|
||||
const FeedbackVectorRef& feedback,
|
||||
const HintsVector& arguments) const;
|
||||
void SetSerializedForCompilation(const SharedFunctionInfoRef& shared,
|
||||
const FeedbackVectorRef& feedback,
|
||||
const HintsVector& arguments);
|
||||
bool IsSerializedForCompilation(const SharedFunctionInfoRef& shared,
|
||||
const FeedbackVectorRef& feedback) const;
|
||||
|
||||
std::ostream& Trace() const;
|
||||
void IncrementTracingIndentation();
|
||||
void DecrementTracingIndentation();
|
||||
@ -240,6 +250,22 @@ class V8_EXPORT_PRIVATE JSHeapBroker {
|
||||
|
||||
ZoneVector<ObjectData*> typed_array_string_tags_;
|
||||
|
||||
struct SerializedFunction {
|
||||
SharedFunctionInfoRef shared;
|
||||
FeedbackVectorRef feedback;
|
||||
|
||||
bool operator<(const SerializedFunction& other) const {
|
||||
if (shared.object().address() < other.shared.object().address()) {
|
||||
return true;
|
||||
}
|
||||
if (shared.object().address() == other.shared.object().address()) {
|
||||
return feedback.object().address() < other.feedback.object().address();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
ZoneMultimap<SerializedFunction, HintsVector> serialized_functions_;
|
||||
|
||||
static const size_t kMinimalRefsBucketCount = 8; // must be power of 2
|
||||
static const size_t kInitialRefsBucketCount = 1024; // must be power of 2
|
||||
};
|
||||
|
@ -37,7 +37,7 @@ bool CanConsiderForInlining(JSHeapBroker* broker,
|
||||
}
|
||||
|
||||
DCHECK(shared.HasBytecodeArray());
|
||||
if (!shared.IsSerializedForCompilation(feedback_vector)) {
|
||||
if (!broker->IsSerializedForCompilation(shared, feedback_vector)) {
|
||||
TRACE_BROKER_MISSING(
|
||||
broker, "data for " << shared << " (not serialized for compilation)");
|
||||
TRACE("Cannot consider " << shared << " for inlining with "
|
||||
|
@ -431,7 +431,7 @@ Reduction JSInliner::ReduceJSCall(Node* node) {
|
||||
// Determine the target's feedback vector and its context.
|
||||
Node* context;
|
||||
FeedbackVectorRef feedback_vector = DetermineCallContext(node, &context);
|
||||
CHECK(shared_info->IsSerializedForCompilation(feedback_vector));
|
||||
CHECK(broker()->IsSerializedForCompilation(*shared_info, feedback_vector));
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// After this point, we've made a decision to inline this function.
|
||||
|
@ -10,8 +10,8 @@
|
||||
#include "src/compiler/access-info.h"
|
||||
#include "src/compiler/bytecode-analysis.h"
|
||||
#include "src/compiler/compilation-dependencies.h"
|
||||
#include "src/compiler/functional-list.h"
|
||||
#include "src/compiler/js-heap-broker.h"
|
||||
#include "src/compiler/serializer-hints.h"
|
||||
#include "src/compiler/zone-stats.h"
|
||||
#include "src/handles/handles-inl.h"
|
||||
#include "src/ic/call-optimization.h"
|
||||
@ -232,118 +232,6 @@ namespace compiler {
|
||||
UNCONDITIONAL_JUMPS_LIST(V) \
|
||||
UNREACHABLE_BYTECODE_LIST(V)
|
||||
|
||||
template <typename T, typename EqualTo>
|
||||
class FunctionalSet {
|
||||
public:
|
||||
void Add(T const& elem, Zone* zone) {
|
||||
for (auto const& l : data_) {
|
||||
if (equal_to(l, elem)) return;
|
||||
}
|
||||
data_.PushFront(elem, zone);
|
||||
}
|
||||
|
||||
bool Includes(FunctionalSet<T, EqualTo> const& other) const {
|
||||
return std::all_of(other.begin(), other.end(), [&](T const& other_elem) {
|
||||
return std::any_of(this->begin(), this->end(), [&](T const& this_elem) {
|
||||
return equal_to(this_elem, other_elem);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
bool IsEmpty() const { return data_.begin() == data_.end(); }
|
||||
|
||||
void Clear() { data_.Clear(); }
|
||||
|
||||
// Warning: quadratic time complexity.
|
||||
bool operator==(const FunctionalSet<T, EqualTo>& other) const {
|
||||
return this->data_.Size() == other.data_.Size() && this->Includes(other) &&
|
||||
other.Includes(*this);
|
||||
}
|
||||
bool operator!=(const FunctionalSet<T, EqualTo>& other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
using iterator = typename FunctionalList<T>::iterator;
|
||||
|
||||
iterator begin() const { return data_.begin(); }
|
||||
iterator end() const { return data_.end(); }
|
||||
|
||||
private:
|
||||
static EqualTo equal_to;
|
||||
FunctionalList<T> data_;
|
||||
};
|
||||
|
||||
template <typename T, typename EqualTo>
|
||||
EqualTo FunctionalSet<T, EqualTo>::equal_to;
|
||||
|
||||
struct VirtualContext {
|
||||
unsigned int distance;
|
||||
Handle<Context> context;
|
||||
|
||||
VirtualContext(unsigned int distance_in, Handle<Context> context_in)
|
||||
: distance(distance_in), context(context_in) {
|
||||
CHECK_GT(distance, 0);
|
||||
}
|
||||
bool operator==(const VirtualContext& other) const {
|
||||
return context.equals(other.context) && distance == other.distance;
|
||||
}
|
||||
};
|
||||
|
||||
class FunctionBlueprint;
|
||||
struct VirtualBoundFunction;
|
||||
|
||||
using ConstantsSet = FunctionalSet<Handle<Object>, Handle<Object>::equal_to>;
|
||||
using VirtualContextsSet =
|
||||
FunctionalSet<VirtualContext, std::equal_to<VirtualContext>>;
|
||||
using MapsSet = FunctionalSet<Handle<Map>, Handle<Map>::equal_to>;
|
||||
using BlueprintsSet =
|
||||
FunctionalSet<FunctionBlueprint, std::equal_to<FunctionBlueprint>>;
|
||||
using BoundFunctionsSet =
|
||||
FunctionalSet<VirtualBoundFunction, std::equal_to<VirtualBoundFunction>>;
|
||||
|
||||
class Hints {
|
||||
public:
|
||||
Hints() = default;
|
||||
|
||||
static Hints SingleConstant(Handle<Object> constant, Zone* zone);
|
||||
|
||||
const ConstantsSet& constants() const;
|
||||
const MapsSet& maps() const;
|
||||
const BlueprintsSet& function_blueprints() const;
|
||||
const VirtualContextsSet& virtual_contexts() const;
|
||||
const BoundFunctionsSet& virtual_bound_functions() const;
|
||||
|
||||
void AddConstant(Handle<Object> constant, Zone* zone);
|
||||
void AddMap(Handle<Map> map, Zone* zone);
|
||||
void AddFunctionBlueprint(FunctionBlueprint const& function_blueprint,
|
||||
Zone* zone);
|
||||
void AddVirtualContext(VirtualContext const& virtual_context, Zone* zone);
|
||||
void AddVirtualBoundFunction(VirtualBoundFunction const& bound_function,
|
||||
Zone* zone);
|
||||
|
||||
void Add(const Hints& other, Zone* zone);
|
||||
void AddFromChildSerializer(const Hints& other, Zone* zone);
|
||||
|
||||
void Clear();
|
||||
bool IsEmpty() const;
|
||||
|
||||
bool operator==(Hints const& other) const;
|
||||
bool operator!=(Hints const& other) const { return !(*this == other); }
|
||||
|
||||
#ifdef ENABLE_SLOW_DCHECKS
|
||||
bool Includes(Hints const& other) const;
|
||||
bool Equals(Hints const& other) const;
|
||||
#endif
|
||||
|
||||
private:
|
||||
VirtualContextsSet virtual_contexts_;
|
||||
ConstantsSet constants_;
|
||||
MapsSet maps_;
|
||||
BlueprintsSet function_blueprints_;
|
||||
BoundFunctionsSet virtual_bound_functions_;
|
||||
};
|
||||
|
||||
using HintsVector = ZoneVector<Hints>;
|
||||
|
||||
struct VirtualBoundFunction {
|
||||
Hints bound_target;
|
||||
@ -470,7 +358,8 @@ class SerializerForBackgroundCompilation {
|
||||
ZoneStats* zone_stats, JSHeapBroker* broker,
|
||||
CompilationDependencies* dependencies, Handle<JSFunction> closure,
|
||||
SerializerForBackgroundCompilationFlags flags, BailoutId osr_offset);
|
||||
Hints Run(); // NOTE: Returns empty for an already-serialized function.
|
||||
Hints Run(); // NOTE: Returns empty for an
|
||||
// already-serialized function.
|
||||
|
||||
class Environment;
|
||||
|
||||
@ -616,6 +505,7 @@ class SerializerForBackgroundCompilation {
|
||||
ZoneUnorderedMap<int, Environment*> jump_target_environments_;
|
||||
SerializerForBackgroundCompilationFlags const flags_;
|
||||
BailoutId const osr_offset_;
|
||||
const HintsVector arguments_;
|
||||
};
|
||||
|
||||
void RunSerializerForBackgroundCompilation(
|
||||
@ -1045,7 +935,8 @@ SerializerForBackgroundCompilation::SerializerForBackgroundCompilation(
|
||||
zone(), CompilationSubject(closure, broker_->isolate(), zone()))),
|
||||
jump_target_environments_(zone()),
|
||||
flags_(flags),
|
||||
osr_offset_(osr_offset) {
|
||||
osr_offset_(osr_offset),
|
||||
arguments_(zone()) {
|
||||
JSFunctionRef(broker, closure).Serialize();
|
||||
}
|
||||
|
||||
@ -1063,7 +954,8 @@ SerializerForBackgroundCompilation::SerializerForBackgroundCompilation(
|
||||
new_target, arguments, padding)),
|
||||
jump_target_environments_(zone()),
|
||||
flags_(flags),
|
||||
osr_offset_(BailoutId::None()) {
|
||||
osr_offset_(BailoutId::None()),
|
||||
arguments_(arguments) {
|
||||
TraceScope tracer(
|
||||
broker_, this,
|
||||
"SerializerForBackgroundCompilation::SerializerForBackgroundCompilation");
|
||||
@ -1099,13 +991,15 @@ Hints SerializerForBackgroundCompilation::Run() {
|
||||
<< broker()->zone()->allocation_size());
|
||||
SharedFunctionInfoRef shared(broker(), environment()->function().shared());
|
||||
FeedbackVectorRef feedback_vector_ref(broker(), feedback_vector());
|
||||
if (shared.IsSerializedForCompilation(feedback_vector_ref)) {
|
||||
if (!broker()->ShouldBeSerializedForCompilation(shared, feedback_vector_ref,
|
||||
arguments_)) {
|
||||
TRACE_BROKER(broker(), "Already ran serializer for SharedFunctionInfo "
|
||||
<< Brief(*shared.object())
|
||||
<< ", bailing out.\n");
|
||||
return Hints();
|
||||
}
|
||||
shared.SetSerializedForCompilation(feedback_vector_ref);
|
||||
broker()->SetSerializedForCompilation(shared, feedback_vector_ref,
|
||||
arguments_);
|
||||
|
||||
// We eagerly call the {EnsureSourcePositionsAvailable} for all serialized
|
||||
// SFIs while still on the main thread. Source positions will later be used
|
||||
|
143
src/compiler/serializer-hints.h
Normal file
143
src/compiler/serializer-hints.h
Normal file
@ -0,0 +1,143 @@
|
||||
// Copyright 2019 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// This file defines the hints classed gathered temporarily by the
|
||||
// SerializerForBackgroundCompilation while it's analysing the bytecode
|
||||
// and copying the necessary data to the JSHeapBroker for further usage
|
||||
// by the reducers that run on the background thread.
|
||||
|
||||
#ifndef V8_COMPILER_SERIALIZER_HINTS_H_
|
||||
#define V8_COMPILER_SERIALIZER_HINTS_H_
|
||||
|
||||
#include "src/compiler/functional-list.h"
|
||||
#include "src/handles/handles.h"
|
||||
#include "src/zone/zone-containers.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
class Context;
|
||||
class Object;
|
||||
class Map;
|
||||
|
||||
namespace compiler {
|
||||
|
||||
template <typename T, typename EqualTo>
|
||||
class FunctionalSet {
|
||||
public:
|
||||
void Add(T const& elem, Zone* zone) {
|
||||
for (auto const& l : data_) {
|
||||
if (equal_to(l, elem)) return;
|
||||
}
|
||||
data_.PushFront(elem, zone);
|
||||
}
|
||||
|
||||
bool Includes(FunctionalSet<T, EqualTo> const& other) const {
|
||||
return std::all_of(other.begin(), other.end(), [&](T const& other_elem) {
|
||||
return std::any_of(this->begin(), this->end(), [&](T const& this_elem) {
|
||||
return equal_to(this_elem, other_elem);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
bool IsEmpty() const { return data_.begin() == data_.end(); }
|
||||
|
||||
void Clear() { data_.Clear(); }
|
||||
|
||||
// Warning: quadratic time complexity.
|
||||
bool operator==(const FunctionalSet<T, EqualTo>& other) const {
|
||||
return this->data_.Size() == other.data_.Size() && this->Includes(other) &&
|
||||
other.Includes(*this);
|
||||
}
|
||||
bool operator!=(const FunctionalSet<T, EqualTo>& other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
using iterator = typename FunctionalList<T>::iterator;
|
||||
|
||||
iterator begin() const { return data_.begin(); }
|
||||
iterator end() const { return data_.end(); }
|
||||
|
||||
private:
|
||||
static EqualTo equal_to;
|
||||
FunctionalList<T> data_;
|
||||
};
|
||||
|
||||
template <typename T, typename EqualTo>
|
||||
EqualTo FunctionalSet<T, EqualTo>::equal_to;
|
||||
|
||||
struct VirtualContext {
|
||||
unsigned int distance;
|
||||
Handle<Context> context;
|
||||
|
||||
VirtualContext(unsigned int distance_in, Handle<Context> context_in)
|
||||
: distance(distance_in), context(context_in) {
|
||||
CHECK_GT(distance, 0);
|
||||
}
|
||||
bool operator==(const VirtualContext& other) const {
|
||||
return context.equals(other.context) && distance == other.distance;
|
||||
}
|
||||
};
|
||||
|
||||
class FunctionBlueprint;
|
||||
struct VirtualBoundFunction;
|
||||
|
||||
using ConstantsSet = FunctionalSet<Handle<Object>, Handle<Object>::equal_to>;
|
||||
using VirtualContextsSet =
|
||||
FunctionalSet<VirtualContext, std::equal_to<VirtualContext>>;
|
||||
using MapsSet = FunctionalSet<Handle<Map>, Handle<Map>::equal_to>;
|
||||
using BlueprintsSet =
|
||||
FunctionalSet<FunctionBlueprint, std::equal_to<FunctionBlueprint>>;
|
||||
using BoundFunctionsSet =
|
||||
FunctionalSet<VirtualBoundFunction, std::equal_to<VirtualBoundFunction>>;
|
||||
|
||||
class Hints {
|
||||
public:
|
||||
Hints() = default;
|
||||
|
||||
static Hints SingleConstant(Handle<Object> constant, Zone* zone);
|
||||
|
||||
const ConstantsSet& constants() const;
|
||||
const MapsSet& maps() const;
|
||||
const BlueprintsSet& function_blueprints() const;
|
||||
const VirtualContextsSet& virtual_contexts() const;
|
||||
const BoundFunctionsSet& virtual_bound_functions() const;
|
||||
|
||||
void AddConstant(Handle<Object> constant, Zone* zone);
|
||||
void AddMap(Handle<Map> map, Zone* zone);
|
||||
void AddFunctionBlueprint(FunctionBlueprint const& function_blueprint,
|
||||
Zone* zone);
|
||||
void AddVirtualContext(VirtualContext const& virtual_context, Zone* zone);
|
||||
void AddVirtualBoundFunction(VirtualBoundFunction const& bound_function,
|
||||
Zone* zone);
|
||||
|
||||
void Add(const Hints& other, Zone* zone);
|
||||
void AddFromChildSerializer(const Hints& other, Zone* zone);
|
||||
|
||||
void Clear();
|
||||
bool IsEmpty() const;
|
||||
|
||||
bool operator==(Hints const& other) const;
|
||||
bool operator!=(Hints const& other) const { return !(*this == other); }
|
||||
|
||||
#ifdef ENABLE_SLOW_DCHECKS
|
||||
bool Includes(Hints const& other) const;
|
||||
bool Equals(Hints const& other) const;
|
||||
#endif
|
||||
|
||||
private:
|
||||
VirtualContextsSet virtual_contexts_;
|
||||
ConstantsSet constants_;
|
||||
MapsSet maps_;
|
||||
BlueprintsSet function_blueprints_;
|
||||
BoundFunctionsSet virtual_bound_functions_;
|
||||
};
|
||||
|
||||
using HintsVector = ZoneVector<Hints>;
|
||||
|
||||
} // namespace compiler
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
||||
#endif // V8_COMPILER_SERIALIZER_HINTS_H_
|
@ -53,8 +53,8 @@ TEST(SerializeEmptyFunction) {
|
||||
SerializerTester tester(
|
||||
"function f() {}; %EnsureFeedbackVectorForFunction(f); return f;");
|
||||
JSFunctionRef function = tester.function();
|
||||
CHECK(
|
||||
function.shared().IsSerializedForCompilation(function.feedback_vector()));
|
||||
CHECK(tester.broker()->IsSerializedForCompilation(
|
||||
function.shared(), function.feedback_vector()));
|
||||
}
|
||||
|
||||
// This helper function allows for testing whether an inlinee candidate
|
||||
@ -64,7 +64,8 @@ void CheckForSerializedInlinee(const char* source, int argc = 0,
|
||||
Handle<Object> argv[] = {}) {
|
||||
SerializerTester tester(source);
|
||||
JSFunctionRef f = tester.function();
|
||||
CHECK(f.shared().IsSerializedForCompilation(f.feedback_vector()));
|
||||
CHECK(tester.broker()->IsSerializedForCompilation(f.shared(),
|
||||
f.feedback_vector()));
|
||||
|
||||
MaybeHandle<Object> g_obj = Execution::Call(
|
||||
tester.isolate(), tester.function().object(),
|
||||
@ -81,7 +82,7 @@ void CheckForSerializedInlinee(const char* source, int argc = 0,
|
||||
handle(g_func->shared(), tester.isolate()));
|
||||
FeedbackVectorRef g_fv(tester.broker(),
|
||||
handle(g_func->feedback_vector(), tester.isolate()));
|
||||
CHECK(g_sfi.IsSerializedForCompilation(g_fv));
|
||||
CHECK(tester.broker()->IsSerializedForCompilation(g_sfi, g_fv));
|
||||
}
|
||||
|
||||
TEST(SerializeInlinedClosure) {
|
||||
@ -348,6 +349,22 @@ TEST(BoundFunctionResult) {
|
||||
"foo(); return foo;");
|
||||
}
|
||||
|
||||
TEST(MultipleFunctionCalls) {
|
||||
CheckForSerializedInlinee(
|
||||
"function inc(x) { return ++x; }"
|
||||
"function dec(x) { return --x; }"
|
||||
"function apply(f, x) { return f(x); }"
|
||||
"function foo() { apply(inc, 42); apply(dec, 42); return dec; }"
|
||||
"%PrepareFunctionForOptimization(inc);"
|
||||
"%PrepareFunctionForOptimization(dec);"
|
||||
"%PrepareFunctionForOptimization(apply);"
|
||||
"%PrepareFunctionForOptimization(foo);"
|
||||
"foo();"
|
||||
"foo();"
|
||||
"%OptimizeFunctionOnNextCall(foo);"
|
||||
"foo(); return foo;");
|
||||
}
|
||||
|
||||
} // namespace compiler
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
Loading…
Reference in New Issue
Block a user