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