1// Copyright 2012 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 "debug.h" 36#include "full-codegen.h" 37#include "gdb-jit.h" 38#include "hydrogen.h" 39#include "isolate-inl.h" 40#include "lithium.h" 41#include "liveedit.h" 42#include "parser.h" 43#include "rewriter.h" 44#include "runtime-profiler.h" 45#include "scanner-character-streams.h" 46#include "scopeinfo.h" 47#include "scopes.h" 48#include "vm-state-inl.h" 49 50namespace v8 { 51namespace internal { 52 53 54CompilationInfo::CompilationInfo(Handle<Script> script) 55 : isolate_(script->GetIsolate()), 56 flags_(LanguageModeField::encode(CLASSIC_MODE)), 57 function_(NULL), 58 scope_(NULL), 59 global_scope_(NULL), 60 script_(script), 61 extension_(NULL), 62 pre_parse_data_(NULL), 63 osr_ast_id_(AstNode::kNoNumber) { 64 Initialize(BASE); 65} 66 67 68CompilationInfo::CompilationInfo(Handle<SharedFunctionInfo> shared_info) 69 : isolate_(shared_info->GetIsolate()), 70 flags_(LanguageModeField::encode(CLASSIC_MODE) | 71 IsLazy::encode(true)), 72 function_(NULL), 73 scope_(NULL), 74 global_scope_(NULL), 75 shared_info_(shared_info), 76 script_(Handle<Script>(Script::cast(shared_info->script()))), 77 extension_(NULL), 78 pre_parse_data_(NULL), 79 osr_ast_id_(AstNode::kNoNumber) { 80 Initialize(BASE); 81} 82 83 84CompilationInfo::CompilationInfo(Handle<JSFunction> closure) 85 : isolate_(closure->GetIsolate()), 86 flags_(LanguageModeField::encode(CLASSIC_MODE) | 87 IsLazy::encode(true)), 88 function_(NULL), 89 scope_(NULL), 90 global_scope_(NULL), 91 closure_(closure), 92 shared_info_(Handle<SharedFunctionInfo>(closure->shared())), 93 script_(Handle<Script>(Script::cast(shared_info_->script()))), 94 extension_(NULL), 95 pre_parse_data_(NULL), 96 osr_ast_id_(AstNode::kNoNumber) { 97 Initialize(BASE); 98} 99 100 101// Disable optimization for the rest of the compilation pipeline. 102void CompilationInfo::DisableOptimization() { 103 bool is_optimizable_closure = 104 FLAG_optimize_closures && 105 closure_.is_null() && 106 !scope_->HasTrivialOuterContext() && 107 !scope_->outer_scope_calls_non_strict_eval() && 108 !scope_->inside_with(); 109 SetMode(is_optimizable_closure ? BASE : NONOPT); 110} 111 112 113// Primitive functions are unlikely to be picked up by the stack-walking 114// profiler, so they trigger their own optimization when they're called 115// for the SharedFunctionInfo::kCallsUntilPrimitiveOptimization-th time. 116bool CompilationInfo::ShouldSelfOptimize() { 117 return FLAG_self_optimization && 118 FLAG_crankshaft && 119 !function()->flags()->Contains(kDontSelfOptimize) && 120 !function()->flags()->Contains(kDontOptimize) && 121 function()->scope()->AllowsLazyRecompilation() && 122 (shared_info().is_null() || !shared_info()->optimization_disabled()); 123} 124 125 126void CompilationInfo::AbortOptimization() { 127 Handle<Code> code(shared_info()->code()); 128 SetCode(code); 129} 130 131 132// Determine whether to use the full compiler for all code. If the flag 133// --always-full-compiler is specified this is the case. For the virtual frame 134// based compiler the full compiler is also used if a debugger is connected, as 135// the code from the full compiler supports mode precise break points. For the 136// crankshaft adaptive compiler debugging the optimized code is not possible at 137// all. However crankshaft support recompilation of functions, so in this case 138// the full compiler need not be be used if a debugger is attached, but only if 139// break points has actually been set. 140static bool is_debugging_active() { 141#ifdef ENABLE_DEBUGGER_SUPPORT 142 Isolate* isolate = Isolate::Current(); 143 return V8::UseCrankshaft() ? 144 isolate->debug()->has_break_points() : 145 isolate->debugger()->IsDebuggerActive(); 146#else 147 return false; 148#endif 149} 150 151 152static bool AlwaysFullCompiler() { 153 return FLAG_always_full_compiler || is_debugging_active(); 154} 155 156 157static void FinishOptimization(Handle<JSFunction> function, int64_t start) { 158 int opt_count = function->shared()->opt_count(); 159 function->shared()->set_opt_count(opt_count + 1); 160 double ms = static_cast<double>(OS::Ticks() - start) / 1000; 161 if (FLAG_trace_opt) { 162 PrintF("[optimizing: "); 163 function->PrintName(); 164 PrintF(" / %" V8PRIxPTR, reinterpret_cast<intptr_t>(*function)); 165 PrintF(" - took %0.3f ms]\n", ms); 166 } 167 if (FLAG_trace_opt_stats) { 168 static double compilation_time = 0.0; 169 static int compiled_functions = 0; 170 static int code_size = 0; 171 172 compilation_time += ms; 173 compiled_functions++; 174 code_size += function->shared()->SourceSize(); 175 PrintF("Compiled: %d functions with %d byte source size in %fms.\n", 176 compiled_functions, 177 code_size, 178 compilation_time); 179 } 180} 181 182 183static bool MakeCrankshaftCode(CompilationInfo* info) { 184 // Test if we can optimize this function when asked to. We can only 185 // do this after the scopes are computed. 186 if (!V8::UseCrankshaft()) { 187 info->DisableOptimization(); 188 } 189 190 // In case we are not optimizing simply return the code from 191 // the full code generator. 192 if (!info->IsOptimizing()) { 193 return FullCodeGenerator::MakeCode(info); 194 } 195 196 // We should never arrive here if there is not code object on the 197 // shared function object. 198 Handle<Code> code(info->shared_info()->code()); 199 ASSERT(code->kind() == Code::FUNCTION); 200 201 // We should never arrive here if optimization has been disabled on the 202 // shared function info. 203 ASSERT(!info->shared_info()->optimization_disabled()); 204 205 // Fall back to using the full code generator if it's not possible 206 // to use the Hydrogen-based optimizing compiler. We already have 207 // generated code for this from the shared function object. 208 if (AlwaysFullCompiler()) { 209 info->SetCode(code); 210 return true; 211 } 212 213 // Limit the number of times we re-compile a functions with 214 // the optimizing compiler. 215 const int kMaxOptCount = 216 FLAG_deopt_every_n_times == 0 ? Compiler::kDefaultMaxOptCount : 1000; 217 if (info->shared_info()->opt_count() > kMaxOptCount) { 218 info->AbortOptimization(); 219 info->shared_info()->DisableOptimization(); 220 // True indicates the compilation pipeline is still going, not 221 // necessarily that we optimized the code. 222 return true; 223 } 224 225 // Due to an encoding limit on LUnallocated operands in the Lithium 226 // language, we cannot optimize functions with too many formal parameters 227 // or perform on-stack replacement for function with too many 228 // stack-allocated local variables. 229 // 230 // The encoding is as a signed value, with parameters and receiver using 231 // the negative indices and locals the non-negative ones. 232 const int parameter_limit = -LUnallocated::kMinFixedIndex; 233 const int locals_limit = LUnallocated::kMaxFixedIndex; 234 Scope* scope = info->scope(); 235 if ((scope->num_parameters() + 1) > parameter_limit || 236 (info->osr_ast_id() != AstNode::kNoNumber && 237 scope->num_parameters() + 1 + scope->num_stack_slots() > locals_limit)) { 238 info->AbortOptimization(); 239 info->shared_info()->DisableOptimization(); 240 // True indicates the compilation pipeline is still going, not 241 // necessarily that we optimized the code. 242 return true; 243 } 244 245 // Take --hydrogen-filter into account. 246 Handle<String> name = info->function()->debug_name(); 247 if (*FLAG_hydrogen_filter != '\0') { 248 Vector<const char> filter = CStrVector(FLAG_hydrogen_filter); 249 if ((filter[0] == '-' 250 && name->IsEqualTo(filter.SubVector(1, filter.length()))) 251 || (filter[0] != '-' && !name->IsEqualTo(filter))) { 252 info->SetCode(code); 253 return true; 254 } 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, info->isolate()); 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) { 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 // Keep using the shared code. 316 info->AbortOptimization(); 317 if (!builder.inline_bailout()) { 318 // Mark the shared code as unoptimizable unless it was an inlined 319 // function that bailed out. 320 info->shared_info()->DisableOptimization(); 321 } 322 // True indicates the compilation pipeline is still going, not necessarily 323 // that we optimized the code. 324 return true; 325} 326 327 328static bool GenerateCode(CompilationInfo* info) { 329 return info->IsCompilingForDebugging() || !V8::UseCrankshaft() ? 330 FullCodeGenerator::MakeCode(info) : 331 MakeCrankshaftCode(info); 332} 333 334 335static bool MakeCode(CompilationInfo* info) { 336 // Precondition: code has been parsed. Postcondition: the code field in 337 // the compilation info is set if compilation succeeded. 338 ASSERT(info->function() != NULL); 339 return Rewriter::Rewrite(info) && Scope::Analyze(info) && GenerateCode(info); 340} 341 342 343#ifdef ENABLE_DEBUGGER_SUPPORT 344bool Compiler::MakeCodeForLiveEdit(CompilationInfo* info) { 345 // Precondition: code has been parsed. Postcondition: the code field in 346 // the compilation info is set if compilation succeeded. 347 bool succeeded = MakeCode(info); 348 if (!info->shared_info().is_null()) { 349 Handle<ScopeInfo> scope_info = ScopeInfo::Create(info->scope()); 350 info->shared_info()->set_scope_info(*scope_info); 351 } 352 return succeeded; 353} 354#endif 355 356 357static Handle<SharedFunctionInfo> MakeFunctionInfo(CompilationInfo* info) { 358 Isolate* isolate = info->isolate(); 359 ZoneScope zone_scope(isolate, DELETE_ON_EXIT); 360 PostponeInterruptsScope postpone(isolate); 361 362 ASSERT(!isolate->global_context().is_null()); 363 Handle<Script> script = info->script(); 364 script->set_context_data((*isolate->global_context())->data()); 365 366#ifdef ENABLE_DEBUGGER_SUPPORT 367 if (info->is_eval()) { 368 Script::CompilationType compilation_type = Script::COMPILATION_TYPE_EVAL; 369 script->set_compilation_type(Smi::FromInt(compilation_type)); 370 // For eval scripts add information on the function from which eval was 371 // called. 372 if (info->is_eval()) { 373 StackTraceFrameIterator it(isolate); 374 if (!it.done()) { 375 script->set_eval_from_shared( 376 JSFunction::cast(it.frame()->function())->shared()); 377 Code* code = it.frame()->LookupCode(); 378 int offset = static_cast<int>( 379 it.frame()->pc() - code->instruction_start()); 380 script->set_eval_from_instructions_offset(Smi::FromInt(offset)); 381 } 382 } 383 } 384 385 // Notify debugger 386 isolate->debugger()->OnBeforeCompile(script); 387#endif 388 389 // Only allow non-global compiles for eval. 390 ASSERT(info->is_eval() || info->is_global()); 391 ParsingFlags flags = kNoParsingFlags; 392 if (info->pre_parse_data() != NULL || 393 String::cast(script->source())->length() > FLAG_min_preparse_length) { 394 flags = kAllowLazy; 395 } 396 if (!ParserApi::Parse(info, flags)) { 397 return Handle<SharedFunctionInfo>::null(); 398 } 399 400 // Measure how long it takes to do the compilation; only take the 401 // rest of the function into account to avoid overlap with the 402 // parsing statistics. 403 HistogramTimer* rate = info->is_eval() 404 ? info->isolate()->counters()->compile_eval() 405 : info->isolate()->counters()->compile(); 406 HistogramTimerScope timer(rate); 407 408 // Compile the code. 409 FunctionLiteral* lit = info->function(); 410 LiveEditFunctionTracker live_edit_tracker(isolate, lit); 411 if (!MakeCode(info)) { 412 if (!isolate->has_pending_exception()) isolate->StackOverflow(); 413 return Handle<SharedFunctionInfo>::null(); 414 } 415 416 // Allocate function. 417 ASSERT(!info->code().is_null()); 418 Handle<SharedFunctionInfo> result = 419 isolate->factory()->NewSharedFunctionInfo( 420 lit->name(), 421 lit->materialized_literal_count(), 422 info->code(), 423 ScopeInfo::Create(info->scope())); 424 425 ASSERT_EQ(RelocInfo::kNoPosition, lit->function_token_position()); 426 Compiler::SetFunctionInfo(result, lit, true, script); 427 428 if (script->name()->IsString()) { 429 PROFILE(isolate, CodeCreateEvent( 430 info->is_eval() 431 ? Logger::EVAL_TAG 432 : Logger::ToNativeByScript(Logger::SCRIPT_TAG, *script), 433 *info->code(), 434 *result, 435 String::cast(script->name()))); 436 GDBJIT(AddCode(Handle<String>(String::cast(script->name())), 437 script, 438 info->code(), 439 info)); 440 } else { 441 PROFILE(isolate, CodeCreateEvent( 442 info->is_eval() 443 ? Logger::EVAL_TAG 444 : Logger::ToNativeByScript(Logger::SCRIPT_TAG, *script), 445 *info->code(), 446 *result, 447 isolate->heap()->empty_string())); 448 GDBJIT(AddCode(Handle<String>(), script, info->code(), info)); 449 } 450 451 // Hint to the runtime system used when allocating space for initial 452 // property space by setting the expected number of properties for 453 // the instances of the function. 454 SetExpectedNofPropertiesFromEstimate(result, lit->expected_property_count()); 455 456 script->set_compilation_state( 457 Smi::FromInt(Script::COMPILATION_STATE_COMPILED)); 458 459#ifdef ENABLE_DEBUGGER_SUPPORT 460 // Notify debugger 461 isolate->debugger()->OnAfterCompile( 462 script, Debugger::NO_AFTER_COMPILE_FLAGS); 463#endif 464 465 live_edit_tracker.RecordFunctionInfo(result, lit); 466 467 return result; 468} 469 470 471Handle<SharedFunctionInfo> Compiler::Compile(Handle<String> source, 472 Handle<Object> script_name, 473 int line_offset, 474 int column_offset, 475 v8::Extension* extension, 476 ScriptDataImpl* pre_data, 477 Handle<Object> script_data, 478 NativesFlag natives) { 479 Isolate* isolate = source->GetIsolate(); 480 int source_length = source->length(); 481 isolate->counters()->total_load_size()->Increment(source_length); 482 isolate->counters()->total_compile_size()->Increment(source_length); 483 484 // The VM is in the COMPILER state until exiting this function. 485 VMState state(isolate, COMPILER); 486 487 CompilationCache* compilation_cache = isolate->compilation_cache(); 488 489 // Do a lookup in the compilation cache but not for extensions. 490 Handle<SharedFunctionInfo> result; 491 if (extension == NULL) { 492 result = compilation_cache->LookupScript(source, 493 script_name, 494 line_offset, 495 column_offset); 496 } 497 498 if (result.is_null()) { 499 // No cache entry found. Do pre-parsing, if it makes sense, and compile 500 // the script. 501 // Building preparse data that is only used immediately after is only a 502 // saving if we might skip building the AST for lazily compiled functions. 503 // I.e., preparse data isn't relevant when the lazy flag is off, and 504 // for small sources, odds are that there aren't many functions 505 // that would be compiled lazily anyway, so we skip the preparse step 506 // in that case too. 507 508 // Create a script object describing the script to be compiled. 509 Handle<Script> script = FACTORY->NewScript(source); 510 if (natives == NATIVES_CODE) { 511 script->set_type(Smi::FromInt(Script::TYPE_NATIVE)); 512 } 513 if (!script_name.is_null()) { 514 script->set_name(*script_name); 515 script->set_line_offset(Smi::FromInt(line_offset)); 516 script->set_column_offset(Smi::FromInt(column_offset)); 517 } 518 519 script->set_data(script_data.is_null() ? HEAP->undefined_value() 520 : *script_data); 521 522 // Compile the function and add it to the cache. 523 CompilationInfo info(script); 524 info.MarkAsGlobal(); 525 info.SetExtension(extension); 526 info.SetPreParseData(pre_data); 527 if (FLAG_use_strict) { 528 info.SetLanguageMode(FLAG_harmony_scoping ? EXTENDED_MODE : STRICT_MODE); 529 } 530 result = MakeFunctionInfo(&info); 531 if (extension == NULL && !result.is_null()) { 532 compilation_cache->PutScript(source, result); 533 } 534 } else { 535 if (result->ic_age() != HEAP->global_ic_age()) { 536 result->ResetForNewContext(HEAP->global_ic_age()); 537 } 538 } 539 540 if (result.is_null()) isolate->ReportPendingMessages(); 541 return result; 542} 543 544 545Handle<SharedFunctionInfo> Compiler::CompileEval(Handle<String> source, 546 Handle<Context> context, 547 bool is_global, 548 LanguageMode language_mode, 549 int scope_position) { 550 Isolate* isolate = source->GetIsolate(); 551 int source_length = source->length(); 552 isolate->counters()->total_eval_size()->Increment(source_length); 553 isolate->counters()->total_compile_size()->Increment(source_length); 554 555 // The VM is in the COMPILER state until exiting this function. 556 VMState state(isolate, COMPILER); 557 558 // Do a lookup in the compilation cache; if the entry is not there, invoke 559 // the compiler and add the result to the cache. 560 Handle<SharedFunctionInfo> result; 561 CompilationCache* compilation_cache = isolate->compilation_cache(); 562 result = compilation_cache->LookupEval(source, 563 context, 564 is_global, 565 language_mode, 566 scope_position); 567 568 if (result.is_null()) { 569 // Create a script object describing the script to be compiled. 570 Handle<Script> script = isolate->factory()->NewScript(source); 571 CompilationInfo info(script); 572 info.MarkAsEval(); 573 if (is_global) info.MarkAsGlobal(); 574 info.SetLanguageMode(language_mode); 575 info.SetCallingContext(context); 576 result = MakeFunctionInfo(&info); 577 if (!result.is_null()) { 578 // Explicitly disable optimization for eval code. We're not yet prepared 579 // to handle eval-code in the optimizing compiler. 580 result->DisableOptimization(); 581 582 // If caller is strict mode, the result must be in strict mode or 583 // extended mode as well, but not the other way around. Consider: 584 // eval("'use strict'; ..."); 585 ASSERT(language_mode != STRICT_MODE || !result->is_classic_mode()); 586 // If caller is in extended mode, the result must also be in 587 // extended mode. 588 ASSERT(language_mode != EXTENDED_MODE || 589 result->is_extended_mode()); 590 compilation_cache->PutEval( 591 source, context, is_global, result, scope_position); 592 } 593 } else { 594 if (result->ic_age() != HEAP->global_ic_age()) { 595 result->ResetForNewContext(HEAP->global_ic_age()); 596 } 597 } 598 599 return result; 600} 601 602 603bool Compiler::CompileLazy(CompilationInfo* info) { 604 Isolate* isolate = info->isolate(); 605 606 ZoneScope zone_scope(isolate, DELETE_ON_EXIT); 607 608 // The VM is in the COMPILER state until exiting this function. 609 VMState state(isolate, COMPILER); 610 611 PostponeInterruptsScope postpone(isolate); 612 613 Handle<SharedFunctionInfo> shared = info->shared_info(); 614 int compiled_size = shared->end_position() - shared->start_position(); 615 isolate->counters()->total_compile_size()->Increment(compiled_size); 616 617 // Generate the AST for the lazily compiled function. 618 if (ParserApi::Parse(info, kNoParsingFlags)) { 619 // Measure how long it takes to do the lazy compilation; only take the 620 // rest of the function into account to avoid overlap with the lazy 621 // parsing statistics. 622 HistogramTimerScope timer(isolate->counters()->compile_lazy()); 623 624 // After parsing we know the function's language mode. Remember it. 625 LanguageMode language_mode = info->function()->language_mode(); 626 info->SetLanguageMode(language_mode); 627 shared->set_language_mode(language_mode); 628 629 // Compile the code. 630 if (!MakeCode(info)) { 631 if (!isolate->has_pending_exception()) { 632 isolate->StackOverflow(); 633 } 634 } else { 635 ASSERT(!info->code().is_null()); 636 Handle<Code> code = info->code(); 637 // Set optimizable to false if this is disallowed by the shared 638 // function info, e.g., we might have flushed the code and must 639 // reset this bit when lazy compiling the code again. 640 if (shared->optimization_disabled()) code->set_optimizable(false); 641 642 Handle<JSFunction> function = info->closure(); 643 RecordFunctionCompilation(Logger::LAZY_COMPILE_TAG, info, shared); 644 645 if (info->IsOptimizing()) { 646 ASSERT(shared->scope_info() != ScopeInfo::Empty()); 647 function->ReplaceCode(*code); 648 } else { 649 // Update the shared function info with the compiled code and the 650 // scope info. Please note, that the order of the shared function 651 // info initialization is important since set_scope_info might 652 // trigger a GC, causing the ASSERT below to be invalid if the code 653 // was flushed. By setting the code object last we avoid this. 654 Handle<ScopeInfo> scope_info = ScopeInfo::Create(info->scope()); 655 shared->set_scope_info(*scope_info); 656 shared->set_code(*code); 657 if (!function.is_null()) { 658 function->ReplaceCode(*code); 659 ASSERT(!function->IsOptimized()); 660 } 661 662 // Set the expected number of properties for instances. 663 FunctionLiteral* lit = info->function(); 664 int expected = lit->expected_property_count(); 665 SetExpectedNofPropertiesFromEstimate(shared, expected); 666 667 // Set the optimization hints after performing lazy compilation, as 668 // these are not set when the function is set up as a lazily 669 // compiled function. 670 shared->SetThisPropertyAssignmentsInfo( 671 lit->has_only_simple_this_property_assignments(), 672 *lit->this_property_assignments()); 673 674 // Check the function has compiled code. 675 ASSERT(shared->is_compiled()); 676 shared->set_code_age(0); 677 shared->set_dont_optimize(lit->flags()->Contains(kDontOptimize)); 678 shared->set_dont_inline(lit->flags()->Contains(kDontInline)); 679 shared->set_ast_node_count(lit->ast_node_count()); 680 681 if (V8::UseCrankshaft()&& 682 !function.is_null() && 683 !shared->optimization_disabled()) { 684 // If we're asked to always optimize, we compile the optimized 685 // version of the function right away - unless the debugger is 686 // active as it makes no sense to compile optimized code then. 687 if (FLAG_always_opt && 688 !Isolate::Current()->DebuggerHasBreakPoints()) { 689 CompilationInfo optimized(function); 690 optimized.SetOptimizing(AstNode::kNoNumber); 691 return CompileLazy(&optimized); 692 } 693 } 694 } 695 696 return true; 697 } 698 } 699 700 ASSERT(info->code().is_null()); 701 return false; 702} 703 704 705Handle<SharedFunctionInfo> Compiler::BuildFunctionInfo(FunctionLiteral* literal, 706 Handle<Script> script) { 707 // Precondition: code has been parsed and scopes have been analyzed. 708 CompilationInfo info(script); 709 info.SetFunction(literal); 710 info.SetScope(literal->scope()); 711 info.SetLanguageMode(literal->scope()->language_mode()); 712 713 LiveEditFunctionTracker live_edit_tracker(info.isolate(), literal); 714 // Determine if the function can be lazily compiled. This is necessary to 715 // allow some of our builtin JS files to be lazily compiled. These 716 // builtins cannot be handled lazily by the parser, since we have to know 717 // if a function uses the special natives syntax, which is something the 718 // parser records. 719 bool allow_lazy = literal->AllowsLazyCompilation() && 720 !LiveEditFunctionTracker::IsActive(info.isolate()); 721 722 Handle<ScopeInfo> scope_info(ScopeInfo::Empty()); 723 724 // Generate code 725 if (FLAG_lazy && allow_lazy) { 726 Handle<Code> code = info.isolate()->builtins()->LazyCompile(); 727 info.SetCode(code); 728 } else if ((V8::UseCrankshaft() && MakeCrankshaftCode(&info)) || 729 (!V8::UseCrankshaft() && FullCodeGenerator::MakeCode(&info))) { 730 ASSERT(!info.code().is_null()); 731 scope_info = ScopeInfo::Create(info.scope()); 732 } else { 733 return Handle<SharedFunctionInfo>::null(); 734 } 735 736 // Create a shared function info object. 737 Handle<SharedFunctionInfo> result = 738 FACTORY->NewSharedFunctionInfo(literal->name(), 739 literal->materialized_literal_count(), 740 info.code(), 741 scope_info); 742 SetFunctionInfo(result, literal, false, script); 743 RecordFunctionCompilation(Logger::FUNCTION_TAG, &info, result); 744 result->set_allows_lazy_compilation(allow_lazy); 745 746 // Set the expected number of properties for instances and return 747 // the resulting function. 748 SetExpectedNofPropertiesFromEstimate(result, 749 literal->expected_property_count()); 750 live_edit_tracker.RecordFunctionInfo(result, literal); 751 return result; 752} 753 754 755// Sets the function info on a function. 756// The start_position points to the first '(' character after the function name 757// in the full script source. When counting characters in the script source the 758// the first character is number 0 (not 1). 759void Compiler::SetFunctionInfo(Handle<SharedFunctionInfo> function_info, 760 FunctionLiteral* lit, 761 bool is_toplevel, 762 Handle<Script> script) { 763 function_info->set_length(lit->parameter_count()); 764 function_info->set_formal_parameter_count(lit->parameter_count()); 765 function_info->set_script(*script); 766 function_info->set_function_token_position(lit->function_token_position()); 767 function_info->set_start_position(lit->start_position()); 768 function_info->set_end_position(lit->end_position()); 769 function_info->set_is_expression(lit->is_expression()); 770 function_info->set_is_anonymous(lit->is_anonymous()); 771 function_info->set_is_toplevel(is_toplevel); 772 function_info->set_inferred_name(*lit->inferred_name()); 773 function_info->SetThisPropertyAssignmentsInfo( 774 lit->has_only_simple_this_property_assignments(), 775 *lit->this_property_assignments()); 776 function_info->set_allows_lazy_compilation(lit->AllowsLazyCompilation()); 777 function_info->set_language_mode(lit->language_mode()); 778 function_info->set_uses_arguments(lit->scope()->arguments() != NULL); 779 function_info->set_has_duplicate_parameters(lit->has_duplicate_parameters()); 780 function_info->set_ast_node_count(lit->ast_node_count()); 781 function_info->set_is_function(lit->is_function()); 782 function_info->set_dont_optimize(lit->flags()->Contains(kDontOptimize)); 783 function_info->set_dont_inline(lit->flags()->Contains(kDontInline)); 784} 785 786 787void Compiler::RecordFunctionCompilation(Logger::LogEventsAndTags tag, 788 CompilationInfo* info, 789 Handle<SharedFunctionInfo> shared) { 790 // SharedFunctionInfo is passed separately, because if CompilationInfo 791 // was created using Script object, it will not have it. 792 793 // Log the code generation. If source information is available include 794 // script name and line number. Check explicitly whether logging is 795 // enabled as finding the line number is not free. 796 if (info->isolate()->logger()->is_logging() || 797 CpuProfiler::is_profiling(info->isolate())) { 798 Handle<Script> script = info->script(); 799 Handle<Code> code = info->code(); 800 if (*code == info->isolate()->builtins()->builtin(Builtins::kLazyCompile)) 801 return; 802 if (script->name()->IsString()) { 803 int line_num = GetScriptLineNumber(script, shared->start_position()) + 1; 804 USE(line_num); 805 PROFILE(info->isolate(), 806 CodeCreateEvent(Logger::ToNativeByScript(tag, *script), 807 *code, 808 *shared, 809 String::cast(script->name()), 810 line_num)); 811 } else { 812 PROFILE(info->isolate(), 813 CodeCreateEvent(Logger::ToNativeByScript(tag, *script), 814 *code, 815 *shared, 816 shared->DebugName())); 817 } 818 } 819 820 GDBJIT(AddCode(Handle<String>(shared->DebugName()), 821 Handle<Script>(info->script()), 822 Handle<Code>(info->code()), 823 info)); 824} 825 826} } // namespace v8::internal 827