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 }