• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2015 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "src/inspector/v8-profiler-agent-impl.h"
6 
7 #include <vector>
8 
9 #include "include/v8-profiler.h"
10 #include "src/base/atomicops.h"
11 #include "src/base/platform/time.h"
12 #include "src/debug/debug-interface.h"
13 #include "src/inspector/protocol/Protocol.h"
14 #include "src/inspector/string-util.h"
15 #include "src/inspector/v8-debugger.h"
16 #include "src/inspector/v8-inspector-impl.h"
17 #include "src/inspector/v8-inspector-session-impl.h"
18 #include "src/inspector/v8-stack-trace-impl.h"
19 
20 namespace v8_inspector {
21 
22 namespace ProfilerAgentState {
23 static const char samplingInterval[] = "samplingInterval";
24 static const char userInitiatedProfiling[] = "userInitiatedProfiling";
25 static const char profilerEnabled[] = "profilerEnabled";
26 static const char preciseCoverageStarted[] = "preciseCoverageStarted";
27 static const char preciseCoverageCallCount[] = "preciseCoverageCallCount";
28 static const char preciseCoverageDetailed[] = "preciseCoverageDetailed";
29 static const char preciseCoverageAllowTriggeredUpdates[] =
30     "preciseCoverageAllowTriggeredUpdates";
31 static const char typeProfileStarted[] = "typeProfileStarted";
32 }  // namespace ProfilerAgentState
33 
34 namespace {
35 
resourceNameToUrl(V8InspectorImpl * inspector,v8::Local<v8::String> v8Name)36 String16 resourceNameToUrl(V8InspectorImpl* inspector,
37                            v8::Local<v8::String> v8Name) {
38   String16 name = toProtocolString(inspector->isolate(), v8Name);
39   if (!inspector) return name;
40   std::unique_ptr<StringBuffer> url =
41       inspector->client()->resourceNameToUrl(toStringView(name));
42   return url ? toString16(url->string()) : name;
43 }
44 
45 std::unique_ptr<protocol::Array<protocol::Profiler::PositionTickInfo>>
buildInspectorObjectForPositionTicks(const v8::CpuProfileNode * node)46 buildInspectorObjectForPositionTicks(const v8::CpuProfileNode* node) {
47   unsigned lineCount = node->GetHitLineCount();
48   if (!lineCount) return nullptr;
49   auto array =
50       std::make_unique<protocol::Array<protocol::Profiler::PositionTickInfo>>();
51   std::vector<v8::CpuProfileNode::LineTick> entries(lineCount);
52   if (node->GetLineTicks(&entries[0], lineCount)) {
53     for (unsigned i = 0; i < lineCount; i++) {
54       std::unique_ptr<protocol::Profiler::PositionTickInfo> line =
55           protocol::Profiler::PositionTickInfo::create()
56               .setLine(entries[i].line)
57               .setTicks(entries[i].hit_count)
58               .build();
59       array->emplace_back(std::move(line));
60     }
61   }
62   return array;
63 }
64 
buildInspectorObjectFor(V8InspectorImpl * inspector,const v8::CpuProfileNode * node)65 std::unique_ptr<protocol::Profiler::ProfileNode> buildInspectorObjectFor(
66     V8InspectorImpl* inspector, const v8::CpuProfileNode* node) {
67   v8::Isolate* isolate = inspector->isolate();
68   v8::HandleScope handleScope(isolate);
69   auto callFrame =
70       protocol::Runtime::CallFrame::create()
71           .setFunctionName(toProtocolString(isolate, node->GetFunctionName()))
72           .setScriptId(String16::fromInteger(node->GetScriptId()))
73           .setUrl(resourceNameToUrl(inspector, node->GetScriptResourceName()))
74           .setLineNumber(node->GetLineNumber() - 1)
75           .setColumnNumber(node->GetColumnNumber() - 1)
76           .build();
77   auto result = protocol::Profiler::ProfileNode::create()
78                     .setCallFrame(std::move(callFrame))
79                     .setHitCount(node->GetHitCount())
80                     .setId(node->GetNodeId())
81                     .build();
82 
83   const int childrenCount = node->GetChildrenCount();
84   if (childrenCount) {
85     auto children = std::make_unique<protocol::Array<int>>();
86     for (int i = 0; i < childrenCount; i++)
87       children->emplace_back(node->GetChild(i)->GetNodeId());
88     result->setChildren(std::move(children));
89   }
90 
91   const char* deoptReason = node->GetBailoutReason();
92   if (deoptReason && deoptReason[0] && strcmp(deoptReason, "no reason"))
93     result->setDeoptReason(deoptReason);
94 
95   auto positionTicks = buildInspectorObjectForPositionTicks(node);
96   if (positionTicks) result->setPositionTicks(std::move(positionTicks));
97 
98   return result;
99 }
100 
buildInspectorObjectForSamples(v8::CpuProfile * v8profile)101 std::unique_ptr<protocol::Array<int>> buildInspectorObjectForSamples(
102     v8::CpuProfile* v8profile) {
103   auto array = std::make_unique<protocol::Array<int>>();
104   int count = v8profile->GetSamplesCount();
105   for (int i = 0; i < count; i++)
106     array->emplace_back(v8profile->GetSample(i)->GetNodeId());
107   return array;
108 }
109 
buildInspectorObjectForTimestamps(v8::CpuProfile * v8profile)110 std::unique_ptr<protocol::Array<int>> buildInspectorObjectForTimestamps(
111     v8::CpuProfile* v8profile) {
112   auto array = std::make_unique<protocol::Array<int>>();
113   int count = v8profile->GetSamplesCount();
114   uint64_t lastTime = v8profile->GetStartTime();
115   for (int i = 0; i < count; i++) {
116     uint64_t ts = v8profile->GetSampleTimestamp(i);
117     array->emplace_back(static_cast<int>(ts - lastTime));
118     lastTime = ts;
119   }
120   return array;
121 }
122 
flattenNodesTree(V8InspectorImpl * inspector,const v8::CpuProfileNode * node,protocol::Array<protocol::Profiler::ProfileNode> * list)123 void flattenNodesTree(V8InspectorImpl* inspector,
124                       const v8::CpuProfileNode* node,
125                       protocol::Array<protocol::Profiler::ProfileNode>* list) {
126   list->emplace_back(buildInspectorObjectFor(inspector, node));
127   const int childrenCount = node->GetChildrenCount();
128   for (int i = 0; i < childrenCount; i++)
129     flattenNodesTree(inspector, node->GetChild(i), list);
130 }
131 
createCPUProfile(V8InspectorImpl * inspector,v8::CpuProfile * v8profile)132 std::unique_ptr<protocol::Profiler::Profile> createCPUProfile(
133     V8InspectorImpl* inspector, v8::CpuProfile* v8profile) {
134   auto nodes =
135       std::make_unique<protocol::Array<protocol::Profiler::ProfileNode>>();
136   flattenNodesTree(inspector, v8profile->GetTopDownRoot(), nodes.get());
137   return protocol::Profiler::Profile::create()
138       .setNodes(std::move(nodes))
139       .setStartTime(static_cast<double>(v8profile->GetStartTime()))
140       .setEndTime(static_cast<double>(v8profile->GetEndTime()))
141       .setSamples(buildInspectorObjectForSamples(v8profile))
142       .setTimeDeltas(buildInspectorObjectForTimestamps(v8profile))
143       .build();
144 }
145 
currentDebugLocation(V8InspectorImpl * inspector)146 std::unique_ptr<protocol::Debugger::Location> currentDebugLocation(
147     V8InspectorImpl* inspector) {
148   auto stackTrace = V8StackTraceImpl::capture(inspector->debugger(), 1);
149   CHECK(stackTrace);
150   CHECK(!stackTrace->isEmpty());
151   return protocol::Debugger::Location::create()
152       .setScriptId(String16::fromInteger(stackTrace->topScriptId()))
153       .setLineNumber(stackTrace->topLineNumber())
154       .setColumnNumber(stackTrace->topColumnNumber())
155       .build();
156 }
157 
158 volatile int s_lastProfileId = 0;
159 
160 }  // namespace
161 
162 class V8ProfilerAgentImpl::ProfileDescriptor {
163  public:
ProfileDescriptor(const String16 & id,const String16 & title)164   ProfileDescriptor(const String16& id, const String16& title)
165       : m_id(id), m_title(title) {}
166   String16 m_id;
167   String16 m_title;
168 };
169 
V8ProfilerAgentImpl(V8InspectorSessionImpl * session,protocol::FrontendChannel * frontendChannel,protocol::DictionaryValue * state)170 V8ProfilerAgentImpl::V8ProfilerAgentImpl(
171     V8InspectorSessionImpl* session, protocol::FrontendChannel* frontendChannel,
172     protocol::DictionaryValue* state)
173     : m_session(session),
174       m_isolate(m_session->inspector()->isolate()),
175       m_state(state),
176       m_frontend(frontendChannel) {}
177 
~V8ProfilerAgentImpl()178 V8ProfilerAgentImpl::~V8ProfilerAgentImpl() {
179   if (m_profiler) m_profiler->Dispose();
180 }
181 
consoleProfile(const String16 & title)182 void V8ProfilerAgentImpl::consoleProfile(const String16& title) {
183   if (!m_enabled) return;
184   String16 id = nextProfileId();
185   m_startedProfiles.push_back(ProfileDescriptor(id, title));
186   startProfiling(id);
187   m_frontend.consoleProfileStarted(
188       id, currentDebugLocation(m_session->inspector()), title);
189 }
190 
consoleProfileEnd(const String16 & title)191 void V8ProfilerAgentImpl::consoleProfileEnd(const String16& title) {
192   if (!m_enabled) return;
193   String16 id;
194   String16 resolvedTitle;
195   // Take last started profile if no title was passed.
196   if (title.isEmpty()) {
197     if (m_startedProfiles.empty()) return;
198     id = m_startedProfiles.back().m_id;
199     resolvedTitle = m_startedProfiles.back().m_title;
200     m_startedProfiles.pop_back();
201   } else {
202     for (size_t i = 0; i < m_startedProfiles.size(); i++) {
203       if (m_startedProfiles[i].m_title == title) {
204         resolvedTitle = title;
205         id = m_startedProfiles[i].m_id;
206         m_startedProfiles.erase(m_startedProfiles.begin() + i);
207         break;
208       }
209     }
210     if (id.isEmpty()) return;
211   }
212   std::unique_ptr<protocol::Profiler::Profile> profile =
213       stopProfiling(id, true);
214   if (!profile) return;
215   m_frontend.consoleProfileFinished(
216       id, currentDebugLocation(m_session->inspector()), std::move(profile),
217       resolvedTitle);
218 }
219 
enable()220 Response V8ProfilerAgentImpl::enable() {
221   if (!m_enabled) {
222     m_enabled = true;
223     m_state->setBoolean(ProfilerAgentState::profilerEnabled, true);
224   }
225 
226   return Response::Success();
227 }
228 
disable()229 Response V8ProfilerAgentImpl::disable() {
230   if (m_enabled) {
231     for (size_t i = m_startedProfiles.size(); i > 0; --i)
232       stopProfiling(m_startedProfiles[i - 1].m_id, false);
233     m_startedProfiles.clear();
234     stop(nullptr);
235     stopPreciseCoverage();
236     DCHECK(!m_profiler);
237     m_enabled = false;
238     m_state->setBoolean(ProfilerAgentState::profilerEnabled, false);
239   }
240 
241   return Response::Success();
242 }
243 
setSamplingInterval(int interval)244 Response V8ProfilerAgentImpl::setSamplingInterval(int interval) {
245   if (m_profiler) {
246     return Response::ServerError(
247         "Cannot change sampling interval when profiling.");
248   }
249   m_state->setInteger(ProfilerAgentState::samplingInterval, interval);
250   return Response::Success();
251 }
252 
restore()253 void V8ProfilerAgentImpl::restore() {
254   DCHECK(!m_enabled);
255   if (m_state->booleanProperty(ProfilerAgentState::profilerEnabled, false)) {
256     m_enabled = true;
257     DCHECK(!m_profiler);
258     if (m_state->booleanProperty(ProfilerAgentState::userInitiatedProfiling,
259                                  false)) {
260       start();
261     }
262     if (m_state->booleanProperty(ProfilerAgentState::preciseCoverageStarted,
263                                  false)) {
264       bool callCount = m_state->booleanProperty(
265           ProfilerAgentState::preciseCoverageCallCount, false);
266       bool detailed = m_state->booleanProperty(
267           ProfilerAgentState::preciseCoverageDetailed, false);
268       bool updatesAllowed = m_state->booleanProperty(
269           ProfilerAgentState::preciseCoverageAllowTriggeredUpdates, false);
270       double timestamp;
271       startPreciseCoverage(Maybe<bool>(callCount), Maybe<bool>(detailed),
272                            Maybe<bool>(updatesAllowed), &timestamp);
273     }
274   }
275 }
276 
start()277 Response V8ProfilerAgentImpl::start() {
278   if (m_recordingCPUProfile) return Response::Success();
279   if (!m_enabled) return Response::ServerError("Profiler is not enabled");
280   m_recordingCPUProfile = true;
281   m_frontendInitiatedProfileId = nextProfileId();
282   startProfiling(m_frontendInitiatedProfileId);
283   m_state->setBoolean(ProfilerAgentState::userInitiatedProfiling, true);
284   return Response::Success();
285 }
286 
stop(std::unique_ptr<protocol::Profiler::Profile> * profile)287 Response V8ProfilerAgentImpl::stop(
288     std::unique_ptr<protocol::Profiler::Profile>* profile) {
289   if (!m_recordingCPUProfile) {
290     return Response::ServerError("No recording profiles found");
291   }
292   m_recordingCPUProfile = false;
293   std::unique_ptr<protocol::Profiler::Profile> cpuProfile =
294       stopProfiling(m_frontendInitiatedProfileId, !!profile);
295   if (profile) {
296     *profile = std::move(cpuProfile);
297     if (!profile->get()) return Response::ServerError("Profile is not found");
298   }
299   m_frontendInitiatedProfileId = String16();
300   m_state->setBoolean(ProfilerAgentState::userInitiatedProfiling, false);
301   return Response::Success();
302 }
303 
startPreciseCoverage(Maybe<bool> callCount,Maybe<bool> detailed,Maybe<bool> allowTriggeredUpdates,double * out_timestamp)304 Response V8ProfilerAgentImpl::startPreciseCoverage(
305     Maybe<bool> callCount, Maybe<bool> detailed,
306     Maybe<bool> allowTriggeredUpdates, double* out_timestamp) {
307   if (!m_enabled) return Response::ServerError("Profiler is not enabled");
308   *out_timestamp = v8::base::TimeTicks::Now().since_origin().InSecondsF();
309   bool callCountValue = callCount.fromMaybe(false);
310   bool detailedValue = detailed.fromMaybe(false);
311   bool allowTriggeredUpdatesValue = allowTriggeredUpdates.fromMaybe(false);
312   m_state->setBoolean(ProfilerAgentState::preciseCoverageStarted, true);
313   m_state->setBoolean(ProfilerAgentState::preciseCoverageCallCount,
314                       callCountValue);
315   m_state->setBoolean(ProfilerAgentState::preciseCoverageDetailed,
316                       detailedValue);
317   m_state->setBoolean(ProfilerAgentState::preciseCoverageAllowTriggeredUpdates,
318                       allowTriggeredUpdatesValue);
319   // BlockCount is a superset of PreciseCount. It includes block-granularity
320   // coverage data if it exists (at the time of writing, that's the case for
321   // each function recompiled after the BlockCount mode has been set); and
322   // function-granularity coverage data otherwise.
323   using C = v8::debug::Coverage;
324   using Mode = v8::debug::CoverageMode;
325   Mode mode = callCountValue
326                   ? (detailedValue ? Mode::kBlockCount : Mode::kPreciseCount)
327                   : (detailedValue ? Mode::kBlockBinary : Mode::kPreciseBinary);
328   C::SelectMode(m_isolate, mode);
329   return Response::Success();
330 }
331 
stopPreciseCoverage()332 Response V8ProfilerAgentImpl::stopPreciseCoverage() {
333   if (!m_enabled) return Response::ServerError("Profiler is not enabled");
334   m_state->setBoolean(ProfilerAgentState::preciseCoverageStarted, false);
335   m_state->setBoolean(ProfilerAgentState::preciseCoverageCallCount, false);
336   m_state->setBoolean(ProfilerAgentState::preciseCoverageDetailed, false);
337   v8::debug::Coverage::SelectMode(m_isolate,
338                                   v8::debug::CoverageMode::kBestEffort);
339   return Response::Success();
340 }
341 
342 namespace {
createCoverageRange(int start,int end,int count)343 std::unique_ptr<protocol::Profiler::CoverageRange> createCoverageRange(
344     int start, int end, int count) {
345   return protocol::Profiler::CoverageRange::create()
346       .setStartOffset(start)
347       .setEndOffset(end)
348       .setCount(count)
349       .build();
350 }
351 
coverageToProtocol(V8InspectorImpl * inspector,const v8::debug::Coverage & coverage,std::unique_ptr<protocol::Array<protocol::Profiler::ScriptCoverage>> * out_result)352 Response coverageToProtocol(
353     V8InspectorImpl* inspector, const v8::debug::Coverage& coverage,
354     std::unique_ptr<protocol::Array<protocol::Profiler::ScriptCoverage>>*
355         out_result) {
356   auto result =
357       std::make_unique<protocol::Array<protocol::Profiler::ScriptCoverage>>();
358   v8::Isolate* isolate = inspector->isolate();
359   for (size_t i = 0; i < coverage.ScriptCount(); i++) {
360     v8::debug::Coverage::ScriptData script_data = coverage.GetScriptData(i);
361     v8::Local<v8::debug::Script> script = script_data.GetScript();
362     auto functions = std::make_unique<
363         protocol::Array<protocol::Profiler::FunctionCoverage>>();
364     for (size_t j = 0; j < script_data.FunctionCount(); j++) {
365       v8::debug::Coverage::FunctionData function_data =
366           script_data.GetFunctionData(j);
367       auto ranges = std::make_unique<
368           protocol::Array<protocol::Profiler::CoverageRange>>();
369 
370       // Add function range.
371       ranges->emplace_back(createCoverageRange(function_data.StartOffset(),
372                                                function_data.EndOffset(),
373                                                function_data.Count()));
374 
375       // Process inner blocks.
376       for (size_t k = 0; k < function_data.BlockCount(); k++) {
377         v8::debug::Coverage::BlockData block_data =
378             function_data.GetBlockData(k);
379         ranges->emplace_back(createCoverageRange(block_data.StartOffset(),
380                                                  block_data.EndOffset(),
381                                                  block_data.Count()));
382       }
383 
384       functions->emplace_back(
385           protocol::Profiler::FunctionCoverage::create()
386               .setFunctionName(toProtocolString(
387                   isolate,
388                   function_data.Name().FromMaybe(v8::Local<v8::String>())))
389               .setRanges(std::move(ranges))
390               .setIsBlockCoverage(function_data.HasBlockCoverage())
391               .build());
392     }
393     String16 url;
394     v8::Local<v8::String> name;
395     if (script->SourceURL().ToLocal(&name) && name->Length()) {
396       url = toProtocolString(isolate, name);
397     } else if (script->Name().ToLocal(&name) && name->Length()) {
398       url = resourceNameToUrl(inspector, name);
399     }
400     result->emplace_back(protocol::Profiler::ScriptCoverage::create()
401                              .setScriptId(String16::fromInteger(script->Id()))
402                              .setUrl(url)
403                              .setFunctions(std::move(functions))
404                              .build());
405   }
406   *out_result = std::move(result);
407   return Response::Success();
408 }
409 }  // anonymous namespace
410 
takePreciseCoverage(std::unique_ptr<protocol::Array<protocol::Profiler::ScriptCoverage>> * out_result,double * out_timestamp)411 Response V8ProfilerAgentImpl::takePreciseCoverage(
412     std::unique_ptr<protocol::Array<protocol::Profiler::ScriptCoverage>>*
413         out_result,
414     double* out_timestamp) {
415   if (!m_state->booleanProperty(ProfilerAgentState::preciseCoverageStarted,
416                                 false)) {
417     return Response::ServerError("Precise coverage has not been started.");
418   }
419   v8::HandleScope handle_scope(m_isolate);
420   v8::debug::Coverage coverage = v8::debug::Coverage::CollectPrecise(m_isolate);
421   *out_timestamp = v8::base::TimeTicks::Now().since_origin().InSecondsF();
422   return coverageToProtocol(m_session->inspector(), coverage, out_result);
423 }
424 
triggerPreciseCoverageDeltaUpdate(const String16 & occasion)425 void V8ProfilerAgentImpl::triggerPreciseCoverageDeltaUpdate(
426     const String16& occasion) {
427   if (!m_state->booleanProperty(ProfilerAgentState::preciseCoverageStarted,
428                                 false)) {
429     return;
430   }
431   if (!m_state->booleanProperty(
432           ProfilerAgentState::preciseCoverageAllowTriggeredUpdates, false)) {
433     return;
434   }
435   v8::HandleScope handle_scope(m_isolate);
436   v8::debug::Coverage coverage = v8::debug::Coverage::CollectPrecise(m_isolate);
437   std::unique_ptr<protocol::Array<protocol::Profiler::ScriptCoverage>>
438       out_result;
439   coverageToProtocol(m_session->inspector(), coverage, &out_result);
440   double now = v8::base::TimeTicks::Now().since_origin().InSecondsF();
441   m_frontend.preciseCoverageDeltaUpdate(now, occasion, std::move(out_result));
442 }
443 
getBestEffortCoverage(std::unique_ptr<protocol::Array<protocol::Profiler::ScriptCoverage>> * out_result)444 Response V8ProfilerAgentImpl::getBestEffortCoverage(
445     std::unique_ptr<protocol::Array<protocol::Profiler::ScriptCoverage>>*
446         out_result) {
447   v8::HandleScope handle_scope(m_isolate);
448   v8::debug::Coverage coverage =
449       v8::debug::Coverage::CollectBestEffort(m_isolate);
450   return coverageToProtocol(m_session->inspector(), coverage, out_result);
451 }
452 
453 namespace {
454 std::unique_ptr<protocol::Array<protocol::Profiler::ScriptTypeProfile>>
typeProfileToProtocol(V8InspectorImpl * inspector,const v8::debug::TypeProfile & type_profile)455 typeProfileToProtocol(V8InspectorImpl* inspector,
456                       const v8::debug::TypeProfile& type_profile) {
457   auto result = std::make_unique<
458       protocol::Array<protocol::Profiler::ScriptTypeProfile>>();
459   v8::Isolate* isolate = inspector->isolate();
460   for (size_t i = 0; i < type_profile.ScriptCount(); i++) {
461     v8::debug::TypeProfile::ScriptData script_data =
462         type_profile.GetScriptData(i);
463     v8::Local<v8::debug::Script> script = script_data.GetScript();
464     auto entries = std::make_unique<
465         protocol::Array<protocol::Profiler::TypeProfileEntry>>();
466 
467     for (const auto& entry : script_data.Entries()) {
468       auto types =
469           std::make_unique<protocol::Array<protocol::Profiler::TypeObject>>();
470       for (const auto& type : entry.Types()) {
471         types->emplace_back(
472             protocol::Profiler::TypeObject::create()
473                 .setName(toProtocolString(
474                     isolate, type.FromMaybe(v8::Local<v8::String>())))
475                 .build());
476       }
477       entries->emplace_back(protocol::Profiler::TypeProfileEntry::create()
478                                 .setOffset(entry.SourcePosition())
479                                 .setTypes(std::move(types))
480                                 .build());
481     }
482     String16 url;
483     v8::Local<v8::String> name;
484     if (script->SourceURL().ToLocal(&name) && name->Length()) {
485       url = toProtocolString(isolate, name);
486     } else if (script->Name().ToLocal(&name) && name->Length()) {
487       url = resourceNameToUrl(inspector, name);
488     }
489     result->emplace_back(protocol::Profiler::ScriptTypeProfile::create()
490                              .setScriptId(String16::fromInteger(script->Id()))
491                              .setUrl(url)
492                              .setEntries(std::move(entries))
493                              .build());
494   }
495   return result;
496 }
497 }  // anonymous namespace
498 
startTypeProfile()499 Response V8ProfilerAgentImpl::startTypeProfile() {
500   m_state->setBoolean(ProfilerAgentState::typeProfileStarted, true);
501   v8::debug::TypeProfile::SelectMode(m_isolate,
502                                      v8::debug::TypeProfileMode::kCollect);
503   return Response::Success();
504 }
505 
stopTypeProfile()506 Response V8ProfilerAgentImpl::stopTypeProfile() {
507   m_state->setBoolean(ProfilerAgentState::typeProfileStarted, false);
508   v8::debug::TypeProfile::SelectMode(m_isolate,
509                                      v8::debug::TypeProfileMode::kNone);
510   return Response::Success();
511 }
512 
takeTypeProfile(std::unique_ptr<protocol::Array<protocol::Profiler::ScriptTypeProfile>> * out_result)513 Response V8ProfilerAgentImpl::takeTypeProfile(
514     std::unique_ptr<protocol::Array<protocol::Profiler::ScriptTypeProfile>>*
515         out_result) {
516   if (!m_state->booleanProperty(ProfilerAgentState::typeProfileStarted,
517                                 false)) {
518     return Response::ServerError("Type profile has not been started.");
519   }
520   v8::HandleScope handle_scope(m_isolate);
521   v8::debug::TypeProfile type_profile =
522       v8::debug::TypeProfile::Collect(m_isolate);
523   *out_result = typeProfileToProtocol(m_session->inspector(), type_profile);
524   return Response::Success();
525 }
526 
nextProfileId()527 String16 V8ProfilerAgentImpl::nextProfileId() {
528   return String16::fromInteger(
529       v8::base::Relaxed_AtomicIncrement(&s_lastProfileId, 1));
530 }
531 
startProfiling(const String16 & title)532 void V8ProfilerAgentImpl::startProfiling(const String16& title) {
533   v8::HandleScope handleScope(m_isolate);
534   if (!m_startedProfilesCount) {
535     DCHECK(!m_profiler);
536     m_profiler = v8::CpuProfiler::New(m_isolate);
537     int interval =
538         m_state->integerProperty(ProfilerAgentState::samplingInterval, 0);
539     if (interval) m_profiler->SetSamplingInterval(interval);
540   }
541   ++m_startedProfilesCount;
542   m_profiler->StartProfiling(toV8String(m_isolate, title), true);
543 }
544 
stopProfiling(const String16 & title,bool serialize)545 std::unique_ptr<protocol::Profiler::Profile> V8ProfilerAgentImpl::stopProfiling(
546     const String16& title, bool serialize) {
547   v8::HandleScope handleScope(m_isolate);
548   v8::CpuProfile* profile =
549       m_profiler->StopProfiling(toV8String(m_isolate, title));
550   std::unique_ptr<protocol::Profiler::Profile> result;
551   if (profile) {
552     if (serialize) result = createCPUProfile(m_session->inspector(), profile);
553     profile->Delete();
554   }
555   --m_startedProfilesCount;
556   if (!m_startedProfilesCount) {
557     m_profiler->Dispose();
558     m_profiler = nullptr;
559   }
560   return result;
561 }
562 
563 }  // namespace v8_inspector
564