… | |
… | |
28 | #include <cstdarg> |
28 | #include <cstdarg> |
29 | #include <cstdio> |
29 | #include <cstdio> |
30 | #include <cstring> |
30 | #include <cstring> |
31 | #include <cerrno> |
31 | #include <cerrno> |
32 | |
32 | |
|
|
33 | #include <iostream> |
33 | #include <sstream> |
34 | #include <sstream> |
34 | #include <fstream> |
35 | #include <fstream> |
35 | #include <stdexcept> |
36 | #include <stdexcept> |
36 | #include <iomanip> |
37 | #include <iomanip> |
37 | |
38 | |
… | |
… | |
48 | #include <dlfcn.h> |
49 | #include <dlfcn.h> |
49 | |
50 | |
50 | #define STR_(str) #str |
51 | #define STR_(str) #str |
51 | #define STR(str) STR_(str) |
52 | #define STR(str) STR_(str) |
52 | |
53 | |
|
|
54 | #define IDX_VERSION 1 |
|
|
55 | |
53 | namespace cpjit |
56 | namespace cpjit |
54 | { |
57 | { |
|
|
58 | |
|
|
59 | using namespace std; |
55 | |
60 | |
56 | const char typestr<U8 >::str[] = "unsigned " STR(TYPE_INT8); |
61 | const char typestr<U8 >::str[] = "unsigned " STR(TYPE_INT8); |
57 | const char typestr<U16 >::str[] = "unsigned " STR(TYPE_INT16); |
62 | const char typestr<U16 >::str[] = "unsigned " STR(TYPE_INT16); |
58 | const char typestr<U32 >::str[] = "unsigned " STR(TYPE_INT32); |
63 | const char typestr<U32 >::str[] = "unsigned " STR(TYPE_INT32); |
59 | const char typestr<U64 >::str[] = "unsigned " STR(TYPE_INT64); |
64 | const char typestr<U64 >::str[] = "unsigned " STR(TYPE_INT64); |
… | |
… | |
80 | ///////////////////////////////////////////////////////////////////////////// |
85 | ///////////////////////////////////////////////////////////////////////////// |
81 | |
86 | |
82 | struct digest : md5_ctx |
87 | struct digest : md5_ctx |
83 | { |
88 | { |
84 | digest (); |
89 | digest (); |
85 | void operator ()(const std::string &data); |
90 | void operator ()(const string &data); |
86 | operator std::string(); |
91 | operator string(); |
87 | }; |
92 | }; |
88 | |
93 | |
89 | digest::digest () |
94 | digest::digest () |
90 | { |
95 | { |
91 | md5_init_ctx (this); |
96 | md5_init_ctx (this); |
92 | } |
97 | } |
93 | |
98 | |
94 | void digest::operator ()(const std::string &data) |
99 | void digest::operator ()(const string &data) |
95 | { |
100 | { |
96 | md5_process_bytes (data.c_str (), data.size (), this); |
101 | md5_process_bytes (data.c_str (), data.size (), this); |
97 | } |
102 | } |
98 | |
103 | |
99 | digest::operator std::string () |
104 | digest::operator string () |
100 | { |
105 | { |
101 | unsigned char data[16]; |
106 | unsigned char data[16]; |
102 | std::ostringstream s; |
107 | std::ostringstream s; |
103 | |
108 | |
104 | md5_finish_ctx (this, data); |
109 | md5_finish_ctx (this, data); |
… | |
… | |
110 | } |
115 | } |
111 | |
116 | |
112 | ///////////////////////////////////////////////////////////////////////////// |
117 | ///////////////////////////////////////////////////////////////////////////// |
113 | |
118 | |
114 | static inline bool |
119 | static inline bool |
115 | is_null (const std::string &s) |
120 | is_null (const string &s) |
116 | { |
121 | { |
117 | return s.empty (); |
122 | return s.empty (); |
118 | } |
123 | } |
119 | |
124 | |
120 | ///////////////////////////////////////////////////////////////////////////// |
125 | ///////////////////////////////////////////////////////////////////////////// |
… | |
… | |
141 | FATAL ("could not get file stamp"); |
146 | FATAL ("could not get file stamp"); |
142 | |
147 | |
143 | return (long)st.st_mtime; |
148 | return (long)st.st_mtime; |
144 | } |
149 | } |
145 | |
150 | |
146 | static void set_stamp (const std::string &path, long stamp) |
151 | static void set_stamp (const string &path, long stamp) |
147 | { |
152 | { |
148 | struct utimbuf ut; |
153 | struct utimbuf ut; |
149 | |
154 | |
150 | ut.actime = stamp; |
155 | ut.actime = stamp; |
151 | ut.modtime = stamp; |
156 | ut.modtime = stamp; |
152 | |
157 | |
153 | if (utime (path.c_str (), &ut)) |
158 | if (utime (path.c_str (), &ut)) |
154 | FATAL ("could not set file stamp"); |
159 | FATAL ("could not set file stamp"); |
155 | } |
160 | } |
156 | |
161 | |
157 | env::env (const std::string &path, bool temporary) |
162 | env::env (const string &path, bool temporary) |
158 | : path(path), temporary(temporary) |
163 | : path(path), temporary(temporary) |
159 | { |
164 | { |
|
|
165 | bool create; |
160 | mode_t oflags = O_RDWR | O_EXCL; |
166 | mode_t oflags = O_RDWR | O_EXCL; |
161 | |
167 | |
162 | if (is_null (path)) |
168 | if (is_null (path)) |
163 | { |
169 | { |
|
|
170 | temporary = true; |
164 | this->path = tmpnam (0); |
171 | this->path = tmpnam (0); |
165 | |
|
|
166 | temporary = true; |
|
|
167 | } |
172 | } |
168 | |
173 | |
169 | if (mkdir (this->path.c_str (), 0777) == 0) |
174 | create = mkdir (this->path.c_str (), 0777) == 0; |
170 | oflags |= O_CREAT; |
175 | |
171 | else |
176 | if (!create && temporary) |
172 | if (temporary) |
|
|
173 | FATAL ("error while creating libcpjit temporary directory" << ERRNO); |
177 | FATAL ("error while creating libcpjit temporary directory" << ERRNO); |
174 | |
178 | |
175 | idxpath = this->path + "/libcpjit.idx"; |
179 | idxpath = this->path + "/libcpjit.idx"; |
176 | idxfd = open (idxpath.c_str (), oflags, 0666); |
180 | idxfd = open (idxpath.c_str (), O_RDWR | (create ? O_CREAT | O_EXCL : 0), 0666); |
177 | if (idxfd < 0) |
181 | if (idxfd < 0) |
178 | FATAL (path << ": unable to open index file" << idxpath); |
182 | FATAL (path << ": unable to open index file " << idxpath); |
179 | |
183 | |
180 | lock (); |
184 | lock (); |
|
|
185 | |
|
|
186 | if (create) |
|
|
187 | { |
|
|
188 | idxstamp = get_stamp (idxfd) - 1; |
|
|
189 | nextid = 0; |
|
|
190 | save_index (); |
|
|
191 | } |
|
|
192 | |
181 | load_index (); |
193 | load_index (); |
|
|
194 | unlock (); |
182 | compact (); |
195 | compact (); |
183 | unlock (); |
|
|
184 | } |
196 | } |
185 | |
197 | |
186 | env::~env () |
198 | env::~env () |
187 | { |
199 | { |
188 | if (temporary) |
200 | if (temporary) |
… | |
… | |
199 | while ((de = readdir (dir))) |
211 | while ((de = readdir (dir))) |
200 | { |
212 | { |
201 | if (de->d_name [0] == '.') |
213 | if (de->d_name [0] == '.') |
202 | continue; |
214 | continue; |
203 | |
215 | |
204 | std::string f = path + "/" + de->d_name; |
216 | string f = path + "/" + de->d_name; |
205 | unlink (f.c_str ()); |
217 | unlink (f.c_str ()); |
206 | } |
218 | } |
207 | |
219 | |
208 | closedir (dir); |
220 | closedir (dir); |
209 | } |
221 | } |
… | |
… | |
234 | void env::unlock () |
246 | void env::unlock () |
235 | { |
247 | { |
236 | dolock (false); |
248 | dolock (false); |
237 | } |
249 | } |
238 | |
250 | |
239 | void |
251 | bool |
240 | env::load_index () |
252 | env::load_index () |
241 | { |
253 | { |
242 | // caller must lock() |
254 | // caller must lock() |
243 | |
255 | |
244 | long stamp = get_stamp (idxfd); |
256 | long stamp = get_stamp (idxfd); |
245 | |
257 | |
246 | if (stamp == idxstamp) |
258 | if (stamp == idxstamp) |
247 | return; |
259 | return false; |
248 | |
260 | |
249 | idxstamp = stamp; |
261 | idxstamp = stamp; |
250 | |
262 | |
251 | // ... TODO |
263 | fstream f (idxpath.c_str (), ios::in); |
252 | |
264 | |
|
|
265 | if (!f) |
|
|
266 | FATAL (idxpath << ": unable to read index" << ERRNO); |
|
|
267 | |
|
|
268 | f >> nextid; |
|
|
269 | |
|
|
270 | if (nextid != IDX_VERSION) |
|
|
271 | FATAL (idxpath << ": index file corrupted"); |
|
|
272 | |
|
|
273 | f >> nextid; |
|
|
274 | |
|
|
275 | id2file.clear (); |
|
|
276 | |
|
|
277 | while (f) |
|
|
278 | { |
|
|
279 | string id; f >> id; |
|
|
280 | |
|
|
281 | if (id == "-") |
|
|
282 | break; |
|
|
283 | |
|
|
284 | string fileid; f >> fileid; |
|
|
285 | |
|
|
286 | id2file [id] = fileid; |
|
|
287 | |
|
|
288 | } |
|
|
289 | |
|
|
290 | string end; f >> end; |
|
|
291 | |
|
|
292 | if (end != "__end__" || !f) |
|
|
293 | FATAL (idxpath << ": index file corrupted"); |
|
|
294 | |
|
|
295 | f.close (); |
|
|
296 | |
|
|
297 | return true; |
253 | } |
298 | } |
254 | |
299 | |
255 | void |
300 | void |
256 | env::save_index () |
301 | env::save_index () |
257 | { |
302 | { |
258 | // caller must lock()+load_index() |
303 | // caller must lock()+load_index() |
259 | |
304 | |
260 | // ... TODO |
305 | std::fstream f (idxpath.c_str ()); |
|
|
306 | |
|
|
307 | if (!f) |
|
|
308 | FATAL (idxpath << ": unable to write index" << ERRNO); |
|
|
309 | |
|
|
310 | f << IDX_VERSION << "\n" |
|
|
311 | << nextid << "\n"; |
|
|
312 | |
|
|
313 | for (map<string, string>::const_iterator i = id2file.begin (); |
|
|
314 | i != id2file.end (); |
|
|
315 | ++i) |
|
|
316 | f << (*i).first << " " << (*i).second << "\n"; |
|
|
317 | |
|
|
318 | f << "-\n"; |
|
|
319 | f << "__end__\n"; |
|
|
320 | |
|
|
321 | f.close (); |
|
|
322 | |
261 | set_stamp (idxpath, ++idxstamp); |
323 | set_stamp (idxpath, ++idxstamp); |
262 | } |
324 | } |
263 | |
325 | |
264 | void |
326 | void |
265 | env::compact () |
327 | env::compact () |
266 | { |
328 | { |
|
|
329 | lock (); |
|
|
330 | save_index (); |
|
|
331 | unlock (); |
267 | } |
332 | } |
268 | |
333 | |
269 | ///////////////////////////////////////////////////////////////////////////// |
334 | void env::register_fragment (const string &id, const string &source) |
|
|
335 | { |
|
|
336 | fragments.push_back (pair<string, string> (id, source)); |
|
|
337 | } |
270 | |
338 | |
|
|
339 | void *env::dlsym (const string &id, const char *symbol) |
|
|
340 | { |
|
|
341 | assert (id2file.find (id) != id2file.end ()); |
|
|
342 | |
|
|
343 | const string &fileid = id2file [id]; |
|
|
344 | |
|
|
345 | void *so; |
|
|
346 | |
|
|
347 | // load so |
|
|
348 | if (file2so.find (fileid) == file2so.end ()) |
|
|
349 | { |
|
|
350 | string sopath = path + "/" + fileid + ".so"; |
|
|
351 | |
|
|
352 | so = dlopen (sopath.c_str (), RTLD_LAZY | RTLD_GLOBAL); |
|
|
353 | if (!so) |
|
|
354 | FATAL (sopath << ": so file should be there but isn't" << ERRNO); |
|
|
355 | } |
|
|
356 | else |
|
|
357 | so = file2so [fileid]; |
|
|
358 | |
|
|
359 | return ::dlsym (so, symbol); |
|
|
360 | } |
|
|
361 | |
|
|
362 | void *env::sym (const string &id, const char *symbol) |
|
|
363 | { |
|
|
364 | // not yet compiled? |
|
|
365 | if (id2file.find (id) == id2file.end ()) |
|
|
366 | { |
|
|
367 | lock (); |
|
|
368 | |
|
|
369 | // nobody else compiled it? |
|
|
370 | if (!load_index () || id2file.find (id) == id2file.end ()) |
|
|
371 | { |
|
|
372 | ostringstream sfile; |
|
|
373 | sfile << nextid++; |
|
|
374 | string fileid = sfile.str (); |
|
|
375 | string base = path + "/" + fileid; |
|
|
376 | |
|
|
377 | string fc = base + ".c"; |
|
|
378 | string fo = base + ".o"; |
|
|
379 | string fso = base + ".so"; |
|
|
380 | |
|
|
381 | std::ofstream f (fc.c_str ()); |
|
|
382 | |
|
|
383 | for (vector< pair<string, string> >::const_iterator i = fragments.begin (); |
|
|
384 | i != fragments.end (); |
|
|
385 | ++i) |
|
|
386 | if (id2file.find ((*i).first) == id2file.end ()) |
|
|
387 | { |
|
|
388 | f << "#line 1 \"" << (*i).first << "\"\n" |
|
|
389 | << (*i).second << "\n"; |
|
|
390 | |
|
|
391 | id2file [(*i).first] = fileid; |
|
|
392 | } |
|
|
393 | |
|
|
394 | f.close (); |
|
|
395 | |
|
|
396 | fragments.clear (); |
|
|
397 | |
|
|
398 | system (("gcc -O6 -c -o " + fo + " " + fc).c_str ()); |
|
|
399 | |
|
|
400 | //unlink (fc.c_str ()); |
|
|
401 | |
|
|
402 | system (("gcc -O6 -nostdlib -lgcc -shared -o " + fso + " " + fo).c_str ()); |
|
|
403 | |
|
|
404 | printf ("%s\n", fso.c_str ()); |
|
|
405 | |
|
|
406 | #if 0 |
|
|
407 | void *so = dlopen (fso.c_str (), RTLD_LAZY); |
|
|
408 | assert (so); |
|
|
409 | |
|
|
410 | funptr = dlsym (so, id.c_str ()); |
|
|
411 | assert (funptr); |
|
|
412 | #endif |
|
|
413 | |
|
|
414 | save_index (); |
|
|
415 | } |
|
|
416 | |
|
|
417 | unlock (); |
|
|
418 | } |
|
|
419 | |
|
|
420 | void *p = dlsym (id, symbol); |
|
|
421 | |
|
|
422 | if (!p) |
|
|
423 | { |
|
|
424 | lock (); |
|
|
425 | load_index (); |
|
|
426 | unlock (); |
|
|
427 | p = dlsym (id, symbol); |
|
|
428 | } |
|
|
429 | |
|
|
430 | if (!p) |
|
|
431 | FATAL ("symbol " << id << ":" << symbol << " not where it should be"); |
|
|
432 | |
|
|
433 | return p; |
|
|
434 | } |
|
|
435 | |
|
|
436 | ///////////////////////////////////////////////////////////////////////////// |
|
|
437 | |
271 | fun::fun (env &e, const std::string &id, const std::string &source) |
438 | fun::fun (env &e, const string &id, const string &source) |
272 | : e(e), id(id), source(source), funptr(0) |
439 | : e(e), id(id), funptr(0) |
273 | { |
440 | { |
|
|
441 | e.register_fragment (id, source); |
274 | } |
442 | } |
275 | |
443 | |
276 | void *fun::ptr () |
444 | void *fun::ptr () |
277 | { |
445 | { |
278 | if (!funptr) |
446 | 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 ()); |
447 | funptr = e.sym (id, id.c_str ()); |
306 | assert (funptr); |
|
|
307 | |
|
|
308 | e.save_index (); |
|
|
309 | e.unlock (); |
|
|
310 | } |
|
|
311 | |
448 | |
312 | return funptr; |
449 | return funptr; |
313 | } |
450 | } |
314 | |
451 | |
315 | ///////////////////////////////////////////////////////////////////////////// |
452 | ///////////////////////////////////////////////////////////////////////////// |
… | |
… | |
337 | |
474 | |
338 | arglist = argl.str (); |
475 | arglist = argl.str (); |
339 | } |
476 | } |
340 | |
477 | |
341 | void |
478 | void |
342 | funbuild::finish (std::string &id, std::string &source) |
479 | funbuild::finish (string &id, string &source) |
343 | { |
480 | { |
344 | digest dgst; |
481 | digest dgst; |
345 | |
482 | |
346 | dgst (retlist); |
483 | dgst (retlist); |
347 | dgst (arglist); |
484 | dgst (arglist); |
348 | dgst (str ()); |
485 | dgst (str ()); |
349 | |
486 | |
350 | id = "f_" + (std::string) dgst; |
487 | id = "f_" + (string) dgst; |
351 | |
488 | |
352 | std::ostringstream o; |
489 | std::ostringstream o; |
353 | o << retlist << " " << id << " (" << arglist << ")\n{\n" << str () << "\n}\n"; |
490 | o << retlist << " " << id << " (" << arglist << ")\n{\n" << str () << "\n}\n"; |
354 | source = o.str (); |
491 | source = o.str (); |
355 | } |
492 | } |