/*
* This file is part of the Jikes RVM project (http://jikesrvm.org).
*
* This file is licensed to You under the Common Public License (CPL);
* You may not use this file except in compliance with the License. You
* may obtain a copy of the License at
*
* http://www.opensource.org/licenses/cpl1.0.php
*
* See the COPYRIGHT.txt file distributed with this work for information
* regarding copyright ownership.
*/
package org.jikesrvm.classloader;
import java.io.DataInputStream;
import java.io.IOException;
import org.jikesrvm.VM_CodeArray;
import org.jikesrvm.ArchitectureSpecific;
import org.jikesrvm.SubordinateArchitecture;
import org.jikesrvm.VM;
import org.jikesrvm.compilers.common.VM_CompiledMethod;
import org.jikesrvm.compilers.common.VM_CompiledMethods;
import org.jikesrvm.runtime.VM_Entrypoints;
import org.jikesrvm.runtime.VM_Statics;
import org.jikesrvm.runtime.VM_SubArchStatics;
import org.vmmagic.pragma.Uninterruptible;
import org.vmmagic.pragma.Unpreemptible;
import org.vmmagic.unboxed.Offset;
/**
* A method of a java class corresponding to a method_info structure
* in the class file. A method is read from a class file using the
* {@link #readMethod} method.
*/
public abstract class VM_Method extends VM_Member implements VM_BytecodeConstants {
/**
* current compiled method for this method
*/
protected VM_CompiledMethod currentCompiledMethod;
/**
* current compiled method for this method
*/
protected VM_CompiledMethod currentSubArchCompiledMethod;
/**
* exceptions this method might throw (null --> none)
*/
protected final VM_TypeReference[] exceptionTypes;
/**
* Method paramter annotations from the class file that are
* described as runtime visible. These annotations are available to
* the reflection API.
*/
protected final VM_Annotation[] parameterAnnotations;
/**
* A value present in the method info tables of annotation types. It
* represents the default result from an annotation method.
*/
protected final Object annotationDefault;
/**
* The offset of this virtual method in the jtoc if it's been placed
* there by constant propagation, otherwise 0.
*/
private Offset jtocOffset;
/**
* Construct a read method
*
* @param declaringClass the VM_Class object of the class that declared this field
* @param memRef the canonical memberReference for this method.
* @param modifiers modifiers associated with this method.
* @param exceptionTypes exceptions thrown by this method.
* @param signature generic type of this method.
* @param annotations array of runtime visible annotations
* @param parameterAnnotations array of runtime visible parameter annotations
* @param annotationDefault value for this annotation that appears
*/
protected VM_Method(VM_TypeReference declaringClass, VM_MemberReference memRef, short modifiers, short annoModifiers,
VM_TypeReference[] exceptionTypes, VM_Atom signature, VM_Annotation[] annotations,
VM_Annotation[] parameterAnnotations, Object annotationDefault) {
super(declaringClass, memRef, (short) (modifiers & APPLICABLE_TO_METHODS), annoModifiers, signature, annotations);
this.parameterAnnotations = parameterAnnotations;
this.annotationDefault = annotationDefault;
this.exceptionTypes = exceptionTypes;
this.jtocOffset = Offset.fromIntSignExtend(-1);
}
/**
* Called from {@link VM_Class#readClass(VM_TypeReference,DataInputStream)} to create an
* instance of a VM_Method by reading the relevant data from the argument bytecode stream.
*
* @param declaringClass the VM_TypeReference of the class being loaded
* @param constantPool the constantPool of the VM_Class object that's being constructed
* @param memRef the canonical memberReference for this member.
* @param modifiers modifiers associated with this member.
* @param input the DataInputStream to read the method's attributes from
*/
static VM_Method readMethod(VM_TypeReference declaringClass, int[] constantPool, VM_MemberReference memRef,
short modifiers, DataInputStream input) throws IOException {
short tmp_localWords = 0;
short tmp_operandWords = 0;
byte[] tmp_bytecodes = null;
VM_ExceptionHandlerMap tmp_exceptionHandlerMap = null;
VM_TypeReference[] tmp_exceptionTypes = null;
int[] tmp_lineNumberMap = null;
VM_Atom tmp_signature = null;
VM_Annotation[] annotations = null;
VM_Annotation[] parameterAnnotations = null;
Object tmp_annotationDefault = null;
// Read the attributes
for (int i = 0, n = input.readUnsignedShort(); i < n; i++) {
VM_Atom attName = VM_Class.getUtf(constantPool, input.readUnsignedShort());
int attLength = input.readInt();
// Only bother to interpret non-boring Method attributes
if (attName == VM_ClassLoader.codeAttributeName) {
tmp_operandWords = input.readShort();
tmp_localWords = input.readShort();
tmp_bytecodes = new byte[input.readInt()];
input.readFully(tmp_bytecodes);
tmp_exceptionHandlerMap = VM_ExceptionHandlerMap.readExceptionHandlerMap(input, constantPool);
// Read the attributes portion of the code attribute
for (int j = 0, n2 = input.readUnsignedShort(); j < n2; j++) {
attName = VM_Class.getUtf(constantPool, input.readUnsignedShort());
attLength = input.readInt();
if (attName == VM_ClassLoader.lineNumberTableAttributeName) {
int cnt = input.readUnsignedShort();
if (cnt != 0) {
tmp_lineNumberMap = new int[cnt];
for (int k = 0; k < cnt; k++) {
int startPC = input.readUnsignedShort();
int lineNumber = input.readUnsignedShort();
tmp_lineNumberMap[k] = (lineNumber << BITS_IN_SHORT) | startPC;
}
}
} else {
// All other entries in the attribute portion of the code attribute are boring.
input.skipBytes(attLength);
}
}
} else if (attName == VM_ClassLoader.exceptionsAttributeName) {
int cnt = input.readUnsignedShort();
if (cnt != 0) {
tmp_exceptionTypes = new VM_TypeReference[cnt];
for (int j = 0, m = tmp_exceptionTypes.length; j < m; ++j) {
tmp_exceptionTypes[j] = VM_Class.getTypeRef(constantPool, input.readUnsignedShort());
}
}
} else if (attName == VM_ClassLoader.syntheticAttributeName) {
modifiers |= ACC_SYNTHETIC;
} else if (attName == VM_ClassLoader.signatureAttributeName) {
tmp_signature = VM_Class.getUtf(constantPool, input.readUnsignedShort());
} else if (attName == VM_ClassLoader.runtimeVisibleAnnotationsAttributeName) {
annotations = VM_AnnotatedElement.readAnnotations(constantPool, input, 2, declaringClass.getClassLoader());
} else if (attName == VM_ClassLoader.runtimeVisibleParameterAnnotationsAttributeName) {
parameterAnnotations =
VM_AnnotatedElement.readAnnotations(constantPool, input, 1, declaringClass.getClassLoader());
} else if (attName == VM_ClassLoader.annotationDefaultAttributeName) {
try {
tmp_annotationDefault = VM_Annotation.readValue(constantPool, input, declaringClass.getClassLoader());
} catch (ClassNotFoundException e) {
throw new Error(e);
}
} else {
// all other method attributes are boring
input.skipBytes(attLength);
}
}
short annoModifiers = createAnnoModifer (annotations);
VM_Method method;
if ((modifiers & ACC_NATIVE) != 0) {
method =
new VM_NativeMethod(declaringClass,
memRef,
modifiers,
annoModifiers,
tmp_exceptionTypes,
tmp_signature,
annotations,
parameterAnnotations,
tmp_annotationDefault);
} else if ((modifiers & ACC_ABSTRACT) != 0) {
method =
new VM_AbstractMethod(declaringClass,
memRef,
modifiers,
annoModifiers,
tmp_exceptionTypes,
tmp_signature,
annotations,
parameterAnnotations,
tmp_annotationDefault);
} else {
method =
new VM_NormalMethod(declaringClass,
memRef,
modifiers,
annoModifiers,
tmp_exceptionTypes,
tmp_localWords,
tmp_operandWords,
tmp_bytecodes,
tmp_exceptionHandlerMap,
tmp_lineNumberMap,
constantPool,
tmp_signature,
annotations,
parameterAnnotations,
tmp_annotationDefault);
}
return method;
}
/**
* Create a copy of the method that occurs in the annotation
* interface. The method body will contain a read of the field at
* the constant pool index specified.
*
* @param annotationClass the class this method belongs to
* @param constantPool for the class
* @param memRef the member reference corresponding to this method
* @param interfaceMethod the interface method that will copied to
* produce the annotation method
* @param constantPoolIndex the index of the field that will be
* returned by this method
* @return the created method
*/
static VM_Method createAnnotationMethod(VM_TypeReference annotationClass, int[] constantPool,
VM_MemberReference memRef, VM_Method interfaceMethod,
int constantPoolIndex) {
byte[] bytecodes =
new byte[]{
(byte) JBC_aload_0,
(byte) JBC_getfield, (byte) (constantPoolIndex >>> 8), (byte) constantPoolIndex,
// Xreturn
(byte) typeRefToReturnBytecode(interfaceMethod.getReturnType())};
return new VM_NormalMethod(annotationClass,
memRef,
(short) (ACC_PUBLIC | ACC_FINAL | ACC_SYNTHETIC),
(short) 0,
null,
(short) 1,
(short) 2,
bytecodes,
null,
null,
constantPool,
null,
null,
null,
null);
}
/**
* Create a method to initialise the annotation class
*
* @param aClass the class this method belongs to
* @param constantPool for the class
* @param memRef the member reference corresponding to this method
* @param objectInitIndex an index into the constant pool for a
* method reference to java.lang.Object.<init>
* @param aFields
* @param aMethods
* @return the created method
*/
static VM_Method createAnnotationInit(VM_TypeReference aClass, int[] constantPool, VM_MemberReference memRef,
int objectInitIndex, VM_Field[] aFields, VM_Method[] aMethods,
int[] defaultConstants) {
byte[] bytecode = new byte[6 + (defaultConstants.length * 7)];
bytecode[0] = (byte) JBC_aload_0; // stack[0] = this
bytecode[1] = (byte) JBC_aload_1; // stack[1] = instanceof VM_Annotation
bytecode[2] = (byte) JBC_invokespecial;
bytecode[3] = (byte) (objectInitIndex >>> 8);
bytecode[4] = (byte) objectInitIndex;
for (int i = 0, j = 0; i < aMethods.length; i++) {
if (aMethods[i].annotationDefault != null) {
bytecode[(j * 7) + 5 + 0] = (byte) JBC_aload_0; // stack[0] = this
if (VM_Class.getLiteralSize(constantPool, defaultConstants[j]) == BYTES_IN_INT) {
bytecode[(j * 7) + 5 + 1] = (byte) JBC_ldc_w; // stack[1] = value
} else {
bytecode[(j * 7) + 5 + 1] = (byte) JBC_ldc2_w;// stack[1&2] = value
}
bytecode[(j * 7) + 5 + 2] = (byte) (defaultConstants[j] >>> 8);
bytecode[(j * 7) + 5 + 3] = (byte) defaultConstants[j];
bytecode[(j * 7) + 5 + 4] = (byte) JBC_putfield;
bytecode[(j * 7) + 5 + 5] = (byte) (i >>> 8);
bytecode[(j * 7) + 5 + 6] = (byte) i;
j++;
}
}
bytecode[bytecode.length - 1] = (byte) JBC_return;
return new VM_NormalMethod(aClass,
memRef,
(short) (ACC_PUBLIC | ACC_FINAL | ACC_SYNTHETIC),
(short) 0,
null,
(short) 2,
(short) 3,
bytecode,
null,
null,
constantPool,
null,
null,
null,
null);
}
/**
* What would be the appropriate return bytecode for the given type
* reference?
*/
private static int typeRefToReturnBytecode(VM_TypeReference tr) {
if (!tr.isPrimitiveType()) {
return JBC_areturn;
} else {
VM_Primitive pt = (VM_Primitive) tr.peekType();
if ((pt == VM_Type.BooleanType) ||
(pt == VM_Type.ByteType) ||
(pt == VM_Type.ShortType) ||
(pt == VM_Type.CharType) ||
(pt == VM_Type.IntType)) {
return JBC_ireturn;
} else if (pt == VM_Type.LongType) {
return JBC_lreturn;
} else if (pt == VM_Type.FloatType) {
return JBC_freturn;
} else if (pt == VM_Type.DoubleType) {
return JBC_dreturn;
} else {
VM._assert(false);
return -1;
}
}
}
/**
* Is this method a class initializer?
*/
@Uninterruptible
public final boolean isClassInitializer() {
return getName() == VM_ClassLoader.StandardClassInitializerMethodName;
}
/**
* Is this method an object initializer?
*/
@Uninterruptible
public final boolean isObjectInitializer() {
return getName() == VM_ClassLoader.StandardObjectInitializerMethodName;
}
/**
* Is this method a compiler-generated object initializer helper?
*/
@Uninterruptible
public final boolean isObjectInitializerHelper() {
return getName() == VM_ClassLoader.StandardObjectInitializerHelperMethodName;
}
/**
* Type of this method's return value.
*/
@Uninterruptible
public final VM_TypeReference getReturnType() {
return memRef.asMethodReference().getReturnType();
}
/**
* Type of this method's parameters.
* Note: does *not* include implicit "this" parameter, if any.
*/
@Uninterruptible
public final VM_TypeReference[] getParameterTypes() {
return memRef.asMethodReference().getParameterTypes();
}
/**
* Space required by this method for its parameters, in words.
* Note: does *not* include implicit "this" parameter, if any.
*/
@Uninterruptible
public final int getParameterWords() {
return memRef.asMethodReference().getParameterWords();
}
/**
* Has machine code been generated for this method's bytecodes?
*/
public final boolean isCompiled(boolean forSubArch) {
if (!forSubArch) {
return currentCompiledMethod != null;
} else {
return currentSubArchCompiledMethod != null;
}
}
/**
* Get the current compiled method for this method.
* Will return null if there is no current compiled method!
*
* We make this method Unpreemptible to avoid a race-condition
* in VM_Reflection.invoke.
* @return compiled method
*/
@Unpreemptible
public final synchronized VM_CompiledMethod getCurrentCompiledMethod(boolean forSubArch) {
return forSubArch ? currentSubArchCompiledMethod : currentCompiledMethod;
}
/**
* Declared as statically dispatched?
*/
@Uninterruptible
public final boolean isStatic() {
return (modifiers & ACC_STATIC) != 0;
}
/**
* Declared as non-overridable by subclasses?
*/
@Uninterruptible
public final boolean isFinal() {
return (modifiers & ACC_FINAL) != 0;
}
/**
* Guarded by monitorenter/monitorexit?
*/
@Uninterruptible
public final boolean isSynchronized() {
return (modifiers & ACC_SYNCHRONIZED) != 0;
}
/**
* Not implemented in java?
*/
@Uninterruptible
public final boolean isNative() {
return (modifiers & ACC_NATIVE) != 0;
}
/**
* Not implemented in Java and use C not JNI calling convention
*/
public final boolean isSysCall() {
return isNative() && isStatic() && isAnnotationDeclared(VM_TypeReference.SysCall);
}
/**
* Not implemented in Java and use C not JNI calling convention
*/
public final boolean isSpecializedInvoke() {
return isAnnotationDeclared(VM_TypeReference.SpecializedMethodInvoke);
}
/**
* Implemented in subclass?
*/
@Uninterruptible
public final boolean isAbstract() {
return (modifiers & ACC_ABSTRACT) != 0;
}
/**
* Not present in source code file?
*/
public boolean isSynthetic() {
return (modifiers & ACC_SYNTHETIC) != 0;
}
/**
* This method should be migrated to subarch
*/
public boolean isSubArchMigrationPoint() {
return ((annoModifiers & ANO_SUBARCH) != 0) || getDeclaringClass().isDeclaredForSubArch();
}
/**
* Compile this method for subarch?
*/
public boolean isCompilableForSubArch() {
return ((annoModifiers & ANO_NO_SUBARCH) == 0) && getDeclaringClass().isCompilableForSubArch();
}
/**
* Compile this method for subarch?
*/
public boolean isCompilableForMainArch() {
return ((annoModifiers & ANO_NO_MAINARCH) == 0) && getDeclaringClass().isCompilableForMainArch();
}
/**
* Is used as an entrypoint
*/
public boolean isEntrypoint() {
return ((annoModifiers & ANO_ENTRYPOINT) != 0);
}
/**
* Exceptions thrown by this method -
* something like { "java/lang/IOException", "java/lang/EOFException" }
* @return info (null --> method doesn't throw any exceptions)
*/
@Uninterruptible
public final VM_TypeReference[] getExceptionTypes() {
return exceptionTypes;
}
/**
* Is this method interruptible?
* In other words, should the compiler insert yieldpoints
* in method prologue, epilogue, and backwards branches.
* Also, only methods that are Interruptible have stackoverflow checks
* in the method prologue (since there is no mechanism for handling a stackoverflow
* that doesn't violate the uninterruptiblity of the method).
* To determine if a method is interruptible, the following conditions
* are checked (<em>in order</em>):
* <ul>
* <li> If it is a <clinit> or <init> method then it is interruptible.
* <li> If is the synthetic 'this' method used by jikes to
* factor out default initializers for <init> methods then it is interruptible.
* <li> If it is annotated with <CODE>Interruptible</CODE> it is interruptible.
* <li> If it is annotated with <CODE>Preemptible</CODE> it is interruptible.
* <li> If it is annotated with <CODE>Uninterruptible</CODE> it is not interruptible.
* <li> If it is annotated with <CODE>UninterruptibleNoWarn</CODE> it is not interruptible.
* <li> If it is annotated with <CODE>Unpreemptible</CODE> it is not interruptible.
* <li> If its declaring class is annotated with <CODE>Uninterruptible</CODE>
* or <CODE>Unpreemptible</CODE> it is not interruptible.
* </ul>
*/
public final boolean isInterruptible() {
if (isClassInitializer() || isObjectInitializer()) return true;
if (isObjectInitializerHelper()) return true;
if (hasInterruptibleAnnotation()) return true;
if (hasPreemptibleAnnotation()) return true;
if (hasUninterruptibleNoWarnAnnotation()) return false;
if (hasUninterruptibleAnnotation()) return false;
if (hasUnpreemptibleAnnotation()) return false;
if (getDeclaringClass().hasUnpreemptibleAnnotation()) return false;
return !getDeclaringClass().hasUninterruptibleAnnotation();
}
/**
* Is the method Unpreemptible? See the comment in {@link #isInterruptible}
*/
public final boolean isUnpreemptible() {
if (isClassInitializer() || isObjectInitializer()) return false;
if (isObjectInitializerHelper()) return false;
if (hasInterruptibleAnnotation()) return false;
if (hasPreemptibleAnnotation()) return false;
if (hasUninterruptibleAnnotation()) return false;
if (hasUninterruptibleNoWarnAnnotation()) return false;
if (hasUnpreemptibleAnnotation()) return true;
return getDeclaringClass().hasUnpreemptibleAnnotation();
}
/**
* Is the method Uninterruptible? See the comment in {@link #isInterruptible}
*/
public final boolean isUninterruptible() {
if (isClassInitializer() || isObjectInitializer()) return false;
if (isObjectInitializerHelper()) return false;
if (hasInterruptibleAnnotation()) return false;
if (hasPreemptibleAnnotation()) return false;
if (hasUnpreemptibleAnnotation()) return false;
if (hasUninterruptibleAnnotation()) return true;
if (hasUninterruptibleNoWarnAnnotation()) return true;
return getDeclaringClass().hasUninterruptibleAnnotation();
}
/**
* Is the method Pure? That is would it, without any side effects, return the
* same value given the same arguments?
*
* @return whether the method has a pure annotation
*/
public final boolean isPure() {
return hasPureAnnotation();
}
/**
* Has this method been marked as forbidden to inline?
* ie., it is marked with the <CODE>NoInline</CODE> annotation or
* the <CODE>NoOptCompile</CODE> annotation?
*/
public final boolean hasNoInlinePragma() {
return (hasNoInlineAnnotation() || hasNoOptCompileAnnotation());
}
/**
* @return true if the method may write to a given field
*/
public boolean mayWrite(VM_Field field) {
return true; // be conservative. native methods can write to anything
}
/**
* @return true if the method is the implementation of a runtime service
* that is called "under the covers" from the generated code and thus is not subject to
* inlining via the normal mechanisms.
*/
public boolean isRuntimeServiceMethod() {
return false; // only VM_NormalMethods can be runtime service impls in Jikes RVM and they override this method
}
//------------------------------------------------------------------//
// Section 2. //
// The following are available after the declaring class has been //
// "resolved". //
//------------------------------------------------------------------//
/**
* Get the code array that corresponds to the entry point (prologue) for the method.
*/
public final synchronized VM_CodeArray getCurrentEntryCodeArray(boolean forSubArch) {
VM_Class declaringClass = getDeclaringClass();
if (VM.VerifyAssertions) VM._assert(declaringClass.isResolved(forSubArch));
if (isCompiled(forSubArch)) {
return (VM_CodeArray) getCurrentCompiledMethod(forSubArch).getEntryCodeArray();
// TODO - Enable dynamic linking for subarch
} else if ((!VM.writingBootImage || isNative()) && !forSubArch) {
if (!isStatic() && !isObjectInitializer() && !isPrivate()) {
// A non-private virtual method.
if (declaringClass.isJavaLangObjectType() ||
declaringClass.getSuperClass().findVirtualMethod(getName(), getDescriptor()) == null) {
// The root method of a virtual method family can use the lazy method invoker directly.
return VM_Entrypoints.lazyMethodInvokerMethod.getCurrentEntryCodeArray(forSubArch);
} else {
// All other virtual methods in the family must generate unique stubs to
// ensure correct operation of the method test (guarded inlining of virtual calls).
if (!forSubArch) {
return ArchitectureSpecific.VM_LazyCompilationTrampolineGenerator.getTrampoline();
} else {
return SubordinateArchitecture.VM_LazyCompilationTrampolineGenerator.getTrampoline();
}
}
} else {
// We'll never do a method test against this method.
// Therefore we can use the lazy method invoker directly.
return VM_Entrypoints.lazyMethodInvokerMethod.getCurrentEntryCodeArray(forSubArch);
}
} else {
compile(forSubArch);
return (VM_CodeArray) getCurrentCompiledMethod(forSubArch).getEntryCodeArray();
}
}
/**
* Generate machine code for this method if valid
* machine code doesn't already exist.
* Return the resulting VM_CompiledMethod object.
*/
public final synchronized void compile(boolean forSubArch) {
if (VM.VerifyAssertions) VM._assert(getDeclaringClass().isResolved(forSubArch));
if (isCompiled(forSubArch)) return;
if (VM.TraceClassLoading && VM.runningVM) VM.sysWrite("VM_Method: (begin) compiling " + this + "\n");
VM_CompiledMethod cm = genCode(forSubArch);
// Ensure that cm wasn't invalidated while it was being compiled.
synchronized (cm) {
if (cm.isInvalid()) {
VM_CompiledMethods.setCompiledMethodObsolete(cm);
} else {
if (VM.VerifyAssertions) VM._assert(cm.isSubArchCompilation() == forSubArch);
if (!forSubArch) {
currentCompiledMethod = cm;
} else {
currentSubArchCompiledMethod = cm;
}
}
}
if (VM.TraceClassLoading && VM.runningVM) VM.sysWrite("VM_Method: (end) compiling " + this + "\n");
}
protected abstract VM_CompiledMethod genCode(boolean forSubArch);
//----------------------------------------------------------------//
// Section 3. //
// The following are available after the declaring class has been //
// "instantiated". //
//----------------------------------------------------------------//
/**
* Change machine code that will be used by future executions of this method
* (ie. optimized <-> non-optimized)
* @param compiledMethod new machine code
* Side effect: updates jtoc or method dispatch tables
* ("type information blocks")
* for this class and its subclasses
*/
public final synchronized void replaceCompiledMethod(VM_CompiledMethod compiledMethod, boolean forSubArch) {
if (VM.VerifyAssertions) VM._assert(getDeclaringClass().isInstantiated(forSubArch));
// If we're replacing with a non-null compiledMethod, ensure that is still valid!
if (compiledMethod != null) {
synchronized (compiledMethod) {
if (compiledMethod.isInvalid()) return;
}
}
VM_CompiledMethod oldCompiledMethod;
if (forSubArch) {
// Grab version that is being replaced
oldCompiledMethod = currentSubArchCompiledMethod;
currentSubArchCompiledMethod = compiledMethod;
} else {
// Grab version that is being replaced
oldCompiledMethod = currentCompiledMethod;
currentCompiledMethod = compiledMethod;
}
// Install the new method in jtoc/tib. If virtual, will also replace in
// all subclasses that inherited the method.
getDeclaringClass().updateMethod(this, forSubArch);
// Replace constant-ified virtual method in JTOC if necessary
if (!forSubArch && (jtocOffset.toInt() != -1)) {
VM_Statics.setSlotContents(jtocOffset, getCurrentEntryCodeArray(forSubArch));
}
// Now that we've updated the jtoc/tib, old version is obsolete
if (oldCompiledMethod != null) {
VM_CompiledMethods.setCompiledMethodObsolete(oldCompiledMethod);
}
}
/**
* If CM is the current compiled code for this, then invaldiate it.
*/
public final synchronized void invalidateCompiledMethod(VM_CompiledMethod cm, boolean forSubArch) {
if (VM.VerifyAssertions) VM._assert(getDeclaringClass().isInstantiated(forSubArch));
if (!forSubArch && currentCompiledMethod == cm) {
replaceCompiledMethod(null, forSubArch);
} else if (forSubArch && currentSubArchCompiledMethod == cm) {
replaceCompiledMethod(null, forSubArch);
}
}
/**
* Find or create a jtoc offset for this method
*/
public final synchronized Offset findOrCreateJtocOffset(boolean forSubArch) {
if (VM.VerifyAssertions) VM._assert(!isStatic() && !isObjectInitializer());
if (!forSubArch && jtocOffset.EQ(Offset.zero())) {
jtocOffset = VM_Statics.allocateReferenceSlot(true);
VM_Statics.setSlotContents(jtocOffset, getCurrentEntryCodeArray(forSubArch));
}
return forSubArch ? null : jtocOffset;
}
public int getSubArchLength() {
if (!isCompiled(true)) {
// compile if not compiled
this.getCurrentEntryCodeArray(true);
}
return this.getDeclaringClass().getSubArchMethodLength(this);
}
public void setSubArchLength(int length) {
this.getDeclaringClass().updateSubArchMethodLength(this, length);
}
}