vmsystemclassloader.java

来自「纯java操作系统jnode,安装简单和操作简单的个人使用的Java操作系统」· Java 代码 · 共 695 行 · 第 1/2 页

JAVA
695
字号
/**
 * $Id: VmSystemClassLoader.java,v 1.5 2004/02/20 08:21:02 epr Exp $
 * 
 * Copyright 2001-2003, E.W. Prangsma
 * 
 * All rights reserved
 */
package org.jnode.vm;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.TreeMap;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

import org.jnode.assembler.ObjectResolver;
import org.jnode.vm.classmgr.ClassDecoder;
import org.jnode.vm.classmgr.SelectorMap;
import org.jnode.vm.classmgr.VmMethod;
import org.jnode.vm.classmgr.VmStatics;
import org.jnode.vm.classmgr.VmType;
import org.jnode.vm.compiler.NativeCodeCompiler;

/**
 * Default classloader.
 * 
 * @author Ewout Prangsma (epr@users.sourceforge.net)
 */
public final class VmSystemClassLoader extends VmAbstractClassLoader {

    private transient TreeMap classInfos;

    private VmType[] bootClasses;

    private transient URL classesURL;

    private transient boolean verbose = false;

    private transient boolean failOnNewLoad = false;

    private transient ClassLoader classLoader;

    private transient ObjectResolver resolver;

    private byte[] systemRtJar;

    private static JarFile systemJarFile;

    private final ClassLoader parent;

    /** Our mapping from method signatures to selectors */
    private final SelectorMap selectorMap;

    private final VmArchitecture arch;

    private boolean requiresCompile = false;

    private final VmStatics statics;

    /**
     * Constructor for VmClassLoader.
     * 
     * @param classesURL
     * @param arch
     */
    public VmSystemClassLoader(URL classesURL, VmArchitecture arch) {
        this(classesURL, arch, null);
    }

    /**
     * Constructor for VmClassLoader.
     * 
     * @param classesURL
     * @param arch
     */
    public VmSystemClassLoader(URL classesURL, VmArchitecture arch,
            ObjectResolver resolver) {
        this.classesURL = classesURL;
        this.classInfos = new TreeMap();
        this.parent = null;
        this.selectorMap = new SelectorMap();
        this.arch = arch;
        this.resolver = resolver;
        this.statics = new VmStatics(arch, resolver);
    }

    /**
     * Constructor for VmClassLoader.
     * 
     * @param classLoader
     */
    public VmSystemClassLoader(ClassLoader classLoader) {
        this.classLoader = classLoader;
        this.classInfos = new TreeMap();
        this.parent = classLoader.getParent();
        final VmSystemClassLoader sysCl = VmSystem.getSystemClassLoader();
        this.selectorMap = sysCl.selectorMap;
        this.arch = sysCl.arch;
        this.statics = sysCl.statics;
    }

    /**
     * Gets the collection with all currently loaded classes. All collection
     * elements are instanceof VmClass.
     * 
     * @return Collection
     */
    public Collection getLoadedClasses() {
        if (classInfos != null) {
            final ArrayList list = new ArrayList();
            for (Iterator i = classInfos.values().iterator(); i.hasNext();) {
                final ClassInfo ci = (ClassInfo) i.next();
                if (ci.isLoaded()) {
                    try {
                        list.add(ci.getVmClass());
                    } catch (ClassNotFoundException ex) {
                        /* ignore */
                    }
                }
            }
            return list;
        } else {
            final ArrayList list = new ArrayList();
            final VmType[] arr = bootClasses;
            final int count = arr.length;
            for (int i = 0; i < count; i++) {
                list.add(arr[ i]);
            }
            return list;
        }
    }

    /**
     * Gets the number of loaded classes.
     */
    public int getLoadedClassCount() {
        if (classInfos != null) {
            return classInfos.size();
        } else {
            return bootClasses.length;
        }
    }

    /**
     * Gets the loaded class with a given name, or null if no such class has
     * been loaded.
     * 
     * @param name
     * @return VmClass
     */
    public VmType findLoadedClass(String name) {
        if (classInfos != null) {
            if (name.indexOf('/') >= 0) { throw new IllegalArgumentException(
                    "name contains '/'"); }
            final ClassInfo ci = getClassInfo(name, false);
            if (ci != null) {
                try {
                    return ci.getVmClass();
                } catch (ClassNotFoundException ex) {
                    throw new RuntimeException(ex);
                }
            } else {
                return null;
            }
        } else {
            final VmType[] list = bootClasses;
            final int count = list.length;
            for (int i = 0; i < count; i++) {
                VmType vmClass = list[ i];
                if (vmClass.nameEquals(name)) { return vmClass; }
            }
            return null;
        }
    }

    /**
     * Result all loaded classes as an array of VmClass entries.
     * 
     * @return VmClass[]
     * @throws ClassNotFoundException
     */
    public VmType[] prepareAfterBootstrap() throws ClassNotFoundException {
        if (this.classInfos != null) {
            final VmType[] result = new VmType[ classInfos.size()];
            int j = 0;
            for (Iterator i = classInfos.values().iterator(); i.hasNext();) {
                final ClassInfo ci = (ClassInfo) i.next();
                result[ j++] = ci.getVmClass();
            }
            bootClasses = result;
            return result;
        } else {
            return bootClasses;
        }
    }

    /**
     * Add a class that has been loaded.
     * 
     * @param name
     * @param cls
     */
    public synchronized void addLoadedClass(String name, VmType cls) {
        if (failOnNewLoad) { throw new RuntimeException(
                "Cannot load a new class when failOnNewLoad is set (" + name
                        + ")"); }
        if (classInfos != null) {
            classInfos.put(name, new ClassInfo(cls));
        }
    }

    /**
     * Gets the ClassInfo for the given name. If not found and create is True,
     * a new ClassInfo is created, added to the list and returned. If not found
     * and create is False, null is returned.
     * 
     * @param name
     * @param create
     * @return
     */
    private synchronized ClassInfo getClassInfo(String name, boolean create) {
        ClassInfo ci = (ClassInfo) classInfos.get(name);
        if (ci != null) {
            return ci;
        } else if (create) {
            ci = new ClassInfo(name);
            classInfos.put(name, ci);
        }
        return ci;
    }

    /**
     * Load a class with a given name
     * 
     * @param name
     * @param resolve
     * @see org.jnode.vm.classmgr.VmClassLoader#loadClass(String, boolean)
     * @return The loaded class
     * @throws ClassNotFoundException
     */
    public VmType loadClass(String name, boolean resolve)
            throws ClassNotFoundException {

        // Also implement the java.lang.ClassLoader principals here
        // otherwise they cannot work in java.lang.ClassLoader.
        if ((parent != null) && !parent.skipParentLoader(name)) {
            try {
                final Class cls = parent.loadClass(name);
                return cls.getVmClass();
            } catch (ClassNotFoundException ex) {
                // Don't care, try it ourselves.
            }
        }

        VmType cls = findLoadedClass(name);
        if (cls != null) { return cls; }
        if (classInfos == null) { 
        //Unsafe.debug("classInfos==null");
        throw new ClassNotFoundException(name); }

        //BootLog.debug("load class" + name);

        if (name.indexOf('/') >= 0) { throw new IllegalArgumentException(
                "name contains '/'"); }
        final ClassInfo ci = getClassInfo(name, true);
        if (!ci.isLoaded()) {
            try {
                if (failOnNewLoad) { throw new RuntimeException(
                        "Cannot load a new class when failOnNewLoad is set ("
                                + name + ")"); }
                if (name.charAt(0) == '[') {
                    ci.setVmClass(loadArrayClass(name, resolve));
                } else {
                    ci.setVmClass(loadNormalClass(name));
                }
            } catch (ClassNotFoundException ex) {
                ci.setLoadError(ex.toString());
                classInfos.remove(ci.getName());
                throw new ClassNotFoundException(name, ex);
            } catch (IOException ex) {
                ci.setLoadError(ex.toString());
                classInfos.remove(ci.getName());
                throw new ClassNotFoundException(name, ex);
            }
            if (resolve) {
                ci.getVmClass().link();
            }
        }
        return ci.getVmClass();
    }

    /**
     * Gets the ClassLoader belonging to this loader.
     * 
     * @return ClassLoader
     */
    public final ClassLoader asClassLoader() {
        if (classLoader == null) {
            classLoader = new ClassLoaderWrapper(this);
        }
        return classLoader;
    }

    /**
     * Load a normal (non-array) class with a given name
     * 
     * @param name
     * @return VmClass
     * @throws IOException
     * @throws ClassNotFoundException
     */
    private VmType loadNormalClass(String name) throws IOException,
            ClassNotFoundException {

        if (failOnNewLoad) { throw new RuntimeException(
                "Cannot load a new class when failOnNewLoad is set (" + name
                        + ")"); }

        boolean rejectNatives = (!name.equals("org.jnode.vm.Unsafe"));

        //System.out.println("bvi.loadClass: " +name);
        byte[] image = getClassStream(name);
        return ClassDecoder.defineClass(name, image, 0, image.length,
                rejectNatives, this);
    }

    /**
     * Gets the number of loaded classes.
     * 
     * @return int
     */
    public int size() {
        if (classInfos != null) {
            return classInfos.size();
        } else {
            return bootClasses.length;
        }
    }

    /**
     * Gets an inputstream for the class file that contains the given
     * classname.

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?