diff options
author | Roland Levillain <rpl@google.com> | 2015-04-24 16:43:49 +0100 |
---|---|---|
committer | Roland Levillain <rpl@google.com> | 2015-04-24 16:43:49 +0100 |
commit | 4c0eb42259d790fddcd9978b66328dbb3ab65615 (patch) | |
tree | 9d1ac505dfd4d0225f479d860b72a58747c8f6ce /test/476-clinit-check-inlining-static-invoke | |
parent | 223f2f5b2a20ca8246da1523494900a2424d5956 (diff) | |
download | art-4c0eb42259d790fddcd9978b66328dbb3ab65615.zip art-4c0eb42259d790fddcd9978b66328dbb3ab65615.tar.gz art-4c0eb42259d790fddcd9978b66328dbb3ab65615.tar.bz2 |
Ensure inlined static calls perform clinit checks in Optimizing.
Calls to static methods have implicit class initialization
(clinit) checks of the method's declaring class in
Optimizing. However, when such a static call is inlined,
the implicit clinit check vanishes, possibly leading to an
incorrect behavior.
To ensure that inlining static methods does not change the
behavior of a program, add explicit class initialization
checks (art::HClinitCheck) as well as load class
instructions (art::HLoadClass) as last input of static
calls (art::HInvokeStaticOrDirect) in Optimizing' control
flow graphs, when the declaring class is reachable and not
known to be already initialized. Then when considering the
inlining of a static method call, proceed only if the method
has no implicit clinit check requirement.
The added explicit clinit checks are already removed by the
art::PrepareForRegisterAllocation visitor. This CL also
extends this visitor to turn explicit clinit checks from
static invokes into implicit ones after the inlining step,
by removing the added art::HLoadClass nodes mentioned
hereinbefore.
Change-Id: I9ba452b8bd09ae1fdd9a3797ef556e3e7e19c651
Diffstat (limited to 'test/476-clinit-check-inlining-static-invoke')
3 files changed, 52 insertions, 0 deletions
diff --git a/test/476-clinit-check-inlining-static-invoke/expected.txt b/test/476-clinit-check-inlining-static-invoke/expected.txt new file mode 100644 index 0000000..c55bf72 --- /dev/null +++ b/test/476-clinit-check-inlining-static-invoke/expected.txt @@ -0,0 +1,2 @@ +checkClinitCheckBeforeStaticMethodInvoke START +checkClinitCheckBeforeStaticMethodInvoke PASSED diff --git a/test/476-clinit-check-inlining-static-invoke/info.txt b/test/476-clinit-check-inlining-static-invoke/info.txt new file mode 100644 index 0000000..1a439fc --- /dev/null +++ b/test/476-clinit-check-inlining-static-invoke/info.txt @@ -0,0 +1,3 @@ +Regression test for a bug where an inlined call to a static method +failed to emit a prior initialization check of the method's declaring +class. diff --git a/test/476-clinit-check-inlining-static-invoke/src/Main.java b/test/476-clinit-check-inlining-static-invoke/src/Main.java new file mode 100644 index 0000000..a7d3bcd --- /dev/null +++ b/test/476-clinit-check-inlining-static-invoke/src/Main.java @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +public class Main { + + public static void main(String[] args) { + checkClinitCheckBeforeStaticMethodInvoke(); + } + + static void checkClinitCheckBeforeStaticMethodInvoke() { + System.out.println("checkClinitCheckBeforeStaticMethodInvoke START"); + + // Call static method to cause implicit class initialization, even + // if it is inlined. + ClassWithClinit.$opt$inline$StaticMethod(); + if (!classWithClinitInitialized) { + System.out.println("checkClinitCheckBeforeStaticMethodInvoke FAILED"); + return; + } + + System.out.println("checkClinitCheckBeforeStaticMethodInvoke PASSED"); + } + + static class ClassWithClinit { + static { + Main.classWithClinitInitialized = true; + } + + static void $opt$inline$StaticMethod() { + } + } + + static boolean classWithClinitInitialized = false; +} |