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.classloader;
014    
015    import org.jikesrvm.VM;
016    import org.jikesrvm.Constants;
017    import org.jikesrvm.mm.mminterface.MemoryManager;
018    import org.jikesrvm.runtime.Magic;
019    import org.jikesrvm.runtime.RuntimeEntrypoints;
020    import org.vmmagic.pragma.Entrypoint;
021    
022    /**
023     * Dynamic linking via indirection tables. <p>
024     *
025     * The main idea for dynamic linking is that we maintain
026     * arrays of member offsets indexed by the member's
027     * dynamic linking id. The generated code at a dynamically linked
028     * site will load the appropriate value from the offset table and
029     * check to see if the value is valid. If it is, then no dynamic linking
030     * is required.  If the value is invalid, then resolveDynamicLink
031     * is invoked to perform any required dynamic class loading.
032     * After member resolution and class loading completes, we can
033     * store the offset value in the offset table.
034     * Thus when resolve method returns, execution can be restarted
035     * by reloading/indexing the offset table. <p>
036     *
037     * NOTE: We believe that only use of invokespecial that could possibly
038     * require dynamic linking is that of invoking an object initializer.
039     */
040    public class TableBasedDynamicLinker implements Constants {
041    
042      /**
043       * Linking table keyed by member reference IDs. Value indicates offset of
044       * member or whether the member needs linking.
045       */
046      @Entrypoint
047      private static int[] memberOffsets;
048    
049      static {
050        memberOffsets = MemoryManager.newContiguousIntArray(32000);
051        if (NEEDS_DYNAMIC_LINK != 0) {
052          java.util.Arrays.fill(memberOffsets, NEEDS_DYNAMIC_LINK);
053        }
054      }
055    
056      /**
057       * Cause dynamic linking of the RVMMember whose member reference id is given.
058       * Invoked directly from (baseline) compiled code.
059       * @param memberId the dynamicLinkingId of the method to link.
060       * @return returns the offset of the member.
061       */
062      @Entrypoint
063      public static int resolveMember(int memberId) throws NoClassDefFoundError {
064        MemberReference ref = MemberReference.getMemberRef(memberId);
065        return resolveMember(ref);
066      }
067    
068      /**
069       * Cause dynamic linking of the argument MemberReference
070       * @param ref reference to the member to link
071       * @return returns the offset of the member.
072       */
073      public static int resolveMember(MemberReference ref) throws NoClassDefFoundError {
074        RVMMember resolvedMember = ref.resolveMember();
075        RVMClass declaringClass = resolvedMember.getDeclaringClass();
076        RuntimeEntrypoints.initializeClassForDynamicLink(declaringClass);
077        int offset = resolvedMember.getOffset().toInt();
078        if (VM.VerifyAssertions) VM._assert(offset != NEEDS_DYNAMIC_LINK);
079        memberOffsets[ref.getId()] = offset;
080        return offset;
081      }
082    
083      /**
084       * Method invoked from MemberReference to
085       * ensure that there is space in the dynamic linking table for
086       * the given member reference.
087       */
088      static synchronized void ensureCapacity(int id) {
089        if (id >= memberOffsets.length) {
090          int oldLen = memberOffsets.length;
091          int[] tmp1 = MemoryManager.newContiguousIntArray((oldLen * 3) / 2);
092          System.arraycopy(memberOffsets, 0, tmp1, 0, oldLen);
093          if (NEEDS_DYNAMIC_LINK != 0) {
094            java.util.Arrays.fill(tmp1, oldLen, tmp1.length, NEEDS_DYNAMIC_LINK);
095          }
096          Magic.sync(); // be sure array initialization is visible before we publish the reference!
097          memberOffsets = tmp1;
098        }
099      }
100    }