1 // Copyright 2014 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/graph-inl.h" 6 #include "src/compiler/js-operator.h" 7 #include "src/compiler/node.h" 8 #include "src/compiler/node-properties-inl.h" 9 #include "src/compiler/node-properties.h" 10 #include "src/compiler/simplified-operator.h" 11 #include "src/compiler/typer.h" 12 13 namespace v8 { 14 namespace internal { 15 namespace compiler { 16 17 Typer::Typer(Zone* zone) : zone_(zone) { 18 Type* number = Type::Number(zone); 19 Type* signed32 = Type::Signed32(zone); 20 Type* unsigned32 = Type::Unsigned32(zone); 21 Type* integral32 = Type::Integral32(zone); 22 Type* object = Type::Object(zone); 23 Type* undefined = Type::Undefined(zone); 24 number_fun0_ = Type::Function(number, zone); 25 number_fun1_ = Type::Function(number, number, zone); 26 number_fun2_ = Type::Function(number, number, number, zone); 27 imul_fun_ = Type::Function(signed32, integral32, integral32, zone); 28 29 #define NATIVE_TYPE(sem, rep) \ 30 Type::Intersect(Type::sem(zone), Type::rep(zone), zone) 31 // TODO(rossberg): Use range types for more precision, once we have them. 32 Type* int8 = NATIVE_TYPE(SignedSmall, UntaggedInt8); 33 Type* int16 = NATIVE_TYPE(SignedSmall, UntaggedInt16); 34 Type* int32 = NATIVE_TYPE(Signed32, UntaggedInt32); 35 Type* uint8 = NATIVE_TYPE(UnsignedSmall, UntaggedInt8); 36 Type* uint16 = NATIVE_TYPE(UnsignedSmall, UntaggedInt16); 37 Type* uint32 = NATIVE_TYPE(Unsigned32, UntaggedInt32); 38 Type* float32 = NATIVE_TYPE(Number, UntaggedFloat32); 39 Type* float64 = NATIVE_TYPE(Number, UntaggedFloat64); 40 #undef NATIVE_TYPE 41 Type* buffer = Type::Buffer(zone); 42 Type* int8_array = Type::Array(int8, zone); 43 Type* int16_array = Type::Array(int16, zone); 44 Type* int32_array = Type::Array(int32, zone); 45 Type* uint8_array = Type::Array(uint8, zone); 46 Type* uint16_array = Type::Array(uint16, zone); 47 Type* uint32_array = Type::Array(uint32, zone); 48 Type* float32_array = Type::Array(float32, zone); 49 Type* float64_array = Type::Array(float64, zone); 50 Type* arg1 = Type::Union(unsigned32, object, zone); 51 Type* arg2 = Type::Union(unsigned32, undefined, zone); 52 Type* arg3 = arg2; 53 array_buffer_fun_ = Type::Function(buffer, unsigned32, zone); 54 int8_array_fun_ = Type::Function(int8_array, arg1, arg2, arg3, zone); 55 int16_array_fun_ = Type::Function(int16_array, arg1, arg2, arg3, zone); 56 int32_array_fun_ = Type::Function(int32_array, arg1, arg2, arg3, zone); 57 uint8_array_fun_ = Type::Function(uint8_array, arg1, arg2, arg3, zone); 58 uint16_array_fun_ = Type::Function(uint16_array, arg1, arg2, arg3, zone); 59 uint32_array_fun_ = Type::Function(uint32_array, arg1, arg2, arg3, zone); 60 float32_array_fun_ = Type::Function(float32_array, arg1, arg2, arg3, zone); 61 float64_array_fun_ = Type::Function(float64_array, arg1, arg2, arg3, zone); 62 } 63 64 65 class Typer::Visitor : public NullNodeVisitor { 66 public: 67 Visitor(Typer* typer, MaybeHandle<Context> context) 68 : typer_(typer), context_(context) {} 69 70 Bounds TypeNode(Node* node) { 71 switch (node->opcode()) { 72 #define DECLARE_CASE(x) case IrOpcode::k##x: return Type##x(node); 73 DECLARE_CASE(Start) 74 VALUE_OP_LIST(DECLARE_CASE) 75 #undef DECLARE_CASE 76 77 #define DECLARE_CASE(x) case IrOpcode::k##x: 78 DECLARE_CASE(End) 79 INNER_CONTROL_OP_LIST(DECLARE_CASE) 80 #undef DECLARE_CASE 81 break; 82 } 83 UNREACHABLE(); 84 return Bounds(); 85 } 86 87 Type* TypeConstant(Handle<Object> value); 88 89 protected: 90 #define DECLARE_METHOD(x) inline Bounds Type##x(Node* node); 91 DECLARE_METHOD(Start) 92 VALUE_OP_LIST(DECLARE_METHOD) 93 #undef DECLARE_METHOD 94 95 Bounds OperandType(Node* node, int i) { 96 return NodeProperties::GetBounds(NodeProperties::GetValueInput(node, i)); 97 } 98 99 Type* ContextType(Node* node) { 100 Bounds result = 101 NodeProperties::GetBounds(NodeProperties::GetContextInput(node)); 102 DCHECK(result.upper->Maybe(Type::Internal())); 103 // TODO(rossberg): More precisely, instead of the above assertion, we should 104 // back-propagate the constraint that it has to be a subtype of Internal. 105 return result.upper; 106 } 107 108 Zone* zone() { return typer_->zone(); } 109 Isolate* isolate() { return typer_->isolate(); } 110 MaybeHandle<Context> context() { return context_; } 111 112 private: 113 Typer* typer_; 114 MaybeHandle<Context> context_; 115 }; 116 117 118 class Typer::RunVisitor : public Typer::Visitor { 119 public: 120 RunVisitor(Typer* typer, MaybeHandle<Context> context) 121 : Visitor(typer, context), 122 redo(NodeSet::key_compare(), NodeSet::allocator_type(typer->zone())) {} 123 124 GenericGraphVisit::Control Post(Node* node) { 125 if (OperatorProperties::HasValueOutput(node->op())) { 126 Bounds bounds = TypeNode(node); 127 NodeProperties::SetBounds(node, bounds); 128 // Remember incompletely typed nodes for least fixpoint iteration. 129 int arity = OperatorProperties::GetValueInputCount(node->op()); 130 for (int i = 0; i < arity; ++i) { 131 // TODO(rossberg): change once IsTyped is available. 132 // if (!NodeProperties::IsTyped(NodeProperties::GetValueInput(node, i))) 133 if (OperandType(node, i).upper->Is(Type::None())) { 134 redo.insert(node); 135 break; 136 } 137 } 138 } 139 return GenericGraphVisit::CONTINUE; 140 } 141 142 NodeSet redo; 143 }; 144 145 146 class Typer::NarrowVisitor : public Typer::Visitor { 147 public: 148 NarrowVisitor(Typer* typer, MaybeHandle<Context> context) 149 : Visitor(typer, context) {} 150 151 GenericGraphVisit::Control Pre(Node* node) { 152 if (OperatorProperties::HasValueOutput(node->op())) { 153 Bounds previous = NodeProperties::GetBounds(node); 154 Bounds bounds = TypeNode(node); 155 NodeProperties::SetBounds(node, Bounds::Both(bounds, previous, zone())); 156 DCHECK(bounds.Narrows(previous)); 157 // Stop when nothing changed (but allow re-entry in case it does later). 158 return previous.Narrows(bounds) 159 ? GenericGraphVisit::DEFER : GenericGraphVisit::REENTER; 160 } else { 161 return GenericGraphVisit::SKIP; 162 } 163 } 164 165 GenericGraphVisit::Control Post(Node* node) { 166 return GenericGraphVisit::REENTER; 167 } 168 }; 169 170 171 class Typer::WidenVisitor : public Typer::Visitor { 172 public: 173 WidenVisitor(Typer* typer, MaybeHandle<Context> context) 174 : Visitor(typer, context) {} 175 176 GenericGraphVisit::Control Pre(Node* node) { 177 if (OperatorProperties::HasValueOutput(node->op())) { 178 Bounds previous = NodeProperties::GetBounds(node); 179 Bounds bounds = TypeNode(node); 180 DCHECK(previous.lower->Is(bounds.lower)); 181 DCHECK(previous.upper->Is(bounds.upper)); 182 NodeProperties::SetBounds(node, bounds); // TODO(rossberg): Either? 183 // Stop when nothing changed (but allow re-entry in case it does later). 184 return bounds.Narrows(previous) 185 ? GenericGraphVisit::DEFER : GenericGraphVisit::REENTER; 186 } else { 187 return GenericGraphVisit::SKIP; 188 } 189 } 190 191 GenericGraphVisit::Control Post(Node* node) { 192 return GenericGraphVisit::REENTER; 193 } 194 }; 195 196 197 void Typer::Run(Graph* graph, MaybeHandle<Context> context) { 198 RunVisitor typing(this, context); 199 graph->VisitNodeInputsFromEnd(&typing); 200 // Find least fixpoint. 201 for (NodeSetIter i = typing.redo.begin(); i != typing.redo.end(); ++i) { 202 Widen(graph, *i, context); 203 } 204 } 205 206 207 void Typer::Narrow(Graph* graph, Node* start, MaybeHandle<Context> context) { 208 NarrowVisitor typing(this, context); 209 graph->VisitNodeUsesFrom(start, &typing); 210 } 211 212 213 void Typer::Widen(Graph* graph, Node* start, MaybeHandle<Context> context) { 214 WidenVisitor typing(this, context); 215 graph->VisitNodeUsesFrom(start, &typing); 216 } 217 218 219 void Typer::Init(Node* node) { 220 if (OperatorProperties::HasValueOutput(node->op())) { 221 Visitor typing(this, MaybeHandle<Context>()); 222 Bounds bounds = typing.TypeNode(node); 223 NodeProperties::SetBounds(node, bounds); 224 } 225 } 226 227 228 // ----------------------------------------------------------------------------- 229 230 231 // Control operators. 232 233 Bounds Typer::Visitor::TypeStart(Node* node) { 234 return Bounds(Type::Internal(zone())); 235 } 236 237 238 // Common operators. 239 240 Bounds Typer::Visitor::TypeParameter(Node* node) { 241 return Bounds::Unbounded(zone()); 242 } 243 244 245 Bounds Typer::Visitor::TypeInt32Constant(Node* node) { 246 // TODO(titzer): only call Type::Of() if the type is not already known. 247 return Bounds(Type::Of(OpParameter<int32_t>(node), zone())); 248 } 249 250 251 Bounds Typer::Visitor::TypeInt64Constant(Node* node) { 252 // TODO(titzer): only call Type::Of() if the type is not already known. 253 return Bounds( 254 Type::Of(static_cast<double>(OpParameter<int64_t>(node)), zone())); 255 } 256 257 258 Bounds Typer::Visitor::TypeFloat32Constant(Node* node) { 259 // TODO(titzer): only call Type::Of() if the type is not already known. 260 return Bounds(Type::Of(OpParameter<float>(node), zone())); 261 } 262 263 264 Bounds Typer::Visitor::TypeFloat64Constant(Node* node) { 265 // TODO(titzer): only call Type::Of() if the type is not already known. 266 return Bounds(Type::Of(OpParameter<double>(node), zone())); 267 } 268 269 270 Bounds Typer::Visitor::TypeNumberConstant(Node* node) { 271 // TODO(titzer): only call Type::Of() if the type is not already known. 272 return Bounds(Type::Of(OpParameter<double>(node), zone())); 273 } 274 275 276 Bounds Typer::Visitor::TypeHeapConstant(Node* node) { 277 return Bounds(TypeConstant(OpParameter<Unique<Object> >(node).handle())); 278 } 279 280 281 Bounds Typer::Visitor::TypeExternalConstant(Node* node) { 282 return Bounds(Type::Internal(zone())); 283 } 284 285 286 Bounds Typer::Visitor::TypePhi(Node* node) { 287 int arity = OperatorProperties::GetValueInputCount(node->op()); 288 Bounds bounds = OperandType(node, 0); 289 for (int i = 1; i < arity; ++i) { 290 bounds = Bounds::Either(bounds, OperandType(node, i), zone()); 291 } 292 return bounds; 293 } 294 295 296 Bounds Typer::Visitor::TypeEffectPhi(Node* node) { 297 UNREACHABLE(); 298 return Bounds(); 299 } 300 301 302 Bounds Typer::Visitor::TypeControlEffect(Node* node) { 303 UNREACHABLE(); 304 return Bounds(); 305 } 306 307 308 Bounds Typer::Visitor::TypeValueEffect(Node* node) { 309 UNREACHABLE(); 310 return Bounds(); 311 } 312 313 314 Bounds Typer::Visitor::TypeFinish(Node* node) { 315 return OperandType(node, 0); 316 } 317 318 319 Bounds Typer::Visitor::TypeFrameState(Node* node) { 320 // TODO(rossberg): Ideally FrameState wouldn't have a value output. 321 return Bounds(Type::Internal(zone())); 322 } 323 324 325 Bounds Typer::Visitor::TypeStateValues(Node* node) { 326 return Bounds(Type::Internal(zone())); 327 } 328 329 330 Bounds Typer::Visitor::TypeCall(Node* node) { 331 return Bounds::Unbounded(zone()); 332 } 333 334 335 Bounds Typer::Visitor::TypeProjection(Node* node) { 336 // TODO(titzer): use the output type of the input to determine the bounds. 337 return Bounds::Unbounded(zone()); 338 } 339 340 341 // JS comparison operators. 342 343 #define DEFINE_METHOD(x) \ 344 Bounds Typer::Visitor::Type##x(Node* node) { \ 345 return Bounds(Type::Boolean(zone())); \ 346 } 347 JS_COMPARE_BINOP_LIST(DEFINE_METHOD) 348 #undef DEFINE_METHOD 349 350 351 // JS bitwise operators. 352 353 Bounds Typer::Visitor::TypeJSBitwiseOr(Node* node) { 354 Bounds left = OperandType(node, 0); 355 Bounds right = OperandType(node, 1); 356 Type* upper = Type::Union(left.upper, right.upper, zone()); 357 if (!upper->Is(Type::Signed32())) upper = Type::Signed32(zone()); 358 Type* lower = Type::Intersect(Type::SignedSmall(zone()), upper, zone()); 359 return Bounds(lower, upper); 360 } 361 362 363 Bounds Typer::Visitor::TypeJSBitwiseAnd(Node* node) { 364 Bounds left = OperandType(node, 0); 365 Bounds right = OperandType(node, 1); 366 Type* upper = Type::Union(left.upper, right.upper, zone()); 367 if (!upper->Is(Type::Signed32())) upper = Type::Signed32(zone()); 368 Type* lower = Type::Intersect(Type::SignedSmall(zone()), upper, zone()); 369 return Bounds(lower, upper); 370 } 371 372 373 Bounds Typer::Visitor::TypeJSBitwiseXor(Node* node) { 374 return Bounds(Type::SignedSmall(zone()), Type::Signed32(zone())); 375 } 376 377 378 Bounds Typer::Visitor::TypeJSShiftLeft(Node* node) { 379 return Bounds(Type::SignedSmall(zone()), Type::Signed32(zone())); 380 } 381 382 383 Bounds Typer::Visitor::TypeJSShiftRight(Node* node) { 384 return Bounds(Type::SignedSmall(zone()), Type::Signed32(zone())); 385 } 386 387 388 Bounds Typer::Visitor::TypeJSShiftRightLogical(Node* node) { 389 return Bounds(Type::UnsignedSmall(zone()), Type::Unsigned32(zone())); 390 } 391 392 393 // JS arithmetic operators. 394 395 Bounds Typer::Visitor::TypeJSAdd(Node* node) { 396 Bounds left = OperandType(node, 0); 397 Bounds right = OperandType(node, 1); 398 Type* lower = 399 left.lower->Is(Type::None()) || right.lower->Is(Type::None()) ? 400 Type::None(zone()) : 401 left.lower->Is(Type::Number()) && right.lower->Is(Type::Number()) ? 402 Type::SignedSmall(zone()) : 403 left.lower->Is(Type::String()) || right.lower->Is(Type::String()) ? 404 Type::String(zone()) : Type::None(zone()); 405 Type* upper = 406 left.upper->Is(Type::None()) && right.upper->Is(Type::None()) ? 407 Type::None(zone()) : 408 left.upper->Is(Type::Number()) && right.upper->Is(Type::Number()) ? 409 Type::Number(zone()) : 410 left.upper->Is(Type::String()) || right.upper->Is(Type::String()) ? 411 Type::String(zone()) : Type::NumberOrString(zone()); 412 return Bounds(lower, upper); 413 } 414 415 416 Bounds Typer::Visitor::TypeJSSubtract(Node* node) { 417 return Bounds(Type::SignedSmall(zone()), Type::Number(zone())); 418 } 419 420 421 Bounds Typer::Visitor::TypeJSMultiply(Node* node) { 422 return Bounds(Type::SignedSmall(zone()), Type::Number(zone())); 423 } 424 425 426 Bounds Typer::Visitor::TypeJSDivide(Node* node) { 427 return Bounds(Type::SignedSmall(zone()), Type::Number(zone())); 428 } 429 430 431 Bounds Typer::Visitor::TypeJSModulus(Node* node) { 432 return Bounds(Type::SignedSmall(zone()), Type::Number(zone())); 433 } 434 435 436 // JS unary operators. 437 438 Bounds Typer::Visitor::TypeJSUnaryNot(Node* node) { 439 return Bounds(Type::Boolean(zone())); 440 } 441 442 443 Bounds Typer::Visitor::TypeJSTypeOf(Node* node) { 444 return Bounds(Type::InternalizedString(zone())); 445 } 446 447 448 // JS conversion operators. 449 450 Bounds Typer::Visitor::TypeJSToBoolean(Node* node) { 451 return Bounds(Type::Boolean(zone())); 452 } 453 454 455 Bounds Typer::Visitor::TypeJSToNumber(Node* node) { 456 return Bounds(Type::SignedSmall(zone()), Type::Number(zone())); 457 } 458 459 460 Bounds Typer::Visitor::TypeJSToString(Node* node) { 461 return Bounds(Type::None(zone()), Type::String(zone())); 462 } 463 464 465 Bounds Typer::Visitor::TypeJSToName(Node* node) { 466 return Bounds(Type::None(zone()), Type::Name(zone())); 467 } 468 469 470 Bounds Typer::Visitor::TypeJSToObject(Node* node) { 471 return Bounds(Type::None(zone()), Type::Receiver(zone())); 472 } 473 474 475 // JS object operators. 476 477 Bounds Typer::Visitor::TypeJSCreate(Node* node) { 478 return Bounds(Type::None(zone()), Type::Object(zone())); 479 } 480 481 482 Bounds Typer::Visitor::TypeJSLoadProperty(Node* node) { 483 Bounds object = OperandType(node, 0); 484 Bounds name = OperandType(node, 1); 485 Bounds result = Bounds::Unbounded(zone()); 486 // TODO(rossberg): Use range types and sized array types to filter undefined. 487 if (object.lower->IsArray() && name.lower->Is(Type::Integral32())) { 488 result.lower = Type::Union( 489 object.lower->AsArray()->Element(), Type::Undefined(zone()), zone()); 490 } 491 if (object.upper->IsArray() && name.upper->Is(Type::Integral32())) { 492 result.upper = Type::Union( 493 object.upper->AsArray()->Element(), Type::Undefined(zone()), zone()); 494 } 495 return result; 496 } 497 498 499 Bounds Typer::Visitor::TypeJSLoadNamed(Node* node) { 500 return Bounds::Unbounded(zone()); 501 } 502 503 504 Bounds Typer::Visitor::TypeJSStoreProperty(Node* node) { 505 UNREACHABLE(); 506 return Bounds(); 507 } 508 509 510 Bounds Typer::Visitor::TypeJSStoreNamed(Node* node) { 511 UNREACHABLE(); 512 return Bounds(); 513 } 514 515 516 Bounds Typer::Visitor::TypeJSDeleteProperty(Node* node) { 517 return Bounds(Type::Boolean(zone())); 518 } 519 520 521 Bounds Typer::Visitor::TypeJSHasProperty(Node* node) { 522 return Bounds(Type::Boolean(zone())); 523 } 524 525 526 Bounds Typer::Visitor::TypeJSInstanceOf(Node* node) { 527 return Bounds(Type::Boolean(zone())); 528 } 529 530 531 // JS context operators. 532 533 Bounds Typer::Visitor::TypeJSLoadContext(Node* node) { 534 Bounds outer = OperandType(node, 0); 535 DCHECK(outer.upper->Maybe(Type::Internal())); 536 // TODO(rossberg): More precisely, instead of the above assertion, we should 537 // back-propagate the constraint that it has to be a subtype of Internal. 538 539 ContextAccess access = OpParameter<ContextAccess>(node); 540 Type* context_type = outer.upper; 541 MaybeHandle<Context> context; 542 if (context_type->IsConstant()) { 543 context = Handle<Context>::cast(context_type->AsConstant()->Value()); 544 } 545 // Walk context chain (as far as known), mirroring dynamic lookup. 546 // Since contexts are mutable, the information is only useful as a lower 547 // bound. 548 // TODO(rossberg): Could use scope info to fix upper bounds for constant 549 // bindings if we know that this code is never shared. 550 for (int i = access.depth(); i > 0; --i) { 551 if (context_type->IsContext()) { 552 context_type = context_type->AsContext()->Outer(); 553 if (context_type->IsConstant()) { 554 context = Handle<Context>::cast(context_type->AsConstant()->Value()); 555 } 556 } else if (!context.is_null()) { 557 context = handle(context.ToHandleChecked()->previous(), isolate()); 558 } 559 } 560 if (context.is_null()) { 561 return Bounds::Unbounded(zone()); 562 } else { 563 Handle<Object> value = 564 handle(context.ToHandleChecked()->get(access.index()), isolate()); 565 Type* lower = TypeConstant(value); 566 return Bounds(lower, Type::Any(zone())); 567 } 568 } 569 570 571 Bounds Typer::Visitor::TypeJSStoreContext(Node* node) { 572 UNREACHABLE(); 573 return Bounds(); 574 } 575 576 577 Bounds Typer::Visitor::TypeJSCreateFunctionContext(Node* node) { 578 Type* outer = ContextType(node); 579 return Bounds(Type::Context(outer, zone())); 580 } 581 582 583 Bounds Typer::Visitor::TypeJSCreateCatchContext(Node* node) { 584 Type* outer = ContextType(node); 585 return Bounds(Type::Context(outer, zone())); 586 } 587 588 589 Bounds Typer::Visitor::TypeJSCreateWithContext(Node* node) { 590 Type* outer = ContextType(node); 591 return Bounds(Type::Context(outer, zone())); 592 } 593 594 595 Bounds Typer::Visitor::TypeJSCreateBlockContext(Node* node) { 596 Type* outer = ContextType(node); 597 return Bounds(Type::Context(outer, zone())); 598 } 599 600 601 Bounds Typer::Visitor::TypeJSCreateModuleContext(Node* node) { 602 // TODO(rossberg): this is probably incorrect 603 Type* outer = ContextType(node); 604 return Bounds(Type::Context(outer, zone())); 605 } 606 607 608 Bounds Typer::Visitor::TypeJSCreateGlobalContext(Node* node) { 609 Type* outer = ContextType(node); 610 return Bounds(Type::Context(outer, zone())); 611 } 612 613 614 // JS other operators. 615 616 Bounds Typer::Visitor::TypeJSYield(Node* node) { 617 return Bounds::Unbounded(zone()); 618 } 619 620 621 Bounds Typer::Visitor::TypeJSCallConstruct(Node* node) { 622 return Bounds(Type::None(zone()), Type::Receiver(zone())); 623 } 624 625 626 Bounds Typer::Visitor::TypeJSCallFunction(Node* node) { 627 Bounds fun = OperandType(node, 0); 628 Type* lower = fun.lower->IsFunction() 629 ? fun.lower->AsFunction()->Result() : Type::None(zone()); 630 Type* upper = fun.upper->IsFunction() 631 ? fun.upper->AsFunction()->Result() : Type::Any(zone()); 632 return Bounds(lower, upper); 633 } 634 635 636 Bounds Typer::Visitor::TypeJSCallRuntime(Node* node) { 637 return Bounds::Unbounded(zone()); 638 } 639 640 641 Bounds Typer::Visitor::TypeJSDebugger(Node* node) { 642 return Bounds::Unbounded(zone()); 643 } 644 645 646 // Simplified operators. 647 648 Bounds Typer::Visitor::TypeBooleanNot(Node* node) { 649 return Bounds(Type::Boolean(zone())); 650 } 651 652 653 Bounds Typer::Visitor::TypeBooleanToNumber(Node* node) { 654 return Bounds(Type::Number(zone())); 655 } 656 657 658 Bounds Typer::Visitor::TypeNumberEqual(Node* node) { 659 return Bounds(Type::Boolean(zone())); 660 } 661 662 663 Bounds Typer::Visitor::TypeNumberLessThan(Node* node) { 664 return Bounds(Type::Boolean(zone())); 665 } 666 667 668 Bounds Typer::Visitor::TypeNumberLessThanOrEqual(Node* node) { 669 return Bounds(Type::Boolean(zone())); 670 } 671 672 673 Bounds Typer::Visitor::TypeNumberAdd(Node* node) { 674 return Bounds(Type::Number(zone())); 675 } 676 677 678 Bounds Typer::Visitor::TypeNumberSubtract(Node* node) { 679 return Bounds(Type::Number(zone())); 680 } 681 682 683 Bounds Typer::Visitor::TypeNumberMultiply(Node* node) { 684 return Bounds(Type::Number(zone())); 685 } 686 687 688 Bounds Typer::Visitor::TypeNumberDivide(Node* node) { 689 return Bounds(Type::Number(zone())); 690 } 691 692 693 Bounds Typer::Visitor::TypeNumberModulus(Node* node) { 694 return Bounds(Type::Number(zone())); 695 } 696 697 698 Bounds Typer::Visitor::TypeNumberToInt32(Node* node) { 699 Bounds arg = OperandType(node, 0); 700 Type* s32 = Type::Signed32(zone()); 701 Type* lower = arg.lower->Is(s32) ? arg.lower : s32; 702 Type* upper = arg.upper->Is(s32) ? arg.upper : s32; 703 return Bounds(lower, upper); 704 } 705 706 707 Bounds Typer::Visitor::TypeNumberToUint32(Node* node) { 708 Bounds arg = OperandType(node, 0); 709 Type* u32 = Type::Unsigned32(zone()); 710 Type* lower = arg.lower->Is(u32) ? arg.lower : u32; 711 Type* upper = arg.upper->Is(u32) ? arg.upper : u32; 712 return Bounds(lower, upper); 713 } 714 715 716 Bounds Typer::Visitor::TypeReferenceEqual(Node* node) { 717 return Bounds(Type::Boolean(zone())); 718 } 719 720 721 Bounds Typer::Visitor::TypeStringEqual(Node* node) { 722 return Bounds(Type::Boolean(zone())); 723 } 724 725 726 Bounds Typer::Visitor::TypeStringLessThan(Node* node) { 727 return Bounds(Type::Boolean(zone())); 728 } 729 730 731 Bounds Typer::Visitor::TypeStringLessThanOrEqual(Node* node) { 732 return Bounds(Type::Boolean(zone())); 733 } 734 735 736 Bounds Typer::Visitor::TypeStringAdd(Node* node) { 737 return Bounds(Type::String(zone())); 738 } 739 740 741 Bounds Typer::Visitor::TypeChangeTaggedToInt32(Node* node) { 742 // TODO(titzer): type is type of input, representation is Word32. 743 return Bounds(Type::Integral32()); 744 } 745 746 747 Bounds Typer::Visitor::TypeChangeTaggedToUint32(Node* node) { 748 return Bounds(Type::Integral32()); // TODO(titzer): add appropriate rep 749 } 750 751 752 Bounds Typer::Visitor::TypeChangeTaggedToFloat64(Node* node) { 753 // TODO(titzer): type is type of input, representation is Float64. 754 return Bounds(Type::Number()); 755 } 756 757 758 Bounds Typer::Visitor::TypeChangeInt32ToTagged(Node* node) { 759 // TODO(titzer): type is type of input, representation is Tagged. 760 return Bounds(Type::Integral32()); 761 } 762 763 764 Bounds Typer::Visitor::TypeChangeUint32ToTagged(Node* node) { 765 // TODO(titzer): type is type of input, representation is Tagged. 766 return Bounds(Type::Unsigned32()); 767 } 768 769 770 Bounds Typer::Visitor::TypeChangeFloat64ToTagged(Node* node) { 771 // TODO(titzer): type is type of input, representation is Tagged. 772 return Bounds(Type::Number()); 773 } 774 775 776 Bounds Typer::Visitor::TypeChangeBoolToBit(Node* node) { 777 // TODO(titzer): type is type of input, representation is Bit. 778 return Bounds(Type::Boolean()); 779 } 780 781 782 Bounds Typer::Visitor::TypeChangeBitToBool(Node* node) { 783 // TODO(titzer): type is type of input, representation is Tagged. 784 return Bounds(Type::Boolean()); 785 } 786 787 788 Bounds Typer::Visitor::TypeLoadField(Node* node) { 789 return Bounds(FieldAccessOf(node->op()).type); 790 } 791 792 793 Bounds Typer::Visitor::TypeLoadElement(Node* node) { 794 return Bounds(ElementAccessOf(node->op()).type); 795 } 796 797 798 Bounds Typer::Visitor::TypeStoreField(Node* node) { 799 UNREACHABLE(); 800 return Bounds(); 801 } 802 803 804 Bounds Typer::Visitor::TypeStoreElement(Node* node) { 805 UNREACHABLE(); 806 return Bounds(); 807 } 808 809 810 // Machine operators. 811 812 // TODO(rossberg): implement 813 #define DEFINE_METHOD(x) \ 814 Bounds Typer::Visitor::Type##x(Node* node) { return Bounds(Type::None()); } 815 MACHINE_OP_LIST(DEFINE_METHOD) 816 #undef DEFINE_METHOD 817 818 819 // Heap constants. 820 821 Type* Typer::Visitor::TypeConstant(Handle<Object> value) { 822 if (value->IsJSFunction() && JSFunction::cast(*value)->IsBuiltin() && 823 !context().is_null()) { 824 Handle<Context> native = 825 handle(context().ToHandleChecked()->native_context(), isolate()); 826 if (*value == native->math_abs_fun()) { 827 return typer_->number_fun1_; // TODO(rossberg): can't express overloading 828 } else if (*value == native->math_acos_fun()) { 829 return typer_->number_fun1_; 830 } else if (*value == native->math_asin_fun()) { 831 return typer_->number_fun1_; 832 } else if (*value == native->math_atan_fun()) { 833 return typer_->number_fun1_; 834 } else if (*value == native->math_atan2_fun()) { 835 return typer_->number_fun2_; 836 } else if (*value == native->math_ceil_fun()) { 837 return typer_->number_fun1_; 838 } else if (*value == native->math_cos_fun()) { 839 return typer_->number_fun1_; 840 } else if (*value == native->math_exp_fun()) { 841 return typer_->number_fun1_; 842 } else if (*value == native->math_floor_fun()) { 843 return typer_->number_fun1_; 844 } else if (*value == native->math_imul_fun()) { 845 return typer_->imul_fun_; 846 } else if (*value == native->math_log_fun()) { 847 return typer_->number_fun1_; 848 } else if (*value == native->math_pow_fun()) { 849 return typer_->number_fun2_; 850 } else if (*value == native->math_random_fun()) { 851 return typer_->number_fun0_; 852 } else if (*value == native->math_round_fun()) { 853 return typer_->number_fun1_; 854 } else if (*value == native->math_sin_fun()) { 855 return typer_->number_fun1_; 856 } else if (*value == native->math_sqrt_fun()) { 857 return typer_->number_fun1_; 858 } else if (*value == native->math_tan_fun()) { 859 return typer_->number_fun1_; 860 } else if (*value == native->array_buffer_fun()) { 861 return typer_->array_buffer_fun_; 862 } else if (*value == native->int8_array_fun()) { 863 return typer_->int8_array_fun_; 864 } else if (*value == native->int16_array_fun()) { 865 return typer_->int16_array_fun_; 866 } else if (*value == native->int32_array_fun()) { 867 return typer_->int32_array_fun_; 868 } else if (*value == native->uint8_array_fun()) { 869 return typer_->uint8_array_fun_; 870 } else if (*value == native->uint16_array_fun()) { 871 return typer_->uint16_array_fun_; 872 } else if (*value == native->uint32_array_fun()) { 873 return typer_->uint32_array_fun_; 874 } else if (*value == native->float32_array_fun()) { 875 return typer_->float32_array_fun_; 876 } else if (*value == native->float64_array_fun()) { 877 return typer_->float64_array_fun_; 878 } 879 } 880 return Type::Constant(value, zone()); 881 } 882 883 884 namespace { 885 886 class TyperDecorator : public GraphDecorator { 887 public: 888 explicit TyperDecorator(Typer* typer) : typer_(typer) {} 889 virtual void Decorate(Node* node) { typer_->Init(node); } 890 891 private: 892 Typer* typer_; 893 }; 894 895 } 896 897 898 void Typer::DecorateGraph(Graph* graph) { 899 graph->AddDecorator(new (zone()) TyperDecorator(this)); 900 } 901 902 } 903 } 904 } // namespace v8::internal::compiler 905