OLD | NEW |
1 // Copyright 2014 the V8 project authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/compiler/graph-inl.h" | 5 #include "src/compiler/graph-inl.h" |
6 #include "src/compiler/js-operator.h" | 6 #include "src/compiler/js-operator.h" |
7 #include "src/compiler/node.h" | 7 #include "src/compiler/node.h" |
8 #include "src/compiler/node-properties-inl.h" | 8 #include "src/compiler/node-properties-inl.h" |
9 #include "src/compiler/node-properties.h" | 9 #include "src/compiler/node-properties.h" |
10 #include "src/compiler/simplified-operator.h" | 10 #include "src/compiler/simplified-operator.h" |
11 #include "src/compiler/typer.h" | 11 #include "src/compiler/typer.h" |
12 | 12 |
13 namespace v8 { | 13 namespace v8 { |
14 namespace internal { | 14 namespace internal { |
15 namespace compiler { | 15 namespace compiler { |
16 | 16 |
17 Typer::Typer(Zone* zone) : zone_(zone) { | 17 |
| 18 class Typer::Decorator : public GraphDecorator { |
| 19 public: |
| 20 explicit Decorator(Typer* typer) : typer_(typer) {} |
| 21 virtual void Decorate(Node* node); |
| 22 |
| 23 private: |
| 24 Typer* typer_; |
| 25 }; |
| 26 |
| 27 |
| 28 Typer::Typer(Graph* graph, MaybeHandle<Context> context) |
| 29 : graph_(graph), context_(context), decorator_(NULL) { |
| 30 Zone* zone = this->zone(); |
18 Type* number = Type::Number(zone); | 31 Type* number = Type::Number(zone); |
19 Type* signed32 = Type::Signed32(zone); | 32 Type* signed32 = Type::Signed32(zone); |
20 Type* unsigned32 = Type::Unsigned32(zone); | 33 Type* unsigned32 = Type::Unsigned32(zone); |
21 Type* integral32 = Type::Integral32(zone); | 34 Type* integral32 = Type::Integral32(zone); |
22 Type* object = Type::Object(zone); | 35 Type* object = Type::Object(zone); |
23 Type* undefined = Type::Undefined(zone); | 36 Type* undefined = Type::Undefined(zone); |
24 number_fun0_ = Type::Function(number, zone); | 37 number_fun0_ = Type::Function(number, zone); |
25 number_fun1_ = Type::Function(number, number, zone); | 38 number_fun1_ = Type::Function(number, number, zone); |
26 number_fun2_ = Type::Function(number, number, number, zone); | 39 number_fun2_ = Type::Function(number, number, number, zone); |
27 imul_fun_ = Type::Function(signed32, integral32, integral32, zone); | 40 imul_fun_ = Type::Function(signed32, integral32, integral32, zone); |
(...skipping 27 matching lines...) Expand all Loading... |
55 int16_array_fun_ = Type::Function(int16_array, arg1, arg2, arg3, zone); | 68 int16_array_fun_ = Type::Function(int16_array, arg1, arg2, arg3, zone); |
56 int32_array_fun_ = Type::Function(int32_array, arg1, arg2, arg3, zone); | 69 int32_array_fun_ = Type::Function(int32_array, arg1, arg2, arg3, zone); |
57 uint8_array_fun_ = Type::Function(uint8_array, arg1, arg2, arg3, zone); | 70 uint8_array_fun_ = Type::Function(uint8_array, arg1, arg2, arg3, zone); |
58 uint16_array_fun_ = Type::Function(uint16_array, arg1, arg2, arg3, zone); | 71 uint16_array_fun_ = Type::Function(uint16_array, arg1, arg2, arg3, zone); |
59 uint32_array_fun_ = Type::Function(uint32_array, arg1, arg2, arg3, zone); | 72 uint32_array_fun_ = Type::Function(uint32_array, arg1, arg2, arg3, zone); |
60 float32_array_fun_ = Type::Function(float32_array, arg1, arg2, arg3, zone); | 73 float32_array_fun_ = Type::Function(float32_array, arg1, arg2, arg3, zone); |
61 float64_array_fun_ = Type::Function(float64_array, arg1, arg2, arg3, zone); | 74 float64_array_fun_ = Type::Function(float64_array, arg1, arg2, arg3, zone); |
62 } | 75 } |
63 | 76 |
64 | 77 |
| 78 Typer::~Typer() { |
| 79 if (decorator_) graph_->RemoveDecorator(decorator_); |
| 80 } |
| 81 |
| 82 |
65 class Typer::Visitor : public NullNodeVisitor { | 83 class Typer::Visitor : public NullNodeVisitor { |
66 public: | 84 public: |
67 Visitor(Typer* typer, MaybeHandle<Context> context) | 85 explicit Visitor(Typer* typer) : typer_(typer) {} |
68 : typer_(typer), context_(context) {} | |
69 | 86 |
70 Bounds TypeNode(Node* node) { | 87 Bounds TypeNode(Node* node) { |
71 switch (node->opcode()) { | 88 switch (node->opcode()) { |
72 #define DECLARE_CASE(x) case IrOpcode::k##x: return Type##x(node); | 89 #define DECLARE_CASE(x) case IrOpcode::k##x: return Type##x(node); |
| 90 DECLARE_CASE(Start) |
73 VALUE_OP_LIST(DECLARE_CASE) | 91 VALUE_OP_LIST(DECLARE_CASE) |
74 #undef DECLARE_CASE | 92 #undef DECLARE_CASE |
75 | 93 |
76 #define DECLARE_CASE(x) case IrOpcode::k##x: | 94 #define DECLARE_CASE(x) case IrOpcode::k##x: |
77 CONTROL_OP_LIST(DECLARE_CASE) | 95 DECLARE_CASE(End) |
| 96 INNER_CONTROL_OP_LIST(DECLARE_CASE) |
78 #undef DECLARE_CASE | 97 #undef DECLARE_CASE |
79 break; | 98 break; |
80 } | 99 } |
81 return Bounds(Type::None(zone())); | 100 UNREACHABLE(); |
| 101 return Bounds(); |
82 } | 102 } |
83 | 103 |
84 Type* TypeConstant(Handle<Object> value); | 104 Type* TypeConstant(Handle<Object> value); |
85 | 105 |
86 protected: | 106 protected: |
87 #define DECLARE_METHOD(x) inline Bounds Type##x(Node* node); | 107 #define DECLARE_METHOD(x) inline Bounds Type##x(Node* node); |
| 108 DECLARE_METHOD(Start) |
88 VALUE_OP_LIST(DECLARE_METHOD) | 109 VALUE_OP_LIST(DECLARE_METHOD) |
89 #undef DECLARE_METHOD | 110 #undef DECLARE_METHOD |
90 | 111 |
91 Bounds OperandType(Node* node, int i) { | 112 Bounds operand(Node* node, int i) { |
92 return NodeProperties::GetBounds(NodeProperties::GetValueInput(node, i)); | 113 Node* operand_node = NodeProperties::GetValueInput(node, i); |
| 114 return GetBoundsOrNone(operand_node); |
93 } | 115 } |
94 | 116 |
95 Type* ContextType(Node* node) { | 117 Type* context_type(Node* node) { |
96 Bounds result = | 118 Bounds result = GetBoundsOrNone(NodeProperties::GetContextInput(node)); |
97 NodeProperties::GetBounds(NodeProperties::GetContextInput(node)); | |
98 DCHECK(result.upper->Is(Type::Internal())); | 119 DCHECK(result.upper->Is(Type::Internal())); |
99 DCHECK(result.lower->Equals(result.upper)); | 120 DCHECK(result.lower->Equals(result.upper)); |
100 return result.upper; | 121 return result.upper; |
101 } | 122 } |
102 | 123 |
103 Zone* zone() { return typer_->zone(); } | 124 Zone* zone() { return typer_->zone(); } |
104 Isolate* isolate() { return typer_->isolate(); } | 125 Isolate* isolate() { return typer_->isolate(); } |
105 MaybeHandle<Context> context() { return context_; } | 126 Graph* graph() { return typer_->graph(); } |
| 127 MaybeHandle<Context> context() { return typer_->context(); } |
106 | 128 |
107 private: | 129 private: |
108 Typer* typer_; | 130 Typer* typer_; |
109 MaybeHandle<Context> context_; | 131 |
| 132 Bounds GetBoundsOrNone(Node* node) { |
| 133 return NodeProperties::IsTyped(node) |
| 134 ? NodeProperties::GetBounds(node) : Bounds(Type::None(zone())); |
| 135 } |
110 }; | 136 }; |
111 | 137 |
112 | 138 |
113 class Typer::RunVisitor : public Typer::Visitor { | 139 class Typer::RunVisitor : public Typer::Visitor { |
114 public: | 140 public: |
115 RunVisitor(Typer* typer, MaybeHandle<Context> context) | 141 explicit RunVisitor(Typer* typer) |
116 : Visitor(typer, context), | 142 : Visitor(typer), |
117 phis(NodeSet::key_compare(), NodeSet::allocator_type(typer->zone())) {} | 143 phis(NodeSet::key_compare(), NodeSet::allocator_type(typer->zone())) {} |
118 | 144 |
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; | |
125 } | |
126 | |
127 GenericGraphVisit::Control Post(Node* node) { | 145 GenericGraphVisit::Control Post(Node* node) { |
128 Bounds bounds = TypeNode(node); | 146 if (OperatorProperties::HasValueOutput(node->op())) { |
129 if (node->opcode() == IrOpcode::kPhi) { | 147 Bounds bounds = TypeNode(node); |
| 148 NodeProperties::SetBounds(node, bounds); |
130 // Remember phis for least fixpoint iteration. | 149 // Remember phis for least fixpoint iteration. |
131 phis.insert(node); | 150 if (node->opcode() == IrOpcode::kPhi) phis.insert(node); |
132 } else { | |
133 NodeProperties::SetBounds(node, bounds); | |
134 } | 151 } |
135 return GenericGraphVisit::CONTINUE; | 152 return GenericGraphVisit::CONTINUE; |
136 } | 153 } |
137 | 154 |
138 NodeSet phis; | 155 NodeSet phis; |
139 }; | 156 }; |
140 | 157 |
141 | 158 |
142 class Typer::NarrowVisitor : public Typer::Visitor { | 159 class Typer::NarrowVisitor : public Typer::Visitor { |
143 public: | 160 public: |
144 NarrowVisitor(Typer* typer, MaybeHandle<Context> context) | 161 explicit NarrowVisitor(Typer* typer) : Visitor(typer) {} |
145 : Visitor(typer, context) {} | |
146 | 162 |
147 GenericGraphVisit::Control Pre(Node* node) { | 163 GenericGraphVisit::Control Pre(Node* node) { |
148 Bounds previous = NodeProperties::GetBounds(node); | 164 if (OperatorProperties::HasValueOutput(node->op())) { |
149 Bounds bounds = TypeNode(node); | 165 Bounds previous = NodeProperties::GetBounds(node); |
150 NodeProperties::SetBounds(node, Bounds::Both(bounds, previous, zone())); | 166 Bounds bounds = TypeNode(node); |
151 DCHECK(bounds.Narrows(previous)); | 167 NodeProperties::SetBounds(node, Bounds::Both(bounds, previous, zone())); |
152 // Stop when nothing changed (but allow reentry in case it does later). | 168 DCHECK(bounds.Narrows(previous)); |
153 return previous.Narrows(bounds) | 169 // Stop when nothing changed (but allow re-entry in case it does later). |
154 ? GenericGraphVisit::DEFER : GenericGraphVisit::REENTER; | 170 return previous.Narrows(bounds) |
| 171 ? GenericGraphVisit::DEFER : GenericGraphVisit::REENTER; |
| 172 } else { |
| 173 return GenericGraphVisit::SKIP; |
| 174 } |
155 } | 175 } |
156 | 176 |
157 GenericGraphVisit::Control Post(Node* node) { | 177 GenericGraphVisit::Control Post(Node* node) { |
158 return GenericGraphVisit::REENTER; | 178 return GenericGraphVisit::REENTER; |
159 } | 179 } |
160 }; | 180 }; |
161 | 181 |
162 | 182 |
163 class Typer::WidenVisitor : public Typer::Visitor { | 183 class Typer::WidenVisitor : public Typer::Visitor { |
164 public: | 184 public: |
165 WidenVisitor(Typer* typer, MaybeHandle<Context> context) | 185 explicit WidenVisitor(Typer* typer) : Visitor(typer) {} |
166 : Visitor(typer, context) {} | |
167 | 186 |
168 GenericGraphVisit::Control Pre(Node* node) { | 187 GenericGraphVisit::Control Pre(Node* node) { |
169 Bounds previous = NodeProperties::GetBounds(node); | 188 if (OperatorProperties::HasValueOutput(node->op())) { |
170 Bounds bounds = TypeNode(node); | 189 Bounds previous = NodeProperties::GetBounds(node); |
171 DCHECK(previous.lower->Is(bounds.lower)); | 190 Bounds bounds = TypeNode(node); |
172 DCHECK(previous.upper->Is(bounds.upper)); | 191 DCHECK(previous.lower->Is(bounds.lower)); |
173 NodeProperties::SetBounds(node, bounds); // TODO(rossberg): Either? | 192 DCHECK(previous.upper->Is(bounds.upper)); |
174 // Stop when nothing changed (but allow reentry in case it does later). | 193 NodeProperties::SetBounds(node, bounds); // TODO(rossberg): Either? |
175 return bounds.Narrows(previous) | 194 // Stop when nothing changed (but allow re-entry in case it does later). |
176 ? GenericGraphVisit::DEFER : GenericGraphVisit::REENTER; | 195 return bounds.Narrows(previous) |
| 196 ? GenericGraphVisit::DEFER : GenericGraphVisit::REENTER; |
| 197 } else { |
| 198 return GenericGraphVisit::SKIP; |
| 199 } |
177 } | 200 } |
178 | 201 |
179 GenericGraphVisit::Control Post(Node* node) { | 202 GenericGraphVisit::Control Post(Node* node) { |
180 return GenericGraphVisit::REENTER; | 203 return GenericGraphVisit::REENTER; |
181 } | 204 } |
182 }; | 205 }; |
183 | 206 |
184 | 207 |
185 void Typer::Run(Graph* graph, MaybeHandle<Context> context) { | 208 void Typer::Run() { |
186 RunVisitor typing(this, context); | 209 RunVisitor typing(this); |
187 graph->VisitNodeInputsFromEnd(&typing); | 210 graph_->VisitNodeInputsFromEnd(&typing); |
188 // Find least fixpoint. | 211 // Find least fixpoint. |
189 for (NodeSetIter i = typing.phis.begin(); i != typing.phis.end(); ++i) { | 212 WidenVisitor widen(this); |
190 Widen(graph, *i, context); | 213 for (NodeSetIter it = typing.phis.begin(); it != typing.phis.end(); ++it) { |
| 214 graph_->VisitNodeUsesFrom(*it, &widen); |
| 215 } |
| 216 |
| 217 DCHECK(decorator_ == NULL); |
| 218 decorator_ = new (zone()) Decorator(this); |
| 219 graph_->AddDecorator(decorator_); |
| 220 } |
| 221 |
| 222 |
| 223 void Typer::Narrow(Node* start) { |
| 224 NarrowVisitor typing(this); |
| 225 graph_->VisitNodeUsesFrom(start, &typing); |
| 226 } |
| 227 |
| 228 |
| 229 void Typer::Decorator::Decorate(Node* node) { |
| 230 if (OperatorProperties::HasValueOutput(node->op())) { |
| 231 Visitor typing(typer_); |
| 232 Bounds bounds = typing.TypeNode(node); |
| 233 NodeProperties::SetBounds(node, bounds); |
191 } | 234 } |
192 } | 235 } |
193 | 236 |
194 | 237 |
195 void Typer::Narrow(Graph* graph, Node* start, MaybeHandle<Context> context) { | 238 // ----------------------------------------------------------------------------- |
196 NarrowVisitor typing(this, context); | |
197 graph->VisitNodeUsesFrom(start, &typing); | |
198 } | |
199 | 239 |
| 240 // Control operators. |
200 | 241 |
201 void Typer::Widen(Graph* graph, Node* start, MaybeHandle<Context> context) { | 242 Bounds Typer::Visitor::TypeStart(Node* node) { |
202 WidenVisitor typing(this, context); | 243 return Bounds(Type::Internal(zone())); |
203 graph->VisitNodeUsesFrom(start, &typing); | |
204 } | |
205 | |
206 | |
207 void Typer::Init(Node* node) { | |
208 Visitor typing(this, MaybeHandle<Context>()); | |
209 Bounds bounds = typing.TypeNode(node); | |
210 NodeProperties::SetBounds(node, bounds); | |
211 } | 244 } |
212 | 245 |
213 | 246 |
214 // Common operators. | 247 // Common operators. |
| 248 |
215 Bounds Typer::Visitor::TypeParameter(Node* node) { | 249 Bounds Typer::Visitor::TypeParameter(Node* node) { |
216 return Bounds::Unbounded(zone()); | 250 return Bounds::Unbounded(zone()); |
217 } | 251 } |
218 | 252 |
219 | 253 |
220 Bounds Typer::Visitor::TypeInt32Constant(Node* node) { | 254 Bounds Typer::Visitor::TypeInt32Constant(Node* node) { |
221 // TODO(titzer): only call Type::Of() if the type is not already known. | 255 // TODO(titzer): only call Type::Of() if the type is not already known. |
222 return Bounds(Type::Of(ValueOf<int32_t>(node->op()), zone())); | 256 return Bounds(Type::Of(ValueOf<int32_t>(node->op()), zone())); |
223 } | 257 } |
224 | 258 |
(...skipping 22 matching lines...) Expand all Loading... |
247 } | 281 } |
248 | 282 |
249 | 283 |
250 Bounds Typer::Visitor::TypeExternalConstant(Node* node) { | 284 Bounds Typer::Visitor::TypeExternalConstant(Node* node) { |
251 return Bounds(Type::Internal(zone())); | 285 return Bounds(Type::Internal(zone())); |
252 } | 286 } |
253 | 287 |
254 | 288 |
255 Bounds Typer::Visitor::TypePhi(Node* node) { | 289 Bounds Typer::Visitor::TypePhi(Node* node) { |
256 int arity = OperatorProperties::GetValueInputCount(node->op()); | 290 int arity = OperatorProperties::GetValueInputCount(node->op()); |
257 Bounds bounds = OperandType(node, 0); | 291 Bounds bounds = operand(node, 0); |
258 for (int i = 1; i < arity; ++i) { | 292 for (int i = 1; i < arity; ++i) { |
259 bounds = Bounds::Either(bounds, OperandType(node, i), zone()); | 293 bounds = Bounds::Either(bounds, operand(node, i), zone()); |
260 } | 294 } |
261 return bounds; | 295 return bounds; |
262 } | 296 } |
263 | 297 |
264 | 298 |
265 Bounds Typer::Visitor::TypeEffectPhi(Node* node) { | 299 Bounds Typer::Visitor::TypeEffectPhi(Node* node) { |
266 return Bounds(Type::None(zone())); | 300 UNREACHABLE(); |
| 301 return Bounds(); |
267 } | 302 } |
268 | 303 |
269 | 304 |
270 Bounds Typer::Visitor::TypeControlEffect(Node* node) { | 305 Bounds Typer::Visitor::TypeControlEffect(Node* node) { |
271 return Bounds(Type::None(zone())); | 306 UNREACHABLE(); |
| 307 return Bounds(); |
272 } | 308 } |
273 | 309 |
274 | 310 |
275 Bounds Typer::Visitor::TypeValueEffect(Node* node) { | 311 Bounds Typer::Visitor::TypeValueEffect(Node* node) { |
276 return Bounds(Type::None(zone())); | 312 UNREACHABLE(); |
| 313 return Bounds(); |
277 } | 314 } |
278 | 315 |
279 | 316 |
280 Bounds Typer::Visitor::TypeFinish(Node* node) { return OperandType(node, 0); } | 317 Bounds Typer::Visitor::TypeFinish(Node* node) { |
| 318 return operand(node, 0); |
| 319 } |
281 | 320 |
282 | 321 |
283 Bounds Typer::Visitor::TypeFrameState(Node* node) { | 322 Bounds Typer::Visitor::TypeFrameState(Node* node) { |
284 return Bounds(Type::None(zone())); | 323 UNREACHABLE(); |
| 324 return Bounds(); |
285 } | 325 } |
286 | 326 |
287 | 327 |
288 Bounds Typer::Visitor::TypeStateValues(Node* node) { | 328 Bounds Typer::Visitor::TypeStateValues(Node* node) { |
289 return Bounds(Type::None(zone())); | 329 UNREACHABLE(); |
| 330 return Bounds(); |
290 } | 331 } |
291 | 332 |
292 | 333 |
293 Bounds Typer::Visitor::TypeCall(Node* node) { | 334 Bounds Typer::Visitor::TypeCall(Node* node) { |
294 return Bounds::Unbounded(zone()); | 335 return Bounds::Unbounded(zone()); |
295 } | 336 } |
296 | 337 |
297 | 338 |
298 Bounds Typer::Visitor::TypeProjection(Node* node) { | 339 Bounds Typer::Visitor::TypeProjection(Node* node) { |
299 // TODO(titzer): use the output type of the input to determine the bounds. | 340 // TODO(titzer): use the output type of the input to determine the bounds. |
300 return Bounds::Unbounded(zone()); | 341 return Bounds::Unbounded(zone()); |
301 } | 342 } |
302 | 343 |
303 | 344 |
304 // JS comparison operators. | 345 // JS comparison operators. |
305 | 346 |
306 #define DEFINE_METHOD(x) \ | 347 #define DEFINE_METHOD(x) \ |
307 Bounds Typer::Visitor::Type##x(Node* node) { \ | 348 Bounds Typer::Visitor::Type##x(Node* node) { \ |
308 return Bounds(Type::Boolean(zone())); \ | 349 return Bounds(Type::Boolean(zone())); \ |
309 } | 350 } |
310 JS_COMPARE_BINOP_LIST(DEFINE_METHOD) | 351 JS_COMPARE_BINOP_LIST(DEFINE_METHOD) |
311 #undef DEFINE_METHOD | 352 #undef DEFINE_METHOD |
312 | 353 |
313 | 354 |
314 // JS bitwise operators. | 355 // JS bitwise operators. |
315 | 356 |
316 Bounds Typer::Visitor::TypeJSBitwiseOr(Node* node) { | 357 Bounds Typer::Visitor::TypeJSBitwiseOr(Node* node) { |
317 Bounds left = OperandType(node, 0); | 358 Bounds left = operand(node, 0); |
318 Bounds right = OperandType(node, 1); | 359 Bounds right = operand(node, 1); |
319 Type* upper = Type::Union(left.upper, right.upper, zone()); | 360 Type* upper = Type::Union(left.upper, right.upper, zone()); |
320 if (!upper->Is(Type::Signed32())) upper = Type::Signed32(zone()); | 361 if (!upper->Is(Type::Signed32())) upper = Type::Signed32(zone()); |
321 Type* lower = Type::Intersect(Type::SignedSmall(zone()), upper, zone()); | 362 Type* lower = Type::Intersect(Type::SignedSmall(zone()), upper, zone()); |
322 return Bounds(lower, upper); | 363 return Bounds(lower, upper); |
323 } | 364 } |
324 | 365 |
325 | 366 |
326 Bounds Typer::Visitor::TypeJSBitwiseAnd(Node* node) { | 367 Bounds Typer::Visitor::TypeJSBitwiseAnd(Node* node) { |
327 Bounds left = OperandType(node, 0); | 368 Bounds left = operand(node, 0); |
328 Bounds right = OperandType(node, 1); | 369 Bounds right = operand(node, 1); |
329 Type* upper = Type::Union(left.upper, right.upper, zone()); | 370 Type* upper = Type::Union(left.upper, right.upper, zone()); |
330 if (!upper->Is(Type::Signed32())) upper = Type::Signed32(zone()); | 371 if (!upper->Is(Type::Signed32())) upper = Type::Signed32(zone()); |
331 Type* lower = Type::Intersect(Type::SignedSmall(zone()), upper, zone()); | 372 Type* lower = Type::Intersect(Type::SignedSmall(zone()), upper, zone()); |
332 return Bounds(lower, upper); | 373 return Bounds(lower, upper); |
333 } | 374 } |
334 | 375 |
335 | 376 |
336 Bounds Typer::Visitor::TypeJSBitwiseXor(Node* node) { | 377 Bounds Typer::Visitor::TypeJSBitwiseXor(Node* node) { |
337 return Bounds(Type::SignedSmall(zone()), Type::Signed32(zone())); | 378 return Bounds(Type::SignedSmall(zone()), Type::Signed32(zone())); |
338 } | 379 } |
(...skipping 10 matching lines...) Expand all Loading... |
349 | 390 |
350 | 391 |
351 Bounds Typer::Visitor::TypeJSShiftRightLogical(Node* node) { | 392 Bounds Typer::Visitor::TypeJSShiftRightLogical(Node* node) { |
352 return Bounds(Type::UnsignedSmall(zone()), Type::Unsigned32(zone())); | 393 return Bounds(Type::UnsignedSmall(zone()), Type::Unsigned32(zone())); |
353 } | 394 } |
354 | 395 |
355 | 396 |
356 // JS arithmetic operators. | 397 // JS arithmetic operators. |
357 | 398 |
358 Bounds Typer::Visitor::TypeJSAdd(Node* node) { | 399 Bounds Typer::Visitor::TypeJSAdd(Node* node) { |
359 Bounds left = OperandType(node, 0); | 400 Bounds left = operand(node, 0); |
360 Bounds right = OperandType(node, 1); | 401 Bounds right = operand(node, 1); |
361 Type* lower = | 402 Type* lower = |
362 left.lower->Is(Type::None()) || right.lower->Is(Type::None()) ? | 403 left.lower->Is(Type::None()) || right.lower->Is(Type::None()) ? |
363 Type::None(zone()) : | 404 Type::None(zone()) : |
364 left.lower->Is(Type::Number()) && right.lower->Is(Type::Number()) ? | 405 left.lower->Is(Type::Number()) && right.lower->Is(Type::Number()) ? |
365 Type::SignedSmall(zone()) : | 406 Type::SignedSmall(zone()) : |
366 left.lower->Is(Type::String()) || right.lower->Is(Type::String()) ? | 407 left.lower->Is(Type::String()) || right.lower->Is(Type::String()) ? |
367 Type::String(zone()) : Type::None(zone()); | 408 Type::String(zone()) : Type::None(zone()); |
368 Type* upper = | 409 Type* upper = |
369 left.upper->Is(Type::None()) && right.upper->Is(Type::None()) ? | 410 left.upper->Is(Type::None()) && right.upper->Is(Type::None()) ? |
370 Type::None(zone()) : | 411 Type::None(zone()) : |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
424 return Bounds(Type::None(zone()), Type::String(zone())); | 465 return Bounds(Type::None(zone()), Type::String(zone())); |
425 } | 466 } |
426 | 467 |
427 | 468 |
428 Bounds Typer::Visitor::TypeJSToName(Node* node) { | 469 Bounds Typer::Visitor::TypeJSToName(Node* node) { |
429 return Bounds(Type::None(zone()), Type::Name(zone())); | 470 return Bounds(Type::None(zone()), Type::Name(zone())); |
430 } | 471 } |
431 | 472 |
432 | 473 |
433 Bounds Typer::Visitor::TypeJSToObject(Node* node) { | 474 Bounds Typer::Visitor::TypeJSToObject(Node* node) { |
434 return Bounds(Type::None(zone()), Type::Object(zone())); | 475 return Bounds(Type::None(zone()), Type::Receiver(zone())); |
435 } | 476 } |
436 | 477 |
437 | 478 |
438 // JS object operators. | 479 // JS object operators. |
439 | 480 |
440 Bounds Typer::Visitor::TypeJSCreate(Node* node) { | 481 Bounds Typer::Visitor::TypeJSCreate(Node* node) { |
441 return Bounds(Type::None(zone()), Type::Object(zone())); | 482 return Bounds(Type::None(zone()), Type::Object(zone())); |
442 } | 483 } |
443 | 484 |
444 | 485 |
445 Bounds Typer::Visitor::TypeJSLoadProperty(Node* node) { | 486 Bounds Typer::Visitor::TypeJSLoadProperty(Node* node) { |
446 Bounds object = OperandType(node, 0); | 487 Bounds object = operand(node, 0); |
447 Bounds name = OperandType(node, 1); | 488 Bounds name = operand(node, 1); |
448 Bounds result = Bounds::Unbounded(zone()); | 489 Bounds result = Bounds::Unbounded(zone()); |
449 // TODO(rossberg): Use range types and sized array types to filter undefined. | 490 // TODO(rossberg): Use range types and sized array types to filter undefined. |
450 if (object.lower->IsArray() && name.lower->Is(Type::Integral32())) { | 491 if (object.lower->IsArray() && name.lower->Is(Type::Integral32())) { |
451 result.lower = Type::Union( | 492 result.lower = Type::Union( |
452 object.lower->AsArray()->Element(), Type::Undefined(zone()), zone()); | 493 object.lower->AsArray()->Element(), Type::Undefined(zone()), zone()); |
453 } | 494 } |
454 if (object.upper->IsArray() && name.upper->Is(Type::Integral32())) { | 495 if (object.upper->IsArray() && name.upper->Is(Type::Integral32())) { |
455 result.upper = Type::Union( | 496 result.upper = Type::Union( |
456 object.upper->AsArray()->Element(), Type::Undefined(zone()), zone()); | 497 object.upper->AsArray()->Element(), Type::Undefined(zone()), zone()); |
457 } | 498 } |
458 return result; | 499 return result; |
459 } | 500 } |
460 | 501 |
461 | 502 |
462 Bounds Typer::Visitor::TypeJSLoadNamed(Node* node) { | 503 Bounds Typer::Visitor::TypeJSLoadNamed(Node* node) { |
463 return Bounds::Unbounded(zone()); | 504 return Bounds::Unbounded(zone()); |
464 } | 505 } |
465 | 506 |
466 | 507 |
467 Bounds Typer::Visitor::TypeJSStoreProperty(Node* node) { | 508 Bounds Typer::Visitor::TypeJSStoreProperty(Node* node) { |
468 return Bounds(Type::None(zone())); | 509 UNREACHABLE(); |
| 510 return Bounds(); |
469 } | 511 } |
470 | 512 |
471 | 513 |
472 Bounds Typer::Visitor::TypeJSStoreNamed(Node* node) { | 514 Bounds Typer::Visitor::TypeJSStoreNamed(Node* node) { |
473 return Bounds(Type::None(zone())); | 515 UNREACHABLE(); |
| 516 return Bounds(); |
474 } | 517 } |
475 | 518 |
476 | 519 |
477 Bounds Typer::Visitor::TypeJSDeleteProperty(Node* node) { | 520 Bounds Typer::Visitor::TypeJSDeleteProperty(Node* node) { |
478 return Bounds(Type::Boolean(zone())); | 521 return Bounds(Type::Boolean(zone())); |
479 } | 522 } |
480 | 523 |
481 | 524 |
482 Bounds Typer::Visitor::TypeJSHasProperty(Node* node) { | 525 Bounds Typer::Visitor::TypeJSHasProperty(Node* node) { |
483 return Bounds(Type::Boolean(zone())); | 526 return Bounds(Type::Boolean(zone())); |
484 } | 527 } |
485 | 528 |
486 | 529 |
487 Bounds Typer::Visitor::TypeJSInstanceOf(Node* node) { | 530 Bounds Typer::Visitor::TypeJSInstanceOf(Node* node) { |
488 return Bounds(Type::Boolean(zone())); | 531 return Bounds(Type::Boolean(zone())); |
489 } | 532 } |
490 | 533 |
491 | 534 |
492 // JS context operators. | 535 // JS context operators. |
493 | 536 |
494 Bounds Typer::Visitor::TypeJSLoadContext(Node* node) { | 537 Bounds Typer::Visitor::TypeJSLoadContext(Node* node) { |
495 Bounds outer = OperandType(node, 0); | 538 Bounds outer = operand(node, 0); |
496 DCHECK(outer.upper->Is(Type::Internal())); | 539 DCHECK(outer.upper->Maybe(Type::Internal())); |
497 DCHECK(outer.lower->Equals(outer.upper)); | 540 // TODO(rossberg): More precisely, instead of the above assertion, we should |
| 541 // back-propagate the constraint that it has to be a subtype of Internal. |
| 542 |
498 ContextAccess access = OpParameter<ContextAccess>(node); | 543 ContextAccess access = OpParameter<ContextAccess>(node); |
499 Type* context_type = outer.upper; | 544 Type* context_type = outer.upper; |
500 MaybeHandle<Context> context; | 545 MaybeHandle<Context> context; |
501 if (context_type->IsConstant()) { | 546 if (context_type->IsConstant()) { |
502 context = Handle<Context>::cast(context_type->AsConstant()->Value()); | 547 context = Handle<Context>::cast(context_type->AsConstant()->Value()); |
503 } | 548 } |
504 // Walk context chain (as far as known), mirroring dynamic lookup. | 549 // Walk context chain (as far as known), mirroring dynamic lookup. |
505 // Since contexts are mutable, the information is only useful as a lower | 550 // Since contexts are mutable, the information is only useful as a lower |
506 // bound. | 551 // bound. |
507 // TODO(rossberg): Could use scope info to fix upper bounds for constant | 552 // TODO(rossberg): Could use scope info to fix upper bounds for constant |
(...skipping 13 matching lines...) Expand all Loading... |
521 } else { | 566 } else { |
522 Handle<Object> value = | 567 Handle<Object> value = |
523 handle(context.ToHandleChecked()->get(access.index()), isolate()); | 568 handle(context.ToHandleChecked()->get(access.index()), isolate()); |
524 Type* lower = TypeConstant(value); | 569 Type* lower = TypeConstant(value); |
525 return Bounds(lower, Type::Any(zone())); | 570 return Bounds(lower, Type::Any(zone())); |
526 } | 571 } |
527 } | 572 } |
528 | 573 |
529 | 574 |
530 Bounds Typer::Visitor::TypeJSStoreContext(Node* node) { | 575 Bounds Typer::Visitor::TypeJSStoreContext(Node* node) { |
531 return Bounds(Type::None(zone())); | 576 UNREACHABLE(); |
| 577 return Bounds(); |
532 } | 578 } |
533 | 579 |
534 | 580 |
535 Bounds Typer::Visitor::TypeJSCreateFunctionContext(Node* node) { | 581 Bounds Typer::Visitor::TypeJSCreateFunctionContext(Node* node) { |
536 Type* outer = ContextType(node); | 582 Type* outer = context_type(node); |
537 return Bounds(Type::Context(outer, zone())); | 583 return Bounds(Type::Context(outer, zone())); |
538 } | 584 } |
539 | 585 |
540 | 586 |
541 Bounds Typer::Visitor::TypeJSCreateCatchContext(Node* node) { | 587 Bounds Typer::Visitor::TypeJSCreateCatchContext(Node* node) { |
542 Type* outer = ContextType(node); | 588 Type* outer = context_type(node); |
543 return Bounds(Type::Context(outer, zone())); | 589 return Bounds(Type::Context(outer, zone())); |
544 } | 590 } |
545 | 591 |
546 | 592 |
547 Bounds Typer::Visitor::TypeJSCreateWithContext(Node* node) { | 593 Bounds Typer::Visitor::TypeJSCreateWithContext(Node* node) { |
548 Type* outer = ContextType(node); | 594 Type* outer = context_type(node); |
549 return Bounds(Type::Context(outer, zone())); | 595 return Bounds(Type::Context(outer, zone())); |
550 } | 596 } |
551 | 597 |
552 | 598 |
553 Bounds Typer::Visitor::TypeJSCreateBlockContext(Node* node) { | 599 Bounds Typer::Visitor::TypeJSCreateBlockContext(Node* node) { |
554 Type* outer = ContextType(node); | 600 Type* outer = context_type(node); |
555 return Bounds(Type::Context(outer, zone())); | 601 return Bounds(Type::Context(outer, zone())); |
556 } | 602 } |
557 | 603 |
558 | 604 |
559 Bounds Typer::Visitor::TypeJSCreateModuleContext(Node* node) { | 605 Bounds Typer::Visitor::TypeJSCreateModuleContext(Node* node) { |
560 // TODO(rossberg): this is probably incorrect | 606 // TODO(rossberg): this is probably incorrect |
561 Type* outer = ContextType(node); | 607 Type* outer = context_type(node); |
562 return Bounds(Type::Context(outer, zone())); | 608 return Bounds(Type::Context(outer, zone())); |
563 } | 609 } |
564 | 610 |
565 | 611 |
566 Bounds Typer::Visitor::TypeJSCreateGlobalContext(Node* node) { | 612 Bounds Typer::Visitor::TypeJSCreateGlobalContext(Node* node) { |
567 Type* outer = ContextType(node); | 613 Type* outer = context_type(node); |
568 return Bounds(Type::Context(outer, zone())); | 614 return Bounds(Type::Context(outer, zone())); |
569 } | 615 } |
570 | 616 |
571 | 617 |
572 // JS other operators. | 618 // JS other operators. |
573 | 619 |
574 Bounds Typer::Visitor::TypeJSYield(Node* node) { | 620 Bounds Typer::Visitor::TypeJSYield(Node* node) { |
575 return Bounds::Unbounded(zone()); | 621 return Bounds::Unbounded(zone()); |
576 } | 622 } |
577 | 623 |
578 | 624 |
579 Bounds Typer::Visitor::TypeJSCallConstruct(Node* node) { | 625 Bounds Typer::Visitor::TypeJSCallConstruct(Node* node) { |
580 return Bounds(Type::None(zone()), Type::Receiver(zone())); | 626 return Bounds(Type::None(zone()), Type::Receiver(zone())); |
581 } | 627 } |
582 | 628 |
583 | 629 |
584 Bounds Typer::Visitor::TypeJSCallFunction(Node* node) { | 630 Bounds Typer::Visitor::TypeJSCallFunction(Node* node) { |
585 Bounds fun = OperandType(node, 0); | 631 Bounds fun = operand(node, 0); |
586 Type* lower = fun.lower->IsFunction() | 632 Type* lower = fun.lower->IsFunction() |
587 ? fun.lower->AsFunction()->Result() : Type::None(zone()); | 633 ? fun.lower->AsFunction()->Result() : Type::None(zone()); |
588 Type* upper = fun.upper->IsFunction() | 634 Type* upper = fun.upper->IsFunction() |
589 ? fun.upper->AsFunction()->Result() : Type::Any(zone()); | 635 ? fun.upper->AsFunction()->Result() : Type::Any(zone()); |
590 return Bounds(lower, upper); | 636 return Bounds(lower, upper); |
591 } | 637 } |
592 | 638 |
593 | 639 |
594 Bounds Typer::Visitor::TypeJSCallRuntime(Node* node) { | 640 Bounds Typer::Visitor::TypeJSCallRuntime(Node* node) { |
595 return Bounds::Unbounded(zone()); | 641 return Bounds::Unbounded(zone()); |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
642 return Bounds(Type::Number(zone())); | 688 return Bounds(Type::Number(zone())); |
643 } | 689 } |
644 | 690 |
645 | 691 |
646 Bounds Typer::Visitor::TypeNumberModulus(Node* node) { | 692 Bounds Typer::Visitor::TypeNumberModulus(Node* node) { |
647 return Bounds(Type::Number(zone())); | 693 return Bounds(Type::Number(zone())); |
648 } | 694 } |
649 | 695 |
650 | 696 |
651 Bounds Typer::Visitor::TypeNumberToInt32(Node* node) { | 697 Bounds Typer::Visitor::TypeNumberToInt32(Node* node) { |
652 Bounds arg = OperandType(node, 0); | 698 Bounds arg = operand(node, 0); |
653 Type* s32 = Type::Signed32(zone()); | 699 Type* s32 = Type::Signed32(zone()); |
654 Type* lower = arg.lower->Is(s32) ? arg.lower : s32; | 700 Type* lower = arg.lower->Is(s32) ? arg.lower : s32; |
655 Type* upper = arg.upper->Is(s32) ? arg.upper : s32; | 701 Type* upper = arg.upper->Is(s32) ? arg.upper : s32; |
656 return Bounds(lower, upper); | 702 return Bounds(lower, upper); |
657 } | 703 } |
658 | 704 |
659 | 705 |
660 Bounds Typer::Visitor::TypeNumberToUint32(Node* node) { | 706 Bounds Typer::Visitor::TypeNumberToUint32(Node* node) { |
661 Bounds arg = OperandType(node, 0); | 707 Bounds arg = operand(node, 0); |
662 Type* u32 = Type::Unsigned32(zone()); | 708 Type* u32 = Type::Unsigned32(zone()); |
663 Type* lower = arg.lower->Is(u32) ? arg.lower : u32; | 709 Type* lower = arg.lower->Is(u32) ? arg.lower : u32; |
664 Type* upper = arg.upper->Is(u32) ? arg.upper : u32; | 710 Type* upper = arg.upper->Is(u32) ? arg.upper : u32; |
665 return Bounds(lower, upper); | 711 return Bounds(lower, upper); |
666 } | 712 } |
667 | 713 |
668 | 714 |
669 Bounds Typer::Visitor::TypeReferenceEqual(Node* node) { | 715 Bounds Typer::Visitor::TypeReferenceEqual(Node* node) { |
670 return Bounds(Type::Boolean(zone())); | 716 return Bounds(Type::Boolean(zone())); |
671 } | 717 } |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
742 return Bounds(FieldAccessOf(node->op()).type); | 788 return Bounds(FieldAccessOf(node->op()).type); |
743 } | 789 } |
744 | 790 |
745 | 791 |
746 Bounds Typer::Visitor::TypeLoadElement(Node* node) { | 792 Bounds Typer::Visitor::TypeLoadElement(Node* node) { |
747 return Bounds(ElementAccessOf(node->op()).type); | 793 return Bounds(ElementAccessOf(node->op()).type); |
748 } | 794 } |
749 | 795 |
750 | 796 |
751 Bounds Typer::Visitor::TypeStoreField(Node* node) { | 797 Bounds Typer::Visitor::TypeStoreField(Node* node) { |
752 return Bounds(Type::None()); | 798 UNREACHABLE(); |
| 799 return Bounds(); |
753 } | 800 } |
754 | 801 |
755 | 802 |
756 Bounds Typer::Visitor::TypeStoreElement(Node* node) { | 803 Bounds Typer::Visitor::TypeStoreElement(Node* node) { |
757 return Bounds(Type::None()); | 804 UNREACHABLE(); |
| 805 return Bounds(); |
758 } | 806 } |
759 | 807 |
760 | 808 |
761 // Machine operators. | 809 // Machine operators. |
762 | 810 |
763 // TODO(rossberg): implement | 811 // TODO(rossberg): implement |
764 #define DEFINE_METHOD(x) \ | 812 #define DEFINE_METHOD(x) \ |
765 Bounds Typer::Visitor::Type##x(Node* node) { return Bounds(Type::None()); } | 813 Bounds Typer::Visitor::Type##x(Node* node) { return Bounds(Type::None()); } |
766 MACHINE_OP_LIST(DEFINE_METHOD) | 814 MACHINE_OP_LIST(DEFINE_METHOD) |
767 #undef DEFINE_METHOD | 815 #undef DEFINE_METHOD |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
824 return typer_->uint32_array_fun_; | 872 return typer_->uint32_array_fun_; |
825 } else if (*value == native->float32_array_fun()) { | 873 } else if (*value == native->float32_array_fun()) { |
826 return typer_->float32_array_fun_; | 874 return typer_->float32_array_fun_; |
827 } else if (*value == native->float64_array_fun()) { | 875 } else if (*value == native->float64_array_fun()) { |
828 return typer_->float64_array_fun_; | 876 return typer_->float64_array_fun_; |
829 } | 877 } |
830 } | 878 } |
831 return Type::Constant(value, zone()); | 879 return Type::Constant(value, zone()); |
832 } | 880 } |
833 | 881 |
834 | |
835 namespace { | |
836 | |
837 class TyperDecorator : public GraphDecorator { | |
838 public: | |
839 explicit TyperDecorator(Typer* typer) : typer_(typer) {} | |
840 virtual void Decorate(Node* node) { typer_->Init(node); } | |
841 | |
842 private: | |
843 Typer* typer_; | |
844 }; | |
845 | |
846 } | |
847 | |
848 | |
849 void Typer::DecorateGraph(Graph* graph) { | |
850 graph->AddDecorator(new (zone()) TyperDecorator(this)); | |
851 } | |
852 | |
853 } | 882 } |
854 } | 883 } |
855 } // namespace v8::internal::compiler | 884 } // namespace v8::internal::compiler |
OLD | NEW |