Changeset 15363


Ignore:
Timestamp:
08/06/20 16:03:15 (3 years ago)
Author:
Mark Evenson
Message:

Refined serialization of local functions and closures (including compiled closures).
Proper tests however should involve multiple instances of ABCL to avoid any in-process effects.

Location:
trunk/abcl
Files:
1 added
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/abcl/abcl.asd

    r15341 r15363  
    5858                         (:file "runtime-class")
    5959                         #+abcl
    60                          (:file "package-local-nicknames-tests")))))
     60                         (:file "package-local-nicknames-tests")
     61                         #+abcl
     62                         (:file "closure-serialization")))))
    6163
    6264;;; FIXME Currently requires ACBL-CONTRIB and QUICKLISP-ABCL to be
  • trunk/abcl/src/org/armedbear/lisp/Function.java

    r15361 r15363  
    195195
    196196    public final LispObject getClassBytes() {
    197   LispObject o = getf(propertyList, Symbol.CLASS_BYTES, NIL);
    198   if(o != NIL) {
    199       return o;
    200   } else {
    201       ClassLoader c = getClass().getClassLoader();
    202       if(c instanceof FaslClassLoader) {
    203     final LispThread thread = LispThread.currentThread();
    204     SpecialBindingsMark mark = thread.markSpecialBindings();
    205     try {
    206         thread.bindSpecial(Symbol.LOAD_TRUENAME, loadedFrom);
    207         return new JavaObject(((FaslClassLoader) c).getFunctionClassBytes(this));
    208     } catch(Throwable t) {
    209         //This is because unfortunately getFunctionClassBytes uses
    210         //Debug.assertTrue(false) to signal errors
    211         if(t instanceof ControlTransfer) {
    212       throw (ControlTransfer) t;
    213         } else {
    214       return NIL;
    215         }
    216     } finally {
    217         thread.resetSpecialBindings(mark);
    218     }   
    219       } else {
    220     return NIL;
    221       }
    222   }
     197        LispObject o = getf(propertyList, Symbol.CLASS_BYTES, NIL);
     198        if(o != NIL) {
     199            return o;
     200        } else {
     201            ClassLoader c = getClass().getClassLoader();
     202            if(c instanceof JavaClassLoader) {
     203                final LispThread thread = LispThread.currentThread();
     204                SpecialBindingsMark mark = thread.markSpecialBindings();
     205                try {
     206                    thread.bindSpecial(Symbol.LOAD_TRUENAME, loadedFrom);
     207                    return new JavaObject(((JavaClassLoader) c).getFunctionClassBytes(this));
     208                } catch(Throwable t) {
     209                    //This is because unfortunately getFunctionClassBytes uses
     210                    //Debug.assertTrue(false) to signal errors
     211                    if(t instanceof ControlTransfer) {
     212                        throw (ControlTransfer) t;
     213                    } else {
     214                        return NIL;
     215                    }
     216                } finally {
     217                    thread.resetSpecialBindings(mark);
     218                }
     219            } else {
     220                return NIL;
     221            }
     222        }
    223223    }
    224224
     
    402402    }
    403403
     404    public static class ObjectInputStreamWithClassLoader extends ObjectInputStream {
     405        private final ClassLoader classLoader;
     406        public ObjectInputStreamWithClassLoader(InputStream in, ClassLoader classLoader) throws IOException {
     407            super(in);
     408            this.classLoader = classLoader;
     409        }
     410
     411        @Override
     412        protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException {
     413            return Class.forName(desc.getName(), false, classLoader);
     414        }
     415    }
     416
    404417    public static class SerializedLocalFunction implements Serializable {
    405418        final LispObject className;
     
    408421
    409422        public SerializedLocalFunction(Function function) {
    410             this.className = JavaObject.getInstance(function.getClass().getName());
     423            this.className = new SimpleString(function.getClass().getName());
    411424            this.classBytes = function.getClassBytes();
    412425            serializingClosure.set(true);
     
    425438            MemoryClassLoader loader = new MemoryClassLoader();
    426439            MemoryClassLoader.PUT_MEMORY_FUNCTION.execute(JavaObject.getInstance(loader), className, classBytes);
    427             Thread thread = Thread.currentThread();
    428             ClassLoader oldLoader = thread.getContextClassLoader();
    429440            try {
    430                 thread.setContextClassLoader(loader);
    431                 return new ObjectInputStream(new ByteArrayInputStream(serializedFunction)).readObject();
     441                ByteArrayInputStream in = new ByteArrayInputStream(serializedFunction);
     442                return new ObjectInputStreamWithClassLoader(in, loader).readObject();
    432443            } catch (Exception e) {
    433444                InvalidObjectException ex = new InvalidObjectException("Could not read the serialized function back");
    434445                ex.initCause(e);
    435446                throw ex;
    436             } finally {
    437                 thread.setContextClassLoader(oldLoader);
    438447            }
    439448        }
     
    445454        if(shouldSerializeByName()) {
    446455            return new SerializedNamedFunction((Symbol) getLambdaName());
    447         } else if(serializingClosure.get() != null) {
     456        } else if(getClassBytes() == NIL || serializingClosure.get() != null) {
     457            return this;
     458        } else {
    448459            return new SerializedLocalFunction(this);
    449         } else {
    450             return this;
    451460        }
    452461    }
  • trunk/abcl/src/org/armedbear/lisp/JavaObject.java

    r15234 r15363  
    3636import static org.armedbear.lisp.Lisp.*;
    3737
     38import java.io.Serializable;
    3839import java.lang.reflect.Array;
    3940import java.lang.reflect.Field;
     
    4142import java.util.*;
    4243
    43 public final class JavaObject extends LispObject {
     44public final class JavaObject extends LispObject implements Serializable {
    4445    final Object obj;
    4546    private final Class<?> intendedClass;
Note: See TracChangeset for help on using the changeset viewer.