From 88371e63f66e2fcdd88819d94be1a5da1a50a1d5 Mon Sep 17 00:00:00 2001 From: "fschneider@chromium.org" Date: Wed, 21 Oct 2009 09:17:39 +0000 Subject: [PATCH] Adding declaration of global variables and functions in new compiler. Adding calls to global functions to the new compiler. Review URL: http://codereview.chromium.org/302002 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@3099 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/arm/codegen-arm.h | 4 +- src/arm/fast-codegen-arm.cc | 114 +++++++++++++++++++++++++++++++++ src/codegen.cc | 2 +- src/codegen.h | 1 + src/compiler.cc | 70 +++++++++++++++++--- src/fast-codegen.cc | 116 +++++++++++++++++++++++++++------- src/fast-codegen.h | 14 +++- src/ia32/codegen-ia32.h | 4 +- src/ia32/fast-codegen-ia32.cc | 107 +++++++++++++++++++++++++++++++ src/x64/codegen-x64.h | 4 +- src/x64/fast-codegen-x64.cc | 107 +++++++++++++++++++++++++++++++ 11 files changed, 504 insertions(+), 39 deletions(-) diff --git a/src/arm/codegen-arm.h b/src/arm/codegen-arm.h index 0901df2b27..e0799508e0 100644 --- a/src/arm/codegen-arm.h +++ b/src/arm/codegen-arm.h @@ -330,10 +330,11 @@ class CodeGenerator: public AstVisitor { const InlineRuntimeLUT& new_entry, InlineRuntimeLUT* old_entry); + static Handle ComputeLazyCompile(int argc); Handle BuildBoilerplate(FunctionLiteral* node); void ProcessDeclarations(ZoneList* declarations); - Handle ComputeCallInitialize(int argc, InLoopFlag in_loop); + static Handle ComputeCallInitialize(int argc, InLoopFlag in_loop); // Declare global variables and functions in the given array of // name/value pairs. @@ -426,6 +427,7 @@ class CodeGenerator: public AstVisitor { friend class JumpTarget; friend class Reference; friend class FastCodeGenerator; + friend class CodeGenSelector; DISALLOW_COPY_AND_ASSIGN(CodeGenerator); }; diff --git a/src/arm/fast-codegen-arm.cc b/src/arm/fast-codegen-arm.cc index c99e051310..49a20582b7 100644 --- a/src/arm/fast-codegen-arm.cc +++ b/src/arm/fast-codegen-arm.cc @@ -85,6 +85,10 @@ void FastCodeGenerator::Generate(FunctionLiteral* fun) { lo); } + { Comment cmnt(masm_, "[ Declarations"); + VisitDeclarations(fun->scope()->declarations()); + } + { Comment cmnt(masm_, "[ Body"); VisitStatements(fun->body()); } @@ -104,6 +108,25 @@ void FastCodeGenerator::Generate(FunctionLiteral* fun) { } +void FastCodeGenerator::DeclareGlobals(Handle pairs) { + // Call the runtime to declare the globals. + __ mov(r0, Operand(pairs)); + __ push(r0); + __ push(cp); // The context is the second argument. + __ mov(r0, Operand(Smi::FromInt(is_eval_ ? 1 : 0))); + __ push(r0); + __ CallRuntime(Runtime::kDeclareGlobals, 3); + // Return value is ignored. +} + + +void FastCodeGenerator::VisitBlock(Block* stmt) { + Comment cmnt(masm_, "[ Block"); + SetStatementPosition(stmt); + VisitStatements(stmt->statements()); +} + + void FastCodeGenerator::VisitExpressionStatement(ExpressionStatement* stmt) { Comment cmnt(masm_, "[ ExpressionStatement"); SetStatementPosition(stmt); @@ -136,6 +159,29 @@ void FastCodeGenerator::VisitReturnStatement(ReturnStatement* stmt) { } +void FastCodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) { + Comment cmnt(masm_, "[ FunctionLiteral"); + + // Build the function boilerplate and instantiate it. + Handle boilerplate = BuildBoilerplate(expr); + if (HasStackOverflow()) return; + + ASSERT(boilerplate->IsBoilerplate()); + + // Create a new closure. + __ mov(r0, Operand(boilerplate)); + __ push(r0); + __ push(cp); + __ CallRuntime(Runtime::kNewClosure, 2); + + if (expr->location().is_temporary()) { + __ push(r0); + } else { + ASSERT(expr->location().is_nowhere()); + } +} + + void FastCodeGenerator::VisitVariableProxy(VariableProxy* expr) { Comment cmnt(masm_, "[ VariableProxy"); Expression* rewrite = expr->var()->rewrite(); @@ -224,4 +270,72 @@ void FastCodeGenerator::VisitAssignment(Assignment* expr) { } +void FastCodeGenerator::VisitCall(Call* expr) { + Comment cmnt(masm_, "[ Call"); + Expression* fun = expr->expression(); + ZoneList* args = expr->arguments(); + Variable* var = fun->AsVariableProxy()->AsVariable(); + ASSERT(var != NULL && !var->is_this() && var->is_global()); + ASSERT(!var->is_possibly_eval()); + + __ mov(r0, Operand(var->name())); + __ push(r0); + // Push global object (receiver) + __ ldr(r0, CodeGenerator::GlobalObject()); + __ push(r0); + int arg_count = args->length(); + for (int i = 0; i < arg_count; i++) { + Visit(args->at(i)); + ASSERT(!args->at(i)->location().is_nowhere()); + if (args->at(i)->location().is_constant()) { + ASSERT(args->at(i)->AsLiteral() != NULL); + __ mov(r0, Operand(args->at(i)->AsLiteral()->handle())); + __ push(r0); + } + } + // Record source position for debugger + SetSourcePosition(expr->position()); + // Call the IC initialization code. + Handle ic = CodeGenerator::ComputeCallInitialize(arg_count, + NOT_IN_LOOP); + __ Call(ic, RelocInfo::CODE_TARGET_CONTEXT); + // Restore context register. + __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); + if (expr->location().is_temporary()) { + __ str(r0, MemOperand(sp)); + } else { + ASSERT(expr->location().is_nowhere()); + __ pop(); + } +} + + +void FastCodeGenerator::VisitCallRuntime(CallRuntime* expr) { + Comment cmnt(masm_, "[ CallRuntime"); + ZoneList* args = expr->arguments(); + Runtime::Function* function = expr->function(); + + ASSERT(function != NULL); + + // Push the arguments ("left-to-right"). + int arg_count = args->length(); + for (int i = 0; i < arg_count; i++) { + Visit(args->at(i)); + ASSERT(!args->at(i)->location().is_nowhere()); + if (args->at(i)->location().is_constant()) { + ASSERT(args->at(i)->AsLiteral() != NULL); + __ mov(r0, Operand(args->at(i)->AsLiteral()->handle())); + __ push(r0); + } + } + + __ CallRuntime(function, arg_count); + if (expr->location().is_temporary()) { + __ push(r0); + } else { + ASSERT(expr->location().is_nowhere()); + } +} + + } } // namespace v8::internal diff --git a/src/codegen.cc b/src/codegen.cc index 096a1a1910..28c0ba5f9e 100644 --- a/src/codegen.cc +++ b/src/codegen.cc @@ -274,7 +274,7 @@ void CodeGenerator::SetFunctionInfo(Handle fun, } -static Handle ComputeLazyCompile(int argc) { +Handle CodeGenerator::ComputeLazyCompile(int argc) { CALL_HEAP_FUNCTION(StubCache::ComputeLazyCompile(argc), Code); } diff --git a/src/codegen.h b/src/codegen.h index 1209f36ec6..8c1b733675 100644 --- a/src/codegen.h +++ b/src/codegen.h @@ -56,6 +56,7 @@ // ~CodeGenerator // ProcessDeferred // GenCode +// ComputeLazyCompile // BuildBoilerplate // ComputeCallInitialize // ComputeCallInitializeInLoop diff --git a/src/compiler.cc b/src/compiler.cc index 7fb7021fff..57dc77dadb 100644 --- a/src/compiler.cc +++ b/src/compiler.cc @@ -51,6 +51,7 @@ class CodeGenSelector: public AstVisitor { CodeGenTag Select(FunctionLiteral* fun); private: + void VisitDeclarations(ZoneList* decls); void VisitStatements(ZoneList* stmts); // AST node visit functions. @@ -107,7 +108,7 @@ static Handle MakeCode(FunctionLiteral* literal, CodeGenSelector selector; CodeGenSelector::CodeGenTag code_gen = selector.Select(literal); if (code_gen == CodeGenSelector::FAST) { - return FastCodeGenerator::MakeCode(literal, script); + return FastCodeGenerator::MakeCode(literal, script, is_eval); } ASSERT(code_gen == CodeGenSelector::NORMAL); } @@ -450,14 +451,22 @@ bool Compiler::CompileLazy(Handle shared, CodeGenSelector::CodeGenTag CodeGenSelector::Select(FunctionLiteral* fun) { Scope* scope = fun->scope(); - if (!scope->is_global_scope()) return NORMAL; + if (!scope->is_global_scope()) { + if (FLAG_trace_bailout) PrintF("Non-global scope\n"); + return NORMAL; + } ASSERT(scope->num_heap_slots() == 0); ASSERT(scope->arguments() == NULL); - if (!scope->declarations()->is_empty()) return NORMAL; - if (fun->materialized_literal_count() > 0) return NORMAL; + if (fun->materialized_literal_count() > 0) { + if (FLAG_trace_bailout) PrintF("Unsupported literal\n"); + return NORMAL; + } has_supported_syntax_ = true; + VisitDeclarations(fun->scope()->declarations()); + if (!has_supported_syntax_) return NORMAL; + VisitStatements(fun->body()); return has_supported_syntax_ ? FAST : NORMAL; } @@ -479,21 +488,32 @@ CodeGenSelector::CodeGenTag CodeGenSelector::Select(FunctionLiteral* fun) { } while (false) +void CodeGenSelector::VisitDeclarations(ZoneList* decls) { + for (int i = 0; i < decls->length(); i++) { + Visit(decls->at(i)); + CHECK_BAILOUT; + } +} + + void CodeGenSelector::VisitStatements(ZoneList* stmts) { for (int i = 0, len = stmts->length(); i < len; i++) { - CHECK_BAILOUT; Visit(stmts->at(i)); + CHECK_BAILOUT; } } void CodeGenSelector::VisitDeclaration(Declaration* decl) { - BAILOUT("Declaration"); + Variable* var = decl->proxy()->var(); + if (!var->is_global() || var->mode() == Variable::CONST) { + BAILOUT("Non-global declaration"); + } } void CodeGenSelector::VisitBlock(Block* stmt) { - BAILOUT("Block"); + VisitStatements(stmt->statements()); } @@ -581,7 +601,9 @@ void CodeGenSelector::VisitDebuggerStatement(DebuggerStatement* stmt) { void CodeGenSelector::VisitFunctionLiteral(FunctionLiteral* expr) { - BAILOUT("FunctionLiteral"); + if (!expr->AllowsLazyCompilation()) { + BAILOUT("FunctionLiteral does not allow lazy compilation"); + } } @@ -674,7 +696,25 @@ void CodeGenSelector::VisitProperty(Property* expr) { void CodeGenSelector::VisitCall(Call* expr) { - BAILOUT("Call"); + Expression* fun = expr->expression(); + ZoneList* args = expr->arguments(); + Variable* var = fun->AsVariableProxy()->AsVariable(); + + // Check for supported calls + if (var != NULL && var->is_possibly_eval()) { + BAILOUT("Call to a function named 'eval'"); + } else if (var != NULL && !var->is_this() && var->is_global()) { + // ---------------------------------- + // JavaScript example: 'foo(1, 2, 3)' // foo is global + // ---------------------------------- + } else { + BAILOUT("Call to a non-global function"); + } + // Check all arguments to the call + for (int i = 0; i < args->length(); i++) { + Visit(args->at(i)); + CHECK_BAILOUT; + } } @@ -684,7 +724,17 @@ void CodeGenSelector::VisitCallNew(CallNew* expr) { void CodeGenSelector::VisitCallRuntime(CallRuntime* expr) { - BAILOUT("CallRuntime"); + // In case of JS runtime function bail out. + if (expr->function() == NULL) BAILOUT("CallRuntime"); + // Check for inline runtime call + if (expr->name()->Get(0) == '_' && + CodeGenerator::FindInlineRuntimeLUT(expr->name()) != NULL) { + BAILOUT("InlineRuntimeCall"); + } + for (int i = 0; i < expr->arguments()->length(); i++) { + Visit(expr->arguments()->at(i)); + CHECK_BAILOUT; + } } diff --git a/src/fast-codegen.cc b/src/fast-codegen.cc index e67a149fc2..2fa45542a9 100644 --- a/src/fast-codegen.cc +++ b/src/fast-codegen.cc @@ -29,16 +29,19 @@ #include "codegen-inl.h" #include "fast-codegen.h" +#include "stub-cache.h" +#include "debug.h" namespace v8 { namespace internal { Handle FastCodeGenerator::MakeCode(FunctionLiteral* fun, - Handle