The data contained in this repository can be downloaded to your computer using one of several clients.
Please see the documentation of your version control software client for more information.

Please select the desired protocol below to get the URL.

This URL has Read-Only access.

Statistics
| Branch: | Revision:

main_repo / deps / v8 / src / typing.cc @ f230a1cf

History | View | Annotate | Download (21 KB)

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(info->isolate());
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::VisitCaseClause(CaseClause* clause) {
210
  UNREACHABLE();
211
}
212

    
213

    
214
void AstTyper::VisitDoWhileStatement(DoWhileStatement* stmt) {
215
  // Collect type feedback.
216
  if (!stmt->cond()->ToBooleanIsTrue()) {
217
    stmt->cond()->RecordToBooleanTypeFeedback(oracle());
218
  }
219

    
220
  // TODO(rossberg): refine the unconditional Forget (here and elsewhere) by
221
  // computing the set of variables assigned in only some of the origins of the
222
  // control transfer (such as the loop body here).
223
  store_.Forget();  // Control may transfer here via looping or 'continue'.
224
  RECURSE(Visit(stmt->body()));
225
  RECURSE(Visit(stmt->cond()));
226
  store_.Forget();  // Control may transfer here via 'break'.
227
}
228

    
229

    
230
void AstTyper::VisitWhileStatement(WhileStatement* stmt) {
231
  // Collect type feedback.
232
  if (!stmt->cond()->ToBooleanIsTrue()) {
233
    stmt->cond()->RecordToBooleanTypeFeedback(oracle());
234
  }
235

    
236
  store_.Forget();  // Control may transfer here via looping or 'continue'.
237
  RECURSE(Visit(stmt->cond()));
238
  RECURSE(Visit(stmt->body()));
239
  store_.Forget();  // Control may transfer here via termination or 'break'.
240
}
241

    
242

    
243
void AstTyper::VisitForStatement(ForStatement* stmt) {
244
  if (stmt->init() != NULL) {
245
    RECURSE(Visit(stmt->init()));
246
  }
247
  store_.Forget();  // Control may transfer here via looping.
248
  if (stmt->cond() != NULL) {
249
    // Collect type feedback.
250
    stmt->cond()->RecordToBooleanTypeFeedback(oracle());
251

    
252
    RECURSE(Visit(stmt->cond()));
253
  }
254
  RECURSE(Visit(stmt->body()));
255
  if (stmt->next() != NULL) {
256
    store_.Forget();  // Control may transfer here via 'continue'.
257
    RECURSE(Visit(stmt->next()));
258
  }
259
  store_.Forget();  // Control may transfer here via termination or 'break'.
260
}
261

    
262

    
263
void AstTyper::VisitForInStatement(ForInStatement* stmt) {
264
  // Collect type feedback.
265
  stmt->RecordTypeFeedback(oracle());
266

    
267
  RECURSE(Visit(stmt->enumerable()));
268
  store_.Forget();  // Control may transfer here via looping or 'continue'.
269
  RECURSE(Visit(stmt->body()));
270
  store_.Forget();  // Control may transfer here via 'break'.
271
}
272

    
273

    
274
void AstTyper::VisitForOfStatement(ForOfStatement* stmt) {
275
  RECURSE(Visit(stmt->iterable()));
276
  store_.Forget();  // Control may transfer here via looping or 'continue'.
277
  RECURSE(Visit(stmt->body()));
278
  store_.Forget();  // Control may transfer here via 'break'.
279
}
280

    
281

    
282
void AstTyper::VisitTryCatchStatement(TryCatchStatement* stmt) {
283
  Effects try_effects = EnterEffects();
284
  RECURSE(Visit(stmt->try_block()));
285
  ExitEffects();
286
  Effects catch_effects = EnterEffects();
287
  store_.Forget();  // Control may transfer here via 'throw'.
288
  RECURSE(Visit(stmt->catch_block()));
289
  ExitEffects();
290
  try_effects.Alt(catch_effects);
291
  store_.Seq(try_effects);
292
  // At this point, only variables that were reassigned in the catch block are
293
  // still remembered.
294
}
295

    
296

    
297
void AstTyper::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
298
  RECURSE(Visit(stmt->try_block()));
299
  store_.Forget();  // Control may transfer here via 'throw'.
300
  RECURSE(Visit(stmt->finally_block()));
301
}
302

    
303

    
304
void AstTyper::VisitDebuggerStatement(DebuggerStatement* stmt) {
305
  store_.Forget();  // May do whatever.
306
}
307

    
308

    
309
void AstTyper::VisitFunctionLiteral(FunctionLiteral* expr) {
310
}
311

    
312

    
313
void AstTyper::VisitNativeFunctionLiteral(NativeFunctionLiteral* expr) {
314
}
315

    
316

    
317
void AstTyper::VisitConditional(Conditional* expr) {
318
  // Collect type feedback.
319
  expr->condition()->RecordToBooleanTypeFeedback(oracle());
320

    
321
  RECURSE(Visit(expr->condition()));
322
  Effects then_effects = EnterEffects();
323
  RECURSE(Visit(expr->then_expression()));
324
  ExitEffects();
325
  Effects else_effects = EnterEffects();
326
  RECURSE(Visit(expr->else_expression()));
327
  ExitEffects();
328
  then_effects.Alt(else_effects);
329
  store_.Seq(then_effects);
330

    
331
  NarrowType(expr, Bounds::Either(
332
      expr->then_expression()->bounds(),
333
      expr->else_expression()->bounds(), isolate_));
334
}
335

    
336

    
337
void AstTyper::VisitVariableProxy(VariableProxy* expr) {
338
  Variable* var = expr->var();
339
  if (var->IsStackAllocated()) {
340
    NarrowType(expr, store_.LookupBounds(variable_index(var)));
341
  }
342
}
343

    
344

    
345
void AstTyper::VisitLiteral(Literal* expr) {
346
  Type* type = Type::Constant(expr->value(), isolate_);
347
  NarrowType(expr, Bounds(type, isolate_));
348
}
349

    
350

    
351
void AstTyper::VisitRegExpLiteral(RegExpLiteral* expr) {
352
  NarrowType(expr, Bounds(Type::RegExp(), isolate_));
353
}
354

    
355

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

    
361
    // Collect type feedback.
362
    if ((prop->kind() == ObjectLiteral::Property::MATERIALIZED_LITERAL &&
363
        !CompileTimeValue::IsCompileTimeValue(prop->value())) ||
364
        prop->kind() == ObjectLiteral::Property::COMPUTED) {
365
      if (prop->key()->value()->IsInternalizedString() && prop->emit_store()) {
366
        prop->RecordTypeFeedback(oracle());
367
      }
368
    }
369

    
370
    RECURSE(Visit(prop->value()));
371
  }
372

    
373
  NarrowType(expr, Bounds(Type::Object(), isolate_));
374
}
375

    
376

    
377
void AstTyper::VisitArrayLiteral(ArrayLiteral* expr) {
378
  ZoneList<Expression*>* values = expr->values();
379
  for (int i = 0; i < values->length(); ++i) {
380
    Expression* value = values->at(i);
381
    RECURSE(Visit(value));
382
  }
383

    
384
  NarrowType(expr, Bounds(Type::Array(), isolate_));
385
}
386

    
387

    
388
void AstTyper::VisitAssignment(Assignment* expr) {
389
  // TODO(rossberg): Can we clean this up?
390
  if (expr->is_compound()) {
391
    // Collect type feedback.
392
    Expression* target = expr->target();
393
    Property* prop = target->AsProperty();
394
    if (prop != NULL) {
395
      prop->RecordTypeFeedback(oracle(), zone());
396
      expr->RecordTypeFeedback(oracle(), zone());
397
    }
398

    
399
    RECURSE(Visit(expr->binary_operation()));
400

    
401
    NarrowType(expr, expr->binary_operation()->bounds());
402
  } else {
403
    // Collect type feedback.
404
    if (expr->target()->IsProperty()) {
405
      expr->RecordTypeFeedback(oracle(), zone());
406
    }
407

    
408
    RECURSE(Visit(expr->target()));
409
    RECURSE(Visit(expr->value()));
410

    
411
    NarrowType(expr, expr->value()->bounds());
412
  }
413

    
414
  VariableProxy* proxy = expr->target()->AsVariableProxy();
415
  if (proxy != NULL && proxy->var()->IsStackAllocated()) {
416
    store_.Seq(variable_index(proxy->var()), Effect(expr->bounds()));
417
  }
418
}
419

    
420

    
421
void AstTyper::VisitYield(Yield* expr) {
422
  RECURSE(Visit(expr->generator_object()));
423
  RECURSE(Visit(expr->expression()));
424

    
425
  // We don't know anything about the result type.
426
}
427

    
428

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

    
433
  NarrowType(expr, Bounds(Type::None(), isolate_));
434
}
435

    
436

    
437
void AstTyper::VisitProperty(Property* expr) {
438
  // Collect type feedback.
439
  expr->RecordTypeFeedback(oracle(), zone());
440

    
441
  RECURSE(Visit(expr->obj()));
442
  RECURSE(Visit(expr->key()));
443

    
444
  // We don't know anything about the result type.
445
}
446

    
447

    
448
void AstTyper::VisitCall(Call* expr) {
449
  // Collect type feedback.
450
  Expression* callee = expr->expression();
451
  Property* prop = callee->AsProperty();
452
  if (prop != NULL) {
453
    if (prop->key()->IsPropertyName())
454
      expr->RecordTypeFeedback(oracle(), CALL_AS_METHOD);
455
  } else {
456
    expr->RecordTypeFeedback(oracle(), CALL_AS_FUNCTION);
457
  }
458

    
459
  RECURSE(Visit(expr->expression()));
460
  ZoneList<Expression*>* args = expr->arguments();
461
  for (int i = 0; i < args->length(); ++i) {
462
    Expression* arg = args->at(i);
463
    RECURSE(Visit(arg));
464
  }
465

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

    
471
  // We don't know anything about the result type.
472
}
473

    
474

    
475
void AstTyper::VisitCallNew(CallNew* expr) {
476
  // Collect type feedback.
477
  expr->RecordTypeFeedback(oracle());
478

    
479
  RECURSE(Visit(expr->expression()));
480
  ZoneList<Expression*>* args = expr->arguments();
481
  for (int i = 0; i < args->length(); ++i) {
482
    Expression* arg = args->at(i);
483
    RECURSE(Visit(arg));
484
  }
485

    
486
  // We don't know anything about the result type.
487
}
488

    
489

    
490
void AstTyper::VisitCallRuntime(CallRuntime* expr) {
491
  ZoneList<Expression*>* args = expr->arguments();
492
  for (int i = 0; i < args->length(); ++i) {
493
    Expression* arg = args->at(i);
494
    RECURSE(Visit(arg));
495
  }
496

    
497
  // We don't know anything about the result type.
498
}
499

    
500

    
501
void AstTyper::VisitUnaryOperation(UnaryOperation* expr) {
502
  // Collect type feedback.
503
  if (expr->op() == Token::NOT) {
504
    // TODO(rossberg): only do in test or value context.
505
    expr->expression()->RecordToBooleanTypeFeedback(oracle());
506
  }
507

    
508
  RECURSE(Visit(expr->expression()));
509

    
510
  switch (expr->op()) {
511
    case Token::NOT:
512
    case Token::DELETE:
513
      NarrowType(expr, Bounds(Type::Boolean(), isolate_));
514
      break;
515
    case Token::VOID:
516
      NarrowType(expr, Bounds(Type::Undefined(), isolate_));
517
      break;
518
    case Token::TYPEOF:
519
      NarrowType(expr, Bounds(Type::InternalizedString(), isolate_));
520
      break;
521
    default:
522
      UNREACHABLE();
523
  }
524
}
525

    
526

    
527
void AstTyper::VisitCountOperation(CountOperation* expr) {
528
  // Collect type feedback.
529
  expr->RecordTypeFeedback(oracle(), zone());
530
  Property* prop = expr->expression()->AsProperty();
531
  if (prop != NULL) {
532
    prop->RecordTypeFeedback(oracle(), zone());
533
  }
534

    
535
  RECURSE(Visit(expr->expression()));
536

    
537
  NarrowType(expr, Bounds(Type::Smi(), Type::Number(), isolate_));
538

    
539
  VariableProxy* proxy = expr->expression()->AsVariableProxy();
540
  if (proxy != NULL && proxy->var()->IsStackAllocated()) {
541
    store_.Seq(variable_index(proxy->var()), Effect(expr->bounds()));
542
  }
543
}
544

    
545

    
546
void AstTyper::VisitBinaryOperation(BinaryOperation* expr) {
547
  // Collect type feedback.
548
  Handle<Type> type, left_type, right_type;
549
  Maybe<int> fixed_right_arg;
550
  oracle()->BinaryType(expr->BinaryOperationFeedbackId(),
551
      &left_type, &right_type, &type, &fixed_right_arg, expr->op());
552
  NarrowLowerType(expr, type);
553
  NarrowLowerType(expr->left(), left_type);
554
  NarrowLowerType(expr->right(), right_type);
555
  expr->set_fixed_right_arg(fixed_right_arg);
556
  if (expr->op() == Token::OR || expr->op() == Token::AND) {
557
    expr->left()->RecordToBooleanTypeFeedback(oracle());
558
  }
559

    
560
  switch (expr->op()) {
561
    case Token::COMMA:
562
      RECURSE(Visit(expr->left()));
563
      RECURSE(Visit(expr->right()));
564
      NarrowType(expr, expr->right()->bounds());
565
      break;
566
    case Token::OR:
567
    case Token::AND: {
568
      Effects left_effects = EnterEffects();
569
      RECURSE(Visit(expr->left()));
570
      ExitEffects();
571
      Effects right_effects = EnterEffects();
572
      RECURSE(Visit(expr->right()));
573
      ExitEffects();
574
      left_effects.Alt(right_effects);
575
      store_.Seq(left_effects);
576

    
577
      NarrowType(expr, Bounds::Either(
578
          expr->left()->bounds(), expr->right()->bounds(), isolate_));
579
      break;
580
    }
581
    case Token::BIT_OR:
582
    case Token::BIT_AND: {
583
      RECURSE(Visit(expr->left()));
584
      RECURSE(Visit(expr->right()));
585
      Handle<Type> upper(
586
          Type::Union(
587
              expr->left()->bounds().upper, expr->right()->bounds().upper),
588
          isolate_);
589
      if (!upper->Is(Type::Signed32()))
590
        upper = handle(Type::Signed32(), isolate_);
591
      Handle<Type> lower(Type::Intersect(
592
          handle(Type::Smi(), isolate_), upper), isolate_);
593
      NarrowType(expr, Bounds(lower, upper));
594
      break;
595
    }
596
    case Token::BIT_XOR:
597
    case Token::SHL:
598
    case Token::SAR:
599
      RECURSE(Visit(expr->left()));
600
      RECURSE(Visit(expr->right()));
601
      NarrowType(expr, Bounds(Type::Smi(), Type::Signed32(), isolate_));
602
      break;
603
    case Token::SHR:
604
      RECURSE(Visit(expr->left()));
605
      RECURSE(Visit(expr->right()));
606
      // TODO(rossberg): The upper bound would be Unsigned32, but since there
607
      // is no 'positive Smi' type for the lower bound, we use the smallest
608
      // union of Smi and Unsigned32 as upper bound instead.
609
      NarrowType(expr, Bounds(Type::Smi(), Type::Number(), isolate_));
610
      break;
611
    case Token::ADD: {
612
      RECURSE(Visit(expr->left()));
613
      RECURSE(Visit(expr->right()));
614
      Bounds l = expr->left()->bounds();
615
      Bounds r = expr->right()->bounds();
616
      Type* lower =
617
          l.lower->Is(Type::None()) || r.lower->Is(Type::None()) ?
618
              Type::None() :
619
          l.lower->Is(Type::String()) || r.lower->Is(Type::String()) ?
620
              Type::String() :
621
          l.lower->Is(Type::Number()) && r.lower->Is(Type::Number()) ?
622
              Type::Smi() : Type::None();
623
      Type* upper =
624
          l.upper->Is(Type::String()) || r.upper->Is(Type::String()) ?
625
              Type::String() :
626
          l.upper->Is(Type::Number()) && r.upper->Is(Type::Number()) ?
627
              Type::Number() : Type::NumberOrString();
628
      NarrowType(expr, Bounds(lower, upper, isolate_));
629
      break;
630
    }
631
    case Token::SUB:
632
    case Token::MUL:
633
    case Token::DIV:
634
    case Token::MOD:
635
      RECURSE(Visit(expr->left()));
636
      RECURSE(Visit(expr->right()));
637
      NarrowType(expr, Bounds(Type::Smi(), Type::Number(), isolate_));
638
      break;
639
    default:
640
      UNREACHABLE();
641
  }
642
}
643

    
644

    
645
void AstTyper::VisitCompareOperation(CompareOperation* expr) {
646
  // Collect type feedback.
647
  Handle<Type> left_type, right_type, combined_type;
648
  oracle()->CompareType(expr->CompareOperationFeedbackId(),
649
      &left_type, &right_type, &combined_type);
650
  NarrowLowerType(expr->left(), left_type);
651
  NarrowLowerType(expr->right(), right_type);
652
  expr->set_combined_type(combined_type);
653

    
654
  RECURSE(Visit(expr->left()));
655
  RECURSE(Visit(expr->right()));
656

    
657
  NarrowType(expr, Bounds(Type::Boolean(), isolate_));
658
}
659

    
660

    
661
void AstTyper::VisitThisFunction(ThisFunction* expr) {
662
}
663

    
664

    
665
void AstTyper::VisitDeclarations(ZoneList<Declaration*>* decls) {
666
  for (int i = 0; i < decls->length(); ++i) {
667
    Declaration* decl = decls->at(i);
668
    RECURSE(Visit(decl));
669
  }
670
}
671

    
672

    
673
void AstTyper::VisitVariableDeclaration(VariableDeclaration* declaration) {
674
}
675

    
676

    
677
void AstTyper::VisitFunctionDeclaration(FunctionDeclaration* declaration) {
678
  RECURSE(Visit(declaration->fun()));
679
}
680

    
681

    
682
void AstTyper::VisitModuleDeclaration(ModuleDeclaration* declaration) {
683
  RECURSE(Visit(declaration->module()));
684
}
685

    
686

    
687
void AstTyper::VisitImportDeclaration(ImportDeclaration* declaration) {
688
  RECURSE(Visit(declaration->module()));
689
}
690

    
691

    
692
void AstTyper::VisitExportDeclaration(ExportDeclaration* declaration) {
693
}
694

    
695

    
696
void AstTyper::VisitModuleLiteral(ModuleLiteral* module) {
697
  RECURSE(Visit(module->body()));
698
}
699

    
700

    
701
void AstTyper::VisitModuleVariable(ModuleVariable* module) {
702
}
703

    
704

    
705
void AstTyper::VisitModulePath(ModulePath* module) {
706
  RECURSE(Visit(module->module()));
707
}
708

    
709

    
710
void AstTyper::VisitModuleUrl(ModuleUrl* module) {
711
}
712

    
713

    
714
void AstTyper::VisitModuleStatement(ModuleStatement* stmt) {
715
  RECURSE(Visit(stmt->body()));
716
}
717

    
718

    
719
} }  // namespace v8::internal