blob: 0df2a5ec690ec74794c53a65b6f6a54a72dfe35b [file] [log] [blame]
Sean Callanan1a8d4092010-08-27 01:01:44 +00001//===-- ASTResultSynthesizer.cpp --------------------------------*- C++ -*-===//
Sean Callanan116be532010-07-01 20:08:22 +00002//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "stdlib.h"
11#include "clang/AST/ASTContext.h"
12#include "clang/AST/Decl.h"
13#include "clang/AST/DeclCXX.h"
14#include "clang/AST/DeclGroup.h"
Sean Callanan17827832010-12-13 22:46:15 +000015#include "clang/AST/DeclObjC.h"
Sean Callanan116be532010-07-01 20:08:22 +000016#include "clang/AST/Expr.h"
17#include "clang/AST/Stmt.h"
Sean Callanan116be532010-07-01 20:08:22 +000018#include "clang/Parse/Parser.h"
Sean Callanan116be532010-07-01 20:08:22 +000019#include "llvm/Support/Casting.h"
20#include "llvm/Support/raw_ostream.h"
21#include "lldb/Core/Log.h"
Sean Callananbccce812011-08-23 21:20:51 +000022#include "lldb/Expression/ClangPersistentVariables.h"
Sean Callanan1a8d4092010-08-27 01:01:44 +000023#include "lldb/Expression/ASTResultSynthesizer.h"
Sean Callananbccce812011-08-23 21:20:51 +000024#include "lldb/Symbol/ClangASTContext.h"
Sean Callanan0eed0d42011-12-06 03:41:14 +000025#include "lldb/Symbol/ClangASTImporter.h"
26#include "lldb/Target/Target.h"
Sean Callanan116be532010-07-01 20:08:22 +000027
28using namespace llvm;
29using namespace clang;
30using namespace lldb_private;
31
Sean Callananf7c3e272010-11-19 02:52:21 +000032ASTResultSynthesizer::ASTResultSynthesizer(ASTConsumer *passthrough,
Sean Callananbccce812011-08-23 21:20:51 +000033 TypeFromUser desired_type,
Sean Callanan0eed0d42011-12-06 03:41:14 +000034 Target &target) :
Greg Claytonc8e11e12010-07-12 23:14:00 +000035 m_ast_context (NULL),
36 m_passthrough (passthrough),
37 m_passthrough_sema (NULL),
Sean Callanan0eed0d42011-12-06 03:41:14 +000038 m_target (target),
Daniel Dunbara08823f2011-10-31 22:50:49 +000039 m_sema (NULL),
40 m_desired_type (desired_type)
Sean Callanan116be532010-07-01 20:08:22 +000041{
42 if (!m_passthrough)
43 return;
44
45 m_passthrough_sema = dyn_cast<SemaConsumer>(passthrough);
46}
47
Sean Callanan1a8d4092010-08-27 01:01:44 +000048ASTResultSynthesizer::~ASTResultSynthesizer()
Sean Callanan116be532010-07-01 20:08:22 +000049{
50}
51
52void
Sean Callanan1a8d4092010-08-27 01:01:44 +000053ASTResultSynthesizer::Initialize(ASTContext &Context)
Sean Callanan116be532010-07-01 20:08:22 +000054{
55 m_ast_context = &Context;
56
57 if (m_passthrough)
58 m_passthrough->Initialize(Context);
59}
60
61void
Sean Callanan1a8d4092010-08-27 01:01:44 +000062ASTResultSynthesizer::TransformTopLevelDecl(Decl* D)
Sean Callanan116be532010-07-01 20:08:22 +000063{
Sean Callanan17827832010-12-13 22:46:15 +000064 lldb::LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
65
66 if (NamedDecl *named_decl = dyn_cast<NamedDecl>(D))
67 {
Sean Callanan7dd98122011-10-14 20:34:21 +000068 if (log && log->GetVerbose())
Sean Callanan17827832010-12-13 22:46:15 +000069 {
70 if (named_decl->getIdentifier())
71 log->Printf("TransformTopLevelDecl(%s)", named_decl->getIdentifier()->getNameStart());
72 else if (ObjCMethodDecl *method_decl = dyn_cast<ObjCMethodDecl>(D))
73 log->Printf("TransformTopLevelDecl(%s)", method_decl->getSelector().getAsString().c_str());
74 else
75 log->Printf("TransformTopLevelDecl(<complex>)");
76 }
77
78 }
Sean Callanan116be532010-07-01 20:08:22 +000079
Sean Callanan17827832010-12-13 22:46:15 +000080 if (LinkageSpecDecl *linkage_spec_decl = dyn_cast<LinkageSpecDecl>(D))
Sean Callanan116be532010-07-01 20:08:22 +000081 {
82 RecordDecl::decl_iterator decl_iterator;
83
84 for (decl_iterator = linkage_spec_decl->decls_begin();
85 decl_iterator != linkage_spec_decl->decls_end();
86 ++decl_iterator)
87 {
88 TransformTopLevelDecl(*decl_iterator);
89 }
90 }
Sean Callanan17827832010-12-13 22:46:15 +000091 else if (ObjCMethodDecl *method_decl = dyn_cast<ObjCMethodDecl>(D))
Sean Callanan116be532010-07-01 20:08:22 +000092 {
Sean Callanan17827832010-12-13 22:46:15 +000093 if (m_ast_context &&
94 !method_decl->getSelector().getAsString().compare("$__lldb_expr:"))
95 {
Sean Callananbccce812011-08-23 21:20:51 +000096 RecordPersistentTypes(method_decl);
Sean Callanan17827832010-12-13 22:46:15 +000097 SynthesizeObjCMethodResult(method_decl);
98 }
99 }
100 else if (FunctionDecl *function_decl = dyn_cast<FunctionDecl>(D))
101 {
102 if (m_ast_context &&
103 !function_decl->getNameInfo().getAsString().compare("$__lldb_expr"))
104 {
Sean Callananbccce812011-08-23 21:20:51 +0000105 RecordPersistentTypes(function_decl);
Sean Callanan17827832010-12-13 22:46:15 +0000106 SynthesizeFunctionResult(function_decl);
107 }
Sean Callanan116be532010-07-01 20:08:22 +0000108 }
109}
110
Sean Callanan7f27d602011-11-19 02:54:21 +0000111bool
Sean Callanan1a8d4092010-08-27 01:01:44 +0000112ASTResultSynthesizer::HandleTopLevelDecl(DeclGroupRef D)
Sean Callanan116be532010-07-01 20:08:22 +0000113{
114 DeclGroupRef::iterator decl_iterator;
115
116 for (decl_iterator = D.begin();
117 decl_iterator != D.end();
118 ++decl_iterator)
119 {
120 Decl *decl = *decl_iterator;
121
122 TransformTopLevelDecl(decl);
123 }
124
125 if (m_passthrough)
Sean Callanan7f27d602011-11-19 02:54:21 +0000126 return m_passthrough->HandleTopLevelDecl(D);
127 return true;
Sean Callanan116be532010-07-01 20:08:22 +0000128}
129
130bool
Sean Callanan17827832010-12-13 22:46:15 +0000131ASTResultSynthesizer::SynthesizeFunctionResult (FunctionDecl *FunDecl)
Sean Callanan116be532010-07-01 20:08:22 +0000132{
Greg Clayton2d4edfb2010-11-06 01:53:30 +0000133 lldb::LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
Sean Callanan116be532010-07-01 20:08:22 +0000134
Sean Callanan17827832010-12-13 22:46:15 +0000135 ASTContext &Ctx(*m_ast_context);
136
Sean Callanan116be532010-07-01 20:08:22 +0000137 if (!m_sema)
138 return false;
Sean Callanan17827832010-12-13 22:46:15 +0000139
Sean Callanan116be532010-07-01 20:08:22 +0000140 FunctionDecl *function_decl = FunDecl;
141
142 if (!function_decl)
143 return false;
144
Jim Inghame3be0c52011-01-22 01:25:40 +0000145 if (log && log->GetVerbose())
Sean Callanan9e6ed532010-09-13 21:34:21 +0000146 {
147 std::string s;
148 raw_string_ostream os(s);
149
Sean Callananc31ba262010-09-22 00:33:31 +0000150 Ctx.getTranslationUnitDecl()->print(os);
Sean Callanan9e6ed532010-09-13 21:34:21 +0000151
152 os.flush();
153
Sean Callananc31ba262010-09-22 00:33:31 +0000154 log->Printf("AST context before transforming:\n%s", s.c_str());
Sean Callanan9e6ed532010-09-13 21:34:21 +0000155 }
156
Sean Callanan116be532010-07-01 20:08:22 +0000157 Stmt *function_body = function_decl->getBody();
158 CompoundStmt *compound_stmt = dyn_cast<CompoundStmt>(function_body);
159
Sean Callanan17827832010-12-13 22:46:15 +0000160 bool ret = SynthesizeBodyResult (compound_stmt,
161 function_decl);
Jim Inghame3be0c52011-01-22 01:25:40 +0000162
163 if (log && log->GetVerbose())
Sean Callanan17827832010-12-13 22:46:15 +0000164 {
165 std::string s;
166 raw_string_ostream os(s);
167
168 function_decl->print(os);
169
170 os.flush();
171
Jim Inghame3be0c52011-01-22 01:25:40 +0000172 log->Printf ("Transformed function AST:\n%s", s.c_str());
Sean Callanan17827832010-12-13 22:46:15 +0000173 }
174
175 return ret;
176}
177
178bool
179ASTResultSynthesizer::SynthesizeObjCMethodResult (ObjCMethodDecl *MethodDecl)
180{
181 lldb::LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
182
183 ASTContext &Ctx(*m_ast_context);
184
185 if (!m_sema)
186 return false;
187
188 if (!MethodDecl)
189 return false;
190
Jim Inghame3be0c52011-01-22 01:25:40 +0000191 if (log && log->GetVerbose())
Sean Callanan17827832010-12-13 22:46:15 +0000192 {
193 std::string s;
194 raw_string_ostream os(s);
195
196 Ctx.getTranslationUnitDecl()->print(os);
197
198 os.flush();
199
200 log->Printf("AST context before transforming:\n%s", s.c_str());
201 }
202
203 Stmt *method_body = MethodDecl->getBody();
Sean Callanan880e6802011-10-07 23:18:13 +0000204
205 if (!method_body)
206 return false;
207
Sean Callanan17827832010-12-13 22:46:15 +0000208 CompoundStmt *compound_stmt = dyn_cast<CompoundStmt>(method_body);
209
210 bool ret = SynthesizeBodyResult (compound_stmt,
211 MethodDecl);
212
213 if (log)
214 {
215 std::string s;
216 raw_string_ostream os(s);
217
218 MethodDecl->print(os);
219
220 os.flush();
221
222 log->Printf("Transformed function AST:\n%s", s.c_str());
223 }
224
225 return ret;
226}
227
228bool
229ASTResultSynthesizer::SynthesizeBodyResult (CompoundStmt *Body,
230 DeclContext *DC)
231{
232 lldb::LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
233
234 ASTContext &Ctx(*m_ast_context);
Sean Callanan22c52d92011-07-18 21:30:18 +0000235
236 if (!Body)
Sean Callanan116be532010-07-01 20:08:22 +0000237 return false;
238
Sean Callanan22c52d92011-07-18 21:30:18 +0000239 if (Body->body_empty())
Sean Callanan116be532010-07-01 20:08:22 +0000240 return false;
241
Sean Callanan22c52d92011-07-18 21:30:18 +0000242 Stmt **last_stmt_ptr = Body->body_end() - 1;
Sean Callanan116be532010-07-01 20:08:22 +0000243 Stmt *last_stmt = *last_stmt_ptr;
244
Sean Callanan9e6ed532010-09-13 21:34:21 +0000245 while (dyn_cast<NullStmt>(last_stmt))
246 {
Sean Callanan22c52d92011-07-18 21:30:18 +0000247 if (last_stmt_ptr != Body->body_begin())
Sean Callanan9e6ed532010-09-13 21:34:21 +0000248 {
249 last_stmt_ptr--;
250 last_stmt = *last_stmt_ptr;
251 }
Sean Callanan2d1f4be2011-02-22 21:52:56 +0000252 else
253 {
254 return false;
255 }
Sean Callanan9e6ed532010-09-13 21:34:21 +0000256 }
257
Sean Callanan116be532010-07-01 20:08:22 +0000258 Expr *last_expr = dyn_cast<Expr>(last_stmt);
259
260 if (!last_expr)
261 // No auxiliary variable necessary; expression returns void
262 return true;
263
Sean Callanan92adcac2011-01-13 08:53:35 +0000264 // is_lvalue is used to record whether the expression returns an assignable Lvalue or an
265 // Rvalue. This is relevant because they are handled differently.
266 //
267 // For Lvalues
268 //
269 // - In AST result synthesis (here!) the expression E is transformed into an initialization
270 // T *$__lldb_expr_result_ptr = &E.
271 //
272 // - In structure allocation, a pointer-sized slot is allocated in the struct that is to be
273 // passed into the expression.
274 //
275 // - In IR transformations, reads and writes to $__lldb_expr_result_ptr are redirected at
276 // an entry in the struct ($__lldb_arg) passed into the expression. (Other persistent
277 // variables are treated similarly, having been materialized as references, but in those
278 // cases the value of the reference itself is never modified.)
279 //
280 // - During materialization, $0 (the result persistent variable) is ignored.
281 //
282 // - During dematerialization, $0 is marked up as a load address with value equal to the
283 // contents of the structure entry.
284 //
285 // For Rvalues
286 //
287 // - In AST result synthesis the expression E is transformed into an initialization
288 // static T $__lldb_expr_result = E.
289 //
290 // - In structure allocation, a pointer-sized slot is allocated in the struct that is to be
291 // passed into the expression.
292 //
293 // - In IR transformations, an instruction is inserted at the beginning of the function to
294 // dereference the pointer resident in the slot. Reads and writes to $__lldb_expr_result
295 // are redirected at that dereferenced version. Guard variables for the static variable
296 // are excised.
297 //
298 // - During materialization, $0 (the result persistent variable) is populated with the location
299 // of a newly-allocated area of memory.
300 //
301 // - During dematerialization, $0 is ignored.
302
303 bool is_lvalue =
304 (last_expr->getValueKind() == VK_LValue || last_expr->getValueKind() == VK_XValue) &&
305 (last_expr->getObjectKind() == OK_Ordinary);
306
Sean Callanan116be532010-07-01 20:08:22 +0000307 QualType expr_qual_type = last_expr->getType();
Sean Callanan78e37602011-01-27 04:42:51 +0000308 const clang::Type *expr_type = expr_qual_type.getTypePtr();
Sean Callanan116be532010-07-01 20:08:22 +0000309
310 if (!expr_type)
311 return false;
312
313 if (expr_type->isVoidType())
314 return true;
315
316 if (log)
317 {
318 std::string s = expr_qual_type.getAsString();
319
Sean Callanan92adcac2011-01-13 08:53:35 +0000320 log->Printf("Last statement is an %s with type: %s", (is_lvalue ? "lvalue" : "rvalue"), s.c_str());
Sean Callanan116be532010-07-01 20:08:22 +0000321 }
322
Sean Callanan77eaf442011-07-08 00:39:14 +0000323 clang::VarDecl *result_decl = NULL;
Sean Callanan116be532010-07-01 20:08:22 +0000324
Sean Callanan92adcac2011-01-13 08:53:35 +0000325 if (is_lvalue)
326 {
Sean Callanan0c4d8d22011-08-04 21:37:47 +0000327 IdentifierInfo *result_ptr_id;
328
329 if (expr_type->isFunctionType())
330 result_ptr_id = &Ctx.Idents.get("$__lldb_expr_result"); // functions actually should be treated like function pointers
331 else
332 result_ptr_id = &Ctx.Idents.get("$__lldb_expr_result_ptr");
Sean Callanan92adcac2011-01-13 08:53:35 +0000333
Sean Callanan5780f9d2011-12-08 19:04:34 +0000334 QualType ptr_qual_type;
335
Sean Callananfc4f2fb2011-12-14 01:13:04 +0000336 if (expr_qual_type->getAs<ObjCObjectType>() != NULL)
Sean Callanan5780f9d2011-12-08 19:04:34 +0000337 ptr_qual_type = Ctx.getObjCObjectPointerType(expr_qual_type);
338 else
339 ptr_qual_type = Ctx.getPointerType(expr_qual_type);
Sean Callanan92adcac2011-01-13 08:53:35 +0000340
341 result_decl = VarDecl::Create(Ctx,
342 DC,
343 SourceLocation(),
Sean Callananfb0b7582011-03-15 00:17:19 +0000344 SourceLocation(),
Sean Callanan0c4d8d22011-08-04 21:37:47 +0000345 result_ptr_id,
Sean Callanan92adcac2011-01-13 08:53:35 +0000346 ptr_qual_type,
347 NULL,
348 SC_Static,
349 SC_Static);
350
351 if (!result_decl)
352 return false;
353
354 ExprResult address_of_expr = m_sema->CreateBuiltinUnaryOp(SourceLocation(), UO_AddrOf, last_expr);
355
Sean Callananfb0b7582011-03-15 00:17:19 +0000356 m_sema->AddInitializerToDecl(result_decl, address_of_expr.take(), true, true);
Sean Callanan92adcac2011-01-13 08:53:35 +0000357 }
358 else
359 {
360 IdentifierInfo &result_id = Ctx.Idents.get("$__lldb_expr_result");
361
362 result_decl = VarDecl::Create(Ctx,
363 DC,
Sean Callananfb0b7582011-03-15 00:17:19 +0000364 SourceLocation(),
365 SourceLocation(),
Sean Callanan92adcac2011-01-13 08:53:35 +0000366 &result_id,
367 expr_qual_type,
368 NULL,
369 SC_Static,
370 SC_Static);
371
372 if (!result_decl)
373 return false;
374
Sean Callananfb0b7582011-03-15 00:17:19 +0000375 m_sema->AddInitializerToDecl(result_decl, last_expr, true, true);
Sean Callanan92adcac2011-01-13 08:53:35 +0000376 }
Sean Callanan116be532010-07-01 20:08:22 +0000377
Sean Callanan17827832010-12-13 22:46:15 +0000378 DC->addDecl(result_decl);
Sean Callanan116be532010-07-01 20:08:22 +0000379
380 ///////////////////////////////
381 // call AddInitializerToDecl
382 //
Sean Callanane2ef6e32010-09-23 03:01:22 +0000383
Sean Callanan92adcac2011-01-13 08:53:35 +0000384 //m_sema->AddInitializerToDecl(result_decl, last_expr);
Sean Callanan116be532010-07-01 20:08:22 +0000385
386 /////////////////////////////////
387 // call ConvertDeclToDeclGroup
388 //
389
Sean Callanane2ef6e32010-09-23 03:01:22 +0000390 Sema::DeclGroupPtrTy result_decl_group_ptr;
Sean Callanan116be532010-07-01 20:08:22 +0000391
Sean Callanane2ef6e32010-09-23 03:01:22 +0000392 result_decl_group_ptr = m_sema->ConvertDeclToDeclGroup(result_decl);
Sean Callanan116be532010-07-01 20:08:22 +0000393
394 ////////////////////////
395 // call ActOnDeclStmt
396 //
397
Sean Callanane2ef6e32010-09-23 03:01:22 +0000398 StmtResult result_initialization_stmt_result(m_sema->ActOnDeclStmt(result_decl_group_ptr,
399 SourceLocation(),
400 SourceLocation()));
Sean Callanan116be532010-07-01 20:08:22 +0000401
Sean Callanan116be532010-07-01 20:08:22 +0000402 ////////////////////////////////////////////////
403 // replace the old statement with the new one
404 //
405
Sean Callananddb46ef2010-07-24 01:37:44 +0000406 *last_stmt_ptr = reinterpret_cast<Stmt*>(result_initialization_stmt_result.take());
Sean Callanan116be532010-07-01 20:08:22 +0000407
Sean Callanan116be532010-07-01 20:08:22 +0000408 return true;
409}
410
411void
Sean Callanan1a8d4092010-08-27 01:01:44 +0000412ASTResultSynthesizer::HandleTranslationUnit(ASTContext &Ctx)
Sean Callanan116be532010-07-01 20:08:22 +0000413{
414 if (m_passthrough)
415 m_passthrough->HandleTranslationUnit(Ctx);
416}
417
Sean Callananbccce812011-08-23 21:20:51 +0000418void
419ASTResultSynthesizer::RecordPersistentTypes(DeclContext *FunDeclCtx)
420{
421 typedef DeclContext::specific_decl_iterator<TypeDecl> TypeDeclIterator;
422
423 for (TypeDeclIterator i = TypeDeclIterator(FunDeclCtx->decls_begin()),
424 e = TypeDeclIterator(FunDeclCtx->decls_end());
425 i != e;
426 ++i)
427 {
428 MaybeRecordPersistentType(*i);
429 }
430}
431
432void
433ASTResultSynthesizer::MaybeRecordPersistentType(TypeDecl *D)
434{
435 if (!D->getIdentifier())
436 return;
437
438 StringRef name = D->getName();
439
440 if (name.size() == 0 || name[0] != '$')
441 return;
442
443 lldb::LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
444
445 ConstString name_cs(name.str().c_str());
446
447 if (log)
448 log->Printf ("Recording persistent type %s\n", name_cs.GetCString());
449
Sean Callanan0eed0d42011-12-06 03:41:14 +0000450 Decl *D_scratch = m_target.GetClangASTImporter()->DeportDecl(m_target.GetScratchClangASTContext()->getASTContext(),
451 m_ast_context,
452 D);
Sean Callananbccce812011-08-23 21:20:51 +0000453
Sean Callanan0eed0d42011-12-06 03:41:14 +0000454 if (TypeDecl *TypeDecl_scratch = dyn_cast<TypeDecl>(D_scratch))
455 m_target.GetPersistentVariables().RegisterPersistentType(name_cs, TypeDecl_scratch);
Sean Callananbccce812011-08-23 21:20:51 +0000456}
457
Sean Callanan116be532010-07-01 20:08:22 +0000458void
Sean Callanan1a8d4092010-08-27 01:01:44 +0000459ASTResultSynthesizer::HandleTagDeclDefinition(TagDecl *D)
Sean Callananbccce812011-08-23 21:20:51 +0000460{
Sean Callanan116be532010-07-01 20:08:22 +0000461 if (m_passthrough)
462 m_passthrough->HandleTagDeclDefinition(D);
463}
464
465void
Sean Callanan1a8d4092010-08-27 01:01:44 +0000466ASTResultSynthesizer::CompleteTentativeDefinition(VarDecl *D)
Sean Callanan116be532010-07-01 20:08:22 +0000467{
468 if (m_passthrough)
469 m_passthrough->CompleteTentativeDefinition(D);
470}
471
472void
Sean Callanan1a8d4092010-08-27 01:01:44 +0000473ASTResultSynthesizer::HandleVTable(CXXRecordDecl *RD, bool DefinitionRequired)
Sean Callanan116be532010-07-01 20:08:22 +0000474{
475 if (m_passthrough)
476 m_passthrough->HandleVTable(RD, DefinitionRequired);
477}
478
479void
Sean Callanan1a8d4092010-08-27 01:01:44 +0000480ASTResultSynthesizer::PrintStats()
Sean Callanan116be532010-07-01 20:08:22 +0000481{
482 if (m_passthrough)
483 m_passthrough->PrintStats();
484}
485
486void
Sean Callanan1a8d4092010-08-27 01:01:44 +0000487ASTResultSynthesizer::InitializeSema(Sema &S)
Sean Callanan116be532010-07-01 20:08:22 +0000488{
489 m_sema = &S;
Sean Callanan116be532010-07-01 20:08:22 +0000490
491 if (m_passthrough_sema)
492 m_passthrough_sema->InitializeSema(S);
493}
494
495void
Sean Callanan1a8d4092010-08-27 01:01:44 +0000496ASTResultSynthesizer::ForgetSema()
Sean Callanan116be532010-07-01 20:08:22 +0000497{
498 m_sema = NULL;
Sean Callanan116be532010-07-01 20:08:22 +0000499
500 if (m_passthrough_sema)
501 m_passthrough_sema->ForgetSema();
502}