/* * 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.compiler.deps.DependenciesManager.*; import java.util.*; import com.sun.cri.ci.*; import com.sun.cri.ci.CiAssumptions.*; import com.sun.max.annotate.*; import com.sun.max.vm.actor.holder.*; import com.sun.max.vm.actor.member.*; import com.sun.max.vm.compiler.deps.Dependencies.DependencyVisitor; import com.sun.max.vm.compiler.deps.ContextDependents.*; import com.sun.max.vm.compiler.deps.Dependencies.*; import com.sun.max.vm.compiler.target.*; import com.sun.max.vm.jni.*; import com.sun.max.vm.log.hosted.*; import com.sun.max.vm.ti.*; /** * {@link DependencyProcessor} for inlined methods. * * The format of the packed data for this dependency is as follows: * <pre> * inlined_methods { * short length; // length of 'deps' * short deps[length]; // array of local_inlined_method_dep and non_local_inlined_method_dep structs (defined below) * // the context class is always the holder of an inlining method, and the {@link ClassMethodActor} * // of the {@link TargetMethod} always denotes the inlining method, so it does not need to be recorded * // in the dependency data. N.B. This means that the inlining method is lost * // until the TargetMethod is {@link Dependencies#registerValidatedTarget(Dependencies, TargetMethod) set} * } * * // identifies an inlined method in same class as inliner * local_inlined_method_dep { * short inlinee_mindex // positive; inlinee_mindex is the member index of the inlinee method in same class * } * * // identifies an inlined method in different class to inliner * non_local_inlined_method_dep { * short inlinee_mindex // negative; (-mindex - 1) is the member index of the inlinee method in inlineHolder * short inlineHolder; // identifier of the class in which the inlinee method is defined * } * </pre> */ public class InlinedMethodDependencyProcessor extends DependencyProcessor { /** * Essentially the Maxine specific mirror of {@link InlinedMethod}. * Implement this interface in a subclass of {@link DependencyVisitor} to * process these dependencies. */ public interface InlinedMethodDependencyProcessorVisitor extends DependencyProcessorVisitor { /** * Process an inlined method dependency. * @param targetMethod the method compiled with this dependency * @param method the inlining method * @param inlinee the inlined method (inlinee) * @param context class context * @return {@code true} to continue the iteration, {@code false} to terminate it */ boolean doInlinedMethod(TargetMethod targetMethod, ClassMethodActor method, ClassMethodActor inlinee, ClassActor context); } static class ToStringInlinedMethodDependencyProcessorVisitor extends ToStringDependencyProcessorVisitor implements InlinedMethodDependencyProcessorVisitor { @Override public boolean doInlinedMethod(TargetMethod targetMethod, ClassMethodActor method, ClassMethodActor inlinee, ClassActor context) { sb.append(" INL[").append(inlinee).append(']'); return true; } } static final ToStringInlinedMethodDependencyProcessorVisitor toStringInlinedMethodDependencyProcessorVisitor = new ToStringInlinedMethodDependencyProcessorVisitor(); @Override protected ToStringDependencyProcessorVisitor getToStringDependencyProcessorVisitor(StringBuilder sb) { return toStringInlinedMethodDependencyProcessorVisitor.setStringBuilder(sb); } private static final InlinedMethodDependencyProcessor singleton = new InlinedMethodDependencyProcessor(); private InlinedMethodDependencyProcessor() { super(CiAssumptions.InlinedMethod.class); } @Override protected boolean validate(Assumption assumption, ClassDeps classDeps) { ClassActor contextClassActor = (ClassActor) ((ContextAssumption) assumption).context; InlinedMethod inlineMethod = (InlinedMethod) assumption; ClassMethodActor inlinee = (ClassMethodActor) inlineMethod.dependee; if (VMTI.handler().hasBreakpoints(inlinee)) { return false; } short inlineeMIndex = Dependencies.getMIndex(inlinee); if (inlinee.holder() == contextClassActor) { // inlinee in same class, use shorter form classDeps.add(this, inlineeMIndex); } else { classDeps.add(this, (short) -(inlineeMIndex + 1)); classDeps.add(this, (short) inlinee.holder().id); } return true; } @Override protected DependencyProcessorVisitor match(DependencyVisitor dependencyVisitor) { return dependencyVisitor instanceof InlinedMethodDependencyProcessorVisitor ? (InlinedMethodDependencyProcessorVisitor) dependencyVisitor : null; } @Override protected int visit(DependencyProcessorVisitor dependencyProcessorVisitor, ClassActor context, Dependencies dependencies, int index) { InlinedMethodDependencyProcessorVisitor inlineVisitor = (InlinedMethodDependencyProcessorVisitor) dependencyProcessorVisitor; int i = index; int mindex = dependencies.packed[i++]; int inlineeMIndex = mindex; ClassActor inlineeHolder; if (inlineeMIndex >= 0) { inlineeHolder = context; } else { inlineeMIndex = -inlineeMIndex - 1; int inlineeHolderID = dependencies.packed[i++]; inlineeHolder = inlineVisitor != null ? ClassIDManager.toClassActor(inlineeHolderID) : null; } if (inlineVisitor != null) { ClassMethodActor inliningMethod = dependencies.targetMethod.classMethodActor; ClassMethodActor inlineeMethod = (ClassMethodActor) MethodID.toMethodActor(MethodID.fromWord(MemberID.create(inlineeHolder.id, inlineeMIndex))); if (!inlineVisitor.doInlinedMethod(dependencies.targetMethod, inliningMethod, inlineeMethod, context)) { return -1; } } return i; } private static final ArrayList<TargetMethod> EMPTY = new ArrayList<TargetMethod>(0); /** * Returns all the {@link TargetMethod} instances that inlined {@code inlineeToCheck}. * * @param inlineeToCheck */ public static ArrayList<TargetMethod> getInliners(final ClassMethodActor inlineeToCheck) { if (inlineeToCheck.isDeclaredNeverInline()) { return EMPTY; } final ArrayList<TargetMethod> result = new ArrayList<TargetMethod>(); classHierarchyLock.readLock().lock(); try { for (DSet dset : ContextDependents.map.values()) { synchronized (dset) { int i = 0; while (i < dset.size()) { final Dependencies deps = dset.getDeps(i); final int fi = i; deps.visit(new FindInliners() { @Override public boolean doInlinedMethod(TargetMethod targetMethod, ClassMethodActor method, ClassMethodActor inlinee, ClassActor context) { if (inlinee == inlineeToCheck) { inlineLogger.logDoInlinedMethod(fi, deps, targetMethod, method, inlinee, context); add(targetMethod); } return true; } private boolean add(TargetMethod targetMethod) { for (TargetMethod tm : result) { if (tm == targetMethod) { return false; } } result.add(targetMethod); return true; } }); i++; } } } return result; } finally { classHierarchyLock.readLock().unlock(); } } private static abstract class FindInliners extends Dependencies.DependencyVisitor implements InlinedMethodDependencyProcessor.InlinedMethodDependencyProcessorVisitor { } @VMLoggerInterface(noTrace = true) private interface InlineLoggerInterface { void doInlinedMethod(int i, Dependencies deps, TargetMethod targetMethod, ClassMethodActor method, ClassMethodActor inlinee, ClassActor context); } private static final InlineLogger inlineLogger = new InlineLogger(); private static class InlineLogger extends InlineLoggerAuto { InlineLogger() { super("GetInliners", ""); } } // START GENERATED CODE private static abstract class InlineLoggerAuto extends com.sun.max.vm.log.VMLogger { public enum Operation { DoInlinedMethod; @SuppressWarnings("hiding") public static final Operation[] VALUES = values(); } private static final int[] REFMAPS = new int[] {0x6}; protected InlineLoggerAuto(String name, String optionDescription) { super(name, Operation.VALUES.length, optionDescription, REFMAPS); } @Override public String operationName(int opCode) { return Operation.VALUES[opCode].name(); } @INLINE public final void logDoInlinedMethod(int arg1, Dependencies arg2, TargetMethod arg3, ClassMethodActor arg4, ClassMethodActor arg5, ClassActor arg6) { log(Operation.DoInlinedMethod.ordinal(), intArg(arg1), objectArg(arg2), objectArg(arg3), methodActorArg(arg4), methodActorArg(arg5), classActorArg(arg6)); } } // END GENERATED CODE }