diff --git a/libredex/ConfigFiles.cpp b/libredex/ConfigFiles.cpp index 4745917621..eb2cee0ed2 100644 --- a/libredex/ConfigFiles.cpp +++ b/libredex/ConfigFiles.cpp @@ -490,6 +490,8 @@ void ConfigFiles::load_inliner_config(inliner::InlinerConfig* inliner_config) { jw.get("virtual", true, inliner_config->virtual_inline); jw.get("true_virtual_inline", false, inliner_config->true_virtual_inline); jw.get("relaxed_init_inline", false, inliner_config->relaxed_init_inline); + jw.get("strict_throwable_init_inline", false, + inliner_config->strict_throwable_init_inline); jw.get("throws", false, inliner_config->throws_inline); jw.get("throw_after_no_return", false, inliner_config->throw_after_no_return); jw.get("max_cost_for_constant_propagation", diff --git a/libredex/GlobalConfig.cpp b/libredex/GlobalConfig.cpp index e4ebe9ddad..aac35762b9 100644 --- a/libredex/GlobalConfig.cpp +++ b/libredex/GlobalConfig.cpp @@ -11,6 +11,8 @@ void InlinerConfig::bind_config() { bind("delete_non_virtuals", delete_non_virtuals, delete_non_virtuals); bind("true_virtual_inline", true_virtual_inline, true_virtual_inline); bind("relaxed_init_inline", relaxed_init_inline, relaxed_init_inline); + bind("strict_throwable_init_inline", strict_throwable_init_inline, + strict_throwable_init_inline); bind("intermediate_shrinking", intermediate_shrinking, intermediate_shrinking); bind("enforce_method_size_limit", enforce_method_size_limit, diff --git a/libredex/InlinerConfig.h b/libredex/InlinerConfig.h index 83513375f3..6f26e9ca9b 100644 --- a/libredex/InlinerConfig.h +++ b/libredex/InlinerConfig.h @@ -25,6 +25,7 @@ struct InlinerConfig { bool virtual_inline{true}; bool true_virtual_inline{false}; bool relaxed_init_inline{false}; + bool strict_throwable_init_inline{false}; bool throws_inline{false}; bool throw_after_no_return{false}; bool enforce_method_size_limit{true}; diff --git a/service/method-inliner/Inliner.cpp b/service/method-inliner/Inliner.cpp index 1964090103..703715543f 100644 --- a/service/method-inliner/Inliner.cpp +++ b/service/method-inliner/Inliner.cpp @@ -1680,11 +1680,19 @@ bool MultiMethodInliner::can_inline_init(const DexMethod* init_method) { // TODO T184662680: While this is not a correctness issue, // we should fully support relaxed init methods in // class-merging. - bool relaxed = m_config.relaxed_init_inline && - m_shrinker.min_sdk() >= 21 && - !klass::maybe_anonymous_class( - type_class(init_method->get_class())) && - !is_finalizable(init_method->get_class()); + + // We also don't want to inline constructors of throwable + // (exception, error) classes, as they capture the current + // stack trace in a way that is sensitive to inlining. + bool relaxed = + m_config.relaxed_init_inline && + m_shrinker.min_sdk() >= 21 && + !klass::maybe_anonymous_class( + type_class(init_method->get_class())) && + !is_finalizable(init_method->get_class()) && + (!m_config.strict_throwable_init_inline || + !type::check_cast(init_method->get_class(), + type::java_lang_Throwable())); return constructor_analysis::can_inline_init( init_method, finalizable_fields, relaxed); })