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)", ())
ERROR(sil_invalid_instr_operands,decl_parsing,none,
"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,
"integer_literal instruction requires a 'Builtin.Int<n>' type", ())
ERROR(sil_float_literal_not_float_type,decl_parsing,none,

View File

@@ -268,7 +268,29 @@ struct WeakReference {
/// Initialize a weak reference.
///
/// \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.
///
@@ -299,11 +321,6 @@ extern "C" void swift_weakCopyAssign(WeakReference *dest, WeakReference *src);
/// \param src - never null, but can refer to a null object
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
/// 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.
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
/// Swift object.
extern "C" void swift_unknownWeakDestroy(WeakReference *object);

View File

@@ -222,6 +222,15 @@ public:
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,
SILValue DestLValue,
bool canDefaultConstruct) {

View File

@@ -53,6 +53,9 @@ enum class SILInstructionMemoryBehavior {
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
/// of a Swift SILBasicBlock.
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.
class InitializeVarInst
: public UnaryInstructionBase<ValueKind::InitializeVarInst,
@@ -566,9 +616,6 @@ public:
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
/// is similar to:
/// %1 = load %src

View File

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

View File

@@ -606,34 +606,60 @@ namespace {
class SwiftWeakReferenceTypeInfo
: public IndirectTypeInfo<SwiftWeakReferenceTypeInfo,
WeakTypeInfo> {
llvm::Type *ValueType;
public:
SwiftWeakReferenceTypeInfo(llvm::Type *type,
SwiftWeakReferenceTypeInfo(llvm::Type *valueType,
llvm::Type *weakType,
Size size, Alignment alignment)
: IndirectTypeInfo(type, size, alignment) {}
: IndirectTypeInfo(weakType, size, alignment), ValueType(valueType) {}
void initializeWithCopy(IRGenFunction &IGF, Address destAddr,
Address srcAddr) const {
Address srcAddr) const override {
IGF.emitWeakCopyInit(destAddr, srcAddr);
}
void initializeWithTake(IRGenFunction &IGF, Address destAddr,
Address srcAddr) const {
Address srcAddr) const override {
IGF.emitWeakTakeInit(destAddr, srcAddr);
}
void assignWithCopy(IRGenFunction &IGF, Address destAddr,
Address srcAddr) const {
Address srcAddr) const override {
IGF.emitWeakCopyAssign(destAddr, srcAddr);
}
void assignWithTake(IRGenFunction &IGF, Address destAddr,
Address srcAddr) const {
Address srcAddr) const override {
IGF.emitWeakTakeAssign(destAddr, srcAddr);
}
void destroy(IRGenFunction &IGF, Address addr) const {
void destroy(IRGenFunction &IGF, Address addr) const override {
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 *
TypeConverter::createSwiftWeakStorageType(llvm::Type *valueType) {
return new SwiftWeakReferenceTypeInfo(IGM.WeakReferencePtrTy,
return new SwiftWeakReferenceTypeInfo(valueType,
IGM.WeakReferencePtrTy->getElementType(),
IGM.getWeakReferenceSize(),
IGM.getWeakReferenceAlignment());
}
@@ -678,10 +705,14 @@ namespace {
class UnknownWeakReferenceTypeInfo :
public IndirectTypeInfo<UnknownWeakReferenceTypeInfo,
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:
UnknownWeakReferenceTypeInfo(llvm::Type *type,
UnknownWeakReferenceTypeInfo(llvm::Type *valueType,
llvm::Type *weakType,
Size size, Alignment alignment)
: IndirectTypeInfo(type, size, alignment) {}
: IndirectTypeInfo(weakType, size, alignment), ValueType(valueType) {}
void initializeWithCopy(IRGenFunction &IGF, Address destAddr,
Address srcAddr) const {
@@ -706,6 +737,30 @@ namespace {
void destroy(IRGenFunction &IGF, Address addr) const {
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 *
TypeConverter::createUnknownWeakStorageType(llvm::Type *valueType) {
return new UnknownWeakReferenceTypeInfo(IGM.WeakReferencePtrTy,
return new UnknownWeakReferenceTypeInfo(valueType,
IGM.WeakReferencePtrTy->getElementType(),
IGM.getWeakReferenceSize(),
IGM.getWeakReferenceAlignment());
}
@@ -729,17 +785,19 @@ static bool doesNotRequireRefCounting(llvm::Value *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.
///
/// \param fn - expected signature 'void (T*)'
/// \param fn - expected signature 'void (T)'
static void emitUnaryRefCountCall(IRGenFunction &IGF,
llvm::Constant *fn,
llvm::Value *value) {
auto fnTy = cast<llvm::FunctionType>(fn->getType()->getPointerElementType());
// Instead of casting the input to %swift.refcounted*, we cast the
// function type. This tends to produce less IR, but might be evil.
if (value->getType() != fnTy->getParamType(0)) {
// Instead of casting the input, we cast the function type.
// This tends to produce less IR, but might be evil.
if (value->getType() != getTypeOfFunction(fn)->getParamType(0)) {
llvm::FunctionType *fnType =
llvm::FunctionType::get(IGF.IGM.VoidTy, value->getType(), false);
fn = llvm::ConstantExpr::getBitCast(fn, fnType->getPointerTo());
@@ -751,20 +809,19 @@ static void emitUnaryRefCountCall(IRGenFunction &IGF,
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*)'
static void emitBinaryRefCountCall(IRGenFunction &IGF,
llvm::Constant *fn,
llvm::Value *dest,
llvm::Value *src) {
/// \param fn - expected signature 'void (T, T)'
static void emitCopyLikeCall(IRGenFunction &IGF,
llvm::Constant *fn,
llvm::Value *dest,
llvm::Value *src) {
assert(dest->getType() == src->getType() &&
"type mismatch in binary refcounting operation");
// Instead of casting the input to %swift.refcounted*, we cast the
// function type. This tends to produce less IR, but might be evil.
if (dest->getType() !=
cast<llvm::FunctionType>(fn->getType())->getParamType(0)) {
// Instead of casting the inputs, we cast the function type.
// This tends to produce less IR, but might be evil.
if (dest->getType() != getTypeOfFunction(fn)->getParamType(0)) {
llvm::Type *paramTypes[] = { dest->getType(), dest->getType() };
llvm::FunctionType *fnType =
llvm::FunctionType::get(IGF.IGM.VoidTy, paramTypes, false);
@@ -777,6 +834,58 @@ static void emitBinaryRefCountCall(IRGenFunction &IGF,
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
/// this routine; instead you should use emitRetain, which properly
/// balances the retain.
@@ -856,34 +965,52 @@ void IRGenFunction::emitUnknownRelease(llvm::Value *value) {
return emitObjCRelease(value);
}
#define REFCOUNT_VALUE(ID) \
#define DEFINE_VALUE_OP(ID) \
void IRGenFunction::emit##ID(llvm::Value *value) { \
if (doesNotRequireRefCounting(value)) return; \
emitUnaryRefCountCall(*this, IGM.get##ID##Fn(), value); \
}
#define REFCOUNT_ADDR(ID) \
#define DEFINE_ADDR_OP(ID) \
void IRGenFunction::emit##ID(Address addr) { \
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) { \
emitBinaryRefCountCall(*this, IGM.get##ID##Fn(), dest.getAddress(), \
src.getAddress()); \
emitCopyLikeCall(*this, IGM.get##ID##Fn(), dest.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)
REFCOUNT_VALUE(UnownedRelease)
REFCOUNT_VALUE(UnownedRetain)
REFCOUNT_ADDR(WeakDestroy)
REFCOUNT_ADDR_ADDR(WeakCopyInit)
REFCOUNT_ADDR_ADDR(WeakCopyAssign)
REFCOUNT_ADDR_ADDR(WeakTakeInit)
REFCOUNT_ADDR_ADDR(WeakTakeAssign)
REFCOUNT_VALUE(UnknownRetainUnowned)
REFCOUNT_VALUE(UnknownUnownedRelease)
REFCOUNT_VALUE(UnknownUnownedRetain)
REFCOUNT_ADDR(UnknownWeakDestroy)
REFCOUNT_ADDR_ADDR(UnknownWeakCopyInit)
REFCOUNT_ADDR_ADDR(UnknownWeakCopyAssign)
REFCOUNT_ADDR_ADDR(UnknownWeakTakeInit)
REFCOUNT_ADDR_ADDR(UnknownWeakTakeAssign)
DEFINE_VALUE_OP(RetainUnowned)
DEFINE_VALUE_OP(UnownedRelease)
DEFINE_VALUE_OP(UnownedRetain)
DEFINE_LOAD_WEAK_OP(WeakLoadStrong)
DEFINE_LOAD_WEAK_OP(WeakTakeStrong)
DEFINE_STORE_WEAK_OP(WeakInit)
DEFINE_STORE_WEAK_OP(WeakAssign)
DEFINE_ADDR_OP(WeakDestroy)
DEFINE_COPY_OP(WeakCopyInit)
DEFINE_COPY_OP(WeakCopyAssign)
DEFINE_COPY_OP(WeakTakeInit)
DEFINE_COPY_OP(WeakTakeAssign)
DEFINE_VALUE_OP(UnknownRetainUnowned)
DEFINE_VALUE_OP(UnknownUnownedRelease)
DEFINE_VALUE_OP(UnknownUnownedRetain)
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());
}
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 {
return IGF.Builder.CreateStructGEP(existential, NumProtocols,
NumProtocols * IGF.IGM.getPointerSize(),
@@ -602,6 +620,43 @@ namespace {
Address valueAddr = projectValue(IGF, existential);
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

View File

@@ -169,7 +169,10 @@ public:
void emitRetainUnowned(llvm::Value *value);
void emitUnownedRetain(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 emitWeakCopyInit(Address destAddr, Address srcAddr);
void emitWeakTakeInit(Address destAddr, Address srcAddr);
@@ -194,6 +197,10 @@ public:
void emitUnknownWeakTakeInit(Address destAddr, Address srcAddr);
void emitUnknownWeakCopyAssign(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 ------------------------------------------------------
public:

View File

@@ -49,6 +49,7 @@
#include "IRGenModule.h"
#include "Linking.h"
#include "ReferenceTypeInfo.h"
#include "WeakTypeInfo.h"
using namespace swift;
using namespace irgen;
@@ -508,6 +509,8 @@ public:
void visitLoadInst(LoadInst *i);
void visitStoreInst(StoreInst *i);
void visitLoadWeakInst(LoadWeakInst *i);
void visitStoreWeakInst(StoreWeakInst *i);
void visitStructInst(StructInst *i);
void visitTupleInst(TupleInst *i);
void visitBuiltinZeroInst(BuiltinZeroInst *i);
@@ -1674,6 +1677,33 @@ void IRGenSILFunction::visitStoreInst(swift::StoreInst *i) {
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) {
// FIXME: Specialization thunks may eventually require retaining. For now,
// since we don't yet thunk specialized function values, ignore retains

View File

@@ -116,31 +116,55 @@ FUNCTION(UnownedRelease, swift_weakRelease,RuntimeCC,
ARGS(RefCountedPtrTy),
ATTRS(NoUnwind))
// void swift_weakDestroy(void **object);
// void swift_weakDestroy(WeakReference *object);
FUNCTION(WeakDestroy, swift_weakDestroy, RuntimeCC,
RETURNS(VoidTy),
ARGS(WeakReferencePtrTy),
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,
RETURNS(VoidTy),
ARGS(WeakReferencePtrTy, WeakReferencePtrTy),
ATTRS(NoUnwind))
// void swift_weakTakeInit(void **dest, void **src);
// void swift_weakTakeInit(WeakReference *dest, WeakReference *src);
FUNCTION(WeakTakeInit, swift_weakTakeInit, RuntimeCC,
RETURNS(VoidTy),
ARGS(WeakReferencePtrTy, WeakReferencePtrTy),
ATTRS(NoUnwind))
// void swift_weakCopyAssign(void **dest, void **src);
// void swift_weakCopyAssign(WeakReference *dest, WeakReference *src);
FUNCTION(WeakCopyAssign, swift_weakCopyAssign,RuntimeCC,
RETURNS(VoidTy),
ARGS(WeakReferencePtrTy, WeakReferencePtrTy),
ATTRS(NoUnwind))
// void swift_weakTakeAssign(void **dest, void **src);
// void swift_weakTakeAssign(WeakReference *dest, WeakReference *src);
FUNCTION(WeakTakeAssign, swift_weakTakeAssign,RuntimeCC,
RETURNS(VoidTy),
ARGS(WeakReferencePtrTy, WeakReferencePtrTy),
@@ -164,31 +188,55 @@ FUNCTION(UnknownUnownedRelease, swift_unknownWeakRelease, RuntimeCC,
ARGS(RefCountedPtrTy),
ATTRS(NoUnwind))
// void swift_unknownWeakDestroy(void **object);
// void swift_unknownWeakDestroy(WeakReference *object);
FUNCTION(UnknownWeakDestroy, swift_unknownWeakDestroy, RuntimeCC,
RETURNS(VoidTy),
ARGS(WeakReferencePtrTy),
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,
RETURNS(VoidTy),
ARGS(WeakReferencePtrTy, WeakReferencePtrTy),
ATTRS(NoUnwind))
// void swift_unknownWeakTakeInit(void **dest, void **src);
// void swift_unknownWeakTakeInit(WeakReference *dest, WeakReference *src);
FUNCTION(UnknownWeakTakeInit, swift_unknownWeakTakeInit, RuntimeCC,
RETURNS(VoidTy),
ARGS(WeakReferencePtrTy, WeakReferencePtrTy),
ATTRS(NoUnwind))
// void swift_unknownWeakCopyAssign(void **dest, void **src);
// void swift_unknownWeakCopyAssign(WeakReference *dest, WeakReference *src);
FUNCTION(UnknownWeakCopyAssign, swift_unknownWeakCopyAssign,RuntimeCC,
RETURNS(VoidTy),
ARGS(WeakReferencePtrTy, WeakReferencePtrTy),
ATTRS(NoUnwind))
// void swift_unknownWeakTakeAssign(void **dest, void **src);
// void swift_unknownWeakTakeAssign(WeakReference *dest, WeakReference *src);
FUNCTION(UnknownWeakTakeAssign, swift_unknownWeakTakeAssign,RuntimeCC,
RETURNS(VoidTy),
ARGS(WeakReferencePtrTy, WeakReferencePtrTy),

View File

@@ -31,6 +31,15 @@ protected:
: FixedTypeInfo(type, size, align, IsNotPOD, STIK_Weak) {}
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 TypeInfo *type) {
return type->getSpecialTypeInfoKind() == STIK_Weak;

View File

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

View File

@@ -357,7 +357,7 @@ ManagedValue SILGenFunction::emitLoad(SILLocation loc,
IsTake_t isTake) {
auto &addrTL = getTypeLowering(addr.getType());
auto &semanticTL = addrTL.getSemanticTypeLowering(SGM.Types);
if (addrTL.isAddressOnly()) {
if (semanticTL.isAddressOnly()) {
// Copy the address-only value.
SILValue copy = getBufferForExprResult(loc, semanticTL.getLoweredType(), C);
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) {
}
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,
IsTake_t isTakeOfSrc,

View File

@@ -440,6 +440,15 @@ public:
OS << "store " << getID(SI->getSrc()) << " to "
<< 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) {
OS << "copy_addr ";
if (CI->isTakeOfSrc())

View File

@@ -470,6 +470,19 @@ bool SILType::isAddressOnly(CanType type, SILModule &M) {
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 {
/// A class for loadable types.
class LoadableTypeLowering : public TypeLowering {
@@ -684,13 +697,7 @@ namespace {
void emitSemanticStore(SILBuilder &B, SILLocation loc,
SILValue value, SILValue addr,
IsInitialization_t isInit) const override {
// 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);
emitReferenceSemanticStore(B, loc, value, addr, isInit);
}
SILValue emitSemanticLoad(SILBuilder &B, SILLocation loc,
@@ -788,20 +795,24 @@ namespace {
void emitSemanticStore(SILBuilder &B, SILLocation loc,
SILValue value, SILValue addr,
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 addr, IsTake_t isTake) const override {
// FIXME
return SILValue();
return B.createLoadWeak(loc, addr, isTake);
}
void emitSemanticLoadInto(SILBuilder &B, SILLocation loc,
SILValue src, SILValue dest,
IsTake_t isTake,
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;
}
void swift::swift_weakInit(WeakReference *ref) {
ref->Value = nullptr;
void swift::swift_weakInit(WeakReference *ref, HeapObject *value) {
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) {
@@ -488,17 +513,6 @@ void swift::swift_weakTakeAssign(WeakReference *dest, WeakReference *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) {
fprintf(stderr, "attempting to retain deallocated object at %p", object);
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
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.
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);
}