blob: f0d53b8e241a8e792ef0ae213a30a6a672b66fe4 [file] [log] [blame]
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001// Copyright 2006-2008 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
30#include "ast.h"
31#include "scopes.h"
32#include "rewriter.h"
33
34namespace v8 { namespace internal {
35
36
ager@chromium.orga74f0da2008-12-03 16:05:52 +000037class AstOptimizer: public AstVisitor {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000038 public:
39 explicit AstOptimizer() {
40 }
41
42 void Optimize(ZoneList<Statement*>* statements);
43
44 private:
45 // Helpers
46 void OptimizeArguments(ZoneList<Expression*>* arguments);
47
48 // Node visitors.
49#define DEF_VISIT(type) \
50 virtual void Visit##type(type* node);
51 NODE_LIST(DEF_VISIT)
52#undef DEF_VISIT
53
54 DISALLOW_COPY_AND_ASSIGN(AstOptimizer);
55};
56
57
58void AstOptimizer::Optimize(ZoneList<Statement*>* statements) {
59 int len = statements->length();
60 for (int i = 0; i < len; i++) {
61 Visit(statements->at(i));
62 }
63}
64
65
66void AstOptimizer::OptimizeArguments(ZoneList<Expression*>* arguments) {
67 for (int i = 0; i < arguments->length(); i++) {
68 Visit(arguments->at(i));
69 }
70}
71
72
73void AstOptimizer::VisitBlock(Block* node) {
74 Optimize(node->statements());
75}
76
77
78void AstOptimizer::VisitExpressionStatement(ExpressionStatement* node) {
79 Visit(node->expression());
80}
81
82
83void AstOptimizer::VisitIfStatement(IfStatement* node) {
84 Visit(node->condition());
85 Visit(node->then_statement());
86 if (node->HasElseStatement()) {
87 Visit(node->else_statement());
88 }
89}
90
91
92
93
94void AstOptimizer::VisitLoopStatement(LoopStatement* node) {
95 if (node->init() != NULL) {
96 Visit(node->init());
97 }
98 if (node->cond() != NULL) {
99 Visit(node->cond());
100 }
101 if (node->body() != NULL) {
102 Visit(node->body());
103 }
104 if (node->next() != NULL) {
105 Visit(node->next());
106 }
107}
108
109
110void AstOptimizer::VisitForInStatement(ForInStatement* node) {
111 Visit(node->each());
112 Visit(node->enumerable());
113 Visit(node->body());
114}
115
116
117void AstOptimizer::VisitTryCatch(TryCatch* node) {
118 Visit(node->try_block());
119 Visit(node->catch_var());
120 Visit(node->catch_block());
121}
122
123
124void AstOptimizer::VisitTryFinally(TryFinally* node) {
125 Visit(node->try_block());
126 Visit(node->finally_block());
127}
128
129
130void AstOptimizer::VisitSwitchStatement(SwitchStatement* node) {
131 Visit(node->tag());
132 for (int i = 0; i < node->cases()->length(); i++) {
133 CaseClause* clause = node->cases()->at(i);
134 if (!clause->is_default()) {
135 Visit(clause->label());
136 }
137 Optimize(clause->statements());
138 }
139}
140
141
142void AstOptimizer::VisitContinueStatement(ContinueStatement* node) {
143 USE(node);
144}
145
146
147void AstOptimizer::VisitBreakStatement(BreakStatement* node) {
148 USE(node);
149}
150
151
152void AstOptimizer::VisitDeclaration(Declaration* node) {
153 // Will not be reached by the current optimizations.
154 USE(node);
155}
156
157
158void AstOptimizer::VisitEmptyStatement(EmptyStatement* node) {
159 USE(node);
160}
161
162
163void AstOptimizer::VisitReturnStatement(ReturnStatement* node) {
164 Visit(node->expression());
165}
166
167
168void AstOptimizer::VisitWithEnterStatement(WithEnterStatement* node) {
169 Visit(node->expression());
170}
171
172
173void AstOptimizer::VisitWithExitStatement(WithExitStatement* node) {
174 USE(node);
175}
176
177
178void AstOptimizer::VisitDebuggerStatement(DebuggerStatement* node) {
179 USE(node);
180}
181
182
183void AstOptimizer::VisitFunctionLiteral(FunctionLiteral* node) {
184 USE(node);
185}
186
187
188void AstOptimizer::VisitFunctionBoilerplateLiteral(
189 FunctionBoilerplateLiteral* node) {
190 USE(node);
191}
192
193
194void AstOptimizer::VisitConditional(Conditional* node) {
195 Visit(node->condition());
196 Visit(node->then_expression());
197 Visit(node->else_expression());
198}
199
200
201void AstOptimizer::VisitSlot(Slot* node) {
202 USE(node);
203}
204
205
206void AstOptimizer::VisitVariableProxy(VariableProxy* node) {
207 Variable* var = node->AsVariable();
208 if (var != NULL) {
209 if (var->type()->IsKnown()) {
210 node->type()->CopyFrom(var->type());
211 } else if (node->type()->IsLikelySmi()) {
212 var->type()->SetAsLikelySmi();
213 }
214 }
215}
216
217
218void AstOptimizer::VisitLiteral(Literal* node) {
219 Handle<Object> literal = node->handle();
220 if (literal->IsSmi()) {
221 node->type()->SetAsLikelySmi();
222 }
223}
224
225
226void AstOptimizer::VisitRegExpLiteral(RegExpLiteral* node) {
227 USE(node);
228}
229
230
231void AstOptimizer::VisitArrayLiteral(ArrayLiteral* node) {
232 for (int i = 0; i < node->values()->length(); i++) {
233 Visit(node->values()->at(i));
234 }
235}
236
237
238void AstOptimizer::VisitObjectLiteral(ObjectLiteral* node) {
239 for (int i = 0; i < node->properties()->length(); i++) {
240 Visit(node->properties()->at(i)->key());
241 Visit(node->properties()->at(i)->value());
242 }
243}
244
245
246void AstOptimizer::VisitAssignment(Assignment* node) {
247 switch (node->op()) {
248 case Token::INIT_VAR:
249 case Token::INIT_CONST:
250 case Token::ASSIGN:
251 // No type can be infered from the general assignment.
252 break;
253 case Token::ASSIGN_BIT_OR:
254 case Token::ASSIGN_BIT_XOR:
255 case Token::ASSIGN_BIT_AND:
256 case Token::ASSIGN_SHL:
257 case Token::ASSIGN_SAR:
258 case Token::ASSIGN_SHR:
259 node->type()->SetAsLikelySmiIfUnknown();
260 node->target()->type()->SetAsLikelySmiIfUnknown();
261 node->value()->type()->SetAsLikelySmiIfUnknown();
262 break;
263 case Token::ASSIGN_ADD:
264 case Token::ASSIGN_SUB:
265 case Token::ASSIGN_MUL:
266 case Token::ASSIGN_DIV:
267 case Token::ASSIGN_MOD:
268 if (node->type()->IsLikelySmi()) {
269 node->target()->type()->SetAsLikelySmiIfUnknown();
270 node->value()->type()->SetAsLikelySmiIfUnknown();
271 }
272 break;
273 default:
274 UNREACHABLE();
275 break;
276 }
277
278 Visit(node->target());
279 Visit(node->value());
280
281 switch (node->op()) {
282 case Token::INIT_VAR:
283 case Token::INIT_CONST:
284 case Token::ASSIGN:
285 // Pure assigment copies the type from the value.
286 node->type()->CopyFrom(node->value()->type());
287 break;
288 case Token::ASSIGN_BIT_OR:
289 case Token::ASSIGN_BIT_XOR:
290 case Token::ASSIGN_BIT_AND:
291 case Token::ASSIGN_SHL:
292 case Token::ASSIGN_SAR:
293 case Token::ASSIGN_SHR:
294 // Should have been setup above already.
295 break;
296 case Token::ASSIGN_ADD:
297 case Token::ASSIGN_SUB:
298 case Token::ASSIGN_MUL:
299 case Token::ASSIGN_DIV:
300 case Token::ASSIGN_MOD:
301 if (node->type()->IsUnknown()) {
302 if (node->target()->type()->IsLikelySmi() ||
303 node->value()->type()->IsLikelySmi()) {
304 node->type()->SetAsLikelySmi();
305 }
306 }
307 break;
308 default:
309 UNREACHABLE();
310 break;
311 }
312
313 // Since this is an assignment. We have to propagate this node's type to the
314 // variable.
315 VariableProxy* proxy = node->target()->AsVariableProxy();
316 if (proxy != NULL) {
317 Variable* var = proxy->AsVariable();
318 if (var != NULL) {
319 StaticType* var_type = var->type();
320 if (var_type->IsUnknown()) {
321 var_type->CopyFrom(node->type());
322 } else if (var_type->IsLikelySmi()) {
323 // We do not reset likely types to Unknown.
324 }
325 }
326 }
327}
328
329
330void AstOptimizer::VisitThrow(Throw* node) {
331 Visit(node->exception());
332}
333
334
335void AstOptimizer::VisitProperty(Property* node) {
336 Visit(node->obj());
337 Visit(node->key());
338}
339
340
341void AstOptimizer::VisitCall(Call* node) {
342 Visit(node->expression());
343 OptimizeArguments(node->arguments());
344}
345
346
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000347void AstOptimizer::VisitCallEval(CallEval* node) {
348 Visit(node->expression());
349 OptimizeArguments(node->arguments());
350}
351
352
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000353void AstOptimizer::VisitCallNew(CallNew* node) {
354 Visit(node->expression());
355 OptimizeArguments(node->arguments());
356}
357
358
359void AstOptimizer::VisitCallRuntime(CallRuntime* node) {
360 OptimizeArguments(node->arguments());
361}
362
363
364void AstOptimizer::VisitUnaryOperation(UnaryOperation* node) {
365 Visit(node->expression());
366}
367
368
369void AstOptimizer::VisitCountOperation(CountOperation* node) {
370 // Count operations assume that they work on Smis.
371 node->type()->SetAsLikelySmiIfUnknown();
372 node->expression()->type()->SetAsLikelySmiIfUnknown();
373 Visit(node->expression());
374}
375
376
377void AstOptimizer::VisitBinaryOperation(BinaryOperation* node) {
378 // Depending on the operation we can propagate this node's type down the
379 // AST nodes.
380 switch (node->op()) {
381 case Token::COMMA:
382 case Token::OR:
383 case Token::AND:
384 break;
385 case Token::BIT_OR:
386 case Token::BIT_XOR:
387 case Token::BIT_AND:
388 case Token::SHL:
389 case Token::SAR:
390 case Token::SHR:
391 node->type()->SetAsLikelySmiIfUnknown();
392 node->left()->type()->SetAsLikelySmiIfUnknown();
393 node->right()->type()->SetAsLikelySmiIfUnknown();
394 break;
395 case Token::ADD:
396 case Token::SUB:
397 case Token::MUL:
398 case Token::DIV:
399 case Token::MOD:
400 if (node->type()->IsLikelySmi()) {
401 node->left()->type()->SetAsLikelySmiIfUnknown();
402 node->right()->type()->SetAsLikelySmiIfUnknown();
403 }
404 break;
405 default:
406 UNREACHABLE();
407 break;
408 }
409
410 Visit(node->left());
411 Visit(node->right());
412
413 // After visiting the operand nodes we have to check if this node's type
414 // can be updated. If it does, then we can push that information down
415 // towards the leafs again if the new information is an upgrade over the
416 // previous type of the operand nodes.
417 if (node->type()->IsUnknown()) {
418 if (node->left()->type()->IsLikelySmi() ||
419 node->right()->type()->IsLikelySmi()) {
420 node->type()->SetAsLikelySmi();
421 }
422 if (node->type()->IsLikelySmi()) {
423 // The type of this node changed to LIKELY_SMI. Propagate this knowlege
424 // down through the nodes.
425 if (node->left()->type()->IsUnknown()) {
426 node->left()->type()->SetAsLikelySmi();
427 Visit(node->left());
428 }
429 if (node->right()->type()->IsUnknown()) {
430 node->right()->type()->SetAsLikelySmi();
431 Visit(node->right());
432 }
433 }
434 }
435}
436
437
438void AstOptimizer::VisitCompareOperation(CompareOperation* node) {
439 if (node->type()->IsKnown()) {
440 // Propagate useful information down towards the leafs.
441 node->left()->type()->SetAsLikelySmiIfUnknown();
442 node->right()->type()->SetAsLikelySmiIfUnknown();
443 }
444
445 Visit(node->left());
446 Visit(node->right());
447
448 // After visiting the operand nodes we have to check if this node's type
449 // can be updated. If it does, then we can push that information down
450 // towards the leafs again if the new information is an upgrade over the
451 // previous type of the operand nodes.
452 if (node->type()->IsUnknown()) {
453 if (node->left()->type()->IsLikelySmi() ||
454 node->right()->type()->IsLikelySmi()) {
455 node->type()->SetAsLikelySmi();
456 }
457 if (node->type()->IsLikelySmi()) {
458 // The type of this node changed to LIKELY_SMI. Propagate this knowlege
459 // down through the nodes.
460 if (node->left()->type()->IsUnknown()) {
461 node->left()->type()->SetAsLikelySmi();
462 Visit(node->left());
463 }
464 if (node->right()->type()->IsUnknown()) {
465 node->right()->type()->SetAsLikelySmi();
466 Visit(node->right());
467 }
468 }
469 }
470}
471
472
473void AstOptimizer::VisitThisFunction(ThisFunction* node) {
474 USE(node);
475}
476
477
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000478class Processor: public AstVisitor {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000479 public:
480 explicit Processor(VariableProxy* result)
481 : result_(result),
482 result_assigned_(false),
483 is_set_(false),
484 in_try_(false) {
485 }
486
487 void Process(ZoneList<Statement*>* statements);
488 bool result_assigned() const { return result_assigned_; }
489
490 private:
491 VariableProxy* result_;
492
493 // We are not tracking result usage via the result_'s use
494 // counts (we leave the accurate computation to the
495 // usage analyzer). Instead we simple remember if
496 // there was ever an assignment to result_.
497 bool result_assigned_;
498
499 // To avoid storing to .result all the time, we eliminate some of
500 // the stores by keeping track of whether or not we're sure .result
501 // will be overwritten anyway. This is a bit more tricky than what I
502 // was hoping for
503 bool is_set_;
504 bool in_try_;
505
506 Expression* SetResult(Expression* value) {
507 result_assigned_ = true;
ager@chromium.org236ad962008-09-25 09:45:57 +0000508 return new Assignment(Token::ASSIGN, result_, value,
509 RelocInfo::kNoPosition);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000510 }
511
512 // Node visitors.
513#define DEF_VISIT(type) \
514 virtual void Visit##type(type* node);
515 NODE_LIST(DEF_VISIT)
516#undef DEF_VISIT
517};
518
519
520void Processor::Process(ZoneList<Statement*>* statements) {
521 for (int i = statements->length() - 1; i >= 0; --i) {
522 Visit(statements->at(i));
523 }
524}
525
526
527void Processor::VisitBlock(Block* node) {
528 // An initializer block is the rewritten form of a variable declaration
529 // with initialization expressions. The initializer block contains the
530 // list of assignments corresponding to the initialization expressions.
531 // While unclear from the spec (ECMA-262, 3rd., 12.2), the value of
532 // a variable declaration with initialization expression is 'undefined'
533 // with some JS VMs: For instance, using smjs, print(eval('var x = 7'))
534 // returns 'undefined'. To obtain the same behavior with v8, we need
535 // to prevent rewriting in that case.
536 if (!node->is_initializer_block()) Process(node->statements());
537}
538
539
540void Processor::VisitExpressionStatement(ExpressionStatement* node) {
541 // Rewrite : <x>; -> .result = <x>;
542 if (!is_set_) {
543 node->set_expression(SetResult(node->expression()));
544 if (!in_try_) is_set_ = true;
545 }
546}
547
548
549void Processor::VisitIfStatement(IfStatement* node) {
550 // Rewrite both then and else parts (reversed).
551 bool save = is_set_;
552 Visit(node->else_statement());
553 bool set_after_then = is_set_;
554 is_set_ = save;
555 Visit(node->then_statement());
556 is_set_ = is_set_ && set_after_then;
557}
558
559
560
561
562void Processor::VisitLoopStatement(LoopStatement* node) {
563 // Rewrite loop body statement.
564 bool set_after_loop = is_set_;
565 Visit(node->body());
566 is_set_ = is_set_ && set_after_loop;
567}
568
569
570void Processor::VisitForInStatement(ForInStatement* node) {
571 // Rewrite for-in body statement.
572 bool set_after_for = is_set_;
573 Visit(node->body());
574 is_set_ = is_set_ && set_after_for;
575}
576
577
578void Processor::VisitTryCatch(TryCatch* node) {
579 // Rewrite both try and catch blocks (reversed order).
580 bool set_after_catch = is_set_;
581 Visit(node->catch_block());
582 is_set_ = is_set_ && set_after_catch;
583 bool save = in_try_;
584 in_try_ = true;
585 Visit(node->try_block());
586 in_try_ = save;
587}
588
589
590void Processor::VisitTryFinally(TryFinally* node) {
591 // Rewrite both try and finally block (reversed order).
592 Visit(node->finally_block());
593 bool save = in_try_;
594 in_try_ = true;
595 Visit(node->try_block());
596 in_try_ = save;
597}
598
599
600void Processor::VisitSwitchStatement(SwitchStatement* node) {
601 // Rewrite statements in all case clauses in reversed order.
602 ZoneList<CaseClause*>* clauses = node->cases();
603 bool set_after_switch = is_set_;
604 for (int i = clauses->length() - 1; i >= 0; --i) {
605 CaseClause* clause = clauses->at(i);
606 Process(clause->statements());
607 }
608 is_set_ = is_set_ && set_after_switch;
609}
610
611
612void Processor::VisitContinueStatement(ContinueStatement* node) {
613 is_set_ = false;
614}
615
616
617void Processor::VisitBreakStatement(BreakStatement* node) {
618 is_set_ = false;
619}
620
621
622// Do nothing:
623void Processor::VisitDeclaration(Declaration* node) {}
624void Processor::VisitEmptyStatement(EmptyStatement* node) {}
625void Processor::VisitReturnStatement(ReturnStatement* node) {}
626void Processor::VisitWithEnterStatement(WithEnterStatement* node) {}
627void Processor::VisitWithExitStatement(WithExitStatement* node) {}
628void Processor::VisitDebuggerStatement(DebuggerStatement* node) {}
629
630
631// Expressions are never visited yet.
632void Processor::VisitFunctionLiteral(FunctionLiteral* node) {
633 USE(node);
634 UNREACHABLE();
635}
636
637
638void Processor::VisitFunctionBoilerplateLiteral(
639 FunctionBoilerplateLiteral* node) {
640 USE(node);
641 UNREACHABLE();
642}
643
644
645void Processor::VisitConditional(Conditional* node) {
646 USE(node);
647 UNREACHABLE();
648}
649
650
651void Processor::VisitSlot(Slot* node) {
652 USE(node);
653 UNREACHABLE();
654}
655
656
657void Processor::VisitVariableProxy(VariableProxy* node) {
658 USE(node);
659 UNREACHABLE();
660}
661
662
663void Processor::VisitLiteral(Literal* node) {
664 USE(node);
665 UNREACHABLE();
666}
667
668
669void Processor::VisitRegExpLiteral(RegExpLiteral* node) {
670 USE(node);
671 UNREACHABLE();
672}
673
674
675void Processor::VisitArrayLiteral(ArrayLiteral* node) {
676 USE(node);
677 UNREACHABLE();
678}
679
680
681void Processor::VisitObjectLiteral(ObjectLiteral* node) {
682 USE(node);
683 UNREACHABLE();
684}
685
686
687void Processor::VisitAssignment(Assignment* node) {
688 USE(node);
689 UNREACHABLE();
690}
691
692
693void Processor::VisitThrow(Throw* node) {
694 USE(node);
695 UNREACHABLE();
696}
697
698
699void Processor::VisitProperty(Property* node) {
700 USE(node);
701 UNREACHABLE();
702}
703
704
705void Processor::VisitCall(Call* node) {
706 USE(node);
707 UNREACHABLE();
708}
709
710
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000711void Processor::VisitCallEval(CallEval* node) {
712 USE(node);
713 UNREACHABLE();
714}
715
716
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000717void Processor::VisitCallNew(CallNew* node) {
718 USE(node);
719 UNREACHABLE();
720}
721
722
723void Processor::VisitCallRuntime(CallRuntime* node) {
724 USE(node);
725 UNREACHABLE();
726}
727
728
729void Processor::VisitUnaryOperation(UnaryOperation* node) {
730 USE(node);
731 UNREACHABLE();
732}
733
734
735void Processor::VisitCountOperation(CountOperation* node) {
736 USE(node);
737 UNREACHABLE();
738}
739
740
741void Processor::VisitBinaryOperation(BinaryOperation* node) {
742 USE(node);
743 UNREACHABLE();
744}
745
746
747void Processor::VisitCompareOperation(CompareOperation* node) {
748 USE(node);
749 UNREACHABLE();
750}
751
752
753void Processor::VisitThisFunction(ThisFunction* node) {
754 USE(node);
755 UNREACHABLE();
756}
757
758
759bool Rewriter::Process(FunctionLiteral* function) {
760 Scope* scope = function->scope();
761 if (scope->is_function_scope()) return true;
762
763 ZoneList<Statement*>* body = function->body();
764 if (body->is_empty()) return true;
765
766 VariableProxy* result = scope->NewTemporary(Factory::result_symbol());
767 Processor processor(result);
768 processor.Process(body);
769 if (processor.HasStackOverflow()) return false;
770
771 if (processor.result_assigned()) body->Add(new ReturnStatement(result));
772 return true;
773}
774
775
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000776bool Rewriter::Optimize(FunctionLiteral* function) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000777 ZoneList<Statement*>* body = function->body();
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000778
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000779 if (FLAG_optimize_ast && !body->is_empty()) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000780 Scope* scope = function->scope();
781 if (!scope->is_global_scope()) {
782 AstOptimizer optimizer;
783 optimizer.Optimize(body);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000784 if (optimizer.HasStackOverflow()) {
785 return false;
786 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000787 }
788 }
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000789 return true;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000790}
791
792
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000793} } // namespace v8::internal