source: branches/0.22.x/abcl/src/org/armedbear/lisp/AutoloadedFunctionProxy.java

Last change on this file was 12650, checked in by ehuelsmann, 15 years ago

Fix #79: Equally named -but different- uninterned symbols coalesced into
one in FASLs.

This commit removes the *FASL-ANONYMOUS-PACKAGE*: it's replaced by
*FASL-UNINTERNED-SYMBOLS* and a dispatch macro function which resolves
symbols by index instead of by name.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 11.0 KB
Line 
1/*
2 * AutoloadedFunctionProxy.java
3 *
4 * Copyright (C) 2009 Erik Huelsmann
5 * $Id: AutoloadedFunctionProxy.java 12650 2010-05-02 19:58:56Z ehuelsmann $
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.*;
37import java.util.Hashtable;
38
39public class AutoloadedFunctionProxy extends Function {
40
41    public enum FunctionType
42    {
43        NORMAL, SETF, MACRO
44    };
45
46    /** List of symbols that need to be saved upon instantiation of a
47     * proxy and restored while loading the actual function.
48     */
49    final static Symbol[] symsToSave =
50        new Symbol[]
51        {
52            AUTOLOADING_CACHE, // allow loading local preloaded functions
53            Load._FASL_UNINTERNED_SYMBOLS_, // vector of uninterned symbols
54            Symbol._PACKAGE_,              // current package
55            Symbol.LOAD_TRUENAME           // LOAD-TIME-VALUE depends on this
56        };
57
58    final private Symbol symbol;
59    final private String name;
60    final private LispObject cache;
61    final private LispObject[] savedSyms;
62    final private FunctionType fType;
63    Function fun = null;
64
65    public AutoloadedFunctionProxy(Symbol symbol, LispObject name,
66                                   LispObject cache,
67                                   LispObject[] savedSyms,
68                                   FunctionType ft) {
69        super();
70        this.symbol = symbol;
71        this.name = name.getStringValue();
72        this.cache = cache;
73        this.savedSyms = savedSyms;
74        Debug.assertTrue(! (cache instanceof Nil));
75        this.fType = ft;
76    }
77
78    /** Resolve this instance by returning the function we're proxy for */
79    @Override
80    public LispObject resolve() {
81        return load();
82    }
83
84
85    final private synchronized Function load() {
86        if (fun != null)
87            return fun;
88
89        LispThread thread = LispThread.currentThread();
90        SpecialBindingsMark mark = thread.markSpecialBindings();
91
92        for (int i = 0; i < symsToSave.length; i++)
93            thread.bindSpecial(symsToSave[i], savedSyms[i]);
94
95        // set a specific reader environment, because we may be triggered in
96        // any undefined dynamic environment; we want something predictable
97        thread.bindSpecial(Symbol.READ_SUPPRESS, NIL);
98        thread.bindSpecial(Symbol.READ_EVAL, T);
99        thread.bindSpecial(Symbol.READ_BASE, LispInteger.getInstance(10));
100        // don't need to bind *READ-DEFAULT-FLOAT-FORMAT*,
101        // because DUMP-FORM sets it to NIL, forcing exponent markers everywhere
102
103        byte[] classbytes =
104            (byte[])((Hashtable)cache.javaInstance()).get(name);
105        try {
106            fun = loadClassBytes(classbytes);
107        }
108        catch (Throwable t) {
109            Debug.trace(t);
110        } // ### fixme
111        finally {
112            thread.resetSpecialBindings(mark);
113        }
114
115        if (symbol != null)
116            installFunction(fType, symbol, fun);
117
118        return fun;
119    }
120
121    final static private void installFunction(FunctionType fType,
122                                              Symbol sym, Function fun) {
123
124        if (fType == FunctionType.SETF)
125            put(sym, Symbol.SETF_FUNCTION, fun);
126        else if (fType == FunctionType.MACRO) {
127            if (sym.getSymbolFunction() instanceof SpecialOperator)
128                put(sym, Symbol.MACROEXPAND_MACRO,
129                    new MacroObject(sym, fun));
130            else
131                sym.setSymbolFunction(new MacroObject(sym, fun));
132        } else
133            sym.setSymbolFunction(fun);
134    }
135
136    @Override
137    public LispObject execute()
138    {
139        return load().execute();
140    }
141
142    @Override
143    public LispObject execute(LispObject arg)
144    {
145        return load().execute(arg);
146    }
147
148    @Override
149    public LispObject execute(LispObject first, LispObject second)
150
151    {
152        return load().execute(first, second);
153    }
154
155    @Override
156    public LispObject execute(LispObject first, LispObject second,
157                              LispObject third)
158
159    {
160        return load().execute(first, second, third);
161    }
162
163    @Override
164    public LispObject execute(LispObject first, LispObject second,
165                              LispObject third, LispObject fourth)
166
167    {
168        return load().execute(first, second, third, fourth);
169    }
170
171    @Override
172    public LispObject execute(LispObject first, LispObject second,
173                              LispObject third, LispObject fourth,
174                              LispObject fifth)
175
176    {
177        return load().execute(first, second, third, fourth, fifth);
178    }
179
180    @Override
181    public LispObject execute(LispObject first, LispObject second,
182                              LispObject third, LispObject fourth,
183                              LispObject fifth, LispObject sixth)
184
185    {
186        return load().execute(first, second, third, fourth, fifth, sixth);
187    }
188
189    @Override
190    public LispObject execute(LispObject first, LispObject second,
191                              LispObject third, LispObject fourth,
192                              LispObject fifth, LispObject sixth,
193                              LispObject seventh)
194
195    {
196        return load().execute(first, second, third, fourth, fifth, sixth,
197                              seventh);
198    }
199
200    @Override
201    public LispObject execute(LispObject first, LispObject second,
202                              LispObject third, LispObject fourth,
203                              LispObject fifth, LispObject sixth,
204                              LispObject seventh, LispObject eighth)
205
206    {
207        return load().execute(first, second, third, fourth, fifth, sixth,
208                              seventh, eighth);
209    }
210
211    @Override
212    public LispObject execute(LispObject[] args)
213    {
214        return load().execute(args);
215    }
216
217    @SuppressWarnings("unchecked")
218    final public static LispObject loadPreloadedFunction(String name) {
219      LispThread thread = LispThread.currentThread();
220      LispObject value = AUTOLOADING_CACHE.symbolValue(thread);
221
222      if (value instanceof Nil) {
223          byte[] bytes = readFunctionBytes(new Pathname(name));
224          return (bytes == null) ? null : loadClassBytes(bytes);
225      }
226
227      Hashtable cache = (Hashtable)value.javaInstance();
228      byte[] bytes = (byte[])cache.get(name);
229      if (bytes == null)
230          return error(new LispError("Function '" + name + "' not preloaded" +
231                                     " while preloading requested."));
232      try {
233        return loadClassBytes(bytes);
234      }
235      catch (VerifyError e)
236      {
237        return error(new LispError("Class verification failed: " +
238                                   e.getMessage()));
239      }
240      catch (Throwable t)
241      {
242        Debug.trace(t);
243      }
244      return error(new FileError("Can't read file off stream."));
245    }
246
247    final static LispObject makePreloadingContext() {
248        return new JavaObject(new Hashtable());
249    }
250
251    // ### proxy-preloaded-function symbol name => function
252    final private static Primitive PROXY_PRELOADED_FUNCTION = new proxy_preloaded_function();
253    final private static class proxy_preloaded_function extends Primitive {
254        proxy_preloaded_function() {
255            super("proxy-preloaded-function", PACKAGE_SYS, false,
256                  "symbol name");
257        }
258        @Override
259        final public LispObject execute(LispObject symbol, LispObject name) {
260            LispThread thread = LispThread.currentThread();
261            Symbol sym;
262            Function fun;
263            FunctionType fType = FunctionType.NORMAL;
264
265            if (symbol instanceof Symbol)
266                sym = (Symbol)symbol;
267            else if (isValidSetfFunctionName(symbol)) {
268                sym = (Symbol)symbol.cadr();
269                fType = FunctionType.SETF;
270            } else if (isValidMacroFunctionName(symbol)) {
271                sym = (Symbol)symbol.cadr();
272                fType = FunctionType.MACRO;
273            } else {
274                checkSymbol(symbol); // generate an error
275                return null; // not reached
276            }
277
278            LispObject cache = AUTOLOADING_CACHE.symbolValue(thread);
279            if (cache instanceof Nil)
280                // during EVAL-WHEN :compile-toplevel, this function will
281                // be called without a caching environment; we'll need to
282                // forward to the compiled function loader
283                return loadCompiledFunction(name.getStringValue());
284            else {
285                LispObject[] cachedSyms = new LispObject[symsToSave.length];
286                for (int i = 0; i < symsToSave.length; i++)
287                    cachedSyms[i] = symsToSave[i].symbolValue(thread);
288
289                fun = new AutoloadedFunctionProxy(sym, name, cache,
290                                                  cachedSyms, fType);
291                fun.setClassBytes((byte[])((Hashtable)cache.javaInstance())
292                                  .get(name.getStringValue()));
293            }
294            return fun;
295        }
296    }
297
298    //  ### function-preload name => success
299    final private static Primitive FUNCTION_PRELOAD = new function_preload();
300    private static class function_preload extends Primitive {
301        function_preload() {
302            super("function-preload", PACKAGE_SYS, false, "name");
303        }
304        @SuppressWarnings("unchecked")
305        @Override
306        final public LispObject execute(LispObject name) {
307            String namestring = name.getStringValue();
308            LispThread thread = LispThread.currentThread();
309            Hashtable cache
310                = (Hashtable)AUTOLOADING_CACHE.symbolValue(thread).javaInstance();
311
312            Pathname pathname = new Pathname(namestring);
313            byte[] bytes = readFunctionBytes(pathname);
314            cache.put(namestring, bytes);
315           
316            return T;
317        }
318    }
319}
Note: See TracBrowser for help on using the repository browser.