1 /*
  2  * Copyright (c) 2022, BELLSOFT. 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 package compiler.c2.aarch64;
 24 
 25 import jdk.test.lib.process.OutputAnalyzer;
 26 import jdk.test.lib.process.ProcessTools;
 27 import java.util.regex.Matcher;
 28 import java.util.regex.Pattern;
 29 import java.util.*;
 30 
 31 /*
 32  * @test
 33  * @bug 8280872
 34  * @summary Far call to runtime stub should be generated with single instruction for CodeHeap up to 250MB
 35  * @library /test/lib /
 36  *
 37  * @requires vm.flagless
 38  * @requires os.arch=="aarch64"
 39  * @requires vm.debug == false
 40  * @requires vm.compiler2.enabled
 41  *
 42  * @run driver compiler.c2.aarch64.TestFarJump
 43  */
 44 public class TestFarJump {
 45 
 46     // ADRP instruction encoding:
 47     //   |31 30 29 28|27 26 25 24|23 22 21 20|19 18 17 16|15 14 13 12|11 10 09 08|07 06 05 04|03 02 01 10|
 48     //   | 1|immlo| 1  0  0  0  0|                immhi                                   |     Rd       |
 49     static boolean isADRP(int encoding) {
 50         final int mask = 0b1001_1111;
 51         final int val  = 0b1001_0000;
 52         return ((encoding >> 24) & mask) == val;
 53     }
 54 
 55     // Looking for adrp instruction in binary/text assembly output:
 56     //     0x0000ffff7ff1b7d0: c8ff ffd0 | 0801 1091 | 0001 1fd6
 57     //     0x0000ffff6bf20ee0: adrp        x8, 0x0000ffff6bef1000
 58     static boolean containsADRP(String input) {
 59         int index = input.indexOf(": ");
 60         if (index == -1) {
 61             return false;
 62         }
 63         input = input.substring(index + 1);
 64         if (input.contains("adrp")) {
 65             return true;
 66         }
 67         Pattern pattern = Pattern.compile("[0-9a-f ]*");
 68         Matcher matcher = pattern.matcher(input);
 69         while (matcher.find()) {
 70             String match = matcher.group();
 71             match = match.replace(" " , "");
 72             if (match.length() != 8) {
 73                 continue;
 74             }
 75             int dump = (int)Long.parseLong(match, 16);
 76             int encoding = Integer.reverseBytes(dump);
 77             // Check the first instruction only. The raw pointer can be confused with the encoded adrp instruction:
 78             // emit_exception_handler() = far_call() + should_not_reach_here() = ADRP + ADD + BLR + DCPS1 + raw_pointer
 79             return isADRP(encoding);
 80         }
 81         return false;
 82     }
 83 
 84     static void runVM(boolean bigCodeHeap) throws Exception {
 85         String className = TestFarJump.class.getName();
 86         String[] procArgs = {
 87             "-XX:-Inline",
 88             "-Xcomp",
 89             "-Xbatch",
 90             "-XX:+TieredCompilation",
 91             "-XX:+SegmentedCodeCache",
 92             "-XX:CompileOnly=" + className + "::main",
 93             "-XX:ReservedCodeCacheSize=" + (bigCodeHeap ? "256M" : "200M"),
 94             "-XX:+UnlockDiagnosticVMOptions",
 95             "-XX:+PrintAssembly",
 96             className};
 97 
 98         ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder(procArgs);
 99         OutputAnalyzer output = new OutputAnalyzer(pb.start());
100         List<String> lines = output.asLines();
101 
102         ListIterator<String> itr = lines.listIterator();
103         while (itr.hasNext()) {
104             String line = itr.next();
105             if (line.contains("[Exception Handler]")) {
106                 String next1 = itr.next();
107                 String next2 = itr.next();
108                 System.out.println(line);
109                 System.out.println(next1);
110                 System.out.println(next2);
111                 boolean containsADRP = containsADRP(next1) || containsADRP(next2);
112                 if (bigCodeHeap && !containsADRP) {
113                     throw new RuntimeException("ADRP instruction is expected on far jump");
114                 }
115                 if (!bigCodeHeap && containsADRP) {
116                     throw new RuntimeException("for CodeHeap < 250MB the far jump is expected to be encoded with a single branch instruction");
117                 }
118                 return;
119             }
120         }
121         throw new RuntimeException("Assembly output: exception Handler is not found");
122     }
123 
124     public static void main(String[] args) throws Exception {
125         if (args.length == 0) {
126             // Main VM: fork VM with options
127             runVM(true);
128             runVM(false);
129             return;
130         }
131         if (args.length > 0) {
132             // We are in a forked VM. Just exit
133             System.out.println("Ok");
134         }
135     }
136 }
137