Home | History | Annotate | Download | only in src
      1 // Copyright 2013 the V8 project authors. All rights reserved.
      2 // Redistribution and use in source and binary forms, with or without
      3 // modification, are permitted provided that the following conditions are
      4 // met:
      5 //
      6 //     * Redistributions of source code must retain the above copyright
      7 //       notice, this list of conditions and the following disclaimer.
      8 //     * Redistributions in binary form must reproduce the above
      9 //       copyright notice, this list of conditions and the following
     10 //       disclaimer in the documentation and/or other materials provided
     11 //       with the distribution.
     12 //     * Neither the name of Google Inc. nor the names of its
     13 //       contributors may be used to endorse or promote products derived
     14 //       from this software without specific prior written permission.
     15 //
     16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27 
     28 #include "typing.h"
     29 
     30 #include "parser.h"  // for CompileTimeValue; TODO(rossberg): should move
     31 #include "scopes.h"
     32 
     33 namespace v8 {
     34 namespace internal {
     35 
     36 
     37 AstTyper::AstTyper(CompilationInfo* info)
     38     : info_(info),
     39       oracle_(
     40           Handle<Code>(info->closure()->shared()->code()),
     41           Handle<Context>(info->closure()->context()->native_context()),
     42           info->isolate(),
     43           info->zone()),
     44       store_(info->zone()) {
     45   InitializeAstVisitor();
     46 }
     47 
     48 
     49 #define RECURSE(call)                         \
     50   do {                                        \
     51     ASSERT(!visitor->HasStackOverflow());     \
     52     call;                                     \
     53     if (visitor->HasStackOverflow()) return;  \
     54   } while (false)
     55 
     56 void AstTyper::Run(CompilationInfo* info) {
     57   AstTyper* visitor = new(info->zone()) AstTyper(info);
     58   Scope* scope = info->scope();
     59 
     60   // Handle implicit declaration of the function name in named function
     61   // expressions before other declarations.
     62   if (scope->is_function_scope() && scope->function() != NULL) {
     63     RECURSE(visitor->VisitVariableDeclaration(scope->function()));
     64   }
     65   RECURSE(visitor->VisitDeclarations(scope->declarations()));
     66   RECURSE(visitor->VisitStatements(info->function()->body()));
     67 }
     68 
     69 #undef RECURSE
     70 
     71 #define RECURSE(call)                \
     72   do {                               \
     73     ASSERT(!HasStackOverflow());     \
     74     call;                            \
     75     if (HasStackOverflow()) return;  \
     76   } while (false)
     77 
     78 
     79 void AstTyper::VisitStatements(ZoneList<Statement*>* stmts) {
     80   for (int i = 0; i < stmts->length(); ++i) {
     81     Statement* stmt = stmts->at(i);
     82     RECURSE(Visit(stmt));
     83     if (stmt->IsJump()) break;
     84   }
     85 }
     86 
     87 
     88 void AstTyper::VisitBlock(Block* stmt) {
     89   RECURSE(VisitStatements(stmt->statements()));
     90   if (stmt->labels() != NULL) {
     91     store_.Forget();  // Control may transfer here via 'break l'.
     92   }
     93 }
     94 
     95 
     96 void AstTyper::VisitExpressionStatement(ExpressionStatement* stmt) {
     97   RECURSE(Visit(stmt->expression()));
     98 }
     99 
    100 
    101 void AstTyper::VisitEmptyStatement(EmptyStatement* stmt) {
    102 }
    103 
    104 
    105 void AstTyper::VisitIfStatement(IfStatement* stmt) {
    106   // Collect type feedback.
    107   if (!stmt->condition()->ToBooleanIsTrue() &&
    108       !stmt->condition()->ToBooleanIsFalse()) {
    109     stmt->condition()->RecordToBooleanTypeFeedback(oracle());
    110   }
    111 
    112   RECURSE(Visit(stmt->condition()));
    113   Effects then_effects = EnterEffects();
    114   RECURSE(Visit(stmt->then_statement()));
    115   ExitEffects();
    116   Effects else_effects = EnterEffects();
    117   RECURSE(Visit(stmt->else_statement()));
    118   ExitEffects();
    119   then_effects.Alt(else_effects);
    120   store_.Seq(then_effects);
    121 }
    122 
    123 
    124 void AstTyper::VisitContinueStatement(ContinueStatement* stmt) {
    125   // TODO(rossberg): is it worth having a non-termination effect?
    126 }
    127 
    128 
    129 void AstTyper::VisitBreakStatement(BreakStatement* stmt) {
    130   // TODO(rossberg): is it worth having a non-termination effect?
    131 }
    132 
    133 
    134 void AstTyper::VisitReturnStatement(ReturnStatement* stmt) {
    135   // Collect type feedback.
    136   // TODO(rossberg): we only need this for inlining into test contexts...
    137   stmt->expression()->RecordToBooleanTypeFeedback(oracle());
    138 
    139   RECURSE(Visit(stmt->expression()));
    140   // TODO(rossberg): is it worth having a non-termination effect?
    141 }
    142 
    143 
    144 void AstTyper::VisitWithStatement(WithStatement* stmt) {
    145   RECURSE(stmt->expression());
    146   RECURSE(stmt->statement());
    147 }
    148 
    149 
    150 void AstTyper::VisitSwitchStatement(SwitchStatement* stmt) {
    151   RECURSE(Visit(stmt->tag()));
    152 
    153   ZoneList<CaseClause*>* clauses = stmt->cases();
    154   SwitchStatement::SwitchType switch_type = stmt->switch_type();
    155   Effects local_effects(zone());
    156   bool complex_effects = false;  // True for label effects or fall-through.
    157 
    158   for (int i = 0; i < clauses->length(); ++i) {
    159     CaseClause* clause = clauses->at(i);
    160     Effects clause_effects = EnterEffects();
    161 
    162     if (!clause->is_default()) {
    163       Expression* label = clause->label();
    164       SwitchStatement::SwitchType label_switch_type =
    165           label->IsSmiLiteral() ? SwitchStatement::SMI_SWITCH :
    166           label->IsStringLiteral() ? SwitchStatement::STRING_SWITCH :
    167               SwitchStatement::GENERIC_SWITCH;
    168       if (switch_type == SwitchStatement::UNKNOWN_SWITCH)
    169         switch_type = label_switch_type;
    170       else if (switch_type != label_switch_type)
    171         switch_type = SwitchStatement::GENERIC_SWITCH;
    172 
    173       RECURSE(Visit(label));
    174       if (!clause_effects.IsEmpty()) complex_effects = true;
    175     }
    176 
    177     ZoneList<Statement*>* stmts = clause->statements();
    178     RECURSE(VisitStatements(stmts));
    179     ExitEffects();
    180     if (stmts->is_empty() || stmts->last()->IsJump()) {
    181       local_effects.Alt(clause_effects);
    182     } else {
    183       complex_effects = true;
    184     }
    185   }
    186 
    187   if (complex_effects) {
    188     store_.Forget();  // Reached this in unknown state.
    189   } else {
    190     store_.Seq(local_effects);
    191   }
    192 
    193   if (switch_type == SwitchStatement::UNKNOWN_SWITCH)
    194     switch_type = SwitchStatement::GENERIC_SWITCH;
    195   stmt->set_switch_type(switch_type);
    196 
    197   // Collect type feedback.
    198   // TODO(rossberg): can we eliminate this special case and extra loop?
    199   if (switch_type == SwitchStatement::SMI_SWITCH) {
    200     for (int i = 0; i < clauses->length(); ++i) {
    201       CaseClause* clause = clauses->at(i);
    202       if (!clause->is_default())
    203         clause->RecordTypeFeedback(oracle());
    204     }
    205   }
    206 }
    207 
    208 
    209 void AstTyper::VisitDoWhileStatement(DoWhileStatement* stmt) {
    210   // Collect type feedback.
    211   if (!stmt->cond()->ToBooleanIsTrue()) {
    212     stmt->cond()->RecordToBooleanTypeFeedback(oracle());
    213   }
    214 
    215   // TODO(rossberg): refine the unconditional Forget (here and elsewhere) by
    216   // computing the set of variables assigned in only some of the origins of the
    217   // control transfer (such as the loop body here).
    218   store_.Forget();  // Control may transfer here via looping or 'continue'.
    219   RECURSE(Visit(stmt->body()));
    220   RECURSE(Visit(stmt->cond()));
    221   store_.Forget();  // Control may transfer here via 'break'.
    222 }
    223 
    224 
    225 void AstTyper::VisitWhileStatement(WhileStatement* stmt) {
    226   // Collect type feedback.
    227   if (!stmt->cond()->ToBooleanIsTrue()) {
    228     stmt->cond()->RecordToBooleanTypeFeedback(oracle());
    229   }
    230 
    231   store_.Forget();  // Control may transfer here via looping or 'continue'.
    232   RECURSE(Visit(stmt->cond()));
    233   RECURSE(Visit(stmt->body()));
    234   store_.Forget();  // Control may transfer here via termination or 'break'.
    235 }
    236 
    237 
    238 void AstTyper::VisitForStatement(ForStatement* stmt) {
    239   if (stmt->init() != NULL) {
    240     RECURSE(Visit(stmt->init()));
    241   }
    242   store_.Forget();  // Control may transfer here via looping.
    243   if (stmt->cond() != NULL) {
    244     // Collect type feedback.
    245     stmt->cond()->RecordToBooleanTypeFeedback(oracle());
    246 
    247     RECURSE(Visit(stmt->cond()));
    248   }
    249   RECURSE(Visit(stmt->body()));
    250   store_.Forget();  // Control may transfer here via 'continue'.
    251   if (stmt->next() != NULL) {
    252     RECURSE(Visit(stmt->next()));
    253   }
    254   store_.Forget();  // Control may transfer here via termination or 'break'.
    255 }
    256 
    257 
    258 void AstTyper::VisitForInStatement(ForInStatement* stmt) {
    259   // Collect type feedback.
    260   stmt->RecordTypeFeedback(oracle());
    261 
    262   RECURSE(Visit(stmt->enumerable()));
    263   store_.Forget();  // Control may transfer here via looping or 'continue'.
    264   RECURSE(Visit(stmt->body()));
    265   store_.Forget();  // Control may transfer here via 'break'.
    266 }
    267 
    268 
    269 void AstTyper::VisitForOfStatement(ForOfStatement* stmt) {
    270   RECURSE(Visit(stmt->iterable()));
    271   store_.Forget();  // Control may transfer here via looping or 'continue'.
    272   RECURSE(Visit(stmt->body()));
    273   store_.Forget();  // Control may transfer here via 'break'.
    274 }
    275 
    276 
    277 void AstTyper::VisitTryCatchStatement(TryCatchStatement* stmt) {
    278   Effects try_effects = EnterEffects();
    279   RECURSE(Visit(stmt->try_block()));
    280   ExitEffects();
    281   Effects catch_effects = EnterEffects();
    282   store_.Forget();  // Control may transfer here via 'throw'.
    283   RECURSE(Visit(stmt->catch_block()));
    284   ExitEffects();
    285   try_effects.Alt(catch_effects);
    286   store_.Seq(try_effects);
    287   // At this point, only variables that were reassigned in the catch block are
    288   // still remembered.
    289 }
    290 
    291 
    292 void AstTyper::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
    293   RECURSE(Visit(stmt->try_block()));
    294   store_.Forget();  // Control may transfer here via 'throw'.
    295   RECURSE(Visit(stmt->finally_block()));
    296 }
    297 
    298 
    299 void AstTyper::VisitDebuggerStatement(DebuggerStatement* stmt) {
    300   store_.Forget();  // May do whatever.
    301 }
    302 
    303 
    304 void AstTyper::VisitFunctionLiteral(FunctionLiteral* expr) {
    305 }
    306 
    307 
    308 void AstTyper::VisitSharedFunctionInfoLiteral(SharedFunctionInfoLiteral* expr) {
    309 }
    310 
    311 
    312 void AstTyper::VisitConditional(Conditional* expr) {
    313   // Collect type feedback.
    314   expr->condition()->RecordToBooleanTypeFeedback(oracle());
    315 
    316   RECURSE(Visit(expr->condition()));
    317   Effects then_effects = EnterEffects();
    318   RECURSE(Visit(expr->then_expression()));
    319   ExitEffects();
    320   Effects else_effects = EnterEffects();
    321   RECURSE(Visit(expr->else_expression()));
    322   ExitEffects();
    323   then_effects.Alt(else_effects);
    324   store_.Seq(then_effects);
    325 
    326   NarrowType(expr, Bounds::Either(
    327       expr->then_expression()->bounds(),
    328       expr->else_expression()->bounds(), isolate_));
    329 }
    330 
    331 
    332 void AstTyper::VisitVariableProxy(VariableProxy* expr) {
    333   Variable* var = expr->var();
    334   if (var->IsStackAllocated()) {
    335     NarrowType(expr, store_.LookupBounds(variable_index(var)));
    336   }
    337 }
    338 
    339 
    340 void AstTyper::VisitLiteral(Literal* expr) {
    341   Type* type = Type::Constant(expr->value(), isolate_);
    342   NarrowType(expr, Bounds(type, isolate_));
    343 }
    344 
    345 
    346 void AstTyper::VisitRegExpLiteral(RegExpLiteral* expr) {
    347   NarrowType(expr, Bounds(Type::RegExp(), isolate_));
    348 }
    349 
    350 
    351 void AstTyper::VisitObjectLiteral(ObjectLiteral* expr) {
    352   ZoneList<ObjectLiteral::Property*>* properties = expr->properties();
    353   for (int i = 0; i < properties->length(); ++i) {
    354     ObjectLiteral::Property* prop = properties->at(i);
    355 
    356     // Collect type feedback.
    357     if ((prop->kind() == ObjectLiteral::Property::MATERIALIZED_LITERAL &&
    358         !CompileTimeValue::IsCompileTimeValue(prop->value())) ||
    359         prop->kind() == ObjectLiteral::Property::COMPUTED) {
    360       if (prop->key()->value()->IsInternalizedString() && prop->emit_store()) {
    361         prop->RecordTypeFeedback(oracle());
    362       }
    363     }
    364 
    365     RECURSE(Visit(prop->value()));
    366   }
    367 
    368   NarrowType(expr, Bounds(Type::Object(), isolate_));
    369 }
    370 
    371 
    372 void AstTyper::VisitArrayLiteral(ArrayLiteral* expr) {
    373   ZoneList<Expression*>* values = expr->values();
    374   for (int i = 0; i < values->length(); ++i) {
    375     Expression* value = values->at(i);
    376     RECURSE(Visit(value));
    377   }
    378 
    379   NarrowType(expr, Bounds(Type::Array(), isolate_));
    380 }
    381 
    382 
    383 void AstTyper::VisitAssignment(Assignment* expr) {
    384   // TODO(rossberg): Can we clean this up?
    385   if (expr->is_compound()) {
    386     // Collect type feedback.
    387     Expression* target = expr->target();
    388     Property* prop = target->AsProperty();
    389     if (prop != NULL) {
    390       prop->RecordTypeFeedback(oracle(), zone());
    391       expr->RecordTypeFeedback(oracle(), zone());
    392     }
    393 
    394     RECURSE(Visit(expr->binary_operation()));
    395 
    396     NarrowType(expr, expr->binary_operation()->bounds());
    397   } else {
    398     // Collect type feedback.
    399     if (expr->target()->IsProperty()) {
    400       expr->RecordTypeFeedback(oracle(), zone());
    401     }
    402 
    403     RECURSE(Visit(expr->target()));
    404     RECURSE(Visit(expr->value()));
    405 
    406     NarrowType(expr, expr->value()->bounds());
    407   }
    408 
    409   VariableProxy* proxy = expr->target()->AsVariableProxy();
    410   if (proxy != NULL && proxy->var()->IsStackAllocated()) {
    411     store_.Seq(variable_index(proxy->var()), Effect(expr->bounds()));
    412   }
    413 }
    414 
    415 
    416 void AstTyper::VisitYield(Yield* expr) {
    417   RECURSE(Visit(expr->generator_object()));
    418   RECURSE(Visit(expr->expression()));
    419 
    420   // We don't know anything about the result type.
    421 }
    422 
    423 
    424 void AstTyper::VisitThrow(Throw* expr) {
    425   RECURSE(Visit(expr->exception()));
    426   // TODO(rossberg): is it worth having a non-termination effect?
    427 
    428   NarrowType(expr, Bounds(Type::None(), isolate_));
    429 }
    430 
    431 
    432 void AstTyper::VisitProperty(Property* expr) {
    433   // Collect type feedback.
    434   expr->RecordTypeFeedback(oracle(), zone());
    435 
    436   RECURSE(Visit(expr->obj()));
    437   RECURSE(Visit(expr->key()));
    438 
    439   // We don't know anything about the result type.
    440 }
    441 
    442 
    443 void AstTyper::VisitCall(Call* expr) {
    444   // Collect type feedback.
    445   Expression* callee = expr->expression();
    446   Property* prop = callee->AsProperty();
    447   if (prop != NULL) {
    448     if (prop->key()->IsPropertyName())
    449       expr->RecordTypeFeedback(oracle(), CALL_AS_METHOD);
    450   } else {
    451     expr->RecordTypeFeedback(oracle(), CALL_AS_FUNCTION);
    452   }
    453 
    454   RECURSE(Visit(expr->expression()));
    455   ZoneList<Expression*>* args = expr->arguments();
    456   for (int i = 0; i < args->length(); ++i) {
    457     Expression* arg = args->at(i);
    458     RECURSE(Visit(arg));
    459   }
    460 
    461   VariableProxy* proxy = expr->expression()->AsVariableProxy();
    462   if (proxy != NULL && proxy->var()->is_possibly_eval(isolate())) {
    463     store_.Forget();  // Eval could do whatever to local variables.
    464   }
    465 
    466   // We don't know anything about the result type.
    467 }
    468 
    469 
    470 void AstTyper::VisitCallNew(CallNew* expr) {
    471   // Collect type feedback.
    472   expr->RecordTypeFeedback(oracle());
    473 
    474   RECURSE(Visit(expr->expression()));
    475   ZoneList<Expression*>* args = expr->arguments();
    476   for (int i = 0; i < args->length(); ++i) {
    477     Expression* arg = args->at(i);
    478     RECURSE(Visit(arg));
    479   }
    480 
    481   // We don't know anything about the result type.
    482 }
    483 
    484 
    485 void AstTyper::VisitCallRuntime(CallRuntime* expr) {
    486   ZoneList<Expression*>* args = expr->arguments();
    487   for (int i = 0; i < args->length(); ++i) {
    488     Expression* arg = args->at(i);
    489     RECURSE(Visit(arg));
    490   }
    491 
    492   // We don't know anything about the result type.
    493 }
    494 
    495 
    496 void AstTyper::VisitUnaryOperation(UnaryOperation* expr) {
    497   // Collect type feedback.
    498   if (expr->op() == Token::NOT) {
    499     // TODO(rossberg): only do in test or value context.
    500     expr->expression()->RecordToBooleanTypeFeedback(oracle());
    501   }
    502 
    503   RECURSE(Visit(expr->expression()));
    504 
    505   switch (expr->op()) {
    506     case Token::NOT:
    507     case Token::DELETE:
    508       NarrowType(expr, Bounds(Type::Boolean(), isolate_));
    509       break;
    510     case Token::VOID:
    511       NarrowType(expr, Bounds(Type::Undefined(), isolate_));
    512       break;
    513     case Token::TYPEOF:
    514       NarrowType(expr, Bounds(Type::InternalizedString(), isolate_));
    515       break;
    516     default:
    517       UNREACHABLE();
    518   }
    519 }
    520 
    521 
    522 void AstTyper::VisitCountOperation(CountOperation* expr) {
    523   // Collect type feedback.
    524   expr->RecordTypeFeedback(oracle(), zone());
    525   Property* prop = expr->expression()->AsProperty();
    526   if (prop != NULL) {
    527     prop->RecordTypeFeedback(oracle(), zone());
    528   }
    529 
    530   RECURSE(Visit(expr->expression()));
    531 
    532   NarrowType(expr, Bounds(Type::Smi(), Type::Number(), isolate_));
    533 
    534   VariableProxy* proxy = expr->expression()->AsVariableProxy();
    535   if (proxy != NULL && proxy->var()->IsStackAllocated()) {
    536     store_.Seq(variable_index(proxy->var()), Effect(expr->bounds()));
    537   }
    538 }
    539 
    540 
    541 void AstTyper::VisitBinaryOperation(BinaryOperation* expr) {
    542   // Collect type feedback.
    543   Handle<Type> type, left_type, right_type;
    544   Maybe<int> fixed_right_arg;
    545   oracle()->BinaryType(expr->BinaryOperationFeedbackId(),
    546       &left_type, &right_type, &type, &fixed_right_arg);
    547   NarrowLowerType(expr, type);
    548   NarrowLowerType(expr->left(), left_type);
    549   NarrowLowerType(expr->right(), right_type);
    550   expr->set_fixed_right_arg(fixed_right_arg);
    551   if (expr->op() == Token::OR || expr->op() == Token::AND) {
    552     expr->left()->RecordToBooleanTypeFeedback(oracle());
    553   }
    554 
    555   switch (expr->op()) {
    556     case Token::COMMA:
    557       RECURSE(Visit(expr->left()));
    558       RECURSE(Visit(expr->right()));
    559       NarrowType(expr, expr->right()->bounds());
    560       break;
    561     case Token::OR:
    562     case Token::AND: {
    563       Effects left_effects = EnterEffects();
    564       RECURSE(Visit(expr->left()));
    565       ExitEffects();
    566       Effects right_effects = EnterEffects();
    567       RECURSE(Visit(expr->right()));
    568       ExitEffects();
    569       left_effects.Alt(right_effects);
    570       store_.Seq(left_effects);
    571 
    572       NarrowType(expr, Bounds::Either(
    573           expr->left()->bounds(), expr->right()->bounds(), isolate_));
    574       break;
    575     }
    576     case Token::BIT_OR:
    577     case Token::BIT_AND: {
    578       RECURSE(Visit(expr->left()));
    579       RECURSE(Visit(expr->right()));
    580       Type* upper = Type::Union(
    581           expr->left()->bounds().upper, expr->right()->bounds().upper);
    582       if (!upper->Is(Type::Signed32())) upper = Type::Signed32();
    583       NarrowType(expr, Bounds(Type::Smi(), upper, isolate_));
    584       break;
    585     }
    586     case Token::BIT_XOR:
    587     case Token::SHL:
    588     case Token::SAR:
    589       RECURSE(Visit(expr->left()));
    590       RECURSE(Visit(expr->right()));
    591       NarrowType(expr, Bounds(Type::Smi(), Type::Signed32(), isolate_));
    592       break;
    593     case Token::SHR:
    594       RECURSE(Visit(expr->left()));
    595       RECURSE(Visit(expr->right()));
    596       NarrowType(expr, Bounds(Type::Smi(), Type::Unsigned32(), isolate_));
    597       break;
    598     case Token::ADD: {
    599       RECURSE(Visit(expr->left()));
    600       RECURSE(Visit(expr->right()));
    601       Bounds l = expr->left()->bounds();
    602       Bounds r = expr->right()->bounds();
    603       Type* lower =
    604           l.lower->Is(Type::Number()) && r.lower->Is(Type::Number()) ?
    605               Type::Smi() :
    606           l.lower->Is(Type::String()) || r.lower->Is(Type::String()) ?
    607               Type::String() : Type::None();
    608       Type* upper =
    609           l.upper->Is(Type::Number()) && r.upper->Is(Type::Number()) ?
    610               Type::Number() :
    611           l.upper->Is(Type::String()) || r.upper->Is(Type::String()) ?
    612               Type::String() : Type::NumberOrString();
    613       NarrowType(expr, Bounds(lower, upper, isolate_));
    614       break;
    615     }
    616     case Token::SUB:
    617     case Token::MUL:
    618     case Token::DIV:
    619     case Token::MOD:
    620       RECURSE(Visit(expr->left()));
    621       RECURSE(Visit(expr->right()));
    622       NarrowType(expr, Bounds(Type::Smi(), Type::Number(), isolate_));
    623       break;
    624     default:
    625       UNREACHABLE();
    626   }
    627 }
    628 
    629 
    630 void AstTyper::VisitCompareOperation(CompareOperation* expr) {
    631   // Collect type feedback.
    632   Handle<Type> left_type, right_type, combined_type;
    633   oracle()->CompareType(expr->CompareOperationFeedbackId(),
    634       &left_type, &right_type, &combined_type);
    635   NarrowLowerType(expr->left(), left_type);
    636   NarrowLowerType(expr->right(), right_type);
    637   expr->set_combined_type(combined_type);
    638 
    639   RECURSE(Visit(expr->left()));
    640   RECURSE(Visit(expr->right()));
    641 
    642   NarrowType(expr, Bounds(Type::Boolean(), isolate_));
    643 }
    644 
    645 
    646 void AstTyper::VisitThisFunction(ThisFunction* expr) {
    647 }
    648 
    649 
    650 void AstTyper::VisitDeclarations(ZoneList<Declaration*>* decls) {
    651   for (int i = 0; i < decls->length(); ++i) {
    652     Declaration* decl = decls->at(i);
    653     RECURSE(Visit(decl));
    654   }
    655 }
    656 
    657 
    658 void AstTyper::VisitVariableDeclaration(VariableDeclaration* declaration) {
    659 }
    660 
    661 
    662 void AstTyper::VisitFunctionDeclaration(FunctionDeclaration* declaration) {
    663   RECURSE(Visit(declaration->fun()));
    664 }
    665 
    666 
    667 void AstTyper::VisitModuleDeclaration(ModuleDeclaration* declaration) {
    668   RECURSE(Visit(declaration->module()));
    669 }
    670 
    671 
    672 void AstTyper::VisitImportDeclaration(ImportDeclaration* declaration) {
    673   RECURSE(Visit(declaration->module()));
    674 }
    675 
    676 
    677 void AstTyper::VisitExportDeclaration(ExportDeclaration* declaration) {
    678 }
    679 
    680 
    681 void AstTyper::VisitModuleLiteral(ModuleLiteral* module) {
    682   RECURSE(Visit(module->body()));
    683 }
    684 
    685 
    686 void AstTyper::VisitModuleVariable(ModuleVariable* module) {
    687 }
    688 
    689 
    690 void AstTyper::VisitModulePath(ModulePath* module) {
    691   RECURSE(Visit(module->module()));
    692 }
    693 
    694 
    695 void AstTyper::VisitModuleUrl(ModuleUrl* module) {
    696 }
    697 
    698 
    699 void AstTyper::VisitModuleStatement(ModuleStatement* stmt) {
    700   RECURSE(Visit(stmt->body()));
    701 }
    702 
    703 
    704 } }  // namespace v8::internal
    705