blob: 013f50fd5c5c76fde3ed6726f7de469fabb45d4c [file] [log] [blame]
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001// 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
14namespace v8 {
15namespace internal {
16
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017AstTyper::AstTyper(Isolate* isolate, Zone* zone, Handle<JSFunction> closure,
Ben Murdochc5610432016-08-08 18:44:38 +010018 Scope* scope, BailoutId osr_ast_id, FunctionLiteral* root,
19 AstTypeBounds* bounds)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000020 : 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()),
Ben Murdoch61f157c2016-09-16 13:49:30 +010027 handle(closure->feedback_vector()),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000028 handle(closure->context()->native_context())),
Ben Murdochc5610432016-08-08 18:44:38 +010029 store_(zone),
30 bounds_(bounds) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000031 InitializeAstVisitor(isolate);
32}
33
34
35#ifdef OBJECT_PRINT
36 static void PrintObserved(Variable* var, Object* value, Type* type) {
37 OFStream os(stdout);
38 os << " observed " << (var->IsParameter() ? "param" : "local") << " ";
39 var->name()->Print(os);
40 os << " : " << Brief(value) << " -> ";
41 type->PrintTo(os);
42 os << std::endl;
43 }
44#endif // OBJECT_PRINT
45
46
47Effect AstTyper::ObservedOnStack(Object* value) {
48 Type* lower = Type::NowOf(value, zone());
Ben Murdoch097c5b22016-05-18 11:27:45 +010049 return Effect(Bounds(lower, Type::Any()));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000050}
51
52
53void AstTyper::ObserveTypesAtOsrEntry(IterationStatement* stmt) {
54 if (stmt->OsrEntryId() != osr_ast_id_) return;
55
56 DisallowHeapAllocation no_gc;
57 JavaScriptFrameIterator it(isolate_);
58 JavaScriptFrame* frame = it.frame();
59
60 // Assert that the frame on the stack belongs to the function we want to OSR.
61 DCHECK_EQ(*closure_, frame->function());
62
63 int params = scope_->num_parameters();
64 int locals = scope_->StackLocalCount();
65
66 // Use sequential composition to achieve desired narrowing.
67 // The receiver is a parameter with index -1.
68 store_.Seq(parameter_index(-1), ObservedOnStack(frame->receiver()));
69 for (int i = 0; i < params; i++) {
70 store_.Seq(parameter_index(i), ObservedOnStack(frame->GetParameter(i)));
71 }
72
73 for (int i = 0; i < locals; i++) {
74 store_.Seq(stack_local_index(i), ObservedOnStack(frame->GetExpression(i)));
75 }
76
77#ifdef OBJECT_PRINT
78 if (FLAG_trace_osr && FLAG_print_scopes) {
79 PrintObserved(scope_->receiver(), frame->receiver(),
80 store_.LookupBounds(parameter_index(-1)).lower);
81
82 for (int i = 0; i < params; i++) {
83 PrintObserved(scope_->parameter(i), frame->GetParameter(i),
84 store_.LookupBounds(parameter_index(i)).lower);
85 }
86
87 ZoneList<Variable*> local_vars(locals, zone());
88 ZoneList<Variable*> context_vars(scope_->ContextLocalCount(), zone());
89 ZoneList<Variable*> global_vars(scope_->ContextGlobalCount(), zone());
90 scope_->CollectStackAndContextLocals(&local_vars, &context_vars,
91 &global_vars);
92 for (int i = 0; i < locals; i++) {
93 PrintObserved(local_vars.at(i),
94 frame->GetExpression(i),
95 store_.LookupBounds(stack_local_index(i)).lower);
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
110void AstTyper::Run() {
111 RECURSE(VisitDeclarations(scope_->declarations()));
112 RECURSE(VisitStatements(root_->body()));
113}
114
115
116void 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
125void 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
133void AstTyper::VisitExpressionStatement(ExpressionStatement* stmt) {
134 RECURSE(Visit(stmt->expression()));
135}
136
137
138void AstTyper::VisitEmptyStatement(EmptyStatement* stmt) {
139}
140
141
142void AstTyper::VisitSloppyBlockFunctionStatement(
143 SloppyBlockFunctionStatement* stmt) {
144 Visit(stmt->statement());
145}
146
147
148void 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
167void AstTyper::VisitContinueStatement(ContinueStatement* stmt) {
168 // TODO(rossberg): is it worth having a non-termination effect?
169}
170
171
172void AstTyper::VisitBreakStatement(BreakStatement* stmt) {
173 // TODO(rossberg): is it worth having a non-termination effect?
174}
175
176
177void 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
187void AstTyper::VisitWithStatement(WithStatement* stmt) {
188 RECURSE(stmt->expression());
189 RECURSE(stmt->statement());
190}
191
192
193void 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 Type* tag_type;
209 Type* label_type;
210 Type* combined_type;
211 oracle()->CompareType(clause->CompareId(),
212 &tag_type, &label_type, &combined_type);
213 NarrowLowerType(stmt->tag(), tag_type);
214 NarrowLowerType(label, label_type);
215 clause->set_compare_type(combined_type);
216
217 RECURSE(Visit(label));
218 if (!clause_effects.IsEmpty()) complex_effects = true;
219 }
220
221 ZoneList<Statement*>* stmts = clause->statements();
222 RECURSE(VisitStatements(stmts));
223 ExitEffects();
224 if (stmts->is_empty() || stmts->last()->IsJump()) {
225 local_effects.Alt(clause_effects);
226 } else {
227 complex_effects = true;
228 }
229 }
230
231 if (complex_effects) {
232 store_.Forget(); // Reached this in unknown state.
233 } else {
234 store_.Seq(local_effects);
235 }
236}
237
238
239void AstTyper::VisitCaseClause(CaseClause* clause) {
240 UNREACHABLE();
241}
242
243
244void AstTyper::VisitDoWhileStatement(DoWhileStatement* stmt) {
245 // Collect type feedback.
246 if (!stmt->cond()->ToBooleanIsTrue()) {
247 stmt->cond()->RecordToBooleanTypeFeedback(oracle());
248 }
249
250 // TODO(rossberg): refine the unconditional Forget (here and elsewhere) by
251 // computing the set of variables assigned in only some of the origins of the
252 // control transfer (such as the loop body here).
253 store_.Forget(); // Control may transfer here via looping or 'continue'.
254 ObserveTypesAtOsrEntry(stmt);
255 RECURSE(Visit(stmt->body()));
256 RECURSE(Visit(stmt->cond()));
257 store_.Forget(); // Control may transfer here via 'break'.
258}
259
260
261void AstTyper::VisitWhileStatement(WhileStatement* stmt) {
262 // Collect type feedback.
263 if (!stmt->cond()->ToBooleanIsTrue()) {
264 stmt->cond()->RecordToBooleanTypeFeedback(oracle());
265 }
266
267 store_.Forget(); // Control may transfer here via looping or 'continue'.
268 RECURSE(Visit(stmt->cond()));
269 ObserveTypesAtOsrEntry(stmt);
270 RECURSE(Visit(stmt->body()));
271 store_.Forget(); // Control may transfer here via termination or 'break'.
272}
273
274
275void AstTyper::VisitForStatement(ForStatement* stmt) {
276 if (stmt->init() != NULL) {
277 RECURSE(Visit(stmt->init()));
278 }
279 store_.Forget(); // Control may transfer here via looping.
280 if (stmt->cond() != NULL) {
281 // Collect type feedback.
282 stmt->cond()->RecordToBooleanTypeFeedback(oracle());
283
284 RECURSE(Visit(stmt->cond()));
285 }
286 ObserveTypesAtOsrEntry(stmt);
287 RECURSE(Visit(stmt->body()));
288 if (stmt->next() != NULL) {
289 store_.Forget(); // Control may transfer here via 'continue'.
290 RECURSE(Visit(stmt->next()));
291 }
292 store_.Forget(); // Control may transfer here via termination or 'break'.
293}
294
295
296void AstTyper::VisitForInStatement(ForInStatement* stmt) {
297 // Collect type feedback.
298 stmt->set_for_in_type(static_cast<ForInStatement::ForInType>(
299 oracle()->ForInType(stmt->ForInFeedbackSlot())));
300
301 RECURSE(Visit(stmt->enumerable()));
302 store_.Forget(); // Control may transfer here via looping or 'continue'.
303 ObserveTypesAtOsrEntry(stmt);
304 RECURSE(Visit(stmt->body()));
305 store_.Forget(); // Control may transfer here via 'break'.
306}
307
Ben Murdochc5610432016-08-08 18:44:38 +0100308void AstTyper::VisitForOfStatement(ForOfStatement* stmt) {}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000309
310void AstTyper::VisitTryCatchStatement(TryCatchStatement* stmt) {
311 Effects try_effects = EnterEffects();
312 RECURSE(Visit(stmt->try_block()));
313 ExitEffects();
314 Effects catch_effects = EnterEffects();
315 store_.Forget(); // Control may transfer here via 'throw'.
316 RECURSE(Visit(stmt->catch_block()));
317 ExitEffects();
318 try_effects.Alt(catch_effects);
319 store_.Seq(try_effects);
320 // At this point, only variables that were reassigned in the catch block are
321 // still remembered.
322}
323
324
325void AstTyper::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
326 RECURSE(Visit(stmt->try_block()));
327 store_.Forget(); // Control may transfer here via 'throw'.
328 RECURSE(Visit(stmt->finally_block()));
329}
330
331
332void AstTyper::VisitDebuggerStatement(DebuggerStatement* stmt) {
333 store_.Forget(); // May do whatever.
334}
335
336
337void AstTyper::VisitFunctionLiteral(FunctionLiteral* expr) {}
338
339
340void AstTyper::VisitClassLiteral(ClassLiteral* expr) {}
341
342
343void AstTyper::VisitNativeFunctionLiteral(NativeFunctionLiteral* expr) {
344}
345
346
347void AstTyper::VisitDoExpression(DoExpression* expr) {
348 RECURSE(VisitBlock(expr->block()));
349 RECURSE(VisitVariableProxy(expr->result()));
Ben Murdochc5610432016-08-08 18:44:38 +0100350 NarrowType(expr, bounds_->get(expr->result()));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000351}
352
353
354void AstTyper::VisitConditional(Conditional* expr) {
355 // Collect type feedback.
356 expr->condition()->RecordToBooleanTypeFeedback(oracle());
357
358 RECURSE(Visit(expr->condition()));
359 Effects then_effects = EnterEffects();
360 RECURSE(Visit(expr->then_expression()));
361 ExitEffects();
362 Effects else_effects = EnterEffects();
363 RECURSE(Visit(expr->else_expression()));
364 ExitEffects();
365 then_effects.Alt(else_effects);
366 store_.Seq(then_effects);
367
Ben Murdochc5610432016-08-08 18:44:38 +0100368 NarrowType(expr,
369 Bounds::Either(bounds_->get(expr->then_expression()),
370 bounds_->get(expr->else_expression()), zone()));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000371}
372
373
374void AstTyper::VisitVariableProxy(VariableProxy* expr) {
375 Variable* var = expr->var();
376 if (var->IsStackAllocated()) {
377 NarrowType(expr, store_.LookupBounds(variable_index(var)));
378 }
379}
380
381
382void AstTyper::VisitLiteral(Literal* expr) {
383 Type* type = Type::Constant(expr->value(), zone());
384 NarrowType(expr, Bounds(type));
385}
386
387
388void AstTyper::VisitRegExpLiteral(RegExpLiteral* expr) {
389 // TODO(rossberg): Reintroduce RegExp type.
Ben Murdoch097c5b22016-05-18 11:27:45 +0100390 NarrowType(expr, Bounds(Type::Object()));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000391}
392
393
394void AstTyper::VisitObjectLiteral(ObjectLiteral* expr) {
395 ZoneList<ObjectLiteral::Property*>* properties = expr->properties();
396 for (int i = 0; i < properties->length(); ++i) {
397 ObjectLiteral::Property* prop = properties->at(i);
398
399 // Collect type feedback.
400 if ((prop->kind() == ObjectLiteral::Property::MATERIALIZED_LITERAL &&
401 !CompileTimeValue::IsCompileTimeValue(prop->value())) ||
402 prop->kind() == ObjectLiteral::Property::COMPUTED) {
403 if (!prop->is_computed_name() &&
404 prop->key()->AsLiteral()->value()->IsInternalizedString() &&
405 prop->emit_store()) {
406 // Record type feed back for the property.
407 FeedbackVectorSlot slot = prop->GetSlot();
408 SmallMapList maps;
409 oracle()->CollectReceiverTypes(slot, &maps);
410 prop->set_receiver_type(maps.length() == 1 ? maps.at(0)
411 : Handle<Map>::null());
412 }
413 }
414
415 RECURSE(Visit(prop->value()));
416 }
417
Ben Murdoch097c5b22016-05-18 11:27:45 +0100418 NarrowType(expr, Bounds(Type::Object()));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000419}
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
Ben Murdoch097c5b22016-05-18 11:27:45 +0100429 NarrowType(expr, Bounds(Type::Object()));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000430}
431
432
433void AstTyper::VisitAssignment(Assignment* expr) {
434 // Collect type feedback.
435 Property* prop = expr->target()->AsProperty();
436 if (prop != NULL) {
437 FeedbackVectorSlot slot = expr->AssignmentSlot();
438 expr->set_is_uninitialized(oracle()->StoreIsUninitialized(slot));
439 if (!expr->IsUninitialized()) {
440 SmallMapList* receiver_types = expr->GetReceiverTypes();
441 if (prop->key()->IsPropertyName()) {
442 Literal* lit_key = prop->key()->AsLiteral();
443 DCHECK(lit_key != NULL && lit_key->value()->IsString());
444 Handle<String> name = Handle<String>::cast(lit_key->value());
445 oracle()->AssignmentReceiverTypes(slot, name, receiver_types);
446 } else {
447 KeyedAccessStoreMode store_mode;
448 IcCheckType key_type;
449 oracle()->KeyedAssignmentReceiverTypes(slot, receiver_types,
450 &store_mode, &key_type);
451 expr->set_store_mode(store_mode);
452 expr->set_key_type(key_type);
453 }
454 }
455 }
456
457 Expression* rhs =
458 expr->is_compound() ? expr->binary_operation() : expr->value();
459 RECURSE(Visit(expr->target()));
460 RECURSE(Visit(rhs));
Ben Murdochc5610432016-08-08 18:44:38 +0100461 NarrowType(expr, bounds_->get(rhs));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000462
463 VariableProxy* proxy = expr->target()->AsVariableProxy();
464 if (proxy != NULL && proxy->var()->IsStackAllocated()) {
Ben Murdochc5610432016-08-08 18:44:38 +0100465 store_.Seq(variable_index(proxy->var()), Effect(bounds_->get(expr)));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000466 }
467}
468
469
470void AstTyper::VisitYield(Yield* expr) {
471 RECURSE(Visit(expr->generator_object()));
472 RECURSE(Visit(expr->expression()));
473
474 // We don't know anything about the result type.
475}
476
477
478void AstTyper::VisitThrow(Throw* expr) {
479 RECURSE(Visit(expr->exception()));
480 // TODO(rossberg): is it worth having a non-termination effect?
481
Ben Murdoch097c5b22016-05-18 11:27:45 +0100482 NarrowType(expr, Bounds(Type::None()));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000483}
484
485
486void AstTyper::VisitProperty(Property* expr) {
487 // Collect type feedback.
488 FeedbackVectorSlot slot = expr->PropertyFeedbackSlot();
489 expr->set_inline_cache_state(oracle()->LoadInlineCacheState(slot));
490
491 if (!expr->IsUninitialized()) {
492 if (expr->key()->IsPropertyName()) {
493 Literal* lit_key = expr->key()->AsLiteral();
494 DCHECK(lit_key != NULL && lit_key->value()->IsString());
495 Handle<String> name = Handle<String>::cast(lit_key->value());
496 oracle()->PropertyReceiverTypes(slot, name, expr->GetReceiverTypes());
497 } else {
498 bool is_string;
499 IcCheckType key_type;
500 oracle()->KeyedPropertyReceiverTypes(slot, expr->GetReceiverTypes(),
501 &is_string, &key_type);
502 expr->set_is_string_access(is_string);
503 expr->set_key_type(key_type);
504 }
505 }
506
507 RECURSE(Visit(expr->obj()));
508 RECURSE(Visit(expr->key()));
509
510 // We don't know anything about the result type.
511}
512
513
514void AstTyper::VisitCall(Call* expr) {
515 // Collect type feedback.
516 RECURSE(Visit(expr->expression()));
517 bool is_uninitialized = true;
518 if (expr->IsUsingCallFeedbackICSlot(isolate_)) {
519 FeedbackVectorSlot slot = expr->CallFeedbackICSlot();
520 is_uninitialized = oracle()->CallIsUninitialized(slot);
521 if (!expr->expression()->IsProperty() &&
522 oracle()->CallIsMonomorphic(slot)) {
523 expr->set_target(oracle()->GetCallTarget(slot));
524 Handle<AllocationSite> site = oracle()->GetCallAllocationSite(slot);
525 expr->set_allocation_site(site);
526 }
527 }
528
529 expr->set_is_uninitialized(is_uninitialized);
530
531 ZoneList<Expression*>* args = expr->arguments();
532 for (int i = 0; i < args->length(); ++i) {
533 Expression* arg = args->at(i);
534 RECURSE(Visit(arg));
535 }
536
537 VariableProxy* proxy = expr->expression()->AsVariableProxy();
538 if (proxy != NULL && proxy->var()->is_possibly_eval(isolate_)) {
539 store_.Forget(); // Eval could do whatever to local variables.
540 }
541
542 // We don't know anything about the result type.
543}
544
545
546void AstTyper::VisitCallNew(CallNew* expr) {
547 // Collect type feedback.
548 FeedbackVectorSlot allocation_site_feedback_slot =
549 expr->CallNewFeedbackSlot();
550 expr->set_allocation_site(
551 oracle()->GetCallNewAllocationSite(allocation_site_feedback_slot));
552 bool monomorphic =
553 oracle()->CallNewIsMonomorphic(expr->CallNewFeedbackSlot());
554 expr->set_is_monomorphic(monomorphic);
555 if (monomorphic) {
556 expr->set_target(oracle()->GetCallNewTarget(expr->CallNewFeedbackSlot()));
557 }
558
559 RECURSE(Visit(expr->expression()));
560 ZoneList<Expression*>* args = expr->arguments();
561 for (int i = 0; i < args->length(); ++i) {
562 Expression* arg = args->at(i);
563 RECURSE(Visit(arg));
564 }
565
Ben Murdoch097c5b22016-05-18 11:27:45 +0100566 NarrowType(expr, Bounds(Type::None(), Type::Receiver()));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000567}
568
569
570void AstTyper::VisitCallRuntime(CallRuntime* expr) {
571 ZoneList<Expression*>* args = expr->arguments();
572 for (int i = 0; i < args->length(); ++i) {
573 Expression* arg = args->at(i);
574 RECURSE(Visit(arg));
575 }
576
577 // We don't know anything about the result type.
578}
579
580
581void AstTyper::VisitUnaryOperation(UnaryOperation* expr) {
582 // Collect type feedback.
583 if (expr->op() == Token::NOT) {
584 // TODO(rossberg): only do in test or value context.
585 expr->expression()->RecordToBooleanTypeFeedback(oracle());
586 }
587
588 RECURSE(Visit(expr->expression()));
589
590 switch (expr->op()) {
591 case Token::NOT:
592 case Token::DELETE:
Ben Murdoch097c5b22016-05-18 11:27:45 +0100593 NarrowType(expr, Bounds(Type::Boolean()));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000594 break;
595 case Token::VOID:
Ben Murdoch097c5b22016-05-18 11:27:45 +0100596 NarrowType(expr, Bounds(Type::Undefined()));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000597 break;
598 case Token::TYPEOF:
Ben Murdoch097c5b22016-05-18 11:27:45 +0100599 NarrowType(expr, Bounds(Type::InternalizedString()));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000600 break;
601 default:
602 UNREACHABLE();
603 }
604}
605
606
607void AstTyper::VisitCountOperation(CountOperation* expr) {
608 // Collect type feedback.
609 FeedbackVectorSlot slot = expr->CountSlot();
610 KeyedAccessStoreMode store_mode;
611 IcCheckType key_type;
612 oracle()->GetStoreModeAndKeyType(slot, &store_mode, &key_type);
613 oracle()->CountReceiverTypes(slot, expr->GetReceiverTypes());
614 expr->set_store_mode(store_mode);
615 expr->set_key_type(key_type);
616 expr->set_type(oracle()->CountType(expr->CountBinOpFeedbackId()));
617 // TODO(rossberg): merge the count type with the generic expression type.
618
619 RECURSE(Visit(expr->expression()));
620
Ben Murdoch097c5b22016-05-18 11:27:45 +0100621 NarrowType(expr, Bounds(Type::SignedSmall(), Type::Number()));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000622
623 VariableProxy* proxy = expr->expression()->AsVariableProxy();
624 if (proxy != NULL && proxy->var()->IsStackAllocated()) {
Ben Murdochc5610432016-08-08 18:44:38 +0100625 store_.Seq(variable_index(proxy->var()), Effect(bounds_->get(expr)));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000626 }
627}
628
629
630void AstTyper::VisitBinaryOperation(BinaryOperation* expr) {
631 // Collect type feedback.
632 Type* type;
633 Type* left_type;
634 Type* right_type;
635 Maybe<int> fixed_right_arg = Nothing<int>();
636 Handle<AllocationSite> allocation_site;
637 oracle()->BinaryType(expr->BinaryOperationFeedbackId(),
638 &left_type, &right_type, &type, &fixed_right_arg,
639 &allocation_site, expr->op());
640 NarrowLowerType(expr, type);
641 NarrowLowerType(expr->left(), left_type);
642 NarrowLowerType(expr->right(), right_type);
643 expr->set_allocation_site(allocation_site);
644 expr->set_fixed_right_arg(fixed_right_arg);
645 if (expr->op() == Token::OR || expr->op() == Token::AND) {
646 expr->left()->RecordToBooleanTypeFeedback(oracle());
647 }
648
649 switch (expr->op()) {
650 case Token::COMMA:
651 RECURSE(Visit(expr->left()));
652 RECURSE(Visit(expr->right()));
Ben Murdochc5610432016-08-08 18:44:38 +0100653 NarrowType(expr, bounds_->get(expr->right()));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000654 break;
655 case Token::OR:
656 case Token::AND: {
657 Effects left_effects = EnterEffects();
658 RECURSE(Visit(expr->left()));
659 ExitEffects();
660 Effects right_effects = EnterEffects();
661 RECURSE(Visit(expr->right()));
662 ExitEffects();
663 left_effects.Alt(right_effects);
664 store_.Seq(left_effects);
665
Ben Murdochc5610432016-08-08 18:44:38 +0100666 NarrowType(expr, Bounds::Either(bounds_->get(expr->left()),
667 bounds_->get(expr->right()), zone()));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000668 break;
669 }
670 case Token::BIT_OR:
671 case Token::BIT_AND: {
672 RECURSE(Visit(expr->left()));
673 RECURSE(Visit(expr->right()));
Ben Murdochc5610432016-08-08 18:44:38 +0100674 Type* upper = Type::Union(bounds_->get(expr->left()).upper,
675 bounds_->get(expr->right()).upper, zone());
Ben Murdoch097c5b22016-05-18 11:27:45 +0100676 if (!upper->Is(Type::Signed32())) upper = Type::Signed32();
677 Type* lower = Type::Intersect(Type::SignedSmall(), upper, zone());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000678 NarrowType(expr, Bounds(lower, upper));
679 break;
680 }
681 case Token::BIT_XOR:
682 case Token::SHL:
683 case Token::SAR:
684 RECURSE(Visit(expr->left()));
685 RECURSE(Visit(expr->right()));
Ben Murdoch097c5b22016-05-18 11:27:45 +0100686 NarrowType(expr, Bounds(Type::SignedSmall(), Type::Signed32()));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000687 break;
688 case Token::SHR:
689 RECURSE(Visit(expr->left()));
690 RECURSE(Visit(expr->right()));
691 // TODO(rossberg): The upper bound would be Unsigned32, but since there
692 // is no 'positive Smi' type for the lower bound, we use the smallest
693 // union of Smi and Unsigned32 as upper bound instead.
Ben Murdoch097c5b22016-05-18 11:27:45 +0100694 NarrowType(expr, Bounds(Type::SignedSmall(), Type::Number()));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000695 break;
696 case Token::ADD: {
697 RECURSE(Visit(expr->left()));
698 RECURSE(Visit(expr->right()));
Ben Murdochc5610432016-08-08 18:44:38 +0100699 Bounds l = bounds_->get(expr->left());
700 Bounds r = bounds_->get(expr->right());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000701 Type* lower =
Ben Murdoch097c5b22016-05-18 11:27:45 +0100702 !l.lower->IsInhabited() || !r.lower->IsInhabited()
703 ? Type::None()
704 : l.lower->Is(Type::String()) || r.lower->Is(Type::String())
705 ? Type::String()
706 : l.lower->Is(Type::Number()) && r.lower->Is(Type::Number())
707 ? Type::SignedSmall()
708 : Type::None();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000709 Type* upper =
Ben Murdoch097c5b22016-05-18 11:27:45 +0100710 l.upper->Is(Type::String()) || r.upper->Is(Type::String())
711 ? Type::String()
712 : l.upper->Is(Type::Number()) && r.upper->Is(Type::Number())
713 ? Type::Number()
714 : Type::NumberOrString();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000715 NarrowType(expr, Bounds(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()));
Ben Murdoch097c5b22016-05-18 11:27:45 +0100724 NarrowType(expr, Bounds(Type::SignedSmall(), Type::Number()));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000725 break;
726 default:
727 UNREACHABLE();
728 }
729}
730
731
732void AstTyper::VisitCompareOperation(CompareOperation* expr) {
733 // Collect type feedback.
734 Type* left_type;
735 Type* right_type;
736 Type* combined_type;
737 oracle()->CompareType(expr->CompareOperationFeedbackId(),
738 &left_type, &right_type, &combined_type);
739 NarrowLowerType(expr->left(), left_type);
740 NarrowLowerType(expr->right(), right_type);
741 expr->set_combined_type(combined_type);
742
743 RECURSE(Visit(expr->left()));
744 RECURSE(Visit(expr->right()));
745
Ben Murdoch097c5b22016-05-18 11:27:45 +0100746 NarrowType(expr, Bounds(Type::Boolean()));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000747}
748
749
Ben Murdoch097c5b22016-05-18 11:27:45 +0100750void AstTyper::VisitSpread(Spread* expr) { UNREACHABLE(); }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000751
752
753void AstTyper::VisitEmptyParentheses(EmptyParentheses* expr) {
754 UNREACHABLE();
755}
756
757
Ben Murdoch097c5b22016-05-18 11:27:45 +0100758void AstTyper::VisitThisFunction(ThisFunction* expr) {}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000759
760
761void AstTyper::VisitSuperPropertyReference(SuperPropertyReference* expr) {}
762
763
764void AstTyper::VisitSuperCallReference(SuperCallReference* expr) {}
765
766
Ben Murdoch097c5b22016-05-18 11:27:45 +0100767void AstTyper::VisitRewritableExpression(RewritableExpression* expr) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000768 Visit(expr->expression());
769}
770
771
772void AstTyper::VisitDeclarations(ZoneList<Declaration*>* decls) {
773 for (int i = 0; i < decls->length(); ++i) {
774 Declaration* decl = decls->at(i);
775 RECURSE(Visit(decl));
776 }
777}
778
779
780void AstTyper::VisitVariableDeclaration(VariableDeclaration* declaration) {
781}
782
783
784void AstTyper::VisitFunctionDeclaration(FunctionDeclaration* declaration) {
785 RECURSE(Visit(declaration->fun()));
786}
787
788
789void AstTyper::VisitImportDeclaration(ImportDeclaration* declaration) {
790}
791
792
793void AstTyper::VisitExportDeclaration(ExportDeclaration* declaration) {
794}
795
796
797} // namespace internal
798} // namespace v8