Mercurial > hg > xemacs-beta
diff src/specifier.c @ 276:6330739388db r21-0b36
Import from CVS: tag r21-0b36
author | cvs |
---|---|
date | Mon, 13 Aug 2007 10:30:37 +0200 |
parents | c5d627a313b1 |
children | 7df0dd720c89 |
line wrap: on
line diff
--- a/src/specifier.c Mon Aug 13 10:29:43 2007 +0200 +++ b/src/specifier.c Mon Aug 13 10:30:37 2007 +0200 @@ -47,7 +47,7 @@ Lisp_Object Qconsole_type, Qdevice_class; -Lisp_Object Vuser_defined_tags; +static Lisp_Object Vuser_defined_tags; typedef struct specifier_type_entry specifier_type_entry; struct specifier_type_entry @@ -63,18 +63,20 @@ specifier_type_entry_dynarr *the_specifier_type_entry_dynarr; -Lisp_Object Vspecifier_type_list; - -Lisp_Object Vcached_specifiers; +static Lisp_Object Vspecifier_type_list; + +static Lisp_Object Vcached_specifiers; /* Do NOT mark through this, or specifiers will never be GC'd. */ -Lisp_Object Vall_specifiers; +static Lisp_Object Vall_specifiers; + +static Lisp_Object Vreveal_ghoste_specifiers; /* #### The purpose of this is to check for inheritance loops in specifiers that can inherit from other specifiers, but it's not yet implemented. #### Look into this for 19.14. */ -Lisp_Object_dynarr current_specifiers; +static Lisp_Object_dynarr current_specifiers; static void recompute_cached_specifier_everywhere (Lisp_Object specifier); @@ -184,8 +186,10 @@ ((markobj) (specifier->frame_specs)); ((markobj) (specifier->window_specs)); ((markobj) (specifier->buffer_specs)); + ((markobj) (specifier->magic_parent)); ((markobj) (specifier->fallback)); - MAYBE_SPECMETH (specifier, mark, (obj, markobj)); + if (!GHOST_SPECIFIER_P (XSPECIFIER (obj))) + MAYBE_SPECMETH (specifier, mark, (obj, markobj)); return Qnil; } @@ -219,13 +223,20 @@ { if (! ((*obj_marked_p) (rest))) { + struct Lisp_Specifier* sp = XSPECIFIER (rest); + /* A bit of assertion that we're removing both parts of the + magic one altogether */ + assert (!GC_MAGIC_SPECIFIER_P(sp) + || (GC_BODILY_SPECIFIER_P(sp) && (*obj_marked_p)(sp->fallback)) + || (GC_GHOST_SPECIFIER_P(sp) && (*obj_marked_p)(sp->magic_parent))); /* This specifier is garbage. Remove it from the list. */ if (GC_NILP (prev)) - Vall_specifiers = XSPECIFIER (rest)->next_specifier; + Vall_specifiers = sp->next_specifier; else - XSPECIFIER (prev)->next_specifier = - XSPECIFIER (rest)->next_specifier; + XSPECIFIER (prev)->next_specifier = sp->next_specifier; } + else + prev = rest; } } @@ -266,7 +277,7 @@ { struct Lisp_Specifier *sp = (struct Lisp_Specifier *) header; /* don't be snafued by the disksave finalization. */ - if (!for_disksave && sp->caching) + if (!for_disksave && !GC_GHOST_SPECIFIER_P(sp) && sp->caching) { xfree (sp->caching); sp->caching = 0; @@ -293,6 +304,7 @@ internal_equal (s1->frame_specs, s2->frame_specs, depth) && internal_equal (s1->window_specs, s2->window_specs, depth) && internal_equal (s1->buffer_specs, s2->buffer_specs, depth)); + /* #### Why do not compare fallbacks here? */ if (retval && HAS_SPECMETH_P (s1, equal)) retval = SPECMETH (s1, equal, (o1, o2, depth - 1)); @@ -320,8 +332,13 @@ static size_t sizeof_specifier (CONST void *header) { - CONST struct Lisp_Specifier *p = (CONST struct Lisp_Specifier *) header; - return sizeof (*p) + p->methods->extra_data_size - 1; + if (GHOST_SPECIFIER_P ((struct Lisp_Specifier *) header)) + return sizeof (struct Lisp_Specifier); + else + { + CONST struct Lisp_Specifier *p = (CONST struct Lisp_Specifier *) header; + return sizeof (*p) + p->methods->extra_data_size - 1; + } } DEFINE_LRECORD_SEQUENCE_IMPLEMENTATION ("specifier", specifier, @@ -389,13 +406,13 @@ } static Lisp_Object -make_specifier (struct specifier_methods *spec_meths) +make_specifier_internal (struct specifier_methods *spec_meths, + size_t data_size, int call_create_meth) { Lisp_Object specifier; - struct gcpro gcpro1; struct Lisp_Specifier *sp = (struct Lisp_Specifier *) alloc_lcrecord (sizeof (struct Lisp_Specifier) + - spec_meths->extra_data_size - 1, lrecord_specifier); + data_size - 1, lrecord_specifier); sp->methods = spec_meths; sp->global_specs = Qnil; @@ -404,16 +421,48 @@ sp->window_specs = make_weak_list (WEAK_LIST_KEY_ASSOC); sp->buffer_specs = Qnil; sp->fallback = Qnil; + sp->magic_parent = Qnil; sp->caching = 0; sp->next_specifier = Vall_specifiers; XSETSPECIFIER (specifier, sp); Vall_specifiers = specifier; - GCPRO1 (specifier); - MAYBE_SPECMETH (XSPECIFIER (specifier), create, (specifier)); + if (call_create_meth) + { + struct gcpro gcpro1; + GCPRO1 (specifier); + MAYBE_SPECMETH (XSPECIFIER (specifier), create, (specifier)); + UNGCPRO; + } + return specifier; +} + +static Lisp_Object +make_specifier (struct specifier_methods *meths) +{ + return make_specifier_internal (meths, meths->extra_data_size, 1); +} + +Lisp_Object +make_magic_specifier (Lisp_Object type) +{ + /* This function can GC */ + struct specifier_methods *meths = decode_specifier_type (type, ERROR_ME); + Lisp_Object bodily, ghost; + struct gcpro gcpro1; + + bodily = make_specifier (meths); + GCPRO1 (bodily); + ghost = make_specifier_internal (meths, 0, 0); UNGCPRO; - return specifier; + + /* Connect guys together */ + XSPECIFIER(bodily)->magic_parent = Qt; + XSPECIFIER(bodily)->fallback = ghost; + XSPECIFIER(ghost)->magic_parent = bodily; + + return bodily; } DEFUN ("make-specifier", Fmake_specifier, 1, 1, 0, /* @@ -1188,6 +1237,49 @@ return SPEC_PREPEND; /* not reached */ } +/* Given a specifier object SPEC, return its bodily specifier for a + ghost specifier, otherwise return the object itself +*/ +static Lisp_Object +bodily_specifier (Lisp_Object spec) +{ + return (GHOST_SPECIFIER_P (XSPECIFIER (spec)) + ? XSPECIFIER(spec)->magic_parent : spec); +} + +/* Given a specifier object SPEC, return a specifier to be operated on + by external lisp function. This is a ghost specifier for a magic + specifier when and only when Vreveal_ghoste_specifiers is non-nil, + otherwise SPEC itself. +*/ +static Lisp_Object +maybe_ghost_specifier (Lisp_Object spec) +{ + return (!NILP (Vreveal_ghoste_specifiers) + && BODILY_SPECIFIER_P (XSPECIFIER (spec)) + ? XSPECIFIER(spec)->fallback : spec); +} + +/* Helper function which unwind protects the value of + Vreveal_ghoste_specifiers, then sets it to non-nil value */ + +static Lisp_Object +restore_reveal_value (Lisp_Object val) +{ + Vreveal_ghoste_specifiers = val; + return val; +} + +int +reveal_ghost_specifiers_protected (void) +{ + int depth = specpdl_depth (); + record_unwind_protect (restore_reveal_value, + Vreveal_ghoste_specifiers); + Vreveal_ghoste_specifiers = Qt; + return depth; +} + /* This gets hit so much that the function call overhead had a measurable impact (according to Quantify). #### We should figure out the frequency with which this is called with the various types @@ -1382,7 +1474,8 @@ } if (was_removed) - MAYBE_SPECMETH (XSPECIFIER (specifier), after_change, (specifier, locale)); + MAYBE_SPECMETH (XSPECIFIER (specifier), after_change, + (bodily_specifier (specifier), locale)); } static void @@ -1428,7 +1521,7 @@ if (was_removed) MAYBE_SPECMETH (XSPECIFIER (specifier), after_change, - (specifier, XCAR (spec))); + (bodily_specifier (specifier), XCAR (spec))); } } @@ -1502,7 +1595,8 @@ /* call the will-add method; it may GC */ sub_inst_list = HAS_SPECMETH_P (sp, going_to_add) ? SPECMETH (sp, going_to_add, - (specifier, locale, tag_set, instantiator)) : + (bodily_specifier (specifier), locale, + tag_set, instantiator)) : Qt; if (EQ (sub_inst_list, Qt)) /* no change here. */ @@ -1576,7 +1670,8 @@ UNGCPRO; /* call the after-change method */ - MAYBE_SPECMETH (sp, after_change, (specifier, locale)); + MAYBE_SPECMETH (sp, after_change, + (bodily_specifier (specifier), locale)); } static void @@ -1761,7 +1856,8 @@ inst_list = list1 (Fcons (tag_set, instantiator)); GCPRO1 (inst_list); - specifier_add_spec (specifier, locale, inst_list, add_meth); + specifier_add_spec (maybe_ghost_specifier (specifier), + locale, inst_list, add_meth); recompute_cached_specifier_everywhere (specifier); RETURN_UNGCPRO (Qnil); } @@ -1812,12 +1908,24 @@ Lisp_Object locale = XCAR (specification); Lisp_Object inst_list = XCDR (specification); - specifier_add_spec (specifier, locale, inst_list, add_meth); + specifier_add_spec (maybe_ghost_specifier (specifier), + locale, inst_list, add_meth); } recompute_cached_specifier_everywhere (specifier); return Qnil; } +void +add_spec_to_ghost_specifier (Lisp_Object specifier, Lisp_Object instantiator, + Lisp_Object locale, Lisp_Object tag_set, + Lisp_Object how_to_add) +{ + int depth = reveal_ghost_specifiers_protected (); + Fadd_spec_to_specifier (specifier, instantiator, locale, + tag_set, how_to_add); + unbind_to (depth, Qnil); +} + struct specifier_spec_list_closure { Lisp_Object head, tail; @@ -1905,7 +2013,8 @@ CHECK_SPECIFIER (specifier); cl.head = cl.tail = Qnil; GCPRO2 (cl.head, cl.tail); - map_specifier (specifier, locale, specifier_spec_list_mapfun, + map_specifier (maybe_ghost_specifier (specifier), + locale, specifier_spec_list_mapfun, tag_set, exact_p, &cl); UNGCPRO; return cl.head; @@ -1949,7 +2058,8 @@ tag_set = decode_specifier_tag_set (tag_set); tag_set = canonicalize_tag_set (tag_set); RETURN_UNGCPRO - (specifier_get_external_inst_list (specifier, locale, + (specifier_get_external_inst_list (maybe_ghost_specifier (specifier), + locale, locale_type_from_locale (locale), tag_set, !NILP (exact_p), 1, 1)); @@ -1999,12 +2109,21 @@ (specifier, locale, tag_set, exact_p)) { CHECK_SPECIFIER (specifier); - map_specifier (specifier, locale, remove_specifier_mapfun, tag_set, - exact_p, 0); + map_specifier (maybe_ghost_specifier (specifier), locale, + remove_specifier_mapfun, tag_set, exact_p, 0); recompute_cached_specifier_everywhere (specifier); return Qnil; } +void +remove_ghost_specifier (Lisp_Object specifier, Lisp_Object locale, + Lisp_Object tag_set, Lisp_Object exact_p) +{ + int depth = reveal_ghost_specifiers_protected (); + Fremove_specifier (specifier, locale, tag_set, exact_p); + unbind_to (depth, Qnil); +} + struct copy_specifier_closure { Lisp_Object dest; @@ -2089,10 +2208,10 @@ cl.dest = dest; GCPRO1 (dest); - map_specifier (specifier, locale, copy_specifier_mapfun, - tag_set, exact_p, &cl); + map_specifier (maybe_ghost_specifier (specifier), locale, + copy_specifier_mapfun, tag_set, exact_p, &cl); UNGCPRO; - recompute_cached_specifier_everywhere (specifier); + recompute_cached_specifier_everywhere (dest); return dest; } @@ -2185,9 +2304,13 @@ !NILP (Fvalid_inst_list_p (fallback, Fspecifier_type (specifier)))); if (SPECIFIERP (fallback)) assert (EQ (Fspecifier_type (specifier), Fspecifier_type (fallback))); - sp->fallback = fallback; + if (BODILY_SPECIFIER_P (sp)) + GHOST_SPECIFIER(sp)->fallback = fallback; + else + sp->fallback = fallback; /* call the after-change method */ - MAYBE_SPECMETH (sp, after_change, (specifier, Qfallback)); + MAYBE_SPECMETH (sp, after_change, + (bodily_specifier (specifier), Qfallback)); recompute_cached_specifier_everywhere (specifier); } @@ -2458,7 +2581,8 @@ CHECK_SPECIFIER (specifier); domain = decode_domain (domain); - instance = specifier_instance (specifier, Qunbound, domain, ERROR_ME, 0, + instance = specifier_instance (maybe_ghost_specifier (specifier), + Qunbound, domain, ERROR_ME, 0, !NILP (no_fallback), Qzero); return UNBOUNDP (instance) ? default_ : instance; } @@ -2495,8 +2619,9 @@ ERROR_ME); domain = decode_domain (domain); - instance = specifier_instance (specifier, matchspec, domain, ERROR_ME, 0, - !NILP (no_fallback), Qzero); + instance = specifier_instance (maybe_ghost_specifier (specifier), + matchspec, domain, ERROR_ME, + 0, !NILP (no_fallback), Qzero); return UNBOUNDP (instance) ? default_ : instance; } @@ -2519,11 +2644,12 @@ check_valid_domain (domain); check_valid_inst_list (inst_list, sp->methods, ERROR_ME); GCPRO1 (built_up_list); - built_up_list = build_up_processed_list (specifier, domain, inst_list); + built_up_list = build_up_processed_list (maybe_ghost_specifier (specifier), + domain, inst_list); if (!NILP (built_up_list)) - val = specifier_instance_from_inst_list (specifier, Qunbound, domain, - built_up_list, ERROR_ME, 0, - Qzero); + val = specifier_instance_from_inst_list (maybe_ghost_specifier (specifier), + Qunbound, domain, built_up_list, + ERROR_ME, 0, Qzero); UNGCPRO; return UNBOUNDP (val) ? default_ : val; } @@ -2553,11 +2679,12 @@ check_valid_domain (domain); check_valid_inst_list (inst_list, sp->methods, ERROR_ME); GCPRO1 (built_up_list); - built_up_list = build_up_processed_list (specifier, domain, inst_list); + built_up_list = build_up_processed_list (maybe_ghost_specifier (specifier), + domain, inst_list); if (!NILP (built_up_list)) - val = specifier_instance_from_inst_list (specifier, matchspec, domain, - built_up_list, ERROR_ME, 0, - Qzero); + val = specifier_instance_from_inst_list (maybe_ghost_specifier (specifier), + matchspec, domain, built_up_list, + ERROR_ME, 0, Qzero); UNGCPRO; return UNBOUNDP (val) ? default_ : val; } @@ -2584,6 +2711,7 @@ Lisp_Object oldval)) { struct Lisp_Specifier *sp = XSPECIFIER (specifier); + assert (!GHOST_SPECIFIER_P (sp)); if (!sp->caching) sp->caching = xnew_and_zero (struct specifier_caching); @@ -2592,6 +2720,8 @@ sp->caching->offset_into_struct_frame = struct_frame_offset; sp->caching->value_changed_in_frame = value_changed_in_frame; Vcached_specifiers = Fcons (specifier, Vcached_specifiers); + if (BODILY_SPECIFIER_P (sp)) + GHOST_SPECIFIER(sp)->caching = sp->caching; recompute_cached_specifier_everywhere (specifier); } @@ -2602,6 +2732,8 @@ Lisp_Object window; Lisp_Object newval, *location; + assert (!GHOST_SPECIFIER_P (XSPECIFIER (specifier))); + XSETWINDOW (window, w); newval = specifier_instance (specifier, Qunbound, window, ERROR_ME_WARN, @@ -2628,6 +2760,8 @@ Lisp_Object frame; Lisp_Object newval, *location; + assert (!GHOST_SPECIFIER_P (XSPECIFIER (specifier))); + XSETFRAME (frame, f); newval = specifier_instance (specifier, Qunbound, frame, ERROR_ME_WARN, @@ -2689,6 +2823,8 @@ { Lisp_Object frmcons, devcons, concons; + specifier = bodily_specifier (specifier); + if (!XSPECIFIER (specifier)->caching) return; @@ -2993,4 +3129,7 @@ Vuser_defined_tags = Qnil; staticpro (&Vuser_defined_tags); + + Vreveal_ghoste_specifiers = Qnil; + staticpro (&Vreveal_ghoste_specifiers); }