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

monix.execution.internal.atomic.UnsafeAccess Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2014-2019 by The Monix Project Developers.
 * See the project homepage at: https://monix.io
 *
 * 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 monix.execution.internal.atomic;

import monix.execution.internal.InternalApi;
import scala.util.control.NonFatal;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

/**
 * INTERNAL API — Provides access to `sun.misc.Unsafe`.
 *
 * Being internal it can always change between minor versions,
 * providing no backwards compatibility guarantees and is only public
 * because Java does not provide the capability of marking classes as
 * "internal" to a package and all its sub-packages.
 */
@InternalApi public final class UnsafeAccess {
  private static final Object UNSAFE;

  /** True in case the underlying platform supports
   * `sun.misc.Unsafe`, `false` otherwise.
   *
   * In case [[IS_ALLOWED]] is set to `false`, then
   * [[IS_AVAILABLE]] is also going to be set to `false`.
   */
  public static final boolean IS_AVAILABLE;

  /**
   * True in case the `sun.misc.Unsafe` usage is disabled
   * by means of setting `-Dmonix.environment.canUseUnsafe=false`.
   *
   * In case this is set to `false`, then [[IS_AVAILABLE]] is
   * also going to be set to `false`.
   */
  public static final boolean IS_ALLOWED;

  /**
   * True in case the underlying platform supports Java 8's
   * `Unsafe` features for platform intrinsics.
   */
  public static final boolean HAS_JAVA8_INTRINSICS;

  /**
   * Some platforms do not expose a `theUnsafe` private reference
   * to a `sun.misc.Unsafe` instance, but unfortunately some libraries
   * (notably version 2.0 of JCTools) depends on this.
   *
   * This reference is set to `true` in case `Unsafe.theUnsafe` exists,
   * or `false` otherwise.
   */
  public static final boolean IS_OPENJDK_COMPATIBLE;

  /**
   * Returns a reusable reference for `sun.misc.Unsafe`.
   */
  public static Object getInstance() {
    if (UNSAFE == null)
      throw new AssertionError(
        "Platform does not support sun.misc.Unsafe, " +
        "please file a bug report for the Monix project " +
        "(see https://monix.io)"
      );

    return UNSAFE;
  }

  private static boolean isUnsafeAllowed() {
    String env = System.getProperty("monix.environment.canUseUnsafe", "").trim().toLowerCase();
    boolean disabled = env.equals("no") || env.equals("false") || env.equals("0");
    return !disabled;
  }

  static {
    Object instance = null;
    boolean isJava8 = false;
    boolean isAllowed = false;
    boolean isOpenJDKCompatible = false;

    try {
      isAllowed = isUnsafeAllowed();

      if (isAllowed) {
        Class cls = Class.forName("sun.misc.Unsafe", true, UnsafeAccess.class.getClassLoader());
        try {
          Field field = cls.getDeclaredField("theUnsafe");
          field.setAccessible(true);
          instance = field.get(null);
          if (instance == null) throw null;
          isOpenJDKCompatible = true;
        }
        catch (Exception ex) {
          if (!NonFatal.apply(ex)) {
            throw ex;
          }
          else {
            // Workaround for older Android versions or other non-OpenJDK
            // implementations that may not have a `theUnsafe` instance
            Constructor c = cls.getDeclaredConstructor();
            c.setAccessible(true);
            instance = c.newInstance();
          }
        }

        boolean supportsGetAndSet = false;
        try {
          cls.getMethod("getAndSetObject", Object.class, Long.TYPE, Object.class);
          supportsGetAndSet = true;
        }
        catch (Exception e) {
          if (!NonFatal.apply(e)) throw e;
        }

        boolean supportsGetAndAddInt = false;
        try {
          cls.getMethod("getAndAddInt", Object.class, Long.TYPE, Integer.TYPE);
          supportsGetAndAddInt = true;
        }
        catch (Exception e) {
          if (!NonFatal.apply(e)) throw e;
        }

        boolean supportsGetAndAddLong = false;
        try {
          cls.getMethod("getAndAddLong", Object.class, Long.TYPE, Long.TYPE);
          supportsGetAndAddLong = true;
        }
        catch (Exception e) {
          if (!NonFatal.apply(e)) throw e;
        }

        boolean supportsMemoryFences = false;
        try {
          Method m = cls.getDeclaredMethod("fullFence");
          supportsMemoryFences = m != null;
        }
        catch (Exception e) {
          if (!NonFatal.apply(e)) throw e;
        }

        isJava8 = supportsGetAndSet &&
          supportsGetAndAddInt &&
          supportsGetAndAddLong &&
          supportsMemoryFences;
      }
    }
    catch (Exception ex) {
      instance = null;
      isJava8 = false;
      if (!NonFatal.apply(ex))
        throw new RuntimeException(ex);
    }
    finally {
      UNSAFE = instance;
      IS_AVAILABLE = instance != null;
      IS_ALLOWED = isAllowed;
      HAS_JAVA8_INTRINSICS = isJava8;
      IS_OPENJDK_COMPATIBLE = isOpenJDKCompatible;
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy