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