| 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
|
|
|