[irgen] Use object_getClass instead of object_getType() when lowering objc existential_metatype instructions.

Previously, we were not respecting the representation of the existential
metatype and were treating all existential metatypes as if the metatype
was a thick metatype. Instead now we properly grab the instance of the
class from the existential and then query the runtime for the
objc_class. This is done via the new entrypoint
emitHeapMetadataRefForUnknownHeapObject.

I also modified emitHeapMetadataRefForHeapObject to use
emitHeapMetadataRefForUnknownHeapObject instead of
emitLoadOfObjCHeapMetadataRef since the latter does not properly handle
tagged pointers. This bug was found on inspection when Joe and I were
talking about this change.

rdar://18841292

Swift SVN r23308
This commit is contained in:
Michael Gottesman
2014-11-13 19:36:00 +00:00
parent 9a691a55b2
commit 2e37bef050
6 changed files with 284 additions and 239 deletions

View File

@@ -3516,14 +3516,13 @@ llvm::Value *irgen::emitHeapMetadataRefForHeapObject(IRGenFunction &IGF,
CanType objectType,
bool suppressCast) {
ClassDecl *theClass = objectType.getClassOrBoundGenericClass();
if (isKnownNotTaggedPointer(IGF.IGM, theClass))
if (theClass && isKnownNotTaggedPointer(IGF.IGM, theClass))
return emitLoadOfHeapMetadataRef(IGF, object,
getIsaEncodingForType(IGF.IGM, objectType),
suppressCast);
// OK, ask the runtime for the class pointer of this
// potentially-ObjC object.
return emitLoadOfObjCHeapMetadataRef(IGF, object);
// OK, ask the runtime for the class pointer of this potentially-ObjC object.
return emitHeapMetadataRefForUnknownHeapObject(IGF, object);
}
llvm::Value *irgen::emitHeapMetadataRefForHeapObject(IRGenFunction &IGF,
@@ -3549,6 +3548,20 @@ llvm::Value *irgen::emitDynamicTypeOfOpaqueHeapObject(IRGenFunction &IGF,
return metadata;
}
llvm::Value *irgen::
emitHeapMetadataRefForUnknownHeapObject(IRGenFunction &IGF,
llvm::Value *object) {
object = IGF.Builder.CreateBitCast(object, IGF.IGM.ObjCPtrTy);
auto metadata = IGF.Builder.CreateCall(IGF.IGM.getGetObjectClassFn(),
object,
object->getName() + ".Type");
metadata->setCallingConv(IGF.IGM.RuntimeCC);
metadata->setDoesNotThrow();
metadata->addAttribute(llvm::AttributeSet::FunctionIndex,
llvm::Attribute::ReadOnly);
return metadata;
}
/// Given an object of class type, produce the type metadata reference
/// as a %type*.
llvm::Value *irgen::emitDynamicTypeOfHeapObject(IRGenFunction &IGF,

View File

@@ -167,6 +167,11 @@ namespace irgen {
SILType objectType,
bool suppressCast = false);
/// Given a heap-object instance, with some heap-object type, produce a
/// reference to its heap metadata by dynamically asking the runtime for it.
llvm::Value *emitHeapMetadataRefForUnknownHeapObject(IRGenFunction &IGF,
llvm::Value *object);
/// Given a heap-object instance, with some heap-object type,
/// produce a reference to its heap metadata.
llvm::Value *emitHeapMetadataRefForHeapObject(IRGenFunction &IGF,

File diff suppressed because it is too large Load Diff

View File

@@ -169,8 +169,8 @@ namespace irgen {
/// Emit the existential metatype of a class existential value.
void emitMetatypeOfClassExistential(IRGenFunction &IGF,
Explosion &value,
SILType type, Explosion &out);
Explosion &value, SILType metatypeType,
SILType existentialType, Explosion &out);
std::pair<Address, llvm::Value*>
emitIndirectExistentialProjectionWithMetadata(IRGenFunction &IGF,

View File

@@ -1521,9 +1521,10 @@ void IRGenSILFunction::visitExistentialMetatypeInst(
swift::ExistentialMetatypeInst *i) {
Explosion result;
if (i->getOperand().getType().isClassExistentialType()) {
Explosion existential = getLoweredExplosion(i->getOperand());
emitMetatypeOfClassExistential(*this, existential,
i->getOperand().getType(), result);
SILValue op = i->getOperand();
Explosion existential = getLoweredExplosion(op);
emitMetatypeOfClassExistential(*this, existential, i->getType(),
op.getType(), result);
} else {
Address existential = getLoweredAddress(i->getOperand());
emitMetatypeOfOpaqueExistential(*this, existential,

View File

@@ -82,3 +82,14 @@ entry:
%m = metatype $@objc_metatype T.Type
return %m : $@objc_metatype T.Type
}
// CHECK-LABEL: define %objc_class* @existential_objc_metatype(%objc_object*) {
// CHECK: entry:
// CHECK-NEXT: [[METATYPE:%.*]] = call %objc_class* @object_getClass(%objc_object* %0) #1
// CHECK-NEXT: ret %objc_class* [[METATYPE]]
// CHECK-NEXT: }
sil @existential_objc_metatype : $@thin (AnyObject) -> (@objc_metatype AnyObject.Type) {
bb0(%0 : $AnyObject):
%1 = existential_metatype $@objc_metatype AnyObject.Type, %0 : $AnyObject
return %1 : $@objc_metatype AnyObject.Type
}