Commit b1c641be authored by Maya Lekova's avatar Maya Lekova Committed by Commit Bot

[turbofan] Brokerize ReduceJSCall and ReduceJSConstruct

Bug: v8:7790

Change-Id: Icd0194924d7b0aa58f5b7ee74028cec9f5c39564
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1715460Reviewed-by: 's avatarGeorg Neis <neis@chromium.org>
Reviewed-by: 's avatarMaya Lekova <mslekova@chromium.org>
Commit-Queue: Maya Lekova <mslekova@chromium.org>
Cr-Commit-Position: refs/heads/master@{#63018}
parent 7efd7b0c
...@@ -3348,7 +3348,11 @@ Reduction JSCallReducer::ReduceJSCall(Node* node) { ...@@ -3348,7 +3348,11 @@ Reduction JSCallReducer::ReduceJSCall(Node* node) {
ObjectRef target_ref = m.Ref(broker()); ObjectRef target_ref = m.Ref(broker());
if (target_ref.IsJSFunction()) { if (target_ref.IsJSFunction()) {
JSFunctionRef function = target_ref.AsJSFunction(); JSFunctionRef function = target_ref.AsJSFunction();
function.Serialize(); if (FLAG_concurrent_inlining && !function.serialized()) {
TRACE_BROKER_MISSING(broker(),
"function, not serialized: " << function);
return NoChange();
}
// Don't inline cross native context. // Don't inline cross native context.
if (!function.native_context().equals(native_context())) { if (!function.native_context().equals(native_context())) {
...@@ -3358,7 +3362,11 @@ Reduction JSCallReducer::ReduceJSCall(Node* node) { ...@@ -3358,7 +3362,11 @@ Reduction JSCallReducer::ReduceJSCall(Node* node) {
return ReduceJSCall(node, function.shared()); return ReduceJSCall(node, function.shared());
} else if (target_ref.IsJSBoundFunction()) { } else if (target_ref.IsJSBoundFunction()) {
JSBoundFunctionRef function = target_ref.AsJSBoundFunction(); JSBoundFunctionRef function = target_ref.AsJSBoundFunction();
function.Serialize(); if (FLAG_concurrent_inlining && !function.serialized()) {
TRACE_BROKER_MISSING(broker(),
"function, not serialized: " << function);
return NoChange();
}
ObjectRef bound_this = function.bound_this(); ObjectRef bound_this = function.bound_this();
ConvertReceiverMode const convert_mode = ConvertReceiverMode const convert_mode =
...@@ -3941,7 +3949,11 @@ Reduction JSCallReducer::ReduceJSConstruct(Node* node) { ...@@ -3941,7 +3949,11 @@ Reduction JSCallReducer::ReduceJSConstruct(Node* node) {
if (target_ref.IsJSFunction()) { if (target_ref.IsJSFunction()) {
JSFunctionRef function = target_ref.AsJSFunction(); JSFunctionRef function = target_ref.AsJSFunction();
function.Serialize(); if (FLAG_concurrent_inlining && !function.serialized()) {
TRACE_BROKER_MISSING(broker(),
"function, not serialized: " << function);
return NoChange();
}
// Do not reduce constructors with break points. // Do not reduce constructors with break points.
if (function.shared().HasBreakInfo()) return NoChange(); if (function.shared().HasBreakInfo()) return NoChange();
...@@ -3998,7 +4010,11 @@ Reduction JSCallReducer::ReduceJSConstruct(Node* node) { ...@@ -3998,7 +4010,11 @@ Reduction JSCallReducer::ReduceJSConstruct(Node* node) {
} }
} else if (target_ref.IsJSBoundFunction()) { } else if (target_ref.IsJSBoundFunction()) {
JSBoundFunctionRef function = target_ref.AsJSBoundFunction(); JSBoundFunctionRef function = target_ref.AsJSBoundFunction();
function.Serialize(); if (FLAG_concurrent_inlining && !function.serialized()) {
TRACE_BROKER_MISSING(broker(),
"function, not serialized: " << function);
return NoChange();
}
ObjectRef bound_target_function = function.bound_target_function(); ObjectRef bound_target_function = function.bound_target_function();
FixedArrayRef bound_arguments = function.bound_arguments(); FixedArrayRef bound_arguments = function.bound_arguments();
......
...@@ -3644,6 +3644,11 @@ void JSFunctionRef::Serialize() { ...@@ -3644,6 +3644,11 @@ void JSFunctionRef::Serialize() {
data()->AsJSFunction()->Serialize(broker()); data()->AsJSFunction()->Serialize(broker());
} }
bool JSBoundFunctionRef::serialized() const {
CHECK_NE(broker()->mode(), JSHeapBroker::kDisabled);
return data()->AsJSBoundFunction()->serialized();
}
bool JSFunctionRef::serialized() const { bool JSFunctionRef::serialized() const {
CHECK_NE(broker()->mode(), JSHeapBroker::kDisabled); CHECK_NE(broker()->mode(), JSHeapBroker::kDisabled);
return data()->AsJSFunction()->serialized(); return data()->AsJSFunction()->serialized();
...@@ -3806,11 +3811,6 @@ void JSBoundFunctionRef::Serialize() { ...@@ -3806,11 +3811,6 @@ void JSBoundFunctionRef::Serialize() {
data()->AsJSBoundFunction()->Serialize(broker()); data()->AsJSBoundFunction()->Serialize(broker());
} }
bool JSBoundFunctionRef::serialized() const {
CHECK_NE(broker()->mode(), JSHeapBroker::kDisabled);
return data()->AsJSBoundFunction()->serialized();
}
void PropertyCellRef::Serialize() { void PropertyCellRef::Serialize() {
if (broker()->mode() == JSHeapBroker::kDisabled) return; if (broker()->mode() == JSHeapBroker::kDisabled) return;
CHECK_EQ(broker()->mode(), JSHeapBroker::kSerializing); CHECK_EQ(broker()->mode(), JSHeapBroker::kSerializing);
......
...@@ -349,6 +349,15 @@ class SerializerForBackgroundCompilation { ...@@ -349,6 +349,15 @@ class SerializerForBackgroundCompilation {
SUPPORTED_BYTECODE_LIST(DECLARE_VISIT_BYTECODE) SUPPORTED_BYTECODE_LIST(DECLARE_VISIT_BYTECODE)
#undef DECLARE_VISIT_BYTECODE #undef DECLARE_VISIT_BYTECODE
// Returns whether the callee with the given SFI should be processed further,
// i.e. whether it's inlineable.
bool ProcessSFIForCallOrConstruct(Handle<SharedFunctionInfo> shared,
const HintsVector& arguments,
SpeculationMode speculation_mode);
// Returns whether {function} should be serialized for compilation.
bool ProcessCalleeForCallOrConstruct(Handle<JSFunction> function,
const HintsVector& arguments,
SpeculationMode speculation_mode);
void ProcessCallOrConstruct(Hints callee, base::Optional<Hints> new_target, void ProcessCallOrConstruct(Hints callee, base::Optional<Hints> new_target,
const HintsVector& arguments, FeedbackSlot slot, const HintsVector& arguments, FeedbackSlot slot,
bool with_spread = false); bool with_spread = false);
...@@ -1477,6 +1486,69 @@ base::Optional<HeapObjectRef> GetHeapObjectFeedback( ...@@ -1477,6 +1486,69 @@ base::Optional<HeapObjectRef> GetHeapObjectFeedback(
if (!nexus.GetFeedback()->GetHeapObject(&object)) return base::nullopt; if (!nexus.GetFeedback()->GetHeapObject(&object)) return base::nullopt;
return HeapObjectRef(broker, handle(object, broker->isolate())); return HeapObjectRef(broker, handle(object, broker->isolate()));
} }
} // namespace
bool SerializerForBackgroundCompilation::ProcessSFIForCallOrConstruct(
Handle<SharedFunctionInfo> shared, const HintsVector& arguments,
SpeculationMode speculation_mode) {
if (shared->IsApiFunction()) {
ProcessApiCall(shared, arguments);
DCHECK(!shared->IsInlineable());
} else if (shared->HasBuiltinId()) {
ProcessBuiltinCall(shared, arguments, speculation_mode);
DCHECK(!shared->IsInlineable());
}
return shared->IsInlineable();
}
bool SerializerForBackgroundCompilation::ProcessCalleeForCallOrConstruct(
Handle<JSFunction> function, const HintsVector& arguments,
SpeculationMode speculation_mode) {
JSFunctionRef(broker(), function).Serialize();
Handle<SharedFunctionInfo> shared(function->shared(), broker()->isolate());
return ProcessSFIForCallOrConstruct(shared, arguments, speculation_mode) &&
function->has_feedback_vector();
}
namespace {
// Returns the innermost bound target, if it's a JSFunction and inserts
// all bound arguments and {original_arguments} into {expanded_arguments}
// in the appropriate order.
MaybeHandle<JSFunction> UnrollBoundFunction(
JSBoundFunctionRef const& bound_function, JSHeapBroker* broker,
const HintsVector& original_arguments, HintsVector* expanded_arguments) {
DCHECK(expanded_arguments->empty());
JSReceiverRef target = bound_function.AsJSReceiver();
HintsVector reversed_bound_arguments(broker->zone());
for (; target.IsJSBoundFunction();
target = target.AsJSBoundFunction().bound_target_function()) {
for (int i = target.AsJSBoundFunction().bound_arguments().length() - 1;
i >= 0; --i) {
Hints arg(broker->zone());
arg.AddConstant(
target.AsJSBoundFunction().bound_arguments().get(i).object());
reversed_bound_arguments.push_back(arg);
}
Hints arg(broker->zone());
arg.AddConstant(target.AsJSBoundFunction().bound_this().object());
reversed_bound_arguments.push_back(arg);
}
if (!target.IsJSFunction()) return MaybeHandle<JSFunction>();
expanded_arguments->insert(expanded_arguments->end(),
reversed_bound_arguments.rbegin(),
reversed_bound_arguments.rend());
expanded_arguments->insert(expanded_arguments->end(),
original_arguments.begin(),
original_arguments.end());
return target.AsJSFunction().object();
}
} // namespace } // namespace
void SerializerForBackgroundCompilation::ProcessCallOrConstruct( void SerializerForBackgroundCompilation::ProcessCallOrConstruct(
...@@ -1503,41 +1575,42 @@ void SerializerForBackgroundCompilation::ProcessCallOrConstruct( ...@@ -1503,41 +1575,42 @@ void SerializerForBackgroundCompilation::ProcessCallOrConstruct(
FeedbackNexus nexus(environment()->function().feedback_vector(), slot); FeedbackNexus nexus(environment()->function().feedback_vector(), slot);
SpeculationMode speculation_mode = nexus.GetSpeculationMode(); SpeculationMode speculation_mode = nexus.GetSpeculationMode();
// For JSCallReducer::ReduceJSCall and JSCallReducer::ReduceJSConstruct.
for (auto hint : callee.constants()) { for (auto hint : callee.constants()) {
if (!hint->IsJSFunction()) continue; const HintsVector* actual_arguments = &arguments;
Handle<JSFunction> function;
Handle<JSFunction> function = Handle<JSFunction>::cast(hint); HintsVector expanded_arguments(zone());
JSFunctionRef(broker(), function).Serialize(); if (hint->IsJSBoundFunction()) {
JSBoundFunctionRef bound_function(broker(),
Handle<SharedFunctionInfo> shared(function->shared(), broker()->isolate()); Handle<JSBoundFunction>::cast(hint));
bound_function.Serialize();
if (shared->IsApiFunction()) {
ProcessApiCall(shared, arguments); MaybeHandle<JSFunction> maybe_function = UnrollBoundFunction(
DCHECK(!shared->IsInlineable()); bound_function, broker(), arguments, &expanded_arguments);
} else if (shared->HasBuiltinId()) { if (maybe_function.is_null()) continue;
ProcessBuiltinCall(shared, arguments, speculation_mode); function = maybe_function.ToHandleChecked();
DCHECK(!shared->IsInlineable()); actual_arguments = &expanded_arguments;
} else if (hint->IsJSFunction()) {
function = Handle<JSFunction>::cast(hint);
} else {
continue;
} }
if (!shared->IsInlineable() || !function->has_feedback_vector()) continue; if (ProcessCalleeForCallOrConstruct(function, *actual_arguments,
speculation_mode)) {
environment()->accumulator_hints().Add(RunChildSerializer( environment()->accumulator_hints().Add(RunChildSerializer(
CompilationSubject(function, broker()->isolate(), zone()), new_target, CompilationSubject(function, broker()->isolate(), zone()), new_target,
arguments, with_spread)); *actual_arguments, with_spread));
}
} }
// For JSCallReducer::ReduceJSCall and JSCallReducer::ReduceJSConstruct.
for (auto hint : callee.function_blueprints()) { for (auto hint : callee.function_blueprints()) {
Handle<SharedFunctionInfo> shared = hint.shared(); Handle<SharedFunctionInfo> shared = hint.shared();
if (!ProcessSFIForCallOrConstruct(shared, arguments, speculation_mode)) {
if (shared->IsApiFunction()) { continue;
ProcessApiCall(shared, arguments);
DCHECK(!shared->IsInlineable());
} else if (shared->HasBuiltinId()) {
ProcessBuiltinCall(shared, arguments, speculation_mode);
DCHECK(!shared->IsInlineable());
} }
if (!shared->IsInlineable()) continue;
environment()->accumulator_hints().Add(RunChildSerializer( environment()->accumulator_hints().Add(RunChildSerializer(
CompilationSubject(hint), new_target, arguments, with_spread)); CompilationSubject(hint), new_target, arguments, with_spread));
} }
...@@ -2076,20 +2149,31 @@ SerializerForBackgroundCompilation::ProcessFeedbackMapsForNamedAccess( ...@@ -2076,20 +2149,31 @@ SerializerForBackgroundCompilation::ProcessFeedbackMapsForNamedAccess(
// TODO(turbofan): We want to take receiver hints into account as well, // TODO(turbofan): We want to take receiver hints into account as well,
// not only the feedback maps. // not only the feedback maps.
// For JSNativeContextSpecialization::InlinePropertySetterCall // For JSNativeContextSpecialization::InlinePropertySetterCall
// and InlinePropertyGetterCall. // and InlinePropertyGetterCall.
if (info.IsAccessorConstant() && !info.constant().is_null()) { if (info.IsAccessorConstant() && !info.constant().is_null()) {
if (info.constant()->IsJSFunction()) { if (info.constant()->IsJSFunction()) {
JSFunctionRef function(broker(),
Handle<JSFunction>::cast(info.constant()));
// For JSCallReducer::ReduceJSCall.
function.Serialize();
// For JSCallReducer::ReduceCallApiFunction. // For JSCallReducer::ReduceCallApiFunction.
Handle<SharedFunctionInfo> sfi( Handle<SharedFunctionInfo> sfi = function.shared().object();
handle(Handle<JSFunction>::cast(info.constant())->shared(),
broker()->isolate()));
if (sfi->IsApiFunction()) { if (sfi->IsApiFunction()) {
FunctionTemplateInfoRef fti_ref( FunctionTemplateInfoRef fti_ref(
broker(), handle(sfi->get_api_func_data(), broker()->isolate())); broker(), handle(sfi->get_api_func_data(), broker()->isolate()));
if (fti_ref.has_call_code()) fti_ref.SerializeCallCode(); if (fti_ref.has_call_code()) fti_ref.SerializeCallCode();
ProcessReceiverMapForApiCall(fti_ref, map); ProcessReceiverMapForApiCall(fti_ref, map);
} }
} else if (info.constant()->IsJSBoundFunction()) {
JSBoundFunctionRef function(
broker(), Handle<JSBoundFunction>::cast(info.constant()));
// For JSCallReducer::ReduceJSCall.
function.Serialize();
} else { } else {
FunctionTemplateInfoRef fti_ref( FunctionTemplateInfoRef fti_ref(
broker(), Handle<FunctionTemplateInfo>::cast(info.constant())); broker(), Handle<FunctionTemplateInfo>::cast(info.constant()));
...@@ -2186,6 +2270,8 @@ void SerializerForBackgroundCompilation::ProcessMapForNamedPropertyAccess( ...@@ -2186,6 +2270,8 @@ void SerializerForBackgroundCompilation::ProcessMapForNamedPropertyAccess(
broker()->native_context().global_proxy_object().GetPropertyCell(name, broker()->native_context().global_proxy_object().GetPropertyCell(name,
true); true);
} }
// TODO(mslekova): Compute the property access infos as we do for feedback
// maps, store them somewhere. Add constants to the accumulator.
} }
void SerializerForBackgroundCompilation::VisitLdaKeyedProperty( void SerializerForBackgroundCompilation::VisitLdaKeyedProperty(
......
...@@ -70,7 +70,11 @@ void CheckForSerializedInlinee(const char* source, int argc = 0, ...@@ -70,7 +70,11 @@ void CheckForSerializedInlinee(const char* source, int argc = 0,
Handle<Object> g; Handle<Object> g;
CHECK(g_obj.ToHandle(&g)); CHECK(g_obj.ToHandle(&g));
CHECK_WITH_MSG(
g->IsJSFunction(),
"The return value of the outer function must be a function too");
Handle<JSFunction> g_func = Handle<JSFunction>::cast(g); Handle<JSFunction> g_func = Handle<JSFunction>::cast(g);
SharedFunctionInfoRef g_sfi(tester.broker(), SharedFunctionInfoRef g_sfi(tester.broker(),
handle(g_func->shared(), tester.isolate())); handle(g_func->shared(), tester.isolate()));
FeedbackVectorRef g_fv(tester.broker(), FeedbackVectorRef g_fv(tester.broker(),
...@@ -288,6 +292,34 @@ TEST(MergeJumpTargetEnvironment) { ...@@ -288,6 +292,34 @@ TEST(MergeJumpTargetEnvironment) {
"f(); return f;"); // Two calls to f to make g() megamorhpic. "f(); return f;"); // Two calls to f to make g() megamorhpic.
} }
TEST(BoundFunctionTarget) {
CheckForSerializedInlinee(
"function apply(foo, arg) { return foo(arg); };"
"%EnsureFeedbackVectorForFunction(apply);"
"function test() {"
" const lambda = (a) => a;"
" %EnsureFeedbackVectorForFunction(lambda);"
" let bound = apply.bind(null, lambda).bind(null, 42);"
" %TurbofanStaticAssert(bound() == 42); return apply;"
"};"
"%EnsureFeedbackVectorForFunction(test);"
"test(); return test;");
}
TEST(BoundFunctionArguments) {
CheckForSerializedInlinee(
"function apply(foo, arg) { return foo(arg); };"
"%EnsureFeedbackVectorForFunction(apply);"
"function test() {"
" const lambda = (a) => a;"
" %EnsureFeedbackVectorForFunction(lambda);"
" let bound = apply.bind(null, lambda).bind(null, 42);"
" %TurbofanStaticAssert(bound() == 42); return lambda;"
"};"
"%EnsureFeedbackVectorForFunction(test);"
"test(); return test;");
}
} // namespace compiler } // namespace compiler
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment