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