Skip to content

Commit

Permalink
promote D56091747 and D64742493
Browse files Browse the repository at this point in the history
Reviewed By: NTillmann

Differential Revision: D64794973

fbshipit-source-id: 975ac534da23a6e1ad0ee8198afc98701862b860
  • Loading branch information
ssj933 authored and facebook-github-bot committed Oct 23, 2024
1 parent 866de88 commit 3acdd3e
Show file tree
Hide file tree
Showing 39 changed files with 1,466 additions and 50 deletions.
4 changes: 3 additions & 1 deletion Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ libredex_la_SOURCES = \
checkers/NoInitClassInstructionsChecker.cpp \
checkers/NoResolvablePureRefsChecker.cpp \
checkers/NoUnreachableInstructionsChecker.cpp \
checkers/NoWriteBarrierInstructionsChecker.cpp \
liblocator/locator.cpp \
libredex/AggregateException.cpp \
libredex/AnalysisUsage.cpp \
Expand Down Expand Up @@ -528,7 +529,8 @@ libopt_la_SOURCES = \
opt/virtual_merging/DedupVirtualMethods.cpp \
opt/virtual_merging/VirtualMerging.cpp \
opt/virtual_scope/MethodDevirtualizationPass.cpp \
opt/wrapped-primitives/WrappedPrimitivesPass.cpp
opt/wrapped-primitives/WrappedPrimitivesPass.cpp \
opt/write_barrier/WriteBarrierLoweringPass.cpp

libopt_la_LIBADD = \
libredex.la \
Expand Down
36 changes: 36 additions & 0 deletions checkers/NoWriteBarrierInstructionsChecker.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

#include "NoWriteBarrierInstructionsChecker.h"

#include "Debug.h"
#include "DexClass.h"
#include "Show.h"
#include "Walkers.h"

namespace redex_properties {

void NoWriteBarrierInstructionsChecker::run_checker(DexStoresVector& stores,
ConfigFiles& /* conf */,
PassManager& /*mgr*/,
bool established) {
if (!established) {
return;
}
const auto& scope = build_class_scope(stores);
walk::parallel::opcodes(scope, [&](DexMethod* method, IRInstruction* insn) {
always_assert_log(!opcode::is_write_barrier(insn->opcode()),
"[%s] %s contains write barrier instruction!\n {%s}",
get_name(get_property()), SHOW(method), SHOW(insn));
});
}

} // namespace redex_properties

namespace {
static redex_properties::NoWriteBarrierInstructionsChecker s_checker;
} // namespace
22 changes: 22 additions & 0 deletions checkers/NoWriteBarrierInstructionsChecker.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

#pragma once

#include "RedexPropertyChecker.h"

namespace redex_properties {

class NoWriteBarrierInstructionsChecker : public PropertyChecker {
public:
NoWriteBarrierInstructionsChecker()
: PropertyChecker(names::NoWriteBarrierInstructions) {}

void run_checker(DexStoresVector&, ConfigFiles&, PassManager&, bool) override;
};

} // namespace redex_properties
2 changes: 2 additions & 0 deletions libredex/ConfigFiles.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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("unfinalize_relaxed_init_inline", false,
inliner_config->unfinalize_relaxed_init_inline);
jw.get("strict_throwable_init_inline", false,
inliner_config->strict_throwable_init_inline);
jw.get("throws", false, inliner_config->throws_inline);
Expand Down
8 changes: 7 additions & 1 deletion libredex/DexOutput.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -152,9 +152,15 @@ std::vector<DexMethod*> GatheredTypes::get_dexmethod_emitlist() {
TRACE(OPUT, 3, " [dexmethod_emitlist][dmethod] %s", dmeth->c_str());
}
for (const auto& vmeth : vmethods) {
TRACE(OPUT, 3, " [dexmethod_emitlist][dmethod] %s", vmeth->c_str());
TRACE(OPUT, 3, " [dexmethod_emitlist][vmethod] %s", vmeth->c_str());
}
}
for (auto* m : dmethods) {
always_assert(!m->is_external());
}
for (auto* m : vmethods) {
always_assert(!m->is_external());
}
methlist.insert(methlist.end(), dmethods.begin(), dmethods.end());
methlist.insert(methlist.end(), vmethods.begin(), vmethods.end());
}
Expand Down
2 changes: 2 additions & 0 deletions libredex/GlobalConfig.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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("unfinalize_relaxed_init_inline", unfinalize_relaxed_init_inline,
unfinalize_relaxed_init_inline);
bind("strict_throwable_init_inline", strict_throwable_init_inline,
strict_throwable_init_inline);
bind("intermediate_shrinking", intermediate_shrinking,
Expand Down
3 changes: 3 additions & 0 deletions libredex/IRInstruction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,9 @@ IRInstruction* IRInstruction::set_srcs_size(size_t count) {

uint16_t IRInstruction::size() const {
auto op = m_opcode;
if (opcode::is_write_barrier(op)) {
op = OPCODE_INVOKE_STATIC;
}
if (opcode::is_an_internal(op)) {
return opcode::is_injection_id(op) ? 2 : opcode::is_unreachable(op) ? 1 : 0;
}
Expand Down
4 changes: 3 additions & 1 deletion libredex/IROpcode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -875,6 +875,7 @@ bool may_throw(IROpcode op) {
case OPCODE_CONST_STRING:
case OPCODE_CONST_CLASS:
case IOPCODE_INIT_CLASS:
case IOPCODE_WRITE_BARRIER:
case OPCODE_MONITOR_ENTER:
case OPCODE_MONITOR_EXIT:
case OPCODE_CHECK_CAST:
Expand Down Expand Up @@ -1378,6 +1379,7 @@ bool has_side_effects(IROpcode opc) {
case IOPCODE_LOAD_PARAM_OBJECT:
case IOPCODE_LOAD_PARAM_WIDE:
case IOPCODE_INIT_CLASS:
case IOPCODE_WRITE_BARRIER:
return true;
default:
return false;
Expand All @@ -1391,7 +1393,7 @@ namespace opcode_impl {

bool has_dest(IROpcode op) {
if (opcode::is_an_internal(op)) {
return op != IOPCODE_INIT_CLASS;
return op != IOPCODE_INIT_CLASS && op != IOPCODE_WRITE_BARRIER;
} else {
auto dex_op = opcode::to_dex_opcode(op);
return !opcode::may_throw(op) && dex_opcode::has_dest(dex_op);
Expand Down
3 changes: 2 additions & 1 deletion libredex/IROpcodes.def
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ OP(CONST_METHOD_HANDLE , const_method_handle , Ref::MethodHandle, "
OP(CONST_METHOD_TYPE , const_method_type , Ref::Proto, "const-method-type")

// Internal opcodes cannot be mapped to a corresponding DexOpcode.
OPRANGE(an_internal , IOPCODE_LOAD_PARAM, IOPCODE_UNREACHABLE)
OPRANGE(an_internal , IOPCODE_LOAD_PARAM, IOPCODE_WRITE_BARRIER)
OPRANGE(a_load_param, IOPCODE_LOAD_PARAM, IOPCODE_LOAD_PARAM_WIDE)
IOP(LOAD_PARAM , load_param , Ref::None, "load-param")
IOP(LOAD_PARAM_OBJECT , load_param_object , Ref::None, "load-param-object")
Expand All @@ -239,6 +239,7 @@ IOP(MOVE_RESULT_PSEUDO_WIDE , move_result_pseudo_wide , Ref::None, "move-res
IOP(INIT_CLASS , init_class , Ref::Type, "init-class")
IOP(INJECTION_ID , injection_id , Ref::Literal, "injection-id")
IOP(UNREACHABLE , unreachable , Ref::None, "unreachable")
IOP(WRITE_BARRIER , write_barrier , Ref::None, "write-barrier")

// clang-format on

Expand Down
3 changes: 2 additions & 1 deletion libredex/IRTypeChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1610,7 +1610,8 @@ void IRTypeChecker::check_instruction(IRInstruction* insn,
}
case IOPCODE_INIT_CLASS:
case IOPCODE_INJECTION_ID:
case IOPCODE_UNREACHABLE: {
case IOPCODE_UNREACHABLE:
case IOPCODE_WRITE_BARRIER: {
break;
}
}
Expand Down
1 change: 1 addition & 0 deletions libredex/InlinerConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ struct InlinerConfig {
bool virtual_inline{true};
bool true_virtual_inline{false};
bool relaxed_init_inline{false};
bool unfinalize_relaxed_init_inline{false};
bool strict_throwable_init_inline{false};
bool throws_inline{false};
bool throw_after_no_return{false};
Expand Down
6 changes: 5 additions & 1 deletion libredex/InstructionAnalyzer.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,8 @@
X(binop_lit) \
X(init_class) \
X(injection_id) \
X(unreachable)
X(unreachable) \
X(write_barrier)

/* clang-format on */

Expand Down Expand Up @@ -401,6 +402,9 @@ class InstructionAnalyzerCombiner final {
case IOPCODE_UNREACHABLE:
return analyze_unreachable(
std::index_sequence_for<Analyzers...>{}, insn, env);
case IOPCODE_WRITE_BARRIER:
return analyze_write_barrier(
std::index_sequence_for<Analyzers...>{}, insn, env);
}
}

Expand Down
3 changes: 3 additions & 0 deletions libredex/InstructionLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,9 @@ DexInstruction* create_dex_instruction(const IRInstruction* insn) {
if (insn->opcode() == IOPCODE_UNREACHABLE) {
return new DexInstruction(DOPCODE_CONST);
}
if (insn->opcode() == IOPCODE_WRITE_BARRIER) {
always_assert(false);
}

auto op = opcode::to_dex_opcode(insn->opcode());
switch (opcode::ref(insn->opcode())) {
Expand Down
3 changes: 3 additions & 0 deletions libredex/Purity.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -890,6 +890,9 @@ static size_t analyze_read_locations(
case IOPCODE_INIT_CLASS:
unknown = true;
break;
case IOPCODE_WRITE_BARRIER:
unknown = true;
break;
case OPCODE_NEW_INSTANCE:
if (for_conditional_purity ||
!clinit_has_no_side_effects(insn->get_type())) {
Expand Down
1 change: 1 addition & 0 deletions libredex/RedexProperties.def
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ REDEX_PROPS(NoInitClassInstructions, false, true, true,
REDEX_PROPS(NoResolvablePureRefs, false, false, false, false)
REDEX_PROPS(NoSpuriousGetClassCalls, false, false, false, false)
REDEX_PROPS(NoUnreachableInstructions, false, true, true, false)
REDEX_PROPS(NoWriteBarrierInstructions, false, true, true, true)
REDEX_PROPS(RenameClass, false, false, false, false)
REDEX_PROPS(MethodRegister, false, false, true, true)
// This is different from above because it is only a marker that signals interning happened,
Expand Down
3 changes: 2 additions & 1 deletion libredex/TypeInference.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1556,7 +1556,8 @@ void TypeInference::analyze_instruction(const IRInstruction* insn,
set_int(current_state, RESULT_REGISTER);
break;
}
case IOPCODE_INIT_CLASS: {
case IOPCODE_INIT_CLASS:
case IOPCODE_WRITE_BARRIER: {
break;
}
}
Expand Down
1 change: 1 addition & 0 deletions opt/methodinline/BridgeSynthInlinePass.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ class BridgeSynthInlinePass : public Pass {
// This may be too conservative as the inliner can be configured not to
// DCE in the shrinker.
{SpuriousGetClassCallsInterned, RequiresAndPreserves},
{NoWriteBarrierInstructions, Destroys},
};
}

Expand Down
1 change: 1 addition & 0 deletions opt/methodinline/IntraDexInlinePass.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ class IntraDexInlinePass : public Pass {
// to DCE in the shrinker.
{SpuriousGetClassCallsInterned, RequiresAndPreserves},
{InitialRenameClass, Preserves},
{NoWriteBarrierInstructions, Destroys},
};
}

Expand Down
1 change: 1 addition & 0 deletions opt/methodinline/LocalMethodInlinePass.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ class LocalMethodInlinePass : public Pass {
// This may be too conservative as the inliner can be configured not to
// DCE in the shrinker.
{SpuriousGetClassCallsInterned, RequiresAndPreserves},
{NoWriteBarrierInstructions, Destroys},
};
}

Expand Down
1 change: 1 addition & 0 deletions opt/methodinline/MethodInlinePass.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ class MethodInlinePass : public Pass {
// This may be too conservative as the inliner can be configured not to
// DCE in the shrinker.
{SpuriousGetClassCallsInterned, RequiresAndPreserves},
{NoWriteBarrierInstructions, Destroys},
};
}

Expand Down
1 change: 1 addition & 0 deletions opt/methodinline/PerfMethodInlinePass.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ class PerfMethodInlinePass : public Pass {
// DCE in the shrinker.
{SpuriousGetClassCallsInterned, RequiresAndPreserves},
{InitialRenameClass, Preserves},
{NoWriteBarrierInstructions, Destroys},
};
}

Expand Down
2 changes: 2 additions & 0 deletions opt/outliner/OutlinerTypeAnalysis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,7 @@ const DexType* OutlinerTypeAnalysis::get_result_type_helper(
case OPCODE_THROW:
case IOPCODE_INIT_CLASS:
case IOPCODE_INJECTION_ID:
case IOPCODE_WRITE_BARRIER:
not_reached();

case OPCODE_MOVE_EXCEPTION:
Expand Down Expand Up @@ -489,6 +490,7 @@ const DexType* OutlinerTypeAnalysis::get_type_demand(IRInstruction* insn,
case IOPCODE_INIT_CLASS:
case IOPCODE_INJECTION_ID:
case IOPCODE_UNREACHABLE:
case IOPCODE_WRITE_BARRIER:
not_reached();

case OPCODE_RETURN:
Expand Down
Loading

0 comments on commit 3acdd3e

Please sign in to comment.