xref: /netbsd-src/external/gpl3/gcc/dist/libphobos/libdruntime/core/internal/array/utils.d (revision 0a3071956a3a9fdebdbf7f338cf2d439b45fc728)
1 /**
2  This module contains utility functions to help the implementation of the runtime hook
3 
4   Copyright: Copyright Digital Mars 2000 - 2019.
5   License: Distributed under the
6        $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0).
7      (See accompanying file LICENSE)
8   Source: $(DRUNTIMESRC core/internal/_array/_utils.d)
9 */
10 module core.internal.array.utils;
11 
12 import core.internal.traits : Parameters;
13 
gcStatsPure()14 private auto gcStatsPure() nothrow pure
15 {
16     import core.memory : GC;
17 
18     auto impureBypass = cast(GC.Stats function() pure nothrow)&GC.stats;
19     return impureBypass();
20 }
21 
accumulatePure(string file,int line,string funcname,string name,ulong size)22 private ulong accumulatePure(string file, int line, string funcname, string name, ulong size) nothrow pure
23 {
24     static ulong impureBypass(string file, int line, string funcname, string name, ulong size) @nogc nothrow
25     {
26         import core.internal.traits : externDFunc;
27 
28         alias accumulate = externDFunc!("rt.profilegc.accumulate", void function(string file, uint line, string funcname, string type, ulong sz) @nogc nothrow);
29         accumulate(file, line, funcname, name, size);
30         return size;
31     }
32 
33     auto func = cast(ulong function(string file, int line, string funcname, string name, ulong size) @nogc nothrow pure)&impureBypass;
34     return func(file, line, funcname, name, size);
35 }
36 
37 /**
38  * TraceGC wrapper around runtime hook `Hook`.
39  * Params:
40  *  T = Type of hook to report to accumulate
41  *  Hook = The hook to wrap
42  *  errorMessage = The error message incase `version != D_TypeInfo`
43  *  file = File that called `_d_HookTraceImpl`
44  *  line = Line inside of `file` that called `_d_HookTraceImpl`
45  *  funcname = Function that called `_d_HookTraceImpl`
46  *  parameters = Parameters that will be used to call `Hook`
47  * Bugs:
48  *  This function template needs be between the compiler and a much older runtime hook that bypassed safety,
49  *  purity, and throwabilty checks. To prevent breaking existing code, this function template
50  *  is temporarily declared `@trusted pure` until the implementation can be brought up to modern D expectations.
51 */
_d_HookTraceImpl(T,alias Hook,string errorMessage)52 auto _d_HookTraceImpl(T, alias Hook, string errorMessage)(string file, int line, string funcname, Parameters!Hook parameters) @trusted pure
53 {
54     version (D_TypeInfo)
55     {
56         pragma(inline, false);
57         string name = T.stringof;
58 
59         // FIXME: use rt.tracegc.accumulator when it is accessable in the future.
60         version (tracegc)
61         {
62             import core.stdc.stdio;
63 
64             printf("%sTrace file = '%.*s' line = %d function = '%.*s' type = %.*s\n",
65                 Hook.stringof.ptr,
66                 file.length, file.ptr,
67                 line,
68                 funcname.length, funcname.ptr,
69                 name.length, name.ptr
70             );
71         }
72 
73         ulong currentlyAllocated = gcStatsPure().allocatedInCurrentThread;
74 
75         scope(exit)
76         {
77             ulong size = gcStatsPure().allocatedInCurrentThread - currentlyAllocated;
78             if (size > 0)
79                 if (!accumulatePure(file, line, funcname, name, size)) {
80                     // This 'if' and 'assert' is needed to force the compiler to not remove the call to
81                     // `accumulatePure`. It really want to do that while optimizing as the function is
82                     // `pure` and it does not influence the result of this hook.
83 
84                     // `accumulatePure` returns the value of `size`, which can never be zero due to the
85                     // previous 'if'. So this assert will never be triggered.
86                     assert(0);
87                 }
88         }
89         return Hook(parameters);
90     }
91     else
92         assert(0, errorMessage);
93 }
94 
95 /**
96  * Check if the function `F` is calleable in a `nothrow` scope.
97  * Params:
98  *  F = Function that does not take any parameters
99  * Returns:
100  *  if the function is callable in a `nothrow` scope.
101  */
102 enum isNoThrow(alias F) = is(typeof(() nothrow { F(); }));
103 
104 /**
105  * Check if the type `T`'s postblit is called in nothrow, if it exist
106  * Params:
107  *  T = Type to check
108  * Returns:
109  *  if the postblit is callable in a `nothrow` scope, if it exist.
110  *  if it does not exist, return true.
111  */
isPostblitNoThrow(T)112 template isPostblitNoThrow(T) {
113     static if (__traits(isStaticArray, T))
114         enum isPostblitNoThrow = isPostblitNoThrow!(typeof(T.init[0]));
115     else static if (__traits(hasMember, T, "__xpostblit") &&
116         // Bugzilla 14746: Check that it's the exact member of S.
117         __traits(isSame, T, __traits(parent, T.init.__xpostblit)))
118         enum isPostblitNoThrow = isNoThrow!(T.init.__xpostblit);
119     else
120         enum isPostblitNoThrow = true;
121 }
122