Mercurial > projects > ldc
comparison druntime/src/compiler/ldc/memory.d @ 759:d3eb054172f9
Added copy of druntime from DMD 2.020 modified for LDC.
author | Tomas Lindquist Olsen <tomas.l.olsen@gmail.com> |
---|---|
date | Tue, 11 Nov 2008 01:52:37 +0100 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
758:f04dde6e882c | 759:d3eb054172f9 |
---|---|
1 /** | |
2 * This module exposes functionality for inspecting and manipulating memory. | |
3 * | |
4 * Copyright: Copyright (C) 2005-2006 Digital Mars, www.digitalmars.com. | |
5 * All rights reserved. | |
6 * License: | |
7 * This software is provided 'as-is', without any express or implied | |
8 * warranty. In no event will the authors be held liable for any damages | |
9 * arising from the use of this software. | |
10 * | |
11 * Permission is granted to anyone to use this software for any purpose, | |
12 * including commercial applications, and to alter it and redistribute it | |
13 * freely, in both source and binary form, subject to the following | |
14 * restrictions: | |
15 * | |
16 * o The origin of this software must not be misrepresented; you must not | |
17 * claim that you wrote the original software. If you use this software | |
18 * in a product, an acknowledgment in the product documentation would be | |
19 * appreciated but is not required. | |
20 * o Altered source versions must be plainly marked as such, and must not | |
21 * be misrepresented as being the original software. | |
22 * o This notice may not be removed or altered from any source | |
23 * distribution. | |
24 * Authors: Walter Bright, Sean Kelly | |
25 */ | |
26 module memory; | |
27 | |
28 version = GC_Use_Dynamic_Ranges; | |
29 | |
30 // does Posix suffice? | |
31 version(Posix) | |
32 { | |
33 version = GC_Use_Data_Proc_Maps; | |
34 } | |
35 | |
36 version(GC_Use_Data_Proc_Maps) | |
37 { | |
38 version(Posix) {} else { | |
39 static assert(false, "Proc Maps only supported on Posix systems"); | |
40 } | |
41 | |
42 version( D_Version2 ) | |
43 { | |
44 private import stdc.posix.unistd; | |
45 private import stdc.posix.fcntl; | |
46 private import stdc.string; | |
47 } | |
48 else | |
49 { | |
50 private import tango.stdc.posix.unistd; | |
51 private import tango.stdc.posix.fcntl; | |
52 private import tango.stdc.string; | |
53 } | |
54 | |
55 version = GC_Use_Dynamic_Ranges; | |
56 } | |
57 | |
58 private | |
59 { | |
60 version( linux ) | |
61 { | |
62 //version = SimpleLibcStackEnd; | |
63 | |
64 version( SimpleLibcStackEnd ) | |
65 { | |
66 extern (C) extern void* __libc_stack_end; | |
67 } | |
68 else | |
69 { | |
70 version( D_Version2 ) | |
71 import stdc.posix.dlfcn; | |
72 else | |
73 import tango.stdc.posix.dlfcn; | |
74 } | |
75 } | |
76 version(LDC) | |
77 { | |
78 pragma(intrinsic, "llvm.frameaddress") | |
79 { | |
80 void* llvm_frameaddress(uint level=0); | |
81 } | |
82 } | |
83 } | |
84 | |
85 | |
86 /** | |
87 * | |
88 */ | |
89 extern (C) void* rt_stackBottom() | |
90 { | |
91 version( Win32 ) | |
92 { | |
93 void* bottom; | |
94 asm | |
95 { | |
96 mov EAX, FS:4; | |
97 mov bottom, EAX; | |
98 } | |
99 return bottom; | |
100 } | |
101 else version( linux ) | |
102 { | |
103 version( SimpleLibcStackEnd ) | |
104 { | |
105 return __libc_stack_end; | |
106 } | |
107 else | |
108 { | |
109 // See discussion: http://autopackage.org/forums/viewtopic.php?t=22 | |
110 static void** libc_stack_end; | |
111 | |
112 if( libc_stack_end == libc_stack_end.init ) | |
113 { | |
114 void* handle = dlopen( null, RTLD_NOW ); | |
115 libc_stack_end = cast(void**) dlsym( handle, "__libc_stack_end" ); | |
116 dlclose( handle ); | |
117 } | |
118 return *libc_stack_end; | |
119 } | |
120 } | |
121 else version( darwin ) | |
122 { | |
123 // darwin has a fixed stack bottom | |
124 return cast(void*) 0xc0000000; | |
125 } | |
126 else | |
127 { | |
128 static assert( false, "Operating system not supported." ); | |
129 } | |
130 } | |
131 | |
132 | |
133 /** | |
134 * | |
135 */ | |
136 extern (C) void* rt_stackTop() | |
137 { | |
138 version(LDC) | |
139 { | |
140 return llvm_frameaddress(); | |
141 } | |
142 else version( D_InlineAsm_X86 ) | |
143 { | |
144 asm | |
145 { | |
146 naked; | |
147 mov EAX, ESP; | |
148 ret; | |
149 } | |
150 } | |
151 else | |
152 { | |
153 static assert( false, "Architecture not supported." ); | |
154 } | |
155 } | |
156 | |
157 | |
158 private | |
159 { | |
160 version( Win32 ) | |
161 { | |
162 extern (C) | |
163 { | |
164 extern int _data_start__; | |
165 extern int _bss_end__; | |
166 | |
167 alias _data_start__ Data_Start; | |
168 alias _bss_end__ Data_End; | |
169 } | |
170 } | |
171 else version( linux ) | |
172 { | |
173 extern (C) | |
174 { | |
175 extern int _data; | |
176 extern int __data_start; | |
177 extern int _end; | |
178 extern int _data_start__; | |
179 extern int _data_end__; | |
180 extern int _bss_start__; | |
181 extern int _bss_end__; | |
182 extern int __fini_array_end; | |
183 } | |
184 | |
185 alias __data_start Data_Start; | |
186 alias _end Data_End; | |
187 } | |
188 | |
189 version( GC_Use_Dynamic_Ranges ) | |
190 { | |
191 version( D_Version2 ) | |
192 private import stdc.stdlib; | |
193 else | |
194 private import tango.stdc.stdlib; | |
195 | |
196 struct DataSeg | |
197 { | |
198 void* beg; | |
199 void* end; | |
200 } | |
201 | |
202 DataSeg* allSegs = null; | |
203 size_t numSegs = 0; | |
204 | |
205 extern (C) void _d_gc_add_range( void* beg, void* end ) | |
206 { | |
207 void* ptr = realloc( allSegs, (numSegs + 1) * DataSeg.sizeof ); | |
208 | |
209 if( ptr ) // if realloc fails, we have problems | |
210 { | |
211 allSegs = cast(DataSeg*) ptr; | |
212 allSegs[numSegs].beg = beg; | |
213 allSegs[numSegs].end = end; | |
214 numSegs++; | |
215 } | |
216 } | |
217 | |
218 extern (C) void _d_gc_remove_range( void* beg ) | |
219 { | |
220 for( size_t pos = 0; pos < numSegs; ++pos ) | |
221 { | |
222 if( beg == allSegs[pos].beg ) | |
223 { | |
224 while( ++pos < numSegs ) | |
225 { | |
226 allSegs[pos-1] = allSegs[pos]; | |
227 } | |
228 numSegs--; | |
229 return; | |
230 } | |
231 } | |
232 } | |
233 } | |
234 | |
235 alias void delegate( void*, void* ) scanFn; | |
236 | |
237 void* dataStart, dataEnd; | |
238 } | |
239 | |
240 | |
241 /** | |
242 * | |
243 */ | |
244 extern (C) void rt_scanStaticData( scanFn scan ) | |
245 { | |
246 scan( dataStart, dataEnd ); | |
247 | |
248 version( GC_Use_Dynamic_Ranges ) | |
249 { | |
250 for( size_t pos = 0; pos < numSegs; ++pos ) | |
251 { | |
252 scan( allSegs[pos].beg, allSegs[pos].end ); | |
253 } | |
254 } | |
255 } | |
256 | |
257 void initStaticDataPtrs() | |
258 { | |
259 version( D_Version2 ) | |
260 enum { int S = (void*).sizeof } | |
261 else | |
262 const int S = (void*).sizeof; | |
263 | |
264 // Can't assume the input addresses are word-aligned | |
265 static void* adjust_up( void* p ) | |
266 { | |
267 return p + ((S - (cast(size_t)p & (S-1))) & (S-1)); // cast ok even if 64-bit | |
268 } | |
269 | |
270 static void * adjust_down( void* p ) | |
271 { | |
272 return p - (cast(size_t) p & (S-1)); | |
273 } | |
274 | |
275 version( Win32 ) | |
276 { | |
277 dataStart = adjust_up( &Data_Start ); | |
278 dataEnd = adjust_down( &Data_End ); | |
279 } | |
280 else version( GC_Use_Data_Proc_Maps ) | |
281 { | |
282 // TODO: Exclude zero-mapped regions | |
283 | |
284 int fd = open("/proc/self/maps", O_RDONLY); | |
285 int count; // %% need to configure ret for read.. | |
286 char buf[2024]; | |
287 char* p; | |
288 char* e; | |
289 char* s; | |
290 void* start; | |
291 void* end; | |
292 | |
293 p = buf.ptr; | |
294 if (fd != -1) | |
295 { | |
296 while ( (count = read(fd, p, buf.sizeof - (p - buf.ptr))) > 0 ) | |
297 { | |
298 e = p + count; | |
299 p = buf.ptr; | |
300 while (true) | |
301 { | |
302 s = p; | |
303 while (p < e && *p != '\n') | |
304 p++; | |
305 if (p < e) | |
306 { | |
307 // parse the entry in [s, p) | |
308 static if( S == 4 ) | |
309 { | |
310 enum Ofs | |
311 { | |
312 Write_Prot = 19, | |
313 Start_Addr = 0, | |
314 End_Addr = 9, | |
315 Addr_Len = 8, | |
316 } | |
317 } | |
318 else static if( S == 8 ) | |
319 { | |
320 enum Ofs | |
321 { | |
322 Write_Prot = 35, | |
323 Start_Addr = 0, | |
324 End_Addr = 9, | |
325 Addr_Len = 17, | |
326 } | |
327 } | |
328 else | |
329 { | |
330 static assert( false ); | |
331 } | |
332 | |
333 // %% this is wrong for 64-bit: | |
334 // uint strtoul(char *,char **,int); | |
335 | |
336 if( s[Ofs.Write_Prot] == 'w' ) | |
337 { | |
338 s[Ofs.Start_Addr + Ofs.Addr_Len] = '\0'; | |
339 s[Ofs.End_Addr + Ofs.Addr_Len] = '\0'; | |
340 start = cast(void*) strtoul(s + Ofs.Start_Addr, null, 16); | |
341 end = cast(void*) strtoul(s + Ofs.End_Addr, null, 16); | |
342 | |
343 // 1. Exclude anything overlapping [dataStart, dataEnd) | |
344 // 2. Exclude stack | |
345 if ( ( !dataEnd || | |
346 !( dataStart >= start && dataEnd <= end ) ) && | |
347 !( &buf[0] >= start && &buf[0] < end ) ) | |
348 { | |
349 // we already have static data from this region. anything else | |
350 // is heap (%% check) | |
351 debug (ProcMaps) printf("Adding map range %p 0%p\n", start, end); | |
352 _d_gc_add_range(start, end); | |
353 } | |
354 } | |
355 p++; | |
356 } | |
357 else | |
358 { | |
359 count = p - s; | |
360 memmove(buf.ptr, s, count); | |
361 p = buf.ptr + count; | |
362 break; | |
363 } | |
364 } | |
365 } | |
366 close(fd); | |
367 } | |
368 } | |
369 else version(linux) | |
370 { | |
371 dataStart = adjust_up( &Data_Start ); | |
372 dataEnd = adjust_down( &Data_End ); | |
373 } | |
374 else | |
375 { | |
376 static assert( false, "Operating system not supported." ); | |
377 } | |
378 } |