@@ -248,7 +248,6 @@ mono_profiler_enable_coverage (void)
248
248
return FALSE;
249
249
250
250
mono_os_mutex_init (& mono_profiler_state .coverage_mutex );
251
- mono_profiler_state .coverage_hash = g_hash_table_new (NULL , NULL );
252
251
253
252
if (!mono_debug_enabled ())
254
253
mono_debug_init (MONO_DEBUG_FORMAT_MONO );
@@ -279,17 +278,89 @@ mono_profiler_set_coverage_filter_callback (MonoProfilerHandle handle, MonoProfi
279
278
}
280
279
281
280
static void
282
- coverage_lock (void )
281
+ coverage_domains_lock (void )
283
282
{
284
283
mono_os_mutex_lock (& mono_profiler_state .coverage_mutex );
285
284
}
286
285
287
286
static void
288
- coverage_unlock (void )
287
+ coverage_domains_unlock (void )
289
288
{
290
289
mono_os_mutex_unlock (& mono_profiler_state .coverage_mutex );
291
290
}
292
291
292
+ static MonoDomainCoverage *
293
+ get_coverage_for_domain (MonoDomain * domain )
294
+ {
295
+ coverage_domains_lock ();
296
+ MonoDomainCoverage * cov = mono_profiler_state .coverage_domains ;
297
+ while (cov )
298
+ {
299
+ if (cov -> domain == domain )
300
+ break ;
301
+ cov = cov -> next ;
302
+ }
303
+ coverage_domains_unlock ();
304
+ return cov ;
305
+ }
306
+
307
+ void
308
+ mono_profiler_coverage_domain_init (MonoDomain * domain )
309
+ {
310
+ if (!mono_profiler_state .code_coverage )
311
+ return ;
312
+
313
+ MonoDomainCoverage * cov = g_new0 (MonoDomainCoverage , 1 );
314
+ cov -> domain = domain ;
315
+ cov -> coverage_hash = g_hash_table_new (NULL , NULL );
316
+ mono_os_mutex_init (& cov -> mutex );
317
+
318
+ coverage_domains_lock ();
319
+ cov -> next = mono_profiler_state .coverage_domains ;
320
+ mono_profiler_state .coverage_domains = cov ;
321
+ coverage_domains_unlock ();
322
+ }
323
+
324
+ void
325
+ mono_profiler_coverage_domain_free (MonoDomain * domain )
326
+ {
327
+ if (!mono_profiler_state .code_coverage )
328
+ return ;
329
+
330
+ coverage_domains_lock ();
331
+
332
+ MonoDomainCoverage * cov = mono_profiler_state .coverage_domains ;
333
+ MonoDomainCoverage * * prev = & mono_profiler_state .coverage_domains ;
334
+ while (cov )
335
+ {
336
+ if (cov -> domain == domain )
337
+ break ;
338
+
339
+ prev = & cov -> next ;
340
+ cov = cov -> next ;
341
+ }
342
+
343
+ if (cov != NULL )
344
+ {
345
+ * prev = cov -> next ;
346
+
347
+ GHashTableIter iter ;
348
+ g_hash_table_iter_init (& iter , cov -> coverage_hash );
349
+
350
+ MonoProfilerCoverageInfo * info ;
351
+ while (g_hash_table_iter_next (& iter , NULL , (gpointer * ) & info ))
352
+ g_free (info );
353
+
354
+ g_hash_table_destroy (cov -> coverage_hash );
355
+
356
+ mono_os_mutex_destroy (& cov -> mutex );
357
+
358
+ g_free (cov );
359
+ }
360
+
361
+ coverage_domains_unlock ();
362
+ }
363
+
293
364
/**
294
365
* mono_profiler_get_coverage_data:
295
366
*
@@ -313,11 +384,13 @@ mono_profiler_get_coverage_data (MonoProfilerHandle handle, MonoMethod *method,
313
384
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 ))
314
385
return FALSE;
315
386
316
- coverage_lock ();
387
+ MonoDomainCoverage * domain = get_coverage_for_domain (mono_domain_get ());
388
+
389
+ mono_os_mutex_lock (& domain -> mutex );
317
390
318
- MonoProfilerCoverageInfo * info = g_hash_table_lookup (mono_profiler_state . coverage_hash , method );
391
+ MonoProfilerCoverageInfo * info = g_hash_table_lookup (domain -> coverage_hash , method );
319
392
320
- coverage_unlock ( );
393
+ mono_os_mutex_unlock ( & domain -> mutex );
321
394
322
395
MonoError error ;
323
396
MonoMethodHeader * header = mono_method_get_header_checked (method , & error );
@@ -407,10 +480,137 @@ mono_profiler_get_coverage_data (MonoProfilerHandle handle, MonoMethod *method,
407
480
408
481
return TRUE;
409
482
}
483
+
484
+ typedef struct
485
+ {
486
+ MonoProfilerCoverageCallback cb ;
487
+ MonoProfilerHandle handle ;
488
+ } InvokeCallbackInfo ;
489
+
490
+ static void invoke_coverage_callback_for_hashtable_entry (gpointer key , gpointer value , gpointer user_data )
491
+ {
492
+ InvokeCallbackInfo * invokeInfo = (InvokeCallbackInfo * ) user_data ;
493
+ MonoMethod * method = (MonoMethod * )key ;
494
+ MonoProfilerCoverageInfo * info = (MonoProfilerCoverageInfo * )value ;
495
+
496
+ MonoError error ;
497
+ MonoMethodHeader * header = mono_method_get_header_checked (method , & error );
498
+ mono_error_assert_ok (& error );
499
+
500
+ guint32 size ;
501
+
502
+ const unsigned char * start = mono_method_header_get_code (header , & size , NULL );
503
+ const unsigned char * end = start + size ;
504
+ MonoDebugMethodInfo * minfo = mono_debug_lookup_method (method );
505
+
506
+ for (guint32 i = 0 ; i < info -> entries ; i ++ ) {
507
+ guchar * cil_code = info -> data [i ].cil_code ;
508
+
509
+ if (cil_code && cil_code >= start && cil_code < end ) {
510
+ guint32 offset = cil_code - start ;
511
+
512
+ MonoProfilerCoverageData data = {
513
+ .method = method ,
514
+ .il_offset = offset ,
515
+ .counter = info -> data [i ].count ,
516
+ .line = 1 ,
517
+ .column = 1 ,
518
+ };
519
+
520
+ if (minfo ) {
521
+ MonoDebugSourceLocation * loc = mono_debug_method_lookup_location (minfo , offset );
522
+
523
+ if (loc ) {
524
+ data .file_name = g_strdup (loc -> source_file );
525
+ data .line = loc -> row ;
526
+ data .column = loc -> column ;
527
+
528
+ mono_debug_free_source_location (loc );
529
+ }
530
+ }
531
+
532
+ invokeInfo -> cb (invokeInfo -> handle -> prof , & data );
533
+
534
+ g_free ((char * ) data .file_name );
535
+ }
536
+ }
537
+
538
+ mono_metadata_free_mh (header );
539
+ }
540
+
541
+ mono_bool
542
+ mono_profiler_get_all_coverage_data (MonoProfilerHandle handle , MonoProfilerCoverageCallback cb )
543
+ {
544
+ if (!mono_profiler_state .code_coverage )
545
+ return FALSE;
546
+
547
+ InvokeCallbackInfo info ;
548
+ info .cb = cb ;
549
+ info .handle = handle ;
550
+
551
+ MonoDomainCoverage * domain = get_coverage_for_domain (mono_domain_get ());
552
+
553
+ mono_os_mutex_lock (& domain -> mutex );
554
+
555
+ g_hash_table_foreach (domain -> coverage_hash , invoke_coverage_callback_for_hashtable_entry , & info );
556
+
557
+ mono_os_mutex_unlock (& domain -> mutex );
558
+
559
+ return TRUE;
560
+ }
561
+
562
+ mono_bool
563
+ mono_profiler_reset_coverage (MonoMethod * method )
564
+ {
565
+ if (!mono_profiler_state .code_coverage )
566
+ return FALSE;
567
+
568
+ 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 ))
569
+ return FALSE;
570
+
571
+ MonoDomainCoverage * domain = get_coverage_for_domain (mono_domain_get ());
572
+
573
+ mono_os_mutex_lock (& domain -> mutex );
574
+
575
+ MonoProfilerCoverageInfo * info = g_hash_table_lookup (domain -> coverage_hash , method );
576
+
577
+ mono_os_mutex_unlock (& domain -> mutex );
578
+
579
+ if (!info )
580
+ return TRUE;
581
+
582
+ for (guint32 i = 0 ; i < info -> entries ; i ++ )
583
+ info -> data [i ].count = 0 ;
584
+
585
+ return TRUE;
586
+ }
587
+
588
+ static void reset_coverage_for_hashtable_entry (gpointer key , gpointer value , gpointer user_data )
589
+ {
590
+ MonoProfilerCoverageInfo * info = (MonoProfilerCoverageInfo * )value ;
591
+
592
+ for (guint32 i = 0 ; i < info -> entries ; i ++ )
593
+ info -> data [i ].count = 0 ;
594
+ }
595
+
596
+ void mono_profiler_reset_all_coverage ()
597
+ {
598
+ if (!mono_profiler_state .code_coverage )
599
+ return ;
600
+
601
+ MonoDomainCoverage * domain = get_coverage_for_domain (mono_domain_get ());
602
+
603
+ mono_os_mutex_lock (& domain -> mutex );
604
+
605
+ g_hash_table_foreach (domain -> coverage_hash , reset_coverage_for_hashtable_entry , NULL );
606
+
607
+ mono_os_mutex_unlock (& domain -> mutex );
608
+ }
609
+
410
610
#endif
411
611
412
612
MonoProfilerCoverageInfo *
413
- mono_profiler_coverage_alloc (MonoMethod * method , guint32 entries )
613
+ mono_profiler_coverage_alloc (MonoDomain * domain , MonoMethod * method , guint32 entries )
414
614
{
415
615
if (!mono_profiler_state .code_coverage )
416
616
return FALSE;
@@ -430,15 +630,17 @@ mono_profiler_coverage_alloc (MonoMethod *method, guint32 entries)
430
630
if (!cover )
431
631
return NULL ;
432
632
433
- coverage_lock ();
633
+ MonoDomainCoverage * covdomain = get_coverage_for_domain (domain );
634
+
635
+ mono_os_mutex_lock (& covdomain -> mutex );
434
636
435
637
MonoProfilerCoverageInfo * info = g_malloc0 (sizeof (MonoProfilerCoverageInfo ) + SIZEOF_VOID_P * 2 * entries );
436
638
437
639
info -> entries = entries ;
438
640
439
- g_hash_table_insert (mono_profiler_state . coverage_hash , method , info );
641
+ g_hash_table_insert (covdomain -> coverage_hash , method , info );
440
642
441
- coverage_unlock ( );
643
+ mono_os_mutex_unlock ( & covdomain -> mutex );
442
644
443
645
return info ;
444
646
}
@@ -837,21 +1039,6 @@ mono_profiler_cleanup (void)
837
1039
g_free (cur );
838
1040
}
839
1041
840
- if (mono_profiler_state .code_coverage ) {
841
- mono_os_mutex_destroy (& mono_profiler_state .coverage_mutex );
842
-
843
- GHashTableIter iter ;
844
-
845
- g_hash_table_iter_init (& iter , mono_profiler_state .coverage_hash );
846
-
847
- MonoProfilerCoverageInfo * info ;
848
-
849
- while (g_hash_table_iter_next (& iter , NULL , (gpointer * ) & info ))
850
- g_free (info );
851
-
852
- g_hash_table_destroy (mono_profiler_state .coverage_hash );
853
- }
854
-
855
1042
if (mono_profiler_state .sampling_owner )
856
1043
mono_os_sem_destroy (& mono_profiler_state .sampling_semaphore );
857
1044
}
0 commit comments