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