@@ -263,7 +263,6 @@ mono_profiler_enable_coverage (void)
263263 return FALSE;
264264
265265 mono_os_mutex_init (& mono_profiler_state .coverage_mutex );
266- mono_profiler_state .coverage_hash = g_hash_table_new (NULL , NULL );
267266
268267 if (!mono_debug_enabled ())
269268 mono_debug_init (MONO_DEBUG_FORMAT_MONO );
@@ -294,17 +293,89 @@ mono_profiler_set_coverage_filter_callback (MonoProfilerHandle handle, MonoProfi
294293}
295294
296295static void
297- coverage_lock (void )
296+ coverage_domains_lock (void )
298297{
299298 mono_os_mutex_lock (& mono_profiler_state .coverage_mutex );
300299}
301300
302301static void
303- coverage_unlock (void )
302+ coverage_domains_unlock (void )
304303{
305304 mono_os_mutex_unlock (& mono_profiler_state .coverage_mutex );
306305}
307306
307+ static MonoDomainCoverage *
308+ get_coverage_for_domain (MonoDomain * domain )
309+ {
310+ coverage_domains_lock ();
311+ MonoDomainCoverage * cov = mono_profiler_state .coverage_domains ;
312+ while (cov )
313+ {
314+ if (cov -> domain == domain )
315+ break ;
316+ cov = cov -> next ;
317+ }
318+ coverage_domains_unlock ();
319+ return cov ;
320+ }
321+
322+ void
323+ mono_profiler_coverage_domain_init (MonoDomain * domain )
324+ {
325+ if (!mono_profiler_state .code_coverage )
326+ return ;
327+
328+ MonoDomainCoverage * cov = g_new0 (MonoDomainCoverage , 1 );
329+ cov -> domain = domain ;
330+ cov -> coverage_hash = g_hash_table_new (NULL , NULL );
331+ mono_os_mutex_init (& cov -> mutex );
332+
333+ coverage_domains_lock ();
334+ cov -> next = mono_profiler_state .coverage_domains ;
335+ mono_profiler_state .coverage_domains = cov ;
336+ coverage_domains_unlock ();
337+ }
338+
339+ void
340+ mono_profiler_coverage_domain_free (MonoDomain * domain )
341+ {
342+ if (!mono_profiler_state .code_coverage )
343+ return ;
344+
345+ coverage_domains_lock ();
346+
347+ MonoDomainCoverage * cov = mono_profiler_state .coverage_domains ;
348+ MonoDomainCoverage * * prev = & mono_profiler_state .coverage_domains ;
349+ while (cov )
350+ {
351+ if (cov -> domain == domain )
352+ break ;
353+
354+ prev = & cov -> next ;
355+ cov = cov -> next ;
356+ }
357+
358+ if (cov != NULL )
359+ {
360+ * prev = cov -> next ;
361+
362+ GHashTableIter iter ;
363+ g_hash_table_iter_init (& iter , cov -> coverage_hash );
364+
365+ MonoProfilerCoverageInfo * info ;
366+ while (g_hash_table_iter_next (& iter , NULL , (gpointer * )& info ))
367+ g_free (info );
368+
369+ g_hash_table_destroy (cov -> coverage_hash );
370+
371+ mono_os_mutex_destroy (& cov -> mutex );
372+
373+ g_free (cov );
374+ }
375+
376+ coverage_domains_unlock ();
377+ }
378+
308379/**
309380 * mono_profiler_get_coverage_data:
310381 *
@@ -328,11 +399,13 @@ mono_profiler_get_coverage_data (MonoProfilerHandle handle, MonoMethod *method,
328399 if ((method -> flags & METHOD_ATTRIBUTE_ABSTRACT ) || (method -> iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME ) || (method -> iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL ) || (method -> flags & METHOD_ATTRIBUTE_PINVOKE_IMPL ))
329400 return FALSE;
330401
331- coverage_lock ();
402+ MonoDomainCoverage * domain = get_coverage_for_domain (mono_domain_get ());
403+
404+ mono_os_mutex_lock (& domain -> mutex );
332405
333- MonoProfilerCoverageInfo * info = (MonoProfilerCoverageInfo * )g_hash_table_lookup (mono_profiler_state . coverage_hash , method );
406+ MonoProfilerCoverageInfo * info = (MonoProfilerCoverageInfo * )g_hash_table_lookup (domain -> coverage_hash , method );
334407
335- coverage_unlock ( );
408+ mono_os_mutex_unlock ( & domain -> mutex );
336409
337410 MonoMethodHeaderSummary header ;
338411
@@ -417,6 +490,133 @@ mono_profiler_get_coverage_data (MonoProfilerHandle handle, MonoMethod *method,
417490
418491 return TRUE;
419492}
493+
494+
495+ typedef struct
496+ {
497+ MonoProfilerCoverageCallback cb ;
498+ MonoProfilerHandle handle ;
499+ } InvokeCallbackInfo ;
500+
501+ static void invoke_coverage_callback_for_hashtable_entry (gpointer key , gpointer value , gpointer user_data )
502+ {
503+ InvokeCallbackInfo * invokeInfo = (InvokeCallbackInfo * )user_data ;
504+ MonoMethod * method = (MonoMethod * )key ;
505+ MonoProfilerCoverageInfo * info = (MonoProfilerCoverageInfo * )value ;
506+
507+ MonoError error ;
508+ MonoMethodHeader * header = mono_method_get_header_checked (method , & error );
509+ mono_error_assert_ok (& error );
510+
511+ guint32 size ;
512+
513+ const unsigned char * start = mono_method_header_get_code (header , & size , NULL );
514+ const unsigned char * end = start + size ;
515+ MonoDebugMethodInfo * minfo = mono_debug_lookup_method (method );
516+
517+ for (guint32 i = 0 ; i < info -> entries ; i ++ ) {
518+ guchar * cil_code = info -> data [i ].cil_code ;
519+
520+ if (cil_code && cil_code >= start && cil_code < end ) {
521+ guint32 offset = cil_code - start ;
522+
523+ MonoProfilerCoverageData data = {
524+ .method = method ,
525+ .il_offset = offset ,
526+ .counter = info -> data [i ].count ,
527+ .line = 1 ,
528+ .column = 1 ,
529+ };
530+
531+ if (minfo ) {
532+ MonoDebugSourceLocation * loc = mono_debug_method_lookup_location (minfo , offset );
533+
534+ if (loc ) {
535+ data .file_name = g_strdup (loc -> source_file );
536+ data .line = loc -> row ;
537+ data .column = loc -> column ;
538+
539+ mono_debug_free_source_location (loc );
540+ }
541+ }
542+
543+ invokeInfo -> cb (invokeInfo -> handle -> prof , & data );
544+
545+ g_free ((char * )data .file_name );
546+ }
547+ }
548+
549+ mono_metadata_free_mh (header );
550+ }
551+
552+ mono_bool
553+ mono_profiler_get_all_coverage_data (MonoProfilerHandle handle , MonoProfilerCoverageCallback cb )
554+ {
555+ if (!mono_profiler_state .code_coverage )
556+ return FALSE;
557+
558+ InvokeCallbackInfo info ;
559+ info .cb = cb ;
560+ info .handle = handle ;
561+
562+ MonoDomainCoverage * domain = get_coverage_for_domain (mono_domain_get ());
563+
564+ mono_os_mutex_lock (& domain -> mutex );
565+
566+ g_hash_table_foreach (domain -> coverage_hash , invoke_coverage_callback_for_hashtable_entry , & info );
567+
568+ mono_os_mutex_unlock (& domain -> mutex );
569+
570+ return TRUE;
571+ }
572+
573+ mono_bool
574+ mono_profiler_reset_coverage (MonoMethod * method )
575+ {
576+ if (!mono_profiler_state .code_coverage )
577+ return FALSE;
578+
579+ if ((method -> flags & METHOD_ATTRIBUTE_ABSTRACT ) || (method -> iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME ) || (method -> iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL ) || (method -> flags & METHOD_ATTRIBUTE_PINVOKE_IMPL ))
580+ return FALSE;
581+
582+ MonoDomainCoverage * domain = get_coverage_for_domain (mono_domain_get ());
583+
584+ mono_os_mutex_lock (& domain -> mutex );
585+
586+ MonoProfilerCoverageInfo * info = g_hash_table_lookup (domain -> coverage_hash , method );
587+
588+ mono_os_mutex_unlock (& domain -> mutex );
589+
590+ if (!info )
591+ return TRUE;
592+
593+ for (guint32 i = 0 ; i < info -> entries ; i ++ )
594+ info -> data [i ].count = 0 ;
595+
596+ return TRUE;
597+ }
598+
599+ static void reset_coverage_for_hashtable_entry (gpointer key , gpointer value , gpointer user_data )
600+ {
601+ MonoProfilerCoverageInfo * info = (MonoProfilerCoverageInfo * )value ;
602+
603+ for (guint32 i = 0 ; i < info -> entries ; i ++ )
604+ info -> data [i ].count = 0 ;
605+ }
606+
607+ void mono_profiler_reset_all_coverage ()
608+ {
609+ if (!mono_profiler_state .code_coverage )
610+ return ;
611+
612+ MonoDomainCoverage * domain = get_coverage_for_domain (mono_domain_get ());
613+
614+ mono_os_mutex_lock (& domain -> mutex );
615+
616+ g_hash_table_foreach (domain -> coverage_hash , reset_coverage_for_hashtable_entry , NULL );
617+
618+ mono_os_mutex_unlock (& domain -> mutex );
619+ }
420620#endif
421621
422622gboolean
@@ -435,23 +635,25 @@ mono_profiler_coverage_instrumentation_enabled (MonoMethod *method)
435635}
436636
437637MonoProfilerCoverageInfo *
438- mono_profiler_coverage_alloc (MonoMethod * method , guint32 entries )
638+ mono_profiler_coverage_alloc (MonoDomain * domain , MonoMethod * method , guint32 entries )
439639{
440640 if (!mono_profiler_state .code_coverage )
441641 return NULL ;
442642
443643 if (!mono_profiler_coverage_instrumentation_enabled (method ))
444644 return NULL ;
445645
446- coverage_lock ();
646+ MonoDomainCoverage * covdomain = get_coverage_for_domain (domain );
647+
648+ mono_os_mutex_lock (& covdomain -> mutex );
447649
448650 MonoProfilerCoverageInfo * info = g_malloc0 (sizeof (MonoProfilerCoverageInfo ) + sizeof (MonoProfilerCoverageInfoEntry ) * entries );
449651
450652 info -> entries = entries ;
451653
452- g_hash_table_insert (mono_profiler_state . coverage_hash , method , info );
654+ g_hash_table_insert (covdomain -> coverage_hash , method , info );
453655
454- coverage_unlock ( );
656+ mono_os_mutex_unlock ( & covdomain -> mutex );
455657
456658 return info ;
457659}
@@ -860,21 +1062,6 @@ mono_profiler_cleanup (void)
8601062 g_free (cur );
8611063 }
8621064
863- if (mono_profiler_state .code_coverage ) {
864- mono_os_mutex_destroy (& mono_profiler_state .coverage_mutex );
865-
866- GHashTableIter iter ;
867-
868- g_hash_table_iter_init (& iter , mono_profiler_state .coverage_hash );
869-
870- MonoProfilerCoverageInfo * info ;
871-
872- while (g_hash_table_iter_next (& iter , NULL , (gpointer * ) & info ))
873- g_free (info );
874-
875- g_hash_table_destroy (mono_profiler_state .coverage_hash );
876- }
877-
8781065 if (mono_profiler_state .sampling_owner )
8791066 mono_os_sem_destroy (& mono_profiler_state .sampling_semaphore );
8801067}
0 commit comments