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