diff --git a/common.gypi b/common.gypi
index 415a0559310237..15826a2195fc48 100644
--- a/common.gypi
+++ b/common.gypi
@@ -27,7 +27,7 @@
 
     # Reset this number to 0 on major V8 upgrades.
     # Increment by one for each non-official patch applied to deps/v8.
-    'v8_embedder_string': '-node.9',
+    'v8_embedder_string': '-node.10',
 
     # Enable disassembler for `--print-code` v8 options
     'v8_enable_disassembler': 1,
diff --git a/deps/v8/include/v8-profiler.h b/deps/v8/include/v8-profiler.h
index afa40d25f30fdc..5df9b2a217ea8e 100644
--- a/deps/v8/include/v8-profiler.h
+++ b/deps/v8/include/v8-profiler.h
@@ -988,6 +988,76 @@ struct HeapStatsUpdate {
   uint32_t size;  // New value of size field for the interval with this index.
 };
 
+#define CODE_EVENTS_LIST(V) \
+  V(Builtin)                \
+  V(Callback)               \
+  V(Eval)                   \
+  V(Function)               \
+  V(InterpretedFunction)    \
+  V(Handler)                \
+  V(BytecodeHandler)        \
+  V(LazyCompile)            \
+  V(RegExp)                 \
+  V(Script)                 \
+  V(Stub)
+
+/**
+ * Note that this enum may be extended in the future. Please include a default
+ * case if this enum is used in a switch statement.
+ */
+enum CodeEventType {
+  kUnknownType = 0
+#define V(Name) , k##Name##Type
+  CODE_EVENTS_LIST(V)
+#undef V
+};
+
+/**
+ * Representation of a code creation event
+ */
+class V8_EXPORT CodeEvent {
+ public:
+  uintptr_t GetCodeStartAddress();
+  size_t GetCodeSize();
+  Local<String> GetFunctionName();
+  Local<String> GetScriptName();
+  int GetScriptLine();
+  int GetScriptColumn();
+  /**
+   * NOTE (mmarchini): We can't allocate objects in the heap when we collect
+   * existing code, and both the code type and the comment are not stored in the
+   * heap, so we return those as const char*.
+   */
+  CodeEventType GetCodeType();
+  const char* GetComment();
+
+  static const char* GetCodeEventTypeName(CodeEventType code_event_type);
+};
+
+/**
+ * Interface to listen to code creation events.
+ */
+class V8_EXPORT CodeEventHandler {
+ public:
+  /**
+   * Creates a new listener for the |isolate|. The isolate must be initialized.
+   * The listener object must be disposed after use by calling |Dispose| method.
+   * Multiple listeners can be created for the same isolate.
+   */
+  explicit CodeEventHandler(Isolate* isolate);
+  virtual ~CodeEventHandler();
+
+  virtual void Handle(CodeEvent* code_event) = 0;
+
+  void Enable();
+  void Disable();
+
+ private:
+  CodeEventHandler();
+  CodeEventHandler(const CodeEventHandler&);
+  CodeEventHandler& operator=(const CodeEventHandler&);
+  void* internal_listener_;
+};
 
 }  // namespace v8
 
diff --git a/deps/v8/src/api.cc b/deps/v8/src/api.cc
index e9a5ec69ec4a71..d101bc419a7c55 100644
--- a/deps/v8/src/api.cc
+++ b/deps/v8/src/api.cc
@@ -10211,6 +10211,70 @@ void CpuProfiler::SetIdle(bool is_idle) {
   isolate->SetIdle(is_idle);
 }
 
+uintptr_t CodeEvent::GetCodeStartAddress() {
+  return reinterpret_cast<i::CodeEvent*>(this)->code_start_address;
+}
+
+size_t CodeEvent::GetCodeSize() {
+  return reinterpret_cast<i::CodeEvent*>(this)->code_size;
+}
+
+Local<String> CodeEvent::GetFunctionName() {
+  return ToApiHandle<String>(
+      reinterpret_cast<i::CodeEvent*>(this)->function_name);
+}
+
+Local<String> CodeEvent::GetScriptName() {
+  return ToApiHandle<String>(
+      reinterpret_cast<i::CodeEvent*>(this)->script_name);
+}
+
+int CodeEvent::GetScriptLine() {
+  return reinterpret_cast<i::CodeEvent*>(this)->script_line;
+}
+
+int CodeEvent::GetScriptColumn() {
+  return reinterpret_cast<i::CodeEvent*>(this)->script_column;
+}
+
+CodeEventType CodeEvent::GetCodeType() {
+  return reinterpret_cast<i::CodeEvent*>(this)->code_type;
+}
+
+const char* CodeEvent::GetComment() {
+  return reinterpret_cast<i::CodeEvent*>(this)->comment;
+}
+
+const char* CodeEvent::GetCodeEventTypeName(CodeEventType code_event_type) {
+  switch (code_event_type) {
+    case kUnknownType:
+      return "Unknown";
+#define V(Name)       \
+  case k##Name##Type: \
+    return #Name;
+      CODE_EVENTS_LIST(V)
+#undef V
+  }
+}
+
+CodeEventHandler::CodeEventHandler(Isolate* isolate) {
+  internal_listener_ =
+      new i::ExternalCodeEventListener(reinterpret_cast<i::Isolate*>(isolate));
+}
+
+CodeEventHandler::~CodeEventHandler() {
+  delete reinterpret_cast<i::ExternalCodeEventListener*>(internal_listener_);
+}
+
+void CodeEventHandler::Enable() {
+  reinterpret_cast<i::ExternalCodeEventListener*>(internal_listener_)
+      ->StartListening(this);
+}
+
+void CodeEventHandler::Disable() {
+  reinterpret_cast<i::ExternalCodeEventListener*>(internal_listener_)
+      ->StopListening();
+}
 
 static i::HeapGraphEdge* ToInternal(const HeapGraphEdge* edge) {
   return const_cast<i::HeapGraphEdge*>(
diff --git a/deps/v8/src/code-events.h b/deps/v8/src/code-events.h
index 439cb54dca6b6d..caed5160f47a24 100644
--- a/deps/v8/src/code-events.h
+++ b/deps/v8/src/code-events.h
@@ -24,32 +24,38 @@ class WasmCode;
 using WasmName = Vector<const char>;
 }  // namespace wasm
 
-#define LOG_EVENTS_AND_TAGS_LIST(V)                      \
-  V(CODE_CREATION_EVENT, "code-creation")                \
-  V(CODE_DISABLE_OPT_EVENT, "code-disable-optimization") \
-  V(CODE_MOVE_EVENT, "code-move")                        \
-  V(CODE_DELETE_EVENT, "code-delete")                    \
-  V(CODE_MOVING_GC, "code-moving-gc")                    \
-  V(SHARED_FUNC_MOVE_EVENT, "sfi-move")                  \
-  V(SNAPSHOT_CODE_NAME_EVENT, "snapshot-code-name")      \
-  V(TICK_EVENT, "tick")                                  \
-  V(BUILTIN_TAG, "Builtin")                              \
-  V(CALLBACK_TAG, "Callback")                            \
-  V(EVAL_TAG, "Eval")                                    \
-  V(FUNCTION_TAG, "Function")                            \
-  V(INTERPRETED_FUNCTION_TAG, "InterpretedFunction")     \
-  V(HANDLER_TAG, "Handler")                              \
-  V(BYTECODE_HANDLER_TAG, "BytecodeHandler")             \
-  V(LAZY_COMPILE_TAG, "LazyCompile")                     \
-  V(REG_EXP_TAG, "RegExp")                               \
-  V(SCRIPT_TAG, "Script")                                \
-  V(STUB_TAG, "Stub")                                    \
-  V(NATIVE_FUNCTION_TAG, "Function")                     \
-  V(NATIVE_LAZY_COMPILE_TAG, "LazyCompile")              \
-  V(NATIVE_SCRIPT_TAG, "Script")
+#define LOG_EVENTS_LIST(V)                             \
+  V(CODE_CREATION_EVENT, code-creation)                \
+  V(CODE_DISABLE_OPT_EVENT, code-disable-optimization) \
+  V(CODE_MOVE_EVENT, code-move)                        \
+  V(CODE_DELETE_EVENT, code-delete)                    \
+  V(CODE_MOVING_GC, code-moving-gc)                    \
+  V(SHARED_FUNC_MOVE_EVENT, sfi-move)                  \
+  V(SNAPSHOT_CODE_NAME_EVENT, snapshot-code-name)      \
+  V(TICK_EVENT, tick)
+
+#define TAGS_LIST(V)                               \
+  V(BUILTIN_TAG, Builtin)                          \
+  V(CALLBACK_TAG, Callback)                        \
+  V(EVAL_TAG, Eval)                                \
+  V(FUNCTION_TAG, Function)                        \
+  V(INTERPRETED_FUNCTION_TAG, InterpretedFunction) \
+  V(HANDLER_TAG, Handler)                          \
+  V(BYTECODE_HANDLER_TAG, BytecodeHandler)         \
+  V(LAZY_COMPILE_TAG, LazyCompile)                 \
+  V(REG_EXP_TAG, RegExp)                           \
+  V(SCRIPT_TAG, Script)                            \
+  V(STUB_TAG, Stub)                                \
+  V(NATIVE_FUNCTION_TAG, Function)                 \
+  V(NATIVE_LAZY_COMPILE_TAG, LazyCompile)          \
+  V(NATIVE_SCRIPT_TAG, Script)
 // Note that 'NATIVE_' cases for functions and scripts are mapped onto
 // original tags when writing to the log.
 
+#define LOG_EVENTS_AND_TAGS_LIST(V) \
+  LOG_EVENTS_LIST(V)                \
+  TAGS_LIST(V)
+
 #define PROFILE(the_isolate, Call) (the_isolate)->code_event_dispatcher()->Call;
 
 class CodeEventListener {
@@ -85,6 +91,8 @@ class CodeEventListener {
   enum DeoptKind { kSoft, kLazy, kEager };
   virtual void CodeDeoptEvent(Code* code, DeoptKind kind, Address pc,
                               int fp_to_sp_delta) = 0;
+
+  virtual bool is_listening_to_code_events() { return false; }
 };
 
 class CodeEventDispatcher {
@@ -101,6 +109,14 @@ class CodeEventDispatcher {
     base::LockGuard<base::Mutex> guard(&mutex_);
     listeners_.erase(listener);
   }
+  bool IsListeningToCodeEvents() {
+    for (auto it : listeners_) {
+      if (it->is_listening_to_code_events()) {
+        return true;
+      }
+    }
+    return false;
+  }
 
 #define CODE_EVENT_DISPATCH(code)              \
   base::LockGuard<base::Mutex> guard(&mutex_); \
diff --git a/deps/v8/src/compiler.cc b/deps/v8/src/compiler.cc
index 1b3a154f52e558..d63f03d358e3db 100644
--- a/deps/v8/src/compiler.cc
+++ b/deps/v8/src/compiler.cc
@@ -84,8 +84,9 @@ void LogFunctionCompilation(CodeEventListener::LogEventsAndTags tag,
   // 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 (!isolate->logger()->is_logging_code_events() &&
-      !isolate->is_profiling() && !FLAG_log_function_events) {
+  if (!isolate->logger()->is_listening_to_code_events() &&
+      !isolate->is_profiling() && !FLAG_log_function_events &&
+      !isolate->code_event_dispatcher()->IsListeningToCodeEvents()) {
     return;
   }
 
diff --git a/deps/v8/src/compiler/wasm-compiler.cc b/deps/v8/src/compiler/wasm-compiler.cc
index 61c5c152ba9fce..85bedd3c53c862 100644
--- a/deps/v8/src/compiler/wasm-compiler.cc
+++ b/deps/v8/src/compiler/wasm-compiler.cc
@@ -4625,7 +4625,8 @@ Node* WasmGraphBuilder::AtomicOp(wasm::WasmOpcode opcode, Node* const* inputs,
 
 namespace {
 bool must_record_function_compilation(Isolate* isolate) {
-  return isolate->logger()->is_logging_code_events() || isolate->is_profiling();
+  return isolate->logger()->is_listening_to_code_events() ||
+         isolate->is_profiling();
 }
 
 PRINTF_FORMAT(4, 5)
diff --git a/deps/v8/src/heap/mark-compact.cc b/deps/v8/src/heap/mark-compact.cc
index eedc942835fc53..7784c3e3f67396 100644
--- a/deps/v8/src/heap/mark-compact.cc
+++ b/deps/v8/src/heap/mark-compact.cc
@@ -2458,7 +2458,7 @@ void MarkCompactCollectorBase::CreateAndExecuteEvacuationTasks(
 
   const bool profiling =
       heap()->isolate()->is_profiling() ||
-      heap()->isolate()->logger()->is_logging_code_events() ||
+      heap()->isolate()->logger()->is_listening_to_code_events() ||
       heap()->isolate()->heap_profiler()->is_tracking_object_moves() ||
       heap()->has_heap_object_allocation_tracker();
   ProfilingMigrationObserver profiling_observer(heap());
diff --git a/deps/v8/src/isolate.cc b/deps/v8/src/isolate.cc
index 2c4e22726d7301..7ef0214f4a6462 100644
--- a/deps/v8/src/isolate.cc
+++ b/deps/v8/src/isolate.cc
@@ -2883,7 +2883,7 @@ void CreateOffHeapTrampolines(Isolate* isolate) {
     // thus collected by the GC.
     builtins->set_builtin(i, *trampoline);
 
-    if (isolate->logger()->is_logging_code_events() ||
+    if (isolate->logger()->is_listening_to_code_events() ||
         isolate->is_profiling()) {
       isolate->logger()->LogCodeObject(*trampoline);
     }
diff --git a/deps/v8/src/isolate.h b/deps/v8/src/isolate.h
index 82d33033737c36..99d8f530f0b148 100644
--- a/deps/v8/src/isolate.h
+++ b/deps/v8/src/isolate.h
@@ -56,6 +56,7 @@ class BuiltinsConstantsTableBuilder;
 class CallInterfaceDescriptorData;
 class CancelableTaskManager;
 class CodeEventDispatcher;
+class ExternalCodeEventListener;
 class CodeGenerator;
 class CodeRange;
 class CodeStubDescriptor;
diff --git a/deps/v8/src/log.cc b/deps/v8/src/log.cc
index 661b65d39bd485..38967a34696dda 100644
--- a/deps/v8/src/log.cc
+++ b/deps/v8/src/log.cc
@@ -40,11 +40,33 @@
 namespace v8 {
 namespace internal {
 
-#define DECLARE_EVENT(ignore1, name) name,
+#define DECLARE_EVENT(ignore1, name) #name,
 static const char* kLogEventsNames[CodeEventListener::NUMBER_OF_LOG_EVENTS] = {
     LOG_EVENTS_AND_TAGS_LIST(DECLARE_EVENT)};
 #undef DECLARE_EVENT
 
+static v8::CodeEventType GetCodeEventTypeForTag(
+    CodeEventListener::LogEventsAndTags tag) {
+  switch (tag) {
+    case CodeEventListener::NUMBER_OF_LOG_EVENTS:
+#define V(Event, _) case CodeEventListener::Event:
+      LOG_EVENTS_LIST(V)
+#undef V
+      return v8::CodeEventType::kUnknownType;
+#define V(From, To)             \
+  case CodeEventListener::From: \
+    return v8::CodeEventType::k##To##Type;
+      TAGS_LIST(V)
+#undef V
+  }
+}
+#define CALL_CODE_EVENT_HANDLER(Call) \
+  if (listener_) {                    \
+    listener_->Call;                  \
+  } else {                            \
+    PROFILE(isolate_, Call);          \
+  }
+
 static const char* ComputeMarker(SharedFunctionInfo* shared,
                                  AbstractCode* code) {
   switch (code->kind()) {
@@ -321,9 +343,147 @@ void PerfBasicLogger::LogRecordedBuffer(const wasm::WasmCode* code,
       code->instructions().length(), name, length);
 }
 
-// Low-level logging support.
-#define LL_LOG(Call) if (ll_logger_) ll_logger_->Call;
+// External CodeEventListener
+ExternalCodeEventListener::ExternalCodeEventListener(Isolate* isolate)
+    : is_listening_(false), isolate_(isolate), code_event_handler_(nullptr) {}
+
+ExternalCodeEventListener::~ExternalCodeEventListener() {
+  if (is_listening_) {
+    StopListening();
+  }
+}
+
+void ExternalCodeEventListener::LogExistingCode() {
+  HandleScope scope(isolate_);
+  ExistingCodeLogger logger(isolate_, this);
+  logger.LogCodeObjects();
+  logger.LogBytecodeHandlers();
+  logger.LogCompiledFunctions();
+}
+
+void ExternalCodeEventListener::StartListening(
+    CodeEventHandler* code_event_handler) {
+  if (is_listening_ || code_event_handler == nullptr) {
+    return;
+  }
+  code_event_handler_ = code_event_handler;
+  is_listening_ = isolate_->code_event_dispatcher()->AddListener(this);
+  if (is_listening_) {
+    LogExistingCode();
+  }
+}
 
+void ExternalCodeEventListener::StopListening() {
+  if (!is_listening_) {
+    return;
+  }
+
+  isolate_->code_event_dispatcher()->RemoveListener(this);
+  is_listening_ = false;
+}
+
+void ExternalCodeEventListener::CodeCreateEvent(
+    CodeEventListener::LogEventsAndTags tag, AbstractCode* code,
+    const char* comment) {
+  CodeEvent code_event;
+  code_event.code_start_address =
+      reinterpret_cast<uintptr_t>(code->InstructionStart());
+  code_event.code_size = static_cast<size_t>(code->InstructionSize());
+  code_event.function_name = isolate_->factory()->empty_string();
+  code_event.script_name = isolate_->factory()->empty_string();
+  code_event.script_line = 0;
+  code_event.script_column = 0;
+  code_event.code_type = GetCodeEventTypeForTag(tag);
+  code_event.comment = comment;
+
+  code_event_handler_->Handle(reinterpret_cast<v8::CodeEvent*>(&code_event));
+}
+
+void ExternalCodeEventListener::CodeCreateEvent(
+    CodeEventListener::LogEventsAndTags tag, AbstractCode* code, Name* name) {
+  Handle<String> name_string =
+      Name::ToFunctionName(Handle<Name>(name, isolate_)).ToHandleChecked();
+
+  CodeEvent code_event;
+  code_event.code_start_address =
+      reinterpret_cast<uintptr_t>(code->InstructionStart());
+  code_event.code_size = static_cast<size_t>(code->InstructionSize());
+  code_event.function_name = name_string;
+  code_event.script_name = isolate_->factory()->empty_string();
+  code_event.script_line = 0;
+  code_event.script_column = 0;
+  code_event.code_type = GetCodeEventTypeForTag(tag);
+  code_event.comment = "";
+
+  code_event_handler_->Handle(reinterpret_cast<v8::CodeEvent*>(&code_event));
+}
+
+void ExternalCodeEventListener::CodeCreateEvent(
+    CodeEventListener::LogEventsAndTags tag, AbstractCode* code,
+    SharedFunctionInfo* shared, Name* name) {
+  Handle<String> name_string =
+      Name::ToFunctionName(Handle<Name>(name, isolate_)).ToHandleChecked();
+
+  CodeEvent code_event;
+  code_event.code_start_address =
+      reinterpret_cast<uintptr_t>(code->InstructionStart());
+  code_event.code_size = static_cast<size_t>(code->InstructionSize());
+  code_event.function_name = name_string;
+  code_event.script_name = isolate_->factory()->empty_string();
+  code_event.script_line = 0;
+  code_event.script_column = 0;
+  code_event.code_type = GetCodeEventTypeForTag(tag);
+  code_event.comment = "";
+
+  code_event_handler_->Handle(reinterpret_cast<v8::CodeEvent*>(&code_event));
+}
+
+void ExternalCodeEventListener::CodeCreateEvent(
+    CodeEventListener::LogEventsAndTags tag, AbstractCode* code,
+    SharedFunctionInfo* shared, Name* source, int line, int column) {
+  Handle<String> name_string =
+      Name::ToFunctionName(Handle<Name>(shared->Name(), isolate_))
+          .ToHandleChecked();
+  Handle<String> source_string =
+      Name::ToFunctionName(Handle<Name>(source, isolate_)).ToHandleChecked();
+
+  CodeEvent code_event;
+  code_event.code_start_address =
+      reinterpret_cast<uintptr_t>(code->InstructionStart());
+  code_event.code_size = static_cast<size_t>(code->InstructionSize());
+  code_event.function_name = name_string;
+  code_event.script_name = source_string;
+  code_event.script_line = line;
+  code_event.script_column = column;
+  code_event.code_type = GetCodeEventTypeForTag(tag);
+  code_event.comment = "";
+
+  code_event_handler_->Handle(reinterpret_cast<v8::CodeEvent*>(&code_event));
+}
+
+void ExternalCodeEventListener::CodeCreateEvent(LogEventsAndTags tag,
+                                                const wasm::WasmCode* code,
+                                                wasm::WasmName name) {
+  // TODO(mmarchini): handle later
+}
+
+void ExternalCodeEventListener::RegExpCodeCreateEvent(AbstractCode* code,
+                                                      String* source) {
+  CodeEvent code_event;
+  code_event.code_start_address =
+      reinterpret_cast<uintptr_t>(code->InstructionStart());
+  code_event.code_size = static_cast<size_t>(code->InstructionSize());
+  code_event.function_name = Handle<String>(source, isolate_);
+  code_event.script_name = isolate_->factory()->empty_string();
+  code_event.script_line = 0;
+  code_event.script_column = 0;
+  code_event.code_type = GetCodeEventTypeForTag(CodeEventListener::REG_EXP_TAG);
+  code_event.comment = "";
+
+  code_event_handler_->Handle(reinterpret_cast<v8::CodeEvent*>(&code_event));
+}
+
+// Low-level logging support.
 class LowLevelLogger : public CodeEventLogger {
  public:
   explicit LowLevelLogger(const char* file_name);
@@ -810,7 +970,8 @@ Logger::Logger(Isolate* isolate)
       perf_jit_logger_(nullptr),
       ll_logger_(nullptr),
       jit_logger_(nullptr),
-      is_initialized_(false) {}
+      is_initialized_(false),
+      existing_code_logger_(isolate) {}
 
 Logger::~Logger() {
   delete log_;
@@ -1079,7 +1240,7 @@ void AppendCodeCreateHeader(Log::MessageBuilder& msg,
 
 void Logger::CodeCreateEvent(CodeEventListener::LogEventsAndTags tag,
                              AbstractCode* code, const char* comment) {
-  if (!is_logging_code_events()) return;
+  if (!is_listening_to_code_events()) return;
   if (!FLAG_log_code || !log_->IsEnabled()) return;
   Log::MessageBuilder msg(log_);
   AppendCodeCreateHeader(msg, tag, code, &timer_);
@@ -1089,7 +1250,7 @@ void Logger::CodeCreateEvent(CodeEventListener::LogEventsAndTags tag,
 
 void Logger::CodeCreateEvent(CodeEventListener::LogEventsAndTags tag,
                              AbstractCode* code, Name* name) {
-  if (!is_logging_code_events()) return;
+  if (!is_listening_to_code_events()) return;
   if (!FLAG_log_code || !log_->IsEnabled()) return;
   Log::MessageBuilder msg(log_);
   AppendCodeCreateHeader(msg, tag, code, &timer_);
@@ -1100,7 +1261,7 @@ void Logger::CodeCreateEvent(CodeEventListener::LogEventsAndTags tag,
 void Logger::CodeCreateEvent(CodeEventListener::LogEventsAndTags tag,
                              AbstractCode* code, SharedFunctionInfo* shared,
                              Name* name) {
-  if (!is_logging_code_events()) return;
+  if (!is_listening_to_code_events()) return;
   if (!FLAG_log_code || !log_->IsEnabled()) return;
   if (code == AbstractCode::cast(
                   isolate_->builtins()->builtin(Builtins::kCompileLazy))) {
@@ -1116,7 +1277,7 @@ void Logger::CodeCreateEvent(CodeEventListener::LogEventsAndTags tag,
 
 void Logger::CodeCreateEvent(CodeEventListener::LogEventsAndTags tag,
                              const wasm::WasmCode* code, wasm::WasmName name) {
-  if (!is_logging_code_events()) return;
+  if (!is_listening_to_code_events()) return;
   if (!FLAG_log_code || !log_->IsEnabled()) return;
   Log::MessageBuilder msg(log_);
   AppendCodeCreateHeader(msg, tag, AbstractCode::Kind::WASM_FUNCTION,
@@ -1144,7 +1305,7 @@ void Logger::CodeCreateEvent(CodeEventListener::LogEventsAndTags tag,
 void Logger::CodeCreateEvent(CodeEventListener::LogEventsAndTags tag,
                              AbstractCode* code, SharedFunctionInfo* shared,
                              Name* source, int line, int column) {
-  if (!is_logging_code_events()) return;
+  if (!is_listening_to_code_events()) return;
   if (!FLAG_log_code || !log_->IsEnabled()) return;
 
   Log::MessageBuilder msg(log_);
@@ -1260,7 +1421,7 @@ void Logger::CodeCreateEvent(CodeEventListener::LogEventsAndTags tag,
 
 void Logger::CodeDisableOptEvent(AbstractCode* code,
                                  SharedFunctionInfo* shared) {
-  if (!is_logging_code_events()) return;
+  if (!is_listening_to_code_events()) return;
   if (!FLAG_log_code || !log_->IsEnabled()) return;
   Log::MessageBuilder msg(log_);
   msg << kLogEventsNames[CodeEventListener::CODE_DISABLE_OPT_EVENT] << kNext
@@ -1271,13 +1432,13 @@ void Logger::CodeDisableOptEvent(AbstractCode* code,
 
 
 void Logger::CodeMovingGCEvent() {
-  if (!is_logging_code_events()) return;
+  if (!is_listening_to_code_events()) return;
   if (!log_->IsEnabled() || !FLAG_ll_prof) return;
   base::OS::SignalCodeMovingGC();
 }
 
 void Logger::RegExpCodeCreateEvent(AbstractCode* code, String* source) {
-  if (!is_logging_code_events()) return;
+  if (!is_listening_to_code_events()) return;
   if (!FLAG_log_code || !log_->IsEnabled()) return;
   Log::MessageBuilder msg(log_);
   AppendCodeCreateHeader(msg, CodeEventListener::REG_EXP_TAG, code, &timer_);
@@ -1286,7 +1447,7 @@ void Logger::RegExpCodeCreateEvent(AbstractCode* code, String* source) {
 }
 
 void Logger::CodeMoveEvent(AbstractCode* from, Address to) {
-  if (!is_logging_code_events()) return;
+  if (!is_listening_to_code_events()) return;
   MoveEventInternal(CodeEventListener::CODE_MOVE_EVENT, from->address(), to);
 }
 
@@ -1335,7 +1496,7 @@ void Logger::CodeNameEvent(Address addr, int pos, const char* code_name) {
 
 
 void Logger::SharedFunctionInfoMoveEvent(Address from, Address to) {
-  if (!is_logging_code_events()) return;
+  if (!is_listening_to_code_events()) return;
   MoveEventInternal(CodeEventListener::SHARED_FUNC_MOVE_EVENT, from, to);
 }
 
@@ -1625,170 +1786,28 @@ static int EnumerateWasmModules(Heap* heap,
 }
 
 void Logger::LogCodeObject(Object* object) {
-  AbstractCode* code_object = AbstractCode::cast(object);
-  CodeEventListener::LogEventsAndTags tag = CodeEventListener::STUB_TAG;
-  const char* description = "Unknown code from the snapshot";
-  switch (code_object->kind()) {
-    case AbstractCode::INTERPRETED_FUNCTION:
-    case AbstractCode::OPTIMIZED_FUNCTION:
-      return;  // We log this later using LogCompiledFunctions.
-    case AbstractCode::BYTECODE_HANDLER:
-      return;  // We log it later by walking the dispatch table.
-    case AbstractCode::STUB:
-      description =
-          CodeStub::MajorName(CodeStub::GetMajorKey(code_object->GetCode()));
-      if (description == nullptr) description = "A stub from the snapshot";
-      tag = CodeEventListener::STUB_TAG;
-      break;
-    case AbstractCode::REGEXP:
-      description = "Regular expression code";
-      tag = CodeEventListener::REG_EXP_TAG;
-      break;
-    case AbstractCode::BUILTIN:
-      description =
-          isolate_->builtins()->name(code_object->GetCode()->builtin_index());
-      tag = CodeEventListener::BUILTIN_TAG;
-      break;
-    case AbstractCode::WASM_FUNCTION:
-      description = "A Wasm function";
-      tag = CodeEventListener::FUNCTION_TAG;
-      break;
-    case AbstractCode::JS_TO_WASM_FUNCTION:
-      description = "A JavaScript to Wasm adapter";
-      tag = CodeEventListener::STUB_TAG;
-      break;
-    case AbstractCode::WASM_TO_JS_FUNCTION:
-      description = "A Wasm to JavaScript adapter";
-      tag = CodeEventListener::STUB_TAG;
-      break;
-    case AbstractCode::WASM_INTERPRETER_ENTRY:
-      description = "A Wasm to Interpreter adapter";
-      tag = CodeEventListener::STUB_TAG;
-      break;
-    case AbstractCode::C_WASM_ENTRY:
-      description = "A C to Wasm entry stub";
-      tag = CodeEventListener::STUB_TAG;
-      break;
-    case AbstractCode::NUMBER_OF_KINDS:
-      UNIMPLEMENTED();
-  }
-  PROFILE(isolate_, CodeCreateEvent(tag, code_object, description));
+  existing_code_logger_.LogCodeObject(object);
 }
 
-void Logger::LogCodeObjects() {
-  Heap* heap = isolate_->heap();
-  HeapIterator iterator(heap);
-  DisallowHeapAllocation no_gc;
-  for (HeapObject* obj = iterator.next(); obj != nullptr;
-       obj = iterator.next()) {
-    if (obj->IsCode()) LogCodeObject(obj);
-    if (obj->IsBytecodeArray()) LogCodeObject(obj);
-  }
-}
+void Logger::LogCodeObjects() { existing_code_logger_.LogCodeObjects(); }
 
 void Logger::LogBytecodeHandler(interpreter::Bytecode bytecode,
                                 interpreter::OperandScale operand_scale,
                                 Code* code) {
-  std::string bytecode_name =
-      interpreter::Bytecodes::ToString(bytecode, operand_scale);
-  PROFILE(isolate_,
-          CodeCreateEvent(CodeEventListener::BYTECODE_HANDLER_TAG,
-                          AbstractCode::cast(code), bytecode_name.c_str()));
+  existing_code_logger_.LogBytecodeHandler(bytecode, operand_scale, code);
 }
 
 void Logger::LogBytecodeHandlers() {
-  const interpreter::OperandScale kOperandScales[] = {
-#define VALUE(Name, _) interpreter::OperandScale::k##Name,
-      OPERAND_SCALE_LIST(VALUE)
-#undef VALUE
-  };
-
-  const int last_index = static_cast<int>(interpreter::Bytecode::kLast);
-  interpreter::Interpreter* interpreter = isolate_->interpreter();
-  for (auto operand_scale : kOperandScales) {
-    for (int index = 0; index <= last_index; ++index) {
-      interpreter::Bytecode bytecode = interpreter::Bytecodes::FromByte(index);
-      if (interpreter::Bytecodes::BytecodeHasHandler(bytecode, operand_scale)) {
-        Code* code = interpreter->GetBytecodeHandler(bytecode, operand_scale);
-        if (isolate_->heap()->IsDeserializeLazyHandler(code)) continue;
-        LogBytecodeHandler(bytecode, operand_scale, code);
-      }
-    }
-  }
+  existing_code_logger_.LogBytecodeHandlers();
 }
 
 void Logger::LogExistingFunction(Handle<SharedFunctionInfo> shared,
                                  Handle<AbstractCode> code) {
-  if (shared->script()->IsScript()) {
-    Handle<Script> script(Script::cast(shared->script()));
-    int line_num = Script::GetLineNumber(script, shared->StartPosition()) + 1;
-    int column_num =
-        Script::GetColumnNumber(script, shared->StartPosition()) + 1;
-    if (script->name()->IsString()) {
-      Handle<String> script_name(String::cast(script->name()));
-      if (line_num > 0) {
-        PROFILE(isolate_,
-                CodeCreateEvent(
-                    Logger::ToNativeByScript(
-                        CodeEventListener::LAZY_COMPILE_TAG, *script),
-                    *code, *shared, *script_name, line_num, column_num));
-      } else {
-        // Can't distinguish eval and script here, so always use Script.
-        PROFILE(isolate_,
-                CodeCreateEvent(Logger::ToNativeByScript(
-                                    CodeEventListener::SCRIPT_TAG, *script),
-                                *code, *shared, *script_name));
-      }
-    } else {
-      PROFILE(isolate_,
-              CodeCreateEvent(Logger::ToNativeByScript(
-                                  CodeEventListener::LAZY_COMPILE_TAG, *script),
-                              *code, *shared, isolate_->heap()->empty_string(),
-                              line_num, column_num));
-    }
-  } else if (shared->IsApiFunction()) {
-    // API function.
-    FunctionTemplateInfo* fun_data = shared->get_api_func_data();
-    Object* raw_call_data = fun_data->call_code();
-    if (!raw_call_data->IsUndefined(isolate_)) {
-      CallHandlerInfo* call_data = CallHandlerInfo::cast(raw_call_data);
-      Object* callback_obj = call_data->callback();
-      Address entry_point = v8::ToCData<Address>(callback_obj);
-#if USES_FUNCTION_DESCRIPTORS
-      entry_point = *FUNCTION_ENTRYPOINT_ADDRESS(entry_point);
-#endif
-      PROFILE(isolate_, CallbackEvent(shared->DebugName(), entry_point));
-    }
-  } else {
-    PROFILE(isolate_,
-            CodeCreateEvent(CodeEventListener::LAZY_COMPILE_TAG, *code, *shared,
-                            isolate_->heap()->empty_string()));
-  }
+  existing_code_logger_.LogExistingFunction(shared, code);
 }
 
 void Logger::LogCompiledFunctions() {
-  Heap* heap = isolate_->heap();
-  HandleScope scope(isolate_);
-  const int compiled_funcs_count =
-      EnumerateCompiledFunctions(heap, nullptr, nullptr);
-  ScopedVector<Handle<SharedFunctionInfo>> sfis(compiled_funcs_count);
-  ScopedVector<Handle<AbstractCode> > code_objects(compiled_funcs_count);
-  EnumerateCompiledFunctions(heap, sfis.start(), code_objects.start());
-
-  // During iteration, there can be heap allocation due to
-  // GetScriptLineNumber call.
-  for (int i = 0; i < compiled_funcs_count; ++i) {
-    if (code_objects[i].is_identical_to(BUILTIN_CODE(isolate_, CompileLazy)))
-      continue;
-    LogExistingFunction(sfis[i], code_objects[i]);
-  }
-
-  const int compiled_wasm_modules_count = EnumerateWasmModules(heap, nullptr);
-  ScopedVector<Handle<WasmCompiledModule>> modules(compiled_wasm_modules_count);
-  EnumerateWasmModules(heap, modules.start());
-  for (int i = 0; i < compiled_wasm_modules_count; ++i) {
-    modules[i]->LogWasmCodes(isolate_);
-  }
+  existing_code_logger_.LogCompiledFunctions();
 }
 
 void Logger::LogAccessorCallbacks() {
@@ -2011,5 +2030,172 @@ FILE* Logger::TearDown() {
   return log_->Close();
 }
 
+void ExistingCodeLogger::LogCodeObject(Object* object) {
+  AbstractCode* code_object = AbstractCode::cast(object);
+  CodeEventListener::LogEventsAndTags tag = CodeEventListener::STUB_TAG;
+  const char* description = "Unknown code from before profiling";
+  switch (code_object->kind()) {
+    case AbstractCode::INTERPRETED_FUNCTION:
+    case AbstractCode::OPTIMIZED_FUNCTION:
+      return;  // We log this later using LogCompiledFunctions.
+    case AbstractCode::BYTECODE_HANDLER:
+      return;  // We log it later by walking the dispatch table.
+    case AbstractCode::STUB:
+      description =
+          CodeStub::MajorName(CodeStub::GetMajorKey(code_object->GetCode()));
+      if (description == nullptr) description = "A stub from before profiling";
+      tag = CodeEventListener::STUB_TAG;
+      break;
+    case AbstractCode::REGEXP:
+      description = "Regular expression code";
+      tag = CodeEventListener::REG_EXP_TAG;
+      break;
+    case AbstractCode::BUILTIN:
+      description =
+          isolate_->builtins()->name(code_object->GetCode()->builtin_index());
+      tag = CodeEventListener::BUILTIN_TAG;
+      break;
+    case AbstractCode::WASM_FUNCTION:
+      description = "A Wasm function";
+      tag = CodeEventListener::FUNCTION_TAG;
+      break;
+    case AbstractCode::JS_TO_WASM_FUNCTION:
+      description = "A JavaScript to Wasm adapter";
+      tag = CodeEventListener::STUB_TAG;
+      break;
+    case AbstractCode::WASM_TO_JS_FUNCTION:
+      description = "A Wasm to JavaScript adapter";
+      tag = CodeEventListener::STUB_TAG;
+      break;
+    case AbstractCode::WASM_INTERPRETER_ENTRY:
+      description = "A Wasm to Interpreter adapter";
+      tag = CodeEventListener::STUB_TAG;
+      break;
+    case AbstractCode::C_WASM_ENTRY:
+      description = "A C to Wasm entry stub";
+      tag = CodeEventListener::STUB_TAG;
+      break;
+    case AbstractCode::NUMBER_OF_KINDS:
+      UNIMPLEMENTED();
+  }
+  CALL_CODE_EVENT_HANDLER(CodeCreateEvent(tag, code_object, description))
+}
+
+void ExistingCodeLogger::LogCodeObjects() {
+  Heap* heap = isolate_->heap();
+  HeapIterator iterator(heap);
+  DisallowHeapAllocation no_gc;
+  for (HeapObject* obj = iterator.next(); obj != nullptr;
+       obj = iterator.next()) {
+    if (obj->IsCode()) LogCodeObject(obj);
+    if (obj->IsBytecodeArray()) LogCodeObject(obj);
+  }
+}
+
+void ExistingCodeLogger::LogCompiledFunctions() {
+  Heap* heap = isolate_->heap();
+  HandleScope scope(isolate_);
+  const int compiled_funcs_count =
+      EnumerateCompiledFunctions(heap, nullptr, nullptr);
+  ScopedVector<Handle<SharedFunctionInfo>> sfis(compiled_funcs_count);
+  ScopedVector<Handle<AbstractCode>> code_objects(compiled_funcs_count);
+  EnumerateCompiledFunctions(heap, sfis.start(), code_objects.start());
+
+  // During iteration, there can be heap allocation due to
+  // GetScriptLineNumber call.
+  for (int i = 0; i < compiled_funcs_count; ++i) {
+    if (code_objects[i].is_identical_to(BUILTIN_CODE(isolate_, CompileLazy)))
+      continue;
+    LogExistingFunction(sfis[i], code_objects[i]);
+  }
+
+  const int compiled_wasm_modules_count = EnumerateWasmModules(heap, nullptr);
+  ScopedVector<Handle<WasmCompiledModule>> modules(compiled_wasm_modules_count);
+  EnumerateWasmModules(heap, modules.start());
+  for (int i = 0; i < compiled_wasm_modules_count; ++i) {
+    modules[i]->LogWasmCodes(isolate_);
+  }
+}
+
+void ExistingCodeLogger::LogBytecodeHandler(
+    interpreter::Bytecode bytecode, interpreter::OperandScale operand_scale,
+    Code* code) {
+  std::string bytecode_name =
+      interpreter::Bytecodes::ToString(bytecode, operand_scale);
+  CALL_CODE_EVENT_HANDLER(
+      CodeCreateEvent(CodeEventListener::BYTECODE_HANDLER_TAG,
+                      AbstractCode::cast(code), bytecode_name.c_str()))
+}
+
+void ExistingCodeLogger::LogBytecodeHandlers() {
+  const interpreter::OperandScale kOperandScales[] = {
+#define VALUE(Name, _) interpreter::OperandScale::k##Name,
+      OPERAND_SCALE_LIST(VALUE)
+#undef VALUE
+  };
+
+  const int last_index = static_cast<int>(interpreter::Bytecode::kLast);
+  interpreter::Interpreter* interpreter = isolate_->interpreter();
+  for (auto operand_scale : kOperandScales) {
+    for (int index = 0; index <= last_index; ++index) {
+      interpreter::Bytecode bytecode = interpreter::Bytecodes::FromByte(index);
+      if (interpreter::Bytecodes::BytecodeHasHandler(bytecode, operand_scale)) {
+        Code* code = interpreter->GetBytecodeHandler(bytecode, operand_scale);
+        if (isolate_->heap()->IsDeserializeLazyHandler(code)) continue;
+        LogBytecodeHandler(bytecode, operand_scale, code);
+      }
+    }
+  }
+}
+
+void ExistingCodeLogger::LogExistingFunction(Handle<SharedFunctionInfo> shared,
+                                             Handle<AbstractCode> code) {
+  if (shared->script()->IsScript()) {
+    Handle<Script> script(Script::cast(shared->script()));
+    int line_num = Script::GetLineNumber(script, shared->StartPosition()) + 1;
+    int column_num =
+        Script::GetColumnNumber(script, shared->StartPosition()) + 1;
+    if (script->name()->IsString()) {
+      Handle<String> script_name(String::cast(script->name()));
+      if (line_num > 0) {
+        CALL_CODE_EVENT_HANDLER(
+            CodeCreateEvent(Logger::ToNativeByScript(
+                                CodeEventListener::LAZY_COMPILE_TAG, *script),
+                            *code, *shared, *script_name, line_num, column_num))
+      } else {
+        // Can't distinguish eval and script here, so always use Script.
+        CALL_CODE_EVENT_HANDLER(CodeCreateEvent(
+            Logger::ToNativeByScript(CodeEventListener::SCRIPT_TAG, *script),
+            *code, *shared, *script_name))
+      }
+    } else {
+      CALL_CODE_EVENT_HANDLER(
+          CodeCreateEvent(Logger::ToNativeByScript(
+                              CodeEventListener::LAZY_COMPILE_TAG, *script),
+                          *code, *shared, isolate_->heap()->empty_string(),
+                          line_num, column_num))
+    }
+  } else if (shared->IsApiFunction()) {
+    // API function.
+    FunctionTemplateInfo* fun_data = shared->get_api_func_data();
+    Object* raw_call_data = fun_data->call_code();
+    if (!raw_call_data->IsUndefined(isolate_)) {
+      CallHandlerInfo* call_data = CallHandlerInfo::cast(raw_call_data);
+      Object* callback_obj = call_data->callback();
+      Address entry_point = v8::ToCData<Address>(callback_obj);
+#if USES_FUNCTION_DESCRIPTORS
+      entry_point = *FUNCTION_ENTRYPOINT_ADDRESS(entry_point);
+#endif
+      CALL_CODE_EVENT_HANDLER(CallbackEvent(shared->DebugName(), entry_point))
+    }
+  } else {
+    CALL_CODE_EVENT_HANDLER(CodeCreateEvent(CodeEventListener::LAZY_COMPILE_TAG,
+                                            *code, *shared,
+                                            isolate_->heap()->empty_string()))
+  }
+}
+
+#undef CALL_CODE_EVENT_HANDLER
+
 }  // namespace internal
 }  // namespace v8
diff --git a/deps/v8/src/log.h b/deps/v8/src/log.h
index 6f3e1f244a8f30..fefc4b1a2d123a 100644
--- a/deps/v8/src/log.h
+++ b/deps/v8/src/log.h
@@ -8,6 +8,7 @@
 #include <set>
 #include <string>
 
+#include "include/v8-profiler.h"
 #include "src/allocation.h"
 #include "src/base/compiler-specific.h"
 #include "src/base/platform/elapsed-timer.h"
@@ -87,12 +88,33 @@ class WasmCode;
     if (logger->is_logging()) logger->Call;             \
   } while (false)
 
-#define LOG_CODE_EVENT(isolate, Call)                   \
-  do {                                                  \
-    v8::internal::Logger* logger = (isolate)->logger(); \
-    if (logger->is_logging_code_events()) logger->Call; \
+#define LOG_CODE_EVENT(isolate, Call)                        \
+  do {                                                       \
+    v8::internal::Logger* logger = (isolate)->logger();      \
+    if (logger->is_listening_to_code_events()) logger->Call; \
   } while (false)
 
+class ExistingCodeLogger {
+ public:
+  explicit ExistingCodeLogger(Isolate* isolate,
+                              CodeEventListener* listener = nullptr)
+      : isolate_(isolate), listener_(listener) {}
+
+  void LogCodeObjects();
+  void LogBytecodeHandlers();
+
+  void LogCompiledFunctions();
+  void LogExistingFunction(Handle<SharedFunctionInfo> shared,
+                           Handle<AbstractCode> code);
+  void LogCodeObject(Object* object);
+  void LogBytecodeHandler(interpreter::Bytecode bytecode,
+                          interpreter::OperandScale operand_scale, Code* code);
+
+ private:
+  Isolate* isolate_;
+  CodeEventListener* listener_;
+};
+
 class Logger : public CodeEventListener {
  public:
   enum StartEnd { START = 0, END = 1, STAMP = 2 };
@@ -233,7 +255,7 @@ class Logger : public CodeEventListener {
     return is_logging_;
   }
 
-  bool is_logging_code_events() {
+  bool is_listening_to_code_events() {
     return is_logging() || jit_logger_ != nullptr;
   }
 
@@ -332,6 +354,8 @@ class Logger : public CodeEventListener {
   // 'true' between SetUp() and TearDown().
   bool is_initialized_;
 
+  ExistingCodeLogger existing_code_logger_;
+
   base::ElapsedTimer timer_;
 
   friend class CpuProfiler;
@@ -412,6 +436,58 @@ class CodeEventLogger : public CodeEventListener {
   NameBuffer* name_buffer_;
 };
 
+struct CodeEvent {
+  uintptr_t code_start_address;
+  size_t code_size;
+  Handle<String> function_name;
+  Handle<String> script_name;
+  int script_line;
+  int script_column;
+  CodeEventType code_type;
+  const char* comment;
+};
+
+class ExternalCodeEventListener : public CodeEventListener {
+ public:
+  explicit ExternalCodeEventListener(Isolate* isolate);
+  ~ExternalCodeEventListener() override;
+
+  void CodeCreateEvent(LogEventsAndTags tag, AbstractCode* code,
+                       const char* comment) override;
+  void CodeCreateEvent(LogEventsAndTags tag, AbstractCode* code,
+                       Name* name) override;
+  void CodeCreateEvent(LogEventsAndTags tag, AbstractCode* code,
+                       SharedFunctionInfo* shared, Name* name) override;
+  void CodeCreateEvent(LogEventsAndTags tag, AbstractCode* code,
+                       SharedFunctionInfo* shared, Name* source, int line,
+                       int column) override;
+  void CodeCreateEvent(LogEventsAndTags tag, const wasm::WasmCode* code,
+                       wasm::WasmName name) override;
+
+  void RegExpCodeCreateEvent(AbstractCode* code, String* source) override;
+  void CallbackEvent(Name* name, Address entry_point) override {}
+  void GetterCallbackEvent(Name* name, Address entry_point) override {}
+  void SetterCallbackEvent(Name* name, Address entry_point) override {}
+  void SharedFunctionInfoMoveEvent(Address from, Address to) override {}
+  void CodeMoveEvent(AbstractCode* from, Address to) override {}
+  void CodeDisableOptEvent(AbstractCode* code,
+                           SharedFunctionInfo* shared) override {}
+  void CodeMovingGCEvent() override {}
+  void CodeDeoptEvent(Code* code, DeoptKind kind, Address pc,
+                      int fp_to_sp_delta) override {}
+
+  void StartListening(CodeEventHandler* code_event_handler);
+  void StopListening();
+
+  bool is_listening_to_code_events() override { return true; }
+
+ private:
+  void LogExistingCode();
+
+  bool is_listening_;
+  Isolate* isolate_;
+  v8::CodeEventHandler* code_event_handler_;
+};
 
 }  // namespace internal
 }  // namespace v8
diff --git a/deps/v8/src/runtime/runtime-function.cc b/deps/v8/src/runtime/runtime-function.cc
index 5dcb4115e5153e..9f1cbc00e998b7 100644
--- a/deps/v8/src/runtime/runtime-function.cc
+++ b/deps/v8/src/runtime/runtime-function.cc
@@ -147,7 +147,8 @@ RUNTIME_FUNCTION(Runtime_SetCode) {
   // the target_shared optimized code map.
   JSFunction::EnsureFeedbackVector(target);
 
-  if (isolate->logger()->is_logging_code_events() || isolate->is_profiling()) {
+  if (isolate->logger()->is_listening_to_code_events() ||
+      isolate->is_profiling()) {
     isolate->logger()->LogExistingFunction(
         source_shared, Handle<AbstractCode>(source_shared->abstract_code()));
   }
diff --git a/deps/v8/src/snapshot/code-serializer.cc b/deps/v8/src/snapshot/code-serializer.cc
index 823d8dc9af8b87..d096500686e31b 100644
--- a/deps/v8/src/snapshot/code-serializer.cc
+++ b/deps/v8/src/snapshot/code-serializer.cc
@@ -284,7 +284,8 @@ MaybeHandle<SharedFunctionInfo> CodeSerializer::Deserialize(
     PrintF("[Deserializing from %d bytes took %0.3f ms]\n", length, ms);
   }
 
-  if (isolate->logger()->is_logging_code_events() || isolate->is_profiling()) {
+  if (isolate->logger()->is_listening_to_code_events() ||
+      isolate->is_profiling()) {
     String* name = isolate->heap()->empty_string();
     if (result->script()->IsScript()) {
       Script* script = Script::cast(result->script());
diff --git a/deps/v8/src/snapshot/snapshot-common.cc b/deps/v8/src/snapshot/snapshot-common.cc
index a33c468bb89ee7..a59e1552c6e1d0 100644
--- a/deps/v8/src/snapshot/snapshot-common.cc
+++ b/deps/v8/src/snapshot/snapshot-common.cc
@@ -114,7 +114,8 @@ Code* Snapshot::DeserializeBuiltin(Isolate* isolate, int builtin_id) {
            Builtins::name(builtin_id), bytes, ms);
   }
 
-  if (isolate->logger()->is_logging_code_events() || isolate->is_profiling()) {
+  if (isolate->logger()->is_listening_to_code_events() ||
+      isolate->is_profiling()) {
     isolate->logger()->LogCodeObject(code);
   }
 
@@ -195,7 +196,8 @@ Code* Snapshot::DeserializeHandler(Isolate* isolate,
            bytes, ms);
   }
 
-  if (isolate->logger()->is_logging_code_events() || isolate->is_profiling()) {
+  if (isolate->logger()->is_listening_to_code_events() ||
+      isolate->is_profiling()) {
     isolate->logger()->LogBytecodeHandler(bytecode, operand_scale, code);
   }
 
diff --git a/deps/v8/src/wasm/wasm-code-manager.cc b/deps/v8/src/wasm/wasm-code-manager.cc
index 9811395661beac..f72c0a3a472b42 100644
--- a/deps/v8/src/wasm/wasm-code-manager.cc
+++ b/deps/v8/src/wasm/wasm-code-manager.cc
@@ -190,7 +190,7 @@ bool WasmCode::HasTrapHandlerIndex() const { return trap_handler_index_ >= 0; }
 void WasmCode::ResetTrapHandlerIndex() { trap_handler_index_ = -1; }
 
 bool WasmCode::ShouldBeLogged(Isolate* isolate) {
-  return isolate->logger()->is_logging_code_events() ||
+  return isolate->logger()->is_listening_to_code_events() ||
          isolate->is_profiling() || FLAG_print_wasm_code || FLAG_print_code;
 }
 
diff --git a/deps/v8/test/cctest/test-log.cc b/deps/v8/test/cctest/test-log.cc
index c9a521fcae3977..3f8b0a517809cd 100644
--- a/deps/v8/test/cctest/test-log.cc
+++ b/deps/v8/test/cctest/test-log.cc
@@ -35,6 +35,7 @@
 #endif  // __linux__
 
 #include <unordered_set>
+#include <vector>
 #include "src/api.h"
 #include "src/log-utils.h"
 #include "src/log.h"
@@ -251,6 +252,38 @@ class ScopedLoggerInitializer {
   DISALLOW_COPY_AND_ASSIGN(ScopedLoggerInitializer);
 };
 
+class TestCodeEventHandler : public v8::CodeEventHandler {
+ public:
+  explicit TestCodeEventHandler(v8::Isolate* isolate)
+      : v8::CodeEventHandler(isolate) {}
+
+  const char* FindLine(const char* prefix, const char* suffix = nullptr,
+                       const char* start = nullptr) {
+    if (!log_.length()) return NULL;
+    const char* c_log = log_.c_str();
+    if (start == nullptr) start = c_log;
+    const char* end = c_log + log_.length();
+    return FindLogLine(start, end, prefix, suffix);
+  }
+
+  void Handle(v8::CodeEvent* code_event) override {
+    const char* code_type =
+        v8::CodeEvent::GetCodeEventTypeName(code_event->GetCodeType());
+    char function_name[1000];
+    strncpy(function_name, code_type, 1000);
+    function_name[strlen(code_type)] = ' ';
+    code_event->GetFunctionName()->WriteUtf8(
+        function_name + strlen(code_type) + 1, 1000);
+    function_name[strlen(function_name) + 1] = '\0';
+    function_name[strlen(function_name)] = '\n';
+
+    log_ += std::string(function_name);
+  }
+
+ private:
+  std::string log_;
+};
+
 }  // namespace
 
 TEST(FindLogLine) {
@@ -801,6 +834,48 @@ TEST(LogInterpretedFramesNativeStack) {
   isolate->Dispose();
 }
 
+TEST(ExternalCodeEventListener) {
+  i::FLAG_log = false;
+  i::FLAG_prof = false;
+
+  v8::Isolate::CreateParams create_params;
+  create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
+  v8::Isolate* isolate = v8::Isolate::New(create_params);
+
+  {
+    v8::HandleScope scope(isolate);
+    v8::Isolate::Scope isolate_scope(isolate);
+    v8::Local<v8::Context> context = v8::Context::New(isolate);
+    context->Enter();
+
+    TestCodeEventHandler code_event_handler(isolate);
+
+    const char* source_text_before_start =
+        "function testCodeEventListenerBeforeStart(a,b) { return a + b };"
+        "testCodeEventListenerBeforeStart('1', 1);";
+    CompileRun(source_text_before_start);
+
+    CHECK_NULL(code_event_handler.FindLine("LazyCompile",
+                                           "testCodeEventListenerBeforeStart"));
+
+    code_event_handler.Enable();
+
+    CHECK_NOT_NULL(code_event_handler.FindLine(
+        "LazyCompile", "testCodeEventListenerBeforeStart"));
+
+    const char* source_text_after_start =
+        "function testCodeEventListenerAfterStart(a,b) { return a + b };"
+        "testCodeEventListenerAfterStart('1', 1);";
+    CompileRun(source_text_after_start);
+
+    CHECK_NOT_NULL(code_event_handler.FindLine(
+        "LazyCompile", "testCodeEventListenerAfterStart"));
+
+    context->Exit();
+  }
+  isolate->Dispose();
+}
+
 TEST(TraceMaps) {
   SETUP_FLAGS();
   i::FLAG_trace_maps = true;