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 perfrom 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 * <p> 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 }