Home | History | Annotate | Download | only in src
      1 // Copyright 2011 the V8 project authors. All rights reserved.
      2 // Redistribution and use in source and binary forms, with or without
      3 // modification, are permitted provided that the following conditions are
      4 // met:
      5 //
      6 //     * Redistributions of source code must retain the above copyright
      7 //       notice, this list of conditions and the following disclaimer.
      8 //     * Redistributions in binary form must reproduce the above
      9 //       copyright notice, this list of conditions and the following
     10 //       disclaimer in the documentation and/or other materials provided
     11 //       with the distribution.
     12 //     * Neither the name of Google Inc. nor the names of its
     13 //       contributors may be used to endorse or promote products derived
     14 //       from this software without specific prior written permission.
     15 //
     16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27 
     28 #include "v8.h"
     29 
     30 #include "compiler.h"
     31 
     32 #include "bootstrapper.h"
     33 #include "codegen.h"
     34 #include "compilation-cache.h"
     35 #include "data-flow.h"
     36 #include "debug.h"
     37 #include "full-codegen.h"
     38 #include "gdb-jit.h"
     39 #include "hydrogen.h"
     40 #include "lithium.h"
     41 #include "liveedit.h"
     42 #include "parser.h"
     43 #include "rewriter.h"
     44 #include "runtime-profiler.h"
     45 #include "scopeinfo.h"
     46 #include "scopes.h"
     47 #include "vm-state-inl.h"
     48 
     49 namespace v8 {
     50 namespace internal {
     51 
     52 
     53 CompilationInfo::CompilationInfo(Handle<Script> script)
     54     : isolate_(script->GetIsolate()),
     55       flags_(0),
     56       function_(NULL),
     57       scope_(NULL),
     58       script_(script),
     59       extension_(NULL),
     60       pre_parse_data_(NULL),
     61       supports_deoptimization_(false),
     62       osr_ast_id_(AstNode::kNoNumber) {
     63   Initialize(NONOPT);
     64 }
     65 
     66 
     67 CompilationInfo::CompilationInfo(Handle<SharedFunctionInfo> shared_info)
     68     : isolate_(shared_info->GetIsolate()),
     69       flags_(IsLazy::encode(true)),
     70       function_(NULL),
     71       scope_(NULL),
     72       shared_info_(shared_info),
     73       script_(Handle<Script>(Script::cast(shared_info->script()))),
     74       extension_(NULL),
     75       pre_parse_data_(NULL),
     76       supports_deoptimization_(false),
     77       osr_ast_id_(AstNode::kNoNumber) {
     78   Initialize(BASE);
     79 }
     80 
     81 
     82 CompilationInfo::CompilationInfo(Handle<JSFunction> closure)
     83     : isolate_(closure->GetIsolate()),
     84       flags_(IsLazy::encode(true)),
     85       function_(NULL),
     86       scope_(NULL),
     87       closure_(closure),
     88       shared_info_(Handle<SharedFunctionInfo>(closure->shared())),
     89       script_(Handle<Script>(Script::cast(shared_info_->script()))),
     90       extension_(NULL),
     91       pre_parse_data_(NULL),
     92       supports_deoptimization_(false),
     93       osr_ast_id_(AstNode::kNoNumber) {
     94   Initialize(BASE);
     95 }
     96 
     97 
     98 void CompilationInfo::DisableOptimization() {
     99   if (FLAG_optimize_closures) {
    100     // If we allow closures optimizations and it's an optimizable closure
    101     // mark it correspondingly.
    102     bool is_closure = closure_.is_null() && !scope_->HasTrivialOuterContext();
    103     if (is_closure) {
    104       bool is_optimizable_closure =
    105           !scope_->outer_scope_calls_eval() && !scope_->inside_with();
    106       if (is_optimizable_closure) {
    107         SetMode(BASE);
    108         return;
    109       }
    110     }
    111   }
    112 
    113   SetMode(NONOPT);
    114 }
    115 
    116 
    117 // Determine whether to use the full compiler for all code. If the flag
    118 // --always-full-compiler is specified this is the case. For the virtual frame
    119 // based compiler the full compiler is also used if a debugger is connected, as
    120 // the code from the full compiler supports mode precise break points. For the
    121 // crankshaft adaptive compiler debugging the optimized code is not possible at
    122 // all. However crankshaft support recompilation of functions, so in this case
    123 // the full compiler need not be be used if a debugger is attached, but only if
    124 // break points has actually been set.
    125 static bool AlwaysFullCompiler() {
    126 #ifdef ENABLE_DEBUGGER_SUPPORT
    127   Isolate* isolate = Isolate::Current();
    128   if (V8::UseCrankshaft()) {
    129     return FLAG_always_full_compiler || isolate->debug()->has_break_points();
    130   } else {
    131     return FLAG_always_full_compiler || isolate->debugger()->IsDebuggerActive();
    132   }
    133 #else
    134   return FLAG_always_full_compiler;
    135 #endif
    136 }
    137 
    138 
    139 static void FinishOptimization(Handle<JSFunction> function, int64_t start) {
    140   int opt_count = function->shared()->opt_count();
    141   function->shared()->set_opt_count(opt_count + 1);
    142   double ms = static_cast<double>(OS::Ticks() - start) / 1000;
    143   if (FLAG_trace_opt) {
    144     PrintF("[optimizing: ");
    145     function->PrintName();
    146     PrintF(" / %" V8PRIxPTR, reinterpret_cast<intptr_t>(*function));
    147     PrintF(" - took %0.3f ms]\n", ms);
    148   }
    149   if (FLAG_trace_opt_stats) {
    150     static double compilation_time = 0.0;
    151     static int compiled_functions = 0;
    152     static int code_size = 0;
    153 
    154     compilation_time += ms;
    155     compiled_functions++;
    156     code_size += function->shared()->SourceSize();
    157     PrintF("Compiled: %d functions with %d byte source size in %fms.\n",
    158            compiled_functions,
    159            code_size,
    160            compilation_time);
    161   }
    162 }
    163 
    164 
    165 static void AbortAndDisable(CompilationInfo* info) {
    166   // Disable optimization for the shared function info and mark the
    167   // code as non-optimizable. The marker on the shared function info
    168   // is there because we flush non-optimized code thereby loosing the
    169   // non-optimizable information for the code. When the code is
    170   // regenerated and set on the shared function info it is marked as
    171   // non-optimizable if optimization is disabled for the shared
    172   // function info.
    173   Handle<SharedFunctionInfo> shared = info->shared_info();
    174   shared->set_optimization_disabled(true);
    175   Handle<Code> code = Handle<Code>(shared->code());
    176   ASSERT(code->kind() == Code::FUNCTION);
    177   code->set_optimizable(false);
    178   info->SetCode(code);
    179   Isolate* isolate = code->GetIsolate();
    180   isolate->compilation_cache()->MarkForLazyOptimizing(info->closure());
    181   if (FLAG_trace_opt) {
    182     PrintF("[disabled optimization for: ");
    183     info->closure()->PrintName();
    184     PrintF(" / %" V8PRIxPTR "]\n",
    185            reinterpret_cast<intptr_t>(*info->closure()));
    186   }
    187 }
    188 
    189 
    190 static bool MakeCrankshaftCode(CompilationInfo* info) {
    191   // Test if we can optimize this function when asked to. We can only
    192   // do this after the scopes are computed.
    193   if (!info->AllowOptimize()) info->DisableOptimization();
    194 
    195   // In case we are not optimizing simply return the code from
    196   // the full code generator.
    197   if (!info->IsOptimizing()) {
    198     return FullCodeGenerator::MakeCode(info);
    199   }
    200 
    201   // We should never arrive here if there is not code object on the
    202   // shared function object.
    203   Handle<Code> code(info->shared_info()->code());
    204   ASSERT(code->kind() == Code::FUNCTION);
    205 
    206   // We should never arrive here if optimization has been disabled on the
    207   // shared function info.
    208   ASSERT(!info->shared_info()->optimization_disabled());
    209 
    210   // Fall back to using the full code generator if it's not possible
    211   // to use the Hydrogen-based optimizing compiler. We already have
    212   // generated code for this from the shared function object.
    213   if (AlwaysFullCompiler() || !FLAG_use_hydrogen) {
    214     info->SetCode(code);
    215     return true;
    216   }
    217 
    218   // Limit the number of times we re-compile a functions with
    219   // the optimizing compiler.
    220   const int kMaxOptCount =
    221       FLAG_deopt_every_n_times == 0 ? Compiler::kDefaultMaxOptCount : 1000;
    222   if (info->shared_info()->opt_count() > kMaxOptCount) {
    223     AbortAndDisable(info);
    224     // True indicates the compilation pipeline is still going, not
    225     // necessarily that we optimized the code.
    226     return true;
    227   }
    228 
    229   // Due to an encoding limit on LUnallocated operands in the Lithium
    230   // language, we cannot optimize functions with too many formal parameters
    231   // or perform on-stack replacement for function with too many
    232   // stack-allocated local variables.
    233   //
    234   // The encoding is as a signed value, with parameters and receiver using
    235   // the negative indices and locals the non-negative ones.
    236   const int parameter_limit = -LUnallocated::kMinFixedIndex;
    237   const int locals_limit = LUnallocated::kMaxFixedIndex;
    238   Scope* scope = info->scope();
    239   if ((scope->num_parameters() + 1) > parameter_limit ||
    240       (info->osr_ast_id() != AstNode::kNoNumber &&
    241        scope->num_parameters() + 1 + scope->num_stack_slots() > locals_limit)) {
    242     AbortAndDisable(info);
    243     // True indicates the compilation pipeline is still going, not
    244     // necessarily that we optimized the code.
    245     return true;
    246   }
    247 
    248   // Take --hydrogen-filter into account.
    249   Vector<const char> filter = CStrVector(FLAG_hydrogen_filter);
    250   Handle<String> name = info->function()->debug_name();
    251   bool match = filter.is_empty() || name->IsEqualTo(filter);
    252   if (!match) {
    253     info->SetCode(code);
    254     return true;
    255   }
    256 
    257   // Recompile the unoptimized version of the code if the current version
    258   // doesn't have deoptimization support. Alternatively, we may decide to
    259   // run the full code generator to get a baseline for the compile-time
    260   // performance of the hydrogen-based compiler.
    261   int64_t start = OS::Ticks();
    262   bool should_recompile = !info->shared_info()->has_deoptimization_support();
    263   if (should_recompile || FLAG_hydrogen_stats) {
    264     HPhase phase(HPhase::kFullCodeGen);
    265     CompilationInfo unoptimized(info->shared_info());
    266     // Note that we use the same AST that we will use for generating the
    267     // optimized code.
    268     unoptimized.SetFunction(info->function());
    269     unoptimized.SetScope(info->scope());
    270     if (should_recompile) unoptimized.EnableDeoptimizationSupport();
    271     bool succeeded = FullCodeGenerator::MakeCode(&unoptimized);
    272     if (should_recompile) {
    273       if (!succeeded) return false;
    274       Handle<SharedFunctionInfo> shared = info->shared_info();
    275       shared->EnableDeoptimizationSupport(*unoptimized.code());
    276       // The existing unoptimized code was replaced with the new one.
    277       Compiler::RecordFunctionCompilation(
    278           Logger::LAZY_COMPILE_TAG, &unoptimized, shared);
    279     }
    280   }
    281 
    282   // Check that the unoptimized, shared code is ready for
    283   // optimizations.  When using the always_opt flag we disregard the
    284   // optimizable marker in the code object and optimize anyway. This
    285   // is safe as long as the unoptimized code has deoptimization
    286   // support.
    287   ASSERT(FLAG_always_opt || code->optimizable());
    288   ASSERT(info->shared_info()->has_deoptimization_support());
    289 
    290   if (FLAG_trace_hydrogen) {
    291     PrintF("-----------------------------------------------------------\n");
    292     PrintF("Compiling method %s using hydrogen\n", *name->ToCString());
    293     HTracer::Instance()->TraceCompilation(info->function());
    294   }
    295 
    296   Handle<Context> global_context(info->closure()->context()->global_context());
    297   TypeFeedbackOracle oracle(code, global_context);
    298   HGraphBuilder builder(info, &oracle);
    299   HPhase phase(HPhase::kTotal);
    300   HGraph* graph = builder.CreateGraph();
    301   if (info->isolate()->has_pending_exception()) {
    302     info->SetCode(Handle<Code>::null());
    303     return false;
    304   }
    305 
    306   if (graph != NULL && FLAG_build_lithium) {
    307     Handle<Code> optimized_code = graph->Compile(info);
    308     if (!optimized_code.is_null()) {
    309       info->SetCode(optimized_code);
    310       FinishOptimization(info->closure(), start);
    311       return true;
    312     }
    313   }
    314 
    315   // Compilation with the Hydrogen compiler failed. Keep using the
    316   // shared code but mark it as unoptimizable.
    317   AbortAndDisable(info);
    318   // True indicates the compilation pipeline is still going, not necessarily
    319   // that we optimized the code.
    320   return true;
    321 }
    322 
    323 
    324 static bool MakeCode(CompilationInfo* info) {
    325   // Precondition: code has been parsed.  Postcondition: the code field in
    326   // the compilation info is set if compilation succeeded.
    327   ASSERT(info->function() != NULL);
    328 
    329   if (Rewriter::Rewrite(info) && Scope::Analyze(info)) {
    330     if (V8::UseCrankshaft()) return MakeCrankshaftCode(info);
    331     // If crankshaft is not supported fall back to full code generator
    332     // for all compilation.
    333     return FullCodeGenerator::MakeCode(info);
    334   }
    335 
    336   return false;
    337 }
    338 
    339 
    340 #ifdef ENABLE_DEBUGGER_SUPPORT
    341 bool Compiler::MakeCodeForLiveEdit(CompilationInfo* info) {
    342   // Precondition: code has been parsed.  Postcondition: the code field in
    343   // the compilation info is set if compilation succeeded.
    344   bool succeeded = MakeCode(info);
    345   if (!info->shared_info().is_null()) {
    346     Handle<SerializedScopeInfo> scope_info =
    347         SerializedScopeInfo::Create(info->scope());
    348     info->shared_info()->set_scope_info(*scope_info);
    349   }
    350   return succeeded;
    351 }
    352 #endif
    353 
    354 
    355 static Handle<SharedFunctionInfo> MakeFunctionInfo(CompilationInfo* info) {
    356   CompilationZoneScope zone_scope(DELETE_ON_EXIT);
    357 
    358   Isolate* isolate = info->isolate();
    359   PostponeInterruptsScope postpone(isolate);
    360 
    361   ASSERT(!isolate->global_context().is_null());
    362   Handle<Script> script = info->script();
    363   script->set_context_data((*isolate->global_context())->data());
    364 
    365 #ifdef ENABLE_DEBUGGER_SUPPORT
    366   if (info->is_eval()) {
    367     Script::CompilationType compilation_type = Script::COMPILATION_TYPE_EVAL;
    368     script->set_compilation_type(Smi::FromInt(compilation_type));
    369     // For eval scripts add information on the function from which eval was
    370     // called.
    371     if (info->is_eval()) {
    372       StackTraceFrameIterator it(isolate);
    373       if (!it.done()) {
    374         script->set_eval_from_shared(
    375             JSFunction::cast(it.frame()->function())->shared());
    376         Code* code = it.frame()->LookupCode();
    377         int offset = static_cast<int>(
    378             it.frame()->pc() - code->instruction_start());
    379         script->set_eval_from_instructions_offset(Smi::FromInt(offset));
    380       }
    381     }
    382   }
    383 
    384   // Notify debugger
    385   isolate->debugger()->OnBeforeCompile(script);
    386 #endif
    387 
    388   // Only allow non-global compiles for eval.
    389   ASSERT(info->is_eval() || info->is_global());
    390 
    391   if (!ParserApi::Parse(info)) return Handle<SharedFunctionInfo>::null();
    392 
    393   // Measure how long it takes to do the compilation; only take the
    394   // rest of the function into account to avoid overlap with the
    395   // parsing statistics.
    396   HistogramTimer* rate = info->is_eval()
    397       ? info->isolate()->counters()->compile_eval()
    398       : info->isolate()->counters()->compile();
    399   HistogramTimerScope timer(rate);
    400 
    401   // Compile the code.
    402   FunctionLiteral* lit = info->function();
    403   LiveEditFunctionTracker live_edit_tracker(isolate, lit);
    404   if (!MakeCode(info)) {
    405     isolate->StackOverflow();
    406     return Handle<SharedFunctionInfo>::null();
    407   }
    408 
    409   // Allocate function.
    410   ASSERT(!info->code().is_null());
    411   Handle<SharedFunctionInfo> result =
    412       isolate->factory()->NewSharedFunctionInfo(
    413           lit->name(),
    414           lit->materialized_literal_count(),
    415           info->code(),
    416           SerializedScopeInfo::Create(info->scope()));
    417 
    418   ASSERT_EQ(RelocInfo::kNoPosition, lit->function_token_position());
    419   Compiler::SetFunctionInfo(result, lit, true, script);
    420 
    421   if (script->name()->IsString()) {
    422     PROFILE(isolate, CodeCreateEvent(
    423         info->is_eval()
    424             ? Logger::EVAL_TAG
    425             : Logger::ToNativeByScript(Logger::SCRIPT_TAG, *script),
    426         *info->code(),
    427         *result,
    428         String::cast(script->name())));
    429     GDBJIT(AddCode(Handle<String>(String::cast(script->name())),
    430                    script,
    431                    info->code()));
    432   } else {
    433     PROFILE(isolate, CodeCreateEvent(
    434         info->is_eval()
    435             ? Logger::EVAL_TAG
    436             : Logger::ToNativeByScript(Logger::SCRIPT_TAG, *script),
    437         *info->code(),
    438         *result,
    439         isolate->heap()->empty_string()));
    440     GDBJIT(AddCode(Handle<String>(), script, info->code()));
    441   }
    442 
    443   // Hint to the runtime system used when allocating space for initial
    444   // property space by setting the expected number of properties for
    445   // the instances of the function.
    446   SetExpectedNofPropertiesFromEstimate(result, lit->expected_property_count());
    447 
    448 #ifdef ENABLE_DEBUGGER_SUPPORT
    449   // Notify debugger
    450   isolate->debugger()->OnAfterCompile(
    451       script, Debugger::NO_AFTER_COMPILE_FLAGS);
    452 #endif
    453 
    454   live_edit_tracker.RecordFunctionInfo(result, lit);
    455 
    456   return result;
    457 }
    458 
    459 
    460 Handle<SharedFunctionInfo> Compiler::Compile(Handle<String> source,
    461                                              Handle<Object> script_name,
    462                                              int line_offset,
    463                                              int column_offset,
    464                                              v8::Extension* extension,
    465                                              ScriptDataImpl* input_pre_data,
    466                                              Handle<Object> script_data,
    467                                              NativesFlag natives) {
    468   Isolate* isolate = source->GetIsolate();
    469   int source_length = source->length();
    470   isolate->counters()->total_load_size()->Increment(source_length);
    471   isolate->counters()->total_compile_size()->Increment(source_length);
    472 
    473   // The VM is in the COMPILER state until exiting this function.
    474   VMState state(isolate, COMPILER);
    475 
    476   CompilationCache* compilation_cache = isolate->compilation_cache();
    477 
    478   // Do a lookup in the compilation cache but not for extensions.
    479   Handle<SharedFunctionInfo> result;
    480   if (extension == NULL) {
    481     result = compilation_cache->LookupScript(source,
    482                                              script_name,
    483                                              line_offset,
    484                                              column_offset);
    485   }
    486 
    487   if (result.is_null()) {
    488     // No cache entry found. Do pre-parsing, if it makes sense, and compile
    489     // the script.
    490     // Building preparse data that is only used immediately after is only a
    491     // saving if we might skip building the AST for lazily compiled functions.
    492     // I.e., preparse data isn't relevant when the lazy flag is off, and
    493     // for small sources, odds are that there aren't many functions
    494     // that would be compiled lazily anyway, so we skip the preparse step
    495     // in that case too.
    496     ScriptDataImpl* pre_data = input_pre_data;
    497     if (pre_data == NULL
    498         && source_length >= FLAG_min_preparse_length) {
    499       if (source->IsExternalTwoByteString()) {
    500         ExternalTwoByteStringUC16CharacterStream stream(
    501             Handle<ExternalTwoByteString>::cast(source), 0, source->length());
    502         pre_data = ParserApi::PartialPreParse(&stream, extension);
    503       } else {
    504         GenericStringUC16CharacterStream stream(source, 0, source->length());
    505         pre_data = ParserApi::PartialPreParse(&stream, extension);
    506       }
    507     }
    508 
    509     // Create a script object describing the script to be compiled.
    510     Handle<Script> script = FACTORY->NewScript(source);
    511     if (natives == NATIVES_CODE) {
    512       script->set_type(Smi::FromInt(Script::TYPE_NATIVE));
    513     }
    514     if (!script_name.is_null()) {
    515       script->set_name(*script_name);
    516       script->set_line_offset(Smi::FromInt(line_offset));
    517       script->set_column_offset(Smi::FromInt(column_offset));
    518     }
    519 
    520     script->set_data(script_data.is_null() ? HEAP->undefined_value()
    521                                            : *script_data);
    522 
    523     // Compile the function and add it to the cache.
    524     CompilationInfo info(script);
    525     info.MarkAsGlobal();
    526     info.SetExtension(extension);
    527     info.SetPreParseData(pre_data);
    528     result = MakeFunctionInfo(&info);
    529     if (extension == NULL && !result.is_null()) {
    530       compilation_cache->PutScript(source, result);
    531     }
    532 
    533     // Get rid of the pre-parsing data (if necessary).
    534     if (input_pre_data == NULL && pre_data != NULL) {
    535       delete pre_data;
    536     }
    537   }
    538 
    539   if (result.is_null()) isolate->ReportPendingMessages();
    540   return result;
    541 }
    542 
    543 
    544 Handle<SharedFunctionInfo> Compiler::CompileEval(Handle<String> source,
    545                                                  Handle<Context> context,
    546                                                  bool is_global,
    547                                                  StrictModeFlag strict_mode) {
    548   Isolate* isolate = source->GetIsolate();
    549   int source_length = source->length();
    550   isolate->counters()->total_eval_size()->Increment(source_length);
    551   isolate->counters()->total_compile_size()->Increment(source_length);
    552 
    553   // The VM is in the COMPILER state until exiting this function.
    554   VMState state(isolate, COMPILER);
    555 
    556   // Do a lookup in the compilation cache; if the entry is not there, invoke
    557   // the compiler and add the result to the cache.
    558   Handle<SharedFunctionInfo> result;
    559   CompilationCache* compilation_cache = isolate->compilation_cache();
    560   result = compilation_cache->LookupEval(source,
    561                                          context,
    562                                          is_global,
    563                                          strict_mode);
    564 
    565   if (result.is_null()) {
    566     // Create a script object describing the script to be compiled.
    567     Handle<Script> script = isolate->factory()->NewScript(source);
    568     CompilationInfo info(script);
    569     info.MarkAsEval();
    570     if (is_global) info.MarkAsGlobal();
    571     if (strict_mode == kStrictMode) info.MarkAsStrictMode();
    572     info.SetCallingContext(context);
    573     result = MakeFunctionInfo(&info);
    574     if (!result.is_null()) {
    575       CompilationCache* compilation_cache = isolate->compilation_cache();
    576       // If caller is strict mode, the result must be strict as well,
    577       // but not the other way around. Consider:
    578       // eval("'use strict'; ...");
    579       ASSERT(strict_mode == kNonStrictMode || result->strict_mode());
    580       compilation_cache->PutEval(source, context, is_global, result);
    581     }
    582   }
    583 
    584   return result;
    585 }
    586 
    587 
    588 bool Compiler::CompileLazy(CompilationInfo* info) {
    589   CompilationZoneScope zone_scope(DELETE_ON_EXIT);
    590 
    591   // The VM is in the COMPILER state until exiting this function.
    592   VMState state(info->isolate(), COMPILER);
    593 
    594   Isolate* isolate = info->isolate();
    595   PostponeInterruptsScope postpone(isolate);
    596 
    597   Handle<SharedFunctionInfo> shared = info->shared_info();
    598   int compiled_size = shared->end_position() - shared->start_position();
    599   isolate->counters()->total_compile_size()->Increment(compiled_size);
    600 
    601   // Generate the AST for the lazily compiled function.
    602   if (ParserApi::Parse(info)) {
    603     // Measure how long it takes to do the lazy compilation; only take the
    604     // rest of the function into account to avoid overlap with the lazy
    605     // parsing statistics.
    606     HistogramTimerScope timer(isolate->counters()->compile_lazy());
    607 
    608     // After parsing we know function's strict mode. Remember it.
    609     if (info->function()->strict_mode()) {
    610       shared->set_strict_mode(true);
    611       info->MarkAsStrictMode();
    612     }
    613 
    614     // Compile the code.
    615     if (!MakeCode(info)) {
    616       if (!isolate->has_pending_exception()) {
    617         isolate->StackOverflow();
    618       }
    619     } else {
    620       ASSERT(!info->code().is_null());
    621       Handle<Code> code = info->code();
    622       // Set optimizable to false if this is disallowed by the shared
    623       // function info, e.g., we might have flushed the code and must
    624       // reset this bit when lazy compiling the code again.
    625       if (shared->optimization_disabled()) code->set_optimizable(false);
    626 
    627       Handle<JSFunction> function = info->closure();
    628       RecordFunctionCompilation(Logger::LAZY_COMPILE_TAG, info, shared);
    629 
    630       if (info->IsOptimizing()) {
    631         function->ReplaceCode(*code);
    632       } else {
    633         // Update the shared function info with the compiled code and the
    634         // scope info.  Please note, that the order of the shared function
    635         // info initialization is important since set_scope_info might
    636         // trigger a GC, causing the ASSERT below to be invalid if the code
    637         // was flushed. By settting the code object last we avoid this.
    638         Handle<SerializedScopeInfo> scope_info =
    639             SerializedScopeInfo::Create(info->scope());
    640         shared->set_scope_info(*scope_info);
    641         shared->set_code(*code);
    642         if (!function.is_null()) {
    643           function->ReplaceCode(*code);
    644           ASSERT(!function->IsOptimized());
    645         }
    646 
    647         // Set the expected number of properties for instances.
    648         FunctionLiteral* lit = info->function();
    649         int expected = lit->expected_property_count();
    650         SetExpectedNofPropertiesFromEstimate(shared, expected);
    651 
    652         // Set the optimization hints after performing lazy compilation, as
    653         // these are not set when the function is set up as a lazily
    654         // compiled function.
    655         shared->SetThisPropertyAssignmentsInfo(
    656             lit->has_only_simple_this_property_assignments(),
    657             *lit->this_property_assignments());
    658 
    659         // Check the function has compiled code.
    660         ASSERT(shared->is_compiled());
    661         shared->set_code_age(0);
    662 
    663         if (info->AllowOptimize() && !shared->optimization_disabled()) {
    664           // If we're asked to always optimize, we compile the optimized
    665           // version of the function right away - unless the debugger is
    666           // active as it makes no sense to compile optimized code then.
    667           if (FLAG_always_opt &&
    668               !Isolate::Current()->debug()->has_break_points()) {
    669             CompilationInfo optimized(function);
    670             optimized.SetOptimizing(AstNode::kNoNumber);
    671             return CompileLazy(&optimized);
    672           } else if (isolate->compilation_cache()->ShouldOptimizeEagerly(
    673               function)) {
    674             isolate->runtime_profiler()->OptimizeSoon(*function);
    675           }
    676         }
    677       }
    678 
    679       return true;
    680     }
    681   }
    682 
    683   ASSERT(info->code().is_null());
    684   return false;
    685 }
    686 
    687 
    688 Handle<SharedFunctionInfo> Compiler::BuildFunctionInfo(FunctionLiteral* literal,
    689                                                        Handle<Script> script) {
    690   // Precondition: code has been parsed and scopes have been analyzed.
    691   CompilationInfo info(script);
    692   info.SetFunction(literal);
    693   info.SetScope(literal->scope());
    694 
    695   LiveEditFunctionTracker live_edit_tracker(info.isolate(), literal);
    696   // Determine if the function can be lazily compiled. This is necessary to
    697   // allow some of our builtin JS files to be lazily compiled. These
    698   // builtins cannot be handled lazily by the parser, since we have to know
    699   // if a function uses the special natives syntax, which is something the
    700   // parser records.
    701   bool allow_lazy = literal->AllowsLazyCompilation() &&
    702       !LiveEditFunctionTracker::IsActive(info.isolate());
    703 
    704   Handle<SerializedScopeInfo> scope_info(SerializedScopeInfo::Empty());
    705 
    706   // Generate code
    707   if (FLAG_lazy && allow_lazy) {
    708     Handle<Code> code = info.isolate()->builtins()->LazyCompile();
    709     info.SetCode(code);
    710   } else if ((V8::UseCrankshaft() && MakeCrankshaftCode(&info)) ||
    711              (!V8::UseCrankshaft() && FullCodeGenerator::MakeCode(&info))) {
    712     ASSERT(!info.code().is_null());
    713     scope_info = SerializedScopeInfo::Create(info.scope());
    714   } else {
    715     return Handle<SharedFunctionInfo>::null();
    716   }
    717 
    718   // Create a shared function info object.
    719   Handle<SharedFunctionInfo> result =
    720       FACTORY->NewSharedFunctionInfo(literal->name(),
    721                                      literal->materialized_literal_count(),
    722                                      info.code(),
    723                                      scope_info);
    724   SetFunctionInfo(result, literal, false, script);
    725   RecordFunctionCompilation(Logger::FUNCTION_TAG, &info, result);
    726   result->set_allows_lazy_compilation(allow_lazy);
    727 
    728   // Set the expected number of properties for instances and return
    729   // the resulting function.
    730   SetExpectedNofPropertiesFromEstimate(result,
    731                                        literal->expected_property_count());
    732   live_edit_tracker.RecordFunctionInfo(result, literal);
    733   return result;
    734 }
    735 
    736 
    737 // Sets the function info on a function.
    738 // The start_position points to the first '(' character after the function name
    739 // in the full script source. When counting characters in the script source the
    740 // the first character is number 0 (not 1).
    741 void Compiler::SetFunctionInfo(Handle<SharedFunctionInfo> function_info,
    742                                FunctionLiteral* lit,
    743                                bool is_toplevel,
    744                                Handle<Script> script) {
    745   function_info->set_length(lit->num_parameters());
    746   function_info->set_formal_parameter_count(lit->num_parameters());
    747   function_info->set_script(*script);
    748   function_info->set_function_token_position(lit->function_token_position());
    749   function_info->set_start_position(lit->start_position());
    750   function_info->set_end_position(lit->end_position());
    751   function_info->set_is_expression(lit->is_expression());
    752   function_info->set_is_toplevel(is_toplevel);
    753   function_info->set_inferred_name(*lit->inferred_name());
    754   function_info->SetThisPropertyAssignmentsInfo(
    755       lit->has_only_simple_this_property_assignments(),
    756       *lit->this_property_assignments());
    757   function_info->set_allows_lazy_compilation(lit->AllowsLazyCompilation());
    758   function_info->set_strict_mode(lit->strict_mode());
    759 }
    760 
    761 
    762 void Compiler::RecordFunctionCompilation(Logger::LogEventsAndTags tag,
    763                                          CompilationInfo* info,
    764                                          Handle<SharedFunctionInfo> shared) {
    765   // SharedFunctionInfo is passed separately, because if CompilationInfo
    766   // was created using Script object, it will not have it.
    767 
    768   // Log the code generation. If source information is available include
    769   // script name and line number. Check explicitly whether logging is
    770   // enabled as finding the line number is not free.
    771   if (info->isolate()->logger()->is_logging() || CpuProfiler::is_profiling()) {
    772     Handle<Script> script = info->script();
    773     Handle<Code> code = info->code();
    774     if (*code == info->isolate()->builtins()->builtin(Builtins::kLazyCompile))
    775       return;
    776     if (script->name()->IsString()) {
    777       int line_num = GetScriptLineNumber(script, shared->start_position()) + 1;
    778       USE(line_num);
    779       PROFILE(info->isolate(),
    780               CodeCreateEvent(Logger::ToNativeByScript(tag, *script),
    781                               *code,
    782                               *shared,
    783                               String::cast(script->name()),
    784                               line_num));
    785     } else {
    786       PROFILE(info->isolate(),
    787               CodeCreateEvent(Logger::ToNativeByScript(tag, *script),
    788                               *code,
    789                               *shared,
    790                               shared->DebugName()));
    791     }
    792   }
    793 
    794   GDBJIT(AddCode(Handle<String>(shared->DebugName()),
    795                  Handle<Script>(info->script()),
    796                  Handle<Code>(info->code())));
    797 }
    798 
    799 } }  // namespace v8::internal
    800