Changeset 15361


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

Serialization of local functions and closures w/ tests (except for compiled closures)

Location:
trunk/abcl
Files:
9 edited

Legend:

Unmodified
Added
Removed
  • trunk/abcl/src/org/armedbear/lisp/ArgumentListProcessor.java

    r14465 r15361  
    3535package org.armedbear.lisp;
    3636
     37import java.io.Serializable;
    3738import java.util.List;
    3839import java.util.ArrayList;
     
    4445 * All other lambda lists are parsed elsewhere in our code base.
    4546 */
    46 public class ArgumentListProcessor {
     47public class ArgumentListProcessor implements Serializable {
    4748   
    4849  public enum LambdaListType {
     
    562563   * Because we have two implementations - a fast one and a slower one - we
    563564   * need this abstract super class */
    564   private static abstract class ArgumentMatcher {
     565  private static abstract class ArgumentMatcher implements Serializable {
    565566      abstract LispObject[] match(LispObject[] args, Environment _environment,
    566567              Environment env, LispThread thread);
  • trunk/abcl/src/org/armedbear/lisp/Binding.java

    r13695 r15361  
    3434package org.armedbear.lisp;
    3535
     36import java.io.Serializable;
     37
    3638/** Used by the environment to capture different kinds of bindings:
    3739 * tags, blocks, functions and variables.
     
    3941 */
    4042// Package accessibility.
    41 final class Binding
     43final class Binding implements Serializable
    4244{
    4345    /** The symbol in case of a variable, block, symbol-macro or
  • trunk/abcl/src/org/armedbear/lisp/Closure.java

    r14465 r15361  
    230230    return arglist.match(args, environment, environment, thread);
    231231  }
     232
     233  //Serialization
     234
     235  @Override
     236  protected boolean shouldSerializeByName() {
     237    return false; //Closures have an environment that we must serialize, even if they're top-level function
     238  }
    232239}
  • trunk/abcl/src/org/armedbear/lisp/ClosureBinding.java

    r11866 r15361  
    3434package org.armedbear.lisp;
    3535
     36import java.io.Serializable;
     37
    3638/** This class serves merely to store a reference to an
    3739 * object, used in the closure array.
     
    4143 *
    4244 */
    43 public class ClosureBinding
     45public class ClosureBinding implements Serializable
    4446{
    4547    public LispObject value;
  • trunk/abcl/src/org/armedbear/lisp/Environment.java

    r13695 r15361  
    3434package org.armedbear.lisp;
    3535
     36import java.io.Serializable;
     37
    3638import static org.armedbear.lisp.Lisp.*;
    3739
    38 public final class Environment extends LispObject
     40public final class Environment extends LispObject implements Serializable
    3941{
    4042  Binding vars;
  • trunk/abcl/src/org/armedbear/lisp/Function.java

    r15360 r15361  
    3434package org.armedbear.lisp;
    3535
    36 import java.io.NotSerializableException;
    37 import java.io.Serializable;
     36import java.io.*;
     37import java.io.ByteArrayInputStream;
     38import java.io.ByteArrayOutputStream;
    3839
    3940import static org.armedbear.lisp.Lisp.*;
     
    401402    }
    402403
    403     public Object writeReplace() throws NotSerializableException {
     404    public static class SerializedLocalFunction implements Serializable {
     405        final LispObject className;
     406        final LispObject classBytes;
     407        final byte[] serializedFunction;
     408
     409        public SerializedLocalFunction(Function function) {
     410            this.className = JavaObject.getInstance(function.getClass().getName());
     411            this.classBytes = function.getClassBytes();
     412            serializingClosure.set(true);
     413            try {
     414                ByteArrayOutputStream baos = new ByteArrayOutputStream();
     415                new ObjectOutputStream(baos).writeObject(function);
     416                serializedFunction = baos.toByteArray();
     417            } catch (IOException e) {
     418                throw new RuntimeException(e);
     419            } finally {
     420                serializingClosure.remove();
     421            }
     422        }
     423
     424        public Object readResolve() throws InvalidObjectException {
     425            MemoryClassLoader loader = new MemoryClassLoader();
     426            MemoryClassLoader.PUT_MEMORY_FUNCTION.execute(JavaObject.getInstance(loader), className, classBytes);
     427            Thread thread = Thread.currentThread();
     428            ClassLoader oldLoader = thread.getContextClassLoader();
     429            try {
     430                thread.setContextClassLoader(loader);
     431                return new ObjectInputStream(new ByteArrayInputStream(serializedFunction)).readObject();
     432            } catch (Exception e) {
     433                InvalidObjectException ex = new InvalidObjectException("Could not read the serialized function back");
     434                ex.initCause(e);
     435                throw ex;
     436            } finally {
     437                thread.setContextClassLoader(oldLoader);
     438            }
     439        }
     440    }
     441
     442    private static final ThreadLocal<Boolean> serializingClosure = new ThreadLocal<Boolean>();
     443
     444    public Object writeReplace() throws ObjectStreamException {
     445        if(shouldSerializeByName()) {
     446            return new SerializedNamedFunction((Symbol) getLambdaName());
     447        } else if(serializingClosure.get() != null) {
     448            return new SerializedLocalFunction(this);
     449        } else {
     450            return this;
     451        }
     452    }
     453
     454    protected boolean shouldSerializeByName() {
    404455        LispObject lambdaName = getLambdaName();
    405         if(lambdaName instanceof Symbol && lambdaName.getSymbolFunction() == this) {
    406             return new SerializedNamedFunction((Symbol) lambdaName);
    407         } else {
    408             throw new NotSerializableException(getClass().getName());
    409         }
     456        return lambdaName instanceof Symbol && lambdaName.getSymbolFunction() == this;
    410457    }
    411458}
  • trunk/abcl/src/org/armedbear/lisp/FunctionBinding.java

    r11391 r15361  
    3434package org.armedbear.lisp;
    3535
     36import java.io.Serializable;
     37
    3638// Package accessibility.
    37 final class FunctionBinding
     39final class FunctionBinding implements Serializable
    3840{
    3941    LispObject name;
  • trunk/abcl/src/org/armedbear/lisp/MemoryClassLoader.java

    r14363 r15361  
    145145    };
    146146
    147     private static final Primitive PUT_MEMORY_FUNCTION = new pf_put_memory_function();
     147    public static final Primitive PUT_MEMORY_FUNCTION = new pf_put_memory_function();
    148148    private static final class pf_put_memory_function extends Primitive {
    149149        pf_put_memory_function() {
  • trunk/abcl/test/src/org/armedbear/lisp/serialization/SerializationTest.java

    r15360 r15361  
    4646        ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray()));
    4747        Object readObject = ois.readObject();
    48         assertEquals(readObject, closure);
     48        assertTrue(readObject instanceof Closure);
     49        assertEquals(NIL, ((Closure) readObject).execute());
     50    }
     51
     52    @Test
     53    public void testSerializationOfLocalClosure() throws Exception {
     54        Symbol symbol = new Symbol("test");
     55        LispObject lambda_expression =
     56                new Cons(Symbol.LAMBDA, new Cons(NIL, new Cons(symbol)));
     57        LispObject lambda_name =
     58                list(Symbol.FLET, new Symbol("test"));
     59        Environment env = new Environment();
     60        env.bind(symbol, new SimpleString("OK"));
     61        Closure closure =
     62                new Closure(lambda_name, lambda_expression, env);
     63
     64        ByteArrayOutputStream baos = new ByteArrayOutputStream();
     65        ObjectOutputStream oos = new ObjectOutputStream(baos);
     66        oos.writeObject(closure);
     67
     68        ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray()));
     69        Object readObject = ois.readObject();
     70        assertTrue(readObject instanceof Closure);
     71        assertEquals("OK", ((Closure) readObject).execute().toString());
    4972    }
    5073
Note: See TracChangeset for help on using the changeset viewer.