ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/libcpjit/cpjit.C
Revision: 1.5
Committed: Fri Oct 14 01:29:45 2005 UTC (18 years, 9 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.4: +64 -59 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 if (is_null (path))
131 {
132 this->path = tmpnam (0);
133
134 if (mkdir (this->path.c_str (), 0777))
135 FATAL ("error while creating libcpjit temporary directory" << ERRNO);
136
137 temporary = true;
138 }
139
140 std::string index = this->path + "/libcpjit.idx";
141
142 idxfd = open (index.c_str (), O_RDWR|O_CREAT, 0666);
143
144 if (idxfd < 0)
145 FATAL (path << ": unable to open index file" << index);
146
147 lock ();
148 load_index ();
149 unlock ();
150 }
151
152 env::~env ()
153 {
154 if (temporary)
155 clear ();
156 }
157
158 void env::clear ()
159 {
160 DIR *dir = opendir (path.c_str ());
161
162 if (dir)
163 {
164 struct dirent *de;
165 while ((de = readdir (dir)))
166 {
167 if (de->d_name [0] == '.')
168 continue;
169
170 std::string f = path + "/" + de->d_name;
171 unlink (f.c_str ());
172 }
173
174 closedir (dir);
175 }
176
177 if (rmdir (path.c_str ()))
178 FATAL (path << ": unable to remove libcpjit directory" << ERRNO);
179 }
180
181 void env::dolock (bool lock)
182 {
183 struct flock fl;
184
185 fl.l_type = lock ? F_WRLCK : F_UNLCK;
186 fl.l_whence = SEEK_SET;
187 fl.l_start = 0;
188 fl.l_len = 0;
189
190 while (fcntl (idxfd, F_SETLKW, &fl) < 0)
191 if (errno != EINTR)
192 FATAL (path << ": unable to lock index file" << ERRNO);
193 }
194
195 void env::lock ()
196 {
197 dolock (true);
198 }
199
200 void env::unlock ()
201 {
202 dolock (false);
203 }
204
205 void
206 env::load_index ()
207 {
208 std::ifstream f ((this->path + "/libcpjit.idx").c_str ());
209 assert (("not a cpjit directory", f));
210 f.close ();
211 }
212
213 void
214 env::save_index ()
215 {
216 std::ifstream f ((this->path + "/libcpjit.idx").c_str ());
217 assert (("not a cpjit directory", f));
218 f.close ();
219 }
220
221 fun::fun (env &e, const std::string &id, const std::string &source)
222 : e(e), id(id), source(source), funptr(0)
223 {
224 }
225
226 void *fun::ptr ()
227 {
228 if (!funptr)
229 {
230 e.lock ();
231 e.load_index ();
232
233 std::string base = e.path + "/" + id;
234
235 std::string fc = base + ".c";
236 std::string fo = base + ".o";
237 std::string fso = base + ".so";
238 std::string fa = base + ".a";
239
240 std::ofstream f (fc.c_str ());
241 f << source;
242 f.close ();
243
244 system (("gcc -O6 -c -o " + fo + " " + fc).c_str ());
245
246 unlink (fc.c_str ());
247
248 system (("gcc -O6 -nostdlib -lgcc -shared -o " + fso + " " + fo).c_str ());
249
250 printf ("%s\n", fso.c_str ());
251
252 void *so = dlopen (fso.c_str (), RTLD_LAZY);
253 assert (so);
254
255 funptr = dlsym (so, id.c_str ());
256 assert (funptr);
257
258 e.save_index ();
259 e.unlock ();
260 }
261
262 return funptr;
263 }
264
265 funbuild::funbuild (env &e, const char *rettype, ...)
266 : e(e)
267 {
268 retlist = rettype;
269
270 std::ostringstream argl;
271
272 va_list ap;
273 va_start (ap, rettype);
274
275 int args = 0;
276 while ((rettype = va_arg (ap, const char *)))
277 {
278 if (args++)
279 argl << ", ";
280
281 argl << rettype << " a" << args;
282 }
283
284 va_end (ap);
285
286 arglist = argl.str ();
287 }
288
289 void
290 funbuild::finish (std::string &id, std::string &source)
291 {
292 digest dgst;
293
294 dgst (retlist);
295 dgst (arglist);
296 dgst (str ());
297
298 id = "f_" + (std::string) dgst;
299
300 std::ostringstream o;
301 o << retlist << " " << id << " (" << arglist << ")\n{\n" << str () << "\n}\n";
302 source = o.str ();
303 }
304
305 }