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