/***
* 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.
*/
package org.apache.tajo.util;
import com.google.common.base.Preconditions;
import io.netty.util.internal.PlatformDependent;
import sun.misc.Unsafe;
import sun.nio.ch.DirectBuffer;
import java.lang.reflect.Field;
import java.nio.ByteBuffer;
public class UnsafeUtil {
public static final Unsafe unsafe;
// copied from
// http://stackoverflow.com/questions/52353/in-java-what-is-the-best-way-to-determine-the-size-of-an-object
public static enum AddressMode {
/** Unknown address mode. Size calculations may be unreliable. */
UNKNOWN,
/** 32-bit address mode using 32-bit references. */
MEM_32BIT,
/** 64-bit address mode using 64-bit references. */
MEM_64BIT,
/** 64-bit address mode using 32-bit compressed references. */
MEM_64BIT_COMPRESSED_OOPS
}
public static final AddressMode ADDRESS_MODE;
// offsets
public static final int ARRAY_BOOLEAN_BASE_OFFSET;
public static final int ARRAY_BYTE_BASE_OFFSET;
public static final int ARRAY_SHORT_BASE_OFFSET;
public static final int ARRAY_CHAR_BASE_OFFSET;
public static final int ARRAY_INT_BASE_OFFSET;
public static final int ARRAY_LONG_BASE_OFFSET;
public static final int ARRAY_FLOAT_BASE_OFFSET;
public static final int ARRAY_DOUBLE_BASE_OFFSET;
public static final int ARRAY_OBJECT_BASE_OFFSET;
// scale
public static final int ARRAY_BOOLEAN_INDEX_SCALE;
public static final int ARRAY_BYTE_INDEX_SCALE;
public static final int ARRAY_SHORT_INDEX_SCALE;
public static final int ARRAY_CHAR_INDEX_SCALE;
public static final int ARRAY_INT_INDEX_SCALE;
public static final int ARRAY_LONG_INDEX_SCALE;
public static final int ARRAY_FLOAT_INDEX_SCALE;
public static final int ARRAY_DOUBLE_INDEX_SCALE;
public static final int ARRAY_OBJECT_INDEX_SCALE;
static {
Field field;
try {
field = Unsafe.class.getDeclaredField("theUnsafe");
field.setAccessible(true);
unsafe = (Unsafe) field.get(null);
if (unsafe == null) {
throw new RuntimeException("Unsafe access not available");
}
} catch (Exception e) {
throw new RuntimeException(e);
}
ARRAY_BOOLEAN_BASE_OFFSET = unsafe.arrayBaseOffset(boolean[].class);
ARRAY_BYTE_BASE_OFFSET = unsafe.arrayBaseOffset(byte[].class);
ARRAY_SHORT_BASE_OFFSET = unsafe.arrayBaseOffset(short[].class);
ARRAY_CHAR_BASE_OFFSET = unsafe.arrayBaseOffset(char[].class);
ARRAY_INT_BASE_OFFSET = unsafe.arrayBaseOffset(int[].class);
ARRAY_LONG_BASE_OFFSET = unsafe.arrayBaseOffset(long[].class);
ARRAY_FLOAT_BASE_OFFSET = unsafe.arrayBaseOffset(float[].class);
ARRAY_DOUBLE_BASE_OFFSET = unsafe.arrayBaseOffset(double[].class);
ARRAY_OBJECT_BASE_OFFSET = unsafe.arrayBaseOffset(Object[].class);
ARRAY_BOOLEAN_INDEX_SCALE = unsafe.arrayIndexScale(boolean[].class);
ARRAY_BYTE_INDEX_SCALE = unsafe.arrayIndexScale(byte[].class);
ARRAY_SHORT_INDEX_SCALE = unsafe.arrayIndexScale(short[].class);
ARRAY_CHAR_INDEX_SCALE = unsafe.arrayIndexScale(char[].class);
ARRAY_INT_INDEX_SCALE = unsafe.arrayIndexScale(int[].class);
ARRAY_LONG_INDEX_SCALE = unsafe.arrayIndexScale(long[].class);
ARRAY_FLOAT_INDEX_SCALE = unsafe.arrayIndexScale(float[].class);
ARRAY_DOUBLE_INDEX_SCALE = unsafe.arrayIndexScale(double[].class);
ARRAY_OBJECT_INDEX_SCALE = unsafe.arrayIndexScale(Object[].class);
int addressSize = unsafe.addressSize();
int referenceSize = unsafe.arrayIndexScale(Object[].class);
if (addressSize == 4) {
ADDRESS_MODE = AddressMode.MEM_32BIT;
} else if (addressSize == 8 && referenceSize == 8) {
ADDRESS_MODE = AddressMode.MEM_64BIT;
} else if (addressSize == 8 && referenceSize == 4) {
ADDRESS_MODE = AddressMode.MEM_64BIT_COMPRESSED_OOPS;
} else {
ADDRESS_MODE = AddressMode.UNKNOWN;
}
}
public static int alignedSize(int size) {
int remain = size % SizeOf.BYTES_PER_WORD;
if (remain > 0) {
return size + (SizeOf.BYTES_PER_WORD - remain);
} else {
return size;
}
}
public static long getAddress(ByteBuffer buffer) {
Preconditions.checkArgument(buffer.isDirect(), "ByteBuffer must be DirectBuffer");
return ((DirectBuffer)buffer).address();
}
public static void free(Deallocatable obj) {
obj.release();
}
public static void free(ByteBuffer bb) {
PlatformDependent.freeDirectBuffer(bb);
}
}