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

# 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 <sstream>
34 #include <fstream>
35 #include <stdexcept>
36 #include <iomanip>
37
38 #include <unistd.h>
39 #include <fcntl.h> // for locking
40
41 #include <sys/stat.h>
42 #include <sys/types.h>
43 #include <dirent.h>
44 #include <utime.h>
45
46 #include "md5.h"
47
48 #include <dlfcn.h>
49
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 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 const char typestr<FLT >::str[] = "float";
65 const char typestr<DBL >::str[] = "double";
66
67 const char typestr<PTR >::str[] = "void" " *";
68
69 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 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 const char typestr<FLT *>::str[] = "float" " *";
78 const char typestr<DBL *>::str[] = "double" " *";
79
80 /////////////////////////////////////////////////////////////////////////////
81
82 struct digest : md5_ctx
83 {
84 digest ();
85 void operator ()(const std::string &data);
86 operator std::string();
87 };
88
89 digest::digest ()
90 {
91 md5_init_ctx (this);
92 }
93
94 void digest::operator ()(const std::string &data)
95 {
96 md5_process_bytes (data.c_str (), data.size (), this);
97 }
98
99 digest::operator std::string ()
100 {
101 unsigned char data[16];
102 std::ostringstream s;
103
104 md5_finish_ctx (this, data);
105
106 for (int i = 0; i < 16; i++)
107 s << std::setfill ('0') << std::hex << std::setw (2) << (int)data [i];
108
109 return s.str ();
110 }
111
112 /////////////////////////////////////////////////////////////////////////////
113
114 static inline bool
115 is_null (const std::string &s)
116 {
117 return s.empty ();
118 }
119
120 /////////////////////////////////////////////////////////////////////////////
121
122 // 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 /////////////////////////////////////////////////////////////////////////////
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 env::env (const std::string &path, bool temporary)
158 : path(path), temporary(temporary)
159 {
160 mode_t oflags = O_RDWR | O_EXCL;
161
162 if (is_null (path))
163 {
164 this->path = tmpnam (0);
165
166 temporary = true;
167 }
168
169 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 idxpath = this->path + "/libcpjit.idx";
176 idxfd = open (idxpath.c_str (), oflags, 0666);
177 if (idxfd < 0)
178 FATAL (path << ": unable to open index file" << idxpath);
179
180 lock ();
181 load_index ();
182 compact ();
183 unlock ();
184 }
185
186 env::~env ()
187 {
188 if (temporary)
189 clear ();
190 }
191
192 void env::clear ()
193 {
194 DIR *dir = opendir (path.c_str ());
195
196 if (dir)
197 {
198 struct dirent *de;
199 while ((de = readdir (dir)))
200 {
201 if (de->d_name [0] == '.')
202 continue;
203
204 std::string f = path + "/" + de->d_name;
205 unlink (f.c_str ());
206 }
207
208 closedir (dir);
209 }
210
211 if (rmdir (path.c_str ()))
212 FATAL (path << ": unable to remove libcpjit directory" << ERRNO);
213 }
214
215 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 // 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 }
254
255 void
256 env::save_index ()
257 {
258 // caller must lock()+load_index()
259
260 // ... TODO
261 set_stamp (idxpath, ++idxstamp);
262 }
263
264 void
265 env::compact ()
266 {
267 }
268
269 /////////////////////////////////////////////////////////////////////////////
270
271 fun::fun (env &e, const std::string &id, const std::string &source)
272 : e(e), id(id), source(source), funptr(0)
273 {
274 }
275
276 void *fun::ptr ()
277 {
278 if (!funptr)
279 {
280 e.lock ();
281 e.load_index ();
282
283 std::string base = e.path + "/" + id;
284
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
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 printf ("%s\n", fso.c_str ());
301
302 void *so = dlopen (fso.c_str (), RTLD_LAZY);
303 assert (so);
304
305 funptr = dlsym (so, id.c_str ());
306 assert (funptr);
307
308 e.save_index ();
309 e.unlock ();
310 }
311
312 return funptr;
313 }
314
315 /////////////////////////////////////////////////////////////////////////////
316
317 funbuild::funbuild (env &e, const char *rettype, ...)
318 : e(e)
319 {
320 retlist = rettype;
321
322 std::ostringstream argl;
323
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 argl << ", ";
332
333 argl << rettype << " a" << args;
334 }
335
336 va_end (ap);
337
338 arglist = argl.str ();
339 }
340
341 void
342 funbuild::finish (std::string &id, std::string &source)
343 {
344 digest dgst;
345
346 dgst (retlist);
347 dgst (arglist);
348 dgst (str ());
349
350 id = "f_" + (std::string) dgst;
351
352 std::ostringstream o;
353 o << retlist << " " << id << " (" << arglist << ")\n{\n" << str () << "\n}\n";
354 source = o.str ();
355 }
356
357 }