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