001/*
002 *  This file is part of the Jikes RVM project (http://jikesrvm.org).
003 *
004 *  This file is licensed to You under the Eclipse Public License (EPL);
005 *  You may not use this file except in compliance with the License. You
006 *  may obtain a copy of the License at
007 *
008 *      http://www.opensource.org/licenses/eclipse-1.0.php
009 *
010 *  See the COPYRIGHT.txt file distributed with this work for information
011 *  regarding copyright ownership.
012 */
013package org.jikesrvm.jni;
014
015import java.lang.ref.WeakReference;
016import org.jikesrvm.VM;
017import org.jikesrvm.runtime.Magic;
018import org.jikesrvm.mm.mminterface.MemoryManager;
019import org.vmmagic.pragma.Entrypoint;
020import org.vmmagic.pragma.Uninterruptible;
021import org.vmmagic.unboxed.ObjectReference;
022import org.vmmagic.unboxed.AddressArray;
023import org.vmmagic.unboxed.Address;
024
025/**
026 * Weak Global References are global references (negative numbers), with the
027 * 2^30 bit UNset.  Mask in the 2^30 bit to get the real index into the table.
028 */
029public class JNIGlobalRefTable {
030
031  @Entrypoint
032  public static AddressArray JNIGlobalRefs = AddressArray.create(100);
033  private static int free = 1;
034
035  static int newGlobalRef(Object referent) {
036    if (VM.VerifyAssertions) VM._assert(MemoryManager.validRef(ObjectReference.fromObject(referent)));
037
038    if (free >= JNIGlobalRefs.length()) {
039      AddressArray newGlobalRefs = AddressArray.create(JNIGlobalRefs.length() * 2);
040      copyAndReplaceGlobalRefs(newGlobalRefs);
041    }
042
043    JNIGlobalRefs.set(free, Magic.objectAsAddress(referent));
044    return -free++;
045  }
046
047  @Uninterruptible
048  private static void copyAndReplaceGlobalRefs(AddressArray newGlobalRefs) {
049    for (int i = 0; i < JNIGlobalRefs.length(); i++) {
050      newGlobalRefs.set(i, JNIGlobalRefs.get(i));
051    }
052    JNIGlobalRefs = newGlobalRefs;
053  }
054
055  /* Weak references are returned with the STRONG_REF_BIT bit UNset.  */
056  public static final int STRONG_REF_BIT = 1 << 30;
057
058  static int newWeakRef(Object referent) {
059    int gref = newGlobalRef(new WeakReference<Object>(referent));
060    return gref & ~STRONG_REF_BIT;
061  }
062
063  static void deleteGlobalRef(int index) {
064    if (VM.VerifyAssertions) VM._assert(!isWeakRef(index));
065    JNIGlobalRefs.set(-index, Address.zero());
066  }
067
068  static void deleteWeakRef(int index) {
069    if (VM.VerifyAssertions) VM._assert(isWeakRef(index));
070    int gref = index | STRONG_REF_BIT;
071    deleteGlobalRef(gref);
072  }
073
074  @Uninterruptible
075  static Object globalRef(int index) {
076    if (VM.VerifyAssertions) VM._assert(!isWeakRef(index));
077
078    return Magic.addressAsObject(JNIGlobalRefs.get(-index));
079  }
080
081  @Uninterruptible
082  static Object weakRef(int index) {
083    if (VM.VerifyAssertions) VM._assert(isWeakRef(index));
084    @SuppressWarnings("unchecked") // yes, we're being bad.
085    WeakReference<Object> ref = (WeakReference<Object>) globalRef(index | STRONG_REF_BIT);
086    return java.lang.ref.JikesRVMSupport.uninterruptibleReferenceGet(ref);
087  }
088
089  @Uninterruptible
090  static Object ref(int index) {
091    if (isWeakRef(index)) {
092      return weakRef(index);
093    } else {
094      return globalRef(index);
095    }
096  }
097
098  @Uninterruptible
099  static boolean isWeakRef(int index) {
100    return (index & STRONG_REF_BIT) == 0;
101  }
102}