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 }