Index: src/compiler/js-intrinsic-lowering.cc |
diff --git a/src/compiler/js-intrinsic-lowering.cc b/src/compiler/js-intrinsic-lowering.cc |
index 2a3bdf8fa85bfe3dd54589852432fdefce70d93a..33a43f458b7592b9e393f73cdad857f8cd39ec8f 100644 |
--- a/src/compiler/js-intrinsic-lowering.cc |
+++ b/src/compiler/js-intrinsic-lowering.cc |
@@ -84,6 +84,8 @@ Reduction JSIntrinsicLowering::Reduce(Node* node) { |
return ReduceFixedArraySet(node); |
case Runtime::kInlineGetTypeFeedbackVector: |
return ReduceGetTypeFeedbackVector(node); |
+ case Runtime::kInlineGetCallerJSFunction: |
+ return ReduceGetCallerJSFunction(node); |
default: |
break; |
} |
@@ -455,6 +457,69 @@ Reduction JSIntrinsicLowering::ReduceGetTypeFeedbackVector(Node* node) { |
} |
+Reduction JSIntrinsicLowering::ReduceGetCallerJSFunction(Node* node) { |
+ Node* effect = NodeProperties::GetEffectInput(node); |
+ Node* control = NodeProperties::GetControlInput(node); |
+ |
+ if (FLAG_turbo_deoptimization) { |
+ Node* const frame_state = NodeProperties::GetFrameStateInput(node, 0); |
+ Node* outer_frame = frame_state->InputAt(kFrameStateOuterStateInput); |
+ if (outer_frame->opcode() == IrOpcode::kFrameState) { |
+ FrameStateCallInfo state_info = |
+ OpParameter<FrameStateCallInfo>(outer_frame); |
+ switch (state_info.type()) { |
+ case ARGUMENTS_ADAPTOR: |
+ outer_frame = outer_frame->InputAt(kFrameStateOuterStateInput); |
+ DCHECK(outer_frame->opcode() == IrOpcode::kFrameState); |
+ DCHECK(OpParameter<FrameStateCallInfo>(frame_state).type() == |
+ JS_FRAME); |
+ break; |
+ case JS_FRAME: |
+ break; |
+ } |
+ // The intrinsic is inlined, return the function from the outer frame. |
+ Node* outer_function = outer_frame->InputAt(kFrameStateFunctionInput); |
+ AdvancedReducer::ReplaceWithValue(node, outer_function, effect, control); |
+ return Changed(outer_function); |
+ } |
+ } |
+ |
+ // TODO(danno): If FLAG_turbo_deoptimization is false then this intrinsic |
+ // always returns the JSFunction from the caller's frame, regardless of |
+ // inlining depth, which isn't correct. This implementation also forces |
+ // intrinsic lowering to happen after inlining, which is fine for now, but |
+ // eventually the frame-querying logic probably should go later, e.g. in |
+ // instruction selection, so that there is no phase-ordering dependency. |
+ FieldAccess access = AccessBuilder::ForFrameCallerFramePtr(); |
+ Node* fp = graph()->NewNode(machine()->LoadFramePointer()); |
+ Node* next_fp = |
+ graph()->NewNode(simplified()->LoadField(access), fp, effect, control); |
+ Node* candidate = graph()->NewNode( |
+ simplified()->LoadField(AccessBuilder::ForFrameContext()), next_fp, |
+ effect, control); |
+ |
+ // If JSFunction from the outermost frame is a SMI, then the frame is |
+ // either an arguments adapter or construct frame and needs to be skipped. |
+ Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), candidate); |
+ Node* branch = graph()->NewNode(common()->Branch(), check, control); |
+ |
+ Node* if_true = graph()->NewNode(common()->IfTrue(), branch); |
+ |
+ Node* if_false = graph()->NewNode(common()->IfFalse(), branch); |
+ |
+ Node* next_next_fp = graph()->NewNode( |
+ simplified()->LoadField(AccessBuilder::ForFrameCallerFramePtr()), next_fp, |
+ next_fp, control); |
+ |
+ MachineType const type = static_cast<MachineType>(kMachPtr); |
+ control = graph()->NewNode(common()->Merge(2), if_true, if_false); |
+ next_fp = |
+ graph()->NewNode(common()->Phi(type, 2), next_next_fp, next_fp, control); |
+ return Change(node, simplified()->LoadField(AccessBuilder::ForFrameMarker()), |
+ next_fp, effect, control); |
+} |
+ |
+ |
Reduction JSIntrinsicLowering::Change(Node* node, const Operator* op, Node* a, |
Node* b) { |
node->set_op(op); |