summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--compiler/optimizing/code_generator.h2
-rw-r--r--compiler/optimizing/graph_visualizer.cc2
-rw-r--r--compiler/optimizing/nodes.h3
-rw-r--r--compiler/optimizing/register_allocator.cc60
-rw-r--r--test/536-checker-needs-access-check/expected.txt1
-rw-r--r--test/536-checker-needs-access-check/src/Main.java25
-rw-r--r--test/536-checker-needs-access-check/src/other/InaccessibleClass.java2
-rw-r--r--test/536-checker-needs-access-check/src/other/InaccessibleClassProxy.java23
-rw-r--r--test/536-checker-needs-access-check/src2/other/InaccessibleClass.java2
-rw-r--r--test/536-checker-needs-access-check/src2/other/InaccessibleClassProxy.java23
-rw-r--r--test/537-checker-debuggable/expected.txt0
-rw-r--r--test/537-checker-debuggable/info.txt1
-rw-r--r--test/537-checker-debuggable/smali/TestCase.smali42
-rw-r--r--test/537-checker-debuggable/src/Main.java23
-rw-r--r--test/Android.run-test.mk1
-rwxr-xr-xtest/run-test18
-rwxr-xr-xtools/checker/checker.py10
-rw-r--r--tools/checker/file_format/checker/parser.py20
-rw-r--r--tools/checker/file_format/checker/struct.py3
-rw-r--r--tools/checker/file_format/checker/test.py48
-rw-r--r--tools/checker/match/file.py5
-rwxr-xr-xtools/checker/run_unit_tests.py2
22 files changed, 248 insertions, 68 deletions
diff --git a/compiler/optimizing/code_generator.h b/compiler/optimizing/code_generator.h
index 0a3698946e..acce5b3359 100644
--- a/compiler/optimizing/code_generator.h
+++ b/compiler/optimizing/code_generator.h
@@ -531,6 +531,8 @@ class CodeGenerator {
template <typename LabelType>
LabelType* CommonInitializeLabels() {
+ // We use raw array allocations instead of ArenaVector<> because Labels are
+ // non-constructible and non-movable and as such cannot be held in a vector.
size_t size = GetGraph()->GetBlocks().size();
LabelType* labels = GetGraph()->GetArena()->AllocArray<LabelType>(size,
kArenaAllocCodeGenerator);
diff --git a/compiler/optimizing/graph_visualizer.cc b/compiler/optimizing/graph_visualizer.cc
index 208260a2ad..4111671a9b 100644
--- a/compiler/optimizing/graph_visualizer.cc
+++ b/compiler/optimizing/graph_visualizer.cc
@@ -362,6 +362,8 @@ class HGraphVisualizerPrinter : public HGraphDelegateVisitor {
void VisitLoadClass(HLoadClass* load_class) OVERRIDE {
StartAttributeStream("gen_clinit_check") << std::boolalpha
<< load_class->MustGenerateClinitCheck() << std::noboolalpha;
+ StartAttributeStream("needs_access_check") << std::boolalpha
+ << load_class->NeedsAccessCheck() << std::noboolalpha;
}
void VisitCheckCast(HCheckCast* check_cast) OVERRIDE {
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index bba5a9c350..615012eb3a 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -4510,7 +4510,8 @@ class HLoadClass : public HExpression<1> {
bool CanBeMoved() const OVERRIDE { return true; }
bool InstructionDataEquals(HInstruction* other) const OVERRIDE {
- return other->AsLoadClass()->type_index_ == type_index_;
+ return other->AsLoadClass()->type_index_ == type_index_ &&
+ other->AsLoadClass()->needs_access_check_ == needs_access_check_;
}
size_t ComputeHashCode() const OVERRIDE { return type_index_; }
diff --git a/compiler/optimizing/register_allocator.cc b/compiler/optimizing/register_allocator.cc
index 4d43d1df9c..6fc77721e7 100644
--- a/compiler/optimizing/register_allocator.cc
+++ b/compiler/optimizing/register_allocator.cc
@@ -617,42 +617,40 @@ void RegisterAllocator::LinearScan() {
// (2) Remove currently active intervals that are dead at this position.
// Move active intervals that have a lifetime hole at this position
// to inactive.
- // Note: Copy elements we keep to the beginning, just like
- // v.erase(std::remove(v.begin(), v.end(), value), v.end());
- auto active_kept_end = active_.begin();
- for (auto it = active_.begin(), end = active_.end(); it != end; ++it) {
- LiveInterval* interval = *it;
- if (interval->IsDeadAt(position)) {
- handled_.push_back(interval);
- } else if (!interval->Covers(position)) {
- inactive_.push_back(interval);
- } else {
- *active_kept_end++ = interval; // Keep this interval.
- }
- }
- // We have copied what we want to keep to [active_.begin(), active_kept_end),
- // the rest of the data in active_ is junk - drop it.
+ auto active_kept_end = std::remove_if(
+ active_.begin(),
+ active_.end(),
+ [this, position](LiveInterval* interval) {
+ if (interval->IsDeadAt(position)) {
+ handled_.push_back(interval);
+ return true;
+ } else if (!interval->Covers(position)) {
+ inactive_.push_back(interval);
+ return true;
+ } else {
+ return false; // Keep this interval.
+ }
+ });
active_.erase(active_kept_end, active_.end());
// (3) Remove currently inactive intervals that are dead at this position.
// Move inactive intervals that cover this position to active.
- // Note: Copy elements we keep to the beginning, just like
- // v.erase(std::remove(v.begin(), v.begin() + num, value), v.begin() + num);
- auto inactive_kept_end = inactive_.begin();
auto inactive_to_handle_end = inactive_.begin() + inactive_intervals_to_handle;
- for (auto it = inactive_.begin(); it != inactive_to_handle_end; ++it) {
- LiveInterval* interval = *it;
- DCHECK(interval->GetStart() < position || interval->IsFixed());
- if (interval->IsDeadAt(position)) {
- handled_.push_back(interval);
- } else if (interval->Covers(position)) {
- active_.push_back(interval);
- } else {
- *inactive_kept_end++ = interval; // Keep this interval.
- }
- }
- // We have copied what we want to keep to [inactive_.begin(), inactive_kept_end),
- // the rest of the data in the processed interval is junk - drop it.
+ auto inactive_kept_end = std::remove_if(
+ inactive_.begin(),
+ inactive_to_handle_end,
+ [this, position](LiveInterval* interval) {
+ DCHECK(interval->GetStart() < position || interval->IsFixed());
+ if (interval->IsDeadAt(position)) {
+ handled_.push_back(interval);
+ return true;
+ } else if (interval->Covers(position)) {
+ active_.push_back(interval);
+ return true;
+ } else {
+ return false; // Keep this interval.
+ }
+ });
inactive_.erase(inactive_kept_end, inactive_to_handle_end);
if (current->IsSlowPathSafepoint()) {
diff --git a/test/536-checker-needs-access-check/expected.txt b/test/536-checker-needs-access-check/expected.txt
index 7dc7a33fe5..4acae95b70 100644
--- a/test/536-checker-needs-access-check/expected.txt
+++ b/test/536-checker-needs-access-check/expected.txt
@@ -1,3 +1,4 @@
Got expected error instanceof
Got expected error instanceof null
Got expected error checkcast null
+Got expected error instanceof (keep LoadClass with access check)
diff --git a/test/536-checker-needs-access-check/src/Main.java b/test/536-checker-needs-access-check/src/Main.java
index 8b19dafd2a..7bd49c1c8c 100644
--- a/test/536-checker-needs-access-check/src/Main.java
+++ b/test/536-checker-needs-access-check/src/Main.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009 The Android Open Source Project
+ * 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.
@@ -15,10 +15,9 @@
*/
import other.InaccessibleClass;
+import other.InaccessibleClassProxy;
public class Main {
- public static final boolean VERBOSE = false;
-
public static void main(String[] args) {
try {
testInstanceOf();
@@ -37,6 +36,12 @@ public class Main {
} catch (IllegalAccessError e) {
System.out.println("Got expected error checkcast null");
}
+
+ try {
+ testDontGvnLoadClassWithAccessChecks(new Object());
+ } catch (IllegalAccessError e) {
+ System.out.println("Got expected error instanceof (keep LoadClass with access check)");
+ }
}
/// CHECK-START: boolean Main.testInstanceOf() register (after)
@@ -59,5 +64,19 @@ public class Main {
return (InaccessibleClass) null;
}
+ /// CHECK-START: boolean Main.testDontGvnLoadClassWithAccessChecks(java.lang.Object) inliner (before)
+ /// CHECK: InvokeStaticOrDirect
+
+ /// CHECK-START: boolean Main.testDontGvnLoadClassWithAccessChecks(java.lang.Object) inliner (after)
+ /// CHECK-NOT: InvokeStaticOrDirect
+
+ /// CHECK-START: boolean Main.testDontGvnLoadClassWithAccessChecks(java.lang.Object) GVN (after)
+ /// CHECK: LoadClass needs_access_check:false
+ /// CHECK: LoadClass needs_access_check:true
+ public static boolean testDontGvnLoadClassWithAccessChecks(Object o) {
+ InaccessibleClassProxy.test(o);
+ return ic instanceof InaccessibleClass;
+ }
+
public static InaccessibleClass ic;
}
diff --git a/test/536-checker-needs-access-check/src/other/InaccessibleClass.java b/test/536-checker-needs-access-check/src/other/InaccessibleClass.java
index c49593da75..de2e1d7830 100644
--- a/test/536-checker-needs-access-check/src/other/InaccessibleClass.java
+++ b/test/536-checker-needs-access-check/src/other/InaccessibleClass.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009 The Android Open Source Project
+ * 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.
diff --git a/test/536-checker-needs-access-check/src/other/InaccessibleClassProxy.java b/test/536-checker-needs-access-check/src/other/InaccessibleClassProxy.java
new file mode 100644
index 0000000000..4c005e4dfe
--- /dev/null
+++ b/test/536-checker-needs-access-check/src/other/InaccessibleClassProxy.java
@@ -0,0 +1,23 @@
+/*
+ * 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.
+ */
+
+package other;
+
+public class InaccessibleClassProxy {
+ public static boolean test(Object o) {
+ return o instanceof InaccessibleClass;
+ }
+}
diff --git a/test/536-checker-needs-access-check/src2/other/InaccessibleClass.java b/test/536-checker-needs-access-check/src2/other/InaccessibleClass.java
index ac804ac00a..273226375e 100644
--- a/test/536-checker-needs-access-check/src2/other/InaccessibleClass.java
+++ b/test/536-checker-needs-access-check/src2/other/InaccessibleClass.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009 The Android Open Source Project
+ * 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.
diff --git a/test/536-checker-needs-access-check/src2/other/InaccessibleClassProxy.java b/test/536-checker-needs-access-check/src2/other/InaccessibleClassProxy.java
new file mode 100644
index 0000000000..4c005e4dfe
--- /dev/null
+++ b/test/536-checker-needs-access-check/src2/other/InaccessibleClassProxy.java
@@ -0,0 +1,23 @@
+/*
+ * 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.
+ */
+
+package other;
+
+public class InaccessibleClassProxy {
+ public static boolean test(Object o) {
+ return o instanceof InaccessibleClass;
+ }
+}
diff --git a/test/537-checker-debuggable/expected.txt b/test/537-checker-debuggable/expected.txt
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/test/537-checker-debuggable/expected.txt
diff --git a/test/537-checker-debuggable/info.txt b/test/537-checker-debuggable/info.txt
new file mode 100644
index 0000000000..25597d3f13
--- /dev/null
+++ b/test/537-checker-debuggable/info.txt
@@ -0,0 +1 @@
+Test that CHECK-START-DEBUGGABLE runs only on --debuggable code. \ No newline at end of file
diff --git a/test/537-checker-debuggable/smali/TestCase.smali b/test/537-checker-debuggable/smali/TestCase.smali
new file mode 100644
index 0000000000..8e6c7ef727
--- /dev/null
+++ b/test/537-checker-debuggable/smali/TestCase.smali
@@ -0,0 +1,42 @@
+# 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.
+
+.class public LTestCase;
+
+.super Ljava/lang/Object;
+
+# The phi in this method has no actual uses but one environment use. It will
+# be eliminated in normal mode but kept live in debuggable mode. Test that
+# Checker runs the correct test for each compilation mode.
+
+## CHECK-START: int TestCase.deadPhi(int, int, int) ssa_builder (after)
+## CHECK-NOT: Phi
+
+## CHECK-START-DEBUGGABLE: int TestCase.deadPhi(int, int, int) ssa_builder (after)
+## CHECK: Phi
+
+.method public static deadPhi(III)I
+ .registers 8
+
+ move v0, p1
+ if-eqz p0, :after
+ move v0, p2
+ :after
+ # v0 = Phi [p1, p2] with no uses
+
+ invoke-static {}, Ljava/lang/System;->nanoTime()J # create an env use
+
+ :return
+ return p2
+.end method
diff --git a/test/537-checker-debuggable/src/Main.java b/test/537-checker-debuggable/src/Main.java
new file mode 100644
index 0000000000..a572648109
--- /dev/null
+++ b/test/537-checker-debuggable/src/Main.java
@@ -0,0 +1,23 @@
+/*
+ * 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 {
+
+ // Workaround for b/18051191.
+ class InnerClass {}
+
+ public static void main(String[] args) { }
+}
diff --git a/test/Android.run-test.mk b/test/Android.run-test.mk
index 9899e2dd31..537873f0f0 100644
--- a/test/Android.run-test.mk
+++ b/test/Android.run-test.mk
@@ -470,6 +470,7 @@ TEST_ART_BROKEN_OPTIMIZING_MIPS_RUN_TESTS := \
532-checker-nonnull-arrayset \
534-checker-bce-deoptimization \
536-checker-intrinsic-optimization \
+ 537-checker-debuggable \
ifeq (mips,$(TARGET_ARCH))
ifneq (,$(filter optimizing,$(COMPILER_TYPES)))
diff --git a/test/run-test b/test/run-test
index a5b6e92869..2892ce9f18 100755
--- a/test/run-test
+++ b/test/run-test
@@ -637,18 +637,24 @@ if [[ "$TEST_NAME" =~ ^[0-9]+-checker- ]]; then
# on a particular DEX output, keep building them with dx for now (b/19467889).
USE_JACK="false"
- if [ "$runtime" = "art" -a "$image_suffix" = "-optimizing" -a "$debuggable" = "no" ]; then
+ if [ "$runtime" = "art" -a "$image_suffix" = "-optimizing" ]; then
# In no-prebuild mode, the compiler is only invoked if both dex2oat and
# patchoat are available. Disable Checker otherwise (b/22552692).
if [ "$prebuild_mode" = "yes" ] || [ "$have_patchoat" = "yes" -a "$have_dex2oat" = "yes" ]; then
run_checker="yes"
+
if [ "$target_mode" = "no" ]; then
cfg_output_dir="$tmp_dir"
- checker_arch_option="--arch=${host_arch_name^^}"
+ checker_args="--arch=${host_arch_name^^}"
else
cfg_output_dir="$DEX_LOCATION"
- checker_arch_option="--arch=${target_arch_name^^}"
+ checker_args="--arch=${target_arch_name^^}"
+ fi
+
+ if [ "$debuggable" = "yes" ]; then
+ checker_args="$checker_args --debuggable"
fi
+
run_args="${run_args} -Xcompiler-option --dump-cfg=$cfg_output_dir/$cfg_output \
-Xcompiler-option -j1"
fi
@@ -702,7 +708,7 @@ if [ "$dev_mode" = "yes" ]; then
if [ "$target_mode" = "yes" ]; then
adb pull $cfg_output_dir/$cfg_output &> /dev/null
fi
- "$checker" $checker_arch_option "$cfg_output" "$tmp_dir" 2>&1
+ "$checker" $checker_args "$cfg_output" "$tmp_dir" 2>&1
checker_exit="$?"
if [ "$checker_exit" = "0" ]; then
good="yes"
@@ -727,7 +733,7 @@ elif [ "$update_mode" = "yes" ]; then
if [ "$target_mode" = "yes" ]; then
adb pull $cfg_output_dir/$cfg_output &> /dev/null
fi
- "$checker" -q $checker_arch_option "$cfg_output" "$tmp_dir" >> "$output" 2>&1
+ "$checker" -q $checker_args "$cfg_output" "$tmp_dir" >> "$output" 2>&1
fi
sed -e 's/[[:cntrl:]]$//g' < "$output" >"${td_expected}"
good="yes"
@@ -768,7 +774,7 @@ else
if [ "$target_mode" = "yes" ]; then
adb pull $cfg_output_dir/$cfg_output &> /dev/null
fi
- "$checker" -q $checker_arch_option "$cfg_output" "$tmp_dir" >> "$output" 2>&1
+ "$checker" -q $checker_args "$cfg_output" "$tmp_dir" >> "$output" 2>&1
checker_exit="$?"
if [ "$checker_exit" != "0" ]; then
echo "checker exit status: $checker_exit" 1>&2
diff --git a/tools/checker/checker.py b/tools/checker/checker.py
index bc5e17da6a..2e9faba9fb 100755
--- a/tools/checker/checker.py
+++ b/tools/checker/checker.py
@@ -36,7 +36,9 @@ def ParseArguments():
parser.add_argument("--dump-pass", dest="dump_pass", metavar="PASS",
help="print a compiler pass dump")
parser.add_argument("--arch", dest="arch", choices=archs_list,
- help="Run the tests for the specified target architecture.")
+ help="Run tests for the specified target architecture.")
+ parser.add_argument("--debuggable", action="store_true",
+ help="Run tests for debuggable code.")
parser.add_argument("-q", "--quiet", action="store_true",
help="print only errors")
return parser.parse_args()
@@ -83,13 +85,13 @@ def FindCheckerFiles(path):
Logger.fail("Source path \"" + path + "\" not found")
-def RunTests(checkPrefix, checkPath, outputFilename, targetArch):
+def RunTests(checkPrefix, checkPath, outputFilename, targetArch, debuggableMode):
c1File = ParseC1visualizerStream(os.path.basename(outputFilename), open(outputFilename, "r"))
for checkFilename in FindCheckerFiles(checkPath):
checkerFile = ParseCheckerStream(os.path.basename(checkFilename),
checkPrefix,
open(checkFilename, "r"))
- MatchFiles(checkerFile, c1File, targetArch)
+ MatchFiles(checkerFile, c1File, targetArch, debuggableMode)
if __name__ == "__main__":
@@ -103,4 +105,4 @@ if __name__ == "__main__":
elif args.dump_pass:
DumpPass(args.tested_file, args.dump_pass)
else:
- RunTests(args.check_prefix, args.source_path, args.tested_file, args.arch)
+ RunTests(args.check_prefix, args.source_path, args.tested_file, args.arch, args.debuggable)
diff --git a/tools/checker/file_format/checker/parser.py b/tools/checker/file_format/checker/parser.py
index 446302fed2..f199a50ebe 100644
--- a/tools/checker/file_format/checker/parser.py
+++ b/tools/checker/file_format/checker/parser.py
@@ -22,7 +22,7 @@ import re
def __isCheckerLine(line):
return line.startswith("///") or line.startswith("##")
-def __extractLine(prefix, line, arch = None):
+def __extractLine(prefix, line, arch = None, debuggable = False):
""" Attempts to parse a check line. The regex searches for a comment symbol
followed by the CHECK keyword, given attribute and a colon at the very
beginning of the line. Whitespaces are ignored.
@@ -30,10 +30,11 @@ def __extractLine(prefix, line, arch = None):
rIgnoreWhitespace = r"\s*"
rCommentSymbols = [r"///", r"##"]
arch_specifier = r"-%s" % arch if arch is not None else r""
+ dbg_specifier = r"-DEBUGGABLE" if debuggable else r""
regexPrefix = rIgnoreWhitespace + \
r"(" + r"|".join(rCommentSymbols) + r")" + \
rIgnoreWhitespace + \
- prefix + arch_specifier + r":"
+ prefix + arch_specifier + dbg_specifier + r":"
# The 'match' function succeeds only if the pattern is matched at the
# beginning of the line.
@@ -56,10 +57,11 @@ def __processLine(line, lineNo, prefix, fileName):
# Lines beginning with 'CHECK-START' start a new test case.
# We currently only consider the architecture suffix in "CHECK-START" lines.
- for arch in [None] + archs_list:
- startLine = __extractLine(prefix + "-START", line, arch)
- if startLine is not None:
- return None, startLine, arch
+ for debuggable in [True, False]:
+ for arch in [None] + archs_list:
+ startLine = __extractLine(prefix + "-START", line, arch, debuggable)
+ if startLine is not None:
+ return None, startLine, (arch, debuggable)
# Lines starting only with 'CHECK' are matched in order.
plainLine = __extractLine(prefix, line)
@@ -167,9 +169,11 @@ def ParseCheckerStream(fileName, prefix, stream):
fnProcessLine = lambda line, lineNo: __processLine(line, lineNo, prefix, fileName)
fnLineOutsideChunk = lambda line, lineNo: \
Logger.fail("Checker line not inside a group", fileName, lineNo)
- for caseName, caseLines, startLineNo, testArch in \
+ for caseName, caseLines, startLineNo, testData in \
SplitStream(stream, fnProcessLine, fnLineOutsideChunk):
- testCase = TestCase(checkerFile, caseName, startLineNo, testArch)
+ testArch = testData[0]
+ forDebuggable = testData[1]
+ testCase = TestCase(checkerFile, caseName, startLineNo, testArch, forDebuggable)
for caseLine in caseLines:
ParseCheckerAssertion(testCase, caseLine[0], caseLine[1], caseLine[2])
return checkerFile
diff --git a/tools/checker/file_format/checker/struct.py b/tools/checker/file_format/checker/struct.py
index 7ee09cdb84..a31aa54c91 100644
--- a/tools/checker/file_format/checker/struct.py
+++ b/tools/checker/file_format/checker/struct.py
@@ -36,7 +36,7 @@ class CheckerFile(PrintableMixin):
class TestCase(PrintableMixin):
- def __init__(self, parent, name, startLineNo, testArch = None):
+ def __init__(self, parent, name, startLineNo, testArch = None, forDebuggable = False):
assert isinstance(parent, CheckerFile)
self.parent = parent
@@ -44,6 +44,7 @@ class TestCase(PrintableMixin):
self.assertions = []
self.startLineNo = startLineNo
self.testArch = testArch
+ self.forDebuggable = forDebuggable
if not self.name:
Logger.fail("Test case does not have a name", self.fileName, self.startLineNo)
diff --git a/tools/checker/file_format/checker/test.py b/tools/checker/file_format/checker/test.py
index 495dabc588..579c190d21 100644
--- a/tools/checker/file_format/checker/test.py
+++ b/tools/checker/file_format/checker/test.py
@@ -290,7 +290,7 @@ class CheckerParser_FileLayoutTest(unittest.TestCase):
/// CHECK-NEXT: bar
""")
-class CheckerParser_ArchTests(unittest.TestCase):
+class CheckerParser_SuffixTests(unittest.TestCase):
noarch_block = """
/// CHECK-START: Group
@@ -308,11 +308,12 @@ class CheckerParser_ArchTests(unittest.TestCase):
/// CHECK-DAG: yoyo
"""
+ def parse(self, checkerText):
+ return ParseCheckerStream("<test_file>", "CHECK", io.StringIO(ToUnicode(checkerText)))
+
def test_NonArchTests(self):
for arch in [None] + archs_list:
- checkerFile = ParseCheckerStream("<test-file>",
- "CHECK",
- io.StringIO(ToUnicode(self.noarch_block)))
+ checkerFile = self.parse(self.noarch_block)
self.assertEqual(len(checkerFile.testCases), 1)
self.assertEqual(len(checkerFile.testCases[0].assertions), 4)
@@ -320,9 +321,7 @@ class CheckerParser_ArchTests(unittest.TestCase):
for targetArch in archs_list:
for testArch in [a for a in archs_list if a != targetArch]:
checkerText = self.arch_block.format(test_arch = testArch)
- checkerFile = ParseCheckerStream("<test-file>",
- "CHECK",
- io.StringIO(ToUnicode(checkerText)))
+ checkerFile = self.parse(checkerText)
self.assertEqual(len(checkerFile.testCases), 1)
self.assertEqual(len(checkerFile.testCasesForArch(testArch)), 1)
self.assertEqual(len(checkerFile.testCasesForArch(targetArch)), 0)
@@ -330,13 +329,42 @@ class CheckerParser_ArchTests(unittest.TestCase):
def test_Arch(self):
for arch in archs_list:
checkerText = self.arch_block.format(test_arch = arch)
- checkerFile = ParseCheckerStream("<test-file>",
- "CHECK",
- io.StringIO(ToUnicode(checkerText)))
+ checkerFile = self.parse(checkerText)
self.assertEqual(len(checkerFile.testCases), 1)
self.assertEqual(len(checkerFile.testCasesForArch(arch)), 1)
self.assertEqual(len(checkerFile.testCases[0].assertions), 4)
+ def test_NoDebugAndArch(self):
+ testCase = self.parse("""
+ /// CHECK-START: Group
+ /// CHECK: foo
+ """).testCases[0]
+ self.assertFalse(testCase.forDebuggable)
+ self.assertEqual(testCase.testArch, None)
+
+ def test_SetDebugNoArch(self):
+ testCase = self.parse("""
+ /// CHECK-START-DEBUGGABLE: Group
+ /// CHECK: foo
+ """).testCases[0]
+ self.assertTrue(testCase.forDebuggable)
+ self.assertEqual(testCase.testArch, None)
+
+ def test_NoDebugSetArch(self):
+ testCase = self.parse("""
+ /// CHECK-START-ARM: Group
+ /// CHECK: foo
+ """).testCases[0]
+ self.assertFalse(testCase.forDebuggable)
+ self.assertEqual(testCase.testArch, "ARM")
+
+ def test_SetDebugAndArch(self):
+ testCase = self.parse("""
+ /// CHECK-START-ARM-DEBUGGABLE: Group
+ /// CHECK: foo
+ """).testCases[0]
+ self.assertTrue(testCase.forDebuggable)
+ self.assertEqual(testCase.testArch, "ARM")
class CheckerParser_EvalTests(unittest.TestCase):
def parseTestCase(self, string):
diff --git a/tools/checker/match/file.py b/tools/checker/match/file.py
index 6601a1e965..3ded07482f 100644
--- a/tools/checker/match/file.py
+++ b/tools/checker/match/file.py
@@ -159,10 +159,13 @@ def MatchTestCase(testCase, c1Pass):
matchFrom = match.scope.end + 1
variables = match.variables
-def MatchFiles(checkerFile, c1File, targetArch):
+def MatchFiles(checkerFile, c1File, targetArch, debuggableMode):
for testCase in checkerFile.testCases:
if testCase.testArch not in [None, targetArch]:
continue
+ if testCase.forDebuggable != debuggableMode:
+ continue
+
# TODO: Currently does not handle multiple occurrences of the same group
# name, e.g. when a pass is run multiple times. It will always try to
# match a check group against the first output group of the same name.
diff --git a/tools/checker/run_unit_tests.py b/tools/checker/run_unit_tests.py
index 2e8f2083b5..a0d274df25 100755
--- a/tools/checker/run_unit_tests.py
+++ b/tools/checker/run_unit_tests.py
@@ -19,7 +19,7 @@ from file_format.c1visualizer.test import C1visualizerParser_Test
from file_format.checker.test import CheckerParser_PrefixTest, \
CheckerParser_TestExpressionTest, \
CheckerParser_FileLayoutTest, \
- CheckerParser_ArchTests, \
+ CheckerParser_SuffixTests, \
CheckerParser_EvalTests
from match.test import MatchLines_Test, \
MatchFiles_Test