| Index: src/compiler.cc | 
| diff --git a/src/compiler.cc b/src/compiler.cc | 
| index 750d822a5177df7083fde2648d8e34f32c4baae6..0b103f0e287a419782bda9ee7f0268addcf3f6f3 100644 | 
| --- a/src/compiler.cc | 
| +++ b/src/compiler.cc | 
| @@ -18,6 +18,7 @@ | 
| #include "src/debug/debug.h" | 
| #include "src/debug/liveedit.h" | 
| #include "src/deoptimizer.h" | 
| +#include "src/frames-inl.h" | 
| #include "src/full-codegen/full-codegen.h" | 
| #include "src/interpreter/interpreter.h" | 
| #include "src/isolate-inl.h" | 
| @@ -590,7 +591,6 @@ MUST_USE_RESULT MaybeHandle<Code> GetUnoptimizedCode(CompilationInfo* info) { | 
|  | 
| // Compile either unoptimized code or bytecode for the interpreter. | 
| if (!CompileUnoptimizedCode(info)) return MaybeHandle<Code>(); | 
| -  RecordFunctionCompilation(Logger::LAZY_COMPILE_TAG, info); | 
|  | 
| // Update the shared function info with the scope info. | 
| InstallSharedScopeInfo(info, shared); | 
| @@ -598,6 +598,9 @@ MUST_USE_RESULT MaybeHandle<Code> GetUnoptimizedCode(CompilationInfo* info) { | 
| // Install compilation result on the shared function info | 
| InstallSharedCompilationResult(info, shared); | 
|  | 
| +  // Record the function compilation event. | 
| +  RecordFunctionCompilation(Logger::LAZY_COMPILE_TAG, info); | 
| + | 
| return info->code(); | 
| } | 
|  | 
| @@ -805,8 +808,7 @@ MaybeHandle<Code> GetOptimizedCode(Handle<JSFunction> function, | 
| return cached_code; | 
| } | 
|  | 
| -  DCHECK(AllowCompilation::IsAllowed(isolate)); | 
| - | 
| +  // Reset profiler ticks, function is no longer considered hot. | 
| if (shared->is_compiled()) { | 
| shared->code()->set_profiler_ticks(0); | 
| } | 
| @@ -860,6 +862,103 @@ MaybeHandle<Code> GetOptimizedCode(Handle<JSFunction> function, | 
| return MaybeHandle<Code>(); | 
| } | 
|  | 
| +class InterpreterActivationsFinder : public ThreadVisitor { | 
| + public: | 
| +  SharedFunctionInfo* shared_; | 
| +  bool has_activations_; | 
| + | 
| +  explicit InterpreterActivationsFinder(SharedFunctionInfo* shared) | 
| +      : shared_(shared), has_activations_(false) {} | 
| + | 
| +  void VisitThread(Isolate* isolate, ThreadLocalTop* top) { | 
| +    JavaScriptFrameIterator it(isolate, top); | 
| +    for (; !it.done() && !has_activations_; it.Advance()) { | 
| +      JavaScriptFrame* frame = it.frame(); | 
| +      if (!frame->is_interpreted()) continue; | 
| +      if (frame->function()->shared() == shared_) has_activations_ = true; | 
| +    } | 
| +  } | 
| +}; | 
| + | 
| +bool HasInterpreterActivations(Isolate* isolate, SharedFunctionInfo* shared) { | 
| +  InterpreterActivationsFinder activations_finder(shared); | 
| +  activations_finder.VisitThread(isolate, isolate->thread_local_top()); | 
| +  isolate->thread_manager()->IterateArchivedThreads(&activations_finder); | 
| +  return activations_finder.has_activations_; | 
| +} | 
| + | 
| +MaybeHandle<Code> GetBaselineCode(Handle<JSFunction> function) { | 
| +  Isolate* isolate = function->GetIsolate(); | 
| +  VMState<COMPILER> state(isolate); | 
| +  PostponeInterruptsScope postpone(isolate); | 
| +  CompilationInfoWithZone info(function); | 
| + | 
| +  // Reset profiler ticks, function is no longer considered hot. | 
| +  if (function->shared()->HasBytecodeArray()) { | 
| +    function->shared()->set_profiler_ticks(0); | 
| +  } | 
| + | 
| +  // We do not switch to baseline code when the debugger might have created a | 
| +  // copy of the bytecode with break slots to be able to set break points. | 
| +  if (function->shared()->HasDebugInfo()) { | 
| +    return MaybeHandle<Code>(); | 
| +  } | 
| + | 
| +  // TODO(4280): For now we do not switch generators to baseline code because | 
| +  // there might be suspended activations stored in generator objects on the | 
| +  // heap. We could eventually go directly to TurboFan in this case. | 
| +  if (function->shared()->is_generator()) { | 
| +    return MaybeHandle<Code>(); | 
| +  } | 
| + | 
| +  // TODO(4280): For now we disable switching to baseline code in the presence | 
| +  // of interpreter activations of the given function. The reasons are: | 
| +  //  1) The debugger assumes each function is either full-code or bytecode. | 
| +  //  2) The underlying bytecode is cleared below, breaking stack unwinding. | 
| +  if (HasInterpreterActivations(isolate, function->shared())) { | 
| +    if (FLAG_trace_opt) { | 
| +      OFStream os(stdout); | 
| +      os << "[unable to switch " << Brief(*function) << " due to activations]" | 
| +         << std::endl; | 
| +    } | 
| +    return MaybeHandle<Code>(); | 
| +  } | 
| + | 
| +  if (FLAG_trace_opt) { | 
| +    OFStream os(stdout); | 
| +    os << "[switching method " << Brief(*function) << " to baseline code]" | 
| +       << std::endl; | 
| +  } | 
| + | 
| +  // Parse and update CompilationInfo with the results. | 
| +  if (!Parser::ParseStatic(info.parse_info())) return MaybeHandle<Code>(); | 
| +  Handle<SharedFunctionInfo> shared = info.shared_info(); | 
| +  DCHECK_EQ(shared->language_mode(), info.literal()->language_mode()); | 
| + | 
| +  // Compile baseline code using the full code generator. | 
| +  if (!Compiler::Analyze(info.parse_info()) || | 
| +      !FullCodeGenerator::MakeCode(&info)) { | 
| +    if (!isolate->has_pending_exception()) isolate->StackOverflow(); | 
| +    return MaybeHandle<Code>(); | 
| +  } | 
| + | 
| +  // TODO(4280): For now we play it safe and remove the bytecode array when we | 
| +  // switch to baseline code. We might consider keeping around the bytecode so | 
| +  // that it can be used as the "source of truth" eventually. | 
| +  shared->ClearBytecodeArray(); | 
| + | 
| +  // Update the shared function info with the scope info. | 
| +  InstallSharedScopeInfo(&info, shared); | 
| + | 
| +  // Install compilation result on the shared function info | 
| +  InstallSharedCompilationResult(&info, shared); | 
| + | 
| +  // Record the function compilation event. | 
| +  RecordFunctionCompilation(Logger::LAZY_COMPILE_TAG, &info); | 
| + | 
| +  return info.code(); | 
| +} | 
| + | 
| MaybeHandle<Code> GetLazyCode(Handle<JSFunction> function) { | 
| Isolate* isolate = function->GetIsolate(); | 
| DCHECK(!isolate->has_pending_exception()); | 
| @@ -1089,6 +1188,29 @@ bool Compiler::Compile(Handle<JSFunction> function, ClearExceptionFlag flag) { | 
| return true; | 
| } | 
|  | 
| +bool Compiler::CompileBaseline(Handle<JSFunction> function) { | 
| +  Isolate* isolate = function->GetIsolate(); | 
| +  DCHECK(AllowCompilation::IsAllowed(isolate)); | 
| + | 
| +  // Start a compilation. | 
| +  Handle<Code> code; | 
| +  if (!GetBaselineCode(function).ToHandle(&code)) { | 
| +    // Baseline generation failed, get unoptimized code. | 
| +    DCHECK(function->shared()->is_compiled()); | 
| +    code = handle(function->shared()->code()); | 
| +    isolate->clear_pending_exception(); | 
| +  } | 
| + | 
| +  // Install code on closure. | 
| +  function->ReplaceCode(*code); | 
| + | 
| +  // Check postconditions on success. | 
| +  DCHECK(!isolate->has_pending_exception()); | 
| +  DCHECK(function->shared()->is_compiled()); | 
| +  DCHECK(function->is_compiled()); | 
| +  return true; | 
| +} | 
| + | 
| bool Compiler::CompileOptimized(Handle<JSFunction> function, | 
| ConcurrencyMode mode) { | 
| if (function->IsOptimized()) return true; | 
|  |