Index: src/compiler/js-inlining.cc |
diff --git a/src/compiler/js-inlining.cc b/src/compiler/js-inlining.cc |
index 721dfa97eca734d2c121a72e55464cf084634fbd..db7490e2235ed8f4d815968bd64a1686d6b12e41 100644 |
--- a/src/compiler/js-inlining.cc |
+++ b/src/compiler/js-inlining.cc |
@@ -275,6 +275,56 @@ Node* JSInliner::CreateTailCallerFrameState(Node* node, Node* frame_state) { |
namespace { |
+// TODO(bmeurer): Unify this with the witness helper functions in the |
+// js-builtin-reducer.cc once we have a better understanding of the |
+// map tracking we want to do, and eventually changed the CheckMaps |
+// operator to carry map constants on the operator instead of inputs. |
+// I.e. if the CheckMaps has some kind of SmallMapSet as operator |
+// parameter, then this could be changed to call a generic |
+// |
+// SmallMapSet NodeProperties::CollectMapWitness(receiver, effect) |
+// |
+// function, which either returns the map set from the CheckMaps or |
+// a singleton set from a StoreField. |
+bool NeedsConvertReceiver(Node* receiver, Node* effect) { |
+ for (Node* dominator = effect;;) { |
+ if (dominator->opcode() == IrOpcode::kCheckMaps && |
+ dominator->InputAt(0) == receiver) { |
+ // Check if all maps have the given {instance_type}. |
+ for (int i = 1; i < dominator->op()->ValueInputCount(); ++i) { |
+ HeapObjectMatcher m(NodeProperties::GetValueInput(dominator, i)); |
+ if (!m.HasValue()) return true; |
+ Handle<Map> const map = Handle<Map>::cast(m.Value()); |
+ if (!map->IsJSReceiverMap()) return true; |
+ } |
+ return false; |
+ } |
+ switch (dominator->opcode()) { |
+ case IrOpcode::kStoreField: { |
+ FieldAccess const& access = FieldAccessOf(dominator->op()); |
+ if (access.base_is_tagged == kTaggedBase && |
+ access.offset == HeapObject::kMapOffset) { |
+ return true; |
+ } |
+ break; |
+ } |
+ case IrOpcode::kStoreElement: |
+ case IrOpcode::kStoreTypedElement: |
+ break; |
+ default: { |
+ DCHECK_EQ(1, dominator->op()->EffectOutputCount()); |
+ if (dominator->op()->EffectInputCount() != 1 || |
+ !dominator->op()->HasProperty(Operator::kNoWrite)) { |
+ // Didn't find any appropriate CheckMaps node. |
+ return true; |
+ } |
+ break; |
+ } |
+ } |
+ dominator = NodeProperties::GetEffectInput(dominator); |
+ } |
+} |
+ |
// TODO(mstarzinger,verwaest): Move this predicate onto SharedFunctionInfo? |
bool NeedsImplicitReceiver(Handle<SharedFunctionInfo> shared_info) { |
DisallowHeapAllocation no_gc; |
@@ -561,14 +611,16 @@ Reduction JSInliner::ReduceJSCall(Node* node, Handle<JSFunction> function) { |
// any number of times, it's not observable. |
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 = graph()->NewNode( |
- javascript()->ConvertReceiver(p.convert_mode()), call.receiver(), |
- context, frame_state_before, effect, start); |
- NodeProperties::ReplaceValueInput(node, convert, 1); |
- NodeProperties::ReplaceEffectInput(node, convert); |
+ if (NeedsConvertReceiver(call.receiver(), effect)) { |
+ const CallFunctionParameters& p = CallFunctionParametersOf(node->op()); |
+ Node* frame_state_before = NodeProperties::FindFrameStateBefore(node); |
+ Node* convert = effect = graph()->NewNode( |
+ javascript()->ConvertReceiver(p.convert_mode()), call.receiver(), |
+ context, frame_state_before, effect, start); |
+ NodeProperties::ReplaceValueInput(node, convert, 1); |
+ NodeProperties::ReplaceEffectInput(node, effect); |
+ } |
} |
// If we are inlining a JS call at tail position then we have to pop current |