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    }