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