Implement basic support for [weak].

Swift SVN r7041
This commit is contained in:
John McCall
2013-08-08 04:04:51 +00:00
parent 204980bdfd
commit 14cb7001b3
20 changed files with 887 additions and 110 deletions

View File

@@ -386,6 +386,11 @@ ERROR(sil_expected_allocation_kind,decl_parsing,none,
"expected allocation kind (heap, pseudo, or stack)", ()) "expected allocation kind (heap, pseudo, or stack)", ())
ERROR(sil_invalid_instr_operands,decl_parsing,none, ERROR(sil_invalid_instr_operands,decl_parsing,none,
"invalid instruction operands", ()) "invalid instruction operands", ())
ERROR(sil_operand_not_address,decl_parsing,none,
"%0 operand of '%1' must have address type", (StringRef, StringRef))
ERROR(sil_operand_not_weak_address,decl_parsing,none,
"%0 operand of '%1' must have address of [weak] type",
(StringRef, StringRef))
ERROR(sil_integer_literal_not_integer_type,decl_parsing,none, ERROR(sil_integer_literal_not_integer_type,decl_parsing,none,
"integer_literal instruction requires a 'Builtin.Int<n>' type", ()) "integer_literal instruction requires a 'Builtin.Int<n>' type", ())
ERROR(sil_float_literal_not_float_type,decl_parsing,none, ERROR(sil_float_literal_not_float_type,decl_parsing,none,

View File

@@ -268,7 +268,29 @@ struct WeakReference {
/// Initialize a weak reference. /// Initialize a weak reference.
/// ///
/// \param ref - never null /// \param ref - never null
extern "C" void swift_weakInit(WeakReference *ref); /// \param value - can be null
extern "C" void swift_weakInit(WeakReference *ref, HeapObject *value);
/// Assign a new value to a weak reference.
///
/// \param ref - never null
/// \param value - can be null
extern "C" void swift_weakAssign(WeakReference *ref, HeapObject *value);
/// Load a value from a weak reference. If the current value is a
/// non-null object that has begun deallocation, returns null;
/// otherwise, retains the object before returning.
///
/// \param ref - never null
/// \return can be null
extern "C" HeapObject *swift_weakLoadStrong(WeakReference *ref);
/// Load a value from a weak reference as if by swift_weakLoadStrong,
/// but leaving the reference in an uninitialized state.
///
/// \param ref - never null
/// \return can be null
extern "C" HeapObject *swift_weakTakeStrong(WeakReference *ref);
/// Destroy a weak reference. /// Destroy a weak reference.
/// ///
@@ -299,11 +321,6 @@ extern "C" void swift_weakCopyAssign(WeakReference *dest, WeakReference *src);
/// \param src - never null, but can refer to a null object /// \param src - never null, but can refer to a null object
extern "C" void swift_weakTakeAssign(WeakReference *dest, WeakReference *src); extern "C" void swift_weakTakeAssign(WeakReference *dest, WeakReference *src);
/// Try to retain a weak reference
///
/// \param object - never null, but can refer to a null object
extern "C" HeapObject *swift_weakTryRetain(WeakReference *object);
#if SWIFT_OBJC_INTEROP #if SWIFT_OBJC_INTEROP
/// Increment the strong retain count of an object which may have been /// Increment the strong retain count of an object which may have been
@@ -318,6 +335,33 @@ extern "C" void swift_unknownWeakRetain(void *value);
/// a native Swift object. /// a native Swift object.
extern "C" void swift_unknownWeakRelease(void *value); extern "C" void swift_unknownWeakRelease(void *value);
/// Initialize a weak reference.
///
/// \param ref - never null
/// \param value - not necessarily a native Swift object; can be null
extern "C" void swift_unknownWeakInit(WeakReference *ref, void *value);
/// Assign a new value to a weak reference.
///
/// \param ref - never null
/// \param value - not necessarily a native Swift object; can be null
extern "C" void swift_unknownWeakAssign(WeakReference *ref, void *value);
/// Load a value from a weak reference, much like swift_weakLoadStrong
/// but without requiring the variable to refer to a native Swift object.
///
/// \param ref - never null
/// \return can be null
extern "C" void *swift_unknownWeakLoadStrong(WeakReference *ref);
/// Load a value from a weak reference as if by
/// swift_unknownWeakLoadStrong, but leaving the reference in an
/// uninitialized state.
///
/// \param ref - never null
/// \return can be null
extern "C" void *swift_unknownWeakTakeStrong(WeakReference *ref);
/// Destroy a weak reference variable that might not refer to a native /// Destroy a weak reference variable that might not refer to a native
/// Swift object. /// Swift object.
extern "C" void swift_unknownWeakDestroy(WeakReference *object); extern "C" void swift_unknownWeakDestroy(WeakReference *object);

View File

@@ -222,6 +222,15 @@ public:
StoreInst(Loc, Src, DestLValue)); StoreInst(Loc, Src, DestLValue));
} }
LoadWeakInst *createLoadWeak(SILLocation loc, SILValue src, IsTake_t isTake) {
return insert(new (F.getModule()) LoadWeakInst(loc, src, isTake));
}
StoreWeakInst *createStoreWeak(SILLocation loc, SILValue value,
SILValue dest, IsInitialization_t isInit) {
return insert(new (F.getModule()) StoreWeakInst(loc, value, dest, isInit));
}
InitializeVarInst *createInitializeVar(SILLocation Loc, InitializeVarInst *createInitializeVar(SILLocation Loc,
SILValue DestLValue, SILValue DestLValue,
bool canDefaultConstruct) { bool canDefaultConstruct) {

View File

@@ -53,6 +53,9 @@ enum class SILInstructionMemoryBehavior {
MayWriteAndHaveSideEffects MayWriteAndHaveSideEffects
}; };
enum IsTake_t { IsNotTake, IsTake };
enum IsInitialization_t { IsNotInitialization, IsInitialization };
/// This is the root class for all instructions that can be used as the contents /// This is the root class for all instructions that can be used as the contents
/// of a Swift SILBasicBlock. /// of a Swift SILBasicBlock.
class SILInstruction : public ValueBase,public llvm::ilist_node<SILInstruction>{ class SILInstruction : public ValueBase,public llvm::ilist_node<SILInstruction>{
@@ -549,6 +552,53 @@ public:
} }
}; };
/// Represents a load from a [weak] memory location.
class LoadWeakInst
: public UnaryInstructionBase<ValueKind::LoadWeakInst>
{
static SILType getResultType(SILType operandTy) {
assert(operandTy.isAddress() && "loading from non-address operand?");
auto refType = cast<ReferenceStorageType>(operandTy.getSwiftRValueType());
return SILType::getPrimitiveObjectType(refType.getReferentType());
}
unsigned IsTake : 1; // FIXME: pack this somewhere
public:
/// \param loc The location of the expression that caused the load.
/// \param lvalue The SILValue representing the address to
/// use for the load.
LoadWeakInst(SILLocation loc, SILValue lvalue, IsTake_t isTake)
: UnaryInstructionBase(loc, lvalue, getResultType(lvalue.getType())),
IsTake(unsigned(isTake))
{}
IsTake_t isTake() const { return IsTake_t(IsTake); }
};
/// Represents a store to a [weak] memory location.
class StoreWeakInst : public SILInstruction {
enum { Src, Dest };
FixedOperandList<2> Operands;
unsigned IsInit : 1; // FIXME: pack this somewhere
public:
StoreWeakInst(SILLocation loc, SILValue src, SILValue dest,
IsInitialization_t isInit);
SILValue getSrc() const { return Operands[Src].get(); }
SILValue getDest() const { return Operands[Dest].get(); }
IsInitialization_t isInitialization() const {
return IsInitialization_t(IsInit);
}
ArrayRef<Operand> getAllOperands() const { return Operands.asArray(); }
static bool classof(const ValueBase *V) {
return V->getKind() == ValueKind::StoreWeakInst;
}
};
/// InitializeVarInst - Represents a default initialization of a variable. /// InitializeVarInst - Represents a default initialization of a variable.
class InitializeVarInst class InitializeVarInst
: public UnaryInstructionBase<ValueKind::InitializeVarInst, : public UnaryInstructionBase<ValueKind::InitializeVarInst,
@@ -566,9 +616,6 @@ public:
bool canDefaultConstruct() const { return CanDefaultConstruct; } bool canDefaultConstruct() const { return CanDefaultConstruct; }
}; };
enum IsTake_t { IsNotTake, IsTake };
enum IsInitialization_t { IsNotInitialization, IsInitialization };
/// CopyAddrInst - Represents a copy from one memory location to another. This /// CopyAddrInst - Represents a copy from one memory location to another. This
/// is similar to: /// is similar to:
/// %1 = load %src /// %1 = load %src

View File

@@ -72,7 +72,9 @@ ABSTRACT_VALUE(SILInstruction, ValueBase)
// Accessing memory // Accessing memory
INST(LoadInst, SILInstruction, None) INST(LoadInst, SILInstruction, None)
INST(LoadWeakInst, SILInstruction, None)
INST(StoreInst, SILInstruction, MayWrite) INST(StoreInst, SILInstruction, MayWrite)
INST(StoreWeakInst, SILInstruction, MayWrite)
INST(InitializeVarInst, SILInstruction, MayWrite) INST(InitializeVarInst, SILInstruction, MayWrite)
INST(CopyAddrInst, SILInstruction, MayWrite) INST(CopyAddrInst, SILInstruction, MayWrite)
INST(DestroyAddrInst, SILInstruction, MayHaveSideEffects) INST(DestroyAddrInst, SILInstruction, MayHaveSideEffects)

View File

@@ -606,34 +606,60 @@ namespace {
class SwiftWeakReferenceTypeInfo class SwiftWeakReferenceTypeInfo
: public IndirectTypeInfo<SwiftWeakReferenceTypeInfo, : public IndirectTypeInfo<SwiftWeakReferenceTypeInfo,
WeakTypeInfo> { WeakTypeInfo> {
llvm::Type *ValueType;
public: public:
SwiftWeakReferenceTypeInfo(llvm::Type *type, SwiftWeakReferenceTypeInfo(llvm::Type *valueType,
llvm::Type *weakType,
Size size, Alignment alignment) Size size, Alignment alignment)
: IndirectTypeInfo(type, size, alignment) {} : IndirectTypeInfo(weakType, size, alignment), ValueType(valueType) {}
void initializeWithCopy(IRGenFunction &IGF, Address destAddr, void initializeWithCopy(IRGenFunction &IGF, Address destAddr,
Address srcAddr) const { Address srcAddr) const override {
IGF.emitWeakCopyInit(destAddr, srcAddr); IGF.emitWeakCopyInit(destAddr, srcAddr);
} }
void initializeWithTake(IRGenFunction &IGF, Address destAddr, void initializeWithTake(IRGenFunction &IGF, Address destAddr,
Address srcAddr) const { Address srcAddr) const override {
IGF.emitWeakTakeInit(destAddr, srcAddr); IGF.emitWeakTakeInit(destAddr, srcAddr);
} }
void assignWithCopy(IRGenFunction &IGF, Address destAddr, void assignWithCopy(IRGenFunction &IGF, Address destAddr,
Address srcAddr) const { Address srcAddr) const override {
IGF.emitWeakCopyAssign(destAddr, srcAddr); IGF.emitWeakCopyAssign(destAddr, srcAddr);
} }
void assignWithTake(IRGenFunction &IGF, Address destAddr, void assignWithTake(IRGenFunction &IGF, Address destAddr,
Address srcAddr) const { Address srcAddr) const override {
IGF.emitWeakTakeAssign(destAddr, srcAddr); IGF.emitWeakTakeAssign(destAddr, srcAddr);
} }
void destroy(IRGenFunction &IGF, Address addr) const { void destroy(IRGenFunction &IGF, Address addr) const override {
IGF.emitWeakDestroy(addr); IGF.emitWeakDestroy(addr);
} }
void weakLoadStrong(IRGenFunction &IGF, Address addr,
Explosion &out) const override {
out.add(IGF.emitWeakLoadStrong(addr, ValueType));
}
void weakTakeStrong(IRGenFunction &IGF, Address addr,
Explosion &out) const override {
out.add(IGF.emitWeakTakeStrong(addr, ValueType));
}
void weakInit(IRGenFunction &IGF, Explosion &in,
Address dest) const override {
llvm::Value *value = in.claimNext();
assert(value->getType() == ValueType);
IGF.emitWeakInit(value, dest);
}
void weakAssign(IRGenFunction &IGF, Explosion &in,
Address dest) const override {
llvm::Value *value = in.claimNext();
assert(value->getType() == ValueType);
IGF.emitWeakAssign(value, dest);
}
}; };
} }
@@ -646,7 +672,8 @@ TypeConverter::createSwiftUnownedStorageType(llvm::Type *valueType) {
const WeakTypeInfo * const WeakTypeInfo *
TypeConverter::createSwiftWeakStorageType(llvm::Type *valueType) { TypeConverter::createSwiftWeakStorageType(llvm::Type *valueType) {
return new SwiftWeakReferenceTypeInfo(IGM.WeakReferencePtrTy, return new SwiftWeakReferenceTypeInfo(valueType,
IGM.WeakReferencePtrTy->getElementType(),
IGM.getWeakReferenceSize(), IGM.getWeakReferenceSize(),
IGM.getWeakReferenceAlignment()); IGM.getWeakReferenceAlignment());
} }
@@ -678,10 +705,14 @@ namespace {
class UnknownWeakReferenceTypeInfo : class UnknownWeakReferenceTypeInfo :
public IndirectTypeInfo<UnknownWeakReferenceTypeInfo, public IndirectTypeInfo<UnknownWeakReferenceTypeInfo,
WeakTypeInfo> { WeakTypeInfo> {
/// We need to separately store the value type because we always
/// use the same type to store the weak reference struct.
llvm::Type *ValueType;
public: public:
UnknownWeakReferenceTypeInfo(llvm::Type *type, UnknownWeakReferenceTypeInfo(llvm::Type *valueType,
llvm::Type *weakType,
Size size, Alignment alignment) Size size, Alignment alignment)
: IndirectTypeInfo(type, size, alignment) {} : IndirectTypeInfo(weakType, size, alignment), ValueType(valueType) {}
void initializeWithCopy(IRGenFunction &IGF, Address destAddr, void initializeWithCopy(IRGenFunction &IGF, Address destAddr,
Address srcAddr) const { Address srcAddr) const {
@@ -706,6 +737,30 @@ namespace {
void destroy(IRGenFunction &IGF, Address addr) const { void destroy(IRGenFunction &IGF, Address addr) const {
IGF.emitUnknownWeakDestroy(addr); IGF.emitUnknownWeakDestroy(addr);
} }
void weakLoadStrong(IRGenFunction &IGF, Address addr,
Explosion &out) const override {
out.add(IGF.emitUnknownWeakLoadStrong(addr, ValueType));
}
void weakTakeStrong(IRGenFunction &IGF, Address addr,
Explosion &out) const override {
out.add(IGF.emitUnknownWeakTakeStrong(addr, ValueType));
}
void weakInit(IRGenFunction &IGF, Explosion &in,
Address dest) const override {
llvm::Value *value = in.claimNext();
assert(value->getType() == ValueType);
IGF.emitUnknownWeakInit(value, dest);
}
void weakAssign(IRGenFunction &IGF, Explosion &in,
Address dest) const override {
llvm::Value *value = in.claimNext();
assert(value->getType() == ValueType);
IGF.emitUnknownWeakAssign(value, dest);
}
}; };
} }
@@ -718,7 +773,8 @@ TypeConverter::createUnknownUnownedStorageType(llvm::Type *valueType) {
const WeakTypeInfo * const WeakTypeInfo *
TypeConverter::createUnknownWeakStorageType(llvm::Type *valueType) { TypeConverter::createUnknownWeakStorageType(llvm::Type *valueType) {
return new UnknownWeakReferenceTypeInfo(IGM.WeakReferencePtrTy, return new UnknownWeakReferenceTypeInfo(valueType,
IGM.WeakReferencePtrTy->getElementType(),
IGM.getWeakReferenceSize(), IGM.getWeakReferenceSize(),
IGM.getWeakReferenceAlignment()); IGM.getWeakReferenceAlignment());
} }
@@ -729,17 +785,19 @@ static bool doesNotRequireRefCounting(llvm::Value *value) {
return isa<llvm::Constant>(value); return isa<llvm::Constant>(value);
} }
static llvm::FunctionType *getTypeOfFunction(llvm::Constant *fn) {
return cast<llvm::FunctionType>(fn->getType()->getPointerElementType());
}
/// Emit a unary call to perform a ref-counting operation. /// Emit a unary call to perform a ref-counting operation.
/// ///
/// \param fn - expected signature 'void (T*)' /// \param fn - expected signature 'void (T)'
static void emitUnaryRefCountCall(IRGenFunction &IGF, static void emitUnaryRefCountCall(IRGenFunction &IGF,
llvm::Constant *fn, llvm::Constant *fn,
llvm::Value *value) { llvm::Value *value) {
auto fnTy = cast<llvm::FunctionType>(fn->getType()->getPointerElementType()); // Instead of casting the input, we cast the function type.
// This tends to produce less IR, but might be evil.
// Instead of casting the input to %swift.refcounted*, we cast the if (value->getType() != getTypeOfFunction(fn)->getParamType(0)) {
// function type. This tends to produce less IR, but might be evil.
if (value->getType() != fnTy->getParamType(0)) {
llvm::FunctionType *fnType = llvm::FunctionType *fnType =
llvm::FunctionType::get(IGF.IGM.VoidTy, value->getType(), false); llvm::FunctionType::get(IGF.IGM.VoidTy, value->getType(), false);
fn = llvm::ConstantExpr::getBitCast(fn, fnType->getPointerTo()); fn = llvm::ConstantExpr::getBitCast(fn, fnType->getPointerTo());
@@ -751,20 +809,19 @@ static void emitUnaryRefCountCall(IRGenFunction &IGF,
call->setDoesNotThrow(); call->setDoesNotThrow();
} }
/// Emit a unary call to perform a ref-counting operation. /// Emit a copy-like call to perform a ref-counting operation.
/// ///
/// \param fn - expected signature 'void (T*, T*)' /// \param fn - expected signature 'void (T, T)'
static void emitBinaryRefCountCall(IRGenFunction &IGF, static void emitCopyLikeCall(IRGenFunction &IGF,
llvm::Constant *fn, llvm::Constant *fn,
llvm::Value *dest, llvm::Value *dest,
llvm::Value *src) { llvm::Value *src) {
assert(dest->getType() == src->getType() && assert(dest->getType() == src->getType() &&
"type mismatch in binary refcounting operation"); "type mismatch in binary refcounting operation");
// Instead of casting the input to %swift.refcounted*, we cast the // Instead of casting the inputs, we cast the function type.
// function type. This tends to produce less IR, but might be evil. // This tends to produce less IR, but might be evil.
if (dest->getType() != if (dest->getType() != getTypeOfFunction(fn)->getParamType(0)) {
cast<llvm::FunctionType>(fn->getType())->getParamType(0)) {
llvm::Type *paramTypes[] = { dest->getType(), dest->getType() }; llvm::Type *paramTypes[] = { dest->getType(), dest->getType() };
llvm::FunctionType *fnType = llvm::FunctionType *fnType =
llvm::FunctionType::get(IGF.IGM.VoidTy, paramTypes, false); llvm::FunctionType::get(IGF.IGM.VoidTy, paramTypes, false);
@@ -777,6 +834,58 @@ static void emitBinaryRefCountCall(IRGenFunction &IGF,
call->setDoesNotThrow(); call->setDoesNotThrow();
} }
/// Emit a call to a function with a loadWeak-like signature.
///
/// \param fn - expected signature 'T (Weak*)'
static llvm::Value *emitLoadWeakLikeCall(IRGenFunction &IGF,
llvm::Constant *fn,
llvm::Value *addr,
llvm::Type *resultType) {
assert(addr->getType() == IGF.IGM.WeakReferencePtrTy &&
"address is not of a weak reference");
// Instead of casting the output, we cast the function type.
// This tends to produce less IR, but might be evil.
if (resultType != getTypeOfFunction(fn)->getReturnType()) {
llvm::Type *paramTypes[] = { addr->getType() };
llvm::FunctionType *fnType =
llvm::FunctionType::get(resultType, paramTypes, false);
fn = llvm::ConstantExpr::getBitCast(fn, fnType->getPointerTo());
}
// Emit the call.
llvm::CallInst *call = IGF.Builder.CreateCall(fn, addr);
call->setCallingConv(IGF.IGM.RuntimeCC);
call->setDoesNotThrow();
return call;
}
/// Emit a call to a function with a storeWeak-like signature.
///
/// \param fn - expected signature 'void (Weak*, T)'
static void emitStoreWeakLikeCall(IRGenFunction &IGF,
llvm::Constant *fn,
llvm::Value *addr,
llvm::Value *value) {
assert(addr->getType() == IGF.IGM.WeakReferencePtrTy &&
"address is not of a weak reference");
// Instead of casting the inputs, we cast the function type.
// This tends to produce less IR, but might be evil.
if (value->getType() != getTypeOfFunction(fn)->getParamType(1)) {
llvm::Type *paramTypes[] = { addr->getType(), value->getType() };
llvm::FunctionType *fnType =
llvm::FunctionType::get(IGF.IGM.VoidTy, paramTypes, false);
fn = llvm::ConstantExpr::getBitCast(fn, fnType->getPointerTo());
}
// Emit the call.
llvm::CallInst *call = IGF.Builder.CreateCall2(fn, addr, value);
call->setCallingConv(IGF.IGM.RuntimeCC);
call->setDoesNotThrow();
}
/// Emit a call to swift_retain_noresult. In general, you should not be using /// Emit a call to swift_retain_noresult. In general, you should not be using
/// this routine; instead you should use emitRetain, which properly /// this routine; instead you should use emitRetain, which properly
/// balances the retain. /// balances the retain.
@@ -856,34 +965,52 @@ void IRGenFunction::emitUnknownRelease(llvm::Value *value) {
return emitObjCRelease(value); return emitObjCRelease(value);
} }
#define REFCOUNT_VALUE(ID) \ #define DEFINE_VALUE_OP(ID) \
void IRGenFunction::emit##ID(llvm::Value *value) { \ void IRGenFunction::emit##ID(llvm::Value *value) { \
if (doesNotRequireRefCounting(value)) return; \ if (doesNotRequireRefCounting(value)) return; \
emitUnaryRefCountCall(*this, IGM.get##ID##Fn(), value); \ emitUnaryRefCountCall(*this, IGM.get##ID##Fn(), value); \
} }
#define REFCOUNT_ADDR(ID) \ #define DEFINE_ADDR_OP(ID) \
void IRGenFunction::emit##ID(Address addr) { \ void IRGenFunction::emit##ID(Address addr) { \
emitUnaryRefCountCall(*this, IGM.get##ID##Fn(), addr.getAddress()); \ emitUnaryRefCountCall(*this, IGM.get##ID##Fn(), addr.getAddress()); \
} }
#define REFCOUNT_ADDR_ADDR(ID) \ #define DEFINE_COPY_OP(ID) \
void IRGenFunction::emit##ID(Address dest, Address src) { \ void IRGenFunction::emit##ID(Address dest, Address src) { \
emitBinaryRefCountCall(*this, IGM.get##ID##Fn(), dest.getAddress(), \ emitCopyLikeCall(*this, IGM.get##ID##Fn(), dest.getAddress(), \
src.getAddress()); \ src.getAddress()); \
}
#define DEFINE_LOAD_WEAK_OP(ID) \
llvm::Value *IRGenFunction::emit##ID(Address src, llvm::Type *type) { \
return emitLoadWeakLikeCall(*this, IGM.get##ID##Fn(), \
src.getAddress(), type); \
}
#define DEFINE_STORE_WEAK_OP(ID) \
void IRGenFunction::emit##ID(llvm::Value *value, Address src) { \
emitStoreWeakLikeCall(*this, IGM.get##ID##Fn(), \
src.getAddress(), value); \
} }
REFCOUNT_VALUE(RetainUnowned) DEFINE_VALUE_OP(RetainUnowned)
REFCOUNT_VALUE(UnownedRelease) DEFINE_VALUE_OP(UnownedRelease)
REFCOUNT_VALUE(UnownedRetain) DEFINE_VALUE_OP(UnownedRetain)
REFCOUNT_ADDR(WeakDestroy) DEFINE_LOAD_WEAK_OP(WeakLoadStrong)
REFCOUNT_ADDR_ADDR(WeakCopyInit) DEFINE_LOAD_WEAK_OP(WeakTakeStrong)
REFCOUNT_ADDR_ADDR(WeakCopyAssign) DEFINE_STORE_WEAK_OP(WeakInit)
REFCOUNT_ADDR_ADDR(WeakTakeInit) DEFINE_STORE_WEAK_OP(WeakAssign)
REFCOUNT_ADDR_ADDR(WeakTakeAssign) DEFINE_ADDR_OP(WeakDestroy)
REFCOUNT_VALUE(UnknownRetainUnowned) DEFINE_COPY_OP(WeakCopyInit)
REFCOUNT_VALUE(UnknownUnownedRelease) DEFINE_COPY_OP(WeakCopyAssign)
REFCOUNT_VALUE(UnknownUnownedRetain) DEFINE_COPY_OP(WeakTakeInit)
REFCOUNT_ADDR(UnknownWeakDestroy) DEFINE_COPY_OP(WeakTakeAssign)
REFCOUNT_ADDR_ADDR(UnknownWeakCopyInit) DEFINE_VALUE_OP(UnknownRetainUnowned)
REFCOUNT_ADDR_ADDR(UnknownWeakCopyAssign) DEFINE_VALUE_OP(UnknownUnownedRelease)
REFCOUNT_ADDR_ADDR(UnknownWeakTakeInit) DEFINE_VALUE_OP(UnknownUnownedRetain)
REFCOUNT_ADDR_ADDR(UnknownWeakTakeAssign) DEFINE_LOAD_WEAK_OP(UnknownWeakLoadStrong)
DEFINE_LOAD_WEAK_OP(UnknownWeakTakeStrong)
DEFINE_STORE_WEAK_OP(UnknownWeakInit)
DEFINE_STORE_WEAK_OP(UnknownWeakAssign)
DEFINE_ADDR_OP(UnknownWeakDestroy)
DEFINE_COPY_OP(UnknownWeakCopyInit)
DEFINE_COPY_OP(UnknownWeakCopyAssign)
DEFINE_COPY_OP(UnknownWeakTakeInit)
DEFINE_COPY_OP(UnknownWeakTakeAssign)

View File

@@ -561,6 +561,24 @@ namespace {
IGF.emitMemCpy(dest, src, NumProtocols * IGF.IGM.getPointerSize()); IGF.emitMemCpy(dest, src, NumProtocols * IGF.IGM.getPointerSize());
} }
void emitLoadOfTables(IRGenFunction &IGF, Address existential,
Explosion &out) const {
for (unsigned i = 0; i != NumProtocols; ++i) {
auto tableAddr = IGF.Builder.CreateStructGEP(existential, i,
i * IGF.IGM.getPointerSize());
out.add(IGF.Builder.CreateLoad(tableAddr));
}
}
void emitStoreOfTables(IRGenFunction &IGF, Explosion &in,
Address existential) const {
for (unsigned i = 0; i != NumProtocols; ++i) {
auto tableAddr = IGF.Builder.CreateStructGEP(existential, i,
i * IGF.IGM.getPointerSize());
IGF.Builder.CreateStore(in.claimNext(), tableAddr);
}
}
Address projectValue(IRGenFunction &IGF, Address existential) const { Address projectValue(IRGenFunction &IGF, Address existential) const {
return IGF.Builder.CreateStructGEP(existential, NumProtocols, return IGF.Builder.CreateStructGEP(existential, NumProtocols,
NumProtocols * IGF.IGM.getPointerSize(), NumProtocols * IGF.IGM.getPointerSize(),
@@ -602,6 +620,43 @@ namespace {
Address valueAddr = projectValue(IGF, existential); Address valueAddr = projectValue(IGF, existential);
IGF.emitUnknownWeakDestroy(valueAddr); IGF.emitUnknownWeakDestroy(valueAddr);
} }
// These explosions must follow the same schema as
// ClassExistentialTypeInfo, i.e. first the tables, then the value.
void weakLoadStrong(IRGenFunction &IGF, Address existential,
Explosion &out) const override {
emitLoadOfTables(IGF, existential, out);
Address valueAddr = projectValue(IGF, existential);
out.add(IGF.emitUnknownWeakLoadStrong(valueAddr,
IGF.IGM.UnknownRefCountedPtrTy));
}
void weakTakeStrong(IRGenFunction &IGF, Address existential,
Explosion &out) const override {
emitLoadOfTables(IGF, existential, out);
Address valueAddr = projectValue(IGF, existential);
out.add(IGF.emitUnknownWeakTakeStrong(valueAddr,
IGF.IGM.UnknownRefCountedPtrTy));
}
void weakInit(IRGenFunction &IGF, Explosion &in,
Address existential) const override {
emitStoreOfTables(IGF, in, existential);
llvm::Value *value = in.claimNext();
assert(value->getType() == IGF.IGM.UnknownRefCountedPtrTy);
Address valueAddr = projectValue(IGF, existential);
IGF.emitUnknownWeakInit(value, valueAddr);
}
void weakAssign(IRGenFunction &IGF, Explosion &in,
Address existential) const override {
emitStoreOfTables(IGF, in, existential);
llvm::Value *value = in.claimNext();
assert(value->getType() == IGF.IGM.UnknownRefCountedPtrTy);
Address valueAddr = projectValue(IGF, existential);
IGF.emitUnknownWeakAssign(value, valueAddr);
}
}; };
/// A helper class for working with existential types that can be /// A helper class for working with existential types that can be

View File

@@ -169,7 +169,10 @@ public:
void emitRetainUnowned(llvm::Value *value); void emitRetainUnowned(llvm::Value *value);
void emitUnownedRetain(llvm::Value *value); void emitUnownedRetain(llvm::Value *value);
void emitUnownedRelease(llvm::Value *value); void emitUnownedRelease(llvm::Value *value);
void emitWeakInit(Address addr); void emitWeakInit(llvm::Value *value, Address dest);
void emitWeakAssign(llvm::Value *value, Address dest);
llvm::Value *emitWeakLoadStrong(Address src, llvm::Type *type);
llvm::Value *emitWeakTakeStrong(Address src, llvm::Type *type);
void emitWeakDestroy(Address addr); void emitWeakDestroy(Address addr);
void emitWeakCopyInit(Address destAddr, Address srcAddr); void emitWeakCopyInit(Address destAddr, Address srcAddr);
void emitWeakTakeInit(Address destAddr, Address srcAddr); void emitWeakTakeInit(Address destAddr, Address srcAddr);
@@ -194,6 +197,10 @@ public:
void emitUnknownWeakTakeInit(Address destAddr, Address srcAddr); void emitUnknownWeakTakeInit(Address destAddr, Address srcAddr);
void emitUnknownWeakCopyAssign(Address destAddr, Address srcAddr); void emitUnknownWeakCopyAssign(Address destAddr, Address srcAddr);
void emitUnknownWeakTakeAssign(Address destAddr, Address srcAddr); void emitUnknownWeakTakeAssign(Address destAddr, Address srcAddr);
void emitUnknownWeakInit(llvm::Value *value, Address dest);
void emitUnknownWeakAssign(llvm::Value *value, Address dest);
llvm::Value *emitUnknownWeakLoadStrong(Address src, llvm::Type *type);
llvm::Value *emitUnknownWeakTakeStrong(Address src, llvm::Type *type);
//--- Expression emission ------------------------------------------------------ //--- Expression emission ------------------------------------------------------
public: public:

View File

@@ -49,6 +49,7 @@
#include "IRGenModule.h" #include "IRGenModule.h"
#include "Linking.h" #include "Linking.h"
#include "ReferenceTypeInfo.h" #include "ReferenceTypeInfo.h"
#include "WeakTypeInfo.h"
using namespace swift; using namespace swift;
using namespace irgen; using namespace irgen;
@@ -508,6 +509,8 @@ public:
void visitLoadInst(LoadInst *i); void visitLoadInst(LoadInst *i);
void visitStoreInst(StoreInst *i); void visitStoreInst(StoreInst *i);
void visitLoadWeakInst(LoadWeakInst *i);
void visitStoreWeakInst(StoreWeakInst *i);
void visitStructInst(StructInst *i); void visitStructInst(StructInst *i);
void visitTupleInst(TupleInst *i); void visitTupleInst(TupleInst *i);
void visitBuiltinZeroInst(BuiltinZeroInst *i); void visitBuiltinZeroInst(BuiltinZeroInst *i);
@@ -1674,6 +1677,33 @@ void IRGenSILFunction::visitStoreInst(swift::StoreInst *i) {
type.initialize(*this, source, dest); type.initialize(*this, source, dest);
} }
void IRGenSILFunction::visitLoadWeakInst(swift::LoadWeakInst *i) {
Address source = getLoweredAddress(i->getOperand());
auto &weakTI =
cast<WeakTypeInfo>(getFragileTypeInfo(i->getOperand().getType()));
Explosion result(ExplosionKind::Maximal);
if (i->isTake()) {
weakTI.weakTakeStrong(*this, source, result);
} else {
weakTI.weakLoadStrong(*this, source, result);
}
setLoweredExplosion(SILValue(i, 0), result);
}
void IRGenSILFunction::visitStoreWeakInst(swift::StoreWeakInst *i) {
Explosion source = getLoweredExplosion(i->getSrc());
Address dest = getLoweredAddress(i->getDest());
auto &weakTI = cast<WeakTypeInfo>(getFragileTypeInfo(i->getDest().getType()));
if (i->isInitialization()) {
weakTI.weakInit(*this, source, dest);
} else {
weakTI.weakAssign(*this, source, dest);
}
}
void IRGenSILFunction::visitRetainInst(swift::RetainInst *i) { void IRGenSILFunction::visitRetainInst(swift::RetainInst *i) {
// FIXME: Specialization thunks may eventually require retaining. For now, // FIXME: Specialization thunks may eventually require retaining. For now,
// since we don't yet thunk specialized function values, ignore retains // since we don't yet thunk specialized function values, ignore retains

View File

@@ -116,31 +116,55 @@ FUNCTION(UnownedRelease, swift_weakRelease,RuntimeCC,
ARGS(RefCountedPtrTy), ARGS(RefCountedPtrTy),
ATTRS(NoUnwind)) ATTRS(NoUnwind))
// void swift_weakDestroy(void **object); // void swift_weakDestroy(WeakReference *object);
FUNCTION(WeakDestroy, swift_weakDestroy, RuntimeCC, FUNCTION(WeakDestroy, swift_weakDestroy, RuntimeCC,
RETURNS(VoidTy), RETURNS(VoidTy),
ARGS(WeakReferencePtrTy), ARGS(WeakReferencePtrTy),
ATTRS(NoUnwind)) ATTRS(NoUnwind))
// void swift_weakCopyInit(void **dest, void **src); // void swift_weakInit(WeakReference *object, void *value);
FUNCTION(WeakInit, swift_weakInit, RuntimeCC,
RETURNS(VoidTy),
ARGS(WeakReferencePtrTy, RefCountedPtrTy),
ATTRS(NoUnwind))
// void swift_weakAssign(WeakReference *object, void *value);
FUNCTION(WeakAssign, swift_weakAssign, RuntimeCC,
RETURNS(VoidTy),
ARGS(WeakReferencePtrTy, RefCountedPtrTy),
ATTRS(NoUnwind))
// void *swift_weakLoadStrong(WeakReference *object);
FUNCTION(WeakLoadStrong, swift_weakLoadStrong,RuntimeCC,
RETURNS(RefCountedPtrTy),
ARGS(WeakReferencePtrTy),
ATTRS(NoUnwind))
// void *swift_weakTakeStrong(WeakReference *object);
FUNCTION(WeakTakeStrong, swift_weakTakeStrong,RuntimeCC,
RETURNS(RefCountedPtrTy),
ARGS(WeakReferencePtrTy),
ATTRS(NoUnwind))
// void swift_weakCopyInit(WeakReference *dest, WeakReference *src);
FUNCTION(WeakCopyInit, swift_weakCopyInit, RuntimeCC, FUNCTION(WeakCopyInit, swift_weakCopyInit, RuntimeCC,
RETURNS(VoidTy), RETURNS(VoidTy),
ARGS(WeakReferencePtrTy, WeakReferencePtrTy), ARGS(WeakReferencePtrTy, WeakReferencePtrTy),
ATTRS(NoUnwind)) ATTRS(NoUnwind))
// void swift_weakTakeInit(void **dest, void **src); // void swift_weakTakeInit(WeakReference *dest, WeakReference *src);
FUNCTION(WeakTakeInit, swift_weakTakeInit, RuntimeCC, FUNCTION(WeakTakeInit, swift_weakTakeInit, RuntimeCC,
RETURNS(VoidTy), RETURNS(VoidTy),
ARGS(WeakReferencePtrTy, WeakReferencePtrTy), ARGS(WeakReferencePtrTy, WeakReferencePtrTy),
ATTRS(NoUnwind)) ATTRS(NoUnwind))
// void swift_weakCopyAssign(void **dest, void **src); // void swift_weakCopyAssign(WeakReference *dest, WeakReference *src);
FUNCTION(WeakCopyAssign, swift_weakCopyAssign,RuntimeCC, FUNCTION(WeakCopyAssign, swift_weakCopyAssign,RuntimeCC,
RETURNS(VoidTy), RETURNS(VoidTy),
ARGS(WeakReferencePtrTy, WeakReferencePtrTy), ARGS(WeakReferencePtrTy, WeakReferencePtrTy),
ATTRS(NoUnwind)) ATTRS(NoUnwind))
// void swift_weakTakeAssign(void **dest, void **src); // void swift_weakTakeAssign(WeakReference *dest, WeakReference *src);
FUNCTION(WeakTakeAssign, swift_weakTakeAssign,RuntimeCC, FUNCTION(WeakTakeAssign, swift_weakTakeAssign,RuntimeCC,
RETURNS(VoidTy), RETURNS(VoidTy),
ARGS(WeakReferencePtrTy, WeakReferencePtrTy), ARGS(WeakReferencePtrTy, WeakReferencePtrTy),
@@ -164,31 +188,55 @@ FUNCTION(UnknownUnownedRelease, swift_unknownWeakRelease, RuntimeCC,
ARGS(RefCountedPtrTy), ARGS(RefCountedPtrTy),
ATTRS(NoUnwind)) ATTRS(NoUnwind))
// void swift_unknownWeakDestroy(void **object); // void swift_unknownWeakDestroy(WeakReference *object);
FUNCTION(UnknownWeakDestroy, swift_unknownWeakDestroy, RuntimeCC, FUNCTION(UnknownWeakDestroy, swift_unknownWeakDestroy, RuntimeCC,
RETURNS(VoidTy), RETURNS(VoidTy),
ARGS(WeakReferencePtrTy), ARGS(WeakReferencePtrTy),
ATTRS(NoUnwind)) ATTRS(NoUnwind))
// void swift_unknownWeakCopyInit(void **dest, void **src); // void swift_unknownWeakInit(WeakReference *object, void *value);
FUNCTION(UnknownWeakInit, swift_unknownWeakInit, RuntimeCC,
RETURNS(VoidTy),
ARGS(WeakReferencePtrTy, UnknownRefCountedPtrTy),
ATTRS(NoUnwind))
// void swift_unknownWeakAssign(WeakReference *object, void *value);
FUNCTION(UnknownWeakAssign, swift_unknownWeakAssign, RuntimeCC,
RETURNS(VoidTy),
ARGS(WeakReferencePtrTy, UnknownRefCountedPtrTy),
ATTRS(NoUnwind))
// void *swift_unknownWeakLoad(WeakReference *object);
FUNCTION(UnknownWeakLoadStrong, swift_unknownWeakLoadStrong,RuntimeCC,
RETURNS(UnknownRefCountedPtrTy),
ARGS(WeakReferencePtrTy),
ATTRS(NoUnwind))
// void *swift_unknownWeakTake(WeakReference *object);
FUNCTION(UnknownWeakTakeStrong, swift_unknownWeakTakeStrong,RuntimeCC,
RETURNS(UnknownRefCountedPtrTy),
ARGS(WeakReferencePtrTy),
ATTRS(NoUnwind))
// void swift_unknownWeakCopyInit(WeakReference *dest, WeakReference *src);
FUNCTION(UnknownWeakCopyInit, swift_unknownWeakCopyInit, RuntimeCC, FUNCTION(UnknownWeakCopyInit, swift_unknownWeakCopyInit, RuntimeCC,
RETURNS(VoidTy), RETURNS(VoidTy),
ARGS(WeakReferencePtrTy, WeakReferencePtrTy), ARGS(WeakReferencePtrTy, WeakReferencePtrTy),
ATTRS(NoUnwind)) ATTRS(NoUnwind))
// void swift_unknownWeakTakeInit(void **dest, void **src); // void swift_unknownWeakTakeInit(WeakReference *dest, WeakReference *src);
FUNCTION(UnknownWeakTakeInit, swift_unknownWeakTakeInit, RuntimeCC, FUNCTION(UnknownWeakTakeInit, swift_unknownWeakTakeInit, RuntimeCC,
RETURNS(VoidTy), RETURNS(VoidTy),
ARGS(WeakReferencePtrTy, WeakReferencePtrTy), ARGS(WeakReferencePtrTy, WeakReferencePtrTy),
ATTRS(NoUnwind)) ATTRS(NoUnwind))
// void swift_unknownWeakCopyAssign(void **dest, void **src); // void swift_unknownWeakCopyAssign(WeakReference *dest, WeakReference *src);
FUNCTION(UnknownWeakCopyAssign, swift_unknownWeakCopyAssign,RuntimeCC, FUNCTION(UnknownWeakCopyAssign, swift_unknownWeakCopyAssign,RuntimeCC,
RETURNS(VoidTy), RETURNS(VoidTy),
ARGS(WeakReferencePtrTy, WeakReferencePtrTy), ARGS(WeakReferencePtrTy, WeakReferencePtrTy),
ATTRS(NoUnwind)) ATTRS(NoUnwind))
// void swift_unknownWeakTakeAssign(void **dest, void **src); // void swift_unknownWeakTakeAssign(WeakReference *dest, WeakReference *src);
FUNCTION(UnknownWeakTakeAssign, swift_unknownWeakTakeAssign,RuntimeCC, FUNCTION(UnknownWeakTakeAssign, swift_unknownWeakTakeAssign,RuntimeCC,
RETURNS(VoidTy), RETURNS(VoidTy),
ARGS(WeakReferencePtrTy, WeakReferencePtrTy), ARGS(WeakReferencePtrTy, WeakReferencePtrTy),

View File

@@ -31,6 +31,15 @@ protected:
: FixedTypeInfo(type, size, align, IsNotPOD, STIK_Weak) {} : FixedTypeInfo(type, size, align, IsNotPOD, STIK_Weak) {}
public: public:
virtual void weakLoadStrong(IRGenFunction &IGF, Address addr,
Explosion &out) const = 0;
virtual void weakTakeStrong(IRGenFunction &IGF, Address addr,
Explosion &out) const = 0;
virtual void weakInit(IRGenFunction &IGF, Explosion &src,
Address dest) const = 0;
virtual void weakAssign(IRGenFunction &IGF, Explosion &src,
Address dest) const = 0;
static bool classof(const WeakTypeInfo *type) { return true; } static bool classof(const WeakTypeInfo *type) { return true; }
static bool classof(const TypeInfo *type) { static bool classof(const TypeInfo *type) {
return type->getSpecialTypeInfoKind() == STIK_Weak; return type->getSpecialTypeInfoKind() == STIK_Weak;

View File

@@ -850,6 +850,7 @@ bool SILParser::parseSILOpcode(ValueKind &Opcode, SourceLoc &OpcodeLoc,
.Case("is_nonnull", ValueKind::IsNonnullInst) .Case("is_nonnull", ValueKind::IsNonnullInst)
.Case("function_ref", ValueKind::FunctionRefInst) .Case("function_ref", ValueKind::FunctionRefInst)
.Case("load", ValueKind::LoadInst) .Case("load", ValueKind::LoadInst)
.Case("load_weak", ValueKind::LoadWeakInst)
.Case("metatype", ValueKind::MetatypeInst) .Case("metatype", ValueKind::MetatypeInst)
.Case("object_pointer_to_ref", ValueKind::ObjectPointerToRefInst) .Case("object_pointer_to_ref", ValueKind::ObjectPointerToRefInst)
.Case("partial_apply", ValueKind::PartialApplyInst) .Case("partial_apply", ValueKind::PartialApplyInst)
@@ -871,6 +872,7 @@ bool SILParser::parseSILOpcode(ValueKind &Opcode, SourceLoc &OpcodeLoc,
.Case("retain_unowned", ValueKind::RetainUnownedInst) .Case("retain_unowned", ValueKind::RetainUnownedInst)
.Case("return", ValueKind::ReturnInst) .Case("return", ValueKind::ReturnInst)
.Case("store", ValueKind::StoreInst) .Case("store", ValueKind::StoreInst)
.Case("store_weak", ValueKind::StoreWeakInst)
.Case("string_literal", ValueKind::StringLiteralInst) .Case("string_literal", ValueKind::StringLiteralInst)
.Case("struct", ValueKind::StructInst) .Case("struct", ValueKind::StructInst)
.Case("struct_element_addr", ValueKind::StructElementAddrInst) .Case("struct_element_addr", ValueKind::StructElementAddrInst)
@@ -1156,6 +1158,15 @@ bool SILParser::parseSILInstruction(SILBasicBlock *BB) {
if (parseTypedValueRef(Val)) return true; if (parseTypedValueRef(Val)) return true;
ResultVal = B.createLoad(InstLoc, Val); ResultVal = B.createLoad(InstLoc, Val);
break; break;
case ValueKind::LoadWeakInst: {
bool isTake = false;
if (parseSILOptional(isTake, P, "take") ||
parseTypedValueRef(Val))
return true;
ResultVal = B.createLoadWeak(SILLocation(), Val, IsTake_t(isTake));
break;
}
// Conversion instructions. // Conversion instructions.
case ValueKind::RefToObjectPointerInst: case ValueKind::RefToObjectPointerInst:
@@ -1299,30 +1310,48 @@ bool SILParser::parseSILInstruction(SILBasicBlock *BB) {
break; break;
} }
case ValueKind::StoreInst: { case ValueKind::StoreInst:
UnresolvedValueName From; case ValueKind::StoreWeakInst: {
UnresolvedValueName from;
SourceLoc ToLoc, AddrLoc; SourceLoc toLoc, addrLoc;
Identifier ToToken; Identifier toToken;
SILValue AddrVal; SILValue addrVal;
if (parseValueName(From) || bool isInit = false;
P.parseIdentifier(ToToken, ToLoc, if (parseValueName(from) ||
P.parseIdentifier(toToken, toLoc,
diag::expected_tok_in_sil_instr, "to") || diag::expected_tok_in_sil_instr, "to") ||
parseTypedValueRef(AddrVal, AddrLoc)) (Opcode == ValueKind::StoreWeakInst &&
parseSILOptional(isInit, P, "initialization")) ||
parseTypedValueRef(addrVal, addrLoc))
return true; return true;
if (ToToken.str() != "to") { if (toToken.str() != "to") {
P.diagnose(ToLoc, diag::expected_tok_in_sil_instr, "to"); P.diagnose(toLoc, diag::expected_tok_in_sil_instr, "to");
return true; return true;
} }
if (!AddrVal.getType().isAddress()) { if (!addrVal.getType().isAddress()) {
P.diagnose(AddrLoc, diag::sil_invalid_instr_operands); P.diagnose(addrLoc, diag::sil_operand_not_address,
"destination", OpcodeName);
return true; return true;
} }
SILValue FromVal = getLocalValue(From, AddrVal.getType().getObjectType()); SILType valueTy;
ResultVal = B.createStore(InstLoc, FromVal, AddrVal); if (Opcode == ValueKind::StoreInst) {
valueTy = addrVal.getType().getObjectType();
} else {
auto refType = addrVal.getType().getAs<ReferenceStorageType>();
if (!refType || refType->getOwnership() != Ownership::Weak) {
P.diagnose(addrLoc, diag::sil_operand_not_weak_address,
"destination", OpcodeName);
return true;
}
valueTy = SILType::getPrimitiveObjectType(refType.getReferentType());
}
SILValue fromVal = getLocalValue(from, valueTy);
ResultVal = B.createStore(InstLoc, fromVal, addrVal);
break; break;
} }
case ValueKind::AllocStackInst: case ValueKind::AllocStackInst:

View File

@@ -357,7 +357,7 @@ ManagedValue SILGenFunction::emitLoad(SILLocation loc,
IsTake_t isTake) { IsTake_t isTake) {
auto &addrTL = getTypeLowering(addr.getType()); auto &addrTL = getTypeLowering(addr.getType());
auto &semanticTL = addrTL.getSemanticTypeLowering(SGM.Types); auto &semanticTL = addrTL.getSemanticTypeLowering(SGM.Types);
if (addrTL.isAddressOnly()) { if (semanticTL.isAddressOnly()) {
// Copy the address-only value. // Copy the address-only value.
SILValue copy = getBufferForExprResult(loc, semanticTL.getLoweredType(), C); SILValue copy = getBufferForExprResult(loc, semanticTL.getLoweredType(), C);
addrTL.emitSemanticLoadInto(B, loc, addr, copy, isTake, IsInitialization); addrTL.emitSemanticLoadInto(B, loc, addr, copy, isTake, IsInitialization);

View File

@@ -411,6 +411,11 @@ StoreInst::StoreInst(SILLocation Loc, SILValue Src, SILValue Dest)
Operands(this, Src, Dest) { Operands(this, Src, Dest) {
} }
StoreWeakInst::StoreWeakInst(SILLocation loc, SILValue value, SILValue dest,
IsInitialization_t isInit)
: SILInstruction(ValueKind::StoreWeakInst, loc),
Operands(this, value, dest), IsInit(isInit) {
}
CopyAddrInst::CopyAddrInst(SILLocation Loc, SILValue SrcLValue, SILValue DestLValue, CopyAddrInst::CopyAddrInst(SILLocation Loc, SILValue SrcLValue, SILValue DestLValue,
IsTake_t isTakeOfSrc, IsTake_t isTakeOfSrc,

View File

@@ -440,6 +440,15 @@ public:
OS << "store " << getID(SI->getSrc()) << " to " OS << "store " << getID(SI->getSrc()) << " to "
<< getIDAndType(SI->getDest()); << getIDAndType(SI->getDest());
} }
void visitLoadWeakInst(LoadWeakInst *LI) {
OS << "load_weak " << getIDAndType(LI->getOperand());
}
void visitStoreWeakInst(StoreWeakInst *SI) {
OS << "store_weak " << getID(SI->getSrc()) << " to ";
if (SI->isInitialization())
OS << "[initialization] ";
OS << getIDAndType(SI->getDest());
}
void visitCopyAddrInst(CopyAddrInst *CI) { void visitCopyAddrInst(CopyAddrInst *CI) {
OS << "copy_addr "; OS << "copy_addr ";
if (CI->isTakeOfSrc()) if (CI->isTakeOfSrc())

View File

@@ -470,6 +470,19 @@ bool SILType::isAddressOnly(CanType type, SILModule &M) {
return classifyType(type, M) == LoweredTypeKind::AddressOnly; return classifyType(type, M) == LoweredTypeKind::AddressOnly;
} }
/// Emit the semantic store operation on a reference type.
static void emitReferenceSemanticStore(SILBuilder &B, SILLocation loc,
SILValue value, SILValue addr,
IsInitialization_t isInit) {
// FIXME: Use assign instruction here? Or maybe have two
// variants of this function, one for canonical, one for
// non-canonical.
SILValue old;
if (!isInit) old = B.createLoad(loc, addr);
B.createStore(loc, value, addr);
if (!isInit) B.createRelease(loc, old);
}
namespace { namespace {
/// A class for loadable types. /// A class for loadable types.
class LoadableTypeLowering : public TypeLowering { class LoadableTypeLowering : public TypeLowering {
@@ -684,13 +697,7 @@ namespace {
void emitSemanticStore(SILBuilder &B, SILLocation loc, void emitSemanticStore(SILBuilder &B, SILLocation loc,
SILValue value, SILValue addr, SILValue value, SILValue addr,
IsInitialization_t isInit) const override { IsInitialization_t isInit) const override {
// FIXME: Use assign instruction here? Or maybe have two emitReferenceSemanticStore(B, loc, value, addr, isInit);
// variants of this function, one for canonical, one for
// non-canonical.
SILValue old;
if (!isInit) old = B.createLoad(loc, addr);
B.createStore(loc, value, addr);
if (!isInit) B.createRelease(loc, old);
} }
SILValue emitSemanticLoad(SILBuilder &B, SILLocation loc, SILValue emitSemanticLoad(SILBuilder &B, SILLocation loc,
@@ -788,20 +795,24 @@ namespace {
void emitSemanticStore(SILBuilder &B, SILLocation loc, void emitSemanticStore(SILBuilder &B, SILLocation loc,
SILValue value, SILValue addr, SILValue value, SILValue addr,
IsInitialization_t isInit) const override { IsInitialization_t isInit) const override {
// FIXME B.createStoreWeak(loc, value, addr, isInit);
// store_weak does not consume a retain on its input, so we have
// to balance that out.
B.createRelease(loc, value);
} }
SILValue emitSemanticLoad(SILBuilder &B, SILLocation loc, SILValue emitSemanticLoad(SILBuilder &B, SILLocation loc,
SILValue addr, IsTake_t isTake) const override { SILValue addr, IsTake_t isTake) const override {
// FIXME return B.createLoadWeak(loc, addr, isTake);
return SILValue();
} }
void emitSemanticLoadInto(SILBuilder &B, SILLocation loc, void emitSemanticLoadInto(SILBuilder &B, SILLocation loc,
SILValue src, SILValue dest, SILValue src, SILValue dest,
IsTake_t isTake, IsTake_t isTake,
IsInitialization_t isInit) const override { IsInitialization_t isInit) const override {
// FIXME auto value = B.createLoadWeak(loc, src, isTake);
emitReferenceSemanticStore(B, loc, value, dest, isInit);
} }
}; };

View File

@@ -441,8 +441,33 @@ extern "C" bool swift_isUniquelyReferenced(HeapObject *object) {
return result; return result;
} }
void swift::swift_weakInit(WeakReference *ref) { void swift::swift_weakInit(WeakReference *ref, HeapObject *value) {
ref->Value = nullptr; ref->Value = value;
swift_weakRetain(value);
}
void swift::swift_weakAssign(WeakReference *ref, HeapObject *newValue) {
swift_weakRetain(newValue);
auto oldValue = ref->Value;
ref->Value = newValue;
swift_weakRelease(oldValue);
}
HeapObject *swift::swift_weakLoadStrong(WeakReference *ref) {
auto object = ref->Value;
if (object == nullptr) return nullptr;
if (object->refCount & RC_DEALLOCATING_BIT) {
swift_weakRelease(object);
ref->Value = nullptr;
return nullptr;
}
return swift_tryRetain(object);
}
HeapObject *swift::swift_weakTakeStrong(WeakReference *ref) {
auto result = swift_weakLoadStrong(ref);
swift_weakDestroy(ref);
return result;
} }
void swift::swift_weakDestroy(WeakReference *ref) { void swift::swift_weakDestroy(WeakReference *ref) {
@@ -488,17 +513,6 @@ void swift::swift_weakTakeAssign(WeakReference *dest, WeakReference *src) {
swift_weakTakeInit(dest, src); swift_weakTakeInit(dest, src);
} }
HeapObject *swift::swift_weakTryRetain(WeakReference *ref) {
auto object = ref->Value;
if (object == nullptr) return nullptr;
if (object->refCount & RC_DEALLOCATING_BIT) {
swift_weakRelease(object);
ref->Value = nullptr;
return nullptr;
}
return swift_tryRetain(object);
}
void swift::_swift_abortRetainUnowned(const void *object) { void swift::_swift_abortRetainUnowned(const void *object) {
fprintf(stderr, "attempting to retain deallocated object at %p", object); fprintf(stderr, "attempting to retain deallocated object at %p", object);
abort(); abort();

View File

@@ -0,0 +1,37 @@
// RUN: %swift -emit-silgen %s | FileCheck %s
class C {}
struct A {
var [weak] x : C
}
// CHECK: sil @_T4weak5test0FT1cCS_1C_T_ : $[thin] (c : C) -> () {
func test0(c : C) {
// CHECK: bb0(%0 : $C):
// CHECK: [[C:%.*]] = alloc_box $C
var a : A
// CHECK: [[A:%.*]] = alloc_box $A
var [weak] x = c
// CHECK: [[X:%.*]] = alloc_box $[weak] C
// CHECK-NEXT: [[T0:%.*]] = load [[C]]#1 : $*C
// CHECK-NEXT: retain [[T0]] : $C
// CHECK-NEXT: store_weak [[T0]] to [initialization] [[X]]#1 : $*[weak] C
// CHECK-NEXT: release [[T0]] : $C
a.x = c
// CHECK-NEXT: [[T0:%.*]] = load [[C]]#1 : $*C
// CHECK-NEXT: retain [[T0]] : $C
// CHECK-NEXT: [[T1:%.*]] = struct_element_addr [[A]]#1 : $*A, #x
// CHECK-NEXT: store_weak [[T0]] to [[T1]] : $*[weak] C
// CHECK-NEXT: release [[T0]] : $C
a.x = x
// CHECK-NEXT: [[T0:%.*]] = load_weak [[X]]#1 : $*[weak] C
// CHECK-NEXT: [[T1:%.*]] = struct_element_addr [[A]]#1 : $*A, #x
// CHECK-NEXT: store_weak [[T0]] to [[T1]] : $*[weak] C
// CHECK-NEXT: release [[T0]] : $C
}

View File

@@ -15,6 +15,8 @@ TESTNAME = runtime
include $(SWIFT_LEVEL)/../../Makefile.config include $(SWIFT_LEVEL)/../../Makefile.config
LINK_COMPONENTS := $(TARGETS_TO_BUILD) LINK_COMPONENTS := $(TARGETS_TO_BUILD)
SOURCES = $(notdir $(wildcard $(PROJ_SRC_DIR)/*.cpp $(PROJ_SRC_DIR)/*.mm))
# This is almost certainly not the right way of doing this. # This is almost certainly not the right way of doing this.
ProjLibsOptions += -lswift_stdlib_core ProjLibsOptions += -lswift_stdlib_core

287
unittests/runtime/weak.mm Normal file
View File

@@ -0,0 +1,287 @@
//===- swift/unittests/runtime/weak.mm - Weak-pointer tests ---------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
#include <Foundation/NSObject.h>
#include "swift/Runtime/Alloc.h"
#include "swift/Runtime/Metadata.h"
#include "gtest/gtest.h"
using namespace swift;
// Declare some Objective-C stuff.
extern "C" void objc_release(id);
static unsigned DestroyedObjCCount = 0;
/// A trivial class that increments DestroyedObjCCount when deallocated.
@interface ObjCClass : NSObject @end
@implementation ObjCClass
- (void) dealloc {
DestroyedObjCCount++;
[super dealloc];
}
@end
static HeapObject *make_objc_object() {
return (HeapObject*) [ObjCClass new];
}
// Make a Native Swift object by calling a constructor.
extern "C" HeapObject *_TCSs6ObjectCfMS_FT_S_(void *unused);
static HeapObject *make_swift_object() {
return _TCSs6ObjectCfMS_FT_S_(0);
}
static void unknown_release(void *value) {
objc_release((id) value);
}
TEST(WeakTest, preconditions) {
swift_release(make_swift_object());
unknown_release(make_objc_object());
}
TEST(WeakTest, simple_swift) {
HeapObject *o1 = make_swift_object();
HeapObject *o2 = make_swift_object();
ASSERT_NE(o1, o2);
ASSERT_NE(o1, nullptr);
ASSERT_NE(o2, nullptr);
WeakReference ref1;
swift_weakInit(&ref1, o1);
HeapObject *tmp = swift_weakLoadStrong(&ref1);
ASSERT_EQ(tmp, o1);
swift_release(tmp);
tmp = swift_weakLoadStrong(&ref1);
ASSERT_EQ(o1, tmp);
swift_release(tmp);
swift_weakAssign(&ref1, o2);
tmp = swift_weakLoadStrong(&ref1);
ASSERT_EQ(o2, tmp);
swift_release(tmp);
tmp = swift_weakLoadStrong(&ref1);
ASSERT_EQ(o2, tmp);
swift_release(tmp);
swift_release(o1);
tmp = swift_weakLoadStrong(&ref1);
ASSERT_EQ(o2, tmp);
swift_release(tmp);
swift_release(o2);
tmp = swift_weakLoadStrong(&ref1);
ASSERT_EQ(nullptr, tmp);
swift_release(tmp);
swift_weakDestroy(&ref1);
}
TEST(WeakTest, simple_objc) {
void *o1 = make_objc_object();
void *o2 = make_objc_object();
ASSERT_NE(o1, o2);
ASSERT_NE(o1, nullptr);
ASSERT_NE(o2, nullptr);
DestroyedObjCCount = 0;
WeakReference ref1;
swift_unknownWeakInit(&ref1, o1);
void *tmp = swift_unknownWeakLoadStrong(&ref1);
ASSERT_EQ(tmp, o1);
unknown_release(tmp);
tmp = swift_unknownWeakLoadStrong(&ref1);
ASSERT_EQ(o1, tmp);
unknown_release(tmp);
ASSERT_EQ(0U, DestroyedObjCCount);
swift_unknownWeakAssign(&ref1, o2);
tmp = swift_unknownWeakLoadStrong(&ref1);
ASSERT_EQ(o2, tmp);
unknown_release(tmp);
ASSERT_EQ(0U, DestroyedObjCCount);
tmp = swift_unknownWeakLoadStrong(&ref1);
ASSERT_EQ(o2, tmp);
unknown_release(tmp);
ASSERT_EQ(0U, DestroyedObjCCount);
unknown_release(o1);
ASSERT_EQ(1U, DestroyedObjCCount);
tmp = swift_unknownWeakLoadStrong(&ref1);
ASSERT_EQ(o2, tmp);
unknown_release(tmp);
ASSERT_EQ(1U, DestroyedObjCCount);
unknown_release(o2);
ASSERT_EQ(2U, DestroyedObjCCount);
tmp = swift_unknownWeakLoadStrong(&ref1);
ASSERT_EQ(nullptr, tmp);
unknown_release(tmp);
ASSERT_EQ(2U, DestroyedObjCCount);
swift_unknownWeakDestroy(&ref1);
}
TEST(WeakTest, simple_swift_as_unknown) {
void *o1 = make_swift_object();
void *o2 = make_swift_object();
ASSERT_NE(o1, o2);
ASSERT_NE(o1, nullptr);
ASSERT_NE(o2, nullptr);
WeakReference ref1;
swift_unknownWeakInit(&ref1, o1);
void *tmp = swift_unknownWeakLoadStrong(&ref1);
ASSERT_EQ(tmp, o1);
unknown_release(tmp);
tmp = swift_unknownWeakLoadStrong(&ref1);
ASSERT_EQ(o1, tmp);
unknown_release(tmp);
swift_unknownWeakAssign(&ref1, o2);
tmp = swift_unknownWeakLoadStrong(&ref1);
ASSERT_EQ(o2, tmp);
unknown_release(tmp);
tmp = swift_unknownWeakLoadStrong(&ref1);
ASSERT_EQ(o2, tmp);
unknown_release(tmp);
unknown_release(o1);
tmp = swift_unknownWeakLoadStrong(&ref1);
ASSERT_EQ(o2, tmp);
unknown_release(tmp);
unknown_release(o2);
tmp = swift_unknownWeakLoadStrong(&ref1);
ASSERT_EQ(nullptr, tmp);
unknown_release(tmp);
swift_unknownWeakDestroy(&ref1);
}
TEST(WeakTest, simple_swift_and_objc) {
void *o1 = make_swift_object();
void *o2 = make_objc_object();
ASSERT_NE(o1, o2);
ASSERT_NE(o1, nullptr);
ASSERT_NE(o2, nullptr);
DestroyedObjCCount = 0;
WeakReference ref1;
swift_unknownWeakInit(&ref1, o1);
void *tmp = swift_unknownWeakLoadStrong(&ref1);
ASSERT_EQ(tmp, o1);
unknown_release(tmp);
tmp = swift_unknownWeakLoadStrong(&ref1);
ASSERT_EQ(o1, tmp);
unknown_release(tmp);
ASSERT_EQ(0U, DestroyedObjCCount);
swift_unknownWeakAssign(&ref1, o2);
tmp = swift_unknownWeakLoadStrong(&ref1);
ASSERT_EQ(o2, tmp);
unknown_release(tmp);
ASSERT_EQ(0U, DestroyedObjCCount);
tmp = swift_unknownWeakLoadStrong(&ref1);
ASSERT_EQ(o2, tmp);
unknown_release(tmp);
ASSERT_EQ(0U, DestroyedObjCCount);
unknown_release(o1);
ASSERT_EQ(0U, DestroyedObjCCount);
tmp = swift_unknownWeakLoadStrong(&ref1);
ASSERT_EQ(o2, tmp);
unknown_release(tmp);
ASSERT_EQ(0U, DestroyedObjCCount);
unknown_release(o2);
ASSERT_EQ(1U, DestroyedObjCCount);
tmp = swift_unknownWeakLoadStrong(&ref1);
ASSERT_EQ(nullptr, tmp);
unknown_release(tmp);
ASSERT_EQ(1U, DestroyedObjCCount);
swift_unknownWeakDestroy(&ref1);
}
TEST(WeakTest, simple_objc_and_swift) {
void *o1 = make_objc_object();
void *o2 = make_swift_object();
ASSERT_NE(o1, o2);
ASSERT_NE(o1, nullptr);
ASSERT_NE(o2, nullptr);
DestroyedObjCCount = 0;
WeakReference ref1;
swift_unknownWeakInit(&ref1, o1);
void *tmp = swift_unknownWeakLoadStrong(&ref1);
ASSERT_EQ(tmp, o1);
unknown_release(tmp);
tmp = swift_unknownWeakLoadStrong(&ref1);
ASSERT_EQ(o1, tmp);
unknown_release(tmp);
ASSERT_EQ(0U, DestroyedObjCCount);
swift_unknownWeakAssign(&ref1, o2);
tmp = swift_unknownWeakLoadStrong(&ref1);
ASSERT_EQ(o2, tmp);
unknown_release(tmp);
ASSERT_EQ(0U, DestroyedObjCCount);
tmp = swift_unknownWeakLoadStrong(&ref1);
ASSERT_EQ(o2, tmp);
unknown_release(tmp);
ASSERT_EQ(0U, DestroyedObjCCount);
unknown_release(o1);
ASSERT_EQ(1U, DestroyedObjCCount);
tmp = swift_unknownWeakLoadStrong(&ref1);
ASSERT_EQ(o2, tmp);
unknown_release(tmp);
ASSERT_EQ(1U, DestroyedObjCCount);
unknown_release(o2);
ASSERT_EQ(1U, DestroyedObjCCount);
tmp = swift_unknownWeakLoadStrong(&ref1);
ASSERT_EQ(nullptr, tmp);
unknown_release(tmp);
ASSERT_EQ(1U, DestroyedObjCCount);
swift_unknownWeakDestroy(&ref1);
}