100bf4279Sespie /* alloca.c -- allocate automatically reclaimed memory
200bf4279Sespie (Mostly) portable public-domain implementation -- D A Gwyn
300bf4279Sespie
400bf4279Sespie This implementation of the PWB library alloca function,
500bf4279Sespie which is used to allocate space off the run-time stack so
600bf4279Sespie that it is automatically reclaimed upon procedure exit,
700bf4279Sespie was inspired by discussions with J. Q. Johnson of Cornell.
800bf4279Sespie J.Otto Tennant <jot@cray.com> contributed the Cray support.
900bf4279Sespie
1000bf4279Sespie There are some preprocessor constants that can
1100bf4279Sespie be defined when compiling for your specific system, for
1200bf4279Sespie improved efficiency; however, the defaults should be okay.
1300bf4279Sespie
1400bf4279Sespie The general concept of this implementation is to keep
1500bf4279Sespie track of all alloca-allocated blocks, and reclaim any
1600bf4279Sespie that are found to be deeper in the stack than the current
1700bf4279Sespie invocation. This heuristic does not reclaim storage as
1800bf4279Sespie soon as it becomes invalid, but it will do so eventually.
1900bf4279Sespie
2000bf4279Sespie As a special case, alloca(0) reclaims storage without
2100bf4279Sespie allocating any. It is a good idea to use alloca(0) in
2200bf4279Sespie your main control loop, etc. to force garbage collection. */
2300bf4279Sespie
249588ddcfSespie /*
259588ddcfSespie
269588ddcfSespie @deftypefn Replacement void* alloca (size_t @var{size})
279588ddcfSespie
289588ddcfSespie This function allocates memory which will be automatically reclaimed
299588ddcfSespie after the procedure exits. The @libib{} implementation does not free
309588ddcfSespie the memory immediately but will do so eventually during subsequent
319588ddcfSespie calls to this function. Memory is allocated using @code{xmalloc} under
329588ddcfSespie normal circumstances.
339588ddcfSespie
349588ddcfSespie The header file @file{alloca-conf.h} can be used in conjunction with the
359588ddcfSespie GNU Autoconf test @code{AC_FUNC_ALLOCA} to test for and properly make
369588ddcfSespie available this function. The @code{AC_FUNC_ALLOCA} test requires that
379588ddcfSespie client code use a block of preprocessor code to be safe (see the Autoconf
389588ddcfSespie manual for more); this header incorporates that logic and more, including
399588ddcfSespie the possibility of a GCC built-in function.
409588ddcfSespie
419588ddcfSespie @end deftypefn
429588ddcfSespie
439588ddcfSespie */
449588ddcfSespie
4500bf4279Sespie #ifdef HAVE_CONFIG_H
4600bf4279Sespie #include <config.h>
4700bf4279Sespie #endif
4800bf4279Sespie
499588ddcfSespie #include <libiberty.h>
509588ddcfSespie
5100bf4279Sespie #ifdef HAVE_STRING_H
5200bf4279Sespie #include <string.h>
5300bf4279Sespie #endif
5400bf4279Sespie #ifdef HAVE_STDLIB_H
5500bf4279Sespie #include <stdlib.h>
5600bf4279Sespie #endif
5700bf4279Sespie
589588ddcfSespie /* These variables are used by the ASTRDUP implementation that relies
599588ddcfSespie on C_alloca. */
60*20fce977Smiod #ifdef __cplusplus
61*20fce977Smiod extern "C" {
62*20fce977Smiod #endif /* __cplusplus */
639588ddcfSespie const char *libiberty_optr;
649588ddcfSespie char *libiberty_nptr;
659588ddcfSespie unsigned long libiberty_len;
66*20fce977Smiod #ifdef __cplusplus
67*20fce977Smiod }
68*20fce977Smiod #endif /* __cplusplus */
6900bf4279Sespie
7000bf4279Sespie /* If your stack is a linked list of frames, you have to
7100bf4279Sespie provide an "address metric" ADDRESS_FUNCTION macro. */
7200bf4279Sespie
7300bf4279Sespie #if defined (CRAY) && defined (CRAY_STACKSEG_END)
749588ddcfSespie static long i00afunc ();
7500bf4279Sespie #define ADDRESS_FUNCTION(arg) (char *) i00afunc (&(arg))
7600bf4279Sespie #else
7700bf4279Sespie #define ADDRESS_FUNCTION(arg) &(arg)
7800bf4279Sespie #endif
7900bf4279Sespie
8000bf4279Sespie #ifndef NULL
8100bf4279Sespie #define NULL 0
8200bf4279Sespie #endif
8300bf4279Sespie
8400bf4279Sespie /* Define STACK_DIRECTION if you know the direction of stack
8500bf4279Sespie growth for your system; otherwise it will be automatically
8600bf4279Sespie deduced at run-time.
8700bf4279Sespie
8800bf4279Sespie STACK_DIRECTION > 0 => grows toward higher addresses
8900bf4279Sespie STACK_DIRECTION < 0 => grows toward lower addresses
9000bf4279Sespie STACK_DIRECTION = 0 => direction of growth unknown */
9100bf4279Sespie
9200bf4279Sespie #ifndef STACK_DIRECTION
9300bf4279Sespie #define STACK_DIRECTION 0 /* Direction unknown. */
9400bf4279Sespie #endif
9500bf4279Sespie
9600bf4279Sespie #if STACK_DIRECTION != 0
9700bf4279Sespie
9800bf4279Sespie #define STACK_DIR STACK_DIRECTION /* Known at compile-time. */
9900bf4279Sespie
10000bf4279Sespie #else /* STACK_DIRECTION == 0; need run-time code. */
10100bf4279Sespie
10200bf4279Sespie static int stack_dir; /* 1 or -1 once known. */
10300bf4279Sespie #define STACK_DIR stack_dir
10400bf4279Sespie
10500bf4279Sespie static void
find_stack_direction(void)106*20fce977Smiod find_stack_direction (void)
10700bf4279Sespie {
10800bf4279Sespie static char *addr = NULL; /* Address of first `dummy', once known. */
10900bf4279Sespie auto char dummy; /* To get stack address. */
11000bf4279Sespie
11100bf4279Sespie if (addr == NULL)
11200bf4279Sespie { /* Initial entry. */
11300bf4279Sespie addr = ADDRESS_FUNCTION (dummy);
11400bf4279Sespie
11500bf4279Sespie find_stack_direction (); /* Recurse once. */
11600bf4279Sespie }
11700bf4279Sespie else
11800bf4279Sespie {
11900bf4279Sespie /* Second entry. */
12000bf4279Sespie if (ADDRESS_FUNCTION (dummy) > addr)
12100bf4279Sespie stack_dir = 1; /* Stack grew upward. */
12200bf4279Sespie else
12300bf4279Sespie stack_dir = -1; /* Stack grew downward. */
12400bf4279Sespie }
12500bf4279Sespie }
12600bf4279Sespie
12700bf4279Sespie #endif /* STACK_DIRECTION == 0 */
12800bf4279Sespie
12900bf4279Sespie /* An "alloca header" is used to:
13000bf4279Sespie (a) chain together all alloca'ed blocks;
13100bf4279Sespie (b) keep track of stack depth.
13200bf4279Sespie
13300bf4279Sespie It is very important that sizeof(header) agree with malloc
13400bf4279Sespie alignment chunk size. The following default should work okay. */
13500bf4279Sespie
13600bf4279Sespie #ifndef ALIGN_SIZE
13700bf4279Sespie #define ALIGN_SIZE sizeof(double)
13800bf4279Sespie #endif
13900bf4279Sespie
14000bf4279Sespie typedef union hdr
14100bf4279Sespie {
14200bf4279Sespie char align[ALIGN_SIZE]; /* To force sizeof(header). */
14300bf4279Sespie struct
14400bf4279Sespie {
14500bf4279Sespie union hdr *next; /* For chaining headers. */
14600bf4279Sespie char *deep; /* For stack depth measure. */
14700bf4279Sespie } h;
14800bf4279Sespie } header;
14900bf4279Sespie
15000bf4279Sespie static header *last_alloca_header = NULL; /* -> last alloca header. */
15100bf4279Sespie
15200bf4279Sespie /* Return a pointer to at least SIZE bytes of storage,
15300bf4279Sespie which will be automatically reclaimed upon exit from
15400bf4279Sespie the procedure that called alloca. Originally, this space
15500bf4279Sespie was supposed to be taken from the current stack frame of the
15600bf4279Sespie caller, but that method cannot be made to work for some
15700bf4279Sespie implementations of C, for example under Gould's UTX/32. */
15800bf4279Sespie
1599588ddcfSespie /* @undocumented C_alloca */
1609588ddcfSespie
1619588ddcfSespie PTR
C_alloca(size_t size)162*20fce977Smiod C_alloca (size_t size)
16300bf4279Sespie {
16400bf4279Sespie auto char probe; /* Probes stack depth: */
16500bf4279Sespie register char *depth = ADDRESS_FUNCTION (probe);
16600bf4279Sespie
16700bf4279Sespie #if STACK_DIRECTION == 0
16800bf4279Sespie if (STACK_DIR == 0) /* Unknown growth direction. */
16900bf4279Sespie find_stack_direction ();
17000bf4279Sespie #endif
17100bf4279Sespie
17200bf4279Sespie /* Reclaim garbage, defined as all alloca'd storage that
17300bf4279Sespie was allocated from deeper in the stack than currently. */
17400bf4279Sespie
17500bf4279Sespie {
17600bf4279Sespie register header *hp; /* Traverses linked list. */
17700bf4279Sespie
17800bf4279Sespie for (hp = last_alloca_header; hp != NULL;)
17900bf4279Sespie if ((STACK_DIR > 0 && hp->h.deep > depth)
18000bf4279Sespie || (STACK_DIR < 0 && hp->h.deep < depth))
18100bf4279Sespie {
18200bf4279Sespie register header *np = hp->h.next;
18300bf4279Sespie
1849588ddcfSespie free ((PTR) hp); /* Collect garbage. */
18500bf4279Sespie
18600bf4279Sespie hp = np; /* -> next header. */
18700bf4279Sespie }
18800bf4279Sespie else
18900bf4279Sespie break; /* Rest are not deeper. */
19000bf4279Sespie
19100bf4279Sespie last_alloca_header = hp; /* -> last valid storage. */
19200bf4279Sespie }
19300bf4279Sespie
19400bf4279Sespie if (size == 0)
19500bf4279Sespie return NULL; /* No allocation required. */
19600bf4279Sespie
19700bf4279Sespie /* Allocate combined header + user data storage. */
19800bf4279Sespie
19900bf4279Sespie {
200*20fce977Smiod register void *new_storage = XNEWVEC (char, sizeof (header) + size);
20100bf4279Sespie /* Address of header. */
20200bf4279Sespie
203*20fce977Smiod if (new_storage == 0)
20400bf4279Sespie abort();
20500bf4279Sespie
206*20fce977Smiod ((header *) new_storage)->h.next = last_alloca_header;
207*20fce977Smiod ((header *) new_storage)->h.deep = depth;
20800bf4279Sespie
209*20fce977Smiod last_alloca_header = (header *) new_storage;
21000bf4279Sespie
21100bf4279Sespie /* User storage begins just after header. */
21200bf4279Sespie
213*20fce977Smiod return (PTR) ((char *) new_storage + sizeof (header));
21400bf4279Sespie }
21500bf4279Sespie }
21600bf4279Sespie
21700bf4279Sespie #if defined (CRAY) && defined (CRAY_STACKSEG_END)
21800bf4279Sespie
21900bf4279Sespie #ifdef DEBUG_I00AFUNC
22000bf4279Sespie #include <stdio.h>
22100bf4279Sespie #endif
22200bf4279Sespie
22300bf4279Sespie #ifndef CRAY_STACK
22400bf4279Sespie #define CRAY_STACK
22500bf4279Sespie #ifndef CRAY2
22600bf4279Sespie /* Stack structures for CRAY-1, CRAY X-MP, and CRAY Y-MP */
22700bf4279Sespie struct stack_control_header
22800bf4279Sespie {
22900bf4279Sespie long shgrow:32; /* Number of times stack has grown. */
23000bf4279Sespie long shaseg:32; /* Size of increments to stack. */
23100bf4279Sespie long shhwm:32; /* High water mark of stack. */
23200bf4279Sespie long shsize:32; /* Current size of stack (all segments). */
23300bf4279Sespie };
23400bf4279Sespie
23500bf4279Sespie /* The stack segment linkage control information occurs at
23600bf4279Sespie the high-address end of a stack segment. (The stack
23700bf4279Sespie grows from low addresses to high addresses.) The initial
23800bf4279Sespie part of the stack segment linkage control information is
23900bf4279Sespie 0200 (octal) words. This provides for register storage
24000bf4279Sespie for the routine which overflows the stack. */
24100bf4279Sespie
24200bf4279Sespie struct stack_segment_linkage
24300bf4279Sespie {
24400bf4279Sespie long ss[0200]; /* 0200 overflow words. */
24500bf4279Sespie long sssize:32; /* Number of words in this segment. */
24600bf4279Sespie long ssbase:32; /* Offset to stack base. */
24700bf4279Sespie long:32;
24800bf4279Sespie long sspseg:32; /* Offset to linkage control of previous
24900bf4279Sespie segment of stack. */
25000bf4279Sespie long:32;
25100bf4279Sespie long sstcpt:32; /* Pointer to task common address block. */
25200bf4279Sespie long sscsnm; /* Private control structure number for
25300bf4279Sespie microtasking. */
25400bf4279Sespie long ssusr1; /* Reserved for user. */
25500bf4279Sespie long ssusr2; /* Reserved for user. */
25600bf4279Sespie long sstpid; /* Process ID for pid based multi-tasking. */
25700bf4279Sespie long ssgvup; /* Pointer to multitasking thread giveup. */
25800bf4279Sespie long sscray[7]; /* Reserved for Cray Research. */
25900bf4279Sespie long ssa0;
26000bf4279Sespie long ssa1;
26100bf4279Sespie long ssa2;
26200bf4279Sespie long ssa3;
26300bf4279Sespie long ssa4;
26400bf4279Sespie long ssa5;
26500bf4279Sespie long ssa6;
26600bf4279Sespie long ssa7;
26700bf4279Sespie long sss0;
26800bf4279Sespie long sss1;
26900bf4279Sespie long sss2;
27000bf4279Sespie long sss3;
27100bf4279Sespie long sss4;
27200bf4279Sespie long sss5;
27300bf4279Sespie long sss6;
27400bf4279Sespie long sss7;
27500bf4279Sespie };
27600bf4279Sespie
27700bf4279Sespie #else /* CRAY2 */
27800bf4279Sespie /* The following structure defines the vector of words
27900bf4279Sespie returned by the STKSTAT library routine. */
28000bf4279Sespie struct stk_stat
28100bf4279Sespie {
28200bf4279Sespie long now; /* Current total stack size. */
28300bf4279Sespie long maxc; /* Amount of contiguous space which would
28400bf4279Sespie be required to satisfy the maximum
28500bf4279Sespie stack demand to date. */
28600bf4279Sespie long high_water; /* Stack high-water mark. */
28700bf4279Sespie long overflows; /* Number of stack overflow ($STKOFEN) calls. */
28800bf4279Sespie long hits; /* Number of internal buffer hits. */
28900bf4279Sespie long extends; /* Number of block extensions. */
29000bf4279Sespie long stko_mallocs; /* Block allocations by $STKOFEN. */
29100bf4279Sespie long underflows; /* Number of stack underflow calls ($STKRETN). */
29200bf4279Sespie long stko_free; /* Number of deallocations by $STKRETN. */
29300bf4279Sespie long stkm_free; /* Number of deallocations by $STKMRET. */
29400bf4279Sespie long segments; /* Current number of stack segments. */
29500bf4279Sespie long maxs; /* Maximum number of stack segments so far. */
29600bf4279Sespie long pad_size; /* Stack pad size. */
29700bf4279Sespie long current_address; /* Current stack segment address. */
29800bf4279Sespie long current_size; /* Current stack segment size. This
29900bf4279Sespie number is actually corrupted by STKSTAT to
30000bf4279Sespie include the fifteen word trailer area. */
30100bf4279Sespie long initial_address; /* Address of initial segment. */
30200bf4279Sespie long initial_size; /* Size of initial segment. */
30300bf4279Sespie };
30400bf4279Sespie
30500bf4279Sespie /* The following structure describes the data structure which trails
30600bf4279Sespie any stack segment. I think that the description in 'asdef' is
30700bf4279Sespie out of date. I only describe the parts that I am sure about. */
30800bf4279Sespie
30900bf4279Sespie struct stk_trailer
31000bf4279Sespie {
31100bf4279Sespie long this_address; /* Address of this block. */
31200bf4279Sespie long this_size; /* Size of this block (does not include
31300bf4279Sespie this trailer). */
31400bf4279Sespie long unknown2;
31500bf4279Sespie long unknown3;
31600bf4279Sespie long link; /* Address of trailer block of previous
31700bf4279Sespie segment. */
31800bf4279Sespie long unknown5;
31900bf4279Sespie long unknown6;
32000bf4279Sespie long unknown7;
32100bf4279Sespie long unknown8;
32200bf4279Sespie long unknown9;
32300bf4279Sespie long unknown10;
32400bf4279Sespie long unknown11;
32500bf4279Sespie long unknown12;
32600bf4279Sespie long unknown13;
32700bf4279Sespie long unknown14;
32800bf4279Sespie };
32900bf4279Sespie
33000bf4279Sespie #endif /* CRAY2 */
33100bf4279Sespie #endif /* not CRAY_STACK */
33200bf4279Sespie
33300bf4279Sespie #ifdef CRAY2
33400bf4279Sespie /* Determine a "stack measure" for an arbitrary ADDRESS.
33500bf4279Sespie I doubt that "lint" will like this much. */
33600bf4279Sespie
33700bf4279Sespie static long
i00afunc(long * address)33800bf4279Sespie i00afunc (long *address)
33900bf4279Sespie {
34000bf4279Sespie struct stk_stat status;
34100bf4279Sespie struct stk_trailer *trailer;
34200bf4279Sespie long *block, size;
34300bf4279Sespie long result = 0;
34400bf4279Sespie
34500bf4279Sespie /* We want to iterate through all of the segments. The first
34600bf4279Sespie step is to get the stack status structure. We could do this
34700bf4279Sespie more quickly and more directly, perhaps, by referencing the
34800bf4279Sespie $LM00 common block, but I know that this works. */
34900bf4279Sespie
35000bf4279Sespie STKSTAT (&status);
35100bf4279Sespie
35200bf4279Sespie /* Set up the iteration. */
35300bf4279Sespie
35400bf4279Sespie trailer = (struct stk_trailer *) (status.current_address
35500bf4279Sespie + status.current_size
35600bf4279Sespie - 15);
35700bf4279Sespie
35800bf4279Sespie /* There must be at least one stack segment. Therefore it is
35900bf4279Sespie a fatal error if "trailer" is null. */
36000bf4279Sespie
36100bf4279Sespie if (trailer == 0)
36200bf4279Sespie abort ();
36300bf4279Sespie
36400bf4279Sespie /* Discard segments that do not contain our argument address. */
36500bf4279Sespie
36600bf4279Sespie while (trailer != 0)
36700bf4279Sespie {
36800bf4279Sespie block = (long *) trailer->this_address;
36900bf4279Sespie size = trailer->this_size;
37000bf4279Sespie if (block == 0 || size == 0)
37100bf4279Sespie abort ();
37200bf4279Sespie trailer = (struct stk_trailer *) trailer->link;
37300bf4279Sespie if ((block <= address) && (address < (block + size)))
37400bf4279Sespie break;
37500bf4279Sespie }
37600bf4279Sespie
37700bf4279Sespie /* Set the result to the offset in this segment and add the sizes
37800bf4279Sespie of all predecessor segments. */
37900bf4279Sespie
38000bf4279Sespie result = address - block;
38100bf4279Sespie
38200bf4279Sespie if (trailer == 0)
38300bf4279Sespie {
38400bf4279Sespie return result;
38500bf4279Sespie }
38600bf4279Sespie
38700bf4279Sespie do
38800bf4279Sespie {
38900bf4279Sespie if (trailer->this_size <= 0)
39000bf4279Sespie abort ();
39100bf4279Sespie result += trailer->this_size;
39200bf4279Sespie trailer = (struct stk_trailer *) trailer->link;
39300bf4279Sespie }
39400bf4279Sespie while (trailer != 0);
39500bf4279Sespie
39600bf4279Sespie /* We are done. Note that if you present a bogus address (one
39700bf4279Sespie not in any segment), you will get a different number back, formed
39800bf4279Sespie from subtracting the address of the first block. This is probably
39900bf4279Sespie not what you want. */
40000bf4279Sespie
40100bf4279Sespie return (result);
40200bf4279Sespie }
40300bf4279Sespie
40400bf4279Sespie #else /* not CRAY2 */
40500bf4279Sespie /* Stack address function for a CRAY-1, CRAY X-MP, or CRAY Y-MP.
40600bf4279Sespie Determine the number of the cell within the stack,
40700bf4279Sespie given the address of the cell. The purpose of this
40800bf4279Sespie routine is to linearize, in some sense, stack addresses
40900bf4279Sespie for alloca. */
41000bf4279Sespie
41100bf4279Sespie static long
i00afunc(long address)41200bf4279Sespie i00afunc (long address)
41300bf4279Sespie {
41400bf4279Sespie long stkl = 0;
41500bf4279Sespie
41600bf4279Sespie long size, pseg, this_segment, stack;
41700bf4279Sespie long result = 0;
41800bf4279Sespie
41900bf4279Sespie struct stack_segment_linkage *ssptr;
42000bf4279Sespie
42100bf4279Sespie /* Register B67 contains the address of the end of the
42200bf4279Sespie current stack segment. If you (as a subprogram) store
42300bf4279Sespie your registers on the stack and find that you are past
42400bf4279Sespie the contents of B67, you have overflowed the segment.
42500bf4279Sespie
42600bf4279Sespie B67 also points to the stack segment linkage control
42700bf4279Sespie area, which is what we are really interested in. */
42800bf4279Sespie
42900bf4279Sespie stkl = CRAY_STACKSEG_END ();
43000bf4279Sespie ssptr = (struct stack_segment_linkage *) stkl;
43100bf4279Sespie
43200bf4279Sespie /* If one subtracts 'size' from the end of the segment,
43300bf4279Sespie one has the address of the first word of the segment.
43400bf4279Sespie
43500bf4279Sespie If this is not the first segment, 'pseg' will be
43600bf4279Sespie nonzero. */
43700bf4279Sespie
43800bf4279Sespie pseg = ssptr->sspseg;
43900bf4279Sespie size = ssptr->sssize;
44000bf4279Sespie
44100bf4279Sespie this_segment = stkl - size;
44200bf4279Sespie
44300bf4279Sespie /* It is possible that calling this routine itself caused
44400bf4279Sespie a stack overflow. Discard stack segments which do not
44500bf4279Sespie contain the target address. */
44600bf4279Sespie
44700bf4279Sespie while (!(this_segment <= address && address <= stkl))
44800bf4279Sespie {
44900bf4279Sespie #ifdef DEBUG_I00AFUNC
45000bf4279Sespie fprintf (stderr, "%011o %011o %011o\n", this_segment, address, stkl);
45100bf4279Sespie #endif
45200bf4279Sespie if (pseg == 0)
45300bf4279Sespie break;
45400bf4279Sespie stkl = stkl - pseg;
45500bf4279Sespie ssptr = (struct stack_segment_linkage *) stkl;
45600bf4279Sespie size = ssptr->sssize;
45700bf4279Sespie pseg = ssptr->sspseg;
45800bf4279Sespie this_segment = stkl - size;
45900bf4279Sespie }
46000bf4279Sespie
46100bf4279Sespie result = address - this_segment;
46200bf4279Sespie
46300bf4279Sespie /* If you subtract pseg from the current end of the stack,
46400bf4279Sespie you get the address of the previous stack segment's end.
46500bf4279Sespie This seems a little convoluted to me, but I'll bet you save
46600bf4279Sespie a cycle somewhere. */
46700bf4279Sespie
46800bf4279Sespie while (pseg != 0)
46900bf4279Sespie {
47000bf4279Sespie #ifdef DEBUG_I00AFUNC
47100bf4279Sespie fprintf (stderr, "%011o %011o\n", pseg, size);
47200bf4279Sespie #endif
47300bf4279Sespie stkl = stkl - pseg;
47400bf4279Sespie ssptr = (struct stack_segment_linkage *) stkl;
47500bf4279Sespie size = ssptr->sssize;
47600bf4279Sespie pseg = ssptr->sspseg;
47700bf4279Sespie result += size;
47800bf4279Sespie }
47900bf4279Sespie return (result);
48000bf4279Sespie }
48100bf4279Sespie
48200bf4279Sespie #endif /* not CRAY2 */
48300bf4279Sespie #endif /* CRAY */
484