libredex/MethodUtil.cpp (516 lines of code) (raw):
/*
* 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 "MethodUtil.h"
#include "ControlFlow.h"
#include "EditableCfgAdapter.h"
#include "Resolver.h"
#include "TypeUtil.h"
namespace {
class ClInitSideEffectsAnalysis {
private:
const method::ClInitHasNoSideEffectsPredicate* m_clinit_has_no_side_effects;
const std::unordered_set<DexMethod*>* m_non_true_virtuals;
std::unordered_set<DexMethodRef*> m_active;
std::unordered_set<DexType*> m_initialized;
public:
explicit ClInitSideEffectsAnalysis(
const method::ClInitHasNoSideEffectsPredicate* clinit_has_no_side_effects,
const std::unordered_set<DexMethod*>* non_true_virtuals)
: m_clinit_has_no_side_effects(clinit_has_no_side_effects),
m_non_true_virtuals(non_true_virtuals) {}
const DexClass* run(const DexClass* cls) {
std::stack<const DexClass*> stack;
for (; cls && !cls->is_external();
cls = type_class(cls->get_super_class())) {
stack.push(cls);
}
const DexClass* last_cls = nullptr;
while (!stack.empty()) {
cls = stack.top();
stack.pop();
m_initialized.insert(cls->get_type());
if (cls->rstate.clinit_has_no_side_effects() ||
clinit_has_no_side_effects(cls->get_type())) {
always_assert(!last_cls);
continue;
}
auto clinit = cls->get_clinit();
if (clinit && method_may_have_side_effects(clinit, clinit)) {
last_cls = cls;
}
}
always_assert(m_active.empty());
return last_cls;
}
private:
bool clinit_has_no_side_effects(DexType* type) {
return m_clinit_has_no_side_effects &&
(*m_clinit_has_no_side_effects)(type);
}
bool init_class_or_new_instance_may_have_side_effects(DexType* type) {
return !clinit_has_no_side_effects(type) &&
type != type::java_lang_Object() && !m_initialized.count(type);
}
bool field_op_may_have_side_effects(DexMethod* effective_caller,
IRInstruction* insn) {
auto field = insn->get_field();
if (opcode::is_an_iget(insn->opcode())) {
return false;
} else if (opcode::is_an_iput(insn->opcode())) {
return !method::is_init(effective_caller) ||
!type::is_subclass(field->get_class(),
effective_caller->get_class());
} else if (opcode::is_an_sget(insn->opcode())) {
return init_class_or_new_instance_may_have_side_effects(
field->get_class());
} else {
always_assert(opcode::is_an_sput(insn->opcode()));
return !method::is_clinit(effective_caller) ||
field->get_class() != effective_caller->get_class();
}
}
bool invoke_may_have_side_effects(DexMethod* effective_caller,
IRInstruction* insn) {
auto method_ref = insn->get_method();
if (method::is_clinit_invoked_method_benign(method_ref)) {
return false;
}
if (opcode::is_invoke_interface(insn->opcode()) ||
opcode::is_invoke_super(insn->opcode())) {
return true;
}
always_assert(opcode::is_invoke_direct(insn->opcode()) ||
opcode::is_invoke_virtual(insn->opcode()) ||
opcode::is_invoke_static(insn->opcode()));
auto method = resolve_method(method_ref, opcode_to_search(insn));
if (!method) {
return true;
}
if (opcode::is_invoke_virtual(insn->opcode()) &&
(!m_non_true_virtuals || !m_non_true_virtuals->count(method))) {
return true;
}
if (opcode::is_invoke_static(insn->opcode()) &&
init_class_or_new_instance_may_have_side_effects(method->get_class())) {
return true;
}
if (method::is_init(method)) {
effective_caller = method;
}
return method_may_have_side_effects(effective_caller, method);
}
bool method_may_have_side_effects(DexMethod* effective_caller,
DexMethod* method) {
always_assert(method::is_init(effective_caller) ||
method::is_clinit(effective_caller));
if (method->is_external() || !method->get_code()) {
return true;
}
if (!m_active.insert(method).second) {
// recursion
return true;
}
bool non_trivial = false;
editable_cfg_adapter::iterate_with_iterator(
method->get_code(), [&](const IRList::iterator& it) {
auto insn = it->insn;
if (opcode::is_an_invoke(insn->opcode())) {
if (invoke_may_have_side_effects(effective_caller, insn)) {
non_trivial = true;
return editable_cfg_adapter::LOOP_BREAK;
}
} else if (insn->opcode() == IOPCODE_INIT_CLASS ||
insn->opcode() == OPCODE_NEW_INSTANCE) {
if (init_class_or_new_instance_may_have_side_effects(
insn->get_type())) {
non_trivial = true;
return editable_cfg_adapter::LOOP_BREAK;
}
} else if (insn->has_field()) {
if (field_op_may_have_side_effects(effective_caller, insn)) {
non_trivial = true;
return editable_cfg_adapter::LOOP_BREAK;
}
}
return editable_cfg_adapter::LOOP_CONTINUE;
});
auto erased = m_active.erase(method);
always_assert(erased);
return non_trivial;
}
};
} // namespace
namespace method {
bool is_init(const DexMethodRef* method) {
return strcmp(method->get_name()->c_str(), "<init>") == 0;
}
bool is_clinit(const DexMethodRef* method) {
return strcmp(method->get_name()->c_str(), "<clinit>") == 0;
}
bool is_trivial_clinit(const IRCode& code) {
always_assert(!code.editable_cfg_built());
auto ii = InstructionIterable(code);
return std::none_of(ii.begin(), ii.end(), [](const MethodItemEntry& mie) {
return mie.insn->opcode() != OPCODE_RETURN_VOID;
});
}
bool is_clinit_invoked_method_benign(const DexMethodRef* method_ref) {
const auto& type_name = method_ref->get_class()->str();
if (strcmp(type_name.c_str(), "Lcom/redex/OutlinedStringBuilders;") == 0) {
return true;
}
const auto& name = method_ref->get_name()->str();
if (strcmp(name.c_str(), "clone") == 0 ||
strcmp(name.c_str(), "concat") == 0 ||
strcmp(name.c_str(), "append") == 0) {
return true;
}
static const std::unordered_set<std::string> methods = {
// clang-format off
"Landroid/content/Context;.getApplicationContext:()Landroid/content/Context;",
"Landroid/content/Context;.getApplicationInfo:()Landroid/content/pm/ApplicationInfo;",
"Landroid/content/Context;.getCacheDir:()Ljava/io/File;",
"Landroid/content/Context;.getPackageName:()Ljava/lang/String;",
"Landroid/content/ContextWrapper;.getApplicationContext:()Landroid/content/Context;",
"Landroid/graphics/Color;.rgb:(III)I",
"Landroid/graphics/Path;.<init>:()V",
"Landroid/graphics/PointF;.<init>:(FF)V",
"Landroid/graphics/Rect;.<init>:()V",
"Landroid/net/Uri$Builder;.appendPath:(Ljava/lang/String;)Landroid/net/Uri$Builder;",
"Landroid/net/Uri$Builder;.build:()Landroid/net/Uri;",
"Landroid/net/Uri;.buildUpon:()Landroid/net/Uri$Builder;",
"Landroid/net/Uri;.parse:(Ljava/lang/String;)Landroid/net/Uri;",
"Landroid/os/Handler;.<init>:(Landroid/os/Looper;)V",
"Landroid/os/Looper;.getMainLooper:()Landroid/os/Looper;",
"Landroid/os/Process;.is64Bit:()Z",
"Landroid/os/Trace;.beginSection:(Ljava/lang/String;)V",
"Landroid/os/Trace;.endSection:()V",
"Landroid/os/Process;.myPid:()I",
"Landroid/os/Process;.myUid:()I",
"Landroid/text/TextUtils;.isEmpty:(Ljava/lang/CharSequence;)Z",
"Landroid/text/format/Time;.<init>:()V",
"Landroid/util/Log;.e:(Ljava/lang/String;Ljava/lang/String;)I",
"Landroid/util/Log;.isLoggable:(Ljava/lang/String;I)Z",
"Landroid/util/Log;.w:(Ljava/lang/String;Ljava/lang/String;)I",
"Landroid/util/SparseArray;.<init>:()V",
"Landroid/util/SparseArray;.<init>:(I)V",
"Landroid/util/SparseArray;.put:(ILjava/lang/Object;)V",
"Ljava/io/BufferedReader;.<init>:(Ljava/io/Reader;)V",
"Ljava/io/ByteArrayOutputStream;.<init>:()V",
"Ljava/io/ByteArrayOutputStream;.toByteArray:()[B",
"Ljava/io/File;.equals:(Ljava/lang/Object;)Z",
"Ljava/io/File;.getAbsolutePath:()Ljava/lang/String;",
"Ljava/io/File;.getCanonicalPath:()Ljava/lang/String;",
"Ljava/io/File;.getParentFile:()Ljava/io/File;",
"Ljava/io/OutputStream;.<init>:()V",
"Ljava/io/OutputStream;.write:([B)V",
"Ljava/io/PrintStream;.println:(Ljava/lang/String;)V",
"Ljava/io/PrintWriter;.<init>:(Ljava/io/Writer;)V",
"Ljava/io/PrintWriter;.close:()V",
"Ljava/io/PrintWriter;.println:()V",
"Ljava/io/Writer;.<init>:()V",
"Ljava/io/Writer;.close:()V",
"Ljava/lang/AssertionError;.<init>:()V",
"Ljava/lang/AssertionError;.<init>:(Ljava/lang/Object;)V",
"Ljava/lang/Boolean;.booleanValue:()Z",
"Ljava/lang/Boolean;.parseBoolean:(Ljava/lang/String;)Z",
"Ljava/lang/Boolean;.valueOf:(Ljava/lang/String;)Ljava/lang/Boolean;",
"Ljava/lang/Boolean;.valueOf:(Z)Ljava/lang/Boolean;",
"Ljava/lang/CharSequence;.charAt:(I)C",
"Ljava/lang/CharSequence;.length:()I",
"Ljava/lang/CharSequence;.toString:()Ljava/lang/String;",
"Ljava/lang/Character;.toLowerCase:(C)C",
"Ljava/lang/Character;.toUpperCase:(C)C",
"Ljava/lang/Class;.forName:(Ljava/lang/String;)Ljava/lang/Class;",
"Ljava/lang/Class;.forName:(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;",
"Ljava/lang/Class;.getClassLoader:()Ljava/lang/ClassLoader;",
"Ljava/lang/Class;.getDeclaredField:(Ljava/lang/String;)Ljava/lang/reflect/Field;",
"Ljava/lang/Class;.getDeclaredMethod:(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;",
"Ljava/lang/Class;.getEnumConstants:()[Ljava/lang/Object;",
"Ljava/lang/Class;.getField:(Ljava/lang/String;)Ljava/lang/reflect/Field;",
"Ljava/lang/Class;.getMethod:(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;",
"Ljava/lang/Class;.getName:()Ljava/lang/String;",
"Ljava/lang/Class;.getSimpleName:()Ljava/lang/String;",
"Ljava/lang/Class;.newInstance:()Ljava/lang/Object;",
"Ljava/lang/Class;.toString:()Ljava/lang/String;",
"Ljava/lang/ClassCastException;.<init>:(Ljava/lang/String;)V",
"Ljava/lang/Double;.isNaN:(D)Z",
"Ljava/lang/Double;.parseDouble:(Ljava/lang/String;)D",
"Ljava/lang/Double;.valueOf:(D)Ljava/lang/Double;",
"Ljava/lang/Enum;.<init>:(Ljava/lang/String;I)V",
"Ljava/lang/Enum;.name:()Ljava/lang/String;",
"Ljava/lang/Enum;.ordinal:()I",
"Ljava/lang/Enum;.toString:()Ljava/lang/String;",
"Ljava/lang/Error;.<init>:(Ljava/lang/String;)V",
"Ljava/lang/Error;.<init>:(Ljava/lang/Throwable;)V",
"Ljava/lang/Exception;.<init>:()V",
"Ljava/lang/Float;.floatValue:()F",
"Ljava/lang/Float;.valueOf:(F)Ljava/lang/Float;",
"Ljava/lang/IllegalArgumentException;.<init>:()V",
"Ljava/lang/IllegalArgumentException;.<init>:(Ljava/lang/String;)V",
"Ljava/lang/IllegalStateException;.<init>:(Ljava/lang/String;)V",
"Ljava/lang/IndexOutOfBoundsException;.<init>:(Ljava/lang/String;)V",
"Ljava/lang/Integer;.highestOneBit:(I)I",
"Ljava/lang/Integer;.intValue:()I",
"Ljava/lang/Integer;.parseInt:(Ljava/lang/String;)I",
"Ljava/lang/Integer;.rotateLeft:(II)I",
"Ljava/lang/Integer;.toHexString:(I)Ljava/lang/String;",
"Ljava/lang/Integer;.toString:(I)Ljava/lang/String;",
"Ljava/lang/Integer;.valueOf:(I)Ljava/lang/Integer;",
"Ljava/lang/Long;.parseLong:(Ljava/lang/String;)J",
"Ljava/lang/Long;.valueOf:(J)Ljava/lang/Long;",
"Ljava/lang/Math;.abs:(F)F",
"Ljava/lang/Math;.max:(II)I",
"Ljava/lang/Math;.min:(II)I",
"Ljava/lang/Math;.min:(JJ)J",
"Ljava/lang/Math;.pow:(DD)D",
"Ljava/lang/Math;.signum:(F)F",
"Ljava/lang/Math;.sqrt:(D)D",
"Ljava/lang/NullPointerException;.<init>:(Ljava/lang/String;)V",
"Ljava/lang/Number;.floatValue:()F",
"Ljava/lang/Number;.intValue:()I",
"Ljava/lang/Object;.<init>:()V",
"Ljava/lang/Object;.<init>:()V",
"Ljava/lang/Object;.equals:(Ljava/lang/Object;)Z",
"Ljava/lang/Object;.getClass:()Ljava/lang/Class;",
"Ljava/lang/Object;.hashCode:()I",
"Ljava/lang/Object;.toString:()Ljava/lang/String;",
"Ljava/lang/Runtime;.getRuntime:()Ljava/lang/Runtime;",
"Ljava/lang/Runtime;.availableProcessors:()I",
"Ljava/lang/RuntimeException;.<init>:()V",
"Ljava/lang/RuntimeException;.<init>:(Ljava/lang/String;)V",
"Ljava/lang/RuntimeException;.<init>:(Ljava/lang/String;Ljava/lang/Throwable;)V",
"Ljava/lang/RuntimeException;.<init>:(Ljava/lang/Throwable;)V",
"Ljava/lang/StackTraceElement;.getClassName:()Ljava/lang/String;",
"Ljava/lang/StackTraceElement;.getMethodName:()Ljava/lang/String;",
"Ljava/lang/String;.<init>:([B)V",
"Ljava/lang/String;.<init>:([BLjava/lang/String;)V",
"Ljava/lang/String;.<init>:(Ljava/lang/String;)V",
"Ljava/lang/String;.charAt:(I)C",
"Ljava/lang/String;.contains:(Ljava/lang/CharSequence;)Z",
"Ljava/lang/String;.equals:(Ljava/lang/Object;)Z",
"Ljava/lang/String;.format:(Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/String;",
"Ljava/lang/String;.format:(Ljava/util/Locale;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/String;",
"Ljava/lang/String;.getBytes:(Ljava/lang/String;)[B",
"Ljava/lang/String;.hashCode:()I",
"Ljava/lang/String;.indexOf:(II)I",
"Ljava/lang/String;.indexOf:(Ljava/lang/String;I)I",
"Ljava/lang/String;.isEmpty:()Z",
"Ljava/lang/String;.lastIndexOf:(I)I",
"Ljava/lang/String;.lastIndexOf:(Ljava/lang/String;)I",
"Ljava/lang/String;.length:()I",
"Ljava/lang/String;.replace:(Ljava/lang/CharSequence;Ljava/lang/CharSequence;)Ljava/lang/String;",
"Ljava/lang/String;.startsWith:(Ljava/lang/String;)Z",
"Ljava/lang/String;.substring:(I)Ljava/lang/String;",
"Ljava/lang/String;.substring:(II)Ljava/lang/String;",
"Ljava/lang/String;.toCharArray:()[C",
"Ljava/lang/String;.toLowerCase:(Ljava/util/Locale;)Ljava/lang/String;",
"Ljava/lang/String;.toUpperCase:(Ljava/util/Locale;)Ljava/lang/String;",
"Ljava/lang/String;.valueOf:(Ljava/lang/Object;)Ljava/lang/String;",
"Ljava/lang/String;.valueOf:([C)Ljava/lang/String;",
"Ljava/lang/StringBuilder;.<init>:()V",
"Ljava/lang/StringBuilder;.<init>:(I)V",
"Ljava/lang/StringBuilder;.<init>:(Ljava/lang/String;)V",
"Ljava/lang/StringBuilder;.toString:()Ljava/lang/String;",
"Ljava/lang/System;.arraycopy:(Ljava/lang/Object;ILjava/lang/Object;II)V",
"Ljava/lang/System;.currentTimeMillis:()J",
"Ljava/lang/System;.getProperties:()Ljava/util/Properties;",
"Ljava/lang/System;.getProperty:(Ljava/lang/String;)Ljava/lang/String;",
"Ljava/lang/System;.getProperty:(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;",
"Ljava/lang/System;.identityHashCode:(Ljava/lang/Object;)I",
"Ljava/lang/System;.nanoTime:()J",
"Ljava/lang/Thread;.<init>:(Ljava/lang/Runnable;Ljava/lang/String;)V",
"Ljava/lang/Thread;.currentThread:()Ljava/lang/Thread;",
"Ljava/lang/Thread;.getStackTrace:()[Ljava/lang/StackTraceElement;",
"Ljava/lang/ThreadLocal;.<init>:()V",
"Ljava/lang/Throwable;.<init>:()V",
"Ljava/lang/Throwable;.getMessage:()Ljava/lang/String;",
"Ljava/lang/Throwable;.getStackTrace:()[Ljava/lang/StackTraceElement;",
"Ljava/lang/Throwable;.initCause:(Ljava/lang/Throwable;)Ljava/lang/Throwable;",
"Ljava/lang/Throwable;.printStackTrace:()V",
"Ljava/lang/Throwable;.setStackTrace:([Ljava/lang/StackTraceElement;)V",
"Ljava/lang/Throwable;.toString:()Ljava/lang/String;",
"Ljava/lang/UnsatisfiedLinkError;.<init>:(Ljava/lang/String;)V",
"Ljava/lang/ref/ReferenceQueue;.<init>:()V",
"Ljava/lang/reflect/Field;.get:(Ljava/lang/Object;)Ljava/lang/Object;",
"Ljava/nio/charset/Charset;.forName:(Ljava/lang/String;)Ljava/nio/charset/Charset;",
"Ljava/nio/charset/Charset;.name:()Ljava/lang/String;",
"Ljava/security/Provider;.<init>:(Ljava/lang/String;DLjava/lang/String;)V",
"Ljava/text/BreakIterator;.getCharacterInstance:()Ljava/text/BreakIterator;",
"Ljava/text/BreakIterator;.last:()I",
"Ljava/text/BreakIterator;.setText:(Ljava/lang/String;)V",
"Ljava/text/SimpleDateFormat;.<init>:(Ljava/lang/String;Ljava/util/Locale;)V",
"Ljava/util/AbstractCollection;.<init>:()V",
"Ljava/util/AbstractCollection;.add:(Ljava/lang/Object;)Z",
"Ljava/util/AbstractCollection;.contains:(Ljava/lang/Object;)Z",
"Ljava/util/AbstractCollection;.size:()I",
"Ljava/util/AbstractCollection;.toArray:()[Ljava/lang/Object;",
"Ljava/util/AbstractCollection;.toArray:([Ljava/lang/Object;)[Ljava/lang/Object;",
"Ljava/util/AbstractList;.get:(I)Ljava/lang/Object;",
"Ljava/util/AbstractMap;.<init>:()V",
"Ljava/util/AbstractMap;.get:(Ljava/lang/Object;)Ljava/lang/Object;",
"Ljava/util/AbstractMap;.put:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;",
"Ljava/util/AbstractQueue;.<init>:()V",
"Ljava/util/ArrayList;.<init>:()V",
"Ljava/util/ArrayList;.add:(Ljava/lang/Object;)Z",
"Ljava/util/ArrayList;.get:(I)Ljava/lang/Object;",
"Ljava/util/ArrayList;.size:()I",
"Ljava/util/ArrayList;.toArray:([Ljava/lang/Object;)[Ljava/lang/Object;",
"Ljava/util/Arrays;.asList:([Ljava/lang/Object;)Ljava/util/List;",
"Ljava/util/Arrays;.copyOf:([Ljava/lang/Object;I)[Ljava/lang/Object;",
"Ljava/util/Arrays;.copyOfRange:([BII)[B",
"Ljava/util/Arrays;.copyOfRange:([Ljava/lang/Object;II)[Ljava/lang/Object;",
"Ljava/util/Arrays;.fill:([II)V",
"Ljava/util/Arrays;.fill:([Ljava/lang/Object;IILjava/lang/Object;)V",
"Ljava/util/Arrays;.sort:([C)V",
"Ljava/util/Arrays;.toString:([Ljava/lang/Object;)Ljava/lang/String;",
"Ljava/util/Calendar;.getInstance:(Ljava/util/TimeZone;)Ljava/util/Calendar;",
"Ljava/util/Collection;.add:(Ljava/lang/Object;)Z",
"Ljava/util/Collection;.toArray:()[Ljava/lang/Object;",
"Ljava/util/Collections;.addAll:(Ljava/util/Collection;[Ljava/lang/Object;)Z",
"Ljava/util/Collections;.newSetFromMap:(Ljava/util/Map;)Ljava/util/Set;",
"Ljava/util/Collections;.singleton:(Ljava/lang/Object;)Ljava/util/Set;",
"Ljava/util/Collections;.synchronizedMap:(Ljava/util/Map;)Ljava/util/Map;",
"Ljava/util/Collections;.unmodifiableList:(Ljava/util/List;)Ljava/util/List;",
"Ljava/util/Collections;.unmodifiableMap:(Ljava/util/Map;)Ljava/util/Map;",
"Ljava/util/Collections;.unmodifiableSet:(Ljava/util/Set;)Ljava/util/Set;",
"Ljava/util/Dictionary;.put:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;",
"Ljava/util/EnumMap;.<init>:(Ljava/lang/Class;)V",
"Ljava/util/EnumSet;.copyOf:(Ljava/util/Collection;)Ljava/util/EnumSet;",
"Ljava/util/HashMap;.<init>:()V",
"Ljava/util/HashMap;.<init>:(I)V",
"Ljava/util/HashMap;.get:(Ljava/lang/Object;)Ljava/lang/Object;",
"Ljava/util/HashMap;.put:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;",
"Ljava/util/HashSet;.<init>:()V",
"Ljava/util/HashSet;.<init>:(I)V",
"Ljava/util/HashSet;.<init>:(Ljava/util/Collection;)V",
"Ljava/util/HashSet;.add:(Ljava/lang/Object;)Z",
"Ljava/util/HashSet;.contains:(Ljava/lang/Object;)Z",
"Ljava/util/Iterator;.hasNext:()Z",
"Ljava/util/Iterator;.next:()Ljava/lang/Object;",
"Ljava/util/LinkedHashMap;.<init>:()V",
"Ljava/util/LinkedHashMap;.<init>:(I)V",
"Ljava/util/LinkedHashMap;.<init>:(IFZ)V",
"Ljava/util/LinkedHashSet;.<init>:(I)V",
"Ljava/util/LinkedList;.<init>:()V",
"Ljava/util/Locale;.<init>:(Ljava/lang/String;Ljava/lang/String;)V",
"Ljava/util/Locale;.getDefault:()Ljava/util/Locale;",
"Ljava/util/Map;.containsKey:(Ljava/lang/Object;)Z",
"Ljava/util/Map;.get:(Ljava/lang/Object;)Ljava/lang/Object;",
"Ljava/util/Map;.put:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;",
"Ljava/util/NoSuchElementException;.<init>:(Ljava/lang/String;)V",
"Ljava/util/Random;.<init>:()V",
"Ljava/util/concurrent/Semaphore;.<init>:(I)V",
"Ljava/util/Set;.add:(Ljava/lang/Object;)Z",
"Ljava/util/Set;.contains:(Ljava/lang/Object;)Z",
"Ljava/util/Set;.iterator:()Ljava/util/Iterator;",
"Ljava/util/TimeZone;.getTimeZone:(Ljava/lang/String;)Ljava/util/TimeZone;",
"Ljava/util/Timer;.<init>:()V",
"Ljava/util/TreeSet;.<init>:()V",
"Ljava/util/TreeSet;.add:(Ljava/lang/Object;)Z",
"Ljava/util/TreeSet;.contains:(Ljava/lang/Object;)Z",
"Ljava/util/WeakHashMap;.<init>:()V",
"Ljava/util/WeakHashMap;.<init>:(I)V",
"Ljava/util/concurrent/ConcurrentHashMap;.<init>:()V",
"Ljava/util/concurrent/ConcurrentHashMap;.<init>:(I)V",
"Ljava/util/concurrent/ConcurrentLinkedQueue;.<init>:()V",
"Ljava/util/concurrent/CopyOnWriteArraySet;.<init>:()V",
"Ljava/util/concurrent/LinkedBlockingQueue;.<init>:()V",
"Ljava/util/concurrent/TimeUnit;.toDays:(J)J",
"Ljava/util/concurrent/TimeUnit;.toMillis:(J)J",
"Ljava/util/concurrent/TimeUnit;.toMinutes:(J)J",
"Ljava/util/concurrent/TimeUnit;.toNanos:(J)J",
"Ljava/util/concurrent/TimeUnit;.toSeconds:(J)J",
"Ljava/util/concurrent/ThreadPoolExecutor;.<init>:(IIJLjava/util/concurrent/TimeUnit;Ljava/util/concurrent/BlockingQueue;Ljava/util/concurrent/ThreadFactory;)V",
"Ljava/util/concurrent/atomic/AtomicBoolean;.<init>:(Z)V",
"Ljava/util/concurrent/atomic/AtomicInteger;.<init>:()V",
"Ljava/util/concurrent/atomic/AtomicInteger;.<init>:(I)V",
"Ljava/util/concurrent/atomic/AtomicInteger;.get:()I",
"Ljava/util/concurrent/atomic/AtomicInteger;.getAndIncrement:()I",
"Ljava/util/concurrent/atomic/AtomicLong;.<init>:(J)V",
"Ljava/util/concurrent/atomic/AtomicReference;.<init>:()V",
"Ljava/util/concurrent/atomic/AtomicReference;.<init>:(Ljava/lang/Object;)V",
"Ljava/util/concurrent/atomic/AtomicReferenceArray;.<init>:(I)V",
"Ljava/util/concurrent/atomic/AtomicReferenceArray;.length:()I",
"Ljava/util/concurrent/locks/ReentrantLock;.<init>:()V",
"Ljava/util/concurrent/locks/ReentrantReadWriteLock$ReadLock;.lock:()V",
"Ljava/util/concurrent/locks/ReentrantReadWriteLock$ReadLock;.unlock:()V",
"Ljava/util/concurrent/locks/ReentrantReadWriteLock$WriteLock;.lock:()V",
"Ljava/util/concurrent/locks/ReentrantReadWriteLock$WriteLock;.unlock:()V",
"Ljava/util/concurrent/locks/ReentrantReadWriteLock;.<init>:()V",
"Ljava/util/concurrent/locks/ReentrantReadWriteLock;.readLock:()Ljava/util/concurrent/locks/ReentrantReadWriteLock$ReadLock;",
"Ljava/util/concurrent/locks/ReentrantReadWriteLock;.writeLock:()Ljava/util/concurrent/locks/ReentrantReadWriteLock$WriteLock;",
"Ljava/util/logging/Logger;.getLogger:(Ljava/lang/String;)Ljava/util/logging/Logger;",
"Ljava/util/logging/Logger;.log:(Ljava/util/logging/Level;Ljava/lang/String;)V",
"Ljava/util/logging/Logger;.log:(Ljava/util/logging/Level;Ljava/lang/String;Ljava/lang/Throwable;)V",
"Ljava/util/regex/Pattern;.compile:(Ljava/lang/String;)Ljava/util/regex/Pattern;",
"Ljava/util/regex/Pattern;.compile:(Ljava/lang/String;I)Ljava/util/regex/Pattern;",
"Ljava/util/regex/Pattern;.quote:(Ljava/lang/String;)Ljava/lang/String;",
"Lredex/$EnumUtils;.values:(I)[Ljava/lang/Integer;",
// clang-format on
};
return method_ref->is_def() &&
methods.count(method_ref->as_def()->get_deobfuscated_name_or_empty());
}
const DexClass* clinit_may_have_side_effects(
const DexClass* cls,
const ClInitHasNoSideEffectsPredicate* clinit_has_no_side_effects,
const std::unordered_set<DexMethod*>* non_true_virtuals) {
ClInitSideEffectsAnalysis analysis(clinit_has_no_side_effects,
non_true_virtuals);
return analysis.run(cls);
}
bool no_invoke_super(const IRCode& code) {
always_assert(!code.editable_cfg_built());
for (const auto& mie : InstructionIterable(code)) {
auto insn = mie.insn;
if (insn->opcode() == OPCODE_INVOKE_SUPER) {
return false;
}
}
return true;
}
DexMethod* java_lang_Object_ctor() {
return static_cast<DexMethod*>(
DexMethod::make_method("Ljava/lang/Object;.<init>:()V"));
}
DexMethod* java_lang_Enum_ctor() {
return static_cast<DexMethod*>(
DexMethod::make_method("Ljava/lang/Enum;.<init>:(Ljava/lang/String;I)V"));
}
DexMethod* java_lang_Enum_ordinal() {
return static_cast<DexMethod*>(
DexMethod::make_method("Ljava/lang/Enum;.ordinal:()I"));
}
DexMethod* java_lang_Enum_name() {
return static_cast<DexMethod*>(
DexMethod::make_method("Ljava/lang/Enum;.name:()Ljava/lang/String;"));
}
DexMethod* java_lang_Enum_equals() {
return static_cast<DexMethod*>(
DexMethod::make_method("Ljava/lang/Enum;.equals:(Ljava/lang/Object;)Z"));
}
DexMethod* java_lang_Integer_valueOf() {
return static_cast<DexMethod*>(DexMethod::make_method(
"Ljava/lang/Integer;.valueOf:(I)Ljava/lang/Integer;"));
}
DexMethod* java_lang_Integer_intValue() {
return static_cast<DexMethod*>(
DexMethod::make_method("Ljava/lang/Integer;.intValue:()I"));
}
DexMethod* kotlin_jvm_internal_Intrinsics_checkParameterIsNotNull() {
return static_cast<DexMethod*>(DexMethod::get_method(
"Lkotlin/jvm/internal/Intrinsics;.checkParameterIsNotNull:(Ljava/lang/"
"Object;Ljava/lang/String;)V"));
}
DexMethod* kotlin_jvm_internal_Intrinsics_checkNotNullParameter() {
return static_cast<DexMethod*>(DexMethod::get_method(
"Lkotlin/jvm/internal/Intrinsics;.checkNotNullParameter:(Ljava/lang/"
"Object;Ljava/lang/String;)V"));
}
DexMethod* kotlin_jvm_internal_Intrinsics_checExpressionValueIsNotNull() {
return static_cast<DexMethod*>(DexMethod::get_method(
"Lkotlin/jvm/internal/Intrinsics;.checkExpressionValueIsNotNull:(Ljava/"
"lang/Object;Ljava/lang/String;)V"));
}
DexMethod* kotlin_jvm_internal_Intrinsics_checkNotNullExpressionValue() {
return static_cast<DexMethod*>(DexMethod::get_method(
"Lkotlin/jvm/internal/Intrinsics;.checkNotNullExpressionValue:(Ljava/"
"lang/Object;Ljava/lang/String;)V"));
}
}; // namespace method