blob: be824460f0a1fb1b559cccc89391912c84ff784c [file] [log] [blame]
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001// Copyright 2010 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 "data-flow.h"
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000031#include "scopes.h"
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000032
33namespace v8 {
34namespace internal {
35
36
fschneider@chromium.org086aac62010-03-17 13:18:24 +000037#ifdef DEBUG
38void BitVector::Print() {
39 bool first = true;
40 PrintF("{");
41 for (int i = 0; i < length(); i++) {
42 if (Contains(i)) {
43 if (!first) PrintF(",");
44 first = false;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +000045 PrintF("%d", i);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000046 }
47 }
48 PrintF("}");
49}
50#endif
51
52
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000053bool AssignedVariablesAnalyzer::Analyze(CompilationInfo* info) {
54 info_ = info;
55 Scope* scope = info->scope();
ricow@chromium.org65fae842010-08-25 15:26:24 +000056 int variables = scope->num_parameters() + scope->num_stack_slots();
57 if (variables == 0) return true;
58 av_.ExpandTo(variables);
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000059 VisitStatements(info->function()->body());
ricow@chromium.org65fae842010-08-25 15:26:24 +000060 return !HasStackOverflow();
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000061}
62
63
64Variable* AssignedVariablesAnalyzer::FindSmiLoopVariable(ForStatement* stmt) {
65 // The loop must have all necessary parts.
66 if (stmt->init() == NULL || stmt->cond() == NULL || stmt->next() == NULL) {
67 return NULL;
68 }
69 // The initialization statement has to be a simple assignment.
70 Assignment* init = stmt->init()->StatementAsSimpleAssignment();
71 if (init == NULL) return NULL;
72
73 // We only deal with local variables.
74 Variable* loop_var = init->target()->AsVariableProxy()->AsVariable();
75 if (loop_var == NULL || !loop_var->IsStackAllocated()) return NULL;
76
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +000077 // Don't try to get clever with const or dynamic variables.
78 if (loop_var->mode() != Variable::VAR) return NULL;
79
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000080 // The initial value has to be a smi.
81 Literal* init_lit = init->value()->AsLiteral();
82 if (init_lit == NULL || !init_lit->handle()->IsSmi()) return NULL;
83 int init_value = Smi::cast(*init_lit->handle())->value();
84
85 // The condition must be a compare of variable with <, <=, >, or >=.
86 CompareOperation* cond = stmt->cond()->AsCompareOperation();
87 if (cond == NULL) return NULL;
88 if (cond->op() != Token::LT
89 && cond->op() != Token::LTE
90 && cond->op() != Token::GT
91 && cond->op() != Token::GTE) return NULL;
92
93 // The lhs must be the same variable as in the init expression.
94 if (cond->left()->AsVariableProxy()->AsVariable() != loop_var) return NULL;
95
96 // The rhs must be a smi.
97 Literal* term_lit = cond->right()->AsLiteral();
98 if (term_lit == NULL || !term_lit->handle()->IsSmi()) return NULL;
99 int term_value = Smi::cast(*term_lit->handle())->value();
100
101 // The count operation updates the same variable as in the init expression.
102 CountOperation* update = stmt->next()->StatementAsCountOperation();
103 if (update == NULL) return NULL;
104 if (update->expression()->AsVariableProxy()->AsVariable() != loop_var) {
105 return NULL;
106 }
107
108 // The direction of the count operation must agree with the start and the end
109 // value. We currently do not allow the initial value to be the same as the
110 // terminal value. This _would_ be ok as long as the loop body never executes
111 // or executes exactly one time.
112 if (init_value == term_value) return NULL;
113 if (init_value < term_value && update->op() != Token::INC) return NULL;
114 if (init_value > term_value && update->op() != Token::DEC) return NULL;
115
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000116 // Check that the update operation cannot overflow the smi range. This can
117 // occur in the two cases where the loop bound is equal to the largest or
118 // smallest smi.
119 if (update->op() == Token::INC && term_value == Smi::kMaxValue) return NULL;
120 if (update->op() == Token::DEC && term_value == Smi::kMinValue) return NULL;
121
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000122 // Found a smi loop variable.
123 return loop_var;
124}
125
126int AssignedVariablesAnalyzer::BitIndex(Variable* var) {
127 ASSERT(var != NULL);
128 ASSERT(var->IsStackAllocated());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000129 Slot* slot = var->AsSlot();
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000130 if (slot->type() == Slot::PARAMETER) {
131 return slot->index();
132 } else {
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000133 return info_->scope()->num_parameters() + slot->index();
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000134 }
135}
136
137
138void AssignedVariablesAnalyzer::RecordAssignedVar(Variable* var) {
139 ASSERT(var != NULL);
140 if (var->IsStackAllocated()) {
141 av_.Add(BitIndex(var));
142 }
143}
144
145
146void AssignedVariablesAnalyzer::MarkIfTrivial(Expression* expr) {
147 Variable* var = expr->AsVariableProxy()->AsVariable();
148 if (var != NULL &&
149 var->IsStackAllocated() &&
150 !var->is_arguments() &&
151 var->mode() != Variable::CONST &&
152 (var->is_this() || !av_.Contains(BitIndex(var)))) {
ricow@chromium.org65fae842010-08-25 15:26:24 +0000153 expr->AsVariableProxy()->MarkAsTrivial();
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000154 }
155}
156
157
158void AssignedVariablesAnalyzer::ProcessExpression(Expression* expr) {
159 BitVector saved_av(av_);
160 av_.Clear();
161 Visit(expr);
162 av_.Union(saved_av);
163}
164
165void AssignedVariablesAnalyzer::VisitBlock(Block* stmt) {
166 VisitStatements(stmt->statements());
167}
168
169
170void AssignedVariablesAnalyzer::VisitExpressionStatement(
171 ExpressionStatement* stmt) {
172 ProcessExpression(stmt->expression());
173}
174
175
176void AssignedVariablesAnalyzer::VisitEmptyStatement(EmptyStatement* stmt) {
177 // Do nothing.
178}
179
180
181void AssignedVariablesAnalyzer::VisitIfStatement(IfStatement* stmt) {
182 ProcessExpression(stmt->condition());
183 Visit(stmt->then_statement());
184 Visit(stmt->else_statement());
185}
186
187
188void AssignedVariablesAnalyzer::VisitContinueStatement(
189 ContinueStatement* stmt) {
190 // Nothing to do.
191}
192
193
194void AssignedVariablesAnalyzer::VisitBreakStatement(BreakStatement* stmt) {
195 // Nothing to do.
196}
197
198
199void AssignedVariablesAnalyzer::VisitReturnStatement(ReturnStatement* stmt) {
200 ProcessExpression(stmt->expression());
201}
202
203
204void AssignedVariablesAnalyzer::VisitWithEnterStatement(
205 WithEnterStatement* stmt) {
206 ProcessExpression(stmt->expression());
207}
208
209
210void AssignedVariablesAnalyzer::VisitWithExitStatement(
211 WithExitStatement* stmt) {
212 // Nothing to do.
213}
214
215
216void AssignedVariablesAnalyzer::VisitSwitchStatement(SwitchStatement* stmt) {
217 BitVector result(av_);
218 av_.Clear();
219 Visit(stmt->tag());
220 result.Union(av_);
221 for (int i = 0; i < stmt->cases()->length(); i++) {
222 CaseClause* clause = stmt->cases()->at(i);
223 if (!clause->is_default()) {
224 av_.Clear();
225 Visit(clause->label());
226 result.Union(av_);
227 }
228 VisitStatements(clause->statements());
229 }
230 av_.Union(result);
231}
232
233
234void AssignedVariablesAnalyzer::VisitDoWhileStatement(DoWhileStatement* stmt) {
235 ProcessExpression(stmt->cond());
236 Visit(stmt->body());
237}
238
239
240void AssignedVariablesAnalyzer::VisitWhileStatement(WhileStatement* stmt) {
241 ProcessExpression(stmt->cond());
242 Visit(stmt->body());
243}
244
245
246void AssignedVariablesAnalyzer::VisitForStatement(ForStatement* stmt) {
247 if (stmt->init() != NULL) Visit(stmt->init());
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000248 if (stmt->cond() != NULL) ProcessExpression(stmt->cond());
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000249 if (stmt->next() != NULL) Visit(stmt->next());
250
251 // Process loop body. After visiting the loop body av_ contains
252 // the assigned variables of the loop body.
253 BitVector saved_av(av_);
254 av_.Clear();
255 Visit(stmt->body());
256
257 Variable* var = FindSmiLoopVariable(stmt);
258 if (var != NULL && !av_.Contains(BitIndex(var))) {
259 stmt->set_loop_variable(var);
260 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000261 av_.Union(saved_av);
262}
263
264
265void AssignedVariablesAnalyzer::VisitForInStatement(ForInStatement* stmt) {
266 ProcessExpression(stmt->each());
267 ProcessExpression(stmt->enumerable());
268 Visit(stmt->body());
269}
270
271
272void AssignedVariablesAnalyzer::VisitTryCatchStatement(
273 TryCatchStatement* stmt) {
274 Visit(stmt->try_block());
275 Visit(stmt->catch_block());
276}
277
278
279void AssignedVariablesAnalyzer::VisitTryFinallyStatement(
280 TryFinallyStatement* stmt) {
281 Visit(stmt->try_block());
282 Visit(stmt->finally_block());
283}
284
285
286void AssignedVariablesAnalyzer::VisitDebuggerStatement(
287 DebuggerStatement* stmt) {
288 // Nothing to do.
289}
290
291
292void AssignedVariablesAnalyzer::VisitFunctionLiteral(FunctionLiteral* expr) {
293 // Nothing to do.
294 ASSERT(av_.IsEmpty());
295}
296
297
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000298void AssignedVariablesAnalyzer::VisitSharedFunctionInfoLiteral(
299 SharedFunctionInfoLiteral* expr) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000300 // Nothing to do.
301 ASSERT(av_.IsEmpty());
302}
303
304
305void AssignedVariablesAnalyzer::VisitConditional(Conditional* expr) {
306 ASSERT(av_.IsEmpty());
307
308 Visit(expr->condition());
309
310 BitVector result(av_);
311 av_.Clear();
312 Visit(expr->then_expression());
313 result.Union(av_);
314
315 av_.Clear();
316 Visit(expr->else_expression());
317 av_.Union(result);
318}
319
320
321void AssignedVariablesAnalyzer::VisitSlot(Slot* expr) {
322 UNREACHABLE();
323}
324
325
326void AssignedVariablesAnalyzer::VisitVariableProxy(VariableProxy* expr) {
327 // Nothing to do.
328 ASSERT(av_.IsEmpty());
329}
330
331
332void AssignedVariablesAnalyzer::VisitLiteral(Literal* expr) {
333 // Nothing to do.
334 ASSERT(av_.IsEmpty());
335}
336
337
338void AssignedVariablesAnalyzer::VisitRegExpLiteral(RegExpLiteral* expr) {
339 // Nothing to do.
340 ASSERT(av_.IsEmpty());
341}
342
343
344void AssignedVariablesAnalyzer::VisitObjectLiteral(ObjectLiteral* expr) {
345 ASSERT(av_.IsEmpty());
346 BitVector result(av_.length());
347 for (int i = 0; i < expr->properties()->length(); i++) {
348 Visit(expr->properties()->at(i)->value());
349 result.Union(av_);
350 av_.Clear();
351 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000352 av_ = result;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000353}
354
355
356void AssignedVariablesAnalyzer::VisitArrayLiteral(ArrayLiteral* expr) {
357 ASSERT(av_.IsEmpty());
358 BitVector result(av_.length());
359 for (int i = 0; i < expr->values()->length(); i++) {
360 Visit(expr->values()->at(i));
361 result.Union(av_);
362 av_.Clear();
363 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000364 av_ = result;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000365}
366
367
368void AssignedVariablesAnalyzer::VisitCatchExtensionObject(
369 CatchExtensionObject* expr) {
370 ASSERT(av_.IsEmpty());
371 Visit(expr->key());
372 ProcessExpression(expr->value());
373}
374
375
376void AssignedVariablesAnalyzer::VisitAssignment(Assignment* expr) {
377 ASSERT(av_.IsEmpty());
378
lrn@chromium.org25156de2010-04-06 13:10:27 +0000379 // There are three kinds of assignments: variable assignments, property
380 // assignments, and reference errors (invalid left-hand sides).
381 Variable* var = expr->target()->AsVariableProxy()->AsVariable();
382 Property* prop = expr->target()->AsProperty();
383 ASSERT(var == NULL || prop == NULL);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000384
lrn@chromium.org25156de2010-04-06 13:10:27 +0000385 if (var != NULL) {
386 MarkIfTrivial(expr->value());
387 Visit(expr->value());
388 if (expr->is_compound()) {
389 // Left-hand side occurs also as an rvalue.
390 MarkIfTrivial(expr->target());
391 ProcessExpression(expr->target());
392 }
393 RecordAssignedVar(var);
394
395 } else if (prop != NULL) {
396 MarkIfTrivial(expr->value());
397 Visit(expr->value());
398 if (!prop->key()->IsPropertyName()) {
399 MarkIfTrivial(prop->key());
400 ProcessExpression(prop->key());
401 }
402 MarkIfTrivial(prop->obj());
403 ProcessExpression(prop->obj());
404
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000405 } else {
406 Visit(expr->target());
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000407 }
408}
409
410
411void AssignedVariablesAnalyzer::VisitThrow(Throw* expr) {
412 ASSERT(av_.IsEmpty());
413 Visit(expr->exception());
414}
415
416
417void AssignedVariablesAnalyzer::VisitProperty(Property* expr) {
418 ASSERT(av_.IsEmpty());
lrn@chromium.org25156de2010-04-06 13:10:27 +0000419 if (!expr->key()->IsPropertyName()) {
420 MarkIfTrivial(expr->key());
421 Visit(expr->key());
422 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000423 MarkIfTrivial(expr->obj());
lrn@chromium.org25156de2010-04-06 13:10:27 +0000424 ProcessExpression(expr->obj());
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000425}
426
427
428void AssignedVariablesAnalyzer::VisitCall(Call* expr) {
429 ASSERT(av_.IsEmpty());
430 Visit(expr->expression());
431 BitVector result(av_);
432 for (int i = 0; i < expr->arguments()->length(); i++) {
433 av_.Clear();
434 Visit(expr->arguments()->at(i));
435 result.Union(av_);
436 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000437 av_ = result;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000438}
439
440
441void AssignedVariablesAnalyzer::VisitCallNew(CallNew* expr) {
442 ASSERT(av_.IsEmpty());
443 Visit(expr->expression());
444 BitVector result(av_);
445 for (int i = 0; i < expr->arguments()->length(); i++) {
446 av_.Clear();
447 Visit(expr->arguments()->at(i));
448 result.Union(av_);
449 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000450 av_ = result;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000451}
452
453
454void AssignedVariablesAnalyzer::VisitCallRuntime(CallRuntime* expr) {
455 ASSERT(av_.IsEmpty());
456 BitVector result(av_);
457 for (int i = 0; i < expr->arguments()->length(); i++) {
458 av_.Clear();
459 Visit(expr->arguments()->at(i));
460 result.Union(av_);
461 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000462 av_ = result;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000463}
464
465
466void AssignedVariablesAnalyzer::VisitUnaryOperation(UnaryOperation* expr) {
467 ASSERT(av_.IsEmpty());
ricow@chromium.org65fae842010-08-25 15:26:24 +0000468 MarkIfTrivial(expr->expression());
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000469 Visit(expr->expression());
470}
471
472
ricow@chromium.org65fae842010-08-25 15:26:24 +0000473void AssignedVariablesAnalyzer::VisitIncrementOperation(
474 IncrementOperation* expr) {
475 UNREACHABLE();
476}
477
478
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000479void AssignedVariablesAnalyzer::VisitCountOperation(CountOperation* expr) {
480 ASSERT(av_.IsEmpty());
ricow@chromium.org65fae842010-08-25 15:26:24 +0000481 if (expr->is_prefix()) MarkIfTrivial(expr->expression());
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000482 Visit(expr->expression());
483
484 Variable* var = expr->expression()->AsVariableProxy()->AsVariable();
485 if (var != NULL) RecordAssignedVar(var);
486}
487
488
489void AssignedVariablesAnalyzer::VisitBinaryOperation(BinaryOperation* expr) {
490 ASSERT(av_.IsEmpty());
lrn@chromium.org25156de2010-04-06 13:10:27 +0000491 MarkIfTrivial(expr->right());
492 Visit(expr->right());
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000493 MarkIfTrivial(expr->left());
lrn@chromium.org25156de2010-04-06 13:10:27 +0000494 ProcessExpression(expr->left());
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000495}
496
497
498void AssignedVariablesAnalyzer::VisitCompareOperation(CompareOperation* expr) {
499 ASSERT(av_.IsEmpty());
lrn@chromium.org25156de2010-04-06 13:10:27 +0000500 MarkIfTrivial(expr->right());
501 Visit(expr->right());
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000502 MarkIfTrivial(expr->left());
lrn@chromium.org25156de2010-04-06 13:10:27 +0000503 ProcessExpression(expr->left());
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000504}
505
506
ricow@chromium.org65fae842010-08-25 15:26:24 +0000507void AssignedVariablesAnalyzer::VisitCompareToNull(CompareToNull* expr) {
508 ASSERT(av_.IsEmpty());
509 MarkIfTrivial(expr->expression());
510 Visit(expr->expression());
511}
512
513
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000514void AssignedVariablesAnalyzer::VisitThisFunction(ThisFunction* expr) {
515 // Nothing to do.
516 ASSERT(av_.IsEmpty());
517}
518
519
520void AssignedVariablesAnalyzer::VisitDeclaration(Declaration* decl) {
521 UNREACHABLE();
522}
523
524
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000525} } // namespace v8::internal