1 /*
  2  * Copyright (c) 2024, 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.
  8  *
  9  * This code is distributed in the hope that it will be useful, but WITHOUT
 10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 12  * version 2 for more details (a copy is included in the LICENSE file that
 13  * accompanied this code).
 14  *
 15  * You should have received a copy of the GNU General Public License version
 16  * 2 along with this work; if not, write to the Free Software Foundation,
 17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 18  *
 19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 20  * or visit www.oracle.com if you need additional information or have any
 21  * questions.
 22  */
 23 
 24 import org.testng.Assert;
 25 import org.testng.annotations.Test;
 26 
 27 import java.io.StringWriter;
 28 import java.lang.reflect.Method;
 29 import java.lang.reflect.code.Op;
 30 import java.lang.reflect.code.op.CoreOp;
 31 import java.lang.reflect.code.op.ExtendedOp;
 32 import java.lang.reflect.code.parser.OpParser;
 33 import java.lang.reflect.code.writer.OpWriter;
 34 import java.lang.runtime.CodeReflection;
 35 import java.util.Optional;
 36 
 37 /**
 38  * @test
 39  * @summary Test symbolic access of method
 40  * @run testng TreeAccessTest
 41  */
 42 
 43 public class TreeAccessTest {
 44 
 45     @CodeReflection
 46     public int m(String s) {
 47         return s.length();
 48     }
 49 
 50     @Test
 51     void testTreeAccess() throws Exception {
 52         Method m = TreeAccessTest.class.getDeclaredMethod("m", String.class);
 53 
 54         Optional<CoreOp.FuncOp> tree = m.getCodeModel();
 55         Assert.assertTrue(tree.isPresent());
 56 
 57         CoreOp.FuncOp methodTree = tree.get();
 58 
 59         String expectedTree = """
 60                 func @"m" (%0 : TreeAccessTest, %1 : java.lang.String)int -> {
 61                       %2 : Var<java.lang.String> = var %1 @"s";
 62                       %3 : java.lang.String = var.load %2;
 63                       %4 : int = invoke %3 @"java.lang.String::length()int";
 64                       return %4;
 65                 };
 66                 """;
 67 
 68         Assert.assertEquals(canonicalizeModel(methodTree), canonicalizeModel(expectedTree));
 69     }
 70 
 71     @Test
 72     public int n(String s) {
 73         return s.length();
 74     }
 75 
 76     @Test
 77     void testNoTree() throws Exception {
 78         Method m = TreeAccessTest.class.getDeclaredMethod("n", String.class);
 79 
 80         Optional<CoreOp.FuncOp> tree = m.getCodeModel();
 81         Assert.assertTrue(tree.isEmpty());
 82     }
 83 
 84 
 85     // serializes dropping location information, parses, and then serializes, dropping location information
 86     static String canonicalizeModel(Op o) {
 87         return canonicalizeModel(serialize(o));
 88     }
 89 
 90     // parses, and then serializes, dropping location information
 91     static String canonicalizeModel(String d) {
 92         Op o;
 93         try {
 94             o = OpParser.fromString(ExtendedOp.FACTORY, d).get(0);
 95         } catch (Exception e) {
 96             throw new IllegalStateException(e);
 97         }
 98         return serialize(o);
 99     }
100 
101     // serializes, dropping location information
102     static String serialize(Op o) {
103         StringWriter w = new StringWriter();
104         OpWriter.writeTo(w, o, OpWriter.LocationOption.DROP_LOCATION);
105         return w.toString();
106     }
107 }