@@ -263,7 +263,6 @@ mono_profiler_enable_coverage (void)
263
263
return FALSE;
264
264
265
265
mono_os_mutex_init (& mono_profiler_state .coverage_mutex );
266
- mono_profiler_state .coverage_hash = g_hash_table_new (NULL , NULL );
267
266
268
267
if (!mono_debug_enabled ())
269
268
mono_debug_init (MONO_DEBUG_FORMAT_MONO );
@@ -294,17 +293,89 @@ mono_profiler_set_coverage_filter_callback (MonoProfilerHandle handle, MonoProfi
294
293
}
295
294
296
295
static void
297
- coverage_lock (void )
296
+ coverage_domains_lock (void )
298
297
{
299
298
mono_os_mutex_lock (& mono_profiler_state .coverage_mutex );
300
299
}
301
300
302
301
static void
303
- coverage_unlock (void )
302
+ coverage_domains_unlock (void )
304
303
{
305
304
mono_os_mutex_unlock (& mono_profiler_state .coverage_mutex );
306
305
}
307
306
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
+
308
379
/**
309
380
* mono_profiler_get_coverage_data:
310
381
*
@@ -328,11 +399,13 @@ mono_profiler_get_coverage_data (MonoProfilerHandle handle, MonoMethod *method,
328
399
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 ))
329
400
return FALSE;
330
401
331
- coverage_lock ();
402
+ MonoDomainCoverage * domain = get_coverage_for_domain (mono_domain_get ());
403
+
404
+ mono_os_mutex_lock (& domain -> mutex );
332
405
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 );
334
407
335
- coverage_unlock ( );
408
+ mono_os_mutex_unlock ( & domain -> mutex );
336
409
337
410
MonoMethodHeaderSummary header ;
338
411
@@ -417,6 +490,133 @@ mono_profiler_get_coverage_data (MonoProfilerHandle handle, MonoMethod *method,
417
490
418
491
return TRUE;
419
492
}
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
+ }
420
620
#endif
421
621
422
622
gboolean
@@ -435,23 +635,25 @@ mono_profiler_coverage_instrumentation_enabled (MonoMethod *method)
435
635
}
436
636
437
637
MonoProfilerCoverageInfo *
438
- mono_profiler_coverage_alloc (MonoMethod * method , guint32 entries )
638
+ mono_profiler_coverage_alloc (MonoDomain * domain , MonoMethod * method , guint32 entries )
439
639
{
440
640
if (!mono_profiler_state .code_coverage )
441
641
return NULL ;
442
642
443
643
if (!mono_profiler_coverage_instrumentation_enabled (method ))
444
644
return NULL ;
445
645
446
- coverage_lock ();
646
+ MonoDomainCoverage * covdomain = get_coverage_for_domain (domain );
647
+
648
+ mono_os_mutex_lock (& covdomain -> mutex );
447
649
448
650
MonoProfilerCoverageInfo * info = g_malloc0 (sizeof (MonoProfilerCoverageInfo ) + sizeof (MonoProfilerCoverageInfoEntry ) * entries );
449
651
450
652
info -> entries = entries ;
451
653
452
- g_hash_table_insert (mono_profiler_state . coverage_hash , method , info );
654
+ g_hash_table_insert (covdomain -> coverage_hash , method , info );
453
655
454
- coverage_unlock ( );
656
+ mono_os_mutex_unlock ( & covdomain -> mutex );
455
657
456
658
return info ;
457
659
}
@@ -860,21 +1062,6 @@ mono_profiler_cleanup (void)
860
1062
g_free (cur );
861
1063
}
862
1064
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
-
878
1065
if (mono_profiler_state .sampling_owner )
879
1066
mono_os_sem_destroy (& mono_profiler_state .sampling_semaphore );
880
1067
}
0 commit comments