Upgrade V8 to 2.2.8
[platform/upstream/nodejs.git] / deps / v8 / src / compiler.cc
old mode 100644 (file)
new mode 100755 (executable)
index aecdfb9..901f218
@@ -1,4 +1,4 @@
-// Copyright 2009 the V8 project authors. All rights reserved.
+// Copyright 2010 the V8 project authors. All rights reserved.
 // Redistribution and use in source and binary forms, with or without
 // modification, are permitted provided that the following conditions are
 // met:
 #include "codegen-inl.h"
 #include "compilation-cache.h"
 #include "compiler.h"
+#include "data-flow.h"
 #include "debug.h"
+#include "fast-codegen.h"
+#include "flow-graph.h"
+#include "full-codegen.h"
+#include "liveedit.h"
 #include "oprofile-agent.h"
 #include "rewriter.h"
 #include "scopes.h"
-#include "usage-analyzer.h"
 
 namespace v8 {
 namespace internal {
 
-static Handle<Code> MakeCode(FunctionLiteral* literal,
-                             Handle<Script> script,
-                             Handle<Context> context,
-                             bool is_eval) {
-  ASSERT(literal != NULL);
 
+static Handle<Code> MakeCode(Handle<Context> context, CompilationInfo* info) {
+  FunctionLiteral* function = info->function();
+  ASSERT(function != NULL);
   // Rewrite the AST by introducing .result assignments where needed.
-  if (!Rewriter::Process(literal) || !AnalyzeVariableUsage(literal)) {
+  if (!Rewriter::Process(function)) {
     // Signal a stack overflow by returning a null handle.  The stack
     // overflow exception will be thrown by the caller.
     return Handle<Code>::null();
@@ -58,7 +60,7 @@ static Handle<Code> MakeCode(FunctionLiteral* literal,
     // the top scope only contains the single lazily compiled function,
     // so this doesn't re-allocate variables repeatedly.
     HistogramTimerScope timer(&Counters::variable_allocation);
-    Scope* top = literal->scope();
+    Scope* top = info->scope();
     while (top->outer_scope() != NULL) top = top->outer_scope();
     top->AllocateVariables(context);
   }
@@ -67,50 +69,99 @@ static Handle<Code> MakeCode(FunctionLiteral* literal,
   if (Bootstrapper::IsActive() ?
       FLAG_print_builtin_scopes :
       FLAG_print_scopes) {
-    literal->scope()->Print();
+    info->scope()->Print();
   }
 #endif
 
   // Optimize the AST.
-  if (!Rewriter::Optimize(literal)) {
+  if (!Rewriter::Optimize(function)) {
     // Signal a stack overflow by returning a null handle.  The stack
     // overflow exception will be thrown by the caller.
     return Handle<Code>::null();
   }
 
-  // Generate code and return it.
-  Handle<Code> result = CodeGenerator::MakeCode(literal, script, is_eval);
-  return result;
+  if (function->scope()->num_parameters() > 0 ||
+      function->scope()->num_stack_slots()) {
+    AssignedVariablesAnalyzer ava(function);
+    ava.Analyze();
+    if (ava.HasStackOverflow()) {
+      return Handle<Code>::null();
+    }
+  }
+
+  if (FLAG_use_flow_graph) {
+    FlowGraphBuilder builder;
+    FlowGraph* graph = builder.Build(function);
+    USE(graph);
+
+#ifdef DEBUG
+    if (FLAG_print_graph_text && !builder.HasStackOverflow()) {
+      graph->PrintAsText(function->name());
+    }
+#endif
+  }
+
+  // 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);
+
+  Handle<SharedFunctionInfo> shared = info->shared_info();
+  bool is_run_once = (shared.is_null())
+      ? info->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(function);
+    if (checker.has_supported_syntax()) {
+      return FullCodeGenerator::MakeCode(info);
+    }
+  } else if (FLAG_always_fast_compiler ||
+             (FLAG_fast_compiler && !is_run_once)) {
+    FastCodeGenSyntaxChecker checker;
+    checker.Check(info);
+    if (checker.has_supported_syntax()) {
+      return FastCodeGenerator::MakeCode(info);
+    }
+  }
+
+  return CodeGenerator::MakeCode(info);
 }
 
 
-static bool IsValidJSON(FunctionLiteral* lit) {
-  if (!lit->body()->length() == 1)
-    return false;
-  Statement* stmt = lit->body()->at(0);
-  if (stmt->AsExpressionStatement() == NULL)
-    return false;
-  Expression* expr = stmt->AsExpressionStatement()->expression();
-  return expr->IsValidJSON();
+#ifdef ENABLE_DEBUGGER_SUPPORT
+Handle<Code> MakeCodeForLiveEdit(CompilationInfo* info) {
+  Handle<Context> context = Handle<Context>::null();
+  return MakeCode(context, info);
 }
+#endif
 
 
-static Handle<JSFunction> MakeFunction(bool is_global,
-                                       bool is_eval,
-                                       bool is_json,
-                                       Handle<Script> script,
-                                       Handle<Context> context,
-                                       v8::Extension* extension,
-                                       ScriptDataImpl* pre_data) {
+static Handle<SharedFunctionInfo> MakeFunctionInfo(bool is_global,
+    bool is_eval,
+    Compiler::ValidationState validate,
+    Handle<Script> script,
+    Handle<Context> context,
+    v8::Extension* extension,
+    ScriptDataImpl* pre_data) {
   CompilationZoneScope zone_scope(DELETE_ON_EXIT);
 
-  // Make sure we have an initial stack limit.
-  StackGuard guard;
   PostponeInterruptsScope postpone;
 
   ASSERT(!i::Top::global_context().is_null());
   script->set_context_data((*i::Top::global_context())->data());
 
+  bool is_json = (validate == Compiler::VALIDATE_JSON);
 #ifdef ENABLE_DEBUGGER_SUPPORT
   if (is_eval || is_json) {
     script->set_compilation_type(
@@ -119,10 +170,14 @@ static Handle<JSFunction> MakeFunction(bool is_global,
     // For eval scripts add information on the function from which eval was
     // called.
     if (is_eval) {
-      JavaScriptFrameIterator it;
-      script->set_eval_from_function(it.frame()->function());
-      int offset = it.frame()->pc() - it.frame()->code()->instruction_start();
-      script->set_eval_from_instructions_offset(Smi::FromInt(offset));
+      StackTraceFrameIterator it;
+      if (!it.done()) {
+        script->set_eval_from_shared(
+            JSFunction::cast(it.frame()->function())->shared());
+        int offset = static_cast<int>(
+            it.frame()->pc() - it.frame()->code()->instruction_start());
+        script->set_eval_from_instructions_offset(Smi::FromInt(offset));
+      }
     }
   }
 
@@ -134,25 +189,15 @@ static Handle<JSFunction> MakeFunction(bool is_global,
   ASSERT(is_eval || is_global);
 
   // Build AST.
-  FunctionLiteral* lit = MakeAST(is_global, script, extension, pre_data);
+  FunctionLiteral* lit =
+      MakeAST(is_global, script, extension, pre_data, is_json);
+
+  LiveEditFunctionTracker live_edit_tracker(lit);
 
   // Check for parse errors.
   if (lit == NULL) {
     ASSERT(Top::has_pending_exception());
-    return Handle<JSFunction>::null();
-  }
-
-  // When parsing JSON we do an ordinary parse and then afterwards
-  // check the AST to ensure it was well-formed.  If not we give a
-  // syntax error.
-  if (is_json && !IsValidJSON(lit)) {
-    HandleScope scope;
-    Handle<JSArray> args = Factory::NewJSArray(1);
-    Handle<Object> source(script->source());
-    SetElement(args, 0, source);
-    Handle<Object> result = Factory::NewSyntaxError("invalid_json", args);
-    Top::Throw(*result, NULL);
-    return Handle<JSFunction>::null();
+    return Handle<SharedFunctionInfo>::null();
   }
 
   // Measure how long it takes to do the compilation; only take the
@@ -164,71 +209,69 @@ static Handle<JSFunction> MakeFunction(bool is_global,
   HistogramTimerScope timer(rate);
 
   // Compile the code.
-  Handle<Code> code = MakeCode(lit, script, context, is_eval);
+  CompilationInfo info(lit, script, is_eval);
+  Handle<Code> code = MakeCode(context, &info);
 
   // Check for stack-overflow exceptions.
   if (code.is_null()) {
     Top::StackOverflow();
-    return Handle<JSFunction>::null();
+    return Handle<SharedFunctionInfo>::null();
   }
 
-#if defined ENABLE_LOGGING_AND_PROFILING || defined ENABLE_OPROFILE_AGENT
-  // Log the code generation for the script. Check explicit whether logging is
-  // to avoid allocating when not required.
-  if (Logger::is_logging() || OProfileAgent::is_enabled()) {
-    if (script->name()->IsString()) {
-      SmartPointer<char> data =
-          String::cast(script->name())->ToCString(DISALLOW_NULLS);
-      LOG(CodeCreateEvent(is_eval ? Logger::EVAL_TAG : Logger::SCRIPT_TAG,
-                          *code, *data));
-      OProfileAgent::CreateNativeCodeRegion(*data,
-                                            code->instruction_start(),
-                                            code->instruction_size());
-    } else {
-      LOG(CodeCreateEvent(is_eval ? Logger::EVAL_TAG : Logger::SCRIPT_TAG,
-                          *code, ""));
-      OProfileAgent::CreateNativeCodeRegion(is_eval ? "Eval" : "Script",
-                                            code->instruction_start(),
-                                            code->instruction_size());
-    }
+  if (script->name()->IsString()) {
+    PROFILE(CodeCreateEvent(
+        is_eval ? Logger::EVAL_TAG :
+            Logger::ToNativeByScript(Logger::SCRIPT_TAG, *script),
+        *code, String::cast(script->name())));
+    OPROFILE(CreateNativeCodeRegion(String::cast(script->name()),
+                                    code->instruction_start(),
+                                    code->instruction_size()));
+  } else {
+    PROFILE(CodeCreateEvent(
+        is_eval ? Logger::EVAL_TAG :
+            Logger::ToNativeByScript(Logger::SCRIPT_TAG, *script),
+        *code, ""));
+    OPROFILE(CreateNativeCodeRegion(is_eval ? "Eval" : "Script",
+                                    code->instruction_start(),
+                                    code->instruction_size()));
   }
-#endif
 
   // Allocate function.
-  Handle<JSFunction> fun =
-      Factory::NewFunctionBoilerplate(lit->name(),
-                                      lit->materialized_literal_count(),
-                                      lit->contains_array_literal(),
-                                      code);
-
-  CodeGenerator::SetFunctionInfo(fun, lit->scope()->num_parameters(),
-                                 RelocInfo::kNoPosition,
-                                 lit->start_position(), lit->end_position(),
-                                 lit->is_expression(), true, script,
-                                 lit->inferred_name());
+  Handle<SharedFunctionInfo> result =
+      Factory::NewSharedFunctionInfo(lit->name(),
+                                     lit->materialized_literal_count(),
+                                     code);
+
+  ASSERT_EQ(RelocInfo::kNoPosition, lit->function_token_position());
+  Compiler::SetFunctionInfo(result, lit, true, script);
 
   // Hint to the runtime system used when allocating space for initial
   // property space by setting the expected number of properties for
   // the instances of the function.
-  SetExpectedNofPropertiesFromEstimate(fun, lit->expected_property_count());
+  SetExpectedNofPropertiesFromEstimate(result, lit->expected_property_count());
 
 #ifdef ENABLE_DEBUGGER_SUPPORT
   // Notify debugger
-  Debugger::OnAfterCompile(script, fun);
+  Debugger::OnAfterCompile(script, Debugger::NO_AFTER_COMPILE_FLAGS);
 #endif
 
-  return fun;
+  live_edit_tracker.RecordFunctionInfo(result, lit);
+
+  return result;
 }
 
 
 static StaticResource<SafeStringInputBuffer> safe_string_input_buffer;
 
 
-Handle<JSFunction> Compiler::Compile(Handle<String> source,
-                                     Handle<Object> script_name,
-                                     int line_offset, int column_offset,
-                                     v8::Extension* extension,
-                                     ScriptDataImpl* input_pre_data) {
+Handle<SharedFunctionInfo> Compiler::Compile(Handle<String> source,
+                                             Handle<Object> script_name,
+                                             int line_offset,
+                                             int column_offset,
+                                             v8::Extension* extension,
+                                             ScriptDataImpl* input_pre_data,
+                                             Handle<Object> script_data,
+                                             NativesFlag natives) {
   int source_length = source->length();
   Counters::total_load_size.Increment(source_length);
   Counters::total_compile_size.Increment(source_length);
@@ -237,7 +280,7 @@ Handle<JSFunction> Compiler::Compile(Handle<String> source,
   VMState state(COMPILER);
 
   // Do a lookup in the compilation cache but not for extensions.
-  Handle<JSFunction> result;
+  Handle<SharedFunctionInfo> result;
   if (extension == NULL) {
     result = CompilationCache::LookupScript(source,
                                             script_name,
@@ -251,25 +294,31 @@ Handle<JSFunction> Compiler::Compile(Handle<String> source,
     if (pre_data == NULL && source_length >= FLAG_min_preparse_length) {
       Access<SafeStringInputBuffer> buf(&safe_string_input_buffer);
       buf->Reset(source.location());
-      pre_data = PreParse(buf.value(), extension);
+      pre_data = PreParse(source, buf.value(), extension);
     }
 
     // Create a script object describing the script to be compiled.
     Handle<Script> script = Factory::NewScript(source);
+    if (natives == NATIVES_CODE) {
+      script->set_type(Smi::FromInt(Script::TYPE_NATIVE));
+    }
     if (!script_name.is_null()) {
       script->set_name(*script_name);
       script->set_line_offset(Smi::FromInt(line_offset));
       script->set_column_offset(Smi::FromInt(column_offset));
     }
 
+    script->set_data(script_data.is_null() ? Heap::undefined_value()
+                                           : *script_data);
+
     // Compile the function and add it to the cache.
-    result = MakeFunction(true,
-                          false,
-                          false,
-                          script,
-                          Handle<Context>::null(),
-                          extension,
-                          pre_data);
+    result = MakeFunctionInfo(true,
+                              false,
+                              DONT_VALIDATE_JSON,
+                              script,
+                              Handle<Context>::null(),
+                              extension,
+                              pre_data);
     if (extension == NULL && !result.is_null()) {
       CompilationCache::PutScript(source, result);
     }
@@ -285,10 +334,14 @@ Handle<JSFunction> Compiler::Compile(Handle<String> source,
 }
 
 
-Handle<JSFunction> Compiler::CompileEval(Handle<String> source,
-                                         Handle<Context> context,
-                                         bool is_global,
-                                         bool is_json) {
+Handle<SharedFunctionInfo> Compiler::CompileEval(Handle<String> source,
+                                                 Handle<Context> context,
+                                                 bool is_global,
+                                                 ValidationState validate) {
+  // Note that if validation is required then no path through this
+  // function is allowed to return a value without validating that
+  // the input is legal json.
+
   int source_length = source->length();
   Counters::total_eval_size.Increment(source_length);
   Counters::total_compile_size.Increment(source_length);
@@ -297,20 +350,26 @@ Handle<JSFunction> Compiler::CompileEval(Handle<String> source,
   VMState state(COMPILER);
 
   // Do a lookup in the compilation cache; if the entry is not there,
-  // invoke the compiler and add the result to the cache.
-  Handle<JSFunction> result =
-      CompilationCache::LookupEval(source, context, is_global);
+  // invoke the compiler and add the result to the cache.  If we're
+  // evaluating json we bypass the cache since we can't be sure a
+  // potential value in the cache has been validated.
+  Handle<SharedFunctionInfo> result;
+  if (validate == DONT_VALIDATE_JSON)
+    result = CompilationCache::LookupEval(source, context, is_global);
+
   if (result.is_null()) {
     // Create a script object describing the script to be compiled.
     Handle<Script> script = Factory::NewScript(source);
-    result = MakeFunction(is_global,
-                          true,
-                          is_json,
-                          script,
-                          context,
-                          NULL,
-                          NULL);
-    if (!result.is_null()) {
+    result = MakeFunctionInfo(is_global,
+                              true,
+                              validate,
+                              script,
+                              context,
+                              NULL,
+                              NULL);
+    if (!result.is_null() && validate != VALIDATE_JSON) {
+      // For json it's unlikely that we'll ever see exactly the same
+      // string again so we don't use the compilation cache.
       CompilationCache::PutEval(source, context, is_global, result);
     }
   }
@@ -319,20 +378,17 @@ Handle<JSFunction> Compiler::CompileEval(Handle<String> source,
 }
 
 
-bool Compiler::CompileLazy(Handle<SharedFunctionInfo> shared,
-                           int loop_nesting) {
+bool Compiler::CompileLazy(CompilationInfo* info) {
   CompilationZoneScope zone_scope(DELETE_ON_EXIT);
 
   // The VM is in the COMPILER state until exiting this function.
   VMState state(COMPILER);
 
-  // Make sure we have an initial stack limit.
-  StackGuard guard;
   PostponeInterruptsScope postpone;
 
   // Compute name, source code and script data.
+  Handle<SharedFunctionInfo> shared = info->shared_info();
   Handle<String> name(String::cast(shared->name()));
-  Handle<Script> script(Script::cast(shared->script()));
 
   int start_position = shared->start_position();
   int end_position = shared->end_position();
@@ -341,7 +397,8 @@ bool Compiler::CompileLazy(Handle<SharedFunctionInfo> shared,
 
   // Generate the AST for the lazily compiled function. The AST may be
   // NULL in case of parser stack overflow.
-  FunctionLiteral* lit = MakeLazyAST(script, name,
+  FunctionLiteral* lit = MakeLazyAST(info->script(),
+                                     name,
                                      start_position,
                                      end_position,
                                      is_expression);
@@ -351,9 +408,7 @@ bool Compiler::CompileLazy(Handle<SharedFunctionInfo> shared,
     ASSERT(Top::has_pending_exception());
     return false;
   }
-
-  // Update the loop nesting in the function literal.
-  lit->set_loop_nesting(loop_nesting);
+  info->set_function(lit);
 
   // Measure how long it takes to do the lazy compilation; only take
   // the rest of the function into account to avoid overlap with the
@@ -361,7 +416,7 @@ bool Compiler::CompileLazy(Handle<SharedFunctionInfo> shared,
   HistogramTimerScope timer(&Counters::compile_lazy);
 
   // Compile the code.
-  Handle<Code> code = MakeCode(lit, script, Handle<Context>::null(), false);
+  Handle<Code> code = MakeCode(Handle<Context>::null(), info);
 
   // Check for stack-overflow exception.
   if (code.is_null()) {
@@ -369,30 +424,12 @@ bool Compiler::CompileLazy(Handle<SharedFunctionInfo> shared,
     return false;
   }
 
-#if defined ENABLE_LOGGING_AND_PROFILING || defined ENABLE_OPROFILE_AGENT
-  // Log the code generation. If source information is available include script
-  // name and line number. Check explicit whether logging is enabled as finding
-  // the line number is not for free.
-  if (Logger::is_logging() || OProfileAgent::is_enabled()) {
-    Handle<String> func_name(name->length() > 0 ?
-                             *name : shared->inferred_name());
-    if (script->name()->IsString()) {
-      int line_num = GetScriptLineNumber(script, start_position) + 1;
-      LOG(CodeCreateEvent(Logger::LAZY_COMPILE_TAG, *code, *func_name,
-                          String::cast(script->name()), line_num));
-      OProfileAgent::CreateNativeCodeRegion(*func_name,
-                                            String::cast(script->name()),
-                                            line_num,
-                                            code->instruction_start(),
-                                            code->instruction_size());
-    } else {
-      LOG(CodeCreateEvent(Logger::LAZY_COMPILE_TAG, *code, *func_name));
-      OProfileAgent::CreateNativeCodeRegion(*func_name,
-                                            code->instruction_start(),
-                                            code->instruction_size());
-    }
-  }
-#endif
+  RecordFunctionCompilation(Logger::LAZY_COMPILE_TAG,
+                            name,
+                            Handle<String>(shared->inferred_name()),
+                            start_position,
+                            info->script(),
+                            code);
 
   // Update the shared function info with the compiled code.
   shared->set_code(*code);
@@ -400,10 +437,187 @@ bool Compiler::CompileLazy(Handle<SharedFunctionInfo> shared,
   // Set the expected number of properties for instances.
   SetExpectedNofPropertiesFromEstimate(shared, lit->expected_property_count());
 
+  // Set the optimication hints after performing lazy compilation, as these are
+  // not set when the function is set up as a lazily compiled function.
+  shared->SetThisPropertyAssignmentsInfo(
+      lit->has_only_simple_this_property_assignments(),
+      *lit->this_property_assignments());
+
   // Check the function has compiled code.
   ASSERT(shared->is_compiled());
   return true;
 }
 
 
+Handle<SharedFunctionInfo> Compiler::BuildFunctionInfo(FunctionLiteral* literal,
+                                                       Handle<Script> script,
+                                                       AstVisitor* caller) {
+  LiveEditFunctionTracker live_edit_tracker(literal);
+#ifdef DEBUG
+  // We should not try to compile the same function literal more than
+  // once.
+  literal->mark_as_compiled();
+#endif
+
+  // Determine if the function can be lazily compiled. This is
+  // necessary to allow some of our builtin JS files to be lazily
+  // compiled. These builtins cannot be handled lazily by the parser,
+  // since we have to know if a function uses the special natives
+  // syntax, which is something the parser records.
+  bool allow_lazy = literal->AllowsLazyCompilation() &&
+      !LiveEditFunctionTracker::IsActive();
+
+  // Generate code
+  Handle<Code> code;
+  if (FLAG_lazy && allow_lazy) {
+    code = ComputeLazyCompile(literal->num_parameters());
+  } else {
+    // The bodies of function literals have not yet been visited by
+    // the AST optimizer/analyzer.
+    if (!Rewriter::Optimize(literal)) {
+      return Handle<SharedFunctionInfo>::null();
+    }
+
+    if (literal->scope()->num_parameters() > 0 ||
+        literal->scope()->num_stack_slots()) {
+      AssignedVariablesAnalyzer ava(literal);
+      ava.Analyze();
+      if (ava.HasStackOverflow()) {
+        return Handle<SharedFunctionInfo>::null();
+      }
+    }
+
+    if (FLAG_use_flow_graph) {
+      FlowGraphBuilder builder;
+      FlowGraph* graph = builder.Build(literal);
+      USE(graph);
+
+#ifdef DEBUG
+      if (FLAG_print_graph_text && !builder.HasStackOverflow()) {
+        graph->PrintAsText(literal->name());
+      }
+#endif
+    }
+
+    // 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.
+    CompilationInfo info(literal, script, false);
+
+    CHECK(!FLAG_always_full_compiler || !FLAG_always_fast_compiler);
+    bool is_run_once = literal->try_full_codegen();
+    bool is_compiled = false;
+    if (FLAG_always_full_compiler || (FLAG_full_compiler && is_run_once)) {
+      FullCodeGenSyntaxChecker checker;
+      checker.Check(literal);
+      if (checker.has_supported_syntax()) {
+        code = FullCodeGenerator::MakeCode(&info);
+        is_compiled = true;
+      }
+    } else if (FLAG_always_fast_compiler ||
+               (FLAG_fast_compiler && !is_run_once)) {
+      // Since we are not lazily compiling we do not have a receiver to
+      // specialize for.
+      FastCodeGenSyntaxChecker checker;
+      checker.Check(&info);
+      if (checker.has_supported_syntax()) {
+        code = FastCodeGenerator::MakeCode(&info);
+        is_compiled = true;
+      }
+    }
+
+    if (!is_compiled) {
+      // We fall back to the classic V8 code generator.
+      code = CodeGenerator::MakeCode(&info);
+    }
+
+    // Check for stack-overflow exception.
+    if (code.is_null()) {
+      caller->SetStackOverflow();
+      return Handle<SharedFunctionInfo>::null();
+    }
+
+    // Function compilation complete.
+    RecordFunctionCompilation(Logger::FUNCTION_TAG,
+                              literal->name(),
+                              literal->inferred_name(),
+                              literal->start_position(),
+                              script,
+                              code);
+  }
+
+  // Create a shared function info object.
+  Handle<SharedFunctionInfo> result =
+      Factory::NewSharedFunctionInfo(literal->name(),
+                                     literal->materialized_literal_count(),
+                                     code);
+  SetFunctionInfo(result, literal, false, script);
+
+  // Set the expected number of properties for instances and return
+  // the resulting function.
+  SetExpectedNofPropertiesFromEstimate(result,
+                                       literal->expected_property_count());
+  live_edit_tracker.RecordFunctionInfo(result, literal);
+  return result;
+}
+
+
+// Sets the function info on a function.
+// The start_position points to the first '(' character after the function name
+// in the full script source. When counting characters in the script source the
+// the first character is number 0 (not 1).
+void Compiler::SetFunctionInfo(Handle<SharedFunctionInfo> function_info,
+                               FunctionLiteral* lit,
+                               bool is_toplevel,
+                               Handle<Script> script) {
+  function_info->set_length(lit->num_parameters());
+  function_info->set_formal_parameter_count(lit->num_parameters());
+  function_info->set_script(*script);
+  function_info->set_function_token_position(lit->function_token_position());
+  function_info->set_start_position(lit->start_position());
+  function_info->set_end_position(lit->end_position());
+  function_info->set_is_expression(lit->is_expression());
+  function_info->set_is_toplevel(is_toplevel);
+  function_info->set_inferred_name(*lit->inferred_name());
+  function_info->SetThisPropertyAssignmentsInfo(
+      lit->has_only_simple_this_property_assignments(),
+      *lit->this_property_assignments());
+  function_info->set_try_full_codegen(lit->try_full_codegen());
+}
+
+
+void Compiler::RecordFunctionCompilation(Logger::LogEventsAndTags tag,
+                                         Handle<String> name,
+                                         Handle<String> inferred_name,
+                                         int start_position,
+                                         Handle<Script> script,
+                                         Handle<Code> code) {
+  // Log the code generation. If source information is available
+  // include script name and line number. Check explicitly whether
+  // logging is enabled as finding the line number is not free.
+  if (Logger::is_logging()
+      || OProfileAgent::is_enabled()
+      || CpuProfiler::is_profiling()) {
+    Handle<String> func_name(name->length() > 0 ? *name : *inferred_name);
+    if (script->name()->IsString()) {
+      int line_num = GetScriptLineNumber(script, start_position) + 1;
+      USE(line_num);
+      PROFILE(CodeCreateEvent(Logger::ToNativeByScript(tag, *script),
+                              *code, *func_name,
+                              String::cast(script->name()), line_num));
+      OPROFILE(CreateNativeCodeRegion(*func_name,
+                                      String::cast(script->name()),
+                                      line_num,
+                                      code->instruction_start(),
+                                      code->instruction_size()));
+    } else {
+      PROFILE(CodeCreateEvent(Logger::ToNativeByScript(tag, *script),
+                              *code, *func_name));
+      OPROFILE(CreateNativeCodeRegion(*func_name,
+                                      code->instruction_start(),
+                                      code->instruction_size()));
+    }
+  }
+}
+
 } }  // namespace v8::internal