2 This module contains utility functions to help the implementation of the runtime hook
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)
10 module core
.internal
.array
.utils
;
12 import core
.internal
.traits
: Parameters
;
13 import core
.memory
: GC
;
15 alias BlkAttr
= GC
.BlkAttr
;
17 auto gcStatsPure() nothrow pure
19 import core
.memory
: GC
;
20 auto impureBypass
= cast(GC
.Stats
function() pure nothrow)&GC
.stats
;
21 return impureBypass();
24 ulong accumulatePure(string file
, int line
, string funcname
, string name
, ulong size
) nothrow pure
26 static ulong impureBypass(string file
, int line
, string funcname
, string name
, ulong size
) @nogc nothrow
28 import core
.internal
.traits
: externDFunc
;
30 alias accumulate
= externDFunc
!("rt.profilegc.accumulate", void function(string file
, uint line
, string funcname
, string type
, ulong sz
) @nogc nothrow);
31 accumulate(file
, line
, funcname
, name
, size
);
35 auto func
= cast(ulong function(string file
, int line
, string funcname
, string name
, ulong size
) @nogc nothrow pure)&impureBypass
;
36 return func(file
, line
, funcname
, name
, size
);
42 * TraceGC wrapper generator around the runtime hook `Hook`.
44 * Type = The type of hook to report to accumulate
45 * Hook = The name hook to wrap
47 template TraceHook(string Type
, string Hook
)
49 const char[] TraceHook
= q
{
50 import core
.internal
.array
.utils
: gcStatsPure
, accumulatePure
;
52 pragma(inline
, false);
53 string name
= } ~ "`" ~ Type
~ "`;" ~ q
{
55 // FIXME: use rt.tracegc.accumulator when it is accessable in the future.
58 import core
.stdc
.stdio
;
60 printf("%sTrace file = '%.*s' line = %d function = '%.*s' type = %.*s\n",
61 } ~ "\"" ~ Hook
~ "\".ptr," ~ q
{
62 file
.length
, file
.ptr
,
64 funcname
.length
, funcname
.ptr
,
68 ulong currentlyAllocated
= gcStatsPure().allocatedInCurrentThread
;
72 ulong size
= gcStatsPure().allocatedInCurrentThread
- currentlyAllocated
;
74 if (!accumulatePure(file
, line
, funcname
, name
, size
)) {
75 // This 'if' and 'assert' is needed to force the compiler to not remove the call to
76 // `accumulatePure`. It really want to do that while optimizing as the function is
77 // `pure` and it does not influence the result of this hook.
79 // `accumulatePure` returns the value of `size`, which can never be zero due to the
80 // previous 'if'. So this assert will never be triggered.
88 * TraceGC wrapper around runtime hook `Hook`.
90 * T = Type of hook to report to accumulate
91 * Hook = The hook to wrap
92 * errorMessage = The error message incase `version != D_TypeInfo`
93 * file = File that called `_d_HookTraceImpl`
94 * line = Line inside of `file` that called `_d_HookTraceImpl`
95 * funcname = Function that called `_d_HookTraceImpl`
96 * parameters = Parameters that will be used to call `Hook`
98 * This function template needs be between the compiler and a much older runtime hook that bypassed safety,
99 * purity, and throwabilty checks. To prevent breaking existing code, this function template
100 * is temporarily declared `@trusted pure` until the implementation can be brought up to modern D expectations.
102 auto _d_HookTraceImpl(T
, alias Hook
, string errorMessage
)(string file
, int line
, string funcname
, Parameters
!Hook parameters
) @trusted pure
106 mixin(TraceHook
!(T
.stringof
, __traits(identifier
, Hook
)));
107 return Hook(parameters
);
110 assert(0, errorMessage
);
115 * Check if the function `F` is calleable in a `nothrow` scope.
117 * F = Function that does not take any parameters
119 * if the function is callable in a `nothrow` scope.
121 enum isNoThrow(alias F
) = is(typeof(() nothrow { F(); }));
124 * Check if the type `T`'s postblit is called in nothrow, if it exist
128 * if the postblit is callable in a `nothrow` scope, if it exist.
129 * if it does not exist, return true.
131 template isPostblitNoThrow(T
) {
132 static if (__traits(isStaticArray
, T
))
133 enum isPostblitNoThrow
= isPostblitNoThrow
!(typeof(T
.init
[0]));
134 else static if (__traits(hasMember
, T
, "__xpostblit") &&
135 // Bugzilla 14746: Check that it's the exact member of S.
136 __traits(isSame
, T
, __traits(parent
, T
.init
.__xpostblit
)))
137 enum isPostblitNoThrow
= isNoThrow
!(T
.init
.__xpostblit
);
139 enum isPostblitNoThrow
= true;
143 * Allocate a memory block with appendable capabilities for array usage.
146 * arrSize = size of the allocated array in bytes
148 * `void[]` matching requested size on success, `null` on failure.
150 void[] __arrayAlloc(T
)(size_t arrSize
) @trusted
152 import core
.lifetime
: TypeInfoSize
;
153 import core
.internal
.traits
: hasIndirections
;
155 enum typeInfoSize
= TypeInfoSize
!T
;
156 BlkAttr attr
= BlkAttr
.APPENDABLE
;
158 /* `extern(C++)` classes don't have a classinfo pointer in their vtable,
159 * so the GC can't finalize them.
161 static if (typeInfoSize
)
162 attr |
= BlkAttr
.STRUCTFINAL | BlkAttr
.FINALIZE
;
163 static if (!hasIndirections
!T
)
164 attr |
= BlkAttr
.NO_SCAN
;
166 auto ptr
= GC
.malloc(arrSize
, attr
, typeid(T
));
168 return ptr
[0 .. arrSize
];