@@ -330,6 +330,8 @@ class FJavascriptIsolateImplementation : public FJavascriptIsolate
330
330
ExportMemory (ObjectTemplate);
331
331
332
332
ExportMisc (ObjectTemplate);
333
+
334
+ ExportProfiler (ObjectTemplate);
333
335
}
334
336
335
337
~FJavascriptIsolateImplementation ()
@@ -770,6 +772,172 @@ class FJavascriptIsolateImplementation : public FJavascriptIsolate
770
772
ReadOnly);
771
773
}
772
774
775
+ static Local<Object> Visit (Isolate* isolate, const v8::CpuProfileNode* node)
776
+ {
777
+ static TMap<const v8::CpuProfileNode*, Handle<Object>> Visited;
778
+
779
+ if (!isolate)
780
+ {
781
+ Visited.Empty ();
782
+ return Local<Object>();
783
+ }
784
+ auto Existing = Visited.Find (node);
785
+ if (Existing) return *Existing;
786
+
787
+ FIsolateHelper I (isolate);
788
+
789
+ auto Out = Object::New (isolate);
790
+
791
+ Visited.Add (node, Out);
792
+
793
+ Out->Set (I.Keyword (" ScriptResourceName" ), node->GetScriptResourceName ());
794
+ Out->Set (I.Keyword (" FunctionName" ), node->GetFunctionName ());
795
+ Out->Set (I.Keyword (" HitCount" ), Integer::NewFromUnsigned (isolate,node->GetHitCount ()));
796
+ Out->Set (I.Keyword (" LineNumber" ), Integer::New (isolate,node->GetLineNumber ()));
797
+ Out->Set (I.Keyword (" ColumnNumber" ), Integer::New (isolate,node->GetColumnNumber ()));
798
+ Out->Set (I.Keyword (" ScriptId" ), Integer::New (isolate, node->GetScriptId ()));
799
+
800
+ {
801
+ uint32_t Num = node->GetHitLineCount ();
802
+ TArray<v8::CpuProfileNode::LineTick> Buffer;
803
+ Buffer.AddDefaulted (Num);
804
+ node->GetLineTicks (Buffer.GetData (), Num);
805
+
806
+ auto Arr = Array::New (isolate, Num);
807
+ for (uint32_t Index = 0 ; Index < Num; ++Index)
808
+ {
809
+ const auto & info = Buffer[Index];
810
+ auto item = Object::New (isolate);
811
+ item->Set (I.Keyword (" line" ), Integer::New (isolate,info.line ));
812
+ item->Set (I.Keyword (" hit_count" ), Integer::New (isolate, info.hit_count ));
813
+ Arr->Set (Index, item);
814
+ }
815
+ Out->Set (I.Keyword (" LineTicks" ), Arr);
816
+ }
817
+
818
+ auto BailOutReason = node->GetBailoutReason ();
819
+ if (BailOutReason)
820
+ {
821
+ Out->Set (I.Keyword (" BailOutReason" ), I.Keyword (BailOutReason));
822
+ }
823
+
824
+ {
825
+ const auto & deopt = node->GetDeoptInfos ();
826
+ uint32_t Num = deopt.size ();
827
+ if (Num)
828
+ {
829
+ auto Arr = Array::New (isolate, deopt.size ());
830
+ for (uint32_t Index = 0 ; Index < Num; ++Index)
831
+ {
832
+ const auto & info = deopt[Index];
833
+ FString out;
834
+ for (const auto & frame : info.stack )
835
+ {
836
+ out.Append (FString::Printf (TEXT (" %d:%d " ), (int )frame.script_id , (int )frame.position ));
837
+ }
838
+ auto item = Object::New (isolate);
839
+ item->Set (I.Keyword (" reason" ), I.Keyword (deopt[Index].deopt_reason ));
840
+ item->Set (I.Keyword (" stack" ), I.String (out));
841
+ Arr->Set (Index, item);
842
+ }
843
+ Out->Set (I.Keyword (" DeoptInfos" ), Arr);
844
+ }
845
+ }
846
+
847
+ uint32_t Num = node->GetChildrenCount ();
848
+ if (Num)
849
+ {
850
+ auto Arr = Array::New (isolate, Num);
851
+ for (uint32_t Index = 0 ; Index < Num; ++Index)
852
+ {
853
+ Arr->Set (Index, Visit (isolate, node->GetChild (Index)));
854
+ }
855
+ Out->Set (I.Keyword (" Children" ), Arr);
856
+ }
857
+ return Out;
858
+ };
859
+
860
+ void ExportProfiler (Local<ObjectTemplate> global_templ)
861
+ {
862
+ FIsolateHelper I (isolate_);
863
+
864
+ Local<FunctionTemplate> Template = I.FunctionTemplate ();
865
+
866
+ auto add_fn = [&](const char * name, FunctionCallback fn) {
867
+ Template->PrototypeTemplate ()->Set (I.Keyword (name), I.FunctionTemplate (fn));
868
+ };
869
+
870
+ add_fn (" SetSamplingInterval" , [](const FunctionCallbackInfo<Value>& info)
871
+ {
872
+ FIsolateHelper I (info.GetIsolate ());
873
+
874
+ auto profiler = info.GetIsolate ()->GetCpuProfiler ();
875
+
876
+ if (info.Length () == 1 )
877
+ {
878
+ profiler->SetSamplingInterval (info[0 ]->IntegerValue ());
879
+ }
880
+ });
881
+
882
+ add_fn (" StartProfiling" , [](const FunctionCallbackInfo<Value>& info)
883
+ {
884
+ FIsolateHelper I (info.GetIsolate ());
885
+
886
+ auto profiler = info.GetIsolate ()->GetCpuProfiler ();
887
+
888
+ if (info.Length () == 2 )
889
+ {
890
+ profiler->StartProfiling (info[0 ].As <String>(), info[1 ]->BooleanValue ());
891
+ info.GetReturnValue ().Set (true );
892
+ }
893
+ });
894
+
895
+ add_fn (" StopProfiling" , [](const FunctionCallbackInfo<Value>& info)
896
+ {
897
+ auto isolate = info.GetIsolate ();
898
+ FIsolateHelper I (isolate);
899
+
900
+ auto profiler = isolate->GetCpuProfiler ();
901
+
902
+ if (info.Length () == 1 )
903
+ {
904
+ auto Profile = profiler->StopProfiling (info[0 ].As <String>());
905
+
906
+ auto Out = Object::New (isolate);
907
+ Out->Set (I.Keyword (" Root" ), Visit (isolate, Profile->GetTopDownRoot ()));
908
+ Out->Set (I.Keyword (" Title" ), Profile->GetTitle ());
909
+
910
+ {
911
+ uint32_t Num = Profile->GetSamplesCount ();
912
+ if (Num)
913
+ {
914
+ auto Arr = Array::New (isolate, Num);
915
+ for (uint32_t Index = 0 ; Index < Num; ++Index)
916
+ {
917
+ Arr->Set (Index, Visit (isolate, Profile->GetSample (Index)));
918
+ }
919
+ Out->Set (I.Keyword (" Samples" ), Arr);
920
+ }
921
+ }
922
+
923
+
924
+ // cleanup
925
+ Visit (nullptr , nullptr );
926
+
927
+ info.GetReturnValue ().Set (Out);
928
+
929
+ Profile->Delete ();
930
+ }
931
+ });
932
+
933
+ global_templ->Set (
934
+ I.Keyword (" v8" ),
935
+ // Create an instance
936
+ Template->GetFunction ()->NewInstance (),
937
+ // Do not modify!
938
+ ReadOnly);
939
+ }
940
+
773
941
void ExportMisc (Local<ObjectTemplate> global_templ)
774
942
{
775
943
FIsolateHelper I (isolate_);
0 commit comments