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

Last change on this file was 11754, checked in by vvoutilainen, 16 years ago

Convert using ClassCastException? to checking instanceof.
Performance tests show this approach to be faster.
Patch by Douglas R. Miles. I modified the patch to
remove tabs, so indentation may be slightly off in places.
That's something that we need to handle separately, abcl
doesn't have a clear indentation policy.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 22.6 KB
Line 
1/*
2 * StandardGenericFunction.java
3 *
4 * Copyright (C) 2003-2006 Peter Graves
5 * $Id: StandardGenericFunction.java 11754 2009-04-12 10:53:39Z vvoutilainen $
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 java.util.HashMap;
37
38public final class StandardGenericFunction extends StandardObject
39{
40  private LispObject function;
41
42  private int numberOfRequiredArgs;
43
44  private HashMap<CacheEntry,LispObject> cache;
45  private HashMap<LispObject,LispObject> slotCache;
46
47  public StandardGenericFunction()
48  {
49    super(StandardClass.STANDARD_GENERIC_FUNCTION,
50          StandardClass.STANDARD_GENERIC_FUNCTION.getClassLayout().getLength());
51  }
52
53  public StandardGenericFunction(String name, Package pkg, boolean exported,
54                                 Function function, LispObject lambdaList,
55                                 LispObject specializers)
56  {
57    this();
58    try
59      {
60        Symbol symbol;
61        if (exported)
62          symbol = pkg.internAndExport(name.toUpperCase());
63        else
64          symbol = pkg.intern(name.toUpperCase());
65        symbol.setSymbolFunction(this);
66        this.function = function;
67        slots[StandardGenericFunctionClass.SLOT_INDEX_NAME] = symbol;
68        slots[StandardGenericFunctionClass.SLOT_INDEX_LAMBDA_LIST] =
69          lambdaList;
70        slots[StandardGenericFunctionClass.SLOT_INDEX_REQUIRED_ARGS] =
71          lambdaList;
72        numberOfRequiredArgs = lambdaList.length();
73        slots[StandardGenericFunctionClass.SLOT_INDEX_INITIAL_METHODS] =
74          NIL;
75        StandardMethod method =
76          new StandardMethod(this, function, lambdaList, specializers);
77        slots[StandardGenericFunctionClass.SLOT_INDEX_METHODS] =
78          list(method);
79        slots[StandardGenericFunctionClass.SLOT_INDEX_METHOD_CLASS] =
80          StandardClass.STANDARD_METHOD;
81        slots[StandardGenericFunctionClass.SLOT_INDEX_METHOD_COMBINATION] =
82          Symbol.STANDARD;
83        slots[StandardGenericFunctionClass.SLOT_INDEX_ARGUMENT_PRECEDENCE_ORDER] =
84          NIL;
85        slots[StandardGenericFunctionClass.SLOT_INDEX_CLASSES_TO_EMF_TABLE] =
86          NIL;
87        slots[StandardGenericFunctionClass.SLOT_INDEX_DOCUMENTATION] = NIL;
88      }
89    catch (ConditionThrowable t)
90      {
91        Debug.assertTrue(false);
92      }
93  }
94
95  private void finalizeInternal()
96  {
97    cache = null;
98  }
99
100  @Override
101  public LispObject typep(LispObject type) throws ConditionThrowable
102  {
103    if (type == Symbol.COMPILED_FUNCTION)
104      {
105        if (function != null)
106          return function.typep(type);
107        else
108          return NIL;
109      }
110    if (type == Symbol.STANDARD_GENERIC_FUNCTION)
111      return T;
112    if (type == StandardClass.STANDARD_GENERIC_FUNCTION)
113      return T;
114    return super.typep(type);
115  }
116
117  public LispObject getGenericFunctionName()
118  {
119    return slots[StandardGenericFunctionClass.SLOT_INDEX_NAME];
120  }
121
122  public void setGenericFunctionName(LispObject name)
123  {
124    slots[StandardGenericFunctionClass.SLOT_INDEX_NAME] = name;
125  }
126
127  @Override
128  public LispObject execute() throws ConditionThrowable
129  {
130    return function.execute();
131  }
132
133  @Override
134  public LispObject execute(LispObject arg) throws ConditionThrowable
135  {
136    return function.execute(arg);
137  }
138
139  @Override
140  public LispObject execute(LispObject first, LispObject second)
141    throws ConditionThrowable
142  {
143    return function.execute(first, second);
144  }
145
146  @Override
147  public LispObject execute(LispObject first, LispObject second,
148                            LispObject third)
149    throws ConditionThrowable
150  {
151    return function.execute(first, second, third);
152  }
153
154  @Override
155  public LispObject execute(LispObject first, LispObject second,
156                            LispObject third, LispObject fourth)
157    throws ConditionThrowable
158  {
159    return function.execute(first, second, third, fourth);
160  }
161
162  @Override
163  public LispObject execute(LispObject first, LispObject second,
164                            LispObject third, LispObject fourth,
165                            LispObject fifth)
166    throws ConditionThrowable
167  {
168    return function.execute(first, second, third, fourth,
169                            fifth);
170  }
171
172  @Override
173  public LispObject execute(LispObject first, LispObject second,
174                            LispObject third, LispObject fourth,
175                            LispObject fifth, LispObject sixth)
176    throws ConditionThrowable
177  {
178    return function.execute(first, second, third, fourth,
179                            fifth, sixth);
180  }
181
182  @Override
183  public LispObject execute(LispObject first, LispObject second,
184                            LispObject third, LispObject fourth,
185                            LispObject fifth, LispObject sixth,
186                            LispObject seventh)
187    throws ConditionThrowable
188  {
189    return function.execute(first, second, third, fourth,
190                            fifth, sixth, seventh);
191  }
192
193  @Override
194  public LispObject execute(LispObject first, LispObject second,
195                            LispObject third, LispObject fourth,
196                            LispObject fifth, LispObject sixth,
197                            LispObject seventh, LispObject eighth)
198    throws ConditionThrowable
199  {
200    return function.execute(first, second, third, fourth,
201                            fifth, sixth, seventh, eighth);
202  }
203
204  @Override
205  public LispObject execute(LispObject[] args) throws ConditionThrowable
206  {
207    return function.execute(args);
208  }
209
210  @Override
211  public String writeToString() throws ConditionThrowable
212  {
213    LispObject name = getGenericFunctionName();
214    if (name != null)
215      {
216        FastStringBuffer sb = new FastStringBuffer();
217        sb.append(getLispClass().getSymbol().writeToString());
218        sb.append(' ');
219        sb.append(name.writeToString());
220        return unreadableString(sb.toString());
221      }
222    return super.writeToString();
223  }
224
225  // Profiling.
226  private int callCount;
227
228  @Override
229  public final int getCallCount()
230  {
231    return callCount;
232  }
233
234  @Override
235  public void setCallCount(int n)
236  {
237    callCount = n;
238  }
239
240  @Override
241  public final void incrementCallCount()
242  {
243    ++callCount;
244  }
245
246  // AMOP (p. 216) specifies the following readers as generic functions:
247  //   generic-function-argument-precedence-order
248  //   generic-function-declarations
249  //   generic-function-lambda-list
250  //   generic-function-method-class
251  //   generic-function-method-combination
252  //   generic-function-methods
253  //   generic-function-name
254
255  // ### %generic-function-name
256  private static final Primitive _GENERIC_FUNCTION_NAME =
257    new Primitive("%generic-function-name", PACKAGE_SYS, true)
258    {
259      @Override
260      public LispObject execute(LispObject arg) throws ConditionThrowable
261      {
262          return checkStandardGenericFunction(arg).slots[StandardGenericFunctionClass.SLOT_INDEX_NAME];
263      }
264    };
265
266  // ### %set-generic-function-name
267  private static final Primitive _SET_GENERIC_FUNCTION_NAME =
268    new Primitive("%set-generic-function-name", PACKAGE_SYS, true)
269    {
270      @Override
271      public LispObject execute(LispObject first, LispObject second)
272        throws ConditionThrowable
273      {
274          checkStandardGenericFunction(first).slots[StandardGenericFunctionClass.SLOT_INDEX_NAME] = second;
275          return second;
276      }
277    };
278
279  // ### %generic-function-lambda-list
280  private static final Primitive _GENERIC_FUNCTION_LAMBDA_LIST =
281    new Primitive("%generic-function-lambda-list", PACKAGE_SYS, true)
282    {
283      @Override
284      public LispObject execute(LispObject arg) throws ConditionThrowable
285      {
286          return checkStandardGenericFunction(arg).slots[StandardGenericFunctionClass.SLOT_INDEX_LAMBDA_LIST];
287      }
288    };
289
290  // ### %set-generic-function-lambdaList
291  private static final Primitive _SET_GENERIC_FUNCTION_LAMBDA_LIST =
292    new Primitive("%set-generic-function-lambda-list", PACKAGE_SYS, true)
293    {
294      @Override
295      public LispObject execute(LispObject first, LispObject second)
296        throws ConditionThrowable
297      {
298          checkStandardGenericFunction(first).slots[StandardGenericFunctionClass.SLOT_INDEX_LAMBDA_LIST] = second;
299          return second;
300      }
301    };
302
303  // ### funcallable-instance-function funcallable-instance => function
304  private static final Primitive FUNCALLABLE_INSTANCE_FUNCTION =
305    new Primitive("funcallable-instance-function", PACKAGE_MOP, false,
306                  "funcallable-instance")
307    {
308      @Override
309      public LispObject execute(LispObject arg)
310        throws ConditionThrowable
311      {
312          return checkStandardGenericFunction(arg).function;
313      }
314    };
315
316  // ### set-funcallable-instance-function funcallable-instance function => unspecified
317  // AMOP p. 230
318  private static final Primitive SET_FUNCALLABLE_INSTANCE_FUNCTION =
319    new Primitive("set-funcallable-instance-function", PACKAGE_MOP, true,
320                  "funcallable-instance function")
321    {
322      @Override
323      public LispObject execute(LispObject first, LispObject second)
324        throws ConditionThrowable
325      {
326          checkStandardGenericFunction(first).function = second;
327          return second;
328      }
329    };
330
331  // ### gf-required-args
332  private static final Primitive GF_REQUIRED_ARGS =
333    new Primitive("gf-required-args", PACKAGE_SYS, true)
334    {
335      @Override
336      public LispObject execute(LispObject arg) throws ConditionThrowable
337      {
338          return checkStandardGenericFunction(arg).slots[StandardGenericFunctionClass.SLOT_INDEX_REQUIRED_ARGS];
339      }
340    };
341
342  // ### %set-gf-required-args
343  private static final Primitive _SET_GF_REQUIRED_ARGS =
344    new Primitive("%set-gf-required-args", PACKAGE_SYS, true)
345    {
346      @Override
347      public LispObject execute(LispObject first, LispObject second)
348        throws ConditionThrowable
349      {
350        final StandardGenericFunction gf = checkStandardGenericFunction(first);
351        gf.slots[StandardGenericFunctionClass.SLOT_INDEX_REQUIRED_ARGS] = second;
352        gf.numberOfRequiredArgs = second.length();
353        return second;
354      }
355    };
356
357  // ### generic-function-initial-methods
358  private static final Primitive GENERIC_FUNCTION_INITIAL_METHODS =
359    new Primitive("generic-function-initial-methods", PACKAGE_SYS, true)
360    {
361      @Override
362      public LispObject execute(LispObject arg) throws ConditionThrowable
363      {
364          return checkStandardGenericFunction(arg).slots[StandardGenericFunctionClass.SLOT_INDEX_INITIAL_METHODS];
365      }
366    };
367
368  // ### set-generic-function-initial-methods
369  private static final Primitive SET_GENERIC_FUNCTION_INITIAL_METHODS =
370    new Primitive("set-generic-function-initial-methods", PACKAGE_SYS, true)
371    {
372      @Override
373      public LispObject execute(LispObject first, LispObject second)
374        throws ConditionThrowable
375      {
376          checkStandardGenericFunction(first).slots[StandardGenericFunctionClass.SLOT_INDEX_INITIAL_METHODS] = second;
377          return second;
378      }
379    };
380
381  // ### generic-function-methods
382  private static final Primitive GENERIC_FUNCTION_METHODS =
383    new Primitive("generic-function-methods", PACKAGE_SYS, true)
384    {
385      @Override
386      public LispObject execute(LispObject arg) throws ConditionThrowable
387      {
388          return checkStandardGenericFunction(arg).slots[StandardGenericFunctionClass.SLOT_INDEX_METHODS];
389      }
390    };
391
392  // ### set-generic-function-methods
393  private static final Primitive SET_GENERIC_FUNCTION_METHODS =
394    new Primitive("set-generic-function-methods", PACKAGE_SYS, true)
395    {
396      @Override
397      public LispObject execute(LispObject first, LispObject second)
398        throws ConditionThrowable
399      {
400          checkStandardGenericFunction(first).slots[StandardGenericFunctionClass.SLOT_INDEX_METHODS] = second;
401          return second;
402      }
403    };
404
405  // ### generic-function-method-class
406  private static final Primitive GENERIC_FUNCTION_METHOD_CLASS =
407    new Primitive("generic-function-method-class", PACKAGE_SYS, true)
408    {
409      @Override
410      public LispObject execute(LispObject arg) throws ConditionThrowable
411      {
412          return checkStandardGenericFunction(arg).slots[StandardGenericFunctionClass.SLOT_INDEX_METHOD_CLASS];
413      }
414    };
415
416  // ### set-generic-function-method-class
417  private static final Primitive SET_GENERIC_FUNCTION_METHOD_CLASS =
418    new Primitive("set-generic-function-method-class", PACKAGE_SYS, true)
419    {
420      @Override
421      public LispObject execute(LispObject first, LispObject second)
422        throws ConditionThrowable
423      {
424          checkStandardGenericFunction(first).slots[StandardGenericFunctionClass.SLOT_INDEX_METHOD_CLASS] = second;
425          return second;
426      }
427    };
428
429  // ### generic-function-method-combination
430  private static final Primitive GENERIC_FUNCTION_METHOD_COMBINATION =
431    new Primitive("generic-function-method-combination", PACKAGE_SYS, true)
432    {
433      @Override
434      public LispObject execute(LispObject arg) throws ConditionThrowable
435      {
436          return checkStandardGenericFunction(arg).slots[StandardGenericFunctionClass.SLOT_INDEX_METHOD_COMBINATION];
437      }
438    };
439
440  // ### set-generic-function-method-combination
441  private static final Primitive SET_GENERIC_FUNCTION_METHOD_COMBINATION =
442    new Primitive("set-generic-function-method-combination", PACKAGE_SYS, true)
443    {
444      @Override
445      public LispObject execute(LispObject first, LispObject second)
446        throws ConditionThrowable
447      {
448          checkStandardGenericFunction(first).slots[StandardGenericFunctionClass.SLOT_INDEX_METHOD_COMBINATION] = second;
449          return second;
450      }
451    };
452
453  // ### generic-function-argument-precedence-order
454  private static final Primitive GENERIC_FUNCTION_ARGUMENT_PRECEDENCE_ORDER =
455    new Primitive("generic-function-argument-precedence-order", PACKAGE_SYS, true)
456    {
457      @Override
458      public LispObject execute(LispObject arg) throws ConditionThrowable
459      {
460          return checkStandardGenericFunction(arg).slots[StandardGenericFunctionClass.SLOT_INDEX_ARGUMENT_PRECEDENCE_ORDER];
461      }
462    };
463
464  // ### set-generic-function-argument-precedence-order
465  private static final Primitive SET_GENERIC_FUNCTION_ARGUMENT_PRECEDENCE_ORDER =
466    new Primitive("set-generic-function-argument-precedence-order", PACKAGE_SYS, true)
467    {
468      @Override
469      public LispObject execute(LispObject first, LispObject second)
470        throws ConditionThrowable
471      {
472          checkStandardGenericFunction(first).slots[StandardGenericFunctionClass.SLOT_INDEX_ARGUMENT_PRECEDENCE_ORDER] = second;
473          return second;
474      }
475    };
476
477  // ### generic-function-classes-to-emf-table
478  private static final Primitive GENERIC_FUNCTION_CLASSES_TO_EMF_TABLE =
479    new Primitive("generic-function-classes-to-emf-table", PACKAGE_SYS, true)
480    {
481      @Override
482      public LispObject execute(LispObject arg) throws ConditionThrowable
483      {
484          return checkStandardGenericFunction(arg).slots[StandardGenericFunctionClass.SLOT_INDEX_CLASSES_TO_EMF_TABLE];
485      }
486    };
487
488  // ### set-generic-function-classes-to-emf-table
489  private static final Primitive SET_GENERIC_FUNCTION_CLASSES_TO_EMF_TABLE =
490    new Primitive("set-generic-function-classes-to-emf-table", PACKAGE_SYS, true)
491    {
492      @Override
493      public LispObject execute(LispObject first, LispObject second)
494        throws ConditionThrowable
495      {
496          checkStandardGenericFunction(first).slots[StandardGenericFunctionClass.SLOT_INDEX_CLASSES_TO_EMF_TABLE] = second;
497          return second;
498      }
499    };
500
501  // ### generic-function-documentation
502  private static final Primitive GENERIC_FUNCTION_DOCUMENTATION =
503    new Primitive("generic-function-documentation", PACKAGE_SYS, true)
504    {
505      @Override
506      public LispObject execute(LispObject arg) throws ConditionThrowable
507      {
508          return checkStandardGenericFunction(arg).slots[StandardGenericFunctionClass.SLOT_INDEX_DOCUMENTATION];
509      }
510    };
511
512  // ### set-generic-function-documentation
513  private static final Primitive SET_GENERIC_FUNCTION_DOCUMENTATION =
514    new Primitive("set-generic-function-documentation", PACKAGE_SYS, true)
515    {
516      @Override
517      public LispObject execute(LispObject first, LispObject second)
518        throws ConditionThrowable
519      {
520          checkStandardGenericFunction(first).slots[StandardGenericFunctionClass.SLOT_INDEX_DOCUMENTATION] = second;
521          return second;
522      }
523    };
524
525  // ### %finalize-generic-function
526  private static final Primitive _FINALIZE_GENERIC_FUNCTION =
527    new Primitive("%finalize-generic-function", PACKAGE_SYS, true,
528                  "generic-function")
529    {
530      @Override
531      public LispObject execute(LispObject arg) throws ConditionThrowable
532      {
533          final StandardGenericFunction gf = checkStandardGenericFunction(arg);
534          gf.finalizeInternal();       
535          return T;
536      }
537    };
538
539  // ### cache-emf
540  private static final Primitive CACHE_EMF =
541    new Primitive("cache-emf", PACKAGE_SYS, true, "generic-function args emf")
542    {
543      @Override
544      public LispObject execute(LispObject first, LispObject second,
545                                LispObject third)
546        throws ConditionThrowable
547      {
548        final StandardGenericFunction gf = checkStandardGenericFunction(first);
549        LispObject args = second;
550        LispObject[] array = new LispObject[gf.numberOfRequiredArgs];
551        for (int i = gf.numberOfRequiredArgs; i-- > 0;)
552          {
553            array[i] = args.car().classOf();
554            args = args.cdr();
555          }
556        CacheEntry classes = new CacheEntry(array);
557        HashMap<CacheEntry,LispObject> ht = gf.cache;
558        if (ht == null)
559            ht = gf.cache = new HashMap<CacheEntry,LispObject>();
560        ht.put(classes, third);
561        return third;
562      }
563    };
564
565  // ### get-cached-emf
566  private static final Primitive GET_CACHED_EMF =
567    new Primitive("get-cached-emf", PACKAGE_SYS, true, "generic-function args")
568    {
569      @Override
570      public LispObject execute(LispObject first, LispObject second)
571        throws ConditionThrowable
572      {
573        final StandardGenericFunction gf = checkStandardGenericFunction(first);
574        LispObject args = second;
575        LispObject[] array = new LispObject[gf.numberOfRequiredArgs];
576        for (int i = gf.numberOfRequiredArgs; i-- > 0;)
577          {
578            array[i] = args.car().classOf();
579            args = args.cdr();
580          }
581        CacheEntry classes = new CacheEntry(array);
582        HashMap<CacheEntry,LispObject> ht = gf.cache;
583        if (ht == null)
584          return NIL;
585        LispObject emf = (LispObject) ht.get(classes);
586        return emf != null ? emf : NIL;
587      }
588    };
589
590  // ### cache-slot-location
591  private static final Primitive CACHE_SLOT_LOCATION =
592    new Primitive("cache-slot-location", PACKAGE_SYS, true, "generic-function layout location")
593    {
594      @Override
595      public LispObject execute(LispObject first, LispObject second,
596                                LispObject third)
597        throws ConditionThrowable
598      {
599        final StandardGenericFunction gf = checkStandardGenericFunction(first);
600        LispObject layout = second;
601        LispObject location = third;
602        HashMap<LispObject,LispObject> ht = gf.slotCache;
603        if (ht == null)
604          ht = gf.slotCache = new HashMap<LispObject,LispObject>();
605        ht.put(layout, location);
606        return third;
607      }
608    };
609
610  // ### get-cached-slot-location
611  private static final Primitive GET_CACHED_SLOT_LOCATION =
612    new Primitive("get-cached-slot-location", PACKAGE_SYS, true, "generic-function layout")
613    {
614      @Override
615      public LispObject execute(LispObject first, LispObject second)
616        throws ConditionThrowable
617      {
618        final StandardGenericFunction gf = checkStandardGenericFunction(first);
619        LispObject layout = second;
620        HashMap<LispObject,LispObject> ht = gf.slotCache;
621        if (ht == null)
622          return NIL;
623        LispObject location = (LispObject) ht.get(layout);
624        return location != null ? location : NIL;
625      }
626    };
627
628  private static final StandardGenericFunction GENERIC_FUNCTION_NAME =
629    new StandardGenericFunction("generic-function-name",
630                                PACKAGE_MOP,
631                                true,
632                                _GENERIC_FUNCTION_NAME,
633                                list(Symbol.GENERIC_FUNCTION),
634                                list(StandardClass.STANDARD_GENERIC_FUNCTION));
635
636  private static class CacheEntry
637  {
638    final LispObject[] array;
639
640    CacheEntry(LispObject[] array)
641    {
642      this.array = array;
643    }
644
645    @Override
646    public int hashCode()
647    {
648      int result = 0;
649      for (int i = array.length; i-- > 0;)
650        result ^= array[i].hashCode();
651      return result;
652    }
653
654    @Override
655    public boolean equals(Object object)
656    {
657      if (!(object instanceof CacheEntry))
658        return false;
659      final CacheEntry otherEntry = (CacheEntry) object;
660      if (otherEntry.array.length != array.length)
661        return false;
662      final LispObject[] otherArray = otherEntry.array;
663      for (int i = array.length; i-- > 0;)
664        if (array[i] != otherArray[i])
665          return false;
666      return true;
667    }
668  }
669 
670  public static final StandardGenericFunction checkStandardGenericFunction(LispObject obj)
671  throws ConditionThrowable
672  {
673                if (obj instanceof StandardGenericFunction)
674                        return (StandardGenericFunction) obj;
675                return (StandardGenericFunction) // Not reached.
676                type_error(obj, Symbol.STANDARD_GENERIC_FUNCTION);
677        }
678}
Note: See TracBrowser for help on using the repository browser.