/*
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.max.vm.compiler.deps;
import static com.sun.max.vm.actor.holder.ClassIDManager.*;
import static com.sun.max.vm.actor.holder.ClassActor.HAS_MULTIPLE_CONCRETE_SUBTYPE_MARK;
import static com.sun.max.vm.actor.holder.ClassActor.NO_CONCRETE_SUBTYPE_MARK;
import static com.sun.max.vm.compiler.deps.DependenciesManager.*;
import com.sun.cri.ci.*;
import com.sun.cri.ci.CiAssumptions.*;
import com.sun.max.vm.actor.holder.*;
import com.sun.max.vm.actor.member.*;
import com.sun.max.vm.compiler.deps.Dependencies.*;
import com.sun.max.vm.compiler.target.*;
import com.sun.max.vm.jni.*;
/**
* {@link DependencyProcessor} for unique concrete method dependency.
*
* Statistics from boot image generation showed that the vast majority of target methods have a single concrete
* method dependency, most of which are on leaf methods, i.e., wherein the context is the holder of the concrete method.
* The encoding of the dependencies is optimized for this case.
*
* The format of the packed data for this dependency is as follows:
* <pre>
* concrete_methods {
* short length; // length of 'deps'
* short deps[length]; // array of local_method_dep and non_local_concrete_method_dep structs (defined below)
* }
*
* // identifies a concrete method in the same class as 'type'
* local_method_dep {
* short mindex; // positive; the member index of the method in 'type'
* }
*
* // identifies
* non_local_concrete_method_dep {
* short mindex; // negative; (-mindex - 1) is the member index of the implementation/concrete method in 'implHolder'
* short implHolder; // identifier of the class in which the implementation/concrete method is defined
* short methodHolder; // identifier of the class in which the declared method is defined
* }
*
* </pre>
*/
public class ConcreteMethodDependencyProcessor extends DependencyProcessor {
/**
* Essentially the Maxine specific mirror of {@link ConcreteMethod}.
* Implement this interface in a subclass of {@link DependencyVisitor} to
* process these dependencies.
*/
public interface ConcreteMethodDependencyProcessorVisitor extends DependencyProcessorVisitor {
/**
* Processes a unique concrete method dependency.
*
* @param targetMethod the method compiled with this dependency
* @param method a virtual or interface method
* @param impl the method assumed to be the unique concrete implementation of {@code method}
* @param context class context
* @return {@code true} to continue the iteration, {@code false} to terminate it
*/
boolean doConcreteMethod(TargetMethod targetMethod, MethodActor method, MethodActor impl, ClassActor context);
}
static class ToStringConcreteMethodDependencyProcessorVisitor extends ToStringDependencyProcessorVisitor implements ConcreteMethodDependencyProcessorVisitor {
public boolean doConcreteMethod(TargetMethod targetMethod, MethodActor method, MethodActor impl, ClassActor context) {
sb.append(" UCM[").append(method);
if (method != impl && impl.holder() != context) {
sb.append(",").append(context);
sb.append(",").append(impl);
}
sb.append(']');
return true;
}
}
static final ToStringConcreteMethodDependencyProcessorVisitor toStringConcreteMethodDependencyProcessorVisitor = new ToStringConcreteMethodDependencyProcessorVisitor();
@Override
protected ToStringDependencyProcessorVisitor getToStringDependencyProcessorVisitor(StringBuilder sb) {
return toStringConcreteMethodDependencyProcessorVisitor.setStringBuilder(sb);
}
private static final ConcreteMethodDependencyProcessor singleton = new ConcreteMethodDependencyProcessor();
private static ThreadLocal<UniqueConcreteMethodSearch> ucms = new ThreadLocal<UniqueConcreteMethodSearch>() {
@Override
public UniqueConcreteMethodSearch initialValue() {
return new UniqueConcreteMethodSearch();
}
};
private ConcreteMethodDependencyProcessor() {
super(CiAssumptions.ConcreteMethod.class);
}
/**
* Utility to walk a type tree and find concrete method implementation for a given signature.
*/
static final class UniqueConcreteMethodSearch {
private MethodActor firstConcreteMethod;
private boolean hasMoreThanOne;
private boolean setConcreteMethod(MethodActor concreteMethod) {
assert concreteMethod != null;
if (concreteMethod != firstConcreteMethod) {
if (firstConcreteMethod == null) {
firstConcreteMethod = concreteMethod;
} else {
hasMoreThanOne = true;
}
}
return hasMoreThanOne;
}
/**
*
* @param root
* @param method
* @return true if sub-type needs to be walked over to find concrete implementation
*/
private boolean shouldSearchSubTypes(ClassActor root, MethodActor method) {
final int uct = root.uniqueConcreteType;
if (uct == NO_CONCRETE_SUBTYPE_MARK) {
// No concrete type, no need to search sub-types.
return false;
}
if (uct != HAS_MULTIPLE_CONCRETE_SUBTYPE_MARK) {
ClassActor concreteType = ClassIDManager.toClassActor(uct);
// This is the only concrete sub-type for the current context. The concrete method
// is whatever concrete method is used by this concrete type.
setConcreteMethod((MethodActor) concreteType.resolveMethodImpl(method));
// found the single concrete method for this class actor. No need to search sub-types.
return false;
}
// There is multiple concrete sub-type. Need to search them to determine unique concrete method.
return true;
}
/**
* Search the instance class tree rooted by the specified class actor for concrete implementations
* of the specified method. Result of the search can be obtained via {{@link #uniqueConcreteMethod()}.
*
* @param root a tuple or hybrid class actor
* @param method the method concrete implementation of are being searched
*/
private void searchInstanceClassTree(ClassActor root, MethodActor method) {
// Iterate over all concrete sub-types and determines if they all used the same method.
assert root.isInstanceClass() : "must be an hybrid or tuple class actor";
assert root.firstSubclassActorId != NULL_CLASS_ID : "must have at least one sub-class";
assert firstConcreteMethod == null || !hasMoreThanOne;
setConcreteMethod((MethodActor) root.resolveMethodImpl(method));
if (hasMoreThanOne) {
return;
}
int classId = root.firstSubclassActorId;
do {
ClassActor subType = ClassIDManager.toClassActor(classId);
if (shouldSearchSubTypes(subType, method)) {
searchInstanceClassTree(subType, method);
}
if (hasMoreThanOne) {
// no need to search further.
return;
}
classId = subType.nextSibling();
} while(classId != NULL_CLASS_ID);
}
MethodActor uniqueConcreteMethod() {
return hasMoreThanOne ? null : firstConcreteMethod;
}
MethodActor doIt(ClassActor root, MethodActor method) {
// Reset before initiating the search.
hasMoreThanOne = false;
firstConcreteMethod = null;
if (shouldSearchSubTypes(root, method)) {
if (root.isInterface()) {
// Don't bother for now. Assume can't find concrete method implementation.
return null;
}
searchInstanceClassTree(root, method);
}
return uniqueConcreteMethod();
}
}
@Override
protected boolean validate(Assumption assumption, ClassDeps classDeps) {
ClassActor contextClassActor = (ClassActor) ((ContextAssumption) assumption).context;
ConcreteMethod cm = (ConcreteMethod) assumption;
if (ucms.get().doIt(contextClassActor, (MethodActor) cm.dependee) != cm.dependee) {
return false;
}
MethodActor impl = (MethodActor) cm.dependee;
MethodActor method = (MethodActor) cm.method;
short mIndex = Dependencies.getMIndex(impl);
if (impl == method && impl.holder() == contextClassActor) {
classDeps.add(this, mIndex);
} else {
classDeps.add(this, (short) -(mIndex + 1));
classDeps.add(this, (short) impl.holder().id);
classDeps.add(this, (short) method.holder().id);
}
return true;
}
@Override
protected DependencyProcessorVisitor match(DependencyVisitor dependencyVisitor) {
return dependencyVisitor instanceof ConcreteMethodDependencyProcessorVisitor ? (ConcreteMethodDependencyProcessorVisitor) dependencyVisitor : null;
}
@Override
protected int visit(DependencyProcessorVisitor dependencyProcessorVisitor, ClassActor context, Dependencies dependencies, int index) {
ConcreteMethodDependencyProcessorVisitor ucmVisitor = (ConcreteMethodDependencyProcessorVisitor) dependencyProcessorVisitor;
int i = index;
int mindex = dependencies.packed[i++];
MethodActor impl = null;
MethodActor method = null;
if (mindex >= 0) {
impl = ucmVisitor == null ? null : MethodID.toMethodActor(MethodID.fromWord(MemberID.create(context.id, mindex)));
method = impl;
} else {
int implHolder = dependencies.packed[i++];
int methodHolderID = dependencies.packed[i++];
if (ucmVisitor != null) {
impl = MethodID.toMethodActor(MethodID.fromWord(MemberID.create(implHolder, -mindex - 1)));
ClassActor methodHolder = ClassIDManager.toClassActor(methodHolderID);
method = methodHolder.findLocalMethodActor(impl.name, impl.descriptor());
}
}
if (ucmVisitor != null) {
if (!ucmVisitor.doConcreteMethod(dependencies.targetMethod, method, impl, context)) {
return -1;
}
}
return i;
}
public static MethodActor getUniqueConcreteMethod(ClassActor declaredType, MethodActor method) {
// Default is to return null. See sub-classes of ClassActor for specific details.
assert declaredType.isSubtypeOf(method.holder());
classHierarchyLock.readLock().lock();
try {
return new ConcreteMethodDependencyProcessor.UniqueConcreteMethodSearch().doIt(declaredType, method);
} finally {
classHierarchyLock.readLock().unlock();
}
}
}