blob: 86df02d4554a9a2e974117fa21e09416a6728a57 [file] [log] [blame]
/* 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;
}
}