blob: 780314d9c979c17cf07d6d7dceff6ed830bedcb7 [file] [log] [blame]
Ben Murdochf87a2032010-10-22 12:50:53 +01001// Copyright 2010 the V8 project authors. All rights reserved.
Steve Blocka7e24c12009-10-30 11:49:00 +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
Steve Blocka7e24c12009-10-30 11:49:00 +000030#include "rewriter.h"
31
Ben Murdochf87a2032010-10-22 12:50:53 +010032#include "ast.h"
33#include "compiler.h"
34#include "scopes.h"
35
Steve Blocka7e24c12009-10-30 11:49:00 +000036namespace v8 {
37namespace internal {
38
Steve Blocka7e24c12009-10-30 11:49:00 +000039class AstOptimizer: public AstVisitor {
40 public:
41 explicit AstOptimizer() : has_function_literal_(false) {}
Steve Blocka7e24c12009-10-30 11:49:00 +000042
43 void Optimize(ZoneList<Statement*>* statements);
44
45 private:
46 // Used for loop condition analysis. Cleared before visiting a loop
47 // condition, set when a function literal is visited.
48 bool has_function_literal_;
Steve Blocka7e24c12009-10-30 11:49:00 +000049
50 // Helpers
51 void OptimizeArguments(ZoneList<Expression*>* arguments);
52
53 // Node visitors.
54#define DEF_VISIT(type) \
55 virtual void Visit##type(type* node);
56 AST_NODE_LIST(DEF_VISIT)
57#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) {
Steve Block8defd9f2010-07-08 12:39:36 +010084 node->expression()->set_no_negative_zero(true);
Steve Blocka7e24c12009-10-30 11:49:00 +000085 Visit(node->expression());
86}
87
88
89void AstOptimizer::VisitIfStatement(IfStatement* node) {
Steve Block8defd9f2010-07-08 12:39:36 +010090 node->condition()->set_no_negative_zero(true);
Steve Blocka7e24c12009-10-30 11:49:00 +000091 Visit(node->condition());
92 Visit(node->then_statement());
93 if (node->HasElseStatement()) {
94 Visit(node->else_statement());
95 }
96}
97
98
Steve Block3ce2e202009-11-05 08:53:23 +000099void AstOptimizer::VisitDoWhileStatement(DoWhileStatement* node) {
Steve Block8defd9f2010-07-08 12:39:36 +0100100 node->cond()->set_no_negative_zero(true);
Steve Block3ce2e202009-11-05 08:53:23 +0000101 Visit(node->cond());
102 Visit(node->body());
103}
104
105
106void AstOptimizer::VisitWhileStatement(WhileStatement* node) {
107 has_function_literal_ = false;
Steve Block8defd9f2010-07-08 12:39:36 +0100108 node->cond()->set_no_negative_zero(true);
Steve Block3ce2e202009-11-05 08:53:23 +0000109 Visit(node->cond());
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100110 node->set_may_have_function_literal(has_function_literal_);
Steve Block3ce2e202009-11-05 08:53:23 +0000111 Visit(node->body());
112}
113
114
115void AstOptimizer::VisitForStatement(ForStatement* node) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000116 if (node->init() != NULL) {
117 Visit(node->init());
118 }
119 if (node->cond() != NULL) {
120 has_function_literal_ = false;
Steve Block8defd9f2010-07-08 12:39:36 +0100121 node->cond()->set_no_negative_zero(true);
Steve Blocka7e24c12009-10-30 11:49:00 +0000122 Visit(node->cond());
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100123 node->set_may_have_function_literal(has_function_literal_);
Steve Blocka7e24c12009-10-30 11:49:00 +0000124 }
Steve Block3ce2e202009-11-05 08:53:23 +0000125 Visit(node->body());
Steve Blocka7e24c12009-10-30 11:49:00 +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
Steve Block3ce2e202009-11-05 08:53:23 +0000139void AstOptimizer::VisitTryCatchStatement(TryCatchStatement* node) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000140 Visit(node->try_block());
141 Visit(node->catch_var());
142 Visit(node->catch_block());
143}
144
145
Steve Block3ce2e202009-11-05 08:53:23 +0000146void AstOptimizer::VisitTryFinallyStatement(TryFinallyStatement* node) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000147 Visit(node->try_block());
148 Visit(node->finally_block());
149}
150
151
152void AstOptimizer::VisitSwitchStatement(SwitchStatement* node) {
Steve Block8defd9f2010-07-08 12:39:36 +0100153 node->tag()->set_no_negative_zero(true);
Steve Blocka7e24c12009-10-30 11:49:00 +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) {
207 has_function_literal_ = true;
Steve Blocka7e24c12009-10-30 11:49:00 +0000208}
209
210
Steve Block6ded16b2010-05-10 14:33:55 +0100211void AstOptimizer::VisitSharedFunctionInfoLiteral(
212 SharedFunctionInfoLiteral* node) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000213 USE(node);
214}
215
216
217void AstOptimizer::VisitConditional(Conditional* node) {
Steve Block6ded16b2010-05-10 14:33:55 +0100218 node->condition()->set_no_negative_zero(true);
Steve Blocka7e24c12009-10-30 11:49:00 +0000219 Visit(node->condition());
220 Visit(node->then_expression());
221 Visit(node->else_expression());
222}
223
224
Steve Blocka7e24c12009-10-30 11:49:00 +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 }
233
Steve Block6ded16b2010-05-10 14:33:55 +0100234 if (FLAG_safe_int32_compiler) {
235 if (var->IsStackAllocated() &&
236 !var->is_arguments() &&
237 var->mode() != Variable::CONST) {
238 node->set_side_effect_free(true);
239 }
240 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000241 }
242}
243
244
245void AstOptimizer::VisitLiteral(Literal* node) {
246 Handle<Object> literal = node->handle();
247 if (literal->IsSmi()) {
248 node->type()->SetAsLikelySmi();
Steve Block6ded16b2010-05-10 14:33:55 +0100249 node->set_side_effect_free(true);
Steve Block6ded16b2010-05-10 14:33:55 +0100250 } else if (literal->IsHeapNumber()) {
251 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 }
Steve Blocka7e24c12009-10-30 11:49:00 +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
274void AstOptimizer::VisitObjectLiteral(ObjectLiteral* node) {
275 for (int i = 0; i < node->properties()->length(); i++) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000276 Visit(node->properties()->at(i)->key());
277 Visit(node->properties()->at(i)->value());
278 }
279}
280
281
282void AstOptimizer::VisitCatchExtensionObject(CatchExtensionObject* node) {
283 Visit(node->key());
284 Visit(node->value());
285}
286
287
288void AstOptimizer::VisitAssignment(Assignment* node) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000289 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.
Steve Blocka7e24c12009-10-30 11:49:00 +0000294 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();
Steve Block6ded16b2010-05-10 14:33:55 +0100304 node->value()->set_to_int32(true);
305 node->value()->set_no_negative_zero(true);
Steve Blocka7e24c12009-10-30 11:49:00 +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:
329 // Pure assignment copies the type from the value.
330 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) {
Leon Clarkee46be812010-01-19 14:06:41 +0000363 StaticType* var_type = var->type();
Steve Blocka7e24c12009-10-30 11:49:00 +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) {
Steve Block6ded16b2010-05-10 14:33:55 +0100380 node->key()->set_no_negative_zero(true);
Steve Blocka7e24c12009-10-30 11:49:00 +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) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000399 OptimizeArguments(node->arguments());
400}
401
402
403void AstOptimizer::VisitUnaryOperation(UnaryOperation* node) {
Steve Block6ded16b2010-05-10 14:33:55 +0100404 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 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000409 Visit(node->expression());
Steve Block6ded16b2010-05-10 14:33:55 +0100410 if (FLAG_safe_int32_compiler) {
411 switch (node->op()) {
412 case Token::BIT_NOT:
Steve Block8defd9f2010-07-08 12:39:36 +0100413 node->expression()->set_no_negative_zero(true);
Steve Block6ded16b2010-05-10 14:33:55 +0100414 node->expression()->set_to_int32(true);
415 // Fall through.
416 case Token::ADD:
417 case Token::SUB:
418 node->set_side_effect_free(node->expression()->side_effect_free());
419 break;
420 case Token::NOT:
421 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 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000432}
433
434
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100435void AstOptimizer::VisitIncrementOperation(IncrementOperation* node) {
436 UNREACHABLE();
437}
438
439
Steve Blocka7e24c12009-10-30 11:49:00 +0000440void AstOptimizer::VisitCountOperation(CountOperation* node) {
441 // Count operations assume that they work on Smis.
Steve Block6ded16b2010-05-10 14:33:55 +0100442 node->expression()->set_no_negative_zero(node->is_prefix() ?
443 true :
444 node->no_negative_zero());
Steve Blocka7e24c12009-10-30 11:49:00 +0000445 node->type()->SetAsLikelySmiIfUnknown();
446 node->expression()->type()->SetAsLikelySmiIfUnknown();
447 Visit(node->expression());
448}
449
450
Steve Block8defd9f2010-07-08 12:39:36 +0100451static 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
Steve Blocka7e24c12009-10-30 11:49:00 +0000489void AstOptimizer::VisitBinaryOperation(BinaryOperation* node) {
490 // Depending on the operation we can propagate this node's type down the
491 // AST nodes.
Steve Block8defd9f2010-07-08 12:39:36 +0100492 Token::Value op = node->op();
493 switch (op) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000494 case Token::COMMA:
495 case Token::OR:
Steve Block6ded16b2010-05-10 14:33:55 +0100496 node->left()->set_no_negative_zero(true);
497 node->right()->set_no_negative_zero(node->no_negative_zero());
498 break;
Steve Blocka7e24c12009-10-30 11:49:00 +0000499 case Token::AND:
Steve Block6ded16b2010-05-10 14:33:55 +0100500 node->left()->set_no_negative_zero(node->no_negative_zero());
501 node->right()->set_no_negative_zero(node->no_negative_zero());
Steve Blocka7e24c12009-10-30 11:49:00 +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();
Steve Block6ded16b2010-05-10 14:33:55 +0100512 node->left()->set_to_int32(true);
513 node->right()->set_to_int32(true);
514 node->left()->set_no_negative_zero(true);
515 node->right()->set_no_negative_zero(true);
Steve Blocka7e24c12009-10-30 11:49:00 +0000516 break;
Steve Block8defd9f2010-07-08 12:39:36 +0100517 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) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100525 Slot* lslot = lvar->AsSlot();
526 Slot* rslot = rvar->AsSlot();
Steve Block8defd9f2010-07-08 12:39:36 +0100527 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 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000538 case Token::ADD:
539 case Token::SUB:
Steve Blocka7e24c12009-10-30 11:49:00 +0000540 case Token::DIV:
Steve Block8defd9f2010-07-08 12:39:36 +0100541 case Token::MOD: {
Steve Blocka7e24c12009-10-30 11:49:00 +0000542 if (node->type()->IsLikelySmi()) {
543 node->left()->type()->SetAsLikelySmiIfUnknown();
544 node->right()->type()->SetAsLikelySmiIfUnknown();
545 }
Steve Block8defd9f2010-07-08 12:39:36 +0100546 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 }
Steve Block6ded16b2010-05-10 14:33:55 +0100558 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 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000563 break;
Steve Block8defd9f2010-07-08 12:39:36 +0100564 }
Steve Blocka7e24c12009-10-30 11:49:00 +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
Steve Block8defd9f2010-07-08 12:39:36 +0100575 // towards the leaves again if the new information is an upgrade over the
Steve Blocka7e24c12009-10-30 11:49:00 +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()) {
583 // The type of this node changed to LIKELY_SMI. Propagate this knowledge
584 // 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 }
Steve Block6ded16b2010-05-10 14:33:55 +0100595
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:
608 // Add one to the number of bit operations in this expression.
609 node->set_num_bit_ops(1);
610 // Fall through.
611 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());
618 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 }
624 break;
625 default:
626 UNREACHABLE();
627 break;
628 }
629 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000630}
631
632
633void AstOptimizer::VisitCompareOperation(CompareOperation* node) {
634 if (node->type()->IsKnown()) {
Steve Block8defd9f2010-07-08 12:39:36 +0100635 // Propagate useful information down towards the leaves.
Steve Blocka7e24c12009-10-30 11:49:00 +0000636 node->left()->type()->SetAsLikelySmiIfUnknown();
637 node->right()->type()->SetAsLikelySmiIfUnknown();
638 }
639
Steve Block6ded16b2010-05-10 14:33:55 +0100640 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
Steve Blocka7e24c12009-10-30 11:49:00 +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
Steve Block8defd9f2010-07-08 12:39:36 +0100649 // towards the leaves again if the new information is an upgrade over the
Steve Blocka7e24c12009-10-30 11:49:00 +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()) {
657 // The type of this node changed to LIKELY_SMI. Propagate this knowledge
658 // 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
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100672void AstOptimizer::VisitCompareToNull(CompareToNull* node) {
673 Visit(node->expression());
674}
675
676
Steve Blocka7e24c12009-10-30 11:49:00 +0000677void AstOptimizer::VisitThisFunction(ThisFunction* node) {
678 USE(node);
679}
680
681
682class Processor: public AstVisitor {
683 public:
Ben Murdochb0fe1622011-05-05 13:52:32 +0100684 explicit Processor(Variable* result)
Steve Blocka7e24c12009-10-30 11:49:00 +0000685 : result_(result),
686 result_assigned_(false),
687 is_set_(false),
688 in_try_(false) {
689 }
690
691 void Process(ZoneList<Statement*>* statements);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100692 bool result_assigned() const { return result_assigned_; }
Steve Blocka7e24c12009-10-30 11:49:00 +0000693
694 private:
Ben Murdochb0fe1622011-05-05 13:52:32 +0100695 Variable* result_;
Steve Blocka7e24c12009-10-30 11:49:00 +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;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100712 VariableProxy* result_proxy = new VariableProxy(result_);
713 return new Assignment(Token::ASSIGN, result_proxy, value,
Steve Blocka7e24c12009-10-30 11:49:00 +0000714 RelocInfo::kNoPosition);
715 }
716
717 // Node visitors.
718#define DEF_VISIT(type) \
719 virtual void Visit##type(type* node);
720 AST_NODE_LIST(DEF_VISIT)
721#undef DEF_VISIT
Steve Block3ce2e202009-11-05 08:53:23 +0000722
723 void VisitIterationStatement(IterationStatement* stmt);
Steve Blocka7e24c12009-10-30 11:49:00 +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
Steve Block3ce2e202009-11-05 08:53:23 +0000767void Processor::VisitIterationStatement(IterationStatement* node) {
768 // Rewrite the body.
Steve Blocka7e24c12009-10-30 11:49:00 +0000769 bool set_after_loop = is_set_;
770 Visit(node->body());
771 is_set_ = is_set_ && set_after_loop;
772}
773
774
Steve Block3ce2e202009-11-05 08:53:23 +0000775void Processor::VisitDoWhileStatement(DoWhileStatement* node) {
776 VisitIterationStatement(node);
Steve Blocka7e24c12009-10-30 11:49:00 +0000777}
778
779
Steve Block3ce2e202009-11-05 08:53:23 +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) {
Steve Blocka7e24c12009-10-30 11:49:00 +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
Steve Block3ce2e202009-11-05 08:53:23 +0000807void Processor::VisitTryFinallyStatement(TryFinallyStatement* node) {
Steve Blocka7e24c12009-10-30 11:49:00 +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
Steve Block6ded16b2010-05-10 14:33:55 +0100855void Processor::VisitSharedFunctionInfoLiteral(
856 SharedFunctionInfoLiteral* node) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000857 USE(node);
858 UNREACHABLE();
859}
860
861
862void Processor::VisitConditional(Conditional* node) {
863 USE(node);
864 UNREACHABLE();
865}
866
867
Steve Blocka7e24c12009-10-30 11:49:00 +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
898void Processor::VisitCatchExtensionObject(CatchExtensionObject* node) {
899 USE(node);
900 UNREACHABLE();
901}
902
903
904void 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
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100946void Processor::VisitIncrementOperation(IncrementOperation* node) {
947 UNREACHABLE();
948}
949
950
Steve Blocka7e24c12009-10-30 11:49:00 +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
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100969void Processor::VisitCompareToNull(CompareToNull* node) {
970 USE(node);
971 UNREACHABLE();
972}
973
974
Steve Blocka7e24c12009-10-30 11:49:00 +0000975void Processor::VisitThisFunction(ThisFunction* node) {
976 USE(node);
977 UNREACHABLE();
978}
979
980
Ben Murdochb8e0da22011-05-16 14:20:40 +0100981// Assumes code has been parsed and scopes have been analyzed. Mutates the
Ben Murdochf87a2032010-10-22 12:50:53 +0100982// 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);
Steve Blocka7e24c12009-10-30 11:49:00 +0000986 Scope* scope = function->scope();
Ben Murdochf87a2032010-10-22 12:50:53 +0100987 ASSERT(scope != NULL);
Steve Blocka7e24c12009-10-30 11:49:00 +0000988 if (scope->is_function_scope()) return true;
989
990 ZoneList<Statement*>* body = function->body();
Ben Murdochf87a2032010-10-22 12:50:53 +0100991 if (!body->is_empty()) {
Steve Block44f0eee2011-05-26 01:26:41 +0100992 Variable* result = scope->NewTemporary(
993 info->isolate()->factory()->result_symbol());
Ben Murdochf87a2032010-10-22 12:50:53 +0100994 Processor processor(result);
995 processor.Process(body);
996 if (processor.HasStackOverflow()) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +0000997
Ben Murdochb0fe1622011-05-05 13:52:32 +0100998 if (processor.result_assigned()) {
999 VariableProxy* result_proxy = new VariableProxy(result);
1000 body->Add(new ReturnStatement(result_proxy));
1001 }
Ben Murdochf87a2032010-10-22 12:50:53 +01001002 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001003
Steve Blocka7e24c12009-10-30 11:49:00 +00001004 return true;
1005}
1006
1007
Ben Murdochf87a2032010-10-22 12:50:53 +01001008// Assumes code has been parsed and scopes have been analyzed. Mutates the
1009// AST, so the AST should not continue to be used in the case of failure.
1010bool Rewriter::Analyze(CompilationInfo* info) {
1011 FunctionLiteral* function = info->function();
1012 ASSERT(function != NULL && function->scope() != NULL);
Steve Blocka7e24c12009-10-30 11:49:00 +00001013
Ben Murdochf87a2032010-10-22 12:50:53 +01001014 ZoneList<Statement*>* body = function->body();
Steve Blocka7e24c12009-10-30 11:49:00 +00001015 if (FLAG_optimize_ast && !body->is_empty()) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001016 AstOptimizer optimizer;
Steve Blocka7e24c12009-10-30 11:49:00 +00001017 optimizer.Optimize(body);
Ben Murdochf87a2032010-10-22 12:50:53 +01001018 if (optimizer.HasStackOverflow()) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +00001019 }
1020 return true;
1021}
1022
1023
1024} } // namespace v8::internal