blob: 3f3ff6014bcac000b67e1f1e70065188a9e70649 [file] [log] [blame]
jkummerow@chromium.orgc1184022013-05-28 16:58:15 +00001// 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
jkummerow@chromium.orgc1184022013-05-28 16:58:15 +000030#include "parser.h" // for CompileTimeValue; TODO(rossberg): should move
31#include "scopes.h"
32
33namespace v8 {
34namespace internal {
35
36
37AstTyper::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 InitializeAstVisitor();
45}
46
47
48#define CHECK_ALIVE(call) \
49 do { \
50 call; \
51 if (visitor->HasStackOverflow()) return; \
52 } while (false)
53
54
danno@chromium.org41728482013-06-12 22:31:22 +000055void AstTyper::Run(CompilationInfo* info) {
jkummerow@chromium.orgc1184022013-05-28 16:58:15 +000056 AstTyper* visitor = new(info->zone()) AstTyper(info);
57 Scope* scope = info->scope();
58
59 // Handle implicit declaration of the function name in named function
60 // expressions before other declarations.
61 if (scope->is_function_scope() && scope->function() != NULL) {
62 CHECK_ALIVE(visitor->VisitVariableDeclaration(scope->function()));
63 }
64 CHECK_ALIVE(visitor->VisitDeclarations(scope->declarations()));
65 CHECK_ALIVE(visitor->VisitStatements(info->function()->body()));
66}
67
68
69#undef CHECK_ALIVE
70#define CHECK_ALIVE(call) \
71 do { \
72 call; \
73 if (HasStackOverflow()) return; \
74 } while (false)
75
76
77void AstTyper::VisitStatements(ZoneList<Statement*>* stmts) {
78 ASSERT(!HasStackOverflow());
79 for (int i = 0; i < stmts->length(); ++i) {
80 Statement* stmt = stmts->at(i);
81 CHECK_ALIVE(Visit(stmt));
82 }
83}
84
85
86void AstTyper::VisitBlock(Block* stmt) {
87 ASSERT(!HasStackOverflow());
88 CHECK_ALIVE(VisitStatements(stmt->statements()));
89}
90
91
92void AstTyper::VisitExpressionStatement(ExpressionStatement* stmt) {
93 ASSERT(!HasStackOverflow());
94 CHECK_ALIVE(Visit(stmt->expression()));
95}
96
97
98void AstTyper::VisitEmptyStatement(EmptyStatement* stmt) {
99 ASSERT(!HasStackOverflow());
100}
101
102
103void AstTyper::VisitIfStatement(IfStatement* stmt) {
104 ASSERT(!HasStackOverflow());
105 CHECK_ALIVE(Visit(stmt->condition()));
106 CHECK_ALIVE(Visit(stmt->then_statement()));
107 CHECK_ALIVE(Visit(stmt->else_statement()));
108
109 if (!stmt->condition()->ToBooleanIsTrue() &&
110 !stmt->condition()->ToBooleanIsFalse()) {
111 stmt->condition()->RecordToBooleanTypeFeedback(oracle());
112 }
113}
114
115
116void AstTyper::VisitContinueStatement(ContinueStatement* stmt) {
117 ASSERT(!HasStackOverflow());
118}
119
120
121void AstTyper::VisitBreakStatement(BreakStatement* stmt) {
122 ASSERT(!HasStackOverflow());
123}
124
125
126void AstTyper::VisitReturnStatement(ReturnStatement* stmt) {
127 ASSERT(!HasStackOverflow());
128 CHECK_ALIVE(Visit(stmt->expression()));
129
130 // TODO(rossberg): we only need this for inlining into test contexts...
131 stmt->expression()->RecordToBooleanTypeFeedback(oracle());
132}
133
134
135void AstTyper::VisitWithStatement(WithStatement* stmt) {
136 ASSERT(!HasStackOverflow());
137 CHECK_ALIVE(stmt->expression());
138 CHECK_ALIVE(stmt->statement());
139}
140
141
142void AstTyper::VisitSwitchStatement(SwitchStatement* stmt) {
143 ASSERT(!HasStackOverflow());
144 CHECK_ALIVE(Visit(stmt->tag()));
145 ZoneList<CaseClause*>* clauses = stmt->cases();
146 SwitchStatement::SwitchType switch_type = stmt->switch_type();
147 for (int i = 0; i < clauses->length(); ++i) {
148 CaseClause* clause = clauses->at(i);
149 if (!clause->is_default()) {
150 Expression* label = clause->label();
151 CHECK_ALIVE(Visit(label));
152
153 SwitchStatement::SwitchType label_switch_type =
154 label->IsSmiLiteral() ? SwitchStatement::SMI_SWITCH :
155 label->IsStringLiteral() ? SwitchStatement::STRING_SWITCH :
156 SwitchStatement::GENERIC_SWITCH;
157 if (switch_type == SwitchStatement::UNKNOWN_SWITCH)
158 switch_type = label_switch_type;
159 else if (switch_type != label_switch_type)
160 switch_type = SwitchStatement::GENERIC_SWITCH;
161 }
162 CHECK_ALIVE(VisitStatements(clause->statements()));
163 }
164 if (switch_type == SwitchStatement::UNKNOWN_SWITCH)
165 switch_type = SwitchStatement::GENERIC_SWITCH;
166 stmt->set_switch_type(switch_type);
167
168 // TODO(rossberg): can we eliminate this special case and extra loop?
169 if (switch_type == SwitchStatement::SMI_SWITCH) {
170 for (int i = 0; i < clauses->length(); ++i) {
171 CaseClause* clause = clauses->at(i);
172 if (!clause->is_default())
173 clause->RecordTypeFeedback(oracle());
174 }
175 }
176}
177
178
179void AstTyper::VisitDoWhileStatement(DoWhileStatement* stmt) {
180 ASSERT(!HasStackOverflow());
181 CHECK_ALIVE(Visit(stmt->body()));
182 CHECK_ALIVE(Visit(stmt->cond()));
183
184 if (!stmt->cond()->ToBooleanIsTrue()) {
185 stmt->cond()->RecordToBooleanTypeFeedback(oracle());
186 }
187}
188
189
190void AstTyper::VisitWhileStatement(WhileStatement* stmt) {
191 ASSERT(!HasStackOverflow());
192 CHECK_ALIVE(Visit(stmt->cond()));
193 CHECK_ALIVE(Visit(stmt->body()));
194
195 if (!stmt->cond()->ToBooleanIsTrue()) {
196 stmt->cond()->RecordToBooleanTypeFeedback(oracle());
197 }
198}
199
200
201void AstTyper::VisitForStatement(ForStatement* stmt) {
202 ASSERT(!HasStackOverflow());
203 if (stmt->init() != NULL) {
204 CHECK_ALIVE(Visit(stmt->init()));
205 }
206 if (stmt->cond() != NULL) {
207 CHECK_ALIVE(Visit(stmt->cond()));
208
209 stmt->cond()->RecordToBooleanTypeFeedback(oracle());
210 }
211 CHECK_ALIVE(Visit(stmt->body()));
212 if (stmt->next() != NULL) {
213 CHECK_ALIVE(Visit(stmt->next()));
214 }
215}
216
217
218void AstTyper::VisitForInStatement(ForInStatement* stmt) {
219 ASSERT(!HasStackOverflow());
220 CHECK_ALIVE(Visit(stmt->enumerable()));
221 CHECK_ALIVE(Visit(stmt->body()));
222
223 stmt->RecordTypeFeedback(oracle());
224}
225
226
danno@chromium.org1fd77d52013-06-07 16:01:45 +0000227void AstTyper::VisitForOfStatement(ForOfStatement* stmt) {
228 ASSERT(!HasStackOverflow());
229 CHECK_ALIVE(Visit(stmt->iterable()));
230 CHECK_ALIVE(Visit(stmt->body()));
231}
232
233
jkummerow@chromium.orgc1184022013-05-28 16:58:15 +0000234void AstTyper::VisitTryCatchStatement(TryCatchStatement* stmt) {
235 ASSERT(!HasStackOverflow());
236 CHECK_ALIVE(Visit(stmt->try_block()));
237 CHECK_ALIVE(Visit(stmt->catch_block()));
238}
239
240
241void AstTyper::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
242 ASSERT(!HasStackOverflow());
243 CHECK_ALIVE(Visit(stmt->try_block()));
244 CHECK_ALIVE(Visit(stmt->finally_block()));
245}
246
247
248void AstTyper::VisitDebuggerStatement(DebuggerStatement* stmt) {
249 ASSERT(!HasStackOverflow());
250}
251
252
253void AstTyper::VisitFunctionLiteral(FunctionLiteral* expr) {
254 ASSERT(!HasStackOverflow());
255}
256
257
258void AstTyper::VisitSharedFunctionInfoLiteral(SharedFunctionInfoLiteral* expr) {
259 ASSERT(!HasStackOverflow());
260}
261
262
263void AstTyper::VisitConditional(Conditional* expr) {
264 ASSERT(!HasStackOverflow());
265 CHECK_ALIVE(Visit(expr->condition()));
266 CHECK_ALIVE(Visit(expr->then_expression()));
267 CHECK_ALIVE(Visit(expr->else_expression()));
268
269 expr->condition()->RecordToBooleanTypeFeedback(oracle());
270}
271
272
273void AstTyper::VisitVariableProxy(VariableProxy* expr) {
274 ASSERT(!HasStackOverflow());
275}
276
277
278void AstTyper::VisitLiteral(Literal* expr) {
279 ASSERT(!HasStackOverflow());
280}
281
282
283void AstTyper::VisitRegExpLiteral(RegExpLiteral* expr) {
284 ASSERT(!HasStackOverflow());
285}
286
287
288void AstTyper::VisitObjectLiteral(ObjectLiteral* expr) {
289 ASSERT(!HasStackOverflow());
290 ZoneList<ObjectLiteral::Property*>* properties = expr->properties();
291 for (int i = 0; i < properties->length(); ++i) {
292 ObjectLiteral::Property* prop = properties->at(i);
293 CHECK_ALIVE(Visit(prop->value()));
294
295 if ((prop->kind() == ObjectLiteral::Property::MATERIALIZED_LITERAL &&
296 !CompileTimeValue::IsCompileTimeValue(prop->value())) ||
297 prop->kind() == ObjectLiteral::Property::COMPUTED) {
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +0000298 if (prop->key()->value()->IsInternalizedString() && prop->emit_store())
jkummerow@chromium.orgc1184022013-05-28 16:58:15 +0000299 prop->RecordTypeFeedback(oracle());
300 }
301 }
302}
303
304
305void AstTyper::VisitArrayLiteral(ArrayLiteral* expr) {
306 ASSERT(!HasStackOverflow());
307 ZoneList<Expression*>* values = expr->values();
308 for (int i = 0; i < values->length(); ++i) {
309 Expression* value = values->at(i);
310 CHECK_ALIVE(Visit(value));
311 }
312}
313
314
315void AstTyper::VisitAssignment(Assignment* expr) {
316 ASSERT(!HasStackOverflow());
317 CHECK_ALIVE(Visit(expr->target()));
318 CHECK_ALIVE(Visit(expr->value()));
319
320 // TODO(rossberg): Can we clean this up?
321 if (expr->is_compound()) {
322 CHECK_ALIVE(Visit(expr->binary_operation()));
323
324 Expression* target = expr->target();
325 Property* prop = target->AsProperty();
326 if (prop != NULL) {
327 prop->RecordTypeFeedback(oracle(), zone());
328 if (!prop->key()->IsPropertyName()) // i.e., keyed
329 expr->RecordTypeFeedback(oracle(), zone());
330 }
331 return;
332 }
333 if (expr->target()->AsProperty())
334 expr->RecordTypeFeedback(oracle(), zone());
335}
336
337
338void AstTyper::VisitYield(Yield* expr) {
339 ASSERT(!HasStackOverflow());
340 CHECK_ALIVE(Visit(expr->generator_object()));
341 CHECK_ALIVE(Visit(expr->expression()));
342}
343
344
345void AstTyper::VisitThrow(Throw* expr) {
346 ASSERT(!HasStackOverflow());
347 CHECK_ALIVE(Visit(expr->exception()));
348}
349
350
351void AstTyper::VisitProperty(Property* expr) {
352 ASSERT(!HasStackOverflow());
353 CHECK_ALIVE(Visit(expr->obj()));
354 CHECK_ALIVE(Visit(expr->key()));
355
356 expr->RecordTypeFeedback(oracle(), zone());
357}
358
359
360void AstTyper::VisitCall(Call* expr) {
361 ASSERT(!HasStackOverflow());
362 CHECK_ALIVE(Visit(expr->expression()));
363 ZoneList<Expression*>* args = expr->arguments();
364 for (int i = 0; i < args->length(); ++i) {
365 Expression* arg = args->at(i);
366 CHECK_ALIVE(Visit(arg));
367 }
368
369 Expression* callee = expr->expression();
370 Property* prop = callee->AsProperty();
371 if (prop != NULL) {
372 if (prop->key()->IsPropertyName())
373 expr->RecordTypeFeedback(oracle(), CALL_AS_METHOD);
374 } else {
375 expr->RecordTypeFeedback(oracle(), CALL_AS_FUNCTION);
376 }
377}
378
379
380void AstTyper::VisitCallNew(CallNew* expr) {
381 ASSERT(!HasStackOverflow());
382 CHECK_ALIVE(Visit(expr->expression()));
383 ZoneList<Expression*>* args = expr->arguments();
384 for (int i = 0; i < args->length(); ++i) {
385 Expression* arg = args->at(i);
386 CHECK_ALIVE(Visit(arg));
387 }
388
389 expr->RecordTypeFeedback(oracle());
390}
391
392
393void AstTyper::VisitCallRuntime(CallRuntime* expr) {
394 ASSERT(!HasStackOverflow());
395 ZoneList<Expression*>* args = expr->arguments();
396 for (int i = 0; i < args->length(); ++i) {
397 Expression* arg = args->at(i);
398 CHECK_ALIVE(Visit(arg));
399 }
400}
401
402
403void AstTyper::VisitUnaryOperation(UnaryOperation* expr) {
404 ASSERT(!HasStackOverflow());
405 CHECK_ALIVE(Visit(expr->expression()));
406
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +0000407 // Collect type feedback.
408 Handle<Type> op_type = oracle()->UnaryType(expr->UnaryOperationFeedbackId());
409 MergeLowerType(expr->expression(), op_type);
jkummerow@chromium.orgc1184022013-05-28 16:58:15 +0000410 if (expr->op() == Token::NOT) {
411 // TODO(rossberg): only do in test or value context.
412 expr->expression()->RecordToBooleanTypeFeedback(oracle());
413 }
414}
415
416
417void AstTyper::VisitCountOperation(CountOperation* expr) {
418 ASSERT(!HasStackOverflow());
419 CHECK_ALIVE(Visit(expr->expression()));
420
421 expr->RecordTypeFeedback(oracle(), zone());
422 Property* prop = expr->expression()->AsProperty();
423 if (prop != NULL) {
424 prop->RecordTypeFeedback(oracle(), zone());
425 }
426}
427
428
429void AstTyper::VisitBinaryOperation(BinaryOperation* expr) {
430 ASSERT(!HasStackOverflow());
431 CHECK_ALIVE(Visit(expr->left()));
432 CHECK_ALIVE(Visit(expr->right()));
433
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +0000434 // Collect type feedback.
435 Handle<Type> type, left_type, right_type;
436 Maybe<int> fixed_right_arg;
437 oracle()->BinaryType(expr->BinaryOperationFeedbackId(),
438 &left_type, &right_type, &type, &fixed_right_arg);
439 MergeLowerType(expr, type);
440 MergeLowerType(expr->left(), left_type);
441 MergeLowerType(expr->right(), right_type);
442 expr->set_fixed_right_arg(fixed_right_arg);
jkummerow@chromium.orgc1184022013-05-28 16:58:15 +0000443 if (expr->op() == Token::OR || expr->op() == Token::AND) {
444 expr->left()->RecordToBooleanTypeFeedback(oracle());
445 }
446}
447
448
449void AstTyper::VisitCompareOperation(CompareOperation* expr) {
450 ASSERT(!HasStackOverflow());
451 CHECK_ALIVE(Visit(expr->left()));
452 CHECK_ALIVE(Visit(expr->right()));
453
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +0000454 // Collect type feedback.
455 Handle<Type> left_type, right_type, combined_type;
456 oracle()->CompareType(expr->CompareOperationFeedbackId(),
457 &left_type, &right_type, &combined_type);
458 MergeLowerType(expr->left(), left_type);
459 MergeLowerType(expr->right(), right_type);
460 expr->set_combined_type(combined_type);
jkummerow@chromium.orgc1184022013-05-28 16:58:15 +0000461}
462
463
464void AstTyper::VisitThisFunction(ThisFunction* expr) {
465 ASSERT(!HasStackOverflow());
466}
467
468
469void AstTyper::VisitDeclarations(ZoneList<Declaration*>* decls) {
470 ASSERT(!HasStackOverflow());
471 for (int i = 0; i < decls->length(); ++i) {
472 Declaration* decl = decls->at(i);
473 CHECK_ALIVE(Visit(decl));
474 }
475}
476
477
478void AstTyper::VisitVariableDeclaration(VariableDeclaration* declaration) {
479 ASSERT(!HasStackOverflow());
480}
481
482
483void AstTyper::VisitFunctionDeclaration(FunctionDeclaration* declaration) {
484 ASSERT(!HasStackOverflow());
485 CHECK_ALIVE(Visit(declaration->fun()));
486}
487
488
489void AstTyper::VisitModuleDeclaration(ModuleDeclaration* declaration) {
490 ASSERT(!HasStackOverflow());
491 CHECK_ALIVE(Visit(declaration->module()));
492}
493
494
495void AstTyper::VisitImportDeclaration(ImportDeclaration* declaration) {
496 ASSERT(!HasStackOverflow());
497 CHECK_ALIVE(Visit(declaration->module()));
498}
499
500
501void AstTyper::VisitExportDeclaration(ExportDeclaration* declaration) {
502 ASSERT(!HasStackOverflow());
503}
504
505
506void AstTyper::VisitModuleLiteral(ModuleLiteral* module) {
507 ASSERT(!HasStackOverflow());
508 CHECK_ALIVE(Visit(module->body()));
509}
510
511
512void AstTyper::VisitModuleVariable(ModuleVariable* module) {
513 ASSERT(!HasStackOverflow());
514}
515
516
517void AstTyper::VisitModulePath(ModulePath* module) {
518 ASSERT(!HasStackOverflow());
519 CHECK_ALIVE(Visit(module->module()));
520}
521
522
523void AstTyper::VisitModuleUrl(ModuleUrl* module) {
524 ASSERT(!HasStackOverflow());
525}
526
527
528void AstTyper::VisitModuleStatement(ModuleStatement* stmt) {
529 ASSERT(!HasStackOverflow());
530 CHECK_ALIVE(Visit(stmt->body()));
531}
532
533
534} } // namespace v8::internal