5 #include "src/compiler/node-properties.h" 6 #include "src/compiler/common-operator.h" 7 #include "src/compiler/graph.h" 8 #include "src/compiler/js-operator.h" 9 #include "src/compiler/linkage.h" 10 #include "src/compiler/node-matchers.h" 11 #include "src/compiler/operator-properties.h" 12 #include "src/compiler/simplified-operator.h" 13 #include "src/compiler/verifier.h" 14 #include "src/handles-inl.h" 15 #include "src/objects-inl.h" 16 #include "src/zone/zone-handle-set.h" 23 int NodeProperties::PastValueIndex(Node* node) {
24 return FirstValueIndex(node) + node->op()->ValueInputCount();
29 int NodeProperties::PastContextIndex(Node* node) {
30 return FirstContextIndex(node) +
31 OperatorProperties::GetContextInputCount(node->op());
36 int NodeProperties::PastFrameStateIndex(Node* node) {
37 return FirstFrameStateIndex(node) +
38 OperatorProperties::GetFrameStateInputCount(node->op());
43 int NodeProperties::PastEffectIndex(Node* node) {
44 return FirstEffectIndex(node) + node->op()->EffectInputCount();
49 int NodeProperties::PastControlIndex(Node* node) {
50 return FirstControlIndex(node) + node->op()->ControlInputCount();
55 Node* NodeProperties::GetValueInput(Node* node,
int index) {
56 DCHECK(0 <= index && index < node->op()->ValueInputCount());
57 return node->InputAt(FirstValueIndex(node) + index);
62 Node* NodeProperties::GetContextInput(Node* node) {
63 DCHECK(OperatorProperties::HasContextInput(node->op()));
64 return node->InputAt(FirstContextIndex(node));
69 Node* NodeProperties::GetFrameStateInput(Node* node) {
70 DCHECK_EQ(1, OperatorProperties::GetFrameStateInputCount(node->op()));
71 return node->InputAt(FirstFrameStateIndex(node));
76 Node* NodeProperties::GetEffectInput(Node* node,
int index) {
77 DCHECK(0 <= index && index < node->op()->EffectInputCount());
78 return node->InputAt(FirstEffectIndex(node) + index);
83 Node* NodeProperties::GetControlInput(Node* node,
int index) {
84 DCHECK(0 <= index && index < node->op()->ControlInputCount());
85 return node->InputAt(FirstControlIndex(node) + index);
90 bool NodeProperties::IsValueEdge(Edge edge) {
91 Node*
const node = edge.from();
92 return IsInputRange(edge, FirstValueIndex(node),
93 node->op()->ValueInputCount());
98 bool NodeProperties::IsContextEdge(Edge edge) {
99 Node*
const node = edge.from();
100 return IsInputRange(edge, FirstContextIndex(node),
101 OperatorProperties::GetContextInputCount(node->op()));
106 bool NodeProperties::IsFrameStateEdge(Edge edge) {
107 Node*
const node = edge.from();
108 return IsInputRange(edge, FirstFrameStateIndex(node),
109 OperatorProperties::GetFrameStateInputCount(node->op()));
114 bool NodeProperties::IsEffectEdge(Edge edge) {
115 Node*
const node = edge.from();
116 return IsInputRange(edge, FirstEffectIndex(node),
117 node->op()->EffectInputCount());
122 bool NodeProperties::IsControlEdge(Edge edge) {
123 Node*
const node = edge.from();
124 return IsInputRange(edge, FirstControlIndex(node),
125 node->op()->ControlInputCount());
130 bool NodeProperties::IsExceptionalCall(Node* node, Node** out_exception) {
131 if (node->op()->HasProperty(Operator::kNoThrow))
return false;
132 for (Edge
const edge : node->use_edges()) {
133 if (!NodeProperties::IsControlEdge(edge))
continue;
134 if (edge.from()->opcode() == IrOpcode::kIfException) {
135 if (out_exception !=
nullptr) *out_exception = edge.from();
143 Node* NodeProperties::FindSuccessfulControlProjection(Node* node) {
144 DCHECK_GT(node->op()->ControlOutputCount(), 0);
145 if (node->op()->HasProperty(Operator::kNoThrow))
return node;
146 for (Edge
const edge : node->use_edges()) {
147 if (!NodeProperties::IsControlEdge(edge))
continue;
148 if (edge.from()->opcode() == IrOpcode::kIfSuccess) {
156 void NodeProperties::ReplaceValueInput(Node* node, Node* value,
int index) {
157 DCHECK(index < node->op()->ValueInputCount());
158 node->ReplaceInput(FirstValueIndex(node) + index, value);
163 void NodeProperties::ReplaceValueInputs(Node* node, Node* value) {
164 int value_input_count = node->op()->ValueInputCount();
165 DCHECK_LE(1, value_input_count);
166 node->ReplaceInput(0, value);
167 while (--value_input_count > 0) {
168 node->RemoveInput(value_input_count);
174 void NodeProperties::ReplaceContextInput(Node* node, Node* context) {
175 node->ReplaceInput(FirstContextIndex(node), context);
180 void NodeProperties::ReplaceControlInput(Node* node, Node* control,
int index) {
181 DCHECK(index < node->op()->ControlInputCount());
182 node->ReplaceInput(FirstControlIndex(node) + index, control);
187 void NodeProperties::ReplaceEffectInput(Node* node, Node* effect,
int index) {
188 DCHECK(index < node->op()->EffectInputCount());
189 return node->ReplaceInput(FirstEffectIndex(node) + index, effect);
194 void NodeProperties::ReplaceFrameStateInput(Node* node, Node* frame_state) {
195 DCHECK_EQ(1, OperatorProperties::GetFrameStateInputCount(node->op()));
196 node->ReplaceInput(FirstFrameStateIndex(node), frame_state);
201 void NodeProperties::RemoveNonValueInputs(Node* node) {
202 node->TrimInputCount(node->op()->ValueInputCount());
207 void NodeProperties::RemoveValueInputs(Node* node) {
208 int value_input_count = node->op()->ValueInputCount();
209 while (--value_input_count >= 0) {
210 node->RemoveInput(value_input_count);
215 void NodeProperties::MergeControlToEnd(Graph* graph,
216 CommonOperatorBuilder* common,
218 graph->end()->AppendInput(graph->zone(), node);
219 graph->end()->set_op(common->End(graph->end()->InputCount()));
224 void NodeProperties::ReplaceUses(Node* node, Node* value, Node* effect,
225 Node* success, Node* exception) {
227 for (Edge edge : node->use_edges()) {
228 if (IsControlEdge(edge)) {
229 if (edge.from()->opcode() == IrOpcode::kIfSuccess) {
230 DCHECK_NOT_NULL(success);
231 edge.UpdateTo(success);
232 }
else if (edge.from()->opcode() == IrOpcode::kIfException) {
233 DCHECK_NOT_NULL(exception);
234 edge.UpdateTo(exception);
236 DCHECK_NOT_NULL(success);
237 edge.UpdateTo(success);
239 }
else if (IsEffectEdge(edge)) {
240 DCHECK_NOT_NULL(effect);
241 edge.UpdateTo(effect);
243 DCHECK_NOT_NULL(value);
244 edge.UpdateTo(value);
251 void NodeProperties::ChangeOp(Node* node,
const Operator* new_op) {
252 node->set_op(new_op);
253 Verifier::VerifyNode(node);
258 Node* NodeProperties::FindFrameStateBefore(Node* node) {
259 Node* effect = NodeProperties::GetEffectInput(node);
260 while (effect->opcode() != IrOpcode::kCheckpoint) {
261 if (effect->opcode() == IrOpcode::kDead)
return effect;
262 DCHECK_EQ(1, effect->op()->EffectInputCount());
263 effect = NodeProperties::GetEffectInput(effect);
265 Node* frame_state = GetFrameStateInput(effect);
270 Node* NodeProperties::FindProjection(Node* node,
size_t projection_index) {
271 for (
auto use : node->uses()) {
272 if (use->opcode() == IrOpcode::kProjection &&
273 ProjectionIndexOf(use->op()) == projection_index) {
282 void NodeProperties::CollectValueProjections(Node* node, Node** projections,
283 size_t projection_count) {
285 for (
size_t index = 0; index < projection_count; ++index) {
286 DCHECK_NULL(projections[index]);
289 for (Edge
const edge : node->use_edges()) {
290 if (!IsValueEdge(edge))
continue;
291 Node* use = edge.from();
292 DCHECK_EQ(IrOpcode::kProjection, use->opcode());
293 projections[ProjectionIndexOf(use->op())] = use;
299 void NodeProperties::CollectControlProjections(Node* node, Node** projections,
300 size_t projection_count) {
302 DCHECK_LE(static_cast<int>(projection_count), node->UseCount());
303 std::memset(projections, 0,
sizeof(*projections) * projection_count);
305 size_t if_value_index = 0;
306 for (Edge
const edge : node->use_edges()) {
307 if (!IsControlEdge(edge))
continue;
308 Node* use = edge.from();
310 switch (use->opcode()) {
311 case IrOpcode::kIfTrue:
312 DCHECK_EQ(IrOpcode::kBranch, node->opcode());
315 case IrOpcode::kIfFalse:
316 DCHECK_EQ(IrOpcode::kBranch, node->opcode());
319 case IrOpcode::kIfSuccess:
320 DCHECK(!node->op()->HasProperty(Operator::kNoThrow));
323 case IrOpcode::kIfException:
324 DCHECK(!node->op()->HasProperty(Operator::kNoThrow));
327 case IrOpcode::kIfValue:
328 DCHECK_EQ(IrOpcode::kSwitch, node->opcode());
329 index = if_value_index++;
331 case IrOpcode::kIfDefault:
332 DCHECK_EQ(IrOpcode::kSwitch, node->opcode());
333 index = projection_count - 1;
338 DCHECK_LT(if_value_index, projection_count);
339 DCHECK_LT(index, projection_count);
340 DCHECK_NULL(projections[index]);
341 projections[index] = use;
344 for (
size_t index = 0; index < projection_count; ++index) {
345 DCHECK_NOT_NULL(projections[index]);
351 bool NodeProperties::IsSame(Node* a, Node* b) {
353 if (a->opcode() == IrOpcode::kCheckHeapObject) {
354 a = GetValueInput(a, 0);
357 if (b->opcode() == IrOpcode::kCheckHeapObject) {
358 b = GetValueInput(b, 0);
366 NodeProperties::InferReceiverMapsResult NodeProperties::InferReceiverMaps(
367 JSHeapBroker* broker, Node* receiver, Node* effect,
368 ZoneHandleSet<Map>* maps_return) {
369 HeapObjectMatcher m(receiver);
371 HeapObjectRef receiver = m.Ref(broker).AsHeapObject();
379 if (!receiver.IsJSObject() ||
380 !broker->IsArrayOrObjectPrototype(receiver.AsJSObject())) {
381 if (receiver.map().is_stable()) {
384 *maps_return = ZoneHandleSet<Map>(receiver.map().object());
385 return kUnreliableReceiverMaps;
389 InferReceiverMapsResult result = kReliableReceiverMaps;
391 switch (effect->opcode()) {
392 case IrOpcode::kMapGuard: {
393 Node*
const object = GetValueInput(effect, 0);
394 if (IsSame(receiver,
object)) {
395 *maps_return = MapGuardMapsOf(effect->op()).maps();
400 case IrOpcode::kCheckMaps: {
401 Node*
const object = GetValueInput(effect, 0);
402 if (IsSame(receiver,
object)) {
403 *maps_return = CheckMapsParametersOf(effect->op()).maps();
408 case IrOpcode::kJSCreate: {
409 if (IsSame(receiver, effect)) {
410 HeapObjectMatcher mtarget(GetValueInput(effect, 0));
411 HeapObjectMatcher mnewtarget(GetValueInput(effect, 1));
412 if (mtarget.HasValue() && mnewtarget.HasValue() &&
413 mnewtarget.Ref(broker).IsJSFunction()) {
414 JSFunctionRef original_constructor =
415 mnewtarget.Ref(broker).AsJSFunction();
416 if (original_constructor.has_initial_map()) {
417 original_constructor.Serialize();
418 MapRef initial_map = original_constructor.initial_map();
419 if (initial_map.GetConstructor().equals(mtarget.Ref(broker))) {
420 *maps_return = ZoneHandleSet<Map>(initial_map.object());
426 return kNoReceiverMaps;
430 case IrOpcode::kJSCreatePromise: {
431 if (IsSame(receiver, effect)) {
432 *maps_return = ZoneHandleSet<Map>(broker->native_context()
440 case IrOpcode::kStoreField: {
442 Node*
const object = GetValueInput(effect, 0);
443 FieldAccess
const& access = FieldAccessOf(effect->op());
444 if (access.base_is_tagged == kTaggedBase &&
445 access.offset == HeapObject::kMapOffset) {
446 if (IsSame(receiver,
object)) {
447 Node*
const value = GetValueInput(effect, 1);
448 HeapObjectMatcher m(value);
450 *maps_return = ZoneHandleSet<Map>(m.Ref(broker).AsMap().object());
456 result = kUnreliableReceiverMaps;
460 case IrOpcode::kJSStoreMessage:
461 case IrOpcode::kJSStoreModule:
462 case IrOpcode::kStoreElement:
463 case IrOpcode::kStoreTypedElement: {
467 case IrOpcode::kFinishRegion: {
471 if (IsSame(receiver, effect)) receiver = GetValueInput(effect, 0);
474 case IrOpcode::kEffectPhi: {
475 Node* control = GetControlInput(effect);
476 if (control->opcode() != IrOpcode::kLoop) {
477 DCHECK(control->opcode() == IrOpcode::kDead ||
478 control->opcode() == IrOpcode::kMerge);
479 return kNoReceiverMaps;
484 effect = GetEffectInput(effect, 0);
485 result = kUnreliableReceiverMaps;
489 DCHECK_EQ(1, effect->op()->EffectOutputCount());
490 if (effect->op()->EffectInputCount() != 1) {
492 return kNoReceiverMaps;
494 if (!effect->op()->HasProperty(Operator::kNoWrite)) {
497 result = kUnreliableReceiverMaps;
505 if (IsSame(receiver, effect))
return kNoReceiverMaps;
508 DCHECK_EQ(1, effect->op()->EffectInputCount());
509 effect = NodeProperties::GetEffectInput(effect);
514 MaybeHandle<Map> NodeProperties::GetMapWitness(JSHeapBroker* broker,
516 ZoneHandleSet<Map> maps;
517 Node* receiver = NodeProperties::GetValueInput(node, 1);
518 Node* effect = NodeProperties::GetEffectInput(node);
519 NodeProperties::InferReceiverMapsResult result =
520 NodeProperties::InferReceiverMaps(broker, receiver, effect, &maps);
521 if (result == NodeProperties::kReliableReceiverMaps && maps.size() == 1) {
524 return MaybeHandle<Map>();
528 bool NodeProperties::HasInstanceTypeWitness(JSHeapBroker* broker,
529 Node* receiver, Node* effect,
530 InstanceType instance_type) {
531 ZoneHandleSet<Map> receiver_maps;
532 NodeProperties::InferReceiverMapsResult result =
533 NodeProperties::InferReceiverMaps(broker, receiver, effect,
536 case NodeProperties::kUnreliableReceiverMaps:
537 case NodeProperties::kReliableReceiverMaps:
538 DCHECK_NE(0, receiver_maps.size());
539 for (
size_t i = 0;
i < receiver_maps.size(); ++
i) {
540 MapRef map(broker, receiver_maps[
i]);
541 if (map.instance_type() != instance_type)
return false;
545 case NodeProperties::kNoReceiverMaps:
552 bool NodeProperties::NoObservableSideEffectBetween(Node* effect,
554 while (effect != dominator) {
555 if (effect->op()->EffectInputCount() == 1 &&
556 effect->op()->properties() & Operator::kNoWrite) {
557 effect = NodeProperties::GetEffectInput(effect);
566 bool NodeProperties::CanBePrimitive(JSHeapBroker* broker, Node* receiver,
568 switch (receiver->opcode()) {
569 #define CASE(Opcode) case IrOpcode::k##Opcode: 570 JS_CONSTRUCT_OP_LIST(CASE)
571 JS_CREATE_OP_LIST(CASE)
573 case IrOpcode::kCheckReceiver:
574 case IrOpcode::kConvertReceiver:
575 case IrOpcode::kJSGetSuperConstructor:
576 case IrOpcode::kJSToObject:
578 case IrOpcode::kHeapConstant: {
579 HeapObjectRef value =
580 HeapObjectMatcher(receiver).Ref(broker).AsHeapObject();
581 return value.map().IsPrimitiveMap();
587 ZoneHandleSet<Map> maps;
588 if (InferReceiverMaps(broker, receiver, effect, &maps) !=
591 for (
size_t i = 0;
i < maps.size(); ++
i) {
592 MapRef map(broker, maps[
i]);
593 if (!map.IsJSReceiverMap())
return true;
603 bool NodeProperties::CanBeNullOrUndefined(JSHeapBroker* broker, Node* receiver,
605 if (CanBePrimitive(broker, receiver, effect)) {
606 switch (receiver->opcode()) {
607 case IrOpcode::kCheckInternalizedString:
608 case IrOpcode::kCheckNumber:
609 case IrOpcode::kCheckSmi:
610 case IrOpcode::kCheckString:
611 case IrOpcode::kCheckSymbol:
612 case IrOpcode::kJSToLength:
613 case IrOpcode::kJSToName:
614 case IrOpcode::kJSToNumber:
615 case IrOpcode::kJSToNumberConvertBigInt:
616 case IrOpcode::kJSToNumeric:
617 case IrOpcode::kJSToString:
618 case IrOpcode::kToBoolean:
620 case IrOpcode::kHeapConstant: {
621 HeapObjectRef value =
622 HeapObjectMatcher(receiver).Ref(broker).AsHeapObject();
623 OddballType type = value.map().oddball_type();
624 return type == OddballType::kNull || type == OddballType::kUndefined;
634 Node* NodeProperties::GetOuterContext(Node* node,
size_t* depth) {
635 Node* context = NodeProperties::GetContextInput(node);
637 IrOpcode::IsContextChainExtendingOpcode(context->opcode())) {
638 context = NodeProperties::GetContextInput(context);
645 Type NodeProperties::GetTypeOrAny(Node* node) {
646 return IsTyped(node) ? node->type() : Type::Any();
651 bool NodeProperties::AllValueInputsAreTyped(Node* node) {
652 int input_count = node->op()->ValueInputCount();
653 for (
int index = 0; index < input_count; ++index) {
654 if (!IsTyped(GetValueInput(node, index)))
return false;
661 bool NodeProperties::IsInputRange(Edge edge,
int first,
int num) {
662 if (num == 0)
return false;
663 int const index = edge.index();
664 return first <= index && index < first + num;
668 size_t NodeProperties::HashCode(Node* node) {
669 size_t h = base::hash_combine(node->op()->HashCode(), node->InputCount());
670 for (Node* input : node->inputs()) {
671 h = base::hash_combine(h, input->id());
677 bool NodeProperties::Equals(Node* a, Node* b) {
680 DCHECK_NOT_NULL(a->op());
681 DCHECK_NOT_NULL(b->op());
682 if (!a->op()->Equals(b->op()))
return false;
683 if (a->InputCount() != b->InputCount())
return false;
684 Node::Inputs aInputs = a->inputs();
685 Node::Inputs bInputs = b->inputs();
687 auto aIt = aInputs.begin();
688 auto bIt = bInputs.begin();
689 auto aEnd = aInputs.end();
691 for (; aIt != aEnd; ++aIt, ++bIt) {
692 DCHECK_NOT_NULL(*aIt);
693 DCHECK_NOT_NULL(*bIt);
694 if ((*aIt)->id() != (*bIt)->id())
return false;