1 /** 2 * Contains implementations of functions called when the 3 * -profile=gc 4 * switch is thrown. 5 * 6 * Tests for this functionality can be found in test/profile/src/profilegc.d 7 * 8 * Copyright: Copyright Digital Mars 2015 - 2015. 9 * License: Distributed under the 10 * $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0). 11 * (See accompanying file LICENSE) 12 * Authors: Walter Bright 13 * Source: $(DRUNTIMESRC rt/_tracegc.d) 14 */ 15 16 module rt.tracegc; 17 18 // version = tracegc; 19 20 extern (C) void[] _d_newarrayT(const TypeInfo ti, size_t length); 21 extern (C) void[] _d_newarrayU(const scope TypeInfo ti, size_t length); 22 extern (C) void[] _d_newarrayiT(const TypeInfo ti, size_t length); 23 extern (C) void[] _d_newarraymTX(const TypeInfo ti, size_t[] dims); 24 extern (C) void[] _d_newarraymiTX(const TypeInfo ti, size_t[] dims); 25 extern (C) void* _d_newitemT(const TypeInfo ti); 26 extern (C) void* _d_newitemiT(const TypeInfo ti); 27 extern (C) void _d_callfinalizer(void* p); 28 extern (C) void _d_callinterfacefinalizer(void *p); 29 extern (C) void _d_delclass(Object* p); 30 extern (C) void _d_delinterface(void** p); 31 extern (C) void _d_delmemory(void* *p); 32 extern (C) void* _d_arrayliteralTX(const TypeInfo ti, size_t length); 33 extern (C) void* _d_assocarrayliteralTX(const TypeInfo_AssociativeArray ti, 34 void[] keys, void[] vals); 35 extern (C) byte[] _d_arrayappendcTX(const TypeInfo ti, return scope ref byte[] px, size_t n); 36 extern (C) void[] _d_arrayappendcd(ref byte[] x, dchar c); 37 extern (C) void[] _d_arrayappendwd(ref byte[] x, dchar c); 38 extern (C) void[] _d_arraysetlengthT(const TypeInfo ti, size_t newlength, void[]* p); 39 extern (C) void[] _d_arraysetlengthiT(const TypeInfo ti, size_t newlength, void[]* p); 40 extern (C) void* _d_allocmemory(size_t sz); 41 42 // From GC.BlkInfo_. We cannot import it from core.memory.GC because .stringof 43 // replaces the alias with the private symbol that's not visible from this 44 // module, causing a compile error. 45 private struct BlkInfo 46 { 47 void* base; 48 size_t size; 49 uint attr; 50 } 51 extern (C) void* gc_malloc(size_t sz, uint ba = 0, const scope TypeInfo ti = null); 52 extern (C) BlkInfo gc_qalloc(size_t sz, uint ba = 0, const scope TypeInfo ti = null); 53 extern (C) void* gc_calloc(size_t sz, uint ba = 0, const TypeInfo ti = null); 54 extern (C) void* gc_realloc(return scope void* p, size_t sz, uint ba = 0, const TypeInfo ti = null); 55 extern (C) size_t gc_extend(void* p, size_t mx, size_t sz, const TypeInfo ti = null); 56 57 // Used as wrapper function body to get actual stats. 58 // 59 // Placed here as a separate string constant to simplify maintenance as it is 60 // much more likely to be modified than rest of generation code. 61 enum accumulator = q{ 62 import rt.profilegc : accumulate; 63 import core.memory : GC; 64 65 static if (is(typeof(ci))) 66 string name = ci.name; 67 else static if (is(typeof(ti))) 68 string name = ti ? ti.toString() : "void[]"; 69 else static if (__FUNCTION__ == "rt.tracegc._d_arrayappendcdTrace") 70 string name = "char[]"; 71 else static if (__FUNCTION__ == "rt.tracegc._d_arrayappendwdTrace") 72 string name = "wchar[]"; 73 else static if (__FUNCTION__ == "rt.tracegc._d_allocmemoryTrace") 74 string name = "closure"; 75 else 76 string name = ""; 77 78 version (tracegc) 79 { 80 import core.stdc.stdio; 81 82 printf("%s file = '%.*s' line = %d function = '%.*s' type = %.*s\n", 83 __FUNCTION__.ptr, 84 file.length, file.ptr, 85 line, 86 funcname.length, funcname.ptr, 87 name.length, name.ptr 88 ); 89 } 90 91 ulong currentlyAllocated = GC.allocatedInCurrentThread; 92 93 scope(exit) 94 { 95 ulong size = GC.allocatedInCurrentThread - currentlyAllocated; 96 if (size > 0) 97 accumulate(file, line, funcname, name, size); 98 } 99 }; 100 101 mixin(generateTraceWrappers()); 102 //pragma(msg, generateTraceWrappers()); 103 104 //////////////////////////////////////////////////////////////////////////////// 105 // code gen implementation 106 107 private string generateTraceWrappers() 108 { 109 string code; 110 111 foreach (name; __traits(allMembers, mixin(__MODULE__))) 112 { 113 static if (name.length > 3 && name[0..3] == "_d_") 114 { 115 mixin("alias Declaration = " ~ name ~ ";"); 116 code ~= generateWrapper!Declaration(); 117 } 118 static if (name.length > 3 && name[0..3] == "gc_") 119 { 120 mixin("alias Declaration = " ~ name ~ ";"); 121 code ~= generateWrapper!(Declaration, ParamPos.back)(); 122 } 123 } 124 125 return code; 126 } 127 128 static enum ParamPos { front, back } 129 130 private string generateWrapper(alias Declaration, ParamPos pos = ParamPos.front)() 131 { 132 static size_t findParamIndex(string s) 133 { 134 assert (s[$-1] == ')'); 135 size_t brackets = 1; 136 while (brackets != 0) 137 { 138 s = s[0 .. $-1]; 139 if (s[$-1] == ')') 140 ++brackets; 141 if (s[$-1] == '(') 142 --brackets; 143 } 144 145 assert(s.length > 1); 146 return s.length - 1; 147 } 148 149 auto type_string = typeof(Declaration).stringof; 150 auto name = __traits(identifier, Declaration); 151 auto param_idx = findParamIndex(type_string); 152 153 static if (pos == ParamPos.front) 154 auto new_declaration = type_string[0 .. param_idx] ~ " " ~ name 155 ~ "Trace(string file, int line, string funcname, " 156 ~ type_string[param_idx+1 .. $]; 157 else static if (pos == ParamPos.back) 158 auto new_declaration = type_string[0 .. param_idx] ~ " " ~ name 159 ~ "Trace(" ~ type_string[param_idx+1 .. $-1] 160 ~ `, string file = "", int line = 0, string funcname = "")`; 161 else 162 static assert(0); 163 auto call_original = "return " 164 ~ __traits(identifier, Declaration) ~ "(" ~ Arguments!Declaration() ~ ");"; 165 166 return new_declaration ~ "\n{\n" ~ 167 accumulator ~ "\n" ~ 168 call_original ~ "\n" ~ 169 "}\n"; 170 } 171 172 string Arguments(alias Func)() 173 { 174 string result = ""; 175 176 static if (is(typeof(Func) PT == __parameters)) 177 { 178 foreach (idx, _; PT) 179 result ~= __traits(identifier, PT[idx .. idx + 1]) ~ ", "; 180 } 181 182 return result; 183 } 184 185 unittest 186 { 187 void foo(int x, double y) { } 188 static assert (Arguments!foo == "x, y, "); 189 }