mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Implement basic support for [weak].
Swift SVN r7041
This commit is contained in:
@@ -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,
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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),
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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())
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
37
test/SIL/SILGen/weak.swift
Normal file
37
test/SIL/SILGen/weak.swift
Normal 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
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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
287
unittests/runtime/weak.mm
Normal 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);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user