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