bool Matcher::Mark(Matcher* matcher) {
matcher->pos_ += 1u; // Advance to the next match function before marking.
matcher->mark_ = matcher->pos_; returntrue;
}
// Used for a single invoke in a constructor. In that situation, the method verifier makes // sure we invoke a constructor either in the same class or superclass with at least "this".
ArtMethod* GetTargetConstructor(ArtMethod* method, const Instruction* invoke_direct)
REQUIRES_SHARED(Locks::mutator_lock_) {
DCHECK(invoke_direct->Opcode() == Instruction::INVOKE_DIRECT ||
invoke_direct->Opcode() == Instruction::INVOKE_DIRECT_RANGE); if (kIsDebugBuild) {
uint16_t vregc = invoke_direct->Opcode() == Instruction::INVOKE_DIRECT
? invoke_direct->VRegC_35c()
: invoke_direct->VRegC_3rc();
CodeItemDataAccessor accessor(method->DexInstructionData());
DCHECK_EQ(vregc, accessor.RegistersSize() - accessor.InsSize());
}
uint32_t method_index = invoke_direct->Opcode() == Instruction::INVOKE_DIRECT
? invoke_direct->VRegB_35c()
: invoke_direct->VRegB_3rc();
ArtMethod* target_method = Runtime::Current()->GetClassLinker()->LookupResolvedMethod(
method_index, method->GetDexCache(), method->GetClassLoader()); if (kIsDebugBuild && target_method != nullptr) {
CHECK(!target_method->IsStatic());
CHECK(target_method->IsConstructor());
CHECK(method->GetDeclaringClass()->IsSubClass(target_method->GetDeclaringClass()));
} return target_method;
}
// Return the forwarded arguments and check that all remaining arguments are zero. // If the check fails, return static_cast<size_t>(-1).
size_t CountForwardedConstructorArguments(const CodeItemDataAccessor* code_item, const Instruction* invoke_direct,
uint16_t zero_vreg_mask) {
DCHECK(invoke_direct->Opcode() == Instruction::INVOKE_DIRECT ||
invoke_direct->Opcode() == Instruction::INVOKE_DIRECT_RANGE);
size_t number_of_args = invoke_direct->Opcode() == Instruction::INVOKE_DIRECT
? invoke_direct->VRegA_35c()
: invoke_direct->VRegA_3rc();
DCHECK_NE(number_of_args, 0u);
// We limit the number of IPUTs storing parameters. There can be any number // of IPUTs that store the value 0 as they are useless in a constructor as // the object always starts zero-initialized. We also eliminate all but the // last store to any field as they are not observable; not even if the field // is volatile as no reference to the object can escape from a constructor // with this pattern. static constexpr size_t kMaxConstructorIPuts = 3u;
bool RecordConstructorIPut(ArtMethod* method, const Instruction* new_iput,
uint16_t this_vreg,
uint16_t zero_vreg_mask, /*inout*/ ConstructorIPutData (&iputs)[kMaxConstructorIPuts], /*inout*/ size_t& iput_count)
REQUIRES_SHARED(Locks::mutator_lock_) {
DCHECK(IsInstructionIPut(new_iput->Opcode()));
uint32_t field_index = new_iput->VRegC_22c();
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
ArtField* field = class_linker->LookupResolvedField(field_index, method, /* is_static= */ false); if (UNLIKELY(field == nullptr)) { returnfalse;
} // Remove previous IPUT to the same field, if any. Different field indexes may refer // to the same field, so we need to compare resolved fields from the dex cache. for (size_t old_pos = 0, end = iput_count; old_pos < end; ++old_pos) {
ArtField* f = class_linker->LookupResolvedField(iputs[old_pos].field_index,
method, /* is_static= */ false);
DCHECK(f != nullptr); if (f == field) { auto back_it = std::copy(iputs + old_pos + 1, iputs + iput_count, iputs + old_pos);
*back_it = ConstructorIPutData();
--iput_count; break;
}
} // If the stored value isn't zero, record the IPUT. if ((zero_vreg_mask & (1u << new_iput->VRegA_22c())) == 0u) {
size_t new_pos = iput_count; if (new_pos == arraysize(iputs)) { returnfalse; // Exceeded capacity of the output array.
}
iputs[new_pos].field_index = field_index;
iputs[new_pos].arg = new_iput->VRegA_22c() - this_vreg;
++iput_count;
} returntrue;
}
bool DoAnalyseConstructor(const CodeItemDataAccessor* code_item,
ArtMethod* method, /*inout*/ ConstructorIPutData (&iputs)[kMaxConstructorIPuts], /*inout*/ size_t &iput_count)
REQUIRES_SHARED(Locks::mutator_lock_) { // On entry we should not have any IPUTs yet.
DCHECK_EQ(iput_count, 0u);
// Limit the maximum number of code units we're willing to match. static constexpr size_t kMaxCodeUnits = 16u;
// Limit the number of registers that the constructor may use to 16. // Given that IPUTs must use low 16 registers and we do not match MOVEs, // this is a reasonable limitation. static constexpr size_t kMaxVRegs = 16u;
// We try to match a constructor that calls another constructor (either in // superclass or in the same class) with the same parameters, or with some // parameters truncated (allowed only for calls to superclass constructor) // or with extra parameters with value 0 (with any type, including null). // This call can be followed by optional IPUTs on "this" storing either one // of the parameters or 0 and the code must then finish with RETURN_VOID. // The called constructor must be either java.lang.Object.<init>() or it // must also match the same pattern. static constexpr Matcher::MatchFn* const kConstructorPattern[] = {
&Matcher::Mark,
&Matcher::Repeated<&Matcher::Const0>, // Either invoke-direct or invoke-direct/range works
&Matcher::Required<&Matcher::Or<&Matcher::Opcode<Instruction::INVOKE_DIRECT>,
&Matcher::Opcode<Instruction::INVOKE_DIRECT_RANGE>>>,
&Matcher::Mark,
&Matcher::Repeated<&Matcher::Const0>,
&Matcher::Repeated<&Matcher::IPutOnThis>,
&Matcher::Required<&Matcher::Opcode<Instruction::RETURN_VOID>>,
};
bool InlineMethodAnalyser::AnalyseMethodCode(ArtMethod* method, const CodeItemDataAccessor* code_item,
InlineMethod* result) { // We currently support only plain return or 2-instruction methods.
switch (opcode) { case Instruction::RETURN_VOID: if (result != nullptr) {
result->opcode = kInlineOpNop;
result->d.data = 0u;
} returntrue; case Instruction::RETURN: case Instruction::RETURN_OBJECT: case Instruction::RETURN_WIDE: return AnalyseReturnMethod(code_item, result); case Instruction::CONST: case Instruction::CONST_4: case Instruction::CONST_16: case Instruction::CONST_HIGH16: // TODO: Support wide constants (RETURN_WIDE). if (AnalyseConstMethod(code_item, result)) { returntrue;
}
FALLTHROUGH_INTENDED; case Instruction::CONST_WIDE: case Instruction::CONST_WIDE_16: case Instruction::CONST_WIDE_32: case Instruction::CONST_WIDE_HIGH16: case Instruction::INVOKE_DIRECT: case Instruction::INVOKE_DIRECT_RANGE: if (method != nullptr && !method->IsStatic() && method->IsConstructor()) { return AnalyseConstructor(code_item, method, result);
} returnfalse; case Instruction::IGET: case Instruction::IGET_OBJECT: case Instruction::IGET_BOOLEAN: case Instruction::IGET_BYTE: case Instruction::IGET_CHAR: case Instruction::IGET_SHORT: case Instruction::IGET_WIDE: return AnalyseIGetMethod(method, code_item, result); case Instruction::IPUT: case Instruction::IPUT_OBJECT: case Instruction::IPUT_BOOLEAN: case Instruction::IPUT_BYTE: case Instruction::IPUT_CHAR: case Instruction::IPUT_SHORT: case Instruction::IPUT_WIDE: return AnalyseIPutMethod(method, code_item, result); default: returnfalse;
}
}
DCHECK_LT(opcode == Instruction::IGET_WIDE ? dst_reg + 1 : dst_reg, code_item->RegistersSize()); if (dst_reg != return_reg) { returnfalse; // Not returning the value retrieved by IGET?
}
// InlineIGetIPutData::object_arg is only 4 bits wide. static constexpr uint16_t kMaxObjectArg = 15u; if (object_arg > kMaxObjectArg) { returnfalse;
}
bool is_static = method->IsStatic(); if (is_static || object_arg != 0u) { // TODO: Implement inlining of IGET on non-"this" registers (needs correct stack trace for NPE). // Allow synthetic accessors. We don't care about losing their stack frame in NPE. if (!IsSyntheticAccessor(method)) { returnfalse;
}
}
DCHECK(result != nullptr);
InlineIGetIPutData* data = &result->d.ifield_data; if (!ComputeSpecialAccessorInfo(method, field_idx, false, data)) { returnfalse;
}
result->opcode = kInlineOpIGet;
data->op_variant = enum_cast<uint16_t>(IGetMemAccessType(opcode));
data->method_is_static = is_static ? 1u : 0u;
data->object_arg = object_arg; // Allow IGET on any register, not just "this".
data->src_arg = 0u;
data->return_arg_plus1 = 0u; returntrue;
}
bool is_static = method->IsStatic(); if (is_static || object_arg != 0u) { // TODO: Implement inlining of IPUT on non-"this" registers (needs correct stack trace for NPE). // Allow synthetic accessors. We don't care about losing their stack frame in NPE. if (!IsSyntheticAccessor(method)) { returnfalse;
}
}
DCHECK(result != nullptr);
InlineIGetIPutData* data = &result->d.ifield_data; if (!ComputeSpecialAccessorInfo(method, field_idx, true, data)) { returnfalse;
}
result->opcode = kInlineOpIPut;
data->op_variant = enum_cast<uint16_t>(IPutMemAccessType(opcode));
data->method_is_static = is_static ? 1u : 0u;
data->object_arg = object_arg; // Allow IPUT on any register, not just "this".
data->src_arg = src_arg;
data->return_arg_plus1 = return_arg_plus1; returntrue;
}
bool InlineMethodAnalyser::ComputeSpecialAccessorInfo(ArtMethod* method,
uint32_t field_idx, bool is_put,
InlineIGetIPutData* result) { if (method == nullptr) { returnfalse;
}
ObjPtr<mirror::DexCache> dex_cache = method->GetDexCache();
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
ArtField* field = class_linker->LookupResolvedField(field_idx, method, /* is_static= */ false); if (field == nullptr || field->IsStatic()) { returnfalse;
}
ObjPtr<mirror::Class> method_class = method->GetDeclaringClass();
ObjPtr<mirror::Class> field_class = field->GetDeclaringClass(); if (!method_class->CanAccessResolvedField(field_class, field, dex_cache, field_idx) ||
(is_put && field->IsFinal() && method_class != field_class)) { returnfalse;
}
DCHECK_GE(field->GetOffset().Int32Value(), 0); // Historical note: We made sure not to interleave function calls with bit field writes to // placate Valgrind. Bug: 27552451.
uint32_t field_offset = field->GetOffset().Uint32Value(); bool is_volatile = field->IsVolatile();
result->field_idx = field_idx;
result->field_offset = field_offset;
result->is_volatile = is_volatile ? 1u : 0u; returntrue;
}
} // namespace art
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.2 Sekunden
(vorverarbeitet am 2026-06-29)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.