Java Code Examples for java.lang.ref.Reference#reachabilityFence()

The following examples show how to use java.lang.ref.Reference#reachabilityFence() . You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example 1
Source File: Deflater.java    From Bytecoder with Apache License 2.0 6 votes vote down vote up
/**
 * Sets preset dictionary for compression. A preset dictionary is used
 * when the history buffer can be predetermined. When the data is later
 * uncompressed with Inflater.inflate(), Inflater.getAdler() can be called
 * in order to get the Adler-32 value of the dictionary required for
 * decompression.
 * <p>
 * The bytes in given byte buffer will be fully consumed by this method.  On
 * return, its position will equal its limit.
 *
 * @param dictionary the dictionary data bytes
 * @see Inflater#inflate
 * @see Inflater#getAdler
 */
public void setDictionary(ByteBuffer dictionary) {
    synchronized (zsRef) {
        int position = dictionary.position();
        int remaining = Math.max(dictionary.limit() - position, 0);
        ensureOpen();
        if (dictionary.isDirect()) {
            long address = ((DirectBuffer) dictionary).address();
            try {
                setDictionaryBuffer(zsRef.address(), address + position, remaining);
            } finally {
                Reference.reachabilityFence(dictionary);
            }
        } else {
            byte[] array = ZipUtils.getBufferArray(dictionary);
            int offset = ZipUtils.getBufferOffset(dictionary);
            setDictionary(zsRef.address(), array, offset + position, remaining);
        }
        dictionary.position(position + remaining);
    }
}
 
Example 2
Source File: Inflater.java    From Bytecoder with Apache License 2.0 6 votes vote down vote up
/**
 * Sets the preset dictionary to the bytes in the given buffer. Should be
 * called when inflate() returns 0 and needsDictionary() returns true
 * indicating that a preset dictionary is required. The method getAdler()
 * can be used to get the Adler-32 value of the dictionary needed.
 * <p>
 * The bytes in given byte buffer will be fully consumed by this method.  On
 * return, its position will equal its limit.
 *
 * @param dictionary the dictionary data bytes
 * @see Inflater#needsDictionary
 * @see Inflater#getAdler
 * @since 11
 */
public void setDictionary(ByteBuffer dictionary) {
    synchronized (zsRef) {
        int position = dictionary.position();
        int remaining = Math.max(dictionary.limit() - position, 0);
        ensureOpen();
        if (dictionary.isDirect()) {
            long address = ((DirectBuffer) dictionary).address();
            try {
                setDictionaryBuffer(zsRef.address(), address + position, remaining);
            } finally {
                Reference.reachabilityFence(dictionary);
            }
        } else {
            byte[] array = ZipUtils.getBufferArray(dictionary);
            int offset = ZipUtils.getBufferOffset(dictionary);
            setDictionary(zsRef.address(), array, offset + position, remaining);
        }
        dictionary.position(position + remaining);
        needDict = false;
    }
}
 
Example 3
Source File: ReachabilityFenceTest.java    From openjdk-jdk9 with GNU General Public License v2.0 6 votes vote down vote up
public static boolean fenced() {
    AtomicBoolean finalized = new AtomicBoolean();
    MyFinalizeable o = new MyFinalizeable(finalized);

    for (int i = 0; i < LOOP_ITERS; i++) {
        if (finalized.get()) break;
        if (i > WARMUP_LOOP_ITERS) {
            System.gc();
            System.runFinalization();
        }
    }

    Reference.reachabilityFence(o);

    return finalized.get();
}
 
Example 4
Source File: PBKDF2KeyImpl.java    From Bytecoder with Apache License 2.0 5 votes vote down vote up
public char[] getPassword() {
    // The password is zeroized by finalize()
    // The reachability fence ensures finalize() isn't called early
    char[] result = passwd.clone();
    Reference.reachabilityFence(this);
    return result;
}
 
Example 5
Source File: SoftCleanable.java    From openjdk-jdk9 with GNU General Public License v2.0 5 votes vote down vote up
/**
 * Constructs new {@code SoftCleanableReference} with
 * {@code non-null referent} and {@code non-null cleaner}.
 * The {@code cleaner} is not retained by this reference; it is only used
 * to register the newly constructed {@link Cleaner.Cleanable Cleanable}.
 *
 * @param referent the referent to track
 * @param cleaner  the {@code Cleaner} to register with
 */
public SoftCleanable(T referent, Cleaner cleaner) {
    super(Objects.requireNonNull(referent), CleanerImpl.getCleanerImpl(cleaner).queue);
    list = CleanerImpl.getCleanerImpl(cleaner).softCleanableList;
    insert();

    // Ensure referent and cleaner remain accessible
    Reference.reachabilityFence(referent);
    Reference.reachabilityFence(cleaner);
}
 
Example 6
Source File: WeakCleanable.java    From openjdk-jdk9 with GNU General Public License v2.0 5 votes vote down vote up
/**
 * Constructs new {@code WeakCleanableReference} with
 * {@code non-null referent} and {@code non-null cleaner}.
 * The {@code cleaner} is not retained by this reference; it is only used
 * to register the newly constructed {@link Cleaner.Cleanable Cleanable}.
 *
 * @param referent the referent to track
 * @param cleaner  the {@code Cleaner} to register new reference with
 */
public WeakCleanable(T referent, Cleaner cleaner) {
    super(Objects.requireNonNull(referent), CleanerImpl.getCleanerImpl(cleaner).queue);
    list = CleanerImpl.getCleanerImpl(cleaner).weakCleanableList;
    insert();

    // Ensure referent and cleaner remain accessible
    Reference.reachabilityFence(referent);
    Reference.reachabilityFence(cleaner);

}
 
Example 7
Source File: PhantomCleanable.java    From openjdk-jdk9 with GNU General Public License v2.0 5 votes vote down vote up
/**
 * Constructs new {@code PhantomCleanable} with
 * {@code non-null referent} and {@code non-null cleaner}.
 * The {@code cleaner} is not retained; it is only used to
 * register the newly constructed {@link Cleaner.Cleanable Cleanable}.
 *
 * @param referent the referent to track
 * @param cleaner  the {@code Cleaner} to register with
 */
public PhantomCleanable(T referent, Cleaner cleaner) {
    super(Objects.requireNonNull(referent), CleanerImpl.getCleanerImpl(cleaner).queue);
    this.list = CleanerImpl.getCleanerImpl(cleaner).phantomCleanableList;
    insert();

    // Ensure referent and cleaner remain accessible
    Reference.reachabilityFence(referent);
    Reference.reachabilityFence(cleaner);
}
 
Example 8
Source File: DESKey.java    From Bytecoder with Apache License 2.0 5 votes vote down vote up
public byte[] getEncoded() {
    // Return a copy of the key, rather than a reference,
    // so that the key data cannot be modified from outside

    // The key is zeroized by finalize()
    // The reachability fence ensures finalize() isn't called early
    byte[] result = key.clone();
    Reference.reachabilityFence(this);
    return result;
}
 
Example 9
Source File: PBEKey.java    From Bytecoder with Apache License 2.0 5 votes vote down vote up
public byte[] getEncoded() {
    // The key is zeroized by finalize()
    // The reachability fence ensures finalize() isn't called early
    byte[] result = key.clone();
    Reference.reachabilityFence(this);
    return result;
}
 
Example 10
Source File: PBKDF2KeyImpl.java    From Bytecoder with Apache License 2.0 5 votes vote down vote up
public byte[] getEncoded() {
    // The key is zeroized by finalize()
    // The reachability fence ensures finalize() isn't called early
    byte[] result = key.clone();
    Reference.reachabilityFence(this);
    return result;
}
 
Example 11
Source File: DESedeKey.java    From Bytecoder with Apache License 2.0 5 votes vote down vote up
public byte[] getEncoded() {
    // The key is zeroized by finalize()
    // The reachability fence ensures finalize() isn't called early
    byte[] result = key.clone();
    Reference.reachabilityFence(this);
    return result;
}
 
Example 12
Source File: SoftCleanable.java    From Bytecoder with Apache License 2.0 5 votes vote down vote up
/**
 * Constructs new {@code SoftCleanableReference} with
 * {@code non-null referent} and {@code non-null cleaner}.
 * The {@code cleaner} is not retained by this reference; it is only used
 * to register the newly constructed {@link Cleaner.Cleanable Cleanable}.
 *
 * @param referent the referent to track
 * @param cleaner  the {@code Cleaner} to register with
 */
public SoftCleanable(T referent, Cleaner cleaner) {
    super(Objects.requireNonNull(referent), CleanerImpl.getCleanerImpl(cleaner).queue);
    list = CleanerImpl.getCleanerImpl(cleaner).softCleanableList;
    insert();

    // Ensure referent and cleaner remain accessible
    Reference.reachabilityFence(referent);
    Reference.reachabilityFence(cleaner);
}
 
Example 13
Source File: WeakCleanable.java    From Bytecoder with Apache License 2.0 5 votes vote down vote up
/**
 * Constructs new {@code WeakCleanableReference} with
 * {@code non-null referent} and {@code non-null cleaner}.
 * The {@code cleaner} is not retained by this reference; it is only used
 * to register the newly constructed {@link Cleaner.Cleanable Cleanable}.
 *
 * @param referent the referent to track
 * @param cleaner  the {@code Cleaner} to register new reference with
 */
public WeakCleanable(T referent, Cleaner cleaner) {
    super(Objects.requireNonNull(referent), CleanerImpl.getCleanerImpl(cleaner).queue);
    list = CleanerImpl.getCleanerImpl(cleaner).weakCleanableList;
    insert();

    // Ensure referent and cleaner remain accessible
    Reference.reachabilityFence(referent);
    Reference.reachabilityFence(cleaner);

}
 
Example 14
Source File: PhantomCleanable.java    From Bytecoder with Apache License 2.0 5 votes vote down vote up
/**
 * Constructs new {@code PhantomCleanable} with
 * {@code non-null referent} and {@code non-null cleaner}.
 * The {@code cleaner} is not retained; it is only used to
 * register the newly constructed {@link Cleaner.Cleanable Cleanable}.
 *
 * @param referent the referent to track
 * @param cleaner  the {@code Cleaner} to register with
 */
public PhantomCleanable(T referent, Cleaner cleaner) {
    super(Objects.requireNonNull(referent), CleanerImpl.getCleanerImpl(cleaner).queue);
    this.list = CleanerImpl.getCleanerImpl(cleaner).phantomCleanableList;
    insert();

    // Ensure referent and cleaner remain accessible
    Reference.reachabilityFence(referent);
    Reference.reachabilityFence(cleaner);
}
 
Example 15
Source File: ResourceBundle.java    From openjdk-jdk9 with GNU General Public License v2.0 4 votes vote down vote up
private static ResourceBundle getBundleImpl(Module callerModule,
                                            Module module,
                                            String baseName,
                                            Locale locale,
                                            Control control) {
    if (locale == null || control == null) {
        throw new NullPointerException();
    }

    // We create a CacheKey here for use by this call. The base name
    // and modules will never change during the bundle loading
    // process. We have to make sure that the locale is set before
    // using it as a cache key.
    CacheKey cacheKey = new CacheKey(baseName, locale, module, callerModule);
    ResourceBundle bundle = null;

    // Quick lookup of the cache.
    BundleReference bundleRef = cacheList.get(cacheKey);
    if (bundleRef != null) {
        bundle = bundleRef.get();
        bundleRef = null;
    }

    // If this bundle and all of its parents are valid (not expired),
    // then return this bundle. If any of the bundles is expired, we
    // don't call control.needsReload here but instead drop into the
    // complete loading process below.
    if (isValidBundle(bundle) && hasValidParentChain(bundle)) {
        return bundle;
    }

    // No valid bundle was found in the cache, so we need to load the
    // resource bundle and its parents.

    boolean isKnownControl = (control == Control.INSTANCE) ||
                               (control instanceof SingleFormatControl);
    List<String> formats = control.getFormats(baseName);
    if (!isKnownControl && !checkList(formats)) {
        throw new IllegalArgumentException("Invalid Control: getFormats");
    }

    ResourceBundle baseBundle = null;
    for (Locale targetLocale = locale;
         targetLocale != null;
         targetLocale = control.getFallbackLocale(baseName, targetLocale)) {
        List<Locale> candidateLocales = control.getCandidateLocales(baseName, targetLocale);
        if (!isKnownControl && !checkList(candidateLocales)) {
            throw new IllegalArgumentException("Invalid Control: getCandidateLocales");
        }

        bundle = findBundle(callerModule, module, cacheKey,
                            candidateLocales, formats, 0, control, baseBundle);

        // If the loaded bundle is the base bundle and exactly for the
        // requested locale or the only candidate locale, then take the
        // bundle as the resulting one. If the loaded bundle is the base
        // bundle, it's put on hold until we finish processing all
        // fallback locales.
        if (isValidBundle(bundle)) {
            boolean isBaseBundle = Locale.ROOT.equals(bundle.locale);
            if (!isBaseBundle || bundle.locale.equals(locale)
                || (candidateLocales.size() == 1
                    && bundle.locale.equals(candidateLocales.get(0)))) {
                break;
            }

            // If the base bundle has been loaded, keep the reference in
            // baseBundle so that we can avoid any redundant loading in case
            // the control specify not to cache bundles.
            if (isBaseBundle && baseBundle == null) {
                baseBundle = bundle;
            }
        }
    }

    if (bundle == null) {
        if (baseBundle == null) {
            throwMissingResourceException(baseName, locale, cacheKey.getCause());
        }
        bundle = baseBundle;
    }

    // keep callerModule and module reachable for as long as we are operating
    // with WeakReference(s) to them (in CacheKey)...
    Reference.reachabilityFence(callerModule);
    Reference.reachabilityFence(module);

    return bundle;
}
 
Example 16
Source File: SSLSessionFinalizeTest.java    From openjdk-jdk9 with GNU General Public License v2.0 4 votes vote down vote up
SBListener doClientSide() throws Exception {

        /*
         * Wait for server to get started.
         */
        while (!serverReady) {
            Thread.sleep(50);
        }

        SSLSocketFactory sslsf =
            (SSLSocketFactory) SSLSocketFactory.getDefault();

        try {
                SSLSocket sslSocket = (SSLSocket)
                    sslsf.createSocket("localhost", serverPort);
                InputStream sslIS = sslSocket.getInputStream();
                OutputStream sslOS = sslSocket.getOutputStream();

            sslOS.write(280);
            sslOS.flush();
            sslIS.read();

            sslOS.close();
            sslIS.close();

            SSLSession sslSession = sslSocket.getSession();
            System.out.printf(" sslSession: %s %n   %s%n", sslSession, sslSession.getClass());
            SBListener sbListener = new SBListener(sslSession);

            sslSession.putValue("x", sbListener);

            sslSession.invalidate();

            sslSocket.close();

            sslOS = null;
            sslIS = null;
            sslSession = null;
            sslSocket = null;
            Reference.reachabilityFence(sslOS);
            Reference.reachabilityFence(sslIS);
            Reference.reachabilityFence(sslSession);
            Reference.reachabilityFence(sslSocket);

            return sbListener;
        } catch (Exception ex) {
            ex.printStackTrace();
            throw ex;
        }
    }
 
Example 17
Source File: ResourceBundle.java    From Bytecoder with Apache License 2.0 4 votes vote down vote up
private static ResourceBundle getBundleImpl(Module callerModule,
                                            Module module,
                                            String baseName,
                                            Locale locale,
                                            Control control) {
    if (locale == null || control == null) {
        throw new NullPointerException();
    }

    // We create a CacheKey here for use by this call. The base name
    // and modules will never change during the bundle loading
    // process. We have to make sure that the locale is set before
    // using it as a cache key.
    CacheKey cacheKey = new CacheKey(baseName, locale, module, callerModule);
    ResourceBundle bundle = null;

    // Quick lookup of the cache.
    BundleReference bundleRef = cacheList.get(cacheKey);
    if (bundleRef != null) {
        bundle = bundleRef.get();
        bundleRef = null;
    }

    // If this bundle and all of its parents are valid (not expired),
    // then return this bundle. If any of the bundles is expired, we
    // don't call control.needsReload here but instead drop into the
    // complete loading process below.
    if (isValidBundle(bundle) && hasValidParentChain(bundle)) {
        return bundle;
    }

    // No valid bundle was found in the cache, so we need to load the
    // resource bundle and its parents.

    boolean isKnownControl = (control == Control.INSTANCE) ||
                               (control instanceof SingleFormatControl);
    List<String> formats = control.getFormats(baseName);
    if (!isKnownControl && !checkList(formats)) {
        throw new IllegalArgumentException("Invalid Control: getFormats");
    }

    ResourceBundle baseBundle = null;
    for (Locale targetLocale = locale;
         targetLocale != null;
         targetLocale = control.getFallbackLocale(baseName, targetLocale)) {
        List<Locale> candidateLocales = control.getCandidateLocales(baseName, targetLocale);
        if (!isKnownControl && !checkList(candidateLocales)) {
            throw new IllegalArgumentException("Invalid Control: getCandidateLocales");
        }

        bundle = findBundle(callerModule, module, cacheKey,
                            candidateLocales, formats, 0, control, baseBundle);

        // If the loaded bundle is the base bundle and exactly for the
        // requested locale or the only candidate locale, then take the
        // bundle as the resulting one. If the loaded bundle is the base
        // bundle, it's put on hold until we finish processing all
        // fallback locales.
        if (isValidBundle(bundle)) {
            boolean isBaseBundle = Locale.ROOT.equals(bundle.locale);
            if (!isBaseBundle || bundle.locale.equals(locale)
                || (candidateLocales.size() == 1
                    && bundle.locale.equals(candidateLocales.get(0)))) {
                break;
            }

            // If the base bundle has been loaded, keep the reference in
            // baseBundle so that we can avoid any redundant loading in case
            // the control specify not to cache bundles.
            if (isBaseBundle && baseBundle == null) {
                baseBundle = bundle;
            }
        }
    }

    if (bundle == null) {
        if (baseBundle == null) {
            throwMissingResourceException(baseName, locale, cacheKey.getCause());
        }
        bundle = baseBundle;
    }

    // keep callerModule and module reachable for as long as we are operating
    // with WeakReference(s) to them (in CacheKey)...
    Reference.reachabilityFence(callerModule);
    Reference.reachabilityFence(module);

    return bundle;
}
 
Example 18
Source File: SystemLoggerConfigTest.java    From openjdk-jdk9 with GNU General Public License v2.0 4 votes vote down vote up
public static void test(String name, String step, String ext)
        throws IOException {

    System.out.println("\n*** Testing " + name + step + ext);

    final String systemName1a = "system.logger.one.a." + name + step + ext;
    final String systemName1b = "system.logger.one.b." + name + step + ext;
    final String appName1a = "system.logger.one.a." + name + step;
    final String appName1b = "system.logger.one.b." + name + step;
    final String msg1a = "logger name: " + systemName1a;
    final String msg1b = "logger name: " + systemName1b;
    final String systemName2 = "system.logger.two." + name + step + ext;
    final String appName2 = "system.logger.two." + name + step;
    final String msg2 = "logger name: " + systemName2;
    final String systemName3 = "system.logger.three." + name + step + ext;
    final String appName3 = "system.logger.three." + name + step;
    final String msg3 = "logger name: " + systemName3;
    List<LogRecord> records;

    System.out.println("\n[Case #1] Creating platform logger: " + systemName1a);
    PlatformLogger system1a = createPlatformLogger(systemName1a);
    System.out.println("    Creating platform logger: " + systemName1b);
    PlatformLogger system1b = createPlatformLogger(systemName1b);
    System.out.println("    Adding handler on root logger...");
    TestHandler test1 = new TestHandler();
    Logger.getLogger("").addHandler(test1);

    System.out.println("    Creating and configuring app logger: " + appName1a
            + ", " + appName1b);
    Logger app1a = Logger.getLogger(appName1a);
    app1a.setLevel(Level.INFO);
    Logger app1b = Logger.getLogger(appName1b);
    app1b.setLevel(Level.INFO);
    assertFalse(system1a.isLoggable(PlatformLogger.Level.FINEST),
            "Unexpected level for " + system1a);
    System.out.println("    Configuring root logger...");
    Logger.getLogger("").setLevel(Level.FINEST);
    System.out.println("    Logging through system logger: " + systemName1a);
    system1a.finest(msg1a);
    Reference.reachabilityFence(app1a);
    records = test1.drain();
    assertEquals(0, records.size(), "Unexpected size for " + records.toString());
    System.out.println("    Logging through system logger: " + systemName1b);
    system1b.finest(msg1b);
    Reference.reachabilityFence(app1b);
    records = test1.drain();
    assertEquals(0, records.size(), "Unexpected size for " + records.toString());
    Logger.getLogger("system.logger.one.a").finest("system.logger.one.a");
    records = test1.drain();
    assertEquals("system.logger.one.a", records.get(0).getMessage(), "Unexpected message: ");
    Logger.getLogger("").setLevel(Level.INFO);
    Logger.getLogger("system.logger.one.a").finest("system.logger.one.a");
    records = test1.drain();
    assertEquals(0, records.size(), "Unexpected size for " + records.toString());

    Reference.reachabilityFence(system1a);
    Reference.reachabilityFence(system1b);

    System.out.println("\n[Case #2] Creating system logger: " + systemName2);
    Logger system2 = createSystemLogger(systemName2);
    System.out.println("    Creating app logger: " + appName2);
    Logger app2 = Logger.getLogger(appName2);
    System.out.println("    Configuring app logger...");
    TestHandler test2 = new TestHandler();
    app2.setLevel(Level.ALL);
    app2.setUseParentHandlers(false);
    app2.addHandler(test2);
    System.out.println("    Logging through system logger: " + systemName2);
    system2.finest(msg2);
    records = test2.drain();
    assertEquals(1, records.size(), "Unexpected size for " + records.toString());
    assertEquals(msg2, records.get(0).getMessage(), "Unexpected message: ");
    records = test1.drain();
    assertEquals(0, records.size(), "Unexpected size for " + records.toString());

    Reference.reachabilityFence(app2);
    Reference.reachabilityFence(system2);

    System.out.println("\n[Case #3] Creating app logger: " + appName3);
    Logger app3 = Logger.getLogger(appName3);
    System.out.println("    Configuring app logger...");
    TestHandler test3 = new TestHandler();
    app3.setLevel(Level.ALL);
    app3.setUseParentHandlers(false);
    app3.addHandler(test3);
    System.out.println("    Creating system logger: " + systemName3);
    Logger system3 = createSystemLogger(systemName3);
    System.out.println("    Logging through system logger: " + systemName3);
    system3.finest(msg3);
    records = test3.drain();
    assertEquals(1, records.size(), "Unexpected size for " + records.toString());
    assertEquals(msg3, records.get(0).getMessage(), "Unexpected message: ");
    records = test1.drain();
    assertEquals(0, records.size(), "Unexpected size for " + records.toString());

    Reference.reachabilityFence(app3);
    Reference.reachabilityFence(system3);
    System.gc();

}
 
Example 19
Source File: WeakPairMap.java    From Bytecoder with Apache License 2.0 3 votes vote down vote up
/**
 * If the specified key pair is not already associated with a value,
 * attempts to compute its value using the given mapping function
 * and enters it into this WeakPairMap unless {@code null}. The entire
 * method invocation is performed atomically, so the function is
 * applied at most once per key pair. Some attempted update operations
 * on this WeakPairMap by other threads may be blocked while computation
 * is in progress, so the computation should be short and simple,
 * and must not attempt to update any other mappings of this WeakPairMap.
 *
 * @param k1              the 1st of the pair of keys with which the
 *                        computed value is to be associated
 * @param k2              the 2nd of the pair of keys with which the
 *                        computed value is to be associated
 * @param mappingFunction the function to compute a value
 * @return the current (existing or computed) value associated with
 * the specified key pair, or null if the computed value is null
 * @throws NullPointerException  if any of the specified keys or
 *                               mappingFunction is null
 * @throws IllegalStateException if the computation detectably
 *                               attempts a recursive update to this map
 *                               that would otherwise never complete
 * @throws RuntimeException      or Error if the mappingFunction does so, in
 *                               which case the mapping is left unestablished
 */
public V computeIfAbsent(K1 k1, K2 k2,
                         BiFunction<? super K1, ? super K2, ? extends V>
                             mappingFunction) {
    expungeStaleAssociations();
    try {
        return map.computeIfAbsent(
            Pair.weak(k1, k2, queue),
            pair -> mappingFunction.apply(pair.first(), pair.second()));
    } finally {
        Reference.reachabilityFence(k1);
        Reference.reachabilityFence(k2);
    }
}
 
Example 20
Source File: WeakPairMap.java    From openjdk-jdk9 with GNU General Public License v2.0 3 votes vote down vote up
/**
 * If the specified key pair is not already associated with a value,
 * attempts to compute its value using the given mapping function
 * and enters it into this WeakPairMap unless {@code null}. The entire
 * method invocation is performed atomically, so the function is
 * applied at most once per key pair. Some attempted update operations
 * on this WeakPairMap by other threads may be blocked while computation
 * is in progress, so the computation should be short and simple,
 * and must not attempt to update any other mappings of this WeakPairMap.
 *
 * @param k1              the 1st of the pair of keys with which the
 *                        computed value is to be associated
 * @param k2              the 2nd of the pair of keys with which the
 *                        computed value is to be associated
 * @param mappingFunction the function to compute a value
 * @return the current (existing or computed) value associated with
 * the specified key pair, or null if the computed value is null
 * @throws NullPointerException  if any of the specified keys or
 *                               mappingFunction is null
 * @throws IllegalStateException if the computation detectably
 *                               attempts a recursive update to this map
 *                               that would otherwise never complete
 * @throws RuntimeException      or Error if the mappingFunction does so, in
 *                               which case the mapping is left unestablished
 */
public V computeIfAbsent(K1 k1, K2 k2,
                         BiFunction<? super K1, ? super K2, ? extends V>
                             mappingFunction) {
    expungeStaleAssociations();
    try {
        return map.computeIfAbsent(
            Pair.weak(k1, k2, queue),
            pair -> mappingFunction.apply(pair.first(), pair.second()));
    } finally {
        Reference.reachabilityFence(k1);
        Reference.reachabilityFence(k2);
    }
}