Index: src/ast.cc |
diff --git a/src/ast.cc b/src/ast.cc |
index 2e26999c8cf177d4383d9429f3f51416e4d2d78a..affa704e906c280a049e2b3cd7c58d939de9b1c9 100644 |
--- a/src/ast.cc |
+++ b/src/ast.cc |
@@ -1,4 +1,4 @@ |
-// Copyright 2011 the V8 project authors. All rights reserved. |
+// Copyright 2012 the V8 project authors. All rights reserved. |
// Redistribution and use in source and binary forms, with or without |
// modification, are permitted provided that the following conditions are |
// met: |
@@ -174,6 +174,24 @@ LanguageMode FunctionLiteral::language_mode() const { |
} |
+bool FunctionLiteral::ShouldSelfOptimize() { |
+ AstNodeType::Flag types = 0; |
+ int node_count = 0; |
+ CollectInfo(&types, &node_count); |
+ return (types & (AstNodeType::kContainsBackEdgesMask | |
+ AstNodeType::kContainsCallsMask | |
+ AstNodeType::kPreventsOptimizationMask)) == 0; |
+} |
+ |
+ |
+int FunctionLiteral::AstNodeCount() { |
+ AstNodeType::Flag types = 0; |
+ int node_count = 0; |
+ CollectInfo(&types, &node_count); |
+ return node_count; |
+} |
+ |
+ |
ObjectLiteral::Property::Property(Literal* key, Expression* value) { |
emit_store_ = true; |
key_ = key; |
@@ -426,6 +444,13 @@ bool Declaration::IsInlineable() const { |
} |
+void Declaration::CollectInfo(AstNodeType::Flag* flags, |
+ int* node_count) const { |
+ proxy()->CollectInfo(flags, node_count); |
+ *node_count += 1; |
+} |
+ |
+ |
bool TargetCollector::IsInlineable() const { |
UNREACHABLE(); |
return false; |
@@ -437,28 +462,72 @@ bool ForInStatement::IsInlineable() const { |
} |
+void ForInStatement::CollectInfo(AstNodeType::Flag* flags, |
+ int* node_count) const { |
+ *flags |= AstNodeType::kForInStatementMask; |
+ each()->CollectInfo(flags, node_count); |
+ enumerable()->CollectInfo(flags, node_count); |
+ body()->CollectInfo(flags, node_count); |
+ *node_count += 1; |
+} |
+ |
+ |
bool WithStatement::IsInlineable() const { |
return false; |
} |
+void WithStatement::CollectInfo(AstNodeType::Flag* flags, |
+ int* node_count) const { |
+ *flags |= AstNodeType::kWithStatementMask; |
+ expression()->CollectInfo(flags, node_count); |
+ statement()->CollectInfo(flags, node_count); |
+ *node_count += 1; |
+} |
+ |
+ |
bool SwitchStatement::IsInlineable() const { |
return false; |
} |
+void SwitchStatement::CollectInfo(AstNodeType::Flag* flags, |
+ int* node_count) const { |
+ *flags |= AstNodeType::kSwitchStatementMask; |
+ tag()->CollectInfo(flags, node_count); |
+ for (int i = 0; i < cases()->length(); ++i) { |
+ CaseClause* clause(cases()->at(i)); |
+ if (!clause->is_default()) { |
+ clause->label()->CollectInfo(flags, node_count); |
+ } |
+ for (int j = 0; j < clause->statements()->length(); ++j) { |
+ clause->statements()->at(j)->CollectInfo(flags, node_count); |
+ } |
+ } |
+ *node_count += 1; |
+} |
+ |
+ |
bool TryStatement::IsInlineable() const { |
return false; |
} |
-bool TryCatchStatement::IsInlineable() const { |
- return false; |
+void TryCatchStatement::CollectInfo(AstNodeType::Flag* flags, |
+ int* node_count) const { |
+ *flags |= AstNodeType::kTryCatchStatementMask; |
+ try_block()->CollectInfo(flags, node_count); |
+ catch_block()->CollectInfo(flags, node_count); |
+ *node_count += 1; |
} |
-bool TryFinallyStatement::IsInlineable() const { |
- return false; |
+void TryFinallyStatement::CollectInfo(AstNodeType::Flag* flags, |
+ int* node_count) const { |
+ *flags |= AstNodeType::kTryFinallyStatementMask; |
+ try_block()->CollectInfo(flags, node_count); |
+ finally_block()->CollectInfo(flags, node_count); |
+ *node_count += 1; |
} |
@@ -467,33 +536,106 @@ bool DebuggerStatement::IsInlineable() const { |
} |
+void DebuggerStatement::CollectInfo(AstNodeType::Flag* flags, |
+ int* node_count) const { |
+ *flags |= AstNodeType::kDebuggerStatementMask; |
+ *node_count += 1; |
+} |
+ |
+ |
bool Throw::IsInlineable() const { |
return exception()->IsInlineable(); |
} |
+void Throw::CollectInfo(AstNodeType::Flag* flags, int* node_count) const { |
+ *flags |= AstNodeType::kThrowMask; |
+ exception()->CollectInfo(flags, node_count); |
+ *node_count += 1; |
+} |
+ |
+ |
bool MaterializedLiteral::IsInlineable() const { |
// TODO(1322): Allow materialized literals. |
return false; |
} |
+void ObjectLiteral::CollectInfo(AstNodeType::Flag* flags, |
+ int* node_count) const { |
+ *flags |= AstNodeType::kObjectLiteralMask; |
+ for (int i = 0; i < properties()->length(); ++i) { |
+ properties()->at(i)->key()->CollectInfo(flags, node_count); |
+ properties()->at(i)->value()->CollectInfo(flags, node_count); |
+ } |
+ *node_count += 1; |
+} |
+ |
+ |
+void RegExpLiteral::CollectInfo(AstNodeType::Flag* flags, |
+ int* node_count) const { |
+ *flags |= AstNodeType::kRegExpLiteralMask; |
+ *node_count += 1; |
+} |
+ |
+ |
+void ArrayLiteral::CollectInfo(AstNodeType::Flag* flags, |
+ int* node_count) const { |
+ *flags |= AstNodeType::kArrayLiteralMask; |
+ for (int i = 0; i < values()->length(); ++i) { |
+ values()->at(i)->CollectInfo(flags, node_count); |
+ } |
+ *node_count += 1; |
+} |
+ |
+ |
bool FunctionLiteral::IsInlineable() const { |
// TODO(1322): Allow materialized literals. |
return false; |
} |
+void FunctionLiteral::CollectInfo(AstNodeType::Flag* flags, |
+ int* node_count) const { |
+ *flags |= AstNodeType::kFunctionLiteralMask; |
+ if (scope()->declarations() != NULL) { |
+ for (int i = 0; i < scope()->declarations()->length(); ++i) { |
+ scope()->declarations()->at(i)->CollectInfo(flags, node_count); |
+ } |
+ } |
+ if (body() != NULL) { |
+ for (int i = 0; i < body()->length(); ++i) { |
+ body()->at(i)->CollectInfo(flags, node_count); |
+ } |
+ } |
+ *node_count += 1; |
+} |
+ |
+ |
bool ThisFunction::IsInlineable() const { |
return true; |
} |
+void ThisFunction::CollectInfo(AstNodeType::Flag* flags, |
+ int* node_count) const { |
+ *flags |= AstNodeType::kThisFunctionMask; |
+ *node_count += 1; |
+} |
+ |
+ |
bool SharedFunctionInfoLiteral::IsInlineable() const { |
return false; |
} |
+void SharedFunctionInfoLiteral::CollectInfo(AstNodeType::Flag* flags, |
+ int* node_count) const { |
+ *flags |= AstNodeType::kSharedFunctionInfoLiteralMask; |
+ *node_count += 1; |
+} |
+ |
+ |
bool ForStatement::IsInlineable() const { |
return (init() == NULL || init()->IsInlineable()) |
&& (cond() == NULL || cond()->IsInlineable()) |
@@ -502,33 +644,82 @@ bool ForStatement::IsInlineable() const { |
} |
+void ForStatement::CollectInfo(AstNodeType::Flag* flags, |
+ int* node_count) const { |
+ *flags |= AstNodeType::kForStatementMask; |
+ if (init() != NULL) init()->CollectInfo(flags, node_count); |
+ if (cond() != NULL) cond()->CollectInfo(flags, node_count); |
+ if (next() != NULL) next()->CollectInfo(flags, node_count); |
+ body()->CollectInfo(flags, node_count); |
+ *node_count += 1; |
+} |
+ |
+ |
bool WhileStatement::IsInlineable() const { |
return cond()->IsInlineable() |
&& body()->IsInlineable(); |
} |
+void WhileStatement::CollectInfo(AstNodeType::Flag* flags, |
+ int* node_count) const { |
+ *flags |= AstNodeType::kWhileStatementMask; |
+ cond()->CollectInfo(flags, node_count); |
+ body()->CollectInfo(flags, node_count); |
+ *node_count += 1; |
+} |
+ |
+ |
bool DoWhileStatement::IsInlineable() const { |
return cond()->IsInlineable() |
&& body()->IsInlineable(); |
} |
+void DoWhileStatement::CollectInfo(AstNodeType::Flag* flags, |
+ int* node_count) const { |
+ *flags |= AstNodeType::kDoWhileStatementMask; |
+ cond()->CollectInfo(flags, node_count); |
+ body()->CollectInfo(flags, node_count); |
+ *node_count += 1; |
+} |
+ |
+ |
bool ContinueStatement::IsInlineable() const { |
return true; |
} |
+void ContinueStatement::CollectInfo(AstNodeType::Flag* flags, |
+ int* node_count) const { |
+ *flags |= AstNodeType::kContinueStatementMask; |
+ *node_count += 1; |
+} |
+ |
+ |
bool BreakStatement::IsInlineable() const { |
return true; |
} |
+void BreakStatement::CollectInfo(AstNodeType::Flag* flags, |
+ int* node_count) const { |
+ *flags |= AstNodeType::kBreakStatementMask; |
+ *node_count += 1; |
+} |
+ |
+ |
bool EmptyStatement::IsInlineable() const { |
return true; |
} |
+void EmptyStatement::CollectInfo(AstNodeType::Flag* flags, |
+ int* node_count) const { |
+ // Nothing to see here, move on. |
+} |
+ |
+ |
bool Literal::IsInlineable() const { |
return true; |
} |
@@ -543,11 +734,25 @@ bool Block::IsInlineable() const { |
} |
+void Block::CollectInfo(AstNodeType::Flag* flags, int* node_count) const { |
+ for (int i = 0; i < statements_.length(); ++i) { |
+ statements_[i]->CollectInfo(flags, node_count); |
+ } |
+ *node_count += 1; |
+} |
+ |
+ |
bool ExpressionStatement::IsInlineable() const { |
return expression()->IsInlineable(); |
} |
+void ExpressionStatement::CollectInfo(AstNodeType::Flag* flags, |
+ int* node_count) const { |
+ expression()->CollectInfo(flags, node_count); |
+} |
+ |
+ |
bool IfStatement::IsInlineable() const { |
return condition()->IsInlineable() |
&& then_statement()->IsInlineable() |
@@ -555,17 +760,46 @@ bool IfStatement::IsInlineable() const { |
} |
+void IfStatement::CollectInfo(AstNodeType::Flag* flags, |
+ int* node_count) const { |
+ *flags |= AstNodeType::kIfStatementMask; |
+ condition()->CollectInfo(flags, node_count); |
+ then_statement()->CollectInfo(flags, node_count); |
+ else_statement()->CollectInfo(flags, node_count); |
+ *node_count += 1; |
+} |
+ |
+ |
+ |
bool ReturnStatement::IsInlineable() const { |
return expression()->IsInlineable(); |
} |
+void ReturnStatement::CollectInfo(AstNodeType::Flag* flags, |
+ int* node_count) const { |
+ *flags |= AstNodeType::kReturnStatementMask; |
+ expression()->CollectInfo(flags, node_count); |
+ *node_count += 1; |
+} |
+ |
+ |
bool Conditional::IsInlineable() const { |
return condition()->IsInlineable() && then_expression()->IsInlineable() && |
else_expression()->IsInlineable(); |
} |
+void Conditional::CollectInfo(AstNodeType::Flag* flags, |
+ int* node_count) const { |
+ *flags |= AstNodeType::kConditionalMask; |
+ condition()->CollectInfo(flags, node_count); |
+ then_expression()->CollectInfo(flags, node_count); |
+ else_expression()->CollectInfo(flags, node_count); |
+ *node_count += 1; |
+} |
+ |
+ |
bool VariableProxy::IsInlineable() const { |
return var()->IsUnallocated() |
|| var()->IsStackAllocated() |
@@ -578,11 +812,28 @@ bool Assignment::IsInlineable() const { |
} |
+void Assignment::CollectInfo(AstNodeType::Flag* flags, |
+ int* node_count) const { |
+ target()->CollectInfo(flags, node_count); |
+ value()->CollectInfo(flags, node_count); |
+ *node_count += 1; |
+} |
+ |
+ |
bool Property::IsInlineable() const { |
return obj()->IsInlineable() && key()->IsInlineable(); |
} |
+void Property::CollectInfo(AstNodeType::Flag* flags, |
+ int* node_count) const { |
+ *flags |= AstNodeType::kPropertyMask; |
+ obj()->CollectInfo(flags, node_count); |
+ key()->CollectInfo(flags, node_count); |
+ *node_count += 1; |
+} |
+ |
+ |
bool Call::IsInlineable() const { |
if (!expression()->IsInlineable()) return false; |
const int count = arguments()->length(); |
@@ -593,6 +844,16 @@ bool Call::IsInlineable() const { |
} |
+void Call::CollectInfo(AstNodeType::Flag* flags, int* node_count) const { |
+ *flags |= AstNodeType::kCallMask; |
+ expression()->CollectInfo(flags, node_count); |
+ for (int i = 0; i < arguments()->length(); ++i) { |
+ arguments()->at(i)->CollectInfo(flags, node_count); |
+ } |
+ *node_count += 1; |
+} |
+ |
+ |
bool CallNew::IsInlineable() const { |
if (!expression()->IsInlineable()) return false; |
const int count = arguments()->length(); |
@@ -603,6 +864,16 @@ bool CallNew::IsInlineable() const { |
} |
+void CallNew::CollectInfo(AstNodeType::Flag* flags, int* node_count) const { |
+ *flags |= AstNodeType::kCallNewMask; |
+ expression()->CollectInfo(flags, node_count); |
+ for (int i = 0; i < arguments()->length(); ++i) { |
+ arguments()->at(i)->CollectInfo(flags, node_count); |
+ } |
+ *node_count += 1; |
+} |
+ |
+ |
bool CallRuntime::IsInlineable() const { |
// Don't try to inline JS runtime calls because we don't (currently) even |
// optimize them. |
@@ -623,26 +894,65 @@ bool CallRuntime::IsInlineable() const { |
} |
+void CallRuntime::CollectInfo(AstNodeType::Flag* flags, int* node_count) const { |
+ *flags |= AstNodeType::kCallRuntimeMask; |
+ for (int i = 0; i < arguments()->length(); ++i) { |
+ arguments()->at(i)->CollectInfo(flags, node_count); |
+ } |
+ *node_count += 1; |
+} |
+ |
+ |
bool UnaryOperation::IsInlineable() const { |
return expression()->IsInlineable(); |
} |
+void UnaryOperation::CollectInfo(AstNodeType::Flag* flags, |
+ int* node_count) const { |
+ expression()->CollectInfo(flags, node_count); |
+ *node_count += 1; |
+} |
+ |
+ |
bool BinaryOperation::IsInlineable() const { |
return left()->IsInlineable() && right()->IsInlineable(); |
} |
+void BinaryOperation::CollectInfo(AstNodeType::Flag* flags, |
+ int* node_count) const { |
+ left()->CollectInfo(flags, node_count); |
+ right()->CollectInfo(flags, node_count); |
+ *node_count += 1; |
+} |
+ |
+ |
bool CompareOperation::IsInlineable() const { |
return left()->IsInlineable() && right()->IsInlineable(); |
} |
+void CompareOperation::CollectInfo(AstNodeType::Flag* flags, |
+ int* node_count) const { |
+ left()->CollectInfo(flags, node_count); |
+ right()->CollectInfo(flags, node_count); |
+ *node_count += 1; |
+} |
+ |
+ |
bool CountOperation::IsInlineable() const { |
return expression()->IsInlineable(); |
} |
+void CountOperation::CollectInfo(AstNodeType::Flag* flags, |
+ int* node_count) const { |
+ expression()->CollectInfo(flags, node_count); |
+ *node_count += 1; |
+} |
+ |
+ |
// ---------------------------------------------------------------------------- |
// Recording of type feedback |