@@ -17,9 +17,8 @@ using v8::Integer;
17
17
using v8::Isolate;
18
18
using v8::Local;
19
19
using v8::Name;
20
+ using v8::Number;
20
21
using v8::Object;
21
- using v8::ObjectTemplate;
22
- using v8::Signature;
23
22
using v8::String;
24
23
using v8::Value;
25
24
@@ -30,63 +29,107 @@ uint64_t performance_v8_start;
30
29
uint64_t performance_last_gc_start_mark_ = 0 ;
31
30
v8::GCType performance_last_gc_type_ = v8::GCType::kGCTypeAll ;
32
31
32
+ // Initialize the performance entry object properties
33
+ inline void InitObject (const PerformanceEntry& entry, Local<Object> obj) {
34
+ Environment* env = entry.env ();
35
+ Isolate* isolate = env->isolate ();
36
+ Local<Context> context = env->context ();
37
+ v8::PropertyAttribute attr =
38
+ static_cast <v8::PropertyAttribute>(v8::ReadOnly | v8::DontDelete);
39
+ obj->DefineOwnProperty (context,
40
+ env->name_string (),
41
+ String::NewFromUtf8 (isolate,
42
+ entry.name ().c_str (),
43
+ String::kNormalString ),
44
+ attr).FromJust ();
45
+ obj->DefineOwnProperty (context,
46
+ FIXED_ONE_BYTE_STRING (isolate, " entryType" ),
47
+ String::NewFromUtf8 (isolate,
48
+ entry.type ().c_str (),
49
+ String::kNormalString ),
50
+ attr).FromJust ();
51
+ obj->DefineOwnProperty (context,
52
+ FIXED_ONE_BYTE_STRING (isolate, " startTime" ),
53
+ Number::New (isolate, entry.startTime ()),
54
+ attr).FromJust ();
55
+ obj->DefineOwnProperty (context,
56
+ FIXED_ONE_BYTE_STRING (isolate, " duration" ),
57
+ Number::New (isolate, entry.duration ()),
58
+ attr).FromJust ();
59
+ }
60
+
61
+ // Create a new PerformanceEntry object
62
+ const Local<Object> PerformanceEntry::ToObject () const {
63
+ Local<Object> obj =
64
+ env_->performance_entry_template ()
65
+ ->NewInstance (env_->context ()).ToLocalChecked ();
66
+ InitObject (*this , obj);
67
+ return obj;
68
+ }
69
+
70
+ // Allow creating a PerformanceEntry object from JavaScript
33
71
void PerformanceEntry::New (const FunctionCallbackInfo<Value>& args) {
34
72
Environment* env = Environment::GetCurrent (args);
35
73
Isolate* isolate = env->isolate ();
36
74
Utf8Value name (isolate, args[0 ]);
37
75
Utf8Value type (isolate, args[1 ]);
38
76
uint64_t now = PERFORMANCE_NOW ();
39
- new PerformanceEntry (env, args.This (), *name, *type, now, now);
77
+ PerformanceEntry entry (env, *name, *type, now, now);
78
+ Local<Object> obj = args.This ();
79
+ InitObject (entry, obj);
80
+ PerformanceEntry::Notify (env, entry.kind (), obj);
40
81
}
41
82
42
- void PerformanceEntry::NotifyObservers (Environment* env,
43
- PerformanceEntry* entry) {
83
+ // Pass the PerformanceEntry object to the PerformanceObservers
84
+ inline void PerformanceEntry::Notify (Environment* env,
85
+ PerformanceEntryType type,
86
+ Local<Value> object) {
87
+ Context::Scope scope (env->context ());
44
88
AliasedBuffer<uint32_t , v8::Uint32Array>& observers =
45
89
env->performance_state ()->observers ;
46
- PerformanceEntryType type = ToPerformanceEntryTypeEnum (entry->type ().c_str ());
47
- if (type == NODE_PERFORMANCE_ENTRY_TYPE_INVALID ||
48
- !observers[type]) {
49
- return ;
90
+ if (observers != nullptr &&
91
+ type != NODE_PERFORMANCE_ENTRY_TYPE_INVALID &&
92
+ observers[type]) {
93
+ node::MakeCallback (env->isolate (),
94
+ env->process_object (),
95
+ env->performance_entry_callback (),
96
+ 1 , &object);
50
97
}
51
- Local<Context> context = env->context ();
52
- Isolate* isolate = env->isolate ();
53
- Local<Value> argv = entry->object ();
54
- env->performance_entry_callback ()->Call (context,
55
- v8::Undefined (isolate),
56
- 1 , &argv).ToLocalChecked ();
57
98
}
58
99
100
+ // Create a User Timing Mark
59
101
void Mark (const FunctionCallbackInfo<Value>& args) {
60
102
Environment* env = Environment::GetCurrent (args);
61
- Local<Context> context = env->context ();
62
- Isolate* isolate = env->isolate ();
63
- Utf8Value name (isolate, args[0 ]);
103
+ HandleScope scope (env->isolate ());
104
+ Utf8Value name (env->isolate (), args[0 ]);
64
105
uint64_t now = PERFORMANCE_NOW ();
65
106
auto marks = env->performance_marks ();
66
107
(*marks)[*name] = now;
67
108
68
109
// TODO(jasnell): Once Tracing API is fully implemented, this should
69
110
// record a trace event also.
70
111
71
- Local<Function> fn = env-> performance_entry_template ( );
72
- Local<Object> obj = fn-> NewInstance (context). ToLocalChecked ();
73
- new PerformanceEntry (env, obj, *name, " mark " , now, now );
112
+ PerformanceEntry entry (env, *name, " mark " , now, now );
113
+ Local<Object> obj = entry. ToObject ();
114
+ PerformanceEntry::Notify (env, entry. kind (), obj );
74
115
args.GetReturnValue ().Set (obj);
75
116
}
76
117
118
+
77
119
inline uint64_t GetPerformanceMark (Environment* env, std::string name) {
78
120
auto marks = env->performance_marks ();
79
121
auto res = marks->find (name);
80
122
return res != marks->end () ? res->second : 0 ;
81
123
}
82
124
125
+ // Create a User Timing Measure. A Measure is a PerformanceEntry that
126
+ // measures the duration between two distinct user timing marks
83
127
void Measure (const FunctionCallbackInfo<Value>& args) {
84
128
Environment* env = Environment::GetCurrent (args);
85
- Local<Context> context = env->context ();
86
- Isolate* isolate = env->isolate ();
87
- Utf8Value name (isolate, args[0 ]);
88
- Utf8Value startMark (isolate, args[1 ]);
89
- Utf8Value endMark (isolate, args[2 ]);
129
+ HandleScope scope (env->isolate ());
130
+ Utf8Value name (env->isolate (), args[0 ]);
131
+ Utf8Value startMark (env->isolate (), args[1 ]);
132
+ Utf8Value endMark (env->isolate (), args[2 ]);
90
133
91
134
AliasedBuffer<double , v8::Float64Array>& milestones =
92
135
env->performance_state ()->milestones ;
@@ -114,41 +157,13 @@ void Measure(const FunctionCallbackInfo<Value>& args) {
114
157
// TODO(jasnell): Once Tracing API is fully implemented, this should
115
158
// record a trace event also.
116
159
117
- Local<Function> fn = env->performance_entry_template ();
118
- Local<Object> obj = fn->NewInstance (context).ToLocalChecked ();
119
- new PerformanceEntry (env, obj, *name, " measure" ,
120
- startTimestamp, endTimestamp);
160
+ PerformanceEntry entry (env, *name, " measure" , startTimestamp, endTimestamp);
161
+ Local<Object> obj = entry.ToObject ();
162
+ PerformanceEntry::Notify (env, entry.kind (), obj);
121
163
args.GetReturnValue ().Set (obj);
122
164
}
123
165
124
- void GetPerformanceEntryName (const FunctionCallbackInfo<Value>& info) {
125
- Isolate* isolate = info.GetIsolate ();
126
- PerformanceEntry* entry;
127
- ASSIGN_OR_RETURN_UNWRAP (&entry, info.Holder ());
128
- info.GetReturnValue ().Set (
129
- String::NewFromUtf8 (isolate, entry->name ().c_str (), String::kNormalString ));
130
- }
131
-
132
- void GetPerformanceEntryType (const FunctionCallbackInfo<Value>& info) {
133
- Isolate* isolate = info.GetIsolate ();
134
- PerformanceEntry* entry;
135
- ASSIGN_OR_RETURN_UNWRAP (&entry, info.Holder ());
136
- info.GetReturnValue ().Set (
137
- String::NewFromUtf8 (isolate, entry->type ().c_str (), String::kNormalString ));
138
- }
139
-
140
- void GetPerformanceEntryStartTime (const FunctionCallbackInfo<Value>& info) {
141
- PerformanceEntry* entry;
142
- ASSIGN_OR_RETURN_UNWRAP (&entry, info.Holder ());
143
- info.GetReturnValue ().Set (entry->startTime ());
144
- }
145
-
146
- void GetPerformanceEntryDuration (const FunctionCallbackInfo<Value>& info) {
147
- PerformanceEntry* entry;
148
- ASSIGN_OR_RETURN_UNWRAP (&entry, info.Holder ());
149
- info.GetReturnValue ().Set (entry->duration ());
150
- }
151
-
166
+ // Allows specific Node.js lifecycle milestones to be set from JavaScript
152
167
void MarkMilestone (const FunctionCallbackInfo<Value>& args) {
153
168
Environment* env = Environment::GetCurrent (args);
154
169
Local<Context> context = env->context ();
@@ -162,74 +177,64 @@ void MarkMilestone(const FunctionCallbackInfo<Value>& args) {
162
177
}
163
178
}
164
179
180
+
165
181
void SetupPerformanceObservers (const FunctionCallbackInfo<Value>& args) {
166
182
Environment* env = Environment::GetCurrent (args);
167
183
CHECK (args[0 ]->IsFunction ());
168
184
env->set_performance_entry_callback (args[0 ].As <Function>());
169
185
}
170
186
171
- void PerformanceGCCallback (uv_async_t * handle) {
172
- PerformanceEntry::Data* data =
173
- static_cast <PerformanceEntry::Data*>(handle->data );
174
- Environment* env = data->env ();
175
- Isolate* isolate = env->isolate ();
176
- HandleScope scope (isolate);
187
+ // Creates a GC Performance Entry and passes it to observers
188
+ void PerformanceGCCallback (Environment* env, void * ptr) {
189
+ GCPerformanceEntry* entry = static_cast <GCPerformanceEntry*>(ptr);
190
+ HandleScope scope (env->isolate ());
177
191
Local<Context> context = env->context ();
178
- Context::Scope context_scope (context);
179
- Local<Function> fn;
180
- Local<Object> obj;
181
- PerformanceGCKind kind = static_cast <PerformanceGCKind>(data->data ());
182
192
183
193
AliasedBuffer<uint32_t , v8::Uint32Array>& observers =
184
194
env->performance_state ()->observers ;
185
- if (!observers[NODE_PERFORMANCE_ENTRY_TYPE_GC]) {
186
- goto cleanup;
195
+ if (observers[NODE_PERFORMANCE_ENTRY_TYPE_GC]) {
196
+ Local<Object> obj = entry->ToObject ();
197
+ v8::PropertyAttribute attr =
198
+ static_cast <v8::PropertyAttribute>(v8::ReadOnly | v8::DontDelete);
199
+ obj->DefineOwnProperty (context,
200
+ FIXED_ONE_BYTE_STRING (env->isolate (), " kind" ),
201
+ Integer::New (env->isolate (), entry->gckind ()),
202
+ attr).FromJust ();
203
+ PerformanceEntry::Notify (env, entry->kind (), obj);
187
204
}
188
205
189
- fn = env->performance_entry_template ();
190
- obj = fn->NewInstance (context).ToLocalChecked ();
191
- obj->Set (context,
192
- FIXED_ONE_BYTE_STRING (isolate, " kind" ),
193
- Integer::New (isolate, kind)).FromJust ();
194
- new PerformanceEntry (env, obj, data);
195
-
196
- cleanup:
197
- delete data;
198
- auto closeCB = [](uv_handle_t * handle) {
199
- delete reinterpret_cast <uv_async_t *>(handle);
200
- };
201
- uv_close (reinterpret_cast <uv_handle_t *>(handle), closeCB);
206
+ delete entry;
202
207
}
203
208
209
+ // Marks the start of a GC cycle
204
210
void MarkGarbageCollectionStart (Isolate* isolate,
205
211
v8::GCType type,
206
212
v8::GCCallbackFlags flags) {
207
213
performance_last_gc_start_mark_ = PERFORMANCE_NOW ();
208
214
performance_last_gc_type_ = type;
209
215
}
210
216
217
+ // Marks the end of a GC cycle
211
218
void MarkGarbageCollectionEnd (Isolate* isolate,
212
219
v8::GCType type,
213
220
v8::GCCallbackFlags flags,
214
221
void * data) {
215
222
Environment* env = static_cast <Environment*>(data);
216
- uv_async_t * async = new uv_async_t (); // coverity[leaked_storage]
217
- if (uv_async_init (env->event_loop (), async, PerformanceGCCallback))
218
- return delete async;
219
- uv_unref (reinterpret_cast <uv_handle_t *>(async));
220
- async->data =
221
- new PerformanceEntry::Data (env, " gc" , " gc" ,
222
- performance_last_gc_start_mark_,
223
- PERFORMANCE_NOW (), type);
224
- CHECK_EQ (0 , uv_async_send (async));
223
+ env->SetImmediate (PerformanceGCCallback,
224
+ new GCPerformanceEntry (env,
225
+ static_cast <PerformanceGCKind>(type),
226
+ performance_last_gc_start_mark_,
227
+ PERFORMANCE_NOW ()));
225
228
}
226
229
230
+
227
231
inline void SetupGarbageCollectionTracking (Environment* env) {
228
232
env->isolate ()->AddGCPrologueCallback (MarkGarbageCollectionStart);
229
233
env->isolate ()->AddGCEpilogueCallback (MarkGarbageCollectionEnd,
230
234
static_cast <void *>(env));
231
235
}
232
236
237
+ // Gets the name of a function
233
238
inline Local<Value> GetName (Local<Function> fn) {
234
239
Local<Value> val = fn->GetDebugName ();
235
240
if (val.IsEmpty () || val->IsUndefined ()) {
@@ -241,6 +246,9 @@ inline Local<Value> GetName(Local<Function> fn) {
241
246
return val;
242
247
}
243
248
249
+ // Executes a wrapped Function and captures timing information, causing a
250
+ // Function PerformanceEntry to be emitted to PerformanceObservers after
251
+ // execution.
244
252
void TimerFunctionCall (const FunctionCallbackInfo<Value>& args) {
245
253
Isolate* isolate = args.GetIsolate ();
246
254
HandleScope scope (isolate);
@@ -250,9 +258,8 @@ void TimerFunctionCall(const FunctionCallbackInfo<Value>& args) {
250
258
size_t count = args.Length ();
251
259
size_t idx;
252
260
std::vector<Local<Value>> call_args;
253
- for (size_t i = 0 ; i < count; ++i) {
261
+ for (size_t i = 0 ; i < count; ++i)
254
262
call_args.push_back (args[i]);
255
- }
256
263
257
264
Utf8Value name (isolate, GetName (fn));
258
265
@@ -289,15 +296,14 @@ void TimerFunctionCall(const FunctionCallbackInfo<Value>& args) {
289
296
if (!observers[NODE_PERFORMANCE_ENTRY_TYPE_FUNCTION])
290
297
return ;
291
298
292
- Local<Function> ctor = env->performance_entry_template ();
293
- v8::MaybeLocal<Object> instance = ctor->NewInstance (context);
294
- Local<Object> obj = instance.ToLocalChecked ();
295
- for (idx = 0 ; idx < count; idx++) {
296
- obj->Set (context, idx, args[idx]).ToChecked ();
297
- }
298
- new PerformanceEntry (env, obj, *name, " function" , start, end);
299
+ PerformanceEntry entry (env, *name, " function" , start, end);
300
+ Local<Object> obj = entry.ToObject ();
301
+ for (idx = 0 ; idx < count; idx++)
302
+ obj->Set (context, idx, args[idx]).FromJust ();
303
+ PerformanceEntry::Notify (env, entry.kind (), obj);
299
304
}
300
305
306
+ // Wraps a Function in a TimerFunctionCall
301
307
void Timerify (const FunctionCallbackInfo<Value>& args) {
302
308
Environment* env = Environment::GetCurrent (args);
303
309
Local<Context> context = env->context ();
@@ -310,6 +316,7 @@ void Timerify(const FunctionCallbackInfo<Value>& args) {
310
316
args.GetReturnValue ().Set (wrap);
311
317
}
312
318
319
+
313
320
void Init (Local<Object> target,
314
321
Local<Value> unused,
315
322
Local<Context> context) {
@@ -328,55 +335,10 @@ void Init(Local<Object> target,
328
335
Local<String> performanceEntryString =
329
336
FIXED_ONE_BYTE_STRING (isolate, " PerformanceEntry" );
330
337
331
- Local<FunctionTemplate> pe = env->NewFunctionTemplate (PerformanceEntry::New);
332
- pe->InstanceTemplate ()->SetInternalFieldCount (1 );
338
+ Local<FunctionTemplate> pe = FunctionTemplate::New (isolate);
333
339
pe->SetClassName (performanceEntryString);
334
-
335
- Local<Signature> signature = Signature::New (env->isolate (), pe);
336
-
337
- Local<FunctionTemplate> get_performance_entry_name_templ =
338
- FunctionTemplate::New (env->isolate (),
339
- GetPerformanceEntryName,
340
- env->as_external (),
341
- signature);
342
-
343
- Local<FunctionTemplate> get_performance_entry_type_templ =
344
- FunctionTemplate::New (env->isolate (),
345
- GetPerformanceEntryType,
346
- env->as_external (),
347
- signature);
348
-
349
- Local<FunctionTemplate> get_performance_entry_start_time_templ =
350
- FunctionTemplate::New (env->isolate (),
351
- GetPerformanceEntryStartTime,
352
- env->as_external (),
353
- signature);
354
-
355
- Local<FunctionTemplate> get_performance_entry_duration_templ =
356
- FunctionTemplate::New (env->isolate (),
357
- GetPerformanceEntryDuration,
358
- env->as_external (),
359
- signature);
360
-
361
- Local<ObjectTemplate> ot = pe->InstanceTemplate ();
362
- ot->SetAccessorProperty (env->name_string (),
363
- get_performance_entry_name_templ,
364
- Local<FunctionTemplate>());
365
-
366
- ot->SetAccessorProperty (FIXED_ONE_BYTE_STRING (isolate, " entryType" ),
367
- get_performance_entry_type_templ,
368
- Local<FunctionTemplate>());
369
-
370
- ot->SetAccessorProperty (FIXED_ONE_BYTE_STRING (isolate, " startTime" ),
371
- get_performance_entry_start_time_templ,
372
- Local<FunctionTemplate>());
373
-
374
- ot->SetAccessorProperty (FIXED_ONE_BYTE_STRING (isolate, " duration" ),
375
- get_performance_entry_duration_templ,
376
- Local<FunctionTemplate>());
377
-
378
340
Local<Function> fn = pe->GetFunction ();
379
- target->Set (performanceEntryString, fn);
341
+ target->Set (context, performanceEntryString, fn). FromJust ( );
380
342
env->set_performance_entry_template (fn);
381
343
382
344
env->SetMethod (target, " mark" , Mark);
0 commit comments