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.compiler.gdc.rt.cast_;
28 extern (C):
29 
30 /******************************************
31  * Given a pointer:
32  *      If it is an Object, return that Object.
33  *      If it is an interface, return the Object implementing the interface.
34  *      If it is null, return null.
35  *      Else, undefined crash
36  */
37 
38 Object _d_toObject(void* p)
39 {   Object o;
40 
41     if (p)
42     {
43         o = cast(Object)p;
44         ClassInfo oc = o.classinfo;
45         Interface *pi = **cast(Interface ***)p;
46 
47         /* Interface.offset lines up with ClassInfo.name.ptr,
48          * so we rely on pointers never being less than 64K,
49          * and Objects never being greater.
50          */
51         if (pi.offset < 0x10000)
52         {
53             //printf("\tpi.offset = %d\n", pi.offset);
54             o = cast(Object)(p - pi.offset);
55         }
56     }
57     return o;
58 }
59 
60 
61 /*************************************
62  * Attempts to cast Object o to class c.
63  * Returns o if successful, null if not.
64  */
65 
66 Object _d_interface_cast(void* p, ClassInfo c)
67 {   Object o;
68 
69     //printf("_d_interface_cast(p = %p, c = '%.*s')\n", p, c.name);
70     if (p)
71     {
72         Interface *pi = **cast(Interface ***)p;
73 
74         //printf("\tpi.offset = %d\n", pi.offset);
75         o = cast(Object)(p - pi.offset);
76         return _d_dynamic_cast(o, c);
77     }
78     return o;
79 }
80 
81 Object _d_dynamic_cast(Object o, ClassInfo c)
82 {   ClassInfo oc;
83     size_t offset = 0;
84 
85     //printf("_d_dynamic_cast(o = %p, c = '%.*s')\n", o, c.name);
86 
87     if (o)
88     {
89         oc = o.classinfo;
90         if (_d_isbaseof2(oc, c, offset))
91         {
92             //printf("\toffset = %d\n", offset);
93             o = cast(Object)(cast(void*)o + offset);
94         }
95         else
96             o = null;
97     }
98     //printf("\tresult = %p\n", o);
99     return o;
100 }
101 
102 int _d_isbaseof2(ClassInfo oc, ClassInfo c, ref size_t offset)
103 {   int i;
104 
105     if (oc is c)
106         return 1;
107     do
108     {
109         if (oc.base is c)
110             return 1;
111         for (i = 0; i < oc.interfaces.length; i++)
112         {
113             ClassInfo ic;
114 
115             ic = oc.interfaces[i].classinfo;
116             if (ic is c)
117             {   offset = oc.interfaces[i].offset;
118                 return 1;
119             }
120         }
121         for (i = 0; i < oc.interfaces.length; i++)
122         {
123             ClassInfo ic;
124 
125             ic = oc.interfaces[i].classinfo;
126             if (_d_isbaseof2(ic, c, offset))
127             {   offset = oc.interfaces[i].offset;
128                 return 1;
129             }
130         }
131         oc = oc.base;
132     } while (oc);
133     return 0;
134 }
135 
136 int _d_isbaseof(ClassInfo oc, ClassInfo c)
137 {   int i;
138 
139     if (oc is c)
140         return 1;
141     do
142     {
143         if (oc.base is c)
144             return 1;
145         for (i = 0; i < oc.interfaces.length; i++)
146         {
147             ClassInfo ic;
148 
149             ic = oc.interfaces[i].classinfo;
150             if (ic is c || _d_isbaseof(ic, c))
151                 return 1;
152         }
153         oc = oc.base;
154     } while (oc);
155     return 0;
156 }
157 
158 /*********************************
159  * Find the vtbl[] associated with Interface ic.
160  */
161 
162 void *_d_interface_vtbl(ClassInfo ic, Object o)
163 {   int i;
164     ClassInfo oc;
165 
166     //printf("__d_interface_vtbl(o = %p, ic = %p)\n", o, ic);
167 
168     assert(o);
169 
170     oc = o.classinfo;
171     for (i = 0; i < oc.interfaces.length; i++)
172     {
173         ClassInfo oic;
174 
175         oic = oc.interfaces[i].classinfo;
176         if (oic is ic)
177         {
178             return cast(void *)oc.interfaces[i].vtbl;
179         }
180     }
181     assert(0);
182 }