47 import java.util.Map;
48 import java.util.concurrent.atomic.AtomicInteger;
49 import java.util.concurrent.atomic.AtomicReference;
50 import java.util.function.Predicate;
51
52 import jdk.internal.vm.compiler.collections.EconomicMap;
53 import jdk.internal.vm.compiler.collections.EconomicSet;
54 import jdk.internal.vm.compiler.collections.Equivalence;
55 import jdk.internal.vm.compiler.collections.UnmodifiableEconomicMap;
56 import org.graalvm.compiler.api.replacements.Fold;
57 import org.graalvm.compiler.api.replacements.Snippet;
58 import org.graalvm.compiler.api.replacements.Snippet.ConstantParameter;
59 import org.graalvm.compiler.api.replacements.Snippet.NonNullParameter;
60 import org.graalvm.compiler.api.replacements.Snippet.VarargsParameter;
61 import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
62 import org.graalvm.compiler.core.common.GraalOptions;
63 import org.graalvm.compiler.core.common.type.Stamp;
64 import org.graalvm.compiler.core.common.type.StampFactory;
65 import org.graalvm.compiler.core.common.type.StampPair;
66 import org.graalvm.compiler.core.common.type.TypeReference;
67 import org.graalvm.compiler.debug.CounterKey;
68 import org.graalvm.compiler.debug.DebugCloseable;
69 import org.graalvm.compiler.debug.DebugContext;
70 import org.graalvm.compiler.debug.DebugContext.Description;
71 import org.graalvm.compiler.debug.DebugHandlersFactory;
72 import org.graalvm.compiler.debug.GraalError;
73 import org.graalvm.compiler.debug.TimerKey;
74 import org.graalvm.compiler.graph.Graph.Mark;
75 import org.graalvm.compiler.graph.Node;
76 import org.graalvm.compiler.graph.Node.NodeIntrinsic;
77 import org.graalvm.compiler.graph.NodeClass;
78 import org.graalvm.compiler.graph.NodeSourcePosition;
79 import org.graalvm.compiler.graph.Position;
80 import org.graalvm.compiler.loop.LoopEx;
81 import org.graalvm.compiler.loop.LoopsData;
82 import org.graalvm.compiler.loop.phases.LoopTransformations;
83 import org.graalvm.compiler.nodeinfo.InputType;
84 import org.graalvm.compiler.nodeinfo.NodeInfo;
85 import org.graalvm.compiler.nodes.AbstractBeginNode;
86 import org.graalvm.compiler.nodes.AbstractMergeNode;
153 import jdk.vm.ci.meta.Signature;
154
155 /**
156 * A snippet template is a graph created by parsing a snippet method and then specialized by binding
157 * constants to the snippet's {@link ConstantParameter} parameters.
158 *
159 * Snippet templates can be managed in a cache maintained by {@link AbstractTemplates}.
160 */
161 public class SnippetTemplate {
162
163 private boolean mayRemoveLocation = false;
164
165 /**
166 * Holds the {@link ResolvedJavaMethod} of the snippet, together with some information about the
167 * method that needs to be computed only once. The {@link SnippetInfo} should be created once
168 * per snippet and then cached.
169 */
170 public abstract static class SnippetInfo {
171
172 protected final ResolvedJavaMethod method;
173 protected ResolvedJavaMethod original;
174 protected final LocationIdentity[] privateLocations;
175 protected final Object receiver;
176
177 public Object getReceiver() {
178 return receiver;
179 }
180
181 boolean hasReceiver() {
182 assert hasReceiver(method) == (receiver != null) : "Snippet with the receiver must have it set as constant. Snippet: " + this;
183 return hasReceiver(method);
184 }
185
186 static boolean hasReceiver(ResolvedJavaMethod method) {
187 return method.hasReceiver();
188 }
189
190 /**
191 * Lazily constructed parts of {@link SnippetInfo}.
192 */
193 static class Lazy {
252 slotIdx += kind.getSlotCount();
253 }
254 }
255 }
256 return true;
257 }
258 }
259
260 /**
261 * Times instantiations of all templates derived from this snippet.
262 */
263 private final TimerKey instantiationTimer;
264
265 /**
266 * Counts instantiations of all templates derived from this snippet.
267 */
268 private final CounterKey instantiationCounter;
269
270 protected abstract Lazy lazy();
271
272 protected SnippetInfo(ResolvedJavaMethod method, LocationIdentity[] privateLocations, Object receiver) {
273 this.method = method;
274 this.privateLocations = privateLocations;
275 instantiationCounter = DebugContext.counter("SnippetInstantiationCount[%s]", method.getName());
276 instantiationTimer = DebugContext.timer("SnippetInstantiationTime[%s]", method.getName());
277 this.receiver = receiver;
278 }
279
280 public ResolvedJavaMethod getMethod() {
281 return method;
282 }
283
284 public int getParameterCount() {
285 return lazy().constantParameters.length;
286 }
287
288 public void setOriginalMethod(ResolvedJavaMethod original) {
289 this.original = original;
290 }
291
292 public boolean isConstantParameter(int paramIdx) {
293 return lazy().constantParameters[paramIdx];
294 }
295
296 public boolean isVarargsParameter(int paramIdx) {
297 return lazy().varargsParameters[paramIdx];
298 }
299
300 public boolean isNonNullParameter(int paramIdx) {
301 return lazy().nonNullParameters[paramIdx];
302 }
303
304 public String getParameterName(int paramIdx) {
305 String[] names = lazy().names;
306 if (names != null) {
307 return names[paramIdx];
308 }
309 return null;
310 }
311
312 @Override
313 public String toString() {
314 return getClass().getSimpleName() + ":" + method.format("%h.%n");
315 }
316 }
317
318 protected static class LazySnippetInfo extends SnippetInfo {
319 protected final AtomicReference<Lazy> lazy = new AtomicReference<>(null);
320
321 protected LazySnippetInfo(ResolvedJavaMethod method, LocationIdentity[] privateLocations, Object receiver) {
322 super(method, privateLocations, receiver);
323 }
324
325 @Override
326 protected Lazy lazy() {
327 if (lazy.get() == null) {
328 lazy.compareAndSet(null, new Lazy(method));
329 }
330 return lazy.get();
331 }
332 }
333
334 protected static class EagerSnippetInfo extends SnippetInfo {
335 protected final Lazy lazy;
336
337 protected EagerSnippetInfo(ResolvedJavaMethod method, LocationIdentity[] privateLocations, Object receiver) {
338 super(method, privateLocations, receiver);
339 lazy = new Lazy(method);
340 }
341
342 @Override
343 protected Lazy lazy() {
344 return lazy;
345 }
346 }
347
348 /**
349 * Values that are bound to the snippet method parameters. The methods {@link #add},
350 * {@link #addConst}, and {@link #addVarargs} must be called in the same order as in the
351 * signature of the snippet method. The parameter name is passed to the add methods for
352 * assertion checking, i.e., to enforce that the order matches. Which method needs to be called
353 * depends on the annotation of the snippet method parameter:
354 * <ul>
355 * <li>Use {@link #add} for a parameter without an annotation. The value is bound when the
356 * {@link SnippetTemplate} is {@link SnippetTemplate#instantiate instantiated}.
357 * <li>Use {@link #addConst} for a parameter annotated with {@link ConstantParameter}. The value
358 * is bound when the {@link SnippetTemplate} is {@link SnippetTemplate#SnippetTemplate created}.
625 this.snippetReflection = snippetReflection;
626 this.target = target;
627 this.factories = factories;
628 if (Options.UseSnippetTemplateCache.getValue(options)) {
629 int size = Options.MaxTemplatesPerSnippet.getValue(options);
630 this.templates = Collections.synchronizedMap(new LRUCache<>(size, size));
631 } else {
632 this.templates = null;
633 }
634 }
635
636 public static Method findMethod(Class<? extends Snippets> declaringClass, String methodName, Method except) {
637 for (Method m : declaringClass.getDeclaredMethods()) {
638 if (m.getName().equals(methodName) && !m.equals(except)) {
639 return m;
640 }
641 }
642 return null;
643 }
644
645 protected SnippetInfo snippet(Class<? extends Snippets> declaringClass, String methodName, LocationIdentity... initialPrivateLocations) {
646 return snippet(declaringClass, methodName, null, initialPrivateLocations);
647 }
648
649 /**
650 * Finds the unique method in {@code declaringClass} named {@code methodName} annotated by
651 * {@link Snippet} and returns a {@link SnippetInfo} value describing it. There must be
652 * exactly one snippet method in {@code declaringClass}.
653 */
654 protected SnippetInfo snippet(Class<? extends Snippets> declaringClass, String methodName, Object receiver, LocationIdentity... initialPrivateLocations) {
655 assert methodName != null;
656 Method method = findMethod(declaringClass, methodName, null);
657 assert method != null : "did not find @" + Snippet.class.getSimpleName() + " method in " + declaringClass + " named " + methodName;
658 assert method.getAnnotation(Snippet.class) != null : method + " must be annotated with @" + Snippet.class.getSimpleName();
659 assert findMethod(declaringClass, methodName, method) == null : "found more than one method named " + methodName + " in " + declaringClass;
660 ResolvedJavaMethod javaMethod = providers.getMetaAccess().lookupJavaMethod(method);
661 providers.getReplacements().registerSnippet(javaMethod, GraalOptions.TrackNodeSourcePosition.getValue(options));
662 LocationIdentity[] privateLocations = GraalOptions.SnippetCounters.getValue(options) ? SnippetCounterNode.addSnippetCounters(initialPrivateLocations) : initialPrivateLocations;
663 if (GraalOptions.EagerSnippets.getValue(options)) {
664 return new EagerSnippetInfo(javaMethod, privateLocations, receiver);
665 } else {
666 return new LazySnippetInfo(javaMethod, privateLocations, receiver);
667 }
668 }
669
670 static final AtomicInteger nextSnippetTemplateId = new AtomicInteger();
671
672 private DebugContext openDebugContext(DebugContext outer, Arguments args) {
673 if (DebugStubsAndSnippets.getValue(options)) {
674 Description description = new Description(args.cacheKey.method, "SnippetTemplate_" + nextSnippetTemplateId.incrementAndGet());
675 return DebugContext.create(options, description, outer.getGlobalMetrics(), DEFAULT_LOG_STREAM, factories);
676 }
677 return DebugContext.DISABLED;
678 }
679
680 /**
681 * Gets a template for a given key, creating it first if necessary.
682 */
683 @SuppressWarnings("try")
684 protected SnippetTemplate template(ValueNode replacee, final Arguments args) {
685 StructuredGraph graph = replacee.graph();
686 DebugContext outer = graph.getDebug();
1021 if (targetMethod != null) {
1022 assert targetMethod.getAnnotation(Fold.class) == null && targetMethod.getAnnotation(NodeIntrinsic.class) == null : "plugin should have been processed";
1023 }
1024 }
1025 return true;
1026 }
1027
1028 public static void explodeLoops(final StructuredGraph snippetCopy, PhaseContext phaseContext) {
1029 // Do any required loop explosion
1030 boolean exploded = false;
1031 do {
1032 exploded = false;
1033 ExplodeLoopNode explodeLoop = snippetCopy.getNodes().filter(ExplodeLoopNode.class).first();
1034 if (explodeLoop != null) { // Earlier canonicalization may have removed the loop
1035 // altogether
1036 LoopBeginNode loopBegin = explodeLoop.findLoopBegin();
1037 if (loopBegin != null) {
1038 LoopEx loop = new LoopsData(snippetCopy).loop(loopBegin);
1039 Mark mark = snippetCopy.getMark();
1040 LoopTransformations.fullUnroll(loop, phaseContext, new CanonicalizerPhase());
1041 new CanonicalizerPhase().applyIncremental(snippetCopy, phaseContext, mark);
1042 loop.deleteUnusedNodes();
1043 }
1044 GraphUtil.removeFixedWithUnusedInputs(explodeLoop);
1045 exploded = true;
1046 }
1047 } while (exploded);
1048 }
1049
1050 protected Object[] getConstantArgs(Arguments args) {
1051 Object[] constantArgs = args.values.clone();
1052 for (int i = 0; i < args.info.getParameterCount(); i++) {
1053 if (!args.info.isConstantParameter(i)) {
1054 constantArgs[i] = null;
1055 } else {
1056 assert constantArgs[i] != null : "Can't pass raw null through as argument";
1057 }
1058 }
1059 return constantArgs;
1060 }
1061
|
47 import java.util.Map;
48 import java.util.concurrent.atomic.AtomicInteger;
49 import java.util.concurrent.atomic.AtomicReference;
50 import java.util.function.Predicate;
51
52 import jdk.internal.vm.compiler.collections.EconomicMap;
53 import jdk.internal.vm.compiler.collections.EconomicSet;
54 import jdk.internal.vm.compiler.collections.Equivalence;
55 import jdk.internal.vm.compiler.collections.UnmodifiableEconomicMap;
56 import org.graalvm.compiler.api.replacements.Fold;
57 import org.graalvm.compiler.api.replacements.Snippet;
58 import org.graalvm.compiler.api.replacements.Snippet.ConstantParameter;
59 import org.graalvm.compiler.api.replacements.Snippet.NonNullParameter;
60 import org.graalvm.compiler.api.replacements.Snippet.VarargsParameter;
61 import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
62 import org.graalvm.compiler.core.common.GraalOptions;
63 import org.graalvm.compiler.core.common.type.Stamp;
64 import org.graalvm.compiler.core.common.type.StampFactory;
65 import org.graalvm.compiler.core.common.type.StampPair;
66 import org.graalvm.compiler.core.common.type.TypeReference;
67 import org.graalvm.compiler.debug.Assertions;
68 import org.graalvm.compiler.debug.CounterKey;
69 import org.graalvm.compiler.debug.DebugCloseable;
70 import org.graalvm.compiler.debug.DebugContext;
71 import org.graalvm.compiler.debug.DebugContext.Description;
72 import org.graalvm.compiler.debug.DebugHandlersFactory;
73 import org.graalvm.compiler.debug.GraalError;
74 import org.graalvm.compiler.debug.TimerKey;
75 import org.graalvm.compiler.graph.Graph.Mark;
76 import org.graalvm.compiler.graph.Node;
77 import org.graalvm.compiler.graph.Node.NodeIntrinsic;
78 import org.graalvm.compiler.graph.NodeClass;
79 import org.graalvm.compiler.graph.NodeSourcePosition;
80 import org.graalvm.compiler.graph.Position;
81 import org.graalvm.compiler.loop.LoopEx;
82 import org.graalvm.compiler.loop.LoopsData;
83 import org.graalvm.compiler.loop.phases.LoopTransformations;
84 import org.graalvm.compiler.nodeinfo.InputType;
85 import org.graalvm.compiler.nodeinfo.NodeInfo;
86 import org.graalvm.compiler.nodes.AbstractBeginNode;
87 import org.graalvm.compiler.nodes.AbstractMergeNode;
154 import jdk.vm.ci.meta.Signature;
155
156 /**
157 * A snippet template is a graph created by parsing a snippet method and then specialized by binding
158 * constants to the snippet's {@link ConstantParameter} parameters.
159 *
160 * Snippet templates can be managed in a cache maintained by {@link AbstractTemplates}.
161 */
162 public class SnippetTemplate {
163
164 private boolean mayRemoveLocation = false;
165
166 /**
167 * Holds the {@link ResolvedJavaMethod} of the snippet, together with some information about the
168 * method that needs to be computed only once. The {@link SnippetInfo} should be created once
169 * per snippet and then cached.
170 */
171 public abstract static class SnippetInfo {
172
173 protected final ResolvedJavaMethod method;
174 protected final ResolvedJavaMethod original;
175 protected final LocationIdentity[] privateLocations;
176 protected final Object receiver;
177
178 public Object getReceiver() {
179 return receiver;
180 }
181
182 boolean hasReceiver() {
183 assert hasReceiver(method) == (receiver != null) : "Snippet with the receiver must have it set as constant. Snippet: " + this;
184 return hasReceiver(method);
185 }
186
187 static boolean hasReceiver(ResolvedJavaMethod method) {
188 return method.hasReceiver();
189 }
190
191 /**
192 * Lazily constructed parts of {@link SnippetInfo}.
193 */
194 static class Lazy {
253 slotIdx += kind.getSlotCount();
254 }
255 }
256 }
257 return true;
258 }
259 }
260
261 /**
262 * Times instantiations of all templates derived from this snippet.
263 */
264 private final TimerKey instantiationTimer;
265
266 /**
267 * Counts instantiations of all templates derived from this snippet.
268 */
269 private final CounterKey instantiationCounter;
270
271 protected abstract Lazy lazy();
272
273 protected SnippetInfo(ResolvedJavaMethod method, ResolvedJavaMethod original, LocationIdentity[] privateLocations, Object receiver) {
274 this.method = method;
275 this.original = original;
276 this.privateLocations = privateLocations;
277 instantiationCounter = DebugContext.counter("SnippetInstantiationCount[%s]", method.getName());
278 instantiationTimer = DebugContext.timer("SnippetInstantiationTime[%s]", method.getName());
279 this.receiver = receiver;
280 }
281
282 public ResolvedJavaMethod getMethod() {
283 return method;
284 }
285
286 public int getParameterCount() {
287 return lazy().constantParameters.length;
288 }
289
290 public boolean isConstantParameter(int paramIdx) {
291 return lazy().constantParameters[paramIdx];
292 }
293
294 public boolean isVarargsParameter(int paramIdx) {
295 return lazy().varargsParameters[paramIdx];
296 }
297
298 public boolean isNonNullParameter(int paramIdx) {
299 return lazy().nonNullParameters[paramIdx];
300 }
301
302 public String getParameterName(int paramIdx) {
303 String[] names = lazy().names;
304 if (names != null) {
305 return names[paramIdx];
306 }
307 return null;
308 }
309
310 @Override
311 public String toString() {
312 return getClass().getSimpleName() + ":" + method.format("%h.%n");
313 }
314 }
315
316 protected static class LazySnippetInfo extends SnippetInfo {
317 protected final AtomicReference<Lazy> lazy = new AtomicReference<>(null);
318
319 protected LazySnippetInfo(ResolvedJavaMethod method, ResolvedJavaMethod original, LocationIdentity[] privateLocations, Object receiver) {
320 super(method, original, privateLocations, receiver);
321 }
322
323 @Override
324 protected Lazy lazy() {
325 if (lazy.get() == null) {
326 lazy.compareAndSet(null, new Lazy(method));
327 }
328 return lazy.get();
329 }
330 }
331
332 protected static class EagerSnippetInfo extends SnippetInfo {
333 protected final Lazy lazy;
334
335 protected EagerSnippetInfo(ResolvedJavaMethod method, ResolvedJavaMethod original, LocationIdentity[] privateLocations, Object receiver) {
336 super(method, original, privateLocations, receiver);
337 lazy = new Lazy(method);
338 }
339
340 @Override
341 protected Lazy lazy() {
342 return lazy;
343 }
344 }
345
346 /**
347 * Values that are bound to the snippet method parameters. The methods {@link #add},
348 * {@link #addConst}, and {@link #addVarargs} must be called in the same order as in the
349 * signature of the snippet method. The parameter name is passed to the add methods for
350 * assertion checking, i.e., to enforce that the order matches. Which method needs to be called
351 * depends on the annotation of the snippet method parameter:
352 * <ul>
353 * <li>Use {@link #add} for a parameter without an annotation. The value is bound when the
354 * {@link SnippetTemplate} is {@link SnippetTemplate#instantiate instantiated}.
355 * <li>Use {@link #addConst} for a parameter annotated with {@link ConstantParameter}. The value
356 * is bound when the {@link SnippetTemplate} is {@link SnippetTemplate#SnippetTemplate created}.
623 this.snippetReflection = snippetReflection;
624 this.target = target;
625 this.factories = factories;
626 if (Options.UseSnippetTemplateCache.getValue(options)) {
627 int size = Options.MaxTemplatesPerSnippet.getValue(options);
628 this.templates = Collections.synchronizedMap(new LRUCache<>(size, size));
629 } else {
630 this.templates = null;
631 }
632 }
633
634 public static Method findMethod(Class<? extends Snippets> declaringClass, String methodName, Method except) {
635 for (Method m : declaringClass.getDeclaredMethods()) {
636 if (m.getName().equals(methodName) && !m.equals(except)) {
637 return m;
638 }
639 }
640 return null;
641 }
642
643 public static ResolvedJavaMethod findMethod(MetaAccessProvider metaAccess, Class<?> declaringClass, String methodName) {
644 ResolvedJavaType type = metaAccess.lookupJavaType(declaringClass);
645 ResolvedJavaMethod result = null;
646 for (ResolvedJavaMethod m : type.getDeclaredMethods()) {
647 if (m.getName().equals(methodName)) {
648 if (!Assertions.assertionsEnabled()) {
649 return m;
650 } else {
651 assert result == null : "multiple definitions found";
652 result = m;
653 }
654 }
655 }
656 if (result == null) {
657 throw new GraalError("Could not find method in " + declaringClass + " named " + methodName);
658 }
659 return result;
660 }
661
662 protected SnippetInfo snippet(Class<? extends Snippets> declaringClass, String methodName, LocationIdentity... initialPrivateLocations) {
663 return snippet(declaringClass, methodName, null, null, initialPrivateLocations);
664 }
665
666 /**
667 * Finds the unique method in {@code declaringClass} named {@code methodName} annotated by
668 * {@link Snippet} and returns a {@link SnippetInfo} value describing it. There must be
669 * exactly one snippet method in {@code declaringClass} with a given name.
670 */
671 protected SnippetInfo snippet(Class<? extends Snippets> declaringClass, String methodName, ResolvedJavaMethod original, Object receiver, LocationIdentity... initialPrivateLocations) {
672 assert methodName != null;
673 ResolvedJavaMethod javaMethod = findMethod(providers.getMetaAccess(), declaringClass, methodName);
674 assert javaMethod != null : "did not find @" + Snippet.class.getSimpleName() + " method in " + declaringClass + " named " + methodName;
675 assert javaMethod.getAnnotation(Snippet.class) != null : javaMethod + " must be annotated with @" + Snippet.class.getSimpleName();
676 providers.getReplacements().registerSnippet(javaMethod, original, receiver, GraalOptions.TrackNodeSourcePosition.getValue(options));
677 LocationIdentity[] privateLocations = GraalOptions.SnippetCounters.getValue(options) ? SnippetCounterNode.addSnippetCounters(initialPrivateLocations) : initialPrivateLocations;
678 if (GraalOptions.EagerSnippets.getValue(options)) {
679 return new EagerSnippetInfo(javaMethod, original, privateLocations, receiver);
680 } else {
681 return new LazySnippetInfo(javaMethod, original, privateLocations, receiver);
682 }
683 }
684
685 static final AtomicInteger nextSnippetTemplateId = new AtomicInteger();
686
687 private DebugContext openDebugContext(DebugContext outer, Arguments args) {
688 if (DebugStubsAndSnippets.getValue(options)) {
689 Description description = new Description(args.cacheKey.method, "SnippetTemplate_" + nextSnippetTemplateId.incrementAndGet());
690 return DebugContext.create(options, description, outer.getGlobalMetrics(), DEFAULT_LOG_STREAM, factories);
691 }
692 return DebugContext.DISABLED;
693 }
694
695 /**
696 * Gets a template for a given key, creating it first if necessary.
697 */
698 @SuppressWarnings("try")
699 protected SnippetTemplate template(ValueNode replacee, final Arguments args) {
700 StructuredGraph graph = replacee.graph();
701 DebugContext outer = graph.getDebug();
1036 if (targetMethod != null) {
1037 assert targetMethod.getAnnotation(Fold.class) == null && targetMethod.getAnnotation(NodeIntrinsic.class) == null : "plugin should have been processed";
1038 }
1039 }
1040 return true;
1041 }
1042
1043 public static void explodeLoops(final StructuredGraph snippetCopy, PhaseContext phaseContext) {
1044 // Do any required loop explosion
1045 boolean exploded = false;
1046 do {
1047 exploded = false;
1048 ExplodeLoopNode explodeLoop = snippetCopy.getNodes().filter(ExplodeLoopNode.class).first();
1049 if (explodeLoop != null) { // Earlier canonicalization may have removed the loop
1050 // altogether
1051 LoopBeginNode loopBegin = explodeLoop.findLoopBegin();
1052 if (loopBegin != null) {
1053 LoopEx loop = new LoopsData(snippetCopy).loop(loopBegin);
1054 Mark mark = snippetCopy.getMark();
1055 LoopTransformations.fullUnroll(loop, phaseContext, new CanonicalizerPhase());
1056 new CanonicalizerPhase().applyIncremental(snippetCopy, phaseContext, mark, false);
1057 loop.deleteUnusedNodes();
1058 }
1059 GraphUtil.removeFixedWithUnusedInputs(explodeLoop);
1060 exploded = true;
1061 }
1062 } while (exploded);
1063 }
1064
1065 protected Object[] getConstantArgs(Arguments args) {
1066 Object[] constantArgs = args.values.clone();
1067 for (int i = 0; i < args.info.getParameterCount(); i++) {
1068 if (!args.info.isConstantParameter(i)) {
1069 constantArgs[i] = null;
1070 } else {
1071 assert constantArgs[i] != null : "Can't pass raw null through as argument";
1072 }
1073 }
1074 return constantArgs;
1075 }
1076
|