@@ -17,9 +17,8 @@ using v8::Integer;
1717using v8::Isolate;
1818using v8::Local;
1919using v8::Name;
20+ using v8::Number;
2021using v8::Object;
21- using v8::ObjectTemplate;
22- using v8::Signature;
2322using v8::String;
2423using v8::Value;
2524
@@ -30,63 +29,106 @@ uint64_t performance_v8_start;
3029uint64_t performance_last_gc_start_mark_ = 0 ;
3130v8::GCType performance_last_gc_type_ = v8::GCType::kGCTypeAll ;
3231
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
3371void PerformanceEntry::New (const FunctionCallbackInfo<Value>& args) {
3472 Environment* env = Environment::GetCurrent (args);
3573 Isolate* isolate = env->isolate ();
3674 Utf8Value name (isolate, args[0 ]);
3775 Utf8Value type (isolate, args[1 ]);
3876 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);
4081}
4182
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 ());
4488 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);
5096 }
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 ();
5797}
5898
99+ // Create a User Timing Mark
59100void Mark (const FunctionCallbackInfo<Value>& args) {
60101 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 ]);
64104 uint64_t now = PERFORMANCE_NOW ();
65105 auto marks = env->performance_marks ();
66106 (*marks)[*name] = now;
67107
68108 // TODO(jasnell): Once Tracing API is fully implemented, this should
69109 // record a trace event also.
70110
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 );
74114 args.GetReturnValue ().Set (obj);
75115}
76116
117+
77118inline uint64_t GetPerformanceMark (Environment* env, std::string name) {
78119 auto marks = env->performance_marks ();
79120 auto res = marks->find (name);
80121 return res != marks->end () ? res->second : 0 ;
81122}
82123
124+ // Create a User Timing Measure. A Measure is a PerformanceEntry that
125+ // measures the duration between two distinct user timing marks
83126void Measure (const FunctionCallbackInfo<Value>& args) {
84127 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 ]);
90132
91133 double * milestones = env->performance_state ()->milestones ;
92134
@@ -113,41 +155,13 @@ void Measure(const FunctionCallbackInfo<Value>& args) {
113155 // TODO(jasnell): Once Tracing API is fully implemented, this should
114156 // record a trace event also.
115157
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);
120161 args.GetReturnValue ().Set (obj);
121162}
122163
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
151165void MarkMilestone (const FunctionCallbackInfo<Value>& args) {
152166 Environment* env = Environment::GetCurrent (args);
153167 Local<Context> context = env->context ();
@@ -160,73 +174,63 @@ void MarkMilestone(const FunctionCallbackInfo<Value>& args) {
160174 }
161175}
162176
177+
163178void SetupPerformanceObservers (const FunctionCallbackInfo<Value>& args) {
164179 Environment* env = Environment::GetCurrent (args);
165180 CHECK (args[0 ]->IsFunction ());
166181 env->set_performance_entry_callback (args[0 ].As <Function>());
167182}
168183
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 ());
175188 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 ());
180189
181190 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);
184200 }
185201
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;
199203}
200204
205+ // Marks the start of a GC cycle
201206void MarkGarbageCollectionStart (Isolate* isolate,
202207 v8::GCType type,
203208 v8::GCCallbackFlags flags) {
204209 performance_last_gc_start_mark_ = PERFORMANCE_NOW ();
205210 performance_last_gc_type_ = type;
206211}
207212
213+ // Marks the end of a GC cycle
208214void MarkGarbageCollectionEnd (Isolate* isolate,
209215 v8::GCType type,
210216 v8::GCCallbackFlags flags,
211217 void * data) {
212218 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 ()));
222224}
223225
226+
224227inline void SetupGarbageCollectionTracking (Environment* env) {
225228 env->isolate ()->AddGCPrologueCallback (MarkGarbageCollectionStart);
226229 env->isolate ()->AddGCEpilogueCallback (MarkGarbageCollectionEnd,
227230 static_cast <void *>(env));
228231}
229232
233+ // Gets the name of a function
230234inline Local<Value> GetName (Local<Function> fn) {
231235 Local<Value> val = fn->GetDebugName ();
232236 if (val.IsEmpty () || val->IsUndefined ()) {
@@ -238,6 +242,9 @@ inline Local<Value> GetName(Local<Function> fn) {
238242 return val;
239243}
240244
245+ // Executes a wrapped Function and captures timing information, causing a
246+ // Function PerformanceEntry to be emitted to PerformanceObservers after
247+ // execution.
241248void TimerFunctionCall (const FunctionCallbackInfo<Value>& args) {
242249 Isolate* isolate = args.GetIsolate ();
243250 HandleScope scope (isolate);
@@ -247,9 +254,8 @@ void TimerFunctionCall(const FunctionCallbackInfo<Value>& args) {
247254 size_t count = args.Length ();
248255 size_t idx;
249256 std::vector<Local<Value>> call_args;
250- for (size_t i = 0 ; i < count; ++i) {
257+ for (size_t i = 0 ; i < count; ++i)
251258 call_args.push_back (args[i]);
252- }
253259
254260 Utf8Value name (isolate, GetName (fn));
255261
@@ -286,15 +292,14 @@ void TimerFunctionCall(const FunctionCallbackInfo<Value>& args) {
286292 if (!observers[NODE_PERFORMANCE_ENTRY_TYPE_FUNCTION])
287293 return ;
288294
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);
296300}
297301
302+ // Wraps a Function in a TimerFunctionCall
298303void Timerify (const FunctionCallbackInfo<Value>& args) {
299304 Environment* env = Environment::GetCurrent (args);
300305 Local<Context> context = env->context ();
@@ -307,6 +312,7 @@ void Timerify(const FunctionCallbackInfo<Value>& args) {
307312 args.GetReturnValue ().Set (wrap);
308313}
309314
315+
310316void Init (Local<Object> target,
311317 Local<Value> unused,
312318 Local<Context> context) {
@@ -329,55 +335,10 @@ void Init(Local<Object> target,
329335 Local<String> performanceEntryString =
330336 FIXED_ONE_BYTE_STRING (isolate, " PerformanceEntry" );
331337
332- Local<FunctionTemplate> pe = env->NewFunctionTemplate (PerformanceEntry::New);
333- pe->InstanceTemplate ()->SetInternalFieldCount (1 );
338+ Local<FunctionTemplate> pe = FunctionTemplate::New (isolate);
334339 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-
379340 Local<Function> fn = pe->GetFunction ();
380- target->Set (performanceEntryString, fn);
341+ target->Set (context, performanceEntryString, fn). FromJust ( );
381342 env->set_performance_entry_template (fn);
382343
383344 env->SetMethod (target, " mark" , Mark);
0 commit comments