ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/libcpjit/cpjit.C
Revision: 1.13
Committed: Sat Jul 18 05:59:18 2009 UTC (14 years, 10 months ago) by root
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Changes since 1.12: +0 -2 lines
Log Message:
riddify us of meta.yml garbage in manifest

File Contents

# Content
1 /*
2 cpjit.C -- c portable jit in time compiler
3 Copyright (C) 2005 Marc Lehmann <cpjit@schmorp.de>
4
5 This file is part of libcpjit.
6
7 libcpjit is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with gvpe; if not, write to the Free Software
19 Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22 #include "config.h"
23
24 #include "cpjit.h"
25
26 #include <cassert>
27 #include <cstdlib>
28 #include <cstdarg>
29 #include <cstdio>
30 #include <cstring>
31 #include <cerrno>
32
33 #include <iostream>
34 #include <sstream>
35 #include <fstream>
36 #include <stdexcept>
37 #include <iomanip>
38
39 #include <unistd.h>
40 #include <fcntl.h> // for locking
41
42 #include <sys/stat.h>
43 #include <sys/types.h>
44 #include <dirent.h>
45 #include <utime.h>
46
47 #include "md5.h"
48
49 #include <dlfcn.h>
50
51 #define STR_(str) #str
52 #define STR(str) STR_(str)
53
54 #define IDX_VERSION 1
55
56 namespace cpjit
57 {
58
59 using namespace std;
60
61 const char typestr<U8 >::str[] = "unsigned " STR(TYPE_INT8);
62 const char typestr<U16 >::str[] = "unsigned " STR(TYPE_INT16);
63 const char typestr<U32 >::str[] = "unsigned " STR(TYPE_INT32);
64 const char typestr<U64 >::str[] = "unsigned " STR(TYPE_INT64);
65 const char typestr<I8 >::str[] = "signed " STR(TYPE_INT8);
66 const char typestr<I16 >::str[] = STR(TYPE_INT16);
67 const char typestr<I32 >::str[] = STR(TYPE_INT32);
68 const char typestr<I64 >::str[] = STR(TYPE_INT64);
69 const char typestr<FLT >::str[] = "float";
70 const char typestr<DBL >::str[] = "double";
71
72 const char typestr<PTR >::str[] = "void" " *";
73
74 const char typestr<U8 *>::str[] = "unsigned " STR(TYPE_INT8) " *";
75 const char typestr<U16 *>::str[] = "unsigned " STR(TYPE_INT16) " *";
76 const char typestr<U32 *>::str[] = "unsigned " STR(TYPE_INT32) " *";
77 const char typestr<U64 *>::str[] = "unsigned " STR(TYPE_INT64) " *";
78 const char typestr<I8 *>::str[] = "signed " STR(TYPE_INT8) " *";
79 const char typestr<I16 *>::str[] = STR(TYPE_INT16) " *";
80 const char typestr<I32 *>::str[] = STR(TYPE_INT32) " *";
81 const char typestr<I64 *>::str[] = STR(TYPE_INT64) " *";
82 const char typestr<FLT *>::str[] = "float" " *";
83 const char typestr<DBL *>::str[] = "double" " *";
84
85 /////////////////////////////////////////////////////////////////////////////
86
87 struct digest : md5_ctx
88 {
89 digest ()
90 {
91 md5_init_ctx (this);
92 }
93
94 digest &operator <<(const string &data)
95 {
96 md5_process_bytes (data.c_str (), data.size (), this);
97 return *this;
98 }
99
100 operator string();
101 };
102
103 digest::operator string ()
104 {
105 unsigned char data[16];
106 std::ostringstream s;
107
108 md5_finish_ctx (this, data);
109
110 for (int i = 0; i < 16; i++)
111 s << std::setfill ('0') << std::hex << std::setw (2) << (int)data [i];
112
113 return s.str ();
114 }
115
116 /////////////////////////////////////////////////////////////////////////////
117
118 static inline bool
119 is_null (const string &s)
120 {
121 return s.empty ();
122 }
123
124 /////////////////////////////////////////////////////////////////////////////
125
126 // error exception builder
127 struct error : std::ostringstream
128 {
129 ~error ()
130 {
131 throw std::runtime_error (str ());
132 }
133 };
134
135 #define FATAL(msg) do { error o; o << msg << std::endl; } while (0)
136 #define ERRNO " (" << strerror (errno) << ")"
137
138 /////////////////////////////////////////////////////////////////////////////
139
140 static long get_stamp (int fd)
141 {
142 struct stat st;
143
144 if (fstat (fd, &st))
145 FATAL ("could not get file stamp");
146
147 return (long)st.st_mtime;
148 }
149
150 static void set_stamp (const string &path, long stamp)
151 {
152 struct utimbuf ut;
153
154 ut.actime = stamp;
155 ut.modtime = stamp;
156
157 if (utime (path.c_str (), &ut))
158 FATAL ("could not set file stamp");
159 }
160
161 /////////////////////////////////////////////////////////////////////////////
162
163 funsrc::funsrc ()
164 {
165 }
166
167 void funsrc::update_id (const char *pfx)
168 {
169 digest dgst;
170
171 for (set<string>::const_iterator i = hdrlist.begin ();
172 i != hdrlist.end ();
173 ++i)
174 dgst << *i;
175
176 dgst << retlist << arglist << body;
177
178 id = pfx + (string) dgst;
179 }
180
181 /////////////////////////////////////////////////////////////////////////////
182
183 funbuild::funbuild (env &e, const char *rettype, ...)
184 : e(e)
185 {
186 retlist = rettype;
187
188 std::ostringstream argl;
189
190 va_list ap;
191 va_start (ap, rettype);
192
193 int args = 0;
194 while ((rettype = va_arg (ap, const char *)))
195 {
196 if (args++)
197 argl << ", ";
198
199 argl << rettype << " a" << args;
200 }
201
202 va_end (ap);
203
204 arglist = argl.str ();
205 }
206
207 void funbuild::header (const std::string &hdr)
208 {
209 hdrlist.insert (hdr);
210 }
211
212 funbuild &funbuild::operator <<(const char *src)
213 {
214 bodystream << src;
215 }
216
217 funbuild &funbuild::operator <<(const string &src)
218 {
219 bodystream << src;
220 }
221
222 fun *funbuild::get ()
223 {
224 body = bodystream.str ();
225 update_id ("f_");
226 e.register_fragment (*this);
227
228 return new fun (e, id);
229 }
230
231 /////////////////////////////////////////////////////////////////////////////
232
233 fun::fun (env &e, const funid &id)
234 : e(e), id(id), funptr(0)
235 {
236 }
237
238 void *fun::ptr ()
239 {
240 if (!funptr)
241 funptr = e.sym (id, id.c_str ());
242
243 return funptr;
244 }
245
246 /////////////////////////////////////////////////////////////////////////////
247
248 env::env (const string &path, bool temporary)
249 : path(path), temporary(temporary)
250 {
251 bool create;
252 mode_t oflags = O_RDWR | O_EXCL;
253
254 if (is_null (path))
255 {
256 temporary = true;
257 this->path = tmpnam (0);
258 }
259
260 create = mkdir (this->path.c_str (), 0777) == 0;
261
262 if (!create && temporary)
263 FATAL ("error while creating libcpjit temporary directory" << ERRNO);
264
265 idxpath = this->path + "/libcpjit.idx";
266 idxfd = open (idxpath.c_str (), O_RDWR | (create ? O_CREAT | O_EXCL : 0), 0666);
267 if (idxfd < 0)
268 FATAL (path << ": unable to open index file " << idxpath);
269
270 lock ();
271
272 if (create)
273 {
274 idxstamp = get_stamp (idxfd) - 1;
275 nextid = 0;
276 save_index ();
277 }
278
279 load_index ();
280 unlock ();
281 compact ();
282 }
283
284 env::~env ()
285 {
286 if (temporary)
287 clear ();
288 }
289
290 void env::clear ()
291 {
292 DIR *dir = opendir (path.c_str ());
293
294 if (dir)
295 {
296 struct dirent *de;
297 while ((de = readdir (dir)))
298 {
299 if (de->d_name [0] == '.')
300 continue;
301
302 string f = path + "/" + de->d_name;
303 unlink (f.c_str ());
304 }
305
306 closedir (dir);
307 }
308
309 if (rmdir (path.c_str ()))
310 FATAL (path << ": unable to remove libcpjit directory" << ERRNO);
311 }
312
313 void env::dolock (bool lock)
314 {
315 struct flock fl;
316
317 fl.l_type = lock ? F_WRLCK : F_UNLCK;
318 fl.l_whence = SEEK_SET;
319 fl.l_start = 0;
320 fl.l_len = 0;
321
322 while (fcntl (idxfd, F_SETLKW, &fl) < 0)
323 if (errno != EINTR)
324 FATAL (path << ": unable to lock index file" << ERRNO);
325 }
326
327 void env::lock ()
328 {
329 dolock (true);
330 }
331
332 void env::unlock ()
333 {
334 dolock (false);
335 }
336
337 bool
338 env::load_index ()
339 {
340 // caller must lock()
341
342 long stamp = get_stamp (idxfd);
343
344 if (stamp == idxstamp)
345 return false;
346
347 idxstamp = stamp;
348
349 fstream f (idxpath.c_str (), ios::in);
350
351 if (!f)
352 FATAL (idxpath << ": unable to read index" << ERRNO);
353
354 f >> nextid;
355
356 if (nextid != IDX_VERSION)
357 FATAL (idxpath << ": index file corrupted");
358
359 f >> nextid;
360
361 id2file.clear ();
362
363 while (f)
364 {
365 string id; f >> id;
366
367 if (id == "-")
368 break;
369
370 string fileid; f >> fileid;
371
372 id2file [id] = fileid;
373
374 }
375
376 string end; f >> end;
377
378 if (end != "__end__" || !f)
379 FATAL (idxpath << ": index file corrupted");
380
381 f.close ();
382
383 return true;
384 }
385
386 void
387 env::save_index ()
388 {
389 // caller must lock()+load_index()
390
391 std::fstream f (idxpath.c_str ());
392
393 if (!f)
394 FATAL (idxpath << ": unable to write index" << ERRNO);
395
396 f << IDX_VERSION << "\n"
397 << nextid << "\n";
398
399 for (map<string, string>::const_iterator i = id2file.begin ();
400 i != id2file.end ();
401 ++i)
402 f << (*i).first << " " << (*i).second << "\n";
403
404 f << "-\n";
405 f << "__end__\n";
406
407 f.close ();
408
409 set_stamp (idxpath, ++idxstamp);
410 }
411
412 void
413 env::compact ()
414 {
415 lock ();
416 save_index ();
417 unlock ();
418 }
419
420 void env::register_fragment (const funsrc &fragment)
421 {
422 fragments.push_back (fragment);
423 }
424
425 void *env::dlsym (const string &id, const char *symbol)
426 {
427 assert (id2file.find (id) != id2file.end ());
428
429 const string &fileid = id2file [id];
430
431 void *so;
432
433 // load so
434 if (file2so.find (fileid) == file2so.end ())
435 {
436 string sopath = path + "/" + fileid + ".so";
437
438 so = dlopen (sopath.c_str (), RTLD_LAZY | RTLD_GLOBAL);
439 if (!so)
440 FATAL (sopath << ": so file should be there but isn't" << ERRNO);
441 }
442 else
443 so = file2so [fileid];
444
445 return ::dlsym (so, symbol);
446 }
447
448 void *env::sym (const string &id, const char *symbol)
449 {
450 // not yet compiled?
451 if (id2file.find (id) == id2file.end ())
452 {
453 lock ();
454
455 // nobody else compiled it?
456 if (!load_index () || id2file.find (id) == id2file.end ())
457 {
458 ostringstream sfile;
459 sfile << nextid++;
460 string fileid = sfile.str ();
461 string base = path + "/" + fileid;
462
463 string fc = base + ".c";
464 string fo = base + ".o";
465 string fso = base + ".so";
466
467 std::ofstream f (fc.c_str ());
468 set<string> hdrs;
469
470 for (vector<funsrc>::const_iterator i = fragments.begin ();
471 i != fragments.end ();
472 ++i)
473 if (id2file.find (i->id) == id2file.end ())
474 {
475 f << "#line 1 \"" << i->id << "-hdrlist\"\n";
476
477 for (set<string>::const_iterator j = i->hdrlist.begin ();
478 j != i->hdrlist.end ();
479 ++j)
480 f << *j << "\n";
481
482 f << "#line 1 \"" << i->id << "-body\"\n"
483 << i->retlist << " " << i->id << " (" << i->arglist << ")\n"
484 << "{\n"
485 << i->body
486 << "\n}\n";
487
488 id2file [i->id] = fileid;
489 }
490
491 f.close ();
492 fragments.clear ();
493
494 system ((CC " " CFLAGS " -o " + fo + " " + fc).c_str ());
495 unlink (fc.c_str ());
496 system ((LD " " LFLAGS " -o " + fso + " " + fo).c_str ());
497
498 save_index ();
499 }
500
501 unlock ();
502 }
503
504 void *p = dlsym (id, symbol);
505
506 if (!p)
507 {
508 lock ();
509 load_index ();
510 unlock ();
511 p = dlsym (id, symbol);
512 }
513
514 if (!p)
515 FATAL ("symbol " << id << ":" << symbol << " not where it should be");
516
517 return p;
518 }
519
520 }