blob: fd40cdc3fa0b9c734756c6c55e48fcafee58e011 [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
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000225void AstOptimizer::VisitVariableProxy(VariableProxy* node) {
226 Variable* var = node->AsVariable();
227 if (var != NULL) {
228 if (var->type()->IsKnown()) {
229 node->type()->CopyFrom(var->type());
230 } else if (node->type()->IsLikelySmi()) {
231 var->type()->SetAsLikelySmi();
232 }
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000233
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000234 if (FLAG_safe_int32_compiler) {
fschneider@chromium.org5a49b7a2010-03-18 10:06:01 +0000235 if (var->IsStackAllocated() &&
236 !var->is_arguments() &&
237 var->mode() != Variable::CONST) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000238 node->set_side_effect_free(true);
239 }
240 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000241 }
242}
243
244
245void AstOptimizer::VisitLiteral(Literal* node) {
246 Handle<Object> literal = node->handle();
247 if (literal->IsSmi()) {
248 node->type()->SetAsLikelySmi();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000249 node->set_side_effect_free(true);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000250 } else if (literal->IsHeapNumber()) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000251 if (node->to_int32()) {
252 // Any HeapNumber has an int32 value if it is the input to a bit op.
253 node->set_side_effect_free(true);
254 } else {
255 double double_value = HeapNumber::cast(*literal)->value();
256 int32_t int32_value = DoubleToInt32(double_value);
257 node->set_side_effect_free(double_value == int32_value);
258 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000259 }
260}
261
262
263void AstOptimizer::VisitRegExpLiteral(RegExpLiteral* node) {
264 USE(node);
265}
266
267
268void AstOptimizer::VisitArrayLiteral(ArrayLiteral* node) {
269 for (int i = 0; i < node->values()->length(); i++) {
270 Visit(node->values()->at(i));
271 }
272}
273
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000274void AstOptimizer::VisitObjectLiteral(ObjectLiteral* node) {
275 for (int i = 0; i < node->properties()->length(); i++) {
276 Visit(node->properties()->at(i)->key());
277 Visit(node->properties()->at(i)->value());
278 }
279}
280
281
ager@chromium.org32912102009-01-16 10:38:43 +0000282void AstOptimizer::VisitCatchExtensionObject(CatchExtensionObject* node) {
283 Visit(node->key());
284 Visit(node->value());
285}
286
287
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000288void AstOptimizer::VisitAssignment(Assignment* node) {
289 switch (node->op()) {
290 case Token::INIT_VAR:
291 case Token::INIT_CONST:
292 case Token::ASSIGN:
293 // No type can be infered from the general assignment.
294 break;
295 case Token::ASSIGN_BIT_OR:
296 case Token::ASSIGN_BIT_XOR:
297 case Token::ASSIGN_BIT_AND:
298 case Token::ASSIGN_SHL:
299 case Token::ASSIGN_SAR:
300 case Token::ASSIGN_SHR:
301 node->type()->SetAsLikelySmiIfUnknown();
302 node->target()->type()->SetAsLikelySmiIfUnknown();
303 node->value()->type()->SetAsLikelySmiIfUnknown();
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000304 node->value()->set_to_int32(true);
305 node->value()->set_no_negative_zero(true);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000306 break;
307 case Token::ASSIGN_ADD:
308 case Token::ASSIGN_SUB:
309 case Token::ASSIGN_MUL:
310 case Token::ASSIGN_DIV:
311 case Token::ASSIGN_MOD:
312 if (node->type()->IsLikelySmi()) {
313 node->target()->type()->SetAsLikelySmiIfUnknown();
314 node->value()->type()->SetAsLikelySmiIfUnknown();
315 }
316 break;
317 default:
318 UNREACHABLE();
319 break;
320 }
321
322 Visit(node->target());
323 Visit(node->value());
324
325 switch (node->op()) {
326 case Token::INIT_VAR:
327 case Token::INIT_CONST:
328 case Token::ASSIGN:
ager@chromium.org32912102009-01-16 10:38:43 +0000329 // Pure assignment copies the type from the value.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000330 node->type()->CopyFrom(node->value()->type());
331 break;
332 case Token::ASSIGN_BIT_OR:
333 case Token::ASSIGN_BIT_XOR:
334 case Token::ASSIGN_BIT_AND:
335 case Token::ASSIGN_SHL:
336 case Token::ASSIGN_SAR:
337 case Token::ASSIGN_SHR:
338 // Should have been setup above already.
339 break;
340 case Token::ASSIGN_ADD:
341 case Token::ASSIGN_SUB:
342 case Token::ASSIGN_MUL:
343 case Token::ASSIGN_DIV:
344 case Token::ASSIGN_MOD:
345 if (node->type()->IsUnknown()) {
346 if (node->target()->type()->IsLikelySmi() ||
347 node->value()->type()->IsLikelySmi()) {
348 node->type()->SetAsLikelySmi();
349 }
350 }
351 break;
352 default:
353 UNREACHABLE();
354 break;
355 }
356
357 // Since this is an assignment. We have to propagate this node's type to the
358 // variable.
359 VariableProxy* proxy = node->target()->AsVariableProxy();
360 if (proxy != NULL) {
361 Variable* var = proxy->AsVariable();
362 if (var != NULL) {
sgjesse@chromium.org846fb742009-12-18 08:56:33 +0000363 StaticType* var_type = var->type();
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000364 if (var_type->IsUnknown()) {
365 var_type->CopyFrom(node->type());
366 } else if (var_type->IsLikelySmi()) {
367 // We do not reset likely types to Unknown.
368 }
369 }
370 }
371}
372
373
374void AstOptimizer::VisitThrow(Throw* node) {
375 Visit(node->exception());
376}
377
378
379void AstOptimizer::VisitProperty(Property* node) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000380 node->key()->set_no_negative_zero(true);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000381 Visit(node->obj());
382 Visit(node->key());
383}
384
385
386void AstOptimizer::VisitCall(Call* node) {
387 Visit(node->expression());
388 OptimizeArguments(node->arguments());
389}
390
391
392void AstOptimizer::VisitCallNew(CallNew* node) {
393 Visit(node->expression());
394 OptimizeArguments(node->arguments());
395}
396
397
398void AstOptimizer::VisitCallRuntime(CallRuntime* node) {
399 OptimizeArguments(node->arguments());
400}
401
402
403void AstOptimizer::VisitUnaryOperation(UnaryOperation* node) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000404 if (node->op() == Token::ADD || node->op() == Token::SUB) {
405 node->expression()->set_no_negative_zero(node->no_negative_zero());
406 } else {
407 node->expression()->set_no_negative_zero(true);
408 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000409 Visit(node->expression());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000410 if (FLAG_safe_int32_compiler) {
411 switch (node->op()) {
412 case Token::BIT_NOT:
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000413 node->expression()->set_no_negative_zero(true);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000414 node->expression()->set_to_int32(true);
415 // Fall through.
416 case Token::ADD:
417 case Token::SUB:
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000418 node->set_side_effect_free(node->expression()->side_effect_free());
419 break;
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000420 case Token::NOT:
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000421 case Token::DELETE:
422 case Token::TYPEOF:
423 case Token::VOID:
424 break;
425 default:
426 UNREACHABLE();
427 break;
428 }
429 } else if (node->op() == Token::BIT_NOT) {
430 node->expression()->set_to_int32(true);
431 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000432}
433
434
ricow@chromium.org65fae842010-08-25 15:26:24 +0000435void AstOptimizer::VisitIncrementOperation(IncrementOperation* node) {
436 UNREACHABLE();
437}
438
439
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000440void AstOptimizer::VisitCountOperation(CountOperation* node) {
441 // Count operations assume that they work on Smis.
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000442 node->expression()->set_no_negative_zero(node->is_prefix() ?
443 true :
444 node->no_negative_zero());
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000445 node->type()->SetAsLikelySmiIfUnknown();
446 node->expression()->type()->SetAsLikelySmiIfUnknown();
447 Visit(node->expression());
448}
449
450
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000451static bool CouldBeNegativeZero(AstNode* node) {
452 Literal* literal = node->AsLiteral();
453 if (literal != NULL) {
454 Handle<Object> handle = literal->handle();
455 if (handle->IsString() || handle->IsSmi()) {
456 return false;
457 } else if (handle->IsHeapNumber()) {
458 double double_value = HeapNumber::cast(*handle)->value();
459 if (double_value != 0) {
460 return false;
461 }
462 }
463 }
464 BinaryOperation* binary = node->AsBinaryOperation();
465 if (binary != NULL && Token::IsBitOp(binary->op())) {
466 return false;
467 }
468 return true;
469}
470
471
472static bool CouldBePositiveZero(AstNode* node) {
473 Literal* literal = node->AsLiteral();
474 if (literal != NULL) {
475 Handle<Object> handle = literal->handle();
476 if (handle->IsSmi()) {
477 if (Smi::cast(*handle) != Smi::FromInt(0)) {
478 return false;
479 }
480 } else if (handle->IsHeapNumber()) {
481 // Heap number literal can't be +0, because that's a Smi.
482 return false;
483 }
484 }
485 return true;
486}
487
488
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000489void AstOptimizer::VisitBinaryOperation(BinaryOperation* node) {
490 // Depending on the operation we can propagate this node's type down the
491 // AST nodes.
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000492 Token::Value op = node->op();
493 switch (op) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000494 case Token::COMMA:
495 case Token::OR:
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000496 node->left()->set_no_negative_zero(true);
497 node->right()->set_no_negative_zero(node->no_negative_zero());
498 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000499 case Token::AND:
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000500 node->left()->set_no_negative_zero(node->no_negative_zero());
501 node->right()->set_no_negative_zero(node->no_negative_zero());
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000502 break;
503 case Token::BIT_OR:
504 case Token::BIT_XOR:
505 case Token::BIT_AND:
506 case Token::SHL:
507 case Token::SAR:
508 case Token::SHR:
509 node->type()->SetAsLikelySmiIfUnknown();
510 node->left()->type()->SetAsLikelySmiIfUnknown();
511 node->right()->type()->SetAsLikelySmiIfUnknown();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000512 node->left()->set_to_int32(true);
513 node->right()->set_to_int32(true);
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000514 node->left()->set_no_negative_zero(true);
515 node->right()->set_no_negative_zero(true);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000516 break;
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000517 case Token::MUL: {
518 VariableProxy* lvar_proxy = node->left()->AsVariableProxy();
519 VariableProxy* rvar_proxy = node->right()->AsVariableProxy();
520 if (lvar_proxy != NULL && rvar_proxy != NULL) {
521 Variable* lvar = lvar_proxy->AsVariable();
522 Variable* rvar = rvar_proxy->AsVariable();
523 if (lvar != NULL && rvar != NULL) {
524 if (lvar->mode() == Variable::VAR && rvar->mode() == Variable::VAR) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000525 Slot* lslot = lvar->AsSlot();
526 Slot* rslot = rvar->AsSlot();
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000527 if (lslot->type() == rslot->type() &&
528 (lslot->type() == Slot::PARAMETER ||
529 lslot->type() == Slot::LOCAL) &&
530 lslot->index() == rslot->index()) {
531 // A number squared doesn't give negative zero.
532 node->set_no_negative_zero(true);
533 }
534 }
535 }
536 }
537 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000538 case Token::ADD:
539 case Token::SUB:
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000540 case Token::DIV:
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000541 case Token::MOD: {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000542 if (node->type()->IsLikelySmi()) {
543 node->left()->type()->SetAsLikelySmiIfUnknown();
544 node->right()->type()->SetAsLikelySmiIfUnknown();
545 }
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000546 if (op == Token::ADD && (!CouldBeNegativeZero(node->left()) ||
547 !CouldBeNegativeZero(node->right()))) {
548 node->left()->set_no_negative_zero(true);
549 node->right()->set_no_negative_zero(true);
550 } else if (op == Token::SUB && (!CouldBeNegativeZero(node->left()) ||
551 !CouldBePositiveZero(node->right()))) {
552 node->left()->set_no_negative_zero(true);
553 node->right()->set_no_negative_zero(true);
554 } else {
555 node->left()->set_no_negative_zero(node->no_negative_zero());
556 node->right()->set_no_negative_zero(node->no_negative_zero());
557 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000558 if (node->op() == Token::DIV) {
559 node->right()->set_no_negative_zero(false);
560 } else if (node->op() == Token::MOD) {
561 node->right()->set_no_negative_zero(true);
562 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000563 break;
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000564 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000565 default:
566 UNREACHABLE();
567 break;
568 }
569
570 Visit(node->left());
571 Visit(node->right());
572
573 // After visiting the operand nodes we have to check if this node's type
574 // can be updated. If it does, then we can push that information down
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000575 // towards the leaves again if the new information is an upgrade over the
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000576 // previous type of the operand nodes.
577 if (node->type()->IsUnknown()) {
578 if (node->left()->type()->IsLikelySmi() ||
579 node->right()->type()->IsLikelySmi()) {
580 node->type()->SetAsLikelySmi();
581 }
582 if (node->type()->IsLikelySmi()) {
ager@chromium.org32912102009-01-16 10:38:43 +0000583 // The type of this node changed to LIKELY_SMI. Propagate this knowledge
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000584 // down through the nodes.
585 if (node->left()->type()->IsUnknown()) {
586 node->left()->type()->SetAsLikelySmi();
587 Visit(node->left());
588 }
589 if (node->right()->type()->IsUnknown()) {
590 node->right()->type()->SetAsLikelySmi();
591 Visit(node->right());
592 }
593 }
594 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000595
596 if (FLAG_safe_int32_compiler) {
597 switch (node->op()) {
598 case Token::COMMA:
599 case Token::OR:
600 case Token::AND:
601 break;
602 case Token::BIT_OR:
603 case Token::BIT_XOR:
604 case Token::BIT_AND:
605 case Token::SHL:
606 case Token::SAR:
607 case Token::SHR:
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000608 // Add one to the number of bit operations in this expression.
609 node->set_num_bit_ops(1);
610 // Fall through.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000611 case Token::ADD:
612 case Token::SUB:
613 case Token::MUL:
614 case Token::DIV:
615 case Token::MOD:
616 node->set_side_effect_free(node->left()->side_effect_free() &&
617 node->right()->side_effect_free());
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000618 node->set_num_bit_ops(node->num_bit_ops() +
619 node->left()->num_bit_ops() +
620 node->right()->num_bit_ops());
621 if (!node->no_negative_zero() && node->op() == Token::MUL) {
622 node->set_side_effect_free(false);
623 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000624 break;
625 default:
626 UNREACHABLE();
627 break;
628 }
629 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000630}
631
632
633void AstOptimizer::VisitCompareOperation(CompareOperation* node) {
634 if (node->type()->IsKnown()) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000635 // Propagate useful information down towards the leaves.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000636 node->left()->type()->SetAsLikelySmiIfUnknown();
637 node->right()->type()->SetAsLikelySmiIfUnknown();
638 }
639
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000640 node->left()->set_no_negative_zero(true);
641 // Only [[HasInstance]] has the right argument passed unchanged to it.
642 node->right()->set_no_negative_zero(true);
643
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000644 Visit(node->left());
645 Visit(node->right());
646
647 // After visiting the operand nodes we have to check if this node's type
648 // can be updated. If it does, then we can push that information down
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000649 // towards the leaves again if the new information is an upgrade over the
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000650 // previous type of the operand nodes.
651 if (node->type()->IsUnknown()) {
652 if (node->left()->type()->IsLikelySmi() ||
653 node->right()->type()->IsLikelySmi()) {
654 node->type()->SetAsLikelySmi();
655 }
656 if (node->type()->IsLikelySmi()) {
ager@chromium.org32912102009-01-16 10:38:43 +0000657 // The type of this node changed to LIKELY_SMI. Propagate this knowledge
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000658 // down through the nodes.
659 if (node->left()->type()->IsUnknown()) {
660 node->left()->type()->SetAsLikelySmi();
661 Visit(node->left());
662 }
663 if (node->right()->type()->IsUnknown()) {
664 node->right()->type()->SetAsLikelySmi();
665 Visit(node->right());
666 }
667 }
668 }
669}
670
671
ricow@chromium.org65fae842010-08-25 15:26:24 +0000672void AstOptimizer::VisitCompareToNull(CompareToNull* node) {
673 Visit(node->expression());
674}
675
676
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000677void AstOptimizer::VisitThisFunction(ThisFunction* node) {
678 USE(node);
679}
680
681
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000682class Processor: public AstVisitor {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000683 public:
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000684 explicit Processor(Variable* result)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000685 : result_(result),
686 result_assigned_(false),
687 is_set_(false),
688 in_try_(false) {
689 }
690
691 void Process(ZoneList<Statement*>* statements);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000692 bool result_assigned() const { return result_assigned_; }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000693
694 private:
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000695 Variable* result_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000696
697 // We are not tracking result usage via the result_'s use
698 // counts (we leave the accurate computation to the
699 // usage analyzer). Instead we simple remember if
700 // there was ever an assignment to result_.
701 bool result_assigned_;
702
703 // To avoid storing to .result all the time, we eliminate some of
704 // the stores by keeping track of whether or not we're sure .result
705 // will be overwritten anyway. This is a bit more tricky than what I
706 // was hoping for
707 bool is_set_;
708 bool in_try_;
709
710 Expression* SetResult(Expression* value) {
711 result_assigned_ = true;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000712 VariableProxy* result_proxy = new VariableProxy(result_);
713 return new Assignment(Token::ASSIGN, result_proxy, value,
ager@chromium.org236ad962008-09-25 09:45:57 +0000714 RelocInfo::kNoPosition);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000715 }
716
717 // Node visitors.
718#define DEF_VISIT(type) \
719 virtual void Visit##type(type* node);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000720 AST_NODE_LIST(DEF_VISIT)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000721#undef DEF_VISIT
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000722
723 void VisitIterationStatement(IterationStatement* stmt);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000724};
725
726
727void Processor::Process(ZoneList<Statement*>* statements) {
728 for (int i = statements->length() - 1; i >= 0; --i) {
729 Visit(statements->at(i));
730 }
731}
732
733
734void Processor::VisitBlock(Block* node) {
735 // An initializer block is the rewritten form of a variable declaration
736 // with initialization expressions. The initializer block contains the
737 // list of assignments corresponding to the initialization expressions.
738 // While unclear from the spec (ECMA-262, 3rd., 12.2), the value of
739 // a variable declaration with initialization expression is 'undefined'
740 // with some JS VMs: For instance, using smjs, print(eval('var x = 7'))
741 // returns 'undefined'. To obtain the same behavior with v8, we need
742 // to prevent rewriting in that case.
743 if (!node->is_initializer_block()) Process(node->statements());
744}
745
746
747void Processor::VisitExpressionStatement(ExpressionStatement* node) {
748 // Rewrite : <x>; -> .result = <x>;
749 if (!is_set_) {
750 node->set_expression(SetResult(node->expression()));
751 if (!in_try_) is_set_ = true;
752 }
753}
754
755
756void Processor::VisitIfStatement(IfStatement* node) {
757 // Rewrite both then and else parts (reversed).
758 bool save = is_set_;
759 Visit(node->else_statement());
760 bool set_after_then = is_set_;
761 is_set_ = save;
762 Visit(node->then_statement());
763 is_set_ = is_set_ && set_after_then;
764}
765
766
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000767void Processor::VisitIterationStatement(IterationStatement* node) {
768 // Rewrite the body.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000769 bool set_after_loop = is_set_;
770 Visit(node->body());
771 is_set_ = is_set_ && set_after_loop;
772}
773
774
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000775void Processor::VisitDoWhileStatement(DoWhileStatement* node) {
776 VisitIterationStatement(node);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000777}
778
779
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000780void Processor::VisitWhileStatement(WhileStatement* node) {
781 VisitIterationStatement(node);
782}
783
784
785void Processor::VisitForStatement(ForStatement* node) {
786 VisitIterationStatement(node);
787}
788
789
790void Processor::VisitForInStatement(ForInStatement* node) {
791 VisitIterationStatement(node);
792}
793
794
795void Processor::VisitTryCatchStatement(TryCatchStatement* node) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000796 // Rewrite both try and catch blocks (reversed order).
797 bool set_after_catch = is_set_;
798 Visit(node->catch_block());
799 is_set_ = is_set_ && set_after_catch;
800 bool save = in_try_;
801 in_try_ = true;
802 Visit(node->try_block());
803 in_try_ = save;
804}
805
806
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000807void Processor::VisitTryFinallyStatement(TryFinallyStatement* node) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000808 // Rewrite both try and finally block (reversed order).
809 Visit(node->finally_block());
810 bool save = in_try_;
811 in_try_ = true;
812 Visit(node->try_block());
813 in_try_ = save;
814}
815
816
817void Processor::VisitSwitchStatement(SwitchStatement* node) {
818 // Rewrite statements in all case clauses in reversed order.
819 ZoneList<CaseClause*>* clauses = node->cases();
820 bool set_after_switch = is_set_;
821 for (int i = clauses->length() - 1; i >= 0; --i) {
822 CaseClause* clause = clauses->at(i);
823 Process(clause->statements());
824 }
825 is_set_ = is_set_ && set_after_switch;
826}
827
828
829void Processor::VisitContinueStatement(ContinueStatement* node) {
830 is_set_ = false;
831}
832
833
834void Processor::VisitBreakStatement(BreakStatement* node) {
835 is_set_ = false;
836}
837
838
839// Do nothing:
840void Processor::VisitDeclaration(Declaration* node) {}
841void Processor::VisitEmptyStatement(EmptyStatement* node) {}
842void Processor::VisitReturnStatement(ReturnStatement* node) {}
843void Processor::VisitWithEnterStatement(WithEnterStatement* node) {}
844void Processor::VisitWithExitStatement(WithExitStatement* node) {}
845void Processor::VisitDebuggerStatement(DebuggerStatement* node) {}
846
847
848// Expressions are never visited yet.
849void Processor::VisitFunctionLiteral(FunctionLiteral* node) {
850 USE(node);
851 UNREACHABLE();
852}
853
854
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000855void Processor::VisitSharedFunctionInfoLiteral(
856 SharedFunctionInfoLiteral* node) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000857 USE(node);
858 UNREACHABLE();
859}
860
861
862void Processor::VisitConditional(Conditional* node) {
863 USE(node);
864 UNREACHABLE();
865}
866
867
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000868void Processor::VisitVariableProxy(VariableProxy* node) {
869 USE(node);
870 UNREACHABLE();
871}
872
873
874void Processor::VisitLiteral(Literal* node) {
875 USE(node);
876 UNREACHABLE();
877}
878
879
880void Processor::VisitRegExpLiteral(RegExpLiteral* node) {
881 USE(node);
882 UNREACHABLE();
883}
884
885
886void Processor::VisitArrayLiteral(ArrayLiteral* node) {
887 USE(node);
888 UNREACHABLE();
889}
890
891
892void Processor::VisitObjectLiteral(ObjectLiteral* node) {
893 USE(node);
894 UNREACHABLE();
895}
896
897
ager@chromium.org32912102009-01-16 10:38:43 +0000898void Processor::VisitCatchExtensionObject(CatchExtensionObject* node) {
899 USE(node);
900 UNREACHABLE();
901}
902
903
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000904void Processor::VisitAssignment(Assignment* node) {
905 USE(node);
906 UNREACHABLE();
907}
908
909
910void Processor::VisitThrow(Throw* node) {
911 USE(node);
912 UNREACHABLE();
913}
914
915
916void Processor::VisitProperty(Property* node) {
917 USE(node);
918 UNREACHABLE();
919}
920
921
922void Processor::VisitCall(Call* node) {
923 USE(node);
924 UNREACHABLE();
925}
926
927
928void Processor::VisitCallNew(CallNew* node) {
929 USE(node);
930 UNREACHABLE();
931}
932
933
934void Processor::VisitCallRuntime(CallRuntime* node) {
935 USE(node);
936 UNREACHABLE();
937}
938
939
940void Processor::VisitUnaryOperation(UnaryOperation* node) {
941 USE(node);
942 UNREACHABLE();
943}
944
945
ricow@chromium.org65fae842010-08-25 15:26:24 +0000946void Processor::VisitIncrementOperation(IncrementOperation* node) {
947 UNREACHABLE();
948}
949
950
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000951void Processor::VisitCountOperation(CountOperation* node) {
952 USE(node);
953 UNREACHABLE();
954}
955
956
957void Processor::VisitBinaryOperation(BinaryOperation* node) {
958 USE(node);
959 UNREACHABLE();
960}
961
962
963void Processor::VisitCompareOperation(CompareOperation* node) {
964 USE(node);
965 UNREACHABLE();
966}
967
968
ricow@chromium.org65fae842010-08-25 15:26:24 +0000969void Processor::VisitCompareToNull(CompareToNull* node) {
970 USE(node);
971 UNREACHABLE();
972}
973
974
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000975void Processor::VisitThisFunction(ThisFunction* node) {
976 USE(node);
977 UNREACHABLE();
978}
979
980
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000981// Assumes code has been parsed and scopes have been analyzed. Mutates the
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000982// AST, so the AST should not continue to be used in the case of failure.
983bool Rewriter::Rewrite(CompilationInfo* info) {
984 FunctionLiteral* function = info->function();
985 ASSERT(function != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000986 Scope* scope = function->scope();
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000987 ASSERT(scope != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000988 if (scope->is_function_scope()) return true;
989
990 ZoneList<Statement*>* body = function->body();
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000991 if (!body->is_empty()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000992 Variable* result = scope->NewTemporary(Factory::result_symbol());
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000993 Processor processor(result);
994 processor.Process(body);
995 if (processor.HasStackOverflow()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000996
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000997 if (processor.result_assigned()) {
998 VariableProxy* result_proxy = new VariableProxy(result);
999 body->Add(new ReturnStatement(result_proxy));
1000 }
ager@chromium.orgb61a0d12010-10-13 08:35:23 +00001001 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001002
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001003 return true;
1004}
1005
1006
ager@chromium.orgb61a0d12010-10-13 08:35:23 +00001007// Assumes code has been parsed and scopes have been analyzed. Mutates the
1008// AST, so the AST should not continue to be used in the case of failure.
1009bool Rewriter::Analyze(CompilationInfo* info) {
1010 FunctionLiteral* function = info->function();
1011 ASSERT(function != NULL && function->scope() != NULL);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001012
ager@chromium.orgb61a0d12010-10-13 08:35:23 +00001013 ZoneList<Statement*>* body = function->body();
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001014 if (FLAG_optimize_ast && !body->is_empty()) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00001015 AstOptimizer optimizer;
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00001016 optimizer.Optimize(body);
ager@chromium.orgb61a0d12010-10-13 08:35:23 +00001017 if (optimizer.HasStackOverflow()) return false;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001018 }
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001019 return true;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001020}
1021
1022
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001023} } // namespace v8::internal