| 1 |
#include "gen/llvm.h" |
|---|
| 2 |
|
|---|
| 3 |
#include "mtype.h" |
|---|
| 4 |
#include "aggregate.h" |
|---|
| 5 |
#include "init.h" |
|---|
| 6 |
#include "declaration.h" |
|---|
| 7 |
|
|---|
| 8 |
#include "gen/dvalue.h" |
|---|
| 9 |
#include "gen/irstate.h" |
|---|
| 10 |
|
|---|
| 11 |
#include "gen/arrays.h" |
|---|
| 12 |
#include "gen/classes.h" |
|---|
| 13 |
#include "gen/functions.h" |
|---|
| 14 |
#include "gen/llvmhelpers.h" |
|---|
| 15 |
#include "gen/logger.h" |
|---|
| 16 |
#include "gen/nested.h" |
|---|
| 17 |
#include "gen/rttibuilder.h" |
|---|
| 18 |
#include "gen/runtime.h" |
|---|
| 19 |
#include "gen/structs.h" |
|---|
| 20 |
#include "gen/tollvm.h" |
|---|
| 21 |
#include "gen/utils.h" |
|---|
| 22 |
|
|---|
| 23 |
#include "ir/irstruct.h" |
|---|
| 24 |
#include "ir/irtypeclass.h" |
|---|
| 25 |
|
|---|
| 26 |
////////////////////////////////////////////////////////////////////////////////////////// |
|---|
| 27 |
|
|---|
| 28 |
// FIXME: this needs to be cleaned up |
|---|
| 29 |
|
|---|
| 30 |
void DtoResolveClass(ClassDeclaration* cd) |
|---|
| 31 |
{ |
|---|
| 32 |
// make sure the base classes are processed first |
|---|
| 33 |
ArrayIter<BaseClass> base_iter(cd->baseclasses); |
|---|
| 34 |
while (base_iter.more()) |
|---|
| 35 |
{ |
|---|
| 36 |
BaseClass* bc = base_iter.get(); |
|---|
| 37 |
if (bc) |
|---|
| 38 |
{ |
|---|
| 39 |
bc->base->codegen(Type::sir); |
|---|
| 40 |
} |
|---|
| 41 |
base_iter.next(); |
|---|
| 42 |
} |
|---|
| 43 |
|
|---|
| 44 |
if (cd->ir.resolved) return; |
|---|
| 45 |
cd->ir.resolved = true; |
|---|
| 46 |
|
|---|
| 47 |
Logger::println("DtoResolveClass(%s): %s", cd->toPrettyChars(), cd->loc.toChars()); |
|---|
| 48 |
LOG_SCOPE; |
|---|
| 49 |
|
|---|
| 50 |
// make sure type exists |
|---|
| 51 |
DtoType(cd->type); |
|---|
| 52 |
|
|---|
| 53 |
// create IrStruct |
|---|
| 54 |
assert(cd->ir.irStruct == NULL); |
|---|
| 55 |
IrStruct* irstruct = new IrStruct(cd); |
|---|
| 56 |
cd->ir.irStruct = irstruct; |
|---|
| 57 |
|
|---|
| 58 |
// make sure all fields really get their ir field |
|---|
| 59 |
ArrayIter<VarDeclaration> it(cd->fields); |
|---|
| 60 |
for (; !it.done(); it.next()) |
|---|
| 61 |
{ |
|---|
| 62 |
VarDeclaration* vd = it.get(); |
|---|
| 63 |
if (vd->ir.irField == NULL) { |
|---|
| 64 |
new IrField(vd); |
|---|
| 65 |
} else { |
|---|
| 66 |
IF_LOG Logger::println("class field already exists!!!"); |
|---|
| 67 |
} |
|---|
| 68 |
} |
|---|
| 69 |
|
|---|
| 70 |
bool needs_def = mustDefineSymbol(cd); |
|---|
| 71 |
|
|---|
| 72 |
// emit the ClassZ symbol |
|---|
| 73 |
LLGlobalVariable* ClassZ = irstruct->getClassInfoSymbol(); |
|---|
| 74 |
|
|---|
| 75 |
// emit the interfaceInfosZ symbol if necessary |
|---|
| 76 |
if (cd->vtblInterfaces && cd->vtblInterfaces->dim > 0) |
|---|
| 77 |
irstruct->getInterfaceArraySymbol(); // initializer is applied when it's built |
|---|
| 78 |
|
|---|
| 79 |
// interface only emit typeinfo and classinfo |
|---|
| 80 |
if (cd->isInterfaceDeclaration()) |
|---|
| 81 |
{ |
|---|
| 82 |
irstruct->initializeInterface(); |
|---|
| 83 |
} |
|---|
| 84 |
else |
|---|
| 85 |
{ |
|---|
| 86 |
// emit the initZ symbol |
|---|
| 87 |
LLGlobalVariable* initZ = irstruct->getInitSymbol(); |
|---|
| 88 |
// emit the vtblZ symbol |
|---|
| 89 |
LLGlobalVariable* vtblZ = irstruct->getVtblSymbol(); |
|---|
| 90 |
|
|---|
| 91 |
// perform definition |
|---|
| 92 |
if (needs_def) |
|---|
| 93 |
{ |
|---|
| 94 |
// set symbol initializers |
|---|
| 95 |
initZ->setInitializer(irstruct->getDefaultInit()); |
|---|
| 96 |
vtblZ->setInitializer(irstruct->getVtblInit()); |
|---|
| 97 |
} |
|---|
| 98 |
} |
|---|
| 99 |
|
|---|
| 100 |
// emit members |
|---|
| 101 |
if (cd->members) |
|---|
| 102 |
{ |
|---|
| 103 |
ArrayIter<Dsymbol> it(*cd->members); |
|---|
| 104 |
while (!it.done()) |
|---|
| 105 |
{ |
|---|
| 106 |
Dsymbol* member = it.get(); |
|---|
| 107 |
if (member) |
|---|
| 108 |
member->codegen(Type::sir); |
|---|
| 109 |
it.next(); |
|---|
| 110 |
} |
|---|
| 111 |
} |
|---|
| 112 |
|
|---|
| 113 |
if (needs_def) |
|---|
| 114 |
{ |
|---|
| 115 |
// emit typeinfo |
|---|
| 116 |
DtoTypeInfoOf(cd->type); |
|---|
| 117 |
|
|---|
| 118 |
// define classinfo |
|---|
| 119 |
ClassZ->setInitializer(irstruct->getClassInfoInit()); |
|---|
| 120 |
} |
|---|
| 121 |
} |
|---|
| 122 |
|
|---|
| 123 |
////////////////////////////////////////////////////////////////////////////////////////// |
|---|
| 124 |
|
|---|
| 125 |
DValue* DtoNewClass(Loc loc, TypeClass* tc, NewExp* newexp) |
|---|
| 126 |
{ |
|---|
| 127 |
// resolve type |
|---|
| 128 |
tc->sym->codegen(Type::sir); |
|---|
| 129 |
|
|---|
| 130 |
// allocate |
|---|
| 131 |
LLValue* mem; |
|---|
| 132 |
if (newexp->onstack) |
|---|
| 133 |
{ |
|---|
| 134 |
// FIXME align scope class to its largest member |
|---|
| 135 |
mem = DtoRawAlloca(DtoType(tc)->getContainedType(0), 0, ".newclass_alloca"); |
|---|
| 136 |
} |
|---|
| 137 |
// custom allocator |
|---|
| 138 |
else if (newexp->allocator) |
|---|
| 139 |
{ |
|---|
| 140 |
newexp->allocator->codegen(Type::sir); |
|---|
| 141 |
DFuncValue dfn(newexp->allocator, newexp->allocator->ir.irFunc->func); |
|---|
| 142 |
DValue* res = DtoCallFunction(newexp->loc, NULL, &dfn, newexp->newargs); |
|---|
| 143 |
mem = DtoBitCast(res->getRVal(), DtoType(tc), ".newclass_custom"); |
|---|
| 144 |
} |
|---|
| 145 |
// default allocator |
|---|
| 146 |
else |
|---|
| 147 |
{ |
|---|
| 148 |
llvm::Function* fn = LLVM_D_GetRuntimeFunction(gIR->module, "_d_allocclass"); |
|---|
| 149 |
LLConstant* ci = DtoBitCast(tc->sym->ir.irStruct->getClassInfoSymbol(), DtoType(ClassDeclaration::classinfo->type)); |
|---|
| 150 |
mem = gIR->CreateCallOrInvoke(fn, ci, ".newclass_gc_alloc").getInstruction(); |
|---|
| 151 |
mem = DtoBitCast(mem, DtoType(tc), ".newclass_gc"); |
|---|
| 152 |
} |
|---|
| 153 |
|
|---|
| 154 |
// init |
|---|
| 155 |
DtoInitClass(tc, mem); |
|---|
| 156 |
|
|---|
| 157 |
// init inner-class outer reference |
|---|
| 158 |
if (newexp->thisexp) |
|---|
| 159 |
{ |
|---|
| 160 |
Logger::println("Resolving outer class"); |
|---|
| 161 |
LOG_SCOPE; |
|---|
| 162 |
DValue* thisval = newexp->thisexp->toElem(gIR); |
|---|
| 163 |
size_t idx = tc->sym->vthis->ir.irField->index; |
|---|
| 164 |
LLValue* src = thisval->getRVal(); |
|---|
| 165 |
LLValue* dst = DtoGEPi(mem,0,idx,"tmp"); |
|---|
| 166 |
if (Logger::enabled()) |
|---|
| 167 |
Logger::cout() << "dst: " << *dst << "\nsrc: " << *src << '\n'; |
|---|
| 168 |
DtoStore(src, dst); |
|---|
| 169 |
} |
|---|
| 170 |
// set the context for nested classes |
|---|
| 171 |
else if (tc->sym->isNested() && tc->sym->vthis) |
|---|
| 172 |
{ |
|---|
| 173 |
Logger::println("Resolving nested context"); |
|---|
| 174 |
LOG_SCOPE; |
|---|
| 175 |
|
|---|
| 176 |
// get context |
|---|
| 177 |
LLValue* nest = DtoNestedContext(loc, tc->sym); |
|---|
| 178 |
|
|---|
| 179 |
// store into right location |
|---|
| 180 |
size_t idx = tc->sym->vthis->ir.irField->index; |
|---|
| 181 |
LLValue* gep = DtoGEPi(mem,0,idx,"tmp"); |
|---|
| 182 |
DtoStore(DtoBitCast(nest, gep->getType()->getContainedType(0)), gep); |
|---|
| 183 |
} |
|---|
| 184 |
|
|---|
| 185 |
// call constructor |
|---|
| 186 |
if (newexp->member) |
|---|
| 187 |
{ |
|---|
| 188 |
Logger::println("Calling constructor"); |
|---|
| 189 |
assert(newexp->arguments != NULL); |
|---|
| 190 |
newexp->member->codegen(Type::sir); |
|---|
| 191 |
DFuncValue dfn(newexp->member, newexp->member->ir.irFunc->func, mem); |
|---|
| 192 |
return DtoCallFunction(newexp->loc, tc, &dfn, newexp->arguments); |
|---|
| 193 |
} |
|---|
| 194 |
|
|---|
| 195 |
// return default constructed class |
|---|
| 196 |
return new DImValue(tc, mem); |
|---|
| 197 |
} |
|---|
| 198 |
|
|---|
| 199 |
////////////////////////////////////////////////////////////////////////////////////////// |
|---|
| 200 |
|
|---|
| 201 |
void DtoInitClass(TypeClass* tc, LLValue* dst) |
|---|
| 202 |
{ |
|---|
| 203 |
tc->sym->codegen(Type::sir); |
|---|
| 204 |
|
|---|
| 205 |
uint64_t n = tc->sym->structsize - PTRSIZE * 2; |
|---|
| 206 |
|
|---|
| 207 |
// set vtable field seperately, this might give better optimization |
|---|
| 208 |
LLValue* tmp = DtoGEPi(dst,0,0,"vtbl"); |
|---|
| 209 |
LLValue* val = DtoBitCast(tc->sym->ir.irStruct->getVtblSymbol(), tmp->getType()->getContainedType(0)); |
|---|
| 210 |
DtoStore(val, tmp); |
|---|
| 211 |
|
|---|
| 212 |
// monitor always defaults to zero |
|---|
| 213 |
tmp = DtoGEPi(dst,0,1,"monitor"); |
|---|
| 214 |
val = LLConstant::getNullValue(tmp->getType()->getContainedType(0)); |
|---|
| 215 |
DtoStore(val, tmp); |
|---|
| 216 |
|
|---|
| 217 |
// done? |
|---|
| 218 |
if (n == 0) |
|---|
| 219 |
return; |
|---|
| 220 |
|
|---|
| 221 |
// copy the rest from the static initializer |
|---|
| 222 |
LLValue* dstarr = DtoGEPi(dst,0,2,"tmp"); |
|---|
| 223 |
|
|---|
| 224 |
// init symbols might not have valid types |
|---|
| 225 |
LLValue* initsym = tc->sym->ir.irStruct->getInitSymbol(); |
|---|
| 226 |
initsym = DtoBitCast(initsym, DtoType(tc)); |
|---|
| 227 |
LLValue* srcarr = DtoGEPi(initsym,0,2,"tmp"); |
|---|
| 228 |
|
|---|
| 229 |
DtoMemCpy(dstarr, srcarr, DtoConstSize_t(n)); |
|---|
| 230 |
} |
|---|
| 231 |
|
|---|
| 232 |
////////////////////////////////////////////////////////////////////////////////////////// |
|---|
| 233 |
|
|---|
| 234 |
void DtoFinalizeClass(LLValue* inst) |
|---|
| 235 |
{ |
|---|
| 236 |
// get runtime function |
|---|
| 237 |
llvm::Function* fn = LLVM_D_GetRuntimeFunction(gIR->module, "_d_callfinalizer"); |
|---|
| 238 |
// build args |
|---|
| 239 |
LLSmallVector<LLValue*,1> arg; |
|---|
| 240 |
arg.push_back(DtoBitCast(inst, fn->getFunctionType()->getParamType(0), ".tmp")); |
|---|
| 241 |
// call |
|---|
| 242 |
gIR->CreateCallOrInvoke(fn, arg.begin(), arg.end(), ""); |
|---|
| 243 |
} |
|---|
| 244 |
|
|---|
| 245 |
////////////////////////////////////////////////////////////////////////////////////////// |
|---|
| 246 |
|
|---|
| 247 |
DValue* DtoCastClass(DValue* val, Type* _to) |
|---|
| 248 |
{ |
|---|
| 249 |
Logger::println("DtoCastClass(%s, %s)", val->getType()->toChars(), _to->toChars()); |
|---|
| 250 |
LOG_SCOPE; |
|---|
| 251 |
|
|---|
| 252 |
Type* to = _to->toBasetype(); |
|---|
| 253 |
|
|---|
| 254 |
// class -> pointer |
|---|
| 255 |
if (to->ty == Tpointer) { |
|---|
| 256 |
IF_LOG Logger::println("to pointer"); |
|---|
| 257 |
const LLType* tolltype = DtoType(_to); |
|---|
| 258 |
LLValue* rval = DtoBitCast(val->getRVal(), tolltype); |
|---|
| 259 |
return new DImValue(_to, rval); |
|---|
| 260 |
} |
|---|
| 261 |
// class -> bool |
|---|
| 262 |
else if (to->ty == Tbool) { |
|---|
| 263 |
IF_LOG Logger::println("to bool"); |
|---|
| 264 |
LLValue* llval = val->getRVal(); |
|---|
| 265 |
LLValue* zero = LLConstant::getNullValue(llval->getType()); |
|---|
| 266 |
return new DImValue(_to, gIR->ir->CreateICmpNE(llval, zero, "tmp")); |
|---|
| 267 |
} |
|---|
| 268 |
// class -> integer |
|---|
| 269 |
else if (to->isintegral()) { |
|---|
| 270 |
IF_LOG Logger::println("to %s", to->toChars()); |
|---|
| 271 |
|
|---|
| 272 |
// get class ptr |
|---|
| 273 |
LLValue* v = val->getRVal(); |
|---|
| 274 |
// cast to size_t |
|---|
| 275 |
v = gIR->ir->CreatePtrToInt(v, DtoSize_t(), ""); |
|---|
| 276 |
// cast to the final int type |
|---|
| 277 |
DImValue im(Type::tsize_t, v); |
|---|
| 278 |
Loc loc; |
|---|
| 279 |
return DtoCastInt(loc, &im, _to); |
|---|
| 280 |
} |
|---|
| 281 |
|
|---|
| 282 |
// must be class/interface |
|---|
| 283 |
assert(to->ty == Tclass); |
|---|
| 284 |
TypeClass* tc = (TypeClass*)to; |
|---|
| 285 |
|
|---|
| 286 |
// from type |
|---|
| 287 |
Type* from = val->getType()->toBasetype(); |
|---|
| 288 |
TypeClass* fc = (TypeClass*)from; |
|---|
| 289 |
|
|---|
| 290 |
// x -> interface |
|---|
| 291 |
if (InterfaceDeclaration* it = tc->sym->isInterfaceDeclaration()) { |
|---|
| 292 |
Logger::println("to interface"); |
|---|
| 293 |
// interface -> interface |
|---|
| 294 |
if (fc->sym->isInterfaceDeclaration()) { |
|---|
| 295 |
Logger::println("from interface"); |
|---|
| 296 |
return DtoDynamicCastInterface(val, _to); |
|---|
| 297 |
} |
|---|
| 298 |
// class -> interface - static cast |
|---|
| 299 |
else if (it->isBaseOf(fc->sym,NULL)) { |
|---|
| 300 |
Logger::println("static down cast"); |
|---|
| 301 |
|
|---|
| 302 |
// get the from class |
|---|
| 303 |
ClassDeclaration* cd = fc->sym->isClassDeclaration(); |
|---|
| 304 |
DtoResolveClass(cd); // add this |
|---|
| 305 |
IrStruct* irstruct = cd->ir.irStruct; |
|---|
| 306 |
IrTypeClass* typeclass = fc->irtype->isClass(); |
|---|
| 307 |
|
|---|
| 308 |
// find interface impl |
|---|
| 309 |
|
|---|
| 310 |
size_t i_index = typeclass->getInterfaceIndex(it); |
|---|
| 311 |
assert(i_index != ~0 && "requesting interface that is not implemented by this class"); |
|---|
| 312 |
|
|---|
| 313 |
// offset pointer |
|---|
| 314 |
LLValue* v = val->getRVal(); |
|---|
| 315 |
LLValue* orig = v; |
|---|
| 316 |
v = DtoGEPi(v, 0, i_index); |
|---|
| 317 |
const LLType* ifType = DtoType(_to); |
|---|
| 318 |
if (Logger::enabled()) |
|---|
| 319 |
{ |
|---|
| 320 |
Logger::cout() << "V = " << *v << std::endl; |
|---|
| 321 |
Logger::cout() << "T = " << *ifType << std::endl; |
|---|
| 322 |
} |
|---|
| 323 |
v = DtoBitCast(v, ifType); |
|---|
| 324 |
|
|---|
| 325 |
// Check whether the original value was null, and return null if so. |
|---|
| 326 |
// Sure we could have jumped over the code above in this case, but |
|---|
| 327 |
// it's just a GEP and (maybe) a pointer-to-pointer BitCast, so it |
|---|
| 328 |
// should be pretty cheap and perfectly safe even if the original was null. |
|---|
| 329 |
LLValue* isNull = gIR->ir->CreateICmpEQ(orig, LLConstant::getNullValue(orig->getType()), ".nullcheck"); |
|---|
| 330 |
v = gIR->ir->CreateSelect(isNull, LLConstant::getNullValue(ifType), v, ".interface"); |
|---|
| 331 |
|
|---|
| 332 |
// return r-value |
|---|
| 333 |
return new DImValue(_to, v); |
|---|
| 334 |
} |
|---|
| 335 |
// class -> interface |
|---|
| 336 |
else { |
|---|
| 337 |
Logger::println("from object"); |
|---|
| 338 |
return DtoDynamicCastObject(val, _to); |
|---|
| 339 |
} |
|---|
| 340 |
} |
|---|
| 341 |
// x -> class |
|---|
| 342 |
else { |
|---|
| 343 |
Logger::println("to class"); |
|---|
| 344 |
int poffset; |
|---|
| 345 |
// interface -> class |
|---|
| 346 |
if (fc->sym->isInterfaceDeclaration()) { |
|---|
| 347 |
Logger::println("interface cast"); |
|---|
| 348 |
return DtoDynamicCastInterface(val, _to); |
|---|
| 349 |
} |
|---|
| 350 |
// class -> class - static down cast |
|---|
| 351 |
else if (tc->sym->isBaseOf(fc->sym,NULL)) { |
|---|
| 352 |
Logger::println("static down cast"); |
|---|
| 353 |
const LLType* tolltype = DtoType(_to); |
|---|
| 354 |
LLValue* rval = DtoBitCast(val->getRVal(), tolltype); |
|---|
| 355 |
return new DImValue(_to, rval); |
|---|
| 356 |
} |
|---|
| 357 |
// class -> class - dynamic up cast |
|---|
| 358 |
else { |
|---|
| 359 |
Logger::println("dynamic up cast"); |
|---|
| 360 |
return DtoDynamicCastObject(val, _to); |
|---|
| 361 |
} |
|---|
| 362 |
} |
|---|
| 363 |
} |
|---|
| 364 |
|
|---|
| 365 |
////////////////////////////////////////////////////////////////////////////////////////// |
|---|
| 366 |
|
|---|
| 367 |
DValue* DtoDynamicCastObject(DValue* val, Type* _to) |
|---|
| 368 |
{ |
|---|
| 369 |
// call: |
|---|
| 370 |
// Object _d_dynamic_cast(Object o, ClassInfo c) |
|---|
| 371 |
|
|---|
| 372 |
ClassDeclaration::object->codegen(Type::sir); |
|---|
| 373 |
ClassDeclaration::classinfo->codegen(Type::sir); |
|---|
| 374 |
|
|---|
| 375 |
llvm::Function* func = LLVM_D_GetRuntimeFunction(gIR->module, "_d_dynamic_cast"); |
|---|
| 376 |
const llvm::FunctionType* funcTy = func->getFunctionType(); |
|---|
| 377 |
|
|---|
| 378 |
std::vector<LLValue*> args; |
|---|
| 379 |
|
|---|
| 380 |
// Object o |
|---|
| 381 |
LLValue* obj = val->getRVal(); |
|---|
| 382 |
obj = DtoBitCast(obj, funcTy->getParamType(0)); |
|---|
| 383 |
assert(funcTy->getParamType(0) == obj->getType()); |
|---|
| 384 |
|
|---|
| 385 |
// ClassInfo c |
|---|
| 386 |
TypeClass* to = (TypeClass*)_to->toBasetype(); |
|---|
| 387 |
to->sym->codegen(Type::sir); |
|---|
| 388 |
|
|---|
| 389 |
LLValue* cinfo = to->sym->ir.irStruct->getClassInfoSymbol(); |
|---|
| 390 |
// unfortunately this is needed as the implementation of object differs somehow from the declaration |
|---|
| 391 |
// this could happen in user code as well :/ |
|---|
| 392 |
cinfo = DtoBitCast(cinfo, funcTy->getParamType(1)); |
|---|
| 393 |
assert(funcTy->getParamType(1) == cinfo->getType()); |
|---|
| 394 |
|
|---|
| 395 |
// call it |
|---|
| 396 |
LLValue* ret = gIR->CreateCallOrInvoke2(func, obj, cinfo, "tmp").getInstruction(); |
|---|
| 397 |
|
|---|
| 398 |
// cast return value |
|---|
| 399 |
ret = DtoBitCast(ret, DtoType(_to)); |
|---|
| 400 |
|
|---|
| 401 |
return new DImValue(_to, ret); |
|---|
| 402 |
} |
|---|
| 403 |
|
|---|
| 404 |
////////////////////////////////////////////////////////////////////////////////////////// |
|---|
| 405 |
|
|---|
| 406 |
DValue* DtoCastInterfaceToObject(DValue* val, Type* to) |
|---|
| 407 |
{ |
|---|
| 408 |
// call: |
|---|
| 409 |
// Object _d_toObject(void* p) |
|---|
| 410 |
|
|---|
| 411 |
llvm::Function* func = LLVM_D_GetRuntimeFunction(gIR->module, "_d_toObject"); |
|---|
| 412 |
const llvm::FunctionType* funcTy = func->getFunctionType(); |
|---|
| 413 |
|
|---|
| 414 |
// void* p |
|---|
| 415 |
LLValue* tmp = val->getRVal(); |
|---|
| 416 |
tmp = DtoBitCast(tmp, funcTy->getParamType(0)); |
|---|
| 417 |
|
|---|
| 418 |
// call it |
|---|
| 419 |
LLValue* ret = gIR->CreateCallOrInvoke(func, tmp, "tmp").getInstruction(); |
|---|
| 420 |
|
|---|
| 421 |
// cast return value |
|---|
| 422 |
if (to != NULL) |
|---|
| 423 |
ret = DtoBitCast(ret, DtoType(to)); |
|---|
| 424 |
else |
|---|
| 425 |
to = ClassDeclaration::object->type; |
|---|
| 426 |
|
|---|
| 427 |
return new DImValue(to, ret); |
|---|
| 428 |
} |
|---|
| 429 |
|
|---|
| 430 |
////////////////////////////////////////////////////////////////////////////////////////// |
|---|
| 431 |
|
|---|
| 432 |
DValue* DtoDynamicCastInterface(DValue* val, Type* _to) |
|---|
| 433 |
{ |
|---|
| 434 |
// call: |
|---|
| 435 |
// Object _d_interface_cast(void* p, ClassInfo c) |
|---|
| 436 |
|
|---|
| 437 |
ClassDeclaration::object->codegen(Type::sir); |
|---|
| 438 |
ClassDeclaration::classinfo->codegen(Type::sir); |
|---|
| 439 |
|
|---|
| 440 |
llvm::Function* func = LLVM_D_GetRuntimeFunction(gIR->module, "_d_interface_cast"); |
|---|
| 441 |
const llvm::FunctionType* funcTy = func->getFunctionType(); |
|---|
| 442 |
|
|---|
| 443 |
std::vector<LLValue*> args; |
|---|
| 444 |
|
|---|
| 445 |
// void* p |
|---|
| 446 |
LLValue* ptr = val->getRVal(); |
|---|
| 447 |
ptr = DtoBitCast(ptr, funcTy->getParamType(0)); |
|---|
| 448 |
|
|---|
| 449 |
// ClassInfo c |
|---|
| 450 |
TypeClass* to = (TypeClass*)_to->toBasetype(); |
|---|
| 451 |
to->sym->codegen(Type::sir); |
|---|
| 452 |
LLValue* cinfo = to->sym->ir.irStruct->getClassInfoSymbol(); |
|---|
| 453 |
// unfortunately this is needed as the implementation of object differs somehow from the declaration |
|---|
| 454 |
// this could happen in user code as well :/ |
|---|
| 455 |
cinfo = DtoBitCast(cinfo, funcTy->getParamType(1)); |
|---|
| 456 |
|
|---|
| 457 |
// call it |
|---|
| 458 |
LLValue* ret = gIR->CreateCallOrInvoke2(func, ptr, cinfo, "tmp").getInstruction(); |
|---|
| 459 |
|
|---|
| 460 |
// cast return value |
|---|
| 461 |
ret = DtoBitCast(ret, DtoType(_to)); |
|---|
| 462 |
|
|---|
| 463 |
return new DImValue(_to, ret); |
|---|
| 464 |
} |
|---|
| 465 |
|
|---|
| 466 |
////////////////////////////////////////////////////////////////////////////////////////// |
|---|
| 467 |
|
|---|
| 468 |
LLValue* DtoIndexClass(LLValue* src, ClassDeclaration* cd, VarDeclaration* vd) |
|---|
| 469 |
{ |
|---|
| 470 |
Logger::println("indexing class field %s:", vd->toPrettyChars()); |
|---|
| 471 |
LOG_SCOPE; |
|---|
| 472 |
|
|---|
| 473 |
if (Logger::enabled()) |
|---|
| 474 |
Logger::cout() << "src: " << *src << '\n'; |
|---|
| 475 |
|
|---|
| 476 |
// make sure class is resolved |
|---|
| 477 |
DtoResolveClass(cd); |
|---|
| 478 |
|
|---|
| 479 |
// vd must be a field |
|---|
| 480 |
IrField* field = vd->ir.irField; |
|---|
| 481 |
assert(field); |
|---|
| 482 |
|
|---|
| 483 |
// get the start pointer |
|---|
| 484 |
const LLType* st = DtoType(cd->type); |
|---|
| 485 |
// cast to the struct type |
|---|
| 486 |
src = DtoBitCast(src, st); |
|---|
| 487 |
|
|---|
| 488 |
// gep to the index |
|---|
| 489 |
#if 0 |
|---|
| 490 |
if (Logger::enabled()) |
|---|
| 491 |
{ |
|---|
| 492 |
Logger::cout() << "src2: " << *src << '\n'; |
|---|
| 493 |
Logger::cout() << "index: " << field->index << '\n'; |
|---|
| 494 |
Logger::cout() << "srctype: " << *src->getType() << '\n'; |
|---|
| 495 |
} |
|---|
| 496 |
#endif |
|---|
| 497 |
LLValue* val = DtoGEPi(src, 0, field->index); |
|---|
| 498 |
|
|---|
| 499 |
// do we need to offset further? (union area) |
|---|
| 500 |
if (field->unionOffset) |
|---|
| 501 |
{ |
|---|
| 502 |
// cast to void* |
|---|
| 503 |
val = DtoBitCast(val, getVoidPtrType()); |
|---|
| 504 |
// offset |
|---|
| 505 |
val = DtoGEPi1(val, field->unionOffset); |
|---|
| 506 |
} |
|---|
| 507 |
|
|---|
| 508 |
// cast it to the right type |
|---|
| 509 |
val = DtoBitCast(val, getPtrToType(DtoType(vd->type))); |
|---|
| 510 |
|
|---|
| 511 |
if (Logger::enabled()) |
|---|
| 512 |
Logger::cout() << "value: " << *val << '\n'; |
|---|
| 513 |
|
|---|
| 514 |
return val; |
|---|
| 515 |
} |
|---|
| 516 |
|
|---|
| 517 |
////////////////////////////////////////////////////////////////////////////////////////// |
|---|
| 518 |
|
|---|
| 519 |
LLValue* DtoVirtualFunctionPointer(DValue* inst, FuncDeclaration* fdecl, char* name) |
|---|
| 520 |
{ |
|---|
| 521 |
// sanity checks |
|---|
| 522 |
assert(fdecl->isVirtual()); |
|---|
| 523 |
assert(!fdecl->isFinal()); |
|---|
| 524 |
assert(fdecl->vtblIndex > 0); // 0 is always ClassInfo/Interface* |
|---|
| 525 |
assert(inst->getType()->toBasetype()->ty == Tclass); |
|---|
| 526 |
|
|---|
| 527 |
// get instance |
|---|
| 528 |
LLValue* vthis = inst->getRVal(); |
|---|
| 529 |
if (Logger::enabled()) |
|---|
| 530 |
Logger::cout() << "vthis: " << *vthis << '\n'; |
|---|
| 531 |
|
|---|
| 532 |
LLValue* funcval = vthis; |
|---|
| 533 |
// get the vtbl for objects |
|---|
| 534 |
funcval = DtoGEPi(funcval, 0, 0, "tmp"); |
|---|
| 535 |
// load vtbl ptr |
|---|
| 536 |
funcval = DtoLoad(funcval); |
|---|
| 537 |
// index vtbl |
|---|
| 538 |
std::string vtblname = name; |
|---|
| 539 |
vtblname.append("@vtbl"); |
|---|
| 540 |
funcval = DtoGEPi(funcval, 0, fdecl->vtblIndex, vtblname.c_str()); |
|---|
| 541 |
// load funcptr |
|---|
| 542 |
funcval = DtoAlignedLoad(funcval); |
|---|
| 543 |
|
|---|
| 544 |
if (Logger::enabled()) |
|---|
| 545 |
Logger::cout() << "funcval: " << *funcval << '\n'; |
|---|
| 546 |
|
|---|
| 547 |
// cast to final funcptr type |
|---|
| 548 |
funcval = DtoBitCast(funcval, getPtrToType(DtoType(fdecl->type))); |
|---|
| 549 |
|
|---|
| 550 |
// postpone naming until after casting to get the name in call instructions |
|---|
| 551 |
funcval->setName(name); |
|---|
| 552 |
|
|---|
| 553 |
if (Logger::enabled()) |
|---|
| 554 |
Logger::cout() << "funcval casted: " << *funcval << '\n'; |
|---|
| 555 |
|
|---|
| 556 |
return funcval; |
|---|
| 557 |
} |
|---|
| 558 |
|
|---|
| 559 |
////////////////////////////////////////////////////////////////////////////////////////// |
|---|
| 560 |
|
|---|
| 561 |
#if GENERATE_OFFTI |
|---|
| 562 |
|
|---|
| 563 |
// build a single element for the OffsetInfo[] of ClassInfo |
|---|
| 564 |
static LLConstant* build_offti_entry(ClassDeclaration* cd, VarDeclaration* vd) |
|---|
| 565 |
{ |
|---|
| 566 |
std::vector<LLConstant*> inits(2); |
|---|
| 567 |
|
|---|
| 568 |
// size_t offset; |
|---|
| 569 |
// |
|---|
| 570 |
assert(vd->ir.irField); |
|---|
| 571 |
// grab the offset from llvm and the formal class type |
|---|
| 572 |
size_t offset = gTargetData->getStructLayout(isaStruct(cd->type->ir.type->get()))->getElementOffset(vd->ir.irField->index); |
|---|
| 573 |
// offset nested struct/union fields |
|---|
| 574 |
offset += vd->ir.irField->unionOffset; |
|---|
| 575 |
|
|---|
| 576 |
// assert that it matches DMD |
|---|
| 577 |
Logger::println("offsets: %lu vs %u", offset, vd->offset); |
|---|
| 578 |
assert(offset == vd->offset); |
|---|
| 579 |
|
|---|
| 580 |
inits[0] = DtoConstSize_t(offset); |
|---|
| 581 |
|
|---|
| 582 |
// TypeInfo ti; |
|---|
| 583 |
inits[1] = DtoTypeInfoOf(vd->type, true); |
|---|
| 584 |
|
|---|
| 585 |
// done |
|---|
| 586 |
return llvm::ConstantStruct::get(inits); |
|---|
| 587 |
} |
|---|
| 588 |
|
|---|
| 589 |
static LLConstant* build_offti_array(ClassDeclaration* cd, const LLType* arrayT) |
|---|
| 590 |
{ |
|---|
| 591 |
IrStruct* irstruct = cd->ir.irStruct; |
|---|
| 592 |
|
|---|
| 593 |
size_t nvars = irstruct->varDecls.size(); |
|---|
| 594 |
std::vector<LLConstant*> arrayInits(nvars); |
|---|
| 595 |
|
|---|
| 596 |
for (size_t i=0; i<nvars; i++) |
|---|
| 597 |
{ |
|---|
| 598 |
arrayInits[i] = build_offti_entry(cd, irstruct->varDecls[i]); |
|---|
| 599 |
} |
|---|
| 600 |
|
|---|
| 601 |
LLConstant* size = DtoConstSize_t(nvars); |
|---|
| 602 |
LLConstant* ptr; |
|---|
| 603 |
|
|---|
| 604 |
if (nvars == 0) |
|---|
| 605 |
return LLConstant::getNullValue( arrayT ); |
|---|
| 606 |
|
|---|
| 607 |
// array type |
|---|
| 608 |
const llvm::ArrayType* arrTy = llvm::ArrayType::get(arrayInits[0]->getType(), nvars); |
|---|
| 609 |
LLConstant* arrInit = LLConstantArray::get(arrTy, arrayInits); |
|---|
| 610 |
|
|---|
| 611 |
// mangle |
|---|
| 612 |
std::string name(cd->type->vtinfo->toChars()); |
|---|
| 613 |
name.append("__OffsetTypeInfos"); |
|---|
| 614 |
|
|---|
| 615 |
// create symbol |
|---|
| 616 |
llvm::GlobalVariable* gvar = new llvm::GlobalVariable(arrTy,true,DtoInternalLinkage(cd),arrInit,name,gIR->module); |
|---|
| 617 |
ptr = DtoBitCast(gvar, getPtrToType(arrTy->getElementType())); |
|---|
| 618 |
|
|---|
| 619 |
return DtoConstSlice(size, ptr); |
|---|
| 620 |
} |
|---|
| 621 |
|
|---|
| 622 |
#endif // GENERATE_OFFTI |
|---|
| 623 |
|
|---|
| 624 |
static LLConstant* build_class_dtor(ClassDeclaration* cd) |
|---|
| 625 |
{ |
|---|
| 626 |
FuncDeclaration* dtor = cd->dtor; |
|---|
| 627 |
|
|---|
| 628 |
// if no destructor emit a null |
|---|
| 629 |
if (!dtor) |
|---|
| 630 |
return getNullPtr(getVoidPtrType()); |
|---|
| 631 |
|
|---|
| 632 |
dtor->codegen(Type::sir); |
|---|
| 633 |
return llvm::ConstantExpr::getBitCast(dtor->ir.irFunc->func, getPtrToType(LLType::getInt8Ty(gIR->context()))); |
|---|
| 634 |
} |
|---|
| 635 |
|
|---|
| 636 |
static unsigned build_classinfo_flags(ClassDeclaration* cd) |
|---|
| 637 |
{ |
|---|
| 638 |
// adapted from original dmd code |
|---|
| 639 |
unsigned flags = 0; |
|---|
| 640 |
//flags |= isCOMclass(); // IUnknown |
|---|
| 641 |
bool hasOffTi = false; |
|---|
| 642 |
if (cd->ctor) flags |= 8; |
|---|
| 643 |
for (ClassDeclaration *cd2 = cd; cd2; cd2 = cd2->baseClass) |
|---|
| 644 |
{ |
|---|
| 645 |
if (cd2->members) |
|---|
| 646 |
{ |
|---|
| 647 |
for (size_t i = 0; i < cd2->members->dim; i++) |
|---|
| 648 |
{ |
|---|
| 649 |
Dsymbol *sm = (Dsymbol *)cd2->members->data[i]; |
|---|
| 650 |
if (sm->isVarDeclaration() && !sm->isVarDeclaration()->isDataseg()) // is this enough? |
|---|
| 651 |
hasOffTi = true; |
|---|
| 652 |
//printf("sm = %s %s\n", sm->kind(), sm->toChars()); |
|---|
| 653 |
if (sm->hasPointers()) |
|---|
| 654 |
goto L2; |
|---|
| 655 |
} |
|---|
| 656 |
} |
|---|
| 657 |
} |
|---|
| 658 |
flags |= 2; // no pointers |
|---|
| 659 |
L2: |
|---|
| 660 |
if (hasOffTi) |
|---|
| 661 |
flags |= 4; |
|---|
| 662 |
|
|---|
| 663 |
// always define the typeinfo field. |
|---|
| 664 |
// why would ever not do this? |
|---|
| 665 |
flags |= 32; |
|---|
| 666 |
|
|---|
| 667 |
return flags; |
|---|
| 668 |
} |
|---|
| 669 |
|
|---|
| 670 |
LLConstant* DtoDefineClassInfo(ClassDeclaration* cd) |
|---|
| 671 |
{ |
|---|
| 672 |
// The layout is: |
|---|
| 673 |
// { |
|---|
| 674 |
// void **vptr; |
|---|
| 675 |
// monitor_t monitor; |
|---|
| 676 |
// byte[] initializer; // static initialization data |
|---|
| 677 |
// char[] name; // class name |
|---|
| 678 |
// void *[] vtbl; |
|---|
| 679 |
// Interface[] interfaces; |
|---|
| 680 |
// ClassInfo *base; // base class |
|---|
| 681 |
// void *destructor; |
|---|
| 682 |
// void *invariant; // class invariant |
|---|
| 683 |
// uint flags; |
|---|
| 684 |
// void *deallocator; |
|---|
| 685 |
// OffsetTypeInfo[] offTi; |
|---|
| 686 |
// void *defaultConstructor; |
|---|
| 687 |
// version(D_Version2) |
|---|
| 688 |
// const(MemberInfo[]) function(string) xgetMembers; |
|---|
| 689 |
// TypeInfo typeinfo; // since dmd 1.045 |
|---|
| 690 |
// } |
|---|
| 691 |
|
|---|
| 692 |
Logger::println("DtoDefineClassInfo(%s)", cd->toChars()); |
|---|
| 693 |
LOG_SCOPE; |
|---|
| 694 |
|
|---|
| 695 |
assert(cd->type->ty == Tclass); |
|---|
| 696 |
TypeClass* cdty = (TypeClass*)cd->type; |
|---|
| 697 |
|
|---|
| 698 |
IrStruct* ir = cd->ir.irStruct; |
|---|
| 699 |
assert(ir); |
|---|
| 700 |
|
|---|
| 701 |
ClassDeclaration* cinfo = ClassDeclaration::classinfo; |
|---|
| 702 |
|
|---|
| 703 |
#if DMDV2 |
|---|
| 704 |
if (cinfo->fields.dim != 13) |
|---|
| 705 |
#else |
|---|
| 706 |
if (cinfo->fields.dim != 12) |
|---|
| 707 |
#endif |
|---|
| 708 |
{ |
|---|
| 709 |
error("object.d ClassInfo class is incorrect"); |
|---|
| 710 |
fatal(); |
|---|
| 711 |
} |
|---|
| 712 |
|
|---|
| 713 |
// use the rtti builder |
|---|
| 714 |
RTTIBuilder b(ClassDeclaration::classinfo); |
|---|
| 715 |
|
|---|
| 716 |
LLConstant* c; |
|---|
| 717 |
|
|---|
| 718 |
const LLType* voidPtr = getVoidPtrType(); |
|---|
| 719 |
const LLType* voidPtrPtr = getPtrToType(voidPtr); |
|---|
| 720 |
|
|---|
| 721 |
// byte[] init |
|---|
| 722 |
if (cd->isInterfaceDeclaration()) |
|---|
| 723 |
{ |
|---|
| 724 |
b.push_null_void_array(); |
|---|
| 725 |
} |
|---|
| 726 |
else |
|---|
| 727 |
{ |
|---|
| 728 |
const LLType* cd_type = cdty->irtype->getPA(); |
|---|
| 729 |
size_t initsz = getTypePaddedSize(cd_type); |
|---|
| 730 |
b.push_void_array(initsz, ir->getInitSymbol()); |
|---|
| 731 |
} |
|---|
| 732 |
|
|---|
| 733 |
// class name |
|---|
| 734 |
// code from dmd |
|---|
| 735 |
const char *name = cd->ident->toChars(); |
|---|
| 736 |
size_t namelen = strlen(name); |
|---|
| 737 |
if (!(namelen > 9 && memcmp(name, "TypeInfo_", 9) == 0)) |
|---|
| 738 |
{ |
|---|
| 739 |
name = cd->toPrettyChars(); |
|---|
| 740 |
namelen = strlen(name); |
|---|
| 741 |
} |
|---|
| 742 |
b.push_string(name); |
|---|
| 743 |
|
|---|
| 744 |
// vtbl array |
|---|
| 745 |
if (cd->isInterfaceDeclaration()) |
|---|
| 746 |
{ |
|---|
| 747 |
b.push_array(0, getNullValue(voidPtrPtr)); |
|---|
| 748 |
} |
|---|
| 749 |
else |
|---|
| 750 |
{ |
|---|
| 751 |
c = DtoBitCast(ir->getVtblSymbol(), voidPtrPtr); |
|---|
| 752 |
b.push_array(cd->vtbl.dim, c); |
|---|
| 753 |
} |
|---|
| 754 |
|
|---|
| 755 |
// interfaces array |
|---|
| 756 |
b.push(ir->getClassInfoInterfaces()); |
|---|
| 757 |
|
|---|
| 758 |
// base classinfo |
|---|
| 759 |
// interfaces never get a base , just the interfaces[] |
|---|
| 760 |
if (cd->baseClass && !cd->isInterfaceDeclaration()) |
|---|
| 761 |
b.push_classinfo(cd->baseClass); |
|---|
| 762 |
else |
|---|
| 763 |
b.push_null(cinfo->type); |
|---|
| 764 |
|
|---|
| 765 |
// destructor |
|---|
| 766 |
if (cd->isInterfaceDeclaration()) |
|---|
| 767 |
b.push_null_vp(); |
|---|
| 768 |
else |
|---|
| 769 |
b.push(build_class_dtor(cd)); |
|---|
| 770 |
|
|---|
| 771 |
// invariant |
|---|
| 772 |
VarDeclaration* invVar = (VarDeclaration*)cinfo->fields.data[6]; |
|---|
| 773 |
b.push_funcptr(cd->inv, invVar->type); |
|---|
| 774 |
|
|---|
| 775 |
// uint flags |
|---|
| 776 |
if (cd->isInterfaceDeclaration()) |
|---|
| 777 |
b.push_uint(0); |
|---|
| 778 |
else |
|---|
| 779 |
b.push_uint(build_classinfo_flags(cd)); |
|---|
| 780 |
|
|---|
| 781 |
// deallocator |
|---|
| 782 |
b.push_funcptr(cd->aggDelete, Type::tvoid->pointerTo()); |
|---|
| 783 |
|
|---|
| 784 |
// offset typeinfo |
|---|
| 785 |
VarDeclaration* offTiVar = (VarDeclaration*)cinfo->fields.data[9]; |
|---|
| 786 |
|
|---|
| 787 |
#if GENERATE_OFFTI |
|---|
| 788 |
|
|---|
| 789 |
if (cd->isInterfaceDeclaration()) |
|---|
| 790 |
b.push_null(offTiVar->type); |
|---|
| 791 |
else |
|---|
| 792 |
b.push(build_offti_array(cd, DtoType(offTiVar->type))); |
|---|
| 793 |
|
|---|
| 794 |
#else // GENERATE_OFFTI |
|---|
| 795 |
|
|---|
| 796 |
b.push_null(offTiVar->type); |
|---|
| 797 |
|
|---|
| 798 |
#endif // GENERATE_OFFTI |
|---|
| 799 |
|
|---|
| 800 |
// default constructor |
|---|
| 801 |
b.push_funcptr(cd->defaultCtor, Type::tvoid->pointerTo()); |
|---|
| 802 |
|
|---|
| 803 |
#if DMDV2 |
|---|
| 804 |
|
|---|
| 805 |
// xgetMembers |
|---|
| 806 |
VarDeclaration* xgetVar = (VarDeclaration*)cinfo->fields.data[11]; |
|---|
| 807 |
|
|---|
| 808 |
// FIXME: fill it out! |
|---|
| 809 |
b.push_null(xgetVar->type); |
|---|
| 810 |
|
|---|
| 811 |
#endif |
|---|
| 812 |
|
|---|
| 813 |
// typeinfo - since 1.045 |
|---|
| 814 |
b.push_typeinfo(cd->type); |
|---|
| 815 |
|
|---|
| 816 |
/*size_t n = inits.size(); |
|---|
| 817 |
for (size_t i=0; i<n; ++i) |
|---|
| 818 |
{ |
|---|
| 819 |
Logger::cout() << "inits[" << i << "]: " << *inits[i] << '\n'; |
|---|
| 820 |
}*/ |
|---|
| 821 |
|
|---|
| 822 |
// build the initializer |
|---|
| 823 |
LLConstant* finalinit = b.get_constant(); |
|---|
| 824 |
|
|---|
| 825 |
//Logger::cout() << "built the classinfo initializer:\n" << *finalinit <<'\n'; |
|---|
| 826 |
ir->constClassInfo = finalinit; |
|---|
| 827 |
|
|---|
| 828 |
// sanity check |
|---|
| 829 |
assert(finalinit->getType() == ir->classInfo->getType()->getContainedType(0) && |
|---|
| 830 |
"__ClassZ initializer does not match the ClassInfo type"); |
|---|
| 831 |
|
|---|
| 832 |
// return initializer |
|---|
| 833 |
return finalinit; |
|---|
| 834 |
} |
|---|