ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/libcpjit/cpjit.C
Revision: 1.10
Committed: Fri Oct 14 23:40:24 2005 UTC (18 years, 9 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.9: +187 -50 lines
Log Message:
*** empty log message ***

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.5 digest ();
90 root 1.10 void operator ()(const string &data);
91     operator string();
92 root 1.4 };
93    
94 root 1.5 digest::digest ()
95 root 1.4 {
96 root 1.5 md5_init_ctx (this);
97     }
98 root 1.4
99 root 1.10 void digest::operator ()(const string &data)
100 root 1.5 {
101     md5_process_bytes (data.c_str (), data.size (), this);
102 root 1.4 }
103    
104 root 1.10 digest::operator string ()
105 root 1.4 {
106 root 1.5 unsigned char data[16];
107 root 1.4 std::ostringstream s;
108    
109 root 1.5 md5_finish_ctx (this, data);
110    
111     for (int i = 0; i < 16; i++)
112 root 1.4 s << std::setfill ('0') << std::hex << std::setw (2) << (int)data [i];
113    
114     return s.str ();
115     }
116 root 1.1
117 root 1.8 /////////////////////////////////////////////////////////////////////////////
118    
119 root 1.2 static inline bool
120 root 1.10 is_null (const string &s)
121 root 1.2 {
122     return s.empty ();
123     }
124    
125 root 1.8 /////////////////////////////////////////////////////////////////////////////
126    
127 root 1.4 // error exception builder
128     struct error : std::ostringstream
129     {
130     ~error ()
131     {
132     throw std::runtime_error (str ());
133     }
134     };
135    
136     #define FATAL(msg) do { error o; o << msg << std::endl; } while (0)
137     #define ERRNO " (" << strerror (errno) << ")"
138    
139 root 1.8 /////////////////////////////////////////////////////////////////////////////
140    
141     static long get_stamp (int fd)
142     {
143     struct stat st;
144    
145     if (fstat (fd, &st))
146     FATAL ("could not get file stamp");
147    
148     return (long)st.st_mtime;
149     }
150    
151 root 1.10 static void set_stamp (const string &path, long stamp)
152 root 1.8 {
153     struct utimbuf ut;
154    
155     ut.actime = stamp;
156     ut.modtime = stamp;
157    
158     if (utime (path.c_str (), &ut))
159     FATAL ("could not set file stamp");
160     }
161    
162 root 1.10 env::env (const string &path, bool temporary)
163 root 1.2 : path(path), temporary(temporary)
164     {
165 root 1.10 bool create;
166 root 1.6 mode_t oflags = O_RDWR | O_EXCL;
167    
168 root 1.2 if (is_null (path))
169     {
170 root 1.10 temporary = true;
171 root 1.2 this->path = tmpnam (0);
172 root 1.10 }
173 root 1.2
174 root 1.10 create = mkdir (this->path.c_str (), 0777) == 0;
175 root 1.2
176 root 1.10 if (!create && temporary)
177     FATAL ("error while creating libcpjit temporary directory" << ERRNO);
178 root 1.6
179 root 1.8 idxpath = this->path + "/libcpjit.idx";
180 root 1.10 idxfd = open (idxpath.c_str (), O_RDWR | (create ? O_CREAT | O_EXCL : 0), 0666);
181 root 1.4 if (idxfd < 0)
182 root 1.10 FATAL (path << ": unable to open index file " << idxpath);
183 root 1.4
184     lock ();
185 root 1.10
186     if (create)
187     {
188     idxstamp = get_stamp (idxfd) - 1;
189     nextid = 0;
190     save_index ();
191     }
192    
193 root 1.4 load_index ();
194 root 1.10 unlock ();
195 root 1.9 compact ();
196 root 1.2 }
197    
198     env::~env ()
199     {
200     if (temporary)
201 root 1.5 clear ();
202     }
203    
204     void env::clear ()
205     {
206     DIR *dir = opendir (path.c_str ());
207    
208     if (dir)
209 root 1.2 {
210 root 1.5 struct dirent *de;
211     while ((de = readdir (dir)))
212 root 1.2 {
213 root 1.5 if (de->d_name [0] == '.')
214     continue;
215 root 1.2
216 root 1.10 string f = path + "/" + de->d_name;
217 root 1.5 unlink (f.c_str ());
218 root 1.2 }
219    
220 root 1.5 closedir (dir);
221 root 1.2 }
222 root 1.5
223     if (rmdir (path.c_str ()))
224     FATAL (path << ": unable to remove libcpjit directory" << ERRNO);
225 root 1.2 }
226    
227 root 1.4 void env::dolock (bool lock)
228     {
229     struct flock fl;
230    
231     fl.l_type = lock ? F_WRLCK : F_UNLCK;
232     fl.l_whence = SEEK_SET;
233     fl.l_start = 0;
234     fl.l_len = 0;
235    
236     while (fcntl (idxfd, F_SETLKW, &fl) < 0)
237     if (errno != EINTR)
238     FATAL (path << ": unable to lock index file" << ERRNO);
239     }
240    
241     void env::lock ()
242     {
243     dolock (true);
244     }
245    
246     void env::unlock ()
247     {
248     dolock (false);
249     }
250    
251 root 1.10 bool
252 root 1.4 env::load_index ()
253     {
254 root 1.8 // caller must lock()
255    
256     long stamp = get_stamp (idxfd);
257    
258     if (stamp == idxstamp)
259 root 1.10 return false;
260 root 1.8
261     idxstamp = stamp;
262    
263 root 1.10 fstream f (idxpath.c_str (), ios::in);
264    
265     if (!f)
266     FATAL (idxpath << ": unable to read index" << ERRNO);
267    
268     f >> nextid;
269    
270     if (nextid != IDX_VERSION)
271     FATAL (idxpath << ": index file corrupted");
272    
273     f >> nextid;
274    
275     id2file.clear ();
276    
277     while (f)
278     {
279     string id; f >> id;
280    
281     if (id == "-")
282     break;
283    
284     string fileid; f >> fileid;
285    
286     id2file [id] = fileid;
287    
288     }
289    
290     string end; f >> end;
291    
292     if (end != "__end__" || !f)
293     FATAL (idxpath << ": index file corrupted");
294    
295     f.close ();
296    
297     return true;
298 root 1.4 }
299    
300 root 1.5 void
301     env::save_index ()
302 root 1.2 {
303 root 1.8 // caller must lock()+load_index()
304    
305 root 1.10 std::fstream f (idxpath.c_str ());
306    
307     if (!f)
308     FATAL (idxpath << ": unable to write index" << ERRNO);
309    
310     f << IDX_VERSION << "\n"
311     << nextid << "\n";
312    
313     for (map<string, string>::const_iterator i = id2file.begin ();
314     i != id2file.end ();
315     ++i)
316     f << (*i).first << " " << (*i).second << "\n";
317    
318     f << "-\n";
319     f << "__end__\n";
320    
321     f.close ();
322    
323 root 1.8 set_stamp (idxpath, ++idxstamp);
324 root 1.2 }
325    
326 root 1.9 void
327     env::compact ()
328     {
329 root 1.10 lock ();
330     save_index ();
331     unlock ();
332 root 1.9 }
333    
334 root 1.10 void env::register_fragment (const string &id, const string &source)
335     {
336     fragments.push_back (pair<string, string> (id, source));
337     }
338 root 1.8
339 root 1.10 void *env::dlsym (const string &id, const char *symbol)
340 root 1.3 {
341 root 1.10 assert (id2file.find (id) != id2file.end ());
342    
343     const string &fileid = id2file [id];
344    
345     void *so;
346    
347     // load so
348     if (file2so.find (fileid) == file2so.end ())
349     {
350     string sopath = path + "/" + fileid + ".so";
351    
352     so = dlopen (sopath.c_str (), RTLD_LAZY | RTLD_GLOBAL);
353     if (!so)
354     FATAL (sopath << ": so file should be there but isn't" << ERRNO);
355     }
356     else
357     so = file2so [fileid];
358    
359     return ::dlsym (so, symbol);
360 root 1.3 }
361    
362 root 1.10 void *env::sym (const string &id, const char *symbol)
363 root 1.1 {
364 root 1.10 // not yet compiled?
365     if (id2file.find (id) == id2file.end ())
366 root 1.2 {
367 root 1.10 lock ();
368    
369     // nobody else compiled it?
370     if (!load_index () || id2file.find (id) == id2file.end ())
371     {
372     ostringstream sfile;
373     sfile << nextid++;
374     string fileid = sfile.str ();
375     string base = path + "/" + fileid;
376    
377     string fc = base + ".c";
378     string fo = base + ".o";
379     string fso = base + ".so";
380    
381     std::ofstream f (fc.c_str ());
382 root 1.5
383 root 1.10 for (vector< pair<string, string> >::const_iterator i = fragments.begin ();
384     i != fragments.end ();
385     ++i)
386     if (id2file.find ((*i).first) == id2file.end ())
387     {
388     f << "#line 1 \"" << (*i).first << "\"\n"
389     << (*i).second << "\n";
390 root 1.4
391 root 1.10 id2file [(*i).first] = fileid;
392     }
393    
394     f.close ();
395 root 1.2
396 root 1.10 fragments.clear ();
397 root 1.2
398 root 1.10 system (("gcc -O6 -c -o " + fo + " " + fc).c_str ());
399 root 1.2
400 root 1.10 //unlink (fc.c_str ());
401 root 1.2
402 root 1.10 system (("gcc -O6 -nostdlib -lgcc -shared -o " + fso + " " + fo).c_str ());
403 root 1.2
404 root 1.10 printf ("%s\n", fso.c_str ());
405 root 1.4
406 root 1.10 #if 0
407     void *so = dlopen (fso.c_str (), RTLD_LAZY);
408     assert (so);
409 root 1.2
410 root 1.10 funptr = dlsym (so, id.c_str ());
411     assert (funptr);
412     #endif
413 root 1.5
414 root 1.10 save_index ();
415     }
416    
417     unlock ();
418 root 1.2 }
419    
420 root 1.10 void *p = dlsym (id, symbol);
421    
422     if (!p)
423     {
424     lock ();
425     load_index ();
426     unlock ();
427     p = dlsym (id, symbol);
428     }
429    
430     if (!p)
431     FATAL ("symbol " << id << ":" << symbol << " not where it should be");
432    
433     return p;
434     }
435    
436     /////////////////////////////////////////////////////////////////////////////
437    
438     fun::fun (env &e, const string &id, const string &source)
439     : e(e), id(id), funptr(0)
440     {
441     e.register_fragment (id, source);
442     }
443    
444     void *fun::ptr ()
445     {
446     if (!funptr)
447     funptr = e.sym (id, id.c_str ());
448    
449 root 1.2 return funptr;
450 root 1.1 }
451    
452 root 1.8 /////////////////////////////////////////////////////////////////////////////
453    
454 root 1.5 funbuild::funbuild (env &e, const char *rettype, ...)
455     : e(e)
456 root 1.1 {
457 root 1.5 retlist = rettype;
458 root 1.3
459 root 1.5 std::ostringstream argl;
460 root 1.1
461     va_list ap;
462     va_start (ap, rettype);
463    
464     int args = 0;
465     while ((rettype = va_arg (ap, const char *)))
466     {
467     if (args++)
468 root 1.5 argl << ", ";
469 root 1.1
470 root 1.5 argl << rettype << " a" << args;
471 root 1.1 }
472    
473     va_end (ap);
474    
475 root 1.5 arglist = argl.str ();
476 root 1.1 }
477    
478 root 1.5 void
479 root 1.10 funbuild::finish (string &id, string &source)
480 root 1.1 {
481 root 1.5 digest dgst;
482    
483     dgst (retlist);
484     dgst (arglist);
485     dgst (str ());
486    
487 root 1.10 id = "f_" + (string) dgst;
488 root 1.3
489 root 1.5 std::ostringstream o;
490     o << retlist << " " << id << " (" << arglist << ")\n{\n" << str () << "\n}\n";
491     source = o.str ();
492 root 1.1 }
493    
494     }