blob: 73301b91864e797040c525d6c25b0840e243fd79 [file] [log] [blame]
Steve Blocka7e24c12009-10-30 11:49:00 +00001// Copyright 2006-2008 the V8 project authors. All rights reserved.
2// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include "v8.h"
29
30#include "ast.h"
31#include "func-name-inferrer.h"
32#include "scopes.h"
33#include "rewriter.h"
34
35namespace v8 {
36namespace internal {
37
38
39class AstOptimizer: public AstVisitor {
40 public:
41 explicit AstOptimizer() : has_function_literal_(false) {}
42 explicit AstOptimizer(Handle<String> enclosing_name)
43 : has_function_literal_(false) {
44 func_name_inferrer_.PushEnclosingName(enclosing_name);
45 }
46
47 void Optimize(ZoneList<Statement*>* statements);
48
49 private:
50 // Used for loop condition analysis. Cleared before visiting a loop
51 // condition, set when a function literal is visited.
52 bool has_function_literal_;
53 // Helper object for function name inferring.
54 FuncNameInferrer func_name_inferrer_;
55
56 // Helpers
57 void OptimizeArguments(ZoneList<Expression*>* arguments);
58
59 // Node visitors.
60#define DEF_VISIT(type) \
61 virtual void Visit##type(type* node);
62 AST_NODE_LIST(DEF_VISIT)
63#undef DEF_VISIT
64
65 DISALLOW_COPY_AND_ASSIGN(AstOptimizer);
66};
67
68
69void AstOptimizer::Optimize(ZoneList<Statement*>* statements) {
70 int len = statements->length();
71 for (int i = 0; i < len; i++) {
72 Visit(statements->at(i));
73 }
74}
75
76
77void AstOptimizer::OptimizeArguments(ZoneList<Expression*>* arguments) {
78 for (int i = 0; i < arguments->length(); i++) {
79 Visit(arguments->at(i));
80 }
81}
82
83
84void AstOptimizer::VisitBlock(Block* node) {
85 Optimize(node->statements());
86}
87
88
89void AstOptimizer::VisitExpressionStatement(ExpressionStatement* node) {
Steve Block8defd9f2010-07-08 12:39:36 +010090 node->expression()->set_no_negative_zero(true);
Steve Blocka7e24c12009-10-30 11:49:00 +000091 Visit(node->expression());
92}
93
94
95void AstOptimizer::VisitIfStatement(IfStatement* node) {
Steve Block8defd9f2010-07-08 12:39:36 +010096 node->condition()->set_no_negative_zero(true);
Steve Blocka7e24c12009-10-30 11:49:00 +000097 Visit(node->condition());
98 Visit(node->then_statement());
99 if (node->HasElseStatement()) {
100 Visit(node->else_statement());
101 }
102}
103
104
Steve Block3ce2e202009-11-05 08:53:23 +0000105void AstOptimizer::VisitDoWhileStatement(DoWhileStatement* node) {
Steve Block8defd9f2010-07-08 12:39:36 +0100106 node->cond()->set_no_negative_zero(true);
Steve Block3ce2e202009-11-05 08:53:23 +0000107 Visit(node->cond());
108 Visit(node->body());
109}
110
111
112void AstOptimizer::VisitWhileStatement(WhileStatement* node) {
113 has_function_literal_ = false;
Steve Block8defd9f2010-07-08 12:39:36 +0100114 node->cond()->set_no_negative_zero(true);
Steve Block3ce2e202009-11-05 08:53:23 +0000115 Visit(node->cond());
116 node->may_have_function_literal_ = has_function_literal_;
117 Visit(node->body());
118}
119
120
121void AstOptimizer::VisitForStatement(ForStatement* node) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000122 if (node->init() != NULL) {
123 Visit(node->init());
124 }
125 if (node->cond() != NULL) {
126 has_function_literal_ = false;
Steve Block8defd9f2010-07-08 12:39:36 +0100127 node->cond()->set_no_negative_zero(true);
Steve Blocka7e24c12009-10-30 11:49:00 +0000128 Visit(node->cond());
129 node->may_have_function_literal_ = has_function_literal_;
130 }
Steve Block3ce2e202009-11-05 08:53:23 +0000131 Visit(node->body());
Steve Blocka7e24c12009-10-30 11:49:00 +0000132 if (node->next() != NULL) {
133 Visit(node->next());
134 }
135}
136
137
138void AstOptimizer::VisitForInStatement(ForInStatement* node) {
139 Visit(node->each());
140 Visit(node->enumerable());
141 Visit(node->body());
142}
143
144
Steve Block3ce2e202009-11-05 08:53:23 +0000145void AstOptimizer::VisitTryCatchStatement(TryCatchStatement* node) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000146 Visit(node->try_block());
147 Visit(node->catch_var());
148 Visit(node->catch_block());
149}
150
151
Steve Block3ce2e202009-11-05 08:53:23 +0000152void AstOptimizer::VisitTryFinallyStatement(TryFinallyStatement* node) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000153 Visit(node->try_block());
154 Visit(node->finally_block());
155}
156
157
158void AstOptimizer::VisitSwitchStatement(SwitchStatement* node) {
Steve Block8defd9f2010-07-08 12:39:36 +0100159 node->tag()->set_no_negative_zero(true);
Steve Blocka7e24c12009-10-30 11:49:00 +0000160 Visit(node->tag());
161 for (int i = 0; i < node->cases()->length(); i++) {
162 CaseClause* clause = node->cases()->at(i);
163 if (!clause->is_default()) {
164 Visit(clause->label());
165 }
166 Optimize(clause->statements());
167 }
168}
169
170
171void AstOptimizer::VisitContinueStatement(ContinueStatement* node) {
172 USE(node);
173}
174
175
176void AstOptimizer::VisitBreakStatement(BreakStatement* node) {
177 USE(node);
178}
179
180
181void AstOptimizer::VisitDeclaration(Declaration* node) {
182 // Will not be reached by the current optimizations.
183 USE(node);
184}
185
186
187void AstOptimizer::VisitEmptyStatement(EmptyStatement* node) {
188 USE(node);
189}
190
191
192void AstOptimizer::VisitReturnStatement(ReturnStatement* node) {
193 Visit(node->expression());
194}
195
196
197void AstOptimizer::VisitWithEnterStatement(WithEnterStatement* node) {
198 Visit(node->expression());
199}
200
201
202void AstOptimizer::VisitWithExitStatement(WithExitStatement* node) {
203 USE(node);
204}
205
206
207void AstOptimizer::VisitDebuggerStatement(DebuggerStatement* node) {
208 USE(node);
209}
210
211
212void AstOptimizer::VisitFunctionLiteral(FunctionLiteral* node) {
213 has_function_literal_ = true;
214
215 if (node->name()->length() == 0) {
216 // Anonymous function.
217 func_name_inferrer_.AddFunction(node);
218 }
219}
220
221
Steve Block6ded16b2010-05-10 14:33:55 +0100222void AstOptimizer::VisitSharedFunctionInfoLiteral(
223 SharedFunctionInfoLiteral* node) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000224 USE(node);
225}
226
227
228void AstOptimizer::VisitConditional(Conditional* node) {
Steve Block6ded16b2010-05-10 14:33:55 +0100229 node->condition()->set_no_negative_zero(true);
Steve Blocka7e24c12009-10-30 11:49:00 +0000230 Visit(node->condition());
231 Visit(node->then_expression());
232 Visit(node->else_expression());
233}
234
235
236void AstOptimizer::VisitSlot(Slot* node) {
237 USE(node);
238}
239
240
241void AstOptimizer::VisitVariableProxy(VariableProxy* node) {
242 Variable* var = node->AsVariable();
243 if (var != NULL) {
244 if (var->type()->IsKnown()) {
245 node->type()->CopyFrom(var->type());
246 } else if (node->type()->IsLikelySmi()) {
247 var->type()->SetAsLikelySmi();
248 }
249
250 if (!var->is_this() &&
251 !Heap::result_symbol()->Equals(*var->name())) {
252 func_name_inferrer_.PushName(var->name());
253 }
Steve Block6ded16b2010-05-10 14:33:55 +0100254
255 if (FLAG_safe_int32_compiler) {
256 if (var->IsStackAllocated() &&
257 !var->is_arguments() &&
258 var->mode() != Variable::CONST) {
259 node->set_side_effect_free(true);
260 }
261 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000262 }
263}
264
265
266void AstOptimizer::VisitLiteral(Literal* node) {
267 Handle<Object> literal = node->handle();
268 if (literal->IsSmi()) {
269 node->type()->SetAsLikelySmi();
Steve Block6ded16b2010-05-10 14:33:55 +0100270 node->set_side_effect_free(true);
Steve Blocka7e24c12009-10-30 11:49:00 +0000271 } else if (literal->IsString()) {
272 Handle<String> lit_str(Handle<String>::cast(literal));
273 if (!Heap::prototype_symbol()->Equals(*lit_str)) {
274 func_name_inferrer_.PushName(lit_str);
275 }
Steve Block6ded16b2010-05-10 14:33:55 +0100276 } else if (literal->IsHeapNumber()) {
277 if (node->to_int32()) {
278 // Any HeapNumber has an int32 value if it is the input to a bit op.
279 node->set_side_effect_free(true);
280 } else {
281 double double_value = HeapNumber::cast(*literal)->value();
282 int32_t int32_value = DoubleToInt32(double_value);
283 node->set_side_effect_free(double_value == int32_value);
284 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000285 }
286}
287
288
289void AstOptimizer::VisitRegExpLiteral(RegExpLiteral* node) {
290 USE(node);
291}
292
293
294void AstOptimizer::VisitArrayLiteral(ArrayLiteral* node) {
295 for (int i = 0; i < node->values()->length(); i++) {
296 Visit(node->values()->at(i));
297 }
298}
299
300void AstOptimizer::VisitObjectLiteral(ObjectLiteral* node) {
301 for (int i = 0; i < node->properties()->length(); i++) {
302 ScopedFuncNameInferrer scoped_fni(&func_name_inferrer_);
303 scoped_fni.Enter();
304 Visit(node->properties()->at(i)->key());
305 Visit(node->properties()->at(i)->value());
306 }
307}
308
309
310void AstOptimizer::VisitCatchExtensionObject(CatchExtensionObject* node) {
311 Visit(node->key());
312 Visit(node->value());
313}
314
315
316void AstOptimizer::VisitAssignment(Assignment* node) {
317 ScopedFuncNameInferrer scoped_fni(&func_name_inferrer_);
318 switch (node->op()) {
319 case Token::INIT_VAR:
320 case Token::INIT_CONST:
321 case Token::ASSIGN:
322 // No type can be infered from the general assignment.
323
324 // Don't infer if it is "a = function(){...}();"-like expression.
325 if (node->value()->AsCall() == NULL) {
326 scoped_fni.Enter();
327 }
328 break;
329 case Token::ASSIGN_BIT_OR:
330 case Token::ASSIGN_BIT_XOR:
331 case Token::ASSIGN_BIT_AND:
332 case Token::ASSIGN_SHL:
333 case Token::ASSIGN_SAR:
334 case Token::ASSIGN_SHR:
335 node->type()->SetAsLikelySmiIfUnknown();
336 node->target()->type()->SetAsLikelySmiIfUnknown();
337 node->value()->type()->SetAsLikelySmiIfUnknown();
Steve Block6ded16b2010-05-10 14:33:55 +0100338 node->value()->set_to_int32(true);
339 node->value()->set_no_negative_zero(true);
Steve Blocka7e24c12009-10-30 11:49:00 +0000340 break;
341 case Token::ASSIGN_ADD:
342 case Token::ASSIGN_SUB:
343 case Token::ASSIGN_MUL:
344 case Token::ASSIGN_DIV:
345 case Token::ASSIGN_MOD:
346 if (node->type()->IsLikelySmi()) {
347 node->target()->type()->SetAsLikelySmiIfUnknown();
348 node->value()->type()->SetAsLikelySmiIfUnknown();
349 }
350 break;
351 default:
352 UNREACHABLE();
353 break;
354 }
355
356 Visit(node->target());
357 Visit(node->value());
358
359 switch (node->op()) {
360 case Token::INIT_VAR:
361 case Token::INIT_CONST:
362 case Token::ASSIGN:
363 // Pure assignment copies the type from the value.
364 node->type()->CopyFrom(node->value()->type());
365 break;
366 case Token::ASSIGN_BIT_OR:
367 case Token::ASSIGN_BIT_XOR:
368 case Token::ASSIGN_BIT_AND:
369 case Token::ASSIGN_SHL:
370 case Token::ASSIGN_SAR:
371 case Token::ASSIGN_SHR:
372 // Should have been setup above already.
373 break;
374 case Token::ASSIGN_ADD:
375 case Token::ASSIGN_SUB:
376 case Token::ASSIGN_MUL:
377 case Token::ASSIGN_DIV:
378 case Token::ASSIGN_MOD:
379 if (node->type()->IsUnknown()) {
380 if (node->target()->type()->IsLikelySmi() ||
381 node->value()->type()->IsLikelySmi()) {
382 node->type()->SetAsLikelySmi();
383 }
384 }
385 break;
386 default:
387 UNREACHABLE();
388 break;
389 }
390
391 // Since this is an assignment. We have to propagate this node's type to the
392 // variable.
393 VariableProxy* proxy = node->target()->AsVariableProxy();
394 if (proxy != NULL) {
395 Variable* var = proxy->AsVariable();
396 if (var != NULL) {
Leon Clarkee46be812010-01-19 14:06:41 +0000397 StaticType* var_type = var->type();
Steve Blocka7e24c12009-10-30 11:49:00 +0000398 if (var_type->IsUnknown()) {
399 var_type->CopyFrom(node->type());
400 } else if (var_type->IsLikelySmi()) {
401 // We do not reset likely types to Unknown.
402 }
403 }
404 }
405}
406
407
408void AstOptimizer::VisitThrow(Throw* node) {
409 Visit(node->exception());
410}
411
412
413void AstOptimizer::VisitProperty(Property* node) {
Steve Block6ded16b2010-05-10 14:33:55 +0100414 node->key()->set_no_negative_zero(true);
Steve Blocka7e24c12009-10-30 11:49:00 +0000415 Visit(node->obj());
416 Visit(node->key());
417}
418
419
420void AstOptimizer::VisitCall(Call* node) {
421 Visit(node->expression());
422 OptimizeArguments(node->arguments());
423}
424
425
426void AstOptimizer::VisitCallNew(CallNew* node) {
427 Visit(node->expression());
428 OptimizeArguments(node->arguments());
429}
430
431
432void AstOptimizer::VisitCallRuntime(CallRuntime* node) {
433 ScopedFuncNameInferrer scoped_fni(&func_name_inferrer_);
434 if (Factory::InitializeVarGlobal_symbol()->Equals(*node->name()) &&
435 node->arguments()->length() >= 2 &&
436 node->arguments()->at(1)->AsFunctionLiteral() != NULL) {
437 scoped_fni.Enter();
438 }
439 OptimizeArguments(node->arguments());
440}
441
442
443void AstOptimizer::VisitUnaryOperation(UnaryOperation* node) {
Steve Block6ded16b2010-05-10 14:33:55 +0100444 if (node->op() == Token::ADD || node->op() == Token::SUB) {
445 node->expression()->set_no_negative_zero(node->no_negative_zero());
446 } else {
447 node->expression()->set_no_negative_zero(true);
448 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000449 Visit(node->expression());
Steve Block6ded16b2010-05-10 14:33:55 +0100450 if (FLAG_safe_int32_compiler) {
451 switch (node->op()) {
452 case Token::BIT_NOT:
Steve Block8defd9f2010-07-08 12:39:36 +0100453 node->expression()->set_no_negative_zero(true);
Steve Block6ded16b2010-05-10 14:33:55 +0100454 node->expression()->set_to_int32(true);
455 // Fall through.
456 case Token::ADD:
457 case Token::SUB:
458 node->set_side_effect_free(node->expression()->side_effect_free());
459 break;
460 case Token::NOT:
461 case Token::DELETE:
462 case Token::TYPEOF:
463 case Token::VOID:
464 break;
465 default:
466 UNREACHABLE();
467 break;
468 }
469 } else if (node->op() == Token::BIT_NOT) {
470 node->expression()->set_to_int32(true);
471 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000472}
473
474
475void AstOptimizer::VisitCountOperation(CountOperation* node) {
476 // Count operations assume that they work on Smis.
Steve Block6ded16b2010-05-10 14:33:55 +0100477 node->expression()->set_no_negative_zero(node->is_prefix() ?
478 true :
479 node->no_negative_zero());
Steve Blocka7e24c12009-10-30 11:49:00 +0000480 node->type()->SetAsLikelySmiIfUnknown();
481 node->expression()->type()->SetAsLikelySmiIfUnknown();
482 Visit(node->expression());
483}
484
485
Steve Block8defd9f2010-07-08 12:39:36 +0100486static bool CouldBeNegativeZero(AstNode* node) {
487 Literal* literal = node->AsLiteral();
488 if (literal != NULL) {
489 Handle<Object> handle = literal->handle();
490 if (handle->IsString() || handle->IsSmi()) {
491 return false;
492 } else if (handle->IsHeapNumber()) {
493 double double_value = HeapNumber::cast(*handle)->value();
494 if (double_value != 0) {
495 return false;
496 }
497 }
498 }
499 BinaryOperation* binary = node->AsBinaryOperation();
500 if (binary != NULL && Token::IsBitOp(binary->op())) {
501 return false;
502 }
503 return true;
504}
505
506
507static bool CouldBePositiveZero(AstNode* node) {
508 Literal* literal = node->AsLiteral();
509 if (literal != NULL) {
510 Handle<Object> handle = literal->handle();
511 if (handle->IsSmi()) {
512 if (Smi::cast(*handle) != Smi::FromInt(0)) {
513 return false;
514 }
515 } else if (handle->IsHeapNumber()) {
516 // Heap number literal can't be +0, because that's a Smi.
517 return false;
518 }
519 }
520 return true;
521}
522
523
Steve Blocka7e24c12009-10-30 11:49:00 +0000524void AstOptimizer::VisitBinaryOperation(BinaryOperation* node) {
525 // Depending on the operation we can propagate this node's type down the
526 // AST nodes.
Steve Block8defd9f2010-07-08 12:39:36 +0100527 Token::Value op = node->op();
528 switch (op) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000529 case Token::COMMA:
530 case Token::OR:
Steve Block6ded16b2010-05-10 14:33:55 +0100531 node->left()->set_no_negative_zero(true);
532 node->right()->set_no_negative_zero(node->no_negative_zero());
533 break;
Steve Blocka7e24c12009-10-30 11:49:00 +0000534 case Token::AND:
Steve Block6ded16b2010-05-10 14:33:55 +0100535 node->left()->set_no_negative_zero(node->no_negative_zero());
536 node->right()->set_no_negative_zero(node->no_negative_zero());
Steve Blocka7e24c12009-10-30 11:49:00 +0000537 break;
538 case Token::BIT_OR:
539 case Token::BIT_XOR:
540 case Token::BIT_AND:
541 case Token::SHL:
542 case Token::SAR:
543 case Token::SHR:
544 node->type()->SetAsLikelySmiIfUnknown();
545 node->left()->type()->SetAsLikelySmiIfUnknown();
546 node->right()->type()->SetAsLikelySmiIfUnknown();
Steve Block6ded16b2010-05-10 14:33:55 +0100547 node->left()->set_to_int32(true);
548 node->right()->set_to_int32(true);
549 node->left()->set_no_negative_zero(true);
550 node->right()->set_no_negative_zero(true);
Steve Blocka7e24c12009-10-30 11:49:00 +0000551 break;
Steve Block8defd9f2010-07-08 12:39:36 +0100552 case Token::MUL: {
553 VariableProxy* lvar_proxy = node->left()->AsVariableProxy();
554 VariableProxy* rvar_proxy = node->right()->AsVariableProxy();
555 if (lvar_proxy != NULL && rvar_proxy != NULL) {
556 Variable* lvar = lvar_proxy->AsVariable();
557 Variable* rvar = rvar_proxy->AsVariable();
558 if (lvar != NULL && rvar != NULL) {
559 if (lvar->mode() == Variable::VAR && rvar->mode() == Variable::VAR) {
560 Slot* lslot = lvar->slot();
561 Slot* rslot = rvar->slot();
562 if (lslot->type() == rslot->type() &&
563 (lslot->type() == Slot::PARAMETER ||
564 lslot->type() == Slot::LOCAL) &&
565 lslot->index() == rslot->index()) {
566 // A number squared doesn't give negative zero.
567 node->set_no_negative_zero(true);
568 }
569 }
570 }
571 }
572 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000573 case Token::ADD:
574 case Token::SUB:
Steve Blocka7e24c12009-10-30 11:49:00 +0000575 case Token::DIV:
Steve Block8defd9f2010-07-08 12:39:36 +0100576 case Token::MOD: {
Steve Blocka7e24c12009-10-30 11:49:00 +0000577 if (node->type()->IsLikelySmi()) {
578 node->left()->type()->SetAsLikelySmiIfUnknown();
579 node->right()->type()->SetAsLikelySmiIfUnknown();
580 }
Steve Block8defd9f2010-07-08 12:39:36 +0100581 if (op == Token::ADD && (!CouldBeNegativeZero(node->left()) ||
582 !CouldBeNegativeZero(node->right()))) {
583 node->left()->set_no_negative_zero(true);
584 node->right()->set_no_negative_zero(true);
585 } else if (op == Token::SUB && (!CouldBeNegativeZero(node->left()) ||
586 !CouldBePositiveZero(node->right()))) {
587 node->left()->set_no_negative_zero(true);
588 node->right()->set_no_negative_zero(true);
589 } else {
590 node->left()->set_no_negative_zero(node->no_negative_zero());
591 node->right()->set_no_negative_zero(node->no_negative_zero());
592 }
Steve Block6ded16b2010-05-10 14:33:55 +0100593 if (node->op() == Token::DIV) {
594 node->right()->set_no_negative_zero(false);
595 } else if (node->op() == Token::MOD) {
596 node->right()->set_no_negative_zero(true);
597 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000598 break;
Steve Block8defd9f2010-07-08 12:39:36 +0100599 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000600 default:
601 UNREACHABLE();
602 break;
603 }
604
605 Visit(node->left());
606 Visit(node->right());
607
608 // After visiting the operand nodes we have to check if this node's type
609 // can be updated. If it does, then we can push that information down
Steve Block8defd9f2010-07-08 12:39:36 +0100610 // towards the leaves again if the new information is an upgrade over the
Steve Blocka7e24c12009-10-30 11:49:00 +0000611 // previous type of the operand nodes.
612 if (node->type()->IsUnknown()) {
613 if (node->left()->type()->IsLikelySmi() ||
614 node->right()->type()->IsLikelySmi()) {
615 node->type()->SetAsLikelySmi();
616 }
617 if (node->type()->IsLikelySmi()) {
618 // The type of this node changed to LIKELY_SMI. Propagate this knowledge
619 // down through the nodes.
620 if (node->left()->type()->IsUnknown()) {
621 node->left()->type()->SetAsLikelySmi();
622 Visit(node->left());
623 }
624 if (node->right()->type()->IsUnknown()) {
625 node->right()->type()->SetAsLikelySmi();
626 Visit(node->right());
627 }
628 }
629 }
Steve Block6ded16b2010-05-10 14:33:55 +0100630
631 if (FLAG_safe_int32_compiler) {
632 switch (node->op()) {
633 case Token::COMMA:
634 case Token::OR:
635 case Token::AND:
636 break;
637 case Token::BIT_OR:
638 case Token::BIT_XOR:
639 case Token::BIT_AND:
640 case Token::SHL:
641 case Token::SAR:
642 case Token::SHR:
643 // Add one to the number of bit operations in this expression.
644 node->set_num_bit_ops(1);
645 // Fall through.
646 case Token::ADD:
647 case Token::SUB:
648 case Token::MUL:
649 case Token::DIV:
650 case Token::MOD:
651 node->set_side_effect_free(node->left()->side_effect_free() &&
652 node->right()->side_effect_free());
653 node->set_num_bit_ops(node->num_bit_ops() +
654 node->left()->num_bit_ops() +
655 node->right()->num_bit_ops());
656 if (!node->no_negative_zero() && node->op() == Token::MUL) {
657 node->set_side_effect_free(false);
658 }
659 break;
660 default:
661 UNREACHABLE();
662 break;
663 }
664 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000665}
666
667
668void AstOptimizer::VisitCompareOperation(CompareOperation* node) {
669 if (node->type()->IsKnown()) {
Steve Block8defd9f2010-07-08 12:39:36 +0100670 // Propagate useful information down towards the leaves.
Steve Blocka7e24c12009-10-30 11:49:00 +0000671 node->left()->type()->SetAsLikelySmiIfUnknown();
672 node->right()->type()->SetAsLikelySmiIfUnknown();
673 }
674
Steve Block6ded16b2010-05-10 14:33:55 +0100675 node->left()->set_no_negative_zero(true);
676 // Only [[HasInstance]] has the right argument passed unchanged to it.
677 node->right()->set_no_negative_zero(true);
678
Steve Blocka7e24c12009-10-30 11:49:00 +0000679 Visit(node->left());
680 Visit(node->right());
681
682 // After visiting the operand nodes we have to check if this node's type
683 // can be updated. If it does, then we can push that information down
Steve Block8defd9f2010-07-08 12:39:36 +0100684 // towards the leaves again if the new information is an upgrade over the
Steve Blocka7e24c12009-10-30 11:49:00 +0000685 // previous type of the operand nodes.
686 if (node->type()->IsUnknown()) {
687 if (node->left()->type()->IsLikelySmi() ||
688 node->right()->type()->IsLikelySmi()) {
689 node->type()->SetAsLikelySmi();
690 }
691 if (node->type()->IsLikelySmi()) {
692 // The type of this node changed to LIKELY_SMI. Propagate this knowledge
693 // down through the nodes.
694 if (node->left()->type()->IsUnknown()) {
695 node->left()->type()->SetAsLikelySmi();
696 Visit(node->left());
697 }
698 if (node->right()->type()->IsUnknown()) {
699 node->right()->type()->SetAsLikelySmi();
700 Visit(node->right());
701 }
702 }
703 }
704}
705
706
707void AstOptimizer::VisitThisFunction(ThisFunction* node) {
708 USE(node);
709}
710
711
712class Processor: public AstVisitor {
713 public:
714 explicit Processor(VariableProxy* result)
715 : result_(result),
716 result_assigned_(false),
717 is_set_(false),
718 in_try_(false) {
719 }
720
721 void Process(ZoneList<Statement*>* statements);
722 bool result_assigned() const { return result_assigned_; }
723
724 private:
725 VariableProxy* result_;
726
727 // We are not tracking result usage via the result_'s use
728 // counts (we leave the accurate computation to the
729 // usage analyzer). Instead we simple remember if
730 // there was ever an assignment to result_.
731 bool result_assigned_;
732
733 // To avoid storing to .result all the time, we eliminate some of
734 // the stores by keeping track of whether or not we're sure .result
735 // will be overwritten anyway. This is a bit more tricky than what I
736 // was hoping for
737 bool is_set_;
738 bool in_try_;
739
740 Expression* SetResult(Expression* value) {
741 result_assigned_ = true;
742 return new Assignment(Token::ASSIGN, result_, value,
743 RelocInfo::kNoPosition);
744 }
745
746 // Node visitors.
747#define DEF_VISIT(type) \
748 virtual void Visit##type(type* node);
749 AST_NODE_LIST(DEF_VISIT)
750#undef DEF_VISIT
Steve Block3ce2e202009-11-05 08:53:23 +0000751
752 void VisitIterationStatement(IterationStatement* stmt);
Steve Blocka7e24c12009-10-30 11:49:00 +0000753};
754
755
756void Processor::Process(ZoneList<Statement*>* statements) {
757 for (int i = statements->length() - 1; i >= 0; --i) {
758 Visit(statements->at(i));
759 }
760}
761
762
763void Processor::VisitBlock(Block* node) {
764 // An initializer block is the rewritten form of a variable declaration
765 // with initialization expressions. The initializer block contains the
766 // list of assignments corresponding to the initialization expressions.
767 // While unclear from the spec (ECMA-262, 3rd., 12.2), the value of
768 // a variable declaration with initialization expression is 'undefined'
769 // with some JS VMs: For instance, using smjs, print(eval('var x = 7'))
770 // returns 'undefined'. To obtain the same behavior with v8, we need
771 // to prevent rewriting in that case.
772 if (!node->is_initializer_block()) Process(node->statements());
773}
774
775
776void Processor::VisitExpressionStatement(ExpressionStatement* node) {
777 // Rewrite : <x>; -> .result = <x>;
778 if (!is_set_) {
779 node->set_expression(SetResult(node->expression()));
780 if (!in_try_) is_set_ = true;
781 }
782}
783
784
785void Processor::VisitIfStatement(IfStatement* node) {
786 // Rewrite both then and else parts (reversed).
787 bool save = is_set_;
788 Visit(node->else_statement());
789 bool set_after_then = is_set_;
790 is_set_ = save;
791 Visit(node->then_statement());
792 is_set_ = is_set_ && set_after_then;
793}
794
795
Steve Block3ce2e202009-11-05 08:53:23 +0000796void Processor::VisitIterationStatement(IterationStatement* node) {
797 // Rewrite the body.
Steve Blocka7e24c12009-10-30 11:49:00 +0000798 bool set_after_loop = is_set_;
799 Visit(node->body());
800 is_set_ = is_set_ && set_after_loop;
801}
802
803
Steve Block3ce2e202009-11-05 08:53:23 +0000804void Processor::VisitDoWhileStatement(DoWhileStatement* node) {
805 VisitIterationStatement(node);
Steve Blocka7e24c12009-10-30 11:49:00 +0000806}
807
808
Steve Block3ce2e202009-11-05 08:53:23 +0000809void Processor::VisitWhileStatement(WhileStatement* node) {
810 VisitIterationStatement(node);
811}
812
813
814void Processor::VisitForStatement(ForStatement* node) {
815 VisitIterationStatement(node);
816}
817
818
819void Processor::VisitForInStatement(ForInStatement* node) {
820 VisitIterationStatement(node);
821}
822
823
824void Processor::VisitTryCatchStatement(TryCatchStatement* node) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000825 // Rewrite both try and catch blocks (reversed order).
826 bool set_after_catch = is_set_;
827 Visit(node->catch_block());
828 is_set_ = is_set_ && set_after_catch;
829 bool save = in_try_;
830 in_try_ = true;
831 Visit(node->try_block());
832 in_try_ = save;
833}
834
835
Steve Block3ce2e202009-11-05 08:53:23 +0000836void Processor::VisitTryFinallyStatement(TryFinallyStatement* node) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000837 // Rewrite both try and finally block (reversed order).
838 Visit(node->finally_block());
839 bool save = in_try_;
840 in_try_ = true;
841 Visit(node->try_block());
842 in_try_ = save;
843}
844
845
846void Processor::VisitSwitchStatement(SwitchStatement* node) {
847 // Rewrite statements in all case clauses in reversed order.
848 ZoneList<CaseClause*>* clauses = node->cases();
849 bool set_after_switch = is_set_;
850 for (int i = clauses->length() - 1; i >= 0; --i) {
851 CaseClause* clause = clauses->at(i);
852 Process(clause->statements());
853 }
854 is_set_ = is_set_ && set_after_switch;
855}
856
857
858void Processor::VisitContinueStatement(ContinueStatement* node) {
859 is_set_ = false;
860}
861
862
863void Processor::VisitBreakStatement(BreakStatement* node) {
864 is_set_ = false;
865}
866
867
868// Do nothing:
869void Processor::VisitDeclaration(Declaration* node) {}
870void Processor::VisitEmptyStatement(EmptyStatement* node) {}
871void Processor::VisitReturnStatement(ReturnStatement* node) {}
872void Processor::VisitWithEnterStatement(WithEnterStatement* node) {}
873void Processor::VisitWithExitStatement(WithExitStatement* node) {}
874void Processor::VisitDebuggerStatement(DebuggerStatement* node) {}
875
876
877// Expressions are never visited yet.
878void Processor::VisitFunctionLiteral(FunctionLiteral* node) {
879 USE(node);
880 UNREACHABLE();
881}
882
883
Steve Block6ded16b2010-05-10 14:33:55 +0100884void Processor::VisitSharedFunctionInfoLiteral(
885 SharedFunctionInfoLiteral* node) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000886 USE(node);
887 UNREACHABLE();
888}
889
890
891void Processor::VisitConditional(Conditional* node) {
892 USE(node);
893 UNREACHABLE();
894}
895
896
897void Processor::VisitSlot(Slot* node) {
898 USE(node);
899 UNREACHABLE();
900}
901
902
903void Processor::VisitVariableProxy(VariableProxy* node) {
904 USE(node);
905 UNREACHABLE();
906}
907
908
909void Processor::VisitLiteral(Literal* node) {
910 USE(node);
911 UNREACHABLE();
912}
913
914
915void Processor::VisitRegExpLiteral(RegExpLiteral* node) {
916 USE(node);
917 UNREACHABLE();
918}
919
920
921void Processor::VisitArrayLiteral(ArrayLiteral* node) {
922 USE(node);
923 UNREACHABLE();
924}
925
926
927void Processor::VisitObjectLiteral(ObjectLiteral* node) {
928 USE(node);
929 UNREACHABLE();
930}
931
932
933void Processor::VisitCatchExtensionObject(CatchExtensionObject* node) {
934 USE(node);
935 UNREACHABLE();
936}
937
938
939void Processor::VisitAssignment(Assignment* node) {
940 USE(node);
941 UNREACHABLE();
942}
943
944
945void Processor::VisitThrow(Throw* node) {
946 USE(node);
947 UNREACHABLE();
948}
949
950
951void Processor::VisitProperty(Property* node) {
952 USE(node);
953 UNREACHABLE();
954}
955
956
957void Processor::VisitCall(Call* node) {
958 USE(node);
959 UNREACHABLE();
960}
961
962
963void Processor::VisitCallNew(CallNew* node) {
964 USE(node);
965 UNREACHABLE();
966}
967
968
969void Processor::VisitCallRuntime(CallRuntime* node) {
970 USE(node);
971 UNREACHABLE();
972}
973
974
975void Processor::VisitUnaryOperation(UnaryOperation* node) {
976 USE(node);
977 UNREACHABLE();
978}
979
980
981void Processor::VisitCountOperation(CountOperation* node) {
982 USE(node);
983 UNREACHABLE();
984}
985
986
987void Processor::VisitBinaryOperation(BinaryOperation* node) {
988 USE(node);
989 UNREACHABLE();
990}
991
992
993void Processor::VisitCompareOperation(CompareOperation* node) {
994 USE(node);
995 UNREACHABLE();
996}
997
998
999void Processor::VisitThisFunction(ThisFunction* node) {
1000 USE(node);
1001 UNREACHABLE();
1002}
1003
1004
1005bool Rewriter::Process(FunctionLiteral* function) {
1006 HistogramTimerScope timer(&Counters::rewriting);
1007 Scope* scope = function->scope();
1008 if (scope->is_function_scope()) return true;
1009
1010 ZoneList<Statement*>* body = function->body();
1011 if (body->is_empty()) return true;
1012
1013 VariableProxy* result = scope->NewTemporary(Factory::result_symbol());
1014 Processor processor(result);
1015 processor.Process(body);
1016 if (processor.HasStackOverflow()) return false;
1017
1018 if (processor.result_assigned()) body->Add(new ReturnStatement(result));
1019 return true;
1020}
1021
1022
1023bool Rewriter::Optimize(FunctionLiteral* function) {
1024 ZoneList<Statement*>* body = function->body();
1025
1026 if (FLAG_optimize_ast && !body->is_empty()) {
1027 HistogramTimerScope timer(&Counters::ast_optimization);
1028 AstOptimizer optimizer(function->name());
1029 optimizer.Optimize(body);
1030 if (optimizer.HasStackOverflow()) {
1031 return false;
1032 }
1033 }
1034 return true;
1035}
1036
1037
1038} } // namespace v8::internal