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.mm.mmtk;
014    
015    import org.jikesrvm.ArchitectureSpecific;
016    import org.jikesrvm.VM;
017    import org.jikesrvm.Services;
018    import org.jikesrvm.classloader.MemberReference;
019    import org.jikesrvm.classloader.RVMMethod;
020    import org.jikesrvm.classloader.RVMType;
021    import org.jikesrvm.compilers.baseline.BaselineCompiledMethod;
022    import org.jikesrvm.compilers.common.CompiledMethod;
023    import org.jikesrvm.compilers.common.CompiledMethods;
024    import org.jikesrvm.compilers.opt.runtimesupport.OptCompiledMethod;
025    import org.jikesrvm.compilers.opt.runtimesupport.OptEncodedCallSiteTree;
026    import org.jikesrvm.compilers.opt.runtimesupport.OptMachineCodeMap;
027    import org.jikesrvm.objectmodel.MiscHeader;
028    import org.jikesrvm.objectmodel.ObjectModel;
029    import org.jikesrvm.objectmodel.TIB;
030    import org.jikesrvm.runtime.Magic;
031    import org.jikesrvm.scheduler.RVMThread;
032    import org.vmmagic.pragma.Inline;
033    import org.vmmagic.pragma.Interruptible;
034    import org.vmmagic.pragma.NoInline;
035    import org.vmmagic.pragma.Uninterruptible;
036    import org.vmmagic.unboxed.Address;
037    import org.vmmagic.unboxed.ObjectReference;
038    import org.vmmagic.unboxed.Offset;
039    import org.vmmagic.unboxed.Word;
040    
041    /**
042     * Class that supports scanning Objects or Arrays for references
043     * during tracing, handling those references, and computing death times
044     */
045    @Uninterruptible public final class TraceInterface extends org.mmtk.vm.TraceInterface implements ArchitectureSpecific.ArchConstants {
046    
047      /***********************************************************************
048       *
049       * Class variables
050       */
051    
052      /**
053       *
054       */
055      private static byte[][] allocCallMethods;
056    
057      static {
058        /* Build the list of "own methods" */
059        allocCallMethods = new byte[13][];
060        allocCallMethods[0] = "postAlloc".getBytes();
061        allocCallMethods[1] = "traceAlloc".getBytes();
062        allocCallMethods[2] = "allocateScalar".getBytes();
063        allocCallMethods[3] = "allocateArray".getBytes();
064        allocCallMethods[4] = "clone".getBytes();
065        allocCallMethods[5] = "alloc".getBytes();
066        allocCallMethods[6] = "buildMultiDimensionalArray".getBytes();
067        allocCallMethods[7] = "resolvedNewScalar".getBytes();
068        allocCallMethods[8] = "resolvedNewArray".getBytes();
069        allocCallMethods[9] = "unresolvedNewScalar".getBytes();
070        allocCallMethods[10] = "unresolvedNewArray".getBytes();
071        allocCallMethods[11] = "cloneScalar".getBytes();
072        allocCallMethods[12] = "cloneArray".getBytes();
073      }
074    
075      /***********************************************************************
076       *
077       * Public Methods
078       */
079    
080      /**
081       * {@inheritDoc}
082       */
083      @Override
084      public boolean gcEnabled() {
085        return RVMThread.gcEnabled();
086      }
087    
088      /**
089       * Given a method name, determine if it is a "real" method or one
090       * used for allocation/tracing.
091       *
092       * @param name The method name to test as an array of bytes
093       * @return {@code true} if the method is a "real" method, {@code false} otherwise.
094       */
095      private boolean isAllocCall(byte[] name) {
096        for (int i = 0; i < allocCallMethods.length; i++) {
097          byte[] funcName = Services.getArrayNoBarrier(allocCallMethods, i);
098          if (Magic.getArrayLength(name) == Magic.getArrayLength(funcName)) {
099            /* Compare the letters in the allocCallMethod */
100            int j = Magic.getArrayLength(funcName) - 1;
101            while (j >= 0) {
102              if (Services.getArrayNoBarrier(name, j) !=
103                  Services.getArrayNoBarrier(funcName, j))
104                break;
105              j--;
106            }
107            if (j == -1)
108              return true;
109          }
110        }
111        return false;
112      }
113    
114      @Override
115      public Offset adjustSlotOffset(boolean isScalar,
116                                                  ObjectReference src,
117                                                  Address slot) {
118        /* Offset scalar objects so that the fields appear to begin at offset 0
119           of the object. */
120        Offset offset = slot.diff(src.toAddress());
121        if (isScalar)
122          return offset.minus(getHeaderEndOffset());
123        else
124          return offset;
125      }
126    
127      @Override
128      @NoInline
129      @Interruptible // This can't be uninterruptible --- it is an IO routine
130      public Address skipOwnFramesAndDump(ObjectReference typeRef) {
131        TIB tib = Magic.addressAsTIB(typeRef.toAddress());
132        RVMMethod m = null;
133        int bci = -1;
134        int compiledMethodID = 0;
135        Offset ipOffset = Offset.zero();
136        Address fp = Magic.getFramePointer();
137        Address ip = Magic.getReturnAddressUnchecked(fp);
138        fp = Magic.getCallerFramePointer(fp);
139        // This code borrows heavily from RVMThread.dumpStack
140        while (Magic.getCallerFramePointer(fp).NE(STACKFRAME_SENTINEL_FP)) {
141          compiledMethodID = Magic.getCompiledMethodID(fp);
142          if (compiledMethodID != INVISIBLE_METHOD_ID) {
143            // normal java frame(s)
144            CompiledMethod compiledMethod =
145              CompiledMethods.getCompiledMethod(compiledMethodID);
146            if (compiledMethod.getCompilerType() != CompiledMethod.TRAP) {
147              ipOffset = compiledMethod.getInstructionOffset(ip);
148              m = compiledMethod.getMethod();
149              if (VM.BuildForOptCompiler && compiledMethod.getCompilerType() == CompiledMethod.OPT) {
150                OptCompiledMethod optInfo = (OptCompiledMethod)compiledMethod;
151                /* Opt stack frames may contain multiple inlined methods. */
152                OptMachineCodeMap map = optInfo.getMCMap();
153                int iei = map.getInlineEncodingForMCOffset(ipOffset);
154                if (iei >= 0) {
155                  int[] inlineEncoding = map.inlineEncoding;
156                  boolean allocCall = true;
157                  bci = map.getBytecodeIndexForMCOffset(ipOffset);
158                  for (int j = iei; j >= 0 && allocCall;
159                       j = OptEncodedCallSiteTree.getParent(j,inlineEncoding)) {
160                    int mid = OptEncodedCallSiteTree.getMethodID(j, inlineEncoding);
161                    m = MemberReference.getMemberRef(mid).asMethodReference().getResolvedMember();
162                    if (!isAllocCall(m.getName().getBytes()))
163                      allocCall = false;
164                    if (j > 0)
165                      bci = OptEncodedCallSiteTree.getByteCodeOffset(j,
166                                                                        inlineEncoding);
167                  }
168                  if (!allocCall)
169                    break;
170                }
171              } else {
172                if (!isAllocCall(m.getName().getBytes())) {
173                  BaselineCompiledMethod baseInfo =
174                    (BaselineCompiledMethod)compiledMethod;
175                  bci = baseInfo.findBytecodeIndexForInstruction(ipOffset.toWord().lsh(INSTRUCTION_WIDTH).toOffset());
176                  break;
177                }
178              }
179            }
180          }
181          ip = Magic.getReturnAddressUnchecked(fp);
182          fp = Magic.getCallerFramePointer(fp);
183        }
184        if (m != null) {
185          int allocid = (((compiledMethodID & 0x0000ffff) << 15) ^
186                         ((compiledMethodID & 0xffff0000) >> 16) ^
187                         ipOffset.toInt()) & ~0x80000000;
188    
189          /* Now print the location string. */
190          VM.sysWrite('\n');
191          VM.writeHex(allocid);
192          VM.sysWrite('-');
193          VM.sysWrite('>');
194          VM.sysWrite('[');
195          VM.writeHex(compiledMethodID);
196          VM.sysWrite(']');
197          m.getDeclaringClass().getDescriptor().sysWrite();
198          VM.sysWrite(':');
199          m.getName().sysWrite();
200          m.getDescriptor().sysWrite();
201          VM.sysWrite(':');
202          VM.writeHex(bci);
203          VM.sysWrite('\t');
204          RVMType type = tib.getType();
205          type.getDescriptor().sysWrite();
206          VM.sysWrite('\n');
207        }
208        return fp;
209      }
210    
211      /***********************************************************************
212       *
213       * Wrapper methods
214       */
215    
216      /**
217       * {@inheritDoc}
218       */
219      @Override
220      @Inline
221      public void updateDeathTime(ObjectReference obj) {
222        MiscHeader.updateDeathTime(obj.toObject());
223      }
224    
225      @Override
226      @Inline
227      public void setDeathTime(ObjectReference ref, Word time_) {
228        MiscHeader.setDeathTime(ref.toObject(), time_);
229      }
230    
231      @Override
232      @Inline
233      public void setLink(ObjectReference ref, ObjectReference link) {
234        MiscHeader.setLink(ref.toObject(), link);
235      }
236    
237      @Override
238      @Inline
239      public void updateTime(Word time_) {
240        MiscHeader.updateTime(time_);
241      }
242    
243      @Override
244      @Inline
245      public Word getOID(ObjectReference ref) {
246        return MiscHeader.getOID(ref.toObject());
247      }
248    
249      @Override
250      @Inline
251      public Word getDeathTime(ObjectReference ref) {
252        return MiscHeader.getDeathTime(ref.toObject());
253      }
254    
255      @Override
256      @Inline
257      public ObjectReference getLink(ObjectReference ref) {
258        return MiscHeader.getLink(ref.toObject());
259      }
260    
261      @Override
262      @Inline
263      public Address getBootImageLink() {
264        return MiscHeader.getBootImageLink();
265      }
266    
267      @Override
268      @Inline
269      public Word getOID() {
270        return MiscHeader.getOID();
271      }
272    
273      @Override
274      @Inline
275      public void setOID(Word oid) {
276        MiscHeader.setOID(oid);
277      }
278    
279      @Override
280      @Inline
281      public int getHeaderSize() {
282        return MiscHeader.getHeaderSize();
283      }
284    
285      @Override
286      @Inline
287      public int getHeaderEndOffset() {
288        return ObjectModel.getHeaderEndOffset();
289      }
290    }