@@ -50,58 +50,71 @@ void V8ProfilerConnection::DispatchMessage(Local<String> message) {
5050 session_->Dispatch (ToProtocolString (env ()->isolate (), message)->string ());
5151}
5252
53- bool V8ProfilerConnection::WriteResult (const char * path, Local<String> result) {
54- int ret = WriteFileSync (env ()->isolate (), path, result);
53+ static void WriteResult (Environment* env,
54+ const char * path,
55+ Local<String> result) {
56+ int ret = WriteFileSync (env->isolate (), path, result);
5557 if (ret != 0 ) {
5658 char err_buf[128 ];
5759 uv_err_name_r (ret, err_buf, sizeof (err_buf));
5860 fprintf (stderr, " %s: Failed to write file %s\n " , err_buf, path);
59- return false ;
61+ return ;
6062 }
61- Debug (
62- env (), DebugCategory::INSPECTOR_PROFILER, " Written result to %s\n " , path);
63- return true ;
63+ Debug (env, DebugCategory::INSPECTOR_PROFILER, " Written result to %s\n " , path);
6464}
6565
66- void V8CoverageConnection::OnMessage (const v8_inspector::StringView& message) {
67- Debug (env (),
66+ void V8ProfilerConnection::V8ProfilerSessionDelegate::SendMessageToFrontend (
67+ const v8_inspector::StringView& message) {
68+ Environment* env = connection_->env ();
69+ Isolate* isolate = env->isolate ();
70+ HandleScope handle_scope (isolate);
71+ Context::Scope context_scope (env->context ());
72+
73+ // TODO(joyeecheung): always parse the message so that we can use the id to
74+ // identify ending messages as well as printing the message in the debug
75+ // output when there is an error.
76+ const char * type = connection_->type ();
77+ Debug (env,
6878 DebugCategory::INSPECTOR_PROFILER,
69- " Receive coverage message, ending = %s\n " ,
70- ending_ ? " true" : " false" );
71- if (!ending_) {
79+ " Receive %s profile message, ending = %s\n " ,
80+ type,
81+ connection_->ending () ? " true" : " false" );
82+ if (!connection_->ending ()) {
7283 return ;
7384 }
74- Isolate* isolate = env ()->isolate ();
75- Local<Context> context = env ()->context ();
76- HandleScope handle_scope (isolate);
77- Context::Scope context_scope (context);
78- Local<String> result;
85+
86+ // Convert StringView to a Local<String>.
87+ Local<String> message_str;
7988 if (!String::NewFromTwoByte (isolate,
8089 message.characters16 (),
8190 NewStringType::kNormal ,
8291 message.length ())
83- .ToLocal (&result)) {
84- fprintf (stderr, " Failed to covert coverage message\n " );
92+ .ToLocal (&message_str)) {
93+ fprintf (stderr, " Failed to covert %s profile message\n " , type);
94+ return ;
8595 }
86- WriteCoverage (result);
96+
97+ connection_->WriteProfile (message_str);
8798}
8899
89- bool V8CoverageConnection::WriteCoverage (Local<String> message) {
90- const std::string& directory = env ()->coverage_directory ();
91- CHECK (!directory.empty ());
100+ static bool EnsureDirectory (const std::string& directory, const char * type) {
92101 uv_fs_t req;
93102 int ret = fs::MKDirpSync (nullptr , &req, directory, 0777 , nullptr );
94103 uv_fs_req_cleanup (&req);
95104 if (ret < 0 && ret != UV_EEXIST) {
96105 char err_buf[128 ];
97106 uv_err_name_r (ret, err_buf, sizeof (err_buf));
98107 fprintf (stderr,
99- " %s: Failed to create coverage directory %s\n " ,
108+ " %s: Failed to create %s profile directory %s\n " ,
100109 err_buf,
110+ type,
101111 directory.c_str ());
102112 return false ;
103113 }
114+ return true ;
115+ }
104116
117+ std::string V8CoverageConnection::GetFilename () const {
105118 std::string thread_id = std::to_string (env ()->thread_id ());
106119 std::string pid = std::to_string (uv_os_getpid ());
107120 std::string timestamp = std::to_string (
@@ -113,44 +126,79 @@ bool V8CoverageConnection::WriteCoverage(Local<String> message) {
113126 pid.c_str (),
114127 timestamp.c_str (),
115128 thread_id.c_str ());
116- std::string target = directory + kPathSeparator + filename;
117- MaybeLocal<String> result = GetResult (message);
118- if (result.IsEmpty ()) {
119- return false ;
120- }
121- return WriteResult (target.c_str (), result.ToLocalChecked ());
129+ return filename;
122130}
123131
124- MaybeLocal<String> V8CoverageConnection::GetResult (Local<String> message) {
125- Local<Context> context = env ()->context ();
126- Isolate* isolate = env ()->isolate ();
132+ static MaybeLocal<Object> ParseProfile (Environment* env,
133+ Local<String> message,
134+ const char * type) {
135+ Local<Context> context = env->context ();
136+ Isolate* isolate = env->isolate ();
137+
138+ // Get message.result from the response
127139 Local<Value> parsed;
128140 if (!v8::JSON::Parse (context, message).ToLocal (&parsed) ||
129141 !parsed->IsObject ()) {
130- fprintf (stderr, " Failed to parse coverage result as JSON object\n " );
131- return MaybeLocal<String >();
142+ fprintf (stderr, " Failed to parse %s profile result as JSON object\n " , type );
143+ return MaybeLocal<Object >();
132144 }
133145
134146 Local<Value> result_v;
135147 if (!parsed.As <Object>()
136148 ->Get (context, FIXED_ONE_BYTE_STRING (isolate, " result" ))
137149 .ToLocal (&result_v)) {
138- fprintf (stderr, " Failed to get result from coverage message\n " );
139- return MaybeLocal<String >();
150+ fprintf (stderr, " Failed to get ' result' from %s profile message\n " , type );
151+ return MaybeLocal<Object >();
140152 }
141153
142- if (result_v->IsUndefined ()) {
143- fprintf (stderr, " 'result' from coverage message is undefined\n " );
144- return MaybeLocal<String>();
154+ if (!result_v->IsObject ()) {
155+ fprintf (
156+ stderr, " 'result' from %s profile message is not an object\n " , type);
157+ return MaybeLocal<Object>();
145158 }
146159
160+ return result_v.As <Object>();
161+ }
162+
163+ void V8ProfilerConnection::WriteProfile (Local<String> message) {
164+ Local<Context> context = env_->context ();
165+
166+ // Get message.result from the response.
167+ Local<Object> result;
168+ if (!ParseProfile (env_, message, type ()).ToLocal (&result)) {
169+ return ;
170+ }
171+ // Generate the profile output from the subclass.
172+ Local<Object> profile;
173+ if (!GetProfile (result).ToLocal (&profile)) {
174+ return ;
175+ }
147176 Local<String> result_s;
148- if (!v8::JSON::Stringify (context, result_v ).ToLocal (&result_s)) {
149- fprintf (stderr, " Failed to stringify coverage result\n " );
150- return MaybeLocal<String>() ;
177+ if (!v8::JSON::Stringify (context, profile ).ToLocal (&result_s)) {
178+ fprintf (stderr, " Failed to stringify %s profile result\n " , type () );
179+ return ;
151180 }
152181
153- return result_s;
182+ // Create the directory if necessary.
183+ std::string directory = GetDirectory ();
184+ DCHECK (!directory.empty ());
185+ if (!EnsureDirectory (directory, type ())) {
186+ return ;
187+ }
188+
189+ std::string filename = GetFilename ();
190+ DCHECK (!filename.empty ());
191+ std::string path = directory + kPathSeparator + filename;
192+
193+ WriteResult (env_, path.c_str (), result_s);
194+ }
195+
196+ MaybeLocal<Object> V8CoverageConnection::GetProfile (Local<Object> result) {
197+ return result;
198+ }
199+
200+ std::string V8CoverageConnection::GetDirectory () const {
201+ return env ()->coverage_directory ();
154202}
155203
156204void V8CoverageConnection::Start () {
@@ -184,92 +232,28 @@ void V8CoverageConnection::End() {
184232 DispatchMessage (end);
185233}
186234
187- void V8CpuProfilerConnection::OnMessage (
188- const v8_inspector::StringView& message) {
189- Debug (env (),
190- DebugCategory::INSPECTOR_PROFILER,
191- " Receive cpu profiling message, ending = %s\n " ,
192- ending_ ? " true" : " false" );
193- if (!ending_) {
194- return ;
195- }
196- Isolate* isolate = env ()->isolate ();
197- HandleScope handle_scope (isolate);
198- Local<Context> context = env ()->context ();
199- Context::Scope context_scope (context);
200- Local<String> result;
201- if (!String::NewFromTwoByte (isolate,
202- message.characters16 (),
203- NewStringType::kNormal ,
204- message.length ())
205- .ToLocal (&result)) {
206- fprintf (stderr, " Failed to convert profiling message\n " );
207- }
208- WriteCpuProfile (result);
235+ std::string V8CpuProfilerConnection::GetDirectory () const {
236+ return env ()->cpu_prof_dir ();
209237}
210238
211- void V8CpuProfilerConnection::WriteCpuProfile (Local<String> message) {
212- const std::string& filename = env ()->cpu_prof_name ();
213- const std::string& directory = env ()->cpu_prof_dir ();
214- CHECK (!filename.empty ());
215- CHECK (!directory.empty ());
216- uv_fs_t req;
217- int ret = fs::MKDirpSync (nullptr , &req, directory, 0777 , nullptr );
218- uv_fs_req_cleanup (&req);
219- if (ret < 0 && ret != UV_EEXIST) {
220- char err_buf[128 ];
221- uv_err_name_r (ret, err_buf, sizeof (err_buf));
222- fprintf (stderr,
223- " %s: Failed to create cpu profile directory %s\n " ,
224- err_buf,
225- directory.c_str ());
226- return ;
227- }
228- MaybeLocal<String> result = GetResult (message);
229- std::string target = directory + kPathSeparator + filename;
230- if (!result.IsEmpty ()) {
231- WriteResult (target.c_str (), result.ToLocalChecked ());
232- }
239+ std::string V8CpuProfilerConnection::GetFilename () const {
240+ return env ()->cpu_prof_name ();
233241}
234242
235- MaybeLocal<String> V8CpuProfilerConnection::GetResult (Local<String> message) {
236- Local<Context> context = env ()->context ();
237- Isolate* isolate = env ()->isolate ();
238- Local<Value> parsed;
239- if (!v8::JSON::Parse (context, message).ToLocal (&parsed) ||
240- !parsed->IsObject ()) {
241- fprintf (stderr, " Failed to parse CPU profile result as JSON object\n " );
242- return MaybeLocal<String>();
243- }
244-
245- Local<Value> result_v;
246- if (!parsed.As <Object>()
247- ->Get (context, FIXED_ONE_BYTE_STRING (isolate, " result" ))
248- .ToLocal (&result_v)) {
249- fprintf (stderr, " Failed to get result from CPU profile message\n " );
250- return MaybeLocal<String>();
251- }
252-
253- if (!result_v->IsObject ()) {
254- fprintf (stderr, " 'result' from CPU profile message is not an object\n " );
255- return MaybeLocal<String>();
256- }
257-
243+ MaybeLocal<Object> V8CpuProfilerConnection::GetProfile (Local<Object> result) {
258244 Local<Value> profile_v;
259- if (!result_v.As <Object>()
260- ->Get (context, FIXED_ONE_BYTE_STRING (isolate, " profile" ))
245+ if (!result
246+ ->Get (env ()->context (),
247+ FIXED_ONE_BYTE_STRING (env ()->isolate (), " profile" ))
261248 .ToLocal (&profile_v)) {
262249 fprintf (stderr, " 'profile' from CPU profile result is undefined\n " );
263- return MaybeLocal<String >();
250+ return MaybeLocal<Object >();
264251 }
265-
266- Local<String> result_s;
267- if (!v8::JSON::Stringify (context, profile_v).ToLocal (&result_s)) {
268- fprintf (stderr, " Failed to stringify CPU profile result\n " );
269- return MaybeLocal<String>();
252+ if (!profile_v->IsObject ()) {
253+ fprintf (stderr, " 'profile' from CPU profile result is not an Object\n " );
254+ return MaybeLocal<Object>();
270255 }
271-
272- return result_s;
256+ return profile_v.As <Object>();
273257}
274258
275259void V8CpuProfilerConnection::Start () {
@@ -298,16 +282,16 @@ void V8CpuProfilerConnection::End() {
298282// in the future.
299283void EndStartedProfilers (Environment* env) {
300284 Debug (env, DebugCategory::INSPECTOR_PROFILER, " EndStartedProfilers\n " );
301- V8ProfilerConnection* connection = env->coverage_connection ();
285+ V8ProfilerConnection* connection = env->cpu_profiler_connection ();
302286 if (connection != nullptr && !connection->ending ()) {
303- Debug (
304- env, DebugCategory::INSPECTOR_PROFILER, " Ending coverage collection\n " );
287+ Debug (env, DebugCategory::INSPECTOR_PROFILER, " Ending cpu profiling\n " );
305288 connection->End ();
306289 }
307290
308- connection = env->cpu_profiler_connection ();
291+ connection = env->coverage_connection ();
309292 if (connection != nullptr && !connection->ending ()) {
310- Debug (env, DebugCategory::INSPECTOR_PROFILER, " Ending cpu profiling\n " );
293+ Debug (
294+ env, DebugCategory::INSPECTOR_PROFILER, " Ending coverage collection\n " );
311295 connection->End ();
312296 }
313297}
0 commit comments