jdk/src/java.base/share/classes/jdk/internal/jimage/ImageNativeSubstrate.java
author chegar
Mon, 28 Sep 2015 13:39:27 +0100
changeset 32834 e1dca5fe4de3
parent 32649 2ee9017c7597
permissions -rw-r--r--
8137056: Move SharedSecrets and interface friends out of sun.misc Reviewed-by: alanb, mchung, psandoz, rriggs

/*
 * Copyright (c) 2014, 2015, 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.
 */
package jdk.internal.jimage;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;

public final class ImageNativeSubstrate implements ImageSubstrate {
    static {
        java.security.AccessController.doPrivileged(
            new java.security.PrivilegedAction<Void>() {
                @Override
                public Void run() {
                    System.loadLibrary("jimage");
                    return null;
                }
            });
     }

    // TODO: Reinstate when the class below, NIOACCESS, is removed.
    //private static final JavaNioAccess NIOACCESS =
    //        SharedSecrets.getJavaNioAccess();


    private final long id;
    private final long indexAddress;
    private final long dataAddress;

    static native long openImage(String imagePath, boolean bigEndian);
    static native void closeImage(long id);
    static native long getIndexAddress(long id);
    static native long getDataAddress(long id);
    static native boolean readCompressed(long id, long offset,
            ByteBuffer compressedBuffer, long compressedSize,
            ByteBuffer uncompressedBuffer, long uncompressedSize);
    static native boolean read(long id, long offset,
            ByteBuffer uncompressedBuffer, long uncompressedSize);
    static native byte[] getStringBytes(long id, int offset);
    static native long[] getAttributes(long id, int offset);
    static native long[] findAttributes(long id, byte[] path);
    static native int[] attributeOffsets(long id);

    public static native long JIMAGE_Open(String path) throws IOException;
    public static native void JIMAGE_Close(long jimageHandle);
    public static native long JIMAGE_FindResource(long jimageHandle,
                    String moduleName, String Version, String path,
                    long[] size);
    public static native long JIMAGE_GetResource(long jimageHandle,
                    long locationHandle, byte[] buffer, long size);
    // Get an array of names that match; return the count found upto array size
    public static native int JIMAGE_Resources(long jimageHandle,
                    String[] outputNames);
    // Return the module name for the package
    public static native String JIMAGE_PackageToModule(long imageHandle,
                    String packageName);

    static ByteBuffer newDirectByteBuffer(long address, long capacity) {
        assert capacity < Integer.MAX_VALUE;
        return NIOACCESS.newDirectByteBuffer(address, (int)capacity, null);
    }

    private ImageNativeSubstrate(long id) {
        this.id = id;
        this.indexAddress = getIndexAddress(id);
        this.dataAddress = getDataAddress(id);
    }

    static ImageSubstrate openImage(String imagePath, ByteOrder byteOrder)
            throws IOException {
        long id = openImage(imagePath, byteOrder == ByteOrder.BIG_ENDIAN);

        if (id == 0) {
             throw new IOException("Image not found \"" + imagePath + "\"");
        }

        return new ImageNativeSubstrate(id);
    }

    @Override
    public void close() {
        closeImage(id);
    }

    @Override
    public ByteBuffer getIndexBuffer(long offset, long size) {
        return newDirectByteBuffer(indexAddress + offset, size);
    }

    @Override
    public ByteBuffer getDataBuffer(long offset, long size) {
        return dataAddress != 0 ?
                newDirectByteBuffer(dataAddress + offset, size) : null;
    }

    @Override
    public boolean supportsDataBuffer() {
        return dataAddress != 0;
    }

    @Override
    public boolean read(long offset,
                 ByteBuffer compressedBuffer, long compressedSize,
                 ByteBuffer uncompressedBuffer, long uncompressedSize) {
        return readCompressed(id, offset,
                    compressedBuffer, compressedSize,
                    uncompressedBuffer, uncompressedSize);
    }

    @Override
    public boolean read(long offset,
                 ByteBuffer uncompressedBuffer, long uncompressedSize) {
        return read(id, offset, uncompressedBuffer, uncompressedSize);
    }

    @Override
    public byte[] getStringBytes(int offset) {
        byte[] ret = getStringBytes(id, offset);
        if (ret == null) {
            throw new OutOfMemoryError("Error accessing array at offset "
                    + offset);
        }
        return ret;
    }

    @Override
    public long[] getAttributes(int offset) {
        return getAttributes(id, offset);
    }

    @Override
    public ImageLocation findLocation(UTF8String name, ImageStringsReader strings) {
        long[] attributes = findAttributes(id, name.getBytes());

        return attributes != null ? new ImageLocation(attributes, strings) : null;
    }

    @Override
    public int[] attributeOffsets() {
        return attributeOffsets(id);
    }

    // TODO: Remove when JRT-FS no longer indirectly depends on ImageNativeSubstrate
    /**
     * Reflective wrapper around ShareSecrets JavaNioAccess.
     *
     * SharedSecrets and friend interfaces moved from 'sun.misc' to 'jdk.internal.misc'
     * in 1.9. This class provides the runtime with access to the appropriate
     * JavaNioAccess methods whether running on 1.9, or lower.
     */
    static class NIOACCESS {

        private static final String PKG_PREFIX = "jdk.internal.misc";
        private static final String LEGACY_PKG_PREFIX = "sun.misc";

        private static final Object javaNioAccess;
        private static final java.lang.reflect.Method newDirectByteBufferMethod;

        static {
            try {
                Class<?> c = getJDKClass("JavaNioAccess");

                java.lang.reflect.Method m =
                        getJDKClass("SharedSecrets").getDeclaredMethod("getJavaNioAccess");
                javaNioAccess = m.invoke(null);

                newDirectByteBufferMethod = c.getDeclaredMethod("newDirectByteBuffer",
                                                                long.class,
                                                                int.class,
                                                                Object.class);
            } catch (ReflectiveOperationException x) {
                throw new InternalError(x);
            }
        }

        private static Class<?> getJDKClass(String name) throws ClassNotFoundException {
            try {
                return Class.forName(PKG_PREFIX + "." + name);
            } catch (ClassNotFoundException x) {
                try {
                    return Class.forName(LEGACY_PKG_PREFIX + "." + name);
                } catch (ClassNotFoundException ex) {
                    x.addSuppressed(ex);
                    throw x;
                }
            }
        }

        static ByteBuffer newDirectByteBuffer(long addr, int cap, Object ob) {
            try {
                return (ByteBuffer) newDirectByteBufferMethod.invoke(javaNioAccess, addr, cap, ob);
            } catch (ReflectiveOperationException x) {
                throw new InternalError(x);
            }
        }
    }
}