tagged release 0.7.1
[parrot.git] / compilers / imcc / symreg.c
bloba740b6495b9120bc660f115886f72ac13c4a45df
1 /*
2 * Copyright (C) 2002-2008, The Perl Foundation.
3 * $Id$
4 */
6 /*
8 =head1 NAME
10 compilers/imcc/symreg.c
12 =head1 DESCRIPTION
14 imcc symbol handling
16 XXX: SymReg stuff has become overused. SymReg should be for symbolic
17 registers, reg allocation, etc. but we are now using it for extensive
18 symbol table management. Need to convert much of this over the use Symbol
19 and SymbolTable (see symbol.h and symbol.c)
21 =head2 Functions
23 =over 4
25 =cut
30 #include "imc.h"
32 /* Globals: */
33 /* Code: */
35 /* HEADERIZER HFILE: compilers/imcc/symreg.h */
37 /* HEADERIZER BEGIN: static */
38 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
40 PARROT_WARN_UNUSED_RESULT
41 PARROT_CAN_RETURN_NULL
42 static SymReg * _get_sym_typed(
43 ARGIN(const SymHash *hsh),
44 ARGIN(const char *name),
45 int t)
46 __attribute__nonnull__(1)
47 __attribute__nonnull__(2);
49 PARROT_WARN_UNUSED_RESULT
50 PARROT_CANNOT_RETURN_NULL
51 PARROT_MALLOC
52 static char * _mk_fullname(
53 ARGIN_NULLOK(const Namespace *ns),
54 ARGIN(const char *name))
55 __attribute__nonnull__(2);
57 PARROT_WARN_UNUSED_RESULT
58 PARROT_CANNOT_RETURN_NULL
59 static SymReg * _mk_symreg(
60 ARGMOD(SymHash *hsh),
61 ARGIN(const char *name),
62 int t)
63 __attribute__nonnull__(1)
64 __attribute__nonnull__(2)
65 FUNC_MODIFIES(*hsh);
67 PARROT_WARN_UNUSED_RESULT
68 PARROT_CANNOT_RETURN_NULL
69 PARROT_MALLOC
70 static char * add_ns(PARROT_INTERP, ARGIN(const char *name))
71 __attribute__nonnull__(1)
72 __attribute__nonnull__(2);
74 PARROT_CANNOT_RETURN_NULL
75 PARROT_WARN_UNUSED_RESULT
76 static SymReg * mk_pmc_const_2(PARROT_INTERP,
77 ARGMOD(IMC_Unit *unit),
78 ARGIN(SymReg *left),
79 ARGMOD(SymReg *rhs))
80 __attribute__nonnull__(1)
81 __attribute__nonnull__(2)
82 __attribute__nonnull__(3)
83 __attribute__nonnull__(4)
84 FUNC_MODIFIES(*unit)
85 FUNC_MODIFIES(*rhs);
87 static void resize_symhash(ARGMOD(SymHash *hsh))
88 __attribute__nonnull__(1)
89 FUNC_MODIFIES(*hsh);
91 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
92 /* HEADERIZER END: static */
96 =item C<void push_namespace>
98 Begins a new namespace in PASM/PIR, named after the given C<name>.
100 =cut
104 void
105 push_namespace(SHIM_INTERP, ARGIN(const char *name))
107 Namespace * const ns = mem_allocate_zeroed_typed(Namespace);
109 ns->parent = _namespace;
110 ns->name = str_dup(name);
111 _namespace = ns;
117 =item C<void pop_namespace>
119 Ends the current namespace, popping back to the previous. If the namespace
120 stack is empty, throws a syntax error.
122 =cut
126 void
127 pop_namespace(PARROT_INTERP, ARGIN(const char *name))
129 Namespace * const ns = _namespace;
131 if (!ns)
132 IMCC_fataly(interp, EXCEPTION_SYNTAX_ERROR, "pop() on empty namespace stack\n");
134 if (name && !STREQ(name, ns->name))
135 IMCC_fataly(interp, EXCEPTION_SYNTAX_ERROR, "tried to pop namespace(%s), "
136 "but top of stack is namespace(%s)\n", name, ns->name);
138 while (ns->idents) {
139 Identifier * const ident = ns->idents;
140 ns->idents = ident->next;
141 mem_sys_free(ident);
144 _namespace = ns->parent;
145 mem_sys_free(ns);
151 =item C<static SymReg * _get_sym_typed>
153 Gets a symbol from the hash, with the given C<name> of the specific type C<t>.
155 =cut
159 PARROT_WARN_UNUSED_RESULT
160 PARROT_CAN_RETURN_NULL
161 static SymReg *
162 _get_sym_typed(ARGIN(const SymHash *hsh), ARGIN(const char *name), int t)
164 SymReg *p;
165 const unsigned int i = hash_str(name) % hsh->size;
167 for (p = hsh->data[i]; p; p = p->next) {
168 if ((t == p->set) && STREQ(name, p->name))
169 return p;
172 return NULL;
176 /* symbolic registers */
180 =item C<static SymReg * _mk_symreg>
182 Makes a new SymReg in the given SymHash from a varname and type.
184 =cut
188 PARROT_WARN_UNUSED_RESULT
189 PARROT_CANNOT_RETURN_NULL
190 static SymReg *
191 _mk_symreg(ARGMOD(SymHash *hsh), ARGIN(const char *name), int t)
193 SymReg * r = _get_sym_typed(hsh, name, t);
195 if (!r) {
196 r = mem_allocate_zeroed_typed(SymReg);
197 r->set = t;
198 r->type = VTREG;
199 r->name = str_dup(name);
200 r->color = -1;
201 r->want_regno = -1;
203 _store_symreg(hsh, r);
206 return r;
212 =item C<SymReg * mk_symreg>
214 Makes a new SymReg in the current unit, given a varname and type.
216 =cut
220 PARROT_WARN_UNUSED_RESULT
221 PARROT_CANNOT_RETURN_NULL
222 SymReg *
223 mk_symreg(PARROT_INTERP, ARGIN(const char *name), int t)
225 IMC_Unit * const unit = IMCC_INFO(interp)->last_unit;
226 return _mk_symreg(&unit->hash, name, t);
232 =item C<char * symreg_to_str>
234 Dumps a SymReg to a printable format.
236 =cut
240 PARROT_MALLOC
241 PARROT_WARN_UNUSED_RESULT
242 PARROT_CANNOT_RETURN_NULL
243 char *
244 symreg_to_str(ARGIN(const SymReg *s))
246 /* NOTE: the below magic number encompasses all the quoted strings which
247 * may be included in the sprintf output (for now) */
248 char * const buf = (char *)mem_sys_allocate(250 + strlen(s->name));
249 const int t = s->type;
251 sprintf(buf, "symbol [%s] set [%c] color [" INTVAL_FMT "] type [",
252 s->name, s->set, s->color);
254 if (t & VTCONST) { strcat(buf, "VTCONST "); }
255 if (t & VTREG) { strcat(buf, "VTREG "); }
256 if (t & VTIDENTIFIER) { strcat(buf, "VTIDENTIFIER "); }
257 if (t & VTADDRESS) { strcat(buf, "VTADDRESS "); }
258 if (t & VTREGKEY) { strcat(buf, "VTREGKEY "); }
259 if (t & VTPASM) { strcat(buf, "VTPASM "); }
260 if (t & VT_CONSTP) { strcat(buf, "VT_CONSTP "); }
261 if (t & VT_PCC_SUB) { strcat(buf, "VT_PCC_SUB "); }
262 if (t & VT_FLAT) { strcat(buf, "VT_FLAT "); }
263 if (t & VT_OPTIONAL) { strcat(buf, "VT_OPTIONAL "); }
264 if (t & VT_NAMED) { strcat(buf, "VT_NAMED "); }
266 strcat(buf, "]");
268 return buf;
274 =item C<SymReg * mk_temp_reg>
276 Makes a new unique and temporary SymReg of the specified type C<t>.
278 =cut
282 PARROT_WARN_UNUSED_RESULT
283 PARROT_CANNOT_RETURN_NULL
284 SymReg *
285 mk_temp_reg(PARROT_INTERP, int t)
287 char buf[30];
288 static int temp;
290 snprintf(buf, sizeof (buf), "__imcc_temp_%d", ++temp);
291 return mk_symreg(interp, buf, t);
297 =item C<SymReg * mk_pcc_sub>
299 Makes a SymReg representing a PCC sub of the given C<name> with the specified
300 type.
302 =cut
306 PARROT_WARN_UNUSED_RESULT
307 PARROT_CANNOT_RETURN_NULL
308 SymReg *
309 mk_pcc_sub(PARROT_INTERP, ARGIN(const char *name), int proto)
311 IMC_Unit * const unit = IMCC_INFO(interp)->last_unit;
312 SymReg * const r = _mk_symreg(&unit->hash, name, proto);
314 r->type = VT_PCC_SUB;
315 r->pcc_sub = mem_allocate_zeroed_typed(pcc_sub_t);
317 return r;
323 =item C<void add_namespace>
325 Add the current namespace to a sub declaration.
327 =cut
331 void
332 add_namespace(PARROT_INTERP, ARGMOD(IMC_Unit *unit))
334 SymReg * const ns = IMCC_INFO(interp)->cur_namespace;
336 if (!ns)
337 return;
339 if (unit->_namespace)
340 return;
342 if (unit->prev && unit->prev->_namespace == ns)
343 unit->_namespace = ns;
344 else {
345 SymReg * const g = dup_sym(ns);
346 SymReg * const r = _get_sym(&IMCC_INFO(interp)->ghash, g->name);
348 unit->_namespace = g;
349 g->reg = ns;
350 g->type = VT_CONSTP;
352 if (!r || r->type != VT_CONSTP)
353 _store_symreg(&IMCC_INFO(interp)->ghash, g);
360 =item C<void add_pcc_arg>
362 Adds a register or constant to the function arg list.
364 =cut
368 void
369 add_pcc_arg(ARGMOD(SymReg *r), ARGMOD(SymReg *arg))
371 pcc_sub_t * const sub = r->pcc_sub;
372 const int n = sub->nargs;
374 mem_realloc_n_typed(sub->args, n + 1, SymReg *);
375 mem_realloc_n_typed(sub->arg_flags, n + 1, int);
377 sub->args[n] = arg;
378 sub->arg_flags[n] = arg->type;
380 arg->type &= ~(VT_FLAT|VT_OPTIONAL|VT_OPT_FLAG|VT_NAMED);
382 sub->nargs++;
388 =item C<void add_pcc_result>
390 Adds a register or constant to the function's return list.
392 =cut
396 void
397 add_pcc_result(ARGMOD(SymReg *r), ARGMOD(SymReg *arg))
399 pcc_sub_t * const sub = r->pcc_sub;
400 const int n = sub->nret;
402 mem_realloc_n_typed(sub->ret, n + 1, SymReg *);
403 mem_realloc_n_typed(sub->ret_flags, n + 1, int);
405 /* we can't keep the flags in the SymReg as the SymReg
406 * maybe used with different flags for different calls */
407 sub->ret[n] = arg;
408 sub->ret_flags[n] = arg->type;
410 arg->type &= ~(VT_FLAT|VT_OPTIONAL|VT_OPT_FLAG|VT_NAMED);
412 sub->nret++;
418 =item C<void add_pcc_multi>
420 Adds a :multi signature to the sub.
422 =cut
426 void
427 add_pcc_multi(ARGMOD(SymReg *r), ARGIN_NULLOK(SymReg *arg))
429 pcc_sub_t * const sub = r->pcc_sub;
430 const int n = sub->nmulti;
432 mem_realloc_n_typed(sub->multi, n + 1, SymReg *);
433 sub->multi[n] = arg;
434 sub->nmulti++;
440 =item C<void add_pcc_sub>
442 Sets the current sub in the given SymReg to the second SymReg.
444 =cut
448 void
449 add_pcc_sub(ARGMOD(SymReg *r), ARGIN(SymReg *arg))
451 r->pcc_sub->sub = arg;
457 =item C<void add_pcc_cc>
459 Adds a continuation (?) to the current sub.
461 =cut
465 void
466 add_pcc_cc(ARGMOD(SymReg *r), ARGIN(SymReg *arg))
468 r->pcc_sub->cc = arg;
474 =item C<SymReg * mk_pasm_reg>
476 Makes a SymReg representing a PASM register.
478 =cut
482 PARROT_WARN_UNUSED_RESULT
483 PARROT_CANNOT_RETURN_NULL
484 SymReg *
485 mk_pasm_reg(PARROT_INTERP, ARGIN(const char *name))
487 SymReg *r = _get_sym(&IMCC_INFO(interp)->cur_unit->hash, name);
489 if (!r) {
490 r = mk_symreg(interp, name, *name);
491 r->type = VTPASM;
492 r->color = atoi(name + 1);
494 if (r->color < 0)
495 IMCC_fataly(interp, EXCEPTION_SYNTAX_ERROR,
496 "register number out of range '%s'\n", name);
499 return r;
505 =item C<static char * _mk_fullname>
507 Combines the namespace and name together, separated by a C<::>. If there's no
508 namespace, the name is returned on its own.
510 The returned string must be free()d.
512 =cut
516 PARROT_WARN_UNUSED_RESULT
517 PARROT_CANNOT_RETURN_NULL
518 PARROT_MALLOC
519 static char *
520 _mk_fullname(ARGIN_NULLOK(const Namespace *ns), ARGIN(const char *name))
522 if (ns) {
523 const size_t len = strlen(name) + strlen(ns->name) + 3;
524 char *result = (char *) mem_sys_allocate(len);
525 snprintf(result, len, "%s::%s", ns->name, name);
526 return result;
529 return str_dup(name);
535 =item C<SymReg * mk_ident>
537 Makes a new identifier.
539 =cut
543 PARROT_CANNOT_RETURN_NULL
544 PARROT_IGNORABLE_RESULT
545 SymReg *
546 mk_ident(PARROT_INTERP, ARGIN(const char *name), int t)
548 char * const fullname = _mk_fullname(_namespace, name);
549 SymReg *r = mk_symreg(interp, fullname, t);
551 r->type = VTIDENTIFIER;
553 if (_namespace) {
554 Identifier * const ident = mem_allocate_zeroed_typed(Identifier);
556 ident->name = fullname;
557 ident->next = _namespace->idents;
558 _namespace->idents = ident;
560 else
561 mem_sys_free(fullname);
563 if (t == 'P') {
564 r->pmc_type = IMCC_INFO(interp)->cur_pmc_type;
565 IMCC_INFO(interp)->cur_pmc_type = 0;
568 return r;
574 =item C<SymReg* mk_ident_ur>
576 Creates and returns a SymReg representing a unique (non-volatile) register.
578 =cut
582 PARROT_CANNOT_RETURN_NULL
583 PARROT_IGNORABLE_RESULT
584 SymReg*
585 mk_ident_ur(PARROT_INTERP, ARGIN(const char *name), int t)
587 SymReg * const r = mk_ident(interp, name, t);
588 r->usage |= U_NON_VOLATILE;
590 return r;
596 =item C<static SymReg * mk_pmc_const_2>
598 Makes a constant PMC and inserts instructions to access it.
600 =cut
604 PARROT_CANNOT_RETURN_NULL
605 PARROT_WARN_UNUSED_RESULT
606 static SymReg *
607 mk_pmc_const_2(PARROT_INTERP, ARGMOD(IMC_Unit *unit), ARGIN(SymReg *left),
608 ARGMOD(SymReg *rhs))
610 /* XXX This always returns NULL. Probably shouldn't return anything then. */
611 SymReg *r[2];
612 char *name;
613 int len;
615 if (IMCC_INFO(interp)->state->pasm_file)
616 IMCC_fataly(interp, EXCEPTION_SYNTAX_ERROR,
617 "Ident as PMC constant %s\n", left->name);
619 r[0] = left;
621 /* strip delimiters */
622 name = str_dup(rhs->name + 1);
623 len = strlen(name);
624 name[len - 1] = '\0';
626 mem_sys_free(rhs->name);
628 rhs->name = name;
629 rhs->set = 'P';
630 rhs->pmc_type = left->pmc_type;
632 switch (rhs->pmc_type) {
633 case enum_class_Sub:
634 case enum_class_Coroutine:
635 r[1] = rhs;
636 rhs->usage = U_FIXUP;
637 INS(interp, unit, "set_p_pc", "", r, 2, 0, 1);
638 return NULL;
639 default:
640 break;
643 r[1] = rhs;
644 INS(interp, unit, "set_p_pc", "", r, 2, 0, 1);
646 return NULL;
652 =item C<SymReg * mk_const_ident>
654 Makes a new identifier constant with value val.
656 =cut
660 PARROT_CANNOT_RETURN_NULL
661 PARROT_IGNORABLE_RESULT
662 SymReg *
663 mk_const_ident(PARROT_INTERP, ARGIN(const char *name), int t,
664 ARGMOD(SymReg *val), int global)
666 SymReg *r;
669 * Forbid assigning a string to anything other than a string
670 * or PMC constant
672 if (t == 'N' || t == 'I') {
673 if (val->set == 'S')
674 IMCC_fataly(interp, EXCEPTION_SYNTAX_ERROR, "bad const initialisation");
676 /* Cast value to const type */
677 val->set = t;
680 if (global) {
681 if (t == 'P')
682 IMCC_fataly(interp, EXCEPTION_SYNTAX_ERROR,
683 "global PMC constant not allowed");
685 r = _mk_symreg(&IMCC_INFO(interp)->ghash, name, t);
687 else {
688 r = mk_ident(interp, name, t);
690 if (t == 'P')
691 return mk_pmc_const_2(interp, IMCC_INFO(interp)->cur_unit, r, val);
694 r->type = VT_CONSTP;
695 r->reg = val;
697 return r;
703 =item C<SymReg * _mk_const>
705 Makes a new constant (internal use only).
707 =cut
711 PARROT_WARN_UNUSED_RESULT
712 PARROT_CANNOT_RETURN_NULL
713 SymReg *
714 _mk_const(ARGMOD(SymHash *hsh), ARGIN(const char *name), int t)
716 SymReg * const r = _mk_symreg(hsh, name, t);
717 r->type = VTCONST;
719 if (t == 'U') {
720 /* charset:"string" */
721 r->set = 'S';
722 r->type |= VT_ENCODED;
725 r->use_count++;
727 return r;
733 =item C<SymReg * mk_const>
735 Makes a new constant (and populates the cache of global symbols).
737 =cut
741 PARROT_WARN_UNUSED_RESULT
742 PARROT_CANNOT_RETURN_NULL
743 SymReg *
744 mk_const(PARROT_INTERP, ARGIN(const char *name), int t)
746 SymHash * const h = &IMCC_INFO(interp)->ghash;
748 if (!h->data)
749 create_symhash(h);
751 return _mk_const(h, name, t);
757 =item C<static char * add_ns>
759 Adds a namespace to the current sub.
761 =cut
765 PARROT_WARN_UNUSED_RESULT
766 PARROT_CANNOT_RETURN_NULL
767 PARROT_MALLOC
768 static char *
769 add_ns(PARROT_INTERP, ARGIN(const char *name))
771 size_t len, l;
772 char *ns_name, *p;
774 if (!IMCC_INFO(interp)->cur_namespace
775 || (l = strlen(IMCC_INFO(interp)->cur_namespace->name)) <= 2)
776 return str_dup(name);
778 /* TODO keyed syntax */
779 len = strlen(name) + l + 4;
780 ns_name = (char*)mem_sys_allocate(len);
782 strcpy(ns_name, IMCC_INFO(interp)->cur_namespace->name);
783 *ns_name = '_';
784 ns_name[l - 1] = '\0';
785 strcat(ns_name, "@@@");
786 strcat(ns_name, name);
788 p = strstr(ns_name, "\";\""); /* Foo";"Bar -> Foo@@@Bar */
790 while (p) {
791 p[0] = '@';
792 p[1] = '@';
793 p[2] = '@';
794 p = strstr(ns_name, "\";\")");
797 return ns_name;
803 =item C<SymReg * _mk_address>
805 Makes a new address (internal use only).
807 =cut
811 PARROT_WARN_UNUSED_RESULT
812 PARROT_CANNOT_RETURN_NULL
813 SymReg *
814 _mk_address(PARROT_INTERP, ARGMOD(SymHash *hsh), ARGIN(const char *name), int uniq)
816 SymReg *r;
818 if (uniq == U_add_all) {
819 r = mem_allocate_zeroed_typed(SymReg);
820 r->type = VTADDRESS;
821 r->name = str_dup(name);
822 _store_symreg(hsh, r);
824 else {
825 if (uniq == U_add_uniq_sub)
826 name = add_ns(interp, name);
828 r = _get_sym(hsh, name);
830 /* we use this for labels/subs */
831 if (uniq && r && r->type == VTADDRESS && r->lhs_use_count) {
832 if (uniq == U_add_uniq_label)
833 IMCC_fataly(interp, EXCEPTION_SYNTAX_ERROR,
834 "Label '%s' already defined\n", name);
835 else if (uniq == U_add_uniq_sub)
836 IMCC_fataly(interp, EXCEPTION_SYNTAX_ERROR,
837 "Subroutine '%s' already defined\n", name);
840 r = _mk_symreg(hsh, name, 0);
841 r->type = VTADDRESS;
843 if (uniq)
844 r->lhs_use_count++;
847 return r;
853 =item C<SymReg * mk_sub_label>
855 Makes and stores a new address label for a sub. The label gets a fixup entry.
857 =cut
861 PARROT_WARN_UNUSED_RESULT
862 PARROT_CANNOT_RETURN_NULL
863 SymReg *
864 mk_sub_label(PARROT_INTERP, ARGIN(const char *name))
866 SymReg * const s = _mk_address(interp, &IMCC_INFO(interp)->ghash,
867 name, U_add_uniq_sub);
869 s->usage |= U_FIXUP;
871 return s;
877 =item C<SymReg * mk_sub_address>
879 Makes a symbol for a label. The symbol gets a fixup entry.
881 =cut
885 PARROT_WARN_UNUSED_RESULT
886 PARROT_CANNOT_RETURN_NULL
887 SymReg *
888 mk_sub_address(PARROT_INTERP, ARGIN(const char *name))
890 SymReg * const s = _mk_address(interp, &IMCC_INFO(interp)->ghash,
891 name, U_add_all);
893 s->usage |= U_FIXUP;
895 return s;
901 =item C<SymReg * mk_local_label>
903 Makes a local symbol, giving it I<no> fixup entry.
905 =cut
909 PARROT_WARN_UNUSED_RESULT
910 PARROT_CANNOT_RETURN_NULL
911 SymReg *
912 mk_local_label(PARROT_INTERP, ARGIN(const char *name))
914 IMC_Unit * const unit = IMCC_INFO(interp)->last_unit;
915 return _mk_address(interp, &unit->hash, name, U_add_uniq_label);
921 =item C<SymReg * mk_label_address>
923 Makes a new label address.
925 =cut
929 PARROT_WARN_UNUSED_RESULT
930 PARROT_CANNOT_RETURN_NULL
931 SymReg *
932 mk_label_address(PARROT_INTERP, ARGIN(const char *name))
934 IMC_Unit * const unit = IMCC_INFO(interp)->last_unit;
935 return _mk_address(interp, &unit->hash, name, U_add_once);
941 =item C<SymReg * dup_sym>
943 Links keys to a keys structure = SymReg
945 we might have
947 what op type pbc.c:build_key()
948 --------------------------------------------------
949 int const _kic VTCONST no
950 int reg _ki VTREG no
951 str const _kc VTCONST yes
952 str reg _kc VTREG yes
954 "key" ';' "key" _kc -> (list of above) yes
955 "key" ';' $I0 _kc VTREGKEY -> (list of above) yes
957 The information about which reg should be passed to build_key() is
958 in the instruction.
960 A key containing a variable has a special flag VTREGKEY
961 because this key must be considered for life analysis for
962 all the chain members, that are variables.
964 An instruction with a keychain looks like this
966 e.h. set I0, P["abc";0;I1]
968 ins->r[2] = keychain 'K'
969 keychain->nextkey = SymReg(VTCONST) "abc"
970 ->nextkey = SymReg(VTCONST) 0
971 ->nextkey = SymReg(VTREG), ...->reg = VTVAR I1
972 ->nextkey = 0
974 We can't use the consts or keys in the chain directly,
975 because a different usage would destroy the ->nextkey pointers
976 so these are all copies.
977 XXX and currently not freed
979 =cut
983 PARROT_MALLOC
984 PARROT_CANNOT_RETURN_NULL
985 SymReg *
986 dup_sym(ARGIN(const SymReg *r))
988 SymReg * const new_sym = mem_allocate_zeroed_typed(SymReg);
989 STRUCT_COPY(new_sym, r);
990 new_sym->name = str_dup(r->name);
992 if (r->nextkey)
993 new_sym->nextkey = dup_sym(r->nextkey);
995 return new_sym;
1001 =item C<SymReg * link_keys>
1003 Links keys together in a keychain.
1005 =cut
1009 PARROT_MALLOC
1010 PARROT_CANNOT_RETURN_NULL
1011 SymReg *
1012 link_keys(PARROT_INTERP, int nargs, ARGMOD(SymReg **keys), int force)
1014 char *key_str;
1015 SymReg *key;
1016 SymReg *keychain;
1017 int i;
1018 int any_slice = 0;
1019 size_t len = 0;
1021 /* namespace keys are global consts - no cur_unit */
1022 SymHash * const h = IMCC_INFO(interp)->cur_unit
1023 ? &IMCC_INFO(interp)->cur_unit->hash
1024 : &IMCC_INFO(interp)->ghash;
1026 if (nargs == 0)
1027 IMCC_fataly(interp, EXCEPTION_SYNTAX_ERROR, "link_keys: huh? no keys\n");
1029 /* short-circuit simple key unless we've been told not to */
1030 if (nargs == 1 && !force && !(keys[0]->type & VT_SLICE_BITS))
1031 return keys[0];
1033 /* calc len of key_str
1034 * also check if this is a slice - the first key might not
1035 * have the slice flag set */
1036 for (i = 0; i < nargs; i++) {
1037 len += 1 + strlen(keys[i]->name);
1038 if (keys[i]->type & VT_SLICE_BITS)
1039 any_slice = 1;
1042 if (any_slice && !(keys[0]->type & VT_SLICE_BITS))
1043 keys[0]->type |= (VT_START_SLICE|VT_END_SLICE);
1045 key_str = (char *)mem_sys_allocate(len);
1046 *key_str = '\0';
1048 /* first look, if we already have this exact key chain */
1049 for (i = 0; i < nargs; i++) {
1050 strcat(key_str, keys[i]->name);
1051 /* TODO insert : to compare slices */
1052 if (i < nargs - 1)
1053 strcat(key_str, ";");
1056 if (!any_slice && ((keychain = _get_sym(h, key_str)) != NULL)) {
1057 mem_sys_free(key_str);
1058 return keychain;
1061 /* no, need a new one */
1062 keychain = mem_allocate_zeroed_typed(SymReg);
1063 keychain->type = VTCONST;
1065 ++keychain->use_count;
1067 key = keychain;
1069 for (i = 0; i < nargs; i++) {
1070 /* if any component is a variable, we need to track it in
1071 * life analysis */
1072 if (REG_NEEDS_ALLOC(keys[i]))
1073 keychain->type |= VTREGKEY;
1075 key->nextkey = dup_sym(keys[i]);
1076 key = key->nextkey;
1078 /* for registers, point ->reg to the original, needed by
1079 * life analyses & coloring */
1080 if (REG_NEEDS_ALLOC(keys[i]))
1081 key->reg = keys[i];
1084 keychain->name = key_str;
1085 keychain->set = 'K';
1086 keychain->color = -1;
1088 _store_symreg(h, keychain);
1090 return keychain;
1096 =item C<void free_sym>
1098 Frees all memory of the specified SymReg. If it has a pcc_sub_t entry, frees
1099 all memory of that structure as well.
1101 =cut
1105 void
1106 free_sym(ARGMOD(SymReg *r))
1108 pcc_sub_t * const sub = r->pcc_sub;
1110 if (sub) {
1111 mem_sys_free(sub->multi);
1112 mem_sys_free(sub->args);
1113 mem_sys_free(sub->arg_flags);
1114 mem_sys_free(sub->ret);
1115 mem_sys_free(sub->ret_flags);
1116 mem_sys_free(sub);
1119 if (r->set == 'K') {
1120 SymReg *key = r->nextkey;
1121 while (key) {
1122 SymReg *nextkey = key->nextkey;
1123 free_sym(key);
1124 key = nextkey;
1128 mem_sys_free(r->name);
1129 mem_sys_free(r);
1133 * This functions manipulate the hash of symbols.
1134 * XXX: Migrate to use Symbol and SymbolTable
1140 =item C<void create_symhash>
1142 Creates a symbol hash table with space for 16 entries.
1144 =cut
1148 void
1149 create_symhash(ARGOUT(SymHash *hash))
1151 hash->data = mem_allocate_n_zeroed_typed(16, SymReg *);
1152 hash->size = 16;
1153 hash->entries = 0;
1159 =item C<static void resize_symhash>
1161 Resizes a symbol hash table.
1163 =cut
1167 static void
1168 resize_symhash(ARGMOD(SymHash *hsh))
1170 const int new_size = hsh->size << 1; /* new size is twice as large */
1171 int n_next = 16;
1172 SymReg **next_r = mem_allocate_n_zeroed_typed(n_next, SymReg *);
1173 SymHash nh; /* new symbol table */
1174 int i;
1176 nh.data = mem_allocate_n_zeroed_typed(new_size, SymReg *);
1178 for (i = 0; i < hsh->size; i++) {
1179 SymReg *r, *next;
1180 int k;
1181 int j = 0;
1183 for (r = hsh->data[i]; r; r = next) {
1184 next = r->next;
1186 /* remember all the chained next pointers and clear r->next */
1187 if (j >= n_next) {
1188 n_next <<= 1;
1189 mem_realloc_n_typed(next_r, n_next, SymReg *);
1192 r->next = NULL;
1193 next_r[j++] = r;
1196 for (k = 0; k < j; ++k) {
1197 int new_i;
1198 r = next_r[k];
1199 /* recompute hash for this symbol: */
1200 new_i = hash_str(r->name) % new_size;
1201 r->next = nh.data[new_i];
1202 nh.data[new_i] = r;
1206 /* free memory of old hash table */
1207 mem_sys_free(hsh->data);
1208 mem_sys_free(next_r);
1210 /* let the hashtable's data pointers point to the new data */
1211 hsh->data = nh.data;
1212 hsh->size = new_size;
1218 =item C<void _store_symreg>
1220 Stores a symbol in the hash (internal use only).
1222 =cut
1226 void
1227 _store_symreg(ARGMOD(SymHash *hsh), ARGMOD(SymReg *r))
1229 const int i = hash_str(r->name) % hsh->size;
1230 #if IMC_TRACE_HIGH
1231 printf(" store [%s]\n", r->name);
1232 #endif
1233 r->next = hsh->data[i];
1234 hsh->data[i] = r;
1236 hsh->entries++;
1238 if (hsh->entries >= hsh->size)
1239 resize_symhash(hsh);
1245 =item C<void store_symreg>
1247 Stores a symbol in the hash.
1249 =cut
1253 void
1254 store_symreg(PARROT_INTERP, ARGMOD(SymReg *r))
1256 _store_symreg(&IMCC_INFO(interp)->cur_unit->hash, r);
1262 =item C<SymReg * _get_sym>
1264 Fetches a symbol from the hash (internal use only).
1266 =cut
1270 PARROT_CAN_RETURN_NULL
1271 PARROT_WARN_UNUSED_RESULT
1272 SymReg *
1273 _get_sym(ARGIN(const SymHash *hsh), ARGIN(const char *name))
1275 SymReg *p;
1276 const unsigned int i = hash_str(name) % hsh->size;
1278 for (p = hsh->data[i]; p; p = p->next) {
1279 #if IMC_TRACE_HIGH
1280 printf(" [%s]\n", p->name);
1281 #endif
1282 if (STREQ(name, p->name))
1283 return p;
1286 return NULL;
1291 =item C<SymReg * get_sym>
1293 Gets a symbol from the current unit's symbol table.
1295 =cut
1299 PARROT_CAN_RETURN_NULL
1300 PARROT_WARN_UNUSED_RESULT
1301 SymReg *
1302 get_sym(PARROT_INTERP, ARGIN(const char *name))
1304 return _get_sym(&IMCC_INFO(interp)->cur_unit->hash, name);
1310 =item C<SymReg * _find_sym>
1312 Find a symbol hash or ghash (internal use only);
1314 =cut
1318 PARROT_CAN_RETURN_NULL
1319 PARROT_WARN_UNUSED_RESULT
1320 SymReg *
1321 _find_sym(PARROT_INTERP, ARGIN_NULLOK(const Namespace *nspace),
1322 ARGIN(const SymHash *hsh), ARGIN(const char *name))
1324 const Namespace *ns;
1325 SymReg *p;
1327 for (ns = nspace; ns; ns = ns->parent) {
1328 char * const fullname = _mk_fullname(ns, name);
1329 p = _get_sym(hsh, fullname);
1331 mem_sys_free(fullname);
1333 if (p)
1334 return p;
1337 p = _get_sym(hsh, name);
1339 if (p)
1340 return p;
1342 p = _get_sym(&IMCC_INFO(interp)->ghash, name);
1344 if (p)
1345 return p;
1347 return NULL;
1353 =item C<SymReg * find_sym>
1355 Finds a symbol hash or ghash in the current unit, if it exists. Otherwise
1356 returns NULL.
1358 =cut
1362 PARROT_CAN_RETURN_NULL
1363 PARROT_WARN_UNUSED_RESULT
1364 SymReg *
1365 find_sym(PARROT_INTERP, ARGIN(const char *name))
1367 if (IMCC_INFO(interp)->cur_unit)
1368 return _find_sym(interp, _namespace,
1369 &IMCC_INFO(interp)->cur_unit->hash, name);
1371 return NULL;
1377 =item C<void clear_sym_hash>
1379 Frees all memory of the symbols in the specified hash table.
1381 =cut
1385 void
1386 clear_sym_hash(ARGMOD(SymHash *hsh))
1388 int i;
1390 if (!hsh->data)
1391 return;
1393 for (i = 0; i < hsh->size; i++) {
1394 SymReg *p;
1395 for (p = hsh->data[i]; p;) {
1396 SymReg * const next = p->next;
1397 free_sym(p);
1398 p = next;
1401 hsh->data[i] = NULL;
1404 mem_sys_free(hsh->data);
1406 hsh->data = NULL;
1407 hsh->entries = 0;
1408 hsh->size = 0;
1414 =item C<void debug_dump_sym_hash>
1416 Prints all identifiers in the specified hash table to stderr.
1418 =cut
1422 void
1423 debug_dump_sym_hash(ARGIN(const SymHash *hsh))
1425 int i;
1427 for (i = 0; i < hsh->size; i++) {
1428 const SymReg *p = hsh->data[i];
1429 while (p) {
1430 fprintf(stderr, "%s ", p->name);
1431 p = p->next;
1439 =item C<void clear_locals>
1441 Deletes all local symbols and clears life info from the given IMC_Unit.
1443 =cut
1447 void
1448 clear_locals(ARGIN_NULLOK(IMC_Unit *unit))
1450 SymHash * const hsh = &unit->hash;
1451 int i;
1453 for (i = 0; i < hsh->size; i++) {
1454 SymReg *p;
1455 for (p = hsh->data[i]; p;) {
1456 SymReg * const next = p->next;
1458 if (unit && p->life_info)
1459 free_life_info(unit, p);
1461 free_sym(p);
1462 p = next;
1465 hsh->data[i] = NULL;
1468 hsh->entries = 0;
1474 =item C<void clear_globals>
1476 Clears global symbols.
1478 =cut
1482 void
1483 clear_globals(PARROT_INTERP)
1485 SymHash * const hsh = &IMCC_INFO(interp)->ghash;
1487 if (hsh->data)
1488 clear_sym_hash(hsh);
1492 /* utility functions: */
1496 =item C<unsigned int hash_str>
1498 Computes the hash value for the string argument.
1500 =cut
1504 PARROT_PURE_FUNCTION
1505 unsigned int
1506 hash_str(ARGIN(const char *str))
1508 unsigned long key = 0;
1509 const char *s;
1511 for (s = str; *s; s++)
1512 key = key * 65599 + *s;
1514 return key;
1520 =back
1522 =cut
1527 * Local variables:
1528 * c-file-style: "parrot"
1529 * End:
1530 * vim: expandtab shiftwidth=4: