typing.cc 24 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
// Copyright 2013 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
//       copyright notice, this list of conditions and the following
//       disclaimer in the documentation and/or other materials provided
//       with the distribution.
//     * Neither the name of Google Inc. nor the names of its
//       contributors may be used to endorse or promote products derived
//       from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include "typing.h"

30 31
#include "frames.h"
#include "frames-inl.h"
32 33 34 35 36 37 38 39 40 41 42 43
#include "parser.h"  // for CompileTimeValue; TODO(rossberg): should move
#include "scopes.h"

namespace v8 {
namespace internal {


AstTyper::AstTyper(CompilationInfo* info)
    : info_(info),
      oracle_(
          Handle<Code>(info->closure()->shared()->code()),
          Handle<Context>(info->closure()->context()->native_context()),
44 45
          info->zone()),
      store_(info->zone()) {
46
  InitializeAstVisitor(info->zone());
47 48 49
}


50
#define RECURSE(call)                         \
51
  do {                                        \
52
    ASSERT(!visitor->HasStackOverflow());     \
53 54 55 56
    call;                                     \
    if (visitor->HasStackOverflow()) return;  \
  } while (false)

57
void AstTyper::Run(CompilationInfo* info) {
58 59 60 61 62 63
  AstTyper* visitor = new(info->zone()) AstTyper(info);
  Scope* scope = info->scope();

  // Handle implicit declaration of the function name in named function
  // expressions before other declarations.
  if (scope->is_function_scope() && scope->function() != NULL) {
64
    RECURSE(visitor->VisitVariableDeclaration(scope->function()));
65
  }
66 67
  RECURSE(visitor->VisitDeclarations(scope->declarations()));
  RECURSE(visitor->VisitStatements(info->function()->body()));
68 69
}

70
#undef RECURSE
71

72 73

#ifdef OBJECT_PRINT
74
  static void PrintObserved(Variable* var, Object* value, Type* type) {
75 76 77 78 79 80 81 82 83 84
    PrintF("  observed %s ", var->IsParameter() ? "param" : "local");
    var->name()->Print();
    PrintF(" : ");
    value->ShortPrint();
    PrintF(" -> ");
    type->TypePrint();
  }
#endif  // OBJECT_PRINT


85
Effect AstTyper::ObservedOnStack(Object* value) {
86
  Type* lower = Type::NowOf(value, zone());
87
  return Effect(Bounds(lower, Type::Any(zone())));
88 89 90
}


91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
void AstTyper::ObserveTypesAtOsrEntry(IterationStatement* stmt) {
  if (stmt->OsrEntryId() != info_->osr_ast_id()) return;

  DisallowHeapAllocation no_gc;
  JavaScriptFrameIterator it(isolate());
  JavaScriptFrame* frame = it.frame();
  Scope* scope = info_->scope();

  // Assert that the frame on the stack belongs to the function we want to OSR.
  ASSERT_EQ(*info_->closure(), frame->function());

  int params = scope->num_parameters();
  int locals = scope->StackLocalCount();

  // Use sequential composition to achieve desired narrowing.
  // The receiver is a parameter with index -1.
  store_.Seq(parameter_index(-1), ObservedOnStack(frame->receiver()));
  for (int i = 0; i < params; i++) {
    store_.Seq(parameter_index(i), ObservedOnStack(frame->GetParameter(i)));
  }

  for (int i = 0; i < locals; i++) {
    store_.Seq(stack_local_index(i), ObservedOnStack(frame->GetExpression(i)));
  }

#ifdef OBJECT_PRINT
  if (FLAG_trace_osr && FLAG_print_scopes) {
    PrintObserved(scope->receiver(),
                  frame->receiver(),
                  store_.LookupBounds(parameter_index(-1)).lower);

    for (int i = 0; i < params; i++) {
      PrintObserved(scope->parameter(i),
                    frame->GetParameter(i),
                    store_.LookupBounds(parameter_index(i)).lower);
    }

    ZoneList<Variable*> local_vars(locals, zone());
    ZoneList<Variable*> context_vars(scope->ContextLocalCount(), zone());
    scope->CollectStackAndContextLocals(&local_vars, &context_vars);
    for (int i = 0; i < locals; i++) {
      PrintObserved(local_vars.at(i),
                    frame->GetExpression(i),
                    store_.LookupBounds(stack_local_index(i)).lower);
    }
  }
#endif  // OBJECT_PRINT
}


141
#define RECURSE(call)                \
142
  do {                               \
143
    ASSERT(!HasStackOverflow());     \
144 145 146 147 148 149 150 151
    call;                            \
    if (HasStackOverflow()) return;  \
  } while (false)


void AstTyper::VisitStatements(ZoneList<Statement*>* stmts) {
  for (int i = 0; i < stmts->length(); ++i) {
    Statement* stmt = stmts->at(i);
152
    RECURSE(Visit(stmt));
153
    if (stmt->IsJump()) break;
154 155 156 157 158
  }
}


void AstTyper::VisitBlock(Block* stmt) {
159
  RECURSE(VisitStatements(stmt->statements()));
160 161 162
  if (stmt->labels() != NULL) {
    store_.Forget();  // Control may transfer here via 'break l'.
  }
163 164 165 166
}


void AstTyper::VisitExpressionStatement(ExpressionStatement* stmt) {
167
  RECURSE(Visit(stmt->expression()));
168 169 170 171 172 173 174 175
}


void AstTyper::VisitEmptyStatement(EmptyStatement* stmt) {
}


void AstTyper::VisitIfStatement(IfStatement* stmt) {
176
  // Collect type feedback.
177 178 179 180
  if (!stmt->condition()->ToBooleanIsTrue() &&
      !stmt->condition()->ToBooleanIsFalse()) {
    stmt->condition()->RecordToBooleanTypeFeedback(oracle());
  }
181 182 183 184 185 186 187 188 189 190

  RECURSE(Visit(stmt->condition()));
  Effects then_effects = EnterEffects();
  RECURSE(Visit(stmt->then_statement()));
  ExitEffects();
  Effects else_effects = EnterEffects();
  RECURSE(Visit(stmt->else_statement()));
  ExitEffects();
  then_effects.Alt(else_effects);
  store_.Seq(then_effects);
191 192 193 194
}


void AstTyper::VisitContinueStatement(ContinueStatement* stmt) {
195
  // TODO(rossberg): is it worth having a non-termination effect?
196 197 198 199
}


void AstTyper::VisitBreakStatement(BreakStatement* stmt) {
200
  // TODO(rossberg): is it worth having a non-termination effect?
201 202 203 204
}


void AstTyper::VisitReturnStatement(ReturnStatement* stmt) {
205
  // Collect type feedback.
206 207
  // TODO(rossberg): we only need this for inlining into test contexts...
  stmt->expression()->RecordToBooleanTypeFeedback(oracle());
208 209 210

  RECURSE(Visit(stmt->expression()));
  // TODO(rossberg): is it worth having a non-termination effect?
211 212 213 214
}


void AstTyper::VisitWithStatement(WithStatement* stmt) {
215 216
  RECURSE(stmt->expression());
  RECURSE(stmt->statement());
217 218 219 220
}


void AstTyper::VisitSwitchStatement(SwitchStatement* stmt) {
221
  RECURSE(Visit(stmt->tag()));
222

223
  ZoneList<CaseClause*>* clauses = stmt->cases();
224 225 226
  Effects local_effects(zone());
  bool complex_effects = false;  // True for label effects or fall-through.

227 228
  for (int i = 0; i < clauses->length(); ++i) {
    CaseClause* clause = clauses->at(i);
229

230 231
    Effects clause_effects = EnterEffects();

232 233
    if (!clause->is_default()) {
      Expression* label = clause->label();
234
      // Collect type feedback.
235 236 237
      Type* tag_type;
      Type* label_type;
      Type* combined_type;
238 239 240 241 242
      oracle()->CompareType(clause->CompareId(),
                            &tag_type, &label_type, &combined_type);
      NarrowLowerType(stmt->tag(), tag_type);
      NarrowLowerType(label, label_type);
      clause->set_compare_type(combined_type);
243 244 245 246 247 248 249 250 251 252 253 254

      RECURSE(Visit(label));
      if (!clause_effects.IsEmpty()) complex_effects = true;
    }

    ZoneList<Statement*>* stmts = clause->statements();
    RECURSE(VisitStatements(stmts));
    ExitEffects();
    if (stmts->is_empty() || stmts->last()->IsJump()) {
      local_effects.Alt(clause_effects);
    } else {
      complex_effects = true;
255 256
    }
  }
257 258 259 260 261 262

  if (complex_effects) {
    store_.Forget();  // Reached this in unknown state.
  } else {
    store_.Seq(local_effects);
  }
263 264 265
}


266 267 268 269 270
void AstTyper::VisitCaseClause(CaseClause* clause) {
  UNREACHABLE();
}


271
void AstTyper::VisitDoWhileStatement(DoWhileStatement* stmt) {
272
  // Collect type feedback.
273 274 275
  if (!stmt->cond()->ToBooleanIsTrue()) {
    stmt->cond()->RecordToBooleanTypeFeedback(oracle());
  }
276 277 278 279 280

  // TODO(rossberg): refine the unconditional Forget (here and elsewhere) by
  // computing the set of variables assigned in only some of the origins of the
  // control transfer (such as the loop body here).
  store_.Forget();  // Control may transfer here via looping or 'continue'.
281
  ObserveTypesAtOsrEntry(stmt);
282 283 284
  RECURSE(Visit(stmt->body()));
  RECURSE(Visit(stmt->cond()));
  store_.Forget();  // Control may transfer here via 'break'.
285 286 287 288
}


void AstTyper::VisitWhileStatement(WhileStatement* stmt) {
289
  // Collect type feedback.
290 291 292
  if (!stmt->cond()->ToBooleanIsTrue()) {
    stmt->cond()->RecordToBooleanTypeFeedback(oracle());
  }
293 294 295

  store_.Forget();  // Control may transfer here via looping or 'continue'.
  RECURSE(Visit(stmt->cond()));
296
  ObserveTypesAtOsrEntry(stmt);
297 298
  RECURSE(Visit(stmt->body()));
  store_.Forget();  // Control may transfer here via termination or 'break'.
299 300 301 302 303
}


void AstTyper::VisitForStatement(ForStatement* stmt) {
  if (stmt->init() != NULL) {
304
    RECURSE(Visit(stmt->init()));
305
  }
306
  store_.Forget();  // Control may transfer here via looping.
307
  if (stmt->cond() != NULL) {
308
    // Collect type feedback.
309
    stmt->cond()->RecordToBooleanTypeFeedback(oracle());
310 311

    RECURSE(Visit(stmt->cond()));
312
  }
313
  ObserveTypesAtOsrEntry(stmt);
314
  RECURSE(Visit(stmt->body()));
315
  if (stmt->next() != NULL) {
316
    store_.Forget();  // Control may transfer here via 'continue'.
317
    RECURSE(Visit(stmt->next()));
318
  }
319
  store_.Forget();  // Control may transfer here via termination or 'break'.
320 321 322 323
}


void AstTyper::VisitForInStatement(ForInStatement* stmt) {
324
  // Collect type feedback.
325
  stmt->set_for_in_type(static_cast<ForInStatement::ForInType>(
326
      oracle()->ForInType(stmt->ForInFeedbackSlot())));
327

328
  RECURSE(Visit(stmt->enumerable()));
329
  store_.Forget();  // Control may transfer here via looping or 'continue'.
330
  ObserveTypesAtOsrEntry(stmt);
331
  RECURSE(Visit(stmt->body()));
332
  store_.Forget();  // Control may transfer here via 'break'.
333 334 335
}


336
void AstTyper::VisitForOfStatement(ForOfStatement* stmt) {
337
  RECURSE(Visit(stmt->iterable()));
338
  store_.Forget();  // Control may transfer here via looping or 'continue'.
339
  RECURSE(Visit(stmt->body()));
340
  store_.Forget();  // Control may transfer here via 'break'.
341 342 343
}


344
void AstTyper::VisitTryCatchStatement(TryCatchStatement* stmt) {
345
  Effects try_effects = EnterEffects();
346
  RECURSE(Visit(stmt->try_block()));
347 348 349
  ExitEffects();
  Effects catch_effects = EnterEffects();
  store_.Forget();  // Control may transfer here via 'throw'.
350
  RECURSE(Visit(stmt->catch_block()));
351 352 353 354 355
  ExitEffects();
  try_effects.Alt(catch_effects);
  store_.Seq(try_effects);
  // At this point, only variables that were reassigned in the catch block are
  // still remembered.
356 357 358 359
}


void AstTyper::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
360
  RECURSE(Visit(stmt->try_block()));
361
  store_.Forget();  // Control may transfer here via 'throw'.
362
  RECURSE(Visit(stmt->finally_block()));
363 364 365 366
}


void AstTyper::VisitDebuggerStatement(DebuggerStatement* stmt) {
367
  store_.Forget();  // May do whatever.
368 369 370 371
}


void AstTyper::VisitFunctionLiteral(FunctionLiteral* expr) {
372
  expr->InitializeSharedInfo(Handle<Code>(info_->closure()->shared()->code()));
373 374 375
}


376
void AstTyper::VisitNativeFunctionLiteral(NativeFunctionLiteral* expr) {
377 378 379 380
}


void AstTyper::VisitConditional(Conditional* expr) {
381 382 383
  // Collect type feedback.
  expr->condition()->RecordToBooleanTypeFeedback(oracle());

384
  RECURSE(Visit(expr->condition()));
385
  Effects then_effects = EnterEffects();
386
  RECURSE(Visit(expr->then_expression()));
387 388
  ExitEffects();
  Effects else_effects = EnterEffects();
389
  RECURSE(Visit(expr->else_expression()));
390 391 392
  ExitEffects();
  then_effects.Alt(else_effects);
  store_.Seq(then_effects);
393

394 395
  NarrowType(expr, Bounds::Either(
      expr->then_expression()->bounds(),
396
      expr->else_expression()->bounds(), zone()));
397 398 399 400
}


void AstTyper::VisitVariableProxy(VariableProxy* expr) {
401 402 403 404
  Variable* var = expr->var();
  if (var->IsStackAllocated()) {
    NarrowType(expr, store_.LookupBounds(variable_index(var)));
  }
405 406 407 408
}


void AstTyper::VisitLiteral(Literal* expr) {
409
  Type* type = Type::Constant(expr->value(), zone());
410
  NarrowType(expr, Bounds(type));
411 412 413 414
}


void AstTyper::VisitRegExpLiteral(RegExpLiteral* expr) {
415
  NarrowType(expr, Bounds(Type::RegExp(zone())));
416 417 418 419 420 421 422 423
}


void AstTyper::VisitObjectLiteral(ObjectLiteral* expr) {
  ZoneList<ObjectLiteral::Property*>* properties = expr->properties();
  for (int i = 0; i < properties->length(); ++i) {
    ObjectLiteral::Property* prop = properties->at(i);

424
    // Collect type feedback.
425 426 427
    if ((prop->kind() == ObjectLiteral::Property::MATERIALIZED_LITERAL &&
        !CompileTimeValue::IsCompileTimeValue(prop->value())) ||
        prop->kind() == ObjectLiteral::Property::COMPUTED) {
428
      if (prop->key()->value()->IsInternalizedString() && prop->emit_store()) {
429
        prop->RecordTypeFeedback(oracle());
430
      }
431
    }
432 433

    RECURSE(Visit(prop->value()));
434
  }
435

436
  NarrowType(expr, Bounds(Type::Object(zone())));
437 438 439 440 441 442 443
}


void AstTyper::VisitArrayLiteral(ArrayLiteral* expr) {
  ZoneList<Expression*>* values = expr->values();
  for (int i = 0; i < values->length(); ++i) {
    Expression* value = values->at(i);
444
    RECURSE(Visit(value));
445
  }
446

447
  NarrowType(expr, Bounds(Type::Array(zone())));
448 449 450 451
}


void AstTyper::VisitAssignment(Assignment* expr) {
452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468
  // Collect type feedback.
  Property* prop = expr->target()->AsProperty();
  if (prop != NULL) {
    TypeFeedbackId id = expr->AssignmentFeedbackId();
    expr->set_is_uninitialized(oracle()->StoreIsUninitialized(id));
    if (!expr->IsUninitialized()) {
      if (prop->key()->IsPropertyName()) {
        Literal* lit_key = prop->key()->AsLiteral();
        ASSERT(lit_key != NULL && lit_key->value()->IsString());
        Handle<String> name = Handle<String>::cast(lit_key->value());
        oracle()->AssignmentReceiverTypes(id, name, expr->GetReceiverTypes());
      } else {
        KeyedAccessStoreMode store_mode;
        oracle()->KeyedAssignmentReceiverTypes(
            id, expr->GetReceiverTypes(), &store_mode);
        expr->set_store_mode(store_mode);
      }
469
    }
470
  }
471

472 473 474 475 476 477
  Expression* rhs =
      expr->is_compound() ? expr->binary_operation() : expr->value();
  RECURSE(Visit(expr->target()));
  RECURSE(Visit(rhs));
  NarrowType(expr, rhs->bounds());

478 479 480 481
  VariableProxy* proxy = expr->target()->AsVariableProxy();
  if (proxy != NULL && proxy->var()->IsStackAllocated()) {
    store_.Seq(variable_index(proxy->var()), Effect(expr->bounds()));
  }
482 483 484 485
}


void AstTyper::VisitYield(Yield* expr) {
486 487 488
  RECURSE(Visit(expr->generator_object()));
  RECURSE(Visit(expr->expression()));

489
  // We don't know anything about the result type.
490 491 492 493
}


void AstTyper::VisitThrow(Throw* expr) {
494
  RECURSE(Visit(expr->exception()));
495
  // TODO(rossberg): is it worth having a non-termination effect?
496

497
  NarrowType(expr, Bounds(Type::None(zone())));
498 499 500 501
}


void AstTyper::VisitProperty(Property* expr) {
502
  // Collect type feedback.
503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520
  TypeFeedbackId id = expr->PropertyFeedbackId();
  expr->set_is_uninitialized(oracle()->LoadIsUninitialized(id));
  if (!expr->IsUninitialized()) {
    if (expr->key()->IsPropertyName()) {
      Literal* lit_key = expr->key()->AsLiteral();
      ASSERT(lit_key != NULL && lit_key->value()->IsString());
      Handle<String> name = Handle<String>::cast(lit_key->value());
      bool is_prototype;
      oracle()->PropertyReceiverTypes(
          id, name, expr->GetReceiverTypes(), &is_prototype);
      expr->set_is_function_prototype(is_prototype);
    } else {
      bool is_string;
      oracle()->KeyedPropertyReceiverTypes(
          id, expr->GetReceiverTypes(), &is_string);
      expr->set_is_string_access(is_string);
    }
  }
521

522 523
  RECURSE(Visit(expr->obj()));
  RECURSE(Visit(expr->key()));
524

525
  // We don't know anything about the result type.
526 527 528 529
}


void AstTyper::VisitCall(Call* expr) {
530
  // Collect type feedback.
531
  RECURSE(Visit(expr->expression()));
verwaest@chromium.org's avatar
verwaest@chromium.org committed
532
  if (!expr->expression()->IsProperty() &&
533 534 535
      expr->HasCallFeedbackSlot() &&
      oracle()->CallIsMonomorphic(expr->CallFeedbackSlot())) {
    expr->set_target(oracle()->GetCallTarget(expr->CallFeedbackSlot()));
verwaest@chromium.org's avatar
verwaest@chromium.org committed
536 537
  }

538 539 540 541 542 543 544 545 546 547 548 549
  ZoneList<Expression*>* args = expr->arguments();
  for (int i = 0; i < args->length(); ++i) {
    Expression* arg = args->at(i);
    RECURSE(Visit(arg));
  }

  VariableProxy* proxy = expr->expression()->AsVariableProxy();
  if (proxy != NULL && proxy->var()->is_possibly_eval(isolate())) {
    store_.Forget();  // Eval could do whatever to local variables.
  }

  // We don't know anything about the result type.
550 551 552 553
}


void AstTyper::VisitCallNew(CallNew* expr) {
554 555 556
  // Collect type feedback.
  expr->RecordTypeFeedback(oracle());

557
  RECURSE(Visit(expr->expression()));
558 559 560
  ZoneList<Expression*>* args = expr->arguments();
  for (int i = 0; i < args->length(); ++i) {
    Expression* arg = args->at(i);
561
    RECURSE(Visit(arg));
562 563
  }

564
  NarrowType(expr, Bounds(Type::None(zone()), Type::Receiver(zone())));
565 566 567 568 569 570 571
}


void AstTyper::VisitCallRuntime(CallRuntime* expr) {
  ZoneList<Expression*>* args = expr->arguments();
  for (int i = 0; i < args->length(); ++i) {
    Expression* arg = args->at(i);
572
    RECURSE(Visit(arg));
573
  }
574

575
  // We don't know anything about the result type.
576 577 578 579
}


void AstTyper::VisitUnaryOperation(UnaryOperation* expr) {
580
  // Collect type feedback.
581 582 583 584
  if (expr->op() == Token::NOT) {
    // TODO(rossberg): only do in test or value context.
    expr->expression()->RecordToBooleanTypeFeedback(oracle());
  }
585

586 587
  RECURSE(Visit(expr->expression()));

588 589 590
  switch (expr->op()) {
    case Token::NOT:
    case Token::DELETE:
591
      NarrowType(expr, Bounds(Type::Boolean(zone())));
592 593
      break;
    case Token::VOID:
594
      NarrowType(expr, Bounds(Type::Undefined(zone())));
595 596
      break;
    case Token::TYPEOF:
597
      NarrowType(expr, Bounds(Type::InternalizedString(zone())));
598 599 600 601
      break;
    default:
      UNREACHABLE();
  }
602 603 604 605
}


void AstTyper::VisitCountOperation(CountOperation* expr) {
606
  // Collect type feedback.
607 608 609 610 611
  TypeFeedbackId store_id = expr->CountStoreFeedbackId();
  expr->set_store_mode(oracle()->GetStoreMode(store_id));
  oracle()->CountReceiverTypes(store_id, expr->GetReceiverTypes());
  expr->set_type(oracle()->CountType(expr->CountBinOpFeedbackId()));
  // TODO(rossberg): merge the count type with the generic expression type.
612

613 614
  RECURSE(Visit(expr->expression()));

615
  NarrowType(expr, Bounds(Type::SignedSmall(zone()), Type::Number(zone())));
616 617 618 619 620

  VariableProxy* proxy = expr->expression()->AsVariableProxy();
  if (proxy != NULL && proxy->var()->IsStackAllocated()) {
    store_.Seq(variable_index(proxy->var()), Effect(expr->bounds()));
  }
621 622 623 624
}


void AstTyper::VisitBinaryOperation(BinaryOperation* expr) {
625
  // Collect type feedback.
626 627 628
  Type* type;
  Type* left_type;
  Type* right_type;
629
  Maybe<int> fixed_right_arg;
630
  Handle<AllocationSite> allocation_site;
631
  oracle()->BinaryType(expr->BinaryOperationFeedbackId(),
632 633
      &left_type, &right_type, &type, &fixed_right_arg,
      &allocation_site, expr->op());
634 635 636
  NarrowLowerType(expr, type);
  NarrowLowerType(expr->left(), left_type);
  NarrowLowerType(expr->right(), right_type);
637
  expr->set_allocation_site(allocation_site);
638
  expr->set_fixed_right_arg(fixed_right_arg);
639 640 641
  if (expr->op() == Token::OR || expr->op() == Token::AND) {
    expr->left()->RecordToBooleanTypeFeedback(oracle());
  }
642 643 644

  switch (expr->op()) {
    case Token::COMMA:
645 646
      RECURSE(Visit(expr->left()));
      RECURSE(Visit(expr->right()));
647
      NarrowType(expr, expr->right()->bounds());
648 649
      break;
    case Token::OR:
650 651 652 653 654 655 656 657 658 659
    case Token::AND: {
      Effects left_effects = EnterEffects();
      RECURSE(Visit(expr->left()));
      ExitEffects();
      Effects right_effects = EnterEffects();
      RECURSE(Visit(expr->right()));
      ExitEffects();
      left_effects.Alt(right_effects);
      store_.Seq(left_effects);

660
      NarrowType(expr, Bounds::Either(
661
          expr->left()->bounds(), expr->right()->bounds(), zone()));
662
      break;
663
    }
664 665
    case Token::BIT_OR:
    case Token::BIT_AND: {
666 667
      RECURSE(Visit(expr->left()));
      RECURSE(Visit(expr->right()));
668 669 670
      Type* upper = Type::Union(
          expr->left()->bounds().upper, expr->right()->bounds().upper, zone());
      if (!upper->Is(Type::Signed32())) upper = Type::Signed32(zone());
671
      Type* lower = Type::Intersect(Type::SignedSmall(zone()), upper, zone());
672
      NarrowType(expr, Bounds(lower, upper));
673 674 675 676 677
      break;
    }
    case Token::BIT_XOR:
    case Token::SHL:
    case Token::SAR:
678 679
      RECURSE(Visit(expr->left()));
      RECURSE(Visit(expr->right()));
680 681
      NarrowType(expr,
          Bounds(Type::SignedSmall(zone()), Type::Signed32(zone())));
682 683
      break;
    case Token::SHR:
684 685
      RECURSE(Visit(expr->left()));
      RECURSE(Visit(expr->right()));
686 687 688
      // TODO(rossberg): The upper bound would be Unsigned32, but since there
      // is no 'positive Smi' type for the lower bound, we use the smallest
      // union of Smi and Unsigned32 as upper bound instead.
689
      NarrowType(expr, Bounds(Type::SignedSmall(zone()), Type::Number(zone())));
690 691
      break;
    case Token::ADD: {
692 693
      RECURSE(Visit(expr->left()));
      RECURSE(Visit(expr->right()));
694 695
      Bounds l = expr->left()->bounds();
      Bounds r = expr->right()->bounds();
696
      Type* lower =
697
          l.lower->Is(Type::None()) || r.lower->Is(Type::None()) ?
698
              Type::None(zone()) :
699
          l.lower->Is(Type::String()) || r.lower->Is(Type::String()) ?
700
              Type::String(zone()) :
701
          l.lower->Is(Type::Number()) && r.lower->Is(Type::Number()) ?
702
              Type::SignedSmall(zone()) : Type::None(zone());
703
      Type* upper =
704
          l.upper->Is(Type::String()) || r.upper->Is(Type::String()) ?
705
              Type::String(zone()) :
706
          l.upper->Is(Type::Number()) && r.upper->Is(Type::Number()) ?
707
              Type::Number(zone()) : Type::NumberOrString(zone());
708
      NarrowType(expr, Bounds(lower, upper));
709 710 711 712 713 714
      break;
    }
    case Token::SUB:
    case Token::MUL:
    case Token::DIV:
    case Token::MOD:
715 716
      RECURSE(Visit(expr->left()));
      RECURSE(Visit(expr->right()));
717
      NarrowType(expr, Bounds(Type::SignedSmall(zone()), Type::Number(zone())));
718 719 720 721
      break;
    default:
      UNREACHABLE();
  }
722 723 724 725
}


void AstTyper::VisitCompareOperation(CompareOperation* expr) {
726
  // Collect type feedback.
727 728 729
  Type* left_type;
  Type* right_type;
  Type* combined_type;
730 731
  oracle()->CompareType(expr->CompareOperationFeedbackId(),
      &left_type, &right_type, &combined_type);
732 733
  NarrowLowerType(expr->left(), left_type);
  NarrowLowerType(expr->right(), right_type);
734
  expr->set_combined_type(combined_type);
735

736 737 738
  RECURSE(Visit(expr->left()));
  RECURSE(Visit(expr->right()));

739
  NarrowType(expr, Bounds(Type::Boolean(zone())));
740 741 742 743 744 745 746 747 748 749
}


void AstTyper::VisitThisFunction(ThisFunction* expr) {
}


void AstTyper::VisitDeclarations(ZoneList<Declaration*>* decls) {
  for (int i = 0; i < decls->length(); ++i) {
    Declaration* decl = decls->at(i);
750
    RECURSE(Visit(decl));
751 752 753 754 755 756 757 758 759
  }
}


void AstTyper::VisitVariableDeclaration(VariableDeclaration* declaration) {
}


void AstTyper::VisitFunctionDeclaration(FunctionDeclaration* declaration) {
760
  RECURSE(Visit(declaration->fun()));
761 762 763 764
}


void AstTyper::VisitModuleDeclaration(ModuleDeclaration* declaration) {
765
  RECURSE(Visit(declaration->module()));
766 767 768 769
}


void AstTyper::VisitImportDeclaration(ImportDeclaration* declaration) {
770
  RECURSE(Visit(declaration->module()));
771 772 773 774 775 776 777 778
}


void AstTyper::VisitExportDeclaration(ExportDeclaration* declaration) {
}


void AstTyper::VisitModuleLiteral(ModuleLiteral* module) {
779
  RECURSE(Visit(module->body()));
780 781 782 783 784 785 786 787
}


void AstTyper::VisitModuleVariable(ModuleVariable* module) {
}


void AstTyper::VisitModulePath(ModulePath* module) {
788
  RECURSE(Visit(module->module()));
789 790 791 792 793 794 795 796
}


void AstTyper::VisitModuleUrl(ModuleUrl* module) {
}


void AstTyper::VisitModuleStatement(ModuleStatement* stmt) {
797
  RECURSE(Visit(stmt->body()));
798 799 800 801
}


} }  // namespace v8::internal