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