1 // Copyright 2015 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 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" 17 18 namespace v8 { 19 namespace internal { 20 namespace compiler { 21 22 // static 23 int NodeProperties::PastValueIndex(Node* node) { 24 return FirstValueIndex(node) + node->op()->ValueInputCount(); 25 } 26 27 28 // static 29 int NodeProperties::PastContextIndex(Node* node) { 30 return FirstContextIndex(node) + 31 OperatorProperties::GetContextInputCount(node->op()); 32 } 33 34 35 // static 36 int NodeProperties::PastFrameStateIndex(Node* node) { 37 return FirstFrameStateIndex(node) + 38 OperatorProperties::GetFrameStateInputCount(node->op()); 39 } 40 41 42 // static 43 int NodeProperties::PastEffectIndex(Node* node) { 44 return FirstEffectIndex(node) + node->op()->EffectInputCount(); 45 } 46 47 48 // static 49 int NodeProperties::PastControlIndex(Node* node) { 50 return FirstControlIndex(node) + node->op()->ControlInputCount(); 51 } 52 53 54 // static 55 Node* NodeProperties::GetValueInput(Node* node, int index) { 56 DCHECK(0 <= index && index < node->op()->ValueInputCount()); 57 return node->InputAt(FirstValueIndex(node) + index); 58 } 59 60 61 // static 62 Node* NodeProperties::GetContextInput(Node* node) { 63 DCHECK(OperatorProperties::HasContextInput(node->op())); 64 return node->InputAt(FirstContextIndex(node)); 65 } 66 67 68 // static 69 Node* NodeProperties::GetFrameStateInput(Node* node) { 70 DCHECK_EQ(1, OperatorProperties::GetFrameStateInputCount(node->op())); 71 return node->InputAt(FirstFrameStateIndex(node)); 72 } 73 74 75 // static 76 Node* NodeProperties::GetEffectInput(Node* node, int index) { 77 DCHECK(0 <= index && index < node->op()->EffectInputCount()); 78 return node->InputAt(FirstEffectIndex(node) + index); 79 } 80 81 82 // static 83 Node* NodeProperties::GetControlInput(Node* node, int index) { 84 DCHECK(0 <= index && index < node->op()->ControlInputCount()); 85 return node->InputAt(FirstControlIndex(node) + index); 86 } 87 88 89 // static 90 bool NodeProperties::IsValueEdge(Edge edge) { 91 Node* const node = edge.from(); 92 return IsInputRange(edge, FirstValueIndex(node), 93 node->op()->ValueInputCount()); 94 } 95 96 97 // static 98 bool NodeProperties::IsContextEdge(Edge edge) { 99 Node* const node = edge.from(); 100 return IsInputRange(edge, FirstContextIndex(node), 101 OperatorProperties::GetContextInputCount(node->op())); 102 } 103 104 105 // static 106 bool NodeProperties::IsFrameStateEdge(Edge edge) { 107 Node* const node = edge.from(); 108 return IsInputRange(edge, FirstFrameStateIndex(node), 109 OperatorProperties::GetFrameStateInputCount(node->op())); 110 } 111 112 113 // static 114 bool NodeProperties::IsEffectEdge(Edge edge) { 115 Node* const node = edge.from(); 116 return IsInputRange(edge, FirstEffectIndex(node), 117 node->op()->EffectInputCount()); 118 } 119 120 121 // static 122 bool NodeProperties::IsControlEdge(Edge edge) { 123 Node* const node = edge.from(); 124 return IsInputRange(edge, FirstControlIndex(node), 125 node->op()->ControlInputCount()); 126 } 127 128 129 // static 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(); 136 return true; 137 } 138 } 139 return false; 140 } 141 142 // static 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) { 149 return edge.from(); 150 } 151 } 152 return node; 153 } 154 155 // static 156 void NodeProperties::ReplaceValueInput(Node* node, Node* value, int index) { 157 DCHECK(index < node->op()->ValueInputCount()); 158 node->ReplaceInput(FirstValueIndex(node) + index, value); 159 } 160 161 162 // static 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); 169 } 170 } 171 172 173 // static 174 void NodeProperties::ReplaceContextInput(Node* node, Node* context) { 175 node->ReplaceInput(FirstContextIndex(node), context); 176 } 177 178 179 // static 180 void NodeProperties::ReplaceControlInput(Node* node, Node* control, int index) { 181 DCHECK(index < node->op()->ControlInputCount()); 182 node->ReplaceInput(FirstControlIndex(node) + index, control); 183 } 184 185 186 // static 187 void NodeProperties::ReplaceEffectInput(Node* node, Node* effect, int index) { 188 DCHECK(index < node->op()->EffectInputCount()); 189 return node->ReplaceInput(FirstEffectIndex(node) + index, effect); 190 } 191 192 193 // static 194 void NodeProperties::ReplaceFrameStateInput(Node* node, Node* frame_state) { 195 DCHECK_EQ(1, OperatorProperties::GetFrameStateInputCount(node->op())); 196 node->ReplaceInput(FirstFrameStateIndex(node), frame_state); 197 } 198 199 200 // static 201 void NodeProperties::RemoveNonValueInputs(Node* node) { 202 node->TrimInputCount(node->op()->ValueInputCount()); 203 } 204 205 206 // static 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); 211 } 212 } 213 214 215 void NodeProperties::MergeControlToEnd(Graph* graph, 216 CommonOperatorBuilder* common, 217 Node* node) { 218 graph->end()->AppendInput(graph->zone(), node); 219 graph->end()->set_op(common->End(graph->end()->InputCount())); 220 } 221 222 223 // static 224 void NodeProperties::ReplaceUses(Node* node, Node* value, Node* effect, 225 Node* success, Node* exception) { 226 // Requires distinguishing between value, effect and control edges. 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); 235 } else { 236 DCHECK_NOT_NULL(success); 237 edge.UpdateTo(success); 238 } 239 } else if (IsEffectEdge(edge)) { 240 DCHECK_NOT_NULL(effect); 241 edge.UpdateTo(effect); 242 } else { 243 DCHECK_NOT_NULL(value); 244 edge.UpdateTo(value); 245 } 246 } 247 } 248 249 250 // static 251 void NodeProperties::ChangeOp(Node* node, const Operator* new_op) { 252 node->set_op(new_op); 253 Verifier::VerifyNode(node); 254 } 255 256 257 // static 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); 264 } 265 Node* frame_state = GetFrameStateInput(effect); 266 return frame_state; 267 } 268 269 // static 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) { 274 return use; 275 } 276 } 277 return nullptr; 278 } 279 280 281 // static 282 void NodeProperties::CollectValueProjections(Node* node, Node** projections, 283 size_t projection_count) { 284 #ifdef DEBUG 285 for (size_t index = 0; index < projection_count; ++index) { 286 DCHECK_NULL(projections[index]); 287 } 288 #endif 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; 294 } 295 } 296 297 298 // static 299 void NodeProperties::CollectControlProjections(Node* node, Node** projections, 300 size_t projection_count) { 301 #ifdef DEBUG 302 DCHECK_LE(static_cast<int>(projection_count), node->UseCount()); 303 std::memset(projections, 0, sizeof(*projections) * projection_count); 304 #endif 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(); 309 size_t index; 310 switch (use->opcode()) { 311 case IrOpcode::kIfTrue: 312 DCHECK_EQ(IrOpcode::kBranch, node->opcode()); 313 index = 0; 314 break; 315 case IrOpcode::kIfFalse: 316 DCHECK_EQ(IrOpcode::kBranch, node->opcode()); 317 index = 1; 318 break; 319 case IrOpcode::kIfSuccess: 320 DCHECK(!node->op()->HasProperty(Operator::kNoThrow)); 321 index = 0; 322 break; 323 case IrOpcode::kIfException: 324 DCHECK(!node->op()->HasProperty(Operator::kNoThrow)); 325 index = 1; 326 break; 327 case IrOpcode::kIfValue: 328 DCHECK_EQ(IrOpcode::kSwitch, node->opcode()); 329 index = if_value_index++; 330 break; 331 case IrOpcode::kIfDefault: 332 DCHECK_EQ(IrOpcode::kSwitch, node->opcode()); 333 index = projection_count - 1; 334 break; 335 default: 336 continue; 337 } 338 DCHECK_LT(if_value_index, projection_count); 339 DCHECK_LT(index, projection_count); 340 DCHECK_NULL(projections[index]); 341 projections[index] = use; 342 } 343 #ifdef DEBUG 344 for (size_t index = 0; index < projection_count; ++index) { 345 DCHECK_NOT_NULL(projections[index]); 346 } 347 #endif 348 } 349 350 // static 351 bool NodeProperties::IsSame(Node* a, Node* b) { 352 for (;;) { 353 if (a->opcode() == IrOpcode::kCheckHeapObject) { 354 a = GetValueInput(a, 0); 355 continue; 356 } 357 if (b->opcode() == IrOpcode::kCheckHeapObject) { 358 b = GetValueInput(b, 0); 359 continue; 360 } 361 return a == b; 362 } 363 } 364 365 // static 366 NodeProperties::InferReceiverMapsResult NodeProperties::InferReceiverMaps( 367 Isolate* isolate, Node* receiver, Node* effect, 368 ZoneHandleSet<Map>* maps_return) { 369 HeapObjectMatcher m(receiver); 370 if (m.HasValue()) { 371 Handle<HeapObject> receiver = m.Value(); 372 // We don't use ICs for the Array.prototype and the Object.prototype 373 // because the runtime has to be able to intercept them properly, so 374 // we better make sure that TurboFan doesn't outsmart the system here 375 // by storing to elements of either prototype directly. 376 // 377 // TODO(bmeurer): This can be removed once the Array.prototype and 378 // Object.prototype have NO_ELEMENTS elements kind. 379 if (!isolate->IsInAnyContext(*receiver, 380 Context::INITIAL_ARRAY_PROTOTYPE_INDEX) && 381 !isolate->IsInAnyContext(*receiver, 382 Context::INITIAL_OBJECT_PROTOTYPE_INDEX)) { 383 Handle<Map> receiver_map(receiver->map(), isolate); 384 if (receiver_map->is_stable()) { 385 // The {receiver_map} is only reliable when we install a stability 386 // code dependency. 387 *maps_return = ZoneHandleSet<Map>(receiver_map); 388 return kUnreliableReceiverMaps; 389 } 390 } 391 } 392 InferReceiverMapsResult result = kReliableReceiverMaps; 393 while (true) { 394 switch (effect->opcode()) { 395 case IrOpcode::kMapGuard: { 396 Node* const object = GetValueInput(effect, 0); 397 if (IsSame(receiver, object)) { 398 *maps_return = MapGuardMapsOf(effect->op()).maps(); 399 return result; 400 } 401 break; 402 } 403 case IrOpcode::kCheckMaps: { 404 Node* const object = GetValueInput(effect, 0); 405 if (IsSame(receiver, object)) { 406 *maps_return = CheckMapsParametersOf(effect->op()).maps(); 407 return result; 408 } 409 break; 410 } 411 case IrOpcode::kJSCreate: { 412 if (IsSame(receiver, effect)) { 413 HeapObjectMatcher mtarget(GetValueInput(effect, 0)); 414 HeapObjectMatcher mnewtarget(GetValueInput(effect, 1)); 415 if (mtarget.HasValue() && mnewtarget.HasValue() && 416 mnewtarget.Value()->IsJSFunction()) { 417 Handle<JSFunction> original_constructor = 418 Handle<JSFunction>::cast(mnewtarget.Value()); 419 if (original_constructor->has_initial_map()) { 420 Handle<Map> initial_map(original_constructor->initial_map(), 421 isolate); 422 if (initial_map->constructor_or_backpointer() == 423 *mtarget.Value()) { 424 *maps_return = ZoneHandleSet<Map>(initial_map); 425 return result; 426 } 427 } 428 } 429 // We reached the allocation of the {receiver}. 430 return kNoReceiverMaps; 431 } 432 break; 433 } 434 case IrOpcode::kStoreField: { 435 // We only care about StoreField of maps. 436 Node* const object = GetValueInput(effect, 0); 437 FieldAccess const& access = FieldAccessOf(effect->op()); 438 if (access.base_is_tagged == kTaggedBase && 439 access.offset == HeapObject::kMapOffset) { 440 if (IsSame(receiver, object)) { 441 Node* const value = GetValueInput(effect, 1); 442 HeapObjectMatcher m(value); 443 if (m.HasValue()) { 444 *maps_return = ZoneHandleSet<Map>(Handle<Map>::cast(m.Value())); 445 return result; 446 } 447 } 448 // Without alias analysis we cannot tell whether this 449 // StoreField[map] affects {receiver} or not. 450 result = kUnreliableReceiverMaps; 451 } 452 break; 453 } 454 case IrOpcode::kJSStoreMessage: 455 case IrOpcode::kJSStoreModule: 456 case IrOpcode::kStoreElement: 457 case IrOpcode::kStoreTypedElement: { 458 // These never change the map of objects. 459 break; 460 } 461 case IrOpcode::kFinishRegion: { 462 // FinishRegion renames the output of allocations, so we need 463 // to update the {receiver} that we are looking for, if the 464 // {receiver} matches the current {effect}. 465 if (IsSame(receiver, effect)) receiver = GetValueInput(effect, 0); 466 break; 467 } 468 case IrOpcode::kEffectPhi: { 469 Node* control = GetControlInput(effect); 470 if (control->opcode() != IrOpcode::kLoop) { 471 DCHECK(control->opcode() == IrOpcode::kDead || 472 control->opcode() == IrOpcode::kMerge); 473 return kNoReceiverMaps; 474 } 475 476 // Continue search for receiver map outside the loop. Since operations 477 // inside the loop may change the map, the result is unreliable. 478 effect = GetEffectInput(effect, 0); 479 result = kUnreliableReceiverMaps; 480 continue; 481 } 482 default: { 483 DCHECK_EQ(1, effect->op()->EffectOutputCount()); 484 if (effect->op()->EffectInputCount() != 1) { 485 // Didn't find any appropriate CheckMaps node. 486 return kNoReceiverMaps; 487 } 488 if (!effect->op()->HasProperty(Operator::kNoWrite)) { 489 // Without alias/escape analysis we cannot tell whether this 490 // {effect} affects {receiver} or not. 491 result = kUnreliableReceiverMaps; 492 } 493 break; 494 } 495 } 496 497 // Stop walking the effect chain once we hit the definition of 498 // the {receiver} along the {effect}s. 499 if (IsSame(receiver, effect)) return kNoReceiverMaps; 500 501 // Continue with the next {effect}. 502 DCHECK_EQ(1, effect->op()->EffectInputCount()); 503 effect = NodeProperties::GetEffectInput(effect); 504 } 505 } 506 507 // static 508 MaybeHandle<Map> NodeProperties::GetMapWitness(Isolate* isolate, Node* node) { 509 ZoneHandleSet<Map> maps; 510 Node* receiver = NodeProperties::GetValueInput(node, 1); 511 Node* effect = NodeProperties::GetEffectInput(node); 512 NodeProperties::InferReceiverMapsResult result = 513 NodeProperties::InferReceiverMaps(isolate, receiver, effect, &maps); 514 if (result == NodeProperties::kReliableReceiverMaps && maps.size() == 1) { 515 return maps[0]; 516 } 517 return MaybeHandle<Map>(); 518 } 519 520 // static 521 bool NodeProperties::HasInstanceTypeWitness(Isolate* isolate, Node* receiver, 522 Node* effect, 523 InstanceType instance_type) { 524 ZoneHandleSet<Map> receiver_maps; 525 NodeProperties::InferReceiverMapsResult result = 526 NodeProperties::InferReceiverMaps(isolate, receiver, effect, 527 &receiver_maps); 528 switch (result) { 529 case NodeProperties::kUnreliableReceiverMaps: 530 case NodeProperties::kReliableReceiverMaps: 531 DCHECK_NE(0, receiver_maps.size()); 532 for (size_t i = 0; i < receiver_maps.size(); ++i) { 533 if (receiver_maps[i]->instance_type() != instance_type) return false; 534 } 535 return true; 536 537 case NodeProperties::kNoReceiverMaps: 538 return false; 539 } 540 UNREACHABLE(); 541 } 542 543 // static 544 bool NodeProperties::NoObservableSideEffectBetween(Node* effect, 545 Node* dominator) { 546 while (effect != dominator) { 547 if (effect->op()->EffectInputCount() == 1 && 548 effect->op()->properties() & Operator::kNoWrite) { 549 effect = NodeProperties::GetEffectInput(effect); 550 } else { 551 return false; 552 } 553 } 554 return true; 555 } 556 557 // static 558 bool NodeProperties::CanBePrimitive(Isolate* isolate, Node* receiver, 559 Node* effect) { 560 switch (receiver->opcode()) { 561 #define CASE(Opcode) case IrOpcode::k##Opcode: 562 JS_CONSTRUCT_OP_LIST(CASE) 563 JS_CREATE_OP_LIST(CASE) 564 #undef CASE 565 case IrOpcode::kCheckReceiver: 566 case IrOpcode::kConvertReceiver: 567 case IrOpcode::kJSGetSuperConstructor: 568 case IrOpcode::kJSToObject: 569 return false; 570 case IrOpcode::kHeapConstant: { 571 Handle<HeapObject> value = HeapObjectMatcher(receiver).Value(); 572 return value->IsPrimitive(); 573 } 574 default: { 575 // We don't really care about the exact maps here, 576 // just the instance types, which don't change 577 // across potential side-effecting operations. 578 ZoneHandleSet<Map> maps; 579 if (InferReceiverMaps(isolate, receiver, effect, &maps) != 580 kNoReceiverMaps) { 581 // Check if all {maps} are actually JSReceiver maps. 582 for (size_t i = 0; i < maps.size(); ++i) { 583 if (!maps[i]->IsJSReceiverMap()) return true; 584 } 585 return false; 586 } 587 return true; 588 } 589 } 590 } 591 592 // static 593 bool NodeProperties::CanBeNullOrUndefined(Isolate* isolate, Node* receiver, 594 Node* effect) { 595 if (CanBePrimitive(isolate, receiver, effect)) { 596 switch (receiver->opcode()) { 597 case IrOpcode::kCheckInternalizedString: 598 case IrOpcode::kCheckNumber: 599 case IrOpcode::kCheckSmi: 600 case IrOpcode::kCheckString: 601 case IrOpcode::kCheckSymbol: 602 case IrOpcode::kJSToInteger: 603 case IrOpcode::kJSToLength: 604 case IrOpcode::kJSToName: 605 case IrOpcode::kJSToNumber: 606 case IrOpcode::kJSToNumberConvertBigInt: 607 case IrOpcode::kJSToNumeric: 608 case IrOpcode::kJSToString: 609 case IrOpcode::kToBoolean: 610 return false; 611 case IrOpcode::kHeapConstant: { 612 Handle<HeapObject> value = HeapObjectMatcher(receiver).Value(); 613 return value->IsNullOrUndefined(isolate); 614 } 615 default: 616 return true; 617 } 618 } 619 return false; 620 } 621 622 // static 623 Node* NodeProperties::GetOuterContext(Node* node, size_t* depth) { 624 Node* context = NodeProperties::GetContextInput(node); 625 while (*depth > 0 && 626 IrOpcode::IsContextChainExtendingOpcode(context->opcode())) { 627 context = NodeProperties::GetContextInput(context); 628 (*depth)--; 629 } 630 return context; 631 } 632 633 // static 634 Type NodeProperties::GetTypeOrAny(Node* node) { 635 return IsTyped(node) ? node->type() : Type::Any(); 636 } 637 638 639 // static 640 bool NodeProperties::AllValueInputsAreTyped(Node* node) { 641 int input_count = node->op()->ValueInputCount(); 642 for (int index = 0; index < input_count; ++index) { 643 if (!IsTyped(GetValueInput(node, index))) return false; 644 } 645 return true; 646 } 647 648 649 // static 650 bool NodeProperties::IsInputRange(Edge edge, int first, int num) { 651 if (num == 0) return false; 652 int const index = edge.index(); 653 return first <= index && index < first + num; 654 } 655 656 // static 657 size_t NodeProperties::HashCode(Node* node) { 658 size_t h = base::hash_combine(node->op()->HashCode(), node->InputCount()); 659 for (Node* input : node->inputs()) { 660 h = base::hash_combine(h, input->id()); 661 } 662 return h; 663 } 664 665 // static 666 bool NodeProperties::Equals(Node* a, Node* b) { 667 DCHECK_NOT_NULL(a); 668 DCHECK_NOT_NULL(b); 669 DCHECK_NOT_NULL(a->op()); 670 DCHECK_NOT_NULL(b->op()); 671 if (!a->op()->Equals(b->op())) return false; 672 if (a->InputCount() != b->InputCount()) return false; 673 Node::Inputs aInputs = a->inputs(); 674 Node::Inputs bInputs = b->inputs(); 675 676 auto aIt = aInputs.begin(); 677 auto bIt = bInputs.begin(); 678 auto aEnd = aInputs.end(); 679 680 for (; aIt != aEnd; ++aIt, ++bIt) { 681 DCHECK_NOT_NULL(*aIt); 682 DCHECK_NOT_NULL(*bIt); 683 if ((*aIt)->id() != (*bIt)->id()) return false; 684 } 685 return true; 686 } 687 688 } // namespace compiler 689 } // namespace internal 690 } // namespace v8 691