Merge from v8 at revision 3723
diff --git a/src/compiler.cc b/src/compiler.cc
index b7aaedf..7482ae1 100644
--- a/src/compiler.cc
+++ b/src/compiler.cc
@@ -33,6 +33,7 @@
#include "compiler.h"
#include "debug.h"
#include "fast-codegen.h"
+#include "full-codegen.h"
#include "oprofile-agent.h"
#include "rewriter.h"
#include "scopes.h"
@@ -42,29 +43,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,
@@ -104,27 +82,37 @@
return Handle<Code>::null();
}
- // Generate code and return it.
- if (FLAG_fast_compiler) {
- // If there is no shared function info, try the fast code
- // generator for code in the global scope. Otherwise obey the
- // explicit hint in the shared function info.
- // If always_fast_compiler is true, always try the fast compiler.
- if (shared.is_null() && !literal->scope()->is_global_scope() &&
- !FLAG_always_fast_compiler) {
- if (FLAG_trace_bailout) PrintF("Non-global scope\n");
- } else if (!shared.is_null() && !shared->try_fast_codegen() &&
- !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);
- }
- ASSERT(code_gen == CodeGenSelector::NORMAL);
+ // Generate code and return it. Code generator selection is governed by
+ // which backends are enabled and whether the function is considered
+ // run-once code or not:
+ //
+ // --full-compiler enables the dedicated backend for code we expect to be
+ // run once
+ // --fast-compiler enables a speculative optimizing backend (for
+ // non-run-once code)
+ //
+ // The normal choice of backend can be overridden with the flags
+ // --always-full-compiler and --always-fast-compiler, which are mutually
+ // incompatible.
+ CHECK(!FLAG_always_full_compiler || !FLAG_always_fast_compiler);
+
+ bool is_run_once = (shared.is_null())
+ ? literal->scope()->is_global_scope()
+ : (shared->is_toplevel() || shared->try_full_codegen());
+
+ if (FLAG_always_full_compiler || (FLAG_full_compiler && is_run_once)) {
+ FullCodeGenSyntaxChecker checker;
+ checker.Check(literal);
+ if (checker.has_supported_syntax()) {
+ return FullCodeGenerator::MakeCode(literal, script, is_eval);
}
+ } else if (FLAG_always_fast_compiler ||
+ (FLAG_fast_compiler && !is_run_once)) {
+ FastCodeGenSyntaxChecker checker;
+ checker.Check(literal);
+ // Does not yet generate code.
}
+
return CodeGenerator::MakeCode(literal, script, is_eval);
}
@@ -491,21 +479,30 @@
return Handle<JSFunction>::null();
}
- // Generate code and return it.
+ // Generate code and return it. The way that the compilation mode
+ // is controlled by the command-line flags is described in
+ // the static helper function MakeCode.
+ CHECK(!FLAG_always_full_compiler || !FLAG_always_fast_compiler);
+ bool is_run_once = literal->try_full_codegen();
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,
+ if (FLAG_always_full_compiler || (FLAG_full_compiler && is_run_once)) {
+ FullCodeGenSyntaxChecker checker;
+ checker.Check(literal);
+ if (checker.has_supported_syntax()) {
+ code = FullCodeGenerator::MakeCode(literal,
script,
false); // Not eval.
is_compiled = true;
}
+ } else if (FLAG_always_fast_compiler ||
+ (FLAG_fast_compiler && !is_run_once)) {
+ FastCodeGenSyntaxChecker checker;
+ checker.Check(literal);
+ // Generate no code.
}
if (!is_compiled) {
- // We didn't try the fast compiler, or we failed to select it.
+ // We fall back to the classic V8 code generator.
code = CodeGenerator::MakeCode(literal,
script,
false); // Not eval.
@@ -567,422 +564,8 @@
fun->shared()->SetThisPropertyAssignmentsInfo(
lit->has_only_simple_this_property_assignments(),
*lit->this_property_assignments());
- fun->shared()->set_try_fast_codegen(lit->try_fast_codegen());
+ fun->shared()->set_try_full_codegen(lit->try_full_codegen());
}
-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