source: branches/1.1.x/src/org/armedbear/lisp/StandardGenericFunction.java

Last change on this file was 14345, checked in by Mark Evenson, 12 years ago

Backport r14344 | rschlatte | 2012-12-30 18:09:06 +0100 (Sun, 30 Dec 2012) | 5 lines

Avoid premature initialization of method-class, method-combination in gfs

  • reported by Pascal Costanza
  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 28.1 KB
Line 
1/*
2 * StandardGenericFunction.java
3 *
4 * Copyright (C) 2003-2006 Peter Graves
5 * $Id: StandardGenericFunction.java 14345 2012-12-31 10:21:17Z mevenson $
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
20 *
21 * As a special exception, the copyright holders of this library give you
22 * permission to link this library with independent modules to produce an
23 * executable, regardless of the license terms of these independent
24 * modules, and to copy and distribute the resulting executable under
25 * terms of your choice, provided that you also meet, for each linked
26 * independent module, the terms and conditions of the license of that
27 * module.  An independent module is a module which is not derived from
28 * or based on this library.  If you modify this library, you may extend
29 * this exception to your version of the library, but you are not
30 * obligated to do so.  If you do not wish to do so, delete this
31 * exception statement from your version.
32 */
33
34package org.armedbear.lisp;
35
36import static org.armedbear.lisp.Lisp.*;
37
38import java.util.concurrent.ConcurrentHashMap;
39
40public final class StandardGenericFunction extends FuncallableStandardObject
41{
42
43  ConcurrentHashMap<CacheEntry,LispObject> cache;
44  ConcurrentHashMap<LispObject,LispObject> slotCache;
45
46  public StandardGenericFunction()
47  {
48    super(StandardClass.STANDARD_GENERIC_FUNCTION,
49          StandardClass.STANDARD_GENERIC_FUNCTION.getClassLayout().getLength());
50  }
51
52  public StandardGenericFunction(Layout layout)
53  {
54    super(layout);
55    slots[StandardGenericFunctionClass.SLOT_INDEX_NAME] = NIL;
56    slots[StandardGenericFunctionClass.SLOT_INDEX_LAMBDA_LIST] = NIL;
57    slots[StandardGenericFunctionClass.SLOT_INDEX_REQUIRED_ARGS] = NIL;
58    slots[StandardGenericFunctionClass.SLOT_INDEX_OPTIONAL_ARGS] = NIL;
59    slots[StandardGenericFunctionClass.SLOT_INDEX_INITIAL_METHODS] = NIL;
60    slots[StandardGenericFunctionClass.SLOT_INDEX_METHODS] = NIL;
61    slots[StandardGenericFunctionClass.SLOT_INDEX_METHOD_CLASS] =
62      StandardClass.STANDARD_METHOD;
63    slots[StandardGenericFunctionClass.SLOT_INDEX_METHOD_COMBINATION] =
64      list(Symbol.STANDARD); // fixed up by clos.lisp:shared-initialize :after
65    slots[StandardGenericFunctionClass.SLOT_INDEX_ARGUMENT_PRECEDENCE_ORDER] =
66      NIL;
67    slots[StandardGenericFunctionClass.SLOT_INDEX_DECLARATIONS] = NIL;
68    slots[StandardGenericFunctionClass.SLOT_INDEX_CLASSES_TO_EMF_TABLE] = NIL;
69    slots[StandardGenericFunctionClass.SLOT_INDEX_DOCUMENTATION] = NIL;
70  }
71
72  void finalizeInternal()
73  {
74    cache = null;
75  }
76
77  @Override
78  public LispObject typep(LispObject type)
79  {
80    if (type == Symbol.COMPILED_FUNCTION)
81      {
82        if (function != null)
83          return function.typep(type);
84        else
85          return NIL;
86      }
87    if (type == Symbol.STANDARD_GENERIC_FUNCTION)
88      return T;
89    if (type == StandardClass.STANDARD_GENERIC_FUNCTION)
90      return T;
91    return super.typep(type);
92  }
93
94  public LispObject getGenericFunctionName()
95  {
96    return slots[StandardGenericFunctionClass.SLOT_INDEX_NAME];
97  }
98
99  public void setGenericFunctionName(LispObject name)
100  {
101    slots[StandardGenericFunctionClass.SLOT_INDEX_NAME] = name;
102  }
103
104  @Override
105  public String printObject()
106  {
107    LispObject name = getGenericFunctionName();
108    if (name != null)
109      {
110        StringBuilder sb = new StringBuilder();
111        LispObject className;
112        LispObject lispClass = getLispClass();
113        if (lispClass instanceof LispClass)
114          className = ((LispClass)lispClass).getName();
115        else
116          className = Symbol.CLASS_NAME.execute(lispClass);
117
118        sb.append(className.princToString());
119        sb.append(' ');
120        sb.append(name.princToString());
121        return unreadableString(sb.toString());
122      }
123    return super.printObject();
124  }
125
126  // AMOP (p. 216) specifies the following readers as generic functions:
127  //   generic-function-argument-precedence-order
128  //   generic-function-declarations
129  //   generic-function-lambda-list
130  //   generic-function-method-class
131  //   generic-function-method-combination
132  //   generic-function-methods
133  //   generic-function-name
134
135  private static final Primitive _GENERIC_FUNCTION_NAME
136    = new pf__generic_function_name();
137  @DocString(name="%generic-function-name")
138  private static final class pf__generic_function_name extends Primitive
139  {
140    pf__generic_function_name() 
141    {
142      super("%generic-function-name", PACKAGE_SYS, true);
143    }
144    @Override
145    public LispObject execute(LispObject arg)
146    {
147      return checkStandardGenericFunction(arg).slots[StandardGenericFunctionClass.SLOT_INDEX_NAME];
148    }
149  };
150
151  private static final Primitive _SET_GENERIC_FUNCTION_NAME
152    = new pf__set_generic_function_name();
153  @DocString(name="%set-generic-function-name")
154  private static final class pf__set_generic_function_name extends Primitive
155  { 
156    pf__set_generic_function_name() 
157    {
158      super ("%set-generic-function-name", PACKAGE_SYS, true);
159    }
160    @Override
161    public LispObject execute(LispObject first, LispObject second)
162    {
163      checkStandardGenericFunction(first).slots[StandardGenericFunctionClass.SLOT_INDEX_NAME] = second;
164      return second;
165    }
166  };
167
168  private static final Primitive _GENERIC_FUNCTION_LAMBDA_LIST
169    = new pf__generic_function_lambda_list();
170  @DocString(name ="%generic-function-lambda-list")
171  private static final class pf__generic_function_lambda_list extends Primitive {
172    pf__generic_function_lambda_list() 
173    {
174      super("%generic-function-lambda-list", PACKAGE_SYS, true);
175    }
176    @Override
177    public LispObject execute(LispObject arg)
178    {
179      return checkStandardGenericFunction(arg).slots[StandardGenericFunctionClass.SLOT_INDEX_LAMBDA_LIST];
180    }
181  };
182
183  private static final Primitive _SET_GENERIC_FUNCTION_LAMBDA_LIST
184    = new pf__set_generic_function_lambda_list();
185  @DocString(name="%set-generic-function-lambdalist")
186  private static final class pf__set_generic_function_lambda_list extends Primitive
187  {
188    pf__set_generic_function_lambda_list()
189    {
190      super("%set-generic-function-lambda-list", PACKAGE_SYS, true);
191    }
192    @Override
193    public LispObject execute(LispObject first, LispObject second)
194    {
195      checkStandardGenericFunction(first).slots[StandardGenericFunctionClass.SLOT_INDEX_LAMBDA_LIST] = second;
196      return second;
197    }
198  };
199
200  private static final Primitive GF_REQUIRED_ARGS
201    = new pf_gf_required_args();
202  @DocString(name="gf-required-args")
203  private static final class pf_gf_required_args extends Primitive
204  {
205    pf_gf_required_args()
206    {
207      super("gf-required-args", PACKAGE_SYS, true);
208    }
209    @Override
210    public LispObject execute(LispObject arg)
211    {
212      return checkStandardGenericFunction(arg).slots[StandardGenericFunctionClass.SLOT_INDEX_REQUIRED_ARGS];
213    }
214  };
215
216  private static final Primitive _SET_GF_REQUIRED_ARGS
217    = new pf__set_gf_required_args();
218  @DocString(name="%set-gf-required-args")
219  private static final class pf__set_gf_required_args extends Primitive
220  {
221    pf__set_gf_required_args()
222    {
223      super("%set-gf-required-args", PACKAGE_SYS, true);
224    }
225    @Override
226    public LispObject execute(LispObject first, LispObject second)
227    {
228      final StandardGenericFunction gf = checkStandardGenericFunction(first);
229      gf.slots[StandardGenericFunctionClass.SLOT_INDEX_REQUIRED_ARGS] = second;
230      return second;
231    }
232  };
233
234  private static final Primitive GF_OPTIONAL_ARGS
235    = new pf_gf_optional_args();
236  @DocString(name="gf-optional-args")
237  private static final class pf_gf_optional_args extends Primitive
238  {
239    pf_gf_optional_args()
240    {
241      super("gf-optional-args", PACKAGE_SYS, true);
242    }
243    @Override
244    public LispObject execute(LispObject arg)
245    {
246      return checkStandardGenericFunction(arg).slots[StandardGenericFunctionClass.SLOT_INDEX_OPTIONAL_ARGS];
247    }
248  };
249
250  private static final Primitive _SET_GF_OPTIONAL_ARGS
251    = new pf__set_gf_optional_args();
252  @DocString(name="%set-gf-optional-args")
253  private static final class pf__set_gf_optional_args extends Primitive
254  {
255    pf__set_gf_optional_args()
256    {
257      super("%set-gf-optional-args", PACKAGE_SYS, true);
258    }
259    @Override
260    public LispObject execute(LispObject first, LispObject second)
261    {
262      final StandardGenericFunction gf = checkStandardGenericFunction(first);
263      gf.slots[StandardGenericFunctionClass.SLOT_INDEX_OPTIONAL_ARGS] = second;
264      return second;
265    }
266  };
267
268  private static final Primitive GENERIC_FUNCTION_INITIAL_METHODS
269    = new pf_generic_function_initial_methods();
270  @DocString(name="generic-function-initial-methods")
271  private static final class pf_generic_function_initial_methods extends Primitive
272  {
273    pf_generic_function_initial_methods() 
274    {
275      super("generic-function-initial-methods", PACKAGE_SYS, true);
276    }
277    @Override
278    public LispObject execute(LispObject arg)
279    {
280      return checkStandardGenericFunction(arg).slots[StandardGenericFunctionClass.SLOT_INDEX_INITIAL_METHODS];
281    }
282  };
283
284  private static final Primitive SET_GENERIC_FUNCTION_INITIAL_METHODS
285    = new pf_set_generic_function_initial_methods();
286  @DocString(name="set-generic-function-initial-methods")
287  private static final class pf_set_generic_function_initial_methods extends Primitive
288  {
289    pf_set_generic_function_initial_methods()
290    {
291      super("set-generic-function-initial-methods", PACKAGE_SYS, true);
292    }
293    @Override
294    public LispObject execute(LispObject first, LispObject second)
295    {
296      checkStandardGenericFunction(first).slots[StandardGenericFunctionClass.SLOT_INDEX_INITIAL_METHODS] = second;
297      return second;
298    }
299  };
300
301  private static final Primitive GENERIC_FUNCTION_METHODS
302    = new pf_generic_function_methods();
303  @DocString(name="%generic-function-methods")
304  private static final class pf_generic_function_methods extends Primitive
305  {
306    pf_generic_function_methods()
307    {
308      super("%generic-function-methods", PACKAGE_SYS, true);
309    }
310    @Override
311    public LispObject execute(LispObject arg)
312    {
313      return checkStandardGenericFunction(arg).slots[StandardGenericFunctionClass.SLOT_INDEX_METHODS];
314    }
315  };
316
317  private static final Primitive SET_GENERIC_FUNCTION_METHODS
318    = new pf_set_generic_function_methods();
319  @DocString(name="set-generic-function-methods")
320  private static final class pf_set_generic_function_methods extends Primitive
321  {
322    pf_set_generic_function_methods()
323    {
324      super("set-generic-function-methods", PACKAGE_SYS, true);
325    }
326    @Override
327    public LispObject execute(LispObject first, LispObject second)
328    {
329      checkStandardGenericFunction(first).slots[StandardGenericFunctionClass.SLOT_INDEX_METHODS] = second;
330      return second;
331    }
332  };
333
334  private static final Primitive GENERIC_FUNCTION_METHOD_CLASS
335    = new pf_generic_function_method_class();
336  @DocString(name="%generic-function-method-class")
337  private static final class pf_generic_function_method_class extends Primitive
338  {
339    pf_generic_function_method_class()
340    {
341      super("%generic-function-method-class", PACKAGE_SYS, true);
342    }
343    @Override
344    public LispObject execute(LispObject arg)
345    {
346      return checkStandardGenericFunction(arg).slots[StandardGenericFunctionClass.SLOT_INDEX_METHOD_CLASS];
347    }
348  };
349
350  private static final Primitive SET_GENERIC_FUNCTION_METHOD_CLASS
351    = new pf_set_generic_function_method_class();
352  @DocString(name="set-generic-function-method-class")
353  private static final class pf_set_generic_function_method_class extends Primitive
354  {
355    pf_set_generic_function_method_class()
356    {
357      super("set-generic-function-method-class", PACKAGE_SYS, true);
358    }
359    @Override
360    public LispObject execute(LispObject first, LispObject second)
361    {
362      checkStandardGenericFunction(first).slots[StandardGenericFunctionClass.SLOT_INDEX_METHOD_CLASS] = second;
363      return second;
364    }
365  };
366
367  private static final Primitive GENERIC_FUNCTION_METHOD_COMBINATION
368    = new pf_generic_function_method_combination(); 
369  @DocString(name="%generic-function-method-combination")
370  private static final class pf_generic_function_method_combination extends Primitive
371  {
372    pf_generic_function_method_combination()
373    {
374      super("%generic-function-method-combination", PACKAGE_SYS, true);
375    }
376    @Override
377    public LispObject execute(LispObject arg)
378    {
379      return checkStandardGenericFunction(arg).slots[StandardGenericFunctionClass.SLOT_INDEX_METHOD_COMBINATION];
380    }
381  };
382
383  private static final Primitive SET_GENERIC_FUNCTION_METHOD_COMBINATION
384    = new pf_set_generic_function_method_combination(); 
385  @DocString(name="set-generic-function-method-combination")
386  private static final class pf_set_generic_function_method_combination extends Primitive
387  {
388    pf_set_generic_function_method_combination()
389    {
390      super("set-generic-function-method-combination", PACKAGE_SYS, true);
391    }
392    @Override
393    public LispObject execute(LispObject first, LispObject second)
394    {
395      checkStandardGenericFunction(first).slots[StandardGenericFunctionClass.SLOT_INDEX_METHOD_COMBINATION] 
396        = second;
397      return second;
398    }
399  };
400
401  private static final Primitive GENERIC_FUNCTION_ARGUMENT_PRECEDENCE_ORDER
402    = new pf_generic_function_argument_precedence_order();
403  @DocString(name="%generic-function-argument-precedence-order")
404  private static final class pf_generic_function_argument_precedence_order extends Primitive
405  {
406    pf_generic_function_argument_precedence_order()
407    { 
408      super("%generic-function-argument-precedence-order", PACKAGE_SYS, true);
409    }
410    @Override
411    public LispObject execute(LispObject arg)
412    {
413      return checkStandardGenericFunction(arg).slots[StandardGenericFunctionClass
414                                                     .SLOT_INDEX_ARGUMENT_PRECEDENCE_ORDER];
415    }
416  };
417
418  private static final Primitive SET_GENERIC_FUNCTION_ARGUMENT_PRECEDENCE_ORDER
419    = new pf_set_generic_function_argument_precedence_order();
420  @DocString(name="set-generic-function-argument-precedence-order")
421  private static final class pf_set_generic_function_argument_precedence_order extends Primitive
422  {
423    pf_set_generic_function_argument_precedence_order()
424    {
425      super("set-generic-function-argument-precedence-order", PACKAGE_SYS, true);
426    }
427    @Override
428    public LispObject execute(LispObject first, LispObject second)
429    {
430      checkStandardGenericFunction(first)
431        .slots[StandardGenericFunctionClass.SLOT_INDEX_ARGUMENT_PRECEDENCE_ORDER] = second;
432      return second;
433    }
434  };
435
436  private static final Primitive GENERIC_FUNCTION_DECLARATIONS
437    = new pf_generic_function_declarations();
438  @DocString(name="%generic-function-declarations")
439  private static final class pf_generic_function_declarations extends Primitive
440  {
441    pf_generic_function_declarations()
442    { 
443      super("%generic-function-declarations", PACKAGE_SYS, true);
444    }
445    @Override
446    public LispObject execute(LispObject arg)
447    {
448      return checkStandardGenericFunction(arg)
449        .slots[StandardGenericFunctionClass .SLOT_INDEX_DECLARATIONS];
450    }
451  };
452
453  private static final Primitive SET_GENERIC_FUNCTION_DECLARATIONS
454    = new pf_set_generic_function_declarations();
455  @DocString(name="set-generic-function-declarations")
456  private static final class pf_set_generic_function_declarations extends Primitive
457  {
458    pf_set_generic_function_declarations()
459    {
460      super("set-generic-function-declarations", PACKAGE_SYS, true);
461    }
462    @Override
463    public LispObject execute(LispObject first, LispObject second)
464    {
465      checkStandardGenericFunction(first)
466        .slots[StandardGenericFunctionClass.SLOT_INDEX_DECLARATIONS] = second;
467      return second;
468    }
469  };
470
471
472
473  private static final Primitive GENERIC_FUNCTION_CLASSES_TO_EMF_TABLE
474    = new pf_generic_function_classes_to_emf_table();
475  @DocString(name="generic-function-classes-to-emf-table")
476  private static final class pf_generic_function_classes_to_emf_table extends Primitive
477  {
478    pf_generic_function_classes_to_emf_table() 
479    {
480      super("generic-function-classes-to-emf-table", PACKAGE_SYS, true);
481    }
482    @Override
483    public LispObject execute(LispObject arg)
484    {
485      return checkStandardGenericFunction(arg)
486        .slots[StandardGenericFunctionClass.SLOT_INDEX_CLASSES_TO_EMF_TABLE];
487    }
488  };
489
490  private static final Primitive SET_GENERIC_FUNCTION_CLASSES_TO_EMF_TABLE
491    = new pf_set_generic_function_classes_to_emf_table();
492  @DocString(name="set-generic-function-classes-to-emf-table")
493  private static final class pf_set_generic_function_classes_to_emf_table extends Primitive
494  {
495    pf_set_generic_function_classes_to_emf_table()
496    {
497      super("set-generic-function-classes-to-emf-table", PACKAGE_SYS, true);
498    }
499    @Override
500    public LispObject execute(LispObject first, LispObject second)
501    {
502      checkStandardGenericFunction(first)
503        .slots[StandardGenericFunctionClass.SLOT_INDEX_CLASSES_TO_EMF_TABLE] = second;
504      return second;
505    }
506  };
507
508  private static final Primitive GENERIC_FUNCTION_DOCUMENTATION
509    = new pf_generic_function_documentation();
510  @DocString(name="generic-function-documentation")
511  private static final class pf_generic_function_documentation extends Primitive
512  {
513    pf_generic_function_documentation() 
514    {
515      super("generic-function-documentation", PACKAGE_SYS, true);
516    }
517    @Override
518    public LispObject execute(LispObject arg)
519    {
520      return checkStandardGenericFunction(arg).slots[StandardGenericFunctionClass.SLOT_INDEX_DOCUMENTATION];
521    }
522  };
523
524  private static final Primitive SET_GENERIC_FUNCTION_DOCUMENTATION
525    = new pf_set_generic_function_documentation();
526  @DocString(name="set-generic-function-documentation")
527  private static final class pf_set_generic_function_documentation extends Primitive
528  {
529    pf_set_generic_function_documentation()
530    {
531      super("set-generic-function-documentation", PACKAGE_SYS, true);
532    }
533    @Override
534    public LispObject execute(LispObject first, LispObject second)
535    {
536      checkStandardGenericFunction(first).slots[StandardGenericFunctionClass.SLOT_INDEX_DOCUMENTATION] 
537        = second;
538      return second;
539    }
540  };
541
542  private static final Primitive _FINALIZE_GENERIC_FUNCTION
543    = new pf__finalize_generic_function();
544  @DocString(name="%finalize-generic-function",
545             args="generic-function")
546  private static final class  pf__finalize_generic_function extends Primitive
547  {
548    pf__finalize_generic_function()
549    {
550      super("%finalize-generic-function", PACKAGE_SYS, true,
551            "generic-function");
552    }
553    @Override
554    public LispObject execute(LispObject arg)
555    {
556      final StandardGenericFunction gf = checkStandardGenericFunction(arg);
557      gf.finalizeInternal();       
558      return T;
559    }
560  };
561
562  private static final Primitive CACHE_EMF
563    = new pf_cache_emf();
564  @DocString(name="cache-emf",
565             args="generic-function args emf")
566  private static final class pf_cache_emf extends Primitive
567  {
568    pf_cache_emf()
569    {
570      super("cache-emf", PACKAGE_SYS, true, "generic-function args emf");
571    }
572    @Override
573    public LispObject execute(LispObject first, LispObject second,
574                              LispObject third)
575    {
576      final StandardGenericFunction gf = checkStandardGenericFunction(first);
577      LispObject args = second;
578      int numberOfRequiredArgs
579        = gf.slots[StandardGenericFunctionClass.SLOT_INDEX_REQUIRED_ARGS]
580        .length();
581      LispObject[] array = new LispObject[numberOfRequiredArgs];
582      for (int i = numberOfRequiredArgs; i-- > 0;)
583        {
584          array[i] = gf.getArgSpecialization(args.car());
585          args = args.cdr();
586        }
587      CacheEntry specializations = new CacheEntry(array);
588      ConcurrentHashMap<CacheEntry,LispObject> ht = gf.cache;
589      if (ht == null)
590        ht = gf.cache = new ConcurrentHashMap<CacheEntry,LispObject>();
591      ht.put(specializations, third);
592      return third;
593    }
594  };
595
596  private static final Primitive GET_CACHED_EMF
597    = new pf_get_cached_emf();
598  @DocString(name="get-cached-emf",
599             args="generic-function args")
600  private static final class pf_get_cached_emf extends Primitive
601  {
602    pf_get_cached_emf() {
603      super("get-cached-emf", PACKAGE_SYS, true, "generic-function args");
604    }
605    @Override
606    public LispObject execute(LispObject first, LispObject second)
607    {
608      final StandardGenericFunction gf = checkStandardGenericFunction(first);
609      LispObject args = second;
610      int numberOfRequiredArgs
611        = gf.slots[StandardGenericFunctionClass.SLOT_INDEX_REQUIRED_ARGS]
612        .length();
613      LispObject[] array = new LispObject[numberOfRequiredArgs];
614      for (int i = numberOfRequiredArgs; i-- > 0;)
615        {
616          array[i] = gf.getArgSpecialization(args.car());
617          args = args.cdr();
618        }
619      CacheEntry specializations = new CacheEntry(array);
620      ConcurrentHashMap<CacheEntry,LispObject> ht = gf.cache;
621      if (ht == null)
622        return NIL;
623      LispObject emf = (LispObject) ht.get(specializations);
624      return emf != null ? emf : NIL;
625    }
626  };
627
628  /**
629   * Returns an object representing generic function
630   * argument <tt>arg</tt> in a <tt>CacheEntry</tt>
631   *
632   * <p>In the simplest case, when this generic function
633   * does not have EQL specialized methods, and therefore
634   * only argument types are relevant for choosing
635   * applicable methods, the value returned is the
636   * class of <tt>arg</tt>
637   *
638   * <p>If the function has EQL specialized methods:
639   *   - if <tt>arg</tt> is EQL to some of the EQL-specializers,
640   *     a special object representing equality to that specializer
641   *     is returned.
642   *   - otherwise class of the <tt>arg</tt> is returned.
643   *
644   * <p>Note that we do not consider argument position, when
645   * calculating arg specialization. In rare cases (when one argument
646   * is eql-specialized to a symbol specifying class of another
647   * argument) this may result in redundant cache entries caching the
648   * same method. But the method cached is anyway correct for the
649   * arguments (because in case of cache miss, correct method is
650   * calculated by other code, which does not rely on
651   * getArgSpecialization; and because EQL is true only for objects of
652   * the same type, which guaranties that if a type-specialized
653   * methods was chached by eql-specialization, all the cache hits
654   * into this records will be from args of the conforming type).
655   *
656   * <p>Consider:
657   * <pre><tt>
658   * (defgeneric f (a b))
659   *
660   * (defmethod f (a (b (eql 'symbol)))
661   *   "T (EQL 'SYMBOL)")
662   *
663   * (defmethod f ((a symbol) (b (eql 'symbol)))
664   *   "SYMBOL (EQL 'SYMBOL)")
665   *
666   * (f 12 'symbol)
667   * => "T (EQL 'SYMBOL)"
668   *
669   * (f 'twelve 'symbol)
670   * => "SYMBOL (EQL 'SYMBOL)"
671   *
672   * (f 'symbol 'symbol)
673   * => "SYMBOL (EQL 'SYMBOL)"
674   *
675   * </tt></pre>
676   *
677   * After the two above calls <tt>cache</tt> will contain three keys:
678   * <pre>
679   * { class FIXNUM, EqlSpecialization('SYMBOL) }
680   * { class SYMBOL, EqlSpecialization('SYMBOL) }
681   * { EqlSpecialization('SYMBOL), EqlSpecialization('SYMBOL) }.
682   * </pre>
683   */     
684  LispObject getArgSpecialization(LispObject arg)
685  {
686    for (EqlSpecialization eqlSpecialization : eqlSpecializations)
687      {
688        if (eqlSpecialization.eqlTo.eql(arg))
689          return eqlSpecialization;
690      }
691    return arg.classOf();
692  }
693
694  private static final Primitive _GET_ARG_SPECIALIZATION
695    = new pf__get_arg_specialization();
696  @DocString(name="%get-arg-specialization",
697             args="generic-function arg")
698  private static final class pf__get_arg_specialization extends Primitive
699  {
700    pf__get_arg_specialization() 
701    {
702      super("%get-arg-specialization", PACKAGE_SYS, true, "generic-function arg");
703    }
704    @Override
705    public LispObject execute(LispObject first, LispObject second)
706    {
707      final StandardGenericFunction gf = checkStandardGenericFunction(first);
708      return gf.getArgSpecialization(second);
709    }
710  };
711
712  private static final Primitive CACHE_SLOT_LOCATION
713    = new pf_cache_slot_location(); 
714  @DocString(name="cache-slot-location",
715           args="generic-function layout location")
716  private static final class pf_cache_slot_location extends Primitive
717  {
718    pf_cache_slot_location()
719    {
720      super("cache-slot-location", PACKAGE_SYS, true, "generic-function layout location");
721    }
722    @Override
723    public LispObject execute(LispObject first, LispObject second,
724                                LispObject third)
725    {
726      final StandardGenericFunction gf = checkStandardGenericFunction(first);
727      LispObject layout = second;
728      LispObject location = third;
729      ConcurrentHashMap<LispObject,LispObject> ht = gf.slotCache;
730      if (ht == null)
731        ht = gf.slotCache = new ConcurrentHashMap<LispObject,LispObject>();
732      ht.put(layout, location);
733      return third;
734    }
735  };
736
737  private static final Primitive GET_CACHED_SLOT_LOCATION
738    = new pf_get_cached_slot_location();
739  @DocString(name="get-cached-slot-location")
740  private static final class pf_get_cached_slot_location extends Primitive
741  {
742    pf_get_cached_slot_location()
743    {
744      super("get-cached-slot-location", PACKAGE_SYS, true, "generic-function layout");
745    }
746    @Override
747    public LispObject execute(LispObject first, LispObject second)
748    {
749      final StandardGenericFunction gf = checkStandardGenericFunction(first);
750      LispObject layout = second;
751      ConcurrentHashMap<LispObject,LispObject> ht = gf.slotCache;
752      if (ht == null)
753        return NIL;
754      LispObject location = (LispObject) ht.get(layout);
755      return location != null ? location : NIL;
756    }
757  };
758
759  private static class CacheEntry
760  {
761    final LispObject[] array;
762
763    CacheEntry(LispObject[] array)
764    {
765      this.array = array;
766    }
767
768    @Override
769    public int hashCode()
770    {
771      int result = 0;
772      for (int i = array.length; i-- > 0;)
773        result ^= array[i].hashCode();
774      return result;
775    }
776
777    @Override
778    public boolean equals(Object object)
779    {
780      if (!(object instanceof CacheEntry))
781        return false;
782      final CacheEntry otherEntry = (CacheEntry) object;
783      if (otherEntry.array.length != array.length)
784        return false;
785      final LispObject[] otherArray = otherEntry.array;
786      for (int i = array.length; i-- > 0;)
787        if (array[i] != otherArray[i])
788          return false;
789      return true;
790    }
791  }
792
793  EqlSpecialization eqlSpecializations[] = new EqlSpecialization[0];
794
795  private static final Primitive _INIT_EQL_SPECIALIZATIONS 
796    = new pf__init_eql_specializations();
797  @DocString(name="%init-eql-specializations",
798             args="generic-function eql-specilizer-objects-list")
799  private static final class pf__init_eql_specializations extends Primitive
800  {
801    pf__init_eql_specializations()
802    {
803      super("%init-eql-specializations", PACKAGE_SYS, true, 
804            "generic-function eql-specilizer-objects-list");
805    }
806    @Override
807    public LispObject execute(LispObject first, LispObject second)
808    {
809      final StandardGenericFunction gf = checkStandardGenericFunction(first);
810      LispObject eqlSpecializerObjects = second;
811      gf.eqlSpecializations = new EqlSpecialization[eqlSpecializerObjects.length()];
812      for (int i = 0; i < gf.eqlSpecializations.length; i++) {
813        gf.eqlSpecializations[i] = new EqlSpecialization(eqlSpecializerObjects.car());
814        eqlSpecializerObjects = eqlSpecializerObjects.cdr();
815      }
816      return NIL;
817    }
818  };
819
820  private static class EqlSpecialization extends LispObject
821  {
822    public LispObject eqlTo;
823
824    public EqlSpecialization(LispObject eqlTo)
825    {
826        this.eqlTo = eqlTo;
827    }
828  }
829 
830  public static final StandardGenericFunction checkStandardGenericFunction(LispObject obj)
831  {
832    if (obj instanceof StandardGenericFunction)
833      return (StandardGenericFunction) obj;
834    return (StandardGenericFunction) // Not reached.
835      type_error(obj, Symbol.STANDARD_GENERIC_FUNCTION);
836  }
837}
Note: See TracBrowser for help on using the repository browser.