1 /* -*-C-*-
2 
3 Copyright (C) 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994,
4     1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
5     2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014 Massachusetts
6     Institute of Technology
7 
8 This file is part of MIT/GNU Scheme.
9 
10 MIT/GNU Scheme is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or (at
13 your option) any later version.
14 
15 MIT/GNU Scheme is distributed in the hope that it will be useful, but
16 WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18 General Public License for more details.
19 
20 You should have received a copy of the GNU General Public License
21 along with MIT/GNU Scheme; if not, write to the Free Software
22 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301,
23 USA.
24 
25 */
26 
27 /* Environment lookup, modification, and definition.  */
28 
29 #include "scheme.h"
30 #include "trap.h"
31 #include "lookup.h"
32 
33 /* Hopefully a conservative guesstimate. */
34 #ifndef SPACE_PER_UUO_LINK	/* So it can be overriden from config.h */
35 #  define SPACE_PER_UUO_LINK 10
36 #endif
37 
38 /* Cache objects are 3-tuples.  */
39 #define SPACE_PER_CACHE 3
40 
41 /* Each reference uses a pair and a weak pair, and potentially two
42    more pairs if the reference introduces a new name.  */
43 #define SPACE_PER_REFERENCE 8
44 
45 #define RETURN_IF_ERROR(expression)					\
46 {									\
47   long RIE_result = (expression);					\
48   if (RIE_result != PRIM_DONE)						\
49     return (RIE_result);						\
50 }
51 
52 #define DIE_IF_ERROR(expression)					\
53 {									\
54   if ((expression) != PRIM_DONE)					\
55     {									\
56       outf_fatal ("\nRan out of guaranteed space!\n");			\
57       Microcode_Termination (TERM_EXIT);				\
58     }									\
59 }
60 
61 #define GC_CHECK(n)							\
62 {									\
63   if (GC_NEEDED_P (n))							\
64     {									\
65       REQUEST_GC (n);							\
66       return (PRIM_INTERRUPT);						\
67     }									\
68 }
69 
70 #define MAP_TO_UNASSIGNED(value)					\
71   (((value) == EXTERNAL_UNASSIGNED_OBJECT)				\
72    ? UNASSIGNED_OBJECT							\
73    : (value))
74 
75 #define MAP_FROM_UNASSIGNED(value)					\
76   (((value) == UNASSIGNED_OBJECT)					\
77    ? EXTERNAL_UNASSIGNED_OBJECT						\
78    : (value))
79 
80 #define EXTERNAL_UNASSIGNED_OBJECT					\
81   (VECTOR_REF (fixed_objects, NON_OBJECT))
82 
83 #define PALIST_COND(palist_var) (PAIR_P (*palist_var))
84 
85 #define PALIST_HEADER(palist_var, prefs_var)				\
86   SCHEME_OBJECT * prefs_var = (PAIR_CDR_LOC (PAIR_CAR (*palist_var)));
87 
88 #define PALIST_FOOTER(palist_var) do					\
89 {									\
90   if (PAIR_P (PAIR_CDR (PAIR_CAR (*palist_var))))			\
91     palist_var = (PAIR_CDR_LOC (*palist_var));				\
92   else									\
93     (*palist_var) = (PAIR_CDR (*palist_var));				\
94 } while (false)
95 
96 #define PREFS_COND(prefs_var) (PAIR_P (*prefs_var))
97 
98 #define PREFS_HEADER(prefs_var)						\
99   PREFS_HEADER_1 (prefs_var, (PAIR_CAR (*prefs_var)))
100 
101 #define PREFS_HEADER_1(prefs_var, cache)				\
102 {									\
103   if ((GET_CACHE_REFERENCE_BLOCK (cache)) == SHARP_F)			\
104     {									\
105       (*prefs_var) = (PAIR_CDR (*prefs_var));				\
106       continue;								\
107     }									\
108 }
109 
110 #define PREFS_FOOTER(prefs_var) do					\
111 {									\
112   prefs_var = (PAIR_CDR_LOC (*prefs_var));				\
113 } while (false)
114 
115 #define WALK_REFERENCES(refs_pointer, ref_var, body)			\
116 {									\
117   SCHEME_OBJECT * WR_palist = (refs_pointer);				\
118   while (PALIST_COND (WR_palist))					\
119     {									\
120       PALIST_HEADER (WR_palist, WR_prefs);				\
121       while (PREFS_COND (WR_prefs))					\
122 	{								\
123 	  SCHEME_OBJECT ref_var = (PAIR_CAR (*WR_prefs));		\
124 	  PREFS_HEADER_1 (WR_prefs, ref_var);				\
125 	  body;								\
126 	  PREFS_FOOTER (WR_prefs);					\
127 	}								\
128       PALIST_FOOTER (WR_palist);					\
129     }									\
130 }
131 
132 /***** Forward References *****/
133 
134 static long lookup_variable_cache
135   (SCHEME_OBJECT, SCHEME_OBJECT *);
136 static long assign_variable_end
137   (SCHEME_OBJECT *, SCHEME_OBJECT, SCHEME_OBJECT *, int);
138 static long assign_variable_cache
139   (SCHEME_OBJECT, SCHEME_OBJECT, SCHEME_OBJECT *, int);
140 static long guarantee_extension_space
141   (SCHEME_OBJECT);
142 static long allocate_frame_extension
143   (unsigned long, SCHEME_OBJECT, SCHEME_OBJECT *);
144 static long unbind_cached_variable
145   (SCHEME_OBJECT *, SCHEME_OBJECT, SCHEME_OBJECT);
146 static void unbind_variable_1
147   (SCHEME_OBJECT *, SCHEME_OBJECT, SCHEME_OBJECT);
148 static unsigned long update_cache_refs_space
149   (SCHEME_OBJECT, SCHEME_OBJECT, SCHEME_OBJECT);
150 static unsigned long update_cache_refs_space_1
151   (SCHEME_OBJECT, unsigned int, SCHEME_OBJECT, SCHEME_OBJECT);
152 static long update_cache_references
153   (SCHEME_OBJECT, SCHEME_OBJECT *, SCHEME_OBJECT, SCHEME_OBJECT);
154 static SCHEME_OBJECT * find_binding_cell
155   (SCHEME_OBJECT, SCHEME_OBJECT, SCHEME_OBJECT *);
156 static SCHEME_OBJECT * scan_frame
157   (SCHEME_OBJECT, SCHEME_OBJECT, int);
158 static SCHEME_OBJECT * scan_procedure_bindings
159   (SCHEME_OBJECT, SCHEME_OBJECT, SCHEME_OBJECT, int);
160 static unsigned long count_references
161   (SCHEME_OBJECT *);
162 static void update_assignment_references
163   (SCHEME_OBJECT);
164 static long guarantee_cache
165   (SCHEME_OBJECT *);
166 static void update_clone
167   (SCHEME_OBJECT);
168 static long make_cache
169   (SCHEME_OBJECT, SCHEME_OBJECT, SCHEME_OBJECT, SCHEME_OBJECT *);
170 
171 #ifdef CC_SUPPORT_P
172 
173 static long update_uuo_links
174   (SCHEME_OBJECT, SCHEME_OBJECT);
175 static void move_all_references
176   (SCHEME_OBJECT, SCHEME_OBJECT, unsigned int);
177 static long add_cache_reference
178   (SCHEME_OBJECT, SCHEME_OBJECT, SCHEME_OBJECT, unsigned long, unsigned int);
179 static void add_reference
180   (SCHEME_OBJECT *, SCHEME_OBJECT, SCHEME_OBJECT, unsigned long);
181 static void install_cache
182   (SCHEME_OBJECT, SCHEME_OBJECT, unsigned long, unsigned int);
183 static void install_operator_cache
184   (SCHEME_OBJECT, SCHEME_OBJECT, unsigned long);
185 static unsigned long ref_pairs_to_move
186   (SCHEME_OBJECT *, SCHEME_OBJECT, SCHEME_OBJECT);
187 static void delete_ref_pairs
188   (SCHEME_OBJECT, unsigned int, SCHEME_OBJECT, SCHEME_OBJECT);
189 static void move_ref_pairs
190   (SCHEME_OBJECT, SCHEME_OBJECT, unsigned int, SCHEME_OBJECT, SCHEME_OBJECT);
191 static SCHEME_OBJECT * new_alist_entry
192   (SCHEME_OBJECT *, SCHEME_OBJECT);
193 static int move_ref_pair_p
194   (SCHEME_OBJECT, SCHEME_OBJECT);
195 static SCHEME_OBJECT * find_references_named
196   (SCHEME_OBJECT *, SCHEME_OBJECT);
197 static long make_cache_reference
198   (SCHEME_OBJECT, unsigned long, SCHEME_OBJECT *);
199 
200 #endif
201 
202 /***** Basic environment manipulation (lookup, assign, define).  *****/
203 
204 long
lookup_variable(SCHEME_OBJECT environment,SCHEME_OBJECT symbol,SCHEME_OBJECT * value_ret)205 lookup_variable (SCHEME_OBJECT environment, SCHEME_OBJECT symbol,
206 		 SCHEME_OBJECT * value_ret)
207 {
208   SCHEME_OBJECT * cell;
209   SCHEME_OBJECT value;
210 
211   if (! ((ENVIRONMENT_P (environment)) && (SYMBOL_P (symbol))))
212     return (ERR_BAD_FRAME);
213 
214   cell = (find_binding_cell (environment, symbol, 0));
215   if (cell == 0)
216     return (ERR_UNBOUND_VARIABLE);
217 
218   value = (*cell);
219   switch (get_trap_kind (value))
220     {
221     case NON_TRAP_KIND:
222       (*value_ret) = value;
223       return (PRIM_DONE);
224 
225     case TRAP_UNASSIGNED:
226       return (ERR_UNASSIGNED_VARIABLE);
227 
228     case TRAP_UNBOUND:
229       return (ERR_UNBOUND_VARIABLE);
230 
231     case TRAP_MACRO:
232       (*value_ret) = value;
233       return (ERR_MACRO_BINDING);
234 
235     case TRAP_COMPILER_CACHED:
236       return (lookup_variable_cache ((GET_TRAP_CACHE (value)), value_ret));
237 
238     default:
239       return (ERR_ILLEGAL_REFERENCE_TRAP);
240     }
241 }
242 
243 static long
lookup_variable_cache(SCHEME_OBJECT cache,SCHEME_OBJECT * value_ret)244 lookup_variable_cache (SCHEME_OBJECT cache, SCHEME_OBJECT * value_ret)
245 {
246   SCHEME_OBJECT value = (GET_CACHE_VALUE (cache));
247   switch (get_trap_kind (value))
248     {
249     case NON_TRAP_KIND:
250       (*value_ret) = value;
251       return (PRIM_DONE);
252 
253     case TRAP_UNASSIGNED:
254       return (ERR_UNASSIGNED_VARIABLE);
255 
256     case TRAP_UNBOUND:
257       return (ERR_UNBOUND_VARIABLE);
258 
259     case TRAP_MACRO:
260       (*value_ret) = value;
261       return (ERR_MACRO_BINDING);
262 
263     default:
264       return (ERR_ILLEGAL_REFERENCE_TRAP);
265     }
266 }
267 
268 long
safe_lookup_variable(SCHEME_OBJECT environment,SCHEME_OBJECT symbol,SCHEME_OBJECT * value_ret)269 safe_lookup_variable (SCHEME_OBJECT environment, SCHEME_OBJECT symbol,
270 		      SCHEME_OBJECT * value_ret)
271 {
272   long result = (lookup_variable (environment, symbol, value_ret));
273   if (result == ERR_UNASSIGNED_VARIABLE)
274     {
275       (*value_ret) = EXTERNAL_UNASSIGNED_OBJECT;
276       return (PRIM_DONE);
277     }
278   return (result);
279 }
280 
281 long
variable_unassigned_p(SCHEME_OBJECT environment,SCHEME_OBJECT symbol,SCHEME_OBJECT * value_ret)282 variable_unassigned_p (SCHEME_OBJECT environment, SCHEME_OBJECT symbol,
283 		       SCHEME_OBJECT * value_ret)
284 {
285   SCHEME_OBJECT dummy_value;
286   long result = (lookup_variable (environment, symbol, (&dummy_value)));
287   switch (result)
288     {
289     case ERR_UNASSIGNED_VARIABLE:
290       (*value_ret) = SHARP_T;
291       return (PRIM_DONE);
292 
293     case PRIM_DONE:
294       (*value_ret) = SHARP_F;
295       return (PRIM_DONE);
296 
297     default:
298       return (result);
299     }
300 }
301 
302 long
variable_unbound_p(SCHEME_OBJECT environment,SCHEME_OBJECT symbol,SCHEME_OBJECT * value_ret)303 variable_unbound_p (SCHEME_OBJECT environment, SCHEME_OBJECT symbol,
304 		    SCHEME_OBJECT * value_ret)
305 {
306   SCHEME_OBJECT dummy_value;
307   long result = (lookup_variable (environment, symbol, (&dummy_value)));
308   switch (result)
309     {
310     case ERR_UNBOUND_VARIABLE:
311       (*value_ret) = SHARP_T;
312       return (PRIM_DONE);
313 
314     case ERR_UNASSIGNED_VARIABLE:
315     case ERR_MACRO_BINDING:
316     case PRIM_DONE:
317       (*value_ret) = SHARP_F;
318       return (PRIM_DONE);
319 
320     default:
321       return (result);
322     }
323 }
324 
325 long
variable_unreferenceable_p(SCHEME_OBJECT environment,SCHEME_OBJECT symbol,SCHEME_OBJECT * value_ret)326 variable_unreferenceable_p (SCHEME_OBJECT environment, SCHEME_OBJECT symbol,
327 			    SCHEME_OBJECT * value_ret)
328 {
329   SCHEME_OBJECT dummy_value;
330   long result = (lookup_variable (environment, symbol, (&dummy_value)));
331   switch (result)
332     {
333     case ERR_UNBOUND_VARIABLE:
334     case ERR_UNASSIGNED_VARIABLE:
335     case ERR_MACRO_BINDING:
336       (*value_ret) = SHARP_T;
337       return (PRIM_DONE);
338 
339     case PRIM_DONE:
340       (*value_ret) = SHARP_F;
341       return (PRIM_DONE);
342 
343     default:
344       return (result);
345     }
346 }
347 
348 long
assign_variable(SCHEME_OBJECT environment,SCHEME_OBJECT symbol,SCHEME_OBJECT value,SCHEME_OBJECT * value_ret)349 assign_variable (SCHEME_OBJECT environment, SCHEME_OBJECT symbol,
350 		 SCHEME_OBJECT value, SCHEME_OBJECT * value_ret)
351 {
352   if (! ((ENVIRONMENT_P (environment)) || (SYMBOL_P (symbol))))
353     return (ERR_BAD_FRAME);
354   {
355     SCHEME_OBJECT * cell = (find_binding_cell (environment, symbol, 0));
356     if (cell == 0)
357       return (ERR_UNBOUND_VARIABLE);
358     return (assign_variable_end (cell, value, value_ret, 0));
359   }
360 }
361 
362 static long
assign_variable_end(SCHEME_OBJECT * cell,SCHEME_OBJECT value,SCHEME_OBJECT * value_ret,int force_p)363 assign_variable_end (SCHEME_OBJECT * cell, SCHEME_OBJECT value,
364 		     SCHEME_OBJECT * value_ret, int force_p)
365 {
366   SCHEME_OBJECT old_value = (*cell);
367   switch (get_trap_kind (old_value))
368     {
369     case NON_TRAP_KIND:
370     case TRAP_UNASSIGNED:
371       break;
372 
373     case TRAP_UNBOUND:
374       if (force_p)
375 	break;
376       return (ERR_UNBOUND_VARIABLE);
377 
378     case TRAP_MACRO:
379       if (force_p)
380 	break;
381       return (ERR_MACRO_BINDING);
382 
383     case TRAP_COMPILER_CACHED:
384       return
385 	(assign_variable_cache
386 	 ((GET_TRAP_CACHE (old_value)), value, value_ret, force_p));
387 
388     default:
389       return (ERR_ILLEGAL_REFERENCE_TRAP);
390     }
391   (*value_ret) = (MAP_FROM_UNASSIGNED (old_value));
392   (*cell) = (MAP_TO_UNASSIGNED (value));
393   return (PRIM_DONE);
394 }
395 
396 static long
assign_variable_cache(SCHEME_OBJECT cache,SCHEME_OBJECT value,SCHEME_OBJECT * value_ret,int force_p)397 assign_variable_cache (SCHEME_OBJECT cache, SCHEME_OBJECT value,
398 		       SCHEME_OBJECT * value_ret, int force_p)
399 {
400   SCHEME_OBJECT old_value = (GET_CACHE_VALUE (cache));
401   switch (get_trap_kind (old_value))
402     {
403     case NON_TRAP_KIND:
404     case TRAP_UNASSIGNED:
405       break;
406 
407     case TRAP_UNBOUND:
408       if (force_p)
409 	break;
410       return (ERR_UNBOUND_VARIABLE);
411 
412     case TRAP_MACRO:
413       if (force_p)
414 	break;
415       return (ERR_MACRO_BINDING);
416 
417     default:
418       return (ERR_ILLEGAL_REFERENCE_TRAP);
419     }
420   (*value_ret) = (MAP_FROM_UNASSIGNED (old_value));
421   /* Perform the assignment.  If there are any operator references to
422      this variable, update their links.  */
423 #ifdef CC_SUPPORT_P
424   if (PAIR_P (* (GET_CACHE_OPERATOR_REFERENCES (cache))))
425     return (update_uuo_links (cache, (MAP_TO_UNASSIGNED (value))));
426 #endif
427   SET_CACHE_VALUE (cache, (MAP_TO_UNASSIGNED (value)));
428   return (PRIM_DONE);
429 }
430 
431 #ifdef CC_SUPPORT_P
432 static long
update_uuo_links(SCHEME_OBJECT cache,SCHEME_OBJECT new_value)433 update_uuo_links (SCHEME_OBJECT cache, SCHEME_OBJECT new_value)
434 {
435   GC_CHECK
436     (((count_references (GET_CACHE_OPERATOR_REFERENCES (cache)))
437       * SPACE_PER_UUO_LINK)
438      + SPACE_PER_CACHE);
439   SET_CACHE_VALUE (cache, new_value);
440   update_clone (cache);
441   WALK_REFERENCES
442     ((GET_CACHE_OPERATOR_REFERENCES (cache)),
443      reference,
444      {
445        install_operator_cache (cache,
446 			       (GET_CACHE_REFERENCE_BLOCK (reference)),
447 			       (GET_CACHE_REFERENCE_OFFSET (reference)));
448      });
449   return (PRIM_DONE);
450 }
451 #endif
452 
453 long
define_variable(SCHEME_OBJECT environment,SCHEME_OBJECT symbol,SCHEME_OBJECT value)454 define_variable (SCHEME_OBJECT environment, SCHEME_OBJECT symbol,
455 		 SCHEME_OBJECT value)
456 {
457   if (! ((ENVIRONMENT_P (environment)) || (SYMBOL_P (symbol))))
458     return (ERR_BAD_FRAME);
459 
460   /* If there is already a binding, just assign to it.  */
461   {
462     SCHEME_OBJECT * cell = (scan_frame (environment, symbol, 1));
463     SCHEME_OBJECT old_value;
464     if (cell != 0)
465       {
466 	if (GLOBAL_FRAME_P (environment))
467 	  strengthen_symbol (symbol);
468 	return (assign_variable_end (cell, value, (&old_value), 1));
469       }
470   }
471 
472   /* At this point, we know that environment can't be the global
473      environment, because scan_frame would have returned a non-null
474      pointer for the global environment.  */
475 
476   RETURN_IF_ERROR (guarantee_extension_space (environment));
477 
478   /* If this binding shadows another binding, we'll have to recache
479      any references to the other binding, because some of them might
480      now refer to the new binding instead.  */
481   {
482     SCHEME_OBJECT * shadowed_cell
483       = (find_binding_cell ((GET_FRAME_PARENT (environment)), symbol, 0));
484     SCHEME_OBJECT old_cache
485       = (((shadowed_cell != 0)
486 	  && ((get_trap_kind (*shadowed_cell)) == TRAP_COMPILER_CACHED))
487 	 ? (GET_TRAP_CACHE (*shadowed_cell))
488 	 : SHARP_F);
489     unsigned long length = (GET_EXTENDED_FRAME_LENGTH (environment));
490     SCHEME_OBJECT pair;
491 
492     /* Make sure there is enough space available to move any
493        references that need moving.  */
494     GC_CHECK
495       (2
496        + ((old_cache != SHARP_F)
497 	  ? (update_cache_refs_space (old_cache, environment, symbol))
498 	  : 0));
499 
500     /* Create the binding.  */
501     pair = (cons (symbol, (MAP_TO_UNASSIGNED (value))));
502     ((GET_EXTENDED_FRAME_BINDINGS (environment)) [length]) = pair;
503     SET_EXTENDED_FRAME_LENGTH (environment, (length + 1));
504 
505     /* Move any references that need moving.  */
506     return
507       ((old_cache != SHARP_F)
508        ? (update_cache_references
509 	  (old_cache, (PAIR_CDR_LOC (pair)), environment, symbol))
510        : PRIM_DONE);
511   }
512 }
513 
514 static long
guarantee_extension_space(SCHEME_OBJECT environment)515 guarantee_extension_space (SCHEME_OBJECT environment)
516 {
517   if (EXTENDED_FRAME_P (environment))
518     /* Guarantee that there is room in the extension for a binding.  */
519     {
520       unsigned long length = (GET_EXTENDED_FRAME_LENGTH (environment));
521       if (length == (GET_MAX_EXTENDED_FRAME_LENGTH (environment)))
522 	{
523 	  SCHEME_OBJECT extension;
524 	  RETURN_IF_ERROR
525 	    (allocate_frame_extension
526 	     ((2 * length),
527 	      (GET_EXTENDED_FRAME_PROCEDURE (environment)),
528 	      (&extension)));
529 	  memcpy ((GET_FRAME_EXTENSION_BINDINGS (extension)),
530 		  (GET_EXTENDED_FRAME_BINDINGS (environment)),
531 		  (length * (sizeof (SCHEME_OBJECT))));
532 	  SET_FRAME_EXTENSION_LENGTH (extension, length);
533 	  SET_FRAME_EXTENSION (environment, extension);
534 	}
535     }
536   else
537     /* There's no extension, so create one. */
538     {
539       SCHEME_OBJECT extension;
540       RETURN_IF_ERROR
541 	(allocate_frame_extension (16,
542 				   (GET_FRAME_PROCEDURE (environment)),
543 				   (&extension)));
544       SET_FRAME_EXTENSION (environment, extension);
545     }
546   return (PRIM_DONE);
547 }
548 
549 static long
allocate_frame_extension(unsigned long length,SCHEME_OBJECT procedure,SCHEME_OBJECT * extension_ret)550 allocate_frame_extension (unsigned long length, SCHEME_OBJECT procedure,
551 			  SCHEME_OBJECT * extension_ret)
552 {
553   unsigned long n_words = (ENV_EXTENSION_MIN_SIZE + length);
554   GC_CHECK (n_words);
555   {
556     SCHEME_OBJECT extension = (make_vector ((n_words - 1), SHARP_F, 0));
557     SET_FRAME_EXTENSION_PARENT_FRAME
558       (extension, (GET_PROCEDURE_ENVIRONMENT (procedure)));
559     SET_FRAME_EXTENSION_PROCEDURE (extension, procedure);
560     SET_FRAME_EXTENSION_LENGTH (extension, 0);
561     (*extension_ret) = extension;
562     return (PRIM_DONE);
563   }
564 }
565 
566 long
link_variables(SCHEME_OBJECT target_environment,SCHEME_OBJECT target_symbol,SCHEME_OBJECT source_environment,SCHEME_OBJECT source_symbol)567 link_variables (SCHEME_OBJECT target_environment, SCHEME_OBJECT target_symbol,
568 		SCHEME_OBJECT source_environment, SCHEME_OBJECT source_symbol)
569 {
570   SCHEME_OBJECT * source_cell;
571   trap_kind_t source_kind;
572   SCHEME_OBJECT * target_cell;
573 
574   if (! ((ENVIRONMENT_P (target_environment))
575 	 && (ENVIRONMENT_P (source_environment))
576 	 && (SYMBOL_P (target_symbol))
577 	 && (SYMBOL_P (source_symbol))))
578     return (ERR_BAD_FRAME);
579 
580   source_cell = (find_binding_cell (source_environment, source_symbol, 0));
581   if (source_cell == 0)
582     return (ERR_UNBOUND_VARIABLE);
583 
584   source_kind = (get_trap_kind (*source_cell));
585   if (source_kind == TRAP_UNBOUND)
586     return (ERR_UNBOUND_VARIABLE);
587 
588   target_cell = (scan_frame (target_environment, target_symbol, 1));
589   if (target_cell == source_cell)
590     return (PRIM_DONE);
591 
592   if ((target_cell != 0) && (GLOBAL_FRAME_P (target_environment)))
593     strengthen_symbol (target_symbol);
594 
595   if ((target_cell != 0)
596       && ((get_trap_kind (*target_cell)) == TRAP_COMPILER_CACHED))
597     {
598       SCHEME_OBJECT target_cache = (GET_TRAP_CACHE (*target_cell));
599       if (source_kind == TRAP_COMPILER_CACHED)
600 	{
601 	  SCHEME_OBJECT source_cache = (GET_TRAP_CACHE (*source_cell));
602 	  if (source_cache == target_cache)
603 	    /* Already linked.  */
604 	    return (PRIM_DONE);
605 	  GC_CHECK
606 	    (((count_references (GET_CACHE_OPERATOR_REFERENCES (target_cache)))
607 	      * SPACE_PER_UUO_LINK)
608 	     + (2 * SPACE_PER_CACHE));
609 	  SET_CACHE_VALUE (target_cache, (GET_CACHE_VALUE (source_cache)));
610 #ifdef CC_SUPPORT_P
611 	  move_all_references
612 	    (source_cache, target_cache, CACHE_REFERENCES_LOOKUP);
613 	  move_all_references
614 	    (source_cache, target_cache, CACHE_REFERENCES_ASSIGNMENT);
615 	  move_all_references
616 	    (source_cache, target_cache, CACHE_REFERENCES_OPERATOR);
617 #endif
618 	  update_clone (source_cache);
619 	  update_clone (target_cache);
620 
621 	  /* Make sure both traps share the same cache: */
622 	  SET_TRAP_CACHE ((*source_cell), target_cache);
623 	}
624       else
625 	SET_CACHE_VALUE (target_cache, (*source_cell));
626       (*source_cell) = (*target_cell);
627       return (PRIM_DONE);
628     }
629 
630   RETURN_IF_ERROR (guarantee_cache (source_cell));
631   return (define_variable (target_environment, target_symbol, (*source_cell)));
632 }
633 
634 #ifdef CC_SUPPORT_P
635 static void
move_all_references(SCHEME_OBJECT from_cache,SCHEME_OBJECT to_cache,unsigned int reference_kind)636 move_all_references (SCHEME_OBJECT from_cache, SCHEME_OBJECT to_cache,
637 		     unsigned int reference_kind)
638 {
639   SCHEME_OBJECT * pfrom = (GET_CACHE_REFERENCES (from_cache, reference_kind));
640   SCHEME_OBJECT * pto = (GET_CACHE_REFERENCES (to_cache, reference_kind));
641 
642   WALK_REFERENCES
643     (pfrom,
644      reference,
645      {
646        install_cache (to_cache,
647 		      (GET_CACHE_REFERENCE_BLOCK (reference)),
648 		      (GET_CACHE_REFERENCE_OFFSET (reference)),
649 		      reference_kind);
650      });
651 
652   while (PAIR_P (*pto))
653     pto = (PAIR_CDR_LOC (*pto));
654   (*pto) = (*pfrom);
655   (*pfrom) = EMPTY_LIST;
656 }
657 #endif
658 
659 long
unbind_variable(SCHEME_OBJECT environment,SCHEME_OBJECT symbol,SCHEME_OBJECT * value_ret)660 unbind_variable (SCHEME_OBJECT environment, SCHEME_OBJECT symbol,
661 		 SCHEME_OBJECT * value_ret)
662 {
663   SCHEME_OBJECT frame;
664   SCHEME_OBJECT * cell = (find_binding_cell (environment, symbol, (&frame)));
665   if (GLOBAL_FRAME_P (frame))
666     weaken_symbol (symbol);
667   switch ((cell == 0) ? TRAP_UNBOUND : (get_trap_kind (*cell)))
668     {
669     case TRAP_UNBOUND:
670       (*value_ret) = SHARP_F;
671       return (PRIM_DONE);
672 
673     case NON_TRAP_KIND:
674     case TRAP_UNASSIGNED:
675     case TRAP_MACRO:
676       unbind_variable_1 (cell, frame, symbol);
677       (*value_ret) = SHARP_T;
678       return (PRIM_DONE);
679 
680     case TRAP_COMPILER_CACHED:
681       {
682 	SCHEME_OBJECT cache = (GET_TRAP_CACHE (*cell));
683 	switch (get_trap_kind (GET_CACHE_VALUE (cache)))
684 	  {
685 	  case TRAP_UNBOUND:
686 	    (*value_ret) = SHARP_F;
687 	    return (PRIM_DONE);
688 
689 	  case NON_TRAP_KIND:
690 	  case TRAP_UNASSIGNED:
691 	  case TRAP_MACRO:
692 	    if (PROCEDURE_FRAME_P (frame))
693 	      {
694 		RETURN_IF_ERROR
695 		  (unbind_cached_variable (cell, frame, symbol));
696 	      }
697 	    else
698 	      {
699 		SET_CACHE_VALUE (cache, UNBOUND_OBJECT);
700 	      }
701 	    (*value_ret) = SHARP_T;
702 	    return (PRIM_DONE);
703 
704 	  default:
705 	    return (ERR_ILLEGAL_REFERENCE_TRAP);
706 	  }
707       }
708 
709     default:
710       return (ERR_ILLEGAL_REFERENCE_TRAP);
711     }
712 }
713 
714 static long
unbind_cached_variable(SCHEME_OBJECT * cell,SCHEME_OBJECT frame,SCHEME_OBJECT symbol)715 unbind_cached_variable (SCHEME_OBJECT * cell, SCHEME_OBJECT frame,
716 			SCHEME_OBJECT symbol)
717 {
718   SCHEME_OBJECT cache = (GET_TRAP_CACHE (*cell));
719   SCHEME_OBJECT * shadowed_cell
720     = (find_binding_cell ((GET_FRAME_PARENT (frame)), symbol, 0));
721   GC_CHECK (update_cache_refs_space (cache, frame, symbol));
722   unbind_variable_1 (cell, frame, symbol);
723   return (update_cache_references (cache, shadowed_cell, frame, symbol));
724 }
725 
726 static void
unbind_variable_1(SCHEME_OBJECT * cell,SCHEME_OBJECT frame,SCHEME_OBJECT symbol)727 unbind_variable_1 (SCHEME_OBJECT * cell,
728 		   SCHEME_OBJECT frame, SCHEME_OBJECT symbol)
729 {
730   if ((PROCEDURE_FRAME_P (frame)) && (EXTENDED_FRAME_P (frame)))
731     {
732       SCHEME_OBJECT * start = (GET_EXTENDED_FRAME_BINDINGS (frame));
733       unsigned long length = (GET_EXTENDED_FRAME_LENGTH (frame));
734       unsigned long index = 0;
735       while (index < length)
736 	{
737 	  if ((PAIR_CAR (start[index])) == symbol)
738 	    {
739 	      if (index < (length - 1))
740 		(start[index]) = (start [length - 1]);
741 	      SET_EXTENDED_FRAME_LENGTH (frame, (length - 1));
742 	      (start [length - 1]) = SHARP_F;
743 	      return;
744 	    }
745 	  index += 1;
746 	}
747     }
748   (*cell) = UNBOUND_OBJECT;
749 }
750 
751 /***** Interface to compiled code.  *****/
752 
753 #ifdef CC_SUPPORT_P
754 
755 long
compiler_cache_lookup(SCHEME_OBJECT name,SCHEME_OBJECT block,unsigned long offset)756 compiler_cache_lookup (SCHEME_OBJECT name, SCHEME_OBJECT block,
757 		       unsigned long offset)
758 {
759   return
760     (add_cache_reference ((cc_block_environment (block)),
761 			  name, block, offset,
762 			  CACHE_REFERENCES_LOOKUP));
763 }
764 
765 long
compiler_cache_assignment(SCHEME_OBJECT name,SCHEME_OBJECT block,unsigned long offset)766 compiler_cache_assignment (SCHEME_OBJECT name, SCHEME_OBJECT block,
767 			   unsigned long offset)
768 {
769   return
770     (add_cache_reference ((cc_block_environment (block)),
771 			  name, block, offset,
772 			  CACHE_REFERENCES_ASSIGNMENT));
773 }
774 
775 long
compiler_cache_operator(SCHEME_OBJECT name,SCHEME_OBJECT block,unsigned long offset)776 compiler_cache_operator (SCHEME_OBJECT name, SCHEME_OBJECT block,
777 			 unsigned long offset)
778 {
779   return
780     (add_cache_reference ((cc_block_environment (block)),
781 			  name, block, offset,
782 			  CACHE_REFERENCES_OPERATOR));
783 }
784 
785 long
compiler_cache_global_operator(SCHEME_OBJECT name,SCHEME_OBJECT block,unsigned long offset)786 compiler_cache_global_operator (SCHEME_OBJECT name, SCHEME_OBJECT block,
787 				unsigned long offset)
788 {
789   return
790     (add_cache_reference (THE_GLOBAL_ENV,
791 			  name, block, offset,
792 			  CACHE_REFERENCES_OPERATOR));
793 }
794 
795 SCHEME_OBJECT
compiler_var_error(SCHEME_OBJECT cache,SCHEME_OBJECT block,unsigned int reference_kind)796 compiler_var_error (SCHEME_OBJECT cache, SCHEME_OBJECT block,
797 		    unsigned int reference_kind)
798 {
799   WALK_REFERENCES
800     ((GET_CACHE_REFERENCES (cache, reference_kind)),
801      reference,
802      {
803        /* If this reference is in the right block, return the symbol
804 	  being referenced.  */
805        if ((GET_CACHE_REFERENCE_BLOCK (reference)) == block)
806 	 return (PAIR_CAR (PAIR_CAR (*WR_palist)));
807      });
808   return (SHARP_F);
809 }
810 
811 long
compiler_lookup_trap(SCHEME_OBJECT cache,SCHEME_OBJECT * value_ret)812 compiler_lookup_trap (SCHEME_OBJECT cache, SCHEME_OBJECT * value_ret)
813 {
814   return (lookup_variable_cache (cache, value_ret));
815 }
816 
817 long
compiler_safe_lookup_trap(SCHEME_OBJECT cache,SCHEME_OBJECT * value_ret)818 compiler_safe_lookup_trap (SCHEME_OBJECT cache, SCHEME_OBJECT * value_ret)
819 {
820   long result = (lookup_variable_cache (cache, value_ret));
821   if (result == ERR_UNASSIGNED_VARIABLE)
822     {
823       (*value_ret) = EXTERNAL_UNASSIGNED_OBJECT;
824       return (PRIM_DONE);
825     }
826   return (result);
827 }
828 
829 long
compiler_unassigned_p_trap(SCHEME_OBJECT cache,SCHEME_OBJECT * value_ret)830 compiler_unassigned_p_trap (SCHEME_OBJECT cache, SCHEME_OBJECT * value_ret)
831 {
832   SCHEME_OBJECT dummy_value;
833   long result = (lookup_variable_cache (cache, (&dummy_value)));
834   switch (result)
835     {
836     case ERR_UNASSIGNED_VARIABLE:
837       (*value_ret) = SHARP_T;
838       return (PRIM_DONE);
839 
840     case PRIM_DONE:
841       (*value_ret) = SHARP_F;
842       return (PRIM_DONE);
843 
844     default:
845       return (result);
846     }
847 }
848 
849 long
compiler_assignment_trap(SCHEME_OBJECT cache,SCHEME_OBJECT value,SCHEME_OBJECT * value_ret)850 compiler_assignment_trap (SCHEME_OBJECT cache, SCHEME_OBJECT value,
851 			  SCHEME_OBJECT * value_ret)
852 {
853   return
854     (assign_variable_cache
855      ((((GET_CACHE_VALUE (cache)) == EXPENSIVE_OBJECT)
856        /* The cache is a clone.  Get the real cache object.  */
857        ? (GET_CACHE_CLONE (cache))
858        : cache),
859       value,
860       value_ret,
861       0));
862 }
863 
864 long
compiler_operator_reference_trap(SCHEME_OBJECT cache,SCHEME_OBJECT * value_ret)865 compiler_operator_reference_trap (SCHEME_OBJECT cache,
866 				  SCHEME_OBJECT * value_ret)
867 {
868   return (lookup_variable_cache (cache, value_ret));
869 }
870 
871 /***** Variable-reference cache mechanism.  *****/
872 
873 /* add_cache_reference adds a reference to a variable's cache,
874    creating the cache if necessary.  It takes the following arguments:
875 
876    + environment and symbol specify the affected variable.
877 
878    + block is a compiled-code block, and offset is an offset into
879      block.  Together, these specify the location where the variable
880      cache is to be stored.
881 
882    + reference_kind specifies the kind of reference that is being cached.
883 
884    add_cache_reference creates a variable cache for the specified variable,
885    if needed, and stores it in the location specified by (block,
886    offset).  It adds the (block,offset) reference to the appropriate
887    reference list for subsequent updating.
888 
889    If the reference is a lookup reference, the cache is directly
890    stored in the block.
891 
892    If the reference is an assignment reference, and there are no
893    operator references to this variable, the cache is directly stored
894    in the block.
895 
896    If the reference is an assignment reference, and there _are_
897    operator references to this variable, a "clone" cache is stored in
898    the block.  The "clone" cache has a value of EXPENSIVE_OBJECT,
899    which causes any assignment to this cell to trap out to the
900    microcode, where the expensive process of updating all the related
901    operator references can be performed.
902 
903    If the reference is an operator reference, a "UUO" link is stored
904    in the block.  If the variable's value is a compiled procedure, the
905    UUO link is a direct reference to the procedure.  In all other
906    cases it is a dummy procedure that redirects as needed.  If there
907    are assignment references to this variable but no "clone" cache,
908    one is created and all the assignment references updated to point
909    to it.  */
910 
911 static long
add_cache_reference(SCHEME_OBJECT environment,SCHEME_OBJECT symbol,SCHEME_OBJECT block,unsigned long offset,unsigned int reference_kind)912 add_cache_reference (SCHEME_OBJECT environment, SCHEME_OBJECT symbol,
913 		     SCHEME_OBJECT block, unsigned long offset,
914 		     unsigned int reference_kind)
915 {
916   SCHEME_OBJECT frame = 0;
917   SCHEME_OBJECT * cell = (find_binding_cell (environment, symbol, (&frame)));
918   SCHEME_OBJECT dummy_cell = UNBOUND_OBJECT;
919   if (cell == 0)
920     /* There's no binding for the variable, and we don't have access
921        to the global environment.  The compiled code needs a cache, so
922        we'll install one, but it won't be attached to any environment
923        structure.  */
924     cell = (&dummy_cell);
925   else if (GLOBAL_FRAME_P (frame))
926     strengthen_symbol (symbol);
927   /* This procedure must complete to keep the data structures
928      consistent, so we do a GC check in advance to guarantee that all
929      of the allocations will finish.  */
930   GC_CHECK ((2 * SPACE_PER_CACHE) + SPACE_PER_REFERENCE + SPACE_PER_UUO_LINK);
931   DIE_IF_ERROR (guarantee_cache (cell));
932   {
933     SCHEME_OBJECT cache = (GET_TRAP_CACHE (*cell));
934     add_reference
935       ((GET_CACHE_REFERENCES (cache, reference_kind)), symbol, block, offset);
936     update_clone (cache);
937     install_cache (cache, block, offset, reference_kind);
938   }
939   return (PRIM_DONE);
940 }
941 
942 /* Add a new cached reference to the cached reference list pointed at
943    by slot.  Attempt to reuse pairs which have been "emptied" by the
944    garbage collector.  */
945 
946 static void
add_reference(SCHEME_OBJECT * palist,SCHEME_OBJECT symbol,SCHEME_OBJECT block,unsigned long offset)947 add_reference (SCHEME_OBJECT * palist,
948 	       SCHEME_OBJECT symbol, SCHEME_OBJECT block, unsigned long offset)
949 {
950   SCHEME_OBJECT * prefs = (find_references_named (palist, symbol));
951   if (prefs != 0)
952     {
953       while (PREFS_COND (prefs))
954 	{
955 	  if ((GET_CACHE_REFERENCE_BLOCK (PAIR_CAR (*prefs))) == SHARP_F)
956 	    {
957 	      /* Reuse this pair.  */
958 	      SET_CACHE_REFERENCE_BLOCK ((PAIR_CAR (*prefs)), block);
959 	      SET_CACHE_REFERENCE_OFFSET ((PAIR_CAR (*prefs)), offset);
960 	      return;
961 	    }
962 	  PREFS_FOOTER (prefs);
963 	}
964       {
965 	SCHEME_OBJECT reference;
966 	DIE_IF_ERROR (make_cache_reference (block, offset, (&reference)));
967 	(*prefs) = (cons (reference, EMPTY_LIST));
968       }
969       return;
970     }
971   {
972     SCHEME_OBJECT reference;
973     SCHEME_OBJECT alist;
974     DIE_IF_ERROR (make_cache_reference (block, offset, (&reference)));
975     alist = (*palist);
976     (*palist) = (cons ((cons (symbol, (cons (reference, EMPTY_LIST)))), alist));
977   }
978 }
979 
980 static void
install_cache(SCHEME_OBJECT cache,SCHEME_OBJECT block,unsigned long offset,unsigned int reference_kind)981 install_cache (SCHEME_OBJECT cache, SCHEME_OBJECT block, unsigned long offset,
982 	       unsigned int reference_kind)
983 {
984   switch (reference_kind)
985     {
986     case CACHE_REFERENCES_LOOKUP:
987       write_variable_cache (cache, block, offset);
988       break;
989 
990     case CACHE_REFERENCES_ASSIGNMENT:
991       write_variable_cache
992 	((((GET_CACHE_CLONE (cache)) != SHARP_F)
993 	  ? (GET_CACHE_CLONE (cache))
994 	  : cache),
995 	 block,
996 	 offset);
997       break;
998 
999     case CACHE_REFERENCES_OPERATOR:
1000       install_operator_cache (cache, block, offset);
1001       break;
1002 
1003     default:
1004       abort ();
1005       break;
1006     }
1007 }
1008 
1009 static void
install_operator_cache(SCHEME_OBJECT cache,SCHEME_OBJECT block,unsigned long offset)1010 install_operator_cache (SCHEME_OBJECT cache,
1011 			SCHEME_OBJECT block, unsigned long offset)
1012 {
1013   SCHEME_OBJECT value = (GET_CACHE_VALUE (cache));
1014   DIE_IF_ERROR (make_uuo_link (value, cache, block, offset));
1015 }
1016 
1017 #endif /* CC_SUPPORT_P */
1018 
1019 static unsigned long
update_cache_refs_space(SCHEME_OBJECT from_cache,SCHEME_OBJECT environment,SCHEME_OBJECT symbol)1020 update_cache_refs_space (SCHEME_OBJECT from_cache, SCHEME_OBJECT environment,
1021 			 SCHEME_OBJECT symbol)
1022 {
1023 #ifdef CC_SUPPORT_P
1024   return
1025     ((update_cache_refs_space_1
1026       (from_cache, CACHE_REFERENCES_LOOKUP, environment, symbol))
1027      + (update_cache_refs_space_1
1028 	(from_cache, CACHE_REFERENCES_ASSIGNMENT, environment, symbol))
1029      + (update_cache_refs_space_1
1030 	(from_cache, CACHE_REFERENCES_OPERATOR, environment, symbol)));
1031 #else
1032   return (0);
1033 #endif
1034 }
1035 
1036 /* Generate a conservative estimate of the space needed to move some
1037    cache refs from one cache to another.  */
1038 
1039 static unsigned long
update_cache_refs_space_1(SCHEME_OBJECT from_cache,unsigned int kind,SCHEME_OBJECT environment,SCHEME_OBJECT symbol)1040 update_cache_refs_space_1 (SCHEME_OBJECT from_cache, unsigned int kind,
1041 			   SCHEME_OBJECT environment, SCHEME_OBJECT symbol)
1042 {
1043   SCHEME_OBJECT * from_palist = (GET_CACHE_REFERENCES (from_cache, kind));
1044   unsigned long n_refs = (ref_pairs_to_move (from_palist, environment, symbol));
1045   unsigned long result = 0;
1046   if (n_refs > 0)
1047     {
1048       /* Space for new cache and new alist entry, if needed.  */
1049       result += (SPACE_PER_CACHE + 4);
1050       if (kind == CACHE_REFERENCES_OPERATOR)
1051 	/* space for new trampolines, if needed.  */
1052 	result += (n_refs * SPACE_PER_UUO_LINK);
1053     }
1054   return (result);
1055 }
1056 
1057 static long
update_cache_references(SCHEME_OBJECT from_cache,SCHEME_OBJECT * to_cell,SCHEME_OBJECT environment,SCHEME_OBJECT symbol)1058 update_cache_references (SCHEME_OBJECT from_cache, SCHEME_OBJECT * to_cell,
1059 			 SCHEME_OBJECT environment, SCHEME_OBJECT symbol)
1060 {
1061   if (to_cell != 0)
1062     {
1063       DIE_IF_ERROR (guarantee_cache (to_cell));
1064       {
1065 	SCHEME_OBJECT to_cache = (GET_TRAP_CACHE (*to_cell));
1066 #ifdef CC_SUPPORT_P
1067 	move_ref_pairs
1068 	  (from_cache, to_cache, CACHE_REFERENCES_LOOKUP,
1069 	   environment, symbol);
1070 	move_ref_pairs
1071 	  (from_cache, to_cache, CACHE_REFERENCES_ASSIGNMENT,
1072 	   environment, symbol);
1073 	move_ref_pairs
1074 	  (from_cache, to_cache, CACHE_REFERENCES_OPERATOR,
1075 	   environment, symbol);
1076 #endif
1077 	update_clone (to_cache);
1078       }
1079     }
1080 #ifdef CC_SUPPORT_P
1081   else
1082     {
1083       delete_ref_pairs
1084 	(from_cache, CACHE_REFERENCES_LOOKUP, environment, symbol);
1085       delete_ref_pairs
1086 	(from_cache, CACHE_REFERENCES_ASSIGNMENT, environment, symbol);
1087       delete_ref_pairs
1088 	(from_cache, CACHE_REFERENCES_OPERATOR, environment, symbol);
1089     }
1090 #endif
1091   update_clone (from_cache);
1092   return (PRIM_DONE);
1093 }
1094 
1095 #ifdef CC_SUPPORT_P
1096 
1097 static unsigned long
ref_pairs_to_move(SCHEME_OBJECT * palist,SCHEME_OBJECT environment,SCHEME_OBJECT symbol)1098 ref_pairs_to_move (SCHEME_OBJECT * palist, SCHEME_OBJECT environment,
1099 		   SCHEME_OBJECT symbol)
1100 {
1101   SCHEME_OBJECT * prefs = (find_references_named (palist, symbol));
1102   unsigned long n_refs = 0;
1103   if (prefs != 0)
1104     while (PREFS_COND (prefs))
1105       {
1106 	PREFS_HEADER (prefs);
1107 	if (move_ref_pair_p ((*prefs), environment))
1108 	  n_refs += 1;
1109 	PREFS_FOOTER (prefs);
1110       }
1111   return (n_refs);
1112 }
1113 
1114 static void
delete_ref_pairs(SCHEME_OBJECT from_cache,unsigned int kind,SCHEME_OBJECT environment,SCHEME_OBJECT symbol)1115 delete_ref_pairs (SCHEME_OBJECT from_cache, unsigned int kind,
1116 		  SCHEME_OBJECT environment, SCHEME_OBJECT symbol)
1117 {
1118   SCHEME_OBJECT * from_palist = (GET_CACHE_REFERENCES (from_cache, kind));
1119   SCHEME_OBJECT * from_prefs = (find_references_named (from_palist, symbol));
1120   if (from_prefs != 0)
1121     while (PREFS_COND (from_prefs))
1122       {
1123 	PREFS_HEADER (from_prefs);
1124 	if (move_ref_pair_p ((*from_prefs), environment))
1125 	  {
1126 	    (*from_prefs) = (PAIR_CDR (*from_prefs));
1127 	    continue;
1128 	  }
1129 	PREFS_FOOTER (from_prefs);
1130       }
1131 }
1132 
1133 static void
move_ref_pairs(SCHEME_OBJECT from_cache,SCHEME_OBJECT to_cache,unsigned int reference_kind,SCHEME_OBJECT environment,SCHEME_OBJECT symbol)1134 move_ref_pairs (SCHEME_OBJECT from_cache, SCHEME_OBJECT to_cache,
1135 		unsigned int reference_kind, SCHEME_OBJECT environment,
1136 		SCHEME_OBJECT symbol)
1137 {
1138   SCHEME_OBJECT * from_palist
1139     = (GET_CACHE_REFERENCES (from_cache, reference_kind));
1140   SCHEME_OBJECT * to_palist
1141     = (GET_CACHE_REFERENCES (to_cache, reference_kind));
1142   SCHEME_OBJECT * from_prefs = (find_references_named (from_palist, symbol));
1143   SCHEME_OBJECT * to_prefs = (find_references_named (to_palist, symbol));
1144   if (from_prefs != 0)
1145     while (PREFS_COND (from_prefs))
1146       {
1147 	PREFS_HEADER (from_prefs);
1148 	if (move_ref_pair_p ((*from_prefs), environment))
1149 	  {
1150 	    SCHEME_OBJECT p = (*from_prefs);
1151 	    (*from_prefs) = (PAIR_CDR (p));
1152 	    if (to_prefs == 0)
1153 	      to_prefs = (new_alist_entry (to_palist, symbol));
1154 	    SET_PAIR_CDR (p, (*to_prefs));
1155 	    (*to_prefs) = p;
1156 	    install_cache (to_cache,
1157 			   (GET_CACHE_REFERENCE_BLOCK (PAIR_CAR (p))),
1158 			   (GET_CACHE_REFERENCE_OFFSET (PAIR_CAR (p))),
1159 			   reference_kind);
1160 	    continue;
1161 	  }
1162 	PREFS_FOOTER (from_prefs);
1163       }
1164 }
1165 
1166 static SCHEME_OBJECT *
new_alist_entry(SCHEME_OBJECT * to_palist,SCHEME_OBJECT symbol)1167 new_alist_entry (SCHEME_OBJECT * to_palist, SCHEME_OBJECT symbol)
1168 {
1169   SCHEME_OBJECT entry = (cons (symbol, EMPTY_LIST));
1170   SCHEME_OBJECT head = (*to_palist);
1171   (*to_palist) = (cons (entry, head));
1172   return (PAIR_CDR_LOC (entry));
1173 }
1174 
1175 static int
move_ref_pair_p(SCHEME_OBJECT ref_pair,SCHEME_OBJECT ancestor)1176 move_ref_pair_p (SCHEME_OBJECT ref_pair, SCHEME_OBJECT ancestor)
1177 {
1178   SCHEME_OBJECT descendant
1179     = (cc_block_environment
1180        (GET_CACHE_REFERENCE_BLOCK (PAIR_CAR (ref_pair))));
1181   while (PROCEDURE_FRAME_P (descendant))
1182     {
1183       if (descendant == ancestor)
1184 	return (1);
1185       descendant = (GET_FRAME_PARENT (descendant));
1186     }
1187   return (descendant == ancestor);
1188 }
1189 
1190 #endif /* CC_SUPPORT_P */
1191 
1192 /***** Utilities *****/
1193 
1194 static SCHEME_OBJECT *
find_binding_cell(SCHEME_OBJECT environment,SCHEME_OBJECT symbol,SCHEME_OBJECT * frame_ret)1195 find_binding_cell (SCHEME_OBJECT environment, SCHEME_OBJECT symbol,
1196 		   SCHEME_OBJECT * frame_ret)
1197 {
1198   SCHEME_OBJECT frame = environment;
1199   while (1)
1200     {
1201       SCHEME_OBJECT * cell = (scan_frame (frame, symbol, 0));
1202       if ((cell != 0) || (!PROCEDURE_FRAME_P (frame)))
1203 	{
1204 	  if (frame_ret != 0)
1205 	    (*frame_ret) = frame;
1206 	  return (cell);
1207 	}
1208       frame = (GET_FRAME_PARENT (frame));
1209     }
1210 }
1211 
1212 static SCHEME_OBJECT *
scan_frame(SCHEME_OBJECT frame,SCHEME_OBJECT symbol,int find_unbound_p)1213 scan_frame (SCHEME_OBJECT frame, SCHEME_OBJECT symbol, int find_unbound_p)
1214 {
1215   if (PROCEDURE_FRAME_P (frame))
1216     {
1217       if (EXTENDED_FRAME_P (frame))
1218 	{
1219 	  /* Search for a binding in the extension. */
1220 	  SCHEME_OBJECT * scan = (GET_EXTENDED_FRAME_BINDINGS (frame));
1221 	  SCHEME_OBJECT * end = (scan + (GET_EXTENDED_FRAME_LENGTH (frame)));
1222 	  while (scan < end)
1223 	    {
1224 	      if ((PAIR_CAR (*scan)) == symbol)
1225 		return (PAIR_CDR_LOC (*scan));
1226 	      scan += 1;
1227 	    }
1228 	  return
1229 	    (scan_procedure_bindings ((GET_EXTENDED_FRAME_PROCEDURE (frame)),
1230 				      frame, symbol, find_unbound_p));
1231 	}
1232       return
1233 	(scan_procedure_bindings ((GET_FRAME_PROCEDURE (frame)),
1234 				  frame, symbol, find_unbound_p));
1235     }
1236   else if (GLOBAL_FRAME_P (frame))
1237     return (SYMBOL_GLOBAL_VALUE_CELL (symbol));
1238   else
1239     return (0);
1240 }
1241 
1242 static SCHEME_OBJECT *
scan_procedure_bindings(SCHEME_OBJECT procedure,SCHEME_OBJECT frame,SCHEME_OBJECT symbol,int find_unbound_p)1243 scan_procedure_bindings (SCHEME_OBJECT procedure, SCHEME_OBJECT frame,
1244 			 SCHEME_OBJECT symbol, int find_unbound_p)
1245 {
1246   SCHEME_OBJECT lambda = (GET_PROCEDURE_LAMBDA (procedure));
1247   SCHEME_OBJECT * start = (GET_LAMBDA_PARAMETERS (lambda));
1248   SCHEME_OBJECT * scan = start;
1249   SCHEME_OBJECT * end = (scan + (GET_LAMBDA_N_PARAMETERS (lambda)));
1250   while (scan < end)
1251     {
1252       if ((*scan) == symbol)
1253 	{
1254 	  SCHEME_OBJECT * cell = (GET_FRAME_ARG_CELL (frame, (scan - start)));
1255 	  if (find_unbound_p || ((*cell) != UNBOUND_OBJECT))
1256 	    return (cell);
1257 	}
1258       scan += 1;
1259     }
1260   return (0);
1261 }
1262 
1263 trap_kind_t
get_trap_kind(SCHEME_OBJECT object)1264 get_trap_kind (SCHEME_OBJECT object)
1265 {
1266   if (REFERENCE_TRAP_P (object))
1267     {
1268       unsigned long datum = (OBJECT_DATUM (object));
1269       return
1270 	((datum <= TRAP_MAX_IMMEDIATE)
1271 	 ? datum
1272 	 : (OBJECT_DATUM (GET_TRAP_TAG (object))));
1273     }
1274   else
1275     return (NON_TRAP_KIND);
1276 }
1277 
1278 static unsigned long
count_references(SCHEME_OBJECT * palist)1279 count_references (SCHEME_OBJECT * palist)
1280 {
1281   unsigned long n_references = 0;
1282   WALK_REFERENCES (palist, reference, { n_references += 1; });
1283   return (n_references);
1284 }
1285 
1286 #ifdef CC_SUPPORT_P
1287 static SCHEME_OBJECT *
find_references_named(SCHEME_OBJECT * palist,SCHEME_OBJECT symbol)1288 find_references_named (SCHEME_OBJECT * palist, SCHEME_OBJECT symbol)
1289 {
1290   while (PAIR_P (*palist))
1291     {
1292       if ((PAIR_CAR (PAIR_CAR (*palist))) == symbol)
1293 	return (PAIR_CDR_LOC (PAIR_CAR (*palist)));
1294       palist = (PAIR_CDR_LOC (*palist));
1295     }
1296   return (0);
1297 }
1298 #endif
1299 
1300 static void
update_assignment_references(SCHEME_OBJECT cache)1301 update_assignment_references (SCHEME_OBJECT cache)
1302 {
1303 #ifdef CC_SUPPORT_P
1304   SCHEME_OBJECT reference_cache
1305     = (((GET_CACHE_CLONE (cache)) != SHARP_F)
1306        ? (GET_CACHE_CLONE (cache))
1307        : cache);
1308   WALK_REFERENCES
1309     ((GET_CACHE_ASSIGNMENT_REFERENCES (cache)),
1310      reference,
1311      {
1312        write_variable_cache
1313 	 (reference_cache,
1314 	  (GET_CACHE_REFERENCE_BLOCK (reference)),
1315 	  (GET_CACHE_REFERENCE_OFFSET (reference)));
1316      });
1317 #endif
1318 }
1319 
1320 static long
guarantee_cache(SCHEME_OBJECT * cell)1321 guarantee_cache (SCHEME_OBJECT * cell)
1322 {
1323   SCHEME_OBJECT references;
1324   SCHEME_OBJECT cache;
1325 
1326   if ((get_trap_kind (*cell)) == TRAP_COMPILER_CACHED)
1327     return (PRIM_DONE);
1328 
1329   GC_CHECK (3);
1330   references = (MAKE_POINTER_OBJECT (CACHE_REFERENCES_TYPE, Free));
1331   (*Free++) = EMPTY_LIST;
1332   (*Free++) = EMPTY_LIST;
1333   (*Free++) = EMPTY_LIST;
1334 
1335   RETURN_IF_ERROR (make_cache ((*cell), SHARP_F, references, (&cache)));
1336 
1337   GC_CHECK (2);
1338   (*Free++) = (LONG_TO_UNSIGNED_FIXNUM (TRAP_COMPILER_CACHED));
1339   (*Free++) = cache;
1340   (*cell) = (MAKE_POINTER_OBJECT (TC_REFERENCE_TRAP, (Free - 2)));
1341   return (PRIM_DONE);
1342 }
1343 
1344 static void
update_clone(SCHEME_OBJECT cache)1345 update_clone (SCHEME_OBJECT cache)
1346 {
1347   if ((PAIR_P (* (GET_CACHE_ASSIGNMENT_REFERENCES (cache))))
1348       && (PAIR_P (* (GET_CACHE_OPERATOR_REFERENCES (cache)))))
1349     {
1350       if ((GET_CACHE_CLONE (cache)) == SHARP_F)
1351 	{
1352 	  SCHEME_OBJECT clone;
1353 	  DIE_IF_ERROR
1354 	    (make_cache (EXPENSIVE_OBJECT,
1355 			 cache,
1356 			 (GET_CACHE_REFERENCES_OBJECT (cache)),
1357 			 (&clone)));
1358 	  SET_CACHE_CLONE (cache, clone);
1359 	  update_assignment_references (cache);
1360 	}
1361     }
1362   else
1363     {
1364       if ((GET_CACHE_CLONE (cache)) != SHARP_F)
1365 	{
1366 	  SET_CACHE_CLONE (cache, SHARP_F);
1367 	  update_assignment_references (cache);
1368 	}
1369     }
1370 }
1371 
1372 static long
make_cache(SCHEME_OBJECT value,SCHEME_OBJECT clone,SCHEME_OBJECT references,SCHEME_OBJECT * cache_ret)1373 make_cache (SCHEME_OBJECT value, SCHEME_OBJECT clone, SCHEME_OBJECT references,
1374 	    SCHEME_OBJECT * cache_ret)
1375 {
1376   GC_CHECK (3);
1377   (*Free++) = value;
1378   (*Free++) = clone;
1379   (*Free++) = references;
1380   (*cache_ret) = (MAKE_POINTER_OBJECT (CACHE_TYPE, (Free - 3)));
1381   return (PRIM_DONE);
1382 }
1383 
1384 #ifdef CC_SUPPORT_P
1385 static long
make_cache_reference(SCHEME_OBJECT block,unsigned long offset,SCHEME_OBJECT * ref_ret)1386 make_cache_reference (SCHEME_OBJECT block, unsigned long offset,
1387 		      SCHEME_OBJECT * ref_ret)
1388 {
1389   GC_CHECK (2);
1390   (*Free++) = block;
1391   (*Free++) = (LONG_TO_UNSIGNED_FIXNUM (offset));
1392   (*ref_ret) = (MAKE_POINTER_OBJECT (TC_WEAK_CONS, (Free - 2)));
1393   return (PRIM_DONE);
1394 }
1395 #endif
1396