1 /*
2 * Copyright 2010, The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "slang_rs_object_ref_count.h"
18
19 #include <list>
20
21 #include "clang/AST/DeclGroup.h"
22 #include "clang/AST/Expr.h"
23 #include "clang/AST/NestedNameSpecifier.h"
24 #include "clang/AST/OperationKinds.h"
25 #include "clang/AST/Stmt.h"
26 #include "clang/AST/StmtVisitor.h"
27
28 #include "slang_assert.h"
29 #include "slang_rs.h"
30 #include "slang_rs_ast_replace.h"
31 #include "slang_rs_export_type.h"
32
33 namespace slang {
34
35 clang::FunctionDecl *RSObjectRefCount::
36 RSSetObjectFD[RSExportPrimitiveType::LastRSObjectType -
37 RSExportPrimitiveType::FirstRSObjectType + 1];
38 clang::FunctionDecl *RSObjectRefCount::
39 RSClearObjectFD[RSExportPrimitiveType::LastRSObjectType -
40 RSExportPrimitiveType::FirstRSObjectType + 1];
41
GetRSRefCountingFunctions(clang::ASTContext & C)42 void RSObjectRefCount::GetRSRefCountingFunctions(clang::ASTContext &C) {
43 for (unsigned i = 0;
44 i < (sizeof(RSClearObjectFD) / sizeof(clang::FunctionDecl*));
45 i++) {
46 RSSetObjectFD[i] = NULL;
47 RSClearObjectFD[i] = NULL;
48 }
49
50 clang::TranslationUnitDecl *TUDecl = C.getTranslationUnitDecl();
51
52 for (clang::DeclContext::decl_iterator I = TUDecl->decls_begin(),
53 E = TUDecl->decls_end(); I != E; I++) {
54 if ((I->getKind() >= clang::Decl::firstFunction) &&
55 (I->getKind() <= clang::Decl::lastFunction)) {
56 clang::FunctionDecl *FD = static_cast<clang::FunctionDecl*>(*I);
57
58 // points to RSSetObjectFD or RSClearObjectFD
59 clang::FunctionDecl **RSObjectFD;
60
61 if (FD->getName() == "rsSetObject") {
62 slangAssert((FD->getNumParams() == 2) &&
63 "Invalid rsSetObject function prototype (# params)");
64 RSObjectFD = RSSetObjectFD;
65 } else if (FD->getName() == "rsClearObject") {
66 slangAssert((FD->getNumParams() == 1) &&
67 "Invalid rsClearObject function prototype (# params)");
68 RSObjectFD = RSClearObjectFD;
69 } else {
70 continue;
71 }
72
73 const clang::ParmVarDecl *PVD = FD->getParamDecl(0);
74 clang::QualType PVT = PVD->getOriginalType();
75 // The first parameter must be a pointer like rs_allocation*
76 slangAssert(PVT->isPointerType() &&
77 "Invalid rs{Set,Clear}Object function prototype (pointer param)");
78
79 // The rs object type passed to the FD
80 clang::QualType RST = PVT->getPointeeType();
81 RSExportPrimitiveType::DataType DT =
82 RSExportPrimitiveType::GetRSSpecificType(RST.getTypePtr());
83 slangAssert(RSExportPrimitiveType::IsRSObjectType(DT)
84 && "must be RS object type");
85
86 RSObjectFD[(DT - RSExportPrimitiveType::FirstRSObjectType)] = FD;
87 }
88 }
89 }
90
91 namespace {
92
93 // This function constructs a new CompoundStmt from the input StmtList.
BuildCompoundStmt(clang::ASTContext & C,std::list<clang::Stmt * > & StmtList,clang::SourceLocation Loc)94 static clang::CompoundStmt* BuildCompoundStmt(clang::ASTContext &C,
95 std::list<clang::Stmt*> &StmtList, clang::SourceLocation Loc) {
96 unsigned NewStmtCount = StmtList.size();
97 unsigned CompoundStmtCount = 0;
98
99 clang::Stmt **CompoundStmtList;
100 CompoundStmtList = new clang::Stmt*[NewStmtCount];
101
102 std::list<clang::Stmt*>::const_iterator I = StmtList.begin();
103 std::list<clang::Stmt*>::const_iterator E = StmtList.end();
104 for ( ; I != E; I++) {
105 CompoundStmtList[CompoundStmtCount++] = *I;
106 }
107 slangAssert(CompoundStmtCount == NewStmtCount);
108
109 clang::CompoundStmt *CS = new(C) clang::CompoundStmt(
110 C, llvm::makeArrayRef(CompoundStmtList, CompoundStmtCount), Loc, Loc);
111
112 delete [] CompoundStmtList;
113
114 return CS;
115 }
116
AppendAfterStmt(clang::ASTContext & C,clang::CompoundStmt * CS,clang::Stmt * S,std::list<clang::Stmt * > & StmtList)117 static void AppendAfterStmt(clang::ASTContext &C,
118 clang::CompoundStmt *CS,
119 clang::Stmt *S,
120 std::list<clang::Stmt*> &StmtList) {
121 slangAssert(CS);
122 clang::CompoundStmt::body_iterator bI = CS->body_begin();
123 clang::CompoundStmt::body_iterator bE = CS->body_end();
124 clang::Stmt **UpdatedStmtList =
125 new clang::Stmt*[CS->size() + StmtList.size()];
126
127 unsigned UpdatedStmtCount = 0;
128 unsigned Once = 0;
129 for ( ; bI != bE; bI++) {
130 if (!S && ((*bI)->getStmtClass() == clang::Stmt::ReturnStmtClass)) {
131 // If we come across a return here, we don't have anything we can
132 // reasonably replace. We should have already inserted our destructor
133 // code in the proper spot, so we just clean up and return.
134 delete [] UpdatedStmtList;
135
136 return;
137 }
138
139 UpdatedStmtList[UpdatedStmtCount++] = *bI;
140
141 if ((*bI == S) && !Once) {
142 Once++;
143 std::list<clang::Stmt*>::const_iterator I = StmtList.begin();
144 std::list<clang::Stmt*>::const_iterator E = StmtList.end();
145 for ( ; I != E; I++) {
146 UpdatedStmtList[UpdatedStmtCount++] = *I;
147 }
148 }
149 }
150 slangAssert(Once <= 1);
151
152 // When S is NULL, we are appending to the end of the CompoundStmt.
153 if (!S) {
154 slangAssert(Once == 0);
155 std::list<clang::Stmt*>::const_iterator I = StmtList.begin();
156 std::list<clang::Stmt*>::const_iterator E = StmtList.end();
157 for ( ; I != E; I++) {
158 UpdatedStmtList[UpdatedStmtCount++] = *I;
159 }
160 }
161
162 CS->setStmts(C, UpdatedStmtList, UpdatedStmtCount);
163
164 delete [] UpdatedStmtList;
165
166 return;
167 }
168
169 // This class visits a compound statement and inserts DtorStmt
170 // in proper locations. This includes inserting it before any
171 // return statement in any sub-block, at the end of the logical enclosing
172 // scope (compound statement), and/or before any break/continue statement that
173 // would resume outside the declared scope. We will not handle the case for
174 // goto statements that leave a local scope.
175 //
176 // To accomplish these goals, it collects a list of sub-Stmt's that
177 // correspond to scope exit points. It then uses an RSASTReplace visitor to
178 // transform the AST, inserting appropriate destructors before each of those
179 // sub-Stmt's (and also before the exit of the outermost containing Stmt for
180 // the scope).
181 class DestructorVisitor : public clang::StmtVisitor<DestructorVisitor> {
182 private:
183 clang::ASTContext &mCtx;
184
185 // The loop depth of the currently visited node.
186 int mLoopDepth;
187
188 // The switch statement depth of the currently visited node.
189 // Note that this is tracked separately from the loop depth because
190 // SwitchStmt-contained ContinueStmt's should have destructors for the
191 // corresponding loop scope.
192 int mSwitchDepth;
193
194 // The outermost statement block that we are currently visiting.
195 // This should always be a CompoundStmt.
196 clang::Stmt *mOuterStmt;
197
198 // The destructor to execute for this scope/variable.
199 clang::Stmt* mDtorStmt;
200
201 // The stack of statements which should be replaced by a compound statement
202 // containing the new destructor call followed by the original Stmt.
203 std::stack<clang::Stmt*> mReplaceStmtStack;
204
205 // The source location for the variable declaration that we are trying to
206 // insert destructors for. Note that InsertDestructors() will not generate
207 // destructor calls for source locations that occur lexically before this
208 // location.
209 clang::SourceLocation mVarLoc;
210
211 public:
212 DestructorVisitor(clang::ASTContext &C,
213 clang::Stmt* OuterStmt,
214 clang::Stmt* DtorStmt,
215 clang::SourceLocation VarLoc);
216
217 // This code walks the collected list of Stmts to replace and actually does
218 // the replacement. It also finishes up by appending the destructor to the
219 // current outermost CompoundStmt.
InsertDestructors()220 void InsertDestructors() {
221 clang::Stmt *S = NULL;
222 clang::SourceManager &SM = mCtx.getSourceManager();
223 std::list<clang::Stmt *> StmtList;
224 StmtList.push_back(mDtorStmt);
225
226 while (!mReplaceStmtStack.empty()) {
227 S = mReplaceStmtStack.top();
228 mReplaceStmtStack.pop();
229
230 // Skip all source locations that occur before the variable's
231 // declaration, since it won't have been initialized yet.
232 if (SM.isBeforeInTranslationUnit(S->getLocStart(), mVarLoc)) {
233 continue;
234 }
235
236 StmtList.push_back(S);
237 clang::CompoundStmt *CS =
238 BuildCompoundStmt(mCtx, StmtList, S->getLocEnd());
239 StmtList.pop_back();
240
241 RSASTReplace R(mCtx);
242 R.ReplaceStmt(mOuterStmt, S, CS);
243 }
244 clang::CompoundStmt *CS =
245 llvm::dyn_cast<clang::CompoundStmt>(mOuterStmt);
246 slangAssert(CS);
247 AppendAfterStmt(mCtx, CS, NULL, StmtList);
248 }
249
250 void VisitStmt(clang::Stmt *S);
251 void VisitCompoundStmt(clang::CompoundStmt *CS);
252
253 void VisitBreakStmt(clang::BreakStmt *BS);
254 void VisitCaseStmt(clang::CaseStmt *CS);
255 void VisitContinueStmt(clang::ContinueStmt *CS);
256 void VisitDefaultStmt(clang::DefaultStmt *DS);
257 void VisitDoStmt(clang::DoStmt *DS);
258 void VisitForStmt(clang::ForStmt *FS);
259 void VisitIfStmt(clang::IfStmt *IS);
260 void VisitReturnStmt(clang::ReturnStmt *RS);
261 void VisitSwitchCase(clang::SwitchCase *SC);
262 void VisitSwitchStmt(clang::SwitchStmt *SS);
263 void VisitWhileStmt(clang::WhileStmt *WS);
264 };
265
DestructorVisitor(clang::ASTContext & C,clang::Stmt * OuterStmt,clang::Stmt * DtorStmt,clang::SourceLocation VarLoc)266 DestructorVisitor::DestructorVisitor(clang::ASTContext &C,
267 clang::Stmt *OuterStmt,
268 clang::Stmt *DtorStmt,
269 clang::SourceLocation VarLoc)
270 : mCtx(C),
271 mLoopDepth(0),
272 mSwitchDepth(0),
273 mOuterStmt(OuterStmt),
274 mDtorStmt(DtorStmt),
275 mVarLoc(VarLoc) {
276 return;
277 }
278
VisitStmt(clang::Stmt * S)279 void DestructorVisitor::VisitStmt(clang::Stmt *S) {
280 for (clang::Stmt::child_iterator I = S->child_begin(), E = S->child_end();
281 I != E;
282 I++) {
283 if (clang::Stmt *Child = *I) {
284 Visit(Child);
285 }
286 }
287 return;
288 }
289
VisitCompoundStmt(clang::CompoundStmt * CS)290 void DestructorVisitor::VisitCompoundStmt(clang::CompoundStmt *CS) {
291 VisitStmt(CS);
292 return;
293 }
294
VisitBreakStmt(clang::BreakStmt * BS)295 void DestructorVisitor::VisitBreakStmt(clang::BreakStmt *BS) {
296 VisitStmt(BS);
297 if ((mLoopDepth == 0) && (mSwitchDepth == 0)) {
298 mReplaceStmtStack.push(BS);
299 }
300 return;
301 }
302
VisitCaseStmt(clang::CaseStmt * CS)303 void DestructorVisitor::VisitCaseStmt(clang::CaseStmt *CS) {
304 VisitStmt(CS);
305 return;
306 }
307
VisitContinueStmt(clang::ContinueStmt * CS)308 void DestructorVisitor::VisitContinueStmt(clang::ContinueStmt *CS) {
309 VisitStmt(CS);
310 if (mLoopDepth == 0) {
311 // Switch statements can have nested continues.
312 mReplaceStmtStack.push(CS);
313 }
314 return;
315 }
316
VisitDefaultStmt(clang::DefaultStmt * DS)317 void DestructorVisitor::VisitDefaultStmt(clang::DefaultStmt *DS) {
318 VisitStmt(DS);
319 return;
320 }
321
VisitDoStmt(clang::DoStmt * DS)322 void DestructorVisitor::VisitDoStmt(clang::DoStmt *DS) {
323 mLoopDepth++;
324 VisitStmt(DS);
325 mLoopDepth--;
326 return;
327 }
328
VisitForStmt(clang::ForStmt * FS)329 void DestructorVisitor::VisitForStmt(clang::ForStmt *FS) {
330 mLoopDepth++;
331 VisitStmt(FS);
332 mLoopDepth--;
333 return;
334 }
335
VisitIfStmt(clang::IfStmt * IS)336 void DestructorVisitor::VisitIfStmt(clang::IfStmt *IS) {
337 VisitStmt(IS);
338 return;
339 }
340
VisitReturnStmt(clang::ReturnStmt * RS)341 void DestructorVisitor::VisitReturnStmt(clang::ReturnStmt *RS) {
342 mReplaceStmtStack.push(RS);
343 return;
344 }
345
VisitSwitchCase(clang::SwitchCase * SC)346 void DestructorVisitor::VisitSwitchCase(clang::SwitchCase *SC) {
347 slangAssert(false && "Both case and default have specialized handlers");
348 VisitStmt(SC);
349 return;
350 }
351
VisitSwitchStmt(clang::SwitchStmt * SS)352 void DestructorVisitor::VisitSwitchStmt(clang::SwitchStmt *SS) {
353 mSwitchDepth++;
354 VisitStmt(SS);
355 mSwitchDepth--;
356 return;
357 }
358
VisitWhileStmt(clang::WhileStmt * WS)359 void DestructorVisitor::VisitWhileStmt(clang::WhileStmt *WS) {
360 mLoopDepth++;
361 VisitStmt(WS);
362 mLoopDepth--;
363 return;
364 }
365
ClearSingleRSObject(clang::ASTContext & C,clang::Expr * RefRSVar,clang::SourceLocation Loc)366 clang::Expr *ClearSingleRSObject(clang::ASTContext &C,
367 clang::Expr *RefRSVar,
368 clang::SourceLocation Loc) {
369 slangAssert(RefRSVar);
370 const clang::Type *T = RefRSVar->getType().getTypePtr();
371 slangAssert(!T->isArrayType() &&
372 "Should not be destroying arrays with this function");
373
374 clang::FunctionDecl *ClearObjectFD = RSObjectRefCount::GetRSClearObjectFD(T);
375 slangAssert((ClearObjectFD != NULL) &&
376 "rsClearObject doesn't cover all RS object types");
377
378 clang::QualType ClearObjectFDType = ClearObjectFD->getType();
379 clang::QualType ClearObjectFDArgType =
380 ClearObjectFD->getParamDecl(0)->getOriginalType();
381
382 // Example destructor for "rs_font localFont;"
383 //
384 // (CallExpr 'void'
385 // (ImplicitCastExpr 'void (*)(rs_font *)' <FunctionToPointerDecay>
386 // (DeclRefExpr 'void (rs_font *)' FunctionDecl='rsClearObject'))
387 // (UnaryOperator 'rs_font *' prefix '&'
388 // (DeclRefExpr 'rs_font':'rs_font' Var='localFont')))
389
390 // Get address of targeted RS object
391 clang::Expr *AddrRefRSVar =
392 new(C) clang::UnaryOperator(RefRSVar,
393 clang::UO_AddrOf,
394 ClearObjectFDArgType,
395 clang::VK_RValue,
396 clang::OK_Ordinary,
397 Loc);
398
399 clang::Expr *RefRSClearObjectFD =
400 clang::DeclRefExpr::Create(C,
401 clang::NestedNameSpecifierLoc(),
402 clang::SourceLocation(),
403 ClearObjectFD,
404 false,
405 ClearObjectFD->getLocation(),
406 ClearObjectFDType,
407 clang::VK_RValue,
408 NULL);
409
410 clang::Expr *RSClearObjectFP =
411 clang::ImplicitCastExpr::Create(C,
412 C.getPointerType(ClearObjectFDType),
413 clang::CK_FunctionToPointerDecay,
414 RefRSClearObjectFD,
415 NULL,
416 clang::VK_RValue);
417
418 llvm::SmallVector<clang::Expr*, 1> ArgList;
419 ArgList.push_back(AddrRefRSVar);
420
421 clang::CallExpr *RSClearObjectCall =
422 new(C) clang::CallExpr(C,
423 RSClearObjectFP,
424 ArgList,
425 ClearObjectFD->getCallResultType(),
426 clang::VK_RValue,
427 Loc);
428
429 return RSClearObjectCall;
430 }
431
ArrayDim(const clang::Type * T)432 static int ArrayDim(const clang::Type *T) {
433 if (!T || !T->isArrayType()) {
434 return 0;
435 }
436
437 const clang::ConstantArrayType *CAT =
438 static_cast<const clang::ConstantArrayType *>(T);
439 return static_cast<int>(CAT->getSize().getSExtValue());
440 }
441
442 static clang::Stmt *ClearStructRSObject(
443 clang::ASTContext &C,
444 clang::DeclContext *DC,
445 clang::Expr *RefRSStruct,
446 clang::SourceLocation StartLoc,
447 clang::SourceLocation Loc);
448
ClearArrayRSObject(clang::ASTContext & C,clang::DeclContext * DC,clang::Expr * RefRSArr,clang::SourceLocation StartLoc,clang::SourceLocation Loc)449 static clang::Stmt *ClearArrayRSObject(
450 clang::ASTContext &C,
451 clang::DeclContext *DC,
452 clang::Expr *RefRSArr,
453 clang::SourceLocation StartLoc,
454 clang::SourceLocation Loc) {
455 const clang::Type *BaseType = RefRSArr->getType().getTypePtr();
456 slangAssert(BaseType->isArrayType());
457
458 int NumArrayElements = ArrayDim(BaseType);
459 // Actually extract out the base RS object type for use later
460 BaseType = BaseType->getArrayElementTypeNoTypeQual();
461
462 clang::Stmt *StmtArray[2] = {NULL};
463 int StmtCtr = 0;
464
465 if (NumArrayElements <= 0) {
466 return NULL;
467 }
468
469 // Example destructor loop for "rs_font fontArr[10];"
470 //
471 // (CompoundStmt
472 // (DeclStmt "int rsIntIter")
473 // (ForStmt
474 // (BinaryOperator 'int' '='
475 // (DeclRefExpr 'int' Var='rsIntIter')
476 // (IntegerLiteral 'int' 0))
477 // (BinaryOperator 'int' '<'
478 // (DeclRefExpr 'int' Var='rsIntIter')
479 // (IntegerLiteral 'int' 10)
480 // NULL << CondVar >>
481 // (UnaryOperator 'int' postfix '++'
482 // (DeclRefExpr 'int' Var='rsIntIter'))
483 // (CallExpr 'void'
484 // (ImplicitCastExpr 'void (*)(rs_font *)' <FunctionToPointerDecay>
485 // (DeclRefExpr 'void (rs_font *)' FunctionDecl='rsClearObject'))
486 // (UnaryOperator 'rs_font *' prefix '&'
487 // (ArraySubscriptExpr 'rs_font':'rs_font'
488 // (ImplicitCastExpr 'rs_font *' <ArrayToPointerDecay>
489 // (DeclRefExpr 'rs_font [10]' Var='fontArr'))
490 // (DeclRefExpr 'int' Var='rsIntIter')))))))
491
492 // Create helper variable for iterating through elements
493 clang::IdentifierInfo& II = C.Idents.get("rsIntIter");
494 clang::VarDecl *IIVD =
495 clang::VarDecl::Create(C,
496 DC,
497 StartLoc,
498 Loc,
499 &II,
500 C.IntTy,
501 C.getTrivialTypeSourceInfo(C.IntTy),
502 clang::SC_None);
503 clang::Decl *IID = (clang::Decl *)IIVD;
504
505 clang::DeclGroupRef DGR = clang::DeclGroupRef::Create(C, &IID, 1);
506 StmtArray[StmtCtr++] = new(C) clang::DeclStmt(DGR, Loc, Loc);
507
508 // Form the actual destructor loop
509 // for (Init; Cond; Inc)
510 // RSClearObjectCall;
511
512 // Init -> "rsIntIter = 0"
513 clang::DeclRefExpr *RefrsIntIter =
514 clang::DeclRefExpr::Create(C,
515 clang::NestedNameSpecifierLoc(),
516 clang::SourceLocation(),
517 IIVD,
518 false,
519 Loc,
520 C.IntTy,
521 clang::VK_RValue,
522 NULL);
523
524 clang::Expr *Int0 = clang::IntegerLiteral::Create(C,
525 llvm::APInt(C.getTypeSize(C.IntTy), 0), C.IntTy, Loc);
526
527 clang::BinaryOperator *Init =
528 new(C) clang::BinaryOperator(RefrsIntIter,
529 Int0,
530 clang::BO_Assign,
531 C.IntTy,
532 clang::VK_RValue,
533 clang::OK_Ordinary,
534 Loc,
535 false);
536
537 // Cond -> "rsIntIter < NumArrayElements"
538 clang::Expr *NumArrayElementsExpr = clang::IntegerLiteral::Create(C,
539 llvm::APInt(C.getTypeSize(C.IntTy), NumArrayElements), C.IntTy, Loc);
540
541 clang::BinaryOperator *Cond =
542 new(C) clang::BinaryOperator(RefrsIntIter,
543 NumArrayElementsExpr,
544 clang::BO_LT,
545 C.IntTy,
546 clang::VK_RValue,
547 clang::OK_Ordinary,
548 Loc,
549 false);
550
551 // Inc -> "rsIntIter++"
552 clang::UnaryOperator *Inc =
553 new(C) clang::UnaryOperator(RefrsIntIter,
554 clang::UO_PostInc,
555 C.IntTy,
556 clang::VK_RValue,
557 clang::OK_Ordinary,
558 Loc);
559
560 // Body -> "rsClearObject(&VD[rsIntIter]);"
561 // Destructor loop operates on individual array elements
562
563 clang::Expr *RefRSArrPtr =
564 clang::ImplicitCastExpr::Create(C,
565 C.getPointerType(BaseType->getCanonicalTypeInternal()),
566 clang::CK_ArrayToPointerDecay,
567 RefRSArr,
568 NULL,
569 clang::VK_RValue);
570
571 clang::Expr *RefRSArrPtrSubscript =
572 new(C) clang::ArraySubscriptExpr(RefRSArrPtr,
573 RefrsIntIter,
574 BaseType->getCanonicalTypeInternal(),
575 clang::VK_RValue,
576 clang::OK_Ordinary,
577 Loc);
578
579 RSExportPrimitiveType::DataType DT =
580 RSExportPrimitiveType::GetRSSpecificType(BaseType);
581
582 clang::Stmt *RSClearObjectCall = NULL;
583 if (BaseType->isArrayType()) {
584 RSClearObjectCall =
585 ClearArrayRSObject(C, DC, RefRSArrPtrSubscript, StartLoc, Loc);
586 } else if (DT == RSExportPrimitiveType::DataTypeUnknown) {
587 RSClearObjectCall =
588 ClearStructRSObject(C, DC, RefRSArrPtrSubscript, StartLoc, Loc);
589 } else {
590 RSClearObjectCall = ClearSingleRSObject(C, RefRSArrPtrSubscript, Loc);
591 }
592
593 clang::ForStmt *DestructorLoop =
594 new(C) clang::ForStmt(C,
595 Init,
596 Cond,
597 NULL, // no condVar
598 Inc,
599 RSClearObjectCall,
600 Loc,
601 Loc,
602 Loc);
603
604 StmtArray[StmtCtr++] = DestructorLoop;
605 slangAssert(StmtCtr == 2);
606
607 clang::CompoundStmt *CS = new(C) clang::CompoundStmt(
608 C, llvm::makeArrayRef(StmtArray, StmtCtr), Loc, Loc);
609
610 return CS;
611 }
612
CountRSObjectTypes(clang::ASTContext & C,const clang::Type * T,clang::SourceLocation Loc)613 static unsigned CountRSObjectTypes(clang::ASTContext &C,
614 const clang::Type *T,
615 clang::SourceLocation Loc) {
616 slangAssert(T);
617 unsigned RSObjectCount = 0;
618
619 if (T->isArrayType()) {
620 return CountRSObjectTypes(C, T->getArrayElementTypeNoTypeQual(), Loc);
621 }
622
623 RSExportPrimitiveType::DataType DT =
624 RSExportPrimitiveType::GetRSSpecificType(T);
625 if (DT != RSExportPrimitiveType::DataTypeUnknown) {
626 return (RSExportPrimitiveType::IsRSObjectType(DT) ? 1 : 0);
627 }
628
629 if (T->isUnionType()) {
630 clang::RecordDecl *RD = T->getAsUnionType()->getDecl();
631 RD = RD->getDefinition();
632 for (clang::RecordDecl::field_iterator FI = RD->field_begin(),
633 FE = RD->field_end();
634 FI != FE;
635 FI++) {
636 const clang::FieldDecl *FD = *FI;
637 const clang::Type *FT = RSExportType::GetTypeOfDecl(FD);
638 if (CountRSObjectTypes(C, FT, Loc)) {
639 slangAssert(false && "can't have unions with RS object types!");
640 return 0;
641 }
642 }
643 }
644
645 if (!T->isStructureType()) {
646 return 0;
647 }
648
649 clang::RecordDecl *RD = T->getAsStructureType()->getDecl();
650 RD = RD->getDefinition();
651 for (clang::RecordDecl::field_iterator FI = RD->field_begin(),
652 FE = RD->field_end();
653 FI != FE;
654 FI++) {
655 const clang::FieldDecl *FD = *FI;
656 const clang::Type *FT = RSExportType::GetTypeOfDecl(FD);
657 if (CountRSObjectTypes(C, FT, Loc)) {
658 // Sub-structs should only count once (as should arrays, etc.)
659 RSObjectCount++;
660 }
661 }
662
663 return RSObjectCount;
664 }
665
ClearStructRSObject(clang::ASTContext & C,clang::DeclContext * DC,clang::Expr * RefRSStruct,clang::SourceLocation StartLoc,clang::SourceLocation Loc)666 static clang::Stmt *ClearStructRSObject(
667 clang::ASTContext &C,
668 clang::DeclContext *DC,
669 clang::Expr *RefRSStruct,
670 clang::SourceLocation StartLoc,
671 clang::SourceLocation Loc) {
672 const clang::Type *BaseType = RefRSStruct->getType().getTypePtr();
673
674 slangAssert(!BaseType->isArrayType());
675
676 // Structs should show up as unknown primitive types
677 slangAssert(RSExportPrimitiveType::GetRSSpecificType(BaseType) ==
678 RSExportPrimitiveType::DataTypeUnknown);
679
680 unsigned FieldsToDestroy = CountRSObjectTypes(C, BaseType, Loc);
681 slangAssert(FieldsToDestroy != 0);
682
683 unsigned StmtCount = 0;
684 clang::Stmt **StmtArray = new clang::Stmt*[FieldsToDestroy];
685 for (unsigned i = 0; i < FieldsToDestroy; i++) {
686 StmtArray[i] = NULL;
687 }
688
689 // Populate StmtArray by creating a destructor for each RS object field
690 clang::RecordDecl *RD = BaseType->getAsStructureType()->getDecl();
691 RD = RD->getDefinition();
692 for (clang::RecordDecl::field_iterator FI = RD->field_begin(),
693 FE = RD->field_end();
694 FI != FE;
695 FI++) {
696 // We just look through all field declarations to see if we find a
697 // declaration for an RS object type (or an array of one).
698 bool IsArrayType = false;
699 clang::FieldDecl *FD = *FI;
700 const clang::Type *FT = RSExportType::GetTypeOfDecl(FD);
701 const clang::Type *OrigType = FT;
702 while (FT && FT->isArrayType()) {
703 FT = FT->getArrayElementTypeNoTypeQual();
704 IsArrayType = true;
705 }
706
707 if (RSExportPrimitiveType::IsRSObjectType(FT)) {
708 clang::DeclAccessPair FoundDecl =
709 clang::DeclAccessPair::make(FD, clang::AS_none);
710 clang::MemberExpr *RSObjectMember =
711 clang::MemberExpr::Create(C,
712 RefRSStruct,
713 false,
714 clang::NestedNameSpecifierLoc(),
715 clang::SourceLocation(),
716 FD,
717 FoundDecl,
718 clang::DeclarationNameInfo(),
719 NULL,
720 OrigType->getCanonicalTypeInternal(),
721 clang::VK_RValue,
722 clang::OK_Ordinary);
723
724 slangAssert(StmtCount < FieldsToDestroy);
725
726 if (IsArrayType) {
727 StmtArray[StmtCount++] = ClearArrayRSObject(C,
728 DC,
729 RSObjectMember,
730 StartLoc,
731 Loc);
732 } else {
733 StmtArray[StmtCount++] = ClearSingleRSObject(C,
734 RSObjectMember,
735 Loc);
736 }
737 } else if (FT->isStructureType() && CountRSObjectTypes(C, FT, Loc)) {
738 // In this case, we have a nested struct. We may not end up filling all
739 // of the spaces in StmtArray (sub-structs should handle themselves
740 // with separate compound statements).
741 clang::DeclAccessPair FoundDecl =
742 clang::DeclAccessPair::make(FD, clang::AS_none);
743 clang::MemberExpr *RSObjectMember =
744 clang::MemberExpr::Create(C,
745 RefRSStruct,
746 false,
747 clang::NestedNameSpecifierLoc(),
748 clang::SourceLocation(),
749 FD,
750 FoundDecl,
751 clang::DeclarationNameInfo(),
752 NULL,
753 OrigType->getCanonicalTypeInternal(),
754 clang::VK_RValue,
755 clang::OK_Ordinary);
756
757 if (IsArrayType) {
758 StmtArray[StmtCount++] = ClearArrayRSObject(C,
759 DC,
760 RSObjectMember,
761 StartLoc,
762 Loc);
763 } else {
764 StmtArray[StmtCount++] = ClearStructRSObject(C,
765 DC,
766 RSObjectMember,
767 StartLoc,
768 Loc);
769 }
770 }
771 }
772
773 slangAssert(StmtCount > 0);
774 clang::CompoundStmt *CS = new(C) clang::CompoundStmt(
775 C, llvm::makeArrayRef(StmtArray, StmtCount), Loc, Loc);
776
777 delete [] StmtArray;
778
779 return CS;
780 }
781
CreateSingleRSSetObject(clang::ASTContext & C,clang::Expr * DstExpr,clang::Expr * SrcExpr,clang::SourceLocation StartLoc,clang::SourceLocation Loc)782 static clang::Stmt *CreateSingleRSSetObject(clang::ASTContext &C,
783 clang::Expr *DstExpr,
784 clang::Expr *SrcExpr,
785 clang::SourceLocation StartLoc,
786 clang::SourceLocation Loc) {
787 const clang::Type *T = DstExpr->getType().getTypePtr();
788 clang::FunctionDecl *SetObjectFD = RSObjectRefCount::GetRSSetObjectFD(T);
789 slangAssert((SetObjectFD != NULL) &&
790 "rsSetObject doesn't cover all RS object types");
791
792 clang::QualType SetObjectFDType = SetObjectFD->getType();
793 clang::QualType SetObjectFDArgType[2];
794 SetObjectFDArgType[0] = SetObjectFD->getParamDecl(0)->getOriginalType();
795 SetObjectFDArgType[1] = SetObjectFD->getParamDecl(1)->getOriginalType();
796
797 clang::Expr *RefRSSetObjectFD =
798 clang::DeclRefExpr::Create(C,
799 clang::NestedNameSpecifierLoc(),
800 clang::SourceLocation(),
801 SetObjectFD,
802 false,
803 Loc,
804 SetObjectFDType,
805 clang::VK_RValue,
806 NULL);
807
808 clang::Expr *RSSetObjectFP =
809 clang::ImplicitCastExpr::Create(C,
810 C.getPointerType(SetObjectFDType),
811 clang::CK_FunctionToPointerDecay,
812 RefRSSetObjectFD,
813 NULL,
814 clang::VK_RValue);
815
816 llvm::SmallVector<clang::Expr*, 2> ArgList;
817 ArgList.push_back(new(C) clang::UnaryOperator(DstExpr,
818 clang::UO_AddrOf,
819 SetObjectFDArgType[0],
820 clang::VK_RValue,
821 clang::OK_Ordinary,
822 Loc));
823 ArgList.push_back(SrcExpr);
824
825 clang::CallExpr *RSSetObjectCall =
826 new(C) clang::CallExpr(C,
827 RSSetObjectFP,
828 ArgList,
829 SetObjectFD->getCallResultType(),
830 clang::VK_RValue,
831 Loc);
832
833 return RSSetObjectCall;
834 }
835
836 static clang::Stmt *CreateStructRSSetObject(clang::ASTContext &C,
837 clang::Expr *LHS,
838 clang::Expr *RHS,
839 clang::SourceLocation StartLoc,
840 clang::SourceLocation Loc);
841
842 /*static clang::Stmt *CreateArrayRSSetObject(clang::ASTContext &C,
843 clang::Expr *DstArr,
844 clang::Expr *SrcArr,
845 clang::SourceLocation StartLoc,
846 clang::SourceLocation Loc) {
847 clang::DeclContext *DC = NULL;
848 const clang::Type *BaseType = DstArr->getType().getTypePtr();
849 slangAssert(BaseType->isArrayType());
850
851 int NumArrayElements = ArrayDim(BaseType);
852 // Actually extract out the base RS object type for use later
853 BaseType = BaseType->getArrayElementTypeNoTypeQual();
854
855 clang::Stmt *StmtArray[2] = {NULL};
856 int StmtCtr = 0;
857
858 if (NumArrayElements <= 0) {
859 return NULL;
860 }
861
862 // Create helper variable for iterating through elements
863 clang::IdentifierInfo& II = C.Idents.get("rsIntIter");
864 clang::VarDecl *IIVD =
865 clang::VarDecl::Create(C,
866 DC,
867 StartLoc,
868 Loc,
869 &II,
870 C.IntTy,
871 C.getTrivialTypeSourceInfo(C.IntTy),
872 clang::SC_None,
873 clang::SC_None);
874 clang::Decl *IID = (clang::Decl *)IIVD;
875
876 clang::DeclGroupRef DGR = clang::DeclGroupRef::Create(C, &IID, 1);
877 StmtArray[StmtCtr++] = new(C) clang::DeclStmt(DGR, Loc, Loc);
878
879 // Form the actual loop
880 // for (Init; Cond; Inc)
881 // RSSetObjectCall;
882
883 // Init -> "rsIntIter = 0"
884 clang::DeclRefExpr *RefrsIntIter =
885 clang::DeclRefExpr::Create(C,
886 clang::NestedNameSpecifierLoc(),
887 IIVD,
888 Loc,
889 C.IntTy,
890 clang::VK_RValue,
891 NULL);
892
893 clang::Expr *Int0 = clang::IntegerLiteral::Create(C,
894 llvm::APInt(C.getTypeSize(C.IntTy), 0), C.IntTy, Loc);
895
896 clang::BinaryOperator *Init =
897 new(C) clang::BinaryOperator(RefrsIntIter,
898 Int0,
899 clang::BO_Assign,
900 C.IntTy,
901 clang::VK_RValue,
902 clang::OK_Ordinary,
903 Loc);
904
905 // Cond -> "rsIntIter < NumArrayElements"
906 clang::Expr *NumArrayElementsExpr = clang::IntegerLiteral::Create(C,
907 llvm::APInt(C.getTypeSize(C.IntTy), NumArrayElements), C.IntTy, Loc);
908
909 clang::BinaryOperator *Cond =
910 new(C) clang::BinaryOperator(RefrsIntIter,
911 NumArrayElementsExpr,
912 clang::BO_LT,
913 C.IntTy,
914 clang::VK_RValue,
915 clang::OK_Ordinary,
916 Loc);
917
918 // Inc -> "rsIntIter++"
919 clang::UnaryOperator *Inc =
920 new(C) clang::UnaryOperator(RefrsIntIter,
921 clang::UO_PostInc,
922 C.IntTy,
923 clang::VK_RValue,
924 clang::OK_Ordinary,
925 Loc);
926
927 // Body -> "rsSetObject(&Dst[rsIntIter], Src[rsIntIter]);"
928 // Loop operates on individual array elements
929
930 clang::Expr *DstArrPtr =
931 clang::ImplicitCastExpr::Create(C,
932 C.getPointerType(BaseType->getCanonicalTypeInternal()),
933 clang::CK_ArrayToPointerDecay,
934 DstArr,
935 NULL,
936 clang::VK_RValue);
937
938 clang::Expr *DstArrPtrSubscript =
939 new(C) clang::ArraySubscriptExpr(DstArrPtr,
940 RefrsIntIter,
941 BaseType->getCanonicalTypeInternal(),
942 clang::VK_RValue,
943 clang::OK_Ordinary,
944 Loc);
945
946 clang::Expr *SrcArrPtr =
947 clang::ImplicitCastExpr::Create(C,
948 C.getPointerType(BaseType->getCanonicalTypeInternal()),
949 clang::CK_ArrayToPointerDecay,
950 SrcArr,
951 NULL,
952 clang::VK_RValue);
953
954 clang::Expr *SrcArrPtrSubscript =
955 new(C) clang::ArraySubscriptExpr(SrcArrPtr,
956 RefrsIntIter,
957 BaseType->getCanonicalTypeInternal(),
958 clang::VK_RValue,
959 clang::OK_Ordinary,
960 Loc);
961
962 RSExportPrimitiveType::DataType DT =
963 RSExportPrimitiveType::GetRSSpecificType(BaseType);
964
965 clang::Stmt *RSSetObjectCall = NULL;
966 if (BaseType->isArrayType()) {
967 RSSetObjectCall = CreateArrayRSSetObject(C, DstArrPtrSubscript,
968 SrcArrPtrSubscript,
969 StartLoc, Loc);
970 } else if (DT == RSExportPrimitiveType::DataTypeUnknown) {
971 RSSetObjectCall = CreateStructRSSetObject(C, DstArrPtrSubscript,
972 SrcArrPtrSubscript,
973 StartLoc, Loc);
974 } else {
975 RSSetObjectCall = CreateSingleRSSetObject(C, DstArrPtrSubscript,
976 SrcArrPtrSubscript,
977 StartLoc, Loc);
978 }
979
980 clang::ForStmt *DestructorLoop =
981 new(C) clang::ForStmt(C,
982 Init,
983 Cond,
984 NULL, // no condVar
985 Inc,
986 RSSetObjectCall,
987 Loc,
988 Loc,
989 Loc);
990
991 StmtArray[StmtCtr++] = DestructorLoop;
992 slangAssert(StmtCtr == 2);
993
994 clang::CompoundStmt *CS =
995 new(C) clang::CompoundStmt(C, StmtArray, StmtCtr, Loc, Loc);
996
997 return CS;
998 } */
999
CreateStructRSSetObject(clang::ASTContext & C,clang::Expr * LHS,clang::Expr * RHS,clang::SourceLocation StartLoc,clang::SourceLocation Loc)1000 static clang::Stmt *CreateStructRSSetObject(clang::ASTContext &C,
1001 clang::Expr *LHS,
1002 clang::Expr *RHS,
1003 clang::SourceLocation StartLoc,
1004 clang::SourceLocation Loc) {
1005 clang::QualType QT = LHS->getType();
1006 const clang::Type *T = QT.getTypePtr();
1007 slangAssert(T->isStructureType());
1008 slangAssert(!RSExportPrimitiveType::IsRSObjectType(T));
1009
1010 // Keep an extra slot for the original copy (memcpy)
1011 unsigned FieldsToSet = CountRSObjectTypes(C, T, Loc) + 1;
1012
1013 unsigned StmtCount = 0;
1014 clang::Stmt **StmtArray = new clang::Stmt*[FieldsToSet];
1015 for (unsigned i = 0; i < FieldsToSet; i++) {
1016 StmtArray[i] = NULL;
1017 }
1018
1019 clang::RecordDecl *RD = T->getAsStructureType()->getDecl();
1020 RD = RD->getDefinition();
1021 for (clang::RecordDecl::field_iterator FI = RD->field_begin(),
1022 FE = RD->field_end();
1023 FI != FE;
1024 FI++) {
1025 bool IsArrayType = false;
1026 clang::FieldDecl *FD = *FI;
1027 const clang::Type *FT = RSExportType::GetTypeOfDecl(FD);
1028 const clang::Type *OrigType = FT;
1029
1030 if (!CountRSObjectTypes(C, FT, Loc)) {
1031 // Skip to next if we don't have any viable RS object types
1032 continue;
1033 }
1034
1035 clang::DeclAccessPair FoundDecl =
1036 clang::DeclAccessPair::make(FD, clang::AS_none);
1037 clang::MemberExpr *DstMember =
1038 clang::MemberExpr::Create(C,
1039 LHS,
1040 false,
1041 clang::NestedNameSpecifierLoc(),
1042 clang::SourceLocation(),
1043 FD,
1044 FoundDecl,
1045 clang::DeclarationNameInfo(),
1046 NULL,
1047 OrigType->getCanonicalTypeInternal(),
1048 clang::VK_RValue,
1049 clang::OK_Ordinary);
1050
1051 clang::MemberExpr *SrcMember =
1052 clang::MemberExpr::Create(C,
1053 RHS,
1054 false,
1055 clang::NestedNameSpecifierLoc(),
1056 clang::SourceLocation(),
1057 FD,
1058 FoundDecl,
1059 clang::DeclarationNameInfo(),
1060 NULL,
1061 OrigType->getCanonicalTypeInternal(),
1062 clang::VK_RValue,
1063 clang::OK_Ordinary);
1064
1065 if (FT->isArrayType()) {
1066 FT = FT->getArrayElementTypeNoTypeQual();
1067 IsArrayType = true;
1068 }
1069
1070 RSExportPrimitiveType::DataType DT =
1071 RSExportPrimitiveType::GetRSSpecificType(FT);
1072
1073 if (IsArrayType) {
1074 clang::DiagnosticsEngine &DiagEngine = C.getDiagnostics();
1075 DiagEngine.Report(
1076 clang::FullSourceLoc(Loc, C.getSourceManager()),
1077 DiagEngine.getCustomDiagID(
1078 clang::DiagnosticsEngine::Error,
1079 "Arrays of RS object types within structures cannot be copied"));
1080 // TODO(srhines): Support setting arrays of RS objects
1081 // StmtArray[StmtCount++] =
1082 // CreateArrayRSSetObject(C, DstMember, SrcMember, StartLoc, Loc);
1083 } else if (DT == RSExportPrimitiveType::DataTypeUnknown) {
1084 StmtArray[StmtCount++] =
1085 CreateStructRSSetObject(C, DstMember, SrcMember, StartLoc, Loc);
1086 } else if (RSExportPrimitiveType::IsRSObjectType(DT)) {
1087 StmtArray[StmtCount++] =
1088 CreateSingleRSSetObject(C, DstMember, SrcMember, StartLoc, Loc);
1089 } else {
1090 slangAssert(false);
1091 }
1092 }
1093
1094 slangAssert(StmtCount < FieldsToSet);
1095
1096 // We still need to actually do the overall struct copy. For simplicity,
1097 // we just do a straight-up assignment (which will still preserve all
1098 // the proper RS object reference counts).
1099 clang::BinaryOperator *CopyStruct =
1100 new(C) clang::BinaryOperator(LHS, RHS, clang::BO_Assign, QT,
1101 clang::VK_RValue, clang::OK_Ordinary, Loc,
1102 false);
1103 StmtArray[StmtCount++] = CopyStruct;
1104
1105 clang::CompoundStmt *CS = new(C) clang::CompoundStmt(
1106 C, llvm::makeArrayRef(StmtArray, StmtCount), Loc, Loc);
1107
1108 delete [] StmtArray;
1109
1110 return CS;
1111 }
1112
1113 } // namespace
1114
ReplaceRSObjectAssignment(clang::BinaryOperator * AS)1115 void RSObjectRefCount::Scope::ReplaceRSObjectAssignment(
1116 clang::BinaryOperator *AS) {
1117
1118 clang::QualType QT = AS->getType();
1119
1120 clang::ASTContext &C = RSObjectRefCount::GetRSSetObjectFD(
1121 RSExportPrimitiveType::DataTypeRSFont)->getASTContext();
1122
1123 clang::SourceLocation Loc = AS->getExprLoc();
1124 clang::SourceLocation StartLoc = AS->getLHS()->getExprLoc();
1125 clang::Stmt *UpdatedStmt = NULL;
1126
1127 if (!RSExportPrimitiveType::IsRSObjectType(QT.getTypePtr())) {
1128 // By definition, this is a struct assignment if we get here
1129 UpdatedStmt =
1130 CreateStructRSSetObject(C, AS->getLHS(), AS->getRHS(), StartLoc, Loc);
1131 } else {
1132 UpdatedStmt =
1133 CreateSingleRSSetObject(C, AS->getLHS(), AS->getRHS(), StartLoc, Loc);
1134 }
1135
1136 RSASTReplace R(C);
1137 R.ReplaceStmt(mCS, AS, UpdatedStmt);
1138 return;
1139 }
1140
AppendRSObjectInit(clang::VarDecl * VD,clang::DeclStmt * DS,RSExportPrimitiveType::DataType DT,clang::Expr * InitExpr)1141 void RSObjectRefCount::Scope::AppendRSObjectInit(
1142 clang::VarDecl *VD,
1143 clang::DeclStmt *DS,
1144 RSExportPrimitiveType::DataType DT,
1145 clang::Expr *InitExpr) {
1146 slangAssert(VD);
1147
1148 if (!InitExpr) {
1149 return;
1150 }
1151
1152 clang::ASTContext &C = RSObjectRefCount::GetRSSetObjectFD(
1153 RSExportPrimitiveType::DataTypeRSFont)->getASTContext();
1154 clang::SourceLocation Loc = RSObjectRefCount::GetRSSetObjectFD(
1155 RSExportPrimitiveType::DataTypeRSFont)->getLocation();
1156 clang::SourceLocation StartLoc = RSObjectRefCount::GetRSSetObjectFD(
1157 RSExportPrimitiveType::DataTypeRSFont)->getInnerLocStart();
1158
1159 if (DT == RSExportPrimitiveType::DataTypeIsStruct) {
1160 const clang::Type *T = RSExportType::GetTypeOfDecl(VD);
1161 clang::DeclRefExpr *RefRSVar =
1162 clang::DeclRefExpr::Create(C,
1163 clang::NestedNameSpecifierLoc(),
1164 clang::SourceLocation(),
1165 VD,
1166 false,
1167 Loc,
1168 T->getCanonicalTypeInternal(),
1169 clang::VK_RValue,
1170 NULL);
1171
1172 clang::Stmt *RSSetObjectOps =
1173 CreateStructRSSetObject(C, RefRSVar, InitExpr, StartLoc, Loc);
1174
1175 std::list<clang::Stmt*> StmtList;
1176 StmtList.push_back(RSSetObjectOps);
1177 AppendAfterStmt(C, mCS, DS, StmtList);
1178 return;
1179 }
1180
1181 clang::FunctionDecl *SetObjectFD = RSObjectRefCount::GetRSSetObjectFD(DT);
1182 slangAssert((SetObjectFD != NULL) &&
1183 "rsSetObject doesn't cover all RS object types");
1184
1185 clang::QualType SetObjectFDType = SetObjectFD->getType();
1186 clang::QualType SetObjectFDArgType[2];
1187 SetObjectFDArgType[0] = SetObjectFD->getParamDecl(0)->getOriginalType();
1188 SetObjectFDArgType[1] = SetObjectFD->getParamDecl(1)->getOriginalType();
1189
1190 clang::Expr *RefRSSetObjectFD =
1191 clang::DeclRefExpr::Create(C,
1192 clang::NestedNameSpecifierLoc(),
1193 clang::SourceLocation(),
1194 SetObjectFD,
1195 false,
1196 Loc,
1197 SetObjectFDType,
1198 clang::VK_RValue,
1199 NULL);
1200
1201 clang::Expr *RSSetObjectFP =
1202 clang::ImplicitCastExpr::Create(C,
1203 C.getPointerType(SetObjectFDType),
1204 clang::CK_FunctionToPointerDecay,
1205 RefRSSetObjectFD,
1206 NULL,
1207 clang::VK_RValue);
1208
1209 const clang::Type *T = RSExportType::GetTypeOfDecl(VD);
1210 clang::DeclRefExpr *RefRSVar =
1211 clang::DeclRefExpr::Create(C,
1212 clang::NestedNameSpecifierLoc(),
1213 clang::SourceLocation(),
1214 VD,
1215 false,
1216 Loc,
1217 T->getCanonicalTypeInternal(),
1218 clang::VK_RValue,
1219 NULL);
1220
1221 llvm::SmallVector<clang::Expr*, 2> ArgList;
1222 ArgList.push_back(new(C) clang::UnaryOperator(RefRSVar,
1223 clang::UO_AddrOf,
1224 SetObjectFDArgType[0],
1225 clang::VK_RValue,
1226 clang::OK_Ordinary,
1227 Loc));
1228 ArgList.push_back(InitExpr);
1229
1230 clang::CallExpr *RSSetObjectCall =
1231 new(C) clang::CallExpr(C,
1232 RSSetObjectFP,
1233 ArgList,
1234 SetObjectFD->getCallResultType(),
1235 clang::VK_RValue,
1236 Loc);
1237
1238 std::list<clang::Stmt*> StmtList;
1239 StmtList.push_back(RSSetObjectCall);
1240 AppendAfterStmt(C, mCS, DS, StmtList);
1241
1242 return;
1243 }
1244
InsertLocalVarDestructors()1245 void RSObjectRefCount::Scope::InsertLocalVarDestructors() {
1246 for (std::list<clang::VarDecl*>::const_iterator I = mRSO.begin(),
1247 E = mRSO.end();
1248 I != E;
1249 I++) {
1250 clang::VarDecl *VD = *I;
1251 clang::Stmt *RSClearObjectCall = ClearRSObject(VD, VD->getDeclContext());
1252 if (RSClearObjectCall) {
1253 DestructorVisitor DV((*mRSO.begin())->getASTContext(),
1254 mCS,
1255 RSClearObjectCall,
1256 VD->getSourceRange().getBegin());
1257 DV.Visit(mCS);
1258 DV.InsertDestructors();
1259 }
1260 }
1261 return;
1262 }
1263
ClearRSObject(clang::VarDecl * VD,clang::DeclContext * DC)1264 clang::Stmt *RSObjectRefCount::Scope::ClearRSObject(
1265 clang::VarDecl *VD,
1266 clang::DeclContext *DC) {
1267 slangAssert(VD);
1268 clang::ASTContext &C = VD->getASTContext();
1269 clang::SourceLocation Loc = VD->getLocation();
1270 clang::SourceLocation StartLoc = VD->getInnerLocStart();
1271 const clang::Type *T = RSExportType::GetTypeOfDecl(VD);
1272
1273 // Reference expr to target RS object variable
1274 clang::DeclRefExpr *RefRSVar =
1275 clang::DeclRefExpr::Create(C,
1276 clang::NestedNameSpecifierLoc(),
1277 clang::SourceLocation(),
1278 VD,
1279 false,
1280 Loc,
1281 T->getCanonicalTypeInternal(),
1282 clang::VK_RValue,
1283 NULL);
1284
1285 if (T->isArrayType()) {
1286 return ClearArrayRSObject(C, DC, RefRSVar, StartLoc, Loc);
1287 }
1288
1289 RSExportPrimitiveType::DataType DT =
1290 RSExportPrimitiveType::GetRSSpecificType(T);
1291
1292 if (DT == RSExportPrimitiveType::DataTypeUnknown ||
1293 DT == RSExportPrimitiveType::DataTypeIsStruct) {
1294 return ClearStructRSObject(C, DC, RefRSVar, StartLoc, Loc);
1295 }
1296
1297 slangAssert((RSExportPrimitiveType::IsRSObjectType(DT)) &&
1298 "Should be RS object");
1299
1300 return ClearSingleRSObject(C, RefRSVar, Loc);
1301 }
1302
InitializeRSObject(clang::VarDecl * VD,RSExportPrimitiveType::DataType * DT,clang::Expr ** InitExpr)1303 bool RSObjectRefCount::InitializeRSObject(clang::VarDecl *VD,
1304 RSExportPrimitiveType::DataType *DT,
1305 clang::Expr **InitExpr) {
1306 slangAssert(VD && DT && InitExpr);
1307 const clang::Type *T = RSExportType::GetTypeOfDecl(VD);
1308
1309 // Loop through array types to get to base type
1310 while (T && T->isArrayType()) {
1311 T = T->getArrayElementTypeNoTypeQual();
1312 }
1313
1314 bool DataTypeIsStructWithRSObject = false;
1315 *DT = RSExportPrimitiveType::GetRSSpecificType(T);
1316
1317 if (*DT == RSExportPrimitiveType::DataTypeUnknown) {
1318 if (RSExportPrimitiveType::IsStructureTypeWithRSObject(T)) {
1319 *DT = RSExportPrimitiveType::DataTypeIsStruct;
1320 DataTypeIsStructWithRSObject = true;
1321 } else {
1322 return false;
1323 }
1324 }
1325
1326 bool DataTypeIsRSObject = false;
1327 if (DataTypeIsStructWithRSObject) {
1328 DataTypeIsRSObject = true;
1329 } else {
1330 DataTypeIsRSObject = RSExportPrimitiveType::IsRSObjectType(*DT);
1331 }
1332 *InitExpr = VD->getInit();
1333
1334 if (!DataTypeIsRSObject && *InitExpr) {
1335 // If we already have an initializer for a matrix type, we are done.
1336 return DataTypeIsRSObject;
1337 }
1338
1339 clang::Expr *ZeroInitializer =
1340 CreateZeroInitializerForRSSpecificType(*DT,
1341 VD->getASTContext(),
1342 VD->getLocation());
1343
1344 if (ZeroInitializer) {
1345 ZeroInitializer->setType(T->getCanonicalTypeInternal());
1346 VD->setInit(ZeroInitializer);
1347 }
1348
1349 return DataTypeIsRSObject;
1350 }
1351
CreateZeroInitializerForRSSpecificType(RSExportPrimitiveType::DataType DT,clang::ASTContext & C,const clang::SourceLocation & Loc)1352 clang::Expr *RSObjectRefCount::CreateZeroInitializerForRSSpecificType(
1353 RSExportPrimitiveType::DataType DT,
1354 clang::ASTContext &C,
1355 const clang::SourceLocation &Loc) {
1356 clang::Expr *Res = NULL;
1357 switch (DT) {
1358 case RSExportPrimitiveType::DataTypeIsStruct:
1359 case RSExportPrimitiveType::DataTypeRSElement:
1360 case RSExportPrimitiveType::DataTypeRSType:
1361 case RSExportPrimitiveType::DataTypeRSAllocation:
1362 case RSExportPrimitiveType::DataTypeRSSampler:
1363 case RSExportPrimitiveType::DataTypeRSScript:
1364 case RSExportPrimitiveType::DataTypeRSMesh:
1365 case RSExportPrimitiveType::DataTypeRSPath:
1366 case RSExportPrimitiveType::DataTypeRSProgramFragment:
1367 case RSExportPrimitiveType::DataTypeRSProgramVertex:
1368 case RSExportPrimitiveType::DataTypeRSProgramRaster:
1369 case RSExportPrimitiveType::DataTypeRSProgramStore:
1370 case RSExportPrimitiveType::DataTypeRSFont: {
1371 // (ImplicitCastExpr 'nullptr_t'
1372 // (IntegerLiteral 0)))
1373 llvm::APInt Zero(C.getTypeSize(C.IntTy), 0);
1374 clang::Expr *Int0 = clang::IntegerLiteral::Create(C, Zero, C.IntTy, Loc);
1375 clang::Expr *CastToNull =
1376 clang::ImplicitCastExpr::Create(C,
1377 C.NullPtrTy,
1378 clang::CK_IntegralToPointer,
1379 Int0,
1380 NULL,
1381 clang::VK_RValue);
1382
1383 llvm::SmallVector<clang::Expr*, 1>InitList;
1384 InitList.push_back(CastToNull);
1385
1386 Res = new(C) clang::InitListExpr(C, Loc, InitList, Loc);
1387 break;
1388 }
1389 case RSExportPrimitiveType::DataTypeRSMatrix2x2:
1390 case RSExportPrimitiveType::DataTypeRSMatrix3x3:
1391 case RSExportPrimitiveType::DataTypeRSMatrix4x4: {
1392 // RS matrix is not completely an RS object. They hold data by themselves.
1393 // (InitListExpr rs_matrix2x2
1394 // (InitListExpr float[4]
1395 // (FloatingLiteral 0)
1396 // (FloatingLiteral 0)
1397 // (FloatingLiteral 0)
1398 // (FloatingLiteral 0)))
1399 clang::QualType FloatTy = C.FloatTy;
1400 // Constructor sets value to 0.0f by default
1401 llvm::APFloat Val(C.getFloatTypeSemantics(FloatTy));
1402 clang::FloatingLiteral *Float0Val =
1403 clang::FloatingLiteral::Create(C,
1404 Val,
1405 /* isExact = */true,
1406 FloatTy,
1407 Loc);
1408
1409 unsigned N = 0;
1410 if (DT == RSExportPrimitiveType::DataTypeRSMatrix2x2)
1411 N = 2;
1412 else if (DT == RSExportPrimitiveType::DataTypeRSMatrix3x3)
1413 N = 3;
1414 else if (DT == RSExportPrimitiveType::DataTypeRSMatrix4x4)
1415 N = 4;
1416 unsigned N_2 = N * N;
1417
1418 // Assume we are going to be allocating 16 elements, since 4x4 is max.
1419 llvm::SmallVector<clang::Expr*, 16> InitVals;
1420 for (unsigned i = 0; i < N_2; i++)
1421 InitVals.push_back(Float0Val);
1422 clang::Expr *InitExpr =
1423 new(C) clang::InitListExpr(C, Loc, InitVals, Loc);
1424 InitExpr->setType(C.getConstantArrayType(FloatTy,
1425 llvm::APInt(32, N_2),
1426 clang::ArrayType::Normal,
1427 /* EltTypeQuals = */0));
1428 llvm::SmallVector<clang::Expr*, 1> InitExprVec;
1429 InitExprVec.push_back(InitExpr);
1430
1431 Res = new(C) clang::InitListExpr(C, Loc, InitExprVec, Loc);
1432 break;
1433 }
1434 case RSExportPrimitiveType::DataTypeUnknown:
1435 case RSExportPrimitiveType::DataTypeFloat16:
1436 case RSExportPrimitiveType::DataTypeFloat32:
1437 case RSExportPrimitiveType::DataTypeFloat64:
1438 case RSExportPrimitiveType::DataTypeSigned8:
1439 case RSExportPrimitiveType::DataTypeSigned16:
1440 case RSExportPrimitiveType::DataTypeSigned32:
1441 case RSExportPrimitiveType::DataTypeSigned64:
1442 case RSExportPrimitiveType::DataTypeUnsigned8:
1443 case RSExportPrimitiveType::DataTypeUnsigned16:
1444 case RSExportPrimitiveType::DataTypeUnsigned32:
1445 case RSExportPrimitiveType::DataTypeUnsigned64:
1446 case RSExportPrimitiveType::DataTypeBoolean:
1447 case RSExportPrimitiveType::DataTypeUnsigned565:
1448 case RSExportPrimitiveType::DataTypeUnsigned5551:
1449 case RSExportPrimitiveType::DataTypeUnsigned4444:
1450 case RSExportPrimitiveType::DataTypeMax: {
1451 slangAssert(false && "Not RS object type!");
1452 }
1453 // No default case will enable compiler detecting the missing cases
1454 }
1455
1456 return Res;
1457 }
1458
VisitDeclStmt(clang::DeclStmt * DS)1459 void RSObjectRefCount::VisitDeclStmt(clang::DeclStmt *DS) {
1460 for (clang::DeclStmt::decl_iterator I = DS->decl_begin(), E = DS->decl_end();
1461 I != E;
1462 I++) {
1463 clang::Decl *D = *I;
1464 if (D->getKind() == clang::Decl::Var) {
1465 clang::VarDecl *VD = static_cast<clang::VarDecl*>(D);
1466 RSExportPrimitiveType::DataType DT =
1467 RSExportPrimitiveType::DataTypeUnknown;
1468 clang::Expr *InitExpr = NULL;
1469 if (InitializeRSObject(VD, &DT, &InitExpr)) {
1470 // We need to zero-init all RS object types (including matrices), ...
1471 getCurrentScope()->AppendRSObjectInit(VD, DS, DT, InitExpr);
1472 // ... but, only add to the list of RS objects if we have some
1473 // non-matrix RS object fields.
1474 if (CountRSObjectTypes(mCtx, VD->getType().getTypePtr(),
1475 VD->getLocation())) {
1476 getCurrentScope()->addRSObject(VD);
1477 }
1478 }
1479 }
1480 }
1481 return;
1482 }
1483
VisitCompoundStmt(clang::CompoundStmt * CS)1484 void RSObjectRefCount::VisitCompoundStmt(clang::CompoundStmt *CS) {
1485 if (!CS->body_empty()) {
1486 // Push a new scope
1487 Scope *S = new Scope(CS);
1488 mScopeStack.push(S);
1489
1490 VisitStmt(CS);
1491
1492 // Destroy the scope
1493 slangAssert((getCurrentScope() == S) && "Corrupted scope stack!");
1494 S->InsertLocalVarDestructors();
1495 mScopeStack.pop();
1496 delete S;
1497 }
1498 return;
1499 }
1500
VisitBinAssign(clang::BinaryOperator * AS)1501 void RSObjectRefCount::VisitBinAssign(clang::BinaryOperator *AS) {
1502 clang::QualType QT = AS->getType();
1503
1504 if (CountRSObjectTypes(mCtx, QT.getTypePtr(), AS->getExprLoc())) {
1505 getCurrentScope()->ReplaceRSObjectAssignment(AS);
1506 }
1507
1508 return;
1509 }
1510
VisitStmt(clang::Stmt * S)1511 void RSObjectRefCount::VisitStmt(clang::Stmt *S) {
1512 for (clang::Stmt::child_iterator I = S->child_begin(), E = S->child_end();
1513 I != E;
1514 I++) {
1515 if (clang::Stmt *Child = *I) {
1516 Visit(Child);
1517 }
1518 }
1519 return;
1520 }
1521
1522 // This function walks the list of global variables and (potentially) creates
1523 // a single global static destructor function that properly decrements
1524 // reference counts on the contained RS object types.
CreateStaticGlobalDtor()1525 clang::FunctionDecl *RSObjectRefCount::CreateStaticGlobalDtor() {
1526 Init();
1527
1528 clang::DeclContext *DC = mCtx.getTranslationUnitDecl();
1529 clang::SourceLocation loc;
1530
1531 llvm::StringRef SR(".rs.dtor");
1532 clang::IdentifierInfo &II = mCtx.Idents.get(SR);
1533 clang::DeclarationName N(&II);
1534 clang::FunctionProtoType::ExtProtoInfo EPI;
1535 clang::QualType T = mCtx.getFunctionType(mCtx.VoidTy,
1536 llvm::ArrayRef<clang::QualType>(), EPI);
1537 clang::FunctionDecl *FD = NULL;
1538
1539 // Generate rsClearObject() call chains for every global variable
1540 // (whether static or extern).
1541 std::list<clang::Stmt *> StmtList;
1542 for (clang::DeclContext::decl_iterator I = DC->decls_begin(),
1543 E = DC->decls_end(); I != E; I++) {
1544 clang::VarDecl *VD = llvm::dyn_cast<clang::VarDecl>(*I);
1545 if (VD) {
1546 if (CountRSObjectTypes(mCtx, VD->getType().getTypePtr(), loc)) {
1547 if (!FD) {
1548 // Only create FD if we are going to use it.
1549 FD = clang::FunctionDecl::Create(mCtx, DC, loc, loc, N, T, NULL,
1550 clang::SC_None);
1551 }
1552 // Make sure to create any helpers within the function's DeclContext,
1553 // not the one associated with the global translation unit.
1554 clang::Stmt *RSClearObjectCall = Scope::ClearRSObject(VD, FD);
1555 StmtList.push_back(RSClearObjectCall);
1556 }
1557 }
1558 }
1559
1560 // Nothing needs to be destroyed, so don't emit a dtor.
1561 if (StmtList.empty()) {
1562 return NULL;
1563 }
1564
1565 clang::CompoundStmt *CS = BuildCompoundStmt(mCtx, StmtList, loc);
1566
1567 FD->setBody(CS);
1568
1569 return FD;
1570 }
1571
1572 } // namespace slang
1573