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.
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"
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);
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);
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);
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);
65 class Typer::Visitor : public NullNodeVisitor {
67 Visitor(Typer* typer, MaybeHandle<Context> context)
68 : typer_(typer), context_(context) {}
70 Bounds TypeNode(Node* node) {
71 switch (node->opcode()) {
72 #define DECLARE_CASE(x) case IrOpcode::k##x: return Type##x(node);
73 VALUE_OP_LIST(DECLARE_CASE)
76 #define DECLARE_CASE(x) case IrOpcode::k##x:
77 CONTROL_OP_LIST(DECLARE_CASE)
81 return Bounds(Type::None(zone()));
84 Type* TypeConstant(Handle<Object> value);
87 #define DECLARE_METHOD(x) inline Bounds Type##x(Node* node);
88 VALUE_OP_LIST(DECLARE_METHOD)
91 Bounds OperandType(Node* node, int i) {
92 return NodeProperties::GetBounds(NodeProperties::GetValueInput(node, i));
95 Type* ContextType(Node* node) {
97 NodeProperties::GetBounds(NodeProperties::GetContextInput(node));
98 DCHECK(result.upper->Is(Type::Internal()));
99 DCHECK(result.lower->Equals(result.upper));
103 Zone* zone() { return typer_->zone(); }
104 Isolate* isolate() { return typer_->isolate(); }
105 MaybeHandle<Context> context() { return context_; }
109 MaybeHandle<Context> context_;
113 class Typer::RunVisitor : public Typer::Visitor {
115 RunVisitor(Typer* typer, MaybeHandle<Context> context)
116 : Visitor(typer, context),
117 phis(NodeSet::key_compare(), NodeSet::allocator_type(typer->zone())) {}
119 GenericGraphVisit::Control Pre(Node* node) {
120 return NodeProperties::IsControl(node)
121 && node->opcode() != IrOpcode::kEnd
122 && node->opcode() != IrOpcode::kMerge
123 && node->opcode() != IrOpcode::kReturn
124 ? GenericGraphVisit::SKIP : GenericGraphVisit::CONTINUE;
127 GenericGraphVisit::Control Post(Node* node) {
128 Bounds bounds = TypeNode(node);
129 if (node->opcode() == IrOpcode::kPhi) {
130 // Remember phis for least fixpoint iteration.
133 NodeProperties::SetBounds(node, bounds);
135 return GenericGraphVisit::CONTINUE;
142 class Typer::NarrowVisitor : public Typer::Visitor {
144 NarrowVisitor(Typer* typer, MaybeHandle<Context> context)
145 : Visitor(typer, context) {}
147 GenericGraphVisit::Control Pre(Node* node) {
148 Bounds previous = NodeProperties::GetBounds(node);
149 Bounds bounds = TypeNode(node);
150 NodeProperties::SetBounds(node, Bounds::Both(bounds, previous, zone()));
151 DCHECK(bounds.Narrows(previous));
152 // Stop when nothing changed (but allow reentry in case it does later).
153 return previous.Narrows(bounds)
154 ? GenericGraphVisit::DEFER : GenericGraphVisit::REENTER;
157 GenericGraphVisit::Control Post(Node* node) {
158 return GenericGraphVisit::REENTER;
163 class Typer::WidenVisitor : public Typer::Visitor {
165 WidenVisitor(Typer* typer, MaybeHandle<Context> context)
166 : Visitor(typer, context) {}
168 GenericGraphVisit::Control Pre(Node* node) {
169 Bounds previous = NodeProperties::GetBounds(node);
170 Bounds bounds = TypeNode(node);
171 DCHECK(previous.lower->Is(bounds.lower));
172 DCHECK(previous.upper->Is(bounds.upper));
173 NodeProperties::SetBounds(node, bounds); // TODO(rossberg): Either?
174 // Stop when nothing changed (but allow reentry in case it does later).
175 return bounds.Narrows(previous)
176 ? GenericGraphVisit::DEFER : GenericGraphVisit::REENTER;
179 GenericGraphVisit::Control Post(Node* node) {
180 return GenericGraphVisit::REENTER;
185 void Typer::Run(Graph* graph, MaybeHandle<Context> context) {
186 RunVisitor typing(this, context);
187 graph->VisitNodeInputsFromEnd(&typing);
188 // Find least fixpoint.
189 for (NodeSetIter i = typing.phis.begin(); i != typing.phis.end(); ++i) {
190 Widen(graph, *i, context);
195 void Typer::Narrow(Graph* graph, Node* start, MaybeHandle<Context> context) {
196 NarrowVisitor typing(this, context);
197 graph->VisitNodeUsesFrom(start, &typing);
201 void Typer::Widen(Graph* graph, Node* start, MaybeHandle<Context> context) {
202 WidenVisitor typing(this, context);
203 graph->VisitNodeUsesFrom(start, &typing);
207 void Typer::Init(Node* node) {
208 Visitor typing(this, MaybeHandle<Context>());
209 Bounds bounds = typing.TypeNode(node);
210 NodeProperties::SetBounds(node, bounds);
215 Bounds Typer::Visitor::TypeParameter(Node* node) {
216 return Bounds::Unbounded(zone());
220 Bounds Typer::Visitor::TypeInt32Constant(Node* node) {
221 // TODO(titzer): only call Type::Of() if the type is not already known.
222 return Bounds(Type::Of(ValueOf<int32_t>(node->op()), zone()));
226 Bounds Typer::Visitor::TypeInt64Constant(Node* node) {
227 // TODO(titzer): only call Type::Of() if the type is not already known.
229 Type::Of(static_cast<double>(ValueOf<int64_t>(node->op())), zone()));
233 Bounds Typer::Visitor::TypeFloat64Constant(Node* node) {
234 // TODO(titzer): only call Type::Of() if the type is not already known.
235 return Bounds(Type::Of(ValueOf<double>(node->op()), zone()));
239 Bounds Typer::Visitor::TypeNumberConstant(Node* node) {
240 // TODO(titzer): only call Type::Of() if the type is not already known.
241 return Bounds(Type::Of(ValueOf<double>(node->op()), zone()));
245 Bounds Typer::Visitor::TypeHeapConstant(Node* node) {
246 return Bounds(TypeConstant(ValueOf<Handle<Object> >(node->op())));
250 Bounds Typer::Visitor::TypeExternalConstant(Node* node) {
251 return Bounds(Type::Internal(zone()));
255 Bounds Typer::Visitor::TypePhi(Node* node) {
256 int arity = OperatorProperties::GetValueInputCount(node->op());
257 Bounds bounds = OperandType(node, 0);
258 for (int i = 1; i < arity; ++i) {
259 bounds = Bounds::Either(bounds, OperandType(node, i), zone());
265 Bounds Typer::Visitor::TypeEffectPhi(Node* node) {
266 return Bounds(Type::None(zone()));
270 Bounds Typer::Visitor::TypeFrameState(Node* node) {
271 return Bounds(Type::None(zone()));
275 Bounds Typer::Visitor::TypeStateValues(Node* node) {
276 return Bounds(Type::None(zone()));
280 Bounds Typer::Visitor::TypeCall(Node* node) {
281 return Bounds::Unbounded(zone());
285 Bounds Typer::Visitor::TypeProjection(Node* node) {
286 // TODO(titzer): use the output type of the input to determine the bounds.
287 return Bounds::Unbounded(zone());
291 // JS comparison operators.
293 #define DEFINE_METHOD(x) \
294 Bounds Typer::Visitor::Type##x(Node* node) { \
295 return Bounds(Type::Boolean(zone())); \
297 JS_COMPARE_BINOP_LIST(DEFINE_METHOD)
301 // JS bitwise operators.
303 Bounds Typer::Visitor::TypeJSBitwiseOr(Node* node) {
304 Bounds left = OperandType(node, 0);
305 Bounds right = OperandType(node, 1);
306 Type* upper = Type::Union(left.upper, right.upper, zone());
307 if (!upper->Is(Type::Signed32())) upper = Type::Signed32(zone());
308 Type* lower = Type::Intersect(Type::SignedSmall(zone()), upper, zone());
309 return Bounds(lower, upper);
313 Bounds Typer::Visitor::TypeJSBitwiseAnd(Node* node) {
314 Bounds left = OperandType(node, 0);
315 Bounds right = OperandType(node, 1);
316 Type* upper = Type::Union(left.upper, right.upper, zone());
317 if (!upper->Is(Type::Signed32())) upper = Type::Signed32(zone());
318 Type* lower = Type::Intersect(Type::SignedSmall(zone()), upper, zone());
319 return Bounds(lower, upper);
323 Bounds Typer::Visitor::TypeJSBitwiseXor(Node* node) {
324 return Bounds(Type::SignedSmall(zone()), Type::Signed32(zone()));
328 Bounds Typer::Visitor::TypeJSShiftLeft(Node* node) {
329 return Bounds(Type::SignedSmall(zone()), Type::Signed32(zone()));
333 Bounds Typer::Visitor::TypeJSShiftRight(Node* node) {
334 return Bounds(Type::SignedSmall(zone()), Type::Signed32(zone()));
338 Bounds Typer::Visitor::TypeJSShiftRightLogical(Node* node) {
339 return Bounds(Type::UnsignedSmall(zone()), Type::Unsigned32(zone()));
343 // JS arithmetic operators.
345 Bounds Typer::Visitor::TypeJSAdd(Node* node) {
346 Bounds left = OperandType(node, 0);
347 Bounds right = OperandType(node, 1);
349 left.lower->Is(Type::None()) || right.lower->Is(Type::None()) ?
351 left.lower->Is(Type::Number()) && right.lower->Is(Type::Number()) ?
352 Type::SignedSmall(zone()) :
353 left.lower->Is(Type::String()) || right.lower->Is(Type::String()) ?
354 Type::String(zone()) : Type::None(zone());
356 left.upper->Is(Type::None()) && right.upper->Is(Type::None()) ?
358 left.upper->Is(Type::Number()) && right.upper->Is(Type::Number()) ?
359 Type::Number(zone()) :
360 left.upper->Is(Type::String()) || right.upper->Is(Type::String()) ?
361 Type::String(zone()) : Type::NumberOrString(zone());
362 return Bounds(lower, upper);
366 Bounds Typer::Visitor::TypeJSSubtract(Node* node) {
367 return Bounds(Type::SignedSmall(zone()), Type::Number(zone()));
371 Bounds Typer::Visitor::TypeJSMultiply(Node* node) {
372 return Bounds(Type::SignedSmall(zone()), Type::Number(zone()));
376 Bounds Typer::Visitor::TypeJSDivide(Node* node) {
377 return Bounds(Type::SignedSmall(zone()), Type::Number(zone()));
381 Bounds Typer::Visitor::TypeJSModulus(Node* node) {
382 return Bounds(Type::SignedSmall(zone()), Type::Number(zone()));
386 // JS unary operators.
388 Bounds Typer::Visitor::TypeJSUnaryNot(Node* node) {
389 return Bounds(Type::Boolean(zone()));
393 Bounds Typer::Visitor::TypeJSTypeOf(Node* node) {
394 return Bounds(Type::InternalizedString(zone()));
398 // JS conversion operators.
400 Bounds Typer::Visitor::TypeJSToBoolean(Node* node) {
401 return Bounds(Type::Boolean(zone()));
405 Bounds Typer::Visitor::TypeJSToNumber(Node* node) {
406 return Bounds(Type::SignedSmall(zone()), Type::Number(zone()));
410 Bounds Typer::Visitor::TypeJSToString(Node* node) {
411 return Bounds(Type::None(zone()), Type::String(zone()));
415 Bounds Typer::Visitor::TypeJSToName(Node* node) {
416 return Bounds(Type::None(zone()), Type::Name(zone()));
420 Bounds Typer::Visitor::TypeJSToObject(Node* node) {
421 return Bounds(Type::None(zone()), Type::Object(zone()));
425 // JS object operators.
427 Bounds Typer::Visitor::TypeJSCreate(Node* node) {
428 return Bounds(Type::None(zone()), Type::Object(zone()));
432 Bounds Typer::Visitor::TypeJSLoadProperty(Node* node) {
433 Bounds object = OperandType(node, 0);
434 Bounds name = OperandType(node, 1);
435 Bounds result = Bounds::Unbounded(zone());
436 // TODO(rossberg): Use range types and sized array types to filter undefined.
437 if (object.lower->IsArray() && name.lower->Is(Type::Integral32())) {
438 result.lower = Type::Union(
439 object.lower->AsArray()->Element(), Type::Undefined(zone()), zone());
441 if (object.upper->IsArray() && name.upper->Is(Type::Integral32())) {
442 result.upper = Type::Union(
443 object.upper->AsArray()->Element(), Type::Undefined(zone()), zone());
449 Bounds Typer::Visitor::TypeJSLoadNamed(Node* node) {
450 return Bounds::Unbounded(zone());
454 Bounds Typer::Visitor::TypeJSStoreProperty(Node* node) {
455 return Bounds(Type::None(zone()));
459 Bounds Typer::Visitor::TypeJSStoreNamed(Node* node) {
460 return Bounds(Type::None(zone()));
464 Bounds Typer::Visitor::TypeJSDeleteProperty(Node* node) {
465 return Bounds(Type::Boolean(zone()));
469 Bounds Typer::Visitor::TypeJSHasProperty(Node* node) {
470 return Bounds(Type::Boolean(zone()));
474 Bounds Typer::Visitor::TypeJSInstanceOf(Node* node) {
475 return Bounds(Type::Boolean(zone()));
479 // JS context operators.
481 Bounds Typer::Visitor::TypeJSLoadContext(Node* node) {
482 Bounds outer = OperandType(node, 0);
483 DCHECK(outer.upper->Is(Type::Internal()));
484 DCHECK(outer.lower->Equals(outer.upper));
485 ContextAccess access = OpParameter<ContextAccess>(node);
486 Type* context_type = outer.upper;
487 MaybeHandle<Context> context;
488 if (context_type->IsConstant()) {
489 context = Handle<Context>::cast(context_type->AsConstant()->Value());
491 // Walk context chain (as far as known), mirroring dynamic lookup.
492 // Since contexts are mutable, the information is only useful as a lower
494 // TODO(rossberg): Could use scope info to fix upper bounds for constant
495 // bindings if we know that this code is never shared.
496 for (int i = access.depth(); i > 0; --i) {
497 if (context_type->IsContext()) {
498 context_type = context_type->AsContext()->Outer();
499 if (context_type->IsConstant()) {
500 context = Handle<Context>::cast(context_type->AsConstant()->Value());
503 context = handle(context.ToHandleChecked()->previous(), isolate());
506 if (context.is_null()) {
507 return Bounds::Unbounded(zone());
509 Handle<Object> value =
510 handle(context.ToHandleChecked()->get(access.index()), isolate());
511 Type* lower = TypeConstant(value);
512 return Bounds(lower, Type::Any(zone()));
517 Bounds Typer::Visitor::TypeJSStoreContext(Node* node) {
518 return Bounds(Type::None(zone()));
522 Bounds Typer::Visitor::TypeJSCreateFunctionContext(Node* node) {
523 Type* outer = ContextType(node);
524 return Bounds(Type::Context(outer, zone()));
528 Bounds Typer::Visitor::TypeJSCreateCatchContext(Node* node) {
529 Type* outer = ContextType(node);
530 return Bounds(Type::Context(outer, zone()));
534 Bounds Typer::Visitor::TypeJSCreateWithContext(Node* node) {
535 Type* outer = ContextType(node);
536 return Bounds(Type::Context(outer, zone()));
540 Bounds Typer::Visitor::TypeJSCreateBlockContext(Node* node) {
541 Type* outer = ContextType(node);
542 return Bounds(Type::Context(outer, zone()));
546 Bounds Typer::Visitor::TypeJSCreateModuleContext(Node* node) {
547 // TODO(rossberg): this is probably incorrect
548 Type* outer = ContextType(node);
549 return Bounds(Type::Context(outer, zone()));
553 Bounds Typer::Visitor::TypeJSCreateGlobalContext(Node* node) {
554 Type* outer = ContextType(node);
555 return Bounds(Type::Context(outer, zone()));
559 // JS other operators.
561 Bounds Typer::Visitor::TypeJSYield(Node* node) {
562 return Bounds::Unbounded(zone());
566 Bounds Typer::Visitor::TypeJSCallConstruct(Node* node) {
567 return Bounds(Type::None(zone()), Type::Receiver(zone()));
571 Bounds Typer::Visitor::TypeJSCallFunction(Node* node) {
572 Bounds fun = OperandType(node, 0);
573 Type* lower = fun.lower->IsFunction()
574 ? fun.lower->AsFunction()->Result() : Type::None(zone());
575 Type* upper = fun.upper->IsFunction()
576 ? fun.upper->AsFunction()->Result() : Type::Any(zone());
577 return Bounds(lower, upper);
581 Bounds Typer::Visitor::TypeJSCallRuntime(Node* node) {
582 return Bounds::Unbounded(zone());
586 Bounds Typer::Visitor::TypeJSDebugger(Node* node) {
587 return Bounds::Unbounded(zone());
591 // Simplified operators.
593 Bounds Typer::Visitor::TypeBooleanNot(Node* node) {
594 return Bounds(Type::Boolean(zone()));
598 Bounds Typer::Visitor::TypeNumberEqual(Node* node) {
599 return Bounds(Type::Boolean(zone()));
603 Bounds Typer::Visitor::TypeNumberLessThan(Node* node) {
604 return Bounds(Type::Boolean(zone()));
608 Bounds Typer::Visitor::TypeNumberLessThanOrEqual(Node* node) {
609 return Bounds(Type::Boolean(zone()));
613 Bounds Typer::Visitor::TypeNumberAdd(Node* node) {
614 return Bounds(Type::Number(zone()));
618 Bounds Typer::Visitor::TypeNumberSubtract(Node* node) {
619 return Bounds(Type::Number(zone()));
623 Bounds Typer::Visitor::TypeNumberMultiply(Node* node) {
624 return Bounds(Type::Number(zone()));
628 Bounds Typer::Visitor::TypeNumberDivide(Node* node) {
629 return Bounds(Type::Number(zone()));
633 Bounds Typer::Visitor::TypeNumberModulus(Node* node) {
634 return Bounds(Type::Number(zone()));
638 Bounds Typer::Visitor::TypeNumberToInt32(Node* node) {
639 Bounds arg = OperandType(node, 0);
640 Type* s32 = Type::Signed32(zone());
641 Type* lower = arg.lower->Is(s32) ? arg.lower : s32;
642 Type* upper = arg.upper->Is(s32) ? arg.upper : s32;
643 return Bounds(lower, upper);
647 Bounds Typer::Visitor::TypeNumberToUint32(Node* node) {
648 Bounds arg = OperandType(node, 0);
649 Type* u32 = Type::Unsigned32(zone());
650 Type* lower = arg.lower->Is(u32) ? arg.lower : u32;
651 Type* upper = arg.upper->Is(u32) ? arg.upper : u32;
652 return Bounds(lower, upper);
656 Bounds Typer::Visitor::TypeReferenceEqual(Node* node) {
657 return Bounds(Type::Boolean(zone()));
661 Bounds Typer::Visitor::TypeStringEqual(Node* node) {
662 return Bounds(Type::Boolean(zone()));
666 Bounds Typer::Visitor::TypeStringLessThan(Node* node) {
667 return Bounds(Type::Boolean(zone()));
671 Bounds Typer::Visitor::TypeStringLessThanOrEqual(Node* node) {
672 return Bounds(Type::Boolean(zone()));
676 Bounds Typer::Visitor::TypeStringAdd(Node* node) {
677 return Bounds(Type::String(zone()));
681 Bounds Typer::Visitor::TypeChangeTaggedToInt32(Node* node) {
682 // TODO(titzer): type is type of input, representation is Word32.
683 return Bounds(Type::Integral32());
687 Bounds Typer::Visitor::TypeChangeTaggedToUint32(Node* node) {
688 return Bounds(Type::Integral32()); // TODO(titzer): add appropriate rep
692 Bounds Typer::Visitor::TypeChangeTaggedToFloat64(Node* node) {
693 // TODO(titzer): type is type of input, representation is Float64.
694 return Bounds(Type::Number());
698 Bounds Typer::Visitor::TypeChangeInt32ToTagged(Node* node) {
699 // TODO(titzer): type is type of input, representation is Tagged.
700 return Bounds(Type::Integral32());
704 Bounds Typer::Visitor::TypeChangeUint32ToTagged(Node* node) {
705 // TODO(titzer): type is type of input, representation is Tagged.
706 return Bounds(Type::Unsigned32());
710 Bounds Typer::Visitor::TypeChangeFloat64ToTagged(Node* node) {
711 // TODO(titzer): type is type of input, representation is Tagged.
712 return Bounds(Type::Number());
716 Bounds Typer::Visitor::TypeChangeBoolToBit(Node* node) {
717 // TODO(titzer): type is type of input, representation is Bit.
718 return Bounds(Type::Boolean());
722 Bounds Typer::Visitor::TypeChangeBitToBool(Node* node) {
723 // TODO(titzer): type is type of input, representation is Tagged.
724 return Bounds(Type::Boolean());
728 Bounds Typer::Visitor::TypeLoadField(Node* node) {
729 return Bounds(FieldAccessOf(node->op()).type);
733 Bounds Typer::Visitor::TypeLoadElement(Node* node) {
734 return Bounds(ElementAccessOf(node->op()).type);
738 Bounds Typer::Visitor::TypeStoreField(Node* node) {
739 return Bounds(Type::None());
743 Bounds Typer::Visitor::TypeStoreElement(Node* node) {
744 return Bounds(Type::None());
748 // Machine operators.
750 // TODO(rossberg): implement
751 #define DEFINE_METHOD(x) \
752 Bounds Typer::Visitor::Type##x(Node* node) { return Bounds(Type::None()); }
753 MACHINE_OP_LIST(DEFINE_METHOD)
759 Type* Typer::Visitor::TypeConstant(Handle<Object> value) {
760 if (value->IsJSFunction() && JSFunction::cast(*value)->IsBuiltin() &&
761 !context().is_null()) {
762 Handle<Context> native =
763 handle(context().ToHandleChecked()->native_context(), isolate());
764 if (*value == native->math_abs_fun()) {
765 return typer_->number_fun1_; // TODO(rossberg): can't express overloading
766 } else if (*value == native->math_acos_fun()) {
767 return typer_->number_fun1_;
768 } else if (*value == native->math_asin_fun()) {
769 return typer_->number_fun1_;
770 } else if (*value == native->math_atan_fun()) {
771 return typer_->number_fun1_;
772 } else if (*value == native->math_atan2_fun()) {
773 return typer_->number_fun2_;
774 } else if (*value == native->math_ceil_fun()) {
775 return typer_->number_fun1_;
776 } else if (*value == native->math_cos_fun()) {
777 return typer_->number_fun1_;
778 } else if (*value == native->math_exp_fun()) {
779 return typer_->number_fun1_;
780 } else if (*value == native->math_floor_fun()) {
781 return typer_->number_fun1_;
782 } else if (*value == native->math_imul_fun()) {
783 return typer_->imul_fun_;
784 } else if (*value == native->math_log_fun()) {
785 return typer_->number_fun1_;
786 } else if (*value == native->math_pow_fun()) {
787 return typer_->number_fun2_;
788 } else if (*value == native->math_random_fun()) {
789 return typer_->number_fun0_;
790 } else if (*value == native->math_round_fun()) {
791 return typer_->number_fun1_;
792 } else if (*value == native->math_sin_fun()) {
793 return typer_->number_fun1_;
794 } else if (*value == native->math_sqrt_fun()) {
795 return typer_->number_fun1_;
796 } else if (*value == native->math_tan_fun()) {
797 return typer_->number_fun1_;
798 } else if (*value == native->array_buffer_fun()) {
799 return typer_->array_buffer_fun_;
800 } else if (*value == native->int8_array_fun()) {
801 return typer_->int8_array_fun_;
802 } else if (*value == native->int16_array_fun()) {
803 return typer_->int16_array_fun_;
804 } else if (*value == native->int32_array_fun()) {
805 return typer_->int32_array_fun_;
806 } else if (*value == native->uint8_array_fun()) {
807 return typer_->uint8_array_fun_;
808 } else if (*value == native->uint16_array_fun()) {
809 return typer_->uint16_array_fun_;
810 } else if (*value == native->uint32_array_fun()) {
811 return typer_->uint32_array_fun_;
812 } else if (*value == native->float32_array_fun()) {
813 return typer_->float32_array_fun_;
814 } else if (*value == native->float64_array_fun()) {
815 return typer_->float64_array_fun_;
818 return Type::Constant(value, zone());
824 class TyperDecorator : public GraphDecorator {
826 explicit TyperDecorator(Typer* typer) : typer_(typer) {}
827 virtual void Decorate(Node* node) { typer_->Init(node); }
836 void Typer::DecorateGraph(Graph* graph) {
837 graph->AddDecorator(new (zone()) TyperDecorator(this));
842 } // namespace v8::internal::compiler