1 #include "schpriv.h"
2
3 #define CONS(a,b) scheme_make_pair(a,b)
4
scheme_init_marshal(Scheme_Startup_Env * env)5 void scheme_init_marshal(Scheme_Startup_Env *env)
6 {
7 /* nothing */
8 }
9
not_relative_path(Scheme_Object * p,Scheme_Hash_Table * cache)10 static int not_relative_path(Scheme_Object *p, Scheme_Hash_Table *cache)
11 {
12 Scheme_Object *dir, *rel_p;
13
14 dir = scheme_get_param(scheme_current_config(),
15 MZCONFIG_WRITE_DIRECTORY);
16 if (SCHEME_TRUEP(dir)) {
17 rel_p = scheme_extract_relative_to(p, dir, cache);
18 if (SCHEME_PATHP(rel_p))
19 return 1;
20 }
21
22 return 0;
23 }
24
scheme_closure_marshal_name(Scheme_Object * name)25 Scheme_Object *scheme_closure_marshal_name(Scheme_Object *name)
26 {
27 if (name) {
28 if (SCHEME_VECTORP(name)) {
29 /* We can only save marshalable src names, which includes
30 paths, symbols, and strings: */
31 Scheme_Object *src;
32 src = SCHEME_VEC_ELS(name)[1];
33 if ((!SCHEME_PATHP(src)
34 /* If MZCONFIG_WRITE_DIRECTORY, drop any non-relative path
35 (which might happen due to function inlining, for example)
36 to avoid embedding absolute paths in bytecode files: */
37 || not_relative_path(src, scheme_current_thread->current_mt->path_cache))
38 && !SCHEME_CHAR_STRINGP(src)
39 && !SCHEME_SYMBOLP(src)) {
40 /* Just keep the name */
41 name = SCHEME_VEC_ELS(name)[0];
42 }
43 }
44 } else
45 name = scheme_null;
46
47 return name;
48 }
49
scheme_write_lambda(Scheme_Object * obj,Scheme_Object ** _name,Scheme_Object ** _ds,Scheme_Object ** _closure_map,Scheme_Object ** _tl_map)50 void scheme_write_lambda(Scheme_Object *obj,
51 Scheme_Object **_name,
52 Scheme_Object **_ds,
53 Scheme_Object **_closure_map,
54 Scheme_Object **_tl_map)
55 {
56 Scheme_Lambda *data;
57 Scheme_Object *name, *code, *ds, *tl_map, *closure_map;
58 int svec_size, pos;
59 Scheme_Marshal_Tables *mt;
60
61 data = (Scheme_Lambda *)obj;
62
63 name = scheme_closure_marshal_name(data->name);
64
65 svec_size = data->closure_size;
66 if (SCHEME_LAMBDA_FLAGS(data) & LAMBDA_HAS_TYPED_ARGS) {
67 svec_size += scheme_boxmap_size(data->num_params + data->closure_size);
68 {
69 int k, mv;
70 for (k = data->num_params + data->closure_size; --k; ) {
71 mv = scheme_boxmap_get(data->closure_map, k, data->closure_size);
72 if (mv > (LAMBDA_TYPE_TYPE_OFFSET + SCHEME_MAX_LOCAL_TYPE))
73 scheme_signal_error("internal error: inconsistent closure/argument type");
74 }
75 }
76 }
77
78 if (SCHEME_RPAIRP(data->body)) {
79 /* This can happen if loaded bytecode is printed out and the procedure
80 body has never been needed before.
81 It's also possible in non-JIT mode if an empty closure is embedded
82 as a 3-D value in compiled code. */
83 scheme_delay_load_closure(data);
84 }
85
86 /* If the body is simple enough, write it directly.
87 Otherwise, create a delay indirection so that the body
88 is loaded on demand. */
89 code = data->body;
90 switch (SCHEME_TYPE(code)) {
91 case scheme_toplevel_type:
92 case scheme_local_type:
93 case scheme_local_unbox_type:
94 case scheme_true_type:
95 case scheme_false_type:
96 case scheme_void_type:
97 ds = code;
98 break;
99 default:
100 if (SCHEME_NUMBERP(code))
101 ds = code;
102 else
103 ds = NULL;
104 break;
105 }
106
107 if (!ds) {
108 mt = scheme_current_thread->current_mt;
109 if (mt->pass < 0) {
110 /* nothing to do, yet */
111 ds = scheme_false;
112 } else {
113 if (!mt->pass) {
114 int key;
115
116 pos = mt->cdata_counter;
117 if ((!mt->cdata_map || (pos >= 32))
118 && !(pos & (pos - 1))) {
119 /* Need to grow the array */
120 Scheme_Object **a;
121 a = MALLOC_N(Scheme_Object *, (pos ? 2 * pos : 32));
122 if (pos)
123 memcpy(a, mt->cdata_map, pos * sizeof(Scheme_Object *));
124 mt->cdata_map = a;
125 }
126 mt->cdata_counter++;
127
128 key = pos & 255;
129 MZ_OPT_HASH_KEY(&data->iso) = ((int)MZ_OPT_HASH_KEY(&data->iso) & 0x00FF) | (key << 8);
130 } else {
131 pos = ((int)MZ_OPT_HASH_KEY(&data->iso) & 0xFF00) >> 8;
132
133 while (pos < mt->cdata_counter) {
134 ds = mt->cdata_map[pos];
135 if (ds) {
136 ds = SCHEME_PTR_VAL(ds);
137 if (SAME_OBJ(data->body, ds))
138 break;
139 if (SAME_TYPE(scheme_quote_compilation_type, SCHEME_TYPE(ds)))
140 if (SAME_OBJ(data->body, SCHEME_PTR_VAL(ds)))
141 break;
142 }
143 pos += 256;
144 }
145 if (pos >= mt->cdata_counter) {
146 scheme_signal_error("didn't find delay record");
147 }
148 }
149
150 ds = mt->cdata_map[pos];
151 if (!ds) {
152 if (mt->pass)
153 scheme_signal_error("broken closure-data table\n");
154
155 code = scheme_protect_quote(data->body);
156
157 ds = scheme_alloc_small_object();
158 ds->type = scheme_delay_syntax_type;
159 SCHEME_PTR_VAL(ds) = code;
160
161 MZ_OPT_HASH_KEY(&((Scheme_Small_Object *)ds)->iso) |= 1; /* => hash on ds, not contained data */
162
163 mt->cdata_map[pos] = ds;
164 }
165 }
166 }
167
168 /* Encode data->tl_map as either a fixnum or a vector of 16-bit values */
169 if (!data->tl_map)
170 tl_map = scheme_false;
171 else if ((uintptr_t)data->tl_map & 0x1) {
172 if (((uintptr_t)data->tl_map & 0xFFFFFFF) == (uintptr_t)data->tl_map) {
173 /* comfortably a fixnum */
174 tl_map = (Scheme_Object *)data->tl_map;
175 } else {
176 uintptr_t v;
177 tl_map = scheme_make_vector(2, NULL);
178 v = ((uintptr_t)data->tl_map >> 1) & 0x7FFFFFFF;
179 SCHEME_VEC_ELS(tl_map)[0] = scheme_make_integer(v & 0xFFFF);
180 SCHEME_VEC_ELS(tl_map)[1] = scheme_make_integer((v >> 16) & 0xFFFF);
181 }
182 } else {
183 int len = ((int *)data->tl_map)[0], i, v;
184 tl_map = scheme_make_vector(2 * len, NULL);
185 for (i = 0; i < len; i++) {
186 v = ((int *)data->tl_map)[i+1];
187 SCHEME_VEC_ELS(tl_map)[2*i] = scheme_make_integer(v & 0xFFFF);
188 SCHEME_VEC_ELS(tl_map)[(2*i)+1] = scheme_make_integer((v >> 16) & 0xFFFF);
189 }
190 }
191
192 *_name = name;
193 *_ds = ds;
194 closure_map = scheme_make_svector(svec_size, data->closure_map);
195 *_closure_map = closure_map;
196 *_tl_map = tl_map;
197 }
198
scheme_read_lambda(int flags,int closure_size,int num_params,int max_let_depth,Scheme_Object * name,Scheme_Object * ds,Scheme_Object * closure_map,Scheme_Object * tl_map)199 Scheme_Object *scheme_read_lambda(int flags, int closure_size, int num_params, int max_let_depth,
200 Scheme_Object *name,
201 Scheme_Object *ds,
202 Scheme_Object *closure_map,
203 Scheme_Object *tl_map)
204 {
205 Scheme_Lambda *data;
206
207 #define BAD_CC "bad compiled closure"
208 #define X_SCHEME_ASSERT(x, y)
209
210 data = (Scheme_Lambda *)scheme_malloc_tagged(sizeof(Scheme_Lambda));
211 data->iso.so.type = scheme_lambda_type;
212
213 if (scheme_starting_up) flags |= LAMBDA_STATUS_BUILTIN;
214 SCHEME_LAMBDA_FLAGS(data) = (short)flags;
215
216 data->num_params = num_params;
217 if (data->num_params < 0) return NULL;
218
219 data->max_let_depth = max_let_depth;
220 if (data->max_let_depth < 0) return NULL;
221
222 if (!SCHEME_FALSEP(tl_map)) {
223 if (SCHEME_INTP(tl_map))
224 data->tl_map = (void *)tl_map;
225 else if (SCHEME_VECTORP(tl_map)) {
226 int *n, i, len, v1, v2;
227 len = SCHEME_VEC_SIZE(tl_map);
228 if (len & 0x1)
229 return NULL;
230 n = (int *)scheme_malloc_atomic(((len/2) + 1) * sizeof(int));
231 n[0] = len/2;
232 for (i = 0; i < len/2; i++) {
233 v1 = SCHEME_INT_VAL(SCHEME_VEC_ELS(tl_map)[2*i]);
234 v2 = SCHEME_INT_VAL(SCHEME_VEC_ELS(tl_map)[(2*i) + 1]);
235 v2 = ((unsigned int)v2 << 16) | v1;
236 n[i+1] = v2;
237 }
238 if ((len == 2) && (!(n[1] & 0x80000000)))
239 data->tl_map = (void *)(intptr_t)(((uintptr_t)n[1] << 1) | 0x1);
240 else
241 data->tl_map = n;
242 } else
243 return NULL;
244 }
245
246 data->name = name;
247 if (SCHEME_NULLP(data->name))
248 data->name = NULL;
249
250 data->body = ds;
251
252 if (!SAME_TYPE(scheme_svector_type, SCHEME_TYPE(closure_map))) return NULL;
253 data->closure_map = SCHEME_SVEC_VEC(closure_map);
254
255 if (SCHEME_LAMBDA_FLAGS(data) & LAMBDA_HAS_TYPED_ARGS) {
256 data->closure_size = closure_size;
257 if (data->closure_size + scheme_boxmap_size(data->closure_size + data->num_params) != SCHEME_SVEC_LEN(closure_map))
258 return NULL;
259 } else
260 data->closure_size = SCHEME_SVEC_LEN(closure_map);
261
262 /* If the closure is empty, create the closure now */
263 if (!data->closure_size)
264 return scheme_make_closure(NULL, (Scheme_Object *)data, 0);
265 else
266 return (Scheme_Object *)data;
267 }
268
hash_tree_to_vector(Scheme_Hash_Tree * ht)269 static Scheme_Object *hash_tree_to_vector(Scheme_Hash_Tree *ht)
270 {
271 Scheme_Object **keys;
272 Scheme_Object *vec, *k, *v;
273 int i = 0, pos = 0;
274
275 vec = scheme_make_vector(2 * ht->count, NULL);
276
277 keys = scheme_extract_sorted_keys((Scheme_Object *)ht);
278
279 for (i = 0; i < ht->count; i++) {
280 k = keys[i];
281 v = scheme_hash_tree_get(ht, k);
282 SCHEME_VEC_ELS(vec)[pos++] = k;
283 SCHEME_VEC_ELS(vec)[pos++] = v;
284 }
285
286 return vec;
287 }
288
scheme_write_linklet(Scheme_Object * obj)289 Scheme_Object *scheme_write_linklet(Scheme_Object *obj)
290 {
291 Scheme_Linklet *linklet = (Scheme_Linklet *)obj;
292 Scheme_Object *l;
293
294 if (linklet->jit_ready)
295 scheme_arg_mismatch("write",
296 "cannot marshal linklet that has been evaluated: ",
297 obj);
298 if (!linklet->serializable)
299 scheme_contract_error("write",
300 "linklet is not serializable",
301 NULL);
302
303 l = scheme_null;
304
305 if (linklet->import_shapes)
306 l = scheme_make_pair(linklet->import_shapes, l);
307 else
308 l = scheme_make_pair(scheme_false, l);
309
310 l = scheme_make_pair(linklet->importss, l);
311 l = scheme_make_pair(linklet->defns, l);
312 l = scheme_make_pair(hash_tree_to_vector(linklet->source_names), l);
313
314 l = scheme_make_pair(linklet->bodies, l);
315
316 l = scheme_make_pair(scheme_make_integer(linklet->num_exports), l);
317 l = scheme_make_pair(scheme_make_integer(linklet->num_lifts), l);
318 l = scheme_make_pair(scheme_make_integer(linklet->max_let_depth), l);
319 l = scheme_make_pair((linklet->need_instance_access ? scheme_true : scheme_false), l);
320
321 l = scheme_make_pair(linklet->name, l);
322
323 return l;
324 }
325
326 #if 0
327 # define return_NULL() return (printf("%d\n", __LINE__), NULL)
328 #else
329 # define return_NULL() return NULL
330 #endif
331
is_vector_of_symbols(Scheme_Object * v,int false_ok)332 static int is_vector_of_symbols(Scheme_Object *v, int false_ok)
333 {
334 int i;
335
336 if (!SCHEME_VECTORP(v))
337 return 0;
338
339 for (i = SCHEME_VEC_SIZE(v); i--; ) {
340 if (!SCHEME_SYMBOLP(SCHEME_VEC_ELS(v)[i])
341 && (!false_ok || !SCHEME_FALSEP(SCHEME_VEC_ELS(v)[i])))
342 return 0;
343 }
344
345 return 1;
346 }
347
is_vector_of_shapes(Scheme_Object * v)348 static int is_vector_of_shapes(Scheme_Object *v)
349 {
350 int i;
351 Scheme_Object *s;
352
353 if (!SCHEME_VECTORP(v))
354 return 0;
355
356 for (i = SCHEME_VEC_SIZE(v); i--; ) {
357 s = SCHEME_VEC_ELS(v)[i];
358 if (SCHEME_TRUEP(s)
359 && !SCHEME_SYMBOLP(s)
360 && !SCHEME_INTP(s)
361 && !SAME_OBJ(s, scheme_true)
362 && !SAME_OBJ(s, scheme_void))
363 return 0;
364 }
365
366 return 1;
367 }
368
is_vector_of_vector_of_symbols(Scheme_Object * v)369 static int is_vector_of_vector_of_symbols(Scheme_Object *v)
370 {
371 int i;
372
373 if (!SCHEME_VECTORP(v))
374 return 0;
375
376 for (i = SCHEME_VEC_SIZE(v); i--; ) {
377 if (!is_vector_of_symbols(SCHEME_VEC_ELS(v)[i], 0))
378 return 0;
379 }
380
381 return 1;
382 }
383
vector_to_hash_tree(Scheme_Object * vec)384 static Scheme_Object *vector_to_hash_tree(Scheme_Object *vec)
385 {
386 Scheme_Hash_Tree *ht;
387 int i = 0;
388
389 if (!SCHEME_VECTORP(vec))
390 return NULL;
391 if (SCHEME_VEC_SIZE(vec) & 0x1)
392 return NULL;
393
394 ht = scheme_make_hash_tree(0);
395 for (i = SCHEME_VEC_SIZE(vec) - 2; i >= 0; i -= 2) {
396 if (!SCHEME_SYMBOLP(SCHEME_VEC_ELS(vec)[i])
397 || !SCHEME_SYMBOLP(SCHEME_VEC_ELS(vec)[i+1]))
398 return NULL;
399 ht = scheme_hash_tree_set(ht, SCHEME_VEC_ELS(vec)[i], SCHEME_VEC_ELS(vec)[i+1]);
400 }
401
402 return (Scheme_Object *)ht;
403 }
404
scheme_read_linklet(Scheme_Object * obj,int unsafe_ok)405 Scheme_Object *scheme_read_linklet(Scheme_Object *obj, int unsafe_ok)
406 {
407 Scheme_Linklet *linklet = (Scheme_Linklet *)obj;
408 Scheme_Object *e, *a;
409
410 linklet = MALLOC_ONE_TAGGED(Scheme_Linklet);
411 linklet->so.type = scheme_linklet_type;
412
413 linklet->serializable = 1;
414
415 if (!SCHEME_PAIRP(obj)) return_NULL();
416 linklet->name = SCHEME_CAR(obj);
417 if (!SCHEME_SYMBOLP(linklet->name)) return_NULL();
418 obj = SCHEME_CDR(obj);
419
420 if (!SCHEME_PAIRP(obj)) return_NULL();
421 linklet->need_instance_access = SCHEME_TRUEP(SCHEME_CAR(obj));
422 obj = SCHEME_CDR(obj);
423
424 if (!SCHEME_PAIRP(obj)) return_NULL();
425 e = SCHEME_CAR(obj);
426 linklet->max_let_depth = SCHEME_INT_VAL(e);
427 obj = SCHEME_CDR(obj);
428
429 if (!SCHEME_PAIRP(obj)) return_NULL();
430 e = SCHEME_CAR(obj);
431 linklet->num_lifts = SCHEME_INT_VAL(e);
432 obj = SCHEME_CDR(obj);
433
434 if (!SCHEME_PAIRP(obj)) return_NULL();
435 e = SCHEME_CAR(obj);
436 linklet->num_exports = SCHEME_INT_VAL(e);
437 obj = SCHEME_CDR(obj);
438
439 if (!SCHEME_PAIRP(obj)) return_NULL();
440 a = SCHEME_CAR(obj);
441 if (!SCHEME_VECTORP(a)) return_NULL();
442 linklet->bodies = a;
443 obj = SCHEME_CDR(obj);
444
445 if (!SCHEME_PAIRP(obj)) return_NULL();
446 a = vector_to_hash_tree(SCHEME_CAR(obj));
447 if (!a) return_NULL();
448 linklet->source_names = (Scheme_Hash_Tree *)a;
449 obj = SCHEME_CDR(obj);
450
451 if (!SCHEME_PAIRP(obj)) return_NULL();
452 a = SCHEME_CAR(obj);
453 if (!is_vector_of_symbols(a, 1)) return_NULL();
454 linklet->defns = a;
455 obj = SCHEME_CDR(obj);
456
457 if (!SCHEME_PAIRP(obj)) return_NULL();
458 a = SCHEME_CAR(obj);
459 if (!is_vector_of_vector_of_symbols(a)) return_NULL();
460 linklet->importss = a;
461 obj = SCHEME_CDR(obj);
462
463 if (!SCHEME_PAIRP(obj)) return_NULL();
464 a = SCHEME_CAR(obj);
465 if (!SCHEME_FALSEP(a)) {
466 if (!is_vector_of_shapes(a)) return_NULL();
467 linklet->import_shapes = a;
468 }
469
470 if (linklet->num_exports > SCHEME_VEC_SIZE(linklet->defns))
471 return_NULL();
472 if (linklet->num_lifts > (SCHEME_VEC_SIZE(linklet->defns) - linklet->num_exports))
473 return_NULL();
474
475 {
476 int i = 0, j;
477 for (j = SCHEME_VEC_SIZE(linklet->importss); j--; ) {
478 i += SCHEME_VEC_SIZE(SCHEME_VEC_ELS(linklet->importss)[j]);
479 }
480 linklet->num_total_imports = i;
481 }
482
483 if (linklet->import_shapes) {
484 if (linklet->num_total_imports != SCHEME_VEC_SIZE(linklet->import_shapes))
485 return_NULL();
486 }
487
488 if (!unsafe_ok)
489 linklet->reject_eval = 1;
490
491 return (Scheme_Object *)linklet;
492 }
493