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}