From e8fd73f4c2ff5e87505d322c32d09ebe7b4a6877 Mon Sep 17 00:00:00 2001 From: "nboyd%atg.com" Date: Wed, 3 Apr 2002 01:55:50 +0000 Subject: [PATCH] Added support for a DebuggableObject interface that can be implemented for non-ScriptableObject implementations of Scriptable. I checked in fixes for the problems of serializing objects with FunctionObjects or GetterSlots. With Foo.class in the current directory, I can now do: [rhino] java -classpath 'build/rhino1_5R4pre/js.jar;.' org.mozilla.javascript.tools.shell.Main Rhino 1.5 release 4 0000 00 00 (in progress) js> defineClass("Foo") js> f = new Foo [object Foo] js> print(f.counter) 0 js> print(f.counter) 1 js> serialize(f, "f.ser") js> quit() [rhino] java -classpath 'build/rhino1_5R4pre/js.jar;.' org.mozilla.javascript.tools.shell.Main Rhino 1.5 release 4 0000 00 00 (in progress) js> f = deserialize("f.ser") [object Foo] js> f.counter 2 js> f.counter 3 --- .../mozilla/javascript/FunctionObject.java | 145 +++++++++++++++++- .../mozilla/javascript/ScriptableObject.java | 27 +++- .../javascript/debug/DebuggableObject.java | 60 ++++++++ 3 files changed, 223 insertions(+), 9 deletions(-) create mode 100644 js/rhino/src/org/mozilla/javascript/debug/DebuggableObject.java diff --git a/js/rhino/src/org/mozilla/javascript/FunctionObject.java b/js/rhino/src/org/mozilla/javascript/FunctionObject.java index 5aae00e3405..da37e77f69e 100644 --- a/js/rhino/src/org/mozilla/javascript/FunctionObject.java +++ b/js/rhino/src/org/mozilla/javascript/FunctionObject.java @@ -46,8 +46,12 @@ import java.lang.reflect.Member; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.lang.reflect.InvocationTargetException; +import java.io.Serializable; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; -public class FunctionObject extends NativeFunction { +public class FunctionObject extends NativeFunction implements Serializable { static final long serialVersionUID = -4074285335521944312L; @@ -575,6 +579,137 @@ public class FunctionObject extends NativeFunction { } } + private void writeObject(ObjectOutputStream out) + throws IOException + { + out.defaultWriteObject(); + boolean hasConstructor = ctor != null; + Member member = hasConstructor ? (Member)ctor : (Member)method; + writeMember(out, member); + } + + private void readObject(ObjectInputStream in) + throws IOException, ClassNotFoundException + { + in.defaultReadObject(); + Member member = readMember(in); + if (member instanceof Method) { + method = (Method) member; + types = method.getParameterTypes(); + } else { + ctor = (Constructor) member; + types = ctor.getParameterTypes(); + } + } + + /** + * Writes a Constructor or Method object. + * + * Methods and Constructors are not serializable, so we must serialize + * information about the class, the name, and the parameters and + * recreate upon deserialization. + */ + static void writeMember(ObjectOutputStream out, Member member) + throws IOException + { + if (member == null) { + out.writeBoolean(false); + return; + } + out.writeBoolean(true); + if (!(member instanceof Method || member instanceof Constructor)) + throw new IllegalArgumentException("not Method or Constructor"); + out.writeBoolean(member instanceof Method); + out.writeObject(member.getName()); + out.writeObject(member.getDeclaringClass()); + if (member instanceof Method) { + writeParameters(out, ((Method) member).getParameterTypes()); + } else { + writeParameters(out, ((Constructor) member).getParameterTypes()); + } + } + + /** + * Reads a Method or a Constructor from the stream. + */ + static Member readMember(ObjectInputStream in) + throws IOException, ClassNotFoundException + { + if (!in.readBoolean()) + return null; + boolean isMethod = in.readBoolean(); + String name = (String) in.readObject(); + Class declaring = (Class) in.readObject(); + Class[] parms = readParameters(in); + try { + if (isMethod) { + return declaring.getMethod(name, parms); + } else { + return declaring.getConstructor(parms); + } + } catch (NoSuchMethodException e) { + throw new IOException("Cannot find member: " + e); + } + } + + private static final Class[] primitives = { + Boolean.TYPE, + Byte.TYPE, + Character.TYPE, + Double.TYPE, + Float.TYPE, + Integer.TYPE, + Long.TYPE, + Short.TYPE, + Void.TYPE + }; + + /** + * Writes an array of parameter types to the stream. + * + * Requires special handling because primitive types cannot be + * found upon deserialization by the default Java implementation. + */ + static void writeParameters(ObjectOutputStream out, Class[] parms) + throws IOException + { + out.writeShort(parms.length); + outer: + for (int i=0; i < parms.length; i++) { + Class parm = parms[i]; + out.writeBoolean(parm.isPrimitive()); + if (!parm.isPrimitive()) { + out.writeObject(parm); + continue; + } + for (int j=0; j < primitives.length; j++) { + if (parm.equals(primitives[j])) { + out.writeByte(j); + continue outer; + } + } + throw new IllegalArgumentException("Primitive " + parm + + " not found"); + } + } + + /** + * Reads an array of parameter types from the stream. + */ + static Class[] readParameters(ObjectInputStream in) + throws IOException, ClassNotFoundException + { + Class[] result = new Class[in.readShort()]; + for (int i=0; i < result.length; i++) { + if (!in.readBoolean()) { + result[i] = (Class) in.readObject(); + continue; + } + result[i] = primitives[in.readByte()]; + } + return result; + } + /** Get default master implementation or null if not available */ private static Invoker newInvokerMaster() { try { @@ -600,10 +735,10 @@ public class FunctionObject extends NativeFunction { static Method[] methodsCache; - Method method; - Constructor ctor; - private Class[] types; - Invoker invoker; + transient Method method; + transient Constructor ctor; + transient Invoker invoker; + transient private Class[] types; private short parmsLength; private short lengthPropertyValue; private boolean hasVoidReturn; diff --git a/js/rhino/src/org/mozilla/javascript/ScriptableObject.java b/js/rhino/src/org/mozilla/javascript/ScriptableObject.java index 0778b1bd817..cd4f51b750c 100644 --- a/js/rhino/src/org/mozilla/javascript/ScriptableObject.java +++ b/js/rhino/src/org/mozilla/javascript/ScriptableObject.java @@ -42,6 +42,7 @@ package org.mozilla.javascript; import java.lang.reflect.*; import java.util.Hashtable; import java.io.*; +import org.mozilla.javascript.debug.DebuggableObject; /** * This is the default implementation of the Scriptable interface. This @@ -57,7 +58,9 @@ import java.io.*; * @author Norris Boyd */ -public abstract class ScriptableObject implements Scriptable, Serializable { +public abstract class ScriptableObject implements Scriptable, Serializable, + DebuggableObject +{ static final long serialVersionUID = 2762574228534679611L; @@ -1841,11 +1844,27 @@ public abstract class ScriptableObject implements Scriptable, Serializable { byte wasDeleted; } - private static class GetterSlot extends Slot { + static class GetterSlot extends Slot implements Serializable { Object delegateTo; // OPT: merge with "value" - Method getter; - Method setter; + transient Method getter; + transient Method setter; boolean setterReturnsValue; + + private void writeObject(ObjectOutputStream out) + throws IOException + { + out.defaultWriteObject(); + FunctionObject.writeMember(out, getter); + FunctionObject.writeMember(out, setter); + } + + private void readObject(ObjectInputStream in) + throws IOException, ClassNotFoundException + { + in.defaultReadObject(); + getter = (Method) FunctionObject.readMember(in); + setter = (Method) FunctionObject.readMember(in); + } } private static final Class ContextClass = Context.class; diff --git a/js/rhino/src/org/mozilla/javascript/debug/DebuggableObject.java b/js/rhino/src/org/mozilla/javascript/debug/DebuggableObject.java new file mode 100644 index 00000000000..23fbc32011b --- /dev/null +++ b/js/rhino/src/org/mozilla/javascript/debug/DebuggableObject.java @@ -0,0 +1,60 @@ +/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * The contents of this file are subject to the Netscape Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/NPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is Rhino code, released + * May 6, 1999. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1997-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * Norris Boyd + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU Public License (the "GPL"), in which case the + * provisions of the GPL are applicable instead of those above. + * If you wish to allow use of your version of this file only + * under the terms of the GPL and not to allow others to use your + * version of this file under the NPL, indicate your decision by + * deleting the provisions above and replace them with the notice + * and other provisions required by the GPL. If you do not delete + * the provisions above, a recipient may use your version of this + * file under either the NPL or the GPL. + */ + +// API class + +package org.mozilla.javascript.debug; + +import org.mozilla.javascript.*; + +/** + * This interface exposes debugging information from objects. + */ +public interface DebuggableObject { + + /** + * Returns an array of ids for the properties of the object. + * + *

All properties, even those with attribute {DontEnum}, are listed. + * This allows the debugger to display all properties of the object.

+ * + * @return an array of java.lang.Objects with an entry for every + * listed property. Properties accessed via an integer index will + * have a corresponding + * Integer entry in the returned array. Properties accessed by + * a String will have a String entry in the returned array. + */ + public Object[] getAllIds(); +}