diff options
| author | Nicolas Geoffray <ngeoffray@google.com> | 2018-08-07 09:55:57 +0100 |
|---|---|---|
| committer | Nicolas Geoffray <ngeoffray@google.com> | 2018-08-20 17:18:31 +0100 |
| commit | 61ba8d2421a98e9b16510be4f9af7ca7bc4c9055 (patch) | |
| tree | 9a79331dd5ebd46ed46f853b24ab072f43debf28 | |
| parent | eb369ce3669be74dd89b21f8b3ab31ace4a47086 (diff) | |
| download | art-61ba8d2421a98e9b16510be4f9af7ca7bc4c9055.tar.gz art-61ba8d2421a98e9b16510be4f9af7ca7bc4c9055.tar.bz2 art-61ba8d2421a98e9b16510be4f9af7ca7bc4c9055.zip | |
Fix longstanding bug around implicit NPEs and GC, version 2.
The TODO has been there since M (so forever :)):
https://android-review.googlesource.com/c/platform/art/+/122794/13//COMMIT_MSG#13
We hardly see the issue in our tests as we need to have:
1) A GC happening while creating the NPE object.
2) ParallelMoves between the NullCheck and implicit null check operation
that moves references.
The CL piggy backs on the "IsEmittedAtUseSite" flag, to set implicit
null checks with it. The liveness analysis then special cases implicit
null checks to record environment uses at the location of the actual
instruction that will do the implicit null check.
Test: test.py --gcstress
Test: run-libcore-tests --gcstress
bug: 111545159
Change-Id: I3ecea4fe0d7e483e93db83281ca10db47da228c5
| -rw-r--r-- | compiler/optimizing/code_generator.cc | 31 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator_arm64.cc | 2 | ||||
| -rw-r--r-- | compiler/optimizing/codegen_test.cc | 2 | ||||
| -rw-r--r-- | compiler/optimizing/codegen_test_utils.h | 2 | ||||
| -rw-r--r-- | compiler/optimizing/live_ranges_test.cc | 2 | ||||
| -rw-r--r-- | compiler/optimizing/liveness_test.cc | 2 | ||||
| -rw-r--r-- | compiler/optimizing/nodes.h | 17 | ||||
| -rw-r--r-- | compiler/optimizing/optimizing_compiler.cc | 2 | ||||
| -rw-r--r-- | compiler/optimizing/prepare_for_register_allocation.cc | 16 | ||||
| -rw-r--r-- | compiler/optimizing/prepare_for_register_allocation.h | 11 | ||||
| -rw-r--r-- | compiler/optimizing/ssa_liveness_analysis.cc | 71 | ||||
| -rw-r--r-- | compiler/optimizing/ssa_liveness_analysis.h | 7 | ||||
| -rw-r--r-- | test/565-checker-condition-liveness/src/Main.java | 40 | ||||
| -rw-r--r-- | test/knownfailures.json | 6 | ||||
| -rw-r--r-- | tools/libcore_gcstress_failures.txt | 10 |
15 files changed, 117 insertions, 104 deletions
diff --git a/compiler/optimizing/code_generator.cc b/compiler/optimizing/code_generator.cc index a13efcaee2..a90ff3f885 100644 --- a/compiler/optimizing/code_generator.cc +++ b/compiler/optimizing/code_generator.cc @@ -1394,37 +1394,12 @@ void CodeGenerator::EmitEnvironment(HEnvironment* environment, SlowPathCode* slo } bool CodeGenerator::CanMoveNullCheckToUser(HNullCheck* null_check) { - HInstruction* first_next_not_move = null_check->GetNextDisregardingMoves(); - - return (first_next_not_move != nullptr) - && first_next_not_move->CanDoImplicitNullCheckOn(null_check->InputAt(0)); + return null_check->IsEmittedAtUseSite(); } void CodeGenerator::MaybeRecordImplicitNullCheck(HInstruction* instr) { - if (!compiler_options_.GetImplicitNullChecks()) { - return; - } - - // If we are from a static path don't record the pc as we can't throw NPE. - // NB: having the checks here makes the code much less verbose in the arch - // specific code generators. - if (instr->IsStaticFieldSet() || instr->IsStaticFieldGet()) { - return; - } - - if (!instr->CanDoImplicitNullCheckOn(instr->InputAt(0))) { - return; - } - - // Find the first previous instruction which is not a move. - HInstruction* first_prev_not_move = instr->GetPreviousDisregardingMoves(); - - // If the instruction is a null check it means that `instr` is the first user - // and needs to record the pc. - if (first_prev_not_move != nullptr && first_prev_not_move->IsNullCheck()) { - HNullCheck* null_check = first_prev_not_move->AsNullCheck(); - // TODO: The parallel moves modify the environment. Their changes need to be - // reverted otherwise the stack maps at the throw point will not be correct. + HNullCheck* null_check = instr->GetImplicitNullCheck(); + if (null_check != nullptr) { RecordPcInfo(null_check, null_check->GetDexPc()); } } diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc index 260920cb0c..4ebe12e3af 100644 --- a/compiler/optimizing/code_generator_arm64.cc +++ b/compiler/optimizing/code_generator_arm64.cc @@ -5558,7 +5558,7 @@ void CodeGeneratorARM64::GenerateImplicitNullCheck(HNullCheck* instruction) { return; } { - // Ensure that between load and MaybeRecordImplicitNullCheck there are no pools emitted. + // Ensure that between load and RecordPcInfo there are no pools emitted. EmissionCheckScope guard(GetVIXLAssembler(), kMaxMacroInstructionSizeInBytes); Location obj = instruction->GetLocations()->InAt(0); __ Ldr(wzr, HeapOperandFrom(obj, Offset(0))); diff --git a/compiler/optimizing/codegen_test.cc b/compiler/optimizing/codegen_test.cc index 86687e60a9..f186191a0f 100644 --- a/compiler/optimizing/codegen_test.cc +++ b/compiler/optimizing/codegen_test.cc @@ -453,7 +453,7 @@ TEST_F(CodegenTest, NonMaterializedCondition) { ASSERT_FALSE(equal->IsEmittedAtUseSite()); graph->BuildDominatorTree(); - PrepareForRegisterAllocation(graph).Run(); + PrepareForRegisterAllocation(graph, *compiler_options_).Run(); ASSERT_TRUE(equal->IsEmittedAtUseSite()); auto hook_before_codegen = [](HGraph* graph_in) { diff --git a/compiler/optimizing/codegen_test_utils.h b/compiler/optimizing/codegen_test_utils.h index 91811262de..8c062f03b7 100644 --- a/compiler/optimizing/codegen_test_utils.h +++ b/compiler/optimizing/codegen_test_utils.h @@ -288,7 +288,7 @@ static void RunCodeNoCheck(CodeGenerator* codegen, { ScopedArenaAllocator local_allocator(graph->GetArenaStack()); SsaLivenessAnalysis liveness(graph, codegen, &local_allocator); - PrepareForRegisterAllocation(graph).Run(); + PrepareForRegisterAllocation(graph, codegen->GetCompilerOptions()).Run(); liveness.Analyze(); std::unique_ptr<RegisterAllocator> register_allocator = RegisterAllocator::Create(&local_allocator, codegen, liveness); diff --git a/compiler/optimizing/live_ranges_test.cc b/compiler/optimizing/live_ranges_test.cc index 0fb90fb370..60f513ca48 100644 --- a/compiler/optimizing/live_ranges_test.cc +++ b/compiler/optimizing/live_ranges_test.cc @@ -38,7 +38,7 @@ HGraph* LiveRangesTest::BuildGraph(const std::vector<uint16_t>& data) { // on how instructions are ordered. RemoveSuspendChecks(graph); // `Inline` conditions into ifs. - PrepareForRegisterAllocation(graph).Run(); + PrepareForRegisterAllocation(graph, *compiler_options_).Run(); return graph; } diff --git a/compiler/optimizing/liveness_test.cc b/compiler/optimizing/liveness_test.cc index 72f995e773..f11f7a9779 100644 --- a/compiler/optimizing/liveness_test.cc +++ b/compiler/optimizing/liveness_test.cc @@ -47,7 +47,7 @@ static void DumpBitVector(BitVector* vector, void LivenessTest::TestCode(const std::vector<uint16_t>& data, const char* expected) { HGraph* graph = CreateCFG(data); // `Inline` conditions into ifs. - PrepareForRegisterAllocation(graph).Run(); + PrepareForRegisterAllocation(graph, *compiler_options_).Run(); std::unique_ptr<CodeGenerator> codegen = CodeGenerator::Create(graph, *compiler_options_); SsaLivenessAnalysis liveness(graph, codegen.get(), GetScopedAllocator()); liveness.Analyze(); diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h index 8b9e1da0d3..d88b0364f5 100644 --- a/compiler/optimizing/nodes.h +++ b/compiler/optimizing/nodes.h @@ -2079,6 +2079,19 @@ class HInstruction : public ArenaObject<kArenaAllocInstruction> { return false; } + // If this instruction will do an implicit null check, return the `HNullCheck` associated + // with it. Otherwise return null. + HNullCheck* GetImplicitNullCheck() const { + // Find the first previous instruction which is not a move. + HInstruction* first_prev_not_move = GetPreviousDisregardingMoves(); + if (first_prev_not_move != nullptr && + first_prev_not_move->IsNullCheck() && + first_prev_not_move->IsEmittedAtUseSite()) { + return first_prev_not_move->AsNullCheck(); + } + return nullptr; + } + virtual bool IsActualObject() const { return GetType() == DataType::Type::kReference; } @@ -4713,7 +4726,7 @@ class HInvokeVirtual FINAL : public HInvoke { bool CanDoImplicitNullCheckOn(HInstruction* obj) const OVERRIDE { // TODO: Add implicit null checks in intrinsics. - return (obj == InputAt(0)) && !GetLocations()->Intrinsified(); + return (obj == InputAt(0)) && !IsIntrinsic(); } uint32_t GetVTableIndex() const { return vtable_index_; } @@ -4753,7 +4766,7 @@ class HInvokeInterface FINAL : public HInvoke { bool CanDoImplicitNullCheckOn(HInstruction* obj) const OVERRIDE { // TODO: Add implicit null checks in intrinsics. - return (obj == InputAt(0)) && !GetLocations()->Intrinsified(); + return (obj == InputAt(0)) && !IsIntrinsic(); } bool NeedsDexCacheOfDeclaringClass() const OVERRIDE { diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc index c40cbcf52a..f52b96dac9 100644 --- a/compiler/optimizing/optimizing_compiler.cc +++ b/compiler/optimizing/optimizing_compiler.cc @@ -570,7 +570,7 @@ static void AllocateRegisters(HGraph* graph, { PassScope scope(PrepareForRegisterAllocation::kPrepareForRegisterAllocationPassName, pass_observer); - PrepareForRegisterAllocation(graph, stats).Run(); + PrepareForRegisterAllocation(graph, codegen->GetCompilerOptions(), stats).Run(); } // Use local allocator shared by SSA liveness analysis and register allocator. // (Register allocator creates new objects in the liveness data.) diff --git a/compiler/optimizing/prepare_for_register_allocation.cc b/compiler/optimizing/prepare_for_register_allocation.cc index 060613d349..fc81740013 100644 --- a/compiler/optimizing/prepare_for_register_allocation.cc +++ b/compiler/optimizing/prepare_for_register_allocation.cc @@ -17,6 +17,7 @@ #include "prepare_for_register_allocation.h" #include "dex/dex_file_types.h" +#include "driver/compiler_options.h" #include "jni/jni_internal.h" #include "optimizing_compiler_stats.h" #include "well_known_classes.h" @@ -27,7 +28,7 @@ void PrepareForRegisterAllocation::Run() { // Order does not matter. for (HBasicBlock* block : GetGraph()->GetReversePostOrder()) { // No need to visit the phis. - for (HInstructionIterator inst_it(block->GetInstructions()); !inst_it.Done(); + for (HInstructionIteratorHandleChanges inst_it(block->GetInstructions()); !inst_it.Done(); inst_it.Advance()) { inst_it.Current()->Accept(this); } @@ -50,6 +51,19 @@ void PrepareForRegisterAllocation::VisitInstanceOf(HInstanceOf* instance_of) { void PrepareForRegisterAllocation::VisitNullCheck(HNullCheck* check) { check->ReplaceWith(check->InputAt(0)); + if (compiler_options_.GetImplicitNullChecks()) { + HInstruction* next = check->GetNext(); + + // The `PrepareForRegisterAllocation` pass removes `HBoundType` from the graph, + // so do it ourselves now to not prevent optimizations. + while (next->IsBoundType()) { + next = next->GetNext(); + VisitBoundType(next->GetPrevious()->AsBoundType()); + } + if (next->CanDoImplicitNullCheckOn(check->InputAt(0))) { + check->MarkEmittedAtUseSite(); + } + } } void PrepareForRegisterAllocation::VisitDivZeroCheck(HDivZeroCheck* check) { diff --git a/compiler/optimizing/prepare_for_register_allocation.h b/compiler/optimizing/prepare_for_register_allocation.h index f6e4d3ef99..2978add703 100644 --- a/compiler/optimizing/prepare_for_register_allocation.h +++ b/compiler/optimizing/prepare_for_register_allocation.h @@ -21,6 +21,7 @@ namespace art { +class CompilerOptions; class OptimizingCompilerStats; /** @@ -30,9 +31,11 @@ class OptimizingCompilerStats; */ class PrepareForRegisterAllocation : public HGraphDelegateVisitor { public: - explicit PrepareForRegisterAllocation(HGraph* graph, - OptimizingCompilerStats* stats = nullptr) - : HGraphDelegateVisitor(graph, stats) {} + PrepareForRegisterAllocation(HGraph* graph, + const CompilerOptions& compiler_options, + OptimizingCompilerStats* stats = nullptr) + : HGraphDelegateVisitor(graph, stats), + compiler_options_(compiler_options) {} void Run(); @@ -56,6 +59,8 @@ class PrepareForRegisterAllocation : public HGraphDelegateVisitor { bool CanMoveClinitCheck(HInstruction* input, HInstruction* user) const; bool CanEmitConditionAt(HCondition* condition, HInstruction* user) const; + const CompilerOptions& compiler_options_; + DISALLOW_COPY_AND_ASSIGN(PrepareForRegisterAllocation); }; diff --git a/compiler/optimizing/ssa_liveness_analysis.cc b/compiler/optimizing/ssa_liveness_analysis.cc index 2f782f39fc..62a70d6b12 100644 --- a/compiler/optimizing/ssa_liveness_analysis.cc +++ b/compiler/optimizing/ssa_liveness_analysis.cc @@ -103,9 +103,9 @@ void SsaLivenessAnalysis::ComputeLiveness() { ComputeLiveInAndLiveOutSets(); } -static void RecursivelyProcessInputs(HInstruction* current, - HInstruction* actual_user, - BitVector* live_in) { +void SsaLivenessAnalysis::RecursivelyProcessInputs(HInstruction* current, + HInstruction* actual_user, + BitVector* live_in) { HInputsRef inputs = current->GetInputs(); for (size_t i = 0; i < inputs.size(); ++i) { HInstruction* input = inputs[i]; @@ -131,11 +131,40 @@ static void RecursivelyProcessInputs(HInstruction* current, // Check that the inlined input is not a phi. Recursing on loop phis could // lead to an infinite loop. DCHECK(!input->IsPhi()); + DCHECK(!input->HasEnvironment()); RecursivelyProcessInputs(input, actual_user, live_in); } } } +void SsaLivenessAnalysis::ProcessEnvironment(HInstruction* current, + HInstruction* actual_user, + BitVector* live_in) { + for (HEnvironment* environment = current->GetEnvironment(); + environment != nullptr; + environment = environment->GetParent()) { + // Handle environment uses. See statements (b) and (c) of the + // SsaLivenessAnalysis. + for (size_t i = 0, e = environment->Size(); i < e; ++i) { + HInstruction* instruction = environment->GetInstructionAt(i); + if (instruction == nullptr) { + continue; + } + bool should_be_live = ShouldBeLiveForEnvironment(current, instruction); + // If this environment use does not keep the instruction live, it does not + // affect the live range of that instruction. + if (should_be_live) { + CHECK(instruction->HasSsaIndex()) << instruction->DebugName(); + live_in->SetBit(instruction->GetSsaIndex()); + instruction->GetLiveInterval()->AddUse(current, + environment, + i, + actual_user); + } + } + } +} + void SsaLivenessAnalysis::ComputeLiveRanges() { // Do a post order visit, adding inputs of instructions live in the block where // that instruction is defined, and killing instructions that are being visited. @@ -186,32 +215,6 @@ void SsaLivenessAnalysis::ComputeLiveRanges() { current->GetLiveInterval()->SetFrom(current->GetLifetimePosition()); } - // Process the environment first, because we know their uses come after - // or at the same liveness position of inputs. - for (HEnvironment* environment = current->GetEnvironment(); - environment != nullptr; - environment = environment->GetParent()) { - // Handle environment uses. See statements (b) and (c) of the - // SsaLivenessAnalysis. - for (size_t i = 0, e = environment->Size(); i < e; ++i) { - HInstruction* instruction = environment->GetInstructionAt(i); - if (instruction == nullptr) { - continue; - } - bool should_be_live = ShouldBeLiveForEnvironment(current, instruction); - // If this environment use does not keep the instruction live, it does not - // affect the live range of that instruction. - if (should_be_live) { - CHECK(instruction->HasSsaIndex()) << instruction->DebugName(); - live_in->SetBit(instruction->GetSsaIndex()); - instruction->GetLiveInterval()->AddUse(current, - environment, - i, - /* actual_user */ nullptr); - } - } - } - // Process inputs of instructions. if (current->IsEmittedAtUseSite()) { if (kIsDebugBuild) { @@ -224,6 +227,16 @@ void SsaLivenessAnalysis::ComputeLiveRanges() { DCHECK(!current->HasEnvironmentUses()); } } else { + // Process the environment first, because we know their uses come after + // or at the same liveness position of inputs. + ProcessEnvironment(current, current, live_in); + + // Special case implicit null checks. We want their environment uses to be + // emitted at the instruction doing the actual null check. + HNullCheck* check = current->GetImplicitNullCheck(); + if (check != nullptr) { + ProcessEnvironment(check, current, live_in); + } RecursivelyProcessInputs(current, current, live_in); } } diff --git a/compiler/optimizing/ssa_liveness_analysis.h b/compiler/optimizing/ssa_liveness_analysis.h index 83ca5bd5fa..cebd4adcd8 100644 --- a/compiler/optimizing/ssa_liveness_analysis.h +++ b/compiler/optimizing/ssa_liveness_analysis.h @@ -1252,6 +1252,13 @@ class SsaLivenessAnalysis : public ValueObject { // Update the live_out set of the block and returns whether it has changed. bool UpdateLiveOut(const HBasicBlock& block); + static void ProcessEnvironment(HInstruction* instruction, + HInstruction* actual_user, + BitVector* live_in); + static void RecursivelyProcessInputs(HInstruction* instruction, + HInstruction* actual_user, + BitVector* live_in); + // Returns whether `instruction` in an HEnvironment held by `env_holder` // should be kept live by the HEnvironment. static bool ShouldBeLiveForEnvironment(HInstruction* env_holder, HInstruction* instruction) { diff --git a/test/565-checker-condition-liveness/src/Main.java b/test/565-checker-condition-liveness/src/Main.java index 6b6619fa43..374e136885 100644 --- a/test/565-checker-condition-liveness/src/Main.java +++ b/test/565-checker-condition-liveness/src/Main.java @@ -32,20 +32,20 @@ public class Main { } /// CHECK-START: void Main.testThrowIntoCatchBlock(int, java.lang.Object, int[]) liveness (after) - /// CHECK-DAG: <<IntArg:i\d+>> ParameterValue env_uses:[21,25] - /// CHECK-DAG: <<RefArg:l\d+>> ParameterValue env_uses:[11,21,25] - /// CHECK-DAG: <<Array:l\d+>> ParameterValue env_uses:[11,21,25] - /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 env_uses:[21,25] + /// CHECK-DAG: <<IntArg:i\d+>> ParameterValue env_uses:[25] + /// CHECK-DAG: <<RefArg:l\d+>> ParameterValue env_uses:[11,25] + /// CHECK-DAG: <<Array:l\d+>> ParameterValue env_uses:[11,25] + /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 env_uses:[25] /// CHECK-DAG: SuspendCheck env:[[_,<<IntArg>>,<<RefArg>>,<<Array>>]] liveness:10 /// CHECK-DAG: NullCheck env:[[<<Const1>>,<<IntArg>>,<<RefArg>>,<<Array>>]] liveness:20 /// CHECK-DAG: BoundsCheck env:[[<<Const1>>,<<IntArg>>,<<RefArg>>,<<Array>>]] liveness:24 /// CHECK-DAG: TryBoundary /// CHECK-START-DEBUGGABLE: void Main.testThrowIntoCatchBlock(int, java.lang.Object, int[]) liveness (after) - /// CHECK-DAG: <<IntArg:i\d+>> ParameterValue env_uses:[11,21,25] - /// CHECK-DAG: <<RefArg:l\d+>> ParameterValue env_uses:[11,21,25] - /// CHECK-DAG: <<Array:l\d+>> ParameterValue env_uses:[11,21,25] - /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 env_uses:[21,25] + /// CHECK-DAG: <<IntArg:i\d+>> ParameterValue env_uses:[11,25] + /// CHECK-DAG: <<RefArg:l\d+>> ParameterValue env_uses:[11,25] + /// CHECK-DAG: <<Array:l\d+>> ParameterValue env_uses:[11,25] + /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 env_uses:[25] /// CHECK-DAG: SuspendCheck env:[[_,<<IntArg>>,<<RefArg>>,<<Array>>]] liveness:10 /// CHECK-DAG: NullCheck env:[[<<Const1>>,<<IntArg>>,<<RefArg>>,<<Array>>]] liveness:20 /// CHECK-DAG: BoundsCheck env:[[<<Const1>>,<<IntArg>>,<<RefArg>>,<<Array>>]] liveness:24 @@ -62,18 +62,18 @@ public class Main { /// CHECK-START: void Main.testBoundsCheck(int, java.lang.Object, int[]) liveness (after) /// CHECK-DAG: <<IntArg:i\d+>> ParameterValue env_uses:[] - /// CHECK-DAG: <<RefArg:l\d+>> ParameterValue env_uses:[11,17,21] - /// CHECK-DAG: <<Array:l\d+>> ParameterValue env_uses:[11,17,21] + /// CHECK-DAG: <<RefArg:l\d+>> ParameterValue env_uses:[11,21] + /// CHECK-DAG: <<Array:l\d+>> ParameterValue env_uses:[11,21] /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 env_uses:[] /// CHECK-DAG: SuspendCheck env:[[_,<<IntArg>>,<<RefArg>>,<<Array>>]] liveness:10 /// CHECK-DAG: NullCheck env:[[<<Const1>>,<<IntArg>>,<<RefArg>>,<<Array>>]] liveness:16 /// CHECK-DAG: BoundsCheck env:[[<<Const1>>,<<IntArg>>,<<RefArg>>,<<Array>>]] liveness:20 /// CHECK-START-DEBUGGABLE: void Main.testBoundsCheck(int, java.lang.Object, int[]) liveness (after) - /// CHECK-DAG: <<IntArg:i\d+>> ParameterValue env_uses:[11,17,21] - /// CHECK-DAG: <<RefArg:l\d+>> ParameterValue env_uses:[11,17,21] - /// CHECK-DAG: <<Array:l\d+>> ParameterValue env_uses:[11,17,21] - /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 env_uses:[17,21] + /// CHECK-DAG: <<IntArg:i\d+>> ParameterValue env_uses:[11,21] + /// CHECK-DAG: <<RefArg:l\d+>> ParameterValue env_uses:[11,21] + /// CHECK-DAG: <<Array:l\d+>> ParameterValue env_uses:[11,21] + /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 env_uses:[21] /// CHECK-DAG: SuspendCheck env:[[_,<<IntArg>>,<<RefArg>>,<<Array>>]] liveness:10 /// CHECK-DAG: NullCheck env:[[<<Const1>>,<<IntArg>>,<<RefArg>>,<<Array>>]] liveness:16 /// CHECK-DAG: BoundsCheck env:[[<<Const1>>,<<IntArg>>,<<RefArg>>,<<Array>>]] liveness:20 @@ -83,20 +83,22 @@ public class Main { /// CHECK-START: void Main.testDeoptimize(int, java.lang.Object, int[]) liveness (after) /// CHECK-DAG: <<IntArg:i\d+>> ParameterValue env_uses:[25] - /// CHECK-DAG: <<RefArg:l\d+>> ParameterValue env_uses:[13,19,25] - /// CHECK-DAG: <<Array:l\d+>> ParameterValue env_uses:[13,19,25] + /// CHECK-DAG: <<RefArg:l\d+>> ParameterValue env_uses:[13,21,25] + /// CHECK-DAG: <<Array:l\d+>> ParameterValue env_uses:[13,21,25] /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0 env_uses:[25] /// CHECK-DAG: SuspendCheck env:[[_,<<IntArg>>,<<RefArg>>,<<Array>>]] liveness:12 /// CHECK-DAG: NullCheck env:[[<<Const0>>,<<IntArg>>,<<RefArg>>,<<Array>>]] liveness:18 + /// CHECK-DAG: ArrayLength liveness:20 /// CHECK-DAG: Deoptimize env:[[<<Const0>>,<<IntArg>>,<<RefArg>>,<<Array>>]] liveness:24 /// CHECK-START-DEBUGGABLE: void Main.testDeoptimize(int, java.lang.Object, int[]) liveness (after) - /// CHECK-DAG: <<IntArg:i\d+>> ParameterValue env_uses:[13,19,25] - /// CHECK-DAG: <<RefArg:l\d+>> ParameterValue env_uses:[13,19,25] - /// CHECK-DAG: <<Array:l\d+>> ParameterValue env_uses:[13,19,25] + /// CHECK-DAG: <<IntArg:i\d+>> ParameterValue env_uses:[13,21,25] + /// CHECK-DAG: <<RefArg:l\d+>> ParameterValue env_uses:[13,21,25] + /// CHECK-DAG: <<Array:l\d+>> ParameterValue env_uses:[13,21,25] /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0 env_uses:[19,25] /// CHECK-DAG: SuspendCheck env:[[_,<<IntArg>>,<<RefArg>>,<<Array>>]] liveness:12 /// CHECK-DAG: NullCheck env:[[<<Const0>>,<<IntArg>>,<<RefArg>>,<<Array>>]] liveness:18 + /// CHECK-DAG: ArrayLength liveness:20 /// CHECK-DAG: Deoptimize env:[[<<Const0>>,<<IntArg>>,<<RefArg>>,<<Array>>]] liveness:24 // // A value that's not live in compiled code may still be needed in interpreter, diff --git a/test/knownfailures.json b/test/knownfailures.json index 7322a35884..9378bffbcb 100644 --- a/test/knownfailures.json +++ b/test/knownfailures.json @@ -1038,12 +1038,6 @@ "description": ["Test timing out under gcstress possibly due to slower unwinding by libbacktrace"] }, { - "tests": ["624-checker-stringops"], - "variant": "optimizing & gcstress | speed-profile & gcstress", - "bug": "b/111545159", - "description": ["Seem to expose some error with our gc when run in these configurations"] - }, - { "tests": ["021-string2"], "variant": "jit & debuggable", "bug": "b/109791792", diff --git a/tools/libcore_gcstress_failures.txt b/tools/libcore_gcstress_failures.txt index 6840f9ebec..965e85c359 100644 --- a/tools/libcore_gcstress_failures.txt +++ b/tools/libcore_gcstress_failures.txt @@ -33,15 +33,5 @@ "org.apache.harmony.tests.java.util.WeakHashMapTest#test_keySet_hasNext", "libcore.java.text.DecimalFormatTest#testCurrencySymbolSpacing", "libcore.java.text.SimpleDateFormatTest#testLocales"] -}, -{ - description: "GC crash", - result: EXEC_FAILED, - bug: 111545159, - names: ["org.apache.harmony.tests.java.util.AbstractSequentialListTest#test_addAllILjava_util_Collection", - "org.apache.harmony.tests.java.util.HashtableTest#test_putLjava_lang_ObjectLjava_lang_Object", - "org.apache.harmony.tests.java.util.VectorTest#test_addAllILjava_util_Collection", - "org.apache.harmony.tests.java.util.VectorTest#test_addAllLjava_util_Collection", - "org.apache.harmony.tests.java.io.BufferedWriterTest#test_write_LStringII_Exception"] } ] |
