diff --git a/lib/IRGen/GenHeap.cpp b/lib/IRGen/GenHeap.cpp index 85e789f049a42..d6bece1fcb845 100644 --- a/lib/IRGen/GenHeap.cpp +++ b/lib/IRGen/GenHeap.cpp @@ -81,6 +81,34 @@ HeapLayout::HeapLayout(IRGenModule &IGM, LayoutStrategy strategy, #endif } +static llvm::Value *calcInitOffset(swift::irgen::IRGenFunction &IGF, + unsigned int i, + const swift::irgen::HeapLayout &layout) { + llvm::Value *offset = nullptr; + if (i == 0) { + auto startoffset = layout.getSize(); + offset = llvm::ConstantInt::get(IGF.IGM.SizeTy, startoffset.getValue()); + return offset; + } + auto &prevElt = layout.getElement(i - 1); + auto prevType = layout.getElementTypes()[i - 1]; + // Start calculating offsets from the last fixed-offset field. + Size lastFixedOffset = layout.getElement(i - 1).getByteOffset(); + if (auto *fixedType = dyn_cast(&prevElt.getTypeForLayout())) { + // If the last fixed-offset field is also fixed-size, we can + // statically compute the end of the fixed-offset fields. + auto fixedEnd = lastFixedOffset + fixedType->getFixedSize(); + offset = llvm::ConstantInt::get(IGF.IGM.SizeTy, fixedEnd.getValue()); + } else { + // Otherwise, we need to add the dynamic size to the fixed start + // offset. + offset = llvm::ConstantInt::get(IGF.IGM.SizeTy, lastFixedOffset.getValue()); + offset = IGF.Builder.CreateAdd( + offset, prevElt.getTypeForLayout().getSize(IGF, prevType)); + } + return offset; +} + HeapNonFixedOffsets::HeapNonFixedOffsets(IRGenFunction &IGF, const HeapLayout &layout) { if (!layout.isFixedLayout()) { @@ -107,34 +135,8 @@ HeapNonFixedOffsets::HeapNonFixedOffsets(IRGenFunction &IGF, case ElementLayout::Kind::NonFixed: // Start calculating non-fixed offsets from the end of the first fixed // field. - if (i == 0) { - totalAlign = elt.getTypeForLayout().getAlignmentMask(IGF, eltTy); - offset = totalAlign; - Offsets.push_back(totalAlign); - break; - } - - assert(i > 0 && "shouldn't begin with a non-fixed field"); - auto &prevElt = layout.getElement(i-1); - auto prevType = layout.getElementTypes()[i-1]; - // Start calculating offsets from the last fixed-offset field. if (!offset) { - Size lastFixedOffset = layout.getElement(i-1).getByteOffset(); - if (auto *fixedType = dyn_cast(&prevElt.getTypeForLayout())) { - // If the last fixed-offset field is also fixed-size, we can - // statically compute the end of the fixed-offset fields. - auto fixedEnd = lastFixedOffset + fixedType->getFixedSize(); - offset - = llvm::ConstantInt::get(IGF.IGM.SizeTy, fixedEnd.getValue()); - } else { - // Otherwise, we need to add the dynamic size to the fixed start - // offset. - offset - = llvm::ConstantInt::get(IGF.IGM.SizeTy, - lastFixedOffset.getValue()); - offset = IGF.Builder.CreateAdd(offset, - prevElt.getTypeForLayout().getSize(IGF, prevType)); - } + offset = calcInitOffset(IGF, i, layout); } // Round up to alignment to get the offset. diff --git a/test/IRGen/struct_with_resilient_type.swift b/test/IRGen/struct_with_resilient_type.swift new file mode 100644 index 0000000000000..e426537dceb83 --- /dev/null +++ b/test/IRGen/struct_with_resilient_type.swift @@ -0,0 +1,46 @@ +// RUN: %empty-directory(%t) +// RUN: %target-swift-frontend -emit-module -enable-resilience -emit-module-path=%t/resilient_struct.swiftmodule -module-name=resilient_struct %S/../Inputs/resilient_struct.swift +// RUN: %target-swift-frontend -I %t -emit-ir %s | %FileCheck %s + +// REQUIRES: CPU=x86_64 + +import resilient_struct + +struct StructWithFunc { + func foo(ptr: @escaping () -> Void) { + } +} + +struct ProtAndResilStruct { + let foundationType: ResilientBool + + let fooImp: StructWithFunc + + init(fType: ResilientBool, fooImp: StructWithFunc) { + self.foundationType = fType + self.fooImp = fooImp + } + + func bar() { + } + + func crash() { + fooImp.foo(ptr: bar) + } +// CHECK-LABEL: define{{.*}} @"$S26struct_with_resilient_type18ProtAndResilStructV3baryyFTc"(%T26struct_with_resilient_type18ProtAndResilStructV* noalias nocapture) +// CHECK: %flags.alignmentMask = and i64 %flags, 65535 +// CHECK: [[XOR_ALIGN:%.*]] = xor i64 %flags.alignmentMask, -1 +// CHECK: [[INIT_OFFSET:%.*]] = add i64 16, %flags.alignmentMask +// CHECK: [[T0:%.*]] = and i64 [[INIT_OFFSET]], [[XOR_ALIGN]] +// CHECK: [[T1:%.*]] = add i64 [[T0]], %size +// CHECK: [[ALIGN:%.*]] = or i64 7, %flags.alignmentMask +} + +func crashCaller() { + let fType = ResilientBool(b: false) + let fooImp = StructWithFunc() + let badStruct = ProtAndResilStruct(fType: fType, fooImp: fooImp) + badStruct.crash() +} + +crashCaller()