[Turbofan] Brokerize more promise reductions in JSCallReducer

The functions

 * JSCallReducer::ReducePromisePrototypeThen
 * JSCallReducer::ReducePromisePrototypeFinally
 * JSCallReducer::ReducePromisePrototypeCatch

need the prototype for all receiver maps to be serialized in order
to take effect. We can do this by processing our receiver hints
when processing a builtin call in the serializer.

Bug: v8:7790
Change-Id: I3d9144924cf6926cfcd93b60ac703cfba2d3d93a
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1660623
Commit-Queue: Michael Stanton <mvstanton@chromium.org>
Reviewed-by: Jaroslav Sevcik <jarin@chromium.org>
Cr-Commit-Position: refs/heads/master@{#62208}
This commit is contained in:
Mike Stanton 2019-06-17 12:07:52 +02:00 committed by Commit Bot
parent 45a751a187
commit c5b9eda7ca
4 changed files with 69 additions and 62 deletions

View File

@ -5812,6 +5812,31 @@ Reduction JSCallReducer::ReducePromiseInternalResolve(Node* node) {
return Replace(value);
}
bool JSCallReducer::DoPromiseChecks(MapInference* inference) {
if (!inference->HaveMaps()) return false;
MapHandles const& receiver_maps = inference->GetMaps();
// Check whether all {receiver_maps} are JSPromise maps and
// have the initial Promise.prototype as their [[Prototype]].
for (Handle<Map> map : receiver_maps) {
MapRef receiver_map(broker(), map);
if (!receiver_map.IsJSPromiseMap()) return false;
if (!FLAG_concurrent_inlining) {
receiver_map.SerializePrototype();
} else if (!receiver_map.serialized_prototype()) {
TRACE_BROKER_MISSING(broker(),
"Unserialized prototype for map " << receiver_map);
return false;
}
if (!receiver_map.prototype().equals(
native_context().promise_prototype())) {
return false;
}
}
return true;
}
// ES section #sec-promise.prototype.catch
Reduction JSCallReducer::ReducePromisePrototypeCatch(Node* node) {
DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
@ -5825,20 +5850,7 @@ Reduction JSCallReducer::ReducePromisePrototypeCatch(Node* node) {
Node* control = NodeProperties::GetControlInput(node);
MapInference inference(broker(), receiver, effect);
if (!inference.HaveMaps()) return NoChange();
MapHandles const& receiver_maps = inference.GetMaps();
// Check whether all {receiver_maps} are JSPromise maps and
// have the initial Promise.prototype as their [[Prototype]].
for (Handle<Map> map : receiver_maps) {
MapRef receiver_map(broker(), map);
if (!receiver_map.IsJSPromiseMap()) return inference.NoChange();
receiver_map.SerializePrototype();
if (!receiver_map.prototype().equals(
native_context().promise_prototype())) {
return inference.NoChange();
}
}
if (!DoPromiseChecks(&inference)) return NoChange();
if (!dependencies()->DependOnPromiseThenProtector())
return inference.NoChange();
@ -5878,21 +5890,9 @@ Reduction JSCallReducer::ReducePromisePrototypeFinally(Node* node) {
}
MapInference inference(broker(), receiver, effect);
if (!inference.HaveMaps()) return NoChange();
if (!DoPromiseChecks(&inference)) return NoChange();
MapHandles const& receiver_maps = inference.GetMaps();
// Check whether all {receiver_maps} are JSPromise maps and
// have the initial Promise.prototype as their [[Prototype]].
for (Handle<Map> map : receiver_maps) {
MapRef receiver_map(broker(), map);
if (!receiver_map.IsJSPromiseMap()) return inference.NoChange();
receiver_map.SerializePrototype();
if (!receiver_map.prototype().equals(
native_context().promise_prototype())) {
return inference.NoChange();
}
}
// Check if we have the required scope_info.
if (!native_context().scope_info().has_value()) {
TRACE_BROKER_MISSING(broker(), "data for native context scope_info");
@ -6023,28 +6023,8 @@ Reduction JSCallReducer::ReducePromisePrototypeThen(Node* node) {
Node* frame_state = NodeProperties::GetFrameStateInput(node);
DisallowHeapAccessIf no_heap_acess(FLAG_concurrent_inlining);
MapInference inference(broker(), receiver, effect);
if (!inference.HaveMaps()) return NoChange();
MapHandles const& receiver_maps = inference.GetMaps();
// Check whether all {receiver_maps} are JSPromise maps and
// have the initial Promise.prototype as their [[Prototype]].
for (Handle<Map> map : receiver_maps) {
MapRef receiver_map(broker(), map);
if (!receiver_map.IsJSPromiseMap()) return inference.NoChange();
if (!FLAG_concurrent_inlining) {
receiver_map.SerializePrototype();
} else if (!receiver_map.serialized_prototype()) {
TRACE_BROKER_MISSING(broker(),
"Unserialized prototype for map " << receiver_map);
return inference.NoChange();
}
if (!receiver_map.prototype().equals(
native_context().promise_prototype())) {
return inference.NoChange();
}
}
if (!DoPromiseChecks(&inference)) return inference.NoChange();
if (!dependencies()->DependOnPromiseHookProtector())
return inference.NoChange();

View File

@ -29,6 +29,7 @@ struct FieldAccess;
class JSGraph;
class JSHeapBroker;
class JSOperatorBuilder;
class MapInference;
class NodeProperties;
class SimplifiedOperatorBuilder;
@ -191,6 +192,9 @@ class V8_EXPORT_PRIVATE JSCallReducer final : public AdvancedReducer {
Reduction ReduceNumberConstructor(Node* node);
// Helper to verify promise receiver maps are as expected.
bool DoPromiseChecks(MapInference* inference);
// Returns the updated {to} node, and updates control and effect along the
// way.
Node* DoFilterPostCallbackWork(ElementsKind kind, Node** control,

View File

@ -866,20 +866,48 @@ void SerializerForBackgroundCompilation::ProcessBuiltinCall(
switch (builtin_id) {
case Builtins::kPromiseConstructor: {
TRACE_BROKER(broker(), "Serializing data for builtin PromiseConstructor");
// For JSCallReducer::ReducePromiseConstructor.
broker()->native_context().SerializeScopeInfo();
break;
}
case Builtins::kPromisePrototypeCatch: {
TRACE_BROKER(broker(),
"Serializing data for builtin PromisePrototypeCatch");
// For JSCallReducer::ReducePromisePrototypeCatch.
broker()->native_context().SerializeScopeInfo();
CHECK_GE(arguments.size(), 1);
Hints const& receiver_hints = arguments[0];
ProcessMapHintsForPromises(receiver_hints);
break;
}
case Builtins::kPromisePrototypeFinally: {
TRACE_BROKER(broker(),
"Serializing data for builtin PromisePrototypeFinally");
// For JSCallReducer::ReducePromisePrototypeFinally.
broker()->native_context().SerializeScopeInfo();
CHECK_GE(arguments.size(), 1);
Hints const& receiver_hints = arguments[0];
ProcessMapHintsForPromises(receiver_hints);
break;
}
case Builtins::kPromisePrototypeThen: {
TRACE_BROKER(broker(),
"Serializing data for builtin PromisePrototypeThen");
// For JSCallReducer::ReducePromisePrototypeThen.
CHECK_GE(arguments.size(), 1);
Hints const& receiver_hints = arguments[0];
ProcessMapHintsForPromises(receiver_hints);
break;
}
default:
break;
}
}
void SerializerForBackgroundCompilation::ProcessMapHintsForPromises(
Hints const& receiver_hints) {
// We need to serialize the prototypes on each receiver map.
for (auto hint : receiver_hints.constants()) {
if (!hint->IsJSPromise()) continue;
@ -893,12 +921,6 @@ void SerializerForBackgroundCompilation::ProcessBuiltinCall(
MapRef receiver_mapref(broker(), receiver_map);
receiver_mapref.SerializePrototype();
}
break;
}
default:
break;
}
}
void SerializerForBackgroundCompilation::ContributeToJumpTargetEnvironment(

View File

@ -335,6 +335,7 @@ class SerializerForBackgroundCompilation {
AccessMode mode);
void ProcessNamedPropertyAccess(Hints const& receiver, NameRef const& name,
FeedbackSlot slot, AccessMode mode);
void ProcessMapHintsForPromises(Hints const& receiver_hints);
GlobalAccessFeedback const* ProcessFeedbackForGlobalAccess(FeedbackSlot slot);
NamedAccessFeedback const* ProcessFeedbackMapsForNamedAccess(