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