1 module object;
2 
3 import util;
4 import rtoslink;
5 import lifetime.throwable;
6 
7 version(LWDR_DynamicArray)
8 public import lifetime.array_ : _d_arraysetlengthTImpl;
9 
10 public import rt.arrcast : __ArrayCast;
11 
12 version (D_LP64)
13 {
14     alias size_t = ulong;
15     alias ptrdiff_t = long;
16 }
17 else
18 {
19     alias size_t = uint;
20     alias ptrdiff_t = int;
21 }
22 
23 alias sizediff_t = ptrdiff_t; //For backwards compatibility only.
24 
25 alias hash_t = size_t; //For backwards compatibility only.
26 alias equals_t = bool; //For backwards compatibility only.
27 
28 alias string  = immutable(char)[];
29 alias wstring = immutable(wchar)[];
30 alias dstring = immutable(dchar)[];
31 
32 /// assert(bool exp) was called
33 extern(C) void _d_assert(string f, uint l) { rtosbackend_assert(f, l); }
34 /// assert(bool exp, string msg) was called
35 extern(C) void _d_assert_msg(string msg, string f, uint l) { rtosbackend_assertmsg(msg, f, l); }
36 /// A D array was incorrectly accessed
37 extern(C) void _d_arraybounds(string f, size_t l) {rtosbackend_arrayBoundFailure(f, l);}
38 
39 extern(C) bool _xopEquals(in void*, in void*) { return false; }
40 extern(C) int _xopCmp(in void*, in void*) { return 0; }
41 
42 /// Base Object class. All other classes implicitly inherit this.
43 class Object 
44 {
45 	/// Convert Object to human readable string
46 	string toString() { return "Object"; }
47 	/// Compute hash function for Object
48 	size_t toHash() @trusted nothrow
49 	{
50 		auto addr = cast(size_t)cast(void*)this;
51 		return addr ^ (addr >>> 4);
52 	}
53 	
54     /// Compare against another object. NOT IMPLEMENTED!
55 	int opCmp(Object o) { assert(false, "not implemented"); }
56     /// Check equivalence againt another object
57 	bool opEquals(Object o) { return this is o; }
58 	
59     /++ Object factory. NOT IMPLEMENTED!
60     ++/
61 	static Object factory(string classname) { return null; }
62 
63     version(LWDR_Sync)
64 	{
65         interface Monitor 
66 	    {
67             /// Lock the monitor
68             void lock();
69             /// Unlock the monitor
70             void unlock();
71 	    }
72 	}
73 }
74 
75 /// Compare to objects
76 bool opEquals(Object lhs, Object rhs)
77 {
78     // If aliased to the same object or both null => equal
79     if (lhs is rhs) return true;
80 
81     // If either is null => non-equal
82     if (lhs is null || rhs is null) return false;
83 
84     if (!lhs.opEquals(rhs)) return false;
85 
86     // If same exact type => one call to method opEquals
87     if (typeid(lhs) is typeid(rhs) ||
88         !__ctfe && typeid(lhs).opEquals(typeid(rhs)))
89             /* CTFE doesn't like typeid much. 'is' works, but opEquals doesn't
90             (issue 7147). But CTFE also guarantees that equal TypeInfos are
91             always identical. So, no opEquals needed during CTFE. */
92     {
93         return true;
94     }
95 
96     // General case => symmetric calls to method opEquals
97     return rhs.opEquals(lhs);
98 }
99 
100 /************************
101 * Returns true if lhs and rhs are equal.
102 */
103 bool opEquals(const Object lhs, const Object rhs)
104 {
105     // A hack for the moment.
106     return opEquals(cast()lhs, cast()rhs);
107 }
108 
109 /// Raw implementation of an interface
110 struct Interface
111 {
112     TypeInfo_Class   classinfo;  /// .classinfo for this interface (not for containing class)
113     void*[]     vtbl;
114     size_t      offset;     /// offset to Interface 'this' from Object 'this'
115 }
116 
117 /**
118  * Array of pairs giving the offset and type information for each
119  * member in an aggregate.
120  */
121 struct OffsetTypeInfo
122 {
123     size_t   offset;    /// Offset of member from start of object
124     TypeInfo ti;        /// TypeInfo for this member
125 }
126 //enum immutable(void)* rtinfoHasPointers = cast(void*)1;
127 
128 version(LWDR_DynamicArray)
129 {
130     version = LWDR_INTERNAL_ti_next;
131 }
132 
133 /// TypeInfo contains necessary RTTI for a target type.
134 class TypeInfo 
135 {
136     /// Compares two instances for equality.
137 	bool equals(in void* p1, in void* p2) const { return p1 == p2; }
138 
139     /// Returns size of the type.
140     @property size_t tsize() nothrow pure const @safe @nogc { return 0; }
141 
142 	/** Get TypeInfo for 'next' type, as defined by what kind of type this is,
143     null if none. */
144     version(LWDR_INTERNAL_ti_next)
145     @property inout(TypeInfo) next() nothrow pure inout @nogc { return null; }
146 
147     /**
148 	* Return default initializer.  If the type should be initialized to all
149 	* zeros, an array with a null ptr and a length equal to the type size will
150 	* be returned. For static arrays, this returns the default initializer for
151 	* a single element of the array, use `tsize` to get the correct size.
152 	*/
153     abstract const(void)[] initializer() nothrow pure const @safe @nogc;
154 }
155 
156 class TypeInfo_Enum : TypeInfo 
157 {
158 	TypeInfo base;
159 	string name;
160 	void[] m_init; 
161 	
162 	override bool equals(in void* p1, in void* p2) const
163 	{ return base.equals(p1, p2); }
164     override @property size_t tsize() nothrow pure const { return base.tsize; }
165 
166 	override const(void)[] initializer() const
167     { return m_init.length ? m_init : base.initializer(); }
168 
169     version(LWDR_INTERNAL_ti_next)
170     override @property inout(TypeInfo) next() nothrow pure inout 
171 	{ return base.next; }
172 }
173 
174 class TypeInfo_Pointer : TypeInfo 
175 { 
176     TypeInfo m_next; 
177 
178     override bool equals(in void* p1, in void* p2) const
179 	{ return *cast(void**)p1 == *cast(void**)p2; }
180     override @property size_t tsize() nothrow pure const { return (void*).sizeof; }
181 
182 	override const(void)[] initializer() const @trusted
183     { return (cast(void *)null)[0 .. (void*).sizeof]; }
184 
185     version(LWDR_INTERNAL_ti_next)
186     override @property inout(TypeInfo) next() nothrow pure inout 
187 	{ return m_next; }
188 }
189 
190 class TypeInfo_Array : TypeInfo 
191 {
192 	TypeInfo value;
193 
194     override bool equals(in void* p1, in void* p2) const
195 	{
196         void[] a1 = *cast(void[]*)p1;
197         void[] a2 = *cast(void[]*)p2;
198         if(a1.length != a2.length) return false;
199         immutable sz = value.tsize;
200         foreach(size_t i; 0 .. a1.length)
201             if(!value.equals(a1.ptr + i * sz, a2.ptr + i * sz))
202                 return false;
203         return true;
204 	}
205 
206     override @property size_t tsize() nothrow pure const
207     { return (void[]).sizeof; }
208 
209 	override const(void)[] initializer() const @trusted
210     { return (cast(void *)null)[0 .. (void[]).sizeof]; }
211 
212     version(LWDR_INTERNAL_ti_next)
213     override @property inout(TypeInfo) next() nothrow pure inout
214     { return value; }
215 }
216 
217 class TypeInfo_StaticArray : TypeInfo 
218 { 
219 	TypeInfo value;
220 	size_t len;
221 
222 	override bool equals(in void* p1, in void* p2) const
223     {
224         size_t sz = value.tsize;
225 
226         for (size_t u = 0; u < len; u++)
227             if (!value.equals(p1 + u * sz, p2 + u * sz))
228                 return false;
229         return true;
230     }
231 
232     override @property size_t tsize() nothrow pure const
233     { return len * value.tsize; }
234 
235     override const(void)[] initializer() nothrow pure const
236     { return value.initializer(); }
237 
238     version(LWDR_INTERNAL_ti_next)
239     override @property inout(TypeInfo) next() nothrow pure inout 
240 	{ return value; }
241 }
242 
243 class TypeInfo_AssociativeArray : TypeInfo {
244 	TypeInfo value, key;
245 
246 	override const(void)[] initializer() const @trusted
247     { return (cast(void *)null)[0 .. (char[int]).sizeof]; }
248 
249     version(LWDR_INTERNAL_ti_next)
250     override @property inout(TypeInfo) next() nothrow pure inout { return value; }
251 }
252 
253 class TypeInfo_Vector : TypeInfo 
254 {
255     TypeInfo base;
256 
257     override bool equals(in void* p1, in void* p2) const { return base.equals(p1, p2); }
258 
259 	override const(void)[] initializer() nothrow pure const
260     { return base.initializer(); }
261 
262     version(LWDR_INTERNAL_ti_next)
263     override @property inout(TypeInfo) next() nothrow pure inout 
264 	{ return base.next; }
265 }
266 
267 class TypeInfo_Function : TypeInfo 
268 {
269 	string deco;
270 
271     override const(void)[] initializer() const @safe
272     {
273         return null;
274     }
275 }
276 
277 class TypeInfo_Delegate : TypeInfo 
278 {
279 	string deco; 
280 
281     override bool equals(in void* p1, in void* p2) const
282     {
283         auto dg1 = *cast(void delegate()*)p1;
284         auto dg2 = *cast(void delegate()*)p2;
285         return dg1 == dg2;
286     }
287 
288     override const(void)[] initializer() const @trusted
289     {
290         return (cast(void *)null)[0 .. (int delegate()).sizeof];
291     }
292 }
293 
294 //class TypeInfo_v : TypeInfo { const: nothrow: pure: @trusted: }
295 
296 class TypeInfo_Interface : TypeInfo 
297 {
298 	TypeInfo_Class info;
299 	
300 	override bool equals(in void* p1, in void* p2) const
301     {
302         Interface* pi = **cast(Interface ***)*cast(void**)p1;
303         Object o1 = cast(Object)(*cast(void**)p1 - pi.offset);
304         pi = **cast(Interface ***)*cast(void**)p2;
305         Object o2 = cast(Object)(*cast(void**)p2 - pi.offset);
306 
307         return o1 == o2 || (o1 && o1.opCmp(o2) == 0);
308     }
309 
310 	override const(void)[] initializer() const @trusted
311     {
312         return (cast(void *)null)[0 .. Object.sizeof];
313     }
314 
315     override @property size_t tsize() nothrow pure const
316     {
317         return Object.sizeof;
318     }
319 }
320 
321 class TypeInfo_Tuple : TypeInfo
322 {
323     TypeInfo[] elements;
324 
325 	override bool opEquals(Object o)
326     {
327         if (this is o)
328             return true;
329 
330         auto t = cast(const TypeInfo_Tuple)o;
331         if (t && elements.length == t.elements.length)
332         {
333             for (size_t i = 0; i < elements.length; i++)
334                 if (elements[i] != t.elements[i])
335                     return false;
336             return true;
337         }
338         return false;
339     }
340 
341 	override @property size_t tsize() nothrow pure const
342     {
343         assert(0);
344     }
345 
346     override const(void)[] initializer() const @trusted
347     {
348         assert(0);
349     }
350 }
351 
352 class TypeInfo_Class : TypeInfo 
353 {
354 	ubyte[] m_init; /// class static initializer (length gives class size)
355 	string name; /// name of class
356 	void*[] vtbl; // virtual function pointer table
357 	Interface[] interfaces;
358 	TypeInfo_Class base;
359 	void* destructor;
360 	void function(Object) classInvariant;
361 	uint m_flags;
362 	void* deallocator;
363 	void*[] m_offTi;
364 	void function(Object) defaultConstructor;
365 	immutable(void)* rtInfo;
366 
367 	override @property size_t tsize() nothrow pure const
368     { return Object.sizeof; }
369 
370 	override bool equals(in void* p1, in void* p2) const
371     {
372         Object o1 = *cast(Object*)p1;
373         Object o2 = *cast(Object*)p2;
374 
375         return (o1 is o2) || (o1 && o1.opEquals(o2));
376     }
377 
378 	override const(void)[] initializer() nothrow pure const @safe
379     {
380         return m_init;
381     }
382 }
383 alias ClassInfo = TypeInfo_Class;
384 
385 class TypeInfo_Const : TypeInfo {
386 	size_t getHash(scope const void*) const nothrow { return 0; }
387 	TypeInfo base; 
388 
389     override bool equals(in void *p1, in void *p2) const { return base.equals(p1, p2); }
390 
391     override @property size_t tsize() nothrow pure const { return base.tsize; }
392 
393     version(LWDR_INTERNAL_ti_next)
394     override @property inout(TypeInfo) next() nothrow pure inout 
395 	{ return base.next; }
396 
397 	override const(void)[] initializer() nothrow pure const
398     { return base.initializer(); }
399 }
400 
401 class TypeInfo_Struct : TypeInfo {
402 	string name;
403 	void[] m_init;
404 	void* xtohash;
405 	void* xopequals;
406 	void* xopcmp;
407 	void* xtostring;
408 	uint flags;
409 	union {
410 		void function(void*) dtor;
411 		void function(void*, const TypeInfo_Struct) xdtor;
412 	}
413 	void function(void*) postblit;
414 	uint align_;
415 	immutable(void)* rtinfo;
416 
417     override bool equals(in void* p1, in void* p2) @trusted pure nothrow const
418     {
419         if (!p1 || !p2)
420             return false;
421         else if (xopequals)
422             return (*cast(bool function(in void*, in void*) pure nothrow @safe *)xopequals)(p1, p2);
423         else if (p1 == p2)
424             return true;
425         else
426 		{
427             immutable len = m_init.length;
428             auto p1B = cast(ubyte[])p1[0..len];
429             auto p2B = cast(ubyte[])p2[0..len];
430             foreach(i; 0 .. len)
431 			    if(p1B[i] != p2B[i]) 
432                     return false;
433             return true;
434 		}
435     }
436 
437     override @property size_t tsize() nothrow pure const
438     {
439         return initializer().length;
440     }
441 
442     override const(void)[] initializer() nothrow pure const @safe
443     {
444         return m_init;
445     }
446 }
447 
448 class TypeInfo_Invariant : TypeInfo_Const {}
449 class TypeInfo_Shared : TypeInfo_Const {}
450 class TypeInfo_Inout : TypeInfo_Const {}
451 
452 class Throwable : Object 
453 {
454 	interface TraceInfo
455 	{
456 		int opApply(scope int delegate(ref const(char[]))) const;
457 		int opApply(scope int delegate(ref size_t, ref const(char[]))) const;
458 		string toString() const;
459 	}
460 	
461 	string msg;
462 	string file;
463 	size_t line;
464 	TraceInfo info;
465 	
466 	private Throwable nextInChain;
467 	
468 	private uint _refcount;
469 	
470 	@property inout(Throwable) next() @safe inout return scope pure nothrow @nogc { return nextInChain; }
471 	@property void next(Throwable tail) @safe scope nothrow @nogc
472     {
473         if (tail && tail._refcount)
474             ++tail._refcount;           // increment the replacement *first*
475 
476         auto n = nextInChain;
477         nextInChain = null;             // sever the tail before deleting it
478 
479         if (n && n._refcount)
480             _d_delThrowable(n);         // now delete the old tail
481 
482         nextInChain = tail;             // and set the new tail
483     }
484 	 @system @nogc final pure nothrow ref uint refcount() return { return _refcount; }
485 	 int opApply(scope int delegate(Throwable) dg)
486     {
487         int result = 0;
488         for (Throwable t = this; t; t = t.nextInChain)
489         {
490             result = dg(t);
491             if (result)
492                 break;
493         }
494         return result;
495     }
496 	static @__future @system @nogc pure nothrow Throwable chainTogether(return scope Throwable e1, return scope Throwable e2)
497     {
498         if (!e1)
499             return e2;
500         if (!e2)
501             return e1;
502         if (e2.refcount())
503             ++e2.refcount();
504 
505         for (auto e = e1; 1; e = e.nextInChain)
506         {
507             if (!e.nextInChain)
508             {
509                 e.nextInChain = e2;
510                 break;
511             }
512         }
513         return e1;
514     }
515 	@nogc @safe pure nothrow this(string msg, Throwable nextInChain = null)
516     {
517         this.msg = msg;
518         this.nextInChain = nextInChain;
519         //this.info = _d_traceContext();
520     }
521 	@nogc @safe pure nothrow this(string msg, string file, size_t line, Throwable nextInChain = null)
522     {
523         this(msg, nextInChain);
524         this.file = file;
525         this.line = line;
526         //this.info = _d_traceContext();
527     }
528 	@trusted nothrow ~this()
529     {
530         if (nextInChain && nextInChain._refcount)
531             _d_delThrowable(nextInChain);
532     }
533 	
534 	@__future const(char)[] message() const
535     {
536         return this.msg;
537     }
538 }
539 
540 class Exception : Throwable
541 {
542     @nogc @safe pure nothrow this(string msg, string file = __FILE__, size_t line = __LINE__, Throwable nextInChain = null)
543     {
544         super(msg, file, line, nextInChain);
545     }
546 
547     @nogc @safe pure nothrow this(string msg, Throwable nextInChain, string file = __FILE__, size_t line = __LINE__)
548     {
549         super(msg, file, line, nextInChain);
550     }
551 }
552 
553 class Error : Throwable
554 {
555     @nogc @safe pure nothrow this(string msg, Throwable nextInChain = null)
556     {
557         super(msg, nextInChain);
558         bypassedException = null;
559     }
560 
561     @nogc @safe pure nothrow this(string msg, string file, size_t line, Throwable nextInChain = null)
562     {
563         super(msg, file, line, nextInChain);
564         bypassedException = null;
565     }
566 	
567     Throwable bypassedException;
568 }
569 
570 bool __equals(T1, T2)(scope const T1[] lhs, scope const T2[] rhs)
571 @nogc nothrow pure @trusted
572 if (__traits(isScalar, T1) && __traits(isScalar, T2))
573 {
574     if (lhs.length != rhs.length)
575         return false;
576 
577     foreach (const i; 0 .. lhs.length)
578         if (lhs.ptr[i] != rhs.ptr[i])
579             return false;
580     return true;
581 }
582 
583 // Used in Exception Handling LSDA tables to 'wrap' C++ type info
584 // so it can be distinguished from D TypeInfo
585 class __cpp_type_info_ptr
586 {
587     void* ptr;          // opaque pointer to C++ RTTI type info
588 }
589 
590 // Contents of Moduleinfo._flags
591 enum
592 {
593     MIctorstart  = 0x1,   // we've started constructing it
594     MIctordone   = 0x2,   // finished construction
595     MIstandalone = 0x4,   // module ctor does not depend on other module
596 	// ctors being done first
597     MItlsctor    = 8,
598     MItlsdtor    = 0x10,
599     MIctor       = 0x20,
600     MIdtor       = 0x40,
601     MIxgetMembers = 0x80,
602     MIictor      = 0x100,
603     MIunitTest   = 0x200,
604     MIimportedModules = 0x400,
605     MIlocalClasses = 0x800,
606     MIname       = 0x1000,
607 }
608 
609 /*****************************************
610 * An instance of ModuleInfo is generated into the object file for each compiled module.
611 *
612 * It provides access to various aspects of the module.
613 * It is not generated for betterC.
614 */
615 version(LWDR_ModuleCtors)
616 struct ModuleInfo
617 {
618     uint _flags; // MIxxxx
619     uint _index; // index into _moduleinfo_array[]
620 
621     version (all)
622     {
623         deprecated("ModuleInfo cannot be copy-assigned because it is a variable-sized struct.")
624 			void opAssign(const scope ModuleInfo m) { _flags = m._flags; _index = m._index; }
625     }
626     else
627     {
628         @disable this();
629     }
630 
631 const:
632     private void* addrOf(int flag) return nothrow pure @nogc
633 		in
634 		{
635 			assert(flag >= MItlsctor && flag <= MIname);
636 			assert(!(flag & (flag - 1)) && !(flag & ~(flag - 1) << 1));
637 		}
638     do
639     {
640         import core.stdc.string : strlen;
641 
642         void* p = cast(void*)&this + ModuleInfo.sizeof;
643 
644         if (flags & MItlsctor)
645         {
646             if (flag == MItlsctor) return p;
647             p += typeof(tlsctor).sizeof;
648         }
649         if (flags & MItlsdtor)
650         {
651             if (flag == MItlsdtor) return p;
652             p += typeof(tlsdtor).sizeof;
653         }
654         if (flags & MIctor)
655         {
656             if (flag == MIctor) return p;
657             p += typeof(ctor).sizeof;
658         }
659         if (flags & MIdtor)
660         {
661             if (flag == MIdtor) return p;
662             p += typeof(dtor).sizeof;
663         }
664         if (flags & MIxgetMembers)
665         {
666             if (flag == MIxgetMembers) return p;
667             p += typeof(xgetMembers).sizeof;
668         }
669         if (flags & MIictor)
670         {
671             if (flag == MIictor) return p;
672             p += typeof(ictor).sizeof;
673         }
674         if (flags & MIunitTest)
675         {
676             if (flag == MIunitTest) return p;
677             version(unittest)
678                 p += typeof(unitTest).sizeof;
679             else
680                 p += (void function()).sizeof;
681         }
682         if (flags & MIimportedModules)
683         {
684             if (flag == MIimportedModules) return p;
685             p += size_t.sizeof + *cast(size_t*)p * typeof(importedModules[0]).sizeof;
686         }
687         if (flags & MIlocalClasses)
688         {
689             if (flag == MIlocalClasses) return p;
690             p += size_t.sizeof + *cast(size_t*)p * typeof(localClasses[0]).sizeof;
691         }
692         if (true || flags & MIname) // always available for now
693         {
694             if (flag == MIname) return p;
695             p += strlen(cast(immutable char*)p);
696         }
697         assert(0);
698     }
699 
700     @property uint index() nothrow pure @nogc { return _index; }
701 
702     @property uint flags() nothrow pure @nogc { return _flags; }
703 
704     /************************
705 	* Returns:
706 	*  module constructor for thread locals, `null` if there isn't one
707 	*/
708     @property void function() tlsctor() nothrow pure @nogc
709     {
710         return flags & MItlsctor ? *cast(typeof(return)*)addrOf(MItlsctor) : null;
711     }
712 
713     /************************
714 	* Returns:
715 	*  module destructor for thread locals, `null` if there isn't one
716 	*/
717     @property void function() tlsdtor() nothrow pure @nogc
718     {
719         return flags & MItlsdtor ? *cast(typeof(return)*)addrOf(MItlsdtor) : null;
720     }
721 
722     /*****************************
723 	* Returns:
724 	*  address of a module's `const(MemberInfo)[] getMembers(string)` function, `null` if there isn't one
725 	*/
726     @property void* xgetMembers() nothrow pure @nogc
727     {
728         return flags & MIxgetMembers ? *cast(typeof(return)*)addrOf(MIxgetMembers) : null;
729     }
730 
731     /************************
732 	* Returns:
733 	*  module constructor, `null` if there isn't one
734 	*/
735     @property void function() ctor() nothrow pure @nogc
736     {
737         return flags & MIctor ? *cast(typeof(return)*)addrOf(MIctor) : null;
738     }
739 
740     /************************
741 	* Returns:
742 	*  module destructor, `null` if there isn't one
743 	*/
744     @property void function() dtor() nothrow pure @nogc
745     {
746         return flags & MIdtor ? *cast(typeof(return)*)addrOf(MIdtor) : null;
747     }
748 
749     /************************
750 	* Returns:
751 	*  module order independent constructor, `null` if there isn't one
752 	*/
753     @property void function() ictor() nothrow pure @nogc
754     {
755         return flags & MIictor ? *cast(typeof(return)*)addrOf(MIictor) : null;
756     }
757 
758     /*************
759 	* Returns:
760 	*  address of function that runs the module's unittests, `null` if there isn't one
761 	*/
762     version(unittest)
763     @property void function() unitTest() nothrow pure @nogc
764     {
765         return flags & MIunitTest ? *cast(typeof(return)*)addrOf(MIunitTest) : null;
766     }
767 
768     /****************
769 	* Returns:
770 	*  array of pointers to the ModuleInfo's of modules imported by this one
771 	*/
772     @property immutable(ModuleInfo*)[] importedModules() return nothrow pure @nogc
773     {
774         if (flags & MIimportedModules)
775         {
776             auto p = cast(size_t*)addrOf(MIimportedModules);
777             return (cast(immutable(ModuleInfo*)*)(p + 1))[0 .. *p];
778         }
779         return null;
780     }
781 
782     /****************
783 	* Returns:
784 	*  array of TypeInfo_Class references for classes defined in this module
785 	*/
786     @property TypeInfo_Class[] localClasses() return nothrow pure @nogc
787     {
788         if (flags & MIlocalClasses)
789         {
790             auto p = cast(size_t*)addrOf(MIlocalClasses);
791             return (cast(TypeInfo_Class*)(p + 1))[0 .. *p];
792         }
793         return null;
794     }
795 
796     /********************
797 	* Returns:
798 	*  name of module, `null` if no name
799 	*/
800     @property string name() return nothrow pure @nogc
801     {
802         import core.stdc.string : strlen;
803 
804         auto p = cast(immutable char*) addrOf(MIname);
805         return p[0 .. strlen(p)];
806     }
807 }