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     */
013    package org.jikesrvm.jni;
014    
015    import java.lang.ref.WeakReference;
016    import org.jikesrvm.VM;
017    import org.jikesrvm.runtime.Magic;
018    import org.jikesrvm.mm.mminterface.MemoryManager;
019    import org.vmmagic.pragma.Entrypoint;
020    import org.vmmagic.pragma.Uninterruptible;
021    import org.vmmagic.unboxed.ObjectReference;
022    import org.vmmagic.unboxed.AddressArray;
023    import 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     */
029    public 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    }