ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/libcpjit/cpjit.C
Revision: 1.4
Committed: Fri Oct 14 00:21:57 2005 UTC (18 years, 9 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.3: +108 -21 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
80 {
81 unsigned char data[16];
82
83 digest (const std::string &str);
84 operator std::string();
85 };
86
87 digest::digest (const std::string &str)
88 {
89 MD5_CTX ctx;
90 MD5Init (&ctx);
91 MD5Update (&ctx, (const unsigned char *)str.c_str (), str.size ());
92 MD5Final (&ctx);
93
94 memcpy (data, ctx.digest, sizeof (data));
95 }
96
97 digest::operator std::string ()
98 {
99 std::ostringstream s;
100
101 for (int i = 0; i < 15; i++)
102 s << std::setfill ('0') << std::hex << std::setw (2) << (int)data [i];
103
104 return s.str ();
105 }
106
107 static inline bool
108 is_null (const std::string &s)
109 {
110 return s.empty ();
111 }
112
113 // error exception builder
114 struct error : std::ostringstream
115 {
116 ~error ()
117 {
118 throw std::runtime_error (str ());
119 }
120 };
121
122 #define FATAL(msg) do { error o; o << msg << std::endl; } while (0)
123 #define ERRNO " (" << strerror (errno) << ")"
124
125 env::env (const std::string &path, bool temporary)
126 : path(path), temporary(temporary)
127 {
128 if (is_null (path))
129 {
130 this->path = tmpnam (0);
131
132 if (mkdir (this->path.c_str (), 0777))
133 FATAL ("error while creating libcpjit temporary directory" << ERRNO);
134
135 temporary = true;
136 }
137
138 std::string index = this->path + "/libcpjit.idx";
139
140 idxfd = open (index.c_str (), O_RDWR|O_CREAT, 0666);
141
142 if (idxfd < 0)
143 FATAL (path << ": unable to open index file" << index);
144
145 lock ();
146 load_index ();
147 unlock ();
148
149 nextid = 0;
150 }
151
152 env::~env ()
153 {
154 if (temporary)
155 {
156 DIR *dir = opendir (path.c_str ());
157
158 if (dir)
159 {
160 struct dirent *de;
161 while ((de = readdir (dir)))
162 {
163 if (de->d_name [0] == '.')
164 continue;
165
166 std::string f = path + "/" + de->d_name;
167 unlink (f.c_str ());
168 }
169
170 closedir (dir);
171 }
172
173 if (rmdir (path.c_str ()))
174 FATAL (path << ": unable to remove libcpjit temporary directory" << ERRNO);
175 }
176 }
177
178 void env::dolock (bool lock)
179 {
180 struct flock fl;
181
182 fl.l_type = lock ? F_WRLCK : F_UNLCK;
183 fl.l_whence = SEEK_SET;
184 fl.l_start = 0;
185 fl.l_len = 0;
186
187 while (fcntl (idxfd, F_SETLKW, &fl) < 0)
188 if (errno != EINTR)
189 FATAL (path << ": unable to lock index file" << ERRNO);
190 }
191
192 void env::lock ()
193 {
194 dolock (true);
195 }
196
197 void env::unlock ()
198 {
199 dolock (false);
200 }
201
202 void
203 env::load_index ()
204 {
205 std::ifstream f ((this->path + "/libcpjit.idx").c_str ());
206 assert (("not a cpjit directory", f));
207 f.close ();
208 }
209
210 std::string
211 env::genid ()
212 {
213 std::ostringstream os;
214
215 os << "i" << ++nextid;
216 return os.str ();
217 }
218
219 fun::fun (env &e, const idstr &id)
220 : e(e), id(id), funptr(0)
221 {
222 }
223
224 void fun::set_source (const std::string source)
225 {
226 this->source = source;
227 }
228
229 void *fun::ptr ()
230 {
231 if (!funptr)
232 {
233 std::string base = e.path + "/" + (std::string) digest (source);
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 sleep (10);
252
253 void *so = dlopen (fso.c_str (), RTLD_LAZY);
254 assert (so);
255
256 funptr = dlsym (so, id.c_str ());
257 assert (funptr);
258 }
259
260 return funptr;
261 }
262
263 funbuild::funbuild (env &e, const idstr &id, const char *rettype, ...)
264 : e(e), id(id)
265 {
266 std::ostringstream hdrs;
267
268 if (is_null (id))
269 this->id = e.genid ();
270
271 hdrs << rettype << " " << this->id << "(";
272
273 va_list ap;
274 va_start (ap, rettype);
275
276 int args = 0;
277 while ((rettype = va_arg (ap, const char *)))
278 {
279 if (args++)
280 hdrs << ", ";
281
282 hdrs << rettype << " a" << args;
283 }
284
285 va_end (ap);
286
287 hdrs << ")\n{\n";
288
289 hdr = hdrs.str ();
290 }
291
292 std::string
293 funbuild::finish ()
294 {
295 *this << "\n}\n";
296
297 return hdr + str ();
298 }
299
300 }