in opt/reduce-array-literals/ReduceArrayLiterals.cpp [194:331]
void analyze_instruction(
const IRInstruction* insn,
TrackedDomainEnvironment* current_state) const override {
const auto set_current_state_at = [&](reg_t reg, bool wide,
const TrackedDomain& value) {
current_state->set(reg, value);
if (wide) {
current_state->set(reg + 1, TrackedDomain::top());
}
};
const auto get_singleton =
[](const TrackedDomain& domain) -> boost::optional<TrackedValue> {
always_assert(domain.kind() == AbstractValueKind::Value);
auto& elements = domain.elements();
if (elements.size() != 1) {
return boost::none;
}
return boost::optional<TrackedValue>(*elements.begin());
};
const auto escape_new_arrays = [&](uint32_t reg) {
const auto& domain = current_state->get(reg);
always_assert(domain.kind() == AbstractValueKind::Value);
for (auto& value : domain.elements()) {
if (is_new_array(value)) {
if (is_array_literal(value)) {
auto escaped_array = EscapedArrayDomain(get_aput_insns(value));
auto it = m_escaped_arrays.find(value.new_array_insn);
if (it == m_escaped_arrays.end()) {
m_escaped_arrays.emplace(value.new_array_insn, escaped_array);
} else {
it->second.join_with(escaped_array);
}
TRACE(RAL, 4, "[RAL] literal array escaped");
} else {
TRACE(RAL, 4, "[RAL] non-literal array escaped");
m_escaped_arrays[value.new_array_insn] = EscapedArrayDomain::top();
}
}
}
};
const auto default_case = [&]() {
// mark escaping arrays
for (size_t i = 0; i < insn->srcs_size(); i++) {
escape_new_arrays(insn->src(i));
}
// If we get here, reset destination.
if (insn->has_dest()) {
set_current_state_at(insn->dest(), insn->dest_is_wide(),
TrackedDomain(make_other()));
} else if (insn->has_move_result_any()) {
current_state->set(RESULT_REGISTER, TrackedDomain(make_other()));
}
};
TRACE(RAL, 3, "[RAL] %s", SHOW(insn));
switch (insn->opcode()) {
case OPCODE_CONST:
set_current_state_at(insn->dest(), false /* is_wide */,
TrackedDomain(make_literal(insn)));
break;
case OPCODE_NEW_ARRAY: {
TRACE(RAL, 4, "[RAL] new array of type %s", SHOW(insn->get_type()));
const auto length = get_singleton(current_state->get(insn->src(0)));
if (length && is_literal(*length)) {
auto length_literal = get_literal(*length);
TRACE(RAL, 4, "[RAL] with length %" PRId64, length_literal);
always_assert(length_literal >= 0 && length_literal <= 2147483647);
current_state->set(RESULT_REGISTER,
TrackedDomain(make_array(length_literal, insn)));
break;
}
m_escaped_arrays[insn] = EscapedArrayDomain::top();
default_case();
break;
}
case IOPCODE_MOVE_RESULT_PSEUDO_OBJECT: {
const auto& value = current_state->get(RESULT_REGISTER);
set_current_state_at(insn->dest(), false /* is_wide */, value);
break;
}
case OPCODE_APUT:
case OPCODE_APUT_BYTE:
case OPCODE_APUT_CHAR:
case OPCODE_APUT_WIDE:
case OPCODE_APUT_SHORT:
case OPCODE_APUT_OBJECT:
case OPCODE_APUT_BOOLEAN: {
escape_new_arrays(insn->src(0));
const auto array = get_singleton(current_state->get(insn->src(1)));
const auto index = get_singleton(current_state->get(insn->src(2)));
TRACE(RAL, 4, "[RAL] aput: %d %d", array && is_new_array(*array),
index && is_literal(*index));
if (array && is_new_array(*array) && !is_array_literal(*array) && index &&
is_literal(*index)) {
int64_t index_literal = get_literal(*index);
TRACE(RAL, 4, "[RAL] index %" PRIu64 " of %u", index_literal,
array->length);
if (is_next_index(*array, index_literal)) {
TRACE(RAL, 4, "[RAL] is next");
TrackedValue new_array = *array;
if (add_element(new_array, index_literal, insn)) {
current_state->set(insn->src(1), TrackedDomain(new_array));
break;
}
}
}
default_case();
break;
}
case OPCODE_MOVE: {
const auto value = get_singleton(current_state->get(insn->src(0)));
if (value && is_literal(*value)) {
set_current_state_at(insn->dest(), false /* is_wide */,
TrackedDomain(*value));
break;
}
default_case();
break;
}
default: {
default_case();
break;
}
}
}