summaryrefslogtreecommitdiff
path: root/deps/v8/src/compiler/serializer-for-background-compilation.cc
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/compiler/serializer-for-background-compilation.cc')
-rw-r--r--deps/v8/src/compiler/serializer-for-background-compilation.cc623
1 files changed, 441 insertions, 182 deletions
diff --git a/deps/v8/src/compiler/serializer-for-background-compilation.cc b/deps/v8/src/compiler/serializer-for-background-compilation.cc
index 0d761f82b3..6c2eaed7bc 100644
--- a/deps/v8/src/compiler/serializer-for-background-compilation.cc
+++ b/deps/v8/src/compiler/serializer-for-background-compilation.cc
@@ -4,38 +4,49 @@
#include "src/compiler/serializer-for-background-compilation.h"
+#include <sstream>
+
#include "src/compiler/js-heap-broker.h"
#include "src/handles-inl.h"
#include "src/interpreter/bytecode-array-iterator.h"
#include "src/objects/code.h"
#include "src/objects/shared-function-info-inl.h"
+#include "src/vector-slot-pair.h"
#include "src/zone/zone.h"
namespace v8 {
namespace internal {
namespace compiler {
+using BytecodeArrayIterator = interpreter::BytecodeArrayIterator;
+
+CompilationSubject::CompilationSubject(Handle<JSFunction> closure,
+ Isolate* isolate)
+ : blueprint_{handle(closure->shared(), isolate),
+ handle(closure->feedback_vector(), isolate)},
+ closure_(closure) {
+ CHECK(closure->has_feedback_vector());
+}
+
Hints::Hints(Zone* zone)
: constants_(zone), maps_(zone), function_blueprints_(zone) {}
-const ZoneVector<Handle<Object>>& Hints::constants() const {
- return constants_;
-}
+const ConstantsSet& Hints::constants() const { return constants_; }
-const ZoneVector<Handle<Map>>& Hints::maps() const { return maps_; }
+const MapsSet& Hints::maps() const { return maps_; }
-const ZoneVector<FunctionBlueprint>& Hints::function_blueprints() const {
+const BlueprintsSet& Hints::function_blueprints() const {
return function_blueprints_;
}
void Hints::AddConstant(Handle<Object> constant) {
- constants_.push_back(constant);
+ constants_.insert(constant);
}
-void Hints::AddMap(Handle<Map> map) { maps_.push_back(map); }
+void Hints::AddMap(Handle<Map> map) { maps_.insert(map); }
void Hints::AddFunctionBlueprint(FunctionBlueprint function_blueprint) {
- function_blueprints_.push_back(function_blueprint);
+ function_blueprints_.insert(function_blueprint);
}
void Hints::Add(const Hints& other) {
@@ -44,23 +55,53 @@ void Hints::Add(const Hints& other) {
for (auto x : other.function_blueprints()) AddFunctionBlueprint(x);
}
+bool Hints::IsEmpty() const {
+ return constants().empty() && maps().empty() && function_blueprints().empty();
+}
+
+std::ostream& operator<<(std::ostream& out,
+ const FunctionBlueprint& blueprint) {
+ out << Brief(*blueprint.shared) << std::endl;
+ out << Brief(*blueprint.feedback_vector) << std::endl;
+ return out;
+}
+
+std::ostream& operator<<(std::ostream& out, const Hints& hints) {
+ !hints.constants().empty() &&
+ out << "\t\tConstants (" << hints.constants().size() << "):" << std::endl;
+ for (auto x : hints.constants()) out << Brief(*x) << std::endl;
+ !hints.maps().empty() && out << "\t\tMaps (" << hints.maps().size()
+ << "):" << std::endl;
+ for (auto x : hints.maps()) out << Brief(*x) << std::endl;
+ !hints.function_blueprints().empty() &&
+ out << "\t\tBlueprints (" << hints.function_blueprints().size()
+ << "):" << std::endl;
+ for (auto x : hints.function_blueprints()) out << x;
+ return out;
+}
+
void Hints::Clear() {
constants_.clear();
maps_.clear();
function_blueprints_.clear();
+ DCHECK(IsEmpty());
}
class SerializerForBackgroundCompilation::Environment : public ZoneObject {
public:
- explicit Environment(Zone* zone, Isolate* isolate, int register_count,
- int parameter_count);
+ Environment(Zone* zone, CompilationSubject function);
+ Environment(Zone* zone, Isolate* isolate, CompilationSubject function,
+ base::Optional<Hints> new_target, const HintsVector& arguments);
- Environment(SerializerForBackgroundCompilation* serializer, Isolate* isolate,
- int register_count, int parameter_count,
- const HintsVector& arguments);
+ // When control flow bytecodes are encountered, e.g. a conditional jump,
+ // the current environment needs to be stashed together with the target jump
+ // address. Later, when this target bytecode is handled, the stashed
+ // environment will be merged into the current one.
+ void Merge(Environment* other);
- int parameter_count() const { return parameter_count_; }
- int register_count() const { return register_count_; }
+ friend std::ostream& operator<<(std::ostream& out, const Environment& env);
+
+ FunctionBlueprint function() const { return function_; }
Hints& accumulator_hints() { return environment_hints_[accumulator_index()]; }
Hints& register_hints(interpreter::Register reg) {
@@ -70,30 +111,38 @@ class SerializerForBackgroundCompilation::Environment : public ZoneObject {
}
Hints& return_value_hints() { return return_value_hints_; }
- void ClearAccumulatorAndRegisterHints() {
- for (auto& hints : environment_hints_) hints.Clear();
+ // Clears all hints except those for the return value and the closure.
+ void ClearEphemeralHints() {
+ DCHECK_EQ(environment_hints_.size(), function_closure_index() + 1);
+ for (int i = 0; i < function_closure_index(); ++i) {
+ environment_hints_[i].Clear();
+ }
}
- private:
- explicit Environment(Zone* zone)
- : register_count_(0),
- parameter_count_(0),
- environment_hints_(zone),
- return_value_hints_(zone) {}
- Zone* zone() const { return zone_; }
+ // Appends the hints for the given register range to {dst} (in order).
+ void ExportRegisterHints(interpreter::Register first, size_t count,
+ HintsVector& dst);
+ private:
int RegisterToLocalIndex(interpreter::Register reg) const;
- Zone* zone_;
+ Zone* zone() const { return zone_; }
+ int parameter_count() const { return parameter_count_; }
+ int register_count() const { return register_count_; }
+
+ Zone* const zone_;
+ // Instead of storing the blueprint here, we could extract it from the
+ // (closure) hints but that would be cumbersome.
+ FunctionBlueprint const function_;
+ int const parameter_count_;
+ int const register_count_;
// environment_hints_ contains hints for the contents of the registers,
// the accumulator and the parameters. The layout is as follows:
- // [ receiver | parameters | registers | accumulator | context | closure ]
- const int register_count_;
- const int parameter_count_;
+ // [ parameters | registers | accumulator | context | closure ]
+ // The first parameter is the receiver.
HintsVector environment_hints_;
- int register_base() const { return parameter_count_; }
- int accumulator_index() const { return register_base() + register_count_; }
+ int accumulator_index() const { return parameter_count() + register_count(); }
int current_context_index() const { return accumulator_index() + 1; }
int function_closure_index() const { return current_context_index() + 1; }
int environment_hints_size() const { return function_closure_index() + 1; }
@@ -102,91 +151,145 @@ class SerializerForBackgroundCompilation::Environment : public ZoneObject {
};
SerializerForBackgroundCompilation::Environment::Environment(
- Zone* zone, Isolate* isolate, int register_count, int parameter_count)
+ Zone* zone, CompilationSubject function)
: zone_(zone),
- register_count_(register_count),
- parameter_count_(parameter_count),
+ function_(function.blueprint()),
+ parameter_count_(function_.shared->GetBytecodeArray()->parameter_count()),
+ register_count_(function_.shared->GetBytecodeArray()->register_count()),
environment_hints_(environment_hints_size(), Hints(zone), zone),
- return_value_hints_(zone) {}
+ return_value_hints_(zone) {
+ Handle<JSFunction> closure;
+ if (function.closure().ToHandle(&closure)) {
+ environment_hints_[function_closure_index()].AddConstant(closure);
+ } else {
+ environment_hints_[function_closure_index()].AddFunctionBlueprint(
+ function.blueprint());
+ }
+}
SerializerForBackgroundCompilation::Environment::Environment(
- SerializerForBackgroundCompilation* serializer, Isolate* isolate,
- int register_count, int parameter_count, const HintsVector& arguments)
- : Environment(serializer->zone(), isolate, register_count,
- parameter_count) {
- size_t param_count = static_cast<size_t>(parameter_count);
-
+ Zone* zone, Isolate* isolate, CompilationSubject function,
+ base::Optional<Hints> new_target, const HintsVector& arguments)
+ : Environment(zone, function) {
// Copy the hints for the actually passed arguments, at most up to
// the parameter_count.
+ size_t param_count = static_cast<size_t>(parameter_count());
for (size_t i = 0; i < std::min(arguments.size(), param_count); ++i) {
environment_hints_[i] = arguments[i];
}
- Hints undefined_hint(serializer->zone());
- undefined_hint.AddConstant(
- serializer->broker()->isolate()->factory()->undefined_value());
// Pad the rest with "undefined".
+ Hints undefined_hint(zone);
+ undefined_hint.AddConstant(isolate->factory()->undefined_value());
for (size_t i = arguments.size(); i < param_count; ++i) {
environment_hints_[i] = undefined_hint;
}
+
+ interpreter::Register new_target_reg =
+ function_.shared->GetBytecodeArray()
+ ->incoming_new_target_or_generator_register();
+ if (new_target_reg.is_valid()) {
+ DCHECK(register_hints(new_target_reg).IsEmpty());
+ if (new_target.has_value()) {
+ register_hints(new_target_reg).Add(*new_target);
+ }
+ }
+}
+
+void SerializerForBackgroundCompilation::Environment::Merge(
+ Environment* other) {
+ // Presumably the source and the target would have the same layout
+ // so this is enforced here.
+ CHECK_EQ(parameter_count(), other->parameter_count());
+ CHECK_EQ(register_count(), other->register_count());
+ CHECK_EQ(environment_hints_size(), other->environment_hints_size());
+
+ for (size_t i = 0; i < environment_hints_.size(); ++i) {
+ environment_hints_[i].Add(other->environment_hints_[i]);
+ }
+ return_value_hints_.Add(other->return_value_hints_);
+}
+
+std::ostream& operator<<(
+ std::ostream& out,
+ const SerializerForBackgroundCompilation::Environment& env) {
+ std::ostringstream output_stream;
+ output_stream << "Function ";
+ env.function_.shared->Name()->Print(output_stream);
+ output_stream << "Parameter count: " << env.parameter_count() << std::endl;
+ output_stream << "Register count: " << env.register_count() << std::endl;
+
+ output_stream << "Hints (" << env.environment_hints_.size() << "):\n";
+ for (size_t i = 0; i < env.environment_hints_.size(); ++i) {
+ if (env.environment_hints_[i].IsEmpty()) continue;
+
+ output_stream << "\tSlot " << i << std::endl;
+ output_stream << env.environment_hints_[i];
+ }
+ output_stream << "Return value:\n";
+ output_stream << env.return_value_hints_
+ << "===========================================\n";
+
+ out << output_stream.str();
+ return out;
}
int SerializerForBackgroundCompilation::Environment::RegisterToLocalIndex(
interpreter::Register reg) const {
- // TODO(mslekova): We also want to gather hints for the context and
- // we already have data about the closure that we should record.
+ // TODO(mslekova): We also want to gather hints for the context.
if (reg.is_current_context()) return current_context_index();
if (reg.is_function_closure()) return function_closure_index();
if (reg.is_parameter()) {
return reg.ToParameterIndex(parameter_count());
} else {
- return register_base() + reg.index();
+ return parameter_count() + reg.index();
}
}
SerializerForBackgroundCompilation::SerializerForBackgroundCompilation(
- JSHeapBroker* broker, Zone* zone, Handle<JSFunction> function)
+ JSHeapBroker* broker, Zone* zone, Handle<JSFunction> closure)
: broker_(broker),
zone_(zone),
- shared_(function->shared(), broker->isolate()),
- feedback_(function->feedback_vector(), broker->isolate()),
- environment_(new (zone) Environment(
- zone, broker_->isolate(),
- shared_->GetBytecodeArray()->register_count(),
- shared_->GetBytecodeArray()->parameter_count())) {
- JSFunctionRef(broker, function).Serialize();
+ environment_(new (zone) Environment(zone, {closure, broker_->isolate()})),
+ stashed_environments_(zone) {
+ JSFunctionRef(broker, closure).Serialize();
}
SerializerForBackgroundCompilation::SerializerForBackgroundCompilation(
- JSHeapBroker* broker, Zone* zone, FunctionBlueprint function,
- const HintsVector& arguments)
+ JSHeapBroker* broker, Zone* zone, CompilationSubject function,
+ base::Optional<Hints> new_target, const HintsVector& arguments)
: broker_(broker),
zone_(zone),
- shared_(function.shared),
- feedback_(function.feedback),
- environment_(new (zone) Environment(
- this, broker->isolate(),
- shared_->GetBytecodeArray()->register_count(),
- shared_->GetBytecodeArray()->parameter_count(), arguments)) {}
+ environment_(new (zone) Environment(zone, broker_->isolate(), function,
+ new_target, arguments)),
+ stashed_environments_(zone) {
+ Handle<JSFunction> closure;
+ if (function.closure().ToHandle(&closure)) {
+ JSFunctionRef(broker, closure).Serialize();
+ }
+}
Hints SerializerForBackgroundCompilation::Run() {
- SharedFunctionInfoRef shared(broker(), shared_);
- FeedbackVectorRef feedback(broker(), feedback_);
- if (shared.IsSerializedForCompilation(feedback)) {
+ SharedFunctionInfoRef shared(broker(), environment()->function().shared);
+ FeedbackVectorRef feedback_vector(broker(),
+ environment()->function().feedback_vector);
+ if (shared.IsSerializedForCompilation(feedback_vector)) {
return Hints(zone());
}
- shared.SetSerializedForCompilation(feedback);
- feedback.SerializeSlots();
+ shared.SetSerializedForCompilation(feedback_vector);
+ feedback_vector.SerializeSlots();
TraverseBytecode();
return environment()->return_value_hints();
}
void SerializerForBackgroundCompilation::TraverseBytecode() {
BytecodeArrayRef bytecode_array(
- broker(), handle(shared_->GetBytecodeArray(), broker()->isolate()));
- interpreter::BytecodeArrayIterator iterator(bytecode_array.object());
+ broker(), handle(environment()->function().shared->GetBytecodeArray(),
+ broker()->isolate()));
+ BytecodeArrayIterator iterator(bytecode_array.object());
for (; !iterator.done(); iterator.Advance()) {
+ MergeAfterJump(&iterator);
switch (iterator.current_bytecode()) {
#define DEFINE_BYTECODE_CASE(name) \
case interpreter::Bytecode::k##name: \
@@ -195,7 +298,7 @@ void SerializerForBackgroundCompilation::TraverseBytecode() {
SUPPORTED_BYTECODE_LIST(DEFINE_BYTECODE_CASE)
#undef DEFINE_BYTECODE_CASE
default: {
- environment()->ClearAccumulatorAndRegisterHints();
+ environment()->ClearEphemeralHints();
break;
}
}
@@ -203,71 +306,74 @@ void SerializerForBackgroundCompilation::TraverseBytecode() {
}
void SerializerForBackgroundCompilation::VisitIllegal(
- interpreter::BytecodeArrayIterator* iterator) {
+ BytecodeArrayIterator* iterator) {
UNREACHABLE();
}
void SerializerForBackgroundCompilation::VisitWide(
- interpreter::BytecodeArrayIterator* iterator) {
+ BytecodeArrayIterator* iterator) {
UNREACHABLE();
}
void SerializerForBackgroundCompilation::VisitExtraWide(
- interpreter::BytecodeArrayIterator* iterator) {
+ BytecodeArrayIterator* iterator) {
UNREACHABLE();
}
+void SerializerForBackgroundCompilation::VisitStackCheck(
+ BytecodeArrayIterator* iterator) {}
+
void SerializerForBackgroundCompilation::VisitLdaUndefined(
- interpreter::BytecodeArrayIterator* iterator) {
+ BytecodeArrayIterator* iterator) {
environment()->accumulator_hints().Clear();
environment()->accumulator_hints().AddConstant(
broker()->isolate()->factory()->undefined_value());
}
void SerializerForBackgroundCompilation::VisitLdaNull(
- interpreter::BytecodeArrayIterator* iterator) {
+ BytecodeArrayIterator* iterator) {
environment()->accumulator_hints().Clear();
environment()->accumulator_hints().AddConstant(
broker()->isolate()->factory()->null_value());
}
void SerializerForBackgroundCompilation::VisitLdaZero(
- interpreter::BytecodeArrayIterator* iterator) {
+ BytecodeArrayIterator* iterator) {
environment()->accumulator_hints().Clear();
environment()->accumulator_hints().AddConstant(
handle(Smi::FromInt(0), broker()->isolate()));
}
void SerializerForBackgroundCompilation::VisitLdaSmi(
- interpreter::BytecodeArrayIterator* iterator) {
+ BytecodeArrayIterator* iterator) {
environment()->accumulator_hints().Clear();
environment()->accumulator_hints().AddConstant(handle(
Smi::FromInt(iterator->GetImmediateOperand(0)), broker()->isolate()));
}
void SerializerForBackgroundCompilation::VisitLdaConstant(
- interpreter::BytecodeArrayIterator* iterator) {
+ BytecodeArrayIterator* iterator) {
environment()->accumulator_hints().Clear();
environment()->accumulator_hints().AddConstant(
handle(iterator->GetConstantForIndexOperand(0), broker()->isolate()));
}
void SerializerForBackgroundCompilation::VisitLdar(
- interpreter::BytecodeArrayIterator* iterator) {
+ BytecodeArrayIterator* iterator) {
environment()->accumulator_hints().Clear();
environment()->accumulator_hints().Add(
environment()->register_hints(iterator->GetRegisterOperand(0)));
}
void SerializerForBackgroundCompilation::VisitStar(
- interpreter::BytecodeArrayIterator* iterator) {
+ BytecodeArrayIterator* iterator) {
interpreter::Register reg = iterator->GetRegisterOperand(0);
environment()->register_hints(reg).Clear();
environment()->register_hints(reg).Add(environment()->accumulator_hints());
}
void SerializerForBackgroundCompilation::VisitMov(
- interpreter::BytecodeArrayIterator* iterator) {
+ BytecodeArrayIterator* iterator) {
interpreter::Register src = iterator->GetRegisterOperand(0);
interpreter::Register dst = iterator->GetRegisterOperand(1);
environment()->register_hints(dst).Clear();
@@ -275,12 +381,13 @@ void SerializerForBackgroundCompilation::VisitMov(
}
void SerializerForBackgroundCompilation::VisitCreateClosure(
- interpreter::BytecodeArrayIterator* iterator) {
+ BytecodeArrayIterator* iterator) {
Handle<SharedFunctionInfo> shared(
SharedFunctionInfo::cast(iterator->GetConstantForIndexOperand(0)),
broker()->isolate());
- FeedbackNexus nexus(feedback_, iterator->GetSlotOperand(1));
+ FeedbackNexus nexus(environment()->function().feedback_vector,
+ iterator->GetSlotOperand(1));
Handle<Object> cell_value(nexus.GetFeedbackCell()->value(),
broker()->isolate());
@@ -292,106 +399,98 @@ void SerializerForBackgroundCompilation::VisitCreateClosure(
}
void SerializerForBackgroundCompilation::VisitCallUndefinedReceiver(
- interpreter::BytecodeArrayIterator* iterator) {
+ BytecodeArrayIterator* iterator) {
ProcessCallVarArgs(iterator, ConvertReceiverMode::kNullOrUndefined);
}
void SerializerForBackgroundCompilation::VisitCallUndefinedReceiver0(
- interpreter::BytecodeArrayIterator* iterator) {
- Hints receiver(zone());
- receiver.AddConstant(broker()->isolate()->factory()->undefined_value());
-
+ BytecodeArrayIterator* iterator) {
const Hints& callee =
environment()->register_hints(iterator->GetRegisterOperand(0));
+ FeedbackSlot slot = iterator->GetSlotOperand(1);
- HintsVector parameters(zone());
- parameters.push_back(receiver);
- ProcessCallOrConstruct(callee, parameters);
-}
-
-void SerializerForBackgroundCompilation::VisitCallUndefinedReceiver1(
- interpreter::BytecodeArrayIterator* iterator) {
Hints receiver(zone());
receiver.AddConstant(broker()->isolate()->factory()->undefined_value());
+ HintsVector parameters({receiver}, zone());
+ ProcessCallOrConstruct(callee, base::nullopt, parameters, slot);
+}
+
+void SerializerForBackgroundCompilation::VisitCallUndefinedReceiver1(
+ BytecodeArrayIterator* iterator) {
const Hints& callee =
environment()->register_hints(iterator->GetRegisterOperand(0));
const Hints& arg0 =
environment()->register_hints(iterator->GetRegisterOperand(1));
+ FeedbackSlot slot = iterator->GetSlotOperand(2);
- HintsVector parameters(zone());
- parameters.push_back(receiver);
- parameters.push_back(arg0);
+ Hints receiver(zone());
+ receiver.AddConstant(broker()->isolate()->factory()->undefined_value());
- ProcessCallOrConstruct(callee, parameters);
+ HintsVector parameters({receiver, arg0}, zone());
+ ProcessCallOrConstruct(callee, base::nullopt, parameters, slot);
}
void SerializerForBackgroundCompilation::VisitCallUndefinedReceiver2(
- interpreter::BytecodeArrayIterator* iterator) {
- Hints receiver(zone());
- receiver.AddConstant(broker()->isolate()->factory()->undefined_value());
-
+ BytecodeArrayIterator* iterator) {
const Hints& callee =
environment()->register_hints(iterator->GetRegisterOperand(0));
const Hints& arg0 =
environment()->register_hints(iterator->GetRegisterOperand(1));
const Hints& arg1 =
environment()->register_hints(iterator->GetRegisterOperand(2));
+ FeedbackSlot slot = iterator->GetSlotOperand(3);
- HintsVector parameters(zone());
- parameters.push_back(receiver);
- parameters.push_back(arg0);
- parameters.push_back(arg1);
+ Hints receiver(zone());
+ receiver.AddConstant(broker()->isolate()->factory()->undefined_value());
- ProcessCallOrConstruct(callee, parameters);
+ HintsVector parameters({receiver, arg0, arg1}, zone());
+ ProcessCallOrConstruct(callee, base::nullopt, parameters, slot);
}
void SerializerForBackgroundCompilation::VisitCallAnyReceiver(
- interpreter::BytecodeArrayIterator* iterator) {
+ BytecodeArrayIterator* iterator) {
ProcessCallVarArgs(iterator, ConvertReceiverMode::kAny);
}
void SerializerForBackgroundCompilation::VisitCallNoFeedback(
- interpreter::BytecodeArrayIterator* iterator) {
+ BytecodeArrayIterator* iterator) {
ProcessCallVarArgs(iterator, ConvertReceiverMode::kNullOrUndefined);
}
void SerializerForBackgroundCompilation::VisitCallProperty(
- interpreter::BytecodeArrayIterator* iterator) {
+ BytecodeArrayIterator* iterator) {
ProcessCallVarArgs(iterator, ConvertReceiverMode::kNullOrUndefined);
}
void SerializerForBackgroundCompilation::VisitCallProperty0(
- interpreter::BytecodeArrayIterator* iterator) {
+ BytecodeArrayIterator* iterator) {
const Hints& callee =
environment()->register_hints(iterator->GetRegisterOperand(0));
const Hints& receiver =
environment()->register_hints(iterator->GetRegisterOperand(1));
+ FeedbackSlot slot = iterator->GetSlotOperand(2);
- HintsVector parameters(zone());
- parameters.push_back(receiver);
-
- ProcessCallOrConstruct(callee, parameters);
+ HintsVector parameters({receiver}, zone());
+ ProcessCallOrConstruct(callee, base::nullopt, parameters, slot);
}
void SerializerForBackgroundCompilation::VisitCallProperty1(
- interpreter::BytecodeArrayIterator* iterator) {
+ BytecodeArrayIterator* iterator) {
const Hints& callee =
environment()->register_hints(iterator->GetRegisterOperand(0));
const Hints& receiver =
environment()->register_hints(iterator->GetRegisterOperand(1));
const Hints& arg0 =
environment()->register_hints(iterator->GetRegisterOperand(2));
+ FeedbackSlot slot = iterator->GetSlotOperand(3);
- HintsVector parameters(zone());
- parameters.push_back(receiver);
- parameters.push_back(arg0);
-
- ProcessCallOrConstruct(callee, parameters);
+ HintsVector parameters({receiver, arg0}, zone());
+ ProcessCallOrConstruct(callee, base::nullopt, parameters, slot);
}
void SerializerForBackgroundCompilation::VisitCallProperty2(
- interpreter::BytecodeArrayIterator* iterator) {
+ BytecodeArrayIterator* iterator) {
const Hints& callee =
environment()->register_hints(iterator->GetRegisterOperand(0));
const Hints& receiver =
@@ -400,122 +499,282 @@ void SerializerForBackgroundCompilation::VisitCallProperty2(
environment()->register_hints(iterator->GetRegisterOperand(2));
const Hints& arg1 =
environment()->register_hints(iterator->GetRegisterOperand(3));
+ FeedbackSlot slot = iterator->GetSlotOperand(4);
+
+ HintsVector parameters({receiver, arg0, arg1}, zone());
+ ProcessCallOrConstruct(callee, base::nullopt, parameters, slot);
+}
+
+void SerializerForBackgroundCompilation::VisitCallWithSpread(
+ BytecodeArrayIterator* iterator) {
+ ProcessCallVarArgs(iterator, ConvertReceiverMode::kAny, true);
+}
+
+Hints SerializerForBackgroundCompilation::RunChildSerializer(
+ CompilationSubject function, base::Optional<Hints> new_target,
+ const HintsVector& arguments, bool with_spread) {
+ if (with_spread) {
+ DCHECK_LT(0, arguments.size());
+ // Pad the missing arguments in case we were called with spread operator.
+ // Drop the last actually passed argument, which contains the spread.
+ // We don't know what the spread element produces. Therefore we pretend
+ // that the function is called with the maximal number of parameters and
+ // that we have no information about the parameters that were not
+ // explicitly provided.
+ HintsVector padded = arguments;
+ padded.pop_back(); // Remove the spread element.
+ // Fill the rest with empty hints.
+ padded.resize(
+ function.blueprint().shared->GetBytecodeArray()->parameter_count(),
+ Hints(zone()));
+ return RunChildSerializer(function, new_target, padded, false);
+ }
- HintsVector parameters(zone());
- parameters.push_back(receiver);
- parameters.push_back(arg0);
- parameters.push_back(arg1);
+ if (FLAG_trace_heap_broker) {
+ std::ostream& out = broker()->Trace();
+ out << "\nWill run child serializer with environment:\n"
+ << "===========================================\n"
+ << *environment();
+ }
+
+ SerializerForBackgroundCompilation child_serializer(
+ broker(), zone(), function, new_target, arguments);
+ return child_serializer.Run();
+}
- ProcessCallOrConstruct(callee, parameters);
+namespace {
+base::Optional<HeapObjectRef> GetHeapObjectFeedback(
+ JSHeapBroker* broker, Handle<FeedbackVector> feedback_vector,
+ FeedbackSlot slot) {
+ if (slot.IsInvalid()) return base::nullopt;
+ FeedbackNexus nexus(feedback_vector, slot);
+ VectorSlotPair feedback(feedback_vector, slot, nexus.ic_state());
+ DCHECK(feedback.IsValid());
+ if (nexus.IsUninitialized()) return base::nullopt;
+ HeapObject object;
+ if (!nexus.GetFeedback()->GetHeapObject(&object)) return base::nullopt;
+ return HeapObjectRef(broker, handle(object, broker->isolate()));
}
+} // namespace
void SerializerForBackgroundCompilation::ProcessCallOrConstruct(
- const Hints& callee, const HintsVector& arguments) {
+ Hints callee, base::Optional<Hints> new_target,
+ const HintsVector& arguments, FeedbackSlot slot, bool with_spread) {
+ // Incorporate feedback into hints.
+ base::Optional<HeapObjectRef> feedback = GetHeapObjectFeedback(
+ broker(), environment()->function().feedback_vector, slot);
+ if (feedback.has_value() && feedback->map().is_callable()) {
+ if (new_target.has_value()) {
+ // Construct; feedback is new_target, which often is also the callee.
+ new_target->AddConstant(feedback->object());
+ callee.AddConstant(feedback->object());
+ } else {
+ // Call; feedback is callee.
+ callee.AddConstant(feedback->object());
+ }
+ }
+
environment()->accumulator_hints().Clear();
for (auto hint : callee.constants()) {
if (!hint->IsJSFunction()) continue;
Handle<JSFunction> function = Handle<JSFunction>::cast(hint);
- if (!function->shared()->IsInlineable()) continue;
-
- JSFunctionRef(broker(), function).Serialize();
+ if (!function->shared()->IsInlineable() || !function->has_feedback_vector())
+ continue;
- Handle<SharedFunctionInfo> shared(function->shared(), broker()->isolate());
- Handle<FeedbackVector> feedback(function->feedback_vector(),
- broker()->isolate());
- SerializerForBackgroundCompilation child_serializer(
- broker(), zone(), {shared, feedback}, arguments);
- environment()->accumulator_hints().Add(child_serializer.Run());
+ environment()->accumulator_hints().Add(RunChildSerializer(
+ {function, broker()->isolate()}, new_target, arguments, with_spread));
}
for (auto hint : callee.function_blueprints()) {
if (!hint.shared->IsInlineable()) continue;
- SerializerForBackgroundCompilation child_serializer(broker(), zone(), hint,
- arguments);
- environment()->accumulator_hints().Add(child_serializer.Run());
+ environment()->accumulator_hints().Add(RunChildSerializer(
+ CompilationSubject(hint), new_target, arguments, with_spread));
}
}
void SerializerForBackgroundCompilation::ProcessCallVarArgs(
- interpreter::BytecodeArrayIterator* iterator,
- ConvertReceiverMode receiver_mode) {
+ BytecodeArrayIterator* iterator, ConvertReceiverMode receiver_mode,
+ bool with_spread) {
const Hints& callee =
environment()->register_hints(iterator->GetRegisterOperand(0));
interpreter::Register first_reg = iterator->GetRegisterOperand(1);
int reg_count = static_cast<int>(iterator->GetRegisterCountOperand(2));
-
- bool first_reg_is_receiver =
- receiver_mode != ConvertReceiverMode::kNullOrUndefined;
-
- Hints receiver(zone());
- if (first_reg_is_receiver) {
- // The receiver is the first register, followed by the arguments in the
- // consecutive registers.
- receiver.Add(environment()->register_hints(first_reg));
- } else {
- // The receiver is implicit (and undefined), the arguments are in
- // consecutive registers.
- receiver.AddConstant(broker()->isolate()->factory()->undefined_value());
+ FeedbackSlot slot;
+ if (iterator->current_bytecode() != interpreter::Bytecode::kCallNoFeedback) {
+ slot = iterator->GetSlotOperand(3);
}
HintsVector arguments(zone());
- arguments.push_back(receiver);
- int arg_base = BoolToInt(first_reg_is_receiver);
- for (int i = arg_base; i < reg_count; ++i) {
- arguments.push_back(environment()->register_hints(
- interpreter::Register(first_reg.index() + i)));
+ // The receiver is either given in the first register or it is implicitly
+ // the {undefined} value.
+ if (receiver_mode == ConvertReceiverMode::kNullOrUndefined) {
+ Hints receiver(zone());
+ receiver.AddConstant(broker()->isolate()->factory()->undefined_value());
+ arguments.push_back(receiver);
}
+ environment()->ExportRegisterHints(first_reg, reg_count, arguments);
- ProcessCallOrConstruct(callee, arguments);
+ ProcessCallOrConstruct(callee, base::nullopt, arguments, slot);
}
-void SerializerForBackgroundCompilation::VisitReturn(
+void SerializerForBackgroundCompilation::ProcessJump(
+ interpreter::BytecodeArrayIterator* iterator) {
+ int jump_target = iterator->GetJumpTargetOffset();
+ int current_offset = iterator->current_offset();
+ if (current_offset >= jump_target) return;
+
+ stashed_environments_[jump_target] = new (zone()) Environment(*environment());
+}
+
+void SerializerForBackgroundCompilation::MergeAfterJump(
interpreter::BytecodeArrayIterator* iterator) {
+ int current_offset = iterator->current_offset();
+ auto stash = stashed_environments_.find(current_offset);
+ if (stash != stashed_environments_.end()) {
+ environment()->Merge(stash->second);
+ stashed_environments_.erase(stash);
+ }
+}
+
+void SerializerForBackgroundCompilation::VisitReturn(
+ BytecodeArrayIterator* iterator) {
environment()->return_value_hints().Add(environment()->accumulator_hints());
- environment()->ClearAccumulatorAndRegisterHints();
+ environment()->ClearEphemeralHints();
+}
+
+void SerializerForBackgroundCompilation::Environment::ExportRegisterHints(
+ interpreter::Register first, size_t count, HintsVector& dst) {
+ dst.resize(dst.size() + count, Hints(zone()));
+ int reg_base = first.index();
+ for (int i = 0; i < static_cast<int>(count); ++i) {
+ dst.push_back(register_hints(interpreter::Register(reg_base + i)));
+ }
}
void SerializerForBackgroundCompilation::VisitConstruct(
- interpreter::BytecodeArrayIterator* iterator) {
+ BytecodeArrayIterator* iterator) {
const Hints& callee =
environment()->register_hints(iterator->GetRegisterOperand(0));
+ interpreter::Register first_reg = iterator->GetRegisterOperand(1);
+ size_t reg_count = iterator->GetRegisterCountOperand(2);
+ FeedbackSlot slot = iterator->GetSlotOperand(3);
+ const Hints& new_target = environment()->accumulator_hints();
+
+ HintsVector arguments(zone());
+ environment()->ExportRegisterHints(first_reg, reg_count, arguments);
+ ProcessCallOrConstruct(callee, new_target, arguments, slot);
+}
+
+void SerializerForBackgroundCompilation::VisitConstructWithSpread(
+ BytecodeArrayIterator* iterator) {
+ const Hints& callee =
+ environment()->register_hints(iterator->GetRegisterOperand(0));
interpreter::Register first_reg = iterator->GetRegisterOperand(1);
size_t reg_count = iterator->GetRegisterCountOperand(2);
+ FeedbackSlot slot = iterator->GetSlotOperand(3);
+ const Hints& new_target = environment()->accumulator_hints();
HintsVector arguments(zone());
- // Push the target (callee) of the construct.
- arguments.push_back(callee);
-
- // The function arguments are in consecutive registers.
- int arg_base = first_reg.index();
- for (int i = 0; i < static_cast<int>(reg_count); ++i) {
- arguments.push_back(
- environment()->register_hints(interpreter::Register(arg_base + i)));
+ environment()->ExportRegisterHints(first_reg, reg_count, arguments);
+
+ ProcessCallOrConstruct(callee, new_target, arguments, slot, true);
+}
+
+void SerializerForBackgroundCompilation::ProcessFeedbackForKeyedPropertyAccess(
+ BytecodeArrayIterator* iterator) {
+ interpreter::Bytecode bytecode = iterator->current_bytecode();
+ DCHECK(bytecode == interpreter::Bytecode::kLdaKeyedProperty ||
+ bytecode == interpreter::Bytecode::kStaKeyedProperty ||
+ bytecode == interpreter::Bytecode::kStaInArrayLiteral);
+
+ if (environment()->function().feedback_vector.is_null()) return;
+
+ FeedbackSlot slot = iterator->GetSlotOperand(
+ bytecode == interpreter::Bytecode::kLdaKeyedProperty ? 1 : 2);
+ if (slot.IsInvalid()) return;
+
+ FeedbackNexus nexus(environment()->function().feedback_vector, slot);
+ if (broker()->HasFeedback(nexus)) return;
+
+ Handle<Name> name(nexus.GetName(), broker()->isolate());
+ CHECK_IMPLIES(nexus.GetKeyType() == ELEMENT, name->is_null());
+ if (!name->is_null() || nexus.GetKeyType() == PROPERTY) {
+ CHECK_NE(bytecode, interpreter::Bytecode::kStaInArrayLiteral);
+ return; // TODO(neis): Support named access.
}
- // Push the new_target of the construct.
- arguments.push_back(environment()->accumulator_hints());
+ if (nexus.ic_state() == MEGAMORPHIC) {
+ return;
+ }
+
+ ProcessedFeedback& processed = broker()->GetOrCreateFeedback(nexus);
+ MapHandles maps;
+ nexus.ExtractMaps(&maps);
+ ProcessFeedbackMapsForElementAccess(broker()->isolate(), maps, &processed);
- ProcessCallOrConstruct(callee, arguments);
+ // TODO(neis): Have something like MapRef::SerializeForElementStore() and call
+ // it for every receiver map in case of an element store.
}
-#define DEFINE_SKIPPED_JUMP(name, ...) \
+void SerializerForBackgroundCompilation::VisitLdaKeyedProperty(
+ BytecodeArrayIterator* iterator) {
+ environment()->accumulator_hints().Clear();
+ ProcessFeedbackForKeyedPropertyAccess(iterator);
+}
+
+void SerializerForBackgroundCompilation::VisitStaKeyedProperty(
+ BytecodeArrayIterator* iterator) {
+ environment()->accumulator_hints().Clear();
+ ProcessFeedbackForKeyedPropertyAccess(iterator);
+}
+
+void SerializerForBackgroundCompilation::VisitStaInArrayLiteral(
+ BytecodeArrayIterator* iterator) {
+ environment()->accumulator_hints().Clear();
+ ProcessFeedbackForKeyedPropertyAccess(iterator);
+}
+
+#define DEFINE_CLEAR_ENVIRONMENT(name, ...) \
void SerializerForBackgroundCompilation::Visit##name( \
- interpreter::BytecodeArrayIterator* iterator) { \
- environment()->ClearAccumulatorAndRegisterHints(); \
+ BytecodeArrayIterator* iterator) { \
+ environment()->ClearEphemeralHints(); \
}
-CLEAR_ENVIRONMENT_LIST(DEFINE_SKIPPED_JUMP)
-#undef DEFINE_SKIPPED_JUMP
+CLEAR_ENVIRONMENT_LIST(DEFINE_CLEAR_ENVIRONMENT)
+#undef DEFINE_CLEAR_ENVIRONMENT
#define DEFINE_CLEAR_ACCUMULATOR(name, ...) \
void SerializerForBackgroundCompilation::Visit##name( \
- interpreter::BytecodeArrayIterator* iterator) { \
+ BytecodeArrayIterator* iterator) { \
environment()->accumulator_hints().Clear(); \
}
CLEAR_ACCUMULATOR_LIST(DEFINE_CLEAR_ACCUMULATOR)
#undef DEFINE_CLEAR_ACCUMULATOR
+#define DEFINE_CONDITIONAL_JUMP(name, ...) \
+ void SerializerForBackgroundCompilation::Visit##name( \
+ BytecodeArrayIterator* iterator) { \
+ ProcessJump(iterator); \
+ }
+CONDITIONAL_JUMPS_LIST(DEFINE_CONDITIONAL_JUMP)
+#undef DEFINE_CONDITIONAL_JUMP
+
+#define DEFINE_UNCONDITIONAL_JUMP(name, ...) \
+ void SerializerForBackgroundCompilation::Visit##name( \
+ BytecodeArrayIterator* iterator) { \
+ ProcessJump(iterator); \
+ environment()->ClearEphemeralHints(); \
+ }
+UNCONDITIONAL_JUMPS_LIST(DEFINE_UNCONDITIONAL_JUMP)
+#undef DEFINE_UNCONDITIONAL_JUMP
+
+#define DEFINE_IGNORE(name, ...) \
+ void SerializerForBackgroundCompilation::Visit##name( \
+ BytecodeArrayIterator* iterator) {}
+INGORED_BYTECODE_LIST(DEFINE_IGNORE)
+#undef DEFINE_IGNORE
+
} // namespace compiler
} // namespace internal
} // namespace v8