objcode type is an enumeration, not flags
[bpt/guile.git] / libguile / objcodes.c
1 /* Copyright (C) 2001, 2009, 2010, 2011 Free Software Foundation, Inc.
2 *
3 * This library is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU Lesser General Public License
5 * as published by the Free Software Foundation; either version 3 of
6 * the License, or (at your option) any later version.
7 *
8 * This library is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public
14 * License along with this library; if not, write to the Free Software
15 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
16 * 02110-1301 USA
17 */
18
19 #if HAVE_CONFIG_H
20 # include <config.h>
21 #endif
22
23 #include <string.h>
24 #include <fcntl.h>
25 #include <unistd.h>
26 #include <sys/mman.h>
27 #include <sys/stat.h>
28 #include <sys/types.h>
29 #include <assert.h>
30 #include <alignof.h>
31
32 #include "_scm.h"
33 #include "programs.h"
34 #include "objcodes.h"
35
36 /* SCM_OBJCODE_COOKIE, defined in _scm.h, is a magic value prepended
37 to objcode on disk but not in memory.
38
39 The length of the header must be a multiple of 8 bytes. */
40 verify (((sizeof (SCM_OBJCODE_COOKIE) - 1) & 7) == 0);
41
42 \f
43 /*
44 * Objcode type
45 */
46
47 /* The words in an objcode SCM object are as follows:
48 - scm_tc7_objcode | the flags for this objcode
49 - the struct scm_objcode C object
50 - the parent of this objcode, if this is a slice, or #f if none
51 - the file descriptor this objcode came from if this was mmaped,
52 or 0 if none
53 */
54
55 static SCM
56 make_objcode_by_mmap (int fd)
57 #define FUNC_NAME "make_objcode_by_mmap"
58 {
59 int ret;
60 char *addr;
61 struct stat st;
62 SCM sret = SCM_BOOL_F;
63 struct scm_objcode *data;
64
65 ret = fstat (fd, &st);
66 if (ret < 0)
67 SCM_SYSERROR;
68
69 if (st.st_size <= sizeof (struct scm_objcode) + strlen (SCM_OBJCODE_COOKIE))
70 scm_misc_error (FUNC_NAME, "object file too small (~a bytes)",
71 scm_list_1 (SCM_I_MAKINUM (st.st_size)));
72
73 addr = mmap (0, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
74 if (addr == MAP_FAILED)
75 {
76 (void) close (fd);
77 SCM_SYSERROR;
78 }
79
80 if (memcmp (addr, SCM_OBJCODE_COOKIE, strlen (SCM_OBJCODE_COOKIE)))
81 {
82 SCM args = scm_list_1 (scm_from_latin1_stringn
83 (addr, strlen (SCM_OBJCODE_COOKIE)));
84 (void) close (fd);
85 (void) munmap (addr, st.st_size);
86 scm_misc_error (FUNC_NAME, "bad header on object file: ~s", args);
87 }
88
89 data = (struct scm_objcode*)(addr + strlen (SCM_OBJCODE_COOKIE));
90
91 if (data->len + data->metalen != (st.st_size - sizeof (*data) - strlen (SCM_OBJCODE_COOKIE)))
92 {
93 (void) close (fd);
94 (void) munmap (addr, st.st_size);
95 scm_misc_error (FUNC_NAME, "bad length header (~a, ~a)",
96 scm_list_2 (scm_from_size_t (st.st_size),
97 scm_from_uint32 (sizeof (*data) + data->len
98 + data->metalen)));
99 }
100
101 sret = scm_double_cell (SCM_MAKE_OBJCODE_TAG (SCM_OBJCODE_TYPE_MMAP, 0),
102 (scm_t_bits)(addr + strlen (SCM_OBJCODE_COOKIE)),
103 SCM_UNPACK (SCM_BOOL_F),
104 (scm_t_bits)fd);
105
106 /* FIXME: we leak ourselves and the file descriptor. but then again so does
107 dlopen(). */
108 return scm_permanent_object (sret);
109 }
110 #undef FUNC_NAME
111
112 SCM
113 scm_c_make_objcode_slice (SCM parent, const scm_t_uint8 *ptr)
114 #define FUNC_NAME "make-objcode-slice"
115 {
116 const struct scm_objcode *data, *parent_data;
117 const scm_t_uint8 *parent_base;
118
119 SCM_VALIDATE_OBJCODE (1, parent);
120 parent_data = SCM_OBJCODE_DATA (parent);
121 parent_base = SCM_C_OBJCODE_BASE (parent_data);
122
123 if (ptr < parent_base
124 || ptr >= (parent_base + parent_data->len + parent_data->metalen
125 - sizeof (struct scm_objcode)))
126 scm_misc_error
127 (FUNC_NAME, "offset out of bounds (~a vs ~a + ~a + ~a)",
128 scm_list_4 (scm_from_unsigned_integer ((scm_t_bits) ptr),
129 scm_from_unsigned_integer ((scm_t_bits) parent_base),
130 scm_from_uint32 (parent_data->len),
131 scm_from_uint32 (parent_data->metalen)));
132
133 /* Make sure bytecode for the objcode-meta is suitable aligned. Failing to
134 do so leads to SIGBUS/SIGSEGV on some arches (e.g., SPARC). */
135 assert ((((scm_t_bits) ptr) &
136 (alignof_type (struct scm_objcode) - 1UL)) == 0);
137
138 data = (struct scm_objcode*) ptr;
139 assert (SCM_C_OBJCODE_BASE (data) + data->len + data->metalen
140 <= parent_base + parent_data->len + parent_data->metalen);
141
142 return scm_double_cell (SCM_MAKE_OBJCODE_TAG (SCM_OBJCODE_TYPE_SLICE, 0),
143 (scm_t_bits)data, SCM_UNPACK (parent), 0);
144 }
145 #undef FUNC_NAME
146
147 \f
148 /*
149 * Scheme interface
150 */
151
152 SCM_DEFINE (scm_objcode_p, "objcode?", 1, 0, 0,
153 (SCM obj),
154 "")
155 #define FUNC_NAME s_scm_objcode_p
156 {
157 return scm_from_bool (SCM_OBJCODE_P (obj));
158 }
159 #undef FUNC_NAME
160
161 SCM_DEFINE (scm_objcode_meta, "objcode-meta", 1, 0, 0,
162 (SCM objcode),
163 "")
164 #define FUNC_NAME s_scm_objcode_meta
165 {
166 SCM_VALIDATE_OBJCODE (1, objcode);
167
168 if (SCM_OBJCODE_META_LEN (objcode) == 0)
169 return SCM_BOOL_F;
170 else
171 return scm_c_make_objcode_slice (objcode, (SCM_OBJCODE_BASE (objcode)
172 + SCM_OBJCODE_LEN (objcode)));
173 }
174 #undef FUNC_NAME
175
176 SCM_DEFINE (scm_bytecode_to_objcode, "bytecode->objcode", 1, 0, 0,
177 (SCM bytecode),
178 "")
179 #define FUNC_NAME s_scm_bytecode_to_objcode
180 {
181 size_t size;
182 const scm_t_uint8 *c_bytecode;
183 struct scm_objcode *data;
184
185 if (!scm_is_bytevector (bytecode))
186 scm_wrong_type_arg (FUNC_NAME, 1, bytecode);
187
188 size = SCM_BYTEVECTOR_LENGTH (bytecode);
189 c_bytecode = (const scm_t_uint8*)SCM_BYTEVECTOR_CONTENTS (bytecode);
190
191 SCM_ASSERT_RANGE (0, bytecode, size >= sizeof(struct scm_objcode));
192 data = (struct scm_objcode*)c_bytecode;
193
194 if (data->len + data->metalen != (size - sizeof (*data)))
195 scm_misc_error (FUNC_NAME, "bad bytevector size (~a != ~a)",
196 scm_list_2 (scm_from_size_t (size),
197 scm_from_uint32 (sizeof (*data) + data->len + data->metalen)));
198
199 /* foolishly, we assume that as long as bytecode is around, that c_bytecode
200 will be of the same length; perhaps a bad assumption? */
201 return scm_double_cell (SCM_MAKE_OBJCODE_TAG (SCM_OBJCODE_TYPE_BYTEVECTOR, 0),
202 (scm_t_bits)data, SCM_UNPACK (bytecode), 0);
203 }
204 #undef FUNC_NAME
205
206 SCM_DEFINE (scm_load_objcode, "load-objcode", 1, 0, 0,
207 (SCM file),
208 "")
209 #define FUNC_NAME s_scm_load_objcode
210 {
211 int fd;
212 char *c_file;
213
214 SCM_VALIDATE_STRING (1, file);
215
216 c_file = scm_to_locale_string (file);
217 fd = open (c_file, O_RDONLY);
218 free (c_file);
219 if (fd < 0) SCM_SYSERROR;
220
221 return make_objcode_by_mmap (fd);
222 }
223 #undef FUNC_NAME
224
225 SCM_DEFINE (scm_objcode_to_bytecode, "objcode->bytecode", 1, 0, 0,
226 (SCM objcode),
227 "")
228 #define FUNC_NAME s_scm_objcode_to_bytecode
229 {
230 scm_t_int8 *s8vector;
231 scm_t_uint32 len;
232
233 SCM_VALIDATE_OBJCODE (1, objcode);
234
235 len = sizeof (struct scm_objcode) + SCM_OBJCODE_TOTAL_LEN (objcode);
236
237 s8vector = scm_malloc (len);
238 memcpy (s8vector, SCM_OBJCODE_DATA (objcode), len);
239
240 return scm_c_take_bytevector (s8vector, len);
241 }
242 #undef FUNC_NAME
243
244 SCM_DEFINE (scm_write_objcode, "write-objcode", 2, 0, 0,
245 (SCM objcode, SCM port),
246 "")
247 #define FUNC_NAME s_scm_write_objcode
248 {
249 SCM_VALIDATE_OBJCODE (1, objcode);
250 SCM_VALIDATE_OUTPUT_PORT (2, port);
251
252 scm_c_write (port, SCM_OBJCODE_COOKIE, strlen (SCM_OBJCODE_COOKIE));
253 scm_c_write (port, SCM_OBJCODE_DATA (objcode),
254 sizeof (struct scm_objcode) + SCM_OBJCODE_TOTAL_LEN (objcode));
255
256 return SCM_UNSPECIFIED;
257 }
258 #undef FUNC_NAME
259
260 void
261 scm_i_objcode_print (SCM objcode, SCM port, scm_print_state *pstate)
262 {
263 scm_puts ("#<objcode ", port);
264 scm_uintprint ((scm_t_bits)SCM_OBJCODE_BASE (objcode), 16, port);
265 scm_puts (">", port);
266 }
267
268 \f
269 void
270 scm_bootstrap_objcodes (void)
271 {
272 scm_c_register_extension ("libguile-" SCM_EFFECTIVE_VERSION,
273 "scm_init_objcodes",
274 (scm_t_extension_init_func)scm_init_objcodes, NULL);
275 }
276
277 /* Before, we used __BYTE_ORDER, but that is not defined on all
278 systems. So punt and use automake, PDP endianness be damned. */
279 #ifdef WORDS_BIGENDIAN
280 #define SCM_BYTE_ORDER 4321
281 #else
282 #define SCM_BYTE_ORDER 1234
283 #endif
284
285 void
286 scm_init_objcodes (void)
287 {
288 #ifndef SCM_MAGIC_SNARFER
289 #include "libguile/objcodes.x"
290 #endif
291
292 scm_c_define ("word-size", scm_from_size_t (sizeof(SCM)));
293 scm_c_define ("byte-order", scm_from_uint16 (SCM_BYTE_ORDER));
294 }
295
296 /*
297 Local Variables:
298 c-file-style: "gnu"
299 End:
300 */