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