| /* Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| // BEGIN android-note |
| // address length was changed from long to int for performance reasons. |
| // END android-note |
| |
| package org.apache.harmony.luni.platform; |
| |
| import java.io.IOException; |
| import java.nio.channels.FileChannel.MapMode; |
| |
| public class PlatformAddressFactory { |
| |
| // BEGIN android-added |
| /** |
| * Defines the number of PlatformAddress objects to be cached. Must be a |
| * power of two. Caching PlatformAddress objects minimizes the creation |
| * of garbage and reduces the number of GC-hiccups in OpenGL animations. |
| */ |
| private final static int CACHE_SIZE = 1<<8; |
| |
| /** |
| * A mask with all bits set, matching the size of the cache. |
| */ |
| private final static int CACHE_MASK = CACHE_SIZE - 1; |
| |
| /** |
| * Defines the maximum number of probes taken per hash, used for looking |
| * up an empty cache slot or a previously stored PlatformAddress. |
| */ |
| private final static int MAX_PROBES = 5; |
| |
| /** |
| * A cycling index (0 to MAX_PROBES-1) used to replace elements in |
| * the cache. |
| */ |
| private static int replacementIndex = 0; |
| |
| /** |
| * Array of PlatformAddress references kept from garbage collection. |
| */ |
| private static PlatformAddress[] cache = new PlatformAddress[CACHE_SIZE]; |
| |
| /** |
| * Constructs a {@code PlatformAddress} or returns |
| * {@link PlatformAddress#NULL} if given a {@code null} address. |
| * |
| * @param address the start address for the memory; {@code 0} means |
| * {@code null} |
| * @param size the size of the memory in bytes |
| * @return an appropriately-constructed {@code PlatformAddress} |
| */ |
| private static PlatformAddress make(int value, long size) { |
| if (value == 0) { |
| return PlatformAddress.NULL; |
| } |
| |
| return new PlatformAddress(value, size); |
| } |
| // END android-added |
| |
| // BEGIN android-changed |
| public synchronized static PlatformAddress on(int value, long size) { |
| if (value == 0) { |
| return PlatformAddress.NULL; |
| } |
| int idx = value >> 5; |
| for (int probe = 0; probe < MAX_PROBES; probe++) { |
| PlatformAddress cachedObj = cache[(idx + probe) & CACHE_MASK]; |
| if (cachedObj == null) { |
| return cache[(idx + probe) & CACHE_MASK] = |
| new PlatformAddress(value, size); |
| } |
| if (cachedObj.osaddr == value && cachedObj.size == size) { |
| return cachedObj; |
| } |
| } |
| replacementIndex = (replacementIndex + 1) % MAX_PROBES; |
| return cache[(idx + replacementIndex) & CACHE_MASK] = |
| new PlatformAddress(value, size); |
| } |
| // END android-changed |
| |
| public static PlatformAddress on(int value) { |
| return PlatformAddressFactory.on(value, PlatformAddress.UNKNOWN); |
| } |
| |
| public static MappedPlatformAddress mapOn(int value, long size) { |
| MappedPlatformAddress addr = new MappedPlatformAddress(value, size); |
| return addr; |
| } |
| |
| public static PlatformAddress allocMap(int fd, long start, long size, MapMode mode) |
| throws IOException { |
| if (size == 0) { |
| // if size is 0, call to mmap has incorrect behaviour on |
| // unix and windows, so return empty address |
| return mapOn(0, 0); |
| } |
| int osAddress = OSMemory.mmap(fd, start, size, mode); |
| PlatformAddress newMemory = mapOn(osAddress, size); |
| PlatformAddress.memorySpy.alloc(newMemory); |
| return newMemory; |
| } |
| |
| /** |
| * Allocates a contiguous block of OS heap memory and initializes it to |
| * a given value. |
| * |
| * @param size The number of bytes to allocate from the system heap. |
| * @param init The value to initialize the memory. |
| * @return PlatformAddress representing the memory block. |
| */ |
| public static PlatformAddress alloc(int size, byte init) { |
| int osAddress = OSMemory.malloc(size); |
| OSMemory.memset(osAddress, init, size); |
| /* |
| * We use make() and not on() here, for a couple reasons: |
| * First and foremost, doing so means that if the client uses |
| * address.autoFree() (to enable auto-free on gc) the cache |
| * won't prevent the freeing behavior. Second, this avoids |
| * polluting the cache with addresses that aren't likely to be |
| * reused anyway. |
| */ |
| PlatformAddress newMemory = make(osAddress, size); |
| PlatformAddress.memorySpy.alloc(newMemory); |
| return newMemory; |
| } |
| } |