| OLD | NEW |
| (Empty) |
| 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 #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::VisitConditional(Conditional* expr) { | |
| 354 // Collect type feedback. | |
| 355 expr->condition()->RecordToBooleanTypeFeedback(oracle()); | |
| 356 | |
| 357 RECURSE(Visit(expr->condition())); | |
| 358 Effects then_effects = EnterEffects(); | |
| 359 RECURSE(Visit(expr->then_expression())); | |
| 360 ExitEffects(); | |
| 361 Effects else_effects = EnterEffects(); | |
| 362 RECURSE(Visit(expr->else_expression())); | |
| 363 ExitEffects(); | |
| 364 then_effects.Alt(else_effects); | |
| 365 store_.Seq(then_effects); | |
| 366 | |
| 367 NarrowType(expr, Bounds::Either( | |
| 368 expr->then_expression()->bounds(), | |
| 369 expr->else_expression()->bounds(), zone())); | |
| 370 } | |
| 371 | |
| 372 | |
| 373 void AstTyper::VisitVariableProxy(VariableProxy* expr) { | |
| 374 Variable* var = expr->var(); | |
| 375 if (var->IsStackAllocated()) { | |
| 376 NarrowType(expr, store_.LookupBounds(variable_index(var))); | |
| 377 } | |
| 378 } | |
| 379 | |
| 380 | |
| 381 void AstTyper::VisitLiteral(Literal* expr) { | |
| 382 Type* type = Type::Constant(expr->value(), zone()); | |
| 383 NarrowType(expr, Bounds(type)); | |
| 384 } | |
| 385 | |
| 386 | |
| 387 void AstTyper::VisitRegExpLiteral(RegExpLiteral* expr) { | |
| 388 // TODO(rossberg): Reintroduce RegExp type. | |
| 389 NarrowType(expr, Bounds(Type::Object(zone()))); | |
| 390 } | |
| 391 | |
| 392 | |
| 393 void AstTyper::VisitObjectLiteral(ObjectLiteral* expr) { | |
| 394 ZoneList<ObjectLiteral::Property*>* properties = expr->properties(); | |
| 395 for (int i = 0; i < properties->length(); ++i) { | |
| 396 ObjectLiteral::Property* prop = properties->at(i); | |
| 397 | |
| 398 // Collect type feedback. | |
| 399 if ((prop->kind() == ObjectLiteral::Property::MATERIALIZED_LITERAL && | |
| 400 !CompileTimeValue::IsCompileTimeValue(prop->value())) || | |
| 401 prop->kind() == ObjectLiteral::Property::COMPUTED) { | |
| 402 if (!prop->is_computed_name() && | |
| 403 prop->key()->AsLiteral()->value()->IsInternalizedString() && | |
| 404 prop->emit_store()) { | |
| 405 // Record type feed back for the property. | |
| 406 TypeFeedbackId id = prop->key()->AsLiteral()->LiteralFeedbackId(); | |
| 407 FeedbackVectorSlot slot = prop->GetSlot(); | |
| 408 SmallMapList maps; | |
| 409 if (FLAG_vector_stores) { | |
| 410 oracle()->CollectReceiverTypes(slot, &maps); | |
| 411 } else { | |
| 412 oracle()->CollectReceiverTypes(id, &maps); | |
| 413 } | |
| 414 prop->set_receiver_type(maps.length() == 1 ? maps.at(0) | |
| 415 : Handle<Map>::null()); | |
| 416 } | |
| 417 } | |
| 418 | |
| 419 RECURSE(Visit(prop->value())); | |
| 420 } | |
| 421 | |
| 422 NarrowType(expr, Bounds(Type::Object(zone()))); | |
| 423 } | |
| 424 | |
| 425 | |
| 426 void AstTyper::VisitArrayLiteral(ArrayLiteral* expr) { | |
| 427 ZoneList<Expression*>* values = expr->values(); | |
| 428 for (int i = 0; i < values->length(); ++i) { | |
| 429 Expression* value = values->at(i); | |
| 430 RECURSE(Visit(value)); | |
| 431 } | |
| 432 | |
| 433 NarrowType(expr, Bounds(Type::Object(zone()))); | |
| 434 } | |
| 435 | |
| 436 | |
| 437 void AstTyper::VisitAssignment(Assignment* expr) { | |
| 438 // Collect type feedback. | |
| 439 Property* prop = expr->target()->AsProperty(); | |
| 440 if (prop != NULL) { | |
| 441 TypeFeedbackId id = expr->AssignmentFeedbackId(); | |
| 442 FeedbackVectorSlot slot = expr->AssignmentSlot(); | |
| 443 expr->set_is_uninitialized(FLAG_vector_stores | |
| 444 ? oracle()->StoreIsUninitialized(slot) | |
| 445 : oracle()->StoreIsUninitialized(id)); | |
| 446 if (!expr->IsUninitialized()) { | |
| 447 SmallMapList* receiver_types = expr->GetReceiverTypes(); | |
| 448 if (prop->key()->IsPropertyName()) { | |
| 449 Literal* lit_key = prop->key()->AsLiteral(); | |
| 450 DCHECK(lit_key != NULL && lit_key->value()->IsString()); | |
| 451 Handle<String> name = Handle<String>::cast(lit_key->value()); | |
| 452 if (FLAG_vector_stores) { | |
| 453 oracle()->AssignmentReceiverTypes(slot, name, receiver_types); | |
| 454 } else { | |
| 455 oracle()->AssignmentReceiverTypes(id, name, receiver_types); | |
| 456 } | |
| 457 } else { | |
| 458 KeyedAccessStoreMode store_mode; | |
| 459 IcCheckType key_type; | |
| 460 if (FLAG_vector_stores) { | |
| 461 oracle()->KeyedAssignmentReceiverTypes(slot, receiver_types, | |
| 462 &store_mode, &key_type); | |
| 463 } else { | |
| 464 oracle()->KeyedAssignmentReceiverTypes(id, receiver_types, | |
| 465 &store_mode, &key_type); | |
| 466 } | |
| 467 expr->set_store_mode(store_mode); | |
| 468 expr->set_key_type(key_type); | |
| 469 } | |
| 470 } | |
| 471 } | |
| 472 | |
| 473 Expression* rhs = | |
| 474 expr->is_compound() ? expr->binary_operation() : expr->value(); | |
| 475 RECURSE(Visit(expr->target())); | |
| 476 RECURSE(Visit(rhs)); | |
| 477 NarrowType(expr, rhs->bounds()); | |
| 478 | |
| 479 VariableProxy* proxy = expr->target()->AsVariableProxy(); | |
| 480 if (proxy != NULL && proxy->var()->IsStackAllocated()) { | |
| 481 store_.Seq(variable_index(proxy->var()), Effect(expr->bounds())); | |
| 482 } | |
| 483 } | |
| 484 | |
| 485 | |
| 486 void AstTyper::VisitYield(Yield* expr) { | |
| 487 RECURSE(Visit(expr->generator_object())); | |
| 488 RECURSE(Visit(expr->expression())); | |
| 489 | |
| 490 // We don't know anything about the result type. | |
| 491 } | |
| 492 | |
| 493 | |
| 494 void AstTyper::VisitThrow(Throw* expr) { | |
| 495 RECURSE(Visit(expr->exception())); | |
| 496 // TODO(rossberg): is it worth having a non-termination effect? | |
| 497 | |
| 498 NarrowType(expr, Bounds(Type::None(zone()))); | |
| 499 } | |
| 500 | |
| 501 | |
| 502 void AstTyper::VisitProperty(Property* expr) { | |
| 503 // Collect type feedback. | |
| 504 FeedbackVectorSlot slot = expr->PropertyFeedbackSlot(); | |
| 505 expr->set_inline_cache_state(oracle()->LoadInlineCacheState(slot)); | |
| 506 | |
| 507 if (!expr->IsUninitialized()) { | |
| 508 if (expr->key()->IsPropertyName()) { | |
| 509 Literal* lit_key = expr->key()->AsLiteral(); | |
| 510 DCHECK(lit_key != NULL && lit_key->value()->IsString()); | |
| 511 Handle<String> name = Handle<String>::cast(lit_key->value()); | |
| 512 oracle()->PropertyReceiverTypes(slot, name, expr->GetReceiverTypes()); | |
| 513 } else { | |
| 514 bool is_string; | |
| 515 IcCheckType key_type; | |
| 516 oracle()->KeyedPropertyReceiverTypes(slot, expr->GetReceiverTypes(), | |
| 517 &is_string, &key_type); | |
| 518 expr->set_is_string_access(is_string); | |
| 519 expr->set_key_type(key_type); | |
| 520 } | |
| 521 } | |
| 522 | |
| 523 RECURSE(Visit(expr->obj())); | |
| 524 RECURSE(Visit(expr->key())); | |
| 525 | |
| 526 // We don't know anything about the result type. | |
| 527 } | |
| 528 | |
| 529 | |
| 530 void AstTyper::VisitCall(Call* expr) { | |
| 531 // Collect type feedback. | |
| 532 RECURSE(Visit(expr->expression())); | |
| 533 bool is_uninitialized = true; | |
| 534 if (expr->IsUsingCallFeedbackICSlot(isolate_)) { | |
| 535 FeedbackVectorSlot slot = expr->CallFeedbackICSlot(); | |
| 536 is_uninitialized = oracle()->CallIsUninitialized(slot); | |
| 537 if (!expr->expression()->IsProperty() && | |
| 538 oracle()->CallIsMonomorphic(slot)) { | |
| 539 expr->set_target(oracle()->GetCallTarget(slot)); | |
| 540 Handle<AllocationSite> site = oracle()->GetCallAllocationSite(slot); | |
| 541 expr->set_allocation_site(site); | |
| 542 } | |
| 543 } | |
| 544 | |
| 545 expr->set_is_uninitialized(is_uninitialized); | |
| 546 | |
| 547 ZoneList<Expression*>* args = expr->arguments(); | |
| 548 for (int i = 0; i < args->length(); ++i) { | |
| 549 Expression* arg = args->at(i); | |
| 550 RECURSE(Visit(arg)); | |
| 551 } | |
| 552 | |
| 553 VariableProxy* proxy = expr->expression()->AsVariableProxy(); | |
| 554 if (proxy != NULL && proxy->var()->is_possibly_eval(isolate_)) { | |
| 555 store_.Forget(); // Eval could do whatever to local variables. | |
| 556 } | |
| 557 | |
| 558 // We don't know anything about the result type. | |
| 559 } | |
| 560 | |
| 561 | |
| 562 void AstTyper::VisitCallNew(CallNew* expr) { | |
| 563 // Collect type feedback. | |
| 564 FeedbackVectorSlot allocation_site_feedback_slot = | |
| 565 expr->CallNewFeedbackSlot(); | |
| 566 expr->set_allocation_site( | |
| 567 oracle()->GetCallNewAllocationSite(allocation_site_feedback_slot)); | |
| 568 bool monomorphic = | |
| 569 oracle()->CallNewIsMonomorphic(expr->CallNewFeedbackSlot()); | |
| 570 expr->set_is_monomorphic(monomorphic); | |
| 571 if (monomorphic) { | |
| 572 expr->set_target(oracle()->GetCallNewTarget(expr->CallNewFeedbackSlot())); | |
| 573 } | |
| 574 | |
| 575 RECURSE(Visit(expr->expression())); | |
| 576 ZoneList<Expression*>* args = expr->arguments(); | |
| 577 for (int i = 0; i < args->length(); ++i) { | |
| 578 Expression* arg = args->at(i); | |
| 579 RECURSE(Visit(arg)); | |
| 580 } | |
| 581 | |
| 582 NarrowType(expr, Bounds(Type::None(zone()), Type::Receiver(zone()))); | |
| 583 } | |
| 584 | |
| 585 | |
| 586 void AstTyper::VisitCallRuntime(CallRuntime* expr) { | |
| 587 ZoneList<Expression*>* args = expr->arguments(); | |
| 588 for (int i = 0; i < args->length(); ++i) { | |
| 589 Expression* arg = args->at(i); | |
| 590 RECURSE(Visit(arg)); | |
| 591 } | |
| 592 | |
| 593 // We don't know anything about the result type. | |
| 594 } | |
| 595 | |
| 596 | |
| 597 void AstTyper::VisitUnaryOperation(UnaryOperation* expr) { | |
| 598 // Collect type feedback. | |
| 599 if (expr->op() == Token::NOT) { | |
| 600 // TODO(rossberg): only do in test or value context. | |
| 601 expr->expression()->RecordToBooleanTypeFeedback(oracle()); | |
| 602 } | |
| 603 | |
| 604 RECURSE(Visit(expr->expression())); | |
| 605 | |
| 606 switch (expr->op()) { | |
| 607 case Token::NOT: | |
| 608 case Token::DELETE: | |
| 609 NarrowType(expr, Bounds(Type::Boolean(zone()))); | |
| 610 break; | |
| 611 case Token::VOID: | |
| 612 NarrowType(expr, Bounds(Type::Undefined(zone()))); | |
| 613 break; | |
| 614 case Token::TYPEOF: | |
| 615 NarrowType(expr, Bounds(Type::InternalizedString(zone()))); | |
| 616 break; | |
| 617 default: | |
| 618 UNREACHABLE(); | |
| 619 } | |
| 620 } | |
| 621 | |
| 622 | |
| 623 void AstTyper::VisitCountOperation(CountOperation* expr) { | |
| 624 // Collect type feedback. | |
| 625 TypeFeedbackId store_id = expr->CountStoreFeedbackId(); | |
| 626 FeedbackVectorSlot slot = expr->CountSlot(); | |
| 627 KeyedAccessStoreMode store_mode; | |
| 628 IcCheckType key_type; | |
| 629 if (FLAG_vector_stores) { | |
| 630 oracle()->GetStoreModeAndKeyType(slot, &store_mode, &key_type); | |
| 631 oracle()->CountReceiverTypes(slot, expr->GetReceiverTypes()); | |
| 632 } else { | |
| 633 oracle()->GetStoreModeAndKeyType(store_id, &store_mode, &key_type); | |
| 634 oracle()->CountReceiverTypes(store_id, expr->GetReceiverTypes()); | |
| 635 } | |
| 636 expr->set_store_mode(store_mode); | |
| 637 expr->set_key_type(key_type); | |
| 638 expr->set_type(oracle()->CountType(expr->CountBinOpFeedbackId())); | |
| 639 // TODO(rossberg): merge the count type with the generic expression type. | |
| 640 | |
| 641 RECURSE(Visit(expr->expression())); | |
| 642 | |
| 643 NarrowType(expr, Bounds(Type::SignedSmall(zone()), Type::Number(zone()))); | |
| 644 | |
| 645 VariableProxy* proxy = expr->expression()->AsVariableProxy(); | |
| 646 if (proxy != NULL && proxy->var()->IsStackAllocated()) { | |
| 647 store_.Seq(variable_index(proxy->var()), Effect(expr->bounds())); | |
| 648 } | |
| 649 } | |
| 650 | |
| 651 | |
| 652 void AstTyper::VisitBinaryOperation(BinaryOperation* expr) { | |
| 653 // Collect type feedback. | |
| 654 Type* type; | |
| 655 Type* left_type; | |
| 656 Type* right_type; | |
| 657 Maybe<int> fixed_right_arg = Nothing<int>(); | |
| 658 Handle<AllocationSite> allocation_site; | |
| 659 oracle()->BinaryType(expr->BinaryOperationFeedbackId(), | |
| 660 &left_type, &right_type, &type, &fixed_right_arg, | |
| 661 &allocation_site, expr->op()); | |
| 662 NarrowLowerType(expr, type); | |
| 663 NarrowLowerType(expr->left(), left_type); | |
| 664 NarrowLowerType(expr->right(), right_type); | |
| 665 expr->set_allocation_site(allocation_site); | |
| 666 expr->set_fixed_right_arg(fixed_right_arg); | |
| 667 if (expr->op() == Token::OR || expr->op() == Token::AND) { | |
| 668 expr->left()->RecordToBooleanTypeFeedback(oracle()); | |
| 669 } | |
| 670 | |
| 671 switch (expr->op()) { | |
| 672 case Token::COMMA: | |
| 673 RECURSE(Visit(expr->left())); | |
| 674 RECURSE(Visit(expr->right())); | |
| 675 NarrowType(expr, expr->right()->bounds()); | |
| 676 break; | |
| 677 case Token::OR: | |
| 678 case Token::AND: { | |
| 679 Effects left_effects = EnterEffects(); | |
| 680 RECURSE(Visit(expr->left())); | |
| 681 ExitEffects(); | |
| 682 Effects right_effects = EnterEffects(); | |
| 683 RECURSE(Visit(expr->right())); | |
| 684 ExitEffects(); | |
| 685 left_effects.Alt(right_effects); | |
| 686 store_.Seq(left_effects); | |
| 687 | |
| 688 NarrowType(expr, Bounds::Either( | |
| 689 expr->left()->bounds(), expr->right()->bounds(), zone())); | |
| 690 break; | |
| 691 } | |
| 692 case Token::BIT_OR: | |
| 693 case Token::BIT_AND: { | |
| 694 RECURSE(Visit(expr->left())); | |
| 695 RECURSE(Visit(expr->right())); | |
| 696 Type* upper = Type::Union( | |
| 697 expr->left()->bounds().upper, expr->right()->bounds().upper, zone()); | |
| 698 if (!upper->Is(Type::Signed32())) upper = Type::Signed32(zone()); | |
| 699 Type* lower = Type::Intersect(Type::SignedSmall(zone()), upper, zone()); | |
| 700 NarrowType(expr, Bounds(lower, upper)); | |
| 701 break; | |
| 702 } | |
| 703 case Token::BIT_XOR: | |
| 704 case Token::SHL: | |
| 705 case Token::SAR: | |
| 706 RECURSE(Visit(expr->left())); | |
| 707 RECURSE(Visit(expr->right())); | |
| 708 NarrowType(expr, | |
| 709 Bounds(Type::SignedSmall(zone()), Type::Signed32(zone()))); | |
| 710 break; | |
| 711 case Token::SHR: | |
| 712 RECURSE(Visit(expr->left())); | |
| 713 RECURSE(Visit(expr->right())); | |
| 714 // TODO(rossberg): The upper bound would be Unsigned32, but since there | |
| 715 // is no 'positive Smi' type for the lower bound, we use the smallest | |
| 716 // union of Smi and Unsigned32 as upper bound instead. | |
| 717 NarrowType(expr, Bounds(Type::SignedSmall(zone()), Type::Number(zone()))); | |
| 718 break; | |
| 719 case Token::ADD: { | |
| 720 RECURSE(Visit(expr->left())); | |
| 721 RECURSE(Visit(expr->right())); | |
| 722 Bounds l = expr->left()->bounds(); | |
| 723 Bounds r = expr->right()->bounds(); | |
| 724 Type* lower = | |
| 725 !l.lower->IsInhabited() || !r.lower->IsInhabited() ? | |
| 726 Type::None(zone()) : | |
| 727 l.lower->Is(Type::String()) || r.lower->Is(Type::String()) ? | |
| 728 Type::String(zone()) : | |
| 729 l.lower->Is(Type::Number()) && r.lower->Is(Type::Number()) ? | |
| 730 Type::SignedSmall(zone()) : Type::None(zone()); | |
| 731 Type* upper = | |
| 732 l.upper->Is(Type::String()) || r.upper->Is(Type::String()) ? | |
| 733 Type::String(zone()) : | |
| 734 l.upper->Is(Type::Number()) && r.upper->Is(Type::Number()) ? | |
| 735 Type::Number(zone()) : Type::NumberOrString(zone()); | |
| 736 NarrowType(expr, Bounds(lower, upper)); | |
| 737 break; | |
| 738 } | |
| 739 case Token::SUB: | |
| 740 case Token::MUL: | |
| 741 case Token::DIV: | |
| 742 case Token::MOD: | |
| 743 RECURSE(Visit(expr->left())); | |
| 744 RECURSE(Visit(expr->right())); | |
| 745 NarrowType(expr, Bounds(Type::SignedSmall(zone()), Type::Number(zone()))); | |
| 746 break; | |
| 747 default: | |
| 748 UNREACHABLE(); | |
| 749 } | |
| 750 } | |
| 751 | |
| 752 | |
| 753 void AstTyper::VisitCompareOperation(CompareOperation* expr) { | |
| 754 // Collect type feedback. | |
| 755 Type* left_type; | |
| 756 Type* right_type; | |
| 757 Type* combined_type; | |
| 758 oracle()->CompareType(expr->CompareOperationFeedbackId(), | |
| 759 &left_type, &right_type, &combined_type); | |
| 760 NarrowLowerType(expr->left(), left_type); | |
| 761 NarrowLowerType(expr->right(), right_type); | |
| 762 expr->set_combined_type(combined_type); | |
| 763 | |
| 764 RECURSE(Visit(expr->left())); | |
| 765 RECURSE(Visit(expr->right())); | |
| 766 | |
| 767 NarrowType(expr, Bounds(Type::Boolean(zone()))); | |
| 768 } | |
| 769 | |
| 770 | |
| 771 void AstTyper::VisitSpread(Spread* expr) { RECURSE(Visit(expr->expression())); } | |
| 772 | |
| 773 | |
| 774 void AstTyper::VisitEmptyParentheses(EmptyParentheses* expr) { | |
| 775 UNREACHABLE(); | |
| 776 } | |
| 777 | |
| 778 | |
| 779 void AstTyper::VisitThisFunction(ThisFunction* expr) { | |
| 780 } | |
| 781 | |
| 782 | |
| 783 void AstTyper::VisitSuperPropertyReference(SuperPropertyReference* expr) {} | |
| 784 | |
| 785 | |
| 786 void AstTyper::VisitSuperCallReference(SuperCallReference* expr) {} | |
| 787 | |
| 788 | |
| 789 void AstTyper::VisitDeclarations(ZoneList<Declaration*>* decls) { | |
| 790 for (int i = 0; i < decls->length(); ++i) { | |
| 791 Declaration* decl = decls->at(i); | |
| 792 RECURSE(Visit(decl)); | |
| 793 } | |
| 794 } | |
| 795 | |
| 796 | |
| 797 void AstTyper::VisitVariableDeclaration(VariableDeclaration* declaration) { | |
| 798 } | |
| 799 | |
| 800 | |
| 801 void AstTyper::VisitFunctionDeclaration(FunctionDeclaration* declaration) { | |
| 802 RECURSE(Visit(declaration->fun())); | |
| 803 } | |
| 804 | |
| 805 | |
| 806 void AstTyper::VisitImportDeclaration(ImportDeclaration* declaration) { | |
| 807 } | |
| 808 | |
| 809 | |
| 810 void AstTyper::VisitExportDeclaration(ExportDeclaration* declaration) { | |
| 811 } | |
| 812 | |
| 813 | |
| 814 } // namespace internal | |
| 815 } // namespace v8 | |
| OLD | NEW |