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