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