• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
CompilationInfo(Handle<Script> script)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 
CompilationInfo(Handle<SharedFunctionInfo> shared_info)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 
CompilationInfo(Handle<JSFunction> closure)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 
DisableOptimization()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.
AlwaysFullCompiler()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 
FinishOptimization(Handle<JSFunction> function,int64_t start)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 
AbortAndDisable(CompilationInfo * info)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 
MakeCrankshaftCode(CompilationInfo * info)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 
MakeCode(CompilationInfo * info)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
MakeCodeForLiveEdit(CompilationInfo * info)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 
MakeFunctionInfo(CompilationInfo * info)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 
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)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 
CompileEval(Handle<String> source,Handle<Context> context,bool is_global,StrictModeFlag strict_mode)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 
CompileLazy(CompilationInfo * info)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 
BuildFunctionInfo(FunctionLiteral * literal,Handle<Script> script)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).
SetFunctionInfo(Handle<SharedFunctionInfo> function_info,FunctionLiteral * lit,bool is_toplevel,Handle<Script> script)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 
RecordFunctionCompilation(Logger::LogEventsAndTags tag,CompilationInfo * info,Handle<SharedFunctionInfo> shared)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