Fix a bug with returning value that need to be refcounted:

we want to do a take-load out of the return address slot
instead of a normal load, or else we'll end up +1'ing an
already +1 value.

Swift SVN r1564
This commit is contained in:
John McCall
2012-04-23 17:47:07 +00:00
parent d68fee8b41
commit bc32a8aedb
9 changed files with 65 additions and 3 deletions

View File

@@ -44,6 +44,10 @@ namespace {
// FIXME
}
void loadAsTake(IRGenFunction &IGF, Address addr, Explosion &e) const {
// FIXME
}
void assign(IRGenFunction &IGF, Explosion &explosion, Address addr) const {
// FIXME
}

View File

@@ -310,6 +310,16 @@ namespace {
IGF.emitLoadAndRetain(dataAddr, e);
}
void loadAsTake(IRGenFunction &IGF, Address addr, Explosion &e) const {
// Load the function.
Address fnAddr = projectFunction(IGF, addr);
e.addUnmanaged(IGF.Builder.CreateLoad(fnAddr));
// Load the data.
Address dataAddr = projectData(IGF, addr);
e.addUnmanaged(IGF.Builder.CreateLoad(dataAddr));
}
void assign(IRGenFunction &IGF, Explosion &e, Address address) const {
// Store the function pointer.
Address fnAddr = projectFunction(IGF, address);
@@ -1439,7 +1449,7 @@ void IRGenFunction::emitEpilogue() {
Builder.CreateRetVoid();
} else {
Explosion result(CurExplosionLevel);
resultType.load(*this, ReturnSlot, result);
resultType.loadAsTake(*this, ReturnSlot, result);
emitScalarReturn(result);
}

View File

@@ -151,6 +151,10 @@ namespace {
IGF.emitLoadAndRetain(addr, e);
}
void loadAsTake(IRGenFunction &IGF, Address addr, Explosion &e) const {
e.addUnmanaged(IGF.Builder.CreateLoad(addr));
}
void assign(IRGenFunction &IGF, Explosion &e, Address addr) const {
IGF.emitAssignRetained(e.forwardNext(IGF), addr);
}

View File

@@ -222,6 +222,16 @@ namespace {
IGF.emitLoadAndRetain(projectOwner(IGF, address), e);
}
void loadAsTake(IRGenFunction &IGF, Address address, Explosion &e) const {
// Load the reference.
Address refAddr = projectReference(IGF, address);
e.addUnmanaged(IGF.Builder.CreateLoad(refAddr));
// Load the owner.
Address ownerAddr = projectOwner(IGF, address);
e.addUnmanaged(IGF.Builder.CreateLoad(ownerAddr));
}
void assign(IRGenFunction &IGF, Explosion &e, Address address) const {
// Store the reference.
IGF.Builder.CreateStore(e.claimUnmanagedNext(),

View File

@@ -36,6 +36,7 @@ namespace {
unsigned getExplosionSize(ExplosionKind kind) const { return 0; }
void getSchema(ExplosionSchema &schema) const {}
void load(IRGenFunction &IGF, Address addr, Explosion &e) const {}
void loadAsTake(IRGenFunction &IGF, Address addr, Explosion &e) const {}
void assign(IRGenFunction &IGF, Explosion &e, Address addr) const {}
void initialize(IRGenFunction &IGF, Explosion &e, Address addr) const {}
void reexplode(IRGenFunction &IGF, Explosion &src, Explosion &dest) const {}

View File

@@ -96,6 +96,10 @@ namespace {
// FIXME
}
void loadAsTake(IRGenFunction &IGF, Address addr, Explosion &e) const {
// FIXME
}
void assign(IRGenFunction &IGF, Explosion &e, Address addr) const {
// FIXME
}
@@ -157,6 +161,11 @@ namespace {
Singleton->load(IGF, getSingletonAddress(IGF, addr), e);
}
void loadAsTake(IRGenFunction &IGF, Address addr, Explosion &e) const {
if (!Singleton) return;
Singleton->loadAsTake(IGF, getSingletonAddress(IGF, addr), e);
}
void assign(IRGenFunction &IGF, Explosion &e, Address addr) const {
if (!Singleton) return;
Singleton->assign(IGF, e, getSingletonAddress(IGF, addr));
@@ -230,6 +239,10 @@ namespace {
addr->getName() + ".load"));
}
void loadAsTake(IRGenFunction &IGF, Address addr, Explosion &e) const {
return EnumTypeInfo::load(IGF, addr, e);
}
void assign(IRGenFunction &IGF, Explosion &e, Address addr) const {
assert(isComplete());
IGF.Builder.CreateStore(e.claimUnmanagedNext(), projectValue(IGF, addr));

View File

@@ -176,6 +176,16 @@ namespace {
}
}
void loadAsTake(IRGenFunction &IGF, Address addr, Explosion &e) const {
for (auto &field : getFieldInfos()) {
// Ignore fields that don't have storage.
if (!field.hasStorage()) continue;
Address fieldAddr = projectAddress(IGF, addr, field);
field.Type.loadAsTake(IGF, fieldAddr, e);
}
}
void assign(IRGenFunction &IGF, Explosion &e, Address addr) const {
for (auto &field : getFieldInfos()) {
// Ignore fields that don't have storage.

View File

@@ -52,7 +52,7 @@ void TypeInfo::initializeWithTake(IRGenFunction &IGF,
ExplosionSchema schema = getSchema(ExplosionKind::Maximal);
if (!schema.containsAggregate() && schema.size() <= 2) {
Explosion copy(ExplosionKind::Maximal);
load(IGF, srcAddr, copy);
loadAsTake(IGF, srcAddr, copy);
initialize(IGF, copy, destAddr);
return;
}
@@ -102,6 +102,10 @@ namespace {
e.addUnmanaged(IGF.Builder.CreateLoad(addr));
}
void loadAsTake(IRGenFunction &IGF, Address addr, Explosion &e) const {
return PrimitiveTypeInfo::load(IGF, addr, e);
}
void assign(IRGenFunction &IGF, Explosion &e, Address addr) const {
IGF.Builder.CreateStore(e.claimUnmanagedNext(), addr);
}

View File

@@ -122,10 +122,16 @@ public:
/// Return the number of elements in an explosion of this type.
virtual unsigned getExplosionSize(ExplosionKind kind) const = 0;
/// Load a list of exploded values from an address.
/// Load an explosion of values from an address.
virtual void load(IRGenFunction &IGF, Address addr,
Explosion &explosion) const = 0;
/// Perform a 'take' load of the given address. This is like a C++
/// move-initialization, except that the object at the old address
/// will not be destroyed.
virtual void loadAsTake(IRGenFunction &IGF, Address addr,
Explosion &explosion) const = 0;
/// Assign a set of exploded values into an address. The values are
/// consumed out of the explosion.
virtual void assign(IRGenFunction &IGF, Explosion &explosion,