// sMain1.foo() will be always be Main1.foo() before Main2 is loaded/linked. // So sMain1.foo() can be devirtualized to Main1.foo() and be inlined. // After Helper.createMain2() which links in Main2, live testOverride() on stack // should be deoptimized. staticvoid testOverride(boolean createMain2, boolean wait, boolean setHasJIT) { if (setHasJIT) { if (isInterpreted()) {
sHasJIT = false;
} return;
}
if (createMain2 && (sIsOptimizing || sHasJIT)) {
assertIsManaged();
}
if (createMain2) { // Wait for the other thread to start. while (!sOtherThreadStarted); // Create an Main2 instance and assign it to sMain2. // sMain1 is kept the same.
sMain2 = Helper.createMain2(); // Wake up the other thread. synchronized(Main.class) {
Main.class.notify();
}
} elseif (wait) { // This is the other thread. synchronized(Main.class) {
sOtherThreadStarted = true; // Wait for Main2 to be linked and deoptimization is triggered. try {
Main.class.wait();
} catch (Exception e) {
}
}
}
// There should be a deoptimization here right after Main2 is linked by // calling Helper.createMain2(), even though sMain1 didn't change. // The behavior here would be different if inline-cache is used, which // doesn't deoptimize since sMain1 still hits the type cache.
sMain1.foo(sMain1.getClass() == Main1.class ? 1 : 2); if ((createMain2 || wait) && sHasJIT && !sIsOptimizing) { // This method should be deoptimized right after Main2 is created.
assertIsInterpreted();
}
staticlong testNoOverrideLoop(int count) { long sum = 0; for (int i=0; i<count; i++) {
sum += calcValue(sArray[0]);
sum += calcValue(sArray[1]);
sum += calcValue(sArray[2]);
} return sum;
}
staticvoid testNoOverride() {
sArray = new Main1[3];
sArray[0] = new Main1();
sArray[1] = Helper.createMain2();
sArray[2] = Helper.createMain3(); long sum = 0; // Loop enough to get methods JITed. for (int i=0; i<100; i++) {
testNoOverrideLoop(1);
}
ensureJitCompiled(Main.class, "testNoOverrideLoop");
ensureJitCompiled(Main.class, "calcValue");
long t1 = System.currentTimeMillis();
sum = testNoOverrideLoop(100000); long t2 = System.currentTimeMillis(); if (sum != 27300000L) {
System.out.println("Unexpected result.");
}
}
privatestaticvoid assertSingleImplementation(Class<?> clazz, String method_name, boolean b) { if (hasSingleImplementation(clazz, method_name) != b) {
System.out.println(clazz + "." + method_name + " doesn't have single implementation value of " + b);
}
}
// Test scenarios under which CHA-based devirtualization happens, // and class loading that overrides a method can invalidate compiled code. // Also test pure non-overriding case, which is more for checking generated // code form. publicstaticvoid main(String[] args) {
System.loadLibrary(args[0]);
// CHeck some boot-image methods.
// We would want to have this, but currently setting single-implementation in the boot image // does not work well with app images. b/34193647 finalboolean ARRAYLIST_SIZE_EXPECTED = false;
assertSingleImplementation(java.util.ArrayList.class, "size", ARRAYLIST_SIZE_EXPECTED);
// We don't set single-implementation modifier bit for final classes or methods // since we can devirtualize without CHA for those cases. However hasSingleImplementation() // should return true for those cases.
assertSingleImplementation(java.lang.String.class, "charAt", true);
assertSingleImplementation(java.lang.Thread.class, "join", true);
if (isInterpreted()) {
sIsOptimizing = false;
}
// sMain1 is an instance of Main1. Main2 hasn't bee loaded yet.
sMain1 = new Main1();
if (sHasJIT && !sIsOptimizing) {
assertSingleImplementation(Main1.class, "foo", true);
} else { // Main2 is verified ahead-of-time so it's linked in already.
}
assertSingleImplementation(Main1.class, "getValue1", true);
// Create another thread that also calls sMain1.foo(). // Try to test suspend and deopt another thread. newThread() { publicvoid run() {
testOverride(false, true, false);
}
}.start();
// This will create Main2 instance in the middle of testOverride().
testOverride(true, false, false);
assertSingleImplementation(Main1.class, "foo", false);
assertSingleImplementation(Main1.class, "getValue1", true);
// Put createMain2() in another class to avoid class loading due to verifier. class Helper { static Main1 createMain2() { returnnew Main2();
} static Main1 createMain3() { returnnew Main3();
}
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.10 Sekunden
(vorverarbeitet am 2026-06-29)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.