ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/libcpjit/cpjit.C
Revision: 1.9
Committed: Fri Oct 14 02:34:13 2005 UTC (18 years, 9 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.8: +6 -0 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.1 #include <sstream>
34 root 1.2 #include <fstream>
35 root 1.4 #include <stdexcept>
36     #include <iomanip>
37    
38     #include <unistd.h>
39     #include <fcntl.h> // for locking
40 root 1.2
41     #include <sys/stat.h>
42     #include <sys/types.h>
43     #include <dirent.h>
44 root 1.8 #include <utime.h>
45 root 1.2
46 root 1.4 #include "md5.h"
47    
48 root 1.2 #include <dlfcn.h>
49 root 1.1
50     #define STR_(str) #str
51     #define STR(str) STR_(str)
52    
53     namespace cpjit
54     {
55    
56     const char typestr<U8 >::str[] = "unsigned " STR(TYPE_INT8);
57     const char typestr<U16 >::str[] = "unsigned " STR(TYPE_INT16);
58     const char typestr<U32 >::str[] = "unsigned " STR(TYPE_INT32);
59     const char typestr<U64 >::str[] = "unsigned " STR(TYPE_INT64);
60 root 1.2 const char typestr<I8 >::str[] = "signed " STR(TYPE_INT8);
61     const char typestr<I16 >::str[] = STR(TYPE_INT16);
62     const char typestr<I32 >::str[] = STR(TYPE_INT32);
63     const char typestr<I64 >::str[] = STR(TYPE_INT64);
64 root 1.4 const char typestr<FLT >::str[] = "float";
65     const char typestr<DBL >::str[] = "double";
66 root 1.1
67 root 1.2 const char typestr<PTR >::str[] = "void" " *";
68    
69 root 1.1 const char typestr<U8 *>::str[] = "unsigned " STR(TYPE_INT8) " *";
70     const char typestr<U16 *>::str[] = "unsigned " STR(TYPE_INT16) " *";
71     const char typestr<U32 *>::str[] = "unsigned " STR(TYPE_INT32) " *";
72     const char typestr<U64 *>::str[] = "unsigned " STR(TYPE_INT64) " *";
73 root 1.2 const char typestr<I8 *>::str[] = "signed " STR(TYPE_INT8) " *";
74     const char typestr<I16 *>::str[] = STR(TYPE_INT16) " *";
75     const char typestr<I32 *>::str[] = STR(TYPE_INT32) " *";
76     const char typestr<I64 *>::str[] = STR(TYPE_INT64) " *";
77 root 1.4 const char typestr<FLT *>::str[] = "float" " *";
78     const char typestr<DBL *>::str[] = "double" " *";
79    
80 root 1.8 /////////////////////////////////////////////////////////////////////////////
81    
82 root 1.5 struct digest : md5_ctx
83 root 1.4 {
84 root 1.5 digest ();
85     void operator ()(const std::string &data);
86 root 1.4 operator std::string();
87     };
88    
89 root 1.5 digest::digest ()
90 root 1.4 {
91 root 1.5 md5_init_ctx (this);
92     }
93 root 1.4
94 root 1.5 void digest::operator ()(const std::string &data)
95     {
96     md5_process_bytes (data.c_str (), data.size (), this);
97 root 1.4 }
98    
99     digest::operator std::string ()
100     {
101 root 1.5 unsigned char data[16];
102 root 1.4 std::ostringstream s;
103    
104 root 1.5 md5_finish_ctx (this, data);
105    
106     for (int i = 0; i < 16; i++)
107 root 1.4 s << std::setfill ('0') << std::hex << std::setw (2) << (int)data [i];
108    
109     return s.str ();
110     }
111 root 1.1
112 root 1.8 /////////////////////////////////////////////////////////////////////////////
113    
114 root 1.2 static inline bool
115     is_null (const std::string &s)
116     {
117     return s.empty ();
118     }
119    
120 root 1.8 /////////////////////////////////////////////////////////////////////////////
121    
122 root 1.4 // error exception builder
123     struct error : std::ostringstream
124     {
125     ~error ()
126     {
127     throw std::runtime_error (str ());
128     }
129     };
130    
131     #define FATAL(msg) do { error o; o << msg << std::endl; } while (0)
132     #define ERRNO " (" << strerror (errno) << ")"
133    
134 root 1.8 /////////////////////////////////////////////////////////////////////////////
135    
136     static long get_stamp (int fd)
137     {
138     struct stat st;
139    
140     if (fstat (fd, &st))
141     FATAL ("could not get file stamp");
142    
143     return (long)st.st_mtime;
144     }
145    
146     static void set_stamp (const std::string &path, long stamp)
147     {
148     struct utimbuf ut;
149    
150     ut.actime = stamp;
151     ut.modtime = stamp;
152    
153     if (utime (path.c_str (), &ut))
154     FATAL ("could not set file stamp");
155     }
156    
157 root 1.2 env::env (const std::string &path, bool temporary)
158     : path(path), temporary(temporary)
159     {
160 root 1.6 mode_t oflags = O_RDWR | O_EXCL;
161    
162 root 1.2 if (is_null (path))
163     {
164     this->path = tmpnam (0);
165    
166     temporary = true;
167     }
168    
169 root 1.6 if (mkdir (this->path.c_str (), 0777) == 0)
170     oflags |= O_CREAT;
171     else
172     if (temporary)
173     FATAL ("error while creating libcpjit temporary directory" << ERRNO);
174    
175 root 1.8 idxpath = this->path + "/libcpjit.idx";
176     idxfd = open (idxpath.c_str (), oflags, 0666);
177 root 1.4 if (idxfd < 0)
178 root 1.8 FATAL (path << ": unable to open index file" << idxpath);
179 root 1.4
180     lock ();
181     load_index ();
182 root 1.9 compact ();
183 root 1.4 unlock ();
184 root 1.2 }
185    
186     env::~env ()
187     {
188     if (temporary)
189 root 1.5 clear ();
190     }
191    
192     void env::clear ()
193     {
194     DIR *dir = opendir (path.c_str ());
195    
196     if (dir)
197 root 1.2 {
198 root 1.5 struct dirent *de;
199     while ((de = readdir (dir)))
200 root 1.2 {
201 root 1.5 if (de->d_name [0] == '.')
202     continue;
203 root 1.2
204 root 1.5 std::string f = path + "/" + de->d_name;
205     unlink (f.c_str ());
206 root 1.2 }
207    
208 root 1.5 closedir (dir);
209 root 1.2 }
210 root 1.5
211     if (rmdir (path.c_str ()))
212     FATAL (path << ": unable to remove libcpjit directory" << ERRNO);
213 root 1.2 }
214    
215 root 1.4 void env::dolock (bool lock)
216     {
217     struct flock fl;
218    
219     fl.l_type = lock ? F_WRLCK : F_UNLCK;
220     fl.l_whence = SEEK_SET;
221     fl.l_start = 0;
222     fl.l_len = 0;
223    
224     while (fcntl (idxfd, F_SETLKW, &fl) < 0)
225     if (errno != EINTR)
226     FATAL (path << ": unable to lock index file" << ERRNO);
227     }
228    
229     void env::lock ()
230     {
231     dolock (true);
232     }
233    
234     void env::unlock ()
235     {
236     dolock (false);
237     }
238    
239     void
240     env::load_index ()
241     {
242 root 1.8 // caller must lock()
243    
244     long stamp = get_stamp (idxfd);
245    
246     if (stamp == idxstamp)
247     return;
248    
249     idxstamp = stamp;
250    
251     // ... TODO
252    
253 root 1.4 }
254    
255 root 1.5 void
256     env::save_index ()
257 root 1.2 {
258 root 1.8 // caller must lock()+load_index()
259    
260     // ... TODO
261     set_stamp (idxpath, ++idxstamp);
262 root 1.2 }
263    
264 root 1.9 void
265     env::compact ()
266     {
267     }
268    
269 root 1.8 /////////////////////////////////////////////////////////////////////////////
270    
271 root 1.5 fun::fun (env &e, const std::string &id, const std::string &source)
272     : e(e), id(id), source(source), funptr(0)
273 root 1.3 {
274     }
275    
276 root 1.2 void *fun::ptr ()
277 root 1.1 {
278 root 1.2 if (!funptr)
279     {
280 root 1.5 e.lock ();
281     e.load_index ();
282    
283     std::string base = e.path + "/" + id;
284 root 1.4
285     std::string fc = base + ".c";
286     std::string fo = base + ".o";
287     std::string fso = base + ".so";
288     std::string fa = base + ".a";
289 root 1.2
290     std::ofstream f (fc.c_str ());
291     f << source;
292     f.close ();
293    
294     system (("gcc -O6 -c -o " + fo + " " + fc).c_str ());
295    
296     unlink (fc.c_str ());
297    
298     system (("gcc -O6 -nostdlib -lgcc -shared -o " + fso + " " + fo).c_str ());
299    
300 root 1.4 printf ("%s\n", fso.c_str ());
301    
302 root 1.2 void *so = dlopen (fso.c_str (), RTLD_LAZY);
303     assert (so);
304    
305     funptr = dlsym (so, id.c_str ());
306     assert (funptr);
307 root 1.5
308     e.save_index ();
309     e.unlock ();
310 root 1.2 }
311    
312     return funptr;
313 root 1.1 }
314    
315 root 1.8 /////////////////////////////////////////////////////////////////////////////
316    
317 root 1.5 funbuild::funbuild (env &e, const char *rettype, ...)
318     : e(e)
319 root 1.1 {
320 root 1.5 retlist = rettype;
321 root 1.3
322 root 1.5 std::ostringstream argl;
323 root 1.1
324     va_list ap;
325     va_start (ap, rettype);
326    
327     int args = 0;
328     while ((rettype = va_arg (ap, const char *)))
329     {
330     if (args++)
331 root 1.5 argl << ", ";
332 root 1.1
333 root 1.5 argl << rettype << " a" << args;
334 root 1.1 }
335    
336     va_end (ap);
337    
338 root 1.5 arglist = argl.str ();
339 root 1.1 }
340    
341 root 1.5 void
342     funbuild::finish (std::string &id, std::string &source)
343 root 1.1 {
344 root 1.5 digest dgst;
345    
346     dgst (retlist);
347     dgst (arglist);
348     dgst (str ());
349    
350     id = "f_" + (std::string) dgst;
351 root 1.3
352 root 1.5 std::ostringstream o;
353     o << retlist << " " << id << " (" << arglist << ")\n{\n" << str () << "\n}\n";
354     source = o.str ();
355 root 1.1 }
356    
357     }