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 }