compiler.cc 64.6 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 10 11 12
#include "src/ast/ast-numbering.h"
#include "src/ast/prettyprinter.h"
#include "src/ast/scopeinfo.h"
#include "src/ast/scopes.h"
13 14 15
#include "src/bootstrapper.h"
#include "src/codegen.h"
#include "src/compilation-cache.h"
16
#include "src/compiler/pipeline.h"
17 18 19
#include "src/crankshaft/hydrogen.h"
#include "src/crankshaft/lithium.h"
#include "src/crankshaft/typing.h"
20 21
#include "src/debug/debug.h"
#include "src/debug/liveedit.h"
22
#include "src/deoptimizer.h"
23
#include "src/full-codegen/full-codegen.h"
24
#include "src/gdb-jit.h"
25
#include "src/interpreter/interpreter.h"
26
#include "src/isolate-inl.h"
27
#include "src/log-inl.h"
28
#include "src/messages.h"
29 30 31
#include "src/parsing/parser.h"
#include "src/parsing/rewriter.h"
#include "src/parsing/scanner-character-streams.h"
32
#include "src/profiler/cpu-profiler.h"
33
#include "src/runtime-profiler.h"
34
#include "src/snapshot/serialize.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
      debug_name_(debug_name) {
182 183 184 185 186 187 188
  // 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_--;
    }
189 190 191
    set_output_code_kind(code_stub->GetCodeKind());
  } else {
    set_output_code_kind(Code::FUNCTION);
192 193
  }
}
194 195


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


207
int CompilationInfo::num_parameters() const {
208
  return has_scope() ? scope()->num_parameters() : parameter_count_;
209 210 211
}


212 213 214 215 216 217 218 219
int CompilationInfo::num_parameters_including_this() const {
  return num_parameters() + (is_this_defined() ? 1 : 0);
}


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


220
int CompilationInfo::num_heap_slots() const {
221
  return has_scope() ? scope()->num_heap_slots() : 0;
222 223 224
}


225 226 227 228
// 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() {
229
  return FLAG_crankshaft &&
230 231 232
         !(literal()->flags() & AstProperties::kDontSelfOptimize) &&
         !literal()->dont_optimize() &&
         literal()->scope()->AllowsLazyCompilation() &&
233
         (!has_shared_info() || !shared_info()->optimization_disabled());
234 235
}

236

237
void CompilationInfo::EnsureFeedbackVector() {
238
  if (feedback_vector_.is_null()) {
239 240 241
    Handle<TypeFeedbackMetadata> feedback_metadata =
        TypeFeedbackMetadata::New(isolate(), literal()->feedback_vector_spec());
    feedback_vector_ = TypeFeedbackVector::New(isolate(), feedback_metadata);
242
  }
243 244 245

  // It's very important that recompiles do not alter the structure of the
  // type feedback vector.
246 247
  CHECK(!feedback_vector_->metadata()->SpecDiffersFrom(
      literal()->feedback_vector_spec()));
248 249 250
}


251 252
bool CompilationInfo::has_simple_parameters() {
  return scope()->has_simple_parameters();
253
}
254 255 256


int CompilationInfo::TraceInlinedFunction(Handle<SharedFunctionInfo> shared,
257 258
                                          SourcePosition position,
                                          int parent_id) {
259
  DCHECK(track_positions_);
260

261
  int inline_id = static_cast<int>(inlined_function_infos_.size());
262 263 264 265
  InlinedFunctionInfo info(parent_id, position, UnboundScript::kNoScriptId,
      shared->start_position());
  if (!shared->script()->IsUndefined()) {
    Handle<Script> script(Script::cast(shared->script()));
266
    info.script_id = script->id();
267

268
    if (FLAG_hydrogen_track_positions && !script->source()->IsUndefined()) {
269 270 271 272 273 274 275 276 277 278 279 280 281
      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);
        }
282
      }
283 284

      os << "\n--- END ---\n";
285 286 287
    }
  }

288
  inlined_function_infos_.push_back(info);
289

290
  if (FLAG_hydrogen_track_positions && inline_id != 0) {
291 292 293
    CodeTracer::Scope tracing_scope(isolate()->GetCodeTracer());
    OFStream os(tracing_scope.file());
    os << "INLINE (" << shared->DebugName()->ToCString().get() << ") id{"
294 295
       << optimization_id() << "," << inline_id << "} AS " << inline_id
       << " AT " << position << std::endl;
296 297 298 299
  }

  return inline_id;
}
300 301


302 303
void CompilationInfo::LogDeoptCallPosition(int pc_offset, int inlining_id) {
  if (!track_positions_ || IsStub()) return;
304 305
  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);
306 307 308
}


309
base::SmartArrayPointer<char> CompilationInfo::GetDebugName() const {
310
  if (parse_info()) {
311
    AllowHandleDereference allow_deref;
312
    return parse_info()->literal()->debug_name()->ToCString();
313
  }
314 315 316 317 318
  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;
319 320 321
}


322 323
bool CompilationInfo::ExpectsJSReceiverAsReceiver() {
  return is_sloppy(language_mode()) && !is_native();
324 325 326
}


327
class HOptimizedGraphBuilderWithPositions: public HOptimizedGraphBuilder {
328
 public:
329
  explicit HOptimizedGraphBuilderWithPositions(CompilationInfo* info)
330 331 332
      : HOptimizedGraphBuilder(info) {
  }

333
#define DEF_VISIT(type)                                      \
334
  void Visit##type(type* node) override {                    \
335 336 337 338 339 340 341 342 343
    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);                     \
    }                                                        \
344 345 346 347
  }
  EXPRESSION_NODE_LIST(DEF_VISIT)
#undef DEF_VISIT

348
#define DEF_VISIT(type)                                      \
349
  void Visit##type(type* node) override {                    \
350 351 352 353 354 355 356 357 358
    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);                     \
    }                                                        \
359 360 361 362
  }
  STATEMENT_NODE_LIST(DEF_VISIT)
#undef DEF_VISIT

363
#define DEF_VISIT(type)                        \
364
  void Visit##type(type* node) override {      \
365
    HOptimizedGraphBuilder::Visit##type(node); \
366 367 368 369 370 371
  }
  DECLARATION_NODE_LIST(DEF_VISIT)
#undef DEF_VISIT
};


372
OptimizedCompileJob::Status OptimizedCompileJob::CreateGraph() {
373
  DCHECK(info()->IsOptimizing());
374

375
  // Do not use Crankshaft/TurboFan if we need to be able to set break points.
376 377
  if (info()->shared_info()->HasDebugInfo()) {
    return AbortOptimization(kFunctionBeingDebugged);
378
  }
379

380
  // Limit the number of times we try to optimize functions.
381
  const int kMaxOptCount =
382
      FLAG_deopt_every_n_times == 0 ? FLAG_max_opt_count : 1000;
383
  if (info()->opt_count() > kMaxOptCount) {
384
    return AbortOptimization(kOptimizedTooManyTimes);
385 386
  }

387
  // Check the whitelist for Crankshaft.
388
  if (!info()->closure()->PassesFilter(FLAG_hydrogen_filter)) {
389
    return AbortOptimization(kHydrogenFilter);
390 391
  }

392
  // Optimization requires a version of fullcode with deoptimization support.
393
  // Recompile the unoptimized version of the code if the current version
394 395 396
  // 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.
397
  bool should_recompile = !info()->shared_info()->has_deoptimization_support();
398
  if (should_recompile || FLAG_hydrogen_stats) {
399
    base::ElapsedTimer timer;
400
    if (FLAG_hydrogen_stats) {
401
      timer.Start();
402
    }
403 404
    if (!Compiler::EnsureDeoptimizationSupport(info())) {
      return SetLastStatus(FAILED);
405
    }
406
    if (FLAG_hydrogen_stats) {
407
      isolate()->GetHStatistics()->IncrementFullCodeGen(timer.Elapsed());
408
    }
409 410
  }

411
  DCHECK(info()->shared_info()->has_deoptimization_support());
412
  DCHECK(!info()->is_first_compile());
413

414
  // Check the enabling conditions for TurboFan.
415
  bool dont_crankshaft = info()->shared_info()->dont_crankshaft();
416
  if (((FLAG_turbo_asm && info()->shared_info()->asm_function()) ||
417
       (dont_crankshaft && strcmp(FLAG_turbo_filter, "~~") == 0) ||
418 419
       info()->closure()->PassesFilter(FLAG_turbo_filter)) &&
      (FLAG_turbo_osr || !info()->is_osr())) {
420
    // Use TurboFan for the compilation.
421 422 423
    if (FLAG_trace_opt) {
      OFStream os(stdout);
      os << "[compiling method " << Brief(*info()->closure())
424 425 426
         << " using TurboFan";
      if (info()->is_osr()) os << " OSR";
      os << "]" << std::endl;
427
    }
428 429

    if (info()->shared_info()->asm_function()) {
430
      if (info()->osr_frame()) info()->MarkAsFrameSpecializing();
431
      info()->MarkAsFunctionContextSpecializing();
432 433 434
    } else if (info()->has_global_object() &&
               FLAG_native_context_specialization) {
      info()->MarkAsNativeContextSpecializing();
435
      info()->MarkAsTypingEnabled();
436
    }
437 438 439 440
    if (!info()->shared_info()->asm_function() ||
        FLAG_turbo_asm_deoptimization) {
      info()->MarkAsDeoptimizationEnabled();
    }
441

442
    Timer t(this, &time_taken_to_create_graph_);
443 444
    compiler::Pipeline pipeline(info());
    pipeline.GenerateCode();
445 446 447
    if (!info()->code().is_null()) {
      return SetLastStatus(SUCCEEDED);
    }
448 449
  }

450
  if (!isolate()->use_crankshaft() || dont_crankshaft) {
451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466
    // 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);
  }
467

468 469 470 471 472
  if (scope->HasIllegalRedeclaration()) {
    // Crankshaft cannot handle illegal redeclarations.
    return AbortOptimization(kFunctionWithIllegalRedeclaration);
  }

473 474 475
  if (FLAG_trace_opt) {
    OFStream os(stdout);
    os << "[compiling method " << Brief(*info()->closure())
476 477 478
       << " using Crankshaft";
    if (info()->is_osr()) os << " OSR";
    os << "]" << std::endl;
479 480
  }

481
  if (FLAG_trace_hydrogen) {
482
    isolate()->GetHTracer()->TraceCompilation(info());
483
  }
484 485

  // Type-check the function.
486 487 488
  AstTyper(info()->isolate(), info()->zone(), info()->closure(),
           info()->scope(), info()->osr_ast_id(), info()->literal())
      .Run();
489

490 491 492 493 494 495 496
  // 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());
  }

497 498 499 500
  graph_builder_ = (info()->is_tracking_positions() || FLAG_trace_ic)
                       ? new (info()->zone())
                             HOptimizedGraphBuilderWithPositions(info())
                       : new (info()->zone()) HOptimizedGraphBuilder(info());
501 502

  Timer t(this, &time_taken_to_create_graph_);
503 504
  graph_ = graph_builder_->CreateGraph();

505
  if (isolate()->has_pending_exception()) {
506
    return SetLastStatus(FAILED);
507 508
  }

509
  if (graph_ == NULL) return SetLastStatus(BAILED_OUT);
510

511
  if (info()->dependencies()->HasAborted()) {
512 513
    // Dependency has changed during graph creation. Let's try again later.
    return RetryOptimization(kBailedOutDueToDependencyChange);
514 515
  }

516 517 518
  return SetLastStatus(SUCCEEDED);
}

519

520
OptimizedCompileJob::Status OptimizedCompileJob::OptimizeGraph() {
521 522 523
  DisallowHeapAllocation no_allocation;
  DisallowHandleAllocation no_handles;
  DisallowHandleDereference no_deref;
524
  DisallowCodeDependencyChange no_dependency_change;
525

526
  DCHECK(last_status() == SUCCEEDED);
527 528 529 530 531
  // TODO(turbofan): Currently everything is done in the first phase.
  if (!info()->code().is_null()) {
    return last_status();
  }

532
  Timer t(this, &time_taken_to_optimize_);
533
  DCHECK(graph_ != NULL);
534
  BailoutReason bailout_reason = kNoReason;
535 536

  if (graph_->Optimize(&bailout_reason)) {
537
    chunk_ = LChunk::NewChunk(graph_);
538 539 540
    if (chunk_ != NULL) return SetLastStatus(SUCCEEDED);
  } else if (bailout_reason != kNoReason) {
    graph_builder_->Bailout(bailout_reason);
541
  }
542

543
  return SetLastStatus(BAILED_OUT);
544 545 546
}


547
OptimizedCompileJob::Status OptimizedCompileJob::GenerateCode() {
548
  DCHECK(last_status() == SUCCEEDED);
549 550
  // TODO(turbofan): Currently everything is done in the first phase.
  if (!info()->code().is_null()) {
551
    info()->dependencies()->Commit(info()->code());
552
    if (info()->is_deoptimization_enabled()) {
553 554
      info()->parse_info()->context()->native_context()->AddOptimizedCode(
          *info()->code());
555
    }
556 557 558 559
    RecordOptimizationStats();
    return last_status();
  }

560
  DCHECK(!info()->dependencies()->HasAborted());
561
  DisallowCodeDependencyChange no_dependency_change;
562
  DisallowJavascriptExecution no_js(isolate());
563 564
  {  // Scope for timer.
    Timer timer(this, &time_taken_to_codegen_);
565 566
    DCHECK(chunk_ != NULL);
    DCHECK(graph_ != NULL);
567 568 569 570
    // 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.
571
    DisallowDeferredHandleDereference no_deferred_handle_deref;
572
    Handle<Code> optimized_code = chunk_->Codegen();
573
    if (optimized_code.is_null()) {
574
      if (info()->bailout_reason() == kNoReason) {
575
        return AbortOptimization(kCodeGenerationFailed);
576
      }
577
      return SetLastStatus(BAILED_OUT);
578 579
    }
    info()->SetCode(optimized_code);
580
  }
581
  RecordOptimizationStats();
582 583
  // Add to the weak list of optimized code objects.
  info()->context()->native_context()->AddOptimizedCode(*info()->code());
584
  return SetLastStatus(SUCCEEDED);
585 586 587
}


588 589 590 591 592 593
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);
594
  }
595 596 597 598 599 600 601 602
  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);
603
  }
604 605 606 607
  if (FLAG_trace_opt_stats) {
    static double compilation_time = 0.0;
    static int compiled_functions = 0;
    static int code_size = 0;
608

609 610 611 612 613 614 615 616 617 618 619 620 621
    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_);
  }
622 623 624
}


625 626 627 628 629 630 631 632 633 634
// 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.
635
  if (shared->GetIsolate()->serializer_enabled()) {
636
    estimate += 2;
jochen's avatar
jochen committed
637
  } else {
638 639 640 641 642 643 644 645 646
    // 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);
}


647 648 649 650 651 652 653 654
static void MaybeDisableOptimization(Handle<SharedFunctionInfo> shared_info,
                                     BailoutReason bailout_reason) {
  if (bailout_reason != kNoReason) {
    shared_info->DisableOptimization(bailout_reason);
  }
}


655 656 657 658 659 660 661 662 663 664 665
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()) {
666
    Handle<Script> script = info->parse_info()->script();
667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684
    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));
  }
}


685
static bool CompileUnoptimizedCode(CompilationInfo* info) {
686
  DCHECK(AllowCompilation::IsAllowed(info->isolate()));
687 688
  if (!Compiler::Analyze(info->parse_info()) ||
      !FullCodeGenerator::MakeCode(info)) {
689 690 691
    Isolate* isolate = info->isolate();
    if (!isolate->has_pending_exception()) isolate->StackOverflow();
    return false;
692
  }
693 694
  return true;
}
695

696

697 698 699 700 701 702 703 704 705 706 707 708 709 710
// TODO(rmcilroy): Remove this temporary work-around when ignition supports
// catch and eval.
static bool IgnitionShouldFallbackToFullCodeGen(Scope* scope) {
  if (scope->is_eval_scope() || scope->is_catch_scope() ||
      scope->calls_eval()) {
    return true;
  }
  for (auto inner_scope : *scope->inner_scopes()) {
    if (IgnitionShouldFallbackToFullCodeGen(inner_scope)) return true;
  }
  return false;
}


711 712 713 714
static bool UseIgnition(CompilationInfo* info) {
  // Cannot use Ignition when the {function_data} is already used.
  if (info->has_shared_info() && info->shared_info()->HasBuiltinFunctionId()) {
    return false;
715
  }
716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745

  // Checks whether the scope chain is supported.
  if (FLAG_ignition_fallback_on_eval_and_catch &&
      IgnitionShouldFallbackToFullCodeGen(info->scope())) {
    return false;
  }

  // Checks whether top level functions should be passed by the filter.
  if (info->closure().is_null()) {
    Vector<const char> filter = CStrVector(FLAG_ignition_filter);
    return (filter.length() == 0) || (filter.length() == 1 && filter[0] == '*');
  }

  // Finally respect the filter.
  return info->closure()->PassesFilter(FLAG_ignition_filter);
}


static bool GenerateBaselineCode(CompilationInfo* info) {
  if (FLAG_ignition && UseIgnition(info)) {
    return interpreter::Interpreter::MakeBytecode(info);
  } else {
    return FullCodeGenerator::MakeCode(info);
  }
}


static bool CompileBaselineCode(CompilationInfo* info) {
  DCHECK(AllowCompilation::IsAllowed(info->isolate()));
  if (!Compiler::Analyze(info->parse_info()) || !GenerateBaselineCode(info)) {
746 747
    Isolate* isolate = info->isolate();
    if (!isolate->has_pending_exception()) isolate->StackOverflow();
748
    return false;
749
  }
750
  return true;
751 752 753
}


754 755
MUST_USE_RESULT static MaybeHandle<Code> GetUnoptimizedCodeCommon(
    CompilationInfo* info) {
756 757
  VMState<COMPILER> state(info->isolate());
  PostponeInterruptsScope postpone(info->isolate());
758 759

  // Parse and update CompilationInfo with the results.
760
  if (!Parser::ParseStatic(info->parse_info())) return MaybeHandle<Code>();
761
  Handle<SharedFunctionInfo> shared = info->shared_info();
762
  FunctionLiteral* lit = info->literal();
763
  DCHECK_EQ(shared->language_mode(), lit->language_mode());
764
  SetExpectedNofPropertiesFromEstimate(shared, lit->expected_property_count());
765
  MaybeDisableOptimization(shared, lit->dont_optimize_reason());
766

767 768 769
  // Compile either unoptimized code or bytecode for the interpreter.
  if (!CompileBaselineCode(info)) return MaybeHandle<Code>();
  if (info->code()->kind() == Code::FUNCTION) {  // Only for full code.
770 771
    RecordFunctionCompilation(Logger::LAZY_COMPILE_TAG, info, shared);
  }
772 773 774

  // Update the shared function info with the scope info. Allocating the
  // ScopeInfo object may cause a GC.
775 776
  Handle<ScopeInfo> scope_info =
      ScopeInfo::Create(info->isolate(), info->zone(), info->scope());
777 778 779 780 781
  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());
782 783 784 785
  if (info->has_bytecode_array()) {
    DCHECK(shared->function_data()->IsUndefined());
    shared->set_function_data(*info->bytecode_array());
  }
786

787 788
  return info->code();
}
789 790


791 792
MUST_USE_RESULT static MaybeHandle<Code> GetCodeFromOptimizedCodeMap(
    Handle<JSFunction> function, BailoutId osr_ast_id) {
793 794 795 796 797 798 799 800 801 802
  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);
803 804 805 806 807 808 809 810 811
  }
  return MaybeHandle<Code>();
}


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

812 813
  // Function context specialization folds-in the function context,
  // so no sharing can occur.
814 815
  if (info->is_function_context_specializing()) return;
  // Frame specialization implies function context specialization.
816
  DCHECK(!info->is_frame_specializing());
817

818
  // Do not cache bound functions.
819 820
  Handle<JSFunction> function = info->closure();
  if (function->shared()->bound()) return;
821

822
  // Cache optimized context-specific code.
823 824 825 826 827
  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());
828

829
  // Do not cache (native) context-independent code compiled for OSR.
830 831
  if (code->is_turbofanned() && info->is_osr()) return;

832 833 834
  // Cache optimized (native) context-independent code.
  if (FLAG_turbo_cache_shared_code && code->is_turbofanned() &&
      !info->is_native_context_specializing()) {
835
    DCHECK(!info->is_function_context_specializing());
836 837 838 839
    DCHECK(info->osr_ast_id().IsNone());
    Handle<SharedFunctionInfo> shared(function->shared());
    SharedFunctionInfo::AddSharedCodeToOptimizedCodeMap(shared, code);
  }
840 841 842
}


843 844
static bool Renumber(ParseInfo* parse_info) {
  if (!AstNumbering::Renumber(parse_info->isolate(), parse_info->zone(),
845
                              parse_info->literal())) {
846 847
    return false;
  }
848 849
  Handle<SharedFunctionInfo> shared_info = parse_info->shared_info();
  if (!shared_info.is_null()) {
850
    FunctionLiteral* lit = parse_info->literal();
851 852
    shared_info->set_ast_node_count(lit->ast_node_count());
    MaybeDisableOptimization(shared_info, lit->dont_optimize_reason());
853 854
    shared_info->set_dont_crankshaft(lit->flags() &
                                     AstProperties::kDontCrankshaft);
855 856 857 858 859
  }
  return true;
}


860
bool Compiler::Analyze(ParseInfo* info) {
861
  DCHECK_NOT_NULL(info->literal());
862 863
  if (!Rewriter::Rewrite(info)) return false;
  if (!Scope::Analyze(info)) return false;
864
  if (!Renumber(info)) return false;
865
  DCHECK_NOT_NULL(info->scope());
866 867 868 869
  return true;
}


870
bool Compiler::ParseAndAnalyze(ParseInfo* info) {
871
  if (!Parser::ParseStatic(info)) return false;
872 873 874 875
  return Compiler::Analyze(info);
}


876
static bool GetOptimizedCodeNow(CompilationInfo* info) {
877 878 879
  Isolate* isolate = info->isolate();
  CanonicalHandleScope canonical(isolate);

880
  if (!Compiler::ParseAndAnalyze(info->parse_info())) return false;
881

882
  TimerEventScope<TimerEventRecompileSynchronous> timer(isolate);
883 884

  OptimizedCompileJob job(info);
885 886 887 888 889 890 891 892 893 894
  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;
  }
895 896

  // Success!
897
  DCHECK(!isolate->has_pending_exception());
898 899 900 901 902 903 904 905 906
  InsertCodeIntoOptimizedCodeMap(info);
  RecordFunctionCompilation(Logger::LAZY_COMPILE_TAG, info,
                            info->shared_info());
  return true;
}


static bool GetOptimizedCodeLater(CompilationInfo* info) {
  Isolate* isolate = info->isolate();
907 908
  CanonicalHandleScope canonical(isolate);

909
  if (!isolate->optimizing_compile_dispatcher()->IsQueueAvailable()) {
910 911
    if (FLAG_trace_concurrent_recompilation) {
      PrintF("  ** Compilation queue full, will retry optimizing ");
912
      info->closure()->ShortPrint();
913 914 915 916 917 918
      PrintF(" later.\n");
    }
    return false;
  }

  CompilationHandleScope handle_scope(info);
919 920 921 922 923
  if (!Compiler::ParseAndAnalyze(info->parse_info())) return false;

  // Reopen handles in the new CompilationHandleScope.
  info->ReopenHandlesInNewHandleScope();
  info->parse_info()->ReopenHandlesInNewHandleScope();
924 925 926 927 928 929

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

  OptimizedCompileJob* job = new (info->zone()) OptimizedCompileJob(info);
  OptimizedCompileJob::Status status = job->CreateGraph();
  if (status != OptimizedCompileJob::SUCCEEDED) return false;
930
  isolate->optimizing_compile_dispatcher()->QueueForOptimization(job);
931 932 933

  if (FLAG_trace_concurrent_recompilation) {
    PrintF("  ** Queued ");
934
    info->closure()->ShortPrint();
935 936 937 938 939 940 941 942 943 944
    if (info->is_osr()) {
      PrintF(" for concurrent OSR at %d.\n", info->osr_ast_id().ToInt());
    } else {
      PrintF(" for concurrent optimization.\n");
    }
  }
  return true;
}


945
MaybeHandle<Code> Compiler::GetUnoptimizedCode(Handle<JSFunction> function) {
946 947
  DCHECK(!function->GetIsolate()->has_pending_exception());
  DCHECK(!function->is_compiled());
948 949 950
  if (function->shared()->is_compiled()) {
    return Handle<Code>(function->shared()->code());
  }
951

952
  CompilationInfoWithZone info(function);
953 954 955 956
  Handle<Code> result;
  ASSIGN_RETURN_ON_EXCEPTION(info.isolate(), result,
                             GetUnoptimizedCodeCommon(&info),
                             Code);
957 958 959 960 961
  return result;
}


MaybeHandle<Code> Compiler::GetLazyCode(Handle<JSFunction> function) {
962 963
  Isolate* isolate = function->GetIsolate();
  DCHECK(!isolate->has_pending_exception());
964
  DCHECK(!function->is_compiled());
965
  AggregatedHistogramTimerScope timer(isolate->counters()->compile_lazy());
966 967 968
  // 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() &&
969
      (FLAG_turbo_asm_deoptimization || !isolate->debug()->is_active()) &&
970
      !FLAG_turbo_osr) {
971 972
    CompilationInfoWithZone info(function);

973 974
    VMState<COMPILER> state(isolate);
    PostponeInterruptsScope postpone(isolate);
975

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

978 979 980 981
    if (GetOptimizedCodeNow(&info)) {
      DCHECK(function->shared()->is_compiled());
      return info.code();
    }
982 983 984
    // 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();
985 986
  }

987 988 989 990 991 992
  if (function->shared()->is_compiled()) {
    return Handle<Code>(function->shared()->code());
  }

  CompilationInfoWithZone info(function);
  Handle<Code> result;
993 994
  ASSIGN_RETURN_ON_EXCEPTION(isolate, result, GetUnoptimizedCodeCommon(&info),
                             Code);
995

996
  if (FLAG_always_opt) {
997 998 999 1000 1001 1002
    Handle<Code> opt_code;
    if (Compiler::GetOptimizedCode(
            function, result,
            Compiler::NOT_CONCURRENT).ToHandle(&opt_code)) {
      result = opt_code;
    }
1003
  }
1004

1005 1006
  return result;
}
1007

1008

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

1024

1025 1026 1027
// TODO(turbofan): In the future, unoptimized code with deopt support could
// be generated lazily once deopt is triggered.
bool Compiler::EnsureDeoptimizationSupport(CompilationInfo* info) {
1028 1029
  DCHECK_NOT_NULL(info->literal());
  DCHECK(info->has_scope());
1030 1031
  Handle<SharedFunctionInfo> shared = info->shared_info();
  if (!shared->has_deoptimization_support()) {
1032
    // TODO(titzer): just reuse the ParseInfo for the unoptimized compile.
1033
    CompilationInfoWithZone unoptimized(info->closure());
1034 1035
    // Note that we use the same AST that we will use for generating the
    // optimized code.
1036
    ParseInfo* parse_info = unoptimized.parse_info();
1037
    parse_info->set_literal(info->literal());
1038 1039
    parse_info->set_scope(info->scope());
    parse_info->set_context(info->context());
1040
    unoptimized.EnableDeoptimizationSupport();
1041 1042 1043 1044 1045 1046 1047
    // 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();
    }
1048 1049 1050 1051 1052
    if (!FullCodeGenerator::MakeCode(&unoptimized)) return false;

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

1053 1054
    info->MarkAsCompiled();

1055 1056 1057 1058
    // 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 =
1059
          ScopeInfo::Create(info->isolate(), info->zone(), info->scope());
1060 1061 1062 1063 1064 1065 1066 1067 1068 1069
      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;
}


1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095
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;
  }

1096
  FunctionLiteral* lit = parse_info.literal();
1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108
  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) {
1109
  info->MarkAsDebug();
1110
  if (GetUnoptimizedCodeCommon(info).is_null()) {
1111
    info->isolate()->clear_pending_exception();
1112
    return false;
1113
  }
1114
  return true;
1115 1116 1117
}


1118 1119 1120 1121 1122 1123 1124
static inline bool IsEvalToplevel(Handle<SharedFunctionInfo> shared) {
  return shared->is_toplevel() && shared->script()->IsScript() &&
         Script::cast(shared->script())->compilation_type() ==
             Script::COMPILATION_TYPE_EVAL;
}


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


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


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

1154
  // Get rid of old list of shared function infos.
1155
  info.MarkAsFirstCompile();
1156
  info.MarkAsDebug();
1157 1158
  info.parse_info()->set_global();
  if (!Parser::ParseStatic(info.parse_info())) return;
1159

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


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

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

1182
  isolate->debug()->OnBeforeCompile(script);
1183

1184 1185
  DCHECK(parse_info->is_eval() || parse_info->is_global() ||
         parse_info->is_module());
1186

1187
  parse_info->set_toplevel();
1188

1189 1190 1191
  Handle<SharedFunctionInfo> result;

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

1202
      parse_info->set_allow_lazy_parsing(parse_allow_lazy);
1203
      if (!parse_allow_lazy &&
1204 1205
          (options == ScriptCompiler::kProduceParserCache ||
           options == ScriptCompiler::kConsumeParserCache)) {
1206 1207 1208 1209
        // 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.
1210 1211
        parse_info->set_cached_data(nullptr);
        parse_info->set_compile_options(ScriptCompiler::kNoCompileOptions);
1212
      }
1213
      if (!Parser::ParseStatic(parse_info)) {
1214 1215
        return Handle<SharedFunctionInfo>::null();
      }
1216 1217
    }

1218 1219
    DCHECK(!info->is_debug() || !parse_info->allow_lazy_parsing());

1220 1221
    info->MarkAsFirstCompile();

1222
    FunctionLiteral* lit = parse_info->literal();
1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233
    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.
1234 1235
    if (!CompileBaselineCode(info)) {
      return Handle<SharedFunctionInfo>::null();
1236 1237 1238
    }

    // Allocate function.
1239
    DCHECK(!info->code().is_null());
1240
    result = isolate->factory()->NewSharedFunctionInfo(
1241
        lit->name(), lit->materialized_literal_count(), lit->kind(),
1242 1243
        info->code(),
        ScopeInfo::Create(info->isolate(), info->zone(), info->scope()),
1244
        info->feedback_vector());
1245 1246 1247 1248
    if (info->has_bytecode_array()) {
      DCHECK(result->function_data()->IsUndefined());
      result->set_function_data(*info->bytecode_array());
    }
1249

1250
    DCHECK_EQ(RelocInfo::kNoPosition, lit->function_token_position());
1251
    SharedFunctionInfo::InitFromFunctionLiteral(result, lit);
1252
    SharedFunctionInfo::SetScript(result, script);
1253
    result->set_is_toplevel(true);
1254 1255 1256 1257
    if (info->is_eval()) {
      // Eval scripts cannot be (re-)compiled without context.
      result->set_allows_lazy_compilation_without_context(false);
    }
1258

1259 1260 1261 1262
    Handle<String> script_name =
        script->name()->IsString()
            ? Handle<String>(String::cast(script->name()))
            : isolate->factory()->empty_string();
1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275
    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());

1276 1277
    if (!script.is_null())
      script->set_compilation_state(Script::COMPILATION_STATE_COMPILED);
1278 1279 1280 1281 1282 1283 1284 1285

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

  return result;
}


1286
MaybeHandle<JSFunction> Compiler::GetFunctionFromEval(
1287
    Handle<String> source, Handle<SharedFunctionInfo> outer_info,
1288
    Handle<Context> context, LanguageMode language_mode,
1289 1290
    ParseRestriction restriction, int line_offset, int column_offset,
    Handle<Object> script_name, ScriptOriginOptions options) {
1291 1292 1293 1294 1295 1296
  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();
1297
  MaybeHandle<SharedFunctionInfo> maybe_shared_info =
1298
      compilation_cache->LookupEval(source, outer_info, context, language_mode,
1299
                                    line_offset);
1300
  Handle<SharedFunctionInfo> shared_info;
1301

1302
  Handle<Script> script;
1303
  if (!maybe_shared_info.ToHandle(&shared_info)) {
1304
    script = isolate->factory()->NewScript(source);
1305 1306
    if (!script_name.is_null()) {
      script->set_name(*script_name);
1307 1308
      script->set_line_offset(line_offset);
      script->set_column_offset(column_offset);
1309 1310
    }
    script->set_origin_options(options);
1311 1312 1313 1314 1315 1316 1317 1318
    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);
1319 1320 1321 1322 1323 1324

    Debug::RecordEvalCaller(script);

    shared_info = CompileToplevel(&info);

    if (shared_info.is_null()) {
1325
      return MaybeHandle<JSFunction>();
1326 1327 1328
    } else {
      // Explicitly disable optimization for eval code. We're not yet prepared
      // to handle eval-code in the optimizing compiler.
1329 1330 1331
      if (restriction != ONLY_SINGLE_FUNCTION_LITERAL) {
        shared_info->DisableOptimization(kEval);
      }
1332

1333
      // If caller is strict mode, the result must be in strict mode as well.
1334 1335
      DCHECK(is_sloppy(language_mode) ||
             is_strict(shared_info->language_mode()));
1336
      compilation_cache->PutEval(source, outer_info, context, shared_info,
1337
                                 line_offset);
1338 1339 1340 1341 1342
    }
  } else if (shared_info->ic_age() != isolate->heap()->global_ic_age()) {
    shared_info->ResetForNewContext(isolate->heap()->global_ic_age());
  }

1343 1344 1345 1346 1347 1348 1349 1350 1351 1352
  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;
1353 1354 1355
}


1356
Handle<SharedFunctionInfo> Compiler::CompileScript(
1357
    Handle<String> source, Handle<Object> script_name, int line_offset,
1358 1359 1360
    int column_offset, ScriptOriginOptions resource_options,
    Handle<Object> source_map_url, Handle<Context> context,
    v8::Extension* extension, ScriptData** cached_data,
1361 1362
    ScriptCompiler::CompileOptions compile_options, NativesFlag natives,
    bool is_module) {
1363
  Isolate* isolate = source->GetIsolate();
1364
  if (compile_options == ScriptCompiler::kNoCompileOptions) {
1365
    cached_data = NULL;
1366 1367
  } else if (compile_options == ScriptCompiler::kProduceParserCache ||
             compile_options == ScriptCompiler::kProduceCodeCache) {
1368 1369
    DCHECK(cached_data && !*cached_data);
    DCHECK(extension == NULL);
1370
    DCHECK(!isolate->debug()->is_loaded());
1371
  } else {
1372
    DCHECK(compile_options == ScriptCompiler::kConsumeParserCache ||
1373
           compile_options == ScriptCompiler::kConsumeCodeCache);
1374 1375
    DCHECK(cached_data && *cached_data);
    DCHECK(extension == NULL);
1376
  }
1377 1378 1379 1380
  int source_length = source->length();
  isolate->counters()->total_load_size()->Increment(source_length);
  isolate->counters()->total_compile_size()->Increment(source_length);

1381 1382 1383 1384 1385 1386
  // 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);

1387 1388 1389
  CompilationCache* compilation_cache = isolate->compilation_cache();

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

1413 1414 1415 1416 1417 1418
  base::ElapsedTimer timer;
  if (FLAG_profile_deserialization && FLAG_serialize_toplevel &&
      compile_options == ScriptCompiler::kProduceCodeCache) {
    timer.Start();
  }

1419
  if (!maybe_result.ToHandle(&result)) {
1420
    // No cache entry found. Compile the script.
1421 1422

    // Create a script object describing the script to be compiled.
1423
    Handle<Script> script = isolate->factory()->NewScript(source);
1424
    if (natives == NATIVES_CODE) {
1425
      script->set_type(Script::TYPE_NATIVE);
1426
      script->set_hide_source(true);
1427
    }
1428 1429
    if (!script_name.is_null()) {
      script->set_name(*script_name);
1430 1431
      script->set_line_offset(line_offset);
      script->set_column_offset(column_offset);
1432
    }
1433
    script->set_origin_options(resource_options);
1434 1435 1436
    if (!source_map_url.is_null()) {
      script->set_source_mapping_url(*source_map_url);
    }
1437 1438

    // Compile the function and add it to the cache.
1439 1440 1441
    Zone zone;
    ParseInfo parse_info(&zone, script);
    CompilationInfo info(&parse_info);
1442
    if (FLAG_harmony_modules && is_module) {
1443
      parse_info.set_module();
1444
    } else {
1445
      parse_info.set_global();
1446
    }
1447
    if (compile_options != ScriptCompiler::kNoCompileOptions) {
1448
      parse_info.set_cached_data(cached_data);
1449
    }
1450 1451 1452
    parse_info.set_compile_options(compile_options);
    parse_info.set_extension(extension);
    parse_info.set_context(context);
1453 1454
    if (FLAG_serialize_toplevel &&
        compile_options == ScriptCompiler::kProduceCodeCache) {
1455 1456
      info.PrepareForSerializing();
    }
1457

1458
    parse_info.set_language_mode(
1459
        static_cast<LanguageMode>(info.language_mode() | language_mode));
1460
    result = CompileToplevel(&info);
1461
    if (extension == NULL && !result.is_null()) {
1462
      compilation_cache->PutScript(source, context, language_mode, result);
1463
      if (FLAG_serialize_toplevel &&
1464
          compile_options == ScriptCompiler::kProduceCodeCache) {
1465 1466
        HistogramTimerScope histogram_timer(
            isolate->counters()->compile_serialize());
1467
        *cached_data = CodeSerializer::Serialize(isolate, result, source);
1468
        if (FLAG_profile_deserialization) {
1469 1470
          PrintF("[Compiling and serializing took %0.3f ms]\n",
                 timer.Elapsed().InMillisecondsF());
1471
        }
1472
      }
1473
    }
1474

1475 1476 1477 1478 1479
    if (result.is_null()) {
      isolate->ReportPendingMessages();
    } else {
      isolate->debug()->OnAfterCompile(script);
    }
1480
  } else if (result->ic_age() != isolate->heap()->global_ic_age()) {
1481
    result->ResetForNewContext(isolate->heap()->global_ic_age());
1482 1483 1484 1485 1486
  }
  return result;
}


1487
Handle<SharedFunctionInfo> Compiler::CompileStreamedScript(
1488 1489 1490
    Handle<Script> script, ParseInfo* parse_info, int source_length) {
  Isolate* isolate = script->GetIsolate();
  // TODO(titzer): increment the counters in caller.
1491 1492 1493
  isolate->counters()->total_load_size()->Increment(source_length);
  isolate->counters()->total_compile_size()->Increment(source_length);

1494 1495
  LanguageMode language_mode =
      construct_language_mode(FLAG_use_strict, FLAG_use_strong);
1496 1497
  parse_info->set_language_mode(
      static_cast<LanguageMode>(parse_info->language_mode() | language_mode));
1498

1499
  CompilationInfo compile_info(parse_info);
1500

1501 1502
  // The source was parsed lazily, so compiling for debugging is not possible.
  DCHECK(!compile_info.is_debug());
1503

1504 1505 1506
  Handle<SharedFunctionInfo> result = CompileToplevel(&compile_info);
  if (!result.is_null()) isolate->debug()->OnAfterCompile(script);
  return result;
1507 1508 1509
}


1510
Handle<SharedFunctionInfo> Compiler::GetSharedFunctionInfo(
1511 1512
    FunctionLiteral* literal, Handle<Script> script,
    CompilationInfo* outer_info) {
1513
  // Precondition: code has been parsed and scopes have been analyzed.
1514
  Isolate* isolate = outer_info->isolate();
1515 1516 1517
  MaybeHandle<SharedFunctionInfo> maybe_existing;
  if (outer_info->is_first_compile()) {
    // On the first compile, there are no existing shared function info for
1518 1519 1520 1521
    // 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());
1522 1523 1524 1525 1526 1527
  } 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.
1528 1529
  // Carry on if we are compiling eager to obtain code for debugging,
  // unless we already have code with debut break slots.
1530 1531
  Handle<SharedFunctionInfo> existing;
  if (maybe_existing.ToHandle(&existing) && existing->is_compiled()) {
1532 1533 1534
    if (!outer_info->is_debug() || existing->HasDebugCode()) {
      return existing;
    }
1535 1536
  }

1537 1538 1539 1540 1541 1542
  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());
1543
  if (outer_info->will_serialize()) info.PrepareForSerializing();
1544
  if (outer_info->is_first_compile()) info.MarkAsFirstCompile();
1545
  if (outer_info->is_debug()) info.MarkAsDebug();
1546

1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557
  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();
1558 1559 1560 1561 1562
  // 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);
1563

1564 1565
  bool lazy = FLAG_lazy && allow_lazy && !literal->should_eager_compile();

1566 1567
  // Generate code
  Handle<ScopeInfo> scope_info;
1568
  if (lazy) {
1569
    Handle<Code> code = isolate->builtins()->CompileLazy();
1570
    info.SetCode(code);
1571 1572 1573 1574 1575 1576 1577 1578
    // 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();
1579
    scope_info = Handle<ScopeInfo>(ScopeInfo::Empty(isolate));
1580
  } else if (Renumber(info.parse_info()) && GenerateBaselineCode(&info)) {
1581
    // Code generation will ensure that the feedback vector is present and
1582
    // appropriately sized.
1583
    DCHECK(!info.code().is_null());
1584
    scope_info = ScopeInfo::Create(info.isolate(), info.zone(), info.scope());
1585 1586 1587 1588
    if (literal->should_eager_compile() &&
        literal->should_be_used_once_hint()) {
      info.code()->MarkToBeExecutedOnce(isolate);
    }
1589
  } else {
1590
    return Handle<SharedFunctionInfo>::null();
1591
  }
1592

1593 1594
  if (maybe_existing.is_null()) {
    // Create a shared function info object.
1595 1596 1597 1598
    Handle<SharedFunctionInfo> result =
        isolate->factory()->NewSharedFunctionInfo(
            literal->name(), literal->materialized_literal_count(),
            literal->kind(), info.code(), scope_info, info.feedback_vector());
1599 1600 1601 1602
    if (info.has_bytecode_array()) {
      DCHECK(result->function_data()->IsUndefined());
      result->set_function_data(*info.bytecode_array());
    }
1603

1604 1605 1606 1607 1608 1609 1610
    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);
1611

1612 1613 1614
    RecordFunctionCompilation(Logger::FUNCTION_TAG, &info, result);
    result->set_allows_lazy_compilation(literal->AllowsLazyCompilation());
    result->set_allows_lazy_compilation_without_context(allow_lazy_without_ctx);
1615

1616 1617 1618 1619 1620 1621
    // 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;
1622
  } else if (!lazy) {
1623 1624
    // Assert that we are not overwriting (possibly patched) debug code.
    DCHECK(!existing->HasDebugCode());
1625 1626 1627 1628
    existing->ReplaceCode(*info.code());
    existing->set_scope_info(*scope_info);
    existing->set_feedback_vector(*info.feedback_vector());
  }
1629
  return existing;
1630 1631 1632
}


1633 1634 1635
MaybeHandle<Code> Compiler::GetOptimizedCode(Handle<JSFunction> function,
                                             Handle<Code> current_code,
                                             ConcurrencyMode mode,
1636 1637
                                             BailoutId osr_ast_id,
                                             JavaScriptFrame* osr_frame) {
1638 1639 1640 1641
  Isolate* isolate = function->GetIsolate();
  Handle<SharedFunctionInfo> shared(function->shared(), isolate);
  if (shared->HasDebugInfo()) return MaybeHandle<Code>();

1642 1643 1644
  Handle<Code> cached_code;
  if (GetCodeFromOptimizedCodeMap(
          function, osr_ast_id).ToHandle(&cached_code)) {
1645 1646 1647 1648 1649 1650 1651 1652
    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");
    }
1653 1654
    return cached_code;
  }
1655

1656
  DCHECK(AllowCompilation::IsAllowed(isolate));
1657

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

1670
  current_code->set_profiler_ticks(0);
1671

1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683
  // 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
1684 1685
  base::SmartPointer<CompilationInfo> info(
      new CompilationInfoWithZone(function));
1686 1687 1688 1689
  VMState<COMPILER> state(isolate);
  DCHECK(!isolate->has_pending_exception());
  PostponeInterruptsScope postpone(isolate);

1690
  info->SetOptimizing(osr_ast_id, current_code);
1691

1692 1693 1694 1695
  if (mode == CONCURRENT) {
    if (GetOptimizedCodeLater(info.get())) {
      info.Detach();  // The background recompile job owns this now.
      return isolate->builtins()->InOptimizationQueue();
1696
    }
1697
  } else {
1698
    info->set_osr_frame(osr_frame);
1699 1700
    if (GetOptimizedCodeNow(info.get())) return info->code();
  }
1701

1702
  if (isolate->has_pending_exception()) isolate->clear_pending_exception();
1703
  return MaybeHandle<Code>();
1704 1705 1706
}


1707 1708 1709
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
1710
  base::SmartPointer<CompilationInfo> info(job->info());
1711
  Isolate* isolate = info->isolate();
1712

1713
  VMState<COMPILER> state(isolate);
1714
  TimerEventScope<TimerEventRecompileSynchronous> timer(info->isolate());
1715

1716 1717 1718
  Handle<SharedFunctionInfo> shared = info->shared_info();
  shared->code()->set_profiler_ticks(0);

1719 1720
  DCHECK(!shared->HasDebugInfo());

1721
  // 1) Optimization on the concurrent thread may have failed.
1722 1723 1724
  // 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.
1725
  // 4) Code generation may have failed.
1726 1727 1728
  if (job->last_status() == OptimizedCompileJob::SUCCEEDED) {
    if (shared->optimization_disabled()) {
      job->RetryOptimization(kOptimizationDisabled);
1729
    } else if (info->dependencies()->HasAborted()) {
1730 1731 1732
      job->RetryOptimization(kBailedOutDueToDependencyChange);
    } else if (job->GenerateCode() == OptimizedCompileJob::SUCCEEDED) {
      RecordFunctionCompilation(Logger::LAZY_COMPILE_TAG, info.get(), shared);
1733 1734
      if (shared->SearchOptimizedCodeMap(info->context()->native_context(),
                                         info->osr_ast_id()).code == nullptr) {
1735 1736 1737 1738 1739 1740 1741 1742 1743
        InsertCodeIntoOptimizedCodeMap(info.get());
      }
      if (FLAG_trace_opt) {
        PrintF("[completed optimizing ");
        info->closure()->ShortPrint();
        PrintF("]\n");
      }
      return Handle<Code>(*info->code());
    }
1744
  }
1745

1746 1747 1748 1749 1750
  DCHECK(job->last_status() != OptimizedCompileJob::SUCCEEDED);
  if (FLAG_trace_opt) {
    PrintF("[aborted optimizing ");
    info->closure()->ShortPrint();
    PrintF(" because: %s]\n", GetBailoutReason(info->bailout_reason()));
1751
  }
1752
  return Handle<Code>::null();
1753 1754 1755
}


1756
CompilationPhase::CompilationPhase(const char* name, CompilationInfo* info)
1757
    : name_(name), info_(info) {
1758
  if (FLAG_hydrogen_stats) {
1759
    info_zone_start_allocation_size_ = info->zone()->allocation_size();
1760
    timer_.Start();
1761 1762 1763 1764 1765 1766
  }
}


CompilationPhase::~CompilationPhase() {
  if (FLAG_hydrogen_stats) {
1767
    size_t size = zone()->allocation_size();
1768
    size += info_->zone()->allocation_size() - info_zone_start_allocation_size_;
1769
    isolate()->GetHStatistics()->SaveTiming(name_, timer_.Elapsed(), size);
1770 1771 1772 1773 1774
  }
}


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

1786 1787 1788
#if DEBUG
void CompilationInfo::PrintAstForTesting() {
  PrintF("--- Source from AST ---\n%s\n",
1789
         PrettyPrinter(isolate()).PrintProgram(literal()));
1790 1791
}
#endif
1792 1793
}  // namespace internal
}  // namespace v8