]> git.llucax.com Git - personal/website.git/blob - source/blog/posts/2010/10/10-trying-cdgc-howto/0003-Add-precise-heap-scanning-support.patch
Add some missing posts
[personal/website.git] / source / blog / posts / 2010 / 10 / 10-trying-cdgc-howto / 0003-Add-precise-heap-scanning-support.patch
1 From 9d610d0a42cfef7b6379b9f0ee86356fcda10e19 Mon Sep 17 00:00:00 2001
2 From: Leandro Lucarella <llucax@gmail.com>
3 Date: Wed, 28 Jul 2010 18:17:08 -0300
4 Subject: [PATCH 3/4] Add precise heap scanning support
5
6 This is based on a patch[1] written by Vincent Lang (AKA wm4), which was
7 based in a David Simcha idea. The GC part of the patch is not applied, and
8 only the GC interface is patched, keeping the GC fully conservative.
9
10 [1] http://d.puremagic.com/issues/attachment.cgi?id=701
11 ---
12  object.di                                |   35 +++++
13  tango/core/Memory.d                      |   36 ++++--
14  tango/core/rt/compiler/dmd/object_.d     |  229 +++++++++++++++++++++++++++++-
15  tango/core/rt/compiler/dmd/rt/aaA.d      |    4 +-
16  tango/core/rt/compiler/dmd/rt/adi.d      |    4 +-
17  tango/core/rt/compiler/dmd/rt/lifetime.d |   85 +++++++++--
18  tango/core/rt/gc/basic/gc.d              |    6 +-
19  7 files changed, 364 insertions(+), 35 deletions(-)
20
21 diff --git a/object.di b/object.di
22 index 2131c16..979ed34 100644
23 --- a/object.di
24 +++ b/object.di
25 @@ -42,6 +42,29 @@ struct Interface
26      ptrdiff_t   offset;
27  }
28  
29 +struct PointerMap
30 +{
31 +    size_t[] bits = [1, 1, 0];
32 +
33 +    size_t size();
34 +    bool mustScanWordAt(size_t offset);
35 +    bool isPointerAt(size_t offset);
36 +    bool canUpdatePointers();
37 +}
38 +
39 +struct PointerMapBuilder
40 +{
41 +    private size_t[] m_bits = null;
42 +    private size_t m_size = 0;
43 +
44 +    void size(size_t bytes);
45 +    void mustScanWordAt(size_t offset);
46 +    void inlineAt(size_t offset, PointerMap pm);
47 +    PointerMap convertToPointerMap();
48 +}
49 +
50 +//const PointerMap conservativeBitMask = PointerMap([1, 1, 0]);
51 +
52  version (GNU){
53  }else version (DigitalMars)
54  {
55 @@ -76,6 +99,9 @@ class ClassInfo : Object
56          /// TypeInfo information about this class
57          TypeInfo typeinfo;
58      }
59 +    version (D_HavePointerMap) {
60 +        PointerMap pointermap;
61 +    }
62      /// finds the classinfo of the class with the given name
63      static ClassInfo find(char[] classname);
64      /// creates an instance of this class (works only if there is a constructor without arguments)
65 @@ -107,6 +133,7 @@ class TypeInfo
66      void[]   init();
67      /// flags, 1: has possible pointers into GC memory
68      uint     flags();
69 +    PointerMap pointermap();
70      /// offsets of the various elements
71      OffsetTypeInfo[] offTi();
72  }
73 @@ -131,6 +158,10 @@ class TypeInfo_Array : TypeInfo
74  {
75      /// typeinfo of the elements, might be null for basic arrays, it is safer to use next()
76      TypeInfo value;
77 +
78 +    //ensure derived array TypeInfos use correct method
79 +    //if this declaration is forgotten, e.g. TypeInfo_Ai will have a wrong vtbl entry
80 +    PointerMap pointermap();
81  }
82  
83  class TypeInfo_StaticArray : TypeInfo
84 @@ -176,6 +207,10 @@ class TypeInfo_Struct : TypeInfo
85      char[] function()   xtoString;
86  
87      uint m_flags;
88 +
89 +    version (D_HavePointerMap) {
90 +        PointerMap m_pointermap;
91 +    }
92  }
93  
94  class TypeInfo_Tuple : TypeInfo
95 diff --git a/tango/core/Memory.d b/tango/core/Memory.d
96 index 37da0e7..44dee1f 100644
97 --- a/tango/core/Memory.d
98 +++ b/tango/core/Memory.d
99 @@ -8,7 +8,6 @@
100   */
101  module tango.core.Memory;
102  
103 -
104  private
105  {
106      extern (C) void gc_init();
107 @@ -23,9 +22,9 @@ private
108      extern (C) uint gc_setAttr( void* p, uint a );
109      extern (C) uint gc_clrAttr( void* p, uint a );
110  
111 -    extern (C) void*  gc_malloc( size_t sz, uint ba = 0 );
112 -    extern (C) void*  gc_calloc( size_t sz, uint ba = 0 );
113 -    extern (C) void*  gc_realloc( void* p, size_t sz, uint ba = 0 );
114 +    extern (C) void*  gc_malloc( size_t sz, uint ba = 0, PointerMap bitMask = PointerMap.init);
115 +    extern (C) void*  gc_calloc( size_t sz, uint ba = 0, PointerMap bitMask = PointerMap.init);
116 +    extern (C) void*  gc_realloc( void* p, size_t sz, uint ba = 0, PointerMap bitMask = PointerMap.init);
117      extern (C) size_t gc_extend( void* p, size_t mx, size_t sz );
118      extern (C) size_t gc_reserve( size_t sz );
119      extern (C) void   gc_free( void* p );
120 @@ -57,6 +56,13 @@ private
121  /**
122   * This struct encapsulates all garbage collection functionality for the D
123   * programming language.
124 + *
125 + * Documentation of runtime configuration:
126 + *
127 + * The environment variable D_PRECISE_HEAP can be used to control the behavior
128 + * of the GC at runtime.
129 + *  D_PRECISE_HEAP=1 enable precise scanning
130 + *  D_PRECISE_HEAP=0 disable precise scanning (may save space because no bitmasks need to be stored)
131   */
132  struct GC
133  {
134 @@ -196,6 +202,7 @@ struct GC
135       * Params:
136       *  sz = The desired allocation size in bytes.
137       *  ba = A bitmask of the attributes to set on this block.
138 +     *  bitMask = The pointer offset information for precise heap scanning.
139       *
140       * Returns:
141       *  A reference to the allocated memory or null if insufficient memory
142 @@ -204,9 +211,10 @@ struct GC
143       * Throws:
144       *  OutOfMemoryException on allocation failure.
145       */
146 -    static void* malloc( size_t sz, uint ba = 0 )
147 +    static void* malloc( size_t sz, uint ba = 0,
148 +        PointerMap bitMask = PointerMap.init )
149      {
150 -        return gc_malloc( sz, ba );
151 +        return gc_malloc( sz, ba, bitMask );
152      }
153  
154  
155 @@ -221,6 +229,7 @@ struct GC
156       * Params:
157       *  sz = The desired allocation size in bytes.
158       *  ba = A bitmask of the attributes to set on this block.
159 +     *  bitMask = The pointer offset information for precise heap scanning.
160       *
161       * Returns:
162       *  A reference to the allocated memory or null if insufficient memory
163 @@ -229,9 +238,10 @@ struct GC
164       * Throws:
165       *  OutOfMemoryException on allocation failure.
166       */
167 -    static void* calloc( size_t sz, uint ba = 0 )
168 +    static void* calloc( size_t sz, uint ba = 0,
169 +        PointerMap bitMask = PointerMap.init )
170      {
171 -        return gc_calloc( sz, ba );
172 +        return gc_calloc( sz, ba, bitMask );
173      }
174  
175  
176 @@ -253,12 +263,15 @@ struct GC
177       * reallocation is required.  If ba is not zero and p references the head
178       * of a valid, known memory block then the bits in ba will replace those on
179       * the current memory block and will also be set on the new block if a
180 -     * reallocation is required.
181 +     * reallocation is required.  Similarly, if bitMask is non-null, then
182 +     * the bitmask for the current block will propagated to the new block.
183 +     * Otherwise, the bitmask provided will be propagated to the old block.
184       *
185       * Params:
186       *  p  = A pointer to the root of a valid memory block or to null.
187       *  sz = The desired allocation size in bytes.
188       *  ba = A bitmask of the attributes to set on this block.
189 +     *  bitMask = The pointer offset information for precise heap scanning.
190       *
191       * Returns:
192       *  A reference to the allocated memory on success or null if sz is
193 @@ -267,9 +280,10 @@ struct GC
194       * Throws:
195       *  OutOfMemoryException on allocation failure.
196       */
197 -    static void* realloc( void* p, size_t sz, uint ba = 0 )
198 +    static void* realloc( void* p, size_t sz, uint ba = 0,
199 +        PointerMap bitMask = PointerMap.init )
200      {
201 -        return gc_realloc( p, sz, ba );
202 +        return gc_realloc( p, sz, ba, bitMask );
203      }
204  
205  
206 diff --git a/tango/core/rt/compiler/dmd/object_.d b/tango/core/rt/compiler/dmd/object_.d
207 index 6a32856..51bea3c 100644
208 --- a/tango/core/rt/compiler/dmd/object_.d
209 +++ b/tango/core/rt/compiler/dmd/object_.d
210 @@ -147,6 +147,140 @@ struct Interface
211  }
212  
213  /**
214 + * Pointer map for precise heap scanning.
215 + * Format:
216 + *  PointerMap pm = typeid(T).pointermap;
217 + *  pm.bits = [header] ~ scan_bits ~ pointer_bits
218 + *  size_t header is the number of pointer sized units in T (T.sizeof/size_t.sizeof)
219 + *  size_t[] scan_bits is the bitmap; each bit covers size_t bytes of T, meaning:
220 + *      0: guaranteed not to be a pointer, don't scan
221 + *      1: possibly a pointer, must scan
222 + *  size_t[] pointer_bits is a second bitmap similar to scan_bits. If the
223 + *  corrsponding bit in scan_bits is 0, the bit is 0; otherwise its meaning is:
224 + *      0: pointer can not be moved, because it's possibly an integer
225 + *      1: pointer can be moved, the corresponding word is always a pointer
226 + *  Note that not the bit-arrays are concatenated, but the size_t arrays.
227 + * This implies all GC-aware pointers must be aligned on size_t boundaries.
228 + * The compiler won't set any bits for unaligned pointer fields.
229 + * The least significant bit of a size_t item is considered the first bit.
230 + * PointerMap.init is a conservative scanning mask equivelant to void*[]
231 + */
232 +struct PointerMap
233 +{
234 +    size_t[] bits = [1, 1, 0];
235 +
236 +    private const size_t BITS = size_t.sizeof * 8;
237 +
238 +    /// return size in bytes (aligned)
239 +    size_t size()
240 +    {
241 +        return bits[0] * size_t.sizeof;
242 +    }
243 +
244 +    private bool getbit(size_t offset, bool pointer_bit)
245 +    {
246 +        assert(offset < size);
247 +
248 +        if ((offset & (size_t.sizeof - 1)) != 0)
249 +            return false;
250 +
251 +        size_t elem = offset / size_t.sizeof;
252 +        size_t start = 1; //scan_bits offset
253 +        if (pointer_bit)
254 +            start += (bits[0] + BITS - 1) / BITS; //pointer_bits offset
255 +        return !!(bits[start + elem / BITS] & (1 << (elem % BITS)));
256 +    }
257 +
258 +    /// return if the (aligned) field starting at byte offset is a pointer
259 +    /// Warning: the GC may access the internal data structure directly instead
260 +    /// of using this method to make scanning faster
261 +    bool mustScanWordAt(size_t offset)
262 +    {
263 +        return getbit(offset, false);
264 +    }
265 +
266 +    /// return if the (aligned) field starting at byte offset is a moveable pointer
267 +    /// "moveable pointer" means that the memory block referenced by the pointer can
268 +    /// be moved by the GC (the pointer field will be updated with the new address)
269 +    bool isPointerAt(size_t offset)
270 +    {
271 +        return getbit(offset, true);
272 +    }
273 +
274 +    /// return true if and only if there are integer fields overlapping with pointer
275 +    /// fields in this type
276 +    bool canUpdatePointers()
277 +    {
278 +        auto len = (bits.length - 1) / 2;
279 +        return bits[1 .. 1 + len] == bits[1 + len .. $];
280 +    }
281 +
282 +}
283 +
284 +/// code for manually building PointerMaps
285 +/// separate struct from PointerMap because for some representations, it may be
286 +/// hard to handle arbitrary pointerAt() calls to update the internal data structure
287 +/// (think of pointer maps encoded as lists of runs etc.)
288 +/// xxx untested
289 +struct PointerMapBuilder
290 +{
291 +    private size_t[] m_bits = null;
292 +    private size_t m_size = 0;
293 +
294 +    private const size_t BITS = size_t.sizeof * 8;
295 +
296 +    /// set the underlying type's size in bytes
297 +    void size(size_t bytes)
298 +    {
299 +        size_t nelem = bytes / size_t.sizeof;
300 +        m_bits.length = 1 + ((nelem + BITS - 1) / BITS) * 2;
301 +        m_bits[] = 0;
302 +        m_bits[0] = nelem;
303 +        m_size = bytes;
304 +    }
305 +
306 +    /// mark the pointer sized field at byte offset as pointer
307 +    /// if the offset is unaligned, it does nothing
308 +    void mustScanWordAt(size_t offset)
309 +    {
310 +        assert(offset < m_size);
311 +
312 +        if ((offset & (size_t.sizeof - 1)) != 0)
313 +            return;
314 +
315 +        size_t elem = offset / size_t.sizeof;
316 +        m_bits[1 + elem / BITS] |= 1 << (elem % BITS);
317 +    }
318 +
319 +    /// starting at the given byte offset, call pointerAt() for each pointer in pm
320 +    void inlineAt(size_t offset, PointerMap pm)
321 +    {
322 +        assert(offset + pm.size <= m_size);
323 +
324 +        for (size_t n = 0; n < pm.size; n += size_t.sizeof)
325 +        {
326 +            if (pm.mustScanWordAt(n))
327 +                mustScanWordAt(offset + n);
328 +        }
329 +    }
330 +
331 +    /// create a PointerMap instance
332 +    /// accessing this PointerMapBuilder after calling this method is not allowed
333 +    PointerMap convertToPointerMap() {
334 +        //no un-moveable pointer stuff supported => imply all pointers are moveable
335 +        size_t len = (m_bits[0] + BITS - 1) / BITS;
336 +        assert(len == (m_bits.length - 1) / 2);
337 +        m_bits[1 + len .. $] = m_bits[1 .. 1 + len];
338 +
339 +        auto res = PointerMap(m_bits);
340 +        *this = PointerMapBuilder.init; //invalidate this instance
341 +        return res;
342 +    }
343 +}
344 +
345 +//static const PointerMap cPointerMapNoScan = PointerMap([1, 0, 0]);
346 +
347 +/**
348   * Runtime type information about a class. Can be retrieved for any class type
349   * or instance by using the .classinfo property.
350   * A pointer to this appears as the first entry in the class's vtbl[].
351 @@ -174,7 +308,11 @@ class ClassInfo : Object
352      static if (__VERSION__ >= 1045) {
353          TypeInfo typeinfo;
354      }
355 -    
356 +
357 +    version (D_HavePointerMap) {
358 +        PointerMap pointermap;
359 +    }
360 +
361      /**
362       * Search all modules for ClassInfo corresponding to classname.
363       * Returns: null if not found
364 @@ -294,6 +432,35 @@ class TypeInfo
365      /// Get flags for type: 1 means GC should scan for pointers
366      uint flags() { return 0; }
367  
368 +    /// Get a pointer to PointerMap; used for GC scanning
369 +    PointerMap pointermap() {
370 +        if (flags() & 1) {
371 +            return PointerMap.init;
372 +        } else {
373 +            //return cPointerMapNoScan;
374 +            //work around for dmd bug #4397 (triggers infinite recursion)
375 +            static size_t[3] g_arr;
376 +            static PointerMap pm;
377 +            pm.bits = g_arr;
378 +            pm.bits[0] = 1;
379 +            pm.bits[1] = 0;
380 +            pm.bits[2] = 0;
381 +            return pm;
382 +        }
383 +    }
384 +
385 +    //return PointerMap for a single, moveable pointer
386 +    //also just a workaround for dmd bug #4397; should be a const variable
387 +    private PointerMap exactpointer() {
388 +        static size_t[3] g_arr;
389 +        static PointerMap pm;
390 +        pm.bits = g_arr;
391 +        pm.bits[0] = 1;
392 +        pm.bits[1] = 1;
393 +        pm.bits[2] = 1;
394 +        return pm;
395 +    }
396 +
397      /// Get type information on the contents of the type; null if not available
398      OffsetTypeInfo[] offTi() { return null; }
399  }
400 @@ -319,6 +486,7 @@ class TypeInfo_Typedef : TypeInfo
401  
402      override TypeInfo next() { return base; }
403      override uint flags() { return base.flags(); }
404 +    override PointerMap pointermap() { return base.pointermap(); }
405      override void[] init() { return m_init.length ? m_init : base.init(); }
406  
407      TypeInfo base;
408 @@ -377,6 +545,7 @@ class TypeInfo_Pointer : TypeInfo
409  
410      override TypeInfo next() { return m_next; }
411      override uint flags() { return 1; }
412 +    override PointerMap pointermap() { return exactpointer(); }
413  
414      TypeInfo m_next;
415  }
416 @@ -456,6 +625,21 @@ class TypeInfo_Array : TypeInfo
417      }
418  
419      override uint flags() { return 1; }
420 +
421 +    override PointerMap pointermap()
422 +    {
423 +        //return static mask for arrays
424 +        //  word 0: length
425 +        //  word 1: pointer
426 +        //work around for dmd bug #4397 (triggers infinite recursion)
427 +        static size_t[3] g_arr;
428 +        static PointerMap pm;
429 +        pm.bits = g_arr;
430 +        pm.bits[0] = 2;
431 +        pm.bits[1] = 0b10;
432 +        pm.bits[2] = 0b10; //moveable
433 +        return pm;
434 +    }
435  }
436  
437  class TypeInfo_StaticArray : TypeInfo
438 @@ -540,6 +724,20 @@ class TypeInfo_StaticArray : TypeInfo
439      override TypeInfo next() { return value; }
440      override uint flags() { return value.flags(); }
441  
442 +    override PointerMap pointermap()
443 +    {
444 +        //assert(0);
445 +        //this is kind of a hack to make arrays of static arrays work
446 +        //e.g. T[2][] (typeid(T[2]) would be this instance)
447 +        //because the GC repeats GC bitmasks shorter than the allocation size,
448 +        //  this should work well
449 +        //it's a hack because pointermap() is supposed to return a map that
450 +        //  covers the whole type (i.e. doesn't rely on repeat)
451 +        //this also might prevent subtle bugs, when a static array is resized
452 +        //  as dynamic array, and the bitmask is reused (can that happen at all?)
453 +        return value.pointermap();
454 +    }
455 +
456      TypeInfo value;
457      size_t   len;
458  }
459 @@ -606,6 +804,7 @@ class TypeInfo_AssociativeArray : TypeInfo
460  
461      override TypeInfo next() { return value; }
462      override uint flags() { return 1; }
463 +    override PointerMap pointermap() { return exactpointer(); }
464  
465      TypeInfo value;
466      TypeInfo key;
467 @@ -677,6 +876,21 @@ class TypeInfo_Delegate : TypeInfo
468  
469      override uint flags() { return 1; }
470  
471 +    override PointerMap pointermap()
472 +    {
473 +        //return static mask for delegates
474 +        //  word 0: context pointer
475 +        //  word 1: function pointer (not scanned)
476 +        //work around for dmd bug #4397 (triggers infinite recursion)
477 +        static size_t[3] g_arr;
478 +        static PointerMap pm;
479 +        pm.bits = g_arr;
480 +        pm.bits[0] = 2;
481 +        pm.bits[1] = 0b01;
482 +        pm.bits[2] = 0b01; //moveable
483 +        return pm;
484 +    }
485 +
486      TypeInfo next;
487  }
488  
489 @@ -734,6 +948,7 @@ class TypeInfo_Class : TypeInfo
490      }
491  
492      override uint flags() { return 1; }
493 +    override PointerMap pointermap() { return exactpointer(); }
494  
495      override OffsetTypeInfo[] offTi()
496      {
497 @@ -803,6 +1018,7 @@ class TypeInfo_Interface : TypeInfo
498      }
499  
500      override uint flags() { return 1; }
501 +    override PointerMap pointermap() { return exactpointer(); }
502  
503      ClassInfo info;
504  }
505 @@ -898,6 +1114,12 @@ class TypeInfo_Struct : TypeInfo
506      char[] function()   xtoString;
507  
508      uint m_flags;
509 +
510 +    version (D_HavePointerMap) {
511 +        PointerMap m_pointermap;
512 +
513 +        override PointerMap pointermap() { return m_pointermap; }
514 +    }
515  }
516  
517  class TypeInfo_Tuple : TypeInfo
518 @@ -960,6 +1182,11 @@ class TypeInfo_Tuple : TypeInfo
519      {
520          assert(0);
521      }
522 +
523 +    override PointerMap pointermap()
524 +    {
525 +        assert(0);
526 +    }
527  }
528  
529  
530 diff --git a/tango/core/rt/compiler/dmd/rt/aaA.d b/tango/core/rt/compiler/dmd/rt/aaA.d
531 index e043524..9c0e04c 100644
532 --- a/tango/core/rt/compiler/dmd/rt/aaA.d
533 +++ b/tango/core/rt/compiler/dmd/rt/aaA.d
534 @@ -46,8 +46,8 @@ private
535          ALL_BITS = 0b1111_1111
536      }
537  
538 -    extern (C) void* gc_malloc( size_t sz, uint ba = 0 );
539 -    extern (C) void* gc_calloc( size_t sz, uint ba = 0 );
540 +    extern (C) void*  gc_malloc( size_t sz, uint ba = 0, PointerMap bitMask = PointerMap.init);
541 +    extern (C) void*  gc_calloc( size_t sz, uint ba = 0, PointerMap bitMask = PointerMap.init);
542      extern (C) void  gc_free( void* p );
543  }
544  
545 diff --git a/tango/core/rt/compiler/dmd/rt/adi.d b/tango/core/rt/compiler/dmd/rt/adi.d
546 index 0ed0ac9..d294f84 100644
547 --- a/tango/core/rt/compiler/dmd/rt/adi.d
548 +++ b/tango/core/rt/compiler/dmd/rt/adi.d
549 @@ -50,8 +50,8 @@ private
550          ALL_BITS = 0b1111_1111
551      }
552  
553 -    extern (C) void* gc_malloc( size_t sz, uint ba = 0 );
554 -    extern (C) void* gc_calloc( size_t sz, uint ba = 0 );
555 +    extern (C) void*  gc_malloc( size_t sz, uint ba = 0, PointerMap bitMask = PointerMap.init);
556 +    extern (C) void*  gc_calloc( size_t sz, uint ba = 0, PointerMap bitMask = PointerMap.init);
557      extern (C) void  gc_free( void* p );
558  }
559  
560 diff --git a/tango/core/rt/compiler/dmd/rt/lifetime.d b/tango/core/rt/compiler/dmd/rt/lifetime.d
561 index fd89ce7..022e452 100644
562 --- a/tango/core/rt/compiler/dmd/rt/lifetime.d
563 +++ b/tango/core/rt/compiler/dmd/rt/lifetime.d
564 @@ -57,8 +57,8 @@ private
565      extern (C) uint gc_setAttr( void* p, uint a );
566      extern (C) uint gc_clrAttr( void* p, uint a );
567  
568 -    extern (C) void*  gc_malloc( size_t sz, uint ba = 0 );
569 -    extern (C) void*  gc_calloc( size_t sz, uint ba = 0 );
570 +    extern (C) void*  gc_malloc( size_t sz, uint ba = 0, PointerMap bitMask = PointerMap.init);
571 +    extern (C) void*  gc_calloc( size_t sz, uint ba = 0, PointerMap bitMask = PointerMap.init);
572      extern (C) size_t gc_extend( void* p, size_t mx, size_t sz );
573      extern (C) void   gc_free( void* p );
574  
575 @@ -101,8 +101,13 @@ extern (C) Object _d_newclass(ClassInfo ci)
576      }
577      else
578      {
579 +        PointerMap pm;
580 +        version (D_HavePointerMap) {
581 +            pm = ci.pointermap;
582 +        }
583          p = gc_malloc(ci.init.length,
584 -                      BlkAttr.FINALIZE | (ci.flags & 2 ? BlkAttr.NO_SCAN : 0));
585 +                      BlkAttr.FINALIZE | (ci.flags & 2 ? BlkAttr.NO_SCAN : 0),
586 +                      pm);
587          debug(PRINTF) printf(" p = %p\n", p);
588      }
589  
590 @@ -210,7 +215,11 @@ extern (C) ulong _d_newarrayT(TypeInfo ti, size_t length)
591          }
592          else
593              size *= length;
594 -        p = gc_malloc(size + 1, !(ti.next.flags() & 1) ? BlkAttr.NO_SCAN : 0);
595 +        PointerMap pm;
596 +        version (D_HavePointerMap) {
597 +            pm = ti.next.pointermap();
598 +        }
599 +        p = gc_malloc(size + 1, !(ti.next.flags() & 1) ? BlkAttr.NO_SCAN : 0, pm);
600          debug(PRINTF) printf(" p = %p\n", p);
601          memset(p, 0, size);
602          result = cast(ulong)length + (cast(ulong)cast(uint)p << 32);
603 @@ -250,7 +259,11 @@ extern (C) ulong _d_newarrayiT(TypeInfo ti, size_t length)
604          }
605          else
606              size *= length;
607 -        auto p = gc_malloc(size + 1, !(ti.next.flags() & 1) ? BlkAttr.NO_SCAN : 0);
608 +        PointerMap pm;
609 +        version (D_HavePointerMap) {
610 +            pm = ti.next.pointermap();
611 +        }
612 +        auto p = gc_malloc(size + 1, !(ti.next.flags() & 1) ? BlkAttr.NO_SCAN : 0, pm);
613          debug(PRINTF) printf(" p = %p\n", p);
614          if (isize == 1)
615              memset(p, *cast(ubyte*)q, size);
616 @@ -580,7 +593,11 @@ body
617                              goto L1;
618                          }
619                      }
620 -                    newdata = cast(byte *)gc_malloc(newsize + 1, info.attr);
621 +                    PointerMap pm;
622 +                    version (D_HavePointerMap) {
623 +                        pm = ti.next.pointermap();
624 +                    }
625 +                    newdata = cast(byte *)gc_malloc(newsize + 1, info.attr, pm);
626                      newdata[0 .. size] = p.data[0 .. size];
627                  }
628               L1:
629 @@ -589,7 +606,11 @@ body
630          }
631          else
632          {
633 -            newdata = cast(byte *)gc_calloc(newsize + 1, !(ti.next.flags() & 1) ? BlkAttr.NO_SCAN : 0);
634 +            PointerMap pm;
635 +            version (D_HavePointerMap) {
636 +                pm = ti.next.pointermap();
637 +            }
638 +            newdata = cast(byte *)gc_calloc(newsize + 1, !(ti.next.flags() & 1) ? BlkAttr.NO_SCAN : 0, pm);
639          }
640      }
641      else
642 @@ -680,7 +701,11 @@ body
643                              goto L1;
644                          }
645                      }
646 -                    newdata = cast(byte *)gc_malloc(newsize + 1, info.attr);
647 +                    PointerMap pm;
648 +                    version (D_HavePointerMap) {
649 +                        pm = ti.next.pointermap();
650 +                    }
651 +                    newdata = cast(byte *)gc_malloc(newsize + 1, info.attr, pm);
652                      newdata[0 .. size] = p.data[0 .. size];
653                  L1: ;
654                  }
655 @@ -688,7 +713,11 @@ body
656          }
657          else
658          {
659 -            newdata = cast(byte *)gc_malloc(newsize + 1, !(ti.next.flags() & 1) ? BlkAttr.NO_SCAN : 0);
660 +            PointerMap pm;
661 +            version (D_HavePointerMap) {
662 +                pm = ti.next.pointermap();
663 +            }
664 +            newdata = cast(byte *)gc_malloc(newsize + 1, !(ti.next.flags() & 1) ? BlkAttr.NO_SCAN : 0, pm);
665          }
666  
667          auto q = initializer.ptr; // pointer to initializer
668 @@ -746,7 +775,11 @@ extern (C) long _d_arrayappendT(TypeInfo ti, Array *px, byte[] y)
669                  goto L1;
670              }
671          }
672 -        newdata = cast(byte *)gc_malloc(newCapacity(newlength, sizeelem) + 1, info.attr);
673 +        PointerMap pm;
674 +        version (D_HavePointerMap) {
675 +            pm = ti.next.pointermap();
676 +        }
677 +        newdata = cast(byte *)gc_malloc(newCapacity(newlength, sizeelem) + 1, info.attr, pm);
678          memcpy(newdata, px.data, length * sizeelem);
679          px.data = newdata;
680      }
681 @@ -844,10 +877,14 @@ extern (C) byte[] _d_arrayappendcT(TypeInfo ti, ref byte[] x, ...)
682                  goto L1;
683              }
684          }
685 -        debug(PRINTF) printf("_d_arrayappendcT(length = %d, newlength = %d, cap = %d)\n", length, newlength, info.size);
686 +        debug(PRINTF) printf("_d_arrayappendcT(length = %d, newlength = %d, cap = %d, ti=%.*s)\n", length, newlength, info.size, ti.toString());
687          auto newcap = newCapacity(newlength, sizeelem);
688          assert(newcap >= newlength * sizeelem);
689 -        newdata = cast(byte *)gc_malloc(newcap + 1, info.attr);
690 +        PointerMap pm;
691 +        version (D_HavePointerMap) {
692 +            pm = ti.next.pointermap();
693 +        }
694 +        newdata = cast(byte *)gc_malloc(newcap + 1, info.attr, pm);
695          memcpy(newdata, x.ptr, length * sizeelem);
696          (cast(void**)(&x))[1] = newdata;
697      }
698 @@ -1049,7 +1086,11 @@ body
699      if (!len)
700          return null;
701  
702 -    byte* p = cast(byte*)gc_malloc(len + 1, !(ti.next.flags() & 1) ? BlkAttr.NO_SCAN : 0);
703 +    PointerMap pm;
704 +    version (D_HavePointerMap) {
705 +        pm = ti.next.pointermap();
706 +    }
707 +    byte* p = cast(byte*)gc_malloc(len + 1, !(ti.next.flags() & 1) ? BlkAttr.NO_SCAN : 0, pm);
708      memcpy(p, x.ptr, xlen);
709      memcpy(p + xlen, y.ptr, ylen);
710      p[len] = 0;
711 @@ -1078,7 +1119,11 @@ extern (C) byte[] _d_arraycatnT(TypeInfo ti, uint n, ...)
712      if (!length)
713          return null;
714  
715 -    a = gc_malloc(length * size, !(ti.next.flags() & 1) ? BlkAttr.NO_SCAN : 0);
716 +    PointerMap pm;
717 +    version (D_HavePointerMap) {
718 +        pm = ti.next.pointermap();
719 +    }
720 +    a = gc_malloc(length * size, !(ti.next.flags() & 1) ? BlkAttr.NO_SCAN : 0, pm);
721      p = cast(byte[]*)(&n + 1);
722  
723      uint j = 0;
724 @@ -1112,7 +1157,11 @@ extern (C) void* _d_arrayliteralT(TypeInfo ti, size_t length, ...)
725          result = null;
726      else
727      {
728 -        result = gc_malloc(length * sizeelem, !(ti.next.flags() & 1) ? BlkAttr.NO_SCAN : 0);
729 +        PointerMap pm;
730 +        version (D_HavePointerMap) {
731 +            pm = ti.next.pointermap();
732 +        }
733 +        result = gc_malloc(length * sizeelem, !(ti.next.flags() & 1) ? BlkAttr.NO_SCAN : 0, pm);
734  
735          va_list q;
736          va_start!(size_t)(q, length);
737 @@ -1165,7 +1214,11 @@ body
738      {
739          auto sizeelem = ti.next.tsize();                // array element size
740          auto size = a.length * sizeelem;
741 -        r.ptr = gc_malloc(size, !(ti.next.flags() & 1) ? BlkAttr.NO_SCAN : 0);
742 +        PointerMap pm;
743 +        version (D_HavePointerMap) {
744 +            pm = ti.next.pointermap();
745 +        }
746 +        r.ptr = gc_malloc(size, !(ti.next.flags() & 1) ? BlkAttr.NO_SCAN : 0, pm);
747          r.length = a.length;
748          memcpy(r.ptr, a.ptr, size);
749      }
750 diff --git a/tango/core/rt/gc/basic/gc.d b/tango/core/rt/gc/basic/gc.d
751 index bcc91b8..9ed4197 100644
752 --- a/tango/core/rt/gc/basic/gc.d
753 +++ b/tango/core/rt/gc/basic/gc.d
754 @@ -144,17 +144,17 @@ extern (C) uint gc_clrAttr( void* p, uint a )
755      return _gc.clrAttr( p, a );
756  }
757  
758 -extern (C) void* gc_malloc( size_t sz, uint ba = 0 )
759 +extern (C) void* gc_malloc( size_t sz, uint ba = 0, PointerMap bitMask = PointerMap.init)
760  {
761      return _gc.malloc( sz, ba );
762  }
763  
764 -extern (C) void* gc_calloc( size_t sz, uint ba = 0 )
765 +extern (C) void* gc_calloc( size_t sz, uint ba = 0, PointerMap bitMask = PointerMap.init)
766  {
767      return _gc.calloc( sz, ba );
768  }
769  
770 -extern (C) void* gc_realloc( void* p, size_t sz, uint ba = 0 )
771 +extern (C) void* gc_realloc( void* p, size_t sz, uint ba = 0, PointerMap bitMask = PointerMap.init)
772  {
773      return _gc.realloc( p, sz, ba );
774  }
775 -- 
776 1.7.1
777