@@ -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,107 @@ 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 AliasedBuffer<uint32_t , v8::Uint32Array>& observers =
4589 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);
5097 }
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 ();
5798}
5899
100+ // Create a User Timing Mark
59101void Mark (const FunctionCallbackInfo<Value>& args) {
60102 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 ]);
64105 uint64_t now = PERFORMANCE_NOW ();
65106 auto marks = env->performance_marks ();
66107 (*marks)[*name] = now;
67108
68109 // TODO(jasnell): Once Tracing API is fully implemented, this should
69110 // record a trace event also.
70111
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 );
74115 args.GetReturnValue ().Set (obj);
75116}
76117
118+
77119inline uint64_t GetPerformanceMark (Environment* env, std::string name) {
78120 auto marks = env->performance_marks ();
79121 auto res = marks->find (name);
80122 return res != marks->end () ? res->second : 0 ;
81123}
82124
125+ // Create a User Timing Measure. A Measure is a PerformanceEntry that
126+ // measures the duration between two distinct user timing marks
83127void Measure (const FunctionCallbackInfo<Value>& args) {
84128 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 ]);
90133
91134 AliasedBuffer<double , v8::Float64Array>& milestones =
92135 env->performance_state ()->milestones ;
@@ -114,41 +157,13 @@ void Measure(const FunctionCallbackInfo<Value>& args) {
114157 // TODO(jasnell): Once Tracing API is fully implemented, this should
115158 // record a trace event also.
116159
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);
121163 args.GetReturnValue ().Set (obj);
122164}
123165
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
152167void MarkMilestone (const FunctionCallbackInfo<Value>& args) {
153168 Environment* env = Environment::GetCurrent (args);
154169 Local<Context> context = env->context ();
@@ -162,74 +177,64 @@ void MarkMilestone(const FunctionCallbackInfo<Value>& args) {
162177 }
163178}
164179
180+
165181void SetupPerformanceObservers (const FunctionCallbackInfo<Value>& args) {
166182 Environment* env = Environment::GetCurrent (args);
167183 CHECK (args[0 ]->IsFunction ());
168184 env->set_performance_entry_callback (args[0 ].As <Function>());
169185}
170186
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 ());
177191 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 ());
182192
183193 AliasedBuffer<uint32_t , v8::Uint32Array>& observers =
184194 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);
187204 }
188205
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;
202207}
203208
209+ // Marks the start of a GC cycle
204210void MarkGarbageCollectionStart (Isolate* isolate,
205211 v8::GCType type,
206212 v8::GCCallbackFlags flags) {
207213 performance_last_gc_start_mark_ = PERFORMANCE_NOW ();
208214 performance_last_gc_type_ = type;
209215}
210216
217+ // Marks the end of a GC cycle
211218void MarkGarbageCollectionEnd (Isolate* isolate,
212219 v8::GCType type,
213220 v8::GCCallbackFlags flags,
214221 void * data) {
215222 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 ()));
225228}
226229
230+
227231inline void SetupGarbageCollectionTracking (Environment* env) {
228232 env->isolate ()->AddGCPrologueCallback (MarkGarbageCollectionStart);
229233 env->isolate ()->AddGCEpilogueCallback (MarkGarbageCollectionEnd,
230234 static_cast <void *>(env));
231235}
232236
237+ // Gets the name of a function
233238inline Local<Value> GetName (Local<Function> fn) {
234239 Local<Value> val = fn->GetDebugName ();
235240 if (val.IsEmpty () || val->IsUndefined ()) {
@@ -241,6 +246,9 @@ inline Local<Value> GetName(Local<Function> fn) {
241246 return val;
242247}
243248
249+ // Executes a wrapped Function and captures timing information, causing a
250+ // Function PerformanceEntry to be emitted to PerformanceObservers after
251+ // execution.
244252void TimerFunctionCall (const FunctionCallbackInfo<Value>& args) {
245253 Isolate* isolate = args.GetIsolate ();
246254 HandleScope scope (isolate);
@@ -250,9 +258,8 @@ void TimerFunctionCall(const FunctionCallbackInfo<Value>& args) {
250258 size_t count = args.Length ();
251259 size_t idx;
252260 std::vector<Local<Value>> call_args;
253- for (size_t i = 0 ; i < count; ++i) {
261+ for (size_t i = 0 ; i < count; ++i)
254262 call_args.push_back (args[i]);
255- }
256263
257264 Utf8Value name (isolate, GetName (fn));
258265
@@ -289,15 +296,14 @@ void TimerFunctionCall(const FunctionCallbackInfo<Value>& args) {
289296 if (!observers[NODE_PERFORMANCE_ENTRY_TYPE_FUNCTION])
290297 return ;
291298
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);
299304}
300305
306+ // Wraps a Function in a TimerFunctionCall
301307void Timerify (const FunctionCallbackInfo<Value>& args) {
302308 Environment* env = Environment::GetCurrent (args);
303309 Local<Context> context = env->context ();
@@ -310,6 +316,7 @@ void Timerify(const FunctionCallbackInfo<Value>& args) {
310316 args.GetReturnValue ().Set (wrap);
311317}
312318
319+
313320void Init (Local<Object> target,
314321 Local<Value> unused,
315322 Local<Context> context) {
@@ -328,55 +335,10 @@ void Init(Local<Object> target,
328335 Local<String> performanceEntryString =
329336 FIXED_ONE_BYTE_STRING (isolate, " PerformanceEntry" );
330337
331- Local<FunctionTemplate> pe = env->NewFunctionTemplate (PerformanceEntry::New);
332- pe->InstanceTemplate ()->SetInternalFieldCount (1 );
338+ Local<FunctionTemplate> pe = FunctionTemplate::New (isolate);
333339 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-
378340 Local<Function> fn = pe->GetFunction ();
379- target->Set (performanceEntryString, fn);
341+ target->Set (context, performanceEntryString, fn). FromJust ( );
380342 env->set_performance_entry_template (fn);
381343
382344 env->SetMethod (target, " mark" , Mark);
0 commit comments