diff options
Diffstat (limited to 'test')
22 files changed, 753 insertions, 5 deletions
diff --git a/test/458-checker-instruction-simplification/src/Main.java b/test/458-checker-instruction-simplification/src/Main.java index 3c8abeb841..2f80470cb3 100644 --- a/test/458-checker-instruction-simplification/src/Main.java +++ b/test/458-checker-instruction-simplification/src/Main.java @@ -1404,7 +1404,7 @@ public class Main { /// CHECK-START: int Main.floatConditionNotEqualOne(float) ssa_builder (after) /// CHECK: LessThanOrEqual - /// CHECK-START: int Main.floatConditionNotEqualOne(float) register (before) + /// CHECK-START: int Main.floatConditionNotEqualOne(float) instruction_simplifier_before_codegen (after) /// CHECK-DAG: <<Arg:f\d+>> ParameterValue /// CHECK-DAG: <<Const13:i\d+>> IntConstant 13 /// CHECK-DAG: <<Const54:i\d+>> IntConstant 54 @@ -1420,7 +1420,7 @@ public class Main { /// CHECK-START: int Main.doubleConditionEqualZero(double) ssa_builder (after) /// CHECK: LessThanOrEqual - /// CHECK-START: int Main.doubleConditionEqualZero(double) register (before) + /// CHECK-START: int Main.doubleConditionEqualZero(double) instruction_simplifier_before_codegen (after) /// CHECK-DAG: <<Arg:d\d+>> ParameterValue /// CHECK-DAG: <<Const13:i\d+>> IntConstant 13 /// CHECK-DAG: <<Const54:i\d+>> IntConstant 54 diff --git a/test/555-checker-regression-x86const/build b/test/555-checker-regression-x86const/build new file mode 100644 index 0000000000..09dcc363dd --- /dev/null +++ b/test/555-checker-regression-x86const/build @@ -0,0 +1,46 @@ +#!/bin/bash +# +# 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. + +# Stop if something fails. +set -e + +# We can't use src-ex testing infrastructure because src and src-ex are compiled +# with javac independetely and can't share code (without reflection). + +mkdir classes +${JAVAC} -d classes `find src -name '*.java'` + +mkdir classes-ex +mv classes/UnresolvedClass.class classes-ex + +if [ ${USE_JACK} = "true" ]; then + # Create .jack files from classes generated with javac. + ${JILL} classes --output classes.jack + ${JILL} classes-ex --output classes-ex.jack + + # Create DEX files from .jack files. + ${JACK} --import classes.jack --output-dex . + zip $TEST_NAME.jar classes.dex + ${JACK} --import classes-ex.jack --output-dex . + zip ${TEST_NAME}-ex.jar classes.dex +else + if [ ${NEED_DEX} = "true" ]; then + ${DX} -JXmx256m --debug --dex --dump-to=classes.lst --output=classes.dex --dump-width=1000 classes + zip $TEST_NAME.jar classes.dex + ${DX} -JXmx256m --debug --dex --dump-to=classes-ex.lst --output=classes.dex --dump-width=1000 classes-ex + zip ${TEST_NAME}-ex.jar classes.dex + fi +fi diff --git a/test/555-checker-regression-x86const/expected.txt b/test/555-checker-regression-x86const/expected.txt new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/test/555-checker-regression-x86const/expected.txt diff --git a/test/555-checker-regression-x86const/info.txt b/test/555-checker-regression-x86const/info.txt new file mode 100644 index 0000000000..c4037fa88f --- /dev/null +++ b/test/555-checker-regression-x86const/info.txt @@ -0,0 +1,2 @@ +Check that X86 FP constant-area handling handles intrinsics with CurrentMethod +on the call. diff --git a/test/555-checker-regression-x86const/run b/test/555-checker-regression-x86const/run new file mode 100644 index 0000000000..63fdb8c749 --- /dev/null +++ b/test/555-checker-regression-x86const/run @@ -0,0 +1,18 @@ +#!/bin/bash +# +# 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. + +# Use secondary switch to add secondary dex file to class path. +exec ${RUN} "${@}" --secondary diff --git a/test/555-checker-regression-x86const/src/Main.java b/test/555-checker-regression-x86const/src/Main.java new file mode 100644 index 0000000000..914cfde74f --- /dev/null +++ b/test/555-checker-regression-x86const/src/Main.java @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2016 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 extends UnresolvedClass { + + /// CHECK-START: float Main.callAbs(float) register (before) + /// CHECK: <<CurrentMethod:[ij]\d+>> CurrentMethod + /// CHECK: <<ParamValue:f\d+>> ParameterValue + /// CHECK: InvokeStaticOrDirect [<<ParamValue>>,<<CurrentMethod>>] method_name:java.lang.Math.abs + static public float callAbs(float f) { + // An intrinsic invoke in a method that has unresolved references will still + // have a CurrentMethod as an argument. The X86 pc_relative_fixups_x86 pass + // must be able to handle Math.abs invokes that have a CurrentMethod, as both + // the CurrentMethod and the HX86LoadFromConstantTable (for the bitmask) + // expect to be in the 'SpecialInputIndex' input index. + return Math.abs(f); + } + + static public void main(String[] args) { + expectEquals(callAbs(-6.5f), 6.5f); + } + + public static void expectEquals(float expected, float result) { + if (expected != result) { + throw new Error("Expected: " + expected + ", found: " + result); + } + } +} diff --git a/test/555-checker-regression-x86const/src/Unresolved.java b/test/555-checker-regression-x86const/src/Unresolved.java new file mode 100644 index 0000000000..e98bdbf8fb --- /dev/null +++ b/test/555-checker-regression-x86const/src/Unresolved.java @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2016 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. + */ + +class UnresolvedClass { +} diff --git a/test/565-checker-condition-liveness/src/Main.java b/test/565-checker-condition-liveness/src/Main.java index a811e5bb16..dc4cb76258 100644 --- a/test/565-checker-condition-liveness/src/Main.java +++ b/test/565-checker-condition-liveness/src/Main.java @@ -16,6 +16,24 @@ public class Main { + /// CHECK-START-X86: int Main.p(float) liveness (after) + /// CHECK: <<Arg:f\d+>> ParameterValue uses:[<<UseInput:\d+>>] + /// CHECK-DAG: <<Five:f\d+>> FloatConstant 5 uses:[<<UseInput>>] + /// CHECK-DAG: <<Zero:i\d+>> IntConstant 0 + /// CHECK-DAG: <<MinusOne:i\d+>> IntConstant -1 uses:[<<UseInput>>] + /// CHECK: <<Base:i\d+>> X86ComputeBaseMethodAddress uses:[<<UseInput>>] + /// CHECK-NEXT: <<Load:f\d+>> X86LoadFromConstantTable [<<Base>>,<<Five>>] + /// CHECK-NEXT: <<Cond:z\d+>> LessThanOrEqual [<<Arg>>,<<Load>>] + /// CHECK-NEXT: Select [<<Zero>>,<<MinusOne>>,<<Cond>>] liveness:<<LivSel:\d+>> + /// CHECK-EVAL: <<UseInput>> == <<LivSel>> + 1 + + public static int p(float arg) { + if (arg > 5.0f) { + return 0; + } + return -1; + } + /// CHECK-START: void Main.main(java.lang.String[]) liveness (after) /// CHECK: <<X:i\d+>> ArrayLength uses:[<<UseInput:\d+>>] /// CHECK: <<Y:i\d+>> StaticFieldGet uses:[<<UseInput>>] diff --git a/test/565-checker-doublenegbitwise/src/Main.java b/test/565-checker-doublenegbitwise/src/Main.java index c51eda8a66..41af97b3b7 100644 --- a/test/565-checker-doublenegbitwise/src/Main.java +++ b/test/565-checker-doublenegbitwise/src/Main.java @@ -56,6 +56,8 @@ public class Main { /// CHECK-START: int Main.$opt$noinline$andToOr(int, int) instruction_simplifier (after) /// CHECK: Not /// CHECK-NOT: Not + + /// CHECK-START: int Main.$opt$noinline$andToOr(int, int) instruction_simplifier (after) /// CHECK-NOT: And public static int $opt$noinline$andToOr(int a, int b) { @@ -64,6 +66,43 @@ public class Main { } /** + * Test transformation of Not/Not/And into Or/Not for boolean negations. + * Note that the graph before this instruction simplification pass does not + * contain `HBooleanNot` instructions. This is because this transformation + * follows the optimization of `HSelect` to `HBooleanNot` occurring in the + * same pass. + */ + + /// CHECK-START: boolean Main.$opt$noinline$booleanAndToOr(boolean, boolean) instruction_simplifier_after_bce (before) + /// CHECK: <<P1:z\d+>> ParameterValue + /// CHECK: <<P2:z\d+>> ParameterValue + /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0 + /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 + /// CHECK: <<Select1:i\d+>> Select [<<Const1>>,<<Const0>>,<<P1>>] + /// CHECK: <<Select2:i\d+>> Select [<<Const1>>,<<Const0>>,<<P2>>] + /// CHECK: <<And:i\d+>> And [<<Select2>>,<<Select1>>] + /// CHECK: Return [<<And>>] + + /// CHECK-START: boolean Main.$opt$noinline$booleanAndToOr(boolean, boolean) instruction_simplifier_after_bce (after) + /// CHECK: <<Cond1:z\d+>> ParameterValue + /// CHECK: <<Cond2:z\d+>> ParameterValue + /// CHECK: <<Or:i\d+>> Or [<<Cond2>>,<<Cond1>>] + /// CHECK: <<BooleanNot:z\d+>> BooleanNot [<<Or>>] + /// CHECK: Return [<<BooleanNot>>] + + /// CHECK-START: boolean Main.$opt$noinline$booleanAndToOr(boolean, boolean) instruction_simplifier_after_bce (after) + /// CHECK: BooleanNot + /// CHECK-NOT: BooleanNot + + /// CHECK-START: boolean Main.$opt$noinline$booleanAndToOr(boolean, boolean) instruction_simplifier_after_bce (after) + /// CHECK-NOT: And + + public static boolean $opt$noinline$booleanAndToOr(boolean a, boolean b) { + if (doThrow) throw new Error(); + return !a & !b; + } + + /** * Test transformation of Not/Not/Or into And/Not. */ @@ -88,6 +127,8 @@ public class Main { /// CHECK-START: long Main.$opt$noinline$orToAnd(long, long) instruction_simplifier (after) /// CHECK: Not /// CHECK-NOT: Not + + /// CHECK-START: long Main.$opt$noinline$orToAnd(long, long) instruction_simplifier (after) /// CHECK-NOT: Or public static long $opt$noinline$orToAnd(long a, long b) { @@ -96,6 +137,43 @@ public class Main { } /** + * Test transformation of Not/Not/Or into Or/And for boolean negations. + * Note that the graph before this instruction simplification pass does not + * contain `HBooleanNot` instructions. This is because this transformation + * follows the optimization of `HSelect` to `HBooleanNot` occurring in the + * same pass. + */ + + /// CHECK-START: boolean Main.$opt$noinline$booleanOrToAnd(boolean, boolean) instruction_simplifier_after_bce (before) + /// CHECK: <<P1:z\d+>> ParameterValue + /// CHECK: <<P2:z\d+>> ParameterValue + /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0 + /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 + /// CHECK: <<Select1:i\d+>> Select [<<Const1>>,<<Const0>>,<<P1>>] + /// CHECK: <<Select2:i\d+>> Select [<<Const1>>,<<Const0>>,<<P2>>] + /// CHECK: <<Or:i\d+>> Or [<<Select2>>,<<Select1>>] + /// CHECK: Return [<<Or>>] + + /// CHECK-START: boolean Main.$opt$noinline$booleanOrToAnd(boolean, boolean) instruction_simplifier_after_bce (after) + /// CHECK: <<Cond1:z\d+>> ParameterValue + /// CHECK: <<Cond2:z\d+>> ParameterValue + /// CHECK: <<And:i\d+>> And [<<Cond2>>,<<Cond1>>] + /// CHECK: <<BooleanNot:z\d+>> BooleanNot [<<And>>] + /// CHECK: Return [<<BooleanNot>>] + + /// CHECK-START: boolean Main.$opt$noinline$booleanOrToAnd(boolean, boolean) instruction_simplifier_after_bce (after) + /// CHECK: BooleanNot + /// CHECK-NOT: BooleanNot + + /// CHECK-START: boolean Main.$opt$noinline$booleanOrToAnd(boolean, boolean) instruction_simplifier_after_bce (after) + /// CHECK-NOT: Or + + public static boolean $opt$noinline$booleanOrToAnd(boolean a, boolean b) { + if (doThrow) throw new Error(); + return !a | !b; + } + + /** * Test that the transformation copes with inputs being separated from the * bitwise operations. * This is a regression test. The initial logic was inserting the new bitwise @@ -127,6 +205,8 @@ public class Main { /// CHECK-START: int Main.$opt$noinline$regressInputsAway(int, int) instruction_simplifier (after) /// CHECK: Not /// CHECK-NOT: Not + + /// CHECK-START: int Main.$opt$noinline$regressInputsAway(int, int) instruction_simplifier (after) /// CHECK-NOT: Or public static int $opt$noinline$regressInputsAway(int a, int b) { @@ -167,6 +247,38 @@ public class Main { } /** + * Test transformation of Not/Not/Xor into Xor for boolean negations. + * Note that the graph before this instruction simplification pass does not + * contain `HBooleanNot` instructions. This is because this transformation + * follows the optimization of `HSelect` to `HBooleanNot` occurring in the + * same pass. + */ + + /// CHECK-START: boolean Main.$opt$noinline$booleanNotXorToXor(boolean, boolean) instruction_simplifier_after_bce (before) + /// CHECK: <<P1:z\d+>> ParameterValue + /// CHECK: <<P2:z\d+>> ParameterValue + /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0 + /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 + /// CHECK: <<Select1:i\d+>> Select [<<Const1>>,<<Const0>>,<<P1>>] + /// CHECK: <<Select2:i\d+>> Select [<<Const1>>,<<Const0>>,<<P2>>] + /// CHECK: <<Xor:i\d+>> Xor [<<Select2>>,<<Select1>>] + /// CHECK: Return [<<Xor>>] + + /// CHECK-START: boolean Main.$opt$noinline$booleanNotXorToXor(boolean, boolean) instruction_simplifier_after_bce (after) + /// CHECK: <<Cond1:z\d+>> ParameterValue + /// CHECK: <<Cond2:z\d+>> ParameterValue + /// CHECK: <<Xor:i\d+>> Xor [<<Cond2>>,<<Cond1>>] + /// CHECK: Return [<<Xor>>] + + /// CHECK-START: boolean Main.$opt$noinline$booleanNotXorToXor(boolean, boolean) instruction_simplifier_after_bce (after) + /// CHECK-NOT: BooleanNot + + public static boolean $opt$noinline$booleanNotXorToXor(boolean a, boolean b) { + if (doThrow) throw new Error(); + return !a ^ !b; + } + + /** * Check that no transformation is done when one Not has multiple uses. */ diff --git a/test/566-checker-codegen-select/src/Main.java b/test/566-checker-codegen-select/src/Main.java index edb31e6d12..3a1b3fcf85 100644 --- a/test/566-checker-codegen-select/src/Main.java +++ b/test/566-checker-codegen-select/src/Main.java @@ -45,6 +45,13 @@ public class Main { /// CHECK: LessThanOrEqual /// CHECK-NEXT: Select + // Check that we generate CMOV for long on x86_64. + /// CHECK-START-X86_64: long Main.$noinline$longSelect_Constant(long) disassembly (after) + /// CHECK: LessThanOrEqual + /// CHECK-NEXT: Select + /// CHECK: cmpq + /// CHECK: cmovle/ngq + public long $noinline$longSelect_Constant(long param) { if (doThrow) { throw new Error(); } long val_true = longB; @@ -52,12 +59,34 @@ public class Main { return (param > 3L) ? val_true : val_false; } + // Check that we generate CMOV for int on x86_64. + /// CHECK-START-X86_64: int Main.$noinline$intSelect_Constant(int) disassembly (after) + /// CHECK: LessThan + /// CHECK-NEXT: Select + /// CHECK: cmp + /// CHECK: cmovl/nge + + public int $noinline$intSelect_Constant(int param) { + if (doThrow) { throw new Error(); } + int val_true = intB; + int val_false = intC; + return (param >= 3) ? val_true : val_false; + } + public static void main(String[] args) { Main m = new Main(); assertLongEquals(5L, m.$noinline$longSelect(4L)); assertLongEquals(7L, m.$noinline$longSelect(2L)); assertLongEquals(5L, m.$noinline$longSelect_Constant(4L)); assertLongEquals(7L, m.$noinline$longSelect_Constant(2L)); + assertIntEquals(5, m.$noinline$intSelect_Constant(4)); + assertIntEquals(7, m.$noinline$intSelect_Constant(2)); + } + + public static void assertIntEquals(int expected, int actual) { + if (expected != actual) { + throw new Error(expected + " != " + actual); + } } public static void assertLongEquals(long expected, long actual) { @@ -71,4 +100,6 @@ public class Main { public long longA = 3L; public long longB = 5L; public long longC = 7L; + public int intB = 5; + public int intC = 7; } diff --git a/test/566-checker-signum/src/Main.java b/test/566-checker-signum/src/Main.java index cc4a98469c..0ad0042326 100644 --- a/test/566-checker-signum/src/Main.java +++ b/test/566-checker-signum/src/Main.java @@ -54,6 +54,13 @@ public class Main { expectEquals(1, sign64(12345L)); expectEquals(1, sign64(Long.MAX_VALUE)); + expectEquals(-1, sign64(0x800000007FFFFFFFL)); + expectEquals(-1, sign64(0x80000000FFFFFFFFL)); + expectEquals(1, sign64(0x000000007FFFFFFFL)); + expectEquals(1, sign64(0x00000000FFFFFFFFL)); + expectEquals(1, sign64(0x7FFFFFFF7FFFFFFFL)); + expectEquals(1, sign64(0x7FFFFFFFFFFFFFFFL)); + for (long i = -11L; i <= 11L; i++) { int expected = 0; if (i < 0) expected = -1; @@ -61,6 +68,14 @@ public class Main { expectEquals(expected, sign64(i)); } + for (long i = Long.MIN_VALUE; i <= Long.MIN_VALUE + 11L; i++) { + expectEquals(-1, sign64(i)); + } + + for (long i = Long.MAX_VALUE; i >= Long.MAX_VALUE - 11L; i--) { + expectEquals(1, sign64(i)); + } + System.out.println("passed"); } diff --git a/test/567-checker-compare/src/Main.java b/test/567-checker-compare/src/Main.java index 52abb75e89..951d2c7510 100644 --- a/test/567-checker-compare/src/Main.java +++ b/test/567-checker-compare/src/Main.java @@ -88,6 +88,10 @@ public class Main { expectEquals(1, compare64(Long.MAX_VALUE, 1L)); expectEquals(1, compare64(Long.MAX_VALUE, Long.MAX_VALUE - 1L)); + expectEquals(-1, compare64(0x111111117FFFFFFFL, 0x11111111FFFFFFFFL)); + expectEquals(0, compare64(0x111111117FFFFFFFL, 0x111111117FFFFFFFL)); + expectEquals(1, compare64(0x11111111FFFFFFFFL, 0x111111117FFFFFFFL)); + for (long i = -11L; i <= 11L; i++) { for (long j = -11L; j <= 11L; j++) { int expected = 0; @@ -97,6 +101,14 @@ public class Main { } } + for (long i = Long.MIN_VALUE; i <= Long.MIN_VALUE + 11L; i++) { + expectEquals(-1, compare64(i, 0)); + } + + for (long i = Long.MAX_VALUE; i >= Long.MAX_VALUE - 11L; i--) { + expectEquals(1, compare64(i, 0)); + } + System.out.println("passed"); } diff --git a/test/570-checker-osr/expected.txt b/test/570-checker-osr/expected.txt new file mode 100644 index 0000000000..555c6a91d8 --- /dev/null +++ b/test/570-checker-osr/expected.txt @@ -0,0 +1,5 @@ +JNI_OnLoad called +100000000 +200000000 +300000000 +400000000 diff --git a/test/570-checker-osr/info.txt b/test/570-checker-osr/info.txt new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/test/570-checker-osr/info.txt diff --git a/test/570-checker-osr/osr.cc b/test/570-checker-osr/osr.cc new file mode 100644 index 0000000000..fb846872e6 --- /dev/null +++ b/test/570-checker-osr/osr.cc @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2016 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. + */ + +#include "art_method.h" +#include "jit/jit.h" +#include "jit/jit_code_cache.h" +#include "oat_quick_method_header.h" +#include "scoped_thread_state_change.h" +#include "stack_map.h" + +namespace art { + +class OsrVisitor : public StackVisitor { + public: + explicit OsrVisitor(Thread* thread) + SHARED_REQUIRES(Locks::mutator_lock_) + : StackVisitor(thread, nullptr, StackVisitor::StackWalkKind::kIncludeInlinedFrames), + in_osr_method_(false) {} + + bool VisitFrame() SHARED_REQUIRES(Locks::mutator_lock_) { + ArtMethod* m = GetMethod(); + std::string m_name(m->GetName()); + + if ((m_name.compare("$noinline$returnInt") == 0) || + (m_name.compare("$noinline$returnFloat") == 0) || + (m_name.compare("$noinline$returnDouble") == 0) || + (m_name.compare("$noinline$returnLong") == 0) || + (m_name.compare("$noinline$deopt") == 0)) { + const OatQuickMethodHeader* header = + Runtime::Current()->GetJit()->GetCodeCache()->LookupOsrMethodHeader(m); + if (header != nullptr && header == GetCurrentOatQuickMethodHeader()) { + in_osr_method_ = true; + } + return false; + } + return true; + } + + bool in_osr_method_; +}; + +extern "C" JNIEXPORT jboolean JNICALL Java_Main_ensureInOsrCode(JNIEnv*, jclass) { + jit::Jit* jit = Runtime::Current()->GetJit(); + if (jit == nullptr) { + // Just return true for non-jit configurations to stop the infinite loop. + return JNI_TRUE; + } + ScopedObjectAccess soa(Thread::Current()); + OsrVisitor visitor(soa.Self()); + visitor.WalkStack(); + return visitor.in_osr_method_; +} + +} // namespace art diff --git a/test/570-checker-osr/smali/Osr.smali b/test/570-checker-osr/smali/Osr.smali new file mode 100644 index 0000000000..869c7c31b8 --- /dev/null +++ b/test/570-checker-osr/smali/Osr.smali @@ -0,0 +1,35 @@ +# Copyright (C) 2016 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. + +.class public LOsr; + +.super Ljava/lang/Object; + +# Check that blocks only havig nops are not merged when they are loop headers. +# This ensures we can do on-stack replacement for branches to those nop blocks. + +## CHECK-START: int Osr.simpleLoop(int, int) dead_code_elimination_final (after) +## CHECK-DAG: SuspendCheck loop:<<OuterLoop:B\d+>> outer_loop:none +## CHECK-DAG: SuspendCheck loop:{{B\d+}} outer_loop:<<OuterLoop>> +.method public static simpleLoop(II)I + .registers 3 + const/16 v0, 0 + :nop_entry + nop + :loop_entry + add-int v0, v0, v0 + if-eq v0, v1, :loop_entry + if-eq v0, v2, :nop_entry + return v0 +.end method diff --git a/test/570-checker-osr/src/DeoptimizationController.java b/test/570-checker-osr/src/DeoptimizationController.java new file mode 100644 index 0000000000..907d133d3b --- /dev/null +++ b/test/570-checker-osr/src/DeoptimizationController.java @@ -0,0 +1,104 @@ +/* + * 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. + */ + +// This file is a copy of 802-deoptimization/src/DeoptimizationController.java +// because run-test requires standalone individual test. + +import java.io.File; +import java.io.IOException; +import java.lang.reflect.Method; + +/** + * Controls deoptimization using dalvik.system.VMDebug class. + */ +public class DeoptimizationController { + private static final String TEMP_FILE_NAME_PREFIX = "test"; + private static final String TEMP_FILE_NAME_SUFFIX = ".trace"; + + private static File createTempFile() throws Exception { + try { + return File.createTempFile(TEMP_FILE_NAME_PREFIX, TEMP_FILE_NAME_SUFFIX); + } catch (IOException e) { + System.setProperty("java.io.tmpdir", "/data/local/tmp"); + try { + return File.createTempFile(TEMP_FILE_NAME_PREFIX, TEMP_FILE_NAME_SUFFIX); + } catch (IOException e2) { + System.setProperty("java.io.tmpdir", "/sdcard"); + return File.createTempFile(TEMP_FILE_NAME_PREFIX, TEMP_FILE_NAME_SUFFIX); + } + } + } + + public static void startDeoptimization() { + File tempFile = null; + try { + tempFile = createTempFile(); + String tempFileName = tempFile.getPath(); + + VMDebug.startMethodTracing(tempFileName, 0, 0, false, 1000); + if (VMDebug.getMethodTracingMode() == 0) { + throw new IllegalStateException("Not tracing."); + } + } catch (Exception exc) { + exc.printStackTrace(System.err); + } finally { + if (tempFile != null) { + tempFile.delete(); + } + } + } + + public static void stopDeoptimization() { + try { + VMDebug.stopMethodTracing(); + if (VMDebug.getMethodTracingMode() != 0) { + throw new IllegalStateException("Still tracing."); + } + } catch (Exception exc) { + exc.printStackTrace(System.err); + } + } + + private static class VMDebug { + private static final Method startMethodTracingMethod; + private static final Method stopMethodTracingMethod; + private static final Method getMethodTracingModeMethod; + + static { + try { + Class<?> c = Class.forName("dalvik.system.VMDebug"); + startMethodTracingMethod = c.getDeclaredMethod("startMethodTracing", String.class, + Integer.TYPE, Integer.TYPE, Boolean.TYPE, Integer.TYPE); + stopMethodTracingMethod = c.getDeclaredMethod("stopMethodTracing"); + getMethodTracingModeMethod = c.getDeclaredMethod("getMethodTracingMode"); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public static void startMethodTracing(String filename, int bufferSize, int flags, + boolean samplingEnabled, int intervalUs) throws Exception { + startMethodTracingMethod.invoke(null, filename, bufferSize, flags, samplingEnabled, + intervalUs); + } + public static void stopMethodTracing() throws Exception { + stopMethodTracingMethod.invoke(null); + } + public static int getMethodTracingMode() throws Exception { + return (int) getMethodTracingModeMethod.invoke(null); + } + } +} diff --git a/test/570-checker-osr/src/Main.java b/test/570-checker-osr/src/Main.java new file mode 100644 index 0000000000..7485163314 --- /dev/null +++ b/test/570-checker-osr/src/Main.java @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2016 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) { + System.loadLibrary(args[0]); + if ($noinline$returnInt() != 53) { + throw new Error("Unexpected return value"); + } + if ($noinline$returnFloat() != 42.2f) { + throw new Error("Unexpected return value"); + } + if ($noinline$returnDouble() != Double.longBitsToDouble(0xF000000000001111L)) { + throw new Error("Unexpected return value "); + } + if ($noinline$returnLong() != 0xFFFF000000001111L) { + throw new Error("Unexpected return value"); + } + + try { + $noinline$deopt(); + } catch (Exception e) {} + } + + public static int $noinline$returnInt() { + if (doThrow) throw new Error(""); + int i = 0; + for (; i < 100000000; ++i) { + } + while (!ensureInOsrCode()) {} + System.out.println(i); + return 53; + } + + public static float $noinline$returnFloat() { + if (doThrow) throw new Error(""); + int i = 0; + for (; i < 200000000; ++i) { + } + while (!ensureInOsrCode()) {} + System.out.println(i); + return 42.2f; + } + + public static double $noinline$returnDouble() { + if (doThrow) throw new Error(""); + int i = 0; + for (; i < 300000000; ++i) { + } + while (!ensureInOsrCode()) {} + System.out.println(i); + return Double.longBitsToDouble(0xF000000000001111L); + } + + public static long $noinline$returnLong() { + if (doThrow) throw new Error(""); + int i = 1000000; + for (; i < 400000000; ++i) { + } + while (!ensureInOsrCode()) {} + System.out.println(i); + return 0xFFFF000000001111L; + } + + public static void $noinline$deopt() { + if (doThrow) throw new Error(""); + int i = 0; + for (; i < 100000000; ++i) { + } + while (!ensureInOsrCode()) {} + DeoptimizationController.startDeoptimization(); + } + + public static int[] array = new int[4]; + + public static native boolean ensureInOsrCode(); + + public static boolean doThrow = false; +} diff --git a/test/570-checker-select/src/Main.java b/test/570-checker-select/src/Main.java index 2f8094de96..ec60240e90 100644 --- a/test/570-checker-select/src/Main.java +++ b/test/570-checker-select/src/Main.java @@ -19,6 +19,11 @@ public class Main { /// CHECK-START: int Main.BoolCond_IntVarVar(boolean, int, int) register (after) /// CHECK: Select [{{i\d+}},{{i\d+}},{{z\d+}}] + /// CHECK-START-X86_64: int Main.BoolCond_IntVarVar(boolean, int, int) disassembly (after) + /// CHECK: <<Cond:z\d+>> ParameterValue + /// CHECK: Select [{{i\d+}},{{i\d+}},<<Cond>>] + /// CHECK: cmovnz/ne + public static int BoolCond_IntVarVar(boolean cond, int x, int y) { return cond ? x : y; } @@ -26,6 +31,11 @@ public class Main { /// CHECK-START: int Main.BoolCond_IntVarCst(boolean, int) register (after) /// CHECK: Select [{{i\d+}},{{i\d+}},{{z\d+}}] + /// CHECK-START-X86_64: int Main.BoolCond_IntVarCst(boolean, int) disassembly (after) + /// CHECK: <<Cond:z\d+>> ParameterValue + /// CHECK: Select [{{i\d+}},{{i\d+}},<<Cond>>] + /// CHECK: cmovnz/ne + public static int BoolCond_IntVarCst(boolean cond, int x) { return cond ? x : 1; } @@ -33,10 +43,51 @@ public class Main { /// CHECK-START: int Main.BoolCond_IntCstVar(boolean, int) register (after) /// CHECK: Select [{{i\d+}},{{i\d+}},{{z\d+}}] + /// CHECK-START-X86_64: int Main.BoolCond_IntCstVar(boolean, int) disassembly (after) + /// CHECK: <<Cond:z\d+>> ParameterValue + /// CHECK: Select [{{i\d+}},{{i\d+}},<<Cond>>] + /// CHECK: cmovnz/ne + public static int BoolCond_IntCstVar(boolean cond, int y) { return cond ? 1 : y; } + /// CHECK-START: long Main.BoolCond_LongVarVar(boolean, long, long) register (after) + /// CHECK: Select [{{j\d+}},{{j\d+}},{{z\d+}}] + + /// CHECK-START-X86_64: long Main.BoolCond_LongVarVar(boolean, long, long) disassembly (after) + /// CHECK: <<Cond:z\d+>> ParameterValue + /// CHECK: Select [{{j\d+}},{{j\d+}},<<Cond>>] + /// CHECK: cmovnz/neq + + public static long BoolCond_LongVarVar(boolean cond, long x, long y) { + return cond ? x : y; + } + + /// CHECK-START: long Main.BoolCond_LongVarCst(boolean, long) register (after) + /// CHECK: Select [{{j\d+}},{{j\d+}},{{z\d+}}] + + /// CHECK-START-X86_64: long Main.BoolCond_LongVarCst(boolean, long) disassembly (after) + /// CHECK: <<Cond:z\d+>> ParameterValue + /// CHECK: Select [{{j\d+}},{{j\d+}},<<Cond>>] + /// CHECK: cmovnz/neq + + public static long BoolCond_LongVarCst(boolean cond, long x) { + return cond ? x : 1L; + } + + /// CHECK-START: long Main.BoolCond_LongCstVar(boolean, long) register (after) + /// CHECK: Select [{{j\d+}},{{j\d+}},{{z\d+}}] + + /// CHECK-START-X86_64: long Main.BoolCond_LongCstVar(boolean, long) disassembly (after) + /// CHECK: <<Cond:z\d+>> ParameterValue + /// CHECK: Select [{{j\d+}},{{j\d+}},<<Cond>>] + /// CHECK: cmovnz/neq + + public static long BoolCond_LongCstVar(boolean cond, long y) { + return cond ? 1L : y; + } + /// CHECK-START: float Main.BoolCond_FloatVarVar(boolean, float, float) register (after) /// CHECK: Select [{{f\d+}},{{f\d+}},{{z\d+}}] @@ -62,6 +113,11 @@ public class Main { /// CHECK: <<Cond:z\d+>> LessThanOrEqual [{{i\d+}},{{i\d+}}] /// CHECK-NEXT: Select [{{i\d+}},{{i\d+}},<<Cond>>] + /// CHECK-START-X86_64: int Main.IntNonmatCond_IntVarVar(int, int, int, int) disassembly (after) + /// CHECK: <<Cond:z\d+>> LessThanOrEqual [{{i\d+}},{{i\d+}}] + /// CHECK-NEXT: Select [{{i\d+}},{{i\d+}},<<Cond>>] + /// CHECK: cmovle/ng + public static int IntNonmatCond_IntVarVar(int a, int b, int x, int y) { return a > b ? x : y; } @@ -71,11 +127,78 @@ public class Main { /// CHECK-NEXT: <<Sel:i\d+>> Select [{{i\d+}},{{i\d+}},{{z\d+}}] /// CHECK-NEXT: Add [<<Cond>>,<<Sel>>] + /// CHECK-START-X86_64: int Main.IntMatCond_IntVarVar(int, int, int, int) disassembly (after) + /// CHECK: <<Cond:z\d+>> LessThanOrEqual [{{i\d+}},{{i\d+}}] + /// CHECK: Select [{{i\d+}},{{i\d+}},<<Cond>>] + /// CHECK: cmovle/ng + public static int IntMatCond_IntVarVar(int a, int b, int x, int y) { int result = (a > b ? x : y); return result + (a > b ? 0 : 1); } + /// CHECK-START: long Main.IntNonmatCond_LongVarVar(int, int, long, long) register (after) + /// CHECK: <<Cond:z\d+>> LessThanOrEqual [{{i\d+}},{{i\d+}}] + /// CHECK-NEXT: Select [{{j\d+}},{{j\d+}},<<Cond>>] + + /// CHECK-START-X86_64: long Main.IntNonmatCond_LongVarVar(int, int, long, long) disassembly (after) + /// CHECK: <<Cond:z\d+>> LessThanOrEqual [{{i\d+}},{{i\d+}}] + /// CHECK-NEXT: Select [{{j\d+}},{{j\d+}},<<Cond>>] + /// CHECK: cmovle/ngq + + public static long IntNonmatCond_LongVarVar(int a, int b, long x, long y) { + return a > b ? x : y; + } + + /// CHECK-START: long Main.IntMatCond_LongVarVar(int, int, long, long) register (after) + /// CHECK: <<Cond:z\d+>> LessThanOrEqual [{{i\d+}},{{i\d+}}] + /// CHECK: <<Sel1:j\d+>> Select [{{j\d+}},{{j\d+}},<<Cond>>] + /// CHECK: <<Sel2:j\d+>> Select [{{j\d+}},{{j\d+}},<<Cond>>] + /// CHECK: Add [<<Sel2>>,<<Sel1>>] + + /// CHECK-START-X86_64: long Main.IntMatCond_LongVarVar(int, int, long, long) disassembly (after) + /// CHECK: <<Cond:z\d+>> LessThanOrEqual [{{i\d+}},{{i\d+}}] + /// CHECK: Select [{{j\d+}},{{j\d+}},<<Cond>>] + /// CHECK: cmovle/ngq + /// CHECK: Select [{{j\d+}},{{j\d+}},<<Cond>>] + /// CHECK: cmovnz/neq + + public static long IntMatCond_LongVarVar(int a, int b, long x, long y) { + long result = (a > b ? x : y); + return result + (a > b ? 0L : 1L); + } + + /// CHECK-START: long Main.LongNonmatCond_LongVarVar(long, long, long, long) register (after) + /// CHECK: <<Cond:z\d+>> LessThanOrEqual [{{j\d+}},{{j\d+}}] + /// CHECK: Select [{{j\d+}},{{j\d+}},<<Cond>>] + + /// CHECK-START-X86_64: long Main.LongNonmatCond_LongVarVar(long, long, long, long) disassembly (after) + /// CHECK: <<Cond:z\d+>> LessThanOrEqual [{{j\d+}},{{j\d+}}] + /// CHECK: Select [{{j\d+}},{{j\d+}},<<Cond>>] + /// CHECK: cmovle/ngq + + public static long LongNonmatCond_LongVarVar(long a, long b, long x, long y) { + return a > b ? x : y; + } + + /// CHECK-START: long Main.LongMatCond_LongVarVar(long, long, long, long) register (after) + /// CHECK: <<Cond:z\d+>> LessThanOrEqual [{{j\d+}},{{j\d+}}] + /// CHECK: <<Sel1:j\d+>> Select [{{j\d+}},{{j\d+}},<<Cond>>] + /// CHECK: <<Sel2:j\d+>> Select [{{j\d+}},{{j\d+}},<<Cond>>] + /// CHECK: Add [<<Sel2>>,<<Sel1>>] + + /// CHECK-START-X86_64: long Main.LongMatCond_LongVarVar(long, long, long, long) disassembly (after) + /// CHECK: <<Cond:z\d+>> LessThanOrEqual [{{j\d+}},{{j\d+}}] + /// CHECK: Select [{{j\d+}},{{j\d+}},<<Cond>>] + /// CHECK: cmovle/ngq + /// CHECK: Select [{{j\d+}},{{j\d+}},<<Cond>>] + /// CHECK: cmovnz/neq + + public static long LongMatCond_LongVarVar(long a, long b, long x, long y) { + long result = (a > b ? x : y); + return result + (a > b ? 0L : 1L); + } + /// CHECK-START: int Main.FloatLtNonmatCond_IntVarVar(float, float, int, int) register (after) /// CHECK: <<Cond:z\d+>> LessThanOrEqual [{{f\d+}},{{f\d+}}] /// CHECK-NEXT: Select [{{i\d+}},{{i\d+}},<<Cond>>] @@ -150,6 +273,13 @@ public class Main { assertEqual(1, BoolCond_IntCstVar(true, 7)); assertEqual(7, BoolCond_IntCstVar(false, 7)); + assertEqual(5L, BoolCond_LongVarVar(true, 5L, 7L)); + assertEqual(7L, BoolCond_LongVarVar(false, 5L, 7L)); + assertEqual(5L, BoolCond_LongVarCst(true, 5L)); + assertEqual(1L, BoolCond_LongVarCst(false, 5L)); + assertEqual(1L, BoolCond_LongCstVar(true, 7L)); + assertEqual(7L, BoolCond_LongCstVar(false, 7L)); + assertEqual(5, BoolCond_FloatVarVar(true, 5, 7)); assertEqual(7, BoolCond_FloatVarVar(false, 5, 7)); assertEqual(5, BoolCond_FloatVarCst(true, 5)); diff --git a/test/971-iface-super/util-src/generate_smali.py b/test/971-iface-super/util-src/generate_smali.py index f01c9043b9..3681411867 100755 --- a/test/971-iface-super/util-src/generate_smali.py +++ b/test/971-iface-super/util-src/generate_smali.py @@ -39,7 +39,7 @@ import itertools import string # The max depth the type tree can have. -MAX_IFACE_DEPTH = 3 +MAX_IFACE_DEPTH = 2 class MainClass(mixins.DumpMixin, mixins.Named, mixins.SmaliFileMixin): """ diff --git a/test/Android.libarttest.mk b/test/Android.libarttest.mk index faaf1f0d78..e547c72c0e 100644 --- a/test/Android.libarttest.mk +++ b/test/Android.libarttest.mk @@ -40,7 +40,8 @@ LIBARTTEST_COMMON_SRC_FILES := \ 466-get-live-vreg/get_live_vreg_jni.cc \ 497-inlining-and-class-loader/clear_dex_cache.cc \ 543-env-long-ref/env_long_ref.cc \ - 566-polymorphic-inlining/polymorphic_inline.cc + 566-polymorphic-inlining/polymorphic_inline.cc \ + 570-checker-osr/osr.cc ART_TARGET_LIBARTTEST_$(ART_PHONY_TEST_TARGET_SUFFIX) += $(ART_TARGET_TEST_OUT)/$(TARGET_ARCH)/libarttest.so ART_TARGET_LIBARTTEST_$(ART_PHONY_TEST_TARGET_SUFFIX) += $(ART_TARGET_TEST_OUT)/$(TARGET_ARCH)/libarttestd.so diff --git a/test/Android.run-test.mk b/test/Android.run-test.mk index a8938fad40..e6ffd2ed9b 100644 --- a/test/Android.run-test.mk +++ b/test/Android.run-test.mk @@ -401,13 +401,14 @@ TEST_ART_BROKEN_FALLBACK_RUN_TESTS := # 137: # This test unrolls and expects managed frames, but tracing means we run the interpreter. -# 802: +# 802 and 570-checker-osr: # This test dynamically enables tracing to force a deoptimization. This makes the test meaningless # when already tracing, and writes an error message that we do not want to check for. TEST_ART_BROKEN_TRACING_RUN_TESTS := \ 087-gc-after-link \ 137-cfi \ 141-class-unload \ + 570-checker-osr \ 802-deoptimization ifneq (,$(filter trace stream,$(TRACE_TYPES))) |