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) {
ObjectRef target_ref = m.Ref(broker());
if (target_ref.IsJSFunction()) {
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.
if (!function.native_context().equals(native_context())) {
......@@ -3358,7 +3362,11 @@ Reduction JSCallReducer::ReduceJSCall(Node* node) {
return ReduceJSCall(node, function.shared());
} else if (target_ref.IsJSBoundFunction()) {
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();
ConvertReceiverMode const convert_mode =
......@@ -3941,7 +3949,11 @@ Reduction JSCallReducer::ReduceJSConstruct(Node* node) {
if (target_ref.IsJSFunction()) {
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.
if (function.shared().HasBreakInfo()) return NoChange();
......@@ -3998,7 +4010,11 @@ Reduction JSCallReducer::ReduceJSConstruct(Node* node) {
}
} else if (target_ref.IsJSBoundFunction()) {
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();
FixedArrayRef bound_arguments = function.bound_arguments();
......
......@@ -3644,6 +3644,11 @@ void JSFunctionRef::Serialize() {
data()->AsJSFunction()->Serialize(broker());
}
bool JSBoundFunctionRef::serialized() const {
CHECK_NE(broker()->mode(), JSHeapBroker::kDisabled);
return data()->AsJSBoundFunction()->serialized();
}
bool JSFunctionRef::serialized() const {
CHECK_NE(broker()->mode(), JSHeapBroker::kDisabled);
return data()->AsJSFunction()->serialized();
......@@ -3806,11 +3811,6 @@ void JSBoundFunctionRef::Serialize() {
data()->AsJSBoundFunction()->Serialize(broker());
}
bool JSBoundFunctionRef::serialized() const {
CHECK_NE(broker()->mode(), JSHeapBroker::kDisabled);
return data()->AsJSBoundFunction()->serialized();
}
void PropertyCellRef::Serialize() {
if (broker()->mode() == JSHeapBroker::kDisabled) return;
CHECK_EQ(broker()->mode(), JSHeapBroker::kSerializing);
......
......@@ -349,6 +349,15 @@ class SerializerForBackgroundCompilation {
SUPPORTED_BYTECODE_LIST(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,
const HintsVector& arguments, FeedbackSlot slot,
bool with_spread = false);
......@@ -1477,6 +1486,69 @@ base::Optional<HeapObjectRef> GetHeapObjectFeedback(
if (!nexus.GetFeedback()->GetHeapObject(&object)) return base::nullopt;
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
void SerializerForBackgroundCompilation::ProcessCallOrConstruct(
......@@ -1503,41 +1575,42 @@ void SerializerForBackgroundCompilation::ProcessCallOrConstruct(
FeedbackNexus nexus(environment()->function().feedback_vector(), slot);
SpeculationMode speculation_mode = nexus.GetSpeculationMode();
// For JSCallReducer::ReduceJSCall and JSCallReducer::ReduceJSConstruct.
for (auto hint : callee.constants()) {
if (!hint->IsJSFunction()) continue;
Handle<JSFunction> function = Handle<JSFunction>::cast(hint);
JSFunctionRef(broker(), function).Serialize();
Handle<SharedFunctionInfo> shared(function->shared(), broker()->isolate());
if (shared->IsApiFunction()) {
ProcessApiCall(shared, arguments);
DCHECK(!shared->IsInlineable());
} else if (shared->HasBuiltinId()) {
ProcessBuiltinCall(shared, arguments, speculation_mode);
DCHECK(!shared->IsInlineable());
const HintsVector* actual_arguments = &arguments;
Handle<JSFunction> function;
HintsVector expanded_arguments(zone());
if (hint->IsJSBoundFunction()) {
JSBoundFunctionRef bound_function(broker(),
Handle<JSBoundFunction>::cast(hint));
bound_function.Serialize();
MaybeHandle<JSFunction> maybe_function = UnrollBoundFunction(
bound_function, broker(), arguments, &expanded_arguments);
if (maybe_function.is_null()) continue;
function = maybe_function.ToHandleChecked();
actual_arguments = &expanded_arguments;
} else if (hint->IsJSFunction()) {
function = Handle<JSFunction>::cast(hint);
} else {
continue;
}
if (!shared->IsInlineable() || !function->has_feedback_vector()) continue;
environment()->accumulator_hints().Add(RunChildSerializer(
CompilationSubject(function, broker()->isolate(), zone()), new_target,
arguments, with_spread));
if (ProcessCalleeForCallOrConstruct(function, *actual_arguments,
speculation_mode)) {
environment()->accumulator_hints().Add(RunChildSerializer(
CompilationSubject(function, broker()->isolate(), zone()), new_target,
*actual_arguments, with_spread));
}
}
// For JSCallReducer::ReduceJSCall and JSCallReducer::ReduceJSConstruct.
for (auto hint : callee.function_blueprints()) {
Handle<SharedFunctionInfo> shared = hint.shared();
if (shared->IsApiFunction()) {
ProcessApiCall(shared, arguments);
DCHECK(!shared->IsInlineable());
} else if (shared->HasBuiltinId()) {
ProcessBuiltinCall(shared, arguments, speculation_mode);
DCHECK(!shared->IsInlineable());
if (!ProcessSFIForCallOrConstruct(shared, arguments, speculation_mode)) {
continue;
}
if (!shared->IsInlineable()) continue;
environment()->accumulator_hints().Add(RunChildSerializer(
CompilationSubject(hint), new_target, arguments, with_spread));
}
......@@ -2076,20 +2149,31 @@ SerializerForBackgroundCompilation::ProcessFeedbackMapsForNamedAccess(
// TODO(turbofan): We want to take receiver hints into account as well,
// not only the feedback maps.
// For JSNativeContextSpecialization::InlinePropertySetterCall
// and InlinePropertyGetterCall.
if (info.IsAccessorConstant() && !info.constant().is_null()) {
if (info.constant()->IsJSFunction()) {
JSFunctionRef function(broker(),
Handle<JSFunction>::cast(info.constant()));
// For JSCallReducer::ReduceJSCall.
function.Serialize();
// For JSCallReducer::ReduceCallApiFunction.
Handle<SharedFunctionInfo> sfi(
handle(Handle<JSFunction>::cast(info.constant())->shared(),
broker()->isolate()));
Handle<SharedFunctionInfo> sfi = function.shared().object();
if (sfi->IsApiFunction()) {
FunctionTemplateInfoRef fti_ref(
broker(), handle(sfi->get_api_func_data(), broker()->isolate()));
if (fti_ref.has_call_code()) fti_ref.SerializeCallCode();
ProcessReceiverMapForApiCall(fti_ref, map);
}
} else if (info.constant()->IsJSBoundFunction()) {
JSBoundFunctionRef function(
broker(), Handle<JSBoundFunction>::cast(info.constant()));
// For JSCallReducer::ReduceJSCall.
function.Serialize();
} else {
FunctionTemplateInfoRef fti_ref(
broker(), Handle<FunctionTemplateInfo>::cast(info.constant()));
......@@ -2186,6 +2270,8 @@ void SerializerForBackgroundCompilation::ProcessMapForNamedPropertyAccess(
broker()->native_context().global_proxy_object().GetPropertyCell(name,
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(
......
......@@ -70,7 +70,11 @@ void CheckForSerializedInlinee(const char* source, int argc = 0,
Handle<Object> 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);
SharedFunctionInfoRef g_sfi(tester.broker(),
handle(g_func->shared(), tester.isolate()));
FeedbackVectorRef g_fv(tester.broker(),
......@@ -288,6 +292,34 @@ TEST(MergeJumpTargetEnvironment) {
"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 internal
} // 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