compiler.cc 41.7 KB
Newer Older
1
// Copyright 2012 the V8 project authors. All rights reserved.
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
//       copyright notice, this list of conditions and the following
//       disclaimer in the documentation and/or other materials provided
//       with the distribution.
//     * Neither the name of Google Inc. nor the names of its
//       contributors may be used to endorse or promote products derived
//       from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include "v8.h"

30 31
#include "compiler.h"

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

50 51
namespace v8 {
namespace internal {
52

53

54
CompilationInfo::CompilationInfo(Handle<Script> script, Zone* zone)
55
    : flags_(LanguageModeField::encode(CLASSIC_MODE)),
56
      script_(script),
57
      osr_ast_id_(BailoutId::None()) {
58
  Initialize(script->GetIsolate(), BASE, zone);
59 60 61
}


62 63
CompilationInfo::CompilationInfo(Handle<SharedFunctionInfo> shared_info,
                                 Zone* zone)
64
    : flags_(LanguageModeField::encode(CLASSIC_MODE) | IsLazy::encode(true)),
65 66
      shared_info_(shared_info),
      script_(Handle<Script>(Script::cast(shared_info->script()))),
67
      osr_ast_id_(BailoutId::None()) {
68
  Initialize(script_->GetIsolate(), BASE, zone);
69 70 71
}


72
CompilationInfo::CompilationInfo(Handle<JSFunction> closure, Zone* zone)
73
    : flags_(LanguageModeField::encode(CLASSIC_MODE) | IsLazy::encode(true)),
74 75 76
      closure_(closure),
      shared_info_(Handle<SharedFunctionInfo>(closure->shared())),
      script_(Handle<Script>(Script::cast(shared_info_->script()))),
77
      context_(closure->context()),
78
      osr_ast_id_(BailoutId::None()) {
79
  Initialize(script_->GetIsolate(), BASE, zone);
80 81 82
}


83 84 85 86 87 88 89 90 91 92 93 94
CompilationInfo::CompilationInfo(HydrogenCodeStub* stub,
                                 Isolate* isolate, Zone* zone)
    : flags_(LanguageModeField::encode(CLASSIC_MODE) |
             IsLazy::encode(true)),
      osr_ast_id_(BailoutId::None()) {
  Initialize(isolate, STUB, zone);
  code_stub_ = stub;
}


void CompilationInfo::Initialize(Isolate* isolate, Mode mode, Zone* zone) {
  isolate_ = isolate;
95 96 97 98 99 100 101
  function_ = NULL;
  scope_ = NULL;
  global_scope_ = NULL;
  extension_ = NULL;
  pre_parse_data_ = NULL;
  zone_ = zone;
  deferred_handles_ = NULL;
102
  code_stub_ = NULL;
103
  prologue_offset_ = kPrologueOffsetNotSet;
104
  opt_count_ = shared_info().is_null() ? 0 : shared_info()->opt_count();
105 106 107 108 109
  if (mode == STUB) {
    mode_ = STUB;
    return;
  }
  mode_ = V8::UseCrankshaft() ? mode : NONOPT;
110 111 112 113 114 115 116 117
  if (script_->type()->value() == Script::TYPE_NATIVE) {
    MarkAsNative();
  }
  if (!shared_info_.is_null()) {
    ASSERT(language_mode() == CLASSIC_MODE);
    SetLanguageMode(shared_info_->language_mode());
  }
  set_bailout_reason("unknown");
118 119 120
}


121 122 123 124 125
CompilationInfo::~CompilationInfo() {
  delete deferred_handles_;
}


126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
int CompilationInfo::num_parameters() const {
  if (IsStub()) {
    return 0;
  } else {
    return scope()->num_parameters();
  }
}


int CompilationInfo::num_heap_slots() const {
  if (IsStub()) {
    return 0;
  } else {
    return scope()->num_heap_slots();
  }
}


Code::Flags CompilationInfo::flags() const {
  if (IsStub()) {
    return Code::ComputeFlags(Code::COMPILED_STUB);
  } else {
    return Code::ComputeFlags(Code::OPTIMIZED_FUNCTION);
  }
}


153
// Disable optimization for the rest of the compilation pipeline.
154
void CompilationInfo::DisableOptimization() {
155 156 157 158
  bool is_optimizable_closure =
    FLAG_optimize_closures &&
    closure_.is_null() &&
    !scope_->HasTrivialOuterContext() &&
159
    !scope_->outer_scope_calls_non_strict_eval() &&
160 161
    !scope_->inside_with();
  SetMode(is_optimizable_closure ? BASE : NONOPT);
162 163 164
}


165 166 167 168
// Primitive functions are unlikely to be picked up by the stack-walking
// profiler, so they trigger their own optimization when they're called
// for the SharedFunctionInfo::kCallsUntilPrimitiveOptimization-th time.
bool CompilationInfo::ShouldSelfOptimize() {
169
  return FLAG_self_optimization &&
170 171
      FLAG_crankshaft &&
      !function()->flags()->Contains(kDontSelfOptimize) &&
172
      !function()->flags()->Contains(kDontOptimize) &&
173
      function()->scope()->AllowsLazyCompilation() &&
174 175 176 177
      (shared_info().is_null() || !shared_info()->optimization_disabled());
}


178 179 180 181 182 183
void CompilationInfo::AbortOptimization() {
  Handle<Code> code(shared_info()->code());
  SetCode(code);
}


184 185 186 187 188 189 190 191
// Determine whether to use the full compiler for all code. If the flag
// --always-full-compiler is specified this is the case. For the virtual frame
// based compiler the full compiler is also used if a debugger is connected, as
// the code from the full compiler supports mode precise break points. For the
// crankshaft adaptive compiler debugging the optimized code is not possible at
// all. However crankshaft support recompilation of functions, so in this case
// the full compiler need not be be used if a debugger is attached, but only if
// break points has actually been set.
192
static bool IsDebuggerActive(Isolate* isolate) {
193
#ifdef ENABLE_DEBUGGER_SUPPORT
194 195 196
  return V8::UseCrankshaft() ?
    isolate->debug()->has_break_points() :
    isolate->debugger()->IsDebuggerActive();
197
#else
198
  return false;
199 200 201
#endif
}

202

203 204
static bool AlwaysFullCompiler(Isolate* isolate) {
  return FLAG_always_full_compiler || IsDebuggerActive(isolate);
205 206 207
}


208 209
void OptimizingCompiler::RecordOptimizationStats() {
  Handle<JSFunction> function = info()->closure();
210 211
  int opt_count = function->shared()->opt_count();
  function->shared()->set_opt_count(opt_count + 1);
212 213 214 215
  double ms_creategraph =
      static_cast<double>(time_taken_to_create_graph_) / 1000;
  double ms_optimize = static_cast<double>(time_taken_to_optimize_) / 1000;
  double ms_codegen = static_cast<double>(time_taken_to_codegen_) / 1000;
216 217 218 219
  if (FLAG_trace_opt) {
    PrintF("[optimizing: ");
    function->PrintName();
    PrintF(" / %" V8PRIxPTR, reinterpret_cast<intptr_t>(*function));
220 221
    PrintF(" - took %0.3f, %0.3f, %0.3f ms]\n", ms_creategraph, ms_optimize,
           ms_codegen);
222 223 224 225 226 227
  }
  if (FLAG_trace_opt_stats) {
    static double compilation_time = 0.0;
    static int compiled_functions = 0;
    static int code_size = 0;

228
    compilation_time += (ms_creategraph + ms_optimize + ms_codegen);
229 230 231 232 233 234 235
    compiled_functions++;
    code_size += function->shared()->SourceSize();
    PrintF("Compiled: %d functions with %d byte source size in %fms.\n",
           compiled_functions,
           code_size,
           compilation_time);
  }
236 237 238 239 240
  if (FLAG_hydrogen_stats) {
    HStatistics::Instance()->IncrementSubtotals(time_taken_to_create_graph_,
                                                time_taken_to_optimize_,
                                                time_taken_to_codegen_);
  }
241 242 243
}


244 245
// A return value of true indicates the compilation pipeline is still
// going, not necessarily that we optimized the code.
246
static bool MakeCrankshaftCode(CompilationInfo* info) {
247 248 249 250 251 252 253 254
  OptimizingCompiler compiler(info);
  OptimizingCompiler::Status status = compiler.CreateGraph();

  if (status != OptimizingCompiler::SUCCEEDED) {
    return status != OptimizingCompiler::FAILED;
  }
  status = compiler.OptimizeGraph();
  if (status != OptimizingCompiler::SUCCEEDED) {
255
    status = compiler.AbortOptimization();
256 257 258 259 260 261 262 263
    return status != OptimizingCompiler::FAILED;
  }
  status = compiler.GenerateAndInstallCode();
  return status != OptimizingCompiler::FAILED;
}


OptimizingCompiler::Status OptimizingCompiler::CreateGraph() {
264
  ASSERT(V8::UseCrankshaft());
265 266
  ASSERT(info()->IsOptimizing());
  ASSERT(!info()->IsCompilingForDebugging());
267

268
  // We should never arrive here if there is no code object on the
269
  // shared function object.
270
  Handle<Code> code(info()->shared_info()->code());
271 272
  ASSERT(code->kind() == Code::FUNCTION);

273 274
  // We should never arrive here if optimization has been disabled on the
  // shared function info.
275
  ASSERT(!info()->shared_info()->optimization_disabled());
276

277 278 279
  // Fall back to using the full code generator if it's not possible
  // to use the Hydrogen-based optimizing compiler. We already have
  // generated code for this from the shared function object.
280 281 282
  if (AlwaysFullCompiler(info()->isolate())) {
    info()->SetCode(code);
    return SetLastStatus(BAILED_OUT);
283 284 285 286
  }

  // Limit the number of times we re-compile a functions with
  // the optimizing compiler.
287
  const int kMaxOptCount =
288
      FLAG_deopt_every_n_times == 0 ? FLAG_max_opt_count : 1000;
289
  if (info()->opt_count() > kMaxOptCount) {
290
    info()->set_bailout_reason("optimized too many times");
291
    return AbortOptimization();
292 293 294 295 296 297 298
  }

  // Due to an encoding limit on LUnallocated operands in the Lithium
  // language, we cannot optimize functions with too many formal parameters
  // or perform on-stack replacement for function with too many
  // stack-allocated local variables.
  //
299 300
  // The encoding is as a signed value, with parameters and receiver using
  // the negative indices and locals the non-negative ones.
301
  const int parameter_limit = -LUnallocated::kMinFixedIndex;
302
  Scope* scope = info()->scope();
303 304 305 306 307 308 309 310 311
  if ((scope->num_parameters() + 1) > parameter_limit) {
    info()->set_bailout_reason("too many parameters");
    return AbortOptimization();
  }

  const int locals_limit = LUnallocated::kMaxFixedIndex;
  if (!info()->osr_ast_id().IsNone() &&
      scope->num_parameters() + 1 + scope->num_stack_slots() > locals_limit) {
    info()->set_bailout_reason("too many parameters/locals");
312
    return AbortOptimization();
313 314 315
  }

  // Take --hydrogen-filter into account.
316
  Handle<String> name = info()->function()->debug_name();
317 318 319
  if (*FLAG_hydrogen_filter != '\0') {
    Vector<const char> filter = CStrVector(FLAG_hydrogen_filter);
    if ((filter[0] == '-'
320 321
         && name->IsUtf8EqualTo(filter.SubVector(1, filter.length())))
        || (filter[0] != '-' && !name->IsUtf8EqualTo(filter))) {
322 323
      info()->SetCode(code);
      return SetLastStatus(BAILED_OUT);
324
    }
325 326 327 328 329 330
  }

  // Recompile the unoptimized version of the code if the current version
  // doesn't have deoptimization support. Alternatively, we may decide to
  // run the full code generator to get a baseline for the compile-time
  // performance of the hydrogen-based compiler.
331
  bool should_recompile = !info()->shared_info()->has_deoptimization_support();
332
  if (should_recompile || FLAG_hydrogen_stats) {
333
    HPhase phase(HPhase::kFullCodeGen);
334
    CompilationInfoWithZone unoptimized(info()->shared_info());
335 336
    // Note that we use the same AST that we will use for generating the
    // optimized code.
337 338
    unoptimized.SetFunction(info()->function());
    unoptimized.SetScope(info()->scope());
339
    unoptimized.SetContext(info()->context());
340 341 342
    if (should_recompile) unoptimized.EnableDeoptimizationSupport();
    bool succeeded = FullCodeGenerator::MakeCode(&unoptimized);
    if (should_recompile) {
343 344
      if (!succeeded) return SetLastStatus(FAILED);
      Handle<SharedFunctionInfo> shared = info()->shared_info();
345 346
      shared->EnableDeoptimizationSupport(*unoptimized.code());
      // The existing unoptimized code was replaced with the new one.
347 348
      Compiler::RecordFunctionCompilation(
          Logger::LAZY_COMPILE_TAG, &unoptimized, shared);
349 350 351 352 353 354 355 356
    }
  }

  // Check that the unoptimized, shared code is ready for
  // optimizations.  When using the always_opt flag we disregard the
  // optimizable marker in the code object and optimize anyway. This
  // is safe as long as the unoptimized code has deoptimization
  // support.
antonm@chromium.org's avatar
antonm@chromium.org committed
357
  ASSERT(FLAG_always_opt || code->optimizable());
358
  ASSERT(info()->shared_info()->has_deoptimization_support());
359 360 361 362

  if (FLAG_trace_hydrogen) {
    PrintF("-----------------------------------------------------------\n");
    PrintF("Compiling method %s using hydrogen\n", *name->ToCString());
363
    HTracer::Instance()->TraceCompilation(info());
364
  }
365 366
  Handle<Context> native_context(
      info()->closure()->context()->native_context());
367
  oracle_ = new(info()->zone()) TypeFeedbackOracle(
368
      code, native_context, info()->isolate(), info()->zone());
369
  graph_builder_ = new(info()->zone()) HOptimizedGraphBuilder(info(), oracle_);
370 371

  Timer t(this, &time_taken_to_create_graph_);
372 373 374 375 376
  graph_ = graph_builder_->CreateGraph();

  if (info()->isolate()->has_pending_exception()) {
    info()->SetCode(Handle<Code>::null());
    return SetLastStatus(FAILED);
377 378
  }

379 380 381 382 383 384 385 386
  // The function being compiled may have bailed out due to an inline
  // candidate bailing out.  In such a case, we don't disable
  // optimization on the shared_info.
  ASSERT(!graph_builder_->inline_bailout() || graph_ == NULL);
  if (graph_ == NULL) {
    if (graph_builder_->inline_bailout()) {
      info_->AbortOptimization();
      return SetLastStatus(BAILED_OUT);
387
    } else {
388
      return AbortOptimization();
389 390 391
    }
  }

392 393 394 395
  return SetLastStatus(SUCCEEDED);
}

OptimizingCompiler::Status OptimizingCompiler::OptimizeGraph() {
396 397
  AssertNoAllocation no_gc;
  NoHandleAllocation no_handles;
398
  NoHandleDereference no_deref;
399

400 401 402 403 404 405
  ASSERT(last_status() == SUCCEEDED);
  Timer t(this, &time_taken_to_optimize_);
  ASSERT(graph_ != NULL);
  SmartArrayPointer<char> bailout_reason;
  if (!graph_->Optimize(&bailout_reason)) {
    if (!bailout_reason.is_empty()) graph_builder_->Bailout(*bailout_reason);
406
    return SetLastStatus(BAILED_OUT);
407 408 409
  } else {
    chunk_ = LChunk::NewChunk(graph_);
    if (chunk_ == NULL) {
410
      return SetLastStatus(BAILED_OUT);
411
    }
412
  }
413 414 415 416 417 418
  return SetLastStatus(SUCCEEDED);
}


OptimizingCompiler::Status OptimizingCompiler::GenerateAndInstallCode() {
  ASSERT(last_status() == SUCCEEDED);
419 420 421 422
  {  // Scope for timer.
    Timer timer(this, &time_taken_to_codegen_);
    ASSERT(chunk_ != NULL);
    ASSERT(graph_ != NULL);
423
    Handle<Code> optimized_code = chunk_->Codegen(Code::OPTIMIZED_FUNCTION);
424 425 426 427 428
    if (optimized_code.is_null()) {
      info()->set_bailout_reason("code generation failed");
      return AbortOptimization();
    }
    info()->SetCode(optimized_code);
429
  }
430 431
  RecordOptimizationStats();
  return SetLastStatus(SUCCEEDED);
432 433 434
}


435
static bool GenerateCode(CompilationInfo* info) {
436 437 438 439
  bool is_optimizing = V8::UseCrankshaft() &&
                       !info->IsCompilingForDebugging() &&
                       info->IsOptimizing();
  if (is_optimizing) {
440
    Logger::TimerEventScope timer(
441
        info->isolate(), Logger::TimerEventScope::v8_recompile_synchronous);
442 443 444 445 446 447 448
    return MakeCrankshaftCode(info);
  } else {
    if (info->IsOptimizing()) {
      // Have the CompilationInfo decide if the compilation should be
      // BASE or NONOPT.
      info->DisableOptimization();
    }
449
    Logger::TimerEventScope timer(
450
        info->isolate(), Logger::TimerEventScope::v8_compile_full_code);
451 452
    return FullCodeGenerator::MakeCode(info);
  }
453 454 455
}


456 457 458 459
static bool MakeCode(CompilationInfo* info) {
  // Precondition: code has been parsed.  Postcondition: the code field in
  // the compilation info is set if compilation succeeded.
  ASSERT(info->function() != NULL);
460
  return Rewriter::Rewrite(info) && Scope::Analyze(info) && GenerateCode(info);
461 462 463
}


464
#ifdef ENABLE_DEBUGGER_SUPPORT
465 466 467 468
bool Compiler::MakeCodeForLiveEdit(CompilationInfo* info) {
  // Precondition: code has been parsed.  Postcondition: the code field in
  // the compilation info is set if compilation succeeded.
  bool succeeded = MakeCode(info);
469
  if (!info->shared_info().is_null()) {
470
    Handle<ScopeInfo> scope_info = ScopeInfo::Create(info->scope(),
471
                                                     info->zone());
472
    info->shared_info()->set_scope_info(*scope_info);
473
  }
474
  return succeeded;
475 476 477 478
}
#endif


479 480 481 482 483 484 485
static bool DebuggerWantsEagerCompilation(CompilationInfo* info,
                                          bool allow_lazy_without_ctx = false) {
  return LiveEditFunctionTracker::IsActive(info->isolate()) ||
         (info->isolate()->DebuggerHasBreakPoints() && !allow_lazy_without_ctx);
}


486
static Handle<SharedFunctionInfo> MakeFunctionInfo(CompilationInfo* info) {
487
  Isolate* isolate = info->isolate();
488
  ZoneScope zone_scope(info->zone(), DELETE_ON_EXIT);
489
  PostponeInterruptsScope postpone(isolate);
490

491
  ASSERT(!isolate->native_context().is_null());
492
  Handle<Script> script = info->script();
493 494 495
  // TODO(svenpanne) Obscure place for this, perhaps move to OnBeforeCompile?
  FixedArray* array = isolate->native_context()->embedder_data();
  script->set_context_data(array->get(0));
496

497
#ifdef ENABLE_DEBUGGER_SUPPORT
498 499
  if (info->is_eval()) {
    Script::CompilationType compilation_type = Script::COMPILATION_TYPE_EVAL;
500
    script->set_compilation_type(Smi::FromInt(compilation_type));
501 502
    // For eval scripts add information on the function from which eval was
    // called.
503
    if (info->is_eval()) {
504
      StackTraceFrameIterator it(isolate);
505 506 507
      if (!it.done()) {
        script->set_eval_from_shared(
            JSFunction::cast(it.frame()->function())->shared());
508
        Code* code = it.frame()->LookupCode();
509
        int offset = static_cast<int>(
510
            it.frame()->pc() - code->instruction_start());
511 512
        script->set_eval_from_instructions_offset(Smi::FromInt(offset));
      }
513 514 515
    }
  }

516
  // Notify debugger
517
  isolate->debugger()->OnBeforeCompile(script);
518
#endif
519 520

  // Only allow non-global compiles for eval.
521
  ASSERT(info->is_eval() || info->is_global());
522
  ParsingFlags flags = kNoParsingFlags;
523 524 525
  if ((info->pre_parse_data() != NULL ||
       String::cast(script->source())->length() > FLAG_min_preparse_length) &&
      !DebuggerWantsEagerCompilation(info)) {
526 527 528 529 530
    flags = kAllowLazy;
  }
  if (!ParserApi::Parse(info, flags)) {
    return Handle<SharedFunctionInfo>::null();
  }
531

532 533 534
  // Measure how long it takes to do the compilation; only take the
  // rest of the function into account to avoid overlap with the
  // parsing statistics.
535
  HistogramTimer* rate = info->is_eval()
536 537
      ? info->isolate()->counters()->compile_eval()
      : info->isolate()->counters()->compile();
538
  HistogramTimerScope timer(rate);
539 540

  // Compile the code.
541
  FunctionLiteral* lit = info->function();
542
  LiveEditFunctionTracker live_edit_tracker(isolate, lit);
543
  if (!MakeCode(info)) {
544
    if (!isolate->has_pending_exception()) isolate->StackOverflow();
545
    return Handle<SharedFunctionInfo>::null();
546 547
  }

548
  // Allocate function.
549
  ASSERT(!info->code().is_null());
550
  Handle<SharedFunctionInfo> result =
551
      isolate->factory()->NewSharedFunctionInfo(
552 553 554
          lit->name(),
          lit->materialized_literal_count(),
          info->code(),
555
          ScopeInfo::Create(info->scope(), info->zone()));
556 557 558 559

  ASSERT_EQ(RelocInfo::kNoPosition, lit->function_token_position());
  Compiler::SetFunctionInfo(result, lit, true, script);

560
  if (script->name()->IsString()) {
561
    PROFILE(isolate, CodeCreateEvent(
562 563 564
        info->is_eval()
            ? Logger::EVAL_TAG
            : Logger::ToNativeByScript(Logger::SCRIPT_TAG, *script),
565
        *info->code(),
566
        *result,
567
        String::cast(script->name())));
568 569
    GDBJIT(AddCode(Handle<String>(String::cast(script->name())),
                   script,
570 571
                   info->code(),
                   info));
572
  } else {
573
    PROFILE(isolate, CodeCreateEvent(
574 575 576
        info->is_eval()
            ? Logger::EVAL_TAG
            : Logger::ToNativeByScript(Logger::SCRIPT_TAG, *script),
577
        *info->code(),
578
        *result,
579
        isolate->heap()->empty_string()));
580
    GDBJIT(AddCode(Handle<String>(), script, info->code(), info));
581 582 583 584 585
  }

  // Hint to the runtime system used when allocating space for initial
  // property space by setting the expected number of properties for
  // the instances of the function.
586
  SetExpectedNofPropertiesFromEstimate(result, lit->expected_property_count());
587

588 589 590
  script->set_compilation_state(
      Smi::FromInt(Script::COMPILATION_STATE_COMPILED));

591
#ifdef ENABLE_DEBUGGER_SUPPORT
592
  // Notify debugger
593 594
  isolate->debugger()->OnAfterCompile(
      script, Debugger::NO_AFTER_COMPILE_FLAGS);
595
#endif
596

597
  live_edit_tracker.RecordFunctionInfo(result, lit, info->zone());
598

599
  return result;
600 601 602
}


603 604 605 606
Handle<SharedFunctionInfo> Compiler::Compile(Handle<String> source,
                                             Handle<Object> script_name,
                                             int line_offset,
                                             int column_offset,
607
                                             Handle<Context> context,
608
                                             v8::Extension* extension,
609
                                             ScriptDataImpl* pre_data,
610 611
                                             Handle<Object> script_data,
                                             NativesFlag natives) {
612
  Isolate* isolate = source->GetIsolate();
613
  int source_length = source->length();
614 615
  isolate->counters()->total_load_size()->Increment(source_length);
  isolate->counters()->total_compile_size()->Increment(source_length);
616 617

  // The VM is in the COMPILER state until exiting this function.
618 619 620
  VMState state(isolate, COMPILER);

  CompilationCache* compilation_cache = isolate->compilation_cache();
621

622
  // Do a lookup in the compilation cache but not for extensions.
623
  Handle<SharedFunctionInfo> result;
624
  if (extension == NULL) {
625 626 627
    result = compilation_cache->LookupScript(source,
                                             script_name,
                                             line_offset,
628 629
                                             column_offset,
                                             context);
630 631
  }

632
  if (result.is_null()) {
633 634 635 636 637 638 639 640
    // No cache entry found. Do pre-parsing, if it makes sense, and compile
    // the script.
    // Building preparse data that is only used immediately after is only a
    // saving if we might skip building the AST for lazily compiled functions.
    // I.e., preparse data isn't relevant when the lazy flag is off, and
    // for small sources, odds are that there aren't many functions
    // that would be compiled lazily anyway, so we skip the preparse step
    // in that case too.
641 642

    // Create a script object describing the script to be compiled.
643
    Handle<Script> script = FACTORY->NewScript(source);
644 645 646
    if (natives == NATIVES_CODE) {
      script->set_type(Smi::FromInt(Script::TYPE_NATIVE));
    }
647 648 649 650 651 652
    if (!script_name.is_null()) {
      script->set_name(*script_name);
      script->set_line_offset(Smi::FromInt(line_offset));
      script->set_column_offset(Smi::FromInt(column_offset));
    }

653
    script->set_data(script_data.is_null() ? HEAP->undefined_value()
654 655
                                           : *script_data);

656
    // Compile the function and add it to the cache.
657
    CompilationInfoWithZone info(script);
658 659 660
    info.MarkAsGlobal();
    info.SetExtension(extension);
    info.SetPreParseData(pre_data);
661
    info.SetContext(context);
662 663 664
    if (FLAG_use_strict) {
      info.SetLanguageMode(FLAG_harmony_scoping ? EXTENDED_MODE : STRICT_MODE);
    }
665
    result = MakeFunctionInfo(&info);
666
    if (extension == NULL && !result.is_null() && !result->dont_cache()) {
667
      compilation_cache->PutScript(source, context, result);
668
    }
669 670 671 672
  } else {
    if (result->ic_age() != HEAP->global_ic_age()) {
      result->ResetForNewContext(HEAP->global_ic_age());
    }
673 674
  }

675
  if (result.is_null()) isolate->ReportPendingMessages();
676 677 678 679
  return result;
}


680 681
Handle<SharedFunctionInfo> Compiler::CompileEval(Handle<String> source,
                                                 Handle<Context> context,
682
                                                 bool is_global,
683
                                                 LanguageMode language_mode,
684
                                                 int scope_position) {
685
  Isolate* isolate = source->GetIsolate();
686
  int source_length = source->length();
687 688
  isolate->counters()->total_eval_size()->Increment(source_length);
  isolate->counters()->total_compile_size()->Increment(source_length);
689 690

  // The VM is in the COMPILER state until exiting this function.
691
  VMState state(isolate, COMPILER);
692

693
  // Do a lookup in the compilation cache; if the entry is not there, invoke
694
  // the compiler and add the result to the cache.
695
  Handle<SharedFunctionInfo> result;
696 697 698 699
  CompilationCache* compilation_cache = isolate->compilation_cache();
  result = compilation_cache->LookupEval(source,
                                         context,
                                         is_global,
700
                                         language_mode,
701
                                         scope_position);
702

703 704
  if (result.is_null()) {
    // Create a script object describing the script to be compiled.
705
    Handle<Script> script = isolate->factory()->NewScript(source);
706
    CompilationInfoWithZone info(script);
707 708
    info.MarkAsEval();
    if (is_global) info.MarkAsGlobal();
709
    info.SetLanguageMode(language_mode);
710
    info.SetContext(context);
711
    result = MakeFunctionInfo(&info);
712
    if (!result.is_null()) {
713 714
      // Explicitly disable optimization for eval code. We're not yet prepared
      // to handle eval-code in the optimizing compiler.
715
      result->DisableOptimization("eval");
716

717 718
      // If caller is strict mode, the result must be in strict mode or
      // extended mode as well, but not the other way around. Consider:
719
      // eval("'use strict'; ...");
720 721 722 723 724
      ASSERT(language_mode != STRICT_MODE || !result->is_classic_mode());
      // If caller is in extended mode, the result must also be in
      // extended mode.
      ASSERT(language_mode != EXTENDED_MODE ||
             result->is_extended_mode());
725 726 727 728
      if (!result->dont_cache()) {
        compilation_cache->PutEval(
            source, context, is_global, result, scope_position);
      }
729
    }
730 731 732 733
  } else {
    if (result->ic_age() != HEAP->global_ic_age()) {
      result->ResetForNewContext(HEAP->global_ic_age());
    }
734
  }
735

736
  return result;
737 738 739
}


740 741 742 743 744 745 746 747 748 749 750 751
static bool InstallFullCode(CompilationInfo* info) {
  // Update the shared function info with the compiled code and the
  // scope info.  Please note, that the order of the shared function
  // info initialization is important since set_scope_info might
  // trigger a GC, causing the ASSERT below to be invalid if the code
  // was flushed. By setting the code object last we avoid this.
  Handle<SharedFunctionInfo> shared = info->shared_info();
  Handle<Code> code = info->code();
  Handle<JSFunction> function = info->closure();
  Handle<ScopeInfo> scope_info =
      ScopeInfo::Create(info->scope(), info->zone());
  shared->set_scope_info(*scope_info);
752
  shared->ReplaceCode(*code);
753 754 755 756
  if (!function.is_null()) {
    function->ReplaceCode(*code);
    ASSERT(!function->IsOptimized());
  }
757

758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776
  // Set the expected number of properties for instances.
  FunctionLiteral* lit = info->function();
  int expected = lit->expected_property_count();
  SetExpectedNofPropertiesFromEstimate(shared, expected);

  // Set the optimization hints after performing lazy compilation, as
  // these are not set when the function is set up as a lazily
  // compiled function.
  shared->SetThisPropertyAssignmentsInfo(
      lit->has_only_simple_this_property_assignments(),
      *lit->this_property_assignments());

  // Check the function has compiled code.
  ASSERT(shared->is_compiled());
  shared->set_code_age(0);
  shared->set_dont_optimize(lit->flags()->Contains(kDontOptimize));
  shared->set_dont_inline(lit->flags()->Contains(kDontInline));
  shared->set_ast_node_count(lit->ast_node_count());

777
  if (V8::UseCrankshaft() &&
778 779 780 781 782 783 784 785
      !function.is_null() &&
      !shared->optimization_disabled()) {
    // If we're asked to always optimize, we compile the optimized
    // version of the function right away - unless the debugger is
    // active as it makes no sense to compile optimized code then.
    if (FLAG_always_opt &&
        !Isolate::Current()->DebuggerHasBreakPoints()) {
      CompilationInfoWithZone optimized(function);
786
      optimized.SetOptimizing(BailoutId::None());
787 788 789 790 791
      return Compiler::CompileLazy(&optimized);
    }
  }
  return true;
}
792 793


794
static void InstallCodeCommon(CompilationInfo* info) {
795
  Handle<SharedFunctionInfo> shared = info->shared_info();
796 797 798 799 800 801 802
  Handle<Code> code = info->code();
  ASSERT(!code.is_null());

  // Set optimizable to false if this is disallowed by the shared
  // function info, e.g., we might have flushed the code and must
  // reset this bit when lazy compiling the code again.
  if (shared->optimization_disabled()) code->set_optimizable(false);
803

804 805 806 807 808 809
  Compiler::RecordFunctionCompilation(Logger::LAZY_COMPILE_TAG, info, shared);
}


static void InsertCodeIntoOptimizedCodeMap(CompilationInfo* info) {
  Handle<Code> code = info->code();
810 811 812 813
  if (FLAG_cache_optimized_code &&
      info->osr_ast_id().IsNone() &&
      code->kind() == Code::OPTIMIZED_FUNCTION) {
    Handle<JSFunction> function = info->closure();
814 815
    Handle<SharedFunctionInfo> shared(function->shared());
    Handle<FixedArray> literals(function->literals());
816
    Handle<Context> native_context(function->context()->native_context());
817
    SharedFunctionInfo::AddToOptimizedCodeMap(
818
        shared, native_context, code, literals);
819 820 821 822 823
  }
}


static bool InstallCodeFromOptimizedCodeMap(CompilationInfo* info) {
824 825 826
  if (FLAG_cache_optimized_code &&
      info->osr_ast_id().IsNone() &&
      info->IsOptimizing()) {
827
    Handle<SharedFunctionInfo> shared = info->shared_info();
828 829
    Handle<JSFunction> function = info->closure();
    ASSERT(!function.is_null());
830 831
    Handle<Context> native_context(function->context()->native_context());
    int index = shared->SearchOptimizedCodeMap(*native_context);
832 833
    if (index > 0) {
      if (FLAG_trace_opt) {
834
        PrintF("[found optimized code for: ");
835
        function->PrintName();
836
        PrintF(" / %" V8PRIxPTR "]\n", reinterpret_cast<intptr_t>(*function));
837
      }
838 839
      // Caching of optimized code enabled and optimized code found.
      shared->InstallFromOptimizedCodeMap(*function, index);
840 841 842
      return true;
    }
  }
843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861
  return false;
}


bool Compiler::CompileLazy(CompilationInfo* info) {
  Isolate* isolate = info->isolate();

  ZoneScope zone_scope(info->zone(), DELETE_ON_EXIT);

  // The VM is in the COMPILER state until exiting this function.
  VMState state(isolate, COMPILER);

  PostponeInterruptsScope postpone(isolate);

  Handle<SharedFunctionInfo> shared = info->shared_info();
  int compiled_size = shared->end_position() - shared->start_position();
  isolate->counters()->total_compile_size()->Increment(compiled_size);

  if (InstallCodeFromOptimizedCodeMap(info)) return true;
862

863
  // Generate the AST for the lazily compiled function.
864
  if (ParserApi::Parse(info, kNoParsingFlags)) {
865 866 867
    // Measure how long it takes to do the lazy compilation; only take the
    // rest of the function into account to avoid overlap with the lazy
    // parsing statistics.
868
    HistogramTimerScope timer(isolate->counters()->compile_lazy());
869

870 871 872 873
    // After parsing we know the function's language mode. Remember it.
    LanguageMode language_mode = info->function()->language_mode();
    info->SetLanguageMode(language_mode);
    shared->set_language_mode(language_mode);
mmaly@chromium.org's avatar
mmaly@chromium.org committed
874

875 876
    // Compile the code.
    if (!MakeCode(info)) {
877 878
      if (!isolate->has_pending_exception()) {
        isolate->StackOverflow();
879
      }
880
    } else {
881
      InstallCodeCommon(info);
882

883
      if (info->IsOptimizing()) {
884
        Handle<Code> code = info->code();
885
        ASSERT(shared->scope_info() != ScopeInfo::Empty());
886 887 888
        info->closure()->ReplaceCode(*code);
        InsertCodeIntoOptimizedCodeMap(info);
        return true;
889
      } else {
890
        return InstallFullCode(info);
891 892
      }
    }
893
  }
894

895 896
  ASSERT(info->code().is_null());
  return false;
897 898 899
}


900 901
void Compiler::RecompileParallel(Handle<JSFunction> closure) {
  if (closure->IsInRecompileQueue()) return;
902
  ASSERT(closure->IsMarkedForParallelRecompilation());
903 904

  Isolate* isolate = closure->GetIsolate();
905 906 907
  // Here we prepare compile data for the parallel recompilation thread, but
  // this still happens synchronously and interrupts execution.
  Logger::TimerEventScope timer(
908
      isolate, Logger::TimerEventScope::v8_recompile_synchronous);
909

910 911 912 913 914 915 916 917
  if (!isolate->optimizing_compiler_thread()->IsQueueAvailable()) {
    if (FLAG_trace_parallel_recompilation) {
      PrintF("  ** Compilation queue, will retry opting on next run.\n");
    }
    return;
  }

  SmartPointer<CompilationInfo> info(new CompilationInfoWithZone(closure));
918
  VMState state(isolate, PARALLEL_COMPILER);
919 920 921 922 923
  PostponeInterruptsScope postpone(isolate);

  Handle<SharedFunctionInfo> shared = info->shared_info();
  int compiled_size = shared->end_position() - shared->start_position();
  isolate->counters()->total_compile_size()->Increment(compiled_size);
924
  info->SetOptimizing(BailoutId::None());
925 926 927 928

  {
    CompilationHandleScope handle_scope(*info);

929 930 931 932
    if (!FLAG_manual_parallel_recompilation &&
        InstallCodeFromOptimizedCodeMap(*info)) {
      return;
    }
933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965

    if (ParserApi::Parse(*info, kNoParsingFlags)) {
      LanguageMode language_mode = info->function()->language_mode();
      info->SetLanguageMode(language_mode);
      shared->set_language_mode(language_mode);
      info->SaveHandles();

      if (Rewriter::Rewrite(*info) && Scope::Analyze(*info)) {
        OptimizingCompiler* compiler =
            new(info->zone()) OptimizingCompiler(*info);
        OptimizingCompiler::Status status = compiler->CreateGraph();
        if (status == OptimizingCompiler::SUCCEEDED) {
          isolate->optimizing_compiler_thread()->QueueForOptimization(compiler);
          shared->code()->set_profiler_ticks(0);
          closure->ReplaceCode(isolate->builtins()->builtin(
              Builtins::kInRecompileQueue));
          info.Detach();
        } else if (status == OptimizingCompiler::BAILED_OUT) {
          isolate->clear_pending_exception();
          InstallFullCode(*info);
        }
      }
    }
  }

  if (isolate->has_pending_exception()) {
    isolate->clear_pending_exception();
  }
}


void Compiler::InstallOptimizedCode(OptimizingCompiler* optimizing_compiler) {
  SmartPointer<CompilationInfo> info(optimizing_compiler->info());
966 967 968
  Isolate* isolate = info->isolate();
  VMState state(isolate, PARALLEL_COMPILER);
  Logger::TimerEventScope timer(
969
      isolate, Logger::TimerEventScope::v8_recompile_synchronous);
970 971 972 973
  // If crankshaft succeeded, install the optimized code else install
  // the unoptimized code.
  OptimizingCompiler::Status status = optimizing_compiler->last_status();
  if (status != OptimizingCompiler::SUCCEEDED) {
974 975
    optimizing_compiler->info()->set_bailout_reason(
        "failed/bailed out last time");
976 977 978 979 980 981 982 983 984 985 986 987 988
    status = optimizing_compiler->AbortOptimization();
  } else {
    status = optimizing_compiler->GenerateAndInstallCode();
    ASSERT(status == OptimizingCompiler::SUCCEEDED ||
           status == OptimizingCompiler::BAILED_OUT);
  }

  InstallCodeCommon(*info);
  if (status == OptimizingCompiler::SUCCEEDED) {
    Handle<Code> code = info->code();
    ASSERT(info->shared_info()->scope_info() != ScopeInfo::Empty());
    info->closure()->ReplaceCode(*code);
    if (info->shared_info()->SearchOptimizedCodeMap(
989
            info->closure()->context()->native_context()) == -1) {
990 991 992 993 994 995 996 997 998
      InsertCodeIntoOptimizedCodeMap(*info);
    }
  } else {
    info->SetCode(Handle<Code>(info->shared_info()->code()));
    InstallFullCode(*info);
  }
}


999
Handle<SharedFunctionInfo> Compiler::BuildFunctionInfo(FunctionLiteral* literal,
1000 1001
                                                       Handle<Script> script) {
  // Precondition: code has been parsed and scopes have been analyzed.
1002
  CompilationInfoWithZone info(script);
1003 1004
  info.SetFunction(literal);
  info.SetScope(literal->scope());
1005
  info.SetLanguageMode(literal->scope()->language_mode());
1006

1007
  LiveEditFunctionTracker live_edit_tracker(info.isolate(), literal);
1008 1009 1010 1011 1012
  // Determine if the function can be lazily compiled. This is necessary to
  // allow some of our builtin JS files to be lazily compiled. These
  // builtins cannot be handled lazily by the parser, since we have to know
  // if a function uses the special natives syntax, which is something the
  // parser records.
1013 1014 1015
  // If the debugger requests compilation for break points, we cannot be
  // aggressive about lazy compilation, because it might trigger compilation
  // of functions without an outer context when setting a breakpoint through
1016
  // Debug::FindSharedFunctionInfoInScript.
1017
  bool allow_lazy_without_ctx = literal->AllowsLazyCompilationWithoutContext();
1018
  bool allow_lazy = literal->AllowsLazyCompilation() &&
1019
      !DebuggerWantsEagerCompilation(&info, allow_lazy_without_ctx);
1020

1021
  Handle<ScopeInfo> scope_info(ScopeInfo::Empty());
1022

1023
  // Generate code
1024
  if (FLAG_lazy && allow_lazy && !literal->is_parenthesized()) {
1025
    Handle<Code> code = info.isolate()->builtins()->LazyCompile();
1026
    info.SetCode(code);
1027
  } else if (GenerateCode(&info)) {
1028
    ASSERT(!info.code().is_null());
1029
    scope_info = ScopeInfo::Create(info.scope(), info.zone());
1030 1031
  } else {
    return Handle<SharedFunctionInfo>::null();
1032 1033
  }

1034
  // Create a shared function info object.
1035
  Handle<SharedFunctionInfo> result =
1036
      FACTORY->NewSharedFunctionInfo(literal->name(),
1037
                                     literal->materialized_literal_count(),
1038
                                     info.code(),
1039
                                     scope_info);
1040
  SetFunctionInfo(result, literal, false, script);
1041
  RecordFunctionCompilation(Logger::FUNCTION_TAG, &info, result);
1042
  result->set_allows_lazy_compilation(allow_lazy);
1043
  result->set_allows_lazy_compilation_without_context(allow_lazy_without_ctx);
1044 1045 1046

  // Set the expected number of properties for instances and return
  // the resulting function.
1047
  SetExpectedNofPropertiesFromEstimate(result,
1048
                                       literal->expected_property_count());
1049
  live_edit_tracker.RecordFunctionInfo(result, literal, info.zone());
1050
  return result;
1051 1052 1053 1054 1055 1056 1057
}


// Sets the function info on a function.
// The start_position points to the first '(' character after the function name
// in the full script source. When counting characters in the script source the
// the first character is number 0 (not 1).
1058
void Compiler::SetFunctionInfo(Handle<SharedFunctionInfo> function_info,
1059 1060 1061
                               FunctionLiteral* lit,
                               bool is_toplevel,
                               Handle<Script> script) {
1062 1063
  function_info->set_length(lit->parameter_count());
  function_info->set_formal_parameter_count(lit->parameter_count());
1064 1065 1066 1067 1068
  function_info->set_script(*script);
  function_info->set_function_token_position(lit->function_token_position());
  function_info->set_start_position(lit->start_position());
  function_info->set_end_position(lit->end_position());
  function_info->set_is_expression(lit->is_expression());
1069
  function_info->set_is_anonymous(lit->is_anonymous());
1070 1071 1072
  function_info->set_is_toplevel(is_toplevel);
  function_info->set_inferred_name(*lit->inferred_name());
  function_info->SetThisPropertyAssignmentsInfo(
1073 1074
      lit->has_only_simple_this_property_assignments(),
      *lit->this_property_assignments());
1075
  function_info->set_allows_lazy_compilation(lit->AllowsLazyCompilation());
1076 1077
  function_info->set_allows_lazy_compilation_without_context(
      lit->AllowsLazyCompilationWithoutContext());
1078
  function_info->set_language_mode(lit->language_mode());
1079 1080
  function_info->set_uses_arguments(lit->scope()->arguments() != NULL);
  function_info->set_has_duplicate_parameters(lit->has_duplicate_parameters());
1081
  function_info->set_ast_node_count(lit->ast_node_count());
1082 1083
  function_info->set_is_function(lit->is_function());
  function_info->set_dont_optimize(lit->flags()->Contains(kDontOptimize));
1084
  function_info->set_dont_inline(lit->flags()->Contains(kDontInline));
1085
  function_info->set_dont_cache(lit->flags()->Contains(kDontCache));
1086 1087 1088
}


1089
void Compiler::RecordFunctionCompilation(Logger::LogEventsAndTags tag,
1090 1091 1092 1093 1094
                                         CompilationInfo* info,
                                         Handle<SharedFunctionInfo> shared) {
  // SharedFunctionInfo is passed separately, because if CompilationInfo
  // was created using Script object, it will not have it.

1095 1096 1097
  // Log the code generation. If source information is available include
  // script name and line number. Check explicitly whether logging is
  // enabled as finding the line number is not free.
1098
  if (info->isolate()->logger()->is_logging_code_events() ||
1099
      CpuProfiler::is_profiling(info->isolate())) {
1100 1101
    Handle<Script> script = info->script();
    Handle<Code> code = info->code();
1102
    if (*code == info->isolate()->builtins()->builtin(Builtins::kLazyCompile))
1103
      return;
1104
    if (script->name()->IsString()) {
1105
      int line_num = GetScriptLineNumber(script, shared->start_position()) + 1;
1106
      USE(line_num);
1107 1108
      PROFILE(info->isolate(),
              CodeCreateEvent(Logger::ToNativeByScript(tag, *script),
1109
                              *code,
1110
                              *shared,
1111 1112
                              String::cast(script->name()),
                              line_num));
1113
    } else {
1114 1115
      PROFILE(info->isolate(),
              CodeCreateEvent(Logger::ToNativeByScript(tag, *script),
1116
                              *code,
1117 1118
                              *shared,
                              shared->DebugName()));
1119 1120
    }
  }
1121

1122
  GDBJIT(AddCode(Handle<String>(shared->DebugName()),
1123
                 Handle<Script>(info->script()),
1124 1125
                 Handle<Code>(info->code()),
                 info));
1126 1127
}

1128
} }  // namespace v8::internal