1 /*
2  *  Copyright (C) 2004-2006 by Digital Mars, www.digitalmars.com
3  *  Written by Walter Bright
4  *
5  *  This software is provided 'as-is', without any express or implied
6  *  warranty. In no event will the authors be held liable for any damages
7  *  arising from the use of this software.
8  *
9  *  Permission is granted to anyone to use this software for any purpose,
10  *  including commercial applications, and to alter it and redistribute it
11  *  freely, in both source and binary form, subject to the following
12  *  restrictions:
13  *
14  *  o  The origin of this software must not be misrepresented; you must not
15  *     claim that you wrote the original software. If you use this software
16  *     in a product, an acknowledgment in the product documentation would be
17  *     appreciated but is not required.
18  *  o  Altered source versions must be plainly marked as such, and must not
19  *     be misrepresented as being the original software.
20  *  o  This notice may not be removed or altered from any source
21  *     distribution.
22  */
23 
24 /*
25  *  Modified by Sean Kelly <sean@f4.ca> for use with Tango.
26  */
27 module rt.cast_;
28 
29 extern (C):
30 
31 //debug = PRINTF;
32 debug(PRINTF) int printf(char*, ...);
33 
34 /******************************************
35  * Given a pointer:
36  *      If it is an Object, return that Object.
37  *      If it is an interface, return the Object implementing the interface.
38  *      If it is null, return null.
39  *      Else, undefined crash
40  */
41 
42 Object _d_toObject(void* p)
43 {   Object o;
44     debug(PRINTF) printf("toObject(%p)\n", p);
45     if (p)
46     {
47         o = cast(Object)p;
48         debug(PRINTF) printf("o = %p\n", o);
49         debug(PRINTF) printf("o.vtbl = %p\n", *cast(void**)p);
50         ClassInfo oc = o.classinfo;
51         debug(PRINTF) printf("oc = %p\n", oc);
52         Interface *pi = **cast(Interface ***)p;
53         debug(PRINTF) printf("pi = %p\n", pi);
54 
55         /* Interface.offset lines up with ClassInfo.name.ptr,
56          * so we rely on pointers never being less than 64K,
57          * and interface vtable offsets never being greater.
58          */
59         if (pi.offset < 0x10000)
60         {
61             debug(PRINTF) printf("\tpi.offset = %d\n", pi.offset);
62             o = cast(Object)(p - pi.offset);
63         }
64     }
65     debug(PRINTF) printf("toObject = %p\n", o);
66     return o;
67 }
68 
69 
70 /*************************************
71  * Attempts to cast Object o to class c.
72  * Returns o if successful, null if not.
73  */
74 
75 Object _d_interface_cast(void* p, ClassInfo c)
76 {   Object o;
77 
78     debug(PRINTF) printf("_d_interface_cast(p = %p, c = '%.*s')\n", p, c.name.length, c.name.ptr);
79     if (p)
80     {
81         Interface *pi = **cast(Interface ***)p;
82 
83         debug(PRINTF) printf("\tpi.offset = %d\n", pi.offset);
84         o = cast(Object)(p - pi.offset);
85         return _d_dynamic_cast(o, c);
86     }
87     debug(PRINTF) printf("_d_interface_cast = %p\n", o);
88     return o;
89 }
90 
91 Object _d_dynamic_cast(Object o, ClassInfo c)
92 {   ClassInfo oc;
93     size_t offset = 0;
94 
95     debug(PRINTF) printf("_d_dynamic_cast(o = %p, c = '%.*s')\n", o, c.name.length, c.name.ptr);
96 
97     if (o)
98     {
99         oc = o.classinfo;
100         if (_d_isbaseof2(oc, c, offset))
101         {
102             debug(PRINTF) printf("\toffset = %d\n", offset);
103             o = cast(Object)(cast(void*)o + offset);
104         }
105         else
106             o = null;
107     }
108     //printf("\tresult = %p\n", o);
109     debug(PRINTF) printf("_d_dynamic_cast = %p\n", o);
110     return o;
111 }
112 
113 int _d_isbaseof2(ClassInfo oc, ClassInfo c, ref size_t offset)
114 {   int i;
115 
116     debug(PRINTF) printf("_d_isbaseof2(%.*s, %.*s, %ul)\n", oc.name.length, oc.name.ptr, c.name.length, c.name.ptr, offset);
117 
118     if (oc is c)
119         return 1;
120     do
121     {
122         debug(PRINTF) printf("oc.interfaces.length = %ul\n", oc.interfaces.length);
123         if (oc.base is c)
124             return 1;
125         for (i = 0; i < oc.interfaces.length; i++)
126         {
127             ClassInfo ic;
128 
129             ic = oc.interfaces[i].classinfo;
130             debug(PRINTF) printf("checking %.*s\n", ic.name.length, ic.name.ptr);
131             if (ic is c)
132             {   offset = cast(size_t)oc.interfaces[i].offset;
133                 return 1;
134             }
135         }
136         for (i = 0; i < oc.interfaces.length; i++)
137         {
138             ClassInfo ic;
139 
140             ic = oc.interfaces[i].classinfo;
141             if (_d_isbaseof2(ic, c, offset))
142             {   offset = cast(size_t)oc.interfaces[i].offset;
143                 return 1;
144             }
145         }
146         oc = oc.base;
147     } while (oc);
148     return 0;
149 }
150 
151 int _d_isbaseof(ClassInfo oc, ClassInfo c)
152 {   int i;
153 
154     if (oc is c)
155         return 1;
156     do
157     {
158         if (oc.base is c)
159             return 1;
160         for (i = 0; i < oc.interfaces.length; i++)
161         {
162             ClassInfo ic;
163 
164             ic = oc.interfaces[i].classinfo;
165             if (ic is c || _d_isbaseof(ic, c))
166                 return 1;
167         }
168         oc = oc.base;
169     } while (oc);
170     return 0;
171 }
172 
173 /*********************************
174  * Find the vtbl[] associated with Interface ic.
175  */
176 
177 void *_d_interface_vtbl(ClassInfo ic, Object o)
178 {   int i;
179     ClassInfo oc;
180 
181     //printf("__d_interface_vtbl(o = %p, ic = %p)\n", o, ic);
182 
183     assert(o);
184 
185     oc = o.classinfo;
186     for (i = 0; i < oc.interfaces.length; i++)
187     {
188         ClassInfo oic;
189 
190         oic = oc.interfaces[i].classinfo;
191         if (oic is ic)
192         {
193             return cast(void *)oc.interfaces[i].vtbl;
194         }
195     }
196     assert(0);
197 }