Skip to content

Commit 1fbb6d8

Browse files
committed
Fix assert in generated direct property getter/setters due to removal of _cmd parameter.
This fixes a bug from https://reviews.llvm.org/D131424 that removed the implicit `_cmd` parameter as an argument to `objc_direct` method implementations. In many cases the generated getter/setter will call `objc_getProperty` or `objc_setProperty`, both of which require the selector of the getter/setter; since `_cmd` didn't automatically have backing storage, attempting to load the address asserted. For direct property generated getters/setters, this now passes an undefined/uninitialized/poison value as the `_cmd` argument to `objc_getProperty`/`objc_setProperty`. Prior to removing the `_cmd` argument from the ABI of direct methods, it was left uninitialized/undefined; although references within hand-implemented methods would load the selector in the method prologue, generated getters/setters never did and just forwarded the undefined value that was passed as the argument. This change keeps the generated code mostly similar to before, passing an uninitialized/undefined/poison value; for setters, the value argument may be moved to another register. Added a test that triggers the assert prior to the implementation code. Differential Revision: https://reviews.llvm.org/D135091
1 parent 7b45dfc commit 1fbb6d8

File tree

2 files changed

+32
-4
lines changed

2 files changed

+32
-4
lines changed

clang/lib/CodeGen/CGObjC.cpp

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include "llvm/ADT/STLExtras.h"
2626
#include "llvm/Analysis/ObjCARCUtil.h"
2727
#include "llvm/BinaryFormat/MachO.h"
28+
#include "llvm/IR/Constants.h"
2829
#include "llvm/IR/DataLayout.h"
2930
#include "llvm/IR/InlineAsm.h"
3031
using namespace clang;
@@ -1111,6 +1112,25 @@ static void emitCPPObjectAtomicGetterCall(CodeGenFunction &CGF,
11111112
callee, ReturnValueSlot(), args);
11121113
}
11131114

1115+
// emitCmdValueForGetterSetterBody - Handle emitting the load necessary for
1116+
// the `_cmd` selector argument for getter/setter bodies. For direct methods,
1117+
// this returns an undefined/poison value; this matches behavior prior to `_cmd`
1118+
// being removed from the direct method ABI as the getter/setter caller would
1119+
// never load one. For non-direct methods, this emits a load of the implicit
1120+
// `_cmd` storage.
1121+
static llvm::Value *emitCmdValueForGetterSetterBody(CodeGenFunction &CGF,
1122+
ObjCMethodDecl *MD) {
1123+
if (MD->isDirectMethod()) {
1124+
// Direct methods do not have a `_cmd` argument. Emit an undefined/poison
1125+
// value. This will be passed to objc_getProperty/objc_setProperty, which
1126+
// has not appeared bothered by the `_cmd` argument being undefined before.
1127+
llvm::Type *selType = CGF.ConvertType(CGF.getContext().getObjCSelType());
1128+
return llvm::PoisonValue::get(selType);
1129+
}
1130+
1131+
return CGF.Builder.CreateLoad(CGF.GetAddrOfLocalVar(MD->getCmdDecl()), "cmd");
1132+
}
1133+
11141134
void
11151135
CodeGenFunction::generateObjCGetterBody(const ObjCImplementationDecl *classImpl,
11161136
const ObjCPropertyImplDecl *propImpl,
@@ -1189,8 +1209,7 @@ CodeGenFunction::generateObjCGetterBody(const ObjCImplementationDecl *classImpl,
11891209
// Return (ivar-type) objc_getProperty((id) self, _cmd, offset, true).
11901210
// FIXME: Can't this be simpler? This might even be worse than the
11911211
// corresponding gcc code.
1192-
llvm::Value *cmd =
1193-
Builder.CreateLoad(GetAddrOfLocalVar(getterMethod->getCmdDecl()), "cmd");
1212+
llvm::Value *cmd = emitCmdValueForGetterSetterBody(*this, getterMethod);
11941213
llvm::Value *self = Builder.CreateBitCast(LoadObjCSelf(), VoidPtrTy);
11951214
llvm::Value *ivarOffset =
11961215
EmitIvarOffset(classImpl->getClassInterface(), ivar);
@@ -1475,8 +1494,7 @@ CodeGenFunction::generateObjCSetterBody(const ObjCImplementationDecl *classImpl,
14751494

14761495
// Emit objc_setProperty((id) self, _cmd, offset, arg,
14771496
// <is-atomic>, <is-copy>).
1478-
llvm::Value *cmd =
1479-
Builder.CreateLoad(GetAddrOfLocalVar(setterMethod->getCmdDecl()));
1497+
llvm::Value *cmd = emitCmdValueForGetterSetterBody(*this, setterMethod);
14801498
llvm::Value *self =
14811499
Builder.CreateBitCast(LoadObjCSelf(), VoidPtrTy);
14821500
llvm::Value *ivarOffset =

clang/test/CodeGenObjC/direct-method.m

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ @interface Root
1414
- (int)getInt __attribute__((objc_direct));
1515
@property(direct, readonly) int intProperty;
1616
@property(direct, readonly) int intProperty2;
17+
@property(direct, readonly) id objectProperty;
1718
@end
1819

1920
@implementation Root
@@ -167,6 +168,15 @@ - (void)accessCmd __attribute__((objc_direct)) {
167168
@end
168169
// CHECK-LABEL: define hidden i32 @"\01-[Root intProperty]"
169170

171+
// Check the synthesized objectProperty calls objc_getProperty(); this also
172+
// checks that the synthesized method passes undef for the `cmd` argument.
173+
// CHECK-LABEL: define hidden i8* @"\01-[Root objectProperty]"(
174+
// CHECK-LABEL: objc_direct_method.cont:
175+
// CHECK-NEXT: [[SELFVAL:%.*]] = load {{.*}} %self.addr,
176+
// CHECK-NEXT: [[SELF:%.*]] = bitcast {{.*}} [[SELFVAL]] to i8*
177+
// CHECK-NEXT: [[IVAR:%.*]] = load {{.*}} @"OBJC_IVAR_$_Root._objectProperty",
178+
// CHECK-NEXT: call i8* @objc_getProperty(i8* noundef [[SELF]], i8* noundef poison, i64 noundef [[IVAR]], {{.*}})
179+
170180
@interface Foo : Root {
171181
id __strong _cause_cxx_destruct;
172182
}

0 commit comments

Comments
 (0)