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