1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
|
//===----- CGObjCRuntime.h - Interface to ObjC Runtimes ---------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This provides an abstract class for Objective-C code generation. Concrete
// subclasses of this implement code generation for specific Objective-C
// runtime libraries.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_LIB_CODEGEN_CGOBJCRUNTIME_H
#define LLVM_CLANG_LIB_CODEGEN_CGOBJCRUNTIME_H
#include "CGBuilder.h"
#include "CGCall.h"
#include "CGCleanup.h"
#include "CGValue.h"
#include "clang/AST/DeclObjC.h"
#include "clang/Basic/IdentifierTable.h" // Selector
#include "llvm/ADT/UniqueVector.h"
namespace llvm {
class Constant;
class Function;
class Module;
class StructLayout;
class StructType;
class Type;
class Value;
}
namespace clang {
namespace CodeGen {
class CodeGenFunction;
}
class FieldDecl;
class ObjCAtTryStmt;
class ObjCAtThrowStmt;
class ObjCAtSynchronizedStmt;
class ObjCContainerDecl;
class ObjCCategoryImplDecl;
class ObjCImplementationDecl;
class ObjCInterfaceDecl;
class ObjCMessageExpr;
class ObjCMethodDecl;
class ObjCProtocolDecl;
class Selector;
class ObjCIvarDecl;
class ObjCStringLiteral;
class BlockDeclRefExpr;
namespace CodeGen {
class CodeGenModule;
class CGBlockInfo;
// FIXME: Several methods should be pure virtual but aren't to avoid the
// partially-implemented subclass breaking.
/// Implements runtime-specific code generation functions.
class CGObjCRuntime {
protected:
CodeGen::CodeGenModule &CGM;
CGObjCRuntime(CodeGen::CodeGenModule &CGM) : CGM(CGM) {}
// Utility functions for unified ivar access. These need to
// eventually be folded into other places (the structure layout
// code).
/// Compute an offset to the given ivar, suitable for passing to
/// EmitValueForIvarAtOffset. Note that the correct handling of
/// bit-fields is carefully coordinated by these two, use caution!
///
/// The latter overload is suitable for computing the offset of a
/// sythesized ivar.
uint64_t ComputeIvarBaseOffset(CodeGen::CodeGenModule &CGM,
const ObjCInterfaceDecl *OID,
const ObjCIvarDecl *Ivar);
uint64_t ComputeIvarBaseOffset(CodeGen::CodeGenModule &CGM,
const ObjCImplementationDecl *OID,
const ObjCIvarDecl *Ivar);
LValue EmitValueForIvarAtOffset(CodeGen::CodeGenFunction &CGF,
const ObjCInterfaceDecl *OID,
llvm::Value *BaseValue,
const ObjCIvarDecl *Ivar,
unsigned CVRQualifiers,
llvm::Value *Offset);
/// Emits a try / catch statement. This function is intended to be called by
/// subclasses, and provides a generic mechanism for generating these, which
/// should be usable by all runtimes. The caller must provide the functions
/// to call when entering and exiting a \@catch() block, and the function
/// used to rethrow exceptions. If the begin and end catch functions are
/// NULL, then the function assumes that the EH personality function provides
/// the thrown object directly.
void EmitTryCatchStmt(CodeGenFunction &CGF, const ObjCAtTryStmt &S,
llvm::FunctionCallee beginCatchFn,
llvm::FunctionCallee endCatchFn,
llvm::FunctionCallee exceptionRethrowFn);
void EmitInitOfCatchParam(CodeGenFunction &CGF, llvm::Value *exn,
const VarDecl *paramDecl);
/// Emits an \@synchronize() statement, using the \p syncEnterFn and
/// \p syncExitFn arguments as the functions called to lock and unlock
/// the object. This function can be called by subclasses that use
/// zero-cost exception handling.
void EmitAtSynchronizedStmt(CodeGenFunction &CGF,
const ObjCAtSynchronizedStmt &S,
llvm::FunctionCallee syncEnterFn,
llvm::FunctionCallee syncExitFn);
public:
virtual ~CGObjCRuntime();
std::string getSymbolNameForMethod(const ObjCMethodDecl *method,
bool includeCategoryName = true);
/// Generate the function required to register all Objective-C components in
/// this compilation unit with the runtime library.
virtual llvm::Function *ModuleInitFunction() = 0;
/// Get a selector for the specified name and type values.
/// The result should have the LLVM type for ASTContext::getObjCSelType().
virtual llvm::Value *GetSelector(CodeGenFunction &CGF, Selector Sel) = 0;
/// Get the address of a selector for the specified name and type values.
/// This is a rarely-used language extension, but sadly it exists.
///
/// The result should have the LLVM type for a pointer to
/// ASTContext::getObjCSelType().
virtual Address GetAddrOfSelector(CodeGenFunction &CGF, Selector Sel) = 0;
/// Get a typed selector.
virtual llvm::Value *GetSelector(CodeGenFunction &CGF,
const ObjCMethodDecl *Method) = 0;
/// Get the type constant to catch for the given ObjC pointer type.
/// This is used externally to implement catching ObjC types in C++.
/// Runtimes which don't support this should add the appropriate
/// error to Sema.
virtual llvm::Constant *GetEHType(QualType T) = 0;
virtual CatchTypeInfo getCatchAllTypeInfo() { return { nullptr, 0 }; }
/// Generate a constant string object.
virtual ConstantAddress GenerateConstantString(const StringLiteral *) = 0;
/// Generate a category. A category contains a list of methods (and
/// accompanying metadata) and a list of protocols.
virtual void GenerateCategory(const ObjCCategoryImplDecl *OCD) = 0;
/// Generate a class structure for this class.
virtual void GenerateClass(const ObjCImplementationDecl *OID) = 0;
/// Register an class alias.
virtual void RegisterAlias(const ObjCCompatibleAliasDecl *OAD) = 0;
/// Generate an Objective-C message send operation.
///
/// \param Method - The method being called, this may be null if synthesizing
/// a property setter or getter.
virtual CodeGen::RValue
GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
ReturnValueSlot ReturnSlot,
QualType ResultType,
Selector Sel,
llvm::Value *Receiver,
const CallArgList &CallArgs,
const ObjCInterfaceDecl *Class = nullptr,
const ObjCMethodDecl *Method = nullptr) = 0;
/// Generate an Objective-C message send operation.
///
/// This variant allows for the call to be substituted with an optimized
/// variant.
CodeGen::RValue
GeneratePossiblySpecializedMessageSend(CodeGenFunction &CGF,
ReturnValueSlot Return,
QualType ResultType,
Selector Sel,
llvm::Value *Receiver,
const CallArgList& Args,
const ObjCInterfaceDecl *OID,
const ObjCMethodDecl *Method,
bool isClassMessage);
/// Generate an Objective-C message send operation to the super
/// class initiated in a method for Class and with the given Self
/// object.
///
/// \param Method - The method being called, this may be null if synthesizing
/// a property setter or getter.
virtual CodeGen::RValue
GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
ReturnValueSlot ReturnSlot,
QualType ResultType,
Selector Sel,
const ObjCInterfaceDecl *Class,
bool isCategoryImpl,
llvm::Value *Self,
bool IsClassMessage,
const CallArgList &CallArgs,
const ObjCMethodDecl *Method = nullptr) = 0;
/// Walk the list of protocol references from a class, category or
/// protocol to traverse the DAG formed from it's inheritance hierarchy. Find
/// the list of protocols that ends each walk at either a runtime
/// protocol or a non-runtime protocol with no parents. For the common case of
/// just a list of standard runtime protocols this just returns the same list
/// that was passed in.
std::vector<const ObjCProtocolDecl *>
GetRuntimeProtocolList(ObjCProtocolDecl::protocol_iterator begin,
ObjCProtocolDecl::protocol_iterator end);
/// Emit the code to return the named protocol as an object, as in a
/// \@protocol expression.
virtual llvm::Value *GenerateProtocolRef(CodeGenFunction &CGF,
const ObjCProtocolDecl *OPD) = 0;
/// Generate the named protocol. Protocols contain method metadata but no
/// implementations.
virtual void GenerateProtocol(const ObjCProtocolDecl *OPD) = 0;
/// GetOrEmitProtocol - Get the protocol object for the given
/// declaration, emitting it if necessary. The return value has type
/// ProtocolPtrTy.
virtual llvm::Constant *GetOrEmitProtocol(const ObjCProtocolDecl *PD) = 0;
/// Generate a function preamble for a method with the specified
/// types.
// FIXME: Current this just generates the Function definition, but really this
// should also be generating the loads of the parameters, as the runtime
// should have full control over how parameters are passed.
virtual llvm::Function *GenerateMethod(const ObjCMethodDecl *OMD,
const ObjCContainerDecl *CD) = 0;
/// Generates prologue for direct Objective-C Methods.
virtual void GenerateDirectMethodPrologue(CodeGenFunction &CGF,
llvm::Function *Fn,
const ObjCMethodDecl *OMD,
const ObjCContainerDecl *CD) = 0;
/// Return the runtime function for getting properties.
virtual llvm::FunctionCallee GetPropertyGetFunction() = 0;
/// Return the runtime function for setting properties.
virtual llvm::FunctionCallee GetPropertySetFunction() = 0;
/// Return the runtime function for optimized setting properties.
virtual llvm::FunctionCallee GetOptimizedPropertySetFunction(bool atomic,
bool copy) = 0;
// API for atomic copying of qualified aggregates in getter.
virtual llvm::FunctionCallee GetGetStructFunction() = 0;
// API for atomic copying of qualified aggregates in setter.
virtual llvm::FunctionCallee GetSetStructFunction() = 0;
/// API for atomic copying of qualified aggregates with non-trivial copy
/// assignment (c++) in setter.
virtual llvm::FunctionCallee GetCppAtomicObjectSetFunction() = 0;
/// API for atomic copying of qualified aggregates with non-trivial copy
/// assignment (c++) in getter.
virtual llvm::FunctionCallee GetCppAtomicObjectGetFunction() = 0;
/// GetClass - Return a reference to the class for the given
/// interface decl.
virtual llvm::Value *GetClass(CodeGenFunction &CGF,
const ObjCInterfaceDecl *OID) = 0;
virtual llvm::Value *EmitNSAutoreleasePoolClassRef(CodeGenFunction &CGF) {
llvm_unreachable("autoreleasepool unsupported in this ABI");
}
/// EnumerationMutationFunction - Return the function that's called by the
/// compiler when a mutation is detected during foreach iteration.
virtual llvm::FunctionCallee EnumerationMutationFunction() = 0;
virtual void EmitSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
const ObjCAtSynchronizedStmt &S) = 0;
virtual void EmitTryStmt(CodeGen::CodeGenFunction &CGF,
const ObjCAtTryStmt &S) = 0;
virtual void EmitThrowStmt(CodeGen::CodeGenFunction &CGF,
const ObjCAtThrowStmt &S,
bool ClearInsertionPoint=true) = 0;
virtual llvm::Value *EmitObjCWeakRead(CodeGen::CodeGenFunction &CGF,
Address AddrWeakObj) = 0;
virtual void EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF,
llvm::Value *src, Address dest) = 0;
virtual void EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF,
llvm::Value *src, Address dest,
bool threadlocal=false) = 0;
virtual void EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF,
llvm::Value *src, Address dest,
llvm::Value *ivarOffset) = 0;
virtual void EmitObjCStrongCastAssign(CodeGen::CodeGenFunction &CGF,
llvm::Value *src, Address dest) = 0;
virtual LValue EmitObjCValueForIvar(CodeGen::CodeGenFunction &CGF,
QualType ObjectTy,
llvm::Value *BaseValue,
const ObjCIvarDecl *Ivar,
unsigned CVRQualifiers) = 0;
virtual llvm::Value *EmitIvarOffset(CodeGen::CodeGenFunction &CGF,
const ObjCInterfaceDecl *Interface,
const ObjCIvarDecl *Ivar) = 0;
virtual void EmitGCMemmoveCollectable(CodeGen::CodeGenFunction &CGF,
Address DestPtr,
Address SrcPtr,
llvm::Value *Size) = 0;
virtual llvm::Constant *BuildGCBlockLayout(CodeGen::CodeGenModule &CGM,
const CodeGen::CGBlockInfo &blockInfo) = 0;
virtual llvm::Constant *BuildRCBlockLayout(CodeGen::CodeGenModule &CGM,
const CodeGen::CGBlockInfo &blockInfo) = 0;
virtual std::string getRCBlockLayoutStr(CodeGen::CodeGenModule &CGM,
const CGBlockInfo &blockInfo) {
return {};
}
/// Returns an i8* which points to the byref layout information.
virtual llvm::Constant *BuildByrefLayout(CodeGen::CodeGenModule &CGM,
QualType T) = 0;
struct MessageSendInfo {
const CGFunctionInfo &CallInfo;
llvm::PointerType *MessengerType;
MessageSendInfo(const CGFunctionInfo &callInfo,
llvm::PointerType *messengerType)
: CallInfo(callInfo), MessengerType(messengerType) {}
};
MessageSendInfo getMessageSendInfo(const ObjCMethodDecl *method,
QualType resultType,
CallArgList &callArgs);
bool canMessageReceiverBeNull(CodeGenFunction &CGF,
const ObjCMethodDecl *method,
bool isSuper,
const ObjCInterfaceDecl *classReceiver,
llvm::Value *receiver);
static bool isWeakLinkedClass(const ObjCInterfaceDecl *cls);
/// Destroy the callee-destroyed arguments of the given method,
/// if it has any. Used for nil-receiver paths in message sends.
/// Never does anything if the method does not satisfy
/// hasParamDestroyedInCallee().
///
/// \param callArgs - just the formal arguments, not including implicit
/// arguments such as self and cmd
static void destroyCalleeDestroyedArguments(CodeGenFunction &CGF,
const ObjCMethodDecl *method,
const CallArgList &callArgs);
// FIXME: This probably shouldn't be here, but the code to compute
// it is here.
unsigned ComputeBitfieldBitOffset(CodeGen::CodeGenModule &CGM,
const ObjCInterfaceDecl *ID,
const ObjCIvarDecl *Ivar);
};
/// Creates an instance of an Objective-C runtime class.
//TODO: This should include some way of selecting which runtime to target.
CGObjCRuntime *CreateGNUObjCRuntime(CodeGenModule &CGM);
CGObjCRuntime *CreateMacObjCRuntime(CodeGenModule &CGM);
}
}
#endif
|