publicclass Main { staticclass ValueHolder { int getValue() { // Prevent inliner from matching the code pattern when calling this method to test // the normal inlining path that does not inline in blocks that end with a `throw`.
$inline$nop();
// NB It might seem that we'd move the allocation and ifield-set but those are // already moved into the throw block by a combo of partial-LSE and DCE. // Instead all that is actually moved is the LoadClass. Also note the // LoadClass can only be moved since it refers to the 'Main' class itself, // meaning there's no need for any clinit/actual loading. // /// CHECK-START: void Main.testFieldStores(boolean) code_sinking (before) /// CHECK: <<Int42:i\d+>> IntConstant 42 /// CHECK: begin_block /// CHECK: <<LoadClass:l\d+>> LoadClass class_name:Main /// CHECK: <<NewInstance:l\d+>> NewInstance [<<LoadClass>>] /// CHECK: InstanceFieldSet [<<NewInstance>>,<<Int42>>] /// CHECK: Throw
// Make sure code sinking does not crash on dead allocations. publicstaticvoid testOnlyStoreUses() {
Main m = new Main();
Object[] o = new Object[1]; // dead allocation, should eventually be removed b/35634932.
o[0] = m;
o = null; // Avoid environment uses for the array allocation. if (doThrow) { thrownew Error(m.toString());
}
}
// Make sure code sinking does not crash on dead code. publicstaticvoid testNoUse() {
Main m = new Main(); boolean load = Main.doLoop; // dead code, not removed because of environment use. // Ensure one environment use for the static field
$opt$noinline$foo();
load = false; if (doThrow) { thrownew Error(m.toString());
}
}
// Make sure we can move code only used by a phi. /// CHECK-START: void Main.testPhiInput() code_sinking (before) /// CHECK: <<Null:l\d+>> NullConstant /// CHECK: <<LoadClass:l\d+>> LoadClass class_name:java.lang.Object /// CHECK: <<NewInstance:l\d+>> NewInstance [<<LoadClass>>] /// CHECK: If /// CHECK: begin_block /// CHECK: Phi [<<Null>>,<<NewInstance>>] /// CHECK: Throw
/// CHECK-START: void Main.testPhiInput() code_sinking (after) /// CHECK: <<Null:l\d+>> NullConstant /// CHECK-NOT: NewInstance /// CHECK: If /// CHECK: begin_block /// CHECK: <<LoadClass:l\d+>> LoadClass class_name:java.lang.Object /// CHECK: <<NewInstance:l\d+>> NewInstance [<<LoadClass>>] /// CHECK: begin_block /// CHECK: Phi [<<Null>>,<<NewInstance>>] /// CHECK: <<Error:l\d+>> LoadClass class_name:java.lang.Error /// CHECK: NewInstance [<<Error>>] /// CHECK: Throw publicstaticvoid testPhiInput() {
Object f = new Object(); if (doThrow) {
Object o = null; int i = 2; if (doLoop) {
o = f;
i = 42;
} thrownew Error(o.toString() + i);
}
}
staticvoid $opt$noinline$foo() {}
// Check that we do not move volatile stores. /// CHECK-START: void Main.testVolatileStore() code_sinking (before) /// CHECK: <<Int42:i\d+>> IntConstant 42 /// CHECK: <<LoadClass:l\d+>> LoadClass class_name:Main /// CHECK: <<NewInstance:l\d+>> NewInstance [<<LoadClass>>] /// CHECK: InstanceFieldSet [<<NewInstance>>,<<Int42>>] /// CHECK: If /// CHECK: begin_block /// CHECK: Throw
// Consistency check: only one add /// CHECK-START: int Main.$noinline$testDontSinkToReturnBranch(int, int, boolean, java.lang.Object) code_sinking (before) /// CHECK: Add /// CHECK-NOT: Add
/// CHECK-START: int Main.$noinline$testDontSinkToReturnBranch(int, int, boolean, java.lang.Object) code_sinking (before) /// CHECK: Add /// CHECK-NEXT: If
/// CHECK-START: int Main.$noinline$testDontSinkToReturnBranch(int, int, boolean, java.lang.Object) code_sinking (after) /// CHECK: Add /// CHECK-NEXT: If privatestaticint $noinline$testDontSinkToReturnBranch(int a, int b, boolean flag, Object obj) { int c = a + b; if (flag) { return1;
}
// Consistency check: only one add /// CHECK-START: int Main.$noinline$testSinkToThrowBranch(int, int, boolean, java.lang.Object) code_sinking (before) /// CHECK: Add /// CHECK-NOT: Add
/// CHECK-START: int Main.$noinline$testSinkToThrowBranch(int, int, boolean, java.lang.Object) code_sinking (before) /// CHECK: Add /// CHECK: If
/// CHECK-START: int Main.$noinline$testSinkToThrowBranch(int, int, boolean, java.lang.Object) code_sinking (after) /// CHECK: If /// CHECK: Add privatestaticint $noinline$testSinkToThrowBranch(int a, int b, boolean flag, Object obj) { int c = a + b; if (flag) { return1;
}
publicstaticvoid testStaticSideEffects() {
Object o = obj;
$noinline$changeStaticObjectField(); if (doThrow) { thrownew Error(o.getClass().toString());
}
}
staticvoid $noinline$changeStaticObjectField() {
obj = new Main();
}
// Test that we preserve the order of stores. // NB It might seem that we'd move the allocation and ifield-set but those are // already moved into the throw block by a combo of partial-LSE and DCE. // Instead all that is actually moved is the LoadClass. Also note the // LoadClass can only be moved since it refers to the 'Main' class itself, // meaning there's no need for any clinit/actual loading. // /// CHECK-START: void Main.testStoreStore(boolean) code_sinking (before) /// CHECK: <<Int42:i\d+>> IntConstant 42 /// CHECK: <<Int43:i\d+>> IntConstant 43 /// CHECK: <<LoadClass:l\d+>> LoadClass class_name:Main /// CHECK: <<NewInstance:l\d+>> NewInstance [<<LoadClass>>] /// CHECK-DAG: InstanceFieldSet [<<NewInstance>>,<<Int42>>] /// CHECK-DAG: InstanceFieldSet [<<NewInstance>>,<<Int43>>] /// CHECK: Throw /// CHECK-NOT: InstanceFieldSet
// Consistency check to make sure there's only one entry TryBoundary. /// CHECK-START: int Main.testDoNotSinkToTry() code_sinking (after) /// CHECK: TryBoundary kind:entry /// CHECK-NOT: TryBoundary kind:entry
// Tests that we don't sink the Object creation into the try. privatestaticint testDoNotSinkToTry() {
Object o = new Object(); try { if (doEarlyReturn) { thrownew Error(o.toString());
}
} catch (Error e) { thrownew Error();
} return456;
}
/// CHECK-START: int Main.testSinkWithinTryBlock() code_sinking (before) /// CHECK: <<ObjLoadClass:l\d+>> LoadClass class_name:java.lang.Object /// CHECK: NewInstance [<<ObjLoadClass>>] /// CHECK: If
/// CHECK-START: int Main.testSinkWithinTryBlock() code_sinking (after) /// CHECK: If /// CHECK: <<ObjLoadClass:l\d+>> LoadClass class_name:java.lang.Object /// CHECK: NewInstance [<<ObjLoadClass>>] privatestaticint testSinkWithinTryBlock() { try {
Object o = new Object(); if (doEarlyReturn) { thrownew Error(o.toString());
}
} catch (Error e) { return123;
} return456;
}
// Tests that we don't sink the Object creation into a catch handler surrounded by try/catch, even // when that inner catch is not at the boundary of the outer try catch. privatestaticint testDoNotSinkToCatchInsideTryWithMoreThings(boolean a, boolean b) {
Object o = new Object(); try { if (a) {
System.out.println(a);
} try { if (doEarlyReturn) { return123;
}
} catch (Error e) { thrownew Error(o.toString());
} if (b) {
System.out.println(b);
}
} catch (Error e) { thrownew Error();
} return456;
}
// Consistency check to make sure there's only one entry TryBoundary. /// CHECK-START: int Main.DoNotSinkWithOOMThrow() code_sinking (after) /// CHECK: TryBoundary kind:entry /// CHECK-NOT: TryBoundary kind:entry privatestaticint DoNotSinkWithOOMThrow() throws OutOfMemoryError { int x = 0;
ObjectWithInt obj = new ObjectWithInt(); try { // We want an if/else here so that the catch block will have a catch phi. if (doThrow) {
x = 1; // Doesn't really matter what we throw we just want it to not be caught by the // NullPointerException below. thrownew OutOfMemoryError(Integer.toString(obj.x));
} else {
x = 456;
}
} catch (NullPointerException e) {
}
// We want to use obj over here so that it doesn't get deleted by LSE. if (obj.x == 123) { return123;
} return x;
}
// We can remove the ClinitCheck by merging it with the LoadClass right before.
/// CHECK-START: void Main.$noinline$testSinkNewInstanceWithClinitCheck() prepare_for_register_allocation (after) /// CHECK-NOT: ClinitCheck privatestaticvoid $noinline$testSinkNewInstanceWithClinitCheck() {
ValueHolder vh = new ValueHolder();
Object o = new Object();
// The if will always be true but we don't know this after LSE. Code sinking will sink code // since this is an uncommon branch, but then we will have everything in one block before // prepare_for_register_allocation for the crash to appear.
staticIntField = 1; int value = staticIntField; if (value == 1) { thrownew Error(Integer.toString(vh.getValue()) + o.toString());
}
}
// We currently do not inline the `StringBuilder` constructor. // When we did, the `StringBuilderAppend` pattern recognition was looking for // the inlined `NewArray` (and its associated `LoadClass`) and checked in // debug build that the `StringBuilder` has an environment use from this // `NewArray` (and maybe from `LoadClass`). However, code sinking was pruning // the environment of the `NewArray`, leading to a crash when compiling the // code below on the device (we do not inline `core-oj` on host). b/252799691
// We currently have a heuristic that disallows inlining methods if their basic blocks end with a // throw. We could add code so that `requireNonNull`'s block doesn't end with a throw but that // would mean that the string builder optimization wouldn't fire as it requires all uses to be in // the same block. If `requireNonNull` is inlined at some point, we need to re-mark it as $inline$ // so that the test is operational again.
// Before inlining, the environment use from this invoke prevents the // `StringBuilderAppend` pattern recognition. After inlining, we end up // with two paths ending with a `Throw` and we could sink the `sb` // instructions from above down to those below, enabling the // `StringBuilderAppend` pattern recognition. // (But that does not happen when the `StringBuilder` constructor is // not inlined, see above.)
requireNonNull(o);
volatileint volatileField; int intField; int intField2;
Object objectField; staticboolean doThrow; staticboolean doLoop; staticboolean doEarlyReturn; staticboolean doOtherEarlyReturn; staticint staticIntField; static Main mainField = new Main(); static Object obj = new Object();
}
Messung V0.5 in Prozent
¤ 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.0.16Bemerkung:
(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.