source: branches/0.15.x/abcl/src/org/armedbear/lisp/StandardObject.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: 16.3 KB
Line 
1/*
2 * StandardObject.java
3 *
4 * Copyright (C) 2003-2006 Peter Graves
5 * $Id: StandardObject.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
36public class StandardObject extends LispObject
37{
38  protected Layout layout;
39  protected LispObject[] slots;
40
41  protected StandardObject()
42  {
43    layout = new Layout(StandardClass.STANDARD_OBJECT, NIL, NIL);
44  }
45
46  protected StandardObject(LispClass cls, int length)
47  {
48    layout = cls.getClassLayout();
49    slots = new LispObject[length];
50    for (int i = slots.length; i-- > 0;)
51      slots[i] = UNBOUND_VALUE;
52  }
53
54  protected StandardObject(LispClass cls)
55  {
56    layout = cls.getClassLayout();
57    slots = new LispObject[layout.getLength()];
58    for (int i = slots.length; i-- > 0;)
59      slots[i] = UNBOUND_VALUE;
60  }
61
62  @Override
63  public LispObject getParts() throws ConditionThrowable
64  {
65    LispObject parts = NIL;
66    if (layout != null)
67      {
68        if (layout.isInvalid())
69          {
70            // Update instance.
71            layout = updateLayout();
72          }
73      }
74    parts = parts.push(new Cons("LAYOUT", layout));
75    if (layout != null)
76      {
77        LispObject[] slotNames = layout.getSlotNames();
78        if (slotNames != null)
79          {
80            for (int i = 0; i < slotNames.length; i++)
81              {
82                parts = parts.push(new Cons(slotNames[i], slots[i]));
83              }
84          }
85      }
86    return parts.nreverse();
87  }
88
89  public final LispClass getLispClass()
90  {
91    return layout.lispClass;
92  }
93
94  @Override
95  public LispObject typeOf()
96  {
97    // "For objects of metaclass STRUCTURE-CLASS or STANDARD-CLASS, and for
98    // conditions, TYPE-OF returns the proper name of the class returned by
99    // CLASS-OF if it has a proper name, and otherwise returns the class
100    // itself."
101    final LispClass c1 = layout.lispClass;
102    // The proper name of a class is "a symbol that names the class whose
103    // name is that symbol".
104    final Symbol symbol = c1.getSymbol();
105    if (symbol != NIL)
106      {
107        // TYPE-OF.9
108        final LispObject c2 = LispClass.findClass(symbol);
109        if (c2 == c1)
110          return symbol;
111      }
112    return c1;
113  }
114
115  @Override
116  public LispObject classOf()
117  {
118    return layout.lispClass;
119  }
120
121  @Override
122  public LispObject typep(LispObject type) throws ConditionThrowable
123  {
124    if (type == Symbol.STANDARD_OBJECT)
125      return T;
126    if (type == StandardClass.STANDARD_OBJECT)
127      return T;
128    LispClass cls = layout != null ? layout.lispClass : null;
129    if (cls != null)
130      {
131        if (type == cls)
132          return T;
133        if (type == cls.getSymbol())
134          return T;
135        LispObject cpl = cls.getCPL();
136        while (cpl != NIL)
137          {
138            if (type == cpl.car())
139              return T;
140            if (type == ((LispClass)cpl.car()).getSymbol())
141              return T;
142            cpl = cpl.cdr();
143          }
144      }
145    return super.typep(type);
146  }
147
148  @Override
149  public String writeToString() throws ConditionThrowable
150  {
151    final LispThread thread = LispThread.currentThread();
152    int maxLevel = Integer.MAX_VALUE;
153    LispObject printLevel = Symbol.PRINT_LEVEL.symbolValue(thread);
154    if (printLevel instanceof Fixnum)
155      maxLevel = ((Fixnum)printLevel).value;
156    LispObject currentPrintLevel =
157      _CURRENT_PRINT_LEVEL_.symbolValue(thread);
158    int currentLevel = Fixnum.getValue(currentPrintLevel);
159    if (currentLevel >= maxLevel)
160      return "#";
161    if (typep(Symbol.CONDITION) != NIL)
162      {
163        StringOutputStream stream = new StringOutputStream();
164        Symbol.PRINT_OBJECT.execute(this, stream);
165        return stream.getString().getStringValue();
166      }
167    return unreadableString(typeOf().writeToString());
168  }
169
170  private Layout updateLayout() throws ConditionThrowable
171  {
172    Debug.assertTrue(layout.isInvalid());
173    Layout oldLayout = layout;
174    LispClass cls = oldLayout.lispClass;
175    Layout newLayout = cls.getClassLayout();
176    Debug.assertTrue(!newLayout.isInvalid());
177    StandardObject newInstance = new StandardObject(cls);
178    Debug.assertTrue(newInstance.layout == newLayout);
179    LispObject added = NIL;
180    LispObject discarded = NIL;
181    LispObject plist = NIL;
182    // Old local slots.
183    LispObject[] oldSlotNames = oldLayout.getSlotNames();
184    for (int i = 0; i < oldSlotNames.length; i++)
185      {
186        LispObject slotName = oldSlotNames[i];
187        int j = newLayout.getSlotIndex(slotName);
188        if (j >= 0)
189          newInstance.slots[j] = slots[i];
190        else
191          {
192            discarded = discarded.push(slotName);
193            if (slots[i] != UNBOUND_VALUE)
194              {
195                plist = plist.push(slotName);
196                plist = plist.push(slots[i]);
197              }
198          }
199      }
200    // Old shared slots.
201    LispObject rest = oldLayout.getSharedSlots(); // A list.
202    if (rest != null)
203      {
204        while (rest != NIL)
205          {
206            LispObject location = rest.car();
207            LispObject slotName = location.car();
208            int i = newLayout.getSlotIndex(slotName);
209            if (i >= 0)
210              newInstance.slots[i] = location.cdr();
211            rest = rest.cdr();
212          }
213      }
214    // Go through all the new local slots to compute the added slots.
215    LispObject[] newSlotNames = newLayout.getSlotNames();
216    for (int i = 0; i < newSlotNames.length; i++)
217      {
218        LispObject slotName = newSlotNames[i];
219        int j = oldLayout.getSlotIndex(slotName);
220        if (j >= 0)
221          continue;
222        LispObject location = oldLayout.getSharedSlotLocation(slotName);
223        if (location != null)
224          continue;
225        // Not found.
226        added = added.push(slotName);
227      }
228    // Swap slots.
229    LispObject[] tempSlots = slots;
230    slots = newInstance.slots;
231    newInstance.slots = tempSlots;
232    // Swap layouts.
233    Layout tempLayout = layout;
234    layout = newInstance.layout;
235    newInstance.layout = tempLayout;
236    Debug.assertTrue(!layout.isInvalid());
237    // Call UPDATE-INSTANCE-FOR-REDEFINED-CLASS.
238    Symbol.UPDATE_INSTANCE_FOR_REDEFINED_CLASS.execute(this, added,
239                                                       discarded, plist);
240    return newLayout;
241  }
242
243  // Only handles instance slots (not shared slots).
244  public LispObject getInstanceSlotValue(LispObject slotName)
245    throws ConditionThrowable
246  {
247    Debug.assertTrue(layout != null);
248    if (layout.isInvalid())
249      {
250        // Update instance.
251        layout = updateLayout();
252      }
253    Debug.assertTrue(layout != null);
254    int index = layout.getSlotIndex(slotName);
255    Debug.assertTrue(index >= 0);
256    return slots[index];
257  }
258
259  // Only handles instance slots (not shared slots).
260  public void setInstanceSlotValue(LispObject slotName, LispObject newValue)
261    throws ConditionThrowable
262  {
263    Debug.assertTrue(layout != null);
264    if (layout.isInvalid())
265      {
266        // Update instance.
267        layout = updateLayout();
268      }
269    Debug.assertTrue(layout != null);
270    int index = layout.getSlotIndex(slotName);
271    Debug.assertTrue(index >= 0);
272    slots[index] = newValue;
273  }
274
275        final public static StandardObject checkStandardObject(LispObject first) throws ConditionThrowable
276        {
277                if (first instanceof StandardObject)
278                        return (StandardObject) first;
279                return (StandardObject) type_error(first, Symbol.STANDARD_OBJECT);
280        }
281       
282  // ### swap-slots instance-1 instance-2 => nil
283  private static final Primitive SWAP_SLOTS =
284    new Primitive("swap-slots", PACKAGE_SYS, true, "instance-1 instance-2")
285    {
286      @Override
287      public LispObject execute(LispObject first, LispObject second)
288        throws ConditionThrowable
289      {
290        final StandardObject obj1 = checkStandardObject(first);
291        final StandardObject obj2 = checkStandardObject(second);
292        LispObject[] temp = obj1.slots;
293        obj1.slots = obj2.slots;
294        obj2.slots = temp;
295        return NIL;
296      }
297    };
298
299  // ### std-instance-layout
300  private static final Primitive STD_INSTANCE_LAYOUT =
301    new Primitive("std-instance-layout", PACKAGE_SYS, true)
302    {
303      @Override
304      public LispObject execute(LispObject arg) throws ConditionThrowable
305      {
306        final StandardObject instance = checkStandardObject(arg);
307        Layout layout = instance.layout;
308        if (layout.isInvalid())
309          {
310            // Update instance.
311            layout = instance.updateLayout();
312          }
313        return layout;
314      }
315    };
316
317  // ### %set-std-instance-layout
318  private static final Primitive _SET_STD_INSTANCE_LAYOUT =
319    new Primitive("%set-std-instance-layout", PACKAGE_SYS, true)
320    {
321      @Override
322      public LispObject execute(LispObject first, LispObject second)
323        throws ConditionThrowable
324      {
325          checkStandardObject(first).layout = checkLayout(second);         
326          return second;
327      }
328    };
329
330  // ### std-instance-class
331  private static final Primitive STD_INSTANCE_CLASS =
332    new Primitive("std-instance-class", PACKAGE_SYS, true)
333    {
334      @Override
335      public LispObject execute(LispObject arg) throws ConditionThrowable
336      {
337          return checkStandardObject(arg).layout.lispClass;
338      }
339    };
340
341  // ### standard-instance-access instance location => value
342  private static final Primitive STANDARD_INSTANCE_ACCESS =
343    new Primitive("standard-instance-access", PACKAGE_SYS, true,
344                  "instance location")
345    {
346      @Override
347      public LispObject execute(LispObject first, LispObject second)
348        throws ConditionThrowable
349      {
350        final StandardObject instance = checkStandardObject(first);
351        final int index;
352        if (second instanceof Fixnum)
353          {
354            index = ((Fixnum)second).value;
355          }
356        else
357          {
358            return type_error(second,
359                                   list(Symbol.INTEGER, Fixnum.ZERO,
360                                         Fixnum.getInstance(instance.slots.length)));
361          }
362        LispObject value;
363        try
364          {
365            value = instance.slots[index];
366          }
367        catch (ArrayIndexOutOfBoundsException e)
368          {
369            return type_error(second,
370                                   list(Symbol.INTEGER, Fixnum.ZERO,
371                                         Fixnum.getInstance(instance.slots.length)));
372          }
373        if (value == UNBOUND_VALUE)
374          {
375            LispObject slotName = instance.layout.getSlotNames()[index];
376            value = Symbol.SLOT_UNBOUND.execute(instance.getLispClass(),
377                                                instance, slotName);
378            LispThread.currentThread()._values = null;
379          }
380        return value;
381      }
382    };
383
384  // ### %set-standard-instance-access instance location new-value => new-value
385  private static final Primitive _SET_STANDARD_INSTANCE_ACCESS =
386    new Primitive("%set-standard-instance-access", PACKAGE_SYS, true)
387    {
388      @Override
389      public LispObject execute(LispObject first, LispObject second,
390                                LispObject third)
391        throws ConditionThrowable
392      {
393          checkStandardObject(first).slots[Fixnum.getValue(second)] = third; // FIXME
394          return third;
395      }
396    };
397
398  // ### std-slot-boundp
399  private static final Primitive STD_SLOT_BOUNDP =
400    new Primitive(Symbol.STD_SLOT_BOUNDP, "instance slot-name")
401    {
402      @Override
403      public LispObject execute(LispObject first, LispObject second)
404        throws ConditionThrowable
405      {
406        final StandardObject instance = checkStandardObject(first);
407        Layout layout = instance.layout;
408        if (layout.isInvalid())
409          {
410            // Update instance.
411            layout = instance.updateLayout();
412          }
413        final LispObject index = layout.slotTable.get(second);
414        if (index != null)
415          {
416            // Found instance slot.
417            return instance.slots[((Fixnum)index).value] != UNBOUND_VALUE ? T : NIL;
418          }
419        // Check for shared slot.
420        final LispObject location = layout.getSharedSlotLocation(second);
421        if (location != null)
422          return location.cdr() != UNBOUND_VALUE ? T : NIL;
423        // Not found.
424        final LispThread thread = LispThread.currentThread();
425        LispObject value =
426          thread.execute(Symbol.SLOT_MISSING, instance.getLispClass(),
427                         instance, second, Symbol.SLOT_BOUNDP);
428        // "If SLOT-MISSING is invoked and returns a value, a boolean
429        // equivalent to its primary value is returned by SLOT-BOUNDP."
430        thread._values = null;
431        return value != NIL ? T : NIL;
432      }
433    };
434
435  @Override
436  public LispObject SLOT_VALUE(LispObject slotName) throws ConditionThrowable
437  {
438    if (layout.isInvalid())
439      {
440        // Update instance.
441        layout = updateLayout();
442      }
443    LispObject value;
444    final LispObject index = layout.slotTable.get(slotName);
445    if (index != null)
446      {
447        // Found instance slot.
448        value = slots[((Fixnum)index).value];
449      }
450    else
451      {
452        // Check for shared slot.
453        LispObject location = layout.getSharedSlotLocation(slotName);
454        if (location == null)
455          return Symbol.SLOT_MISSING.execute(getLispClass(), this, slotName,
456                                             Symbol.SLOT_VALUE);
457        value = location.cdr();
458      }
459    if (value == UNBOUND_VALUE)
460      {
461        value = Symbol.SLOT_UNBOUND.execute(getLispClass(), this, slotName);
462        LispThread.currentThread()._values = null;
463      }
464    return value;
465  }
466
467  // ### std-slot-value
468  private static final Primitive STD_SLOT_VALUE =
469    new Primitive(Symbol.STD_SLOT_VALUE, "instance slot-name")
470    {
471      @Override
472      public LispObject execute(LispObject first, LispObject second)
473        throws ConditionThrowable
474      {
475        return first.SLOT_VALUE(second);
476      }
477    };
478
479  @Override
480  public void setSlotValue(LispObject slotName, LispObject newValue)
481    throws ConditionThrowable
482  {
483    if (layout.isInvalid())
484      {
485        // Update instance.
486        layout = updateLayout();
487      }
488    final LispObject index = layout.slotTable.get(slotName);
489    if (index != null)
490      {
491        // Found instance slot.
492        slots[((Fixnum)index).value] = newValue;
493        return;
494      }
495    // Check for shared slot.
496    LispObject location = layout.getSharedSlotLocation(slotName);
497    if (location != null)
498      {
499        location.setCdr(newValue);
500        return;
501      }
502    LispObject[] args = new LispObject[5];
503    args[0] = getLispClass();
504    args[1] = this;
505    args[2] = slotName;
506    args[3] = Symbol.SETF;
507    args[4] = newValue;
508    Symbol.SLOT_MISSING.execute(args);
509  }
510
511  // ### set-std-slot-value
512  private static final Primitive SET_STD_SLOT_VALUE =
513    new Primitive(Symbol.SET_STD_SLOT_VALUE, "instance slot-name new-value")
514    {
515      @Override
516      public LispObject execute(LispObject first, LispObject second,
517                                LispObject third)
518        throws ConditionThrowable
519      {
520        first.setSlotValue(second, third);
521        return third;
522      }
523    };
524}
Note: See TracBrowser for help on using the repository browser.