diff options
Diffstat (limited to 'compiler/optimizing')
| -rw-r--r-- | compiler/optimizing/inliner.cc | 16 | ||||
| -rw-r--r-- | compiler/optimizing/nodes.h | 16 | ||||
| -rw-r--r-- | compiler/optimizing/optimizing_compiler.cc | 33 | ||||
| -rw-r--r-- | compiler/optimizing/ssa_liveness_analysis.h | 10 |
4 files changed, 64 insertions, 11 deletions
diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc index 8440e9aa4c..96d6d2a1ae 100644 --- a/compiler/optimizing/inliner.cc +++ b/compiler/optimizing/inliner.cc @@ -1789,6 +1789,14 @@ bool HInliner::TryBuildAndInlineHelper(HInvoke* invoke_instruction, invoke_type = kVirtual; } + bool caller_dead_reference_safe = graph_->IsDeadReferenceSafe(); + const dex::ClassDef& callee_class = resolved_method->GetClassDef(); + // MethodContainsRSensitiveAccess is currently slow, but HasDeadReferenceSafeAnnotation() + // is currently rarely true. + bool callee_dead_reference_safe = + annotations::HasDeadReferenceSafeAnnotation(callee_dex_file, callee_class) + && !annotations::MethodContainsRSensitiveAccess(callee_dex_file, callee_class, method_index); + const int32_t caller_instruction_counter = graph_->GetCurrentInstructionId(); HGraph* callee_graph = new (graph_->GetAllocator()) HGraph( graph_->GetAllocator(), @@ -1797,6 +1805,7 @@ bool HInliner::TryBuildAndInlineHelper(HInvoke* invoke_instruction, method_index, codegen_->GetCompilerOptions().GetInstructionSet(), invoke_type, + callee_dead_reference_safe, graph_->IsDebuggable(), /* osr= */ false, caller_instruction_counter); @@ -2023,6 +2032,13 @@ bool HInliner::TryBuildAndInlineHelper(HInvoke* invoke_instruction, inline_stats_->AddTo(stats_); } + if (caller_dead_reference_safe && !callee_dead_reference_safe) { + // Caller was dead reference safe, but is not anymore, since we inlined dead + // reference unsafe code. Prior transformations remain valid, since they did not + // affect the inlined code. + graph_->MarkDeadReferenceUnsafe(); + } + return true; } diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h index 48fb611da2..c70674b0ad 100644 --- a/compiler/optimizing/nodes.h +++ b/compiler/optimizing/nodes.h @@ -317,6 +317,7 @@ class HGraph : public ArenaObject<kArenaAllocGraph> { uint32_t method_idx, InstructionSet instruction_set, InvokeType invoke_type = kInvalidInvokeType, + bool dead_reference_safe = false, bool debuggable = false, bool osr = false, int start_instruction_id = 0) @@ -336,6 +337,7 @@ class HGraph : public ArenaObject<kArenaAllocGraph> { has_simd_(false), has_loops_(false), has_irreducible_loops_(false), + dead_reference_safe_(dead_reference_safe), debuggable_(debuggable), current_instruction_id_(start_instruction_id), dex_file_(dex_file), @@ -526,6 +528,12 @@ class HGraph : public ArenaObject<kArenaAllocGraph> { has_bounds_checks_ = value; } + // Is the code known to be robust against eliminating dead references + // and the effects of early finalization? + bool IsDeadReferenceSafe() const { return dead_reference_safe_; } + + void MarkDeadReferenceUnsafe() { dead_reference_safe_ = false; } + bool IsDebuggable() const { return debuggable_; } // Returns a constant of the given type and value. If it does not exist @@ -704,6 +712,14 @@ class HGraph : public ArenaObject<kArenaAllocGraph> { // so there might be false positives. bool has_irreducible_loops_; + // Is the code known to be robust against eliminating dead references + // and the effects of early finalization? If false, dead reference variables + // are kept if they might be visible to the garbage collector. + // Currently this means that the class was declared to be dead-reference-safe, + // the method accesses no reachability-sensitive fields or data, and the same + // is true for any methods that were inlined into the current one. + bool dead_reference_safe_; + // Indicates whether the graph should be compiled in a way that // ensures full debuggability. If false, we can apply more // aggressive optimizations that may limit the level of debugging. diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc index 42dbc77087..e8f8d32525 100644 --- a/compiler/optimizing/optimizing_compiler.cc +++ b/compiler/optimizing/optimizing_compiler.cc @@ -828,6 +828,29 @@ CodeGenerator* OptimizingCompiler::TryCompile(ArenaAllocator* allocator, } CodeItemDebugInfoAccessor code_item_accessor(dex_file, code_item, method_idx); + + bool dead_reference_safe; + ArrayRef<const uint8_t> interpreter_metadata; + // For AOT compilation, we may not get a method, for example if its class is erroneous, + // possibly due to an unavailable superclass. JIT should always have a method. + DCHECK(Runtime::Current()->IsAotCompiler() || method != nullptr); + if (method != nullptr) { + const dex::ClassDef* containing_class; + { + ScopedObjectAccess soa(Thread::Current()); + containing_class = &method->GetClassDef(); + interpreter_metadata = method->GetQuickenedInfo(); + } + // MethodContainsRSensitiveAccess is currently slow, but HasDeadReferenceSafeAnnotation() + // is currently rarely true. + dead_reference_safe = + annotations::HasDeadReferenceSafeAnnotation(dex_file, *containing_class) + && !annotations::MethodContainsRSensitiveAccess(dex_file, *containing_class, method_idx); + } else { + // If we could not resolve the class, conservatively assume it's dead-reference unsafe. + dead_reference_safe = false; + } + HGraph* graph = new (allocator) HGraph( allocator, arena_stack, @@ -835,17 +858,12 @@ CodeGenerator* OptimizingCompiler::TryCompile(ArenaAllocator* allocator, method_idx, compiler_options.GetInstructionSet(), kInvalidInvokeType, + dead_reference_safe, compiler_driver->GetCompilerOptions().GetDebuggable(), - osr); + /* osr= */ osr); - ArrayRef<const uint8_t> interpreter_metadata; - // For AOT compilation, we may not get a method, for example if its class is erroneous. - // JIT should always have a method. - DCHECK(Runtime::Current()->IsAotCompiler() || method != nullptr); if (method != nullptr) { graph->SetArtMethod(method); - ScopedObjectAccess soa(Thread::Current()); - interpreter_metadata = method->GetQuickenedInfo(); } std::unique_ptr<CodeGenerator> codegen( @@ -963,6 +981,7 @@ CodeGenerator* OptimizingCompiler::TryCompileIntrinsic( method_idx, compiler_options.GetInstructionSet(), kInvalidInvokeType, + /* dead_reference_safe= */ true, // Intrinsics don't affect dead reference safety. compiler_options.GetDebuggable(), /* osr= */ false); diff --git a/compiler/optimizing/ssa_liveness_analysis.h b/compiler/optimizing/ssa_liveness_analysis.h index 92d0b08301..c88390775c 100644 --- a/compiler/optimizing/ssa_liveness_analysis.h +++ b/compiler/optimizing/ssa_liveness_analysis.h @@ -1155,10 +1155,11 @@ class LiveInterval : public ArenaObject<kArenaAllocSsaLiveness> { * * (a) Non-environment uses of an instruction always make * the instruction live. - * (b) Environment uses of an instruction whose type is - * object (that is, non-primitive), make the instruction live. - * This is due to having to keep alive objects that have - * finalizers deleting native objects. + * (b) Environment uses of an instruction whose type is object (that is, non-primitive), make the + * instruction live, unless the class has an @DeadReferenceSafe annotation. + * This avoids unexpected premature reference enqueuing or finalization, which could + * result in premature deletion of native objects. In the presence of @DeadReferenceSafe, + * object references are treated like primitive types. * (c) When the graph has the debuggable property, environment uses * of an instruction that has a primitive type make the instruction live. * If the graph does not have the debuggable property, the environment @@ -1287,6 +1288,7 @@ class SsaLivenessAnalysis : public ValueObject { // When compiling in OSR mode, all loops in the compiled method may be entered // from the interpreter via SuspendCheck; thus we need to preserve the environment. if (env_holder->IsSuspendCheck() && graph->IsCompilingOsr()) return true; + if (graph -> IsDeadReferenceSafe()) return false; return instruction->GetType() == DataType::Type::kReference; } |