OLD | NEW |
| (Empty) |
1 // Copyright 2013 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/typing.h" | |
6 | |
7 #include "src/frames.h" | |
8 #include "src/frames-inl.h" | |
9 #include "src/ostreams.h" | |
10 #include "src/parser.h" // for CompileTimeValue; TODO(rossberg): should move | |
11 #include "src/scopes.h" | |
12 #include "src/splay-tree-inl.h" | |
13 | |
14 namespace v8 { | |
15 namespace internal { | |
16 | |
17 | |
18 AstTyper::AstTyper(Isolate* isolate, Zone* zone, Handle<JSFunction> closure, | |
19 Scope* scope, BailoutId osr_ast_id, FunctionLiteral* root) | |
20 : isolate_(isolate), | |
21 zone_(zone), | |
22 closure_(closure), | |
23 scope_(scope), | |
24 osr_ast_id_(osr_ast_id), | |
25 root_(root), | |
26 oracle_(isolate, zone, handle(closure->shared()->code()), | |
27 handle(closure->shared()->feedback_vector()), | |
28 handle(closure->context()->native_context())), | |
29 store_(zone) { | |
30 InitializeAstVisitor(isolate); | |
31 } | |
32 | |
33 | |
34 #ifdef OBJECT_PRINT | |
35 static void PrintObserved(Variable* var, Object* value, Type* type) { | |
36 OFStream os(stdout); | |
37 os << " observed " << (var->IsParameter() ? "param" : "local") << " "; | |
38 var->name()->Print(os); | |
39 os << " : " << Brief(value) << " -> "; | |
40 type->PrintTo(os); | |
41 os << std::endl; | |
42 } | |
43 #endif // OBJECT_PRINT | |
44 | |
45 | |
46 Effect AstTyper::ObservedOnStack(Object* value) { | |
47 Type* lower = Type::NowOf(value, zone()); | |
48 return Effect(Bounds(lower, Type::Any(zone()))); | |
49 } | |
50 | |
51 | |
52 void AstTyper::ObserveTypesAtOsrEntry(IterationStatement* stmt) { | |
53 if (stmt->OsrEntryId() != osr_ast_id_) return; | |
54 | |
55 DisallowHeapAllocation no_gc; | |
56 JavaScriptFrameIterator it(isolate_); | |
57 JavaScriptFrame* frame = it.frame(); | |
58 | |
59 // Assert that the frame on the stack belongs to the function we want to OSR. | |
60 DCHECK_EQ(*closure_, frame->function()); | |
61 | |
62 int params = scope_->num_parameters(); | |
63 int locals = scope_->StackLocalCount(); | |
64 | |
65 // Use sequential composition to achieve desired narrowing. | |
66 // The receiver is a parameter with index -1. | |
67 store_.Seq(parameter_index(-1), ObservedOnStack(frame->receiver())); | |
68 for (int i = 0; i < params; i++) { | |
69 store_.Seq(parameter_index(i), ObservedOnStack(frame->GetParameter(i))); | |
70 } | |
71 | |
72 for (int i = 0; i < locals; i++) { | |
73 store_.Seq(stack_local_index(i), ObservedOnStack(frame->GetExpression(i))); | |
74 } | |
75 | |
76 #ifdef OBJECT_PRINT | |
77 if (FLAG_trace_osr && FLAG_print_scopes) { | |
78 PrintObserved(scope_->receiver(), frame->receiver(), | |
79 store_.LookupBounds(parameter_index(-1)).lower); | |
80 | |
81 for (int i = 0; i < params; i++) { | |
82 PrintObserved(scope_->parameter(i), frame->GetParameter(i), | |
83 store_.LookupBounds(parameter_index(i)).lower); | |
84 } | |
85 | |
86 ZoneList<Variable*> local_vars(locals, zone()); | |
87 ZoneList<Variable*> context_vars(scope_->ContextLocalCount(), zone()); | |
88 ZoneList<Variable*> global_vars(scope_->ContextGlobalCount(), zone()); | |
89 scope_->CollectStackAndContextLocals(&local_vars, &context_vars, | |
90 &global_vars); | |
91 for (int i = 0; i < locals; i++) { | |
92 PrintObserved(local_vars.at(i), | |
93 frame->GetExpression(i), | |
94 store_.LookupBounds(stack_local_index(i)).lower); | |
95 } | |
96 } | |
97 #endif // OBJECT_PRINT | |
98 } | |
99 | |
100 | |
101 #define RECURSE(call) \ | |
102 do { \ | |
103 DCHECK(!HasStackOverflow()); \ | |
104 call; \ | |
105 if (HasStackOverflow()) return; \ | |
106 } while (false) | |
107 | |
108 | |
109 void AstTyper::Run() { | |
110 RECURSE(VisitDeclarations(scope_->declarations())); | |
111 RECURSE(VisitStatements(root_->body())); | |
112 } | |
113 | |
114 | |
115 void AstTyper::VisitStatements(ZoneList<Statement*>* stmts) { | |
116 for (int i = 0; i < stmts->length(); ++i) { | |
117 Statement* stmt = stmts->at(i); | |
118 RECURSE(Visit(stmt)); | |
119 if (stmt->IsJump()) break; | |
120 } | |
121 } | |
122 | |
123 | |
124 void AstTyper::VisitBlock(Block* stmt) { | |
125 RECURSE(VisitStatements(stmt->statements())); | |
126 if (stmt->labels() != NULL) { | |
127 store_.Forget(); // Control may transfer here via 'break l'. | |
128 } | |
129 } | |
130 | |
131 | |
132 void AstTyper::VisitExpressionStatement(ExpressionStatement* stmt) { | |
133 RECURSE(Visit(stmt->expression())); | |
134 } | |
135 | |
136 | |
137 void AstTyper::VisitEmptyStatement(EmptyStatement* stmt) { | |
138 } | |
139 | |
140 | |
141 void AstTyper::VisitSloppyBlockFunctionStatement( | |
142 SloppyBlockFunctionStatement* stmt) { | |
143 Visit(stmt->statement()); | |
144 } | |
145 | |
146 | |
147 void AstTyper::VisitIfStatement(IfStatement* stmt) { | |
148 // Collect type feedback. | |
149 if (!stmt->condition()->ToBooleanIsTrue() && | |
150 !stmt->condition()->ToBooleanIsFalse()) { | |
151 stmt->condition()->RecordToBooleanTypeFeedback(oracle()); | |
152 } | |
153 | |
154 RECURSE(Visit(stmt->condition())); | |
155 Effects then_effects = EnterEffects(); | |
156 RECURSE(Visit(stmt->then_statement())); | |
157 ExitEffects(); | |
158 Effects else_effects = EnterEffects(); | |
159 RECURSE(Visit(stmt->else_statement())); | |
160 ExitEffects(); | |
161 then_effects.Alt(else_effects); | |
162 store_.Seq(then_effects); | |
163 } | |
164 | |
165 | |
166 void AstTyper::VisitContinueStatement(ContinueStatement* stmt) { | |
167 // TODO(rossberg): is it worth having a non-termination effect? | |
168 } | |
169 | |
170 | |
171 void AstTyper::VisitBreakStatement(BreakStatement* stmt) { | |
172 // TODO(rossberg): is it worth having a non-termination effect? | |
173 } | |
174 | |
175 | |
176 void AstTyper::VisitReturnStatement(ReturnStatement* stmt) { | |
177 // Collect type feedback. | |
178 // TODO(rossberg): we only need this for inlining into test contexts... | |
179 stmt->expression()->RecordToBooleanTypeFeedback(oracle()); | |
180 | |
181 RECURSE(Visit(stmt->expression())); | |
182 // TODO(rossberg): is it worth having a non-termination effect? | |
183 } | |
184 | |
185 | |
186 void AstTyper::VisitWithStatement(WithStatement* stmt) { | |
187 RECURSE(stmt->expression()); | |
188 RECURSE(stmt->statement()); | |
189 } | |
190 | |
191 | |
192 void AstTyper::VisitSwitchStatement(SwitchStatement* stmt) { | |
193 RECURSE(Visit(stmt->tag())); | |
194 | |
195 ZoneList<CaseClause*>* clauses = stmt->cases(); | |
196 Effects local_effects(zone()); | |
197 bool complex_effects = false; // True for label effects or fall-through. | |
198 | |
199 for (int i = 0; i < clauses->length(); ++i) { | |
200 CaseClause* clause = clauses->at(i); | |
201 | |
202 Effects clause_effects = EnterEffects(); | |
203 | |
204 if (!clause->is_default()) { | |
205 Expression* label = clause->label(); | |
206 // Collect type feedback. | |
207 Type* tag_type; | |
208 Type* label_type; | |
209 Type* combined_type; | |
210 oracle()->CompareType(clause->CompareId(), | |
211 &tag_type, &label_type, &combined_type); | |
212 NarrowLowerType(stmt->tag(), tag_type); | |
213 NarrowLowerType(label, label_type); | |
214 clause->set_compare_type(combined_type); | |
215 | |
216 RECURSE(Visit(label)); | |
217 if (!clause_effects.IsEmpty()) complex_effects = true; | |
218 } | |
219 | |
220 ZoneList<Statement*>* stmts = clause->statements(); | |
221 RECURSE(VisitStatements(stmts)); | |
222 ExitEffects(); | |
223 if (stmts->is_empty() || stmts->last()->IsJump()) { | |
224 local_effects.Alt(clause_effects); | |
225 } else { | |
226 complex_effects = true; | |
227 } | |
228 } | |
229 | |
230 if (complex_effects) { | |
231 store_.Forget(); // Reached this in unknown state. | |
232 } else { | |
233 store_.Seq(local_effects); | |
234 } | |
235 } | |
236 | |
237 | |
238 void AstTyper::VisitCaseClause(CaseClause* clause) { | |
239 UNREACHABLE(); | |
240 } | |
241 | |
242 | |
243 void AstTyper::VisitDoWhileStatement(DoWhileStatement* stmt) { | |
244 // Collect type feedback. | |
245 if (!stmt->cond()->ToBooleanIsTrue()) { | |
246 stmt->cond()->RecordToBooleanTypeFeedback(oracle()); | |
247 } | |
248 | |
249 // TODO(rossberg): refine the unconditional Forget (here and elsewhere) by | |
250 // computing the set of variables assigned in only some of the origins of the | |
251 // control transfer (such as the loop body here). | |
252 store_.Forget(); // Control may transfer here via looping or 'continue'. | |
253 ObserveTypesAtOsrEntry(stmt); | |
254 RECURSE(Visit(stmt->body())); | |
255 RECURSE(Visit(stmt->cond())); | |
256 store_.Forget(); // Control may transfer here via 'break'. | |
257 } | |
258 | |
259 | |
260 void AstTyper::VisitWhileStatement(WhileStatement* stmt) { | |
261 // Collect type feedback. | |
262 if (!stmt->cond()->ToBooleanIsTrue()) { | |
263 stmt->cond()->RecordToBooleanTypeFeedback(oracle()); | |
264 } | |
265 | |
266 store_.Forget(); // Control may transfer here via looping or 'continue'. | |
267 RECURSE(Visit(stmt->cond())); | |
268 ObserveTypesAtOsrEntry(stmt); | |
269 RECURSE(Visit(stmt->body())); | |
270 store_.Forget(); // Control may transfer here via termination or 'break'. | |
271 } | |
272 | |
273 | |
274 void AstTyper::VisitForStatement(ForStatement* stmt) { | |
275 if (stmt->init() != NULL) { | |
276 RECURSE(Visit(stmt->init())); | |
277 } | |
278 store_.Forget(); // Control may transfer here via looping. | |
279 if (stmt->cond() != NULL) { | |
280 // Collect type feedback. | |
281 stmt->cond()->RecordToBooleanTypeFeedback(oracle()); | |
282 | |
283 RECURSE(Visit(stmt->cond())); | |
284 } | |
285 ObserveTypesAtOsrEntry(stmt); | |
286 RECURSE(Visit(stmt->body())); | |
287 if (stmt->next() != NULL) { | |
288 store_.Forget(); // Control may transfer here via 'continue'. | |
289 RECURSE(Visit(stmt->next())); | |
290 } | |
291 store_.Forget(); // Control may transfer here via termination or 'break'. | |
292 } | |
293 | |
294 | |
295 void AstTyper::VisitForInStatement(ForInStatement* stmt) { | |
296 // Collect type feedback. | |
297 stmt->set_for_in_type(static_cast<ForInStatement::ForInType>( | |
298 oracle()->ForInType(stmt->ForInFeedbackSlot()))); | |
299 | |
300 RECURSE(Visit(stmt->enumerable())); | |
301 store_.Forget(); // Control may transfer here via looping or 'continue'. | |
302 ObserveTypesAtOsrEntry(stmt); | |
303 RECURSE(Visit(stmt->body())); | |
304 store_.Forget(); // Control may transfer here via 'break'. | |
305 } | |
306 | |
307 | |
308 void AstTyper::VisitForOfStatement(ForOfStatement* stmt) { | |
309 RECURSE(Visit(stmt->iterable())); | |
310 store_.Forget(); // Control may transfer here via looping or 'continue'. | |
311 RECURSE(Visit(stmt->body())); | |
312 store_.Forget(); // Control may transfer here via 'break'. | |
313 } | |
314 | |
315 | |
316 void AstTyper::VisitTryCatchStatement(TryCatchStatement* stmt) { | |
317 Effects try_effects = EnterEffects(); | |
318 RECURSE(Visit(stmt->try_block())); | |
319 ExitEffects(); | |
320 Effects catch_effects = EnterEffects(); | |
321 store_.Forget(); // Control may transfer here via 'throw'. | |
322 RECURSE(Visit(stmt->catch_block())); | |
323 ExitEffects(); | |
324 try_effects.Alt(catch_effects); | |
325 store_.Seq(try_effects); | |
326 // At this point, only variables that were reassigned in the catch block are | |
327 // still remembered. | |
328 } | |
329 | |
330 | |
331 void AstTyper::VisitTryFinallyStatement(TryFinallyStatement* stmt) { | |
332 RECURSE(Visit(stmt->try_block())); | |
333 store_.Forget(); // Control may transfer here via 'throw'. | |
334 RECURSE(Visit(stmt->finally_block())); | |
335 } | |
336 | |
337 | |
338 void AstTyper::VisitDebuggerStatement(DebuggerStatement* stmt) { | |
339 store_.Forget(); // May do whatever. | |
340 } | |
341 | |
342 | |
343 void AstTyper::VisitFunctionLiteral(FunctionLiteral* expr) {} | |
344 | |
345 | |
346 void AstTyper::VisitClassLiteral(ClassLiteral* expr) {} | |
347 | |
348 | |
349 void AstTyper::VisitNativeFunctionLiteral(NativeFunctionLiteral* expr) { | |
350 } | |
351 | |
352 | |
353 void AstTyper::VisitConditional(Conditional* expr) { | |
354 // Collect type feedback. | |
355 expr->condition()->RecordToBooleanTypeFeedback(oracle()); | |
356 | |
357 RECURSE(Visit(expr->condition())); | |
358 Effects then_effects = EnterEffects(); | |
359 RECURSE(Visit(expr->then_expression())); | |
360 ExitEffects(); | |
361 Effects else_effects = EnterEffects(); | |
362 RECURSE(Visit(expr->else_expression())); | |
363 ExitEffects(); | |
364 then_effects.Alt(else_effects); | |
365 store_.Seq(then_effects); | |
366 | |
367 NarrowType(expr, Bounds::Either( | |
368 expr->then_expression()->bounds(), | |
369 expr->else_expression()->bounds(), zone())); | |
370 } | |
371 | |
372 | |
373 void AstTyper::VisitVariableProxy(VariableProxy* expr) { | |
374 Variable* var = expr->var(); | |
375 if (var->IsStackAllocated()) { | |
376 NarrowType(expr, store_.LookupBounds(variable_index(var))); | |
377 } | |
378 } | |
379 | |
380 | |
381 void AstTyper::VisitLiteral(Literal* expr) { | |
382 Type* type = Type::Constant(expr->value(), zone()); | |
383 NarrowType(expr, Bounds(type)); | |
384 } | |
385 | |
386 | |
387 void AstTyper::VisitRegExpLiteral(RegExpLiteral* expr) { | |
388 // TODO(rossberg): Reintroduce RegExp type. | |
389 NarrowType(expr, Bounds(Type::Object(zone()))); | |
390 } | |
391 | |
392 | |
393 void AstTyper::VisitObjectLiteral(ObjectLiteral* expr) { | |
394 ZoneList<ObjectLiteral::Property*>* properties = expr->properties(); | |
395 for (int i = 0; i < properties->length(); ++i) { | |
396 ObjectLiteral::Property* prop = properties->at(i); | |
397 | |
398 // Collect type feedback. | |
399 if ((prop->kind() == ObjectLiteral::Property::MATERIALIZED_LITERAL && | |
400 !CompileTimeValue::IsCompileTimeValue(prop->value())) || | |
401 prop->kind() == ObjectLiteral::Property::COMPUTED) { | |
402 if (!prop->is_computed_name() && | |
403 prop->key()->AsLiteral()->value()->IsInternalizedString() && | |
404 prop->emit_store()) { | |
405 // Record type feed back for the property. | |
406 TypeFeedbackId id = prop->key()->AsLiteral()->LiteralFeedbackId(); | |
407 FeedbackVectorSlot slot = prop->GetSlot(); | |
408 SmallMapList maps; | |
409 if (FLAG_vector_stores) { | |
410 oracle()->CollectReceiverTypes(slot, &maps); | |
411 } else { | |
412 oracle()->CollectReceiverTypes(id, &maps); | |
413 } | |
414 prop->set_receiver_type(maps.length() == 1 ? maps.at(0) | |
415 : Handle<Map>::null()); | |
416 } | |
417 } | |
418 | |
419 RECURSE(Visit(prop->value())); | |
420 } | |
421 | |
422 NarrowType(expr, Bounds(Type::Object(zone()))); | |
423 } | |
424 | |
425 | |
426 void AstTyper::VisitArrayLiteral(ArrayLiteral* expr) { | |
427 ZoneList<Expression*>* values = expr->values(); | |
428 for (int i = 0; i < values->length(); ++i) { | |
429 Expression* value = values->at(i); | |
430 RECURSE(Visit(value)); | |
431 } | |
432 | |
433 NarrowType(expr, Bounds(Type::Object(zone()))); | |
434 } | |
435 | |
436 | |
437 void AstTyper::VisitAssignment(Assignment* expr) { | |
438 // Collect type feedback. | |
439 Property* prop = expr->target()->AsProperty(); | |
440 if (prop != NULL) { | |
441 TypeFeedbackId id = expr->AssignmentFeedbackId(); | |
442 FeedbackVectorSlot slot = expr->AssignmentSlot(); | |
443 expr->set_is_uninitialized(FLAG_vector_stores | |
444 ? oracle()->StoreIsUninitialized(slot) | |
445 : oracle()->StoreIsUninitialized(id)); | |
446 if (!expr->IsUninitialized()) { | |
447 SmallMapList* receiver_types = expr->GetReceiverTypes(); | |
448 if (prop->key()->IsPropertyName()) { | |
449 Literal* lit_key = prop->key()->AsLiteral(); | |
450 DCHECK(lit_key != NULL && lit_key->value()->IsString()); | |
451 Handle<String> name = Handle<String>::cast(lit_key->value()); | |
452 if (FLAG_vector_stores) { | |
453 oracle()->AssignmentReceiverTypes(slot, name, receiver_types); | |
454 } else { | |
455 oracle()->AssignmentReceiverTypes(id, name, receiver_types); | |
456 } | |
457 } else { | |
458 KeyedAccessStoreMode store_mode; | |
459 IcCheckType key_type; | |
460 if (FLAG_vector_stores) { | |
461 oracle()->KeyedAssignmentReceiverTypes(slot, receiver_types, | |
462 &store_mode, &key_type); | |
463 } else { | |
464 oracle()->KeyedAssignmentReceiverTypes(id, receiver_types, | |
465 &store_mode, &key_type); | |
466 } | |
467 expr->set_store_mode(store_mode); | |
468 expr->set_key_type(key_type); | |
469 } | |
470 } | |
471 } | |
472 | |
473 Expression* rhs = | |
474 expr->is_compound() ? expr->binary_operation() : expr->value(); | |
475 RECURSE(Visit(expr->target())); | |
476 RECURSE(Visit(rhs)); | |
477 NarrowType(expr, rhs->bounds()); | |
478 | |
479 VariableProxy* proxy = expr->target()->AsVariableProxy(); | |
480 if (proxy != NULL && proxy->var()->IsStackAllocated()) { | |
481 store_.Seq(variable_index(proxy->var()), Effect(expr->bounds())); | |
482 } | |
483 } | |
484 | |
485 | |
486 void AstTyper::VisitYield(Yield* expr) { | |
487 RECURSE(Visit(expr->generator_object())); | |
488 RECURSE(Visit(expr->expression())); | |
489 | |
490 // We don't know anything about the result type. | |
491 } | |
492 | |
493 | |
494 void AstTyper::VisitThrow(Throw* expr) { | |
495 RECURSE(Visit(expr->exception())); | |
496 // TODO(rossberg): is it worth having a non-termination effect? | |
497 | |
498 NarrowType(expr, Bounds(Type::None(zone()))); | |
499 } | |
500 | |
501 | |
502 void AstTyper::VisitProperty(Property* expr) { | |
503 // Collect type feedback. | |
504 FeedbackVectorSlot slot = expr->PropertyFeedbackSlot(); | |
505 expr->set_inline_cache_state(oracle()->LoadInlineCacheState(slot)); | |
506 | |
507 if (!expr->IsUninitialized()) { | |
508 if (expr->key()->IsPropertyName()) { | |
509 Literal* lit_key = expr->key()->AsLiteral(); | |
510 DCHECK(lit_key != NULL && lit_key->value()->IsString()); | |
511 Handle<String> name = Handle<String>::cast(lit_key->value()); | |
512 oracle()->PropertyReceiverTypes(slot, name, expr->GetReceiverTypes()); | |
513 } else { | |
514 bool is_string; | |
515 IcCheckType key_type; | |
516 oracle()->KeyedPropertyReceiverTypes(slot, expr->GetReceiverTypes(), | |
517 &is_string, &key_type); | |
518 expr->set_is_string_access(is_string); | |
519 expr->set_key_type(key_type); | |
520 } | |
521 } | |
522 | |
523 RECURSE(Visit(expr->obj())); | |
524 RECURSE(Visit(expr->key())); | |
525 | |
526 // We don't know anything about the result type. | |
527 } | |
528 | |
529 | |
530 void AstTyper::VisitCall(Call* expr) { | |
531 // Collect type feedback. | |
532 RECURSE(Visit(expr->expression())); | |
533 bool is_uninitialized = true; | |
534 if (expr->IsUsingCallFeedbackICSlot(isolate_)) { | |
535 FeedbackVectorSlot slot = expr->CallFeedbackICSlot(); | |
536 is_uninitialized = oracle()->CallIsUninitialized(slot); | |
537 if (!expr->expression()->IsProperty() && | |
538 oracle()->CallIsMonomorphic(slot)) { | |
539 expr->set_target(oracle()->GetCallTarget(slot)); | |
540 Handle<AllocationSite> site = oracle()->GetCallAllocationSite(slot); | |
541 expr->set_allocation_site(site); | |
542 } | |
543 } | |
544 | |
545 expr->set_is_uninitialized(is_uninitialized); | |
546 | |
547 ZoneList<Expression*>* args = expr->arguments(); | |
548 for (int i = 0; i < args->length(); ++i) { | |
549 Expression* arg = args->at(i); | |
550 RECURSE(Visit(arg)); | |
551 } | |
552 | |
553 VariableProxy* proxy = expr->expression()->AsVariableProxy(); | |
554 if (proxy != NULL && proxy->var()->is_possibly_eval(isolate_)) { | |
555 store_.Forget(); // Eval could do whatever to local variables. | |
556 } | |
557 | |
558 // We don't know anything about the result type. | |
559 } | |
560 | |
561 | |
562 void AstTyper::VisitCallNew(CallNew* expr) { | |
563 // Collect type feedback. | |
564 FeedbackVectorSlot allocation_site_feedback_slot = | |
565 expr->CallNewFeedbackSlot(); | |
566 expr->set_allocation_site( | |
567 oracle()->GetCallNewAllocationSite(allocation_site_feedback_slot)); | |
568 bool monomorphic = | |
569 oracle()->CallNewIsMonomorphic(expr->CallNewFeedbackSlot()); | |
570 expr->set_is_monomorphic(monomorphic); | |
571 if (monomorphic) { | |
572 expr->set_target(oracle()->GetCallNewTarget(expr->CallNewFeedbackSlot())); | |
573 } | |
574 | |
575 RECURSE(Visit(expr->expression())); | |
576 ZoneList<Expression*>* args = expr->arguments(); | |
577 for (int i = 0; i < args->length(); ++i) { | |
578 Expression* arg = args->at(i); | |
579 RECURSE(Visit(arg)); | |
580 } | |
581 | |
582 NarrowType(expr, Bounds(Type::None(zone()), Type::Receiver(zone()))); | |
583 } | |
584 | |
585 | |
586 void AstTyper::VisitCallRuntime(CallRuntime* expr) { | |
587 ZoneList<Expression*>* args = expr->arguments(); | |
588 for (int i = 0; i < args->length(); ++i) { | |
589 Expression* arg = args->at(i); | |
590 RECURSE(Visit(arg)); | |
591 } | |
592 | |
593 // We don't know anything about the result type. | |
594 } | |
595 | |
596 | |
597 void AstTyper::VisitUnaryOperation(UnaryOperation* expr) { | |
598 // Collect type feedback. | |
599 if (expr->op() == Token::NOT) { | |
600 // TODO(rossberg): only do in test or value context. | |
601 expr->expression()->RecordToBooleanTypeFeedback(oracle()); | |
602 } | |
603 | |
604 RECURSE(Visit(expr->expression())); | |
605 | |
606 switch (expr->op()) { | |
607 case Token::NOT: | |
608 case Token::DELETE: | |
609 NarrowType(expr, Bounds(Type::Boolean(zone()))); | |
610 break; | |
611 case Token::VOID: | |
612 NarrowType(expr, Bounds(Type::Undefined(zone()))); | |
613 break; | |
614 case Token::TYPEOF: | |
615 NarrowType(expr, Bounds(Type::InternalizedString(zone()))); | |
616 break; | |
617 default: | |
618 UNREACHABLE(); | |
619 } | |
620 } | |
621 | |
622 | |
623 void AstTyper::VisitCountOperation(CountOperation* expr) { | |
624 // Collect type feedback. | |
625 TypeFeedbackId store_id = expr->CountStoreFeedbackId(); | |
626 FeedbackVectorSlot slot = expr->CountSlot(); | |
627 KeyedAccessStoreMode store_mode; | |
628 IcCheckType key_type; | |
629 if (FLAG_vector_stores) { | |
630 oracle()->GetStoreModeAndKeyType(slot, &store_mode, &key_type); | |
631 oracle()->CountReceiverTypes(slot, expr->GetReceiverTypes()); | |
632 } else { | |
633 oracle()->GetStoreModeAndKeyType(store_id, &store_mode, &key_type); | |
634 oracle()->CountReceiverTypes(store_id, expr->GetReceiverTypes()); | |
635 } | |
636 expr->set_store_mode(store_mode); | |
637 expr->set_key_type(key_type); | |
638 expr->set_type(oracle()->CountType(expr->CountBinOpFeedbackId())); | |
639 // TODO(rossberg): merge the count type with the generic expression type. | |
640 | |
641 RECURSE(Visit(expr->expression())); | |
642 | |
643 NarrowType(expr, Bounds(Type::SignedSmall(zone()), Type::Number(zone()))); | |
644 | |
645 VariableProxy* proxy = expr->expression()->AsVariableProxy(); | |
646 if (proxy != NULL && proxy->var()->IsStackAllocated()) { | |
647 store_.Seq(variable_index(proxy->var()), Effect(expr->bounds())); | |
648 } | |
649 } | |
650 | |
651 | |
652 void AstTyper::VisitBinaryOperation(BinaryOperation* expr) { | |
653 // Collect type feedback. | |
654 Type* type; | |
655 Type* left_type; | |
656 Type* right_type; | |
657 Maybe<int> fixed_right_arg = Nothing<int>(); | |
658 Handle<AllocationSite> allocation_site; | |
659 oracle()->BinaryType(expr->BinaryOperationFeedbackId(), | |
660 &left_type, &right_type, &type, &fixed_right_arg, | |
661 &allocation_site, expr->op()); | |
662 NarrowLowerType(expr, type); | |
663 NarrowLowerType(expr->left(), left_type); | |
664 NarrowLowerType(expr->right(), right_type); | |
665 expr->set_allocation_site(allocation_site); | |
666 expr->set_fixed_right_arg(fixed_right_arg); | |
667 if (expr->op() == Token::OR || expr->op() == Token::AND) { | |
668 expr->left()->RecordToBooleanTypeFeedback(oracle()); | |
669 } | |
670 | |
671 switch (expr->op()) { | |
672 case Token::COMMA: | |
673 RECURSE(Visit(expr->left())); | |
674 RECURSE(Visit(expr->right())); | |
675 NarrowType(expr, expr->right()->bounds()); | |
676 break; | |
677 case Token::OR: | |
678 case Token::AND: { | |
679 Effects left_effects = EnterEffects(); | |
680 RECURSE(Visit(expr->left())); | |
681 ExitEffects(); | |
682 Effects right_effects = EnterEffects(); | |
683 RECURSE(Visit(expr->right())); | |
684 ExitEffects(); | |
685 left_effects.Alt(right_effects); | |
686 store_.Seq(left_effects); | |
687 | |
688 NarrowType(expr, Bounds::Either( | |
689 expr->left()->bounds(), expr->right()->bounds(), zone())); | |
690 break; | |
691 } | |
692 case Token::BIT_OR: | |
693 case Token::BIT_AND: { | |
694 RECURSE(Visit(expr->left())); | |
695 RECURSE(Visit(expr->right())); | |
696 Type* upper = Type::Union( | |
697 expr->left()->bounds().upper, expr->right()->bounds().upper, zone()); | |
698 if (!upper->Is(Type::Signed32())) upper = Type::Signed32(zone()); | |
699 Type* lower = Type::Intersect(Type::SignedSmall(zone()), upper, zone()); | |
700 NarrowType(expr, Bounds(lower, upper)); | |
701 break; | |
702 } | |
703 case Token::BIT_XOR: | |
704 case Token::SHL: | |
705 case Token::SAR: | |
706 RECURSE(Visit(expr->left())); | |
707 RECURSE(Visit(expr->right())); | |
708 NarrowType(expr, | |
709 Bounds(Type::SignedSmall(zone()), Type::Signed32(zone()))); | |
710 break; | |
711 case Token::SHR: | |
712 RECURSE(Visit(expr->left())); | |
713 RECURSE(Visit(expr->right())); | |
714 // TODO(rossberg): The upper bound would be Unsigned32, but since there | |
715 // is no 'positive Smi' type for the lower bound, we use the smallest | |
716 // union of Smi and Unsigned32 as upper bound instead. | |
717 NarrowType(expr, Bounds(Type::SignedSmall(zone()), Type::Number(zone()))); | |
718 break; | |
719 case Token::ADD: { | |
720 RECURSE(Visit(expr->left())); | |
721 RECURSE(Visit(expr->right())); | |
722 Bounds l = expr->left()->bounds(); | |
723 Bounds r = expr->right()->bounds(); | |
724 Type* lower = | |
725 !l.lower->IsInhabited() || !r.lower->IsInhabited() ? | |
726 Type::None(zone()) : | |
727 l.lower->Is(Type::String()) || r.lower->Is(Type::String()) ? | |
728 Type::String(zone()) : | |
729 l.lower->Is(Type::Number()) && r.lower->Is(Type::Number()) ? | |
730 Type::SignedSmall(zone()) : Type::None(zone()); | |
731 Type* upper = | |
732 l.upper->Is(Type::String()) || r.upper->Is(Type::String()) ? | |
733 Type::String(zone()) : | |
734 l.upper->Is(Type::Number()) && r.upper->Is(Type::Number()) ? | |
735 Type::Number(zone()) : Type::NumberOrString(zone()); | |
736 NarrowType(expr, Bounds(lower, upper)); | |
737 break; | |
738 } | |
739 case Token::SUB: | |
740 case Token::MUL: | |
741 case Token::DIV: | |
742 case Token::MOD: | |
743 RECURSE(Visit(expr->left())); | |
744 RECURSE(Visit(expr->right())); | |
745 NarrowType(expr, Bounds(Type::SignedSmall(zone()), Type::Number(zone()))); | |
746 break; | |
747 default: | |
748 UNREACHABLE(); | |
749 } | |
750 } | |
751 | |
752 | |
753 void AstTyper::VisitCompareOperation(CompareOperation* expr) { | |
754 // Collect type feedback. | |
755 Type* left_type; | |
756 Type* right_type; | |
757 Type* combined_type; | |
758 oracle()->CompareType(expr->CompareOperationFeedbackId(), | |
759 &left_type, &right_type, &combined_type); | |
760 NarrowLowerType(expr->left(), left_type); | |
761 NarrowLowerType(expr->right(), right_type); | |
762 expr->set_combined_type(combined_type); | |
763 | |
764 RECURSE(Visit(expr->left())); | |
765 RECURSE(Visit(expr->right())); | |
766 | |
767 NarrowType(expr, Bounds(Type::Boolean(zone()))); | |
768 } | |
769 | |
770 | |
771 void AstTyper::VisitSpread(Spread* expr) { RECURSE(Visit(expr->expression())); } | |
772 | |
773 | |
774 void AstTyper::VisitEmptyParentheses(EmptyParentheses* expr) { | |
775 UNREACHABLE(); | |
776 } | |
777 | |
778 | |
779 void AstTyper::VisitThisFunction(ThisFunction* expr) { | |
780 } | |
781 | |
782 | |
783 void AstTyper::VisitSuperPropertyReference(SuperPropertyReference* expr) {} | |
784 | |
785 | |
786 void AstTyper::VisitSuperCallReference(SuperCallReference* expr) {} | |
787 | |
788 | |
789 void AstTyper::VisitDeclarations(ZoneList<Declaration*>* decls) { | |
790 for (int i = 0; i < decls->length(); ++i) { | |
791 Declaration* decl = decls->at(i); | |
792 RECURSE(Visit(decl)); | |
793 } | |
794 } | |
795 | |
796 | |
797 void AstTyper::VisitVariableDeclaration(VariableDeclaration* declaration) { | |
798 } | |
799 | |
800 | |
801 void AstTyper::VisitFunctionDeclaration(FunctionDeclaration* declaration) { | |
802 RECURSE(Visit(declaration->fun())); | |
803 } | |
804 | |
805 | |
806 void AstTyper::VisitImportDeclaration(ImportDeclaration* declaration) { | |
807 } | |
808 | |
809 | |
810 void AstTyper::VisitExportDeclaration(ExportDeclaration* declaration) { | |
811 } | |
812 | |
813 | |
814 } // namespace internal | |
815 } // namespace v8 | |
OLD | NEW |