Skip to content

Commit 5289bf3

Browse files
authored
Merge pull request #10403 from aschwaighofer/swift-4.0-branch-irgen-empty-box-types
[4.0] IRGen: EmptyBoxType's representation cannot be nil because of a conflict with extra inhabitant assumption in indirect enums
2 parents f30c3bd + 7096092 commit 5289bf3

File tree

11 files changed

+108
-5
lines changed

11 files changed

+108
-5
lines changed

docs/Runtime.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ Rename with a non-`stdlib` naming scheme.
7171

7272
```
7373
000000000001cb30 T _swift_allocBox
74+
000000000001cb30 T _swift_allocEmptyBox
7475
000000000001c990 T _swift_allocObject
7576
000000000001ca60 T _swift_bufferAllocate
7677
000000000001ca90 T _swift_bufferHeaderSize

include/swift/Runtime/HeapObject.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,10 @@ SWIFT_RUNTIME_EXPORT
169169
BoxPair::Return swift_makeBoxUnique(OpaqueValue *buffer, Metadata const *type,
170170
size_t alignMask);
171171

172+
/// Returns the address of a heap object representing all empty box types.
173+
SWIFT_RUNTIME_EXPORT
174+
HeapObject* swift_allocEmptyBox();
175+
172176
// Allocate plain old memory. This is the generalized entry point
173177
// Never returns nil. The returned memory is uninitialized.
174178
//

include/swift/Runtime/Metadata.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1840,6 +1840,9 @@ struct TargetHeapLocalVariableMetadata
18401840
static bool classof(const TargetMetadata<Runtime> *metadata) {
18411841
return metadata->getKind() == MetadataKind::HeapLocalVariable;
18421842
}
1843+
constexpr TargetHeapLocalVariableMetadata()
1844+
: TargetHeapMetadata<Runtime>(MetadataKind::HeapLocalVariable),
1845+
OffsetToFirstCapture(0), CaptureDescription(nullptr) {}
18431846
};
18441847
using HeapLocalVariableMetadata
18451848
= TargetHeapLocalVariableMetadata<InProcess>;

include/swift/Runtime/RuntimeFunctions.def

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,11 @@ FUNCTION(ProjectBox, swift_projectBox, DefaultCC,
7373
ARGS(RefCountedPtrTy),
7474
ATTRS(NoUnwind, ReadNone))
7575

76+
FUNCTION(AllocEmptyBox, swift_allocEmptyBox, DefaultCC,
77+
RETURNS(RefCountedPtrTy),
78+
ARGS(),
79+
ATTRS(NoUnwind))
80+
7681
// RefCounted *swift_allocObject(Metadata *type, size_t size, size_t alignMask);
7782
FUNCTION_WITH_GLOBAL_SYMBOL_AND_IMPL(AllocObject, swift_allocObject,
7883
_swift_allocObject, _swift_allocObject_, RegisterPreservingCC,

lib/IRGen/GenHeap.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1430,7 +1430,7 @@ class EmptyBoxTypeInfo final : public BoxTypeInfo {
14301430
allocate(IRGenFunction &IGF, SILType boxedType, GenericEnvironment *env,
14311431
const llvm::Twine &name) const override {
14321432
return OwnedAddress(IGF.getTypeInfo(boxedType).getUndefAddress(),
1433-
IGF.IGM.RefCountedNull);
1433+
IGF.emitAllocEmptyBoxCall());
14341434
}
14351435

14361436
void
@@ -1584,7 +1584,11 @@ const TypeInfo *TypeConverter::convertBoxType(SILBoxType *T) {
15841584
// For fixed-sized types, we can emit concrete box metadata.
15851585
auto &fixedTI = cast<FixedTypeInfo>(eltTI);
15861586

1587-
// For empty types, we don't really need to allocate anything.
1587+
// Because we assume in enum's that payloads with a Builtin.NativeObject which
1588+
// is also the type for indirect enum cases have extra inhabitants of pointers
1589+
// we can't have a nil pointer as a representation for an empty box type --
1590+
// nil conflicts with the extra inhabitants. We return a static singleton
1591+
// empty box object instead.
15881592
if (fixedTI.isKnownEmpty(ResilienceExpansion::Maximal)) {
15891593
if (!EmptyBoxTI)
15901594
EmptyBoxTI = new EmptyBoxTypeInfo(IGM);

lib/IRGen/IRGenFunction.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,20 @@ llvm::Value *IRGenFunction::emitProjectBoxCall(llvm::Value *box,
209209
return call;
210210
}
211211

212+
llvm::Value *IRGenFunction::emitAllocEmptyBoxCall() {
213+
llvm::Attribute::AttrKind attrKinds[] = {
214+
llvm::Attribute::NoUnwind,
215+
};
216+
auto attrs = llvm::AttributeSet::get(IGM.LLVMContext,
217+
llvm::AttributeSet::FunctionIndex,
218+
attrKinds);
219+
llvm::CallInst *call =
220+
Builder.CreateCall(IGM.getAllocEmptyBoxFn(), {});
221+
call->setCallingConv(IGM.DefaultCC);
222+
call->setAttributes(attrs);
223+
return call;
224+
}
225+
212226
static void emitDeallocatingCall(IRGenFunction &IGF, llvm::Constant *fn,
213227
std::initializer_list<llvm::Value *> args) {
214228
auto cc = IGF.IGM.DefaultCC;

lib/IRGen/IRGenFunction.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,8 @@ class IRGenFunction {
188188

189189
llvm::Value *emitProjectBoxCall(llvm::Value *box, llvm::Value *typeMetadata);
190190

191+
llvm::Value *emitAllocEmptyBoxCall();
192+
191193
// Emit a reference to the canonical type metadata record for the given AST
192194
// type. This can be used to identify the type at runtime. For types with
193195
// abstraction difference, the metadata contains the layout information for

stdlib/public/runtime/HeapObject.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include <cstdio>
3232
#include <cstdlib>
3333
#include <thread>
34+
#include "../SwiftShims/GlobalObjects.h"
3435
#include "../SwiftShims/RuntimeShims.h"
3536
#if SWIFT_OBJC_INTEROP
3637
# include <objc/NSObject.h>
@@ -227,6 +228,30 @@ OpaqueValue *swift::swift_projectBox(HeapObject *o) {
227228
return metadata->project(o);
228229
}
229230

231+
namespace { // Begin anonymous namespace.
232+
233+
struct _SwiftEmptyBoxStorage {
234+
HeapObject header;
235+
};
236+
237+
swift::HeapLocalVariableMetadata _emptyBoxStorageMetadata;
238+
239+
/// The singleton empty box storage object.
240+
_SwiftEmptyBoxStorage _EmptyBoxStorage = {
241+
// HeapObject header;
242+
{
243+
&_emptyBoxStorageMetadata,
244+
}
245+
};
246+
247+
} // End anonymous namespace.
248+
249+
HeapObject *swift::swift_allocEmptyBox() {
250+
auto heapObject = reinterpret_cast<HeapObject*>(&_EmptyBoxStorage);
251+
SWIFT_RT_ENTRY_CALL(swift_retain)(heapObject);
252+
return heapObject;
253+
}
254+
230255
// Forward-declare this, but define it after swift_release.
231256
extern "C" LLVM_LIBRARY_VISIBILITY LLVM_ATTRIBUTE_NOINLINE LLVM_ATTRIBUTE_USED
232257
void _swift_release_dealloc(HeapObject *object) SWIFT_CC(RegisterPreservingCC_IMPL);

test/IRGen/access_markers.sil

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,8 +114,7 @@ sil @testPairedBox : $(@guaranteed { var () }) -> () {
114114
bb0(%0 : ${ var () }):
115115
// CHECK: entry:
116116
%2 = project_box %0 : ${ var () }, 0
117-
118-
// CHECK-NEXT: call {{.*}}void @writeEmptyTuple(%swift.opaque* nocapture undef)
117+
// CHECK-NEXT: call {{.*}}void @writeEmptyTuple(%swift.opaque* nocapture undef)
119118
%3 = begin_access [modify] [dynamic] %2 : $*()
120119
%write_fn = function_ref @writeEmptyTuple : $@convention(thin) (@inout ()) -> ()
121120
apply %write_fn(%3) : $@convention(thin) (@inout ()) -> ()

test/IRGen/partial_apply.sil

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -365,7 +365,8 @@ sil public_external @partial_empty_box : $@convention(thin) (@owned <τ_0_0> { v
365365
// CHECK-LABEL: define{{( protected)?}} swiftcc void @empty_box()
366366
sil @empty_box : $@convention(thin) () -> () {
367367
entry:
368-
// CHECK: store %swift.refcounted* null
368+
// CHECK: [[BOX:%.*]] = call {{.*}}swift_allocEmptyBox
369+
// CHECK: store %swift.refcounted* [[BOX]]
369370
// CHECK: store %swift.opaque* undef
370371
%b = alloc_box $<τ_0_0> { var τ_0_0 } <()>
371372
%ba = project_box %b : $<τ_0_0> { var τ_0_0 } <()>, 0

test/Interpreter/enum.swift

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -553,5 +553,50 @@ presentEitherOr(EitherOr<(), String>.Right("foo")) // CHECK-NEXT: Right(foo)
553553
// CHECK-NEXT: Right(foo)
554554
presentEitherOrsOf(t: (), u: "foo")
555555

556+
// SR-5148
557+
enum Payload {
558+
case email
559+
}
560+
enum Test {
561+
case a
562+
indirect case b(Payload)
563+
}
564+
565+
@inline(never)
566+
func printA() {
567+
print("an a")
568+
}
569+
570+
@inline(never)
571+
func printB() {
572+
print("an b")
573+
}
574+
575+
@inline(never)
576+
func testCase(_ testEmail: Test) {
577+
switch testEmail {
578+
case .a:
579+
printA()
580+
case .b:
581+
printB()
582+
}
583+
}
584+
585+
@inline(never)
586+
func createTestB() -> Test {
587+
return Test.b(.email)
588+
}
589+
590+
@inline(never)
591+
func createTestA() -> Test {
592+
return Test.a
593+
}
594+
595+
// CHECK-NEXT: an b
596+
testCase(createTestB())
597+
// CHECK-NEXT: b(a.Payload.email)
598+
print(createTestB())
599+
// CHECK-NEXT: a
600+
print(createTestA())
556601
// CHECK-NEXT: done
557602
print("done")

0 commit comments

Comments
 (0)