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