Index: src/compiler.cc |
=================================================================== |
--- src/compiler.cc (revision 3659) |
+++ src/compiler.cc (working copy) |
@@ -42,29 +42,6 @@ |
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, |
@@ -117,12 +94,11 @@ |
!FLAG_always_fast_compiler) { |
if (FLAG_trace_bailout) PrintF("No hint to try fast\n"); |
} else { |
- CodeGenSelector selector; |
- CodeGenSelector::CodeGenTag code_gen = selector.Select(literal); |
- if (code_gen == CodeGenSelector::FAST) { |
- return FastCodeGenerator::MakeCode(literal, script, is_eval); |
+ FullCodeGenSyntaxChecker checker; |
+ checker.Check(literal); |
+ if (checker.has_supported_syntax()) { |
+ return FullCodeGenerator::MakeCode(literal, script, is_eval); |
} |
- ASSERT(code_gen == CodeGenSelector::NORMAL); |
} |
} |
return CodeGenerator::MakeCode(literal, script, is_eval); |
@@ -494,10 +470,10 @@ |
// Generate code and return it. |
bool is_compiled = false; |
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, |
+ FullCodeGenSyntaxChecker checker; |
+ checker.Check(literal); |
+ if (checker.has_supported_syntax()) { |
+ code = FullCodeGenerator::MakeCode(literal, |
script, |
false); // Not eval. |
is_compiled = true; |
@@ -571,422 +547,4 @@ |
} |
-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("UnaryOperation: BIT_NOT"); |
- case Token::DELETE: |
- BAILOUT("UnaryOperation: DELETE"); |
- case Token::ADD: |
- BAILOUT("UnaryOperation: ADD"); |
- case Token::SUB: |
- BAILOUT("UnaryOperation: SUB"); |
- default: |
- UNREACHABLE(); |
- } |
-} |
- |
- |
-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 |