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}