blob: b6f82406149ea946ecec323363b973cb124326ef [file] [log] [blame]
ager@chromium.orgb61a0d12010-10-13 08:35:23 +00001// Copyright 2010 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002// 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 "v8.h"
29
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000030#include "rewriter.h"
31
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000032#include "ast.h"
33#include "compiler.h"
34#include "scopes.h"
35
kasperl@chromium.org71affb52009-05-26 05:44:31 +000036namespace v8 {
37namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000038
ager@chromium.orga74f0da2008-12-03 16:05:52 +000039class AstOptimizer: public AstVisitor {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000040 public:
kasperl@chromium.orge959c182009-07-27 08:59:04 +000041 explicit AstOptimizer() : has_function_literal_(false) {}
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000042
43 void Optimize(ZoneList<Statement*>* statements);
44
45 private:
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000046 // Used for loop condition analysis. Cleared before visiting a loop
47 // condition, set when a function literal is visited.
48 bool has_function_literal_;
49
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000050 // Helpers
51 void OptimizeArguments(ZoneList<Expression*>* arguments);
52
53 // Node visitors.
54#define DEF_VISIT(type) \
55 virtual void Visit##type(type* node);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000056 AST_NODE_LIST(DEF_VISIT)
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000057#undef DEF_VISIT
58
59 DISALLOW_COPY_AND_ASSIGN(AstOptimizer);
60};
61
62
63void AstOptimizer::Optimize(ZoneList<Statement*>* statements) {
64 int len = statements->length();
65 for (int i = 0; i < len; i++) {
66 Visit(statements->at(i));
67 }
68}
69
70
71void AstOptimizer::OptimizeArguments(ZoneList<Expression*>* arguments) {
72 for (int i = 0; i < arguments->length(); i++) {
73 Visit(arguments->at(i));
74 }
75}
76
77
78void AstOptimizer::VisitBlock(Block* node) {
79 Optimize(node->statements());
80}
81
82
83void AstOptimizer::VisitExpressionStatement(ExpressionStatement* node) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +000084 node->expression()->set_no_negative_zero(true);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000085 Visit(node->expression());
86}
87
88
89void AstOptimizer::VisitIfStatement(IfStatement* node) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +000090 node->condition()->set_no_negative_zero(true);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000091 Visit(node->condition());
92 Visit(node->then_statement());
93 if (node->HasElseStatement()) {
94 Visit(node->else_statement());
95 }
96}
97
98
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000099void AstOptimizer::VisitDoWhileStatement(DoWhileStatement* node) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000100 node->cond()->set_no_negative_zero(true);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000101 Visit(node->cond());
102 Visit(node->body());
103}
104
105
106void AstOptimizer::VisitWhileStatement(WhileStatement* node) {
107 has_function_literal_ = false;
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000108 node->cond()->set_no_negative_zero(true);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000109 Visit(node->cond());
ricow@chromium.org65fae842010-08-25 15:26:24 +0000110 node->set_may_have_function_literal(has_function_literal_);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000111 Visit(node->body());
112}
113
114
115void AstOptimizer::VisitForStatement(ForStatement* node) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000116 if (node->init() != NULL) {
117 Visit(node->init());
118 }
119 if (node->cond() != NULL) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000120 has_function_literal_ = false;
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000121 node->cond()->set_no_negative_zero(true);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000122 Visit(node->cond());
ricow@chromium.org65fae842010-08-25 15:26:24 +0000123 node->set_may_have_function_literal(has_function_literal_);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000124 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000125 Visit(node->body());
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000126 if (node->next() != NULL) {
127 Visit(node->next());
128 }
129}
130
131
132void AstOptimizer::VisitForInStatement(ForInStatement* node) {
133 Visit(node->each());
134 Visit(node->enumerable());
135 Visit(node->body());
136}
137
138
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000139void AstOptimizer::VisitTryCatchStatement(TryCatchStatement* node) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000140 Visit(node->try_block());
141 Visit(node->catch_var());
142 Visit(node->catch_block());
143}
144
145
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000146void AstOptimizer::VisitTryFinallyStatement(TryFinallyStatement* node) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000147 Visit(node->try_block());
148 Visit(node->finally_block());
149}
150
151
152void AstOptimizer::VisitSwitchStatement(SwitchStatement* node) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000153 node->tag()->set_no_negative_zero(true);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000154 Visit(node->tag());
155 for (int i = 0; i < node->cases()->length(); i++) {
156 CaseClause* clause = node->cases()->at(i);
157 if (!clause->is_default()) {
158 Visit(clause->label());
159 }
160 Optimize(clause->statements());
161 }
162}
163
164
165void AstOptimizer::VisitContinueStatement(ContinueStatement* node) {
166 USE(node);
167}
168
169
170void AstOptimizer::VisitBreakStatement(BreakStatement* node) {
171 USE(node);
172}
173
174
175void AstOptimizer::VisitDeclaration(Declaration* node) {
176 // Will not be reached by the current optimizations.
177 USE(node);
178}
179
180
181void AstOptimizer::VisitEmptyStatement(EmptyStatement* node) {
182 USE(node);
183}
184
185
186void AstOptimizer::VisitReturnStatement(ReturnStatement* node) {
187 Visit(node->expression());
188}
189
190
191void AstOptimizer::VisitWithEnterStatement(WithEnterStatement* node) {
192 Visit(node->expression());
193}
194
195
196void AstOptimizer::VisitWithExitStatement(WithExitStatement* node) {
197 USE(node);
198}
199
200
201void AstOptimizer::VisitDebuggerStatement(DebuggerStatement* node) {
202 USE(node);
203}
204
205
206void AstOptimizer::VisitFunctionLiteral(FunctionLiteral* node) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000207 has_function_literal_ = true;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000208}
209
210
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000211void AstOptimizer::VisitSharedFunctionInfoLiteral(
212 SharedFunctionInfoLiteral* node) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000213 USE(node);
214}
215
216
217void AstOptimizer::VisitConditional(Conditional* node) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000218 node->condition()->set_no_negative_zero(true);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000219 Visit(node->condition());
220 Visit(node->then_expression());
221 Visit(node->else_expression());
222}
223
224
225void AstOptimizer::VisitSlot(Slot* node) {
226 USE(node);
227}
228
229
230void AstOptimizer::VisitVariableProxy(VariableProxy* node) {
231 Variable* var = node->AsVariable();
232 if (var != NULL) {
233 if (var->type()->IsKnown()) {
234 node->type()->CopyFrom(var->type());
235 } else if (node->type()->IsLikelySmi()) {
236 var->type()->SetAsLikelySmi();
237 }
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000238
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000239 if (FLAG_safe_int32_compiler) {
fschneider@chromium.org5a49b7a2010-03-18 10:06:01 +0000240 if (var->IsStackAllocated() &&
241 !var->is_arguments() &&
242 var->mode() != Variable::CONST) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000243 node->set_side_effect_free(true);
244 }
245 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000246 }
247}
248
249
250void AstOptimizer::VisitLiteral(Literal* node) {
251 Handle<Object> literal = node->handle();
252 if (literal->IsSmi()) {
253 node->type()->SetAsLikelySmi();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000254 node->set_side_effect_free(true);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000255 } else if (literal->IsHeapNumber()) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000256 if (node->to_int32()) {
257 // Any HeapNumber has an int32 value if it is the input to a bit op.
258 node->set_side_effect_free(true);
259 } else {
260 double double_value = HeapNumber::cast(*literal)->value();
261 int32_t int32_value = DoubleToInt32(double_value);
262 node->set_side_effect_free(double_value == int32_value);
263 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000264 }
265}
266
267
268void AstOptimizer::VisitRegExpLiteral(RegExpLiteral* node) {
269 USE(node);
270}
271
272
273void AstOptimizer::VisitArrayLiteral(ArrayLiteral* node) {
274 for (int i = 0; i < node->values()->length(); i++) {
275 Visit(node->values()->at(i));
276 }
277}
278
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000279void AstOptimizer::VisitObjectLiteral(ObjectLiteral* node) {
280 for (int i = 0; i < node->properties()->length(); i++) {
281 Visit(node->properties()->at(i)->key());
282 Visit(node->properties()->at(i)->value());
283 }
284}
285
286
ager@chromium.org32912102009-01-16 10:38:43 +0000287void AstOptimizer::VisitCatchExtensionObject(CatchExtensionObject* node) {
288 Visit(node->key());
289 Visit(node->value());
290}
291
292
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000293void AstOptimizer::VisitAssignment(Assignment* node) {
294 switch (node->op()) {
295 case Token::INIT_VAR:
296 case Token::INIT_CONST:
297 case Token::ASSIGN:
298 // No type can be infered from the general assignment.
299 break;
300 case Token::ASSIGN_BIT_OR:
301 case Token::ASSIGN_BIT_XOR:
302 case Token::ASSIGN_BIT_AND:
303 case Token::ASSIGN_SHL:
304 case Token::ASSIGN_SAR:
305 case Token::ASSIGN_SHR:
306 node->type()->SetAsLikelySmiIfUnknown();
307 node->target()->type()->SetAsLikelySmiIfUnknown();
308 node->value()->type()->SetAsLikelySmiIfUnknown();
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000309 node->value()->set_to_int32(true);
310 node->value()->set_no_negative_zero(true);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000311 break;
312 case Token::ASSIGN_ADD:
313 case Token::ASSIGN_SUB:
314 case Token::ASSIGN_MUL:
315 case Token::ASSIGN_DIV:
316 case Token::ASSIGN_MOD:
317 if (node->type()->IsLikelySmi()) {
318 node->target()->type()->SetAsLikelySmiIfUnknown();
319 node->value()->type()->SetAsLikelySmiIfUnknown();
320 }
321 break;
322 default:
323 UNREACHABLE();
324 break;
325 }
326
327 Visit(node->target());
328 Visit(node->value());
329
330 switch (node->op()) {
331 case Token::INIT_VAR:
332 case Token::INIT_CONST:
333 case Token::ASSIGN:
ager@chromium.org32912102009-01-16 10:38:43 +0000334 // Pure assignment copies the type from the value.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000335 node->type()->CopyFrom(node->value()->type());
336 break;
337 case Token::ASSIGN_BIT_OR:
338 case Token::ASSIGN_BIT_XOR:
339 case Token::ASSIGN_BIT_AND:
340 case Token::ASSIGN_SHL:
341 case Token::ASSIGN_SAR:
342 case Token::ASSIGN_SHR:
343 // Should have been setup above already.
344 break;
345 case Token::ASSIGN_ADD:
346 case Token::ASSIGN_SUB:
347 case Token::ASSIGN_MUL:
348 case Token::ASSIGN_DIV:
349 case Token::ASSIGN_MOD:
350 if (node->type()->IsUnknown()) {
351 if (node->target()->type()->IsLikelySmi() ||
352 node->value()->type()->IsLikelySmi()) {
353 node->type()->SetAsLikelySmi();
354 }
355 }
356 break;
357 default:
358 UNREACHABLE();
359 break;
360 }
361
362 // Since this is an assignment. We have to propagate this node's type to the
363 // variable.
364 VariableProxy* proxy = node->target()->AsVariableProxy();
365 if (proxy != NULL) {
366 Variable* var = proxy->AsVariable();
367 if (var != NULL) {
sgjesse@chromium.org846fb742009-12-18 08:56:33 +0000368 StaticType* var_type = var->type();
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000369 if (var_type->IsUnknown()) {
370 var_type->CopyFrom(node->type());
371 } else if (var_type->IsLikelySmi()) {
372 // We do not reset likely types to Unknown.
373 }
374 }
375 }
376}
377
378
379void AstOptimizer::VisitThrow(Throw* node) {
380 Visit(node->exception());
381}
382
383
384void AstOptimizer::VisitProperty(Property* node) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000385 node->key()->set_no_negative_zero(true);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000386 Visit(node->obj());
387 Visit(node->key());
388}
389
390
391void AstOptimizer::VisitCall(Call* node) {
392 Visit(node->expression());
393 OptimizeArguments(node->arguments());
394}
395
396
397void AstOptimizer::VisitCallNew(CallNew* node) {
398 Visit(node->expression());
399 OptimizeArguments(node->arguments());
400}
401
402
403void AstOptimizer::VisitCallRuntime(CallRuntime* node) {
404 OptimizeArguments(node->arguments());
405}
406
407
408void AstOptimizer::VisitUnaryOperation(UnaryOperation* node) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000409 if (node->op() == Token::ADD || node->op() == Token::SUB) {
410 node->expression()->set_no_negative_zero(node->no_negative_zero());
411 } else {
412 node->expression()->set_no_negative_zero(true);
413 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000414 Visit(node->expression());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000415 if (FLAG_safe_int32_compiler) {
416 switch (node->op()) {
417 case Token::BIT_NOT:
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000418 node->expression()->set_no_negative_zero(true);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000419 node->expression()->set_to_int32(true);
420 // Fall through.
421 case Token::ADD:
422 case Token::SUB:
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000423 node->set_side_effect_free(node->expression()->side_effect_free());
424 break;
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000425 case Token::NOT:
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000426 case Token::DELETE:
427 case Token::TYPEOF:
428 case Token::VOID:
429 break;
430 default:
431 UNREACHABLE();
432 break;
433 }
434 } else if (node->op() == Token::BIT_NOT) {
435 node->expression()->set_to_int32(true);
436 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000437}
438
439
ricow@chromium.org65fae842010-08-25 15:26:24 +0000440void AstOptimizer::VisitIncrementOperation(IncrementOperation* node) {
441 UNREACHABLE();
442}
443
444
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000445void AstOptimizer::VisitCountOperation(CountOperation* node) {
446 // Count operations assume that they work on Smis.
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000447 node->expression()->set_no_negative_zero(node->is_prefix() ?
448 true :
449 node->no_negative_zero());
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000450 node->type()->SetAsLikelySmiIfUnknown();
451 node->expression()->type()->SetAsLikelySmiIfUnknown();
452 Visit(node->expression());
453}
454
455
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000456static bool CouldBeNegativeZero(AstNode* node) {
457 Literal* literal = node->AsLiteral();
458 if (literal != NULL) {
459 Handle<Object> handle = literal->handle();
460 if (handle->IsString() || handle->IsSmi()) {
461 return false;
462 } else if (handle->IsHeapNumber()) {
463 double double_value = HeapNumber::cast(*handle)->value();
464 if (double_value != 0) {
465 return false;
466 }
467 }
468 }
469 BinaryOperation* binary = node->AsBinaryOperation();
470 if (binary != NULL && Token::IsBitOp(binary->op())) {
471 return false;
472 }
473 return true;
474}
475
476
477static bool CouldBePositiveZero(AstNode* node) {
478 Literal* literal = node->AsLiteral();
479 if (literal != NULL) {
480 Handle<Object> handle = literal->handle();
481 if (handle->IsSmi()) {
482 if (Smi::cast(*handle) != Smi::FromInt(0)) {
483 return false;
484 }
485 } else if (handle->IsHeapNumber()) {
486 // Heap number literal can't be +0, because that's a Smi.
487 return false;
488 }
489 }
490 return true;
491}
492
493
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000494void AstOptimizer::VisitBinaryOperation(BinaryOperation* node) {
495 // Depending on the operation we can propagate this node's type down the
496 // AST nodes.
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000497 Token::Value op = node->op();
498 switch (op) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000499 case Token::COMMA:
500 case Token::OR:
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000501 node->left()->set_no_negative_zero(true);
502 node->right()->set_no_negative_zero(node->no_negative_zero());
503 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000504 case Token::AND:
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000505 node->left()->set_no_negative_zero(node->no_negative_zero());
506 node->right()->set_no_negative_zero(node->no_negative_zero());
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000507 break;
508 case Token::BIT_OR:
509 case Token::BIT_XOR:
510 case Token::BIT_AND:
511 case Token::SHL:
512 case Token::SAR:
513 case Token::SHR:
514 node->type()->SetAsLikelySmiIfUnknown();
515 node->left()->type()->SetAsLikelySmiIfUnknown();
516 node->right()->type()->SetAsLikelySmiIfUnknown();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000517 node->left()->set_to_int32(true);
518 node->right()->set_to_int32(true);
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000519 node->left()->set_no_negative_zero(true);
520 node->right()->set_no_negative_zero(true);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000521 break;
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000522 case Token::MUL: {
523 VariableProxy* lvar_proxy = node->left()->AsVariableProxy();
524 VariableProxy* rvar_proxy = node->right()->AsVariableProxy();
525 if (lvar_proxy != NULL && rvar_proxy != NULL) {
526 Variable* lvar = lvar_proxy->AsVariable();
527 Variable* rvar = rvar_proxy->AsVariable();
528 if (lvar != NULL && rvar != NULL) {
529 if (lvar->mode() == Variable::VAR && rvar->mode() == Variable::VAR) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000530 Slot* lslot = lvar->AsSlot();
531 Slot* rslot = rvar->AsSlot();
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000532 if (lslot->type() == rslot->type() &&
533 (lslot->type() == Slot::PARAMETER ||
534 lslot->type() == Slot::LOCAL) &&
535 lslot->index() == rslot->index()) {
536 // A number squared doesn't give negative zero.
537 node->set_no_negative_zero(true);
538 }
539 }
540 }
541 }
542 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000543 case Token::ADD:
544 case Token::SUB:
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000545 case Token::DIV:
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000546 case Token::MOD: {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000547 if (node->type()->IsLikelySmi()) {
548 node->left()->type()->SetAsLikelySmiIfUnknown();
549 node->right()->type()->SetAsLikelySmiIfUnknown();
550 }
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000551 if (op == Token::ADD && (!CouldBeNegativeZero(node->left()) ||
552 !CouldBeNegativeZero(node->right()))) {
553 node->left()->set_no_negative_zero(true);
554 node->right()->set_no_negative_zero(true);
555 } else if (op == Token::SUB && (!CouldBeNegativeZero(node->left()) ||
556 !CouldBePositiveZero(node->right()))) {
557 node->left()->set_no_negative_zero(true);
558 node->right()->set_no_negative_zero(true);
559 } else {
560 node->left()->set_no_negative_zero(node->no_negative_zero());
561 node->right()->set_no_negative_zero(node->no_negative_zero());
562 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000563 if (node->op() == Token::DIV) {
564 node->right()->set_no_negative_zero(false);
565 } else if (node->op() == Token::MOD) {
566 node->right()->set_no_negative_zero(true);
567 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000568 break;
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000569 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000570 default:
571 UNREACHABLE();
572 break;
573 }
574
575 Visit(node->left());
576 Visit(node->right());
577
578 // After visiting the operand nodes we have to check if this node's type
579 // can be updated. If it does, then we can push that information down
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000580 // towards the leaves again if the new information is an upgrade over the
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000581 // previous type of the operand nodes.
582 if (node->type()->IsUnknown()) {
583 if (node->left()->type()->IsLikelySmi() ||
584 node->right()->type()->IsLikelySmi()) {
585 node->type()->SetAsLikelySmi();
586 }
587 if (node->type()->IsLikelySmi()) {
ager@chromium.org32912102009-01-16 10:38:43 +0000588 // The type of this node changed to LIKELY_SMI. Propagate this knowledge
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000589 // down through the nodes.
590 if (node->left()->type()->IsUnknown()) {
591 node->left()->type()->SetAsLikelySmi();
592 Visit(node->left());
593 }
594 if (node->right()->type()->IsUnknown()) {
595 node->right()->type()->SetAsLikelySmi();
596 Visit(node->right());
597 }
598 }
599 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000600
601 if (FLAG_safe_int32_compiler) {
602 switch (node->op()) {
603 case Token::COMMA:
604 case Token::OR:
605 case Token::AND:
606 break;
607 case Token::BIT_OR:
608 case Token::BIT_XOR:
609 case Token::BIT_AND:
610 case Token::SHL:
611 case Token::SAR:
612 case Token::SHR:
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000613 // Add one to the number of bit operations in this expression.
614 node->set_num_bit_ops(1);
615 // Fall through.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000616 case Token::ADD:
617 case Token::SUB:
618 case Token::MUL:
619 case Token::DIV:
620 case Token::MOD:
621 node->set_side_effect_free(node->left()->side_effect_free() &&
622 node->right()->side_effect_free());
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000623 node->set_num_bit_ops(node->num_bit_ops() +
624 node->left()->num_bit_ops() +
625 node->right()->num_bit_ops());
626 if (!node->no_negative_zero() && node->op() == Token::MUL) {
627 node->set_side_effect_free(false);
628 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000629 break;
630 default:
631 UNREACHABLE();
632 break;
633 }
634 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000635}
636
637
638void AstOptimizer::VisitCompareOperation(CompareOperation* node) {
639 if (node->type()->IsKnown()) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000640 // Propagate useful information down towards the leaves.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000641 node->left()->type()->SetAsLikelySmiIfUnknown();
642 node->right()->type()->SetAsLikelySmiIfUnknown();
643 }
644
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000645 node->left()->set_no_negative_zero(true);
646 // Only [[HasInstance]] has the right argument passed unchanged to it.
647 node->right()->set_no_negative_zero(true);
648
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000649 Visit(node->left());
650 Visit(node->right());
651
652 // After visiting the operand nodes we have to check if this node's type
653 // can be updated. If it does, then we can push that information down
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000654 // towards the leaves again if the new information is an upgrade over the
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000655 // previous type of the operand nodes.
656 if (node->type()->IsUnknown()) {
657 if (node->left()->type()->IsLikelySmi() ||
658 node->right()->type()->IsLikelySmi()) {
659 node->type()->SetAsLikelySmi();
660 }
661 if (node->type()->IsLikelySmi()) {
ager@chromium.org32912102009-01-16 10:38:43 +0000662 // The type of this node changed to LIKELY_SMI. Propagate this knowledge
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000663 // down through the nodes.
664 if (node->left()->type()->IsUnknown()) {
665 node->left()->type()->SetAsLikelySmi();
666 Visit(node->left());
667 }
668 if (node->right()->type()->IsUnknown()) {
669 node->right()->type()->SetAsLikelySmi();
670 Visit(node->right());
671 }
672 }
673 }
674}
675
676
ricow@chromium.org65fae842010-08-25 15:26:24 +0000677void AstOptimizer::VisitCompareToNull(CompareToNull* node) {
678 Visit(node->expression());
679}
680
681
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000682void AstOptimizer::VisitThisFunction(ThisFunction* node) {
683 USE(node);
684}
685
686
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000687class Processor: public AstVisitor {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000688 public:
689 explicit Processor(VariableProxy* result)
690 : result_(result),
691 result_assigned_(false),
692 is_set_(false),
693 in_try_(false) {
694 }
695
696 void Process(ZoneList<Statement*>* statements);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000697 bool result_assigned() const { return result_assigned_; }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000698
699 private:
700 VariableProxy* result_;
701
702 // We are not tracking result usage via the result_'s use
703 // counts (we leave the accurate computation to the
704 // usage analyzer). Instead we simple remember if
705 // there was ever an assignment to result_.
706 bool result_assigned_;
707
708 // To avoid storing to .result all the time, we eliminate some of
709 // the stores by keeping track of whether or not we're sure .result
710 // will be overwritten anyway. This is a bit more tricky than what I
711 // was hoping for
712 bool is_set_;
713 bool in_try_;
714
715 Expression* SetResult(Expression* value) {
716 result_assigned_ = true;
ager@chromium.org236ad962008-09-25 09:45:57 +0000717 return new Assignment(Token::ASSIGN, result_, value,
718 RelocInfo::kNoPosition);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000719 }
720
721 // Node visitors.
722#define DEF_VISIT(type) \
723 virtual void Visit##type(type* node);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000724 AST_NODE_LIST(DEF_VISIT)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000725#undef DEF_VISIT
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000726
727 void VisitIterationStatement(IterationStatement* stmt);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000728};
729
730
731void Processor::Process(ZoneList<Statement*>* statements) {
732 for (int i = statements->length() - 1; i >= 0; --i) {
733 Visit(statements->at(i));
734 }
735}
736
737
738void Processor::VisitBlock(Block* node) {
739 // An initializer block is the rewritten form of a variable declaration
740 // with initialization expressions. The initializer block contains the
741 // list of assignments corresponding to the initialization expressions.
742 // While unclear from the spec (ECMA-262, 3rd., 12.2), the value of
743 // a variable declaration with initialization expression is 'undefined'
744 // with some JS VMs: For instance, using smjs, print(eval('var x = 7'))
745 // returns 'undefined'. To obtain the same behavior with v8, we need
746 // to prevent rewriting in that case.
747 if (!node->is_initializer_block()) Process(node->statements());
748}
749
750
751void Processor::VisitExpressionStatement(ExpressionStatement* node) {
752 // Rewrite : <x>; -> .result = <x>;
753 if (!is_set_) {
754 node->set_expression(SetResult(node->expression()));
755 if (!in_try_) is_set_ = true;
756 }
757}
758
759
760void Processor::VisitIfStatement(IfStatement* node) {
761 // Rewrite both then and else parts (reversed).
762 bool save = is_set_;
763 Visit(node->else_statement());
764 bool set_after_then = is_set_;
765 is_set_ = save;
766 Visit(node->then_statement());
767 is_set_ = is_set_ && set_after_then;
768}
769
770
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000771void Processor::VisitIterationStatement(IterationStatement* node) {
772 // Rewrite the body.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000773 bool set_after_loop = is_set_;
774 Visit(node->body());
775 is_set_ = is_set_ && set_after_loop;
776}
777
778
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000779void Processor::VisitDoWhileStatement(DoWhileStatement* node) {
780 VisitIterationStatement(node);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000781}
782
783
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000784void Processor::VisitWhileStatement(WhileStatement* node) {
785 VisitIterationStatement(node);
786}
787
788
789void Processor::VisitForStatement(ForStatement* node) {
790 VisitIterationStatement(node);
791}
792
793
794void Processor::VisitForInStatement(ForInStatement* node) {
795 VisitIterationStatement(node);
796}
797
798
799void Processor::VisitTryCatchStatement(TryCatchStatement* node) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000800 // Rewrite both try and catch blocks (reversed order).
801 bool set_after_catch = is_set_;
802 Visit(node->catch_block());
803 is_set_ = is_set_ && set_after_catch;
804 bool save = in_try_;
805 in_try_ = true;
806 Visit(node->try_block());
807 in_try_ = save;
808}
809
810
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000811void Processor::VisitTryFinallyStatement(TryFinallyStatement* node) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000812 // Rewrite both try and finally block (reversed order).
813 Visit(node->finally_block());
814 bool save = in_try_;
815 in_try_ = true;
816 Visit(node->try_block());
817 in_try_ = save;
818}
819
820
821void Processor::VisitSwitchStatement(SwitchStatement* node) {
822 // Rewrite statements in all case clauses in reversed order.
823 ZoneList<CaseClause*>* clauses = node->cases();
824 bool set_after_switch = is_set_;
825 for (int i = clauses->length() - 1; i >= 0; --i) {
826 CaseClause* clause = clauses->at(i);
827 Process(clause->statements());
828 }
829 is_set_ = is_set_ && set_after_switch;
830}
831
832
833void Processor::VisitContinueStatement(ContinueStatement* node) {
834 is_set_ = false;
835}
836
837
838void Processor::VisitBreakStatement(BreakStatement* node) {
839 is_set_ = false;
840}
841
842
843// Do nothing:
844void Processor::VisitDeclaration(Declaration* node) {}
845void Processor::VisitEmptyStatement(EmptyStatement* node) {}
846void Processor::VisitReturnStatement(ReturnStatement* node) {}
847void Processor::VisitWithEnterStatement(WithEnterStatement* node) {}
848void Processor::VisitWithExitStatement(WithExitStatement* node) {}
849void Processor::VisitDebuggerStatement(DebuggerStatement* node) {}
850
851
852// Expressions are never visited yet.
853void Processor::VisitFunctionLiteral(FunctionLiteral* node) {
854 USE(node);
855 UNREACHABLE();
856}
857
858
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000859void Processor::VisitSharedFunctionInfoLiteral(
860 SharedFunctionInfoLiteral* node) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000861 USE(node);
862 UNREACHABLE();
863}
864
865
866void Processor::VisitConditional(Conditional* node) {
867 USE(node);
868 UNREACHABLE();
869}
870
871
872void Processor::VisitSlot(Slot* node) {
873 USE(node);
874 UNREACHABLE();
875}
876
877
878void Processor::VisitVariableProxy(VariableProxy* node) {
879 USE(node);
880 UNREACHABLE();
881}
882
883
884void Processor::VisitLiteral(Literal* node) {
885 USE(node);
886 UNREACHABLE();
887}
888
889
890void Processor::VisitRegExpLiteral(RegExpLiteral* node) {
891 USE(node);
892 UNREACHABLE();
893}
894
895
896void Processor::VisitArrayLiteral(ArrayLiteral* node) {
897 USE(node);
898 UNREACHABLE();
899}
900
901
902void Processor::VisitObjectLiteral(ObjectLiteral* node) {
903 USE(node);
904 UNREACHABLE();
905}
906
907
ager@chromium.org32912102009-01-16 10:38:43 +0000908void Processor::VisitCatchExtensionObject(CatchExtensionObject* node) {
909 USE(node);
910 UNREACHABLE();
911}
912
913
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000914void Processor::VisitAssignment(Assignment* node) {
915 USE(node);
916 UNREACHABLE();
917}
918
919
920void Processor::VisitThrow(Throw* node) {
921 USE(node);
922 UNREACHABLE();
923}
924
925
926void Processor::VisitProperty(Property* node) {
927 USE(node);
928 UNREACHABLE();
929}
930
931
932void Processor::VisitCall(Call* node) {
933 USE(node);
934 UNREACHABLE();
935}
936
937
938void Processor::VisitCallNew(CallNew* node) {
939 USE(node);
940 UNREACHABLE();
941}
942
943
944void Processor::VisitCallRuntime(CallRuntime* node) {
945 USE(node);
946 UNREACHABLE();
947}
948
949
950void Processor::VisitUnaryOperation(UnaryOperation* node) {
951 USE(node);
952 UNREACHABLE();
953}
954
955
ricow@chromium.org65fae842010-08-25 15:26:24 +0000956void Processor::VisitIncrementOperation(IncrementOperation* node) {
957 UNREACHABLE();
958}
959
960
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000961void Processor::VisitCountOperation(CountOperation* node) {
962 USE(node);
963 UNREACHABLE();
964}
965
966
967void Processor::VisitBinaryOperation(BinaryOperation* node) {
968 USE(node);
969 UNREACHABLE();
970}
971
972
973void Processor::VisitCompareOperation(CompareOperation* node) {
974 USE(node);
975 UNREACHABLE();
976}
977
978
ricow@chromium.org65fae842010-08-25 15:26:24 +0000979void Processor::VisitCompareToNull(CompareToNull* node) {
980 USE(node);
981 UNREACHABLE();
982}
983
984
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000985void Processor::VisitThisFunction(ThisFunction* node) {
986 USE(node);
987 UNREACHABLE();
988}
989
990
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000991// Assumes code has been parsed and scopes hve been analyzed. Mutates the
992// AST, so the AST should not continue to be used in the case of failure.
993bool Rewriter::Rewrite(CompilationInfo* info) {
994 FunctionLiteral* function = info->function();
995 ASSERT(function != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000996 Scope* scope = function->scope();
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000997 ASSERT(scope != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000998 if (scope->is_function_scope()) return true;
999
1000 ZoneList<Statement*>* body = function->body();
ager@chromium.orgb61a0d12010-10-13 08:35:23 +00001001 if (!body->is_empty()) {
1002 VariableProxy* result = scope->NewTemporary(Factory::result_symbol());
1003 Processor processor(result);
1004 processor.Process(body);
1005 if (processor.HasStackOverflow()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001006
ager@chromium.orgb61a0d12010-10-13 08:35:23 +00001007 if (processor.result_assigned()) body->Add(new ReturnStatement(result));
1008 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001009
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001010 return true;
1011}
1012
1013
ager@chromium.orgb61a0d12010-10-13 08:35:23 +00001014// Assumes code has been parsed and scopes have been analyzed. Mutates the
1015// AST, so the AST should not continue to be used in the case of failure.
1016bool Rewriter::Analyze(CompilationInfo* info) {
1017 FunctionLiteral* function = info->function();
1018 ASSERT(function != NULL && function->scope() != NULL);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001019
ager@chromium.orgb61a0d12010-10-13 08:35:23 +00001020 ZoneList<Statement*>* body = function->body();
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001021 if (FLAG_optimize_ast && !body->is_empty()) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00001022 AstOptimizer optimizer;
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00001023 optimizer.Optimize(body);
ager@chromium.orgb61a0d12010-10-13 08:35:23 +00001024 if (optimizer.HasStackOverflow()) return false;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001025 }
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001026 return true;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001027}
1028
1029
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001030} } // namespace v8::internal