The data contained in this repository can be downloaded to your computer using one of several clients.
Please see the documentation of your version control software client for more information.
Please select the desired protocol below to get the URL.
This URL has Read-Only access.
main_repo / deps / v8 / src / typing.cc @ f230a1cf
History | View | Annotate | Download (21 KB)
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
96 |
void AstTyper::VisitExpressionStatement(ExpressionStatement* stmt) {
|
97 |
RECURSE(Visit(stmt->expression())); |
98 |
} |
99 |
|
100 |
|
101 |
void AstTyper::VisitEmptyStatement(EmptyStatement* stmt) {
|
102 |
} |
103 |
|
104 |
|
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 |
|
124 |
void AstTyper::VisitContinueStatement(ContinueStatement* stmt) {
|
125 |
// TODO(rossberg): is it worth having a non-termination effect?
|
126 |
} |
127 |
|
128 |
|
129 |
void AstTyper::VisitBreakStatement(BreakStatement* stmt) {
|
130 |
// TODO(rossberg): is it worth having a non-termination effect?
|
131 |
} |
132 |
|
133 |
|
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 |
|
144 |
void AstTyper::VisitWithStatement(WithStatement* stmt) {
|
145 |
RECURSE(stmt->expression()); |
146 |
RECURSE(stmt->statement()); |
147 |
} |
148 |
|
149 |
|
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->RecordTypeFeedback(oracle()); |
204 |
} |
205 |
} |
206 |
} |
207 |
|
208 |
|
209 |
void AstTyper::VisitCaseClause(CaseClause* clause) {
|
210 |
UNREACHABLE(); |
211 |
} |
212 |
|
213 |
|
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 |
|
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 |
|
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 |
|
263 |
void AstTyper::VisitForInStatement(ForInStatement* stmt) {
|
264 |
// Collect type feedback.
|
265 |
stmt->RecordTypeFeedback(oracle()); |
266 |
|
267 |
RECURSE(Visit(stmt->enumerable())); |
268 |
store_.Forget(); // Control may transfer here via looping or 'continue'.
|
269 |
RECURSE(Visit(stmt->body())); |
270 |
store_.Forget(); // Control may transfer here via 'break'.
|
271 |
} |
272 |
|
273 |
|
274 |
void AstTyper::VisitForOfStatement(ForOfStatement* stmt) {
|
275 |
RECURSE(Visit(stmt->iterable())); |
276 |
store_.Forget(); // Control may transfer here via looping or 'continue'.
|
277 |
RECURSE(Visit(stmt->body())); |
278 |
store_.Forget(); // Control may transfer here via 'break'.
|
279 |
} |
280 |
|
281 |
|
282 |
void AstTyper::VisitTryCatchStatement(TryCatchStatement* stmt) {
|
283 |
Effects try_effects = EnterEffects(); |
284 |
RECURSE(Visit(stmt->try_block())); |
285 |
ExitEffects(); |
286 |
Effects catch_effects = EnterEffects(); |
287 |
store_.Forget(); // Control may transfer here via 'throw'.
|
288 |
RECURSE(Visit(stmt->catch_block())); |
289 |
ExitEffects(); |
290 |
try_effects.Alt(catch_effects); |
291 |
store_.Seq(try_effects); |
292 |
// At this point, only variables that were reassigned in the catch block are
|
293 |
// still remembered.
|
294 |
} |
295 |
|
296 |
|
297 |
void AstTyper::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
|
298 |
RECURSE(Visit(stmt->try_block())); |
299 |
store_.Forget(); // Control may transfer here via 'throw'.
|
300 |
RECURSE(Visit(stmt->finally_block())); |
301 |
} |
302 |
|
303 |
|
304 |
void AstTyper::VisitDebuggerStatement(DebuggerStatement* stmt) {
|
305 |
store_.Forget(); // May do whatever.
|
306 |
} |
307 |
|
308 |
|
309 |
void AstTyper::VisitFunctionLiteral(FunctionLiteral* expr) {
|
310 |
} |
311 |
|
312 |
|
313 |
void AstTyper::VisitNativeFunctionLiteral(NativeFunctionLiteral* expr) {
|
314 |
} |
315 |
|
316 |
|
317 |
void AstTyper::VisitConditional(Conditional* expr) {
|
318 |
// Collect type feedback.
|
319 |
expr->condition()->RecordToBooleanTypeFeedback(oracle()); |
320 |
|
321 |
RECURSE(Visit(expr->condition())); |
322 |
Effects then_effects = EnterEffects(); |
323 |
RECURSE(Visit(expr->then_expression())); |
324 |
ExitEffects(); |
325 |
Effects else_effects = EnterEffects(); |
326 |
RECURSE(Visit(expr->else_expression())); |
327 |
ExitEffects(); |
328 |
then_effects.Alt(else_effects); |
329 |
store_.Seq(then_effects); |
330 |
|
331 |
NarrowType(expr, Bounds::Either( |
332 |
expr->then_expression()->bounds(), |
333 |
expr->else_expression()->bounds(), isolate_)); |
334 |
} |
335 |
|
336 |
|
337 |
void AstTyper::VisitVariableProxy(VariableProxy* expr) {
|
338 |
Variable* var = expr->var(); |
339 |
if (var->IsStackAllocated()) {
|
340 |
NarrowType(expr, store_.LookupBounds(variable_index(var))); |
341 |
} |
342 |
} |
343 |
|
344 |
|
345 |
void AstTyper::VisitLiteral(Literal* expr) {
|
346 |
Type* type = Type::Constant(expr->value(), isolate_); |
347 |
NarrowType(expr, Bounds(type, isolate_)); |
348 |
} |
349 |
|
350 |
|
351 |
void AstTyper::VisitRegExpLiteral(RegExpLiteral* expr) {
|
352 |
NarrowType(expr, Bounds(Type::RegExp(), isolate_)); |
353 |
} |
354 |
|
355 |
|
356 |
void AstTyper::VisitObjectLiteral(ObjectLiteral* expr) {
|
357 |
ZoneList<ObjectLiteral::Property*>* properties = expr->properties(); |
358 |
for (int i = 0; i < properties->length(); ++i) { |
359 |
ObjectLiteral::Property* prop = properties->at(i); |
360 |
|
361 |
// Collect type feedback.
|
362 |
if ((prop->kind() == ObjectLiteral::Property::MATERIALIZED_LITERAL &&
|
363 |
!CompileTimeValue::IsCompileTimeValue(prop->value())) || |
364 |
prop->kind() == ObjectLiteral::Property::COMPUTED) { |
365 |
if (prop->key()->value()->IsInternalizedString() && prop->emit_store()) {
|
366 |
prop->RecordTypeFeedback(oracle()); |
367 |
} |
368 |
} |
369 |
|
370 |
RECURSE(Visit(prop->value())); |
371 |
} |
372 |
|
373 |
NarrowType(expr, Bounds(Type::Object(), isolate_)); |
374 |
} |
375 |
|
376 |
|
377 |
void AstTyper::VisitArrayLiteral(ArrayLiteral* expr) {
|
378 |
ZoneList<Expression*>* values = expr->values(); |
379 |
for (int i = 0; i < values->length(); ++i) { |
380 |
Expression* value = values->at(i); |
381 |
RECURSE(Visit(value)); |
382 |
} |
383 |
|
384 |
NarrowType(expr, Bounds(Type::Array(), isolate_)); |
385 |
} |
386 |
|
387 |
|
388 |
void AstTyper::VisitAssignment(Assignment* expr) {
|
389 |
// TODO(rossberg): Can we clean this up?
|
390 |
if (expr->is_compound()) {
|
391 |
// Collect type feedback.
|
392 |
Expression* target = expr->target(); |
393 |
Property* prop = target->AsProperty(); |
394 |
if (prop != NULL) { |
395 |
prop->RecordTypeFeedback(oracle(), zone()); |
396 |
expr->RecordTypeFeedback(oracle(), zone()); |
397 |
} |
398 |
|
399 |
RECURSE(Visit(expr->binary_operation())); |
400 |
|
401 |
NarrowType(expr, expr->binary_operation()->bounds()); |
402 |
} else {
|
403 |
// Collect type feedback.
|
404 |
if (expr->target()->IsProperty()) {
|
405 |
expr->RecordTypeFeedback(oracle(), zone()); |
406 |
} |
407 |
|
408 |
RECURSE(Visit(expr->target())); |
409 |
RECURSE(Visit(expr->value())); |
410 |
|
411 |
NarrowType(expr, expr->value()->bounds()); |
412 |
} |
413 |
|
414 |
VariableProxy* proxy = expr->target()->AsVariableProxy(); |
415 |
if (proxy != NULL && proxy->var()->IsStackAllocated()) { |
416 |
store_.Seq(variable_index(proxy->var()), Effect(expr->bounds())); |
417 |
} |
418 |
} |
419 |
|
420 |
|
421 |
void AstTyper::VisitYield(Yield* expr) {
|
422 |
RECURSE(Visit(expr->generator_object())); |
423 |
RECURSE(Visit(expr->expression())); |
424 |
|
425 |
// We don't know anything about the result type.
|
426 |
} |
427 |
|
428 |
|
429 |
void AstTyper::VisitThrow(Throw* expr) {
|
430 |
RECURSE(Visit(expr->exception())); |
431 |
// TODO(rossberg): is it worth having a non-termination effect?
|
432 |
|
433 |
NarrowType(expr, Bounds(Type::None(), isolate_)); |
434 |
} |
435 |
|
436 |
|
437 |
void AstTyper::VisitProperty(Property* expr) {
|
438 |
// Collect type feedback.
|
439 |
expr->RecordTypeFeedback(oracle(), zone()); |
440 |
|
441 |
RECURSE(Visit(expr->obj())); |
442 |
RECURSE(Visit(expr->key())); |
443 |
|
444 |
// We don't know anything about the result type.
|
445 |
} |
446 |
|
447 |
|
448 |
void AstTyper::VisitCall(Call* expr) {
|
449 |
// Collect type feedback.
|
450 |
Expression* callee = expr->expression(); |
451 |
Property* prop = callee->AsProperty(); |
452 |
if (prop != NULL) { |
453 |
if (prop->key()->IsPropertyName())
|
454 |
expr->RecordTypeFeedback(oracle(), CALL_AS_METHOD); |
455 |
} else {
|
456 |
expr->RecordTypeFeedback(oracle(), CALL_AS_FUNCTION); |
457 |
} |
458 |
|
459 |
RECURSE(Visit(expr->expression())); |
460 |
ZoneList<Expression*>* args = expr->arguments(); |
461 |
for (int i = 0; i < args->length(); ++i) { |
462 |
Expression* arg = args->at(i); |
463 |
RECURSE(Visit(arg)); |
464 |
} |
465 |
|
466 |
VariableProxy* proxy = expr->expression()->AsVariableProxy(); |
467 |
if (proxy != NULL && proxy->var()->is_possibly_eval(isolate())) { |
468 |
store_.Forget(); // Eval could do whatever to local variables.
|
469 |
} |
470 |
|
471 |
// We don't know anything about the result type.
|
472 |
} |
473 |
|
474 |
|
475 |
void AstTyper::VisitCallNew(CallNew* expr) {
|
476 |
// Collect type feedback.
|
477 |
expr->RecordTypeFeedback(oracle()); |
478 |
|
479 |
RECURSE(Visit(expr->expression())); |
480 |
ZoneList<Expression*>* args = expr->arguments(); |
481 |
for (int i = 0; i < args->length(); ++i) { |
482 |
Expression* arg = args->at(i); |
483 |
RECURSE(Visit(arg)); |
484 |
} |
485 |
|
486 |
// We don't know anything about the result type.
|
487 |
} |
488 |
|
489 |
|
490 |
void AstTyper::VisitCallRuntime(CallRuntime* expr) {
|
491 |
ZoneList<Expression*>* args = expr->arguments(); |
492 |
for (int i = 0; i < args->length(); ++i) { |
493 |
Expression* arg = args->at(i); |
494 |
RECURSE(Visit(arg)); |
495 |
} |
496 |
|
497 |
// We don't know anything about the result type.
|
498 |
} |
499 |
|
500 |
|
501 |
void AstTyper::VisitUnaryOperation(UnaryOperation* expr) {
|
502 |
// Collect type feedback.
|
503 |
if (expr->op() == Token::NOT) {
|
504 |
// TODO(rossberg): only do in test or value context.
|
505 |
expr->expression()->RecordToBooleanTypeFeedback(oracle()); |
506 |
} |
507 |
|
508 |
RECURSE(Visit(expr->expression())); |
509 |
|
510 |
switch (expr->op()) {
|
511 |
case Token::NOT:
|
512 |
case Token::DELETE:
|
513 |
NarrowType(expr, Bounds(Type::Boolean(), isolate_)); |
514 |
break;
|
515 |
case Token::VOID:
|
516 |
NarrowType(expr, Bounds(Type::Undefined(), isolate_)); |
517 |
break;
|
518 |
case Token::TYPEOF:
|
519 |
NarrowType(expr, Bounds(Type::InternalizedString(), isolate_)); |
520 |
break;
|
521 |
default:
|
522 |
UNREACHABLE(); |
523 |
} |
524 |
} |
525 |
|
526 |
|
527 |
void AstTyper::VisitCountOperation(CountOperation* expr) {
|
528 |
// Collect type feedback.
|
529 |
expr->RecordTypeFeedback(oracle(), zone()); |
530 |
Property* prop = expr->expression()->AsProperty(); |
531 |
if (prop != NULL) { |
532 |
prop->RecordTypeFeedback(oracle(), zone()); |
533 |
} |
534 |
|
535 |
RECURSE(Visit(expr->expression())); |
536 |
|
537 |
NarrowType(expr, Bounds(Type::Smi(), Type::Number(), isolate_)); |
538 |
|
539 |
VariableProxy* proxy = expr->expression()->AsVariableProxy(); |
540 |
if (proxy != NULL && proxy->var()->IsStackAllocated()) { |
541 |
store_.Seq(variable_index(proxy->var()), Effect(expr->bounds())); |
542 |
} |
543 |
} |
544 |
|
545 |
|
546 |
void AstTyper::VisitBinaryOperation(BinaryOperation* expr) {
|
547 |
// Collect type feedback.
|
548 |
Handle<Type> type, left_type, right_type; |
549 |
Maybe<int> fixed_right_arg;
|
550 |
oracle()->BinaryType(expr->BinaryOperationFeedbackId(), |
551 |
&left_type, &right_type, &type, &fixed_right_arg, expr->op()); |
552 |
NarrowLowerType(expr, type); |
553 |
NarrowLowerType(expr->left(), left_type); |
554 |
NarrowLowerType(expr->right(), right_type); |
555 |
expr->set_fixed_right_arg(fixed_right_arg); |
556 |
if (expr->op() == Token::OR || expr->op() == Token::AND) {
|
557 |
expr->left()->RecordToBooleanTypeFeedback(oracle()); |
558 |
} |
559 |
|
560 |
switch (expr->op()) {
|
561 |
case Token::COMMA:
|
562 |
RECURSE(Visit(expr->left())); |
563 |
RECURSE(Visit(expr->right())); |
564 |
NarrowType(expr, expr->right()->bounds()); |
565 |
break;
|
566 |
case Token::OR:
|
567 |
case Token::AND: {
|
568 |
Effects left_effects = EnterEffects(); |
569 |
RECURSE(Visit(expr->left())); |
570 |
ExitEffects(); |
571 |
Effects right_effects = EnterEffects(); |
572 |
RECURSE(Visit(expr->right())); |
573 |
ExitEffects(); |
574 |
left_effects.Alt(right_effects); |
575 |
store_.Seq(left_effects); |
576 |
|
577 |
NarrowType(expr, Bounds::Either( |
578 |
expr->left()->bounds(), expr->right()->bounds(), isolate_)); |
579 |
break;
|
580 |
} |
581 |
case Token::BIT_OR:
|
582 |
case Token::BIT_AND: {
|
583 |
RECURSE(Visit(expr->left())); |
584 |
RECURSE(Visit(expr->right())); |
585 |
Handle<Type> upper( |
586 |
Type::Union( |
587 |
expr->left()->bounds().upper, expr->right()->bounds().upper), |
588 |
isolate_); |
589 |
if (!upper->Is(Type::Signed32()))
|
590 |
upper = handle(Type::Signed32(), isolate_); |
591 |
Handle<Type> lower(Type::Intersect( |
592 |
handle(Type::Smi(), isolate_), upper), isolate_); |
593 |
NarrowType(expr, Bounds(lower, upper)); |
594 |
break;
|
595 |
} |
596 |
case Token::BIT_XOR:
|
597 |
case Token::SHL:
|
598 |
case Token::SAR:
|
599 |
RECURSE(Visit(expr->left())); |
600 |
RECURSE(Visit(expr->right())); |
601 |
NarrowType(expr, Bounds(Type::Smi(), Type::Signed32(), isolate_)); |
602 |
break;
|
603 |
case Token::SHR:
|
604 |
RECURSE(Visit(expr->left())); |
605 |
RECURSE(Visit(expr->right())); |
606 |
// TODO(rossberg): The upper bound would be Unsigned32, but since there
|
607 |
// is no 'positive Smi' type for the lower bound, we use the smallest
|
608 |
// union of Smi and Unsigned32 as upper bound instead.
|
609 |
NarrowType(expr, Bounds(Type::Smi(), Type::Number(), isolate_)); |
610 |
break;
|
611 |
case Token::ADD: {
|
612 |
RECURSE(Visit(expr->left())); |
613 |
RECURSE(Visit(expr->right())); |
614 |
Bounds l = expr->left()->bounds(); |
615 |
Bounds r = expr->right()->bounds(); |
616 |
Type* lower = |
617 |
l.lower->Is(Type::None()) || r.lower->Is(Type::None()) ? |
618 |
Type::None() : |
619 |
l.lower->Is(Type::String()) || r.lower->Is(Type::String()) ? |
620 |
Type::String() : |
621 |
l.lower->Is(Type::Number()) && r.lower->Is(Type::Number()) ? |
622 |
Type::Smi() : Type::None(); |
623 |
Type* upper = |
624 |
l.upper->Is(Type::String()) || r.upper->Is(Type::String()) ? |
625 |
Type::String() : |
626 |
l.upper->Is(Type::Number()) && r.upper->Is(Type::Number()) ? |
627 |
Type::Number() : Type::NumberOrString(); |
628 |
NarrowType(expr, Bounds(lower, upper, isolate_)); |
629 |
break;
|
630 |
} |
631 |
case Token::SUB:
|
632 |
case Token::MUL:
|
633 |
case Token::DIV:
|
634 |
case Token::MOD:
|
635 |
RECURSE(Visit(expr->left())); |
636 |
RECURSE(Visit(expr->right())); |
637 |
NarrowType(expr, Bounds(Type::Smi(), Type::Number(), isolate_)); |
638 |
break;
|
639 |
default:
|
640 |
UNREACHABLE(); |
641 |
} |
642 |
} |
643 |
|
644 |
|
645 |
void AstTyper::VisitCompareOperation(CompareOperation* expr) {
|
646 |
// Collect type feedback.
|
647 |
Handle<Type> left_type, right_type, combined_type; |
648 |
oracle()->CompareType(expr->CompareOperationFeedbackId(), |
649 |
&left_type, &right_type, &combined_type); |
650 |
NarrowLowerType(expr->left(), left_type); |
651 |
NarrowLowerType(expr->right(), right_type); |
652 |
expr->set_combined_type(combined_type); |
653 |
|
654 |
RECURSE(Visit(expr->left())); |
655 |
RECURSE(Visit(expr->right())); |
656 |
|
657 |
NarrowType(expr, Bounds(Type::Boolean(), isolate_)); |
658 |
} |
659 |
|
660 |
|
661 |
void AstTyper::VisitThisFunction(ThisFunction* expr) {
|
662 |
} |
663 |
|
664 |
|
665 |
void AstTyper::VisitDeclarations(ZoneList<Declaration*>* decls) {
|
666 |
for (int i = 0; i < decls->length(); ++i) { |
667 |
Declaration* decl = decls->at(i); |
668 |
RECURSE(Visit(decl)); |
669 |
} |
670 |
} |
671 |
|
672 |
|
673 |
void AstTyper::VisitVariableDeclaration(VariableDeclaration* declaration) {
|
674 |
} |
675 |
|
676 |
|
677 |
void AstTyper::VisitFunctionDeclaration(FunctionDeclaration* declaration) {
|
678 |
RECURSE(Visit(declaration->fun())); |
679 |
} |
680 |
|
681 |
|
682 |
void AstTyper::VisitModuleDeclaration(ModuleDeclaration* declaration) {
|
683 |
RECURSE(Visit(declaration->module())); |
684 |
} |
685 |
|
686 |
|
687 |
void AstTyper::VisitImportDeclaration(ImportDeclaration* declaration) {
|
688 |
RECURSE(Visit(declaration->module())); |
689 |
} |
690 |
|
691 |
|
692 |
void AstTyper::VisitExportDeclaration(ExportDeclaration* declaration) {
|
693 |
} |
694 |
|
695 |
|
696 |
void AstTyper::VisitModuleLiteral(ModuleLiteral* module) {
|
697 |
RECURSE(Visit(module->body())); |
698 |
} |
699 |
|
700 |
|
701 |
void AstTyper::VisitModuleVariable(ModuleVariable* module) {
|
702 |
} |
703 |
|
704 |
|
705 |
void AstTyper::VisitModulePath(ModulePath* module) {
|
706 |
RECURSE(Visit(module->module())); |
707 |
} |
708 |
|
709 |
|
710 |
void AstTyper::VisitModuleUrl(ModuleUrl* module) {
|
711 |
} |
712 |
|
713 |
|
714 |
void AstTyper::VisitModuleStatement(ModuleStatement* stmt) {
|
715 |
RECURSE(Visit(stmt->body())); |
716 |
} |
717 |
|
718 |
|
719 |
} } // namespace v8::internal
|