Revert "Pull from svn bleeding_edge@3716"
This reverts commit 888f6729be6a6f6fbe246cb5a9f122e2dbe455b7.
(Waiting until v8 issue 554101 is in v8 rather than patching it straight into
android)
diff --git a/src/compiler.cc b/src/compiler.cc
index fe61571..b7aaedf 100644
--- a/src/compiler.cc
+++ b/src/compiler.cc
@@ -32,7 +32,7 @@
#include "compilation-cache.h"
#include "compiler.h"
#include "debug.h"
-#include "full-codegen.h"
+#include "fast-codegen.h"
#include "oprofile-agent.h"
#include "rewriter.h"
#include "scopes.h"
@@ -42,6 +42,29 @@
namespace internal {
+class CodeGenSelector: public AstVisitor {
+ public:
+ enum CodeGenTag { NORMAL, FAST };
+
+ CodeGenSelector() : has_supported_syntax_(true) {}
+
+ CodeGenTag Select(FunctionLiteral* fun);
+
+ private:
+ void VisitDeclarations(ZoneList<Declaration*>* decls);
+ void VisitStatements(ZoneList<Statement*>* stmts);
+
+ // AST node visit functions.
+#define DECLARE_VISIT(type) virtual void Visit##type(type* node);
+ AST_NODE_LIST(DECLARE_VISIT)
+#undef DECLARE_VISIT
+
+ bool has_supported_syntax_;
+
+ DISALLOW_COPY_AND_ASSIGN(CodeGenSelector);
+};
+
+
static Handle<Code> MakeCode(FunctionLiteral* literal,
Handle<Script> script,
Handle<Context> context,
@@ -94,11 +117,12 @@
!FLAG_always_fast_compiler) {
if (FLAG_trace_bailout) PrintF("No hint to try fast\n");
} else {
- FullCodeGenSyntaxChecker checker;
- checker.Check(literal);
- if (checker.has_supported_syntax()) {
- return FullCodeGenerator::MakeCode(literal, script, is_eval);
+ CodeGenSelector selector;
+ CodeGenSelector::CodeGenTag code_gen = selector.Select(literal);
+ if (code_gen == CodeGenSelector::FAST) {
+ return FastCodeGenerator::MakeCode(literal, script, is_eval);
}
+ ASSERT(code_gen == CodeGenSelector::NORMAL);
}
}
return CodeGenerator::MakeCode(literal, script, is_eval);
@@ -469,12 +493,11 @@
// Generate code and return it.
bool is_compiled = false;
- if (FLAG_always_fast_compiler ||
- (FLAG_fast_compiler && literal->try_fast_codegen())) {
- FullCodeGenSyntaxChecker checker;
- checker.Check(literal);
- if (checker.has_supported_syntax()) {
- code = FullCodeGenerator::MakeCode(literal,
+ if (FLAG_fast_compiler && literal->try_fast_codegen()) {
+ CodeGenSelector selector;
+ CodeGenSelector::CodeGenTag code_gen = selector.Select(literal);
+ if (code_gen == CodeGenSelector::FAST) {
+ code = FastCodeGenerator::MakeCode(literal,
script,
false); // Not eval.
is_compiled = true;
@@ -548,4 +571,418 @@
}
+CodeGenSelector::CodeGenTag CodeGenSelector::Select(FunctionLiteral* fun) {
+ Scope* scope = fun->scope();
+
+ if (scope->num_heap_slots() > 0) {
+ // We support functions with a local context if they do not have
+ // parameters that need to be copied into the context.
+ for (int i = 0, len = scope->num_parameters(); i < len; i++) {
+ Slot* slot = scope->parameter(i)->slot();
+ if (slot != NULL && slot->type() == Slot::CONTEXT) {
+ if (FLAG_trace_bailout) {
+ PrintF("Function has context-allocated parameters.\n");
+ }
+ return NORMAL;
+ }
+ }
+ }
+
+ has_supported_syntax_ = true;
+ VisitDeclarations(scope->declarations());
+ if (!has_supported_syntax_) return NORMAL;
+
+ VisitStatements(fun->body());
+ return has_supported_syntax_ ? FAST : NORMAL;
+}
+
+
+#define BAILOUT(reason) \
+ do { \
+ if (FLAG_trace_bailout) { \
+ PrintF("%s\n", reason); \
+ } \
+ has_supported_syntax_ = false; \
+ return; \
+ } while (false)
+
+
+#define CHECK_BAILOUT \
+ do { \
+ if (!has_supported_syntax_) return; \
+ } while (false)
+
+
+void CodeGenSelector::VisitDeclarations(ZoneList<Declaration*>* decls) {
+ for (int i = 0; i < decls->length(); i++) {
+ Visit(decls->at(i));
+ CHECK_BAILOUT;
+ }
+}
+
+
+void CodeGenSelector::VisitStatements(ZoneList<Statement*>* stmts) {
+ for (int i = 0, len = stmts->length(); i < len; i++) {
+ Visit(stmts->at(i));
+ CHECK_BAILOUT;
+ }
+}
+
+
+void CodeGenSelector::VisitDeclaration(Declaration* decl) {
+ Property* prop = decl->proxy()->AsProperty();
+ if (prop != NULL) {
+ Visit(prop->obj());
+ Visit(prop->key());
+ }
+
+ if (decl->fun() != NULL) {
+ Visit(decl->fun());
+ }
+}
+
+
+void CodeGenSelector::VisitBlock(Block* stmt) {
+ VisitStatements(stmt->statements());
+}
+
+
+void CodeGenSelector::VisitExpressionStatement(ExpressionStatement* stmt) {
+ Visit(stmt->expression());
+}
+
+
+void CodeGenSelector::VisitEmptyStatement(EmptyStatement* stmt) {}
+
+
+void CodeGenSelector::VisitIfStatement(IfStatement* stmt) {
+ Visit(stmt->condition());
+ CHECK_BAILOUT;
+ Visit(stmt->then_statement());
+ CHECK_BAILOUT;
+ Visit(stmt->else_statement());
+}
+
+
+void CodeGenSelector::VisitContinueStatement(ContinueStatement* stmt) {}
+
+
+void CodeGenSelector::VisitBreakStatement(BreakStatement* stmt) {}
+
+
+void CodeGenSelector::VisitReturnStatement(ReturnStatement* stmt) {
+ Visit(stmt->expression());
+}
+
+
+void CodeGenSelector::VisitWithEnterStatement(WithEnterStatement* stmt) {
+ Visit(stmt->expression());
+}
+
+
+void CodeGenSelector::VisitWithExitStatement(WithExitStatement* stmt) {}
+
+
+void CodeGenSelector::VisitSwitchStatement(SwitchStatement* stmt) {
+ BAILOUT("SwitchStatement");
+}
+
+
+void CodeGenSelector::VisitDoWhileStatement(DoWhileStatement* stmt) {
+ Visit(stmt->cond());
+ CHECK_BAILOUT;
+ Visit(stmt->body());
+}
+
+
+void CodeGenSelector::VisitWhileStatement(WhileStatement* stmt) {
+ Visit(stmt->cond());
+ CHECK_BAILOUT;
+ Visit(stmt->body());
+}
+
+
+void CodeGenSelector::VisitForStatement(ForStatement* stmt) {
+ BAILOUT("ForStatement");
+}
+
+
+void CodeGenSelector::VisitForInStatement(ForInStatement* stmt) {
+ BAILOUT("ForInStatement");
+}
+
+
+void CodeGenSelector::VisitTryCatchStatement(TryCatchStatement* stmt) {
+ Visit(stmt->try_block());
+ CHECK_BAILOUT;
+ Visit(stmt->catch_block());
+}
+
+
+void CodeGenSelector::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
+ Visit(stmt->try_block());
+ CHECK_BAILOUT;
+ Visit(stmt->finally_block());
+}
+
+
+void CodeGenSelector::VisitDebuggerStatement(DebuggerStatement* stmt) {}
+
+
+void CodeGenSelector::VisitFunctionLiteral(FunctionLiteral* expr) {}
+
+
+void CodeGenSelector::VisitFunctionBoilerplateLiteral(
+ FunctionBoilerplateLiteral* expr) {
+ BAILOUT("FunctionBoilerplateLiteral");
+}
+
+
+void CodeGenSelector::VisitConditional(Conditional* expr) {
+ Visit(expr->condition());
+ CHECK_BAILOUT;
+ Visit(expr->then_expression());
+ CHECK_BAILOUT;
+ Visit(expr->else_expression());
+}
+
+
+void CodeGenSelector::VisitSlot(Slot* expr) {
+ UNREACHABLE();
+}
+
+
+void CodeGenSelector::VisitVariableProxy(VariableProxy* expr) {
+ Variable* var = expr->var();
+ if (!var->is_global()) {
+ Slot* slot = var->slot();
+ if (slot != NULL) {
+ Slot::Type type = slot->type();
+ // When LOOKUP slots are enabled, some currently dead code
+ // implementing unary typeof will become live.
+ if (type == Slot::LOOKUP) {
+ BAILOUT("Lookup slot");
+ }
+ } else {
+ // If not global or a slot, it is a parameter rewritten to an explicit
+ // property reference on the (shadow) arguments object.
+#ifdef DEBUG
+ Property* property = var->AsProperty();
+ ASSERT_NOT_NULL(property);
+ Variable* object = property->obj()->AsVariableProxy()->AsVariable();
+ ASSERT_NOT_NULL(object);
+ ASSERT_NOT_NULL(object->slot());
+ ASSERT_NOT_NULL(property->key()->AsLiteral());
+ ASSERT(property->key()->AsLiteral()->handle()->IsSmi());
+#endif
+ }
+ }
+}
+
+
+void CodeGenSelector::VisitLiteral(Literal* expr) {}
+
+
+void CodeGenSelector::VisitRegExpLiteral(RegExpLiteral* expr) {}
+
+
+void CodeGenSelector::VisitObjectLiteral(ObjectLiteral* expr) {
+ ZoneList<ObjectLiteral::Property*>* properties = expr->properties();
+
+ for (int i = 0, len = properties->length(); i < len; i++) {
+ ObjectLiteral::Property* property = properties->at(i);
+ if (property->IsCompileTimeValue()) continue;
+ Visit(property->key());
+ CHECK_BAILOUT;
+ Visit(property->value());
+ CHECK_BAILOUT;
+ }
+}
+
+
+void CodeGenSelector::VisitArrayLiteral(ArrayLiteral* expr) {
+ ZoneList<Expression*>* subexprs = expr->values();
+ for (int i = 0, len = subexprs->length(); i < len; i++) {
+ Expression* subexpr = subexprs->at(i);
+ if (subexpr->AsLiteral() != NULL) continue;
+ if (CompileTimeValue::IsCompileTimeValue(subexpr)) continue;
+ Visit(subexpr);
+ CHECK_BAILOUT;
+ }
+}
+
+
+void CodeGenSelector::VisitCatchExtensionObject(CatchExtensionObject* expr) {
+ Visit(expr->key());
+ CHECK_BAILOUT;
+ Visit(expr->value());
+}
+
+
+void CodeGenSelector::VisitAssignment(Assignment* expr) {
+ // We support plain non-compound assignments to properties, parameters and
+ // non-context (stack-allocated) locals, and global variables.
+ Token::Value op = expr->op();
+ if (op == Token::INIT_CONST) BAILOUT("initialize constant");
+
+ Variable* var = expr->target()->AsVariableProxy()->AsVariable();
+ Property* prop = expr->target()->AsProperty();
+ ASSERT(var == NULL || prop == NULL);
+ if (var != NULL) {
+ if (var->mode() == Variable::CONST) {
+ BAILOUT("Assignment to const");
+ }
+ // All global variables are supported.
+ if (!var->is_global()) {
+ ASSERT(var->slot() != NULL);
+ Slot::Type type = var->slot()->type();
+ if (type == Slot::LOOKUP) {
+ BAILOUT("Lookup slot");
+ }
+ }
+ } else if (prop != NULL) {
+ Visit(prop->obj());
+ CHECK_BAILOUT;
+ Visit(prop->key());
+ CHECK_BAILOUT;
+ } else {
+ // This is a throw reference error.
+ BAILOUT("non-variable/non-property assignment");
+ }
+
+ Visit(expr->value());
+}
+
+
+void CodeGenSelector::VisitThrow(Throw* expr) {
+ Visit(expr->exception());
+}
+
+
+void CodeGenSelector::VisitProperty(Property* expr) {
+ Visit(expr->obj());
+ CHECK_BAILOUT;
+ Visit(expr->key());
+}
+
+
+void CodeGenSelector::VisitCall(Call* expr) {
+ Expression* fun = expr->expression();
+ ZoneList<Expression*>* args = expr->arguments();
+ Variable* var = fun->AsVariableProxy()->AsVariable();
+
+ // Check for supported calls
+ if (var != NULL && var->is_possibly_eval()) {
+ BAILOUT("call to the identifier 'eval'");
+ } else if (var != NULL && !var->is_this() && var->is_global()) {
+ // Calls to global variables are supported.
+ } else if (var != NULL && var->slot() != NULL &&
+ var->slot()->type() == Slot::LOOKUP) {
+ BAILOUT("call to a lookup slot");
+ } else if (fun->AsProperty() != NULL) {
+ Property* prop = fun->AsProperty();
+ Visit(prop->obj());
+ CHECK_BAILOUT;
+ Visit(prop->key());
+ CHECK_BAILOUT;
+ } else {
+ // Otherwise the call is supported if the function expression is.
+ Visit(fun);
+ }
+ // Check all arguments to the call.
+ for (int i = 0; i < args->length(); i++) {
+ Visit(args->at(i));
+ CHECK_BAILOUT;
+ }
+}
+
+
+void CodeGenSelector::VisitCallNew(CallNew* expr) {
+ Visit(expr->expression());
+ CHECK_BAILOUT;
+ ZoneList<Expression*>* args = expr->arguments();
+ // Check all arguments to the call
+ for (int i = 0; i < args->length(); i++) {
+ Visit(args->at(i));
+ CHECK_BAILOUT;
+ }
+}
+
+
+void CodeGenSelector::VisitCallRuntime(CallRuntime* expr) {
+ // Check for inline runtime call
+ if (expr->name()->Get(0) == '_' &&
+ CodeGenerator::FindInlineRuntimeLUT(expr->name()) != NULL) {
+ BAILOUT("inlined runtime call");
+ }
+ // Check all arguments to the call. (Relies on TEMP meaning STACK.)
+ for (int i = 0; i < expr->arguments()->length(); i++) {
+ Visit(expr->arguments()->at(i));
+ CHECK_BAILOUT;
+ }
+}
+
+
+void CodeGenSelector::VisitUnaryOperation(UnaryOperation* expr) {
+ switch (expr->op()) {
+ case Token::VOID:
+ case Token::NOT:
+ case Token::TYPEOF:
+ Visit(expr->expression());
+ break;
+ case Token::BIT_NOT:
+ BAILOUT("UnaryOperataion: BIT_NOT");
+ case Token::DELETE:
+ BAILOUT("UnaryOperataion: DELETE");
+ default:
+ BAILOUT("UnaryOperataion");
+ }
+}
+
+
+void CodeGenSelector::VisitCountOperation(CountOperation* expr) {
+ Variable* var = expr->expression()->AsVariableProxy()->AsVariable();
+ Property* prop = expr->expression()->AsProperty();
+ ASSERT(var == NULL || prop == NULL);
+ if (var != NULL) {
+ // All global variables are supported.
+ if (!var->is_global()) {
+ ASSERT(var->slot() != NULL);
+ Slot::Type type = var->slot()->type();
+ if (type == Slot::LOOKUP) {
+ BAILOUT("CountOperation with lookup slot");
+ }
+ }
+ } else if (prop != NULL) {
+ Visit(prop->obj());
+ CHECK_BAILOUT;
+ Visit(prop->key());
+ CHECK_BAILOUT;
+ } else {
+ // This is a throw reference error.
+ BAILOUT("CountOperation non-variable/non-property expression");
+ }
+}
+
+
+void CodeGenSelector::VisitBinaryOperation(BinaryOperation* expr) {
+ Visit(expr->left());
+ CHECK_BAILOUT;
+ Visit(expr->right());
+}
+
+
+void CodeGenSelector::VisitCompareOperation(CompareOperation* expr) {
+ Visit(expr->left());
+ CHECK_BAILOUT;
+ Visit(expr->right());
+}
+
+
+void CodeGenSelector::VisitThisFunction(ThisFunction* expr) {}
+
+#undef BAILOUT
+#undef CHECK_BAILOUT
+
+
} } // namespace v8::internal