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