Adding declaration of global variables and functions in new compiler.
authorfschneider@chromium.org <fschneider@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 21 Oct 2009 09:17:39 +0000 (09:17 +0000)
committerfschneider@chromium.org <fschneider@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 21 Oct 2009 09:17:39 +0000 (09:17 +0000)
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
src/arm/fast-codegen-arm.cc
src/codegen.cc
src/codegen.h
src/compiler.cc
src/fast-codegen.cc
src/fast-codegen.h
src/ia32/codegen-ia32.h
src/ia32/fast-codegen-ia32.cc
src/x64/codegen-x64.h
src/x64/fast-codegen-x64.cc

index 0901df2..e079950 100644 (file)
@@ -330,10 +330,11 @@ class CodeGenerator: public AstVisitor {
                                       const InlineRuntimeLUT& new_entry,
                                       InlineRuntimeLUT* old_entry);
 
+  static Handle<Code> ComputeLazyCompile(int argc);
   Handle<JSFunction> BuildBoilerplate(FunctionLiteral* node);
   void ProcessDeclarations(ZoneList<Declaration*>* declarations);
 
-  Handle<Code> ComputeCallInitialize(int argc, InLoopFlag in_loop);
+  static Handle<Code> 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);
 };
index c99e051..49a2058 100644 (file)
@@ -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<FixedArray> 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<JSFunction> 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<Expression*>* 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<Code> 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<Expression*>* 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
index 096a1a1..28c0ba5 100644 (file)
@@ -274,7 +274,7 @@ void CodeGenerator::SetFunctionInfo(Handle<JSFunction> fun,
 }
 
 
-static Handle<Code> ComputeLazyCompile(int argc) {
+Handle<Code> CodeGenerator::ComputeLazyCompile(int argc) {
   CALL_HEAP_FUNCTION(StubCache::ComputeLazyCompile(argc), Code);
 }
 
index 1209f36..8c1b733 100644 (file)
@@ -56,6 +56,7 @@
 //   ~CodeGenerator
 //   ProcessDeferred
 //   GenCode
+//   ComputeLazyCompile
 //   BuildBoilerplate
 //   ComputeCallInitialize
 //   ComputeCallInitializeInLoop
index 7fb7021..57dc77d 100644 (file)
@@ -51,6 +51,7 @@ class CodeGenSelector: public AstVisitor {
   CodeGenTag Select(FunctionLiteral* fun);
 
  private:
+  void VisitDeclarations(ZoneList<Declaration*>* decls);
   void VisitStatements(ZoneList<Statement*>* stmts);
 
   // AST node visit functions.
@@ -107,7 +108,7 @@ static Handle<Code> 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<SharedFunctionInfo> 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<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++) {
-    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<Expression*>* 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;
+  }
 }
 
 
index e67a149..2fa4554 100644 (file)
 
 #include "codegen-inl.h"
 #include "fast-codegen.h"
+#include "stub-cache.h"
+#include "debug.h"
 
 namespace v8 {
 namespace internal {
 
 Handle<Code> FastCodeGenerator::MakeCode(FunctionLiteral* fun,
-                                         Handle<Script> script) {
+                                         Handle<Script> script,
+                                         bool is_eval) {
   CodeGenerator::MakeCodePrologue(fun);
   const int kInitialBufferSize = 4 * KB;
   MacroAssembler masm(NULL, kInitialBufferSize);
-  FastCodeGenerator cgen(&masm);
+  FastCodeGenerator cgen(&masm, script, is_eval);
   cgen.Generate(fun);
   if (cgen.HasStackOverflow()) {
     ASSERT(!Top::has_pending_exception());
@@ -66,6 +69,95 @@ int FastCodeGenerator::SlotOffset(Slot* slot) {
   return offset;
 }
 
+
+void FastCodeGenerator::VisitDeclarations(
+    ZoneList<Declaration*>* declarations) {
+  int length = declarations->length();
+  int globals = 0;
+  for (int i = 0; i < length; i++) {
+    Declaration* node = declarations->at(i);
+    Variable* var = node->proxy()->var();
+    Slot* slot = var->slot();
+
+    // If it was not possible to allocate the variable at compile
+    // time, we need to "declare" it at runtime to make sure it
+    // actually exists in the local context.
+    if ((slot != NULL && slot->type() == Slot::LOOKUP) || !var->is_global()) {
+      UNREACHABLE();
+    } else {
+      // Count global variables and functions for later processing
+      globals++;
+    }
+  }
+
+  // Return in case of no declared global functions or variables.
+  if (globals == 0) return;
+
+  // Compute array of global variable and function declarations.
+  Handle<FixedArray> array = Factory::NewFixedArray(2 * globals, TENURED);
+  for (int j = 0, i = 0; i < length; i++) {
+    Declaration* node = declarations->at(i);
+    Variable* var = node->proxy()->var();
+    Slot* slot = var->slot();
+
+    if ((slot == NULL || slot->type() != Slot::LOOKUP) && var->is_global()) {
+      array->set(j++, *(var->name()));
+      if (node->fun() == NULL) {
+        if (var->mode() == Variable::CONST) {
+          // In case this is const property use the hole.
+          array->set_the_hole(j++);
+        } else {
+          array->set_undefined(j++);
+        }
+      } else {
+        Handle<JSFunction> function = BuildBoilerplate(node->fun());
+        // Check for stack-overflow exception.
+        if (HasStackOverflow()) return;
+        array->set(j++, *function);
+      }
+    }
+  }
+
+  // Invoke the platform-dependent code generator to do the actual
+  // declaration the global variables and functions.
+  DeclareGlobals(array);
+}
+
+Handle<JSFunction> FastCodeGenerator::BuildBoilerplate(FunctionLiteral* fun) {
+#ifdef DEBUG
+  // We should not try to compile the same function literal more than
+  // once.
+  fun->mark_as_compiled();
+#endif
+
+  // Generate code
+  Handle<Code> code = CodeGenerator::ComputeLazyCompile(fun->num_parameters());
+  // Check for stack-overflow exception.
+  if (code.is_null()) {
+    SetStackOverflow();
+    return Handle<JSFunction>::null();
+  }
+
+  // Create a boilerplate function.
+  Handle<JSFunction> function =
+      Factory::NewFunctionBoilerplate(fun->name(),
+                                      fun->materialized_literal_count(),
+                                      code);
+  CodeGenerator::SetFunctionInfo(function, fun, false, script_);
+
+#ifdef ENABLE_DEBUGGER_SUPPORT
+  // Notify debugger that a new function has been added.
+  Debugger::OnNewFunction(function);
+#endif
+
+  // Set the expected number of properties for instances and return
+  // the resulting function.
+  SetExpectedNofPropertiesFromEstimate(function,
+                                       fun->expected_property_count());
+  return function;
+}
+
+
 void FastCodeGenerator::SetFunctionPosition(FunctionLiteral* fun) {
   if (FLAG_debug_info) {
     CodeGenerator::RecordPositions(masm_, fun->start_position());
@@ -99,11 +191,6 @@ void FastCodeGenerator::VisitDeclaration(Declaration* decl) {
 }
 
 
-void FastCodeGenerator::VisitBlock(Block* stmt) {
-  UNREACHABLE();
-}
-
-
 void FastCodeGenerator::VisitEmptyStatement(EmptyStatement* stmt) {
   UNREACHABLE();
 }
@@ -174,11 +261,6 @@ void FastCodeGenerator::VisitDebuggerStatement(DebuggerStatement* stmt) {
 }
 
 
-void FastCodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) {
-  UNREACHABLE();
-}
-
-
 void FastCodeGenerator::VisitFunctionBoilerplateLiteral(
     FunctionBoilerplateLiteral* expr) {
   UNREACHABLE();
@@ -231,21 +313,11 @@ void FastCodeGenerator::VisitProperty(Property* expr) {
 }
 
 
-void FastCodeGenerator::VisitCall(Call* expr) {
-  UNREACHABLE();
-}
-
-
 void FastCodeGenerator::VisitCallNew(CallNew* expr) {
   UNREACHABLE();
 }
 
 
-void FastCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
-  UNREACHABLE();
-}
-
-
 void FastCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
   UNREACHABLE();
 }
index e6bb643..42d6cde 100644 (file)
@@ -38,17 +38,23 @@ namespace internal {
 
 class FastCodeGenerator: public AstVisitor {
  public:
-  explicit FastCodeGenerator(MacroAssembler* masm)
-      : masm_(masm), function_(NULL) {
+  FastCodeGenerator(MacroAssembler* masm, Handle<Script> script, bool is_eval)
+    : masm_(masm), function_(NULL), script_(script), is_eval_(is_eval) {
   }
 
-  static Handle<Code> MakeCode(FunctionLiteral* fun, Handle<Script> script);
+  static Handle<Code> MakeCode(FunctionLiteral* fun,
+                               Handle<Script> script,
+                               bool is_eval);
 
   void Generate(FunctionLiteral* fun);
 
  private:
   int SlotOffset(Slot* slot);
 
+  void VisitDeclarations(ZoneList<Declaration*>* declarations);
+  Handle<JSFunction> BuildBoilerplate(FunctionLiteral* fun);
+  void DeclareGlobals(Handle<FixedArray> pairs);
+
   void SetFunctionPosition(FunctionLiteral* fun);
   void SetReturnPosition(FunctionLiteral* fun);
   void SetStatementPosition(Statement* stmt);
@@ -61,6 +67,8 @@ class FastCodeGenerator: public AstVisitor {
 
   MacroAssembler* masm_;
   FunctionLiteral* function_;
+  Handle<Script> script_;
+  bool is_eval_;
 
   DISALLOW_COPY_AND_ASSIGN(FastCodeGenerator);
 };
index 8c50043..e914aff 100644 (file)
@@ -511,10 +511,11 @@ class CodeGenerator: public AstVisitor {
                                       const InlineRuntimeLUT& new_entry,
                                       InlineRuntimeLUT* old_entry);
 
+  static Handle<Code> ComputeLazyCompile(int argc);
   Handle<JSFunction> BuildBoilerplate(FunctionLiteral* node);
   void ProcessDeclarations(ZoneList<Declaration*>* declarations);
 
-  Handle<Code> ComputeCallInitialize(int argc, InLoopFlag in_loop);
+  static Handle<Code> ComputeCallInitialize(int argc, InLoopFlag in_loop);
 
   // Declare global variables and functions in the given array of
   // name/value pairs.
@@ -617,6 +618,7 @@ class CodeGenerator: public AstVisitor {
   friend class Reference;
   friend class Result;
   friend class FastCodeGenerator;
+  friend class CodeGenSelector;
 
   friend class CodeGeneratorPatcher;  // Used in test-log-stack-tracer.cc
 
index 1304535..0c585e5 100644 (file)
@@ -75,6 +75,10 @@ void FastCodeGenerator::Generate(FunctionLiteral* fun) {
     __ bind(&ok);
   }
 
+  { Comment cmnt(masm_, "[ Declarations");
+    VisitDeclarations(fun->scope()->declarations());
+  }
+
   { Comment cmnt(masm_, "[ Body");
     VisitStatements(fun->body());
   }
@@ -94,6 +98,23 @@ void FastCodeGenerator::Generate(FunctionLiteral* fun) {
 }
 
 
+void FastCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
+  // Call the runtime to declare the globals.
+  __ push(Immediate(pairs));
+  __ push(esi);  // The context is the second argument.
+  __ push(Immediate(Smi::FromInt(is_eval_ ? 1 : 0)));
+  __ 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);
@@ -126,6 +147,28 @@ void FastCodeGenerator::VisitReturnStatement(ReturnStatement* stmt) {
 }
 
 
+void FastCodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) {
+  Comment cmnt(masm_, "[ FunctionLiteral");
+
+  // Build the function boilerplate and instantiate it.
+  Handle<JSFunction> boilerplate = BuildBoilerplate(expr);
+  if (HasStackOverflow()) return;
+
+  ASSERT(boilerplate->IsBoilerplate());
+
+  // Create a new closure.
+  __ push(Immediate(boilerplate));
+  __ push(esi);
+  __ CallRuntime(Runtime::kNewClosure, 2);
+
+  if (expr->location().is_temporary()) {
+    __ push(eax);
+  } else {
+    ASSERT(expr->location().is_nowhere());
+  }
+}
+
+
 void FastCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
   Comment cmnt(masm_, "[ VariableProxy");
   Expression* rewrite = expr->var()->rewrite();
@@ -213,4 +256,68 @@ void FastCodeGenerator::VisitAssignment(Assignment* expr) {
 }
 
 
+void FastCodeGenerator::VisitCall(Call* expr) {
+  Expression* fun = expr->expression();
+  ZoneList<Expression*>* args = expr->arguments();
+  Variable* var = fun->AsVariableProxy()->AsVariable();
+  ASSERT(var != NULL && !var->is_this() && var->is_global());
+  ASSERT(!var->is_possibly_eval());
+
+  __ push(Immediate(var->name()));
+  // Push global object (receiver).
+  __ push(CodeGenerator::GlobalObject());
+  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);
+      __ push(Immediate(args->at(i)->AsLiteral()->handle()));
+    }
+  }
+  // Record source position for debugger
+  SetSourcePosition(expr->position());
+  // Call the IC initialization code.
+  Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count,
+                                                         NOT_IN_LOOP);
+  __ call(ic, RelocInfo::CODE_TARGET_CONTEXT);
+  // Restore context register.
+  __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
+  // Discard the function left on TOS.
+  if (expr->location().is_temporary()) {
+    __ mov(Operand(esp, 0), eax);
+  } else {
+    ASSERT(expr->location().is_nowhere());
+    __ pop(eax);
+  }
+}
+
+
+void FastCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
+  Comment cmnt(masm_, "[ CallRuntime");
+  ZoneList<Expression*>* 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);
+      __ push(Immediate(args->at(i)->AsLiteral()->handle()));
+    }
+  }
+
+  __ CallRuntime(function, arg_count);
+  if (expr->location().is_temporary()) {
+    __ push(eax);
+  } else {
+    ASSERT(expr->location().is_nowhere());
+  }
+}
+
+
 } }  // namespace v8::internal
index ddb571d..541da30 100644 (file)
@@ -511,10 +511,11 @@ class CodeGenerator: public AstVisitor {
   static bool PatchInlineRuntimeEntry(Handle<String> name,
                                       const InlineRuntimeLUT& new_entry,
                                       InlineRuntimeLUT* old_entry);
+  static Handle<Code> ComputeLazyCompile(int argc);
   Handle<JSFunction> BuildBoilerplate(FunctionLiteral* node);
   void ProcessDeclarations(ZoneList<Declaration*>* declarations);
 
-  Handle<Code> ComputeCallInitialize(int argc, InLoopFlag in_loop);
+  static Handle<Code> ComputeCallInitialize(int argc, InLoopFlag in_loop);
 
   // Declare global variables and functions in the given array of
   // name/value pairs.
@@ -617,6 +618,7 @@ class CodeGenerator: public AstVisitor {
   friend class Reference;
   friend class Result;
   friend class FastCodeGenerator;
+  friend class CodeGenSelector;
 
   friend class CodeGeneratorPatcher;  // Used in test-log-stack-tracer.cc
 
index 7867b6f..34851aa 100644 (file)
@@ -74,6 +74,10 @@ void FastCodeGenerator::Generate(FunctionLiteral* fun) {
     __ bind(&ok);
   }
 
+  { Comment cmnt(masm_, "[ Declarations");
+    VisitDeclarations(fun->scope()->declarations());
+  }
+
   { Comment cmnt(masm_, "[ Body");
     VisitStatements(fun->body());
   }
@@ -102,6 +106,23 @@ void FastCodeGenerator::Generate(FunctionLiteral* fun) {
 }
 
 
+void FastCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
+  // Call the runtime to declare the globals.
+  __ Push(pairs);
+  __ push(rsi);  // The context is the second argument.
+  __ Push(Smi::FromInt(is_eval_ ? 1 : 0));
+  __ 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);
@@ -143,6 +164,28 @@ void FastCodeGenerator::VisitReturnStatement(ReturnStatement* stmt) {
 }
 
 
+void FastCodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) {
+  Comment cmnt(masm_, "[ FunctionLiteral");
+
+  // Build the function boilerplate and instantiate it.
+  Handle<JSFunction> boilerplate = BuildBoilerplate(expr);
+  if (HasStackOverflow()) return;
+
+  ASSERT(boilerplate->IsBoilerplate());
+
+  // Create a new closure.
+  __ Push(boilerplate);
+  __ push(rsi);
+  __ CallRuntime(Runtime::kNewClosure, 2);
+
+  if (expr->location().is_temporary()) {
+    __ push(rax);
+  } else {
+    ASSERT(expr->location().is_nowhere());
+  }
+}
+
+
 void FastCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
   Comment cmnt(masm_, "[ VariableProxy");
   Expression* rewrite = expr->var()->rewrite();
@@ -227,4 +270,68 @@ void FastCodeGenerator::VisitAssignment(Assignment* expr) {
 }
 
 
+void FastCodeGenerator::VisitCall(Call* expr) {
+  Expression* fun = expr->expression();
+  ZoneList<Expression*>* args = expr->arguments();
+  Variable* var = fun->AsVariableProxy()->AsVariable();
+  ASSERT(var != NULL && !var->is_this() && var->is_global());
+  ASSERT(!var->is_possibly_eval());
+
+  __ Push(var->name());
+  // Push global object (receiver).
+  __ push(CodeGenerator::GlobalObject());
+  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);
+      __ Push(args->at(i)->AsLiteral()->handle());
+    }
+  }
+  // Record source position for debugger
+  SetSourcePosition(expr->position());
+  // Call the IC initialization code.
+  Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count,
+                                                         NOT_IN_LOOP);
+  __ call(ic, RelocInfo::CODE_TARGET_CONTEXT);
+  // Restore context register.
+  __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
+  // Discard the function left on TOS.
+  if (expr->location().is_temporary()) {
+    __ movq(Operand(rsp, 0), rax);
+  } else {
+    ASSERT(expr->location().is_nowhere());
+    __ pop(rax);
+  }
+}
+
+
+void FastCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
+  Comment cmnt(masm_, "[ CallRuntime");
+  ZoneList<Expression*>* 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);
+      __ Push(args->at(i)->AsLiteral()->handle());
+    }
+  }
+
+  __ CallRuntime(function, arg_count);
+  if (expr->location().is_temporary()) {
+    __ push(rax);
+  } else {
+    ASSERT(expr->location().is_nowhere());
+  }
+}
+
+
 } }  // namespace v8::internal