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.runtime; 014 015import static org.jikesrvm.VM.NOT_REACHED; 016 017import org.jikesrvm.VM; 018import org.jikesrvm.classloader.RVMClass; 019import org.jikesrvm.classloader.RVMMethod; 020import org.jikesrvm.classloader.MethodReference; 021import org.jikesrvm.compilers.common.CodeArray; 022import org.jikesrvm.compilers.common.CompiledMethod; 023import org.jikesrvm.compilers.common.CompiledMethods; 024import org.vmmagic.pragma.DynamicBridge; 025import org.vmmagic.pragma.Entrypoint; 026import org.vmmagic.pragma.NoInline; 027import org.vmmagic.unboxed.Address; 028import org.vmmagic.unboxed.Offset; 029 030/** 031 * Implement lazy compilation. 032 */ 033@DynamicBridge 034public class DynamicLinker { 035 036 /** 037 * Resolve, compile if necessary, and invoke a method. 038 * <pre> 039 * Taken: nothing (calling context is implicit) 040 * Returned: does not return (method dispatch table is updated and method is executed) 041 * </pre> 042 */ 043 @Entrypoint 044 static void lazyMethodInvoker() { 045 DynamicLink dl = DL_Helper.resolveDynamicInvocation(); 046 RVMMethod targMethod = DL_Helper.resolveMethodRef(dl); 047 DL_Helper.compileMethod(dl, targMethod); 048 CodeArray code = targMethod.getCurrentEntryCodeArray(); 049 Magic.dynamicBridgeTo(code); // restore parameters and invoke 050 if (VM.VerifyAssertions) VM._assert(NOT_REACHED); // does not return here 051 } 052 053 /** 054 * Report unimplemented native method error. 055 * <pre> 056 * Taken: nothing (calling context is implicit) 057 * Returned: does not return (throws UnsatisfiedLinkError) 058 * </pre> 059 */ 060 @Entrypoint 061 static void unimplementedNativeMethod() { 062 DynamicLink dl = DL_Helper.resolveDynamicInvocation(); 063 RVMMethod targMethod = DL_Helper.resolveMethodRef(dl); 064 throw new UnsatisfiedLinkError(targMethod.toString()); 065 } 066 067 /** 068 * Report a magic SysCall has been mistakenly invoked 069 */ 070 @Entrypoint 071 static void sysCallMethod() { 072 DynamicLink dl = DL_Helper.resolveDynamicInvocation(); 073 RVMMethod targMethod = DL_Helper.resolveMethodRef(dl); 074 throw new UnsatisfiedLinkError(targMethod.toString() + " which is a SysCall"); 075 } 076 077 /** 078 * Helper class that does the real work of resolving method references 079 * and compiling a lazy method invocation. In separate class so 080 * that it doesn't implement DynamicBridge magic. 081 */ 082 private static class DL_Helper { 083 084 /** 085 * Discovers a method reference to be invoked via dynamic bridge. The call 086 * stack is examined to find the invocation site. 087 * 088 * @return an DynamicLink describing the call site 089 */ 090 @NoInline 091 static DynamicLink resolveDynamicInvocation() { 092 093 // find call site 094 // 095 VM.disableGC(); 096 Address callingFrame = Magic.getCallerFramePointer(Magic.getFramePointer()); 097 Address returnAddress = Magic.getReturnAddressUnchecked(callingFrame); 098 callingFrame = Magic.getCallerFramePointer(callingFrame); 099 int callingCompiledMethodId = Magic.getCompiledMethodID(callingFrame); 100 CompiledMethod callingCompiledMethod = CompiledMethods.getCompiledMethod(callingCompiledMethodId); 101 Offset callingInstructionOffset = callingCompiledMethod.getInstructionOffset(returnAddress); 102 VM.enableGC(); 103 104 // obtain symbolic method reference 105 // 106 DynamicLink dynamicLink = new DynamicLink(); 107 callingCompiledMethod.getDynamicLink(dynamicLink, callingInstructionOffset); 108 109 return dynamicLink; 110 } 111 112 /** 113 * Resolves a method ref into appropriate RVMMethod. 114 * 115 * @param dynamicLink a DynamicLink that describes call site 116 * @return the RVMMethod that should be invoked. 117 */ 118 @NoInline 119 static RVMMethod resolveMethodRef(DynamicLink dynamicLink) { 120 // resolve symbolic method reference into actual method 121 // 122 MethodReference methodRef = dynamicLink.methodRef(); 123 if (dynamicLink.isInvokeSpecial()) { 124 return methodRef.resolveInvokeSpecial(); 125 } else if (dynamicLink.isInvokeStatic()) { 126 return methodRef.resolve(); 127 } else { 128 // invokevirtual or invokeinterface 129 VM.disableGC(); 130 Object targetObject; 131 if (VM.BuildForIA32) { 132 targetObject = org.jikesrvm.ia32.DynamicLinkerHelper.getReceiverObject(); 133 } else { 134 if (VM.VerifyAssertions) VM._assert(VM.BuildForPowerPC); 135 targetObject = org.jikesrvm.ppc.DynamicLinkerHelper.getReceiverObject(); 136 } 137 VM.enableGC(); 138 RVMClass targetClass = Magic.getObjectType(targetObject).asClass(); 139 RVMMethod targetMethod = targetClass.findVirtualMethod(methodRef.getName(), methodRef.getDescriptor()); 140 if (targetMethod == null) { 141 throw new IncompatibleClassChangeError(targetClass.getDescriptor().classNameFromDescriptor()); 142 } 143 return targetMethod; 144 } 145 } 146 147 /** 148 * Compile (if necessary) targetMethod and patch the appropriate dispatch tables. 149 * 150 * @param dynamicLink a DynamicLink that describes call site. 151 * @param targetMethod the RVMMethod to compile (if not already compiled) 152 */ 153 @NoInline 154 static void compileMethod(DynamicLink dynamicLink, RVMMethod targetMethod) { 155 156 RVMClass targetClass = targetMethod.getDeclaringClass(); 157 158 // if necessary, compile method 159 // 160 if (!targetMethod.isCompiled()) { 161 targetMethod.compile(); 162 163 // If targetMethod is a virtual method, then eagerly patch tib of declaring class. 164 // (we need to do this to get the method test used by opt to work with lazy compilation). 165 if (!(targetMethod.isObjectInitializer() || targetMethod.isStatic())) { 166 targetClass.updateTIBEntry(targetMethod); 167 } 168 } 169 170 // patch appropriate dispatch table 171 // 172 if (targetMethod.isObjectInitializer() || targetMethod.isStatic()) { 173 targetClass.updateJTOCEntry(targetMethod); 174 } else if (dynamicLink.isInvokeSpecial()) { 175 targetClass.updateTIBEntry(targetMethod); 176 } else { 177 VM.disableGC(); 178 Object targetObject; 179 if (VM.BuildForIA32) { 180 targetObject = org.jikesrvm.ia32.DynamicLinkerHelper.getReceiverObject(); 181 } else { 182 if (VM.VerifyAssertions) VM._assert(VM.BuildForPowerPC); 183 targetObject = org.jikesrvm.ppc.DynamicLinkerHelper.getReceiverObject(); 184 } 185 VM.enableGC(); 186 RVMClass recvClass = (RVMClass) Magic.getObjectType(targetObject); 187 recvClass.updateTIBEntry(targetMethod); 188 } 189 } 190 } 191}