1 #include "schpriv.h"
2 #include "schrunst.h"
3 
4 READ_ONLY Scheme_Object *scheme_varref_const_p_proc;
5 READ_ONLY Scheme_Object *scheme_varref_unsafe_p_proc;
6 
7 SHARED_OK Scheme_Hash_Tree *empty_hash_tree;
8 
9 SHARED_OK static int validate_compile_result = 0;
10 SHARED_OK static int recompile_every_compile = 0;
11 SHARED_OK static int show_linklets = 0;
12 
13 static Scheme_Object *serializable_symbol;
14 static Scheme_Object *unsafe_symbol;
15 static Scheme_Object *static_symbol;
16 static Scheme_Object *use_prompt_symbol;
17 static Scheme_Object *uninterned_literal_symbol;
18 static Scheme_Object *quick_symbol;
19 static Scheme_Object *constant_symbol;
20 static Scheme_Object *consistent_symbol;
21 static Scheme_Object *noncm_symbol;
22 static Scheme_Object *immediate_symbol;
23 static Scheme_Object *omitable_symbol;
24 static Scheme_Object *folding_symbol;
25 
26 THREAD_LOCAL_DECL(Scheme_Hash_Table *local_primitive_tables);
27 THREAD_LOCAL_DECL(extern intptr_t scheme_code_page_total);
28 THREAD_LOCAL_DECL(extern intptr_t scheme_code_total);
29 THREAD_LOCAL_DECL(extern intptr_t scheme_code_count);
30 
31 static Scheme_Object *primitive_table(int argc, Scheme_Object **argv);
32 static Scheme_Object *primitive_to_position(int argc, Scheme_Object **argv);
33 static Scheme_Object *position_to_primitive(int argc, Scheme_Object **argv);
34 static Scheme_Object *primitive_in_category_p(int argc, Scheme_Object **argv);
35 static Scheme_Object *primitive_lookup(int argc, Scheme_Object **argv);
36 
37 static Scheme_Object *linklet_p(int argc, Scheme_Object **argv);
38 static Scheme_Object *compile_linklet(int argc, Scheme_Object **argv);
39 static Scheme_Object *recompile_linklet(int argc, Scheme_Object **argv);
40 static Scheme_Object *eval_linklet(int argc, Scheme_Object **argv);
41 static Scheme_Object *instantiate_linklet(int argc, Scheme_Object **argv);
42 static Scheme_Object *linklet_import_variables(int argc, Scheme_Object **argv);
43 static Scheme_Object *linklet_export_variables(int argc, Scheme_Object **argv);
44 
45 static Scheme_Object *linklet_vm_bytes(int argc, Scheme_Object **argv);
46 static Scheme_Object *write_linklet_bundle_hash(int argc, Scheme_Object **argv);
47 static Scheme_Object *read_linklet_bundle_hash(int argc, Scheme_Object **argv);
48 
49 static Scheme_Object *instance_p(int argc, Scheme_Object **argv);
50 static Scheme_Object *make_instance(int argc, Scheme_Object **argv);
51 static Scheme_Object *instance_name(int argc, Scheme_Object **argv);
52 static Scheme_Object *instance_data(int argc, Scheme_Object **argv);
53 static Scheme_Object *instance_variable_names(int argc, Scheme_Object **argv);
54 static Scheme_Object *instance_variable_value(int argc, Scheme_Object **argv);
55 static Scheme_Object *instance_set_variable_value(int argc, Scheme_Object **argv);
56 static Scheme_Object *instance_unset_variable(int argc, Scheme_Object **argv);
57 static Scheme_Object *instance_describe_variable(int argc, Scheme_Object **argv);
58 
59 static Scheme_Object *variable_p(int argc, Scheme_Object **argv);
60 static Scheme_Object *variable_instance(int argc, Scheme_Object **argv);
61 static Scheme_Object *variable_const_p(int argc, Scheme_Object **argv);
62 static Scheme_Object *variable_unsafe_p(int argc, Scheme_Object **argv);
63 
64 static Scheme_Linklet *compile_and_or_optimize_linklet(Scheme_Object *form, Scheme_Linklet *linklet,
65                                                        Scheme_Object *name,
66                                                        Scheme_Object **_import_keys,
67                                                        Scheme_Object *get_import,
68                                                        int unsafe_mode, int static_mode, int serializable);
69 
70 static Scheme_Object *_instantiate_linklet_multi(Scheme_Linklet *linklet, Scheme_Instance *instance,
71                                                  int num_instances, Scheme_Instance **instances,
72                                                  int use_prompt);
73 
74 static Scheme_Hash_Tree *push_prefix(Scheme_Linklet *linklet, Scheme_Instance *instance,
75                                      int num_instances, Scheme_Instance **instances,
76                                      Scheme_Hash_Tree *source_names);
77 static void pop_prefix();
78 static Scheme_Object *suspend_prefix();
79 static void resume_prefix(Scheme_Object *v);
80 
81 static Scheme_Bucket *make_bucket(Scheme_Object *key, Scheme_Object *val, Scheme_Instance *inst);
82 
83 #ifdef MZ_PRECISE_GC
84 static void mark_pruned_prefixes(struct NewGC *gc);
85 static int check_pruned_prefix(void *p);
86 #endif
87 
88 #ifdef MZ_PRECISE_GC
89 static void register_traversers(void);
90 #endif
91 
92 /*========================================================================*/
93 /*                             initialization                             */
94 /*========================================================================*/
95 
scheme_init_linklet(Scheme_Startup_Env * env)96 void scheme_init_linklet(Scheme_Startup_Env *env)
97 {
98 #ifdef MZ_PRECISE_GC
99   register_traversers();
100 #endif
101 
102   REGISTER_SO(serializable_symbol);
103   REGISTER_SO(unsafe_symbol);
104   REGISTER_SO(static_symbol);
105   REGISTER_SO(use_prompt_symbol);
106   REGISTER_SO(uninterned_literal_symbol);
107   REGISTER_SO(quick_symbol);
108   serializable_symbol = scheme_intern_symbol("serializable");
109   unsafe_symbol = scheme_intern_symbol("unsafe");
110   static_symbol = scheme_intern_symbol("static");
111   use_prompt_symbol = scheme_intern_symbol("use-prompt");
112   uninterned_literal_symbol = scheme_intern_symbol("uninterned-literal");
113   quick_symbol = scheme_intern_symbol("quick");
114 
115   REGISTER_SO(constant_symbol);
116   REGISTER_SO(consistent_symbol);
117   constant_symbol = scheme_intern_symbol("constant");
118   consistent_symbol = scheme_intern_symbol("consistent");
119 
120   REGISTER_SO(noncm_symbol);
121   REGISTER_SO(immediate_symbol);
122   REGISTER_SO(omitable_symbol);
123   REGISTER_SO(folding_symbol);
124   noncm_symbol = scheme_intern_symbol("noncm");
125   immediate_symbol = scheme_intern_symbol("immediate");
126   omitable_symbol = scheme_intern_symbol("omitable");
127   folding_symbol = scheme_intern_symbol("folding");
128 
129   scheme_switch_prim_instance(env, "#%linklet");
130 
131   ADD_IMMED_PRIM("primitive->compiled-position", primitive_to_position, 1, 1, env);
132   ADD_IMMED_PRIM("compiled-position->primitive", position_to_primitive, 1, 1, env);
133   ADD_IMMED_PRIM("primitive-in-category?", primitive_in_category_p, 2, 2, env);
134   ADD_IMMED_PRIM("primitive-lookup", primitive_lookup, 1, 1, env);
135 
136   ADD_FOLDING_PRIM("linklet?", linklet_p, 1, 1, 1, env);
137   ADD_PRIM_W_ARITY2("compile-linklet", compile_linklet, 1, 5, 2, 2, env);
138   ADD_PRIM_W_ARITY2("recompile-linklet", recompile_linklet, 1, 5, 2, 2, env);
139   ADD_IMMED_PRIM("eval-linklet", eval_linklet, 1, 1, env);
140   ADD_PRIM_W_ARITY2("instantiate-linklet", instantiate_linklet, 2, 4, 0, -1, env);
141   ADD_PRIM_W_ARITY("linklet-import-variables", linklet_import_variables, 1, 1, env);
142   ADD_PRIM_W_ARITY("linklet-export-variables", linklet_export_variables, 1, 1, env);
143 
144   ADD_PRIM_W_ARITY("linklet-virtual-machine-bytes", linklet_vm_bytes, 0, 0, env);
145   ADD_PRIM_W_ARITY("write-linklet-bundle-hash", write_linklet_bundle_hash, 2, 2, env);
146   ADD_PRIM_W_ARITY("read-linklet-bundle-hash", read_linklet_bundle_hash, 1, 1, env);
147 
148   ADD_FOLDING_PRIM("instance?", instance_p, 1, 1, 1, env);
149   ADD_PRIM_W_ARITY("make-instance", make_instance, 1, -1, env);
150   ADD_PRIM_W_ARITY("instance-name", instance_name, 1, 1, env);
151   ADD_PRIM_W_ARITY("instance-data", instance_data, 1, 1, env);
152   ADD_PRIM_W_ARITY("instance-variable-names", instance_variable_names, 1, 1, env);
153   ADD_PRIM_W_ARITY2("instance-variable-value", instance_variable_value, 2, 3, 0, -1, env);
154   ADD_PRIM_W_ARITY("instance-set-variable-value!", instance_set_variable_value, 3, 4, env);
155   ADD_PRIM_W_ARITY("instance-unset-variable!", instance_unset_variable, 2, 2, env);
156   ADD_PRIM_W_ARITY("instance-describe-variable!", instance_describe_variable, 3, 3, env);
157 
158   ADD_FOLDING_PRIM_UNARY_INLINED("variable-reference?", variable_p, 1, 1, 1, env);
159   ADD_IMMED_PRIM("variable-reference->instance", variable_instance, 1, 2, env);
160 
161   REGISTER_SO(scheme_varref_const_p_proc);
162   scheme_varref_const_p_proc = scheme_make_prim_w_arity(variable_const_p,
163                                                         "variable-reference-constant?",
164                                                         1, 1);
165   scheme_addto_prim_instance("variable-reference-constant?", scheme_varref_const_p_proc, env);
166 
167   REGISTER_SO(scheme_varref_unsafe_p_proc);
168   scheme_varref_unsafe_p_proc = scheme_make_prim_w_arity(variable_unsafe_p,
169                                                          "variable-reference-from-unsafe?",
170                                                          1, 1);
171   scheme_addto_prim_instance("variable-reference-from-unsafe?", scheme_varref_unsafe_p_proc, env);
172 
173   scheme_restore_prim_instance(env);
174 
175   if (scheme_getenv("PLT_VALIDATE_COMPILE")) {
176     /* Enables validation of bytecode as it is generated,
177        to double-check that the compiler is producing
178        valid bytecode as it should. */
179     validate_compile_result = 1;
180   }
181 
182   {
183     /* Enables re-running the optimizer N times on every compilation. */
184     const char *s;
185     s = scheme_getenv("PLT_RECOMPILE_COMPILE");
186     if (s) {
187       int i = 0;
188       while ((s[i] >= '0') && (s[i] <= '9')) {
189         recompile_every_compile = (recompile_every_compile * 10) + (s[i]-'0');
190         i++;
191       }
192       if (recompile_every_compile <= 0)
193         recompile_every_compile = 1;
194       else if (recompile_every_compile > 32)
195         recompile_every_compile = 32;
196     }
197   }
198 
199   if (scheme_getenv("PLT_LINKLET_SHOW"))
200     show_linklets = 1;
201 }
202 
scheme_init_unsafe_linklet(Scheme_Startup_Env * env)203 void scheme_init_unsafe_linklet(Scheme_Startup_Env *env)
204 {
205 #ifdef MZ_PRECISE_GC
206   register_traversers();
207 #endif
208 
209   scheme_switch_prim_instance(env, "#%linklet");
210 
211   ADD_IMMED_PRIM("primitive-table", primitive_table, 1, 2, env);
212 
213   scheme_restore_prim_instance(env);
214 }
215 
scheme_init_linklet_places(void)216 void scheme_init_linklet_places(void)
217 {
218 #ifdef MZ_PRECISE_GC
219   scheme_prefix_finalize = (Scheme_Prefix *)0x1; /* 0x1 acts as a sentenel */
220   scheme_inc_prefix_finalize = (Scheme_Prefix *)0x1;
221   GC_set_post_propagate_hook(mark_pruned_prefixes);
222   GC_set_treat_as_incremental_mark(scheme_prefix_type, check_pruned_prefix);
223 #endif
224 }
225 
226 /*========================================================================*/
227 /*                    linklet and instance functions                      */
228 /*========================================================================*/
229 
primitive_table(int argc,Scheme_Object * argv[])230 static Scheme_Object *primitive_table(int argc, Scheme_Object *argv[])
231 {
232   Scheme_Hash_Table *table;
233 
234   if (!SCHEME_SYMBOLP(argv[0]))
235     scheme_wrong_contract("primitive-table", "symbol?", 0, argc, argv);
236   if ((argc > 1) && !SCHEME_HASHTRP(argv[1]))
237     scheme_wrong_contract("primitive-table", "(and/c hash? immutable?)", 1, argc, argv);
238 
239   table = (Scheme_Hash_Table *)scheme_hash_get(scheme_startup_env->primitive_tables, argv[0]);
240   if (!table && local_primitive_tables)
241     table = (Scheme_Hash_Table *)scheme_hash_get(local_primitive_tables, argv[0]);
242 
243   if (!table) {
244     if (argc > 1) {
245       if (!local_primitive_tables) {
246         REGISTER_SO(local_primitive_tables);
247         local_primitive_tables = scheme_make_hash_table(SCHEME_hash_ptr);
248       }
249       scheme_hash_set(local_primitive_tables, argv[0], argv[1]);
250     } else
251       return scheme_false;
252   }
253 
254   if (argc < 2)
255     return (Scheme_Object *)table;
256   else
257     return scheme_void;
258 }
259 
primitive_to_position(int argc,Scheme_Object ** argv)260 static Scheme_Object *primitive_to_position(int argc, Scheme_Object **argv)
261 {
262   Scheme_Object *pos;
263   pos = scheme_hash_get(scheme_startup_env->primitive_ids_table, argv[0]);
264   return (pos ? pos : scheme_false);
265 }
266 
position_to_primitive(int argc,Scheme_Object ** argv)267 static Scheme_Object *position_to_primitive(int argc, Scheme_Object **argv)
268 {
269   Scheme_Object *v;
270   if (SCHEME_INTP(argv[0]) && (SCHEME_INT_VAL(argv[0]) >= 0))
271     v = scheme_position_to_builtin(SCHEME_INT_VAL(argv[0]));
272   else
273     v = NULL;
274   return (v ? v : scheme_false);
275 }
276 
primitive_in_category_p(int argc,Scheme_Object ** argv)277 static Scheme_Object *primitive_in_category_p(int argc, Scheme_Object **argv)
278 {
279   Scheme_Object *v, *cat;
280   int r;
281 
282   if (!SCHEME_SYMBOLP(argv[0]))
283     scheme_wrong_contract("primitive-in-category?", "symbol?", 0, argc, argv);
284   cat = argv[1];
285   if (!SCHEME_SYMBOLP(cat))
286     scheme_wrong_contract("primitive-in-category?", "symbol?", 1, argc, argv);
287 
288   v = scheme_hash_get(scheme_startup_env->all_primitives_table, argv[0]);
289   if (!v)
290     r = 0;
291   else if (SCHEME_PRIMP(v)) {
292     int opt = ((Scheme_Prim_Proc_Header *)v)->flags & SCHEME_PRIM_OPT_MASK;
293     if (SAME_OBJ(cat, noncm_symbol)) {
294       r = (opt >= SCHEME_PRIM_OPT_NONCM);
295       /* Remove closures from noncm */
296       if (((Scheme_Prim_Proc_Header *)v)->flags & SCHEME_PRIM_IS_CLOSURE)
297         r = 0;
298     } else if (SAME_OBJ(cat, immediate_symbol))
299       r  = (opt >= SCHEME_PRIM_OPT_IMMEDIATE);
300     else if (SAME_OBJ(cat, folding_symbol))
301       r = (opt >= SCHEME_PRIM_OPT_FOLDING);
302     else if (SAME_OBJ(cat, omitable_symbol))
303       r = (SCHEME_PRIM_PROC_OPT_FLAGS(v) & (SCHEME_PRIM_IS_OMITABLE
304                                             | SCHEME_PRIM_IS_OMITABLE_ALLOCATION
305                                             | SCHEME_PRIM_IS_UNSAFE_OMITABLE
306                                             | SCHEME_PRIM_IS_UNSAFE_FUNCTIONAL));
307     else
308       r = 0;
309   } else
310     r = 0;
311 
312   return (r ? scheme_true : scheme_false);
313 }
314 
primitive_lookup(int argc,Scheme_Object ** argv)315 static Scheme_Object *primitive_lookup(int argc, Scheme_Object **argv)
316 {
317   Scheme_Object *v;
318 
319   if (!SCHEME_SYMBOLP(argv[0]))
320     scheme_wrong_contract("primitive-lookup", "symbol?", 0, argc, argv);
321 
322   v = scheme_hash_get(scheme_startup_env->all_primitives_table, argv[0]);
323 
324   return (v ? v : scheme_false);
325 }
326 
linklet_p(int argc,Scheme_Object ** argv)327 static Scheme_Object *linklet_p(int argc, Scheme_Object **argv)
328 {
329   return (SAME_TYPE(SCHEME_TYPE(argv[0]), scheme_linklet_type)
330           ? scheme_true
331           : scheme_false);
332 }
333 
check_linklet_allowed(const char * who,Scheme_Linklet * linklet)334 static void check_linklet_allowed(const char *who, Scheme_Linklet *linklet)
335 {
336   if (linklet->reject_eval) {
337     scheme_raise_exn(MZEXN_FAIL,
338                      "%s: cannot use unsafe linklet loaded with non-original code inspector",
339                      who);
340   }
341 }
342 
extract_import_info(const char * who,int argc,Scheme_Object ** argv,Scheme_Object ** _import_keys,Scheme_Object ** _get_import)343 void extract_import_info(const char *who, int argc, Scheme_Object **argv,
344                          Scheme_Object **_import_keys, Scheme_Object **_get_import)
345 {
346 
347   if (argc > 2) {
348     *_import_keys = argv[2];
349     if (SCHEME_FALSEP(*_import_keys))
350       *_import_keys = NULL;
351     else if (!SCHEME_VECTORP(*_import_keys))
352       scheme_wrong_contract(who, "(or/c vector? #f)", 2, argc, argv);
353   } else
354     *_import_keys = NULL;
355 
356   if (argc > 3) {
357     scheme_check_proc_arity2(who, 1, 3, argc, argv, 1);
358     if (SCHEME_TRUEP(argv[3])) {
359       if (!*_import_keys) {
360         scheme_contract_error(who,
361                               "no vector supplied for import keys, but import-getting function provided;\n"
362                               " the function argument must be `#f` when the vector argument is `#f`",
363                               "import-getting function", 1, argv[3],
364                               NULL);
365       }
366       *_get_import = argv[3];
367     } else
368       *_get_import = NULL;
369   } else
370     *_get_import = NULL;
371 }
372 
parse_compile_options(const char * who,int arg_pos,int argc,Scheme_Object ** argv,int * _unsafe,int * _static_mode,int * _serializable)373 static void parse_compile_options(const char *who, int arg_pos,
374                                   int argc, Scheme_Object **argv,
375                                   int *_unsafe, int *_static_mode,
376                                   int *_serializable)
377 {
378   Scheme_Object *redundant = NULL, *flag, *flags = argv[arg_pos];
379   int serializable = 0;
380   int unsafe = *_unsafe;
381   int static_mode = *_static_mode;
382   int use_prompt_mode = 0;
383   int uninterned_literal_mode = 0;
384   int quick_mode = 0;
385 
386   while (SCHEME_PAIRP(flags)) {
387     flag = SCHEME_CAR(flags);
388     if (SAME_OBJ(flag, serializable_symbol)) {
389       if (serializable && !redundant)
390         redundant = flag;
391       serializable = 1;
392     } else if (SAME_OBJ(flag, unsafe_symbol)) {
393       if (unsafe && !redundant)
394         redundant = flag;
395       unsafe = 1;
396     } else if (SAME_OBJ(flag, static_symbol)) {
397       if (static_mode && !redundant)
398         redundant = flag;
399       static_mode = 1;
400     } else if (SAME_OBJ(flag, use_prompt_symbol)) {
401       if (use_prompt_mode && !redundant)
402         redundant = flag;
403       use_prompt_mode = 1;
404     } else if (SAME_OBJ(flag, uninterned_literal_symbol)) {
405       if (uninterned_literal_mode && !redundant)
406         redundant = flag;
407       uninterned_literal_mode = 1;
408     } else if (SAME_OBJ(flag, quick_symbol)) {
409       if (quick_mode && !redundant)
410         redundant = flag;
411       quick_mode = 1;
412     } else
413       break;
414     flags = SCHEME_CDR(flags);
415   }
416 
417   if (!SCHEME_NULLP(flags))
418     scheme_wrong_contract("compile-linklet",
419                           "(listof/c 'serializable 'unsafe 'static 'use-prompt 'uninterned-literal 'quick)",
420                           arg_pos, argc, argv);
421 
422   if (redundant)
423     scheme_contract_error("compile-linklet", "redundant option",
424                           "redundant option", 1, redundant,
425                           "supplied options", 1, argv[arg_pos],
426                           NULL);
427 
428   *_unsafe = unsafe;
429   *_static_mode = static_mode;
430   *_serializable = serializable;
431 }
432 
compile_linklet(int argc,Scheme_Object ** argv)433 static Scheme_Object *compile_linklet(int argc, Scheme_Object **argv)
434 {
435   Scheme_Object *name, *e, *import_keys, *get_import, *a[2];
436   int unsafe = 0, static_mode = 0, serializable = 1;
437 
438   extract_import_info("compile-linklet", argc, argv, &import_keys, &get_import);
439 
440   if ((argc > 1) && SCHEME_TRUEP(argv[1]))
441     name = argv[1];
442   else
443     name = scheme_intern_symbol("anonymous");
444 
445   e = argv[0];
446   if (!SCHEME_STXP(e))
447     e = scheme_datum_to_syntax(e, scheme_false, DTS_CAN_GRAPH);
448 
449   if (show_linklets) {
450     char *s;
451     intptr_t s_len;
452     s = scheme_write_to_string(scheme_syntax_to_datum(e), &s_len);
453     printf("%s\n", s);
454   }
455 
456   if (argc > 4)
457     parse_compile_options("compile-linklet", 4, argc, argv, &unsafe, &static_mode, &serializable);
458 
459   e = (Scheme_Object *)compile_and_or_optimize_linklet(e, NULL, name, &import_keys, get_import,
460                                                        unsafe, static_mode, serializable);
461 
462   if (import_keys) {
463     a[0] = e;
464     a[1] = import_keys;
465     return scheme_values(2, a);
466   } else
467     return e;
468 }
469 
recompile_linklet(int argc,Scheme_Object ** argv)470 static Scheme_Object *recompile_linklet(int argc, Scheme_Object **argv)
471 {
472   Scheme_Object *name, *import_keys, *get_import, *a[2];
473   Scheme_Linklet *linklet;
474   int unsafe = 0, static_mode = 0, serializable = 1;
475 
476   if (!SAME_TYPE(SCHEME_TYPE(argv[0]), scheme_linklet_type))
477     scheme_wrong_contract("recompile-linklet", "linklet?", 0, argc, argv);
478 
479   linklet = (Scheme_Linklet *)argv[0];
480 
481   check_linklet_allowed("recompile-linklet", linklet);
482 
483   extract_import_info("recompile-linklet", argc, argv, &import_keys, &get_import);
484 
485   if ((argc > 1) && SCHEME_TRUEP(argv[1]))
486     name = argv[1];
487   else
488     name = ((Scheme_Linklet *)argv[0])->name;
489 
490   if (import_keys && (SCHEME_VEC_SIZE(import_keys) != SCHEME_VEC_SIZE(linklet->importss))) {
491     scheme_contract_error("recompile-linklet",
492                           "given number of import keys does not match import count of linklet",
493                           "linklet", 1, linklet,
494                           "linklet imports", 1, scheme_make_integer(SCHEME_VEC_SIZE(linklet->importss)),
495                           "given keys", 1, scheme_make_integer(SCHEME_VEC_SIZE(import_keys)),
496                           NULL);
497   }
498 
499   if (argc > 4)
500     parse_compile_options("recompile-linklet", 4, argc, argv, &unsafe, &static_mode, &serializable);
501 
502   linklet = compile_and_or_optimize_linklet(NULL, linklet, name, &import_keys, get_import,
503                                             unsafe, static_mode, serializable);
504 
505   if (import_keys) {
506     a[0] = (Scheme_Object *)linklet;
507     a[1] = import_keys;
508 
509     return scheme_values(2, a);
510   } else
511     return (Scheme_Object *)linklet;
512 }
513 
eval_linklet(int argc,Scheme_Object ** argv)514 static Scheme_Object *eval_linklet(int argc, Scheme_Object **argv)
515 {
516   /* "Evaluation" is not necessary before instantiation, but it makes
517      the linklet JIT-prepared (so the JIT-prepared linklet could be
518      reused, for example) while also making the linklet ineligible for
519      marshaling. */
520   Scheme_Linklet *linklet;
521 
522   if (!SAME_TYPE(SCHEME_TYPE(argv[0]), scheme_linklet_type))
523     scheme_wrong_contract("eval-linklet", "linklet?", 0, argc, argv);
524 
525   linklet = (Scheme_Linklet *)argv[0];
526 
527   check_linklet_allowed("eval-linklet", linklet);
528 
529   if (!linklet->jit_ready) {
530     Scheme_Object *b;
531     b = scheme_get_param(scheme_current_config(), MZCONFIG_USE_JIT);
532     if (SCHEME_TRUEP(b)) {
533       /* Make a JIT-prepable linklet --- but don't actually prep until
534          forced by instantiation. */
535       linklet = scheme_jit_linklet(linklet, 1);
536     }
537   }
538 
539 #ifdef MZ_USE_JIT
540   if (linklet->native_lambdas) {
541     Scheme_Object *l;
542     l = linklet->native_lambdas;
543     linklet->native_lambdas = NULL;
544     while (SCHEME_PAIRP(l)) {
545       scheme_force_jit_generate((Scheme_Native_Lambda *)SCHEME_CAR(l));
546       l = SCHEME_CDR(l);
547     }
548   }
549 #endif
550 
551   return (Scheme_Object *)linklet;
552 }
553 
linklet_vm_bytes(int argc,Scheme_Object ** argv)554 static Scheme_Object *linklet_vm_bytes(int argc, Scheme_Object **argv)
555 {
556   return scheme_make_byte_string("racket");
557 }
558 
read_linklet_bundle_hash(int argc,Scheme_Object ** argv)559 static Scheme_Object *read_linklet_bundle_hash(int argc, Scheme_Object **argv)
560 {
561   if (!SCHEME_INPUT_PORTP(argv[0]))
562     scheme_wrong_contract("read-linklet-bundle-hash", "input-port?", 0, argc, argv);
563 
564   return scheme_read_linklet_bundle_hash(argv[0]);
565 }
566 
write_linklet_bundle_hash(int argc,Scheme_Object ** argv)567 static Scheme_Object *write_linklet_bundle_hash(int argc, Scheme_Object **argv)
568 {
569   mzlonglong pos;
570   Scheme_Object *k, *v;
571   Scheme_Hash_Tree *hash;
572 
573   if (!SCHEME_HASHTRP(argv[0])
574       || !SAME_TYPE(scheme_eq_hash_tree_type, SCHEME_HASHTR_TYPE(argv[0])))
575     scheme_wrong_contract("write-linklet-bundle-hash",
576                           "(and/c hash? hash-eq? immutable? (not/c impersonator?))",
577                           0, argc, argv);
578 
579   if (!SCHEME_OUTPUT_PORTP(argv[1]))
580     scheme_wrong_contract("write-linklet-bundle-hash", "output-port?", 0, argc, argv);
581 
582   hash = (Scheme_Hash_Tree *)argv[0];
583 
584   /* mapping: keys must be symbols and fixnums */
585 
586   pos = scheme_hash_tree_next(hash, -1);
587   while (pos != -1) {
588     scheme_hash_tree_index(hash, pos, &k, &v);
589     if (!SCHEME_SYMBOLP(k) && !SCHEME_INTP(k)) {
590       scheme_contract_error("write-linklet-bundle-hash",
591                             "key in given hash is not a symbol or fixnum",
592                             "key", 1, k,
593                             NULL);
594     }
595     pos = scheme_hash_tree_next(hash, pos);
596   }
597 
598   v = scheme_alloc_small_object();
599   v->type = scheme_linklet_bundle_type;
600   SCHEME_PTR_VAL(v) = argv[0];
601 
602   scheme_write(v, argv[1]);
603 
604   return scheme_void;
605 }
606 
instantiate_linklet(int argc,Scheme_Object ** argv)607 static Scheme_Object *instantiate_linklet(int argc, Scheme_Object **argv)
608 {
609   Scheme_Linklet *linklet;
610   Scheme_Object *l;
611   Scheme_Instance *inst, **instances;
612   int len = 0, num_importss, use_prompt, return_instance;
613 
614   if (!SAME_TYPE(SCHEME_TYPE(argv[0]), scheme_linklet_type))
615     scheme_wrong_contract("instantiate-linklet", "linklet?", 0, argc, argv);
616 
617   l = argv[1];
618   while (SCHEME_PAIRP(l)) {
619     if (!SAME_TYPE(SCHEME_TYPE(SCHEME_CAR(l)), scheme_instance_type))
620       break;
621     l = SCHEME_CDR(l);
622     len++;
623   }
624   if (!SCHEME_NULLP(l))
625     scheme_wrong_contract("instantiate-linklet", "(listof instance?)", 1, argc, argv);
626 
627   linklet = (Scheme_Linklet *)argv[0];
628   check_linklet_allowed("instantiate-linklet", linklet);
629   num_importss = SCHEME_VEC_SIZE(linklet->importss);
630   if (len != num_importss)
631     scheme_contract_error("instantiate-linklet",
632                           "given number of instances does not match import count of linklet",
633                           "linklet", 1, linklet,
634                           "expected imports", 1, scheme_make_integer(num_importss),
635                           "given instances", 1, scheme_make_integer(len),
636                           NULL);
637 
638   if ((argc > 2) && SCHEME_TRUEP(argv[2])) {
639     if (!SAME_TYPE(SCHEME_TYPE(argv[2]), scheme_instance_type))
640       scheme_wrong_contract("instantiate-linklet", "(or/c instance? #f)", 2, argc, argv);
641     inst = (Scheme_Instance *)argv[2];
642     return_instance = 0;
643   } else {
644     inst = scheme_make_instance(linklet->name, scheme_false);
645     return_instance = 1;
646   }
647 
648   use_prompt = ((argc < 4) || SCHEME_TRUEP(argv[3]));
649 
650   instances = MALLOC_N(Scheme_Instance*, len);
651   l = argv[1];
652   len = 0;
653   while (!SCHEME_NULLP(l)) {
654     instances[len++] = (Scheme_Instance *)SCHEME_CAR(l);
655     l = SCHEME_CDR(l);
656   }
657 
658   if (!return_instance)
659     return _instantiate_linklet_multi(linklet, inst, len, instances, use_prompt);
660   else {
661     (void)_instantiate_linklet_multi(linklet, inst, len, instances, use_prompt);
662     return (Scheme_Object *)inst;
663   }
664 }
665 
linklet_import_variables(int argc,Scheme_Object ** argv)666 static Scheme_Object *linklet_import_variables(int argc, Scheme_Object **argv)
667 {
668   Scheme_Linklet *linklet;
669   int i, j;
670   Scheme_Object *l, *ll = scheme_null;
671 
672   if (!SAME_TYPE(SCHEME_TYPE(argv[0]), scheme_linklet_type))
673     scheme_wrong_contract("linklet-import-variables", "linklet?", 0, argc, argv);
674 
675   linklet = (Scheme_Linklet *)argv[0];
676 
677   for (i = SCHEME_VEC_SIZE(linklet->importss); i--; ) {
678     l = scheme_null;
679     for (j = SCHEME_VEC_SIZE(SCHEME_VEC_ELS(linklet->importss)[i]); j--; ) {
680       l = scheme_make_pair(SCHEME_VEC_ELS(SCHEME_VEC_ELS(linklet->importss)[i])[j], l);
681     }
682     ll = scheme_make_pair(l, ll);
683   }
684 
685   return ll;
686 }
687 
linklet_export_variables(int argc,Scheme_Object ** argv)688 static Scheme_Object *linklet_export_variables(int argc, Scheme_Object **argv)
689 {
690   Scheme_Linklet *linklet;
691   int i;
692   Scheme_Object *l = scheme_null;
693 
694   if (!SAME_TYPE(SCHEME_TYPE(argv[0]), scheme_linklet_type))
695     scheme_wrong_contract("linklet-export-variables", "linklet?", 0, argc, argv);
696 
697   linklet = (Scheme_Linklet *)argv[0];
698 
699   for (i = linklet->num_exports; i--; ) {
700     l = scheme_make_pair(SCHEME_VEC_ELS(linklet->defns)[i], l);
701   }
702 
703   return l;
704 }
705 
instance_p(int argc,Scheme_Object ** argv)706 static Scheme_Object *instance_p(int argc, Scheme_Object **argv)
707 {
708   return (SAME_TYPE(SCHEME_TYPE(argv[0]), scheme_instance_type)
709           ? scheme_true
710           : scheme_false);
711 }
712 
parse_constantness_flag(const char * who,int i,int argc,Scheme_Object ** argv)713 static int parse_constantness_flag(const char *who, int i, int argc, Scheme_Object **argv)
714 {
715   int set_flags = 0;
716 
717   if (SCHEME_FALSEP(argv[i]))
718     set_flags = 0;
719   else if (SAME_OBJ(argv[i], constant_symbol))
720     set_flags = GLOB_IS_IMMUTATED;
721   else if (SAME_OBJ(argv[i], consistent_symbol))
722     set_flags = GLOB_IS_IMMUTATED | GLOB_IS_CONSISTENT;
723   else
724     scheme_wrong_contract(who, "(or/c #f 'constant 'consistent)", i, argc, argv);
725 
726   return set_flags;
727 }
728 
make_instance(int argc,Scheme_Object ** argv)729 static Scheme_Object *make_instance(int argc, Scheme_Object **argv)
730 {
731   Scheme_Instance *inst;
732   int i;
733 
734   inst = scheme_make_instance(argv[0], (argc > 1) ? argv[1] : scheme_false);
735 
736   if (argc > 3) {
737     Scheme_Bucket **a, *b;
738     int set_flags = 0;
739 
740     set_flags = parse_constantness_flag("make-instance", 2, argc, argv);
741 
742     i = 3;
743     a = MALLOC_N(Scheme_Bucket *, (argc - i) >> 1);
744 
745     for (; i < argc; i += 2) {
746       if (!SCHEME_SYMBOLP(argv[i]))
747         scheme_wrong_contract("make-instance", "symbol?", i, argc, argv);
748       if (i+1 == argc)
749         scheme_contract_error("make-instance",
750                               "value missing for variable name",
751                               "variable name", 1, argv[i],
752                               NULL);
753       b = make_bucket(argv[i], argv[i+1], inst);
754       if (set_flags)
755         ((Scheme_Bucket_With_Flags *)b)->flags |= set_flags;
756       a[(i-2)>>1] = b;
757     }
758 
759     inst->array_size = (argc-2)>>1;
760     inst->variables.a = a;
761   }
762 
763   return (Scheme_Object *)inst;
764 }
765 
instance_name(int argc,Scheme_Object ** argv)766 static Scheme_Object *instance_name(int argc, Scheme_Object **argv)
767 {
768   if (!SAME_TYPE(SCHEME_TYPE(argv[0]), scheme_instance_type))
769     scheme_wrong_contract("instance-name", "instance?", 0, argc, argv);
770 
771   return ((Scheme_Instance *)argv[0])->name;
772 }
773 
instance_data(int argc,Scheme_Object ** argv)774 static Scheme_Object *instance_data(int argc, Scheme_Object **argv)
775 {
776   if (!SAME_TYPE(SCHEME_TYPE(argv[0]), scheme_instance_type))
777     scheme_wrong_contract("instance-data", "instance?", 0, argc, argv);
778 
779   return ((Scheme_Instance *)argv[0])->data;
780 }
781 
instance_variable_names(int argc,Scheme_Object ** argv)782 static Scheme_Object *instance_variable_names(int argc, Scheme_Object **argv)
783 {
784   Scheme_Bucket *b;
785   int i;
786   Scheme_Object *l = scheme_null;
787   Scheme_Instance *inst;
788 
789   if (!SAME_TYPE(SCHEME_TYPE(argv[0]), scheme_instance_type))
790     scheme_wrong_contract("instance-variable-names", "instance?", 0, argc, argv);
791 
792   inst = (Scheme_Instance *)argv[0];
793 
794   if (inst->array_size) {
795     for (i = inst->array_size; i--; ) {
796       l = scheme_make_pair((Scheme_Object *)inst->variables.a[i]->key, l);
797     }
798   } else if (inst->variables.bt) {
799     for (i = inst->variables.bt->size; i--; ) {
800       b = inst->variables.bt->buckets[i];
801       if (b && b->val) {
802         l = scheme_make_pair((Scheme_Object *)b->key, l);
803       }
804     }
805   }
806 
807   return l;
808 }
809 
instance_variable_value(int argc,Scheme_Object ** argv)810 static Scheme_Object *instance_variable_value(int argc, Scheme_Object **argv)
811 {
812   Scheme_Instance *inst;
813   Scheme_Bucket *b;
814 
815   if (!SAME_TYPE(SCHEME_TYPE(argv[0]), scheme_instance_type))
816     scheme_wrong_contract("instance-variable-value", "instance?", 0, argc, argv);
817   if (!SCHEME_SYMBOLP(argv[1]))
818     scheme_wrong_contract("instance-variable-value", "symbol?", 1, argc, argv);
819 
820   inst = (Scheme_Instance *)argv[0];
821 
822   b = scheme_instance_variable_bucket_or_null(argv[1], inst);
823   if (b && b->val)
824     return b->val;
825 
826   if (argc > 2) {
827     if (SCHEME_PROCP(argv[2]))
828       return _scheme_tail_apply(argv[2], 0, NULL);
829     return argv[2];
830   }
831 
832   scheme_raise_exn(MZEXN_FAIL_CONTRACT,
833                    "instance-variable-value: instance variable not found\n"
834                    "  instance: %V\n"
835                    "  name: %S",
836                    inst->name,
837                    argv[1]);
838   return NULL;
839 }
840 
instance_set_variable_value(int argc,Scheme_Object ** argv)841 static Scheme_Object *instance_set_variable_value(int argc, Scheme_Object **argv)
842 {
843   Scheme_Bucket *b;
844   int set_flags = 0;
845 
846   if (!SAME_TYPE(SCHEME_TYPE(argv[0]), scheme_instance_type))
847     scheme_wrong_contract("instance-set-variable-value!", "instance?", 0, argc, argv);
848   if (!SCHEME_SYMBOLP(argv[1]))
849     scheme_wrong_contract("instance-set-variable-value!", "symbol?", 1, argc, argv);
850   if (argc > 3)
851     set_flags = parse_constantness_flag("instance-set-variable-value!", 3, argc, argv);
852 
853   b = scheme_instance_variable_bucket(argv[1], (Scheme_Instance *)argv[0]);
854 
855   scheme_set_global_bucket("instance-set-variable-value!", b, argv[2], 1);
856 
857   b->val = argv[2];
858   if (set_flags)
859     ((Scheme_Bucket_With_Flags *)b)->flags |= set_flags;
860 
861   return scheme_void;
862 }
863 
instance_unset_variable(int argc,Scheme_Object ** argv)864 static Scheme_Object *instance_unset_variable(int argc, Scheme_Object **argv)
865 {
866   Scheme_Bucket *b;
867 
868   if (!SAME_TYPE(SCHEME_TYPE(argv[0]), scheme_instance_type))
869     scheme_wrong_contract("instance-unset-variable!", "instance?", 0, argc, argv);
870   if (!SCHEME_SYMBOLP(argv[1]))
871     scheme_wrong_contract("instance-unset-variable!", "symbol?", 1, argc, argv);
872 
873   b = scheme_instance_variable_bucket(argv[1], (Scheme_Instance *)argv[0]);
874   b->val = NULL;
875 
876   return scheme_void;
877 }
878 
instance_describe_variable(int argc,Scheme_Object ** argv)879 static Scheme_Object *instance_describe_variable(int argc, Scheme_Object **argv)
880 {
881   if (!SAME_TYPE(SCHEME_TYPE(argv[0]), scheme_instance_type))
882     scheme_wrong_contract("instance-describe-variable!", "instance?", 0, argc, argv);
883   if (!SCHEME_SYMBOLP(argv[1]))
884     scheme_wrong_contract("instance-describe-variable!", "symbol?", 1, argc, argv);
885 
886   return scheme_void;
887 }
888 
variable_p(int argc,Scheme_Object ** argv)889 static Scheme_Object *variable_p(int argc, Scheme_Object **argv)
890 {
891   return (SAME_TYPE(SCHEME_TYPE(argv[0]), scheme_global_ref_type)
892           ? scheme_true
893           : scheme_false);
894 }
895 
variable_instance(int argc,Scheme_Object ** argv)896 static Scheme_Object *variable_instance(int argc, Scheme_Object **argv)
897 {
898   Scheme_Object *v;
899 
900   v = argv[0];
901 
902   if (!SAME_TYPE(SCHEME_TYPE(v), scheme_global_ref_type))
903     scheme_wrong_contract("variable-reference->instance", "variable-reference?", 0, argc, argv);
904 
905   if ((argc < 2) || SCHEME_FALSEP(argv[1])) {
906     /* Definition instance might be a primitive-table symbol, or it might be #f for "anonymous": */
907     v = SCHEME_PTR1_VAL(argv[0]);
908     if (SCHEME_SYMBOLP(v) || SCHEME_FALSEP(v))
909       return v;
910     else if (SAME_OBJ(v, scheme_true))
911       return SCHEME_PTR2_VAL(argv[0]); /* same as use instance for a local */
912     else {
913       v = (Scheme_Object *)scheme_get_bucket_home((Scheme_Bucket *)v);
914       if (!v) {
915         /* The definition instance was GCed? Return the use-site instance */
916         return SCHEME_PTR2_VAL(argv[0]);
917       }
918       return v;
919     }
920   } else {
921     /* Get use instance: */
922     return SCHEME_PTR2_VAL(argv[0]);
923   }
924 }
925 
variable_const_p(int argc,Scheme_Object ** argv)926 static Scheme_Object *variable_const_p(int argc, Scheme_Object **argv)
927 {
928   Scheme_Object *v;
929 
930   v = argv[0];
931 
932   if (!SAME_TYPE(SCHEME_TYPE(v), scheme_global_ref_type))
933     scheme_wrong_contract("variable-reference-constant?", "variable-reference?", 0, argc, argv);
934 
935   if (SCHEME_VARREF_FLAGS(v) & VARREF_IS_CONSTANT)
936     return scheme_true;
937 
938   v = SCHEME_PTR1_VAL(v);
939   if (!SCHEME_FALSEP(v)) {
940     if (SCHEME_SYMBOLP(v)
941         || (((Scheme_Bucket_With_Flags *)v)->flags & GLOB_IS_IMMUTATED))
942       return scheme_true;
943   }
944 
945   return scheme_false;
946 }
947 
variable_unsafe_p(int argc,Scheme_Object ** argv)948 static Scheme_Object *variable_unsafe_p(int argc, Scheme_Object **argv)
949 {
950   Scheme_Object *v;
951 
952   v = argv[0];
953 
954   if (!SAME_TYPE(SCHEME_TYPE(v), scheme_global_ref_type))
955     scheme_wrong_contract("variable-reference-from-unsafe?", "variable-reference?", 0, argc, argv);
956 
957   if (SCHEME_VARREF_FLAGS(v) & VARREF_FROM_UNSAFE)
958     return scheme_true;
959   else
960     return scheme_false;
961 }
962 
963 /*========================================================================*/
964 /*                       instance variable buckets                        */
965 /*========================================================================*/
966 
scheme_get_home_weak_link(Scheme_Instance * i)967 Scheme_Object *scheme_get_home_weak_link(Scheme_Instance *i)
968 {
969   if (!i->weak_self_link) {
970     Scheme_Object *wb;
971     if (scheme_starting_up)
972       wb = scheme_box((Scheme_Object *)i);
973     else
974       wb = scheme_make_weak_box((Scheme_Object *)i);
975     i->weak_self_link = wb;
976   }
977 
978   return i->weak_self_link;
979 }
980 
scheme_get_bucket_home(Scheme_Bucket * b)981 Scheme_Instance *scheme_get_bucket_home(Scheme_Bucket *b)
982 {
983   Scheme_Object *l;
984 
985   l = ((Scheme_Bucket_With_Home *)b)->home_link;
986   if (l) {
987     if (((Scheme_Bucket_With_Flags *)b)->flags & GLOB_STRONG_HOME_LINK)
988       return (Scheme_Instance *)l;
989     else
990       return (Scheme_Instance *)SCHEME_WEAK_BOX_VAL(l);
991   } else
992     return NULL;
993 }
994 
scheme_set_bucket_home(Scheme_Bucket * b,Scheme_Instance * e)995 void scheme_set_bucket_home(Scheme_Bucket *b, Scheme_Instance *e)
996 {
997   if (!((Scheme_Bucket_With_Home *)b)->home_link) {
998     if (((Scheme_Bucket_With_Flags *)b)->flags & GLOB_STRONG_HOME_LINK)
999       ((Scheme_Bucket_With_Home *)b)->home_link = (Scheme_Object *)e;
1000     else {
1001       Scheme_Object *link;
1002       link = scheme_get_home_weak_link(e);
1003       ((Scheme_Bucket_With_Home *)b)->home_link = link;
1004     }
1005   }
1006 }
1007 
make_bucket(Scheme_Object * key,Scheme_Object * val,Scheme_Instance * inst)1008 static Scheme_Bucket *make_bucket(Scheme_Object *key, Scheme_Object *val, Scheme_Instance *inst)
1009 {
1010   Scheme_Bucket *b;
1011 
1012   b = (Scheme_Bucket *)MALLOC_ONE_TAGGED(Scheme_Bucket_With_Home);
1013   b->so.type = scheme_variable_type;
1014   b->key = (char *)key;
1015   b->val = val;
1016   scheme_set_bucket_home(b, inst);
1017 
1018   return b;
1019 }
1020 
scheme_make_instance(Scheme_Object * name,Scheme_Object * data)1021 Scheme_Instance *scheme_make_instance(Scheme_Object *name, Scheme_Object *data)
1022 {
1023   Scheme_Instance *inst;
1024 
1025   if (!empty_hash_tree) {
1026     REGISTER_SO(empty_hash_tree);
1027     empty_hash_tree = scheme_make_hash_tree(0);
1028   }
1029 
1030   inst = MALLOC_ONE_TAGGED(Scheme_Instance);
1031   inst->iso.so.type = scheme_instance_type;
1032 
1033   inst->name = (name ? name : scheme_false);
1034   inst->data = data;
1035 
1036   inst->source_names = empty_hash_tree;
1037 
1038   if (scheme_starting_up) {
1039     /* Avoid recording procedure-implementation details in bytecode
1040        that uses the instances that are created on startup. */
1041     SCHEME_INSTANCE_FLAGS(inst) |= SCHEME_INSTANCE_USE_IMPRECISE;
1042   }
1043 
1044   return inst;
1045 }
1046 
scheme_instance_to_hash_mode(Scheme_Instance * inst,int size_estimate)1047 void scheme_instance_to_hash_mode(Scheme_Instance *inst, int size_estimate)
1048 {
1049   Scheme_Bucket_Table *variables;
1050   Scheme_Bucket **a;
1051 
1052   if (inst->array_size) {
1053     size_estimate = inst->array_size * 2;
1054     a = inst->variables.a;
1055   } else
1056     a = NULL;
1057 
1058   variables = scheme_make_bucket_table(size_estimate, SCHEME_hash_ptr);
1059   variables->with_home = 1;
1060 
1061   inst->variables.bt = variables;
1062   inst->array_size = 0;
1063 
1064   if (a) {
1065     size_estimate >>= 1;
1066     while (size_estimate--) {
1067       scheme_add_bucket_to_table(inst->variables.bt, a[size_estimate]);
1068     }
1069   }
1070 }
1071 
scheme_instance_variable_bucket(Scheme_Object * symbol,Scheme_Instance * inst)1072 Scheme_Bucket *scheme_instance_variable_bucket(Scheme_Object *symbol, Scheme_Instance *inst)
1073 {
1074   Scheme_Bucket *b;
1075 
1076   if (inst->array_size) {
1077     int i;
1078     for (i = inst->array_size; i--; ) {
1079       b = inst->variables.a[i];
1080       if (SAME_OBJ(symbol, (Scheme_Object *)b->key))
1081         return b;
1082     }
1083   }
1084 
1085   if (inst->array_size || !inst->variables.bt)
1086     scheme_instance_to_hash_mode(inst, 0);
1087 
1088   b = scheme_bucket_from_table(inst->variables.bt, (char *)symbol);
1089   ASSERT_IS_VARIABLE_BUCKET(b);
1090   if (SCHEME_FALSEP(symbol))
1091     ((Scheme_Bucket_With_Flags *)b)->flags |= GLOB_STRONG_HOME_LINK;
1092 
1093   scheme_set_bucket_home(b, inst);
1094 
1095   return b;
1096 }
1097 
scheme_instance_variable_bucket_or_null(Scheme_Object * symbol,Scheme_Instance * inst)1098 Scheme_Bucket *scheme_instance_variable_bucket_or_null(Scheme_Object *symbol, Scheme_Instance *inst)
1099 {
1100   Scheme_Bucket *b;
1101 
1102   if (inst->array_size) {
1103     int i;
1104     for (i = inst->array_size; i--; ) {
1105       b = inst->variables.a[i];
1106       if (SAME_OBJ(symbol, (Scheme_Object *)b->key))
1107         return b;
1108     }
1109     return NULL;
1110   } else if (!inst->variables.bt)
1111     return NULL;
1112 
1113   b = scheme_bucket_or_null_from_table(inst->variables.bt, (char *)symbol, 0);
1114   if (b) {
1115     ASSERT_IS_VARIABLE_BUCKET(b);
1116     scheme_set_bucket_home(b, inst);
1117   }
1118 
1119   return b;
1120 }
1121 
1122 /*========================================================================*/
1123 /*                          managing bucket names                         */
1124 /*========================================================================*/
1125 
generate_bucket_name(Scheme_Object * old_name,Scheme_Instance * instance)1126 static Scheme_Object *generate_bucket_name(Scheme_Object *old_name, Scheme_Instance *instance)
1127 {
1128   int search_start = 0;
1129   char buf[32];
1130   Scheme_Object *n;
1131 
1132   while (1) {
1133     sprintf(buf, ".%d", search_start);
1134     n = scheme_intern_exact_parallel_symbol(buf, strlen(buf));
1135     n = scheme_symbol_append(old_name, n);
1136     if (!scheme_instance_variable_bucket_or_null(n, instance))
1137       return n;
1138     search_start++;
1139   }
1140 }
1141 
update_source_names(Scheme_Hash_Tree * source_names,Scheme_Object * old_name,Scheme_Object * new_name)1142 static Scheme_Hash_Tree *update_source_names(Scheme_Hash_Tree *source_names,
1143                                              Scheme_Object *old_name, Scheme_Object *new_name)
1144 {
1145   Scheme_Object *v;
1146 
1147   v = scheme_hash_tree_get(source_names, old_name);
1148   if (v)
1149     return scheme_hash_tree_set(source_names, new_name, v);
1150   else
1151     return source_names;
1152 }
1153 
1154 /*========================================================================*/
1155 /*                            compiling linklets                          */
1156 /*========================================================================*/
1157 
compile_and_or_optimize_linklet(Scheme_Object * form,Scheme_Linklet * linklet,Scheme_Object * name,Scheme_Object ** _import_keys,Scheme_Object * get_import,int unsafe_mode,int static_mode,int serializable)1158 static Scheme_Linklet *compile_and_or_optimize_linklet(Scheme_Object *form, Scheme_Linklet *linklet,
1159                                                        Scheme_Object *name,
1160                                                        Scheme_Object **_import_keys, Scheme_Object *get_import,
1161                                                        int unsafe_mode, int static_mode, int serializable)
1162 {
1163   Scheme_Config *config;
1164   int enforce_const, set_undef, can_inline;
1165   Scheme_Performance_State perf_state;
1166 
1167   scheme_performance_record_start(&perf_state);
1168 
1169   config = scheme_current_config();
1170   enforce_const = SCHEME_TRUEP(scheme_get_param(config, MZCONFIG_COMPILE_MODULE_CONSTS));
1171   set_undef = SCHEME_TRUEP(scheme_get_param(config, MZCONFIG_ALLOW_SET_UNDEFINED));
1172   can_inline = SCHEME_FALSEP(scheme_get_param(config, MZCONFIG_DISALLOW_INLINE));
1173 
1174   if (_import_keys && !*_import_keys)
1175     _import_keys = NULL;
1176 
1177   if (!linklet) {
1178     linklet = scheme_compile_linklet(form, set_undef, (_import_keys ? *_import_keys : NULL));
1179     linklet = scheme_letrec_check_linklet(linklet);
1180   } else {
1181     linklet = scheme_unresolve_linklet(linklet, (set_undef ? COMP_ALLOW_SET_UNDEFINED : 0));
1182   }
1183   linklet->name = name;
1184   linklet = scheme_optimize_linklet(linklet, enforce_const, can_inline, unsafe_mode,
1185                                     _import_keys, get_import);
1186 
1187   linklet = scheme_resolve_linklet(linklet, enforce_const, static_mode);
1188   linklet = scheme_sfs_linklet(linklet);
1189 
1190   if (recompile_every_compile) {
1191     int i;
1192     for (i = recompile_every_compile; i--; ) {
1193       linklet = scheme_unresolve_linklet(linklet, (set_undef ? COMP_ALLOW_SET_UNDEFINED : 0));
1194       linklet = scheme_optimize_linklet(linklet, enforce_const, can_inline, unsafe_mode,
1195                                         _import_keys, get_import);
1196       linklet = scheme_resolve_linklet(linklet, enforce_const, static_mode);
1197       linklet = scheme_sfs_linklet(linklet);
1198     }
1199   }
1200 
1201   if (validate_compile_result)
1202     scheme_validate_linklet(NULL, linklet);
1203 
1204   scheme_performance_record_end("compile", &perf_state);
1205 
1206   if (serializable)
1207     linklet->serializable = 1;
1208 
1209   return linklet;
1210 }
1211 
scheme_compile_and_optimize_linklet(Scheme_Object * form,Scheme_Object * name)1212 Scheme_Linklet *scheme_compile_and_optimize_linklet(Scheme_Object *form, Scheme_Object *name)
1213 {
1214   return compile_and_or_optimize_linklet(form, NULL, name, NULL, NULL, 0, 1, 0);
1215 }
1216 
1217 /*========================================================================*/
1218 /*                          instantiating linklets                        */
1219 /*========================================================================*/
1220 
body_one_expr(void * prefix_plus_expr,int argc,Scheme_Object ** argv)1221 static Scheme_Object *body_one_expr(void *prefix_plus_expr, int argc, Scheme_Object **argv)
1222 {
1223   Scheme_Object *v;
1224 
1225   resume_prefix(SCHEME_CAR((Scheme_Object *)prefix_plus_expr));
1226   v = _scheme_eval_linked_expr_multi(SCHEME_CDR((Scheme_Object *)prefix_plus_expr));
1227   (void)suspend_prefix();
1228 
1229   return v;
1230 }
1231 
needs_prompt(Scheme_Object * e)1232 static int needs_prompt(Scheme_Object *e)
1233 {
1234   Scheme_Type t;
1235 
1236   while (1) {
1237     t = SCHEME_TYPE(e);
1238     if (t > _scheme_values_types_)
1239       return 0;
1240 
1241     switch (t) {
1242     case scheme_lambda_type:
1243     case scheme_toplevel_type:
1244     case scheme_local_type:
1245     case scheme_local_unbox_type:
1246       return 0;
1247     case scheme_case_lambda_sequence_type:
1248       return 0;
1249     case scheme_define_values_type:
1250       e = SCHEME_VEC_ELS(e)[0];
1251       break;
1252     case scheme_inline_variant_type:
1253       e = SCHEME_VEC_ELS(e)[0];
1254       break;
1255     default:
1256       return 1;
1257     }
1258   }
1259 }
1260 
scheme_linklet_run_finish(Scheme_Linklet * linklet,Scheme_Instance * instance,int use_prompt)1261 Scheme_Object *scheme_linklet_run_finish(Scheme_Linklet* linklet, Scheme_Instance *instance, int use_prompt)
1262 {
1263   Scheme_Thread *p;
1264   Scheme_Object *body, *save_prefix, *v = scheme_void;
1265   int i, cnt;
1266   mz_jmp_buf newbuf, * volatile savebuf;
1267 
1268   p = scheme_current_thread;
1269   savebuf = p->error_buf;
1270   p->error_buf = &newbuf;
1271 
1272   if (scheme_setjmp(newbuf)) {
1273     Scheme_Thread *p2;
1274     p2 = scheme_current_thread;
1275     p2->error_buf = savebuf;
1276     scheme_longjmp(*savebuf, 1);
1277   } else {
1278     cnt = SCHEME_VEC_SIZE(linklet->bodies);
1279     for (i = 0; i < cnt; i++) {
1280       body = SCHEME_VEC_ELS(linklet->bodies)[i];
1281       if (use_prompt && needs_prompt(body)) {
1282         /* We need to push the prefix after the prompt is set, so
1283            restore the runstack and then add the prefix back. */
1284         save_prefix = suspend_prefix();
1285         v = _scheme_call_with_prompt_multi(body_one_expr,
1286                                            scheme_make_raw_pair(save_prefix, body));
1287         resume_prefix(save_prefix);
1288 
1289         /* Double-check that the definition-installing part of the
1290            continuation was not skipped. Otherwise, the compiler would
1291            not be able to assume that a variable reference that is
1292            lexically later (including a reference to an imported
1293            variable) always references a defined variable. Putting the
1294            prompt around a definition's RHS might be a better
1295            approach, but that would change the language (so mabe next
1296            time). */
1297         if (SAME_TYPE(SCHEME_TYPE(body), scheme_define_values_type)) {
1298           int vcnt, j;
1299 
1300           vcnt = SCHEME_VEC_SIZE(body) - 1;
1301           for (j = 0; j < vcnt; j++) {
1302             Scheme_Object *var;
1303             Scheme_Prefix *toplevels;
1304             Scheme_Bucket *b;
1305 
1306             var = SCHEME_VEC_ELS(body)[j+1];
1307             toplevels = (Scheme_Prefix *)MZ_RUNSTACK[SCHEME_TOPLEVEL_DEPTH(var)];
1308             b = (Scheme_Bucket *)toplevels->a[SCHEME_TOPLEVEL_POS(var)];
1309 
1310             if (!b->val) {
1311               scheme_raise_exn(MZEXN_FAIL_CONTRACT_VARIABLE,
1312                                b->key,
1313                                "define-values: skipped variable definition;\n"
1314                                " cannot continue without defining variable\n"
1315                                "  variable: %S\n"
1316                                "  in module: %D",
1317                                (Scheme_Object *)b->key,
1318                                instance->name);
1319             }
1320           }
1321         }
1322       } else
1323         v = _scheme_eval_linked_expr_multi(body);
1324 
1325       if (i < (cnt - 1))
1326         scheme_ignore_result(v);
1327     }
1328 
1329     p = scheme_current_thread;
1330     p->error_buf = savebuf;
1331   }
1332 
1333   return v;
1334 }
1335 
eval_linklet_body(Scheme_Linklet * linklet,Scheme_Instance * instance,int use_prompt)1336 static Scheme_Object *eval_linklet_body(Scheme_Linklet *linklet, Scheme_Instance *instance, int use_prompt)
1337 {
1338 #ifdef MZ_USE_JIT
1339   if (use_prompt)
1340     return scheme_linklet_run_start(linklet, instance, scheme_make_pair(instance->name, scheme_true));
1341 #endif
1342 
1343   return scheme_linklet_run_finish(linklet, instance, use_prompt);
1344 }
1345 
instantiate_linklet_k(void)1346 static void *instantiate_linklet_k(void)
1347 {
1348   Scheme_Thread *p = scheme_current_thread;
1349   Scheme_Linklet *linklet = (Scheme_Linklet *)p->ku.k.p1;
1350   Scheme_Instance *instance = (Scheme_Instance *)p->ku.k.p2;
1351   Scheme_Instance **instances = (Scheme_Instance **)p->ku.k.p3;
1352   int multi = p->ku.k.i1;
1353   int num_instances = p->ku.k.i2;
1354   int use_prompt = p->ku.k.i3;
1355   int depth;
1356   Scheme_Object *b, *v;
1357   Scheme_Hash_Tree *source_names;
1358   Scheme_Performance_State perf_state;
1359 
1360   p->ku.k.p1 = NULL;
1361   p->ku.k.p2 = NULL;
1362   p->ku.k.p3 = NULL;
1363 
1364   depth = linklet->max_let_depth;
1365   if (!scheme_check_runstack(depth)) {
1366     p->ku.k.p1 = linklet;
1367     p->ku.k.p2 = instance;
1368     p->ku.k.p3 = instances;
1369     p->ku.k.i1 = multi;
1370     p->ku.k.i2 = num_instances;
1371     p->ku.k.i3 = use_prompt;
1372     return (Scheme_Object *)scheme_enlarge_runstack(depth, instantiate_linklet_k);
1373   }
1374 
1375   scheme_performance_record_start(&perf_state);
1376 
1377   if (!linklet->jit_ready) {
1378     b = scheme_get_param(scheme_current_config(), MZCONFIG_USE_JIT);
1379     if (SCHEME_TRUEP(b))
1380       linklet = scheme_jit_linklet(linklet, 2);
1381   } else {
1382     linklet = scheme_jit_linklet(linklet, 2);
1383   }
1384 
1385   /* Pushng the prefix looks up imported variables */
1386   source_names = push_prefix(linklet, instance, num_instances, instances, linklet->source_names);
1387 
1388   /* For variables in this instances, merge source-name info from the
1389      linklet to the instance */
1390   if (source_names->count) {
1391     if (instance->source_names->count) {
1392       mzlonglong pos;
1393       Scheme_Hash_Tree *ht = instance->source_names;
1394       Scheme_Object *k, *v;
1395       pos = scheme_hash_tree_next(source_names, -1);
1396       while (pos != -1) {
1397         scheme_hash_tree_index(source_names, pos, &k, &v);
1398         ht = scheme_hash_tree_set(ht, k, v);
1399         pos = scheme_hash_tree_next(source_names, pos);
1400       }
1401       instance->source_names = ht;
1402     } else
1403       instance->source_names = source_names;
1404   }
1405 
1406   v = eval_linklet_body(linklet, instance, use_prompt);
1407 
1408   pop_prefix();
1409 
1410   if (!multi)
1411     v = scheme_check_one_value(v);
1412 
1413 #ifdef MZ_USE_JIT
1414   if (linklet->native_lambdas) {
1415     int mc;
1416     Scheme_Object **mv, *l;
1417 
1418     if (SAME_OBJ(v, SCHEME_MULTIPLE_VALUES)) {
1419       p = scheme_current_thread;
1420       mv = p->ku.multiple.array;
1421       mc = p->ku.multiple.count;
1422       if (SAME_OBJ(mv, p->values_buffer))
1423         p->values_buffer = NULL;
1424     } else {
1425       mv = NULL;
1426       mc = 0;
1427     }
1428 
1429     l = linklet->native_lambdas;
1430     linklet->native_lambdas = NULL;
1431 
1432     while (SCHEME_PAIRP(l)) {
1433       scheme_force_jit_generate((Scheme_Native_Lambda *)SCHEME_CAR(l));
1434       l = SCHEME_CDR(l);
1435     }
1436 
1437     if (mv) {
1438       p = scheme_current_thread;
1439       p->ku.multiple.array = mv;
1440       p->ku.multiple.count = mc;
1441     }
1442   }
1443 #endif
1444 
1445   scheme_performance_record_end("instantiate", &perf_state);
1446 
1447   return (void *)v;
1448 }
1449 
do_instantiate_linklet(Scheme_Linklet * linklet,Scheme_Instance * instance,int num_instances,Scheme_Instance ** instances,int use_prompt,int multi,int top)1450 static Scheme_Object *do_instantiate_linklet(Scheme_Linklet *linklet, Scheme_Instance *instance,
1451                                              int num_instances, Scheme_Instance **instances,
1452                                              int use_prompt, int multi, int top)
1453 {
1454   Scheme_Thread *p = scheme_current_thread;
1455 
1456   p->ku.k.p1 = linklet;
1457   p->ku.k.p2 = instance;
1458   p->ku.k.p3 = instances;
1459 
1460   p->ku.k.i1 = multi;
1461   p->ku.k.i2 = num_instances;
1462   p->ku.k.i3 = use_prompt;
1463 
1464   if (top)
1465     return (Scheme_Object *)scheme_top_level_do(instantiate_linklet_k, 1);
1466   else
1467     return (Scheme_Object *)instantiate_linklet_k();
1468 }
1469 
_instantiate_linklet_multi(Scheme_Linklet * linklet,Scheme_Instance * instance,int num_instances,Scheme_Instance ** instances,int use_prompt)1470 static Scheme_Object *_instantiate_linklet_multi(Scheme_Linklet *linklet, Scheme_Instance *instance,
1471                                                  int num_instances, Scheme_Instance **instances,
1472                                                  int use_prompt)
1473 {
1474   return do_instantiate_linklet(linklet, instance, num_instances, instances, use_prompt, 1, 0);
1475 }
1476 
scheme_instantiate_linklet_multi(Scheme_Linklet * linklet,Scheme_Instance * instance,int num_instances,Scheme_Instance ** instances,int use_prompt)1477 Scheme_Object *scheme_instantiate_linklet_multi(Scheme_Linklet *linklet, Scheme_Instance *instance,
1478                                                 int num_instances, Scheme_Instance **instances,
1479                                                 int use_prompt)
1480 {
1481   return do_instantiate_linklet(linklet, instance, num_instances, instances, use_prompt, 1, 1);
1482 }
1483 
1484 /*========================================================================*/
1485 /*        creating/pushing prefix for top-levels and syntax objects       */
1486 /*========================================================================*/
1487 
scheme_allocate_linklet_prefix(Scheme_Linklet * linklet,int extra)1488 Scheme_Prefix *scheme_allocate_linklet_prefix(Scheme_Linklet *linklet, int extra)
1489 {
1490   int num_defns, n;
1491 
1492   num_defns = SCHEME_VEC_SIZE(linklet->defns);
1493 
1494   n = 1 + linklet->num_total_imports + num_defns + extra;
1495 
1496   return scheme_allocate_prefix(n);
1497 }
1498 
scheme_allocate_prefix(intptr_t n)1499 Scheme_Prefix *scheme_allocate_prefix(intptr_t n)
1500 {
1501   Scheme_Prefix *pf;
1502   int tl_map_len;
1503 
1504   tl_map_len = (n + 31) / 32;
1505 
1506   pf = scheme_malloc_tagged(sizeof(Scheme_Prefix)
1507                             + ((n-mzFLEX_DELTA) * sizeof(Scheme_Object *))
1508                             + (tl_map_len * sizeof(int)));
1509   pf->iso.so.type = scheme_prefix_type;
1510   pf->num_slots = n;
1511 
1512   return pf;
1513 }
1514 
push_prefix(Scheme_Linklet * linklet,Scheme_Instance * instance,int num_instances,Scheme_Instance ** instances,Scheme_Hash_Tree * source_names)1515 static Scheme_Hash_Tree *push_prefix(Scheme_Linklet *linklet, Scheme_Instance *instance,
1516                                      int num_instances, Scheme_Instance **instances,
1517                                      Scheme_Hash_Tree *source_names)
1518 {
1519   Scheme_Object **rs, *v;
1520   Scheme_Prefix *pf;
1521   int i, j, pos, num_importss, num_defns, starts_empty;
1522   GC_CAN_IGNORE const char *bad_reason = NULL;
1523 
1524   rs = MZ_RUNSTACK;
1525 
1526   num_importss = SCHEME_VEC_SIZE(linklet->importss);
1527   num_defns = SCHEME_VEC_SIZE(linklet->defns);
1528 
1529   pf = linklet->static_prefix;
1530   if (!pf)
1531     pf = scheme_allocate_linklet_prefix(linklet, 0);
1532 
1533   --rs;
1534   MZ_RUNSTACK = rs;
1535   rs[0] = (Scheme_Object *)pf;
1536 
1537   pos = 0;
1538 
1539   /* Initial bucket, key by #f, provides access to the instance */
1540   if (linklet->need_instance_access)
1541     v = (Scheme_Object *)scheme_instance_variable_bucket(scheme_false, instance);
1542   else
1543     v = NULL;
1544   pf->a[pos++] = v;
1545 
1546   for (j = 0; j < num_importss; j++) {
1547     int num_imports = SCHEME_VEC_SIZE(SCHEME_VEC_ELS(linklet->importss)[j]);
1548     for (i = 0; i < num_imports; i++) {
1549       v = SCHEME_VEC_ELS(SCHEME_VEC_ELS(linklet->importss)[j])[i];
1550       v = (Scheme_Object *)scheme_instance_variable_bucket(v, (Scheme_Instance *)instances[j]);
1551 
1552       if (v) {
1553         if (!((Scheme_Bucket *)v)->val) {
1554           bad_reason = "is uninitialized";
1555           v = NULL;
1556         } else if (linklet->import_shapes) {
1557           Scheme_Object *shape = SCHEME_VEC_ELS(linklet->import_shapes)[pos-1];
1558           if (SAME_OBJ(shape, scheme_void)) {
1559             /* Optimizer assumed constant; if it isn't, too bad */
1560             bad_reason = NULL;
1561           } else if (SAME_OBJ(shape, scheme_true)) {
1562             if (!(((Scheme_Bucket_With_Flags *)v)->flags & GLOB_IS_CONSISTENT)) {
1563               bad_reason = "is not a procedure or structure-type constant across all instantiations";
1564               v = NULL;
1565             }
1566           } else if (SCHEME_TRUEP(shape)) {
1567             if (!scheme_get_or_check_procedure_shape(((Scheme_Bucket *)v)->val, shape, 0)) {
1568               bad_reason = "has the wrong procedure or structure-type shape";
1569               v = NULL;
1570             }
1571           }
1572         }
1573       } else
1574         bad_reason = "is not exported";
1575 
1576       if (!v) {
1577         scheme_signal_error("instantiate-linklet: mismatch;\n"
1578                             " reference to a variable that %s;\n"
1579                             " possibly, bytecode file needs re-compile because dependencies changed\n"
1580                             "  name: %D\n"
1581                             "  exporting instance: %D\n"
1582                             "  importing instance: %D",
1583                             bad_reason,
1584                             SCHEME_VEC_ELS(SCHEME_VEC_ELS(linklet->importss)[j])[i],
1585                             instances[j]->name,
1586                             instance->name);
1587       }
1588       pf->a[pos++] = v;
1589     }
1590   }
1591 
1592   starts_empty = (!instance->array_size && !instance->variables.bt);
1593 
1594   if (!num_defns) {
1595     /* don't allocate empty array, etc. */
1596   } else if (starts_empty && (num_defns < 10)) {
1597     /* Faster to build an array-shaped instance (which will be
1598        converted to a bucket table on demand, if necessary) */
1599     Scheme_Bucket **a, *b;
1600 
1601     a = MALLOC_N(Scheme_Bucket *, num_defns);
1602     for (i = 0; i < num_defns; i++) {
1603       v = SCHEME_VEC_ELS(linklet->defns)[i];
1604       if (SCHEME_FALSEP(v)) {
1605         pf->a[pos++] = NULL;
1606       } else {
1607         b = make_bucket(v, NULL, instance);
1608         a[i] = b;
1609         pf->a[pos++] = (Scheme_Object *)b;
1610       }
1611     }
1612 
1613     instance->array_size = num_defns;
1614     instance->variables.a = a;
1615   } else {
1616     /* General case: bucket-table instance: */
1617     for (i = 0; i < num_defns; i++) {
1618       v = SCHEME_VEC_ELS(linklet->defns)[i];
1619       if (SCHEME_FALSEP(v)) {
1620         v = NULL;
1621       } else {
1622         if ((i >= linklet->num_exports) && !starts_empty) {
1623           /* avoid conflict with any existing bucket */
1624           if (scheme_instance_variable_bucket_or_null(v, instance)) {
1625             v = generate_bucket_name(v, instance);
1626             source_names = update_source_names(source_names, SCHEME_VEC_ELS(linklet->defns)[i], v);
1627           }
1628         }
1629         v = (Scheme_Object *)scheme_instance_variable_bucket(v, instance);
1630       }
1631       pf->a[pos++] = v;
1632     }
1633   }
1634 
1635   return source_names;
1636 }
1637 
pop_prefix()1638 static void pop_prefix()
1639 {
1640   /* This function must not allocate, since a relevant multiple-values
1641      result may be in the thread record (and we don't want it zerod) */
1642   MZ_RUNSTACK++;
1643 }
1644 
suspend_prefix()1645 static Scheme_Object *suspend_prefix()
1646 {
1647   Scheme_Object *v;
1648   v = MZ_RUNSTACK[0];
1649   MZ_RUNSTACK++;
1650   return v;
1651 }
1652 
resume_prefix(Scheme_Object * v)1653 static void resume_prefix(Scheme_Object *v)
1654 {
1655   --MZ_RUNSTACK;
1656   MZ_RUNSTACK[0] = v;
1657 }
1658 
1659 #ifdef MZ_PRECISE_GC
mark_pruned_prefixes(struct NewGC * gc)1660 static void mark_pruned_prefixes(struct NewGC *gc) XFORM_SKIP_PROC
1661 {
1662   if (!GC_is_partial(gc)) {
1663     if (scheme_inc_prefix_finalize != (Scheme_Prefix *)0x1) {
1664       Scheme_Prefix *pf = scheme_inc_prefix_finalize;
1665       while (pf->next_final != (Scheme_Prefix *)0x1) {
1666         pf = pf->next_final;
1667       }
1668       pf->next_final = scheme_prefix_finalize;
1669       scheme_prefix_finalize = scheme_inc_prefix_finalize;
1670       scheme_inc_prefix_finalize = (Scheme_Prefix *)0x1;
1671     }
1672   }
1673 
1674   if (scheme_prefix_finalize != (Scheme_Prefix *)0x1) {
1675     Scheme_Prefix *pf = scheme_prefix_finalize, *next;
1676     Scheme_Object *clo;
1677     int i, *use_bits, maxpos;
1678 
1679     scheme_prefix_finalize = (Scheme_Prefix *)0x1;
1680     while (pf != (Scheme_Prefix *)0x1) {
1681       /* If not marked, only references are through closures: */
1682       if (!GC_is_marked2(pf, gc)) {
1683         /* Clear slots that are not use in map */
1684         maxpos = pf->num_slots;
1685         use_bits = PREFIX_TO_USE_BITS(pf);
1686         for (i = (maxpos + 31) / 32; i--; ) {
1687           int j;
1688           for (j = 0; j < 32; j++) {
1689             if (!(use_bits[i] & ((unsigned)1 << j))) {
1690               int pos;
1691               pos = (i * 32) + j;
1692               if (pos < maxpos)
1693                 pf->a[pos] = NULL;
1694             }
1695           }
1696           use_bits[i] = 0;
1697         }
1698         /* Should mark/copy pf, but not trigger or require mark propagation: */
1699 #ifdef MZ_GC_BACKTRACE
1700         GC_set_backpointer_object(pf->backpointer);
1701 #endif
1702         GC_mark_no_recur(gc, 1);
1703         gcMARK2(pf, gc);
1704         pf = (Scheme_Prefix *)GC_resolve2(pf, gc);
1705         GC_retract_only_mark_stack_entry(pf, gc);
1706         GC_mark_no_recur(gc, 0);
1707         pf->saw_num_slots = -1;
1708       } else
1709         pf = (Scheme_Prefix *)GC_resolve2(pf, gc);
1710 
1711       /* Clear use map */
1712       use_bits = PREFIX_TO_USE_BITS(pf);
1713       maxpos = pf->num_slots;
1714       for (i = (maxpos + 31) / 32; i--; )
1715         use_bits[i] = 0;
1716 
1717       /* Fix up closures that reference this prefix: */
1718       clo = (Scheme_Object *)GC_resolve2(pf->fixup_chain, gc);
1719       pf->fixup_chain = NULL;
1720       while (clo) {
1721         Scheme_Object *next;
1722         if (SCHEME_TYPE(clo) == scheme_closure_type) {
1723           Scheme_Closure *cl = (Scheme_Closure *)clo;
1724           int closure_size = ((Scheme_Lambda *)GC_resolve2(cl->code, gc))->closure_size;
1725           next = cl->vals[closure_size - 1];
1726           cl->vals[closure_size-1] = (Scheme_Object *)pf;
1727         } else if (SCHEME_TYPE(clo) == scheme_native_closure_type) {
1728           Scheme_Native_Closure *cl = (Scheme_Native_Closure *)clo;
1729           int closure_size = ((Scheme_Native_Lambda *)GC_resolve2(cl->code, gc))->closure_size;
1730           next = cl->vals[closure_size - 1];
1731           cl->vals[closure_size-1] = (Scheme_Object *)pf;
1732         } else {
1733           MZ_ASSERT(0);
1734           next = NULL;
1735         }
1736         clo = (Scheme_Object *)GC_resolve2(next, gc);
1737       }
1738       if (SCHEME_PREFIX_FLAGS(pf) & 0x1)
1739         SCHEME_PREFIX_FLAGS(pf) -= 0x1;
1740 
1741       /* Next */
1742       next = pf->next_final;
1743       pf->next_final = NULL;
1744 
1745       pf = next;
1746     }
1747   }
1748 }
1749 
check_pruned_prefix(void * p)1750 int check_pruned_prefix(void *p) XFORM_SKIP_PROC
1751 {
1752   Scheme_Prefix *pf = (Scheme_Prefix *)p;
1753   return SCHEME_PREFIX_FLAGS(pf) & 0x1;
1754 }
1755 #endif
1756 
1757 /*========================================================================*/
1758 /*  Recorindg performance times                                           */
1759 /*========================================================================*/
1760 
1761 static intptr_t nested_delta, nested_gc_delta;
1762 static int perf_reg, perf_count;
1763 
1764 typedef struct {
1765   const char *name;
1766   intptr_t accum;
1767   intptr_t gc_accum;
1768   intptr_t count;
1769 } Performance_Entry;
1770 
1771 #define MAX_PERF_ENTRIES 16
1772 
1773 static Performance_Entry perf_entries[MAX_PERF_ENTRIES];
1774 
1775 #define MAX_PERF_CATS    3
1776 #define MAX_PERF_SUBS    3
1777 
1778 typedef struct {
1779   const char *name;
1780   Performance_Entry perf_entries[MAX_PERF_SUBS];
1781   int perf_count;
1782 } Performance_Cat;
1783 
1784 typedef struct {
1785   const char *entry;
1786   const char *cat;
1787 } Performace_Recat;
1788 
1789 static Performace_Recat recats[] = { { "instantiate", "run" },
1790                                      { "jit", "run" },
1791                                      { "comp-ffi-call", "comp-ffi" },
1792                                      { "comp-ffi-back", "comp-ffi" },
1793                                      { NULL, NULL} };
1794 
do_tab(int len,char * tab,int max_len)1795 static char *do_tab(int len, char *tab, int max_len)
1796 {
1797   int i;
1798 
1799   len = max_len - len;
1800   if (len < 0)
1801     len = 0;
1802   for (i = 0; i < len; i++) {
1803     tab[i] = ' ';
1804   }
1805   tab[i] = 0;
1806 
1807   return tab;
1808 }
1809 
numlen(intptr_t n)1810 static int numlen(intptr_t n)
1811 {
1812   int len = 1;
1813 
1814   while (n >= 10) {
1815     n = n / 10;
1816     len++;
1817   }
1818 
1819   return len;
1820 }
1821 
tab_number(intptr_t n,char * tab,int max_len)1822 static char *tab_number(intptr_t n, char *tab, int max_len)
1823 {
1824   return do_tab(numlen(n), tab, max_len);
1825 }
1826 
tab_string(const char * s,char * tab,int max_len)1827 static char *tab_string(const char *s, char *tab, int max_len)
1828 {
1829   return do_tab(strlen(s), tab, max_len);
1830 }
1831 
sort_perf(Performance_Entry * pref_entries,int lo,int hi)1832 static void sort_perf(Performance_Entry *pref_entries, int lo, int hi)
1833 {
1834   int i, pivot;
1835 
1836   if (lo >= hi)
1837     return;
1838 
1839   pivot = lo;
1840   for (i = lo + 1; i < hi; i++) {
1841     if (perf_entries[i].accum < perf_entries[pivot].accum) {
1842       Performance_Entry tmp = perf_entries[pivot];
1843       perf_entries[pivot] = perf_entries[i];
1844       perf_entries[i] = perf_entries[pivot+1];
1845       perf_entries[pivot+1] = tmp;
1846       pivot++;
1847     }
1848   }
1849 
1850   sort_perf(perf_entries, lo, pivot);
1851   sort_perf(perf_entries, pivot+1, hi);
1852 }
1853 
show_perf(Performance_Entry * perf_entries,int perf_count,int len,int name_len,int gc_len,int depth)1854 static void show_perf(Performance_Entry *perf_entries, int perf_count,
1855                       int len, int name_len, int gc_len,
1856                       int depth)
1857 {
1858   intptr_t total = 0, gc_total = 0;
1859   int i, j, k, m, n;
1860   char name_tab[16], tab[10], gc_tab[10], pre_indent[8], post_indent[8];
1861   Performance_Cat cats[MAX_PERF_CATS];
1862   int num_cats = 0;
1863 
1864   memset(cats, 0, sizeof(cats));
1865 
1866   if (!depth) {
1867     for (i = 0; i < perf_count; i++) {
1868       for (j = 0; recats[j].entry; j++) {
1869         if (!strcmp(recats[j].entry, perf_entries[i].name)) {
1870           for (m = 0; m < num_cats; m++) {
1871             if (!strcmp(recats[j].cat, cats[m].name))
1872               break;
1873           }
1874           if (num_cats <= m) num_cats = m+1;
1875           cats[m].name = recats[j].cat;
1876           for (k = 0; k < perf_count; k++) {
1877             if (perf_entries[k].name) {
1878               if (!strcmp(perf_entries[k].name, recats[j].cat))
1879                 break;
1880             } else
1881               break;
1882           }
1883           perf_entries[k].name = recats[j].cat;
1884           if (perf_count <= k) perf_count = k+1;
1885           perf_entries[k].accum += perf_entries[i].accum;
1886           perf_entries[k].gc_accum += perf_entries[i].gc_accum;
1887           perf_entries[k].count = -1;
1888 
1889           n = cats[m].perf_count++;
1890           cats[m].perf_entries[n] = perf_entries[i];
1891           perf_entries[i].accum = 0;
1892           perf_entries[i].gc_accum = 0;
1893           perf_entries[i].count = 0;
1894         }
1895       }
1896     }
1897   }
1898 
1899   sort_perf(perf_entries, 0, perf_count);
1900 
1901   for (i = 0; i < perf_count; i++) {
1902     n = strlen(perf_entries[i].name);
1903     if (n > name_len) name_len = n;
1904     total += perf_entries[i].accum;
1905     gc_total += perf_entries[i].gc_accum;
1906   }
1907 
1908   n = numlen(total);
1909   if (n > len) len = n;
1910   n = numlen(gc_total);
1911   if (n > gc_len) gc_len = n;
1912 
1913   if (name_len >= sizeof(name_tab))
1914     name_len = sizeof(name_tab) - 1;
1915   if (len >= sizeof(tab))
1916     len = sizeof(tab) - 1;
1917   if (gc_len >= sizeof(gc_tab))
1918     gc_len = sizeof(gc_tab) -1;
1919 
1920   for (i = 0; i < depth * 2; i++) {
1921     pre_indent[i] = ' ';
1922   }
1923   pre_indent[i] = 0;
1924   for (i = 0; i < (3 - depth) * 2; i++) {
1925     post_indent[i] = ' ';
1926   }
1927   post_indent[i] = 0;
1928 
1929   if (!depth)
1930     scheme_log(NULL, SCHEME_LOG_ERROR, 0, ";;");
1931 
1932 #define BASE_TIMES_TEMPLATE ";; %s%s%s%s  %s%ld [%s%ld] ms"
1933 #define FULL_TIMES_TEMPLATE BASE_TIMES_TEMPLATE " ; %ld times"
1934 
1935   for (i = 0; i < perf_count; i++) {
1936     if (perf_entries[i].count)
1937       scheme_log(NULL, SCHEME_LOG_ERROR, 0,
1938                  ((perf_entries[i].count < 0)
1939                   ? BASE_TIMES_TEMPLATE
1940                   : FULL_TIMES_TEMPLATE),
1941                  pre_indent,
1942                  perf_entries[i].name,
1943                  tab_string(perf_entries[i].name, name_tab, name_len),
1944                  post_indent,
1945                  tab_number(perf_entries[i].accum, tab, len),
1946                  perf_entries[i].accum,
1947                  tab_number(perf_entries[i].gc_accum, gc_tab, gc_len),
1948                  perf_entries[i].gc_accum,
1949                  perf_entries[i].count);
1950     for (m = 0; m < num_cats; m++) {
1951       if (!strcmp(perf_entries[i].name, cats[m].name))
1952         show_perf(cats[m].perf_entries, cats[m].perf_count, len, name_len, gc_len, depth+1);
1953     }
1954   }
1955 
1956   if (!depth) {
1957     scheme_log(NULL, SCHEME_LOG_ERROR, 0,
1958                ";; %stotal%s  %s%ld [%s%ld] ms",
1959                tab_number(total, tab, len),
1960                tab_string("total", name_tab, name_len),
1961                post_indent,
1962                total,
1963                tab_number(gc_total, gc_tab, gc_len),
1964                gc_total);
1965 #ifdef MZ_PRECISE_GC
1966     scheme_log(NULL, SCHEME_LOG_ERROR, 0, ";;");
1967     scheme_log(NULL, SCHEME_LOG_ERROR, 0,
1968                ";; [JIT code: %d procs  %d bytes  code+admin: %d bytes]",
1969                scheme_code_count,
1970                scheme_code_total,
1971                scheme_code_page_total);
1972 #endif
1973   }
1974 }
1975 
show_all_perf()1976 static void show_all_perf()
1977 {
1978   return show_perf(perf_entries, perf_count, 0, 0, 0, 0);
1979 }
1980 
scheme_performance_record_start(GC_CAN_IGNORE Scheme_Performance_State * perf_state)1981 void scheme_performance_record_start(GC_CAN_IGNORE Scheme_Performance_State *perf_state)
1982 {
1983 #if defined(MZ_USE_PLACES)
1984   if (scheme_current_place_id != 0)
1985     return;
1986 #endif
1987 
1988   if (!perf_reg) {
1989     if (scheme_getenv("PLT_LINKLET_TIMES")) {
1990       perf_reg = 1;
1991       scheme_atexit(show_all_perf);
1992     } else {
1993       perf_reg = -1;
1994     }
1995   }
1996 
1997   if (perf_reg < 0)
1998     return;
1999 
2000   perf_state->gc_start = scheme_total_gc_time;
2001   perf_state->start = scheme_get_process_milliseconds();
2002   perf_state->old_nested_delta = nested_delta;
2003   perf_state->old_nested_gc_delta = nested_gc_delta;
2004 
2005   nested_delta = 0;
2006   nested_gc_delta = 0;
2007 }
2008 
scheme_performance_record_end(const char * who,GC_CAN_IGNORE Scheme_Performance_State * perf_state)2009 void scheme_performance_record_end(const char *who, GC_CAN_IGNORE Scheme_Performance_State *perf_state)
2010 {
2011   int i;
2012   intptr_t d, gc_d;
2013   Scheme_Performance_State zero_perf_state;
2014 
2015 #if defined(MZ_USE_PLACES)
2016   if (scheme_current_place_id != 0)
2017     return;
2018 #endif
2019 
2020   if (perf_reg < 0)
2021     return;
2022 
2023   for (i = 0; i < MAX_PERF_ENTRIES; i++) {
2024     if (perf_entries[i].name) {
2025       if (!strcmp(perf_entries[i].name, who))
2026         break;
2027     } else
2028       break;
2029   }
2030 
2031   if (i >= MAX_PERF_ENTRIES)
2032     return;
2033 
2034   if (!perf_state) {
2035     memset(&zero_perf_state, 0, sizeof(zero_perf_state));
2036     perf_state = &zero_perf_state;
2037   }
2038 
2039   d = (scheme_get_process_milliseconds() - perf_state->start);
2040   gc_d = (scheme_total_gc_time - perf_state->gc_start);
2041 
2042   perf_state->old_nested_delta += d;
2043   perf_state->old_nested_gc_delta += gc_d;
2044 
2045   d -= nested_delta;
2046   gc_d -= nested_gc_delta;
2047 
2048   nested_delta = perf_state->old_nested_delta;
2049   nested_gc_delta = perf_state->old_nested_gc_delta;
2050 
2051   if (!perf_entries[i].name) {
2052     perf_entries[i].name = who;
2053     perf_count++;
2054   }
2055   perf_entries[i].accum += d;
2056   perf_entries[i].gc_accum += gc_d;
2057   perf_entries[i].count++;
2058 }
2059 
2060 /*========================================================================*/
2061 /*                         precise GC traversers                          */
2062 /*========================================================================*/
2063 
2064 #ifdef MZ_PRECISE_GC
2065 
2066 START_XFORM_SKIP;
2067 
2068 #include "mzmark_linklet.inc"
2069 
register_traversers(void)2070 static void register_traversers(void)
2071 {
2072 }
2073 
2074 END_XFORM_SKIP;
2075 
2076 #endif
2077