All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.atomix.catalyst.buffer.util.NativeMemory Maven / Gradle / Ivy

There is a newer version: 1.2.1
Show newest version
/*
 * Copyright 2015 the original author or authors.
 *
 * Licensed 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 io.atomix.catalyst.buffer.util;

import sun.misc.Unsafe;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.nio.ByteOrder;

/**
 * Native memory. Represents memory that can be accessed directly via {@link sun.misc.Unsafe}
 *
 * @author Jordan Halterman
 */
public class NativeMemory implements Memory {
  static final Unsafe UNSAFE;
  private static final boolean UNALIGNED;
  private static final boolean BIG_ENDIAN = ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN;

  /**
   * Allocates native memory via {@link DirectMemoryAllocator}.
   *
   * @param size The count of the memory to allocate.
   * @return The allocated memory.
   */
  public static NativeMemory allocate(long size) {
    return new DirectMemoryAllocator().allocate(size);
  }

  static {
    try {
      Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe");
      unsafeField.setAccessible(true);
      UNSAFE = (Unsafe) unsafeField.get(null);
    } catch (Exception e) {
      throw new AssertionError();
    }

    boolean unaligned;
    try {
      Class bitsClass = Class.forName("java.nio.Bits", false, ClassLoader.getSystemClassLoader());
      Method unalignedMethod = bitsClass.getDeclaredMethod("unaligned");
      unalignedMethod.setAccessible(true);
      unaligned = Boolean.TRUE.equals(unalignedMethod.invoke(null));
    } catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
      unaligned = false;
    }
    UNALIGNED = unaligned;
  }

  private long address;
  private final long size;
  protected final MemoryAllocator allocator;

  @SuppressWarnings("unchecked")
  protected NativeMemory(long address, long size, MemoryAllocator allocator) {
    if (allocator == null)
      throw new NullPointerException("allocator cannot be null");
    this.address = address;
    this.size = size;
    this.allocator = allocator;
  }

  @Override
  @SuppressWarnings("unchecked")
  public MemoryAllocator allocator() {
    return allocator;
  }

  @Override
  public final long address() {
    return address;
  }

  @Override
  public final long address(long offset) {
    return address + offset;
  }

  /**
   * Returns the address for a byte within an offset.
   */
  private long address(long offset, int b) {
    return address + offset + b;
  }

  @Override
  public long size() {
    return size;
  }

  /**
   * Returns the underlying {@link sun.misc.Unsafe} instance.
   *
   * @return The underlying unsafe memory instance.
   */
  public final Unsafe unsafe() {
    return UNSAFE;
  }

  @Override
  public NativeMemory copy() {
    NativeMemory memory = (NativeMemory) allocator.allocate(size);
    UNSAFE.copyMemory(address, memory.address, size);
    return memory;
  }

  @Override
  public byte getByte(long offset) {
    return UNSAFE.getByte(address(offset));
  }

  private byte getByte(long offset, int pos) {
    return UNSAFE.getByte(address(offset, pos));
  }

  @Override
  public char getChar(long offset) {
    if (UNALIGNED) {
      return UNSAFE.getChar(address(offset));
    } else if (BIG_ENDIAN) {
      return (char) (getByte(offset) << 8
        | getByte(offset, 1) & 0xff);
    } else {
      return (char) ((getByte(offset, 1) << 8)
        | getByte(offset) & 0xff);
    }
  }

  @Override
  public short getShort(long offset) {
    if (UNALIGNED) {
      return UNSAFE.getShort(address(offset));
    } else if (BIG_ENDIAN) {
      return (short) (getByte(offset) << 8
        | getByte(offset, 1) & 0xff);
    } else {
      return (short) ((getByte(offset, 1) << 8)
        | getByte(offset) & 0xff);
    }
  }

  @Override
  public int getInt(long offset) {
    if (UNALIGNED) {
      return UNSAFE.getInt(address(offset));
    } else if (BIG_ENDIAN) {
      return (getByte(offset, 0)) << 24
        | (getByte(offset, 1) & 0xff) << 16
        | (getByte(offset, 2) & 0xff) << 8
        | (getByte(offset, 3) & 0xff);
    } else {
      return (getByte(offset, 3)) << 24
        | (getByte(offset, 2) & 0xff) << 16
        | (getByte(offset, 1) & 0xff) << 8
        | (getByte(offset, 0) & 0xff);
    }
  }

  @Override
  public long getLong(long offset) {
    if (UNALIGNED) {
      return UNSAFE.getLong(address(offset));
    } else if (BIG_ENDIAN) {
      return ((long) getByte(offset)) << 56
        | ((long) getByte(offset, 1) & 0xff) << 48
        | ((long) getByte(offset, 2) & 0xff) << 40
        | ((long) getByte(offset, 3) & 0xff) << 32
        | ((long) getByte(offset, 4) & 0xff) << 24
        | ((long) getByte(offset, 5) & 0xff) << 16
        | ((long) getByte(offset, 6) & 0xff) << 8
        | ((long) getByte(offset, 7) & 0xff);
    } else {
      return ((long) getByte(offset, 7)) << 56
        | ((long) getByte(offset, 6) & 0xff) << 48
        | ((long) getByte(offset, 5) & 0xff) << 40
        | ((long) getByte(offset, 4) & 0xff) << 32
        | ((long) getByte(offset, 3) & 0xff) << 24
        | ((long) getByte(offset, 2) & 0xff) << 16
        | ((long) getByte(offset, 1) & 0xff) << 8
        | ((long) getByte(offset) & 0xff);
    }
  }

  @Override
  public float getFloat(long offset) {
    return Float.intBitsToFloat(getInt(offset));
  }

  @Override
  public double getDouble(long offset) {
    return Double.longBitsToDouble(getLong(offset));
  }

  @Override
  public void putByte(long offset, byte b) {
    UNSAFE.putByte(address(offset), b);
  }

  private void putByte(long offset, int pos, byte b) {
    UNSAFE.putByte(address(offset, pos), b);
  }

  @Override
  public void putChar(long offset, char c) {
    if (UNALIGNED) {
      putChar(address(offset), c);
    } else if (BIG_ENDIAN) {
      putByte(offset, (byte) (c >>> 8));
      putByte(offset, 1, (byte) c);
    } else {
      putByte(offset, 1, (byte) (c >>> 8));
      putByte(offset, (byte) c);
    }
  }

  @Override
  public void putShort(long offset, short s) {
    if (UNALIGNED) {
      UNSAFE.putShort(address(offset), s);
    } else if (BIG_ENDIAN) {
      putByte(offset, (byte) (s >>> 8));
      putByte(offset, 1, (byte) s);
    } else {
      putByte(offset, 1, (byte) (s >>> 8));
      putByte(offset, (byte) s);
    }
  }

  @Override
  public void putInt(long offset, int i) {
    if (UNALIGNED) {
      UNSAFE.putInt(address(offset), i);
    } else if (BIG_ENDIAN) {
      putByte(offset, (byte) (i >>> 24));
      putByte(offset, 1, (byte) (i >>> 16));
      putByte(offset, 2, (byte) (i >>> 8));
      putByte(offset, 3, (byte) i);
    } else {
      putByte(offset, 3, (byte) (i >>> 24));
      putByte(offset, 2, (byte) (i >>> 16));
      putByte(offset, 1, (byte) (i >>> 8));
      putByte(offset, (byte) i);
    }
  }

  @Override
  public void putLong(long offset, long l) {
    if (UNALIGNED) {
      UNSAFE.putLong(address(offset), l);
    } else if (BIG_ENDIAN) {
      putByte(offset, (byte) (l >>> 56));
      putByte(offset, 1, (byte) (l >>> 48));
      putByte(offset, 2, (byte) (l >>> 40));
      putByte(offset, 3, (byte) (l >>> 32));
      putByte(offset, 4, (byte) (l >>> 24));
      putByte(offset, 5, (byte) (l >>> 16));
      putByte(offset, 6, (byte) (l >>> 8));
      putByte(offset, 7, (byte) l);
    } else {
      putByte(offset, 7, (byte) (l >>> 56));
      putByte(offset, 6, (byte) (l >>> 48));
      putByte(offset, 5, (byte) (l >>> 40));
      putByte(offset, 4, (byte) (l >>> 32));
      putByte(offset, 3, (byte) (l >>> 24));
      putByte(offset, 2, (byte) (l >>> 16));
      putByte(offset, 1, (byte) (l >>> 8));
      putByte(offset, (byte) l);
    }
  }

  @Override
  public void putFloat(long offset, float f) {
    putInt(offset, Float.floatToRawIntBits(f));
  }

  @Override
  public void putDouble(long offset, double d) {
    putLong(offset, Double.doubleToRawLongBits(d));
  }

  @Override
  public void clear() {
    UNSAFE.setMemory(address, size, (byte) 0);
  }

  @Override
  @SuppressWarnings("unchecked")
  public void free() {
    if (address != 0) {
      NativeMemory.UNSAFE.freeMemory(address);
      address = 0;
    }
  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy