Initial Prototype Experimentation

Paul Sandoz paul.sandoz at oracle.com
Wed Jan 31 20:36:54 UTC 2024


What Maurizio says. As you have probably gathered we have yet to fully document the code model design and how we model Java programs, which is to some extent also a moving target as we make forward progress.

Here is a brief summary of the model structure:

"
A code model is a tree containing operations, bodies, and blocks. An operation
contains zero or more bodies. A body contains one or more blocks. A block
contains a sequence of one or more operations. A block can declare zero or more
block parameters, values. An operation declares an operation result, a value. An
operation may use values as operands, but only after they have been declared.
"

(This is actually copied from some articles we will publish soon that should also help explain things at a high-level.)

In your example the invoke operation (to a static method) uses the result of the constant operation as an operand. From the result of the constant operation you can ask “who uses or depends on me?”, and in this case it would refer to the result of the invoke operation. So it's also possible to jump around the tree. 

There is a method on CodeElement (the top-level class for tree nodes in models) called traverse that performs a pre-order traversal of the tree. It’s very simple, but you might find that useful for exploratory purposes.

Hth,
Paul.

> On Jan 31, 2024, at 7:50 AM, Maurizio Cimadamore <maurizio.cimadamore at oracle.com> wrote:
> 
> Hi Ethan,
> to show the contents of a method body, it is recommended to use the Op::toText method. This converts the op in a representation that can be more easily understood by us humans.
> I suggest you look there, and see if that helps understanding better how things are connected (it sure helped me a lot).
> Cheers
> Maurizio
> 
> On 31/01/2024 15:43, Ethan McCue wrote:
>> Hi all,
>> 
>> I understand this is extremely early, but I started trying to experiment with the prototype API yesterday. I feel like there are some core concepts that I am not understanding.
>> 
>> I was trying to make a basic Java -> JS compiler. The idea is that if you stick to a set of special classes and initialize them with constants, there would be a mechanical translation to equivalent JS.
>> 
>>     final class OnlyAvailableInBrowser extends RuntimeException {
>>     }
>> 
>>     public final class JsConsole {
>>         private JsConsole() {}
>> 
>>         public static void log(JsAny o) {
>>             throw new OnlyAvailableInBrowser();
>>         }
>>     }
>> 
>>     public sealed abstract class JsAny permits JsString {
>>     }
>> 
>>     public final class JsString extends JsAny {
>>         private JsString() {}
>> 
>>         public static JsString of(String s) {
>>             throw new OnlyAvailableInBrowser();
>>         }
>>     }
>> 
>> So if there is a method like this
>> 
>>     @CodeReflection
>>     public static void f() {
>>         var s = JsString.of("abc");
>>         JsConsole.log(s);
>>     }
>> 
>> Then I want to get at the fact that the string constant "abc" is passed to JsString#of, that the result of that gets assigned to a variable, and that that variable gets passed to JsConsole#log
>> 
>> Looking at the model and the body of the model doesn't give me many clues
>> 
>>     public static void main(String[] args) throws NoSuchMethodException {
>>         var model = Main.class.getMethod("f")
>>                 .getCodeModel()
>>                 .orElseThrow();
>> 
>>         System.out.println(model);
>>         System.out.println(model.body());
>> 
>> java.lang.reflect.code.op.CoreOps$FuncOp at 63440df3
>> java.lang.reflect.code.Body at 6121c9d6
>> 
>> Looking at the operations in the body gets me closer
>> 
>>         model.body().entryBlock().ops().forEach(System.out::println);
>> 
>> java.lang.reflect.code.op.CoreOps$ConstantOp at 1060b431
>> java.lang.reflect.code.op.CoreOps$InvokeOp at 612679d6
>> java.lang.reflect.code.op.CoreOps$VarOp at 11758f2a
>> java.lang.reflect.code.op.CoreOps$VarAccessOp$VarLoadOp at e720b71
>> java.lang.reflect.code.op.CoreOps$InvokeOp at 1b26f7b2
>> java.lang.reflect.code.op.CoreOps$ReturnOp at 491cc5c9
>> 
>> But it's unclear, to me, how to tie the invoke op to the constant op. The only unique method on InvokeOp is invokeDescriptor which doesn't seem right.
>> 
>> .operands() seems appropriate, but that has a list of [java.lang.reflect.code.Op$Result at 6a1aab78]. Looking at that class I see an op method
>> 
>>         var invokeOp = (CoreOps.InvokeOp) model
>>                 .body()
>>                 .entryBlock()
>>                 .ops()
>>                 .get(1);
>> 
>>         System.out.println(((Op.Result) invokeOp.operands().get(0)).op());
>> 
>> Which does get me a constant op, but I don't quite understand how to relate that constant op to the op in the list of ops. Or, put another way, I don't understand how to traverse the model properly.
>> 



More information about the babylon-dev mailing list