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