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.runtime; 014 015 import org.jikesrvm.ArchitectureSpecific.CodeArray; 016 import org.jikesrvm.ArchitectureSpecific.DynamicLinkerHelper; 017 import org.jikesrvm.VM; 018 import org.jikesrvm.Constants; 019 import org.jikesrvm.classloader.RVMClass; 020 import org.jikesrvm.classloader.RVMMethod; 021 import org.jikesrvm.classloader.MethodReference; 022 import org.jikesrvm.compilers.common.CompiledMethod; 023 import org.jikesrvm.compilers.common.CompiledMethods; 024 import org.vmmagic.pragma.DynamicBridge; 025 import org.vmmagic.pragma.Entrypoint; 026 import org.vmmagic.pragma.NoInline; 027 import org.vmmagic.unboxed.Address; 028 import org.vmmagic.unboxed.Offset; 029 030 /** 031 * Implement lazy compilation. 032 */ 033 @DynamicBridge 034 public class DynamicLinker implements Constants { 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 * Discover method reference to be invoked via dynamic bridge. 086 * <pre> 087 * Taken: nothing (call stack is examined to find invocation site) 088 * Returned: DynamicLink that describes call site. 089 * </pre> 090 */ 091 @NoInline 092 static DynamicLink resolveDynamicInvocation() { 093 094 // find call site 095 // 096 VM.disableGC(); 097 Address callingFrame = Magic.getCallerFramePointer(Magic.getFramePointer()); 098 Address returnAddress = Magic.getReturnAddressUnchecked(callingFrame); 099 callingFrame = Magic.getCallerFramePointer(callingFrame); 100 int callingCompiledMethodId = Magic.getCompiledMethodID(callingFrame); 101 CompiledMethod callingCompiledMethod = CompiledMethods.getCompiledMethod(callingCompiledMethodId); 102 Offset callingInstructionOffset = callingCompiledMethod.getInstructionOffset(returnAddress); 103 VM.enableGC(); 104 105 // obtain symbolic method reference 106 // 107 DynamicLink dynamicLink = new DynamicLink(); 108 callingCompiledMethod.getDynamicLink(dynamicLink, callingInstructionOffset); 109 110 return dynamicLink; 111 } 112 113 /** 114 * Resolve method ref into appropriate RVMMethod 115 * <pre> 116 * Taken: DynamicLink that describes call site. 117 * Returned: RVMMethod that should be invoked. 118 * </pre> 119 */ 120 @NoInline 121 static RVMMethod resolveMethodRef(DynamicLink dynamicLink) { 122 // resolve symbolic method reference into actual method 123 // 124 MethodReference methodRef = dynamicLink.methodRef(); 125 if (dynamicLink.isInvokeSpecial()) { 126 return methodRef.resolveInvokeSpecial(); 127 } else if (dynamicLink.isInvokeStatic()) { 128 return methodRef.resolve(); 129 } else { 130 // invokevirtual or invokeinterface 131 VM.disableGC(); 132 Object targetObject = DynamicLinkerHelper.getReceiverObject(); 133 VM.enableGC(); 134 RVMClass targetClass = Magic.getObjectType(targetObject).asClass(); 135 RVMMethod targetMethod = targetClass.findVirtualMethod(methodRef.getName(), methodRef.getDescriptor()); 136 if (targetMethod == null) { 137 throw new IncompatibleClassChangeError(targetClass.getDescriptor().classNameFromDescriptor()); 138 } 139 return targetMethod; 140 } 141 } 142 143 /** 144 * Compile (if necessary) targetMethod and patch the appropriate disaptch tables 145 * @param targetMethod the RVMMethod to compile (if not already compiled) 146 */ 147 @NoInline 148 static void compileMethod(DynamicLink dynamicLink, RVMMethod targetMethod) { 149 150 RVMClass targetClass = targetMethod.getDeclaringClass(); 151 152 // if necessary, compile method 153 // 154 if (!targetMethod.isCompiled()) { 155 targetMethod.compile(); 156 157 // If targetMethod is a virtual method, then eagerly patch tib of declaring class. 158 // (we need to do this to get the method test used by opt to work with lazy compilation). 159 if (!(targetMethod.isObjectInitializer() || targetMethod.isStatic())) { 160 targetClass.updateTIBEntry(targetMethod); 161 } 162 } 163 164 // patch appropriate dispatch table 165 // 166 if (targetMethod.isObjectInitializer() || targetMethod.isStatic()) { 167 targetClass.updateJTOCEntry(targetMethod); 168 } else if (dynamicLink.isInvokeSpecial()) { 169 targetClass.updateTIBEntry(targetMethod); 170 } else { 171 VM.disableGC(); 172 Object targetObject = DynamicLinkerHelper.getReceiverObject(); 173 VM.enableGC(); 174 RVMClass recvClass = (RVMClass) Magic.getObjectType(targetObject); 175 recvClass.updateTIBEntry(targetMethod); 176 } 177 } 178 } 179 }