1/*
2 *  Licensed to the Apache Software Foundation (ASF) under one or more
3 *  contributor license agreements.  See the NOTICE file distributed with
4 *  this work for additional information regarding copyright ownership.
5 *  The ASF licenses this file to You under the Apache License, Version 2.0
6 *  (the "License"); you may not use this file except in compliance with
7 *  the License.  You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *  Unless required by applicable law or agreed to in writing, software
12 *  distributed under the License is distributed on an "AS IS" BASIS,
13 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *  See the License for the specific language governing permissions and
15 *  limitations under the License.
16 */
17
18package java.nio;
19
20import dalvik.system.VMRuntime;
21import java.io.FileDescriptor;
22import java.io.IOException;
23import java.nio.channels.FileChannel.MapMode;
24import libcore.io.ErrnoException;
25import libcore.io.Libcore;
26import libcore.io.Memory;
27import static libcore.io.OsConstants.*;
28
29class MemoryBlock {
30    /**
31     * Handles calling munmap(2) on a memory-mapped region.
32     */
33    private static class MemoryMappedBlock extends MemoryBlock {
34        private MemoryMappedBlock(long address, long byteCount) {
35            super(address, byteCount);
36        }
37
38        @Override public void free() {
39            if (address != 0) {
40                try {
41                    Libcore.os.munmap(address, size);
42                } catch (ErrnoException errnoException) {
43                    // The RI doesn't throw, presumably on the assumption that you can't get into
44                    // a state where munmap(2) could return an error.
45                    throw new AssertionError(errnoException);
46                }
47                address = 0;
48            }
49        }
50
51        @Override protected void finalize() throws Throwable {
52            free();
53        }
54    }
55
56    /**
57     * Non-movable heap blocks are byte arrays on the Java heap that the GC
58     * guarantees not to move. Used to implement DirectByteBuffer.
59     *
60     * Losing the strong reference to the array is sufficient
61     * to allow the GC to reclaim the storage. No finalizer needed.
62     */
63    private static class NonMovableHeapBlock extends MemoryBlock {
64        private byte[] array;
65
66        private NonMovableHeapBlock(byte[] array, long address, long byteCount) {
67            super(address, byteCount);
68            this.array = array;
69        }
70
71        @Override public byte[] array() {
72            return array;
73        }
74
75        @Override public void free() {
76            array = null;
77            address = 0;
78        }
79    }
80
81    /**
82     * Represents a block of memory we don't own. (We don't take ownership of memory corresponding
83     * to direct buffers created by the JNI NewDirectByteBuffer function.)
84     */
85    private static class UnmanagedBlock extends MemoryBlock {
86        private UnmanagedBlock(long address, long byteCount) {
87            super(address, byteCount);
88        }
89    }
90
91    protected long address;
92    protected final long size;
93
94    public static MemoryBlock mmap(FileDescriptor fd, long offset, long size, MapMode mapMode) throws IOException {
95        if (size == 0) {
96            // You can't mmap(2) a zero-length region, but Java allows it.
97            return new MemoryBlock(0, 0);
98        }
99        // Check just those errors mmap(2) won't detect.
100        if (offset < 0 || size < 0 || offset > Integer.MAX_VALUE || size > Integer.MAX_VALUE) {
101            throw new IllegalArgumentException("offset=" + offset + " size=" + size);
102        }
103        int prot;
104        int flags;
105        if (mapMode == MapMode.PRIVATE) {
106            prot = PROT_READ|PROT_WRITE;
107            flags = MAP_PRIVATE;
108        } else if (mapMode == MapMode.READ_ONLY) {
109            prot = PROT_READ;
110            flags = MAP_SHARED;
111        } else { // mapMode == MapMode.READ_WRITE
112            prot = PROT_READ|PROT_WRITE;
113            flags = MAP_SHARED;
114        }
115        try {
116            long address = Libcore.os.mmap(0L, size, prot, flags, fd, offset);
117            return new MemoryMappedBlock(address, size);
118        } catch (ErrnoException errnoException) {
119            throw errnoException.rethrowAsIOException();
120        }
121    }
122
123    public static MemoryBlock allocate(int byteCount) {
124        VMRuntime runtime = VMRuntime.getRuntime();
125        byte[] array = (byte[]) runtime.newNonMovableArray(byte.class, byteCount);
126        long address = runtime.addressOf(array);
127        return new NonMovableHeapBlock(array, address, byteCount);
128    }
129
130    public static MemoryBlock wrapFromJni(long address, long byteCount) {
131        return new UnmanagedBlock(address, byteCount);
132    }
133
134    private MemoryBlock(long address, long size) {
135        this.address = address;
136        this.size = size;
137    }
138
139    // Used to support array/arrayOffset/hasArray for direct buffers.
140    public byte[] array() {
141        return null;
142    }
143
144    public void free() {
145    }
146
147    public final void pokeByte(int offset, byte value) {
148        Memory.pokeByte(address + offset, value);
149    }
150
151    public final void pokeByteArray(int offset, byte[] src, int srcOffset, int byteCount) {
152        Memory.pokeByteArray(address + offset, src, srcOffset, byteCount);
153    }
154
155    public final void pokeCharArray(int offset, char[] src, int srcOffset, int charCount, boolean swap) {
156        Memory.pokeCharArray(address + offset, src, srcOffset, charCount, swap);
157    }
158
159    public final void pokeDoubleArray(int offset, double[] src, int srcOffset, int doubleCount, boolean swap) {
160        Memory.pokeDoubleArray(address + offset, src, srcOffset, doubleCount, swap);
161    }
162
163    public final void pokeFloatArray(int offset, float[] src, int srcOffset, int floatCount, boolean swap) {
164        Memory.pokeFloatArray(address + offset, src, srcOffset, floatCount, swap);
165    }
166
167    public final void pokeIntArray(int offset, int[] src, int srcOffset, int intCount, boolean swap) {
168        Memory.pokeIntArray(address + offset, src, srcOffset, intCount, swap);
169    }
170
171    public final void pokeLongArray(int offset, long[] src, int srcOffset, int longCount, boolean swap) {
172        Memory.pokeLongArray(address + offset, src, srcOffset, longCount, swap);
173    }
174
175    public final void pokeShortArray(int offset, short[] src, int srcOffset, int shortCount, boolean swap) {
176        Memory.pokeShortArray(address + offset, src, srcOffset, shortCount, swap);
177    }
178
179    public final byte peekByte(int offset) {
180        return Memory.peekByte(address + offset);
181    }
182
183    public final void peekByteArray(int offset, byte[] dst, int dstOffset, int byteCount) {
184        Memory.peekByteArray(address + offset, dst, dstOffset, byteCount);
185    }
186
187    public final void peekCharArray(int offset, char[] dst, int dstOffset, int charCount, boolean swap) {
188        Memory.peekCharArray(address + offset, dst, dstOffset, charCount, swap);
189    }
190
191    public final void peekDoubleArray(int offset, double[] dst, int dstOffset, int doubleCount, boolean swap) {
192        Memory.peekDoubleArray(address + offset, dst, dstOffset, doubleCount, swap);
193    }
194
195    public final void peekFloatArray(int offset, float[] dst, int dstOffset, int floatCount, boolean swap) {
196        Memory.peekFloatArray(address + offset, dst, dstOffset, floatCount, swap);
197    }
198
199    public final void peekIntArray(int offset, int[] dst, int dstOffset, int intCount, boolean swap) {
200        Memory.peekIntArray(address + offset, dst, dstOffset, intCount, swap);
201    }
202
203    public final void peekLongArray(int offset, long[] dst, int dstOffset, int longCount, boolean swap) {
204        Memory.peekLongArray(address + offset, dst, dstOffset, longCount, swap);
205    }
206
207    public final void peekShortArray(int offset, short[] dst, int dstOffset, int shortCount, boolean swap) {
208        Memory.peekShortArray(address + offset, dst, dstOffset, shortCount, swap);
209    }
210
211    public final void pokeShort(int offset, short value, ByteOrder order) {
212        Memory.pokeShort(address + offset, value, order.needsSwap);
213    }
214
215    public final short peekShort(int offset, ByteOrder order) {
216        return Memory.peekShort(address + offset, order.needsSwap);
217    }
218
219    public final void pokeInt(int offset, int value, ByteOrder order) {
220        Memory.pokeInt(address + offset, value, order.needsSwap);
221    }
222
223    public final int peekInt(int offset, ByteOrder order) {
224        return Memory.peekInt(address + offset, order.needsSwap);
225    }
226
227    public final void pokeLong(int offset, long value, ByteOrder order) {
228        Memory.pokeLong(address + offset, value, order.needsSwap);
229    }
230
231    public final long peekLong(int offset, ByteOrder order) {
232        return Memory.peekLong(address + offset, order.needsSwap);
233    }
234
235    public final long toLong() {
236        return address;
237    }
238
239    public final String toString() {
240        return getClass().getName() + "[" + address + "]";
241    }
242
243    public final long getSize() {
244        return size;
245    }
246}
247