[turbofan] Remove eager frame state from call nodes.
This removes the frame state input representing the before-state from nodes having the {JSCallFunction} or {JSCallConstruct} operator. These frame states can by now be found via checkpoints in the graph. R=bmeurer@chromium.org BUG=v8:5021 Review-Url: https://codereview.chromium.org/2025573003 Cr-Commit-Position: refs/heads/master@{#36669}
This commit is contained in:
parent
5a3a6dafae
commit
864b07e9eb
@ -71,7 +71,6 @@ Reduction JSCallReducer::ReduceArrayConstructor(Node* node) {
|
||||
size_t const arity = p.arity() - 2;
|
||||
NodeProperties::ReplaceValueInput(node, target, 0);
|
||||
NodeProperties::ReplaceValueInput(node, target, 1);
|
||||
NodeProperties::RemoveFrameStateInput(node, 1);
|
||||
// TODO(bmeurer): We might need to propagate the tail call mode to
|
||||
// the JSCreateArray operator, because an Array call in tail call
|
||||
// position must always properly consume the parent stack frame.
|
||||
@ -89,7 +88,6 @@ Reduction JSCallReducer::ReduceNumberConstructor(Node* node) {
|
||||
DCHECK_LE(2u, p.arity());
|
||||
Node* value = (p.arity() == 2) ? jsgraph()->ZeroConstant()
|
||||
: NodeProperties::GetValueInput(node, 2);
|
||||
NodeProperties::RemoveFrameStateInput(node, 1);
|
||||
NodeProperties::ReplaceValueInputs(node, value);
|
||||
NodeProperties::ChangeOp(node, javascript()->ToNumber());
|
||||
return Changed(node);
|
||||
@ -220,9 +218,9 @@ Reduction JSCallReducer::ReduceJSCallFunction(Node* node) {
|
||||
CallFunctionParameters const& p = CallFunctionParametersOf(node->op());
|
||||
Node* target = NodeProperties::GetValueInput(node, 0);
|
||||
Node* context = NodeProperties::GetContextInput(node);
|
||||
Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
|
||||
Node* control = NodeProperties::GetControlInput(node);
|
||||
Node* effect = NodeProperties::GetEffectInput(node);
|
||||
Node* frame_state = NodeProperties::FindFrameStateBefore(node);
|
||||
|
||||
// Try to specialize JSCallFunction {node}s with constant {target}s.
|
||||
HeapObjectMatcher m(target);
|
||||
@ -233,7 +231,6 @@ Reduction JSCallReducer::ReduceJSCallFunction(Node* node) {
|
||||
|
||||
// Raise a TypeError if the {target} is a "classConstructor".
|
||||
if (IsClassConstructor(shared->kind())) {
|
||||
NodeProperties::RemoveFrameStateInput(node, 0);
|
||||
NodeProperties::ReplaceValueInputs(node, target);
|
||||
NodeProperties::ChangeOp(
|
||||
node, javascript()->CallRuntime(
|
||||
@ -370,9 +367,9 @@ Reduction JSCallReducer::ReduceJSCallConstruct(Node* node) {
|
||||
Node* target = NodeProperties::GetValueInput(node, 0);
|
||||
Node* new_target = NodeProperties::GetValueInput(node, arity + 1);
|
||||
Node* context = NodeProperties::GetContextInput(node);
|
||||
Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
|
||||
Node* effect = NodeProperties::GetEffectInput(node);
|
||||
Node* control = NodeProperties::GetControlInput(node);
|
||||
Node* frame_state = NodeProperties::FindFrameStateBefore(node);
|
||||
|
||||
// Try to specialize JSCallConstruct {node}s with constant {target}s.
|
||||
HeapObjectMatcher m(target);
|
||||
@ -382,11 +379,6 @@ Reduction JSCallReducer::ReduceJSCallConstruct(Node* node) {
|
||||
|
||||
// Raise a TypeError if the {target} is not a constructor.
|
||||
if (!function->IsConstructor()) {
|
||||
// Drop the lazy bailout location and use the eager bailout point for
|
||||
// the runtime function (actually as lazy bailout point). It doesn't
|
||||
// really matter which bailout location we use since we never really
|
||||
// go back after throwing the exception.
|
||||
NodeProperties::RemoveFrameStateInput(node, 0);
|
||||
NodeProperties::ReplaceValueInputs(node, target);
|
||||
NodeProperties::ChangeOp(
|
||||
node, javascript()->CallRuntime(Runtime::kThrowCalledNonCallable));
|
||||
@ -406,7 +398,6 @@ Reduction JSCallReducer::ReduceJSCallConstruct(Node* node) {
|
||||
}
|
||||
|
||||
// Turn the {node} into a {JSCreateArray} call.
|
||||
NodeProperties::RemoveFrameStateInput(node, 1);
|
||||
for (int i = arity; i > 0; --i) {
|
||||
NodeProperties::ReplaceValueInput(
|
||||
node, NodeProperties::GetValueInput(node, i), i + 1);
|
||||
@ -460,7 +451,6 @@ Reduction JSCallReducer::ReduceJSCallConstruct(Node* node) {
|
||||
// Turn the {node} into a {JSCreateArray} call.
|
||||
NodeProperties::ReplaceEffectInput(node, effect);
|
||||
NodeProperties::ReplaceControlInput(node, control);
|
||||
NodeProperties::RemoveFrameStateInput(node, 1);
|
||||
for (int i = arity; i > 0; --i) {
|
||||
NodeProperties::ReplaceValueInput(
|
||||
node, NodeProperties::GetValueInput(node, i), i + 1);
|
||||
|
@ -55,12 +55,8 @@ class JSCallAccessor {
|
||||
return call_->InputAt(formal_arguments() + 1);
|
||||
}
|
||||
|
||||
Node* frame_state_before() {
|
||||
return NodeProperties::GetFrameStateInput(call_, 1);
|
||||
}
|
||||
|
||||
Node* frame_state_after() {
|
||||
// Both, {JSCallFunction} and {JSCallConstruct}, have frame state after.
|
||||
Node* frame_state() {
|
||||
// Both, {JSCallFunction} and {JSCallConstruct}, have frame state.
|
||||
return NodeProperties::GetFrameStateInput(call_, 0);
|
||||
}
|
||||
|
||||
@ -334,7 +330,7 @@ Reduction JSInliner::ReduceJSCall(Node* node, Handle<JSFunction> function) {
|
||||
// TODO(turbofan): TranslatedState::GetAdaptedArguments() currently relies on
|
||||
// not inlining recursive functions. We might want to relax that at some
|
||||
// point.
|
||||
for (Node* frame_state = call.frame_state_after();
|
||||
for (Node* frame_state = call.frame_state();
|
||||
frame_state->opcode() == IrOpcode::kFrameState;
|
||||
frame_state = frame_state->InputAt(kFrameStateOuterStateInput)) {
|
||||
FrameStateInfo const& frame_info = OpParameter<FrameStateInfo>(frame_state);
|
||||
@ -419,7 +415,7 @@ Reduction JSInliner::ReduceJSCall(Node* node, Handle<JSFunction> function) {
|
||||
end = graph()->end();
|
||||
}
|
||||
|
||||
Node* frame_state = call.frame_state_after();
|
||||
Node* frame_state = call.frame_state();
|
||||
Node* new_target = jsgraph_->UndefinedConstant();
|
||||
|
||||
// Inline {JSCallConstruct} requires some additional magic.
|
||||
@ -430,11 +426,12 @@ Reduction JSInliner::ReduceJSCall(Node* node, Handle<JSFunction> function) {
|
||||
// Note that the context has to be the callers context (input to call node).
|
||||
Node* receiver = jsgraph_->UndefinedConstant(); // Implicit receiver.
|
||||
if (NeedsImplicitReceiver(shared_info)) {
|
||||
Node* frame_state_before = NodeProperties::FindFrameStateBefore(node);
|
||||
Node* effect = NodeProperties::GetEffectInput(node);
|
||||
Node* context = NodeProperties::GetContextInput(node);
|
||||
Node* create = jsgraph_->graph()->NewNode(
|
||||
jsgraph_->javascript()->Create(), call.target(), call.new_target(),
|
||||
context, call.frame_state_before(), effect);
|
||||
context, frame_state_before, effect);
|
||||
NodeProperties::ReplaceEffectInput(node, create);
|
||||
// Insert a check of the return value to determine whether the return
|
||||
// value
|
||||
@ -481,10 +478,11 @@ Reduction JSInliner::ReduceJSCall(Node* node, Handle<JSFunction> function) {
|
||||
if (node->opcode() == IrOpcode::kJSCallFunction &&
|
||||
is_sloppy(parse_info.language_mode()) && !shared_info->native()) {
|
||||
const CallFunctionParameters& p = CallFunctionParametersOf(node->op());
|
||||
Node* frame_state_before = NodeProperties::FindFrameStateBefore(node);
|
||||
Node* effect = NodeProperties::GetEffectInput(node);
|
||||
Node* convert = jsgraph_->graph()->NewNode(
|
||||
jsgraph_->javascript()->ConvertReceiver(p.convert_mode()),
|
||||
call.receiver(), context, call.frame_state_before(), effect, start);
|
||||
call.receiver(), context, frame_state_before, effect, start);
|
||||
NodeProperties::ReplaceValueInput(node, convert, 1);
|
||||
NodeProperties::ReplaceEffectInput(node, convert);
|
||||
}
|
||||
|
@ -1388,9 +1388,6 @@ Reduction JSTypedLowering::ReduceJSCallConstruct(Node* node) {
|
||||
Handle<JSFunction>::cast(target_type->AsConstant()->Value());
|
||||
Handle<SharedFunctionInfo> shared(function->shared(), isolate());
|
||||
|
||||
// Remove the eager bailout frame state.
|
||||
NodeProperties::RemoveFrameStateInput(node, 1);
|
||||
|
||||
// Patch {node} to an indirect call via the {function}s construct stub.
|
||||
Callable callable(handle(shared->construct_stub(), isolate()),
|
||||
ConstructStubDescriptor(isolate()));
|
||||
@ -1410,9 +1407,6 @@ Reduction JSTypedLowering::ReduceJSCallConstruct(Node* node) {
|
||||
|
||||
// Check if {target} is a JSFunction.
|
||||
if (target_type->Is(Type::Function())) {
|
||||
// Remove the eager bailout frame state.
|
||||
NodeProperties::RemoveFrameStateInput(node, 1);
|
||||
|
||||
// Patch {node} to an indirect call via the ConstructFunction builtin.
|
||||
Callable callable = CodeFactory::ConstructFunction(isolate());
|
||||
node->RemoveInput(arity + 1);
|
||||
@ -1441,9 +1435,9 @@ Reduction JSTypedLowering::ReduceJSCallFunction(Node* node) {
|
||||
Type* target_type = NodeProperties::GetType(target);
|
||||
Node* receiver = NodeProperties::GetValueInput(node, 1);
|
||||
Type* receiver_type = NodeProperties::GetType(receiver);
|
||||
Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
|
||||
Node* effect = NodeProperties::GetEffectInput(node);
|
||||
Node* control = NodeProperties::GetControlInput(node);
|
||||
Node* frame_state = NodeProperties::FindFrameStateBefore(node);
|
||||
|
||||
// Try to infer receiver {convert_mode} from {receiver} type.
|
||||
if (receiver_type->Is(Type::NullOrUndefined())) {
|
||||
@ -1481,9 +1475,6 @@ Reduction JSTypedLowering::ReduceJSCallFunction(Node* node) {
|
||||
// Update the effect dependency for the {node}.
|
||||
NodeProperties::ReplaceEffectInput(node, effect);
|
||||
|
||||
// Remove the eager bailout frame state.
|
||||
NodeProperties::RemoveFrameStateInput(node, 1);
|
||||
|
||||
// Compute flags for the call.
|
||||
CallDescriptor::Flags flags = CallDescriptor::kNeedsFrameState;
|
||||
if (p.tail_call_mode() == TailCallMode::kAllow) {
|
||||
@ -1521,9 +1512,6 @@ Reduction JSTypedLowering::ReduceJSCallFunction(Node* node) {
|
||||
|
||||
// Check if {target} is a JSFunction.
|
||||
if (target_type->Is(Type::Function())) {
|
||||
// Remove the eager bailout frame state.
|
||||
NodeProperties::RemoveFrameStateInput(node, 1);
|
||||
|
||||
// Compute flags for the call.
|
||||
CallDescriptor::Flags flags = CallDescriptor::kNeedsFrameState;
|
||||
if (p.tail_call_mode() == TailCallMode::kAllow) {
|
||||
|
@ -164,6 +164,7 @@ int Linkage::FrameStateInputCount(Runtime::FunctionId function) {
|
||||
case Runtime::kTraceEnter:
|
||||
case Runtime::kTraceExit:
|
||||
return 0;
|
||||
case Runtime::kInlineCall:
|
||||
case Runtime::kInlineGetPrototype:
|
||||
case Runtime::kInlineNewObject:
|
||||
case Runtime::kInlineRegExpConstructResult:
|
||||
@ -179,7 +180,6 @@ int Linkage::FrameStateInputCount(Runtime::FunctionId function) {
|
||||
case Runtime::kInlineToPrimitive_String:
|
||||
case Runtime::kInlineToString:
|
||||
return 1;
|
||||
case Runtime::kInlineCall:
|
||||
case Runtime::kInlineDeoptimizeNow:
|
||||
case Runtime::kInlineThrowNotDateError:
|
||||
return 2;
|
||||
|
@ -179,13 +179,6 @@ void NodeProperties::ReplaceFrameStateInput(Node* node, int index,
|
||||
}
|
||||
|
||||
|
||||
// static
|
||||
void NodeProperties::RemoveFrameStateInput(Node* node, int index) {
|
||||
DCHECK_LT(index, OperatorProperties::GetFrameStateInputCount(node->op()));
|
||||
node->RemoveInput(FirstFrameStateIndex(node) + index);
|
||||
}
|
||||
|
||||
|
||||
// static
|
||||
void NodeProperties::RemoveNonValueInputs(Node* node) {
|
||||
node->TrimInputCount(node->op()->ValueInputCount());
|
||||
@ -242,6 +235,17 @@ void NodeProperties::ChangeOp(Node* node, const Operator* new_op) {
|
||||
}
|
||||
|
||||
|
||||
// static
|
||||
Node* NodeProperties::FindFrameStateBefore(Node* node) {
|
||||
Node* effect = NodeProperties::GetEffectInput(node);
|
||||
while (effect->opcode() != IrOpcode::kCheckpoint) {
|
||||
DCHECK_EQ(1, effect->op()->EffectInputCount());
|
||||
effect = NodeProperties::GetEffectInput(effect);
|
||||
}
|
||||
Node* frame_state = GetFrameStateInput(effect, 0);
|
||||
return frame_state;
|
||||
}
|
||||
|
||||
// static
|
||||
Node* NodeProperties::FindProjection(Node* node, size_t projection_index) {
|
||||
for (auto use : node->uses()) {
|
||||
|
@ -84,7 +84,6 @@ class NodeProperties final {
|
||||
static void ReplaceControlInput(Node* node, Node* control, int index = 0);
|
||||
static void ReplaceEffectInput(Node* node, Node* effect, int index = 0);
|
||||
static void ReplaceFrameStateInput(Node* node, int index, Node* frame_state);
|
||||
static void RemoveFrameStateInput(Node* node, int index);
|
||||
static void RemoveNonValueInputs(Node* node);
|
||||
static void RemoveValueInputs(Node* node);
|
||||
|
||||
@ -109,6 +108,11 @@ class NodeProperties final {
|
||||
// ---------------------------------------------------------------------------
|
||||
// Miscellaneous utilities.
|
||||
|
||||
// Find the last frame state that is effect-wise before the given node. This
|
||||
// assumes a linear effect-chain up to a {CheckPoint} node in the graph.
|
||||
static Node* FindFrameStateBefore(Node* node);
|
||||
|
||||
// Collect the output-value projection for the given output index.
|
||||
static Node* FindProjection(Node* node, size_t projection_index);
|
||||
|
||||
// Collect the branch-related projections from a node, such as IfTrue,
|
||||
|
@ -35,12 +35,6 @@ int OperatorProperties::GetFrameStateInputCount(const Operator* op) {
|
||||
case IrOpcode::kJSStrictNotEqual:
|
||||
return 0;
|
||||
|
||||
// We record the frame state immediately before and immediately after every
|
||||
// construct/function call.
|
||||
case IrOpcode::kJSCallConstruct:
|
||||
case IrOpcode::kJSCallFunction:
|
||||
return 2;
|
||||
|
||||
// Compare operations
|
||||
case IrOpcode::kJSEqual:
|
||||
case IrOpcode::kJSNotEqual:
|
||||
@ -66,6 +60,10 @@ int OperatorProperties::GetFrameStateInputCount(const Operator* op) {
|
||||
case IrOpcode::kJSToObject:
|
||||
case IrOpcode::kJSToString:
|
||||
|
||||
// Call operations
|
||||
case IrOpcode::kJSCallConstruct:
|
||||
case IrOpcode::kJSCallFunction:
|
||||
|
||||
// Misc operations
|
||||
case IrOpcode::kJSConvertReceiver:
|
||||
case IrOpcode::kJSForInNext:
|
||||
|
@ -99,7 +99,7 @@ TEST_F(JSBuiltinReducerTest, MathMax0) {
|
||||
Node* frame_state = graph()->start();
|
||||
Node* call = graph()->NewNode(javascript()->CallFunction(2), function,
|
||||
UndefinedConstant(), context, frame_state,
|
||||
frame_state, effect, control);
|
||||
effect, control);
|
||||
Reduction r = Reduce(call);
|
||||
|
||||
ASSERT_TRUE(r.Changed());
|
||||
@ -118,7 +118,7 @@ TEST_F(JSBuiltinReducerTest, MathMax1) {
|
||||
Node* p0 = Parameter(t0, 0);
|
||||
Node* call = graph()->NewNode(javascript()->CallFunction(3), function,
|
||||
UndefinedConstant(), p0, context, frame_state,
|
||||
frame_state, effect, control);
|
||||
effect, control);
|
||||
Reduction r = Reduce(call);
|
||||
|
||||
ASSERT_TRUE(r.Changed());
|
||||
@ -140,7 +140,7 @@ TEST_F(JSBuiltinReducerTest, MathMax2) {
|
||||
Node* p1 = Parameter(t1, 1);
|
||||
Node* call = graph()->NewNode(javascript()->CallFunction(4), function,
|
||||
UndefinedConstant(), p0, p1, context,
|
||||
frame_state, frame_state, effect, control);
|
||||
frame_state, effect, control);
|
||||
Reduction r = Reduce(call);
|
||||
|
||||
ASSERT_TRUE(r.Changed());
|
||||
@ -168,7 +168,7 @@ TEST_F(JSBuiltinReducerTest, MathImul) {
|
||||
Node* p1 = Parameter(t1, 1);
|
||||
Node* call = graph()->NewNode(javascript()->CallFunction(4), function,
|
||||
UndefinedConstant(), p0, p1, context,
|
||||
frame_state, frame_state, effect, control);
|
||||
frame_state, effect, control);
|
||||
Reduction r = Reduce(call);
|
||||
|
||||
ASSERT_TRUE(r.Changed());
|
||||
@ -194,7 +194,7 @@ TEST_F(JSBuiltinReducerTest, MathFround) {
|
||||
Node* p0 = Parameter(t0, 0);
|
||||
Node* call = graph()->NewNode(javascript()->CallFunction(3), function,
|
||||
UndefinedConstant(), p0, context, frame_state,
|
||||
frame_state, effect, control);
|
||||
effect, control);
|
||||
Reduction r = Reduce(call);
|
||||
|
||||
ASSERT_TRUE(r.Changed());
|
||||
|
Loading…
Reference in New Issue
Block a user