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