OLD | NEW |
1 // Copyright 2006-2008 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2008 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 10 matching lines...) Expand all Loading... |
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 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. | 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
27 | 27 |
28 #include "v8.h" | 28 #include "v8.h" |
29 | 29 |
30 #include "ast.h" | 30 #include "ast.h" |
31 #include "func-name-inferrer.h" | |
32 #include "scopes.h" | 31 #include "scopes.h" |
33 #include "rewriter.h" | 32 #include "rewriter.h" |
34 | 33 |
35 namespace v8 { | 34 namespace v8 { |
36 namespace internal { | 35 namespace internal { |
37 | 36 |
38 | 37 |
39 class AstOptimizer: public AstVisitor { | 38 class AstOptimizer: public AstVisitor { |
40 public: | 39 public: |
41 explicit AstOptimizer() : has_function_literal_(false) {} | 40 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 | 41 |
47 void Optimize(ZoneList<Statement*>* statements); | 42 void Optimize(ZoneList<Statement*>* statements); |
48 | 43 |
49 private: | 44 private: |
50 // Used for loop condition analysis. Cleared before visiting a loop | 45 // Used for loop condition analysis. Cleared before visiting a loop |
51 // condition, set when a function literal is visited. | 46 // condition, set when a function literal is visited. |
52 bool has_function_literal_; | 47 bool has_function_literal_; |
53 // Helper object for function name inferring. | |
54 FuncNameInferrer func_name_inferrer_; | |
55 | 48 |
56 // Helpers | 49 // Helpers |
57 void OptimizeArguments(ZoneList<Expression*>* arguments); | 50 void OptimizeArguments(ZoneList<Expression*>* arguments); |
58 | 51 |
59 // Node visitors. | 52 // Node visitors. |
60 #define DEF_VISIT(type) \ | 53 #define DEF_VISIT(type) \ |
61 virtual void Visit##type(type* node); | 54 virtual void Visit##type(type* node); |
62 AST_NODE_LIST(DEF_VISIT) | 55 AST_NODE_LIST(DEF_VISIT) |
63 #undef DEF_VISIT | 56 #undef DEF_VISIT |
64 | 57 |
(...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
204 } | 197 } |
205 | 198 |
206 | 199 |
207 void AstOptimizer::VisitDebuggerStatement(DebuggerStatement* node) { | 200 void AstOptimizer::VisitDebuggerStatement(DebuggerStatement* node) { |
208 USE(node); | 201 USE(node); |
209 } | 202 } |
210 | 203 |
211 | 204 |
212 void AstOptimizer::VisitFunctionLiteral(FunctionLiteral* node) { | 205 void AstOptimizer::VisitFunctionLiteral(FunctionLiteral* node) { |
213 has_function_literal_ = true; | 206 has_function_literal_ = true; |
214 | |
215 if (node->name()->length() == 0) { | |
216 // Anonymous function. | |
217 func_name_inferrer_.AddFunction(node); | |
218 } | |
219 } | 207 } |
220 | 208 |
221 | 209 |
222 void AstOptimizer::VisitSharedFunctionInfoLiteral( | 210 void AstOptimizer::VisitSharedFunctionInfoLiteral( |
223 SharedFunctionInfoLiteral* node) { | 211 SharedFunctionInfoLiteral* node) { |
224 USE(node); | 212 USE(node); |
225 } | 213 } |
226 | 214 |
227 | 215 |
228 void AstOptimizer::VisitConditional(Conditional* node) { | 216 void AstOptimizer::VisitConditional(Conditional* node) { |
(...skipping 11 matching lines...) Expand all Loading... |
240 | 228 |
241 void AstOptimizer::VisitVariableProxy(VariableProxy* node) { | 229 void AstOptimizer::VisitVariableProxy(VariableProxy* node) { |
242 Variable* var = node->AsVariable(); | 230 Variable* var = node->AsVariable(); |
243 if (var != NULL) { | 231 if (var != NULL) { |
244 if (var->type()->IsKnown()) { | 232 if (var->type()->IsKnown()) { |
245 node->type()->CopyFrom(var->type()); | 233 node->type()->CopyFrom(var->type()); |
246 } else if (node->type()->IsLikelySmi()) { | 234 } else if (node->type()->IsLikelySmi()) { |
247 var->type()->SetAsLikelySmi(); | 235 var->type()->SetAsLikelySmi(); |
248 } | 236 } |
249 | 237 |
250 if (!var->is_this() && | |
251 !Heap::result_symbol()->Equals(*var->name())) { | |
252 func_name_inferrer_.PushName(var->name()); | |
253 } | |
254 | |
255 if (FLAG_safe_int32_compiler) { | 238 if (FLAG_safe_int32_compiler) { |
256 if (var->IsStackAllocated() && | 239 if (var->IsStackAllocated() && |
257 !var->is_arguments() && | 240 !var->is_arguments() && |
258 var->mode() != Variable::CONST) { | 241 var->mode() != Variable::CONST) { |
259 node->set_side_effect_free(true); | 242 node->set_side_effect_free(true); |
260 } | 243 } |
261 } | 244 } |
262 } | 245 } |
263 } | 246 } |
264 | 247 |
265 | 248 |
266 void AstOptimizer::VisitLiteral(Literal* node) { | 249 void AstOptimizer::VisitLiteral(Literal* node) { |
267 Handle<Object> literal = node->handle(); | 250 Handle<Object> literal = node->handle(); |
268 if (literal->IsSmi()) { | 251 if (literal->IsSmi()) { |
269 node->type()->SetAsLikelySmi(); | 252 node->type()->SetAsLikelySmi(); |
270 node->set_side_effect_free(true); | 253 node->set_side_effect_free(true); |
271 } 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 } | |
276 } else if (literal->IsHeapNumber()) { | 254 } else if (literal->IsHeapNumber()) { |
277 if (node->to_int32()) { | 255 if (node->to_int32()) { |
278 // Any HeapNumber has an int32 value if it is the input to a bit op. | 256 // Any HeapNumber has an int32 value if it is the input to a bit op. |
279 node->set_side_effect_free(true); | 257 node->set_side_effect_free(true); |
280 } else { | 258 } else { |
281 double double_value = HeapNumber::cast(*literal)->value(); | 259 double double_value = HeapNumber::cast(*literal)->value(); |
282 int32_t int32_value = DoubleToInt32(double_value); | 260 int32_t int32_value = DoubleToInt32(double_value); |
283 node->set_side_effect_free(double_value == int32_value); | 261 node->set_side_effect_free(double_value == int32_value); |
284 } | 262 } |
285 } | 263 } |
286 } | 264 } |
287 | 265 |
288 | 266 |
289 void AstOptimizer::VisitRegExpLiteral(RegExpLiteral* node) { | 267 void AstOptimizer::VisitRegExpLiteral(RegExpLiteral* node) { |
290 USE(node); | 268 USE(node); |
291 } | 269 } |
292 | 270 |
293 | 271 |
294 void AstOptimizer::VisitArrayLiteral(ArrayLiteral* node) { | 272 void AstOptimizer::VisitArrayLiteral(ArrayLiteral* node) { |
295 for (int i = 0; i < node->values()->length(); i++) { | 273 for (int i = 0; i < node->values()->length(); i++) { |
296 Visit(node->values()->at(i)); | 274 Visit(node->values()->at(i)); |
297 } | 275 } |
298 } | 276 } |
299 | 277 |
300 void AstOptimizer::VisitObjectLiteral(ObjectLiteral* node) { | 278 void AstOptimizer::VisitObjectLiteral(ObjectLiteral* node) { |
301 for (int i = 0; i < node->properties()->length(); i++) { | 279 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()); | 280 Visit(node->properties()->at(i)->key()); |
305 Visit(node->properties()->at(i)->value()); | 281 Visit(node->properties()->at(i)->value()); |
306 } | 282 } |
307 } | 283 } |
308 | 284 |
309 | 285 |
310 void AstOptimizer::VisitCatchExtensionObject(CatchExtensionObject* node) { | 286 void AstOptimizer::VisitCatchExtensionObject(CatchExtensionObject* node) { |
311 Visit(node->key()); | 287 Visit(node->key()); |
312 Visit(node->value()); | 288 Visit(node->value()); |
313 } | 289 } |
314 | 290 |
315 | 291 |
316 void AstOptimizer::VisitAssignment(Assignment* node) { | 292 void AstOptimizer::VisitAssignment(Assignment* node) { |
317 ScopedFuncNameInferrer scoped_fni(&func_name_inferrer_); | |
318 switch (node->op()) { | 293 switch (node->op()) { |
319 case Token::INIT_VAR: | 294 case Token::INIT_VAR: |
320 case Token::INIT_CONST: | 295 case Token::INIT_CONST: |
321 case Token::ASSIGN: | 296 case Token::ASSIGN: |
322 // No type can be infered from the general assignment. | 297 // 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; | 298 break; |
329 case Token::ASSIGN_BIT_OR: | 299 case Token::ASSIGN_BIT_OR: |
330 case Token::ASSIGN_BIT_XOR: | 300 case Token::ASSIGN_BIT_XOR: |
331 case Token::ASSIGN_BIT_AND: | 301 case Token::ASSIGN_BIT_AND: |
332 case Token::ASSIGN_SHL: | 302 case Token::ASSIGN_SHL: |
333 case Token::ASSIGN_SAR: | 303 case Token::ASSIGN_SAR: |
334 case Token::ASSIGN_SHR: | 304 case Token::ASSIGN_SHR: |
335 node->type()->SetAsLikelySmiIfUnknown(); | 305 node->type()->SetAsLikelySmiIfUnknown(); |
336 node->target()->type()->SetAsLikelySmiIfUnknown(); | 306 node->target()->type()->SetAsLikelySmiIfUnknown(); |
337 node->value()->type()->SetAsLikelySmiIfUnknown(); | 307 node->value()->type()->SetAsLikelySmiIfUnknown(); |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
423 } | 393 } |
424 | 394 |
425 | 395 |
426 void AstOptimizer::VisitCallNew(CallNew* node) { | 396 void AstOptimizer::VisitCallNew(CallNew* node) { |
427 Visit(node->expression()); | 397 Visit(node->expression()); |
428 OptimizeArguments(node->arguments()); | 398 OptimizeArguments(node->arguments()); |
429 } | 399 } |
430 | 400 |
431 | 401 |
432 void AstOptimizer::VisitCallRuntime(CallRuntime* node) { | 402 void 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()); | 403 OptimizeArguments(node->arguments()); |
440 } | 404 } |
441 | 405 |
442 | 406 |
443 void AstOptimizer::VisitUnaryOperation(UnaryOperation* node) { | 407 void AstOptimizer::VisitUnaryOperation(UnaryOperation* node) { |
444 if (node->op() == Token::ADD || node->op() == Token::SUB) { | 408 if (node->op() == Token::ADD || node->op() == Token::SUB) { |
445 node->expression()->set_no_negative_zero(node->no_negative_zero()); | 409 node->expression()->set_no_negative_zero(node->no_negative_zero()); |
446 } else { | 410 } else { |
447 node->expression()->set_no_negative_zero(true); | 411 node->expression()->set_no_negative_zero(true); |
448 } | 412 } |
(...skipping 569 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1018 if (processor.result_assigned()) body->Add(new ReturnStatement(result)); | 982 if (processor.result_assigned()) body->Add(new ReturnStatement(result)); |
1019 return true; | 983 return true; |
1020 } | 984 } |
1021 | 985 |
1022 | 986 |
1023 bool Rewriter::Optimize(FunctionLiteral* function) { | 987 bool Rewriter::Optimize(FunctionLiteral* function) { |
1024 ZoneList<Statement*>* body = function->body(); | 988 ZoneList<Statement*>* body = function->body(); |
1025 | 989 |
1026 if (FLAG_optimize_ast && !body->is_empty()) { | 990 if (FLAG_optimize_ast && !body->is_empty()) { |
1027 HistogramTimerScope timer(&Counters::ast_optimization); | 991 HistogramTimerScope timer(&Counters::ast_optimization); |
1028 AstOptimizer optimizer(function->name()); | 992 AstOptimizer optimizer; |
1029 optimizer.Optimize(body); | 993 optimizer.Optimize(body); |
1030 if (optimizer.HasStackOverflow()) { | 994 if (optimizer.HasStackOverflow()) { |
1031 return false; | 995 return false; |
1032 } | 996 } |
1033 } | 997 } |
1034 return true; | 998 return true; |
1035 } | 999 } |
1036 | 1000 |
1037 | 1001 |
1038 } } // namespace v8::internal | 1002 } } // namespace v8::internal |
OLD | NEW |