1 /*
  2  * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  * This code is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 only, as
  7  * published by the Free Software Foundation.  Oracle designates this
  8  * particular file as subject to the "Classpath" exception as provided
  9  * by Oracle in the LICENSE file that accompanied this code.
 10  *
 11  * This code is distributed in the hope that it will be useful, but WITHOUT
 12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 14  * version 2 for more details (a copy is included in the LICENSE file that
 15  * accompanied this code).
 16  *
 17  * You should have received a copy of the GNU General Public License version
 18  * 2 along with this work; if not, write to the Free Software Foundation,
 19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 20  *
 21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 22  * or visit www.oracle.com if you need additional information or have any
 23  * questions.
 24  */
 25 
 26 package java.nio;
 27 
 28 import jdk.internal.misc.Unsafe;
 29 
 30 import java.io.FileDescriptor;
 31 import java.io.IOException;
 32 import java.io.UncheckedIOException;


 33 
 34 /* package */ class MappedMemoryUtils {
 35 
 36     static boolean isLoaded(long address, boolean isSync, long size) {
 37         // a sync mapped buffer is always loaded
 38         if (isSync) {
 39             return true;
 40         }
 41         if ((address == 0) || (size == 0))
 42             return true;
 43         long offset = mappingOffset(address);
 44         long length = mappingLength(offset, size);
 45         return isLoaded0(mappingAddress(address, offset), length, Bits.pageCount(length));
 46     }
 47 
 48     static void load(long address, boolean isSync, long size) {
 49         // no need to load a sync mapped buffer
 50         if (isSync) {
 51             return;
 52         }
 53         if ((address == 0) || (size == 0))
 54             return;
 55         long offset = mappingOffset(address);
 56         long length = mappingLength(offset, size);
 57         load0(mappingAddress(address, offset), length);
 58 
 59         // Read a byte from each page to bring it into memory. A checksum
 60         // is computed as we go along to prevent the compiler from otherwise
 61         // considering the loop as dead code.
 62         Unsafe unsafe = Unsafe.getUnsafe();
 63         int ps = Bits.pageSize();
 64         long count = Bits.pageCount(length);
 65         long a = mappingAddress(address, offset);
 66         byte x = 0;
 67         for (long i=0; i<count; i++) {
 68             // TODO consider changing to getByteOpaque thus avoiding
 69             // dead code elimination and the need to calculate a checksum
 70             x ^= unsafe.getByte(a);
 71             a += ps;
 72         }
 73         if (unused != 0)
 74             unused = x;
 75     }
 76 
 77     // not used, but a potential target for a store, see load() for details.
 78     private static byte unused;
 79 
 80     static void unload(long address, boolean isSync, long size) {
 81         // no need to load a sync mapped buffer
 82         if (isSync) {
 83             return;
 84         }
 85         if ((address == 0) || (size == 0))
 86             return;
 87         long offset = mappingOffset(address);
 88         long length = mappingLength(offset, size);
 89         unload0(mappingAddress(address, offset), length);
 90     }
 91 
 92     static void force(FileDescriptor fd, long address, boolean isSync, long index, long length) {
 93         if (isSync) {
 94             // simply force writeback of associated cache lines
 95             Unsafe.getUnsafe().writebackMemory(address + index, length);
 96         } else {
 97             // force writeback via file descriptor
 98             long offset = mappingOffset(address, index);


 99             try {
100                 force0(fd, mappingAddress(address, offset, index), mappingLength(offset, length));




101             } catch (IOException cause) {
102                 throw new UncheckedIOException(cause);
103             }
104         }
105     }
106 
107     // native methods
108 
109     private static native boolean isLoaded0(long address, long length, long pageCount);
110     private static native void load0(long address, long length);
111     private static native void unload0(long address, long length);
112     private static native void force0(FileDescriptor fd, long address, long length) throws IOException;
113 
114     // utility methods
115 
116     // Returns the distance (in bytes) of the buffer start from the
117     // largest page aligned address of the mapping less than or equal
118     // to the start address.
119     private static long mappingOffset(long address) {
120         return mappingOffset(address, 0);
121     }
122 
123     // Returns the distance (in bytes) of the buffer element
124     // identified by index from the largest page aligned address of
125     // the mapping less than or equal to the element address. Computed
126     // each time to avoid storing in every direct buffer.
127     private static long mappingOffset(long address, long index) {
128         int ps = Bits.pageSize();
129         long indexAddress = address + index;
130         long baseAddress = alignDown(indexAddress, ps);
131         return indexAddress - baseAddress;
132     }
133 
134     // Given an offset previously obtained from calling
135     // mappingOffset() returns the largest page aligned address of the
136     // mapping less than or equal to the buffer start address.
137     private static long mappingAddress(long address, long mappingOffset) {
138         return mappingAddress(address, mappingOffset, 0);
139     }
140 
141     // Given an offset previously otained from calling
142     // mappingOffset(index) returns the largest page aligned address
143     // of the mapping less than or equal to the address of the buffer
144     // element identified by index.
145     private static long mappingAddress(long address, long mappingOffset, long index) {
146         long indexAddress = address + index;
147         return indexAddress - mappingOffset;
148     }
149 
150     // given a mappingOffset previously otained from calling
151     // mappingOffset(index) return that offset added to the supplied
152     // length.
153     private static long mappingLength(long mappingOffset, long length) {
154         return length + mappingOffset;
155     }
156 
157     // align address down to page size
158     private static long alignDown(long address, int pageSize) {
159         // pageSize must be a power of 2
160         return address & ~(pageSize - 1);
161     }
162 }
--- EOF ---