1//===---- RemoteTargetExternal.cpp - LLVM out-of-process JIT execution ----===//
2//
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// Implementation of the RemoteTargetExternal class which executes JITed code
11// in a separate process from where it was built.
12//
13//===----------------------------------------------------------------------===//
14
15#include "llvm/Config/config.h"
16#include "RemoteTarget.h"
17#include "RemoteTargetExternal.h"
18#include "llvm/ADT/StringRef.h"
19#include "llvm/Support/DataTypes.h"
20#include "llvm/Support/Debug.h"
21#include "llvm/Support/Format.h"
22#include "llvm/Support/Memory.h"
23#include "llvm/Support/Program.h"
24#include "llvm/Support/raw_ostream.h"
25#include <string>
26
27using namespace llvm;
28
29#define DEBUG_TYPE "lli"
30
31bool RemoteTargetExternal::allocateSpace(size_t Size, unsigned Alignment,
32                                 uint64_t &Address) {
33  DEBUG(dbgs() << "Message [allocate space] size: " << Size <<
34                  ", align: " << Alignment << "\n");
35  if (!SendAllocateSpace(Alignment, Size)) {
36    ErrorMsg += ", (RemoteTargetExternal::allocateSpace)";
37    return false;
38  }
39  if (!Receive(LLI_AllocationResult, Address)) {
40    ErrorMsg += ", (RemoteTargetExternal::allocateSpace)";
41    return false;
42  }
43  if (Address == 0) {
44    ErrorMsg += "failed allocation, (RemoteTargetExternal::allocateSpace)";
45    return false;
46  }
47  DEBUG(dbgs() << "Message [allocate space] addr: 0x" <<
48                  format("%llx", Address) << "\n");
49  return true;
50}
51
52bool RemoteTargetExternal::loadData(uint64_t Address, const void *Data, size_t Size) {
53  DEBUG(dbgs() << "Message [load data] addr: 0x" << format("%llx", Address) <<
54                  ", size: " << Size << "\n");
55  if (!SendLoadSection(Address, Data, (uint32_t)Size, false)) {
56    ErrorMsg += ", (RemoteTargetExternal::loadData)";
57    return false;
58  }
59  int Status = LLI_Status_Success;
60  if (!Receive(LLI_LoadResult, Status)) {
61    ErrorMsg += ", (RemoteTargetExternal::loadData)";
62    return false;
63  }
64  if (Status == LLI_Status_IncompleteMsg) {
65    ErrorMsg += "incomplete load data, (RemoteTargetExternal::loadData)";
66    return false;
67  }
68  if (Status == LLI_Status_NotAllocated) {
69    ErrorMsg += "data memory not allocated, (RemoteTargetExternal::loadData)";
70    return false;
71  }
72  DEBUG(dbgs() << "Message [load data] complete\n");
73  return true;
74}
75
76bool RemoteTargetExternal::loadCode(uint64_t Address, const void *Data, size_t Size) {
77  DEBUG(dbgs() << "Message [load code] addr: 0x" << format("%llx", Address) <<
78                  ", size: " << Size << "\n");
79  if (!SendLoadSection(Address, Data, (uint32_t)Size, true)) {
80    ErrorMsg += ", (RemoteTargetExternal::loadCode)";
81    return false;
82  }
83  int Status = LLI_Status_Success;
84  if (!Receive(LLI_LoadResult, Status)) {
85    ErrorMsg += ", (RemoteTargetExternal::loadCode)";
86    return false;
87  }
88  if (Status == LLI_Status_IncompleteMsg) {
89    ErrorMsg += "incomplete load data, (RemoteTargetExternal::loadData)";
90    return false;
91  }
92  if (Status == LLI_Status_NotAllocated) {
93    ErrorMsg += "data memory not allocated, (RemoteTargetExternal::loadData)";
94    return false;
95  }
96  DEBUG(dbgs() << "Message [load code] complete\n");
97  return true;
98}
99
100bool RemoteTargetExternal::executeCode(uint64_t Address, int32_t &RetVal) {
101  DEBUG(dbgs() << "Message [exectue code] addr: " << Address << "\n");
102  if (!SendExecute(Address)) {
103    ErrorMsg += ", (RemoteTargetExternal::executeCode)";
104    return false;
105  }
106  if (!Receive(LLI_ExecutionResult, RetVal)) {
107    ErrorMsg += ", (RemoteTargetExternal::executeCode)";
108    return false;
109  }
110  DEBUG(dbgs() << "Message [exectue code] return: " << RetVal << "\n");
111  return true;
112}
113
114void RemoteTargetExternal::stop() {
115  SendTerminate();
116  RPC.Wait();
117}
118
119bool RemoteTargetExternal::SendAllocateSpace(uint32_t Alignment, uint32_t Size) {
120  if (!SendHeader(LLI_AllocateSpace)) {
121    ErrorMsg += ", (RemoteTargetExternal::SendAllocateSpace)";
122    return false;
123  }
124
125  AppendWrite((const void *)&Alignment, 4);
126  AppendWrite((const void *)&Size, 4);
127
128  if (!SendPayload()) {
129    ErrorMsg += ", (RemoteTargetExternal::SendAllocateSpace)";
130    return false;
131  }
132  return true;
133}
134
135bool RemoteTargetExternal::SendLoadSection(uint64_t Addr,
136                                       const void *Data,
137                                       uint32_t Size,
138                                       bool IsCode) {
139  LLIMessageType MsgType = IsCode ? LLI_LoadCodeSection : LLI_LoadDataSection;
140  if (!SendHeader(MsgType)) {
141    ErrorMsg += ", (RemoteTargetExternal::SendLoadSection)";
142    return false;
143  }
144
145  AppendWrite((const void *)&Addr, 8);
146  AppendWrite(Data, Size);
147
148  if (!SendPayload()) {
149    ErrorMsg += ", (RemoteTargetExternal::SendLoadSection)";
150    return false;
151  }
152  return true;
153}
154
155bool RemoteTargetExternal::SendExecute(uint64_t Addr) {
156  if (!SendHeader(LLI_Execute)) {
157    ErrorMsg += ", (RemoteTargetExternal::SendExecute)";
158    return false;
159  }
160
161  AppendWrite((const void *)&Addr, 8);
162
163  if (!SendPayload()) {
164    ErrorMsg += ", (RemoteTargetExternal::SendExecute)";
165    return false;
166  }
167  return true;
168}
169
170bool RemoteTargetExternal::SendTerminate() {
171  return SendHeader(LLI_Terminate);
172  // No data or data size is sent with Terminate
173}
174
175bool RemoteTargetExternal::Receive(LLIMessageType Msg) {
176  if (!ReceiveHeader(Msg))
177    return false;
178  int Unused;
179  AppendRead(&Unused, 0);
180  if (!ReceivePayload())
181    return false;
182  ReceiveData.clear();
183  Sizes.clear();
184  return true;
185}
186
187bool RemoteTargetExternal::Receive(LLIMessageType Msg, int32_t &Data) {
188  if (!ReceiveHeader(Msg))
189    return false;
190  AppendRead(&Data, 4);
191  if (!ReceivePayload())
192    return false;
193  ReceiveData.clear();
194  Sizes.clear();
195  return true;
196}
197
198bool RemoteTargetExternal::Receive(LLIMessageType Msg, uint64_t &Data) {
199  if (!ReceiveHeader(Msg))
200    return false;
201  AppendRead(&Data, 8);
202  if (!ReceivePayload())
203    return false;
204  ReceiveData.clear();
205  Sizes.clear();
206  return true;
207}
208
209bool RemoteTargetExternal::ReceiveHeader(LLIMessageType ExpectedMsgType) {
210  assert(ReceiveData.empty() && Sizes.empty() &&
211         "Payload vector not empty to receive header");
212
213  // Message header, with type to follow
214  uint32_t MsgType;
215  if (!ReadBytes(&MsgType, 4)) {
216    ErrorMsg += ", (RemoteTargetExternal::ReceiveHeader)";
217    return false;
218  }
219  if (MsgType != (uint32_t)ExpectedMsgType) {
220    ErrorMsg = "received unexpected message type";
221    ErrorMsg += ". Expecting: ";
222    ErrorMsg += ExpectedMsgType;
223    ErrorMsg += ", Got: ";
224    ErrorMsg += MsgType;
225    return false;
226  }
227  return true;
228}
229
230bool RemoteTargetExternal::ReceivePayload() {
231  assert(!ReceiveData.empty() &&
232         "Payload vector empty to receive");
233  assert(ReceiveData.size() == Sizes.size() &&
234         "Unexpected mismatch between data and size");
235
236  uint32_t TotalSize = 0;
237  for (int I=0, E=Sizes.size(); I < E; I++)
238    TotalSize += Sizes[I];
239
240  // Payload size header
241  uint32_t DataSize;
242  if (!ReadBytes(&DataSize, 4)) {
243    ErrorMsg += ", invalid data size";
244    return false;
245  }
246  if (DataSize != TotalSize) {
247    ErrorMsg = "unexpected data size";
248    ErrorMsg += ". Expecting: ";
249    ErrorMsg += TotalSize;
250    ErrorMsg += ", Got: ";
251    ErrorMsg += DataSize;
252    return false;
253  }
254  if (DataSize == 0)
255    return true;
256
257  // Payload itself
258  for (int I=0, E=Sizes.size(); I < E; I++) {
259    if (!ReadBytes(ReceiveData[I], Sizes[I])) {
260      ErrorMsg = "unexpected data while reading message";
261      return false;
262    }
263  }
264
265  return true;
266}
267
268bool RemoteTargetExternal::SendHeader(LLIMessageType MsgType) {
269  assert(SendData.empty() && Sizes.empty() &&
270         "Payload vector not empty to send header");
271
272  // Message header, with type to follow
273  if (!WriteBytes(&MsgType, 4)) {
274    ErrorMsg += ", (RemoteTargetExternal::SendHeader)";
275    return false;
276  }
277  return true;
278}
279
280bool RemoteTargetExternal::SendPayload() {
281  assert(!SendData.empty() && !Sizes.empty() &&
282         "Payload vector empty to send");
283  assert(SendData.size() == Sizes.size() &&
284         "Unexpected mismatch between data and size");
285
286  uint32_t TotalSize = 0;
287  for (int I=0, E=Sizes.size(); I < E; I++)
288    TotalSize += Sizes[I];
289
290  // Payload size header
291  if (!WriteBytes(&TotalSize, 4)) {
292    ErrorMsg += ", invalid data size";
293    return false;
294  }
295  if (TotalSize == 0)
296    return true;
297
298  // Payload itself
299  for (int I=0, E=Sizes.size(); I < E; I++) {
300    if (!WriteBytes(SendData[I], Sizes[I])) {
301      ErrorMsg = "unexpected data while writing message";
302      return false;
303    }
304  }
305
306  SendData.clear();
307  Sizes.clear();
308  return true;
309}
310
311void RemoteTargetExternal::AppendWrite(const void *Data, uint32_t Size) {
312  SendData.push_back(Data);
313  Sizes.push_back(Size);
314}
315
316void RemoteTargetExternal::AppendRead(void *Data, uint32_t Size) {
317  ReceiveData.push_back(Data);
318  Sizes.push_back(Size);
319}
320
321#ifdef LLVM_ON_UNIX
322#include "Unix/RPCChannel.inc"
323#endif
324
325#ifdef LLVM_ON_WIN32
326#include "Windows/RPCChannel.inc"
327#endif
328