Home | History | Annotate | Download | only in crankshaft
      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 
     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
     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 
     48 Effect AstTyper::ObservedOnStack(Object* value) {
     49   AstType* lower = AstType::NowOf(value, zone());
     50   return Effect(AstBounds(lower, AstType::Any()));
     51 }
     52 
     53 
     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 
    110 void AstTyper::Run() {
    111   RECURSE(VisitDeclarations(scope_->declarations()));
    112   RECURSE(VisitStatements(root_->body()));
    113 }
    114 
    115 
    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 
    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 
    133 void AstTyper::VisitExpressionStatement(ExpressionStatement* stmt) {
    134   RECURSE(Visit(stmt->expression()));
    135 }
    136 
    137 
    138 void AstTyper::VisitEmptyStatement(EmptyStatement* stmt) {
    139 }
    140 
    141 
    142 void AstTyper::VisitSloppyBlockFunctionStatement(
    143     SloppyBlockFunctionStatement* stmt) {
    144   Visit(stmt->statement());
    145 }
    146 
    147 
    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 
    167 void AstTyper::VisitContinueStatement(ContinueStatement* stmt) {
    168   // TODO(rossberg): is it worth having a non-termination effect?
    169 }
    170 
    171 
    172 void AstTyper::VisitBreakStatement(BreakStatement* stmt) {
    173   // TODO(rossberg): is it worth having a non-termination effect?
    174 }
    175 
    176 
    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 
    187 void AstTyper::VisitWithStatement(WithStatement* stmt) {
    188   RECURSE(stmt->expression());
    189   RECURSE(stmt->statement());
    190 }
    191 
    192 
    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 
    240 void AstTyper::VisitCaseClause(CaseClause* clause) {
    241   UNREACHABLE();
    242 }
    243 
    244 
    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 
    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 
    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 
    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 
    309 void AstTyper::VisitForOfStatement(ForOfStatement* stmt) {}
    310 
    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 
    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 
    333 void AstTyper::VisitDebuggerStatement(DebuggerStatement* stmt) {
    334   store_.Forget();  // May do whatever.
    335 }
    336 
    337 
    338 void AstTyper::VisitFunctionLiteral(FunctionLiteral* expr) {}
    339 
    340 
    341 void AstTyper::VisitClassLiteral(ClassLiteral* expr) {}
    342 
    343 
    344 void AstTyper::VisitNativeFunctionLiteral(NativeFunctionLiteral* expr) {
    345 }
    346 
    347 
    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 
    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 
    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 
    383 void AstTyper::VisitLiteral(Literal* expr) {
    384   AstType* type = AstType::Constant(expr->value(), zone());
    385   NarrowType(expr, AstBounds(type));
    386 }
    387 
    388 
    389 void AstTyper::VisitRegExpLiteral(RegExpLiteral* expr) {
    390   // TODO(rossberg): Reintroduce RegExp type.
    391   NarrowType(expr, AstBounds(AstType::Object()));
    392 }
    393 
    394 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    751 void AstTyper::VisitSpread(Spread* expr) { UNREACHABLE(); }
    752 
    753 
    754 void AstTyper::VisitEmptyParentheses(EmptyParentheses* expr) {
    755   UNREACHABLE();
    756 }
    757 
    758 void AstTyper::VisitGetIterator(GetIterator* expr) { UNREACHABLE(); }
    759 
    760 void AstTyper::VisitThisFunction(ThisFunction* expr) {}
    761 
    762 
    763 void AstTyper::VisitSuperPropertyReference(SuperPropertyReference* expr) {}
    764 
    765 
    766 void AstTyper::VisitSuperCallReference(SuperCallReference* expr) {}
    767 
    768 
    769 void AstTyper::VisitRewritableExpression(RewritableExpression* expr) {
    770   Visit(expr->expression());
    771 }
    772 
    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 
    782 void AstTyper::VisitDeclarations(Declaration::List* decls) {
    783   for (Declaration* decl : *decls) {
    784     RECURSE(Visit(decl));
    785   }
    786 }
    787 
    788 
    789 void AstTyper::VisitVariableDeclaration(VariableDeclaration* declaration) {
    790 }
    791 
    792 
    793 void AstTyper::VisitFunctionDeclaration(FunctionDeclaration* declaration) {
    794   RECURSE(Visit(declaration->fun()));
    795 }
    796 
    797 
    798 }  // namespace internal
    799 }  // namespace v8
    800