LLVM: lib/ExecutionEngine/Orc/SimpleRemoteEPC.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

13

14#define DEBUG_TYPE "orc"

15

16namespace llvm {

17namespace orc {

18

20#ifndef NDEBUG

21 std::lock_guardstd::mutex Lock(SimpleRemoteEPCMutex);

22 assert(Disconnected && "Destroyed without disconnection");

23#endif

24}

25

27SimpleRemoteEPC::loadDylib(const char *DylibPath) {

28 return EPCDylibMgr->open(DylibPath, 0);

29}

30

31

32

33

34static void

37 std::vectortpctypes::LookupResult Result,

39 if (Request.empty())

40 return Complete(std::move(Result));

41

42 auto &Element = Request.front();

43 DylibMgr.lookupAsync(Element.Handle, Element.Symbols,

44 [&DylibMgr, Request, Complete = std::move(Complete),

46 if (!R)

47 return Complete(R.takeError());

48 Result.push_back({});

49 Result.back().reserve(R->size());

51

54 std::move(Complete));

55 });

56}

57

59 SymbolLookupCompleteFn Complete) {

60 lookupSymbolsAsyncHelper(*EPCDylibMgr, Request, {}, std::move(Complete));

61}

62

67 RunAsMainAddr, Result, MainFnAddr, Args))

68 return std::move(Err);

70}

71

75 RunAsVoidFunctionAddr, Result, VoidFnAddr))

76 return std::move(Err);

78}

79

81 int Arg) {

84 RunAsIntFunctionAddr, Result, IntFnAddr, Arg))

85 return std::move(Err);

87}

88

93 {

94 std::lock_guardstd::mutex Lock(SimpleRemoteEPCMutex);

95 SeqNo = getNextSeqNo();

96 assert(!PendingCallWrapperResults.count(SeqNo) && "SeqNo already in use");

97 PendingCallWrapperResults[SeqNo] = std::move(OnComplete);

98 }

99

101 WrapperFnAddr, ArgBuffer)) {

103

104

105

106

107

108

109 {

110 std::lock_guardstd::mutex Lock(SimpleRemoteEPCMutex);

111 auto I = PendingCallWrapperResults.find(SeqNo);

112 if (I != PendingCallWrapperResults.end()) {

113 H = std::move(I->second);

114 PendingCallWrapperResults.erase(I);

115 }

116 }

117

118 if (H)

120

122 }

123}

124

126 T->disconnect();

127 D->shutdown();

128 std::unique_lockstd::mutex Lock(SimpleRemoteEPCMutex);

129 DisconnectCV.wait(Lock, [this] { return Disconnected; });

130 return std::move(DisconnectErr);

131}

132

137

139 dbgs() << "SimpleRemoteEPC::handleMessage: opc = ";

140 switch (OpC) {

142 dbgs() << "Setup";

143 assert(SeqNo == 0 && "Non-zero SeqNo for Setup?");

144 assert(!TagAddr && "Non-zero TagAddr for Setup?");

145 break;

147 dbgs() << "Hangup";

148 assert(SeqNo == 0 && "Non-zero SeqNo for Hangup?");

149 assert(!TagAddr && "Non-zero TagAddr for Hangup?");

150 break;

152 dbgs() << "Result";

153 assert(!TagAddr && "Non-zero TagAddr for Result?");

154 break;

156 dbgs() << "CallWrapper";

157 break;

158 }

159 dbgs() << ", seqno = " << SeqNo << ", tag-addr = " << TagAddr

160 << ", arg-buffer = " << formatv("{0:x}", ArgBytes.size())

161 << " bytes\n";

162 });

163

164 using UT = std::underlying_type_t;

168

169 switch (OpC) {

171 if (auto Err = handleSetup(SeqNo, TagAddr, std::move(ArgBytes)))

172 return std::move(Err);

173 break;

175 T->disconnect();

176 if (auto Err = handleHangup(std::move(ArgBytes)))

177 return std::move(Err);

180 if (auto Err = handleResult(SeqNo, TagAddr, std::move(ArgBytes)))

181 return std::move(Err);

182 break;

184 handleCallWrapper(SeqNo, TagAddr, std::move(ArgBytes));

185 break;

186 }

188}

189

192 dbgs() << "SimpleRemoteEPC::handleDisconnect: "

193 << (Err ? "failure" : "success") << "\n";

194 });

195

196 PendingCallWrapperResultsMap TmpPending;

197

198 {

199 std::lock_guardstd::mutex Lock(SimpleRemoteEPCMutex);

200 std::swap(TmpPending, PendingCallWrapperResults);

201 }

202

203 for (auto &KV : TmpPending)

204 KV.second(

206

207 std::lock_guardstd::mutex Lock(SimpleRemoteEPCMutex);

208 DisconnectErr = joinErrors(std::move(DisconnectErr), std::move(Err));

209 Disconnected = true;

210 DisconnectCV.notify_all();

211}

212

214SimpleRemoteEPC::createDefaultMemoryManager(SimpleRemoteEPC &SREPC) {

217 {{SAs.Allocator, rt::SimpleExecutorMemoryManagerInstanceName},

218 {SAs.Reserve, rt::SimpleExecutorMemoryManagerReserveWrapperName},

219 {SAs.Initialize,

220 rt::SimpleExecutorMemoryManagerInitializeWrapperName},

221 {SAs.Release, rt::SimpleExecutorMemoryManagerReleaseWrapperName}}))

222 return std::move(Err);

223

224 return std::make_unique(SREPC, SAs);

225}

226

227Expected<std::unique_ptr>

228SimpleRemoteEPC::createDefaultMemoryAccess(SimpleRemoteEPC &SREPC) {

229 EPCGenericMemoryAccess::FuncAddrs FAs;

230 if (auto Err = SREPC.getBootstrapSymbols(

231 {{FAs.WriteUInt8s, rt::MemoryWriteUInt8sWrapperName},

232 {FAs.WriteUInt16s, rt::MemoryWriteUInt16sWrapperName},

233 {FAs.WriteUInt32s, rt::MemoryWriteUInt32sWrapperName},

234 {FAs.WriteUInt64s, rt::MemoryWriteUInt64sWrapperName},

235 {FAs.WriteBuffers, rt::MemoryWriteBuffersWrapperName},

236 {FAs.WritePointers, rt::MemoryWritePointersWrapperName},

237 {FAs.ReadUInt8s, rt::MemoryReadUInt8sWrapperName},

238 {FAs.ReadUInt16s, rt::MemoryReadUInt16sWrapperName},

239 {FAs.ReadUInt32s, rt::MemoryReadUInt32sWrapperName},

240 {FAs.ReadUInt64s, rt::MemoryReadUInt64sWrapperName},

241 {FAs.ReadBuffers, rt::MemoryReadBuffersWrapperName},

242 {FAs.ReadStrings, rt::MemoryReadStringsWrapperName}}))

243 return std::move(Err);

244

245 return std::make_unique(SREPC, FAs);

246}

247

248Error SimpleRemoteEPC::sendMessage(SimpleRemoteEPCOpcode OpC, uint64_t SeqNo,

249 ExecutorAddr TagAddr,

250 ArrayRef ArgBytes) {

251 assert(OpC != SimpleRemoteEPCOpcode::Setup &&

252 "SimpleRemoteEPC sending Setup message? That's the wrong direction.");

253

255 dbgs() << "SimpleRemoteEPC::sendMessage: opc = ";

256 switch (OpC) {

257 case SimpleRemoteEPCOpcode::Hangup:

258 dbgs() << "Hangup";

259 assert(SeqNo == 0 && "Non-zero SeqNo for Hangup?");

260 assert(!TagAddr && "Non-zero TagAddr for Hangup?");

261 break;

262 case SimpleRemoteEPCOpcode::Result:

263 dbgs() << "Result";

264 assert(!TagAddr && "Non-zero TagAddr for Result?");

265 break;

266 case SimpleRemoteEPCOpcode::CallWrapper:

267 dbgs() << "CallWrapper";

268 break;

269 default:

271 }

272 dbgs() << ", seqno = " << SeqNo << ", tag-addr = " << TagAddr

273 << ", arg-buffer = " << formatv("{0:x}", ArgBytes.size())

274 << " bytes\n";

275 });

276 auto Err = T->sendMessage(OpC, SeqNo, TagAddr, ArgBytes);

278 if (Err)

279 dbgs() << " \\--> SimpleRemoteEPC::sendMessage failed\n";

280 });

281 return Err;

282}

283

284Error SimpleRemoteEPC::handleSetup(uint64_t SeqNo, ExecutorAddr TagAddr,

285 SimpleRemoteEPCArgBytesVector ArgBytes) {

286 if (SeqNo != 0)

287 return make_error("Setup packet SeqNo not zero",

289

290 if (TagAddr)

291 return make_error("Setup packet TagAddr not zero",

293

294 std::lock_guardstd::mutex Lock(SimpleRemoteEPCMutex);

295 auto I = PendingCallWrapperResults.find(0);

296 assert(PendingCallWrapperResults.size() == 1 &&

297 I != PendingCallWrapperResults.end() &&

298 "Setup message handler not connectly set up");

299 auto SetupMsgHandler = std::move(I->second);

300 PendingCallWrapperResults.erase(I);

301

302 auto WFR =

303 shared::WrapperFunctionResult::copyFrom(ArgBytes.data(), ArgBytes.size());

304 SetupMsgHandler(std::move(WFR));

305 return Error::success();

306}

307

308Error SimpleRemoteEPC::setup(Setup S) {

309 using namespace SimpleRemoteEPCDefaultBootstrapSymbolNames;

310

311 std::promise<MSVCPExpected> EIP;

312 auto EIF = EIP.get_future();

313

314

315 PendingCallWrapperResults[0] =

316 RunInPlace()(

317 [&](shared::WrapperFunctionResult SetupMsgBytes) {

318 if (const char *ErrMsg = SetupMsgBytes.getOutOfBandError()) {

319 EIP.set_value(

321 return;

322 }

323 using SPSSerialize =

324 shared::SPSArgListshared::SPSSimpleRemoteEPCExecutorInfo;

325 shared::SPSInputBuffer IB(SetupMsgBytes.data(), SetupMsgBytes.size());

326 SimpleRemoteEPCExecutorInfo EI;

327 if (SPSSerialize::deserialize(IB, EI))

328 EIP.set_value(EI);

329 else

330 EIP.set_value(make_error(

332 });

333

334

335 if (auto Err = T->start())

336 return Err;

337

338

339 auto EI = EIF.get();

340 if (!EI) {

341 T->disconnect();

342 return EI.takeError();

343 }

344

346 dbgs() << "SimpleRemoteEPC received setup message:\n"

347 << " Triple: " << EI->TargetTriple << "\n"

348 << " Page size: " << EI->PageSize << "\n"

349 << " Bootstrap map" << (EI->BootstrapMap.empty() ? " empty" : ":")

350 << "\n";

351 for (const auto &KV : EI->BootstrapMap)

352 dbgs() << " " << KV.first() << ": " << KV.second.size()

353 << "-byte SPS encoded buffer\n";

354 dbgs() << " Bootstrap symbols"

355 << (EI->BootstrapSymbols.empty() ? " empty" : ":") << "\n";

356 for (const auto &KV : EI->BootstrapSymbols)

357 dbgs() << " " << KV.first() << ": " << KV.second << "\n";

358 });

359 TargetTriple = Triple(EI->TargetTriple);

361 BootstrapMap = std::move(EI->BootstrapMap);

362 BootstrapSymbols = std::move(EI->BootstrapSymbols);

363

364 if (auto Err = getBootstrapSymbols(

367 {RunAsMainAddr, rt::RunAsMainWrapperName},

368 {RunAsVoidFunctionAddr, rt::RunAsVoidFunctionWrapperName},

369 {RunAsIntFunctionAddr, rt::RunAsIntFunctionWrapperName}}))

370 return Err;

371

372 if (auto DM =

373 EPCGenericDylibManager::CreateWithDefaultBootstrapSymbols(*this))

374 EPCDylibMgr = std::make_unique(std::move(*DM));

375 else

376 return DM.takeError();

377

378

379 if (!S.CreateMemoryManager)

380 S.CreateMemoryManager = createDefaultMemoryManager;

381

382 if (auto MemMgr = S.CreateMemoryManager(*this)) {

383 OwnedMemMgr = std::move(*MemMgr);

384 this->MemMgr = OwnedMemMgr.get();

385 } else

386 return MemMgr.takeError();

387

388

389 if (!S.CreateMemoryAccess)

390 S.CreateMemoryAccess = createDefaultMemoryAccess;

391

392 if (auto MemAccess = S.CreateMemoryAccess(*this)) {

393 OwnedMemAccess = std::move(*MemAccess);

394 this->MemAccess = OwnedMemAccess.get();

395 } else

396 return MemAccess.takeError();

397

398 return Error::success();

399}

400

401Error SimpleRemoteEPC::handleResult(uint64_t SeqNo, ExecutorAddr TagAddr,

402 SimpleRemoteEPCArgBytesVector ArgBytes) {

403 IncomingWFRHandler SendResult;

404

405 if (TagAddr)

406 return make_error("Unexpected TagAddr in result message",

408

409 {

410 std::lock_guardstd::mutex Lock(SimpleRemoteEPCMutex);

411 auto I = PendingCallWrapperResults.find(SeqNo);

412 if (I == PendingCallWrapperResults.end())

413 return make_error("No call for sequence number " +

414 Twine(SeqNo),

416 SendResult = std::move(I->second);

417 PendingCallWrapperResults.erase(I);

418 releaseSeqNo(SeqNo);

419 }

420

421 auto WFR =

422 shared::WrapperFunctionResult::copyFrom(ArgBytes.data(), ArgBytes.size());

423 SendResult(std::move(WFR));

424 return Error::success();

425}

426

427void SimpleRemoteEPC::handleCallWrapper(

428 uint64_t RemoteSeqNo, ExecutorAddr TagAddr,

429 SimpleRemoteEPCArgBytesVector ArgBytes) {

430 assert(ES && "No ExecutionSession attached");

432 [this, RemoteSeqNo, TagAddr, ArgBytes = std::move(ArgBytes)]() {

433 ES->runJITDispatchHandler(

434 [this, RemoteSeqNo](shared::WrapperFunctionResult WFR) {

435 if (auto Err =

436 sendMessage(SimpleRemoteEPCOpcode::Result, RemoteSeqNo,

437 ExecutorAddr(), {WFR.data(), WFR.size()}))

438 getExecutionSession().reportError(std::move(Err));

439 },

440 TagAddr, ArgBytes);

441 },

442 "callWrapper task"));

443}

444

445Error SimpleRemoteEPC::handleHangup(SimpleRemoteEPCArgBytesVector ArgBytes) {

448 if (const char *ErrMsg = WFR.getOutOfBandError())

450

457}

458

459}

460}

assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")

static GCRegistry::Add< StatepointGC > D("statepoint-example", "an example strategy for statepoint")

Analysis containing CSE Info

static RegisterPass< DebugifyModulePass > DM("debugify", "Attach debug info to everything")

static cl::opt< int > PageSize("imp-null-check-page-size", cl::desc("The page size of the target in bytes"), cl::init(4096), cl::Hidden)

ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...

ArrayRef< T > drop_front(size_t N=1) const

Drop the first N elements of the array.

const T & front() const

front - Get the first element.

bool empty() const

empty - Check if the array is empty.

Lightweight error class with error context and mandatory checking.

Tagged union holding either a T or a Error.

unique_function< void(Expected< std::vector< tpctypes::LookupResult > >)> SymbolLookupCompleteFn

LLVM_ABI void lookupAsync(tpctypes::DylibHandle H, const SymbolLookupSet &Lookup, SymbolLookupCompleteFn Complete)

Looks up symbols within the given dylib.

Represents an address in the executor process.

A handler or incoming WrapperFunctionResults – either return values from callWrapper* calls,...

std::unique_ptr< TaskDispatcher > D

Error callSPSWrapper(ExecutorAddr WrapperFnAddr, WrapperCallArgTs &&...WrapperCallArgs)

Run a wrapper function using SPS to serialize the arguments and deserialize the results.

Error getBootstrapSymbols(ArrayRef< std::pair< ExecutorAddr &, StringRef > > Pairs) const

For each (ExecutorAddr&, StringRef) pair, looks up the string in the bootstrap symbols map and writes...

ExecutionSession & getExecutionSession()

Return the ExecutionSession associated with this instance.

void handleDisconnect(Error Err) override

Handle a disconnection from the underlying transport.

Definition SimpleRemoteEPC.cpp:190

Expected< int32_t > runAsMain(ExecutorAddr MainFnAddr, ArrayRef< std::string > Args) override

Run function with a main-like signature.

Definition SimpleRemoteEPC.cpp:63

Expected< HandleMessageAction > handleMessage(SimpleRemoteEPCOpcode OpC, uint64_t SeqNo, ExecutorAddr TagAddr, SimpleRemoteEPCArgBytesVector ArgBytes) override

Handle receipt of a message.

Definition SimpleRemoteEPC.cpp:134

~SimpleRemoteEPC() override

Definition SimpleRemoteEPC.cpp:19

Error disconnect() override

Disconnect from the target process.

Definition SimpleRemoteEPC.cpp:125

Expected< int32_t > runAsVoidFunction(ExecutorAddr VoidFnAddr) override

Run function with a int (*)(void) signature.

Definition SimpleRemoteEPC.cpp:72

void callWrapperAsync(ExecutorAddr WrapperFnAddr, IncomingWFRHandler OnComplete, ArrayRef< char > ArgBuffer) override

Run a wrapper function in the executor.

Definition SimpleRemoteEPC.cpp:89

Expected< int32_t > runAsIntFunction(ExecutorAddr IntFnAddr, int Arg) override

Run function with a int (*)(int) signature.

Definition SimpleRemoteEPC.cpp:80

#define llvm_unreachable(msg)

Marks that the current location is not supposed to be reachable.

LLVM_ABI const char * DispatchFnName

LLVM_ABI const char * ExecutorSessionObjectName

std::unique_ptr< GenericNamedTask > makeGenericNamedTask(FnT &&Fn, std::string Desc)

Create a generic named task from a std::string description.

static void lookupSymbolsAsyncHelper(EPCGenericDylibManager &DylibMgr, ArrayRef< DylibManager::LookupRequest > Request, std::vector< tpctypes::LookupResult > Result, DylibManager::SymbolLookupCompleteFn Complete)

Async helper to chain together calls to DylibMgr::lookupAsync to fulfill all all the requests.

Definition SimpleRemoteEPC.cpp:35

SmallVector< char, 128 > SimpleRemoteEPCArgBytesVector

This is an optimization pass for GlobalISel generic memory operations.

LLVM_ABI std::error_code inconvertibleErrorCode()

The value returned by this function can be returned from convertToErrorCode for Error values where no...

void append_range(Container &C, Range &&R)

Wrapper function to append range R to container C.

auto formatv(bool Validate, const char *Fmt, Ts &&...Vals)

Error joinErrors(Error E1, Error E2)

Concatenate errors.

LLVM_ABI raw_ostream & dbgs()

dbgs() - This returns a reference to a raw_ostream for debugging messages.

Error make_error(ArgTs &&... Args)

Make a Error instance representing failure using the given error info type.

ArrayRef(const T &OneElt) -> ArrayRef< T >

void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)

Implement std::swap in terms of BitVector swap.

Function addresses for memory access.