1 /*
  2  * Copyright (c) 2024, 2026, Oracle and/or its affiliates. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  * This code is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 only, as
  7  * published by the Free Software Foundation.  Oracle designates this
  8  * particular file as subject to the "Classpath" exception as provided
  9  * by Oracle in the LICENSE file that accompanied this code.
 10  *
 11  * This code is distributed in the hope that it will be useful, but WITHOUT
 12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 14  * version 2 for more details (a copy is included in the LICENSE file that
 15  * accompanied this code).
 16  *
 17  * You should have received a copy of the GNU General Public License version
 18  * 2 along with this work; if not, write to the Free Software Foundation,
 19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 20  *
 21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 22  * or visit www.oracle.com if you need additional information or have any
 23  * questions.
 24  */
 25 
 26 package jdk.incubator.code;
 27 
 28 import com.sun.tools.javac.api.JavacScope;
 29 import com.sun.tools.javac.api.JavacTrees;
 30 import com.sun.tools.javac.code.Symbol.ClassSymbol;
 31 import com.sun.tools.javac.comp.Attr;
 32 import com.sun.tools.javac.model.JavacElements;
 33 import com.sun.tools.javac.processing.JavacProcessingEnvironment;
 34 import com.sun.tools.javac.tree.JCTree.JCMethodDecl;
 35 import com.sun.tools.javac.tree.TreeMaker;
 36 import com.sun.tools.javac.util.Context;
 37 import jdk.incubator.code.dialect.core.CoreType;
 38 import jdk.incubator.code.dialect.java.JavaOp;
 39 import jdk.incubator.code.internal.ReflectMethods;
 40 import jdk.incubator.code.dialect.core.CoreOp.FuncOp;
 41 import jdk.incubator.code.dialect.core.FunctionType;
 42 import jdk.incubator.code.dialect.java.MethodRef;
 43 import jdk.incubator.code.extern.OpWriter;
 44 import jdk.internal.access.SharedSecrets;
 45 
 46 import javax.annotation.processing.ProcessingEnvironment;
 47 import javax.lang.model.element.ExecutableElement;
 48 import javax.lang.model.element.Modifier;
 49 import java.lang.reflect.Method;
 50 import java.lang.reflect.Proxy;
 51 import java.util.*;
 52 import java.util.function.BiFunction;
 53 
 54 /**
 55  * An operation modeling a unit of program behavior.
 56  * <p>
 57  * An operation uses zero or more values, exposed as a sequence of {@link #operands()}. A
 58  * {@link Op.Terminating terminating} operation may have block references, exposed as a sequence of
 59  * {@link #successors()}. An operation has zero or more bodies, exposed as a sequence of {@link #bodies()}.
 60  *
 61  * <h2>Operation construction</h2>
 62  * <p>
 63  * Constructing an operation creates an <i>unplaced</i> operation. An unplaced operation is not yet part of a code
 64  * model. The operation's operands, successors, bodies, and operation-specific state are fixed when construction
 65  * completes.
 66  * <p>
 67  * An operation can only be constructed with operands whose declaring block is being built. Otherwise, construction
 68  * fails with an exception.
 69  *
 70  * <h2>Operation building</h2>
 71  * <p>
 72  * Building an operation places an unplaced operation in a code model in one of two ways:
 73  * <ol>
 74  * <li>
 75  * the operation is <i>placed</i> in a block, which becomes its parent block, by using a block builder to
 76  * {@link Block.Builder#add(Op) append} the operation to the block. The placed operation has a permanently
 77  * non-{@code null} {@link #result() result} that can be used as an operand of subsequently constructed operations. The
 78  * block being built is not <a href="Body.Builder.html#body-building-observability">observable</a> through this
 79  * operation and any attempt to access the block throws {@link IllegalStateException}.
 80  * <li>
 81  * the operation is <i>placed</i> as the {@link #isRoot() <i>root operation</i>} of a code model by using
 82  * {@link #buildAsRoot()}. The root operation's {@link #result() result} and {@link #parent() parent} are always
 83  * {@code null}.
 84  * </ol>
 85  * <p>
 86  * Building finishes when the parent body builder of the block in which the operation was placed
 87  * <a href="Body.Builder.html#body-building-finishing">finishes</a>, after which the block becomes observable, or when
 88  * the operation is placed as the root of a code model. After building finishes, the operation's placement and location
 89  * are also fixed, and from then on the operation's observable state does not change.
 90  * <p>
 91  * The {@link #location} may be {@link #setLocation set} while the operation is unplaced or placed in a block whose
 92  * parent body builder has not finished.
 93  * <p>
 94  * An unplaced operation, or an operation placed in a block whose parent body builder has not
 95  * <a href="Body.Builder.html#body-building-finishing">finished</a>, is not thread-safe.
 96  *
 97  * <h2>Operation implementation requirements</h2>
 98  * <p>
 99  * A concrete operation class must satisfy the following requirements:
100  * <ul>
101  * <li>
102  * implement {@link #resultType()} to return the result type of operation instances;
103  * <li>
104  * implement {@link #transform(CodeContext, CodeTransformer)} to return a newly constructed, unplaced copy whose
105  * concrete class is the concrete operation class;
106  * <li>
107  * call an appropriate {@code Op} superclass constructor from each concrete operation constructor. Constructors
108  * for new operations pass the operation's operands to {@link #Op(List)}. Constructors for transformed copies can
109  * pass the input operation and code context to {@link #Op(Op, CodeContext)};
110  * <li>
111  * override {@link #bodies()} if instances may have bodies. If the operation class implements {@link Op.Nested}, then
112  * {@code bodies()} must return one or more bodies;
113  * <li>
114  * override {@link #successors()} if instances may have successors. If the operation class implements
115  * {@link Op.BlockTerminating}, then {@code successors()} must return one or more successors;
116  * <li>
117  * copy mutable constructor arguments that define successors, bodies, and operation-specific state, ensuring
118  * they are all fixed when construction completes; and
119  * <li>
120  * return unmodifiable views or immutable values from accessors that expose successors, bodies, and operation-specific
121  * state.
122  * </ul>
123  * <p>
124  * A concrete operation class may additionally:
125  * <ul>
126  * <li>
127  * override {@link #externalizeOpName()} and {@link #externalize()} to define an external form;
128  * <li>
129  * implement {@link Op.Lowerable} to define a lowering; and
130  * <li>
131  * provide operation-specific accessors for operation-specific state.
132  * </ul>
133  *
134  * @apiNote
135  * An operation might model the {@link JavaOp.AddOp addition} of two integers, or a method
136  * {@link JavaOp.InvokeOp invocation} expression. Alternatively an operation may model something more complex like
137  * {@link jdk.incubator.code.dialect.core.CoreOp.FuncOp method} declarations, {@link JavaOp.LambdaOp lambda}
138  * expressions, or {@link JavaOp.TryOp try} statements. In such cases an operation will contain one or more bodies
139  * modeling the nested structure.
140  */
141 public non-sealed abstract class Op implements CodeElement<Op, Body> {
142 
143     /**
144      * An operation characteristic indicating the operation is pure and has no side effects.
145      */
146     public interface Pure {
147     }
148 
149     /**
150      * An operation characteristic indicating the operation has one or more bodies.
151      */
152     public interface Nested {
153         /**
154          * {@return a non-empty list of this nested operation's bodies.}
155          */
156         List<Body> bodies();
157     }
158 
159     /**
160      * An operation characteristic indicating the operation represents a loop.
161      */
162     public interface Loop extends Nested {
163         /**
164          * {@return the body of this loop operation.}
165          * <p>
166          * The returned body is one of this operation's {@link #bodies() bodies}.
167          */
168         Body loopBody();
169     }
170 
171     /**
172      * An operation characteristic indicating the operation has one or more bodies,
173      * all of which are isolated and capture no values.
174      */
175     public interface Isolated extends Nested {
176     }
177 
178     /**
179      * An operation characteristic indicating the operation is invokable.
180      */
181     public interface Invokable extends Nested {
182         /**
183          * {@return the body of this invokable operation.}
184          * <p>
185          * The returned body is one of this operation's {@linkplain #bodies() bodies}.
186          */
187         Body body();
188 
189         /**
190          * {@return the invokable operation's signature, represented as a function type.}
191          * @implSpec
192          * The default implementation returns the signature of the invokable operation's body.
193          */
194         default FunctionType invokableSignature() {
195             return body().bodySignature();
196         }
197 
198         /**
199          * {@return the entry block parameters of this operation's body}
200          * @implSpec
201          * The default implementation returns the entry block's parameters of the invokable operation's body.
202          */
203         default List<Block.Parameter> parameters() {
204             return body().entryBlock().parameters();
205         }
206 
207         /**
208          * Computes values captured by this invokable operation's body.
209          * @implSpec
210          * The default implementation returns an empty unmodifiable list.
211          *
212          * @return the captured values.
213          * @see Body#capturedValues()
214          */
215         default List<Value> capturedValues() {
216             return List.of();
217         }
218     }
219 
220     /**
221      * An operation characteristic indicating the operation can lower itself by replacing itself with blocks and
222      * operations that represent the same behavior.
223      */
224     // @@@ Hide this abstraction within JavaOp?
225     public interface Lowerable {
226 
227         /**
228          * Lowers this operation into the given block builder.
229          * <p>
230          * A lowering implementation emits the replacement blocks and operations into the given builder, and returns
231          * the block builder to use for subsequent operations in an enclosing transformation.
232          * <p>
233          * If this operation lowers one of its bodies, it should transform that body with a lowering code transformer
234          * produced by {@link #loweringTransformer(BiFunction, BiFunction)}. This ensures that lowerable operations
235          * encountered in that body are lowered recursively.
236          * The {@code inherited} transformer is the operation transformer inherited from an enclosing lowering, if any.
237          * A lowering implementation may pass it directly to {@code loweringTransformer}, or compose it with another
238          * transformer and pass the composed transformer. The transformer passed to {@code loweringTransformer} is then
239          * supplied as the inherited transformer when that lowering code transformer recursively lowers lowerable
240          * operations.
241          *
242          * @param b the block builder into which this operation is lowered
243          * @param inherited the inherited operation transformer, may be {@code null}
244          * @return the block builder to use for subsequent building
245          */
246         Block.Builder lower(Block.Builder b, BiFunction<Block.Builder, Op, Block.Builder> inherited);
247 
248         /**
249          * Returns a lowering code transformer that partially composes the given operation transformers and, if
250          * required, lowers lowerable operations and appends non-lowerable operations.
251          * <p>
252          * The returned code transformer accepts an operation by first applying the partial composition of
253          * {@code current} with {@code inherited} in the first argument of {@code current}, as if by the following:
254          * {@snippet lang = "java":
255          * Block.Builder composedBlock = inherited == null
256          *         ? block
257          *         : inherited.apply(block, op);
258          * Block.Builder currentBlock = current.apply(composedBlock, op);
259          * }
260          * The returned continuation builder is then selected as if by the following:
261          * {@snippet lang = "java":
262          * if (currentBlock != null) {
263          *     return currentBlock;
264          * } else if (op instanceof Op.Lowerable lop) {
265          *     return lop.lower(composedBlock, inherited);
266          * } else {
267          *     composedBlock.op(op);
268          *     return composedBlock;
269          * }
270          * }
271          *
272          * @param inherited the inherited operation transformer, may be {@code null}
273          * @param current the current operation transformer
274          * @return the lowering code transformer
275          */
276         static CodeTransformer loweringTransformer(BiFunction<Block.Builder, Op, Block.Builder> inherited,
277                                                    BiFunction<Block.Builder, Op, Block.Builder> current) {
278             Objects.requireNonNull(current);
279             return (block, op) -> {
280                 if (inherited != null) {
281                     block = inherited.apply(block, op);
282                 }
283                 Block.Builder currentBlock = current.apply(block, op);
284                 if (currentBlock != null) {
285                     return currentBlock;
286                 } else if (op instanceof Op.Lowerable lop) {
287                     return lop.lower(block, inherited);
288                 } else {
289                     block.add(op);
290                     return block;
291                 }
292             };
293         }
294     }
295 
296     /**
297      * An operation characteristic indicating the operation is a terminating operation
298      * that occurs as the last operation in a block.
299      * <p>
300      * A terminating operation passes control to either another block within the same parent body
301      * or to that parent body.
302      */
303     public interface Terminating {
304     }
305 
306     /**
307      * An operation characteristic indicating the operation is a body-terminating operation
308      * occurring as the last operation in a block.
309      * <p>
310      * A body-terminating operation passes control back to its nearest ancestor body.
311      */
312     public interface BodyTerminating extends Terminating {
313     }
314 
315     /**
316      * An operation characteristic indicating the operation is a block-terminating operation
317      * occurring as the last operation in a block.
318      * <p>
319      * The operation has one or more successors to other blocks within the same parent body, and passes
320      * control to one of those blocks.
321      */
322     public interface BlockTerminating extends Terminating {
323         /**
324          * {@return a non-empty list of this operation's successors.}
325          */
326         List<Block.Reference> successors();
327     }
328 
329     /**
330      * A value that is the result of an operation.
331      */
332     public static final class Result extends Value {
333 
334         /**
335          * If assigned to an operation's result field, indicates the operation is a root operation.
336          */
337         private static final Result ROOT_RESULT = new Result();
338 
339         final Op op;
340 
341         private Result() {
342             // Constructor for instance of ROOT_RESULT
343             super(null, null);
344             this.op = null;
345         }
346 
347         Result(Block block, Op op) {
348             super(block, op.resultType());
349 
350             this.op = op;
351         }
352 
353         @Override
354         public String toString() {
355             return "%result@" + Integer.toHexString(hashCode());
356         }
357 
358         @Override
359         public SequencedSet<Value> dependsOn() {
360             SequencedSet<Value> depends = new LinkedHashSet<>(op.operands());
361             if (op instanceof Terminating) {
362                 op.successors().stream().flatMap(h -> h.arguments().stream()).forEach(depends::add);
363             }
364 
365             return Collections.unmodifiableSequencedSet(depends);
366         }
367 
368         /**
369          * {@return the result's declaring operation.}
370          */
371         public Op op() {
372             return op;
373         }
374     }
375 
376     /**
377      * Source location information for an operation.
378      *
379      * @param sourceRef the reference to the source, {@code null} if absent
380      * @param line the line in the source
381      * @param column the column in the source
382      */
383     public record Location(String sourceRef, int line, int column) {
384 
385         /**
386          * The location value, {@code null}, indicating no location information.
387          */
388         public static final Location NO_LOCATION = null;
389 
390         /**
391          * Constructs a location with line and column only.
392          *
393          * @param line the line in the source
394          * @param column the column in the source
395          */
396         public Location(int line, int column) {
397             this(null, line, column);
398         }
399     }
400 
401     // Set when op is placed in a block or as a root operation, otherwise null when unplaced
402     // @@@ stable value?
403     Result result;
404 
405     // null if not specified
406     // @@@ stable value?
407     Location location;
408 
409     final List<Value> operands;
410 
411     /**
412      * Constructs an operation with operands mapped from, and location copied from, the given operation.
413      * <p>
414      * The constructed operation's operands are the values computed, in order, by mapping the given operation's operands
415      * using the given code context. The new operation's location is the given operation's location, if any.
416      *
417      * @param that the given operation
418      * @param cc   the code context
419      */
420     protected Op(Op that, CodeContext cc) {
421         List<Value> outputOperands = cc.getValues(that.operands);
422         // Values should be guaranteed to connect to blocks being built since
423         // the context only allows such mappings, assert for clarity
424         assert outputOperands.stream().noneMatch(Value::isBuilt);
425         this.operands = List.copyOf(outputOperands);
426         this.location = that.location;
427     }
428 
429     /**
430      * Transforms this operation, copying the operation and transforming any of its bodies.
431      * <p>
432      * This method returns a newly constructed, unplaced copy of this operation. The returned operation's concrete
433      * class is the same as this operation's concrete class.
434      * <p>
435      * The returned operation copies this operation's operands, successors, and any operation-specific state. Operands
436      * are copied by mapping this operation's operands, in order, with the given code context. Successors are copied as
437      * specified by {@link CodeContext#getReferenceOrCreate(Block.Reference)}. Operation-specific state is copied as
438      * appropriate for the operation, preserving operation-specific behavior.
439      * <p>
440      * Bodies are {@link Body#transform(CodeContext, CodeTransformer) transformed} with the given code context and code
441      * transformer, and built with the returned operation as their parent.
442      *
443      * @apiNote
444      * To copy an operation use the {@link CodeTransformer#COPYING_TRANSFORMER copying transformer}.
445      *
446      * @param cc the code context
447      * @param ct the code transformer
448      * @return the transformed operation
449      * @see CodeTransformer#COPYING_TRANSFORMER
450      */
451     public abstract Op transform(CodeContext cc, CodeTransformer ct);
452 
453     /**
454      * Constructs an operation with a list of operands.
455      *
456      * @param operands the list of operands, a copy of the list is performed if required.
457      * @throws IllegalArgumentException if an operand's declaring block is built.
458      */
459     protected Op(List<? extends Value> operands) {
460         for (Value operand : operands) {
461             if (operand.isBuilt()) {
462                 throw new IllegalArgumentException("Operand's declaring block is built: " + operand);
463             }
464         }
465         this.operands = List.copyOf(operands);
466     }
467 
468     /**
469      * Sets the originating source location of this operation.
470      *
471      * @param l the location, the {@link Location#NO_LOCATION} value indicates the location is not specified.
472      * @throws IllegalStateException if this operation is a root operation, or is placed in a built block.
473      */
474     public final void setLocation(Location l) {
475         // @@@ Fail if location != null?
476         if (isRoot() || (result != null && result.block.isBuilt())) {
477             throw new IllegalStateException("Built operation");
478         }
479 
480         location = l;
481     }
482 
483     /**
484      * {@return the originating source location of this operation, otherwise {@code null} if not specified}
485      */
486     public final Location location() {
487         return location;
488     }
489 
490     /**
491      * Returns this operation's parent block, or {@code null} if this operation is unplaced or a root operation.
492      * <p>
493      * The operation's parent block is the same as the operation result's {@link Value#declaringBlock declaring block}.
494      *
495      * @return operation's parent block, or {@code null} if this operation is unplaced or a root operation.
496      * @throws IllegalStateException if this operation is placed in a block that is
497      * <a href="Body.Builder.html#body-building-observability">unobservable</a>.
498      * @see Value#declaringBlock()
499      */
500     @Override
501     public final Block parent() {
502         if (isRoot() || result == null) {
503             return null;
504         }
505 
506         if (!result.block.isBuilt()) {
507             throw new IllegalStateException("Parent block is unobservable");
508         }
509 
510         return result.block;
511     }
512 
513     @Override
514     public final List<Body> children() {
515         return bodies();
516     }
517 
518     /**
519      * {@return the operation's bodies, as an unmodifiable list}
520      * @implSpec this implementation returns an unmodifiable empty list.
521      * @see #children()
522      */
523     public List<Body> bodies() {
524         return List.of();
525     }
526 
527     /**
528      * {@return the operation's result type}
529      */
530     public abstract CodeType resultType();
531 
532 
533     /**
534      * {@return the operation's result, or {@code null} if this operation is unplaced or a
535      * root operation.}
536      */
537     public final Result result() {
538         return result == Result.ROOT_RESULT ? null : result;
539     }
540 
541     /**
542      * {@return the operation's operands, as an unmodifiable list}
543      */
544     public final List<Value> operands() {
545         return operands;
546     }
547 
548     /**
549      * {@return the operation's successors, as an unmodifiable list}
550      * @implSpec this implementation returns an unmodifiable empty list.
551      */
552     public List<Block.Reference> successors() {
553         return List.of();
554     }
555 
556     /**
557      * Returns the operation's signature, represented as a function type.
558      * <p>
559      * The signature's return type is the operation's result type and its parameter types are the
560      * operation's operand types, in order.
561      *
562      * @return the operation's signature
563      */
564     public final FunctionType opSignature() {
565         List<CodeType> operandTypes = operands.stream().map(Value::type).toList();
566         return CoreType.functionType(resultType(), operandTypes);
567     }
568 
569     /**
570      * Computes values captured by this operation. A captured value is a value that is used but not declared by any
571      * descendant operation of this operation.
572      * <p>
573      * The order of the captured values is first use encountered in depth-first search of this operation's descendant
574      * operations.
575      *
576      * @return the list of captured values, modifiable
577      * @see Body#capturedValues()
578      */
579     public final List<Value> capturedValues() {
580         Set<Value> cvs = new LinkedHashSet<>();
581 
582         Deque<Body> bodyStack = new ArrayDeque<>();
583         for (Body childBody : bodies()) {
584             Body.capturedValues(cvs, bodyStack, childBody);
585         }
586         return new ArrayList<>(cvs);
587     }
588 
589     /**
590      * Builds this operation, placing it as the root operation of a code model. After this operation is placed as a root
591      * operation, its {@link #result() result} and {@link #parent() parent} will always be {@code null}.
592      * <p>
593      * This method is idempotent.
594      *
595      * @throws IllegalStateException if this operation is placed in a block.
596      * @see #isRoot()
597      */
598     public final void buildAsRoot() {
599         if (result == Result.ROOT_RESULT) {
600             return;
601         }
602         if (result != null) {
603             throw new IllegalStateException("Operation is placed in a block");
604         }
605         result = Result.ROOT_RESULT;
606     }
607 
608     /**
609      * {@return {@code true} if this operation is a root operation.}
610      * @see #buildAsRoot()
611      * @see #isPlacedInBlock()
612      */
613     public final boolean isRoot() {
614         return result == Result.ROOT_RESULT;
615     }
616 
617     /**
618      * {@return {@code true} if this operation is placed in a block.}
619      * @see #buildAsRoot()
620      * @see #isRoot()
621      */
622     public final boolean isPlacedInBlock() {
623         return !isRoot() && result != null;
624     }
625 
626     /**
627      * Externalizes this operation's name as a string.
628      * @implSpec this implementation returns the result of the expression {@code this.getClass().getName()}.
629      *
630      * @return the operation name
631      */
632     public String externalizeOpName() {
633         return this.getClass().getName();
634     }
635 
636     /**
637      * Externalizes this operation's specific state as a map of attributes.
638      *
639      * <p>A null attribute value is represented by the constant
640      * value {@link jdk.incubator.code.extern.ExternalizedOp#NULL_ATTRIBUTE_VALUE}.
641      * @implSpec this implementation returns an unmodifiable empty map.
642      *
643      * @return the operation's externalized state, as an unmodifiable map
644      */
645     public Map<String, Object> externalize() {
646         return Map.of();
647     }
648 
649     /**
650      * Returns the code model text for this operation.
651      * <p>
652      * The format of code model text is unspecified.
653      *
654      * @return the code model text for this operation.
655      * @apiNote Code model text is designed to be human-readable and is intended for debugging, testing,
656      * and comprehension.
657      * @see OpWriter#toText(Op, OpWriter.Option...)
658      */
659     public final String toText() {
660         return OpWriter.toText(this);
661     }
662 
663 
664     /**
665      * Returns a quoted instance containing the code model of a reflectable lambda expression or method reference.
666      * <p>
667      * The quoted instance also contains a mapping from {@link Value values} in the code model that model final, or
668      * effectively final, variables used but not declared in the lambda expression to their corresponding run time
669      * values. Such run time values are commonly referred to as captured values.
670      * <p>
671      * Repeated invocations of this method will return a quoted instance containing the same instance of the code model.
672      * Therefore, code elements (and more generally code items) contained within the code model can be reliably compared
673      * using object identity.
674      *
675      * @param fiInstance a functional interface instance that is the result of a reflectable lambda expression or
676      *                   method reference.
677      * @return the quoted instance containing the code model, or an empty optional if the functional interface instance
678      * is not the result of a reflectable lambda expression or method reference.
679      * @throws UnsupportedOperationException if the Java version used at compile time to generate and store the code
680      * model is not the same as the Java version used at runtime to load the code model.
681      * @apiNote if the functional interface instance is a proxy instance, then the quoted code model is unavailable and
682      * this method returns an empty optional.
683      */
684     public static Optional<Quoted<JavaOp.LambdaOp>> ofLambda(Object fiInstance) {
685         Object oq = fiInstance;
686         if (Proxy.isProxyClass(oq.getClass())) {
687             // @@@ The interpreter implements interpretation of
688             // lambdas using a proxy whose invocation handler
689             // supports the internal protocol to access the quoted instance
690             oq = Proxy.getInvocationHandler(oq);
691         }
692 
693         Method method;
694         try {
695             method = oq.getClass().getDeclaredMethod("__internal_quoted");
696         } catch (NoSuchMethodException e) {
697             return Optional.empty();
698         }
699         method.setAccessible(true);
700 
701         Quoted<?> q;
702         try {
703             q = (Quoted<?>) method.invoke(oq);
704         } catch (ReflectiveOperationException e) {
705             // op method may throw UOE in case java compile time version doesn't match runtime version
706             if (e.getCause() instanceof UnsupportedOperationException uoe) {
707                 throw uoe;
708             }
709             throw new RuntimeException(e);
710         }
711         if (!(q.op() instanceof JavaOp.LambdaOp)) {
712             // This can only happen if the stored model is invalid
713             throw new RuntimeException("Invalid code model for lambda expression : " + q);
714         }
715         @SuppressWarnings("unchecked")
716         Quoted<JavaOp.LambdaOp> lq = (Quoted<JavaOp.LambdaOp>) q;
717         return Optional.of(lq);
718     }
719 
720     /**
721      * Returns the code model of a reflectable method.
722      * <p>
723      * Repeated invocations of this method will return the same instance of the code model. Therefore,
724      * code elements (and more generally code items) contained within the code model can be reliably compared using
725      * object identity.
726      *
727      * @param method the method.
728      * @return the code model, or an empty optional if the method is not reflectable.
729      * @throws UnsupportedOperationException if the Java version used at compile time to generate and store the code
730      * model is not the same as the Java version used at runtime to load the code model.
731      */
732     // @@@ Make caller sensitive with the same access control as invoke
733     // and throwing IllegalAccessException
734     // @CallerSensitive
735     @SuppressWarnings("unchecked")
736     public static Optional<FuncOp> ofMethod(Method method) {
737         return (Optional<FuncOp>)SharedSecrets.getJavaLangReflectAccess()
738                 .setCodeModelIfNeeded(method, Op::createCodeModel);
739     }
740 
741     private static Optional<FuncOp> createCodeModel(Method method) {
742         char[] sig = MethodRef.method(method).toString().toCharArray();
743         for (int i = 0; i < sig.length; i++) {
744             switch (sig[i]) {
745                 case '.', ';', '[', '/': sig[i] = '$';
746             }
747         }
748         String opMethodName = new String(sig);
749         Method opMethod;
750         try {
751             // @@@ Use method handle with full power mode
752             opMethod = method.getDeclaringClass().getDeclaredMethod(opMethodName);
753         } catch (NoSuchMethodException e) {
754             return Optional.empty();
755         }
756         opMethod.setAccessible(true);
757         try {
758             FuncOp funcOp = (FuncOp) opMethod.invoke(null);
759             return Optional.of(funcOp);
760         } catch (ReflectiveOperationException e) {
761             // op method may throw UOE in case java compile time version doesn't match runtime version
762             if (e.getCause() instanceof UnsupportedOperationException uoe) {
763                 throw uoe;
764             }
765             throw new RuntimeException(e);
766         }
767     }
768 
769     /**
770      * Returns the code model of provided executable element (if any).
771      * <p>
772      * If the executable element has a code model then it will be an instance of
773      * {@code java.lang.reflect.code.op.CoreOps.FuncOp}.
774      * Note: due to circular dependencies we cannot refer to the type explicitly.
775      *
776      * @param processingEnvironment the annotation processing environment
777      * @param e the executable element.
778      * @return the code model of the provided executable element (if any).
779      */
780     public static Optional<FuncOp> ofElement(ProcessingEnvironment processingEnvironment, ExecutableElement e) {
781         if (e.getModifiers().contains(Modifier.ABSTRACT) ||
782                 e.getModifiers().contains(Modifier.NATIVE)) {
783             return Optional.empty();
784         }
785 
786         Context context = ((JavacProcessingEnvironment)processingEnvironment).getContext();
787         ReflectMethods reflectMethods = ReflectMethods.instance(context);
788         Attr attr = Attr.instance(context);
789         JavacElements elements = JavacElements.instance(context);
790         JavacTrees javacTrees = JavacTrees.instance(context);
791         TreeMaker make = TreeMaker.instance(context);
792         try {
793             JCMethodDecl methodTree = (JCMethodDecl)elements.getTree(e);
794             JavacScope scope = javacTrees.getScope(javacTrees.getPath(e));
795             ClassSymbol enclosingClass = (ClassSymbol) scope.getEnclosingClass();
796             FuncOp op = attr.runWithAttributedMethod(scope.getEnv(), methodTree,
797                     attribBlock -> {
798                         try {
799                             return reflectMethods.getMethodBody(enclosingClass, methodTree, attribBlock, make);
800                         } catch (Throwable ex) {
801                             // this might happen if the source code contains errors
802                             return null;
803                         }
804                     });
805             return Optional.ofNullable(op);
806         } catch (RuntimeException ex) {  // ReflectMethods.UnsupportedASTException
807             // some other error occurred when attempting to attribute the method
808             // @@@ better report of error
809             ex.printStackTrace();
810             return Optional.empty();
811         }
812     }
813 }