1463 lines · 45.7 KB · JavaScript
RawDownload
/* * Copyright (c) 2005, 2008, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation.  Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ /* * The Original Code is HAT. The Initial Developer of the * Original Code is Bill Foote, with contributions from others * at JavaSoft/Sun. */ var hatPkg = Packages.com.sun.tools.hat.internal; /** * This is JavaScript interface for heap analysis using HAT * (Heap Analysis Tool). HAT classes are refered from * this file. In particular, refer to classes in hat.model  * package. *  * HAT model objects are wrapped as convenient script objects so that * fields may be accessed in natural syntax. For eg. Java fields can be * accessed with obj.field_name syntax and array elements can be accessed * with array[index] syntax.  */ // returns an enumeration that wraps elements of// the input enumeration elements.function wrapperEnumeration(e) {    return new java.util.Enumeration() {        hasMoreElements: function() {            return e.hasMoreElements();        },        nextElement: function() {            return wrapJavaValue(e.nextElement());        }    };} // returns an enumeration that filters out elements// of input enumeration using the filter function.function filterEnumeration(e, func, wrap) {    var next = undefined;    var index = 0;     function findNext() {        var tmp;        while (e.hasMoreElements()) {            tmp = e.nextElement();            index++;            if (wrap) {                tmp = wrapJavaValue(tmp);            }            if (func(tmp, index, e)) {                next = tmp;                return;            }        }    }     return new java.util.Enumeration() {        hasMoreElements: function() {            findNext();            return next != undefined;        },         nextElement: function() {            if (next == undefined) {                // user may not have called hasMoreElements?                findNext();            }            if (next == undefined) {                throw "NoSuchElementException";            }            var res = next;            next = undefined;            return res;        }    };} // enumeration that has no elements ..var emptyEnumeration = new java.util.Enumeration() {        hasMoreElements: function() {             return false;        },        nextElement: function() {            throw "NoSuchElementException";        }    }; function wrapRoot(root) {    if (root) {        return {            id: root.idString,            description: root.description,            referrer: wrapJavaValue(root.referer),            type: root.typeName        };    } else {        return null;    }} function JavaClassProto() {        function jclass(obj) {        return obj['wrapped-object'];    }     // return whether given class is subclass of this class or not    this.isSubclassOf = function(other) {        var tmp = jclass(this);        var otherid = objectid(other);        while (tmp != null) {            if (otherid.equals(tmp.idString)) {                return true;            }            tmp = tmp.superclass;        }        return false;    }     // return whether given class is superclass of this class or not    this.isSuperclassOf = function(other) {        return other.isSubclassOf(this);     }     // includes direct and indirect superclasses    this.superclasses = function() {        var res = new Array();        var tmp = this.superclass;        while (tmp != null) {            res[res.length] = tmp;            tmp = tmp.superclass;        }         return res;    }     /**     * Returns an array containing subclasses of this class.     *     * @param indirect should include indirect subclasses or not.     *                 default is true.     */    this.subclasses = function(indirect) {        if (indirect == undefined) indirect = true;        var classes = jclass(this).subclasses;        var res = new Array();        for (var i in classes) {            var subclass = wrapJavaValue(classes[i]);            res[res.length] = subclass;            if (indirect) {                res = res.concat(subclass.subclasses());            }        }        return res;    }    this.toString = function() { return jclass(this).toString(); }} var theJavaClassProto = new JavaClassProto(); // Script wrapper for HAT model objects, values.// wraps a Java value as appropriate for script objectfunction wrapJavaValue(thing) {    if (thing == null || thing == undefined ||        thing instanceof hatPkg.model.HackJavaValue) {	return null;    }         if (thing instanceof hatPkg.model.JavaValue) {        // map primitive values to closest JavaScript primitives        if (thing instanceof hatPkg.model.JavaBoolean) {            return thing.toString() == "true";        } else if (thing instanceof hatPkg.model.JavaChar) {            return thing.toString() + '';        } else {            return java.lang.Double.parseDouble(thing.toString());        }			    } else {        // wrap Java object as script object        return wrapJavaObject(thing);		    }} // wrap Java object with appropriate script objectfunction wrapJavaObject(thing) {     // HAT Java model object wrapper. Handles all cases     // (instance, object/primitive array and Class objects)	    function javaObject(jobject) {		        // FIXME: Do I need this? or can I assume that these would        // have been resolved already?        if (jobject instanceof hatPkg.model.JavaObjectRef) {            jobject = jobject.dereference();            if (jobject instanceof hatPkg.model.HackJavaValue) {                print(jobject);                return null;            }        }         if (jobject instanceof hatPkg.model.JavaObject) {            return new JavaObjectWrapper(jobject);        } else if (jobject instanceof hatPkg.model.JavaClass) {            return new JavaClassWrapper(jobject);        } else if (jobject instanceof hatPkg.model.JavaObjectArray) {            return new JavaObjectArrayWrapper(jobject);        } else if (jobject instanceof hatPkg.model.JavaValueArray) {            return new JavaValueArrayWrapper(jobject);        } else {            print("unknown heap object type: " + jobject.getClass());            return jobject;        }    }        // returns wrapper for Java instances    function JavaObjectWrapper(instance) {        var things = instance.fields;        var fields = instance.clazz.fieldsForInstance;    		        // instance fields can be accessed in natural syntax        return new JSAdapter() {            __getIds__ : function() {                    var res = new Array(fields.length);                    for (var i in fields) {                        res[i] = fields[i].name;                    }                    return res;            },            __has__ : function(name) {                    for (var i in fields) {                        if (name == fields[i].name) return true;                    }                    return name == 'class' || name == 'toString' ||                           name == 'wrapped-object';            },            __get__ : function(name) {                        for (var i in fields) {                        if(fields[i].name == name) {                            return wrapJavaValue(things[i]);                        }                    }                        if (name == 'class') {                        return wrapJavaValue(instance.clazz);                    } else if (name == 'toString') {                        return function() {                             return instance.toString();                        }                    } else if (name == 'wrapped-object') {                        return instance;                    }                         return undefined;            }        }				    }      // return wrapper for Java Class objects    function JavaClassWrapper(jclass) {	        var fields = jclass.statics;            // to access static fields of given Class cl, use         // cl.statics.<static-field-name> syntax        this.statics = new JSAdapter() {            __getIds__ : function() {                var res = new Array(fields.length);                for (var i in fields) {                    res[i] = fields[i].field.name;                }                return res;            },            __has__ : function(name) {                for (var i in fields) {                    if (name == fields[i].field.name) {                        return true;                    }					                }                return theJavaClassProto[name] != undefined;            },            __get__ : function(name) {                for (var i in fields) {                    if (name == fields[i].field.name) {                        return wrapJavaValue(fields[i].value);	                    }					                }                return theJavaClassProto[name];            }        }    		        if (jclass.superclass != null) {            this.superclass = wrapJavaValue(jclass.superclass);        } else {            this.superclass = null;        }         this.loader = wrapJavaValue(jclass.getLoader());        this.signers = wrapJavaValue(jclass.getSigners());        this.protectionDomain = wrapJavaValue(jclass.getProtectionDomain());        this.instanceSize = jclass.instanceSize;        this.name = jclass.name;         this.fields = jclass.fields;        this['wrapped-object'] = jclass;        this.__proto__ = this.statics;    }        // returns wrapper for Java object arrays    function JavaObjectArrayWrapper(array) {        var elements = array.elements;        // array elements can be accessed in natural syntax        // also, 'length' property is supported.        return new JSAdapter() {            __getIds__ : function() {                var res = new Array(elements.length);                for (var i = 0; i < elements.length; i++) {                    res[i] = i;                }                return res;            },            __has__: function(name) {                return (typeof(name) == 'number' &&                        name >= 0 && name < elements.length)  ||                        name == 'length' || name == 'class' ||                        name == 'toString' || name == 'wrapped-object';            },            __get__ : function(name) {                if (typeof(name) == 'number' &&                    name >= 0 && name < elements.length) {                    return wrapJavaValue(elements[name]);                } else if (name == 'length') {                    return elements.length;                } else if (name == 'class') {                    return wrapJavaValue(array.clazz);                } else if (name == 'toString') {                    return function() { return array.toString(); }                          } else if (name == 'wrapped-object') {                    return array;                } else {                    return undefined;                }				            }        }			    }        // returns wrapper for Java primitive arrays    function JavaValueArrayWrapper(array) {        var type = String(java.lang.Character.toString(array.elementType));        var elements = array.elements;        // array elements can be accessed in natural syntax        // also, 'length' property is supported.        return new JSAdapter() {            __getIds__ : function() {                var r = new Array(array.length);                for (var i = 0; i < array.length; i++) {                    r[i] = i;                }                return r;            },            __has__: function(name) {                return (typeof(name) == 'number' &&                        name >= 0 && name < array.length) ||                        name == 'length' || name == 'class' ||                        name == 'toString' || name == 'wrapped-object';            },            __get__: function(name) {                if (typeof(name) == 'number' &&                    name >= 0 && name < array.length) {                    return elements[name];                }                    if (name == 'length') {                    return array.length;                } else if (name == 'toString') {                    return function() { return array.valueString(true); }                 } else if (name == 'wrapped-object') {                    return array;                } else if (name == 'class') {                    return wrapJavaValue(array.clazz);                } else {                    return undefined;                }            }        }    }    return javaObject(thing);} // unwrap a script object to corresponding HAT objectfunction unwrapJavaObject(jobject) {    if (!(jobject instanceof hatPkg.model.JavaHeapObject)) {        try {            jobject = jobject["wrapped-object"];        } catch (e) {            print("unwrapJavaObject: " + jobject + ", " + e);            jobject = undefined;        }    }    return jobject;} /** * readHeapDump parses a heap dump file and returns script wrapper object. * * @param file  Heap dump file name * @param stack flag to tell if allocation site traces are available * @param refs  flag to tell if backward references are needed or not * @param debug debug level for HAT * @return heap as a JavaScript object */function readHeapDump(file, stack, refs, debug) {     // default value of debug is 0    if (!debug) debug = 0;     // by default, we assume no stack traces    if (!stack) stack = false;     // by default, backward references are resolved    if (!refs) refs = true;     // read the heap dump     var heap = hatPkg.parser.HprofReader.readFile(file, stack, debug);     // resolve it    heap.resolve(refs);     // wrap Snapshot as convenient script object    return wrapHeapSnapshot(heap);} /** * The result object supports the following methods: *  *  forEachClass  -- calls a callback for each Java Class *  forEachObject -- calls a callback for each Java object *  findClass -- finds Java Class of given name *  findObject -- finds object from given object id *  objects -- returns all objects of given class as an enumeration *  classes -- returns all classes in the heap as an enumeration *  reachables -- returns all objects reachable from a given object *  livepaths -- returns an array of live paths because of which an *               object alive. *  describeRef -- returns description for a reference from a 'from'  *              object to a 'to' object. */function wrapHeapSnapshot(heap) {    function getClazz(clazz) {        if (clazz == undefined) clazz = "java.lang.Object";        var type = typeof(clazz);        if (type == "string") {            clazz = heap.findClass(clazz);		        } else if (type == "object") {            clazz = unwrapJavaObject(clazz);        } else {            throw "class expected";;        }        return clazz;    }     // return heap as a script object with useful methods.    return {        snapshot: heap,         /**         * Class iteration: Calls callback function for each         * Java Class in the heap. Default callback function          * is 'print'. If callback returns true, the iteration          * is stopped.         *         * @param callback function to be called.         */        forEachClass: function(callback) {            if (callback == undefined) callback = print;            var classes = this.snapshot.classes;            while (classes.hasMoreElements()) {                if (callback(wrapJavaValue(classes.nextElement())))                    return;            }        },

Lines 1–500 of 1463.