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
13namespace v8 {
14namespace internal {
15namespace compiler {
16
17Typer::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
65class 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
118class 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
146class 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
171class 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
197void 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
207void Typer::Narrow(Graph* graph, Node* start, MaybeHandle<Context> context) {
208  NarrowVisitor typing(this, context);
209  graph->VisitNodeUsesFrom(start, &typing);
210}
211
212
213void Typer::Widen(Graph* graph, Node* start, MaybeHandle<Context> context) {
214  WidenVisitor typing(this, context);
215  graph->VisitNodeUsesFrom(start, &typing);
216}
217
218
219void 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
233Bounds Typer::Visitor::TypeStart(Node* node) {
234  return Bounds(Type::Internal(zone()));
235}
236
237
238// Common operators.
239
240Bounds Typer::Visitor::TypeParameter(Node* node) {
241  return Bounds::Unbounded(zone());
242}
243
244
245Bounds 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
251Bounds 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
258Bounds 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
264Bounds 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
270Bounds 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
276Bounds Typer::Visitor::TypeHeapConstant(Node* node) {
277  return Bounds(TypeConstant(OpParameter<Unique<Object> >(node).handle()));
278}
279
280
281Bounds Typer::Visitor::TypeExternalConstant(Node* node) {
282  return Bounds(Type::Internal(zone()));
283}
284
285
286Bounds 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
296Bounds Typer::Visitor::TypeEffectPhi(Node* node) {
297  UNREACHABLE();
298  return Bounds();
299}
300
301
302Bounds Typer::Visitor::TypeControlEffect(Node* node) {
303  UNREACHABLE();
304  return Bounds();
305}
306
307
308Bounds Typer::Visitor::TypeValueEffect(Node* node) {
309  UNREACHABLE();
310  return Bounds();
311}
312
313
314Bounds Typer::Visitor::TypeFinish(Node* node) {
315  return OperandType(node, 0);
316}
317
318
319Bounds 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
325Bounds Typer::Visitor::TypeStateValues(Node* node) {
326  return Bounds(Type::Internal(zone()));
327}
328
329
330Bounds Typer::Visitor::TypeCall(Node* node) {
331  return Bounds::Unbounded(zone());
332}
333
334
335Bounds 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  }
347JS_COMPARE_BINOP_LIST(DEFINE_METHOD)
348#undef DEFINE_METHOD
349
350
351// JS bitwise operators.
352
353Bounds 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
363Bounds 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
373Bounds Typer::Visitor::TypeJSBitwiseXor(Node* node) {
374  return Bounds(Type::SignedSmall(zone()), Type::Signed32(zone()));
375}
376
377
378Bounds Typer::Visitor::TypeJSShiftLeft(Node* node) {
379  return Bounds(Type::SignedSmall(zone()), Type::Signed32(zone()));
380}
381
382
383Bounds Typer::Visitor::TypeJSShiftRight(Node* node) {
384  return Bounds(Type::SignedSmall(zone()), Type::Signed32(zone()));
385}
386
387
388Bounds Typer::Visitor::TypeJSShiftRightLogical(Node* node) {
389  return Bounds(Type::UnsignedSmall(zone()), Type::Unsigned32(zone()));
390}
391
392
393// JS arithmetic operators.
394
395Bounds 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
416Bounds Typer::Visitor::TypeJSSubtract(Node* node) {
417  return Bounds(Type::SignedSmall(zone()), Type::Number(zone()));
418}
419
420
421Bounds Typer::Visitor::TypeJSMultiply(Node* node) {
422  return Bounds(Type::SignedSmall(zone()), Type::Number(zone()));
423}
424
425
426Bounds Typer::Visitor::TypeJSDivide(Node* node) {
427  return Bounds(Type::SignedSmall(zone()), Type::Number(zone()));
428}
429
430
431Bounds Typer::Visitor::TypeJSModulus(Node* node) {
432  return Bounds(Type::SignedSmall(zone()), Type::Number(zone()));
433}
434
435
436// JS unary operators.
437
438Bounds Typer::Visitor::TypeJSUnaryNot(Node* node) {
439  return Bounds(Type::Boolean(zone()));
440}
441
442
443Bounds Typer::Visitor::TypeJSTypeOf(Node* node) {
444  return Bounds(Type::InternalizedString(zone()));
445}
446
447
448// JS conversion operators.
449
450Bounds Typer::Visitor::TypeJSToBoolean(Node* node) {
451  return Bounds(Type::Boolean(zone()));
452}
453
454
455Bounds Typer::Visitor::TypeJSToNumber(Node* node) {
456  return Bounds(Type::SignedSmall(zone()), Type::Number(zone()));
457}
458
459
460Bounds Typer::Visitor::TypeJSToString(Node* node) {
461  return Bounds(Type::None(zone()), Type::String(zone()));
462}
463
464
465Bounds Typer::Visitor::TypeJSToName(Node* node) {
466  return Bounds(Type::None(zone()), Type::Name(zone()));
467}
468
469
470Bounds Typer::Visitor::TypeJSToObject(Node* node) {
471  return Bounds(Type::None(zone()), Type::Receiver(zone()));
472}
473
474
475// JS object operators.
476
477Bounds Typer::Visitor::TypeJSCreate(Node* node) {
478  return Bounds(Type::None(zone()), Type::Object(zone()));
479}
480
481
482Bounds 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
499Bounds Typer::Visitor::TypeJSLoadNamed(Node* node) {
500  return Bounds::Unbounded(zone());
501}
502
503
504Bounds Typer::Visitor::TypeJSStoreProperty(Node* node) {
505  UNREACHABLE();
506  return Bounds();
507}
508
509
510Bounds Typer::Visitor::TypeJSStoreNamed(Node* node) {
511  UNREACHABLE();
512  return Bounds();
513}
514
515
516Bounds Typer::Visitor::TypeJSDeleteProperty(Node* node) {
517  return Bounds(Type::Boolean(zone()));
518}
519
520
521Bounds Typer::Visitor::TypeJSHasProperty(Node* node) {
522  return Bounds(Type::Boolean(zone()));
523}
524
525
526Bounds Typer::Visitor::TypeJSInstanceOf(Node* node) {
527  return Bounds(Type::Boolean(zone()));
528}
529
530
531// JS context operators.
532
533Bounds 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
571Bounds Typer::Visitor::TypeJSStoreContext(Node* node) {
572  UNREACHABLE();
573  return Bounds();
574}
575
576
577Bounds Typer::Visitor::TypeJSCreateFunctionContext(Node* node) {
578  Type* outer = ContextType(node);
579  return Bounds(Type::Context(outer, zone()));
580}
581
582
583Bounds Typer::Visitor::TypeJSCreateCatchContext(Node* node) {
584  Type* outer = ContextType(node);
585  return Bounds(Type::Context(outer, zone()));
586}
587
588
589Bounds Typer::Visitor::TypeJSCreateWithContext(Node* node) {
590  Type* outer = ContextType(node);
591  return Bounds(Type::Context(outer, zone()));
592}
593
594
595Bounds Typer::Visitor::TypeJSCreateBlockContext(Node* node) {
596  Type* outer = ContextType(node);
597  return Bounds(Type::Context(outer, zone()));
598}
599
600
601Bounds 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
608Bounds 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
616Bounds Typer::Visitor::TypeJSYield(Node* node) {
617  return Bounds::Unbounded(zone());
618}
619
620
621Bounds Typer::Visitor::TypeJSCallConstruct(Node* node) {
622  return Bounds(Type::None(zone()), Type::Receiver(zone()));
623}
624
625
626Bounds 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
636Bounds Typer::Visitor::TypeJSCallRuntime(Node* node) {
637  return Bounds::Unbounded(zone());
638}
639
640
641Bounds Typer::Visitor::TypeJSDebugger(Node* node) {
642  return Bounds::Unbounded(zone());
643}
644
645
646// Simplified operators.
647
648Bounds Typer::Visitor::TypeBooleanNot(Node* node) {
649  return Bounds(Type::Boolean(zone()));
650}
651
652
653Bounds Typer::Visitor::TypeBooleanToNumber(Node* node) {
654  return Bounds(Type::Number(zone()));
655}
656
657
658Bounds Typer::Visitor::TypeNumberEqual(Node* node) {
659  return Bounds(Type::Boolean(zone()));
660}
661
662
663Bounds Typer::Visitor::TypeNumberLessThan(Node* node) {
664  return Bounds(Type::Boolean(zone()));
665}
666
667
668Bounds Typer::Visitor::TypeNumberLessThanOrEqual(Node* node) {
669  return Bounds(Type::Boolean(zone()));
670}
671
672
673Bounds Typer::Visitor::TypeNumberAdd(Node* node) {
674  return Bounds(Type::Number(zone()));
675}
676
677
678Bounds Typer::Visitor::TypeNumberSubtract(Node* node) {
679  return Bounds(Type::Number(zone()));
680}
681
682
683Bounds Typer::Visitor::TypeNumberMultiply(Node* node) {
684  return Bounds(Type::Number(zone()));
685}
686
687
688Bounds Typer::Visitor::TypeNumberDivide(Node* node) {
689  return Bounds(Type::Number(zone()));
690}
691
692
693Bounds Typer::Visitor::TypeNumberModulus(Node* node) {
694  return Bounds(Type::Number(zone()));
695}
696
697
698Bounds 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
707Bounds 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
716Bounds Typer::Visitor::TypeReferenceEqual(Node* node) {
717  return Bounds(Type::Boolean(zone()));
718}
719
720
721Bounds Typer::Visitor::TypeStringEqual(Node* node) {
722  return Bounds(Type::Boolean(zone()));
723}
724
725
726Bounds Typer::Visitor::TypeStringLessThan(Node* node) {
727  return Bounds(Type::Boolean(zone()));
728}
729
730
731Bounds Typer::Visitor::TypeStringLessThanOrEqual(Node* node) {
732  return Bounds(Type::Boolean(zone()));
733}
734
735
736Bounds Typer::Visitor::TypeStringAdd(Node* node) {
737  return Bounds(Type::String(zone()));
738}
739
740
741Bounds Typer::Visitor::TypeChangeTaggedToInt32(Node* node) {
742  // TODO(titzer): type is type of input, representation is Word32.
743  return Bounds(Type::Integral32());
744}
745
746
747Bounds Typer::Visitor::TypeChangeTaggedToUint32(Node* node) {
748  return Bounds(Type::Integral32());  // TODO(titzer): add appropriate rep
749}
750
751
752Bounds Typer::Visitor::TypeChangeTaggedToFloat64(Node* node) {
753  // TODO(titzer): type is type of input, representation is Float64.
754  return Bounds(Type::Number());
755}
756
757
758Bounds Typer::Visitor::TypeChangeInt32ToTagged(Node* node) {
759  // TODO(titzer): type is type of input, representation is Tagged.
760  return Bounds(Type::Integral32());
761}
762
763
764Bounds Typer::Visitor::TypeChangeUint32ToTagged(Node* node) {
765  // TODO(titzer): type is type of input, representation is Tagged.
766  return Bounds(Type::Unsigned32());
767}
768
769
770Bounds Typer::Visitor::TypeChangeFloat64ToTagged(Node* node) {
771  // TODO(titzer): type is type of input, representation is Tagged.
772  return Bounds(Type::Number());
773}
774
775
776Bounds Typer::Visitor::TypeChangeBoolToBit(Node* node) {
777  // TODO(titzer): type is type of input, representation is Bit.
778  return Bounds(Type::Boolean());
779}
780
781
782Bounds Typer::Visitor::TypeChangeBitToBool(Node* node) {
783  // TODO(titzer): type is type of input, representation is Tagged.
784  return Bounds(Type::Boolean());
785}
786
787
788Bounds Typer::Visitor::TypeLoadField(Node* node) {
789  return Bounds(FieldAccessOf(node->op()).type);
790}
791
792
793Bounds Typer::Visitor::TypeLoadElement(Node* node) {
794  return Bounds(ElementAccessOf(node->op()).type);
795}
796
797
798Bounds Typer::Visitor::TypeStoreField(Node* node) {
799  UNREACHABLE();
800  return Bounds();
801}
802
803
804Bounds 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()); }
815MACHINE_OP_LIST(DEFINE_METHOD)
816#undef DEFINE_METHOD
817
818
819// Heap constants.
820
821Type* 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
884namespace {
885
886class 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
898void Typer::DecorateGraph(Graph* graph) {
899  graph->AddDecorator(new (zone()) TyperDecorator(this));
900}
901
902}
903}
904}  // namespace v8::internal::compiler
905