Exemple #1
0
  public static void main(String args[]) throws Exception {
    Unsafe unsafe = Utils.getUnsafe();

    // Allocate a byte, write to the location and read back the value
    long address = unsafe.allocateMemory(1);
    assertNotEquals(address, 0L);

    unsafe.putByte(address, Byte.MAX_VALUE);
    assertEquals(Byte.MAX_VALUE, unsafe.getByte(address));
    unsafe.freeMemory(address);

    // Call to allocateMemory() with a negative value should result in an IllegalArgumentException
    try {
      address = unsafe.allocateMemory(-1);
      throw new RuntimeException("Did not get expected IllegalArgumentException");
    } catch (IllegalArgumentException e) {
      // Expected
      assertNotEquals(address, 0L);
    }

    // allocateMemory() should throw an OutOfMemoryError when the underlying malloc fails,
    // we test this by limiting the malloc using -XX:MallocMaxTestWords
    try {
      address = unsafe.allocateMemory(100 * 1024 * 1024 * 8);
    } catch (OutOfMemoryError e) {
      // Expected
      return;
    }
    throw new RuntimeException("Did not get expected OutOfMemoryError");
  }
 private void runTest(TestCase tcase) {
   System.out.println(tcase);
   HotSpotResolvedObjectType resolvedIface =
       CompilerToVMHelper.lookupType(
           Utils.toJVMTypeSignature(tcase.anInterface), getClass(), /* resolve = */ true);
   HotSpotResolvedObjectType resolvedImplementer =
       CompilerToVMHelper.getImplementor(resolvedIface);
   HotSpotResolvedObjectType resolvedExpected = null;
   if (tcase.expectedImplementer != null) {
     resolvedExpected =
         CompilerToVMHelper.lookupType(
             Utils.toJVMTypeSignature(tcase.expectedImplementer),
             getClass(),
             /* resolve = */ true);
   }
   Asserts.assertEQ(
       resolvedImplementer,
       resolvedExpected,
       "Unexpected implementer for " + tcase.anInterface.getName());
 }
  private void checkSanity(CompileCodeTestCase testCase) {
    System.out.println(testCase);
    // to have a clean state
    testCase.deoptimize();
    Pair<Object, ? extends Throwable> reflectionResult;
    Object[] args = Utils.getNullValues(testCase.executable.getParameterTypes());
    reflectionResult = testCase.invoke(args);
    NMethod nMethod = testCase.compile();
    if (nMethod == null) {
      throw new Error(testCase + " : nmethod is null");
    }
    InstalledCode installedCode = testCase.toInstalledCode();
    Object result = null;
    Throwable expectedException = reflectionResult.second;
    boolean gotException = true;
    try {
      args = addReceiver(testCase, args);
      result = CompilerToVMHelper.executeInstalledCode(args, installedCode);
      if (testCase.executable instanceof Constructor) {
        // <init> doesn't have return value, it changes receiver
        result = args[0];
      }
      gotException = false;
    } catch (InvalidInstalledCodeException e) {
      throw new AssertionError(testCase + " : unexpected InvalidInstalledCodeException", e);
    } catch (Throwable t) {
      if (expectedException == null) {
        throw new AssertionError(testCase + " : got unexpected execption : " + t.getMessage(), t);
      }

      if (expectedException.getClass() != t.getClass()) {
        System.err.println("exception from CompilerToVM:");
        t.printStackTrace();
        System.err.println("exception from reflection:");
        expectedException.printStackTrace();
        throw new AssertionError(
            String.format(
                "%s : got unexpected different exceptions : %s != %s",
                testCase, expectedException.getClass(), t.getClass()));
      }
    }

    Asserts.assertEQ(reflectionResult.first, result, testCase + " : different return value");
    if (!gotException) {
      Asserts.assertNull(expectedException, testCase + " : expected exception hasn't been thrown");
    }
  }
    public void run() {
      System.setSecurityManager(getSecurityManager());
      Consumer<Throwable> exceptionCheck =
          e -> {
            if (e == null) {
              if (getExpectedException() != null) {
                String message =
                    name() + ": Didn't get expected exception " + getExpectedException();
                throw new AssertionError(message);
              }
            } else {
              String message =
                  name() + ": Got unexpected exception " + e.getClass().getSimpleName();
              if (getExpectedException() == null) {
                throw new AssertionError(message, e);
              }

              Throwable t = e;
              while (t.getCause() != null) {
                t = t.getCause();
              }
              if (!getExpectedException().isAssignableFrom(t.getClass())) {
                message += " instead of " + getExpectedException().getSimpleName();
                throw new AssertionError(message, e);
              }
            }
          };
      Utils.runAndCheckException(
          () -> {
            try {
              // CompilerToVM::<cinit> provokes CompilerToVM::<init>
              Class.forName("jdk.vm.ci.hotspot.CompilerToVMHelper");
            } catch (ClassNotFoundException e) {
              throw new Error("TESTBUG : " + e, e);
            }
          },
          exceptionCheck);
    }
 private void checkNull() {
   Utils.runAndCheckException(
       () -> CompilerToVMHelper.invalidateInstalledCode(null), NullPointerException.class);
 }
public class ConcurrentClassLoadingTest {
  int numThreads = 0;
  CyclicBarrier l;
  private static final Random rand = Utils.getRandomInstance();

  public static void main(String[] args) throws Throwable {
    ConcurrentClassLoadingTest test = new ConcurrentClassLoadingTest();
    test.parseArgs(args);
    test.run();
  }

  void parseArgs(String[] args) {
    int i = 0;
    while (i < args.length) {
      String flag = args[i];
      switch (flag) {
        case "-numThreads":
          numThreads = Integer.parseInt(args[++i]);
          break;
        default:
          throw new Error("Unknown flag: " + flag);
      }
      ++i;
    }
  }

  void init() {
    if (numThreads == 0) {
      numThreads = Runtime.getRuntime().availableProcessors();
    }

    l = new CyclicBarrier(numThreads + 1);

    System.out.printf("Threads: %d\n", numThreads);
  }

  final List<Loader> loaders = new ArrayList<>();

  void prepare() {
    List<String> c = new ArrayList<>(Arrays.asList(classNames));

    // Split classes between loading threads
    int count = (classNames.length / numThreads) + 1;
    for (int t = 0; t < numThreads; t++) {
      List<String> sel = new ArrayList<>();

      System.out.printf("Thread #%d:\n", t);
      for (int i = 0; i < count; i++) {
        if (c.isEmpty()) {
          break;
        }

        int k = rand.nextInt(c.size());
        String elem = c.remove(k);
        sel.add(elem);
        System.out.printf("\t%s\n", elem);
      }
      loaders.add(new Loader(sel));
    }

    // Print diagnostic info when the test hangs
    Runtime.getRuntime()
        .addShutdownHook(
            new Thread() {
              public void run() {
                boolean alive = false;
                for (Loader l : loaders) {
                  if (!l.isAlive()) continue;

                  if (!alive) {
                    System.out.println("Some threads are still alive:");
                    alive = true;
                  }

                  System.out.println(l.getName());
                  for (StackTraceElement elem : l.getStackTrace()) {
                    System.out.println("\t" + elem.toString());
                  }
                }
              }
            });
  }

  public void run() throws Throwable {
    init();
    prepare();

    for (Loader loader : loaders) {
      loader.start();
    }

    l.await();

    for (Loader loader : loaders) {
      loader.join();
    }
  }

  class Loader extends Thread {
    List<String> classes;

    public Loader(List<String> classes) {
      this.classes = classes;
      setDaemon(true);
    }

    @Override
    public void run() {
      try {
        l.await();

        for (String name : classes) {
          Class.forName(name).getName();
        }
      } catch (ClassNotFoundException | BrokenBarrierException | InterruptedException e) {
        throw new Error(e);
      }
    }
  }

  static final String[] classNames = {
    "java.lang.invoke.CallSite",
    "java.lang.invoke.ConstantCallSite",
    "java.lang.invoke.LambdaConversionException",
    "java.lang.invoke.LambdaMetafactory",
    "java.lang.invoke.MethodHandle",
    "java.lang.invoke.MethodHandleInfo",
    "java.lang.invoke.MethodHandleProxies",
    "java.lang.invoke.MethodHandles",
    "java.lang.invoke.MethodType",
    "java.lang.invoke.MutableCallSite",
    "java.lang.invoke.SerializedLambda",
    "java.lang.invoke.SwitchPoint",
    "java.lang.invoke.VolatileCallSite",
    "java.lang.invoke.WrongMethodTypeException"
  };
}
Exemple #7
0
  /** A test for scale; launch a large number (14) of subprocesses. */
  @Test
  public static void test5() {
    ConcurrentHashMap<ProcessHandle, ProcessHandle> processes = new ConcurrentHashMap<>();

    int factor = 2;
    JavaChild p1 = null;
    Instant start = Instant.now();
    try {
      p1 = JavaChild.spawnJavaChild("stdin");
      ProcessHandle p1Handle = p1.toHandle();

      printf("Spawning %d x %d x %d processes, pid: %d%n", factor, factor, factor, p1.getPid());

      // Start the first tier of subprocesses
      p1.sendAction("spawn", factor, "stdin");

      // Start the second tier of subprocesses
      p1.sendAction("child", "spawn", factor, "stdin");

      // Start the third tier of subprocesses
      p1.sendAction("child", "child", "spawn", factor, "stdin");

      int newChildren = factor * (1 + factor * (1 + factor));
      CountDownLatch spawnCount = new CountDownLatch(newChildren);

      // Gather the PIDs from the output of the spawning process
      p1.forEachOutputLine(
          (s) -> {
            String[] split = s.trim().split(" ");
            if (split.length == 3 && split[1].equals("spawn")) {
              Long child = Long.valueOf(split[2]);
              Long parent = Long.valueOf(split[0].split(":")[0]);
              processes.put(ProcessHandle.of(child).get(), ProcessHandle.of(parent).get());
              spawnCount.countDown();
            }
          });

      // Wait for all the subprocesses to be listed as started
      Assert.assertTrue(
          spawnCount.await(Utils.adjustTimeout(30L), TimeUnit.SECONDS),
          "Timeout waiting for processes to start");

      // Debugging; list descendants that are not expected in processes
      List<ProcessHandle> descendants = ProcessUtil.getDescendants(p1Handle);
      long count = descendants.stream().filter(ph -> !processes.containsKey(ph)).count();
      if (count > 0) {
        descendants
            .stream()
            .filter(ph -> !processes.containsKey(ph))
            .forEach(ph1 -> ProcessUtil.printProcess(ph1, "Extra process: "));
        ProcessUtil.logTaskList();
        Assert.assertEquals(0, count, "Extra processes in descendants");
      }

      Assert.assertEquals(getChildren(p1Handle).size(), factor, "expected direct children");
      count = getDescendants(p1Handle).size();
      long totalChildren = factor * factor * factor + factor * factor + factor;
      Assert.assertTrue(
          count >= totalChildren, "expected at least " + totalChildren + ", actual: " + count);

      List<ProcessHandle> subprocesses = getDescendants(p1Handle);
      printf(
          " descendants:  %s%n",
          subprocesses.stream().map(p -> p.getPid()).collect(Collectors.toList()));

      p1.getOutputStream().close(); // Close stdin for the controlling p1
      p1.waitFor();
    } catch (InterruptedException | IOException ex) {
      Assert.fail("Unexpected Exception", ex);
    } finally {
      printf("Duration: %s%n", Duration.between(start, Instant.now()));
      if (p1 != null) {
        p1.destroyForcibly();
      }
      processes.forEach(
          (p, parent) -> {
            if (p.isAlive()) {
              ProcessUtil.printProcess(p, "Process Cleanup: ");
              p.destroyForcibly();
            }
          });
    }
  }
Exemple #8
0
  /**
   * Test destroy of processes. A JavaChild is started and it starts three children. Each one is
   * then checked to be alive and listed by descendants and forcibly destroyed. After they exit they
   * should no longer be listed by descendants.
   */
  @Test
  public static void test3() {
    ConcurrentHashMap<ProcessHandle, ProcessHandle> processes = new ConcurrentHashMap<>();

    try {
      ProcessHandle self = ProcessHandle.current();

      JavaChild p1 = JavaChild.spawnJavaChild("stdin");
      ProcessHandle p1Handle = p1.toHandle();
      printf(" p1: %s%n", p1.getPid());

      int newChildren = 3;
      CountDownLatch spawnCount = new CountDownLatch(newChildren);
      // Spawn children and have them wait
      p1.sendAction("spawn", newChildren, "stdin");

      // Gather the PIDs from the output of the spawning process
      p1.forEachOutputLine(
          (s) -> {
            String[] split = s.trim().split(" ");
            if (split.length == 3 && split[1].equals("spawn")) {
              Long child = Long.valueOf(split[2]);
              Long parent = Long.valueOf(split[0].split(":")[0]);
              processes.put(ProcessHandle.of(child).get(), ProcessHandle.of(parent).get());
              spawnCount.countDown();
            }
          });

      // Wait for all the subprocesses to be listed as started
      Assert.assertTrue(
          spawnCount.await(Utils.adjustTimeout(30L), TimeUnit.SECONDS),
          "Timeout waiting for processes to start");

      // Debugging; list descendants that are not expected in processes
      List<ProcessHandle> descendants = ProcessUtil.getDescendants(p1Handle);
      long count = descendants.stream().filter(ph -> !processes.containsKey(ph)).count();
      if (count > 0) {
        descendants
            .stream()
            .filter(ph -> !processes.containsKey(ph))
            .forEach(ph1 -> ProcessUtil.printProcess(ph1, "Extra process: "));
        ProcessUtil.logTaskList();
        Assert.assertEquals(0, count, "Extra processes in descendants");
      }

      // Verify that all spawned children are alive, show up in the descendants list
      // then destroy them
      processes.forEach(
          (p, parent) -> {
            Assert.assertEquals(p.isAlive(), true, "Child should be alive: " + p);
            Assert.assertTrue(
                descendants.contains(p), "Spawned child should be listed in descendants: " + p);
            p.destroyForcibly();
          });
      Assert.assertEquals(processes.size(), newChildren, "Wrong number of children");

      // Wait for each of the processes to exit
      processes.forEach(
          (p, parent) -> {
            for (long retries = Utils.adjustTimeout(100L); retries > 0; retries--) {
              if (!p.isAlive()) {
                return; // not alive, go on to the next
              }
              // Wait a bit and retry
              try {
                Thread.sleep(100L);
              } catch (InterruptedException ie) {
                // try again
              }
            }
            printf(
                "Timeout waiting for exit of pid %s, parent: %s, info: %s%n", p, parent, p.info());
            Assert.fail("Process still alive: " + p);
          });
      p1.destroyForcibly();
      p1.waitFor();

      // Verify that none of the spawned children are still listed by descendants
      List<ProcessHandle> remaining = getDescendants(self);
      Assert.assertFalse(remaining.remove(p1Handle), "Child p1 should have exited");
      remaining = remaining.stream().filter(processes::containsKey).collect(Collectors.toList());
      Assert.assertEquals(remaining.size(), 0, "Subprocess(es) should have exited: " + remaining);

    } catch (IOException ioe) {
      Assert.fail("Spawn of subprocess failed", ioe);
    } catch (InterruptedException inte) {
      Assert.fail("InterruptedException", inte);
    } finally {
      processes.forEach(
          (p, parent) -> {
            if (p.isAlive()) {
              ProcessUtil.printProcess(p);
              p.destroyForcibly();
            }
          });
    }
  }
Exemple #9
0
  /** Test counting and spawning and counting of Processes. */
  @Test
  public static void test2() {
    try {
      ConcurrentHashMap<ProcessHandle, ProcessHandle> processes = new ConcurrentHashMap<>();

      ProcessHandle self = ProcessHandle.current();
      List<ProcessHandle> initialChildren = getChildren(self);
      long count = initialChildren.size();
      if (count > 0) {
        initialChildren.forEach(p -> printDeep(p, "test2 initial unexpected: "));
      }

      JavaChild p1 = JavaChild.spawnJavaChild("stdin");
      ProcessHandle p1Handle = p1.toHandle();
      printf("  p1 pid: %d%n", p1.getPid());

      // Gather the PIDs from the output of the spawing process
      p1.forEachOutputLine(
          (s) -> {
            String[] split = s.trim().split(" ");
            if (split.length == 3 && split[1].equals("spawn")) {
              Long child = Long.valueOf(split[2]);
              Long parent = Long.valueOf(split[0].split(":")[0]);
              processes.put(ProcessHandle.of(child).get(), ProcessHandle.of(parent).get());
            }
          });

      int spawnNew = 3;
      p1.sendAction("spawn", spawnNew, "stdin");

      // Wait for direct children to be created and save the list
      List<ProcessHandle> subprocesses = waitForAllChildren(p1Handle, spawnNew);
      Optional<Instant> p1Start = p1Handle.info().startInstant();
      for (ProcessHandle ph : subprocesses) {
        Assert.assertTrue(ph.isAlive(), "Child should be alive: " + ph);
        // Verify each child was started after the parent
        ph.info()
            .startInstant()
            .ifPresent(
                childStart ->
                    p1Start.ifPresent(
                        parentStart -> {
                          Assert.assertFalse(
                              childStart.isBefore(parentStart),
                              String.format(
                                  "Child process started before parent: child: %s, parent: %s",
                                  childStart, parentStart));
                        }));
      }

      // Each child spawns two processes and waits for commands
      int spawnNewSub = 2;
      p1.sendAction("child", "spawn", spawnNewSub, "stdin");

      // Poll until all 9 child processes exist or the timeout is reached
      int expected = 9;
      long timeout = Utils.adjustTimeout(60L);
      Instant endTimeout = Instant.now().plusSeconds(timeout);
      do {
        Thread.sleep(200L);
        printf(" subprocess count: %d, waiting for %d%n", processes.size(), expected);
      } while (processes.size() < expected && Instant.now().isBefore(endTimeout));

      if (processes.size() < expected) {
        printf("WARNING: not all children have been started. Can't complete test.%n");
        printf("         You can try to increase the timeout or%n");
        printf("         you can try to use a faster VM (i.e. not a debug version).%n");
      }

      // show the complete list of children (for debug)
      List<ProcessHandle> descendants = getDescendants(p1Handle);
      printf(
          " descendants:  %s%n",
          descendants.stream().map(p -> p.getPid()).collect(Collectors.toList()));

      // Verify that all spawned children show up in the descendants  List
      processes.forEach(
          (p, parent) -> {
            Assert.assertEquals(p.isAlive(), true, "Child should be alive: " + p);
            Assert.assertTrue(
                descendants.contains(p), "Spawned child should be listed in descendants: " + p);
          });

      // Closing JavaChild's InputStream will cause all children to exit
      p1.getOutputStream().close();

      for (ProcessHandle p : descendants) {
        try {
          p.onExit().get(); // wait for the child to exit
        } catch (ExecutionException e) {
          Assert.fail("waiting for process to exit", e);
        }
      }
      p1.waitFor(); // wait for spawned process to exit

      // Verify spawned processes are no longer alive
      processes.forEach(
          (ph, parent) -> Assert.assertFalse(ph.isAlive(), "process should not be alive: " + ph));
    } catch (IOException | InterruptedException t) {
      t.printStackTrace();
      throw new RuntimeException(t);
    }
  }
/** Tests for jdk.vm.ci.hotspot.CompilerToVM::getConstantPool method */
public class GetConstantPoolTest {
  private static enum TestCase {
    NULL_BASE {
      @Override
      ConstantPool getConstantPool() {
        return CompilerToVMHelper.getConstantPool(null, getPtrToCpAddress());
      }
    },
    JAVA_METHOD_BASE {
      @Override
      ConstantPool getConstantPool() {
        HotSpotResolvedJavaMethod methodInstance =
            CompilerToVMHelper.getResolvedJavaMethodAtSlot(TEST_CLASS, 0);
        Field field;
        try {
          // jdk.vm.ci.hotspot.HotSpotResolvedJavaMethodImpl.metaspaceMethod
          field = methodInstance.getClass().getDeclaredField("metaspaceMethod");
          field.setAccessible(true);
          field.set(methodInstance, getPtrToCpAddress());
        } catch (ReflectiveOperationException e) {
          throw new Error("TESTBUG : " + e, e);
        }

        return CompilerToVMHelper.getConstantPool(methodInstance, 0L);
      }
    },
    CONSTANT_POOL_BASE {
      @Override
      ConstantPool getConstantPool() {
        ConstantPool cpInst;
        try {
          cpInst = CompilerToVMHelper.getConstantPool(null, getPtrToCpAddress());
          Field field =
              CompilerToVMHelper.HotSpotConstantPoolClass()
                  .getDeclaredField("metaspaceConstantPool");
          field.setAccessible(true);
          field.set(cpInst, getPtrToCpAddress());
        } catch (ReflectiveOperationException e) {
          throw new Error("TESTBUG : " + e.getMessage(), e);
        }
        return CompilerToVMHelper.getConstantPool(cpInst, 0L);
      }
    },
    CONSTANT_POOL_BASE_IN_TWO {
      @Override
      ConstantPool getConstantPool() {
        long ptr = getPtrToCpAddress();
        ConstantPool cpInst;
        try {
          cpInst = CompilerToVMHelper.getConstantPool(null, ptr);
          Field field =
              CompilerToVMHelper.HotSpotConstantPoolClass()
                  .getDeclaredField("metaspaceConstantPool");
          field.setAccessible(true);
          field.set(cpInst, ptr / 2L);
        } catch (ReflectiveOperationException e) {
          throw new Error("TESTBUG : " + e.getMessage(), e);
        }
        return CompilerToVMHelper.getConstantPool(cpInst, ptr - ptr / 2L);
      }
    },
    CONSTANT_POOL_BASE_ZERO {
      @Override
      ConstantPool getConstantPool() {
        long ptr = getPtrToCpAddress();
        ConstantPool cpInst;
        try {
          cpInst = CompilerToVMHelper.getConstantPool(null, ptr);
          Field field =
              CompilerToVMHelper.HotSpotConstantPoolClass()
                  .getDeclaredField("metaspaceConstantPool");
          field.setAccessible(true);
          field.set(cpInst, 0L);
        } catch (ReflectiveOperationException e) {
          throw new Error("TESTBUG : " + e.getMessage(), e);
        }
        return CompilerToVMHelper.getConstantPool(cpInst, ptr);
      }
    },
    OBJECT_TYPE_BASE {
      @Override
      ConstantPool getConstantPool() {
        HotSpotResolvedObjectType type =
            HotSpotResolvedObjectType.fromObjectClass(OBJECT_TYPE_BASE.getClass());
        long ptrToClass = UNSAFE.getKlassPointer(OBJECT_TYPE_BASE);
        return CompilerToVMHelper.getConstantPool(type, getPtrToCpAddress() - ptrToClass);
      }
    },
    ;

    abstract ConstantPool getConstantPool();
  }

  private static final WhiteBox WB = WhiteBox.getWhiteBox();
  private static final Unsafe UNSAFE = Utils.getUnsafe();

  private static final Class TEST_CLASS = GetConstantPoolTest.class;
  private static final long CP_ADDRESS = WB.getConstantPool(GetConstantPoolTest.class);

  public void test(TestCase testCase) {
    System.out.println(testCase.name());
    ConstantPool cp = testCase.getConstantPool();
    String cpStringRep = cp.toString();
    String cpClassSimpleName = CompilerToVMHelper.HotSpotConstantPoolClass().getSimpleName();
    if (!cpStringRep.contains(cpClassSimpleName) || !cpStringRep.contains(TEST_CLASS.getName())) {
      String msg =
          String.format(
              "%s : "
                  + " Constant pool is not valid."
                  + " String representation should contain \"%s\" and \"%s\"",
              testCase.name(), cpClassSimpleName, TEST_CLASS.getName());
      throw new AssertionError(msg);
    }
  }

  public static void main(String[] args) {
    GetConstantPoolTest test = new GetConstantPoolTest();
    for (TestCase testCase : TestCase.values()) {
      test.test(testCase);
    }
    testObjectBase();
    testMetaspaceWrapperBase();
  }

  private static void testObjectBase() {
    try {
      Object cp = CompilerToVMHelper.getConstantPool(new Object(), 0L);
      throw new AssertionError(
          "Test OBJECT_BASE." + " Expected IllegalArgumentException has not been caught");
    } catch (IllegalArgumentException iae) {
      // expected
    }
  }

  private static void testMetaspaceWrapperBase() {
    try {
      Object cp =
          CompilerToVMHelper.getConstantPool(
              new PublicMetaspaceWrapperObject() {
                @Override
                public long getMetaspacePointer() {
                  return getPtrToCpAddress();
                }
              },
              0L);
      throw new AssertionError(
          "Test METASPACE_WRAPPER_BASE."
              + " Expected IllegalArgumentException has not been caught");
    } catch (IllegalArgumentException iae) {
      // expected
    }
  }

  private static long getPtrToCpAddress() {
    Field field;
    try {
      field = TEST_CLASS.getDeclaredField("CP_ADDRESS");
    } catch (NoSuchFieldException nsfe) {
      throw new Error("TESTBUG : cannot find field \"CP_ADDRESS\" : " + nsfe.getMessage(), nsfe);
    }
    Object base = UNSAFE.staticFieldBase(field);
    return WB.getObjectAddress(base) + UNSAFE.staticFieldOffset(field);
  }
}