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, 11 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

# User Rev Content
1 root 1.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 root 1.2 #include <cassert>
27     #include <cstdlib>
28 root 1.1 #include <cstdarg>
29 root 1.2 #include <cstdio>
30 root 1.4 #include <cstring>
31     #include <cerrno>
32    
33 root 1.10 #include <iostream>
34 root 1.1 #include <sstream>
35 root 1.2 #include <fstream>
36 root 1.4 #include <stdexcept>
37     #include <iomanip>
38    
39     #include <unistd.h>
40     #include <fcntl.h> // for locking
41 root 1.2
42     #include <sys/stat.h>
43     #include <sys/types.h>
44     #include <dirent.h>
45 root 1.8 #include <utime.h>
46 root 1.2
47 root 1.4 #include "md5.h"
48    
49 root 1.2 #include <dlfcn.h>
50 root 1.1
51     #define STR_(str) #str
52     #define STR(str) STR_(str)
53    
54 root 1.10 #define IDX_VERSION 1
55    
56 root 1.1 namespace cpjit
57     {
58    
59 root 1.10 using namespace std;
60    
61 root 1.1 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 root 1.2 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 root 1.4 const char typestr<FLT >::str[] = "float";
70     const char typestr<DBL >::str[] = "double";
71 root 1.1
72 root 1.2 const char typestr<PTR >::str[] = "void" " *";
73    
74 root 1.1 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 root 1.2 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 root 1.4 const char typestr<FLT *>::str[] = "float" " *";
83     const char typestr<DBL *>::str[] = "double" " *";
84    
85 root 1.8 /////////////////////////////////////////////////////////////////////////////
86    
87 root 1.5 struct digest : md5_ctx
88 root 1.4 {
89 root 1.12 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 root 1.10 operator string();
101 root 1.4 };
102    
103 root 1.10 digest::operator string ()
104 root 1.4 {
105 root 1.5 unsigned char data[16];
106 root 1.4 std::ostringstream s;
107    
108 root 1.5 md5_finish_ctx (this, data);
109    
110     for (int i = 0; i < 16; i++)
111 root 1.4 s << std::setfill ('0') << std::hex << std::setw (2) << (int)data [i];
112    
113     return s.str ();
114     }
115 root 1.1
116 root 1.8 /////////////////////////////////////////////////////////////////////////////
117    
118 root 1.2 static inline bool
119 root 1.10 is_null (const string &s)
120 root 1.2 {
121     return s.empty ();
122     }
123    
124 root 1.8 /////////////////////////////////////////////////////////////////////////////
125    
126 root 1.4 // 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 root 1.8 /////////////////////////////////////////////////////////////////////////////
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 root 1.10 static void set_stamp (const string &path, long stamp)
151 root 1.8 {
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 root 1.12 /////////////////////////////////////////////////////////////////////////////
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 root 1.10 env::env (const string &path, bool temporary)
249 root 1.2 : path(path), temporary(temporary)
250     {
251 root 1.10 bool create;
252 root 1.6 mode_t oflags = O_RDWR | O_EXCL;
253    
254 root 1.2 if (is_null (path))
255     {
256 root 1.10 temporary = true;
257 root 1.2 this->path = tmpnam (0);
258 root 1.10 }
259 root 1.2
260 root 1.10 create = mkdir (this->path.c_str (), 0777) == 0;
261 root 1.2
262 root 1.10 if (!create && temporary)
263     FATAL ("error while creating libcpjit temporary directory" << ERRNO);
264 root 1.6
265 root 1.8 idxpath = this->path + "/libcpjit.idx";
266 root 1.10 idxfd = open (idxpath.c_str (), O_RDWR | (create ? O_CREAT | O_EXCL : 0), 0666);
267 root 1.4 if (idxfd < 0)
268 root 1.10 FATAL (path << ": unable to open index file " << idxpath);
269 root 1.4
270     lock ();
271 root 1.10
272     if (create)
273     {
274     idxstamp = get_stamp (idxfd) - 1;
275     nextid = 0;
276     save_index ();
277     }
278    
279 root 1.4 load_index ();
280 root 1.10 unlock ();
281 root 1.9 compact ();
282 root 1.2 }
283    
284     env::~env ()
285     {
286     if (temporary)
287 root 1.5 clear ();
288     }
289    
290     void env::clear ()
291     {
292     DIR *dir = opendir (path.c_str ());
293    
294     if (dir)
295 root 1.2 {
296 root 1.5 struct dirent *de;
297     while ((de = readdir (dir)))
298 root 1.2 {
299 root 1.5 if (de->d_name [0] == '.')
300     continue;
301 root 1.2
302 root 1.10 string f = path + "/" + de->d_name;
303 root 1.5 unlink (f.c_str ());
304 root 1.2 }
305    
306 root 1.5 closedir (dir);
307 root 1.2 }
308 root 1.5
309     if (rmdir (path.c_str ()))
310     FATAL (path << ": unable to remove libcpjit directory" << ERRNO);
311 root 1.2 }
312    
313 root 1.4 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 root 1.10 bool
338 root 1.4 env::load_index ()
339     {
340 root 1.8 // caller must lock()
341    
342     long stamp = get_stamp (idxfd);
343    
344     if (stamp == idxstamp)
345 root 1.10 return false;
346 root 1.8
347     idxstamp = stamp;
348    
349 root 1.10 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 root 1.4 }
385    
386 root 1.5 void
387     env::save_index ()
388 root 1.2 {
389 root 1.8 // caller must lock()+load_index()
390    
391 root 1.10 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 root 1.8 set_stamp (idxpath, ++idxstamp);
410 root 1.2 }
411    
412 root 1.9 void
413     env::compact ()
414     {
415 root 1.10 lock ();
416     save_index ();
417     unlock ();
418 root 1.9 }
419    
420 root 1.12 void env::register_fragment (const funsrc &fragment)
421 root 1.10 {
422 root 1.12 fragments.push_back (fragment);
423 root 1.10 }
424 root 1.8
425 root 1.10 void *env::dlsym (const string &id, const char *symbol)
426 root 1.3 {
427 root 1.10 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 root 1.3 }
447    
448 root 1.10 void *env::sym (const string &id, const char *symbol)
449 root 1.1 {
450 root 1.10 // not yet compiled?
451     if (id2file.find (id) == id2file.end ())
452 root 1.2 {
453 root 1.10 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 root 1.12 set<string> hdrs;
469 root 1.5
470 root 1.12 for (vector<funsrc>::const_iterator i = fragments.begin ();
471 root 1.10 i != fragments.end ();
472     ++i)
473 root 1.12 if (id2file.find (i->id) == id2file.end ())
474 root 1.10 {
475 root 1.12 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 root 1.4
488 root 1.12 id2file [i->id] = fileid;
489 root 1.10 }
490    
491     f.close ();
492     fragments.clear ();
493 root 1.2
494 root 1.11 system ((CC " " CFLAGS " -o " + fo + " " + fc).c_str ());
495     unlink (fc.c_str ());
496     system ((LD " " LFLAGS " -o " + fso + " " + fo).c_str ());
497 root 1.5
498 root 1.10 save_index ();
499     }
500    
501     unlock ();
502 root 1.2 }
503    
504 root 1.10 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 root 1.1 }