compiler.cc 65.2 KB
Newer Older
1
// Copyright 2012 the V8 project authors. All rights reserved.
2 3
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
4

5
#include "src/compiler.h"
6

7 8
#include <algorithm>

9
#include "src/ast-numbering.h"
10 11 12
#include "src/bootstrapper.h"
#include "src/codegen.h"
#include "src/compilation-cache.h"
13
#include "src/compiler/pipeline.h"
14 15
#include "src/debug/debug.h"
#include "src/debug/liveedit.h"
16
#include "src/deoptimizer.h"
17
#include "src/full-codegen/full-codegen.h"
18 19
#include "src/gdb-jit.h"
#include "src/hydrogen.h"
20
#include "src/interpreter/interpreter.h"
21
#include "src/isolate-inl.h"
22
#include "src/lithium.h"
23
#include "src/log-inl.h"
24
#include "src/messages.h"
25
#include "src/parser.h"
26
#include "src/prettyprinter.h"
27
#include "src/profiler/cpu-profiler.h"
28 29 30 31 32
#include "src/rewriter.h"
#include "src/runtime-profiler.h"
#include "src/scanner-character-streams.h"
#include "src/scopeinfo.h"
#include "src/scopes.h"
33
#include "src/snapshot/serialize.h"
34
#include "src/typing.h"
35
#include "src/vm-state-inl.h"
36

37 38
namespace v8 {
namespace internal {
39

40 41 42 43 44 45 46 47 48 49 50
std::ostream& operator<<(std::ostream& os, const SourcePosition& p) {
  if (p.IsUnknown()) {
    return os << "<?>";
  } else if (FLAG_hydrogen_track_positions) {
    return os << "<" << p.inlining_id() << ":" << p.position() << ">";
  } else {
    return os << "<0:" << p.raw() << ">";
  }
}


51 52 53 54
#define PARSE_INFO_GETTER(type, name)  \
  type CompilationInfo::name() const { \
    CHECK(parse_info());               \
    return parse_info()->name();       \
55 56 57
  }


58 59 60 61
#define PARSE_INFO_GETTER_WITH_DEFAULT(type, name, def) \
  type CompilationInfo::name() const {                  \
    return parse_info() ? parse_info()->name() : def;   \
  }
62 63


64 65 66 67
PARSE_INFO_GETTER(Handle<Script>, script)
PARSE_INFO_GETTER(bool, is_eval)
PARSE_INFO_GETTER(bool, is_native)
PARSE_INFO_GETTER(bool, is_module)
68
PARSE_INFO_GETTER(FunctionLiteral*, literal)
svenpanne's avatar
svenpanne committed
69
PARSE_INFO_GETTER_WITH_DEFAULT(LanguageMode, language_mode, STRICT)
70 71 72 73 74 75 76 77 78 79
PARSE_INFO_GETTER_WITH_DEFAULT(Handle<JSFunction>, closure,
                               Handle<JSFunction>::null())
PARSE_INFO_GETTER_WITH_DEFAULT(Scope*, scope, nullptr)
PARSE_INFO_GETTER(Handle<Context>, context)
PARSE_INFO_GETTER(Handle<SharedFunctionInfo>, shared_info)

#undef PARSE_INFO_GETTER
#undef PARSE_INFO_GETTER_WITH_DEFAULT


80 81 82 83 84 85 86 87 88 89 90 91
// Exactly like a CompilationInfo, except being allocated via {new} and it also
// creates and enters a Zone on construction and deallocates it on destruction.
class CompilationInfoWithZone : public CompilationInfo {
 public:
  explicit CompilationInfoWithZone(Handle<JSFunction> function)
      : CompilationInfo(new ParseInfo(&zone_, function)) {}

  // Virtual destructor because a CompilationInfoWithZone has to exit the
  // zone scope and get rid of dependent maps even when the destructor is
  // called when cast as a CompilationInfo.
  virtual ~CompilationInfoWithZone() {
    DisableFutureOptimization();
92
    dependencies()->Rollback();
93 94 95 96 97 98 99 100 101
    delete parse_info_;
    parse_info_ = nullptr;
  }

 private:
  Zone zone_;
};


102 103
bool CompilationInfo::has_shared_info() const {
  return parse_info_ && !parse_info_->shared_info().is_null();
104 105 106
}


107 108 109 110 111
bool CompilationInfo::has_context() const {
  return parse_info_ && !parse_info_->context().is_null();
}


112 113 114 115 116 117 118 119 120 121
bool CompilationInfo::has_literal() const {
  return parse_info_ && parse_info_->literal() != nullptr;
}


bool CompilationInfo::has_scope() const {
  return parse_info_ && parse_info_->scope() != nullptr;
}


122
CompilationInfo::CompilationInfo(ParseInfo* parse_info)
123
    : CompilationInfo(parse_info, nullptr, nullptr, BASE, parse_info->isolate(),
124
                      parse_info->zone()) {
125 126 127 128 129 130 131 132
  // Compiling for the snapshot typically results in different code than
  // compiling later on. This means that code recompiled with deoptimization
  // support won't be "equivalent" (as defined by SharedFunctionInfo::
  // EnableDeoptimizationSupport), so it will replace the old code and all
  // its type feedback. To avoid this, always compile functions in the snapshot
  // with deoptimization support.
  if (isolate_->serializer_enabled()) EnableDeoptimizationSupport();

133
  if (FLAG_function_context_specialization) MarkAsFunctionContextSpecializing();
134
  if (FLAG_turbo_inlining) MarkAsInliningEnabled();
135
  if (FLAG_turbo_source_positions) MarkAsSourcePositionsEnabled();
136
  if (FLAG_turbo_splitting) MarkAsSplittingEnabled();
137
  if (FLAG_turbo_types) MarkAsTypingEnabled();
138

139 140 141 142 143 144 145 146
  if (has_shared_info()) {
    if (shared_info()->is_compiled()) {
      // We should initialize the CompilationInfo feedback vector from the
      // passed in shared info, rather than creating a new one.
      feedback_vector_ = Handle<TypeFeedbackVector>(
          shared_info()->feedback_vector(), parse_info->isolate());
    }
    if (shared_info()->never_compiled()) MarkAsFirstCompile();
147
  }
148 149 150
}


151
CompilationInfo::CompilationInfo(CodeStub* stub, Isolate* isolate, Zone* zone)
152 153
    : CompilationInfo(nullptr, stub, CodeStub::MajorName(stub->MajorKey()),
                      STUB, isolate, zone) {}
154

155 156
CompilationInfo::CompilationInfo(const char* debug_name, Isolate* isolate,
                                 Zone* zone)
157 158 159
    : CompilationInfo(nullptr, nullptr, debug_name, STUB, isolate, zone) {
  set_output_code_kind(Code::STUB);
}
160 161

CompilationInfo::CompilationInfo(ParseInfo* parse_info, CodeStub* code_stub,
162
                                 const char* debug_name, Mode mode,
163
                                 Isolate* isolate, Zone* zone)
164 165 166 167 168 169 170 171
    : parse_info_(parse_info),
      isolate_(isolate),
      flags_(0),
      code_stub_(code_stub),
      mode_(mode),
      osr_ast_id_(BailoutId::None()),
      zone_(zone),
      deferred_handles_(nullptr),
172
      dependencies_(isolate, zone),
173 174
      bailout_reason_(kNoReason),
      prologue_offset_(Code::kPrologueOffsetNotSet),
175 176
      track_positions_(FLAG_hydrogen_track_positions ||
                       isolate->cpu_profiler()->is_profiling()),
177 178 179
      opt_count_(has_shared_info() ? shared_info()->opt_count() : 0),
      parameter_count_(0),
      optimization_id_(-1),
180
      osr_expr_stack_height_(0),
181
      function_type_(nullptr),
182
      debug_name_(debug_name) {
183 184 185 186 187 188 189
  // Parameter count is number of stack parameters.
  if (code_stub_ != NULL) {
    CodeStubDescriptor descriptor(code_stub_);
    parameter_count_ = descriptor.GetStackParameterCount();
    if (descriptor.function_mode() == NOT_JS_FUNCTION_STUB_MODE) {
      parameter_count_--;
    }
190 191 192
    set_output_code_kind(code_stub->GetCodeKind());
  } else {
    set_output_code_kind(Code::FUNCTION);
193 194
  }
}
195 196


197
CompilationInfo::~CompilationInfo() {
198
  DisableFutureOptimization();
199
  delete deferred_handles_;
200 201 202
#ifdef DEBUG
  // Check that no dependent maps have been added or added dependent maps have
  // been rolled back or committed.
203
  DCHECK(dependencies()->IsEmpty());
204 205 206 207
#endif  // DEBUG
}


208 209 210
void CompilationInfo::SetStub(CodeStub* code_stub) {
  SetMode(STUB);
  code_stub_ = code_stub;
211
  debug_name_ = CodeStub::MajorName(code_stub->MajorKey());
212
  set_output_code_kind(code_stub->GetCodeKind());
213 214 215
}


216
int CompilationInfo::num_parameters() const {
217
  return has_scope() ? scope()->num_parameters() : parameter_count_;
218 219 220
}


221 222 223 224 225 226 227 228
int CompilationInfo::num_parameters_including_this() const {
  return num_parameters() + (is_this_defined() ? 1 : 0);
}


bool CompilationInfo::is_this_defined() const { return !IsStub(); }


229
int CompilationInfo::num_heap_slots() const {
230
  return has_scope() ? scope()->num_heap_slots() : 0;
231 232 233
}


234 235 236 237
// 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() {
238
  return FLAG_crankshaft &&
239 240 241
         !(literal()->flags() & AstProperties::kDontSelfOptimize) &&
         !literal()->dont_optimize() &&
         literal()->scope()->AllowsLazyCompilation() &&
242
         (!has_shared_info() || !shared_info()->optimization_disabled());
243 244
}

245

246
void CompilationInfo::EnsureFeedbackVector() {
247
  if (feedback_vector_.is_null()) {
248 249 250
    Handle<TypeFeedbackMetadata> feedback_metadata =
        TypeFeedbackMetadata::New(isolate(), literal()->feedback_vector_spec());
    feedback_vector_ = TypeFeedbackVector::New(isolate(), feedback_metadata);
251
  }
252 253 254

  // It's very important that recompiles do not alter the structure of the
  // type feedback vector.
255 256
  CHECK(!feedback_vector_->metadata()->SpecDiffersFrom(
      literal()->feedback_vector_spec()));
257 258 259
}


260 261
bool CompilationInfo::has_simple_parameters() {
  return scope()->has_simple_parameters();
262
}
263 264 265


int CompilationInfo::TraceInlinedFunction(Handle<SharedFunctionInfo> shared,
266 267
                                          SourcePosition position,
                                          int parent_id) {
268
  DCHECK(track_positions_);
269

270
  int inline_id = static_cast<int>(inlined_function_infos_.size());
271 272 273 274
  InlinedFunctionInfo info(parent_id, position, UnboundScript::kNoScriptId,
      shared->start_position());
  if (!shared->script()->IsUndefined()) {
    Handle<Script> script(Script::cast(shared->script()));
275
    info.script_id = script->id();
276

277
    if (FLAG_hydrogen_track_positions && !script->source()->IsUndefined()) {
278 279 280 281 282 283 284 285 286 287 288 289 290
      CodeTracer::Scope tracing_scope(isolate()->GetCodeTracer());
      OFStream os(tracing_scope.file());
      os << "--- FUNCTION SOURCE (" << shared->DebugName()->ToCString().get()
         << ") id{" << optimization_id() << "," << inline_id << "} ---\n";
      {
        DisallowHeapAllocation no_allocation;
        int start = shared->start_position();
        int len = shared->end_position() - start;
        String::SubStringRange source(String::cast(script->source()), start,
                                      len);
        for (const auto& c : source) {
          os << AsReversiblyEscapedUC16(c);
        }
291
      }
292 293

      os << "\n--- END ---\n";
294 295 296
    }
  }

297
  inlined_function_infos_.push_back(info);
298

299
  if (FLAG_hydrogen_track_positions && inline_id != 0) {
300 301 302
    CodeTracer::Scope tracing_scope(isolate()->GetCodeTracer());
    OFStream os(tracing_scope.file());
    os << "INLINE (" << shared->DebugName()->ToCString().get() << ") id{"
303 304
       << optimization_id() << "," << inline_id << "} AS " << inline_id
       << " AT " << position << std::endl;
305 306 307 308
  }

  return inline_id;
}
309 310


311 312
void CompilationInfo::LogDeoptCallPosition(int pc_offset, int inlining_id) {
  if (!track_positions_ || IsStub()) return;
313 314
  DCHECK_LT(static_cast<size_t>(inlining_id), inlined_function_infos_.size());
  inlined_function_infos_.at(inlining_id).deopt_pc_offsets.push_back(pc_offset);
315 316 317
}


318
base::SmartArrayPointer<char> CompilationInfo::GetDebugName() const {
319
  if (parse_info()) {
320
    AllowHandleDereference allow_deref;
321
    return parse_info()->literal()->debug_name()->ToCString();
322
  }
323 324 325 326 327
  const char* str = debug_name_ ? debug_name_ : "unknown";
  size_t len = strlen(str) + 1;
  base::SmartArrayPointer<char> name(new char[len]);
  memcpy(name.get(), str, len);
  return name;
328 329 330
}


331 332 333 334 335 336
bool CompilationInfo::MustReplaceUndefinedReceiverWithGlobalProxy() {
  return is_sloppy(language_mode()) && !is_native() &&
         scope()->has_this_declaration() && scope()->receiver()->is_used();
}


337
class HOptimizedGraphBuilderWithPositions: public HOptimizedGraphBuilder {
338
 public:
339
  explicit HOptimizedGraphBuilderWithPositions(CompilationInfo* info)
340 341 342
      : HOptimizedGraphBuilder(info) {
  }

343
#define DEF_VISIT(type)                                      \
344
  void Visit##type(type* node) override {                    \
345 346 347 348 349 350 351 352 353
    SourcePosition old_position = SourcePosition::Unknown(); \
    if (node->position() != RelocInfo::kNoPosition) {        \
      old_position = source_position();                      \
      SetSourcePosition(node->position());                   \
    }                                                        \
    HOptimizedGraphBuilder::Visit##type(node);               \
    if (!old_position.IsUnknown()) {                         \
      set_source_position(old_position);                     \
    }                                                        \
354 355 356 357
  }
  EXPRESSION_NODE_LIST(DEF_VISIT)
#undef DEF_VISIT

358
#define DEF_VISIT(type)                                      \
359
  void Visit##type(type* node) override {                    \
360 361 362 363 364 365 366 367 368
    SourcePosition old_position = SourcePosition::Unknown(); \
    if (node->position() != RelocInfo::kNoPosition) {        \
      old_position = source_position();                      \
      SetSourcePosition(node->position());                   \
    }                                                        \
    HOptimizedGraphBuilder::Visit##type(node);               \
    if (!old_position.IsUnknown()) {                         \
      set_source_position(old_position);                     \
    }                                                        \
369 370 371 372
  }
  STATEMENT_NODE_LIST(DEF_VISIT)
#undef DEF_VISIT

373
#define DEF_VISIT(type)                        \
374
  void Visit##type(type* node) override {      \
375
    HOptimizedGraphBuilder::Visit##type(node); \
376 377 378 379 380 381
  }
  DECLARATION_NODE_LIST(DEF_VISIT)
#undef DEF_VISIT
};


382
OptimizedCompileJob::Status OptimizedCompileJob::CreateGraph() {
383
  DCHECK(info()->IsOptimizing());
384

385
  // Do not use Crankshaft/TurboFan if we need to be able to set break points.
386 387
  if (info()->shared_info()->HasDebugInfo()) {
    return AbortOptimization(kFunctionBeingDebugged);
388
  }
389

390
  // Limit the number of times we try to optimize functions.
391
  const int kMaxOptCount =
392
      FLAG_deopt_every_n_times == 0 ? FLAG_max_opt_count : 1000;
393
  if (info()->opt_count() > kMaxOptCount) {
394
    return AbortOptimization(kOptimizedTooManyTimes);
395 396
  }

397
  // Check the whitelist for Crankshaft.
398
  if (!info()->closure()->PassesFilter(FLAG_hydrogen_filter)) {
399
    return AbortOptimization(kHydrogenFilter);
400 401
  }

402
  // Optimization requires a version of fullcode with deoptimization support.
403
  // Recompile the unoptimized version of the code if the current version
404 405 406
  // doesn't have deoptimization support already.
  // Otherwise, if we are gathering compilation time and space statistics
  // for hydrogen, gather baseline statistics for a fullcode compilation.
407
  bool should_recompile = !info()->shared_info()->has_deoptimization_support();
408
  if (should_recompile || FLAG_hydrogen_stats) {
409
    base::ElapsedTimer timer;
410
    if (FLAG_hydrogen_stats) {
411
      timer.Start();
412
    }
413 414
    if (!Compiler::EnsureDeoptimizationSupport(info())) {
      return SetLastStatus(FAILED);
415
    }
416
    if (FLAG_hydrogen_stats) {
417
      isolate()->GetHStatistics()->IncrementFullCodeGen(timer.Elapsed());
418
    }
419 420
  }

421
  DCHECK(info()->shared_info()->has_deoptimization_support());
422
  DCHECK(!info()->is_first_compile());
423

424
  // Check the enabling conditions for TurboFan.
425
  bool dont_crankshaft = info()->shared_info()->dont_crankshaft();
426
  if (((FLAG_turbo_asm && info()->shared_info()->asm_function()) ||
427
       (dont_crankshaft && strcmp(FLAG_turbo_filter, "~~") == 0) ||
428 429
       info()->closure()->PassesFilter(FLAG_turbo_filter)) &&
      (FLAG_turbo_osr || !info()->is_osr())) {
430
    // Use TurboFan for the compilation.
431 432 433
    if (FLAG_trace_opt) {
      OFStream os(stdout);
      os << "[compiling method " << Brief(*info()->closure())
434 435 436
         << " using TurboFan";
      if (info()->is_osr()) os << " OSR";
      os << "]" << std::endl;
437
    }
438 439

    if (info()->shared_info()->asm_function()) {
440
      if (info()->osr_frame()) info()->MarkAsFrameSpecializing();
441
      info()->MarkAsFunctionContextSpecializing();
442 443 444
    } else if (info()->has_global_object() &&
               FLAG_native_context_specialization) {
      info()->MarkAsNativeContextSpecializing();
445
      info()->MarkAsTypingEnabled();
446 447
    } else if (FLAG_turbo_type_feedback) {
      info()->MarkAsTypeFeedbackEnabled();
448
      info()->EnsureFeedbackVector();
449
    }
450 451 452 453
    if (!info()->shared_info()->asm_function() ||
        FLAG_turbo_asm_deoptimization) {
      info()->MarkAsDeoptimizationEnabled();
    }
454

455
    Timer t(this, &time_taken_to_create_graph_);
456 457
    compiler::Pipeline pipeline(info());
    pipeline.GenerateCode();
458 459 460
    if (!info()->code().is_null()) {
      return SetLastStatus(SUCCEEDED);
    }
461 462
  }

463
  if (!isolate()->use_crankshaft() || dont_crankshaft) {
464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479
    // Crankshaft is entirely disabled.
    return SetLastStatus(FAILED);
  }

  Scope* scope = info()->scope();
  if (LUnallocated::TooManyParameters(scope->num_parameters())) {
    // Crankshaft would require too many Lithium operands.
    return AbortOptimization(kTooManyParameters);
  }

  if (info()->is_osr() &&
      LUnallocated::TooManyParametersOrStackSlots(scope->num_parameters(),
                                                  scope->num_stack_slots())) {
    // Crankshaft would require too many Lithium operands.
    return AbortOptimization(kTooManyParametersLocals);
  }
480

481 482 483 484 485
  if (scope->HasIllegalRedeclaration()) {
    // Crankshaft cannot handle illegal redeclarations.
    return AbortOptimization(kFunctionWithIllegalRedeclaration);
  }

486 487 488
  if (FLAG_trace_opt) {
    OFStream os(stdout);
    os << "[compiling method " << Brief(*info()->closure())
489 490 491
       << " using Crankshaft";
    if (info()->is_osr()) os << " OSR";
    os << "]" << std::endl;
492 493
  }

494
  if (FLAG_trace_hydrogen) {
495
    isolate()->GetHTracer()->TraceCompilation(info());
496
  }
497 498

  // Type-check the function.
499 500 501
  AstTyper(info()->isolate(), info()->zone(), info()->closure(),
           info()->scope(), info()->osr_ast_id(), info()->literal())
      .Run();
502

503 504 505 506 507 508 509
  // Optimization could have been disabled by the parser. Note that this check
  // is only needed because the Hydrogen graph builder is missing some bailouts.
  if (info()->shared_info()->optimization_disabled()) {
    return AbortOptimization(
        info()->shared_info()->disable_optimization_reason());
  }

510 511 512 513
  graph_builder_ = (info()->is_tracking_positions() || FLAG_trace_ic)
                       ? new (info()->zone())
                             HOptimizedGraphBuilderWithPositions(info())
                       : new (info()->zone()) HOptimizedGraphBuilder(info());
514 515

  Timer t(this, &time_taken_to_create_graph_);
516 517
  graph_ = graph_builder_->CreateGraph();

518
  if (isolate()->has_pending_exception()) {
519
    return SetLastStatus(FAILED);
520 521
  }

522
  if (graph_ == NULL) return SetLastStatus(BAILED_OUT);
523

524
  if (info()->dependencies()->HasAborted()) {
525 526
    // Dependency has changed during graph creation. Let's try again later.
    return RetryOptimization(kBailedOutDueToDependencyChange);
527 528
  }

529 530 531
  return SetLastStatus(SUCCEEDED);
}

532

533
OptimizedCompileJob::Status OptimizedCompileJob::OptimizeGraph() {
534 535 536
  DisallowHeapAllocation no_allocation;
  DisallowHandleAllocation no_handles;
  DisallowHandleDereference no_deref;
537
  DisallowCodeDependencyChange no_dependency_change;
538

539
  DCHECK(last_status() == SUCCEEDED);
540 541 542 543 544
  // TODO(turbofan): Currently everything is done in the first phase.
  if (!info()->code().is_null()) {
    return last_status();
  }

545
  Timer t(this, &time_taken_to_optimize_);
546
  DCHECK(graph_ != NULL);
547
  BailoutReason bailout_reason = kNoReason;
548 549

  if (graph_->Optimize(&bailout_reason)) {
550
    chunk_ = LChunk::NewChunk(graph_);
551 552 553
    if (chunk_ != NULL) return SetLastStatus(SUCCEEDED);
  } else if (bailout_reason != kNoReason) {
    graph_builder_->Bailout(bailout_reason);
554
  }
555

556
  return SetLastStatus(BAILED_OUT);
557 558 559
}


560
OptimizedCompileJob::Status OptimizedCompileJob::GenerateCode() {
561
  DCHECK(last_status() == SUCCEEDED);
562 563
  // TODO(turbofan): Currently everything is done in the first phase.
  if (!info()->code().is_null()) {
564
    info()->dependencies()->Commit(info()->code());
565
    if (info()->is_deoptimization_enabled()) {
566 567
      info()->parse_info()->context()->native_context()->AddOptimizedCode(
          *info()->code());
568
    }
569 570 571 572
    RecordOptimizationStats();
    return last_status();
  }

573
  DCHECK(!info()->dependencies()->HasAborted());
574
  DisallowCodeDependencyChange no_dependency_change;
575
  DisallowJavascriptExecution no_js(isolate());
576 577
  {  // Scope for timer.
    Timer timer(this, &time_taken_to_codegen_);
578 579
    DCHECK(chunk_ != NULL);
    DCHECK(graph_ != NULL);
580 581 582 583
    // Deferred handles reference objects that were accessible during
    // graph creation.  To make sure that we don't encounter inconsistencies
    // between graph creation and code generation, we disallow accessing
    // objects through deferred handles during the latter, with exceptions.
584
    DisallowDeferredHandleDereference no_deferred_handle_deref;
585
    Handle<Code> optimized_code = chunk_->Codegen();
586
    if (optimized_code.is_null()) {
587
      if (info()->bailout_reason() == kNoReason) {
588
        return AbortOptimization(kCodeGenerationFailed);
589
      }
590
      return SetLastStatus(BAILED_OUT);
591 592
    }
    info()->SetCode(optimized_code);
593
  }
594
  RecordOptimizationStats();
595 596
  // Add to the weak list of optimized code objects.
  info()->context()->native_context()->AddOptimizedCode(*info()->code());
597
  return SetLastStatus(SUCCEEDED);
598 599 600
}


601 602 603 604 605 606
void OptimizedCompileJob::RecordOptimizationStats() {
  Handle<JSFunction> function = info()->closure();
  if (!function->IsOptimized()) {
    // Concurrent recompilation and OSR may race.  Increment only once.
    int opt_count = function->shared()->opt_count();
    function->shared()->set_opt_count(opt_count + 1);
607
  }
608 609 610 611 612 613 614 615
  double ms_creategraph = time_taken_to_create_graph_.InMillisecondsF();
  double ms_optimize = time_taken_to_optimize_.InMillisecondsF();
  double ms_codegen = time_taken_to_codegen_.InMillisecondsF();
  if (FLAG_trace_opt) {
    PrintF("[optimizing ");
    function->ShortPrint();
    PrintF(" - took %0.3f, %0.3f, %0.3f ms]\n", ms_creategraph, ms_optimize,
           ms_codegen);
616
  }
617 618 619 620
  if (FLAG_trace_opt_stats) {
    static double compilation_time = 0.0;
    static int compiled_functions = 0;
    static int code_size = 0;
621

622 623 624 625 626 627 628 629 630 631 632 633 634
    compilation_time += (ms_creategraph + ms_optimize + ms_codegen);
    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);
  }
  if (FLAG_hydrogen_stats) {
    isolate()->GetHStatistics()->IncrementSubtotals(time_taken_to_create_graph_,
                                                    time_taken_to_optimize_,
                                                    time_taken_to_codegen_);
  }
635 636 637
}


638 639 640 641 642 643 644 645 646 647
// Sets the expected number of properties based on estimate from compiler.
void SetExpectedNofPropertiesFromEstimate(Handle<SharedFunctionInfo> shared,
                                          int estimate) {
  // If no properties are added in the constructor, they are more likely
  // to be added later.
  if (estimate == 0) estimate = 2;

  // TODO(yangguo): check whether those heuristics are still up-to-date.
  // We do not shrink objects that go into a snapshot (yet), so we adjust
  // the estimate conservatively.
648
  if (shared->GetIsolate()->serializer_enabled()) {
649
    estimate += 2;
jochen's avatar
jochen committed
650
  } else {
651 652 653 654 655 656 657 658 659
    // Inobject slack tracking will reclaim redundant inobject space later,
    // so we can afford to adjust the estimate generously.
    estimate += 8;
  }

  shared->set_expected_nof_properties(estimate);
}


660 661 662 663 664 665 666 667
static void MaybeDisableOptimization(Handle<SharedFunctionInfo> shared_info,
                                     BailoutReason bailout_reason) {
  if (bailout_reason != kNoReason) {
    shared_info->DisableOptimization(bailout_reason);
  }
}


668 669 670 671 672 673 674 675 676 677 678
static void RecordFunctionCompilation(Logger::LogEventsAndTags tag,
                                      CompilationInfo* info,
                                      Handle<SharedFunctionInfo> shared) {
  // SharedFunctionInfo is passed separately, because if CompilationInfo
  // was created using Script object, it will not have it.

  // 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.
  if (info->isolate()->logger()->is_logging_code_events() ||
      info->isolate()->cpu_profiler()->is_profiling()) {
679
    Handle<Script> script = info->parse_info()->script();
680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697
    Handle<Code> code = info->code();
    if (code.is_identical_to(info->isolate()->builtins()->CompileLazy())) {
      return;
    }
    int line_num = Script::GetLineNumber(script, shared->start_position()) + 1;
    int column_num =
        Script::GetColumnNumber(script, shared->start_position()) + 1;
    String* script_name = script->name()->IsString()
                              ? String::cast(script->name())
                              : info->isolate()->heap()->empty_string();
    Logger::LogEventsAndTags log_tag = Logger::ToNativeByScript(tag, *script);
    PROFILE(info->isolate(),
            CodeCreateEvent(log_tag, *code, *shared, info, script_name,
                            line_num, column_num));
  }
}


698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715
// Checks whether top level functions should be passed by {raw_filter}.
// TODO(rmcilroy): Remove filtering once ignition can handle test262 harness.
static bool TopLevelFunctionPassesFilter(const char* raw_filter) {
  Vector<const char> filter = CStrVector(raw_filter);
  return (filter.length() == 0) || (filter.length() == 1 && filter[0] == '*');
}


// Checks whether the passed {raw_filter} is a prefix of the given scripts name.
// TODO(rmcilroy): Remove filtering once ignition can handle test262 harness.
static bool ScriptPassesFilter(const char* raw_filter, Handle<Script> script) {
  Vector<const char> filter = CStrVector(raw_filter);
  if (!script->name()->IsString()) return filter.length() == 0;
  String* name = String::cast(script->name());
  return name->IsUtf8EqualTo(filter, true);
}


716
static bool CompileUnoptimizedCode(CompilationInfo* info) {
717
  DCHECK(AllowCompilation::IsAllowed(info->isolate()));
718 719
  if (!Compiler::Analyze(info->parse_info()) ||
      !FullCodeGenerator::MakeCode(info)) {
720 721 722
    Isolate* isolate = info->isolate();
    if (!isolate->has_pending_exception()) isolate->StackOverflow();
    return false;
723
  }
724 725
  return true;
}
726

727

728 729 730 731 732 733 734 735 736 737 738 739
static bool GenerateBytecode(CompilationInfo* info) {
  DCHECK(AllowCompilation::IsAllowed(info->isolate()));
  if (!Compiler::Analyze(info->parse_info()) ||
      !interpreter::Interpreter::MakeBytecode(info)) {
    Isolate* isolate = info->isolate();
    if (!isolate->has_pending_exception()) isolate->StackOverflow();
    return false;
  }
  return true;
}


740 741
MUST_USE_RESULT static MaybeHandle<Code> GetUnoptimizedCodeCommon(
    CompilationInfo* info) {
742 743
  VMState<COMPILER> state(info->isolate());
  PostponeInterruptsScope postpone(info->isolate());
744 745

  // Parse and update CompilationInfo with the results.
746
  if (!Parser::ParseStatic(info->parse_info())) return MaybeHandle<Code>();
747
  Handle<SharedFunctionInfo> shared = info->shared_info();
748
  FunctionLiteral* lit = info->literal();
749
  shared->set_language_mode(lit->language_mode());
750
  SetExpectedNofPropertiesFromEstimate(shared, lit->expected_property_count());
751
  MaybeDisableOptimization(shared, lit->dont_optimize_reason());
752

753 754
  if (FLAG_ignition && info->closure()->PassesFilter(FLAG_ignition_filter) &&
      ScriptPassesFilter(FLAG_ignition_script_filter, info->script())) {
755 756 757 758 759
    // Compile bytecode for the interpreter.
    if (!GenerateBytecode(info)) return MaybeHandle<Code>();
  } else {
    // Compile unoptimized code.
    if (!CompileUnoptimizedCode(info)) return MaybeHandle<Code>();
760

761 762 763
    CHECK_EQ(Code::FUNCTION, info->code()->kind());
    RecordFunctionCompilation(Logger::LAZY_COMPILE_TAG, info, shared);
  }
764 765 766

  // Update the shared function info with the scope info. Allocating the
  // ScopeInfo object may cause a GC.
767 768
  Handle<ScopeInfo> scope_info =
      ScopeInfo::Create(info->isolate(), info->zone(), info->scope());
769 770 771 772 773
  shared->set_scope_info(*scope_info);

  // Update the code and feedback vector for the shared function info.
  shared->ReplaceCode(*info->code());
  shared->set_feedback_vector(*info->feedback_vector());
774 775 776 777
  if (info->has_bytecode_array()) {
    DCHECK(shared->function_data()->IsUndefined());
    shared->set_function_data(*info->bytecode_array());
  }
778

779 780
  return info->code();
}
781 782


783 784
MUST_USE_RESULT static MaybeHandle<Code> GetCodeFromOptimizedCodeMap(
    Handle<JSFunction> function, BailoutId osr_ast_id) {
785 786 787 788 789 790 791 792 793 794
  Handle<SharedFunctionInfo> shared(function->shared());
  DisallowHeapAllocation no_gc;
  CodeAndLiterals cached = shared->SearchOptimizedCodeMap(
      function->context()->native_context(), osr_ast_id);
  if (cached.code != nullptr) {
    // Caching of optimized code enabled and optimized code found.
    if (cached.literals != nullptr) function->set_literals(cached.literals);
    DCHECK(!cached.code->marked_for_deoptimization());
    DCHECK(function->shared()->is_compiled());
    return Handle<Code>(cached.code);
795 796 797 798 799 800 801 802 803
  }
  return MaybeHandle<Code>();
}


static void InsertCodeIntoOptimizedCodeMap(CompilationInfo* info) {
  Handle<Code> code = info->code();
  if (code->kind() != Code::OPTIMIZED_FUNCTION) return;  // Nothing to do.

804 805
  // Function context specialization folds-in the function context,
  // so no sharing can occur.
806 807
  if (info->is_function_context_specializing()) return;
  // Frame specialization implies function context specialization.
808
  DCHECK(!info->is_frame_specializing());
809

810
  // Do not cache bound functions.
811 812
  Handle<JSFunction> function = info->closure();
  if (function->shared()->bound()) return;
813

814
  // Cache optimized context-specific code.
815 816 817 818 819
  Handle<SharedFunctionInfo> shared(function->shared());
  Handle<LiteralsArray> literals(function->literals());
  Handle<Context> native_context(function->context()->native_context());
  SharedFunctionInfo::AddToOptimizedCodeMap(shared, native_context, code,
                                            literals, info->osr_ast_id());
820

821
  // Do not cache (native) context-independent code compiled for OSR.
822 823
  if (code->is_turbofanned() && info->is_osr()) return;

824 825 826
  // Cache optimized (native) context-independent code.
  if (FLAG_turbo_cache_shared_code && code->is_turbofanned() &&
      !info->is_native_context_specializing()) {
827
    DCHECK(!info->is_function_context_specializing());
828 829 830 831
    DCHECK(info->osr_ast_id().IsNone());
    Handle<SharedFunctionInfo> shared(function->shared());
    SharedFunctionInfo::AddSharedCodeToOptimizedCodeMap(shared, code);
  }
832 833 834
}


835 836
static bool Renumber(ParseInfo* parse_info) {
  if (!AstNumbering::Renumber(parse_info->isolate(), parse_info->zone(),
837
                              parse_info->literal())) {
838 839
    return false;
  }
840 841
  Handle<SharedFunctionInfo> shared_info = parse_info->shared_info();
  if (!shared_info.is_null()) {
842
    FunctionLiteral* lit = parse_info->literal();
843 844
    shared_info->set_ast_node_count(lit->ast_node_count());
    MaybeDisableOptimization(shared_info, lit->dont_optimize_reason());
845 846
    shared_info->set_dont_crankshaft(lit->flags() &
                                     AstProperties::kDontCrankshaft);
847 848 849 850 851
  }
  return true;
}


852
bool Compiler::Analyze(ParseInfo* info) {
853
  DCHECK_NOT_NULL(info->literal());
854 855
  if (!Rewriter::Rewrite(info)) return false;
  if (!Scope::Analyze(info)) return false;
856
  if (!Renumber(info)) return false;
857
  DCHECK_NOT_NULL(info->scope());
858 859 860 861
  return true;
}


862
bool Compiler::ParseAndAnalyze(ParseInfo* info) {
863
  if (!Parser::ParseStatic(info)) return false;
864 865 866 867
  return Compiler::Analyze(info);
}


868
static bool GetOptimizedCodeNow(CompilationInfo* info) {
869
  if (!Compiler::ParseAndAnalyze(info->parse_info())) return false;
870 871 872 873

  TimerEventScope<TimerEventRecompileSynchronous> timer(info->isolate());

  OptimizedCompileJob job(info);
874 875 876 877 878 879 880 881 882 883
  if (job.CreateGraph() != OptimizedCompileJob::SUCCEEDED ||
      job.OptimizeGraph() != OptimizedCompileJob::SUCCEEDED ||
      job.GenerateCode() != OptimizedCompileJob::SUCCEEDED) {
    if (FLAG_trace_opt) {
      PrintF("[aborted optimizing ");
      info->closure()->ShortPrint();
      PrintF(" because: %s]\n", GetBailoutReason(info->bailout_reason()));
    }
    return false;
  }
884 885 886 887 888 889 890 891 892 893 894 895

  // Success!
  DCHECK(!info->isolate()->has_pending_exception());
  InsertCodeIntoOptimizedCodeMap(info);
  RecordFunctionCompilation(Logger::LAZY_COMPILE_TAG, info,
                            info->shared_info());
  return true;
}


static bool GetOptimizedCodeLater(CompilationInfo* info) {
  Isolate* isolate = info->isolate();
896
  if (!isolate->optimizing_compile_dispatcher()->IsQueueAvailable()) {
897 898
    if (FLAG_trace_concurrent_recompilation) {
      PrintF("  ** Compilation queue full, will retry optimizing ");
899
      info->closure()->ShortPrint();
900 901 902 903 904 905
      PrintF(" later.\n");
    }
    return false;
  }

  CompilationHandleScope handle_scope(info);
906 907 908 909 910
  if (!Compiler::ParseAndAnalyze(info->parse_info())) return false;

  // Reopen handles in the new CompilationHandleScope.
  info->ReopenHandlesInNewHandleScope();
  info->parse_info()->ReopenHandlesInNewHandleScope();
911 912 913 914 915 916

  TimerEventScope<TimerEventRecompileSynchronous> timer(info->isolate());

  OptimizedCompileJob* job = new (info->zone()) OptimizedCompileJob(info);
  OptimizedCompileJob::Status status = job->CreateGraph();
  if (status != OptimizedCompileJob::SUCCEEDED) return false;
917
  isolate->optimizing_compile_dispatcher()->QueueForOptimization(job);
918 919 920

  if (FLAG_trace_concurrent_recompilation) {
    PrintF("  ** Queued ");
921
    info->closure()->ShortPrint();
922 923 924 925 926 927 928 929 930 931
    if (info->is_osr()) {
      PrintF(" for concurrent OSR at %d.\n", info->osr_ast_id().ToInt());
    } else {
      PrintF(" for concurrent optimization.\n");
    }
  }
  return true;
}


932
MaybeHandle<Code> Compiler::GetUnoptimizedCode(Handle<JSFunction> function) {
933 934
  DCHECK(!function->GetIsolate()->has_pending_exception());
  DCHECK(!function->is_compiled());
935 936 937
  if (function->shared()->is_compiled()) {
    return Handle<Code>(function->shared()->code());
  }
938

939
  CompilationInfoWithZone info(function);
940 941 942 943
  Handle<Code> result;
  ASSIGN_RETURN_ON_EXCEPTION(info.isolate(), result,
                             GetUnoptimizedCodeCommon(&info),
                             Code);
944 945 946 947 948
  return result;
}


MaybeHandle<Code> Compiler::GetLazyCode(Handle<JSFunction> function) {
949 950
  Isolate* isolate = function->GetIsolate();
  DCHECK(!isolate->has_pending_exception());
951
  DCHECK(!function->is_compiled());
952
  AggregatedHistogramTimerScope timer(isolate->counters()->compile_lazy());
953 954 955
  // If the debugger is active, do not compile with turbofan unless we can
  // deopt from turbofan code.
  if (FLAG_turbo_asm && function->shared()->asm_function() &&
956
      (FLAG_turbo_asm_deoptimization || !isolate->debug()->is_active()) &&
957
      !FLAG_turbo_osr) {
958 959
    CompilationInfoWithZone info(function);

960 961
    VMState<COMPILER> state(isolate);
    PostponeInterruptsScope postpone(isolate);
962

963
    info.SetOptimizing(BailoutId::None(), handle(function->shared()->code()));
964

965 966 967 968
    if (GetOptimizedCodeNow(&info)) {
      DCHECK(function->shared()->is_compiled());
      return info.code();
    }
969 970 971
    // We have failed compilation. If there was an exception clear it so that
    // we can compile unoptimized code.
    if (isolate->has_pending_exception()) isolate->clear_pending_exception();
972 973
  }

974 975 976 977 978 979
  if (function->shared()->is_compiled()) {
    return Handle<Code>(function->shared()->code());
  }

  CompilationInfoWithZone info(function);
  Handle<Code> result;
980 981
  ASSIGN_RETURN_ON_EXCEPTION(isolate, result, GetUnoptimizedCodeCommon(&info),
                             Code);
982

983
  if (FLAG_always_opt) {
984 985 986 987 988 989
    Handle<Code> opt_code;
    if (Compiler::GetOptimizedCode(
            function, result,
            Compiler::NOT_CONCURRENT).ToHandle(&opt_code)) {
      result = opt_code;
    }
990
  }
991

992 993
  return result;
}
994

995

996 997 998 999 1000 1001 1002
MaybeHandle<Code> Compiler::GetStubCode(Handle<JSFunction> function,
                                        CodeStub* stub) {
  // Build a "hybrid" CompilationInfo for a JSFunction/CodeStub pair.
  Zone zone;
  ParseInfo parse_info(&zone, function);
  CompilationInfo info(&parse_info);
  info.SetFunctionType(stub->GetCallInterfaceDescriptor().GetFunctionType());
1003
  info.MarkAsFunctionContextSpecializing();
1004 1005 1006 1007 1008 1009 1010 1011 1012 1013
  info.MarkAsDeoptimizationEnabled();
  info.SetStub(stub);

  // Run a "mini pipeline", extracted from compiler.cc.
  if (!ParseAndAnalyze(&parse_info)) return MaybeHandle<Code>();
  return compiler::Pipeline(&info).GenerateCode();
}


bool Compiler::Compile(Handle<JSFunction> function, ClearExceptionFlag flag) {
1014
  if (function->is_compiled()) return true;
1015
  MaybeHandle<Code> maybe_code = Compiler::GetLazyCode(function);
1016 1017
  Handle<Code> code;
  if (!maybe_code.ToHandle(&code)) {
1018 1019 1020 1021 1022 1023
    if (flag == CLEAR_EXCEPTION) {
      function->GetIsolate()->clear_pending_exception();
    }
    return false;
  }
  function->ReplaceCode(*code);
1024
  DCHECK(function->is_compiled());
1025 1026
  return true;
}
1027

1028

1029 1030 1031
// TODO(turbofan): In the future, unoptimized code with deopt support could
// be generated lazily once deopt is triggered.
bool Compiler::EnsureDeoptimizationSupport(CompilationInfo* info) {
1032 1033
  DCHECK_NOT_NULL(info->literal());
  DCHECK(info->has_scope());
1034 1035
  Handle<SharedFunctionInfo> shared = info->shared_info();
  if (!shared->has_deoptimization_support()) {
1036
    // TODO(titzer): just reuse the ParseInfo for the unoptimized compile.
1037
    CompilationInfoWithZone unoptimized(info->closure());
1038 1039
    // Note that we use the same AST that we will use for generating the
    // optimized code.
1040
    ParseInfo* parse_info = unoptimized.parse_info();
1041
    parse_info->set_literal(info->literal());
1042 1043
    parse_info->set_scope(info->scope());
    parse_info->set_context(info->context());
1044
    unoptimized.EnableDeoptimizationSupport();
1045 1046 1047 1048 1049 1050 1051
    // If the current code has reloc info for serialization, also include
    // reloc info for serialization for the new code, so that deopt support
    // can be added without losing IC state.
    if (shared->code()->kind() == Code::FUNCTION &&
        shared->code()->has_reloc_info_for_serialization()) {
      unoptimized.PrepareForSerializing();
    }
1052 1053 1054 1055 1056
    if (!FullCodeGenerator::MakeCode(&unoptimized)) return false;

    shared->EnableDeoptimizationSupport(*unoptimized.code());
    shared->set_feedback_vector(*unoptimized.feedback_vector());

1057 1058
    info->MarkAsCompiled();

1059 1060 1061 1062
    // The scope info might not have been set if a lazily compiled
    // function is inlined before being called for the first time.
    if (shared->scope_info() == ScopeInfo::Empty(info->isolate())) {
      Handle<ScopeInfo> target_scope_info =
1063
          ScopeInfo::Create(info->isolate(), info->zone(), info->scope());
1064 1065 1066 1067 1068 1069 1070 1071 1072 1073
      shared->set_scope_info(*target_scope_info);
    }

    // The existing unoptimized code was replaced with the new one.
    RecordFunctionCompilation(Logger::LAZY_COMPILE_TAG, &unoptimized, shared);
  }
  return true;
}


1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099
bool CompileEvalForDebugging(Handle<JSFunction> function,
                             Handle<SharedFunctionInfo> shared) {
  Handle<Script> script(Script::cast(shared->script()));
  Handle<Context> context(function->context());

  Zone zone;
  ParseInfo parse_info(&zone, script);
  CompilationInfo info(&parse_info);
  Isolate* isolate = info.isolate();

  parse_info.set_eval();
  parse_info.set_context(context);
  if (context->IsNativeContext()) parse_info.set_global();
  parse_info.set_toplevel();
  parse_info.set_allow_lazy_parsing(false);
  parse_info.set_language_mode(shared->language_mode());
  parse_info.set_parse_restriction(NO_PARSE_RESTRICTION);
  info.MarkAsDebug();

  VMState<COMPILER> state(info.isolate());

  if (!Parser::ParseStatic(&parse_info)) {
    isolate->clear_pending_exception();
    return false;
  }

1100
  FunctionLiteral* lit = parse_info.literal();
1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112
  LiveEditFunctionTracker live_edit_tracker(isolate, lit);

  if (!CompileUnoptimizedCode(&info)) {
    isolate->clear_pending_exception();
    return false;
  }
  shared->ReplaceCode(*info.code());
  return true;
}


bool CompileForDebugging(CompilationInfo* info) {
1113
  info->MarkAsDebug();
1114
  if (GetUnoptimizedCodeCommon(info).is_null()) {
1115
    info->isolate()->clear_pending_exception();
1116
    return false;
1117
  }
1118
  return true;
1119 1120 1121
}


1122 1123 1124 1125 1126 1127 1128
static inline bool IsEvalToplevel(Handle<SharedFunctionInfo> shared) {
  return shared->is_toplevel() && shared->script()->IsScript() &&
         Script::cast(shared->script())->compilation_type() ==
             Script::COMPILATION_TYPE_EVAL;
}


1129 1130
bool Compiler::CompileDebugCode(Handle<JSFunction> function) {
  Handle<SharedFunctionInfo> shared(function->shared());
1131
  if (IsEvalToplevel(shared)) {
1132 1133 1134 1135 1136
    return CompileEvalForDebugging(function, shared);
  } else {
    CompilationInfoWithZone info(function);
    return CompileForDebugging(&info);
  }
1137 1138 1139
}


1140
bool Compiler::CompileDebugCode(Handle<SharedFunctionInfo> shared) {
1141
  DCHECK(shared->allows_lazy_compilation_without_context());
1142
  DCHECK(!IsEvalToplevel(shared));
1143 1144 1145 1146 1147 1148 1149
  Zone zone;
  ParseInfo parse_info(&zone, shared);
  CompilationInfo info(&parse_info);
  return CompileForDebugging(&info);
}


1150 1151
void Compiler::CompileForLiveEdit(Handle<Script> script) {
  // TODO(635): support extensions.
1152 1153 1154
  Zone zone;
  ParseInfo parse_info(&zone, script);
  CompilationInfo info(&parse_info);
1155
  PostponeInterruptsScope postpone(info.isolate());
1156 1157
  VMState<COMPILER> state(info.isolate());

1158
  // Get rid of old list of shared function infos.
1159
  info.MarkAsFirstCompile();
1160 1161
  info.parse_info()->set_global();
  if (!Parser::ParseStatic(info.parse_info())) return;
1162

1163
  LiveEditFunctionTracker tracker(info.isolate(), parse_info.literal());
1164
  if (!CompileUnoptimizedCode(&info)) return;
1165
  if (info.has_shared_info()) {
1166 1167
    Handle<ScopeInfo> scope_info =
        ScopeInfo::Create(info.isolate(), info.zone(), info.scope());
1168 1169 1170 1171 1172 1173 1174 1175
    info.shared_info()->set_scope_info(*scope_info);
  }
  tracker.RecordRootFunctionInfo(info.code());
}


static Handle<SharedFunctionInfo> CompileToplevel(CompilationInfo* info) {
  Isolate* isolate = info->isolate();
1176
  PostponeInterruptsScope postpone(isolate);
1177
  DCHECK(!isolate->native_context().is_null());
1178 1179
  ParseInfo* parse_info = info->parse_info();
  Handle<Script> script = parse_info->script();
1180 1181 1182

  // TODO(svenpanne) Obscure place for this, perhaps move to OnBeforeCompile?
  FixedArray* array = isolate->native_context()->embedder_data();
1183
  script->set_context_data(array->get(v8::Context::kDebugIdIndex));
1184

1185
  isolate->debug()->OnBeforeCompile(script);
1186

1187 1188
  DCHECK(parse_info->is_eval() || parse_info->is_global() ||
         parse_info->is_module());
1189

1190
  parse_info->set_toplevel();
1191

1192 1193 1194
  Handle<SharedFunctionInfo> result;

  { VMState<COMPILER> state(info->isolate());
1195
    if (parse_info->literal() == NULL) {
1196
      // Parse the script if needed (if it's already parsed, literal() is
1197 1198
      // non-NULL). If compiling for debugging, we may eagerly compile inner
      // functions, so do not parse lazily in that case.
1199 1200 1201 1202
      ScriptCompiler::CompileOptions options = parse_info->compile_options();
      bool parse_allow_lazy = (options == ScriptCompiler::kConsumeParserCache ||
                               String::cast(script->source())->length() >
                                   FLAG_min_preparse_length) &&
1203
                              !info->is_debug();
1204

1205
      parse_info->set_allow_lazy_parsing(parse_allow_lazy);
1206
      if (!parse_allow_lazy &&
1207 1208
          (options == ScriptCompiler::kProduceParserCache ||
           options == ScriptCompiler::kConsumeParserCache)) {
1209 1210 1211 1212
        // We are going to parse eagerly, but we either 1) have cached data
        // produced by lazy parsing or 2) are asked to generate cached data.
        // Eager parsing cannot benefit from cached data, and producing cached
        // data while parsing eagerly is not implemented.
1213 1214
        parse_info->set_cached_data(nullptr);
        parse_info->set_compile_options(ScriptCompiler::kNoCompileOptions);
1215
      }
1216
      if (!Parser::ParseStatic(parse_info)) {
1217 1218
        return Handle<SharedFunctionInfo>::null();
      }
1219 1220
    }

1221 1222
    DCHECK(!info->is_debug() || !parse_info->allow_lazy_parsing());

1223 1224
    info->MarkAsFirstCompile();

1225
    FunctionLiteral* lit = parse_info->literal();
1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236
    LiveEditFunctionTracker live_edit_tracker(isolate, lit);

    // 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.
    HistogramTimer* rate = info->is_eval()
          ? info->isolate()->counters()->compile_eval()
          : info->isolate()->counters()->compile();
    HistogramTimerScope timer(rate);

    // Compile the code.
1237 1238
    if (FLAG_ignition && TopLevelFunctionPassesFilter(FLAG_ignition_filter) &&
        ScriptPassesFilter(FLAG_ignition_script_filter, script)) {
1239 1240 1241 1242 1243 1244 1245
      if (!GenerateBytecode(info)) {
        return Handle<SharedFunctionInfo>::null();
      }
    } else {
      if (!CompileUnoptimizedCode(info)) {
        return Handle<SharedFunctionInfo>::null();
      }
1246 1247 1248
    }

    // Allocate function.
1249
    DCHECK(!info->code().is_null());
1250
    result = isolate->factory()->NewSharedFunctionInfo(
1251
        lit->name(), lit->materialized_literal_count(), lit->kind(),
1252 1253
        info->code(),
        ScopeInfo::Create(info->isolate(), info->zone(), info->scope()),
1254
        info->feedback_vector());
1255 1256 1257 1258
    if (info->has_bytecode_array()) {
      DCHECK(result->function_data()->IsUndefined());
      result->set_function_data(*info->bytecode_array());
    }
1259

1260
    DCHECK_EQ(RelocInfo::kNoPosition, lit->function_token_position());
1261
    SharedFunctionInfo::InitFromFunctionLiteral(result, lit);
1262
    SharedFunctionInfo::SetScript(result, script);
1263
    result->set_is_toplevel(true);
1264 1265 1266 1267
    if (info->is_eval()) {
      // Eval scripts cannot be (re-)compiled without context.
      result->set_allows_lazy_compilation_without_context(false);
    }
1268

1269 1270 1271 1272
    Handle<String> script_name =
        script->name()->IsString()
            ? Handle<String>(String::cast(script->name()))
            : isolate->factory()->empty_string();
1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285
    Logger::LogEventsAndTags log_tag = info->is_eval()
        ? Logger::EVAL_TAG
        : Logger::ToNativeByScript(Logger::SCRIPT_TAG, *script);

    PROFILE(isolate, CodeCreateEvent(
                log_tag, *info->code(), *result, info, *script_name));

    // 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.
    SetExpectedNofPropertiesFromEstimate(result,
                                         lit->expected_property_count());

1286 1287
    if (!script.is_null())
      script->set_compilation_state(Script::COMPILATION_STATE_COMPILED);
1288 1289 1290 1291 1292 1293 1294 1295

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

  return result;
}


1296
MaybeHandle<JSFunction> Compiler::GetFunctionFromEval(
1297
    Handle<String> source, Handle<SharedFunctionInfo> outer_info,
1298
    Handle<Context> context, LanguageMode language_mode,
1299 1300
    ParseRestriction restriction, int line_offset, int column_offset,
    Handle<Object> script_name, ScriptOriginOptions options) {
1301 1302 1303 1304 1305 1306
  Isolate* isolate = source->GetIsolate();
  int source_length = source->length();
  isolate->counters()->total_eval_size()->Increment(source_length);
  isolate->counters()->total_compile_size()->Increment(source_length);

  CompilationCache* compilation_cache = isolate->compilation_cache();
1307
  MaybeHandle<SharedFunctionInfo> maybe_shared_info =
1308
      compilation_cache->LookupEval(source, outer_info, context, language_mode,
1309
                                    line_offset);
1310
  Handle<SharedFunctionInfo> shared_info;
1311

1312
  Handle<Script> script;
1313
  if (!maybe_shared_info.ToHandle(&shared_info)) {
1314
    script = isolate->factory()->NewScript(source);
1315 1316
    if (!script_name.is_null()) {
      script->set_name(*script_name);
1317 1318
      script->set_line_offset(line_offset);
      script->set_column_offset(column_offset);
1319 1320
    }
    script->set_origin_options(options);
1321 1322 1323 1324 1325 1326 1327 1328
    Zone zone;
    ParseInfo parse_info(&zone, script);
    CompilationInfo info(&parse_info);
    parse_info.set_eval();
    if (context->IsNativeContext()) parse_info.set_global();
    parse_info.set_language_mode(language_mode);
    parse_info.set_parse_restriction(restriction);
    parse_info.set_context(context);
1329 1330 1331 1332 1333 1334

    Debug::RecordEvalCaller(script);

    shared_info = CompileToplevel(&info);

    if (shared_info.is_null()) {
1335
      return MaybeHandle<JSFunction>();
1336 1337 1338
    } else {
      // Explicitly disable optimization for eval code. We're not yet prepared
      // to handle eval-code in the optimizing compiler.
1339 1340 1341
      if (restriction != ONLY_SINGLE_FUNCTION_LITERAL) {
        shared_info->DisableOptimization(kEval);
      }
1342

1343
      // If caller is strict mode, the result must be in strict mode as well.
1344 1345
      DCHECK(is_sloppy(language_mode) ||
             is_strict(shared_info->language_mode()));
1346
      compilation_cache->PutEval(source, outer_info, context, shared_info,
1347
                                 line_offset);
1348 1349 1350 1351 1352
    }
  } else if (shared_info->ic_age() != isolate->heap()->global_ic_age()) {
    shared_info->ResetForNewContext(isolate->heap()->global_ic_age());
  }

1353 1354 1355 1356 1357 1358 1359 1360 1361 1362
  Handle<JSFunction> result =
      isolate->factory()->NewFunctionFromSharedFunctionInfo(
          shared_info, context, NOT_TENURED);

  // OnAfterCompile has to be called after we create the JSFunction, which we
  // may require to recompile the eval for debugging, if we find a function
  // that contains break points in the eval script.
  isolate->debug()->OnAfterCompile(script);

  return result;
1363 1364 1365
}


1366
Handle<SharedFunctionInfo> Compiler::CompileScript(
1367
    Handle<String> source, Handle<Object> script_name, int line_offset,
1368 1369 1370
    int column_offset, ScriptOriginOptions resource_options,
    Handle<Object> source_map_url, Handle<Context> context,
    v8::Extension* extension, ScriptData** cached_data,
1371 1372
    ScriptCompiler::CompileOptions compile_options, NativesFlag natives,
    bool is_module) {
1373
  Isolate* isolate = source->GetIsolate();
1374
  if (compile_options == ScriptCompiler::kNoCompileOptions) {
1375
    cached_data = NULL;
1376 1377
  } else if (compile_options == ScriptCompiler::kProduceParserCache ||
             compile_options == ScriptCompiler::kProduceCodeCache) {
1378 1379
    DCHECK(cached_data && !*cached_data);
    DCHECK(extension == NULL);
1380
    DCHECK(!isolate->debug()->is_loaded());
1381
  } else {
1382
    DCHECK(compile_options == ScriptCompiler::kConsumeParserCache ||
1383
           compile_options == ScriptCompiler::kConsumeCodeCache);
1384 1385
    DCHECK(cached_data && *cached_data);
    DCHECK(extension == NULL);
1386
  }
1387 1388 1389 1390
  int source_length = source->length();
  isolate->counters()->total_load_size()->Increment(source_length);
  isolate->counters()->total_compile_size()->Increment(source_length);

1391 1392 1393 1394 1395 1396
  // TODO(rossberg): The natives do not yet obey strong mode rules
  // (for example, some macros use '==').
  bool use_strong = FLAG_use_strong && !isolate->bootstrapper()->IsActive();
  LanguageMode language_mode =
      construct_language_mode(FLAG_use_strict, use_strong);

1397 1398 1399
  CompilationCache* compilation_cache = isolate->compilation_cache();

  // Do a lookup in the compilation cache but not for extensions.
1400
  MaybeHandle<SharedFunctionInfo> maybe_result;
1401
  Handle<SharedFunctionInfo> result;
1402
  if (extension == NULL) {
1403
    // First check per-isolate compilation cache.
1404
    maybe_result = compilation_cache->LookupScript(
1405 1406
        source, script_name, line_offset, column_offset, resource_options,
        context, language_mode);
1407
    if (maybe_result.is_null() && FLAG_serialize_toplevel &&
1408 1409
        compile_options == ScriptCompiler::kConsumeCodeCache &&
        !isolate->debug()->is_loaded()) {
1410
      // Then check cached code provided by embedder.
1411
      HistogramTimerScope timer(isolate->counters()->compile_deserialize());
1412 1413 1414
      Handle<SharedFunctionInfo> result;
      if (CodeSerializer::Deserialize(isolate, *cached_data, source)
              .ToHandle(&result)) {
1415 1416
        // Promote to per-isolate compilation cache.
        compilation_cache->PutScript(source, context, language_mode, result);
1417 1418 1419
        return result;
      }
      // Deserializer failed. Fall through to compile.
1420
    }
1421 1422
  }

1423 1424 1425 1426 1427 1428
  base::ElapsedTimer timer;
  if (FLAG_profile_deserialization && FLAG_serialize_toplevel &&
      compile_options == ScriptCompiler::kProduceCodeCache) {
    timer.Start();
  }

1429
  if (!maybe_result.ToHandle(&result)) {
1430
    // No cache entry found. Compile the script.
1431 1432

    // Create a script object describing the script to be compiled.
1433
    Handle<Script> script = isolate->factory()->NewScript(source);
1434
    if (natives == NATIVES_CODE) {
1435
      script->set_type(Script::TYPE_NATIVE);
1436
      script->set_hide_source(true);
1437
    }
1438 1439
    if (!script_name.is_null()) {
      script->set_name(*script_name);
1440 1441
      script->set_line_offset(line_offset);
      script->set_column_offset(column_offset);
1442
    }
1443
    script->set_origin_options(resource_options);
1444 1445 1446
    if (!source_map_url.is_null()) {
      script->set_source_mapping_url(*source_map_url);
    }
1447 1448

    // Compile the function and add it to the cache.
1449 1450 1451
    Zone zone;
    ParseInfo parse_info(&zone, script);
    CompilationInfo info(&parse_info);
1452
    if (FLAG_harmony_modules && is_module) {
1453
      parse_info.set_module();
1454
    } else {
1455
      parse_info.set_global();
1456
    }
1457
    if (compile_options != ScriptCompiler::kNoCompileOptions) {
1458
      parse_info.set_cached_data(cached_data);
1459
    }
1460 1461 1462
    parse_info.set_compile_options(compile_options);
    parse_info.set_extension(extension);
    parse_info.set_context(context);
1463 1464
    if (FLAG_serialize_toplevel &&
        compile_options == ScriptCompiler::kProduceCodeCache) {
1465 1466
      info.PrepareForSerializing();
    }
1467

1468
    parse_info.set_language_mode(
1469
        static_cast<LanguageMode>(info.language_mode() | language_mode));
1470
    result = CompileToplevel(&info);
1471
    if (extension == NULL && !result.is_null()) {
1472
      compilation_cache->PutScript(source, context, language_mode, result);
1473
      if (FLAG_serialize_toplevel &&
1474
          compile_options == ScriptCompiler::kProduceCodeCache) {
1475 1476
        HistogramTimerScope histogram_timer(
            isolate->counters()->compile_serialize());
1477
        *cached_data = CodeSerializer::Serialize(isolate, result, source);
1478
        if (FLAG_profile_deserialization) {
1479 1480
          PrintF("[Compiling and serializing took %0.3f ms]\n",
                 timer.Elapsed().InMillisecondsF());
1481
        }
1482
      }
1483
    }
1484

1485 1486 1487 1488 1489
    if (result.is_null()) {
      isolate->ReportPendingMessages();
    } else {
      isolate->debug()->OnAfterCompile(script);
    }
1490
  } else if (result->ic_age() != isolate->heap()->global_ic_age()) {
1491
    result->ResetForNewContext(isolate->heap()->global_ic_age());
1492 1493 1494 1495 1496
  }
  return result;
}


1497
Handle<SharedFunctionInfo> Compiler::CompileStreamedScript(
1498 1499 1500
    Handle<Script> script, ParseInfo* parse_info, int source_length) {
  Isolate* isolate = script->GetIsolate();
  // TODO(titzer): increment the counters in caller.
1501 1502 1503
  isolate->counters()->total_load_size()->Increment(source_length);
  isolate->counters()->total_compile_size()->Increment(source_length);

1504 1505
  LanguageMode language_mode =
      construct_language_mode(FLAG_use_strict, FLAG_use_strong);
1506 1507
  parse_info->set_language_mode(
      static_cast<LanguageMode>(parse_info->language_mode() | language_mode));
1508

1509
  CompilationInfo compile_info(parse_info);
1510

1511 1512
  // The source was parsed lazily, so compiling for debugging is not possible.
  DCHECK(!compile_info.is_debug());
1513

1514 1515 1516
  Handle<SharedFunctionInfo> result = CompileToplevel(&compile_info);
  if (!result.is_null()) isolate->debug()->OnAfterCompile(script);
  return result;
1517 1518 1519
}


1520
Handle<SharedFunctionInfo> Compiler::GetSharedFunctionInfo(
1521 1522
    FunctionLiteral* literal, Handle<Script> script,
    CompilationInfo* outer_info) {
1523
  // Precondition: code has been parsed and scopes have been analyzed.
1524
  Isolate* isolate = outer_info->isolate();
1525 1526 1527
  MaybeHandle<SharedFunctionInfo> maybe_existing;
  if (outer_info->is_first_compile()) {
    // On the first compile, there are no existing shared function info for
1528 1529 1530 1531
    // inner functions yet, so do not try to find them. All bets are off for
    // live edit though.
    DCHECK(script->FindSharedFunctionInfo(literal).is_null() ||
           isolate->debug()->live_edit_enabled());
1532 1533 1534 1535 1536 1537
  } else {
    maybe_existing = script->FindSharedFunctionInfo(literal);
  }
  // We found an existing shared function info. If it's already compiled,
  // don't worry about compiling it, and simply return it. If it's not yet
  // compiled, continue to decide whether to eagerly compile.
1538 1539
  // Carry on if we are compiling eager to obtain code for debugging,
  // unless we already have code with debut break slots.
1540 1541
  Handle<SharedFunctionInfo> existing;
  if (maybe_existing.ToHandle(&existing) && existing->is_compiled()) {
1542 1543 1544
    if (!outer_info->is_debug() || existing->HasDebugCode()) {
      return existing;
    }
1545 1546
  }

1547 1548 1549 1550 1551 1552
  Zone zone;
  ParseInfo parse_info(&zone, script);
  CompilationInfo info(&parse_info);
  parse_info.set_literal(literal);
  parse_info.set_scope(literal->scope());
  parse_info.set_language_mode(literal->scope()->language_mode());
1553
  if (outer_info->will_serialize()) info.PrepareForSerializing();
1554
  if (outer_info->is_first_compile()) info.MarkAsFirstCompile();
1555
  if (outer_info->is_debug()) info.MarkAsDebug();
1556

1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567
  LiveEditFunctionTracker live_edit_tracker(isolate, literal);
  // 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.
  // 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
  // Debug::FindSharedFunctionInfoInScript.
  bool allow_lazy_without_ctx = literal->AllowsLazyCompilationWithoutContext();
1568 1569 1570 1571 1572
  // Compile eagerly for live edit. When compiling debug code, eagerly compile
  // unless we can lazily compile without the context.
  bool allow_lazy = literal->AllowsLazyCompilation() &&
                    !LiveEditFunctionTracker::IsActive(isolate) &&
                    (!info.is_debug() || allow_lazy_without_ctx);
1573

1574 1575
  bool lazy = FLAG_lazy && allow_lazy && !literal->should_eager_compile();

1576 1577
  // Generate code
  Handle<ScopeInfo> scope_info;
1578
  if (lazy) {
1579
    Handle<Code> code = isolate->builtins()->CompileLazy();
1580
    info.SetCode(code);
1581 1582 1583 1584 1585 1586 1587 1588
    // There's no need in theory for a lazy-compiled function to have a type
    // feedback vector, but some parts of the system expect all
    // SharedFunctionInfo instances to have one.  The size of the vector depends
    // on how many feedback-needing nodes are in the tree, and when lazily
    // parsing we might not know that, if this function was never parsed before.
    // In that case the vector will be replaced the next time MakeCode is
    // called.
    info.EnsureFeedbackVector();
1589
    scope_info = Handle<ScopeInfo>(ScopeInfo::Empty(isolate));
1590 1591
  } else if (Renumber(info.parse_info()) &&
             FullCodeGenerator::MakeCode(&info)) {
1592 1593
    // MakeCode will ensure that the feedback vector is present and
    // appropriately sized.
1594
    DCHECK(!info.code().is_null());
1595
    scope_info = ScopeInfo::Create(info.isolate(), info.zone(), info.scope());
1596 1597 1598 1599
    if (literal->should_eager_compile() &&
        literal->should_be_used_once_hint()) {
      info.code()->MarkToBeExecutedOnce(isolate);
    }
1600
  } else {
1601
    return Handle<SharedFunctionInfo>::null();
1602
  }
1603

1604 1605
  if (maybe_existing.is_null()) {
    // Create a shared function info object.
1606 1607 1608 1609
    Handle<SharedFunctionInfo> result =
        isolate->factory()->NewSharedFunctionInfo(
            literal->name(), literal->materialized_literal_count(),
            literal->kind(), info.code(), scope_info, info.feedback_vector());
1610

1611 1612 1613 1614 1615 1616 1617
    SharedFunctionInfo::InitFromFunctionLiteral(result, literal);
    SharedFunctionInfo::SetScript(result, script);
    result->set_is_toplevel(false);
    // If the outer function has been compiled before, we cannot be sure that
    // shared function info for this function literal has been created for the
    // first time. It may have already been compiled previously.
    result->set_never_compiled(outer_info->is_first_compile() && lazy);
1618

1619 1620 1621
    RecordFunctionCompilation(Logger::FUNCTION_TAG, &info, result);
    result->set_allows_lazy_compilation(literal->AllowsLazyCompilation());
    result->set_allows_lazy_compilation_without_context(allow_lazy_without_ctx);
1622

1623 1624 1625 1626 1627 1628
    // Set the expected number of properties for instances and return
    // the resulting function.
    SetExpectedNofPropertiesFromEstimate(result,
                                         literal->expected_property_count());
    live_edit_tracker.RecordFunctionInfo(result, literal, info.zone());
    return result;
1629
  } else if (!lazy) {
1630 1631
    // Assert that we are not overwriting (possibly patched) debug code.
    DCHECK(!existing->HasDebugCode());
1632 1633 1634 1635
    existing->ReplaceCode(*info.code());
    existing->set_scope_info(*scope_info);
    existing->set_feedback_vector(*info.feedback_vector());
  }
1636
  return existing;
1637 1638 1639
}


1640 1641 1642
MaybeHandle<Code> Compiler::GetOptimizedCode(Handle<JSFunction> function,
                                             Handle<Code> current_code,
                                             ConcurrencyMode mode,
1643 1644
                                             BailoutId osr_ast_id,
                                             JavaScriptFrame* osr_frame) {
1645 1646 1647 1648
  Isolate* isolate = function->GetIsolate();
  Handle<SharedFunctionInfo> shared(function->shared(), isolate);
  if (shared->HasDebugInfo()) return MaybeHandle<Code>();

1649 1650 1651
  Handle<Code> cached_code;
  if (GetCodeFromOptimizedCodeMap(
          function, osr_ast_id).ToHandle(&cached_code)) {
1652 1653 1654 1655 1656 1657 1658 1659
    if (FLAG_trace_opt) {
      PrintF("[found optimized code for ");
      function->ShortPrint();
      if (!osr_ast_id.IsNone()) {
        PrintF(" at OSR AST id %d", osr_ast_id.ToInt());
      }
      PrintF("]\n");
    }
1660 1661
    return cached_code;
  }
1662

1663
  DCHECK(AllowCompilation::IsAllowed(isolate));
1664

1665 1666
  if (!shared->is_compiled() ||
      shared->scope_info() == ScopeInfo::Empty(isolate)) {
1667
    // The function was never compiled. Compile it unoptimized first.
1668
    // TODO(titzer): reuse the AST and scope info from this compile.
1669 1670 1671
    CompilationInfoWithZone unoptimized(function);
    unoptimized.EnableDeoptimizationSupport();
    if (!GetUnoptimizedCodeCommon(&unoptimized).ToHandle(&current_code)) {
1672 1673
      return MaybeHandle<Code>();
    }
1674
    shared->ReplaceCode(*current_code);
1675
  }
1676

1677
  current_code->set_profiler_ticks(0);
1678

1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690
  // TODO(mstarzinger): We cannot properly deserialize a scope chain containing
  // an eval scope and hence would fail at parsing the eval source again.
  if (shared->disable_optimization_reason() == kEval) {
    return MaybeHandle<Code>();
  }

  // TODO(mstarzinger): We cannot properly deserialize a scope chain for the
  // builtin context, hence Genesis::InstallExperimentalNatives would fail.
  if (shared->is_toplevel() && isolate->bootstrapper()->IsActive()) {
    return MaybeHandle<Code>();
  }

rmcilroy's avatar
rmcilroy committed
1691 1692
  base::SmartPointer<CompilationInfo> info(
      new CompilationInfoWithZone(function));
1693 1694 1695 1696
  VMState<COMPILER> state(isolate);
  DCHECK(!isolate->has_pending_exception());
  PostponeInterruptsScope postpone(isolate);

1697
  info->SetOptimizing(osr_ast_id, current_code);
1698

1699 1700 1701 1702
  if (mode == CONCURRENT) {
    if (GetOptimizedCodeLater(info.get())) {
      info.Detach();  // The background recompile job owns this now.
      return isolate->builtins()->InOptimizationQueue();
1703
    }
1704
  } else {
1705
    info->set_osr_frame(osr_frame);
1706 1707
    if (GetOptimizedCodeNow(info.get())) return info->code();
  }
1708

1709
  if (isolate->has_pending_exception()) isolate->clear_pending_exception();
1710
  return MaybeHandle<Code>();
1711 1712 1713
}


1714 1715 1716
Handle<Code> Compiler::GetConcurrentlyOptimizedCode(OptimizedCompileJob* job) {
  // Take ownership of compilation info.  Deleting compilation info
  // also tears down the zone and the recompile job.
rmcilroy's avatar
rmcilroy committed
1717
  base::SmartPointer<CompilationInfo> info(job->info());
1718
  Isolate* isolate = info->isolate();
1719

1720
  VMState<COMPILER> state(isolate);
1721
  TimerEventScope<TimerEventRecompileSynchronous> timer(info->isolate());
1722

1723 1724 1725
  Handle<SharedFunctionInfo> shared = info->shared_info();
  shared->code()->set_profiler_ticks(0);

1726 1727
  DCHECK(!shared->HasDebugInfo());

1728
  // 1) Optimization on the concurrent thread may have failed.
1729 1730 1731
  // 2) The function may have already been optimized by OSR.  Simply continue.
  //    Except when OSR already disabled optimization for some reason.
  // 3) The code may have already been invalidated due to dependency change.
1732
  // 4) Code generation may have failed.
1733 1734 1735
  if (job->last_status() == OptimizedCompileJob::SUCCEEDED) {
    if (shared->optimization_disabled()) {
      job->RetryOptimization(kOptimizationDisabled);
1736
    } else if (info->dependencies()->HasAborted()) {
1737 1738 1739
      job->RetryOptimization(kBailedOutDueToDependencyChange);
    } else if (job->GenerateCode() == OptimizedCompileJob::SUCCEEDED) {
      RecordFunctionCompilation(Logger::LAZY_COMPILE_TAG, info.get(), shared);
1740 1741
      if (shared->SearchOptimizedCodeMap(info->context()->native_context(),
                                         info->osr_ast_id()).code == nullptr) {
1742 1743 1744 1745 1746 1747 1748 1749 1750
        InsertCodeIntoOptimizedCodeMap(info.get());
      }
      if (FLAG_trace_opt) {
        PrintF("[completed optimizing ");
        info->closure()->ShortPrint();
        PrintF("]\n");
      }
      return Handle<Code>(*info->code());
    }
1751
  }
1752

1753 1754 1755 1756 1757
  DCHECK(job->last_status() != OptimizedCompileJob::SUCCEEDED);
  if (FLAG_trace_opt) {
    PrintF("[aborted optimizing ");
    info->closure()->ShortPrint();
    PrintF(" because: %s]\n", GetBailoutReason(info->bailout_reason()));
1758
  }
1759
  return Handle<Code>::null();
1760 1761 1762
}


1763
CompilationPhase::CompilationPhase(const char* name, CompilationInfo* info)
1764
    : name_(name), info_(info) {
1765
  if (FLAG_hydrogen_stats) {
1766
    info_zone_start_allocation_size_ = info->zone()->allocation_size();
1767
    timer_.Start();
1768 1769 1770 1771 1772 1773
  }
}


CompilationPhase::~CompilationPhase() {
  if (FLAG_hydrogen_stats) {
1774
    size_t size = zone()->allocation_size();
1775
    size += info_->zone()->allocation_size() - info_zone_start_allocation_size_;
1776
    isolate()->GetHStatistics()->SaveTiming(name_, timer_.Elapsed(), size);
1777 1778 1779 1780 1781
  }
}


bool CompilationPhase::ShouldProduceTraceOutput() const {
1782 1783
  // Trace if the appropriate trace flag is set and the phase name's first
  // character is in the FLAG_trace_phase command line parameter.
1784
  AllowHandleDereference allow_deref;
1785 1786 1787 1788
  bool tracing_on = info()->IsStub()
      ? FLAG_trace_hydrogen_stubs
      : (FLAG_trace_hydrogen &&
         info()->closure()->PassesFilter(FLAG_trace_hydrogen_filter));
1789
  return (tracing_on &&
1790
      base::OS::StrChr(const_cast<char*>(FLAG_trace_phase), name_[0]) != NULL);
1791 1792
}

1793 1794 1795
#if DEBUG
void CompilationInfo::PrintAstForTesting() {
  PrintF("--- Source from AST ---\n%s\n",
1796
         PrettyPrinter(isolate()).PrintProgram(literal()));
1797 1798
}
#endif
1799 1800
}  // namespace internal
}  // namespace v8