1 /*
   2  * Copyright (c) 2015, 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 /*
  25  * @test
  26  * @bug 8136421
  27  * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64")
  28  * @library / /testlibrary
  29  * @library ../common/patches
  30  * @modules jdk.vm.ci/jdk.vm.ci.hotspot
  31  * @build jdk.vm.ci/jdk.vm.ci.hotspot.CompilerToVMHelper
  32  * @build compiler.jvmci.compilerToVM.InitializeConfigurationTest
  33  * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI
  34  *                   compiler.jvmci.compilerToVM.InitializeConfigurationTest
  35  */
  36 
  37 package compiler.jvmci.compilerToVM;
  38 
  39 import java.util.ArrayList;
  40 import java.util.Iterator;
  41 import java.util.List;
  42 import java.util.NoSuchElementException;
  43 import java.util.Objects;
  44 import java.util.function.Consumer;
  45 import jdk.vm.ci.hotspot.CompilerToVMHelper;
  46 import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime;
  47 import jdk.test.lib.Asserts;
  48 import jdk.test.lib.Utils;
  49 import sun.misc.Unsafe;
  50 
  51 public class InitializeConfigurationTest {
  52     private static final Unsafe UNSAFE = Utils.getUnsafe();
  53 
  54     public static void main(String args[]) {
  55         new InitializeConfigurationTest().runTest(generateTestCases());
  56     }
  57 
  58     private static List<TestCase> generateTestCases() {
  59         List<TestCase> result = new ArrayList<>();
  60         result.add(new TestCase("CodeCache", "_high_bound", "address",
  61                 InitializeConfigurationTest::verifyLongIsNotZero));
  62         result.add(new TestCase("StubRoutines", "_jint_arraycopy", "address",
  63                 InitializeConfigurationTest::verifyLongIsNotZero));
  64         return result;
  65     }
  66 
  67     private static void verifyLongIsNotZero(Object o) {
  68         Asserts.assertNotNull(o, "Got null value");
  69         Asserts.assertEQ(o.getClass(), Long.class, "Unexpected value type");
  70         Asserts.assertNE(o, 0L, "Got null address");
  71     }
  72 
  73     private void runTest(List<TestCase> tcases) {
  74         VMStructDataReader reader = new VMStructDataReader(
  75                 CompilerToVMHelper.initializeConfiguration(HotSpotJVMCIRuntime.runtime().getConfig()));
  76         while (reader.hasNext()) {
  77             VMFieldData data = reader.next();
  78             for (TestCase tcase : tcases) {
  79                 tcase.check(data);
  80             }
  81         }
  82         // now check if all passed
  83         for (TestCase tcase: tcases) {
  84             Asserts.assertTrue(tcase.isFound(), "Case failed: " + tcase);
  85         }
  86     }
  87 
  88     private static class VMStructDataReader implements Iterator<VMFieldData> {
  89         // see jvmciCompilerToVM:105 static uintptr_t ciHotSpotVMData[28];
  90         private static final int HOTSPOT_VM_DATA_INDEX_COUNT = 28;
  91         private final long addresses[];
  92         private final long vmStructsBase;
  93         private final long entityNameFieldOffset;
  94         private final long nameFieldOffset;
  95         private final long typeStringFieldOffset;
  96         private final long addressOffset;
  97         private final long entrySize;
  98         private long nextElementAddress;
  99         private VMFieldData nextElement;
 100 
 101         public VMStructDataReader(long gHotSpotVMData) {
 102             Asserts.assertNE(gHotSpotVMData, 0L, "Got null base address");
 103             addresses = new long[HOTSPOT_VM_DATA_INDEX_COUNT];
 104             for (int i = 0; i < HOTSPOT_VM_DATA_INDEX_COUNT; i++) {
 105                 addresses[i] = UNSAFE.getAddress(
 106                         gHotSpotVMData + Unsafe.ADDRESS_SIZE * i);
 107             }
 108             vmStructsBase = addresses[0];
 109             entityNameFieldOffset = addresses[1];
 110             nameFieldOffset = addresses[2];
 111             typeStringFieldOffset = addresses[3];
 112             addressOffset = addresses[6];
 113             entrySize = addresses[7];
 114             nextElementAddress = vmStructsBase;
 115             nextElement = read();
 116         }
 117 
 118         @Override
 119         public boolean hasNext() {
 120             return nextElement != null;
 121         }
 122 
 123         @Override
 124         public VMFieldData next() {
 125             if (nextElement == null) {
 126                 throw new NoSuchElementException("Next element is null");
 127             }
 128             VMFieldData toReturn = nextElement;
 129             nextElementAddress += entrySize;
 130             nextElement = read();
 131             return toReturn;
 132         }
 133 
 134         private VMFieldData read() {
 135             String entityFieldName = readCString(
 136                     UNSAFE.getAddress(nextElementAddress + nameFieldOffset));
 137             if (entityFieldName == null) {
 138                 return null;
 139             }
 140             String fieldType = readCString(UNSAFE.getAddress(
 141                     nextElementAddress + typeStringFieldOffset));
 142             String entityName = readCString(UNSAFE.getAddress(
 143                     nextElementAddress + entityNameFieldOffset));
 144             Object value;
 145             if ("address".equals(fieldType)) {
 146                 long address = UNSAFE.getAddress(
 147                         nextElementAddress + addressOffset);
 148                 value = address;
 149             } else {
 150                 // non-address cases are not supported
 151                 value = null;
 152             }
 153             return new VMFieldData(entityName, entityFieldName, fieldType,
 154                     value);
 155         }
 156 
 157         private static String readCString(long address) {
 158             if (address == 0) {
 159                 return null;
 160             }
 161             StringBuilder sb = new StringBuilder();
 162             for (int i = 0;; i++) {
 163                 char c = (char) UNSAFE.getByte(address + i);
 164                 if (c == 0) {
 165                     break;
 166                 }
 167                 sb.append(c);
 168             }
 169             return sb.toString();
 170         }
 171     }
 172 
 173     private static class VMFieldData {
 174         public final String entityFieldName;
 175         public final String entityName;
 176         public final String fieldType;
 177         public final Object value;
 178 
 179         private VMFieldData(String entityName, String entityFieldName,
 180                 String fieldType, Object value) {
 181             this.entityName = entityName;
 182             this.entityFieldName = entityFieldName;
 183             this.fieldType = fieldType;
 184             this.value = value;
 185         }
 186     }
 187 
 188     private static class TestCase {
 189         public final String entityName;
 190         public final String fieldType;
 191         public final String entityFieldName;
 192         public final Consumer consumer;
 193         private boolean found;
 194 
 195         public TestCase(String entityName, String entityFieldName,
 196                 String fieldType, Consumer predicate) {
 197             Objects.requireNonNull(entityName, "Got null entityName");
 198             Objects.requireNonNull(entityFieldName, "Got null entityFieldName");
 199             Objects.requireNonNull(fieldType, "Got null type");
 200             if (!"address".equals(fieldType)) {
 201                 throw new Error("TESTBUG: unsupported testcase with fieldType="
 202                         + fieldType);
 203             }
 204             this.entityName = entityName;
 205             this.fieldType = fieldType;
 206             this.entityFieldName = entityFieldName;
 207             this.consumer = predicate;
 208             this.found = false;
 209         }
 210 
 211         public void check(VMFieldData data) {
 212             if (entityFieldName.equals(data.entityFieldName)
 213                     && entityName.equals(data.entityName)
 214                     && fieldType.equals(data.fieldType)) {
 215                 Asserts.assertFalse(found, "Found 2 entries of " + this);
 216                 found = true;
 217                 consumer.accept(data.value);
 218             }
 219         }
 220 
 221         @Override
 222         public String toString() {
 223             return "CASE: entityName=" + entityName + " entityFieldName="
 224                     + entityFieldName + " fieldType=" + fieldType;
 225         }
 226 
 227         public boolean isFound() {
 228             return found;
 229         }
 230     }
 231 }