Merge "Template BitTable based on the accessors."
diff --git a/build/Android.oat.mk b/build/Android.oat.mk
index ba3ef05..08b1e10 100644
--- a/build/Android.oat.mk
+++ b/build/Android.oat.mk
@@ -96,7 +96,7 @@
$$(core_image_name): $$(HOST_CORE_DEX_LOCATIONS) $$(core_dex2oat_dependency)
@echo "host dex2oat: $$@"
@mkdir -p $$(dir $$@)
- $$(hide) $$(DEX2OAT) --runtime-arg -Xms$(DEX2OAT_IMAGE_XMS) \
+ $$(hide) ANDROID_LOG_TAGS="*:e" $$(DEX2OAT) --runtime-arg -Xms$(DEX2OAT_IMAGE_XMS) \
--runtime-arg -Xmx$(DEX2OAT_IMAGE_XMX) \
--image-classes=$$(PRELOADED_CLASSES) $$(addprefix --dex-file=,$$(HOST_CORE_DEX_FILES)) \
$$(addprefix --dex-location=,$$(HOST_CORE_DEX_LOCATIONS)) --oat-file=$$(PRIVATE_CORE_OAT_NAME) \
diff --git a/compiler/optimizing/gvn.cc b/compiler/optimizing/gvn.cc
index 4863718..e6b6326 100644
--- a/compiler/optimizing/gvn.cc
+++ b/compiler/optimizing/gvn.cc
@@ -479,7 +479,10 @@
HInstruction* next = current->GetNext();
// Do not kill the set with the side effects of the instruction just now: if
// the instruction is GVN'ed, we don't need to kill.
- if (current->CanBeMoved()) {
+ //
+ // BoundType is a special case example of an instruction which shouldn't be moved but can be
+ // GVN'ed.
+ if (current->CanBeMoved() || current->IsBoundType()) {
if (current->IsBinaryOperation() && current->AsBinaryOperation()->IsCommutative()) {
// For commutative ops, (x op y) will be treated the same as (y op x)
// after fixed ordering.
diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc
index ef8a757..661f66a 100644
--- a/compiler/optimizing/nodes.cc
+++ b/compiler/optimizing/nodes.cc
@@ -2786,6 +2786,14 @@
SetPackedFlag<kFlagReferenceTypeIsExact>(rti.IsExact());
}
+bool HBoundType::InstructionDataEquals(const HInstruction* other) const {
+ const HBoundType* other_bt = other->AsBoundType();
+ ScopedObjectAccess soa(Thread::Current());
+ return GetUpperBound().IsEqual(other_bt->GetUpperBound()) &&
+ GetUpperCanBeNull() == other_bt->GetUpperCanBeNull() &&
+ CanBeNull() == other_bt->CanBeNull();
+}
+
void HBoundType::SetUpperBound(const ReferenceTypeInfo& upper_bound, bool can_be_null) {
if (kIsDebugBuild) {
ScopedObjectAccess soa(Thread::Current());
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index 2037879..975ad1c 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -7142,6 +7142,7 @@
SetRawInputAt(0, input);
}
+ bool InstructionDataEquals(const HInstruction* other) const OVERRIDE;
bool IsClonable() const OVERRIDE { return true; }
// {Get,Set}Upper* should only be used in reference type propagation.
diff --git a/compiler/optimizing/ssa_liveness_analysis.cc b/compiler/optimizing/ssa_liveness_analysis.cc
index f6bd052..2f782f3 100644
--- a/compiler/optimizing/ssa_liveness_analysis.cc
+++ b/compiler/optimizing/ssa_liveness_analysis.cc
@@ -195,14 +195,19 @@
// SsaLivenessAnalysis.
for (size_t i = 0, e = environment->Size(); i < e; ++i) {
HInstruction* instruction = environment->GetInstructionAt(i);
+ if (instruction == nullptr) {
+ continue;
+ }
bool should_be_live = ShouldBeLiveForEnvironment(current, instruction);
+ // If this environment use does not keep the instruction live, it does not
+ // affect the live range of that instruction.
if (should_be_live) {
CHECK(instruction->HasSsaIndex()) << instruction->DebugName();
live_in->SetBit(instruction->GetSsaIndex());
- }
- if (instruction != nullptr) {
- instruction->GetLiveInterval()->AddUse(
- current, environment, i, /* actual_user */ nullptr, should_be_live);
+ instruction->GetLiveInterval()->AddUse(current,
+ environment,
+ i,
+ /* actual_user */ nullptr);
}
}
}
diff --git a/compiler/optimizing/ssa_liveness_analysis.h b/compiler/optimizing/ssa_liveness_analysis.h
index f83bb52..83ca5bd 100644
--- a/compiler/optimizing/ssa_liveness_analysis.h
+++ b/compiler/optimizing/ssa_liveness_analysis.h
@@ -300,8 +300,7 @@
void AddUse(HInstruction* instruction,
HEnvironment* environment,
size_t input_index,
- HInstruction* actual_user = nullptr,
- bool keep_alive = false) {
+ HInstruction* actual_user = nullptr) {
bool is_environment = (environment != nullptr);
LocationSummary* locations = instruction->GetLocations();
if (actual_user == nullptr) {
@@ -359,12 +358,6 @@
uses_.push_front(*new_use);
}
- if (is_environment && !keep_alive) {
- // If this environment use does not keep the instruction live, it does not
- // affect the live range of that instruction.
- return;
- }
-
size_t start_block_position = instruction->GetBlock()->GetLifetimeStart();
if (first_range_ == nullptr) {
// First time we see a use of that interval.
@@ -1157,8 +1150,11 @@
* of an instruction that has a primitive type make the instruction live.
* If the graph does not have the debuggable property, the environment
* use has no effect, and may get a 'none' value after register allocation.
+ * (d) When compiling in OSR mode, all loops in the compiled method may be entered
+ * from the interpreter via SuspendCheck; such use in SuspendCheck makes the instruction
+ * live.
*
- * (b) and (c) are implemented through SsaLivenessAnalysis::ShouldBeLiveForEnvironment.
+ * (b), (c) and (d) are implemented through SsaLivenessAnalysis::ShouldBeLiveForEnvironment.
*/
class SsaLivenessAnalysis : public ValueObject {
public:
@@ -1259,14 +1255,18 @@
// Returns whether `instruction` in an HEnvironment held by `env_holder`
// should be kept live by the HEnvironment.
static bool ShouldBeLiveForEnvironment(HInstruction* env_holder, HInstruction* instruction) {
- if (instruction == nullptr) return false;
+ DCHECK(instruction != nullptr);
// A value that's not live in compiled code may still be needed in interpreter,
// due to code motion, etc.
if (env_holder->IsDeoptimize()) return true;
// A value live at a throwing instruction in a try block may be copied by
// the exception handler to its location at the top of the catch block.
if (env_holder->CanThrowIntoCatchBlock()) return true;
- if (instruction->GetBlock()->GetGraph()->IsDebuggable()) return true;
+ HGraph* graph = instruction->GetBlock()->GetGraph();
+ if (graph->IsDebuggable()) return true;
+ // When compiling in OSR mode, all loops in the compiled method may be entered
+ // from the interpreter via SuspendCheck; thus we need to preserve the environment.
+ if (env_holder->IsSuspendCheck() && graph->IsCompilingOsr()) return true;
return instruction->GetType() == DataType::Type::kReference;
}
diff --git a/compiler/optimizing/ssa_liveness_analysis_test.cc b/compiler/optimizing/ssa_liveness_analysis_test.cc
index b9bfbaa..ae5e4e7 100644
--- a/compiler/optimizing/ssa_liveness_analysis_test.cc
+++ b/compiler/optimizing/ssa_liveness_analysis_test.cc
@@ -134,12 +134,12 @@
static const char* const expected[] = {
"ranges: { [2,21) }, uses: { 15 17 21 }, { 15 19 } is_fixed: 0, is_split: 0 is_low: 0 "
"is_high: 0",
- "ranges: { [4,21) }, uses: { 19 21 }, { 15 19 } is_fixed: 0, is_split: 0 is_low: 0 "
+ "ranges: { [4,21) }, uses: { 19 21 }, { } is_fixed: 0, is_split: 0 is_low: 0 "
"is_high: 0",
- "ranges: { [6,21) }, uses: { 21 }, { 15 19 } is_fixed: 0, is_split: 0 is_low: 0 "
+ "ranges: { [6,21) }, uses: { 21 }, { } is_fixed: 0, is_split: 0 is_low: 0 "
"is_high: 0",
// Environment uses do not keep the non-reference argument alive.
- "ranges: { [8,10) }, uses: { }, { 15 19 } is_fixed: 0, is_split: 0 is_low: 0 is_high: 0",
+ "ranges: { [8,10) }, uses: { }, { } is_fixed: 0, is_split: 0 is_low: 0 is_high: 0",
// Environment uses keep the reference argument alive.
"ranges: { [10,19) }, uses: { }, { 15 19 } is_fixed: 0, is_split: 0 is_low: 0 is_high: 0",
};
@@ -207,11 +207,11 @@
static const char* const expected[] = {
"ranges: { [2,23) }, uses: { 15 17 23 }, { 15 21 } is_fixed: 0, is_split: 0 is_low: 0 "
"is_high: 0",
- "ranges: { [4,23) }, uses: { 19 23 }, { 15 21 } is_fixed: 0, is_split: 0 is_low: 0 "
+ "ranges: { [4,23) }, uses: { 19 23 }, { 21 } is_fixed: 0, is_split: 0 is_low: 0 "
"is_high: 0",
- "ranges: { [6,23) }, uses: { 23 }, { 15 21 } is_fixed: 0, is_split: 0 is_low: 0 is_high: 0",
+ "ranges: { [6,23) }, uses: { 23 }, { 21 } is_fixed: 0, is_split: 0 is_low: 0 is_high: 0",
// Environment use in HDeoptimize keeps even the non-reference argument alive.
- "ranges: { [8,21) }, uses: { }, { 15 21 } is_fixed: 0, is_split: 0 is_low: 0 is_high: 0",
+ "ranges: { [8,21) }, uses: { }, { 21 } is_fixed: 0, is_split: 0 is_low: 0 is_high: 0",
// Environment uses keep the reference argument alive.
"ranges: { [10,21) }, uses: { }, { 15 21 } is_fixed: 0, is_split: 0 is_low: 0 is_high: 0",
};
diff --git a/dexlayout/compact_dex_writer.cc b/dexlayout/compact_dex_writer.cc
index 3f5dbcf..00fb0af 100644
--- a/dexlayout/compact_dex_writer.cc
+++ b/dexlayout/compact_dex_writer.cc
@@ -40,9 +40,8 @@
uint32_t CompactDexWriter::WriteDebugInfoOffsetTable(Stream* stream) {
const uint32_t start_offset = stream->Tell();
- const dex_ir::Collections& collections = header_->GetCollections();
// Debug offsets for method indexes. 0 means no debug info.
- std::vector<uint32_t> debug_info_offsets(collections.MethodIdsSize(), 0u);
+ std::vector<uint32_t> debug_info_offsets(header_->MethodIds().Size(), 0u);
static constexpr InvokeType invoke_types[] = {
kDirect,
@@ -50,7 +49,7 @@
};
for (InvokeType invoke_type : invoke_types) {
- for (const std::unique_ptr<dex_ir::ClassDef>& class_def : collections.ClassDefs()) {
+ for (auto& class_def : header_->ClassDefs()) {
// Skip classes that are not defined in this dex file.
dex_ir::ClassData* class_data = class_def->GetClassData();
if (class_data == nullptr) {
@@ -232,14 +231,13 @@
}
void CompactDexWriter::SortDebugInfosByMethodIndex() {
- dex_ir::Collections& collections = header_->GetCollections();
static constexpr InvokeType invoke_types[] = {
kDirect,
kVirtual
};
std::map<const dex_ir::DebugInfoItem*, uint32_t> method_idx_map;
for (InvokeType invoke_type : invoke_types) {
- for (std::unique_ptr<dex_ir::ClassDef>& class_def : collections.ClassDefs()) {
+ for (auto& class_def : header_->ClassDefs()) {
// Skip classes that are not defined in this dex file.
dex_ir::ClassData* class_data = class_def->GetClassData();
if (class_data == nullptr) {
@@ -257,8 +255,8 @@
}
}
}
- std::sort(collections.DebugInfoItems().begin(),
- collections.DebugInfoItems().end(),
+ std::sort(header_->DebugInfoItems().begin(),
+ header_->DebugInfoItems().end(),
[&](const std::unique_ptr<dex_ir::DebugInfoItem>& a,
const std::unique_ptr<dex_ir::DebugInfoItem>& b) {
auto it_a = method_idx_map.find(a.get());
@@ -282,20 +280,19 @@
header.endian_tag_ = header_->EndianTag();
header.link_size_ = header_->LinkSize();
header.link_off_ = header_->LinkOffset();
- const dex_ir::Collections& collections = header_->GetCollections();
- header.map_off_ = collections.MapListOffset();
- header.string_ids_size_ = collections.StringIdsSize();
- header.string_ids_off_ = collections.StringIdsOffset();
- header.type_ids_size_ = collections.TypeIdsSize();
- header.type_ids_off_ = collections.TypeIdsOffset();
- header.proto_ids_size_ = collections.ProtoIdsSize();
- header.proto_ids_off_ = collections.ProtoIdsOffset();
- header.field_ids_size_ = collections.FieldIdsSize();
- header.field_ids_off_ = collections.FieldIdsOffset();
- header.method_ids_size_ = collections.MethodIdsSize();
- header.method_ids_off_ = collections.MethodIdsOffset();
- header.class_defs_size_ = collections.ClassDefsSize();
- header.class_defs_off_ = collections.ClassDefsOffset();
+ header.map_off_ = header_->MapListOffset();
+ header.string_ids_size_ = header_->StringIds().Size();
+ header.string_ids_off_ = header_->StringIds().GetOffset();
+ header.type_ids_size_ = header_->TypeIds().Size();
+ header.type_ids_off_ = header_->TypeIds().GetOffset();
+ header.proto_ids_size_ = header_->ProtoIds().Size();
+ header.proto_ids_off_ = header_->ProtoIds().GetOffset();
+ header.field_ids_size_ = header_->FieldIds().Size();
+ header.field_ids_off_ = header_->FieldIds().GetOffset();
+ header.method_ids_size_ = header_->MethodIds().Size();
+ header.method_ids_off_ = header_->MethodIds().GetOffset();
+ header.class_defs_size_ = header_->ClassDefs().Size();
+ header.class_defs_off_ = header_->ClassDefs().GetOffset();
header.data_size_ = header_->DataSize();
header.data_off_ = header_->DataOffset();
header.owned_data_begin_ = owned_data_begin_;
@@ -332,16 +329,15 @@
}
bool CompactDexWriter::CanGenerateCompactDex(std::string* error_msg) {
- dex_ir::Collections& collections = header_->GetCollections();
static constexpr InvokeType invoke_types[] = {
kDirect,
kVirtual
};
- std::vector<bool> saw_method_id(collections.MethodIdsSize(), false);
- std::vector<dex_ir::CodeItem*> method_id_code_item(collections.MethodIdsSize(), nullptr);
- std::vector<dex_ir::DebugInfoItem*> method_id_debug_info(collections.MethodIdsSize(), nullptr);
+ std::vector<bool> saw_method_id(header_->MethodIds().Size(), false);
+ std::vector<dex_ir::CodeItem*> method_id_code_item(header_->MethodIds().Size(), nullptr);
+ std::vector<dex_ir::DebugInfoItem*> method_id_debug_info(header_->MethodIds().Size(), nullptr);
for (InvokeType invoke_type : invoke_types) {
- for (std::unique_ptr<dex_ir::ClassDef>& class_def : collections.ClassDefs()) {
+ for (auto& class_def : header_->ClassDefs()) {
// Skip classes that are not defined in this dex file.
dex_ir::ClassData* class_data = class_def->GetClassData();
if (class_data == nullptr) {
@@ -407,8 +403,6 @@
// Starting offset is right after the header.
main_stream->Seek(GetHeaderSize());
- dex_ir::Collections& collection = header_->GetCollections();
-
// Based on: https://source.android.com/devices/tech/dalvik/dex-format
// Since the offsets may not be calculated already, the writing must be done in the correct order.
const uint32_t string_ids_offset = main_stream->Tell();
@@ -469,16 +463,16 @@
// Write the map list.
if (compute_offsets_) {
data_stream->AlignTo(SectionAlignment(DexFile::kDexTypeMapList));
- collection.SetMapListOffset(data_stream->Tell());
+ header_->SetMapListOffset(data_stream->Tell());
} else {
- data_stream->Seek(collection.MapListOffset());
+ data_stream->Seek(header_->MapListOffset());
}
// Map items are included in the data section.
GenerateAndWriteMapItems(data_stream);
// Write link data if it exists.
- const std::vector<uint8_t>& link_data = collection.LinkData();
+ const std::vector<uint8_t>& link_data = header_->LinkData();
if (link_data.size() > 0) {
CHECK_EQ(header_->LinkSize(), static_cast<uint32_t>(link_data.size()));
if (compute_offsets_) {
diff --git a/dexlayout/dex_ir.cc b/dexlayout/dex_ir.cc
index 15e3baf..3917847 100644
--- a/dexlayout/dex_ir.cc
+++ b/dexlayout/dex_ir.cc
@@ -30,873 +30,11 @@
namespace art {
namespace dex_ir {
-static uint64_t ReadVarWidth(const uint8_t** data, uint8_t length, bool sign_extend) {
- uint64_t value = 0;
- for (uint32_t i = 0; i <= length; i++) {
- value |= static_cast<uint64_t>(*(*data)++) << (i * 8);
- }
- if (sign_extend) {
- int shift = (7 - length) * 8;
- return (static_cast<int64_t>(value) << shift) >> shift;
- }
- return value;
-}
-
-static uint32_t GetDebugInfoStreamSize(const uint8_t* debug_info_stream) {
- const uint8_t* stream = debug_info_stream;
- DecodeUnsignedLeb128(&stream); // line_start
- uint32_t parameters_size = DecodeUnsignedLeb128(&stream);
- for (uint32_t i = 0; i < parameters_size; ++i) {
- DecodeUnsignedLeb128P1(&stream); // Parameter name.
- }
-
- for (;;) {
- uint8_t opcode = *stream++;
- switch (opcode) {
- case DexFile::DBG_END_SEQUENCE:
- return stream - debug_info_stream; // end of stream.
- case DexFile::DBG_ADVANCE_PC:
- DecodeUnsignedLeb128(&stream); // addr_diff
- break;
- case DexFile::DBG_ADVANCE_LINE:
- DecodeSignedLeb128(&stream); // line_diff
- break;
- case DexFile::DBG_START_LOCAL:
- DecodeUnsignedLeb128(&stream); // register_num
- DecodeUnsignedLeb128P1(&stream); // name_idx
- DecodeUnsignedLeb128P1(&stream); // type_idx
- break;
- case DexFile::DBG_START_LOCAL_EXTENDED:
- DecodeUnsignedLeb128(&stream); // register_num
- DecodeUnsignedLeb128P1(&stream); // name_idx
- DecodeUnsignedLeb128P1(&stream); // type_idx
- DecodeUnsignedLeb128P1(&stream); // sig_idx
- break;
- case DexFile::DBG_END_LOCAL:
- case DexFile::DBG_RESTART_LOCAL:
- DecodeUnsignedLeb128(&stream); // register_num
- break;
- case DexFile::DBG_SET_PROLOGUE_END:
- case DexFile::DBG_SET_EPILOGUE_BEGIN:
- break;
- case DexFile::DBG_SET_FILE: {
- DecodeUnsignedLeb128P1(&stream); // name_idx
- break;
- }
- default: {
- break;
- }
- }
- }
-}
-
-static bool GetIdFromInstruction(Collections& collections,
- const Instruction* dec_insn,
- std::vector<TypeId*>* type_ids,
- std::vector<StringId*>* string_ids,
- std::vector<MethodId*>* method_ids,
- std::vector<FieldId*>* field_ids) {
- // Determine index and width of the string.
- uint32_t index = 0;
- switch (Instruction::FormatOf(dec_insn->Opcode())) {
- // SOME NOT SUPPORTED:
- // case Instruction::k20bc:
- case Instruction::k21c:
- case Instruction::k35c:
- // case Instruction::k35ms:
- case Instruction::k3rc:
- // case Instruction::k3rms:
- // case Instruction::k35mi:
- // case Instruction::k3rmi:
- case Instruction::k45cc:
- case Instruction::k4rcc:
- index = dec_insn->VRegB();
- break;
- case Instruction::k31c:
- index = dec_insn->VRegB();
- break;
- case Instruction::k22c:
- // case Instruction::k22cs:
- index = dec_insn->VRegC();
- break;
- default:
- break;
- } // switch
-
- // Determine index type, and add reference to the appropriate collection.
- switch (Instruction::IndexTypeOf(dec_insn->Opcode())) {
- case Instruction::kIndexTypeRef:
- if (index < collections.TypeIdsSize()) {
- type_ids->push_back(collections.GetTypeId(index));
- return true;
- }
- break;
- case Instruction::kIndexStringRef:
- if (index < collections.StringIdsSize()) {
- string_ids->push_back(collections.GetStringId(index));
- return true;
- }
- break;
- case Instruction::kIndexMethodRef:
- case Instruction::kIndexMethodAndProtoRef:
- if (index < collections.MethodIdsSize()) {
- method_ids->push_back(collections.GetMethodId(index));
- return true;
- }
- break;
- case Instruction::kIndexFieldRef:
- if (index < collections.FieldIdsSize()) {
- field_ids->push_back(collections.GetFieldId(index));
- return true;
- }
- break;
- case Instruction::kIndexUnknown:
- case Instruction::kIndexNone:
- case Instruction::kIndexVtableOffset:
- case Instruction::kIndexFieldOffset:
- default:
- break;
- } // switch
- return false;
-}
-
-/*
- * Get all the types, strings, methods, and fields referred to from bytecode.
- */
-static bool GetIdsFromByteCode(Collections& collections,
- const CodeItem* code,
- std::vector<TypeId*>* type_ids,
- std::vector<StringId*>* string_ids,
- std::vector<MethodId*>* method_ids,
- std::vector<FieldId*>* field_ids) {
- bool has_id = false;
- IterationRange<DexInstructionIterator> instructions = code->Instructions();
- SafeDexInstructionIterator it(instructions.begin(), instructions.end());
- for (; !it.IsErrorState() && it < instructions.end(); ++it) {
- // In case the instruction goes past the end of the code item, make sure to not process it.
- SafeDexInstructionIterator next = it;
- ++next;
- if (next.IsErrorState()) {
- break;
- }
- has_id |= GetIdFromInstruction(collections,
- &it.Inst(),
- type_ids,
- string_ids,
- method_ids,
- field_ids);
- } // for
- return has_id;
-}
-
-EncodedValue* Collections::ReadEncodedValue(const DexFile& dex_file, const uint8_t** data) {
- const uint8_t encoded_value = *(*data)++;
- const uint8_t type = encoded_value & 0x1f;
- EncodedValue* item = new EncodedValue(type);
- ReadEncodedValue(dex_file, data, type, encoded_value >> 5, item);
- return item;
-}
-
-EncodedValue* Collections::ReadEncodedValue(const DexFile& dex_file,
- const uint8_t** data,
- uint8_t type,
- uint8_t length) {
- EncodedValue* item = new EncodedValue(type);
- ReadEncodedValue(dex_file, data, type, length, item);
- return item;
-}
-
-void Collections::ReadEncodedValue(const DexFile& dex_file,
- const uint8_t** data,
- uint8_t type,
- uint8_t length,
- EncodedValue* item) {
- switch (type) {
- case DexFile::kDexAnnotationByte:
- item->SetByte(static_cast<int8_t>(ReadVarWidth(data, length, false)));
- break;
- case DexFile::kDexAnnotationShort:
- item->SetShort(static_cast<int16_t>(ReadVarWidth(data, length, true)));
- break;
- case DexFile::kDexAnnotationChar:
- item->SetChar(static_cast<uint16_t>(ReadVarWidth(data, length, false)));
- break;
- case DexFile::kDexAnnotationInt:
- item->SetInt(static_cast<int32_t>(ReadVarWidth(data, length, true)));
- break;
- case DexFile::kDexAnnotationLong:
- item->SetLong(static_cast<int64_t>(ReadVarWidth(data, length, true)));
- break;
- case DexFile::kDexAnnotationFloat: {
- // Fill on right.
- union {
- float f;
- uint32_t data;
- } conv;
- conv.data = static_cast<uint32_t>(ReadVarWidth(data, length, false)) << (3 - length) * 8;
- item->SetFloat(conv.f);
- break;
- }
- case DexFile::kDexAnnotationDouble: {
- // Fill on right.
- union {
- double d;
- uint64_t data;
- } conv;
- conv.data = ReadVarWidth(data, length, false) << (7 - length) * 8;
- item->SetDouble(conv.d);
- break;
- }
- case DexFile::kDexAnnotationMethodType: {
- const uint32_t proto_index = static_cast<uint32_t>(ReadVarWidth(data, length, false));
- item->SetProtoId(GetProtoId(proto_index));
- break;
- }
- case DexFile::kDexAnnotationMethodHandle: {
- const uint32_t method_handle_index = static_cast<uint32_t>(ReadVarWidth(data, length, false));
- item->SetMethodHandle(GetMethodHandle(method_handle_index));
- break;
- }
- case DexFile::kDexAnnotationString: {
- const uint32_t string_index = static_cast<uint32_t>(ReadVarWidth(data, length, false));
- item->SetStringId(GetStringId(string_index));
- break;
- }
- case DexFile::kDexAnnotationType: {
- const uint32_t string_index = static_cast<uint32_t>(ReadVarWidth(data, length, false));
- item->SetTypeId(GetTypeId(string_index));
- break;
- }
- case DexFile::kDexAnnotationField:
- case DexFile::kDexAnnotationEnum: {
- const uint32_t field_index = static_cast<uint32_t>(ReadVarWidth(data, length, false));
- item->SetFieldId(GetFieldId(field_index));
- break;
- }
- case DexFile::kDexAnnotationMethod: {
- const uint32_t method_index = static_cast<uint32_t>(ReadVarWidth(data, length, false));
- item->SetMethodId(GetMethodId(method_index));
- break;
- }
- case DexFile::kDexAnnotationArray: {
- EncodedValueVector* values = new EncodedValueVector();
- const uint32_t offset = *data - dex_file.DataBegin();
- const uint32_t size = DecodeUnsignedLeb128(data);
- // Decode all elements.
- for (uint32_t i = 0; i < size; i++) {
- values->push_back(std::unique_ptr<EncodedValue>(ReadEncodedValue(dex_file, data)));
- }
- EncodedArrayItem* array_item = new EncodedArrayItem(values);
- if (eagerly_assign_offsets_) {
- array_item->SetOffset(offset);
- }
- item->SetEncodedArray(array_item);
- break;
- }
- case DexFile::kDexAnnotationAnnotation: {
- AnnotationElementVector* elements = new AnnotationElementVector();
- const uint32_t type_idx = DecodeUnsignedLeb128(data);
- const uint32_t size = DecodeUnsignedLeb128(data);
- // Decode all name=value pairs.
- for (uint32_t i = 0; i < size; i++) {
- const uint32_t name_index = DecodeUnsignedLeb128(data);
- elements->push_back(std::unique_ptr<AnnotationElement>(
- new AnnotationElement(GetStringId(name_index), ReadEncodedValue(dex_file, data))));
- }
- item->SetEncodedAnnotation(new EncodedAnnotation(GetTypeId(type_idx), elements));
- break;
- }
- case DexFile::kDexAnnotationNull:
- break;
- case DexFile::kDexAnnotationBoolean:
- item->SetBoolean(length != 0);
- break;
- default:
- break;
- }
-}
-
-void Collections::CreateStringId(const DexFile& dex_file, uint32_t i) {
- const DexFile::StringId& disk_string_id = dex_file.GetStringId(dex::StringIndex(i));
- StringData* string_data = CreateAndAddItem(string_datas_map_,
- string_datas_,
- disk_string_id.string_data_off_,
- dex_file.GetStringData(disk_string_id));
- CreateAndAddIndexedItem(string_ids_,
- StringIdsOffset() + i * StringId::ItemSize(),
- i,
- string_data);
-}
-
-void Collections::CreateTypeId(const DexFile& dex_file, uint32_t i) {
- const DexFile::TypeId& disk_type_id = dex_file.GetTypeId(dex::TypeIndex(i));
- CreateAndAddIndexedItem(type_ids_,
- TypeIdsOffset() + i * TypeId::ItemSize(),
- i,
- GetStringId(disk_type_id.descriptor_idx_.index_));
-}
-
-void Collections::CreateProtoId(const DexFile& dex_file, uint32_t i) {
- const DexFile::ProtoId& disk_proto_id = dex_file.GetProtoId(dex::ProtoIndex(i));
- const DexFile::TypeList* type_list = dex_file.GetProtoParameters(disk_proto_id);
- TypeList* parameter_type_list = CreateTypeList(type_list, disk_proto_id.parameters_off_);
-
- CreateAndAddIndexedItem(proto_ids_,
- ProtoIdsOffset() + i * ProtoId::ItemSize(),
- i,
- GetStringId(disk_proto_id.shorty_idx_.index_),
- GetTypeId(disk_proto_id.return_type_idx_.index_),
- parameter_type_list);
-}
-
-void Collections::CreateFieldId(const DexFile& dex_file, uint32_t i) {
- const DexFile::FieldId& disk_field_id = dex_file.GetFieldId(i);
- CreateAndAddIndexedItem(field_ids_,
- FieldIdsOffset() + i * FieldId::ItemSize(),
- i,
- GetTypeId(disk_field_id.class_idx_.index_),
- GetTypeId(disk_field_id.type_idx_.index_),
- GetStringId(disk_field_id.name_idx_.index_));
-}
-
-void Collections::CreateMethodId(const DexFile& dex_file, uint32_t i) {
- const DexFile::MethodId& disk_method_id = dex_file.GetMethodId(i);
- CreateAndAddIndexedItem(method_ids_,
- MethodIdsOffset() + i * MethodId::ItemSize(),
- i,
- GetTypeId(disk_method_id.class_idx_.index_),
- GetProtoId(disk_method_id.proto_idx_.index_),
- GetStringId(disk_method_id.name_idx_.index_));
-}
-
-void Collections::CreateClassDef(const DexFile& dex_file, uint32_t i) {
- const DexFile::ClassDef& disk_class_def = dex_file.GetClassDef(i);
- const TypeId* class_type = GetTypeId(disk_class_def.class_idx_.index_);
- uint32_t access_flags = disk_class_def.access_flags_;
- const TypeId* superclass = GetTypeIdOrNullPtr(disk_class_def.superclass_idx_.index_);
-
- const DexFile::TypeList* type_list = dex_file.GetInterfacesList(disk_class_def);
- TypeList* interfaces_type_list = CreateTypeList(type_list, disk_class_def.interfaces_off_);
-
- const StringId* source_file = GetStringIdOrNullPtr(disk_class_def.source_file_idx_.index_);
- // Annotations.
- AnnotationsDirectoryItem* annotations = nullptr;
- const DexFile::AnnotationsDirectoryItem* disk_annotations_directory_item =
- dex_file.GetAnnotationsDirectory(disk_class_def);
- if (disk_annotations_directory_item != nullptr) {
- annotations = CreateAnnotationsDirectoryItem(
- dex_file, disk_annotations_directory_item, disk_class_def.annotations_off_);
- }
- // Static field initializers.
- const uint8_t* static_data = dex_file.GetEncodedStaticFieldValuesArray(disk_class_def);
- EncodedArrayItem* static_values =
- CreateEncodedArrayItem(dex_file, static_data, disk_class_def.static_values_off_);
- ClassData* class_data = CreateClassData(
- dex_file, dex_file.GetClassData(disk_class_def), disk_class_def.class_data_off_);
- CreateAndAddIndexedItem(class_defs_,
- ClassDefsOffset() + i * ClassDef::ItemSize(),
- i,
- class_type,
- access_flags,
- superclass,
- interfaces_type_list,
- source_file,
- annotations,
- static_values,
- class_data);
-}
-
-TypeList* Collections::CreateTypeList(const DexFile::TypeList* dex_type_list, uint32_t offset) {
- if (dex_type_list == nullptr) {
- return nullptr;
- }
- TypeList* type_list = type_lists_map_.GetExistingObject(offset);
- if (type_list == nullptr) {
- TypeIdVector* type_vector = new TypeIdVector();
- uint32_t size = dex_type_list->Size();
- for (uint32_t index = 0; index < size; ++index) {
- type_vector->push_back(GetTypeId(dex_type_list->GetTypeItem(index).type_idx_.index_));
- }
- type_list = CreateAndAddItem(type_lists_map_, type_lists_, offset, type_vector);
- }
- return type_list;
-}
-
-EncodedArrayItem* Collections::CreateEncodedArrayItem(const DexFile& dex_file,
- const uint8_t* static_data,
- uint32_t offset) {
- if (static_data == nullptr) {
- return nullptr;
- }
- EncodedArrayItem* encoded_array_item = encoded_array_items_map_.GetExistingObject(offset);
- if (encoded_array_item == nullptr) {
- uint32_t size = DecodeUnsignedLeb128(&static_data);
- EncodedValueVector* values = new EncodedValueVector();
- for (uint32_t i = 0; i < size; ++i) {
- values->push_back(std::unique_ptr<EncodedValue>(ReadEncodedValue(dex_file, &static_data)));
- }
- // TODO: Calculate the size of the encoded array.
- encoded_array_item = CreateAndAddItem(encoded_array_items_map_,
- encoded_array_items_,
- offset,
- values);
- }
- return encoded_array_item;
-}
-
-void Collections::AddAnnotationsFromMapListSection(const DexFile& dex_file,
- uint32_t start_offset,
- uint32_t count) {
- uint32_t current_offset = start_offset;
- for (size_t i = 0; i < count; ++i) {
- // Annotation that we didn't process already, add it to the set.
- const DexFile::AnnotationItem* annotation = dex_file.GetAnnotationItemAtOffset(current_offset);
- AnnotationItem* annotation_item = CreateAnnotationItem(dex_file, annotation);
- DCHECK(annotation_item != nullptr);
- current_offset += annotation_item->GetSize();
- }
-}
-
-AnnotationItem* Collections::CreateAnnotationItem(const DexFile& dex_file,
- const DexFile::AnnotationItem* annotation) {
- const uint8_t* const start_data = reinterpret_cast<const uint8_t*>(annotation);
- const uint32_t offset = start_data - dex_file.DataBegin();
- AnnotationItem* annotation_item = annotation_items_map_.GetExistingObject(offset);
- if (annotation_item == nullptr) {
- uint8_t visibility = annotation->visibility_;
- const uint8_t* annotation_data = annotation->annotation_;
- std::unique_ptr<EncodedValue> encoded_value(
- ReadEncodedValue(dex_file, &annotation_data, DexFile::kDexAnnotationAnnotation, 0));
- annotation_item = CreateAndAddItem(annotation_items_map_,
- annotation_items_,
- offset,
- visibility,
- encoded_value->ReleaseEncodedAnnotation());
- annotation_item->SetSize(annotation_data - start_data);
- }
- return annotation_item;
-}
-
-
-AnnotationSetItem* Collections::CreateAnnotationSetItem(const DexFile& dex_file,
- const DexFile::AnnotationSetItem* disk_annotations_item, uint32_t offset) {
- if (disk_annotations_item == nullptr || (disk_annotations_item->size_ == 0 && offset == 0)) {
- return nullptr;
- }
- AnnotationSetItem* annotation_set_item = annotation_set_items_map_.GetExistingObject(offset);
- if (annotation_set_item == nullptr) {
- std::vector<AnnotationItem*>* items = new std::vector<AnnotationItem*>();
- for (uint32_t i = 0; i < disk_annotations_item->size_; ++i) {
- const DexFile::AnnotationItem* annotation =
- dex_file.GetAnnotationItem(disk_annotations_item, i);
- if (annotation == nullptr) {
- continue;
- }
- AnnotationItem* annotation_item = CreateAnnotationItem(dex_file, annotation);
- items->push_back(annotation_item);
- }
- annotation_set_item = CreateAndAddItem(annotation_set_items_map_,
- annotation_set_items_,
- offset,
- items);
- }
- return annotation_set_item;
-}
-
-AnnotationsDirectoryItem* Collections::CreateAnnotationsDirectoryItem(const DexFile& dex_file,
- const DexFile::AnnotationsDirectoryItem* disk_annotations_item, uint32_t offset) {
- AnnotationsDirectoryItem* annotations_directory_item =
- annotations_directory_items_map_.GetExistingObject(offset);
- if (annotations_directory_item != nullptr) {
- return annotations_directory_item;
- }
- const DexFile::AnnotationSetItem* class_set_item =
- dex_file.GetClassAnnotationSet(disk_annotations_item);
- AnnotationSetItem* class_annotation = nullptr;
- if (class_set_item != nullptr) {
- uint32_t item_offset = disk_annotations_item->class_annotations_off_;
- class_annotation = CreateAnnotationSetItem(dex_file, class_set_item, item_offset);
- }
- const DexFile::FieldAnnotationsItem* fields =
- dex_file.GetFieldAnnotations(disk_annotations_item);
- FieldAnnotationVector* field_annotations = nullptr;
- if (fields != nullptr) {
- field_annotations = new FieldAnnotationVector();
- for (uint32_t i = 0; i < disk_annotations_item->fields_size_; ++i) {
- FieldId* field_id = GetFieldId(fields[i].field_idx_);
- const DexFile::AnnotationSetItem* field_set_item =
- dex_file.GetFieldAnnotationSetItem(fields[i]);
- uint32_t annotation_set_offset = fields[i].annotations_off_;
- AnnotationSetItem* annotation_set_item =
- CreateAnnotationSetItem(dex_file, field_set_item, annotation_set_offset);
- field_annotations->push_back(std::unique_ptr<FieldAnnotation>(
- new FieldAnnotation(field_id, annotation_set_item)));
- }
- }
- const DexFile::MethodAnnotationsItem* methods =
- dex_file.GetMethodAnnotations(disk_annotations_item);
- MethodAnnotationVector* method_annotations = nullptr;
- if (methods != nullptr) {
- method_annotations = new MethodAnnotationVector();
- for (uint32_t i = 0; i < disk_annotations_item->methods_size_; ++i) {
- MethodId* method_id = GetMethodId(methods[i].method_idx_);
- const DexFile::AnnotationSetItem* method_set_item =
- dex_file.GetMethodAnnotationSetItem(methods[i]);
- uint32_t annotation_set_offset = methods[i].annotations_off_;
- AnnotationSetItem* annotation_set_item =
- CreateAnnotationSetItem(dex_file, method_set_item, annotation_set_offset);
- method_annotations->push_back(std::unique_ptr<MethodAnnotation>(
- new MethodAnnotation(method_id, annotation_set_item)));
- }
- }
- const DexFile::ParameterAnnotationsItem* parameters =
- dex_file.GetParameterAnnotations(disk_annotations_item);
- ParameterAnnotationVector* parameter_annotations = nullptr;
- if (parameters != nullptr) {
- parameter_annotations = new ParameterAnnotationVector();
- for (uint32_t i = 0; i < disk_annotations_item->parameters_size_; ++i) {
- MethodId* method_id = GetMethodId(parameters[i].method_idx_);
- const DexFile::AnnotationSetRefList* list =
- dex_file.GetParameterAnnotationSetRefList(¶meters[i]);
- parameter_annotations->push_back(std::unique_ptr<ParameterAnnotation>(
- GenerateParameterAnnotation(dex_file, method_id, list, parameters[i].annotations_off_)));
- }
- }
- // TODO: Calculate the size of the annotations directory.
- return CreateAndAddItem(annotations_directory_items_map_,
- annotations_directory_items_,
- offset,
- class_annotation,
- field_annotations,
- method_annotations,
- parameter_annotations);
-}
-
-ParameterAnnotation* Collections::GenerateParameterAnnotation(
- const DexFile& dex_file, MethodId* method_id,
- const DexFile::AnnotationSetRefList* annotation_set_ref_list, uint32_t offset) {
- AnnotationSetRefList* set_ref_list = annotation_set_ref_lists_map_.GetExistingObject(offset);
- if (set_ref_list == nullptr) {
- std::vector<AnnotationSetItem*>* annotations = new std::vector<AnnotationSetItem*>();
- for (uint32_t i = 0; i < annotation_set_ref_list->size_; ++i) {
- const DexFile::AnnotationSetItem* annotation_set_item =
- dex_file.GetSetRefItemItem(&annotation_set_ref_list->list_[i]);
- uint32_t set_offset = annotation_set_ref_list->list_[i].annotations_off_;
- annotations->push_back(CreateAnnotationSetItem(dex_file, annotation_set_item, set_offset));
- }
- set_ref_list = CreateAndAddItem(annotation_set_ref_lists_map_,
- annotation_set_ref_lists_,
- offset,
- annotations);
- }
- return new ParameterAnnotation(method_id, set_ref_list);
-}
-
-CodeItem* Collections::DedupeOrCreateCodeItem(const DexFile& dex_file,
- const DexFile::CodeItem* disk_code_item,
- uint32_t offset,
- uint32_t dex_method_index) {
- if (disk_code_item == nullptr) {
- return nullptr;
- }
- CodeItemDebugInfoAccessor accessor(dex_file, disk_code_item, dex_method_index);
- const uint32_t debug_info_offset = accessor.DebugInfoOffset();
-
- // Create the offsets pair and dedupe based on it.
- std::pair<uint32_t, uint32_t> offsets_pair(offset, debug_info_offset);
- auto existing = code_items_map_.find(offsets_pair);
- if (existing != code_items_map_.end()) {
- return existing->second;
- }
-
- const uint8_t* debug_info_stream = dex_file.GetDebugInfoStream(debug_info_offset);
- DebugInfoItem* debug_info = nullptr;
- if (debug_info_stream != nullptr) {
- debug_info = debug_info_items_map_.GetExistingObject(debug_info_offset);
- if (debug_info == nullptr) {
- uint32_t debug_info_size = GetDebugInfoStreamSize(debug_info_stream);
- uint8_t* debug_info_buffer = new uint8_t[debug_info_size];
- memcpy(debug_info_buffer, debug_info_stream, debug_info_size);
- debug_info = CreateAndAddItem(debug_info_items_map_,
- debug_info_items_,
- debug_info_offset,
- debug_info_size,
- debug_info_buffer);
- }
- }
-
- uint32_t insns_size = accessor.InsnsSizeInCodeUnits();
- uint16_t* insns = new uint16_t[insns_size];
- memcpy(insns, accessor.Insns(), insns_size * sizeof(uint16_t));
-
- TryItemVector* tries = nullptr;
- CatchHandlerVector* handler_list = nullptr;
- if (accessor.TriesSize() > 0) {
- tries = new TryItemVector();
- handler_list = new CatchHandlerVector();
- for (const DexFile::TryItem& disk_try_item : accessor.TryItems()) {
- uint32_t start_addr = disk_try_item.start_addr_;
- uint16_t insn_count = disk_try_item.insn_count_;
- uint16_t handler_off = disk_try_item.handler_off_;
- const CatchHandler* handlers = nullptr;
- for (std::unique_ptr<const CatchHandler>& existing_handlers : *handler_list) {
- if (handler_off == existing_handlers->GetListOffset()) {
- handlers = existing_handlers.get();
- break;
- }
- }
- if (handlers == nullptr) {
- bool catch_all = false;
- TypeAddrPairVector* addr_pairs = new TypeAddrPairVector();
- for (CatchHandlerIterator it(accessor, disk_try_item); it.HasNext(); it.Next()) {
- const dex::TypeIndex type_index = it.GetHandlerTypeIndex();
- const TypeId* type_id = GetTypeIdOrNullPtr(type_index.index_);
- catch_all |= type_id == nullptr;
- addr_pairs->push_back(std::unique_ptr<const TypeAddrPair>(
- new TypeAddrPair(type_id, it.GetHandlerAddress())));
- }
- handlers = new CatchHandler(catch_all, handler_off, addr_pairs);
- handler_list->push_back(std::unique_ptr<const CatchHandler>(handlers));
- }
- TryItem* try_item = new TryItem(start_addr, insn_count, handlers);
- tries->push_back(std::unique_ptr<const TryItem>(try_item));
- }
- // Manually walk catch handlers list and add any missing handlers unreferenced by try items.
- const uint8_t* handlers_base = accessor.GetCatchHandlerData();
- const uint8_t* handlers_data = handlers_base;
- uint32_t handlers_size = DecodeUnsignedLeb128(&handlers_data);
- while (handlers_size > handler_list->size()) {
- bool already_added = false;
- uint16_t handler_off = handlers_data - handlers_base;
- for (std::unique_ptr<const CatchHandler>& existing_handlers : *handler_list) {
- if (handler_off == existing_handlers->GetListOffset()) {
- already_added = true;
- break;
- }
- }
- int32_t size = DecodeSignedLeb128(&handlers_data);
- bool has_catch_all = size <= 0;
- if (has_catch_all) {
- size = -size;
- }
- if (already_added) {
- for (int32_t i = 0; i < size; i++) {
- DecodeUnsignedLeb128(&handlers_data);
- DecodeUnsignedLeb128(&handlers_data);
- }
- if (has_catch_all) {
- DecodeUnsignedLeb128(&handlers_data);
- }
- continue;
- }
- TypeAddrPairVector* addr_pairs = new TypeAddrPairVector();
- for (int32_t i = 0; i < size; i++) {
- const TypeId* type_id = GetTypeIdOrNullPtr(DecodeUnsignedLeb128(&handlers_data));
- uint32_t addr = DecodeUnsignedLeb128(&handlers_data);
- addr_pairs->push_back(
- std::unique_ptr<const TypeAddrPair>(new TypeAddrPair(type_id, addr)));
- }
- if (has_catch_all) {
- uint32_t addr = DecodeUnsignedLeb128(&handlers_data);
- addr_pairs->push_back(
- std::unique_ptr<const TypeAddrPair>(new TypeAddrPair(nullptr, addr)));
- }
- const CatchHandler* handler = new CatchHandler(has_catch_all, handler_off, addr_pairs);
- handler_list->push_back(std::unique_ptr<const CatchHandler>(handler));
- }
- }
-
- uint32_t size = dex_file.GetCodeItemSize(*disk_code_item);
- CodeItem* code_item = code_items_.CreateAndAddItem(accessor.RegistersSize(),
- accessor.InsSize(),
- accessor.OutsSize(),
- debug_info,
- insns_size,
- insns,
- tries,
- handler_list);
- code_item->SetSize(size);
-
- // Add the code item to the map.
- DCHECK(!code_item->OffsetAssigned());
- if (eagerly_assign_offsets_) {
- code_item->SetOffset(offset);
- }
- code_items_map_.emplace(offsets_pair, code_item);
-
- // Add "fixup" references to types, strings, methods, and fields.
- // This is temporary, as we will probably want more detailed parsing of the
- // instructions here.
- std::vector<TypeId*> type_ids;
- std::vector<StringId*> string_ids;
- std::vector<MethodId*> method_ids;
- std::vector<FieldId*> field_ids;
- if (GetIdsFromByteCode(*this,
- code_item,
- /*out*/ &type_ids,
- /*out*/ &string_ids,
- /*out*/ &method_ids,
- /*out*/ &field_ids)) {
- CodeFixups* fixups = new CodeFixups(std::move(type_ids),
- std::move(string_ids),
- std::move(method_ids),
- std::move(field_ids));
- code_item->SetCodeFixups(fixups);
- }
-
- return code_item;
-}
-
-MethodItem Collections::GenerateMethodItem(const DexFile& dex_file, ClassDataItemIterator& cdii) {
- MethodId* method_id = GetMethodId(cdii.GetMemberIndex());
- uint32_t access_flags = cdii.GetRawMemberAccessFlags();
- const DexFile::CodeItem* disk_code_item = cdii.GetMethodCodeItem();
- // Temporary hack to prevent incorrectly deduping code items if they have the same offset since
- // they may have different debug info streams.
- CodeItem* code_item = DedupeOrCreateCodeItem(dex_file,
- disk_code_item,
- cdii.GetMethodCodeItemOffset(),
- cdii.GetMemberIndex());
- return MethodItem(access_flags, method_id, code_item);
-}
-
-ClassData* Collections::CreateClassData(
- const DexFile& dex_file, const uint8_t* encoded_data, uint32_t offset) {
- // Read the fields and methods defined by the class, resolving the circular reference from those
- // to classes by setting class at the same time.
- ClassData* class_data = class_datas_map_.GetExistingObject(offset);
- if (class_data == nullptr && encoded_data != nullptr) {
- ClassDataItemIterator cdii(dex_file, encoded_data);
- // Static fields.
- FieldItemVector* static_fields = new FieldItemVector();
- for (; cdii.HasNextStaticField(); cdii.Next()) {
- FieldId* field_item = GetFieldId(cdii.GetMemberIndex());
- uint32_t access_flags = cdii.GetRawMemberAccessFlags();
- static_fields->emplace_back(access_flags, field_item);
- }
- // Instance fields.
- FieldItemVector* instance_fields = new FieldItemVector();
- for (; cdii.HasNextInstanceField(); cdii.Next()) {
- FieldId* field_item = GetFieldId(cdii.GetMemberIndex());
- uint32_t access_flags = cdii.GetRawMemberAccessFlags();
- instance_fields->emplace_back(access_flags, field_item);
- }
- // Direct methods.
- MethodItemVector* direct_methods = new MethodItemVector();
- for (; cdii.HasNextDirectMethod(); cdii.Next()) {
- direct_methods->push_back(GenerateMethodItem(dex_file, cdii));
- }
- // Virtual methods.
- MethodItemVector* virtual_methods = new MethodItemVector();
- for (; cdii.HasNextVirtualMethod(); cdii.Next()) {
- virtual_methods->push_back(GenerateMethodItem(dex_file, cdii));
- }
- class_data = CreateAndAddItem(class_datas_map_,
- class_datas_,
- offset,
- static_fields,
- instance_fields,
- direct_methods,
- virtual_methods);
- class_data->SetSize(cdii.EndDataPointer() - encoded_data);
- }
- return class_data;
-}
-
-void Collections::CreateCallSitesAndMethodHandles(const DexFile& dex_file) {
- // Iterate through the map list and set the offset of the CallSiteIds and MethodHandleItems.
- const DexFile::MapList* map = dex_file.GetMapList();
- for (uint32_t i = 0; i < map->size_; ++i) {
- const DexFile::MapItem* item = map->list_ + i;
- switch (item->type_) {
- case DexFile::kDexTypeCallSiteIdItem:
- SetCallSiteIdsOffset(item->offset_);
- break;
- case DexFile::kDexTypeMethodHandleItem:
- SetMethodHandleItemsOffset(item->offset_);
- break;
- default:
- break;
- }
- }
- // Populate MethodHandleItems first (CallSiteIds may depend on them).
- for (uint32_t i = 0; i < dex_file.NumMethodHandles(); i++) {
- CreateMethodHandleItem(dex_file, i);
- }
- // Populate CallSiteIds.
- for (uint32_t i = 0; i < dex_file.NumCallSiteIds(); i++) {
- CreateCallSiteId(dex_file, i);
- }
-}
-
-void Collections::CreateCallSiteId(const DexFile& dex_file, uint32_t i) {
- const DexFile::CallSiteIdItem& disk_call_site_id = dex_file.GetCallSiteId(i);
- const uint8_t* disk_call_item_ptr = dex_file.DataBegin() + disk_call_site_id.data_off_;
- EncodedArrayItem* call_site_item =
- CreateEncodedArrayItem(dex_file, disk_call_item_ptr, disk_call_site_id.data_off_);
-
- CreateAndAddIndexedItem(call_site_ids_,
- CallSiteIdsOffset() + i * CallSiteId::ItemSize(),
- i,
- call_site_item);
-}
-
-void Collections::CreateMethodHandleItem(const DexFile& dex_file, uint32_t i) {
- const DexFile::MethodHandleItem& disk_method_handle = dex_file.GetMethodHandle(i);
- uint16_t index = disk_method_handle.field_or_method_idx_;
- DexFile::MethodHandleType type =
- static_cast<DexFile::MethodHandleType>(disk_method_handle.method_handle_type_);
- bool is_invoke = type == DexFile::MethodHandleType::kInvokeStatic ||
- type == DexFile::MethodHandleType::kInvokeInstance ||
- type == DexFile::MethodHandleType::kInvokeConstructor ||
- type == DexFile::MethodHandleType::kInvokeDirect ||
- type == DexFile::MethodHandleType::kInvokeInterface;
- static_assert(DexFile::MethodHandleType::kLast == DexFile::MethodHandleType::kInvokeInterface,
- "Unexpected method handle types.");
- IndexedItem* field_or_method_id;
- if (is_invoke) {
- field_or_method_id = GetMethodId(index);
- } else {
- field_or_method_id = GetFieldId(index);
- }
- CreateAndAddIndexedItem(method_handle_items_,
- MethodHandleItemsOffset() + i * MethodHandleItem::ItemSize(),
- i,
- type,
- field_or_method_id);
-}
-
-void Collections::SortVectorsByMapOrder() {
- string_datas_.SortByMapOrder(string_datas_map_.Collection());
- type_lists_.SortByMapOrder(type_lists_map_.Collection());
- encoded_array_items_.SortByMapOrder(encoded_array_items_map_.Collection());
- annotation_items_.SortByMapOrder(annotation_items_map_.Collection());
- annotation_set_items_.SortByMapOrder(annotation_set_items_map_.Collection());
- annotation_set_ref_lists_.SortByMapOrder(annotation_set_ref_lists_map_.Collection());
- annotations_directory_items_.SortByMapOrder(annotations_directory_items_map_.Collection());
- debug_info_items_.SortByMapOrder(debug_info_items_map_.Collection());
- code_items_.SortByMapOrder(code_items_map_);
- class_datas_.SortByMapOrder(class_datas_map_.Collection());
-}
-
-void Collections::ClearMaps() {
- string_datas_map_.Collection().clear();
- type_lists_map_.Collection().clear();
- encoded_array_items_map_.Collection().clear();
- annotation_items_map_.Collection().clear();
- annotation_set_items_map_.Collection().clear();
- annotation_set_ref_lists_map_.Collection().clear();
- annotations_directory_items_map_.Collection().clear();
- debug_info_items_map_.Collection().clear();
- code_items_map_.clear();
- class_datas_map_.Collection().clear();
-}
-
-static uint32_t HeaderOffset(const dex_ir::Collections& collections ATTRIBUTE_UNUSED) {
+static uint32_t HeaderOffset(const dex_ir::Header* header ATTRIBUTE_UNUSED) {
return 0;
}
-static uint32_t HeaderSize(const dex_ir::Collections& collections ATTRIBUTE_UNUSED) {
+static uint32_t HeaderSize(const dex_ir::Header* header ATTRIBUTE_UNUSED) {
// Size is in elements, so there is only one header.
return 1;
}
@@ -907,9 +45,9 @@
std::string name;
uint16_t type;
// A function that when applied to a collection object, gives the size of the section.
- std::function<uint32_t(const dex_ir::Collections&)> size_fn;
+ std::function<uint32_t(dex_ir::Header*)> size_fn;
// A function that when applied to a collection object, gives the offset of the section.
- std::function<uint32_t(const dex_ir::Collections&)> offset_fn;
+ std::function<uint32_t(dex_ir::Header*)> offset_fn;
};
static const FileSectionDescriptor kFileSectionDescriptors[] = {
@@ -921,106 +59,105 @@
}, {
"StringId",
DexFile::kDexTypeStringIdItem,
- &dex_ir::Collections::StringIdsSize,
- &dex_ir::Collections::StringIdsOffset
+ [](const dex_ir::Header* h) { return h->StringIds().Size(); },
+ [](const dex_ir::Header* h) { return h->StringIds().GetOffset(); }
}, {
"TypeId",
DexFile::kDexTypeTypeIdItem,
- &dex_ir::Collections::TypeIdsSize,
- &dex_ir::Collections::TypeIdsOffset
+ [](const dex_ir::Header* h) { return h->TypeIds().Size(); },
+ [](const dex_ir::Header* h) { return h->TypeIds().GetOffset(); }
}, {
"ProtoId",
DexFile::kDexTypeProtoIdItem,
- &dex_ir::Collections::ProtoIdsSize,
- &dex_ir::Collections::ProtoIdsOffset
+ [](const dex_ir::Header* h) { return h->ProtoIds().Size(); },
+ [](const dex_ir::Header* h) { return h->ProtoIds().GetOffset(); }
}, {
"FieldId",
DexFile::kDexTypeFieldIdItem,
- &dex_ir::Collections::FieldIdsSize,
- &dex_ir::Collections::FieldIdsOffset
+ [](const dex_ir::Header* h) { return h->FieldIds().Size(); },
+ [](const dex_ir::Header* h) { return h->FieldIds().GetOffset(); }
}, {
"MethodId",
DexFile::kDexTypeMethodIdItem,
- &dex_ir::Collections::MethodIdsSize,
- &dex_ir::Collections::MethodIdsOffset
+ [](const dex_ir::Header* h) { return h->MethodIds().Size(); },
+ [](const dex_ir::Header* h) { return h->MethodIds().GetOffset(); }
}, {
"ClassDef",
DexFile::kDexTypeClassDefItem,
- &dex_ir::Collections::ClassDefsSize,
- &dex_ir::Collections::ClassDefsOffset
+ [](const dex_ir::Header* h) { return h->ClassDefs().Size(); },
+ [](const dex_ir::Header* h) { return h->ClassDefs().GetOffset(); }
}, {
"CallSiteId",
DexFile::kDexTypeCallSiteIdItem,
- &dex_ir::Collections::CallSiteIdsSize,
- &dex_ir::Collections::CallSiteIdsOffset
+ [](const dex_ir::Header* h) { return h->CallSiteIds().Size(); },
+ [](const dex_ir::Header* h) { return h->CallSiteIds().GetOffset(); }
}, {
"MethodHandle",
DexFile::kDexTypeMethodHandleItem,
- &dex_ir::Collections::MethodHandleItemsSize,
- &dex_ir::Collections::MethodHandleItemsOffset
+ [](const dex_ir::Header* h) { return h->MethodHandleItems().Size(); },
+ [](const dex_ir::Header* h) { return h->MethodHandleItems().GetOffset(); }
}, {
"StringData",
DexFile::kDexTypeStringDataItem,
- &dex_ir::Collections::StringDatasSize,
- &dex_ir::Collections::StringDatasOffset
+ [](const dex_ir::Header* h) { return h->StringDatas().Size(); },
+ [](const dex_ir::Header* h) { return h->StringDatas().GetOffset(); }
}, {
"TypeList",
DexFile::kDexTypeTypeList,
- &dex_ir::Collections::TypeListsSize,
- &dex_ir::Collections::TypeListsOffset
+ [](const dex_ir::Header* h) { return h->TypeLists().Size(); },
+ [](const dex_ir::Header* h) { return h->TypeLists().GetOffset(); }
}, {
"EncArr",
DexFile::kDexTypeEncodedArrayItem,
- &dex_ir::Collections::EncodedArrayItemsSize,
- &dex_ir::Collections::EncodedArrayItemsOffset
+ [](const dex_ir::Header* h) { return h->EncodedArrayItems().Size(); },
+ [](const dex_ir::Header* h) { return h->EncodedArrayItems().GetOffset(); }
}, {
"Annotation",
DexFile::kDexTypeAnnotationItem,
- &dex_ir::Collections::AnnotationItemsSize,
- &dex_ir::Collections::AnnotationItemsOffset
+ [](const dex_ir::Header* h) { return h->AnnotationItems().Size(); },
+ [](const dex_ir::Header* h) { return h->AnnotationItems().GetOffset(); }
}, {
"AnnoSet",
DexFile::kDexTypeAnnotationSetItem,
- &dex_ir::Collections::AnnotationSetItemsSize,
- &dex_ir::Collections::AnnotationSetItemsOffset
+ [](const dex_ir::Header* h) { return h->AnnotationSetItems().Size(); },
+ [](const dex_ir::Header* h) { return h->AnnotationSetItems().GetOffset(); }
}, {
"AnnoSetRL",
DexFile::kDexTypeAnnotationSetRefList,
- &dex_ir::Collections::AnnotationSetRefListsSize,
- &dex_ir::Collections::AnnotationSetRefListsOffset
+ [](const dex_ir::Header* h) { return h->AnnotationSetRefLists().Size(); },
+ [](const dex_ir::Header* h) { return h->AnnotationSetRefLists().GetOffset(); }
}, {
"AnnoDir",
DexFile::kDexTypeAnnotationsDirectoryItem,
- &dex_ir::Collections::AnnotationsDirectoryItemsSize,
- &dex_ir::Collections::AnnotationsDirectoryItemsOffset
+ [](const dex_ir::Header* h) { return h->AnnotationsDirectoryItems().Size(); },
+ [](const dex_ir::Header* h) { return h->AnnotationsDirectoryItems().GetOffset(); }
}, {
"DebugInfo",
DexFile::kDexTypeDebugInfoItem,
- &dex_ir::Collections::DebugInfoItemsSize,
- &dex_ir::Collections::DebugInfoItemsOffset
+ [](const dex_ir::Header* h) { return h->DebugInfoItems().Size(); },
+ [](const dex_ir::Header* h) { return h->DebugInfoItems().GetOffset(); }
}, {
"CodeItem",
DexFile::kDexTypeCodeItem,
- &dex_ir::Collections::CodeItemsSize,
- &dex_ir::Collections::CodeItemsOffset
+ [](const dex_ir::Header* h) { return h->CodeItems().Size(); },
+ [](const dex_ir::Header* h) { return h->CodeItems().GetOffset(); }
}, {
"ClassData",
DexFile::kDexTypeClassDataItem,
- &dex_ir::Collections::ClassDatasSize,
- &dex_ir::Collections::ClassDatasOffset
+ [](const dex_ir::Header* h) { return h->ClassDatas().Size(); },
+ [](const dex_ir::Header* h) { return h->ClassDatas().GetOffset(); }
}
};
std::vector<dex_ir::DexFileSection> GetSortedDexFileSections(dex_ir::Header* header,
dex_ir::SortDirection direction) {
- const dex_ir::Collections& collections = header->GetCollections();
std::vector<dex_ir::DexFileSection> sorted_sections;
// Build the table that will map from offset to color
for (const FileSectionDescriptor& s : kFileSectionDescriptors) {
sorted_sections.push_back(dex_ir::DexFileSection(s.name,
s.type,
- s.size_fn(collections),
- s.offset_fn(collections)));
+ s.size_fn(header),
+ s.offset_fn(header)));
}
// Sort by offset.
std::sort(sorted_sections.begin(),
diff --git a/dexlayout/dex_ir.h b/dexlayout/dex_ir.h
index 54ff105..9f355ba 100644
--- a/dexlayout/dex_ir.h
+++ b/dexlayout/dex_ir.h
@@ -24,6 +24,7 @@
#include <map>
#include <vector>
+#include "base/iteration_range.h"
#include "base/leb128.h"
#include "base/stl_util.h"
#include "dex/dex_file-inl.h"
@@ -107,17 +108,114 @@
DISALLOW_COPY_AND_ASSIGN(AbstractDispatcher);
};
+template<class T> class Iterator : public std::iterator<std::random_access_iterator_tag, T> {
+ public:
+ using value_type = typename std::iterator<std::random_access_iterator_tag, T>::value_type;
+ using difference_type =
+ typename std::iterator<std::random_access_iterator_tag, value_type>::difference_type;
+ using pointer = typename std::iterator<std::random_access_iterator_tag, value_type>::pointer;
+ using reference = typename std::iterator<std::random_access_iterator_tag, value_type>::reference;
+
+ Iterator(const Iterator&) = default;
+ Iterator(Iterator&&) = default;
+ Iterator& operator=(const Iterator&) = default;
+ Iterator& operator=(Iterator&&) = default;
+
+ Iterator(const std::vector<T>& vector,
+ uint32_t position,
+ uint32_t iterator_end)
+ : vector_(&vector),
+ position_(position),
+ iterator_end_(iterator_end) { }
+ Iterator() : vector_(nullptr), position_(0U), iterator_end_(0U) { }
+
+ bool IsValid() const { return position_ < iterator_end_; }
+
+ bool operator==(const Iterator& rhs) const { return position_ == rhs.position_; }
+ bool operator!=(const Iterator& rhs) const { return !(*this == rhs); }
+ bool operator<(const Iterator& rhs) const { return position_ < rhs.position_; }
+ bool operator>(const Iterator& rhs) const { return rhs < *this; }
+ bool operator<=(const Iterator& rhs) const { return !(rhs < *this); }
+ bool operator>=(const Iterator& rhs) const { return !(*this < rhs); }
+
+ Iterator& operator++() { // Value after modification.
+ ++position_;
+ return *this;
+ }
+
+ Iterator operator++(int) {
+ Iterator temp = *this;
+ ++position_;
+ return temp;
+ }
+
+ Iterator& operator+=(difference_type delta) {
+ position_ += delta;
+ return *this;
+ }
+
+ Iterator operator+(difference_type delta) const {
+ Iterator temp = *this;
+ temp += delta;
+ return temp;
+ }
+
+ Iterator& operator--() { // Value after modification.
+ --position_;
+ return *this;
+ }
+
+ Iterator operator--(int) {
+ Iterator temp = *this;
+ --position_;
+ return temp;
+ }
+
+ Iterator& operator-=(difference_type delta) {
+ position_ -= delta;
+ return *this;
+ }
+
+ Iterator operator-(difference_type delta) const {
+ Iterator temp = *this;
+ temp -= delta;
+ return temp;
+ }
+
+ difference_type operator-(const Iterator& rhs) {
+ return position_ - rhs.position_;
+ }
+
+ reference operator*() const {
+ return const_cast<reference>((*vector_)[position_]);
+ }
+
+ pointer operator->() const {
+ return const_cast<pointer>(&((*vector_)[position_]));
+ }
+
+ reference operator[](difference_type n) const {
+ return (*vector_)[position_ + n];
+ }
+
+ private:
+ const std::vector<T>* vector_;
+ uint32_t position_;
+ uint32_t iterator_end_;
+
+ template <typename U>
+ friend bool operator<(const Iterator<U>& lhs, const Iterator<U>& rhs);
+};
+
// Collections become owners of the objects added by moving them into unique pointers.
-template<class T> class CollectionBase {
+class CollectionBase {
public:
CollectionBase() = default;
+ virtual ~CollectionBase() { }
- uint32_t GetOffset() const {
- return offset_;
- }
- void SetOffset(uint32_t new_offset) {
- offset_ = new_offset;
- }
+ uint32_t GetOffset() const { return offset_; }
+ void SetOffset(uint32_t new_offset) { offset_ = new_offset; }
+ virtual uint32_t Size() const { return 0U; }
private:
// Start out unassigned.
@@ -126,18 +224,37 @@
DISALLOW_COPY_AND_ASSIGN(CollectionBase);
};
-template<class T> class CollectionVector : public CollectionBase<T> {
+template<class T> class CollectionVector : public CollectionBase {
public:
- using Vector = std::vector<std::unique_ptr<T>>;
+ using ElementType = std::unique_ptr<T>;
+
CollectionVector() { }
explicit CollectionVector(size_t size) {
// Preallocate so that assignment does not invalidate pointers into the vector.
collection_.reserve(size);
}
+ virtual ~CollectionVector() OVERRIDE { }
- uint32_t Size() const { return collection_.size(); }
- Vector& Collection() { return collection_; }
- const Vector& Collection() const { return collection_; }
+ template<class... Args>
+ T* CreateAndAddItem(Args&&... args) {
+ T* object = new T(std::forward<Args>(args)...);
+ collection_.push_back(std::unique_ptr<T>(object));
+ return object;
+ }
+
+ virtual uint32_t Size() const OVERRIDE { return collection_.size(); }
+
+ Iterator<ElementType> begin() const { return Iterator<ElementType>(collection_, 0U, Size()); }
+ Iterator<ElementType> end() const { return Iterator<ElementType>(collection_, Size(), Size()); }
+
+ const ElementType& operator[](size_t index) const {
+ DCHECK_LT(index, Size());
+ return collection_[index];
+ }
+ ElementType& operator[](size_t index) {
+ DCHECK_LT(index, Size());
+ return collection_[index];
+ }
// Sort the vector by copying pointers over.
template <typename MapType>
@@ -147,24 +264,16 @@
for (size_t i = 0; i < Size(); ++i) {
// There are times when the array will temporarily contain the same pointer twice, doing the
// release here sure there is no double free errors.
- Collection()[i].release();
- Collection()[i].reset(it->second);
+ collection_[i].release();
+ collection_[i].reset(it->second);
++it;
}
}
protected:
- Vector collection_;
-
- template<class... Args>
- T* CreateAndAddItem(Args&&... args) {
- T* object = new T(std::forward<Args>(args)...);
- collection_.push_back(std::unique_ptr<T>(object));
- return object;
- }
+ std::vector<ElementType> collection_;
private:
- friend class Collections;
DISALLOW_COPY_AND_ASSIGN(CollectionVector);
};
@@ -174,7 +283,6 @@
IndexedCollectionVector() = default;
explicit IndexedCollectionVector(size_t size) : CollectionVector<T>(size) { }
- private:
template <class... Args>
T* CreateAndAddIndexedItem(uint32_t index, Args&&... args) {
T* object = CollectionVector<T>::CreateAndAddItem(std::forward<Args>(args)...);
@@ -182,332 +290,15 @@
return object;
}
- T* GetElement(uint32_t index) {
- DCHECK_LT(index, CollectionVector<T>::Size());
+ T* operator[](size_t index) const {
DCHECK_NE(CollectionVector<T>::collection_[index].get(), static_cast<T*>(nullptr));
return CollectionVector<T>::collection_[index].get();
}
- friend class Collections;
+ private:
DISALLOW_COPY_AND_ASSIGN(IndexedCollectionVector);
};
-template<class T> class CollectionMap : public CollectionBase<T> {
- public:
- CollectionMap() = default;
-
- // Returns the existing item if it is already inserted, null otherwise.
- T* GetExistingObject(uint32_t offset) {
- auto it = collection_.find(offset);
- return it != collection_.end() ? it->second : nullptr;
- }
-
- // Lower case for template interop with std::map.
- uint32_t size() const { return collection_.size(); }
- std::map<uint32_t, T*>& Collection() { return collection_; }
-
- private:
- std::map<uint32_t, T*> collection_;
-
- // CollectionMaps do not own the objects they contain, therefore AddItem is supported
- // rather than CreateAndAddItem.
- void AddItem(T* object, uint32_t offset) {
- auto it = collection_.emplace(offset, object);
- CHECK(it.second) << "CollectionMap already has an object with offset " << offset << " "
- << " and address " << it.first->second;
- }
-
- friend class Collections;
- DISALLOW_COPY_AND_ASSIGN(CollectionMap);
-};
-
-class Collections {
- public:
- Collections() = default;
- Collections(uint32_t num_string_ids,
- uint32_t num_type_ids,
- uint32_t num_proto_ids,
- uint32_t num_field_ids,
- uint32_t num_method_ids,
- uint32_t num_class_defs)
- : string_ids_(num_string_ids),
- type_ids_(num_type_ids),
- proto_ids_(num_proto_ids),
- field_ids_(num_field_ids),
- method_ids_(num_method_ids),
- class_defs_(num_class_defs) { }
-
- IndexedCollectionVector<StringId>::Vector& StringIds() { return string_ids_.Collection(); }
- IndexedCollectionVector<TypeId>::Vector& TypeIds() { return type_ids_.Collection(); }
- IndexedCollectionVector<ProtoId>::Vector& ProtoIds() { return proto_ids_.Collection(); }
- IndexedCollectionVector<FieldId>::Vector& FieldIds() { return field_ids_.Collection(); }
- IndexedCollectionVector<MethodId>::Vector& MethodIds() { return method_ids_.Collection(); }
- IndexedCollectionVector<ClassDef>::Vector& ClassDefs() { return class_defs_.Collection(); }
- CollectionVector<CallSiteId>::Vector& CallSiteIds() { return call_site_ids_.Collection(); }
- CollectionVector<MethodHandleItem>::Vector& MethodHandleItems()
- { return method_handle_items_.Collection(); }
- CollectionVector<StringData>::Vector& StringDatas() { return string_datas_.Collection(); }
- CollectionVector<TypeList>::Vector& TypeLists() { return type_lists_.Collection(); }
- CollectionVector<EncodedArrayItem>::Vector& EncodedArrayItems()
- { return encoded_array_items_.Collection(); }
- CollectionVector<AnnotationItem>::Vector& AnnotationItems()
- { return annotation_items_.Collection(); }
- CollectionVector<AnnotationSetItem>::Vector& AnnotationSetItems()
- { return annotation_set_items_.Collection(); }
- CollectionVector<AnnotationSetRefList>::Vector& AnnotationSetRefLists()
- { return annotation_set_ref_lists_.Collection(); }
- CollectionVector<AnnotationsDirectoryItem>::Vector& AnnotationsDirectoryItems()
- { return annotations_directory_items_.Collection(); }
- CollectionVector<DebugInfoItem>::Vector& DebugInfoItems()
- { return debug_info_items_.Collection(); }
- CollectionVector<CodeItem>::Vector& CodeItems() { return code_items_.Collection(); }
- CollectionVector<ClassData>::Vector& ClassDatas() { return class_datas_.Collection(); }
-
- const CollectionVector<ClassDef>::Vector& ClassDefs() const { return class_defs_.Collection(); }
-
- void CreateStringId(const DexFile& dex_file, uint32_t i);
- void CreateTypeId(const DexFile& dex_file, uint32_t i);
- void CreateProtoId(const DexFile& dex_file, uint32_t i);
- void CreateFieldId(const DexFile& dex_file, uint32_t i);
- void CreateMethodId(const DexFile& dex_file, uint32_t i);
- void CreateClassDef(const DexFile& dex_file, uint32_t i);
- void CreateCallSiteId(const DexFile& dex_file, uint32_t i);
- void CreateMethodHandleItem(const DexFile& dex_file, uint32_t i);
-
- void CreateCallSitesAndMethodHandles(const DexFile& dex_file);
-
- TypeList* CreateTypeList(const DexFile::TypeList* type_list, uint32_t offset);
- EncodedArrayItem* CreateEncodedArrayItem(const DexFile& dex_file,
- const uint8_t* static_data,
- uint32_t offset);
- AnnotationItem* CreateAnnotationItem(const DexFile& dex_file,
- const DexFile::AnnotationItem* annotation);
- AnnotationSetItem* CreateAnnotationSetItem(const DexFile& dex_file,
- const DexFile::AnnotationSetItem* disk_annotations_item, uint32_t offset);
- AnnotationsDirectoryItem* CreateAnnotationsDirectoryItem(const DexFile& dex_file,
- const DexFile::AnnotationsDirectoryItem* disk_annotations_item, uint32_t offset);
- CodeItem* DedupeOrCreateCodeItem(const DexFile& dex_file,
- const DexFile::CodeItem* disk_code_item,
- uint32_t offset,
- uint32_t dex_method_index);
- ClassData* CreateClassData(const DexFile& dex_file, const uint8_t* encoded_data, uint32_t offset);
- void AddAnnotationsFromMapListSection(const DexFile& dex_file,
- uint32_t start_offset,
- uint32_t count);
-
- StringId* GetStringId(uint32_t index) {
- return string_ids_.GetElement(index);
- }
- TypeId* GetTypeId(uint32_t index) {
- return type_ids_.GetElement(index);
- }
- ProtoId* GetProtoId(uint32_t index) {
- return proto_ids_.GetElement(index);
- }
- FieldId* GetFieldId(uint32_t index) {
- return field_ids_.GetElement(index);
- }
- MethodId* GetMethodId(uint32_t index) {
- return method_ids_.GetElement(index);
- }
- ClassDef* GetClassDef(uint32_t index) {
- return class_defs_.GetElement(index);
- }
- CallSiteId* GetCallSiteId(uint32_t index) {
- CHECK_LT(index, CallSiteIdsSize());
- return CallSiteIds()[index].get();
- }
- MethodHandleItem* GetMethodHandle(uint32_t index) {
- CHECK_LT(index, MethodHandleItemsSize());
- return MethodHandleItems()[index].get();
- }
-
- StringId* GetStringIdOrNullPtr(uint32_t index) {
- return index == dex::kDexNoIndex ? nullptr : GetStringId(index);
- }
- TypeId* GetTypeIdOrNullPtr(uint16_t index) {
- return index == DexFile::kDexNoIndex16 ? nullptr : GetTypeId(index);
- }
-
- uint32_t StringIdsOffset() const { return string_ids_.GetOffset(); }
- uint32_t TypeIdsOffset() const { return type_ids_.GetOffset(); }
- uint32_t ProtoIdsOffset() const { return proto_ids_.GetOffset(); }
- uint32_t FieldIdsOffset() const { return field_ids_.GetOffset(); }
- uint32_t MethodIdsOffset() const { return method_ids_.GetOffset(); }
- uint32_t ClassDefsOffset() const { return class_defs_.GetOffset(); }
- uint32_t CallSiteIdsOffset() const { return call_site_ids_.GetOffset(); }
- uint32_t MethodHandleItemsOffset() const { return method_handle_items_.GetOffset(); }
- uint32_t StringDatasOffset() const { return string_datas_.GetOffset(); }
- uint32_t TypeListsOffset() const { return type_lists_.GetOffset(); }
- uint32_t EncodedArrayItemsOffset() const { return encoded_array_items_.GetOffset(); }
- uint32_t AnnotationItemsOffset() const { return annotation_items_.GetOffset(); }
- uint32_t AnnotationSetItemsOffset() const { return annotation_set_items_.GetOffset(); }
- uint32_t AnnotationSetRefListsOffset() const { return annotation_set_ref_lists_.GetOffset(); }
- uint32_t AnnotationsDirectoryItemsOffset() const
- { return annotations_directory_items_.GetOffset(); }
- uint32_t DebugInfoItemsOffset() const { return debug_info_items_.GetOffset(); }
- uint32_t CodeItemsOffset() const { return code_items_.GetOffset(); }
- uint32_t ClassDatasOffset() const { return class_datas_.GetOffset(); }
- uint32_t MapListOffset() const { return map_list_offset_; }
-
- void SetStringIdsOffset(uint32_t new_offset) { string_ids_.SetOffset(new_offset); }
- void SetTypeIdsOffset(uint32_t new_offset) { type_ids_.SetOffset(new_offset); }
- void SetProtoIdsOffset(uint32_t new_offset) { proto_ids_.SetOffset(new_offset); }
- void SetFieldIdsOffset(uint32_t new_offset) { field_ids_.SetOffset(new_offset); }
- void SetMethodIdsOffset(uint32_t new_offset) { method_ids_.SetOffset(new_offset); }
- void SetClassDefsOffset(uint32_t new_offset) { class_defs_.SetOffset(new_offset); }
- void SetCallSiteIdsOffset(uint32_t new_offset) { call_site_ids_.SetOffset(new_offset); }
- void SetMethodHandleItemsOffset(uint32_t new_offset)
- { method_handle_items_.SetOffset(new_offset); }
- void SetStringDatasOffset(uint32_t new_offset) { string_datas_.SetOffset(new_offset); }
- void SetTypeListsOffset(uint32_t new_offset) { type_lists_.SetOffset(new_offset); }
- void SetEncodedArrayItemsOffset(uint32_t new_offset)
- { encoded_array_items_.SetOffset(new_offset); }
- void SetAnnotationItemsOffset(uint32_t new_offset) { annotation_items_.SetOffset(new_offset); }
- void SetAnnotationSetItemsOffset(uint32_t new_offset)
- { annotation_set_items_.SetOffset(new_offset); }
- void SetAnnotationSetRefListsOffset(uint32_t new_offset)
- { annotation_set_ref_lists_.SetOffset(new_offset); }
- void SetAnnotationsDirectoryItemsOffset(uint32_t new_offset)
- { annotations_directory_items_.SetOffset(new_offset); }
- void SetDebugInfoItemsOffset(uint32_t new_offset) { debug_info_items_.SetOffset(new_offset); }
- void SetCodeItemsOffset(uint32_t new_offset) { code_items_.SetOffset(new_offset); }
- void SetClassDatasOffset(uint32_t new_offset) { class_datas_.SetOffset(new_offset); }
- void SetMapListOffset(uint32_t new_offset) { map_list_offset_ = new_offset; }
-
- uint32_t StringIdsSize() const { return string_ids_.Size(); }
- uint32_t TypeIdsSize() const { return type_ids_.Size(); }
- uint32_t ProtoIdsSize() const { return proto_ids_.Size(); }
- uint32_t FieldIdsSize() const { return field_ids_.Size(); }
- uint32_t MethodIdsSize() const { return method_ids_.Size(); }
- uint32_t ClassDefsSize() const { return class_defs_.Size(); }
- uint32_t CallSiteIdsSize() const { return call_site_ids_.Size(); }
- uint32_t MethodHandleItemsSize() const { return method_handle_items_.Size(); }
- uint32_t StringDatasSize() const { return string_datas_.Size(); }
- uint32_t TypeListsSize() const { return type_lists_.Size(); }
- uint32_t EncodedArrayItemsSize() const { return encoded_array_items_.Size(); }
- uint32_t AnnotationItemsSize() const { return annotation_items_.Size(); }
- uint32_t AnnotationSetItemsSize() const { return annotation_set_items_.Size(); }
- uint32_t AnnotationSetRefListsSize() const { return annotation_set_ref_lists_.Size(); }
- uint32_t AnnotationsDirectoryItemsSize() const { return annotations_directory_items_.Size(); }
- uint32_t DebugInfoItemsSize() const { return debug_info_items_.Size(); }
- uint32_t CodeItemsSize() const { return code_items_.Size(); }
- uint32_t ClassDatasSize() const { return class_datas_.Size(); }
-
- // Sort the vectors buy map order (same order that was used in the input file).
- void SortVectorsByMapOrder();
- // Empty the maps, which are only used for IR construction.
- void ClearMaps();
-
- template <typename Type, class... Args>
- Type* CreateAndAddItem(CollectionMap<Type>& map,
- CollectionVector<Type>& vector,
- uint32_t offset,
- Args&&... args) {
- Type* item = vector.CreateAndAddItem(std::forward<Args>(args)...);
- DCHECK(!map.GetExistingObject(offset));
- DCHECK(!item->OffsetAssigned());
- if (eagerly_assign_offsets_) {
- item->SetOffset(offset);
- }
- map.AddItem(item, offset);
- return item;
- }
-
- template <typename Type, class... Args>
- Type* CreateAndAddIndexedItem(IndexedCollectionVector<Type>& vector,
- uint32_t offset,
- uint32_t index,
- Args&&... args) {
- Type* item = vector.CreateAndAddIndexedItem(index, std::forward<Args>(args)...);
- DCHECK(!item->OffsetAssigned());
- if (eagerly_assign_offsets_) {
- item->SetOffset(offset);
- }
- return item;
- }
-
- void SetEagerlyAssignOffsets(bool eagerly_assign_offsets) {
- eagerly_assign_offsets_ = eagerly_assign_offsets;
- }
-
- void SetLinkData(std::vector<uint8_t>&& link_data) {
- link_data_ = std::move(link_data);
- }
-
- const std::vector<uint8_t>& LinkData() const {
- return link_data_;
- }
-
- private:
- EncodedValue* ReadEncodedValue(const DexFile& dex_file, const uint8_t** data);
- EncodedValue* ReadEncodedValue(const DexFile& dex_file,
- const uint8_t** data,
- uint8_t type,
- uint8_t length);
- void ReadEncodedValue(const DexFile& dex_file,
- const uint8_t** data,
- uint8_t type,
- uint8_t length,
- EncodedValue* item);
-
- ParameterAnnotation* GenerateParameterAnnotation(const DexFile& dex_file, MethodId* method_id,
- const DexFile::AnnotationSetRefList* annotation_set_ref_list, uint32_t offset);
- MethodItem GenerateMethodItem(const DexFile& dex_file, ClassDataItemIterator& cdii);
-
- // Collection vectors own the IR data.
- IndexedCollectionVector<StringId> string_ids_;
- IndexedCollectionVector<TypeId> type_ids_;
- IndexedCollectionVector<ProtoId> proto_ids_;
- IndexedCollectionVector<FieldId> field_ids_;
- IndexedCollectionVector<MethodId> method_ids_;
- IndexedCollectionVector<ClassDef> class_defs_;
- IndexedCollectionVector<CallSiteId> call_site_ids_;
- IndexedCollectionVector<MethodHandleItem> method_handle_items_;
- IndexedCollectionVector<StringData> string_datas_;
- IndexedCollectionVector<TypeList> type_lists_;
- IndexedCollectionVector<EncodedArrayItem> encoded_array_items_;
- IndexedCollectionVector<AnnotationItem> annotation_items_;
- IndexedCollectionVector<AnnotationSetItem> annotation_set_items_;
- IndexedCollectionVector<AnnotationSetRefList> annotation_set_ref_lists_;
- IndexedCollectionVector<AnnotationsDirectoryItem> annotations_directory_items_;
- // The order of the vectors controls the layout of the output file by index order, to change the
- // layout just sort the vector. Note that you may only change the order of the non indexed vectors
- // below. Indexed vectors are accessed by indices in other places, changing the sorting order will
- // invalidate the existing indices and is not currently supported.
- CollectionVector<DebugInfoItem> debug_info_items_;
- CollectionVector<CodeItem> code_items_;
- CollectionVector<ClassData> class_datas_;
-
- // Note that the maps do not have ownership, the vectors do.
- // TODO: These maps should only be required for building the IR and should be put in a separate
- // IR builder class.
- CollectionMap<StringData> string_datas_map_;
- CollectionMap<TypeList> type_lists_map_;
- CollectionMap<EncodedArrayItem> encoded_array_items_map_;
- CollectionMap<AnnotationItem> annotation_items_map_;
- CollectionMap<AnnotationSetItem> annotation_set_items_map_;
- CollectionMap<AnnotationSetRefList> annotation_set_ref_lists_map_;
- CollectionMap<AnnotationsDirectoryItem> annotations_directory_items_map_;
- CollectionMap<DebugInfoItem> debug_info_items_map_;
- // Code item maps need to check both the debug info offset and debug info offset, do not use
- // CollectionMap.
- // First offset is the code item offset, second is the debug info offset.
- std::map<std::pair<uint32_t, uint32_t>, CodeItem*> code_items_map_;
- CollectionMap<ClassData> class_datas_map_;
-
- uint32_t map_list_offset_ = 0;
-
- // Link data.
- std::vector<uint8_t> link_data_;
-
- // If we eagerly assign offsets during IR building or later after layout. Must be false if
- // changing the layout is enabled.
- bool eagerly_assign_offsets_;
-
- DISALLOW_COPY_AND_ASSIGN(Collections);
-};
-
class Item {
public:
Item() { }
@@ -598,12 +389,12 @@
uint32_t num_class_defs)
: Item(0, kHeaderItemSize),
support_default_methods_(support_default_methods),
- collections_(num_string_ids,
- num_type_ids,
- num_proto_ids,
- num_field_ids,
- num_method_ids,
- num_class_defs) {
+ string_ids_(num_string_ids),
+ type_ids_(num_type_ids),
+ proto_ids_(num_proto_ids),
+ field_ids_(num_field_ids),
+ method_ids_(num_method_ids),
+ class_defs_(num_class_defs) {
ConstructorHelper(magic,
checksum,
signature,
@@ -641,7 +432,69 @@
void SetDataSize(uint32_t new_data_size) { data_size_ = new_data_size; }
void SetDataOffset(uint32_t new_data_offset) { data_offset_ = new_data_offset; }
- Collections& GetCollections() { return collections_; }
+ IndexedCollectionVector<StringId>& StringIds() { return string_ids_; }
+ const IndexedCollectionVector<StringId>& StringIds() const { return string_ids_; }
+ IndexedCollectionVector<TypeId>& TypeIds() { return type_ids_; }
+ const IndexedCollectionVector<TypeId>& TypeIds() const { return type_ids_; }
+ IndexedCollectionVector<ProtoId>& ProtoIds() { return proto_ids_; }
+ const IndexedCollectionVector<ProtoId>& ProtoIds() const { return proto_ids_; }
+ IndexedCollectionVector<FieldId>& FieldIds() { return field_ids_; }
+ const IndexedCollectionVector<FieldId>& FieldIds() const { return field_ids_; }
+ IndexedCollectionVector<MethodId>& MethodIds() { return method_ids_; }
+ const IndexedCollectionVector<MethodId>& MethodIds() const { return method_ids_; }
+ IndexedCollectionVector<ClassDef>& ClassDefs() { return class_defs_; }
+ const IndexedCollectionVector<ClassDef>& ClassDefs() const { return class_defs_; }
+ IndexedCollectionVector<CallSiteId>& CallSiteIds() { return call_site_ids_; }
+ const IndexedCollectionVector<CallSiteId>& CallSiteIds() const { return call_site_ids_; }
+ IndexedCollectionVector<MethodHandleItem>& MethodHandleItems() { return method_handle_items_; }
+ const IndexedCollectionVector<MethodHandleItem>& MethodHandleItems() const {
+ return method_handle_items_;
+ }
+ CollectionVector<StringData>& StringDatas() { return string_datas_; }
+ const CollectionVector<StringData>& StringDatas() const { return string_datas_; }
+ CollectionVector<TypeList>& TypeLists() { return type_lists_; }
+ const CollectionVector<TypeList>& TypeLists() const { return type_lists_; }
+ CollectionVector<EncodedArrayItem>& EncodedArrayItems() { return encoded_array_items_; }
+ const CollectionVector<EncodedArrayItem>& EncodedArrayItems() const {
+ return encoded_array_items_;
+ }
+ CollectionVector<AnnotationItem>& AnnotationItems() { return annotation_items_; }
+ const CollectionVector<AnnotationItem>& AnnotationItems() const { return annotation_items_; }
+ CollectionVector<AnnotationSetItem>& AnnotationSetItems() { return annotation_set_items_; }
+ const CollectionVector<AnnotationSetItem>& AnnotationSetItems() const {
+ return annotation_set_items_;
+ }
+ CollectionVector<AnnotationSetRefList>& AnnotationSetRefLists() {
+ return annotation_set_ref_lists_;
+ }
+ const CollectionVector<AnnotationSetRefList>& AnnotationSetRefLists() const {
+ return annotation_set_ref_lists_;
+ }
+ CollectionVector<AnnotationsDirectoryItem>& AnnotationsDirectoryItems() {
+ return annotations_directory_items_;
+ }
+ const CollectionVector<AnnotationsDirectoryItem>& AnnotationsDirectoryItems() const {
+ return annotations_directory_items_;
+ }
+ CollectionVector<DebugInfoItem>& DebugInfoItems() { return debug_info_items_; }
+ const CollectionVector<DebugInfoItem>& DebugInfoItems() const { return debug_info_items_; }
+ CollectionVector<CodeItem>& CodeItems() { return code_items_; }
+ const CollectionVector<CodeItem>& CodeItems() const { return code_items_; }
+ CollectionVector<ClassData>& ClassDatas() { return class_datas_; }
+ const CollectionVector<ClassData>& ClassDatas() const { return class_datas_; }
+
+ StringId* GetStringIdOrNullPtr(uint32_t index) {
+ return index == dex::kDexNoIndex ? nullptr : StringIds()[index];
+ }
+ TypeId* GetTypeIdOrNullPtr(uint16_t index) {
+ return index == DexFile::kDexNoIndex16 ? nullptr : TypeIds()[index];
+ }
+
+ uint32_t MapListOffset() const { return map_list_offset_; }
+ void SetMapListOffset(uint32_t new_offset) { map_list_offset_ = new_offset; }
+
+ const std::vector<uint8_t>& LinkData() const { return link_data_; }
+ void SetLinkData(std::vector<uint8_t>&& link_data) { link_data_ = std::move(link_data); }
void Accept(AbstractDispatcher* dispatch) { dispatch->Dispatch(this); }
@@ -683,7 +536,35 @@
memcpy(magic_, magic, sizeof(magic_));
memcpy(signature_, signature, sizeof(signature_));
}
- Collections collections_;
+
+ // Collection vectors own the IR data.
+ IndexedCollectionVector<StringId> string_ids_;
+ IndexedCollectionVector<TypeId> type_ids_;
+ IndexedCollectionVector<ProtoId> proto_ids_;
+ IndexedCollectionVector<FieldId> field_ids_;
+ IndexedCollectionVector<MethodId> method_ids_;
+ IndexedCollectionVector<ClassDef> class_defs_;
+ IndexedCollectionVector<CallSiteId> call_site_ids_;
+ IndexedCollectionVector<MethodHandleItem> method_handle_items_;
+ IndexedCollectionVector<StringData> string_datas_;
+ IndexedCollectionVector<TypeList> type_lists_;
+ IndexedCollectionVector<EncodedArrayItem> encoded_array_items_;
+ IndexedCollectionVector<AnnotationItem> annotation_items_;
+ IndexedCollectionVector<AnnotationSetItem> annotation_set_items_;
+ IndexedCollectionVector<AnnotationSetRefList> annotation_set_ref_lists_;
+ IndexedCollectionVector<AnnotationsDirectoryItem> annotations_directory_items_;
+ // The order of the vectors controls the layout of the output file by index order, to change the
+ // layout just sort the vector. Note that you may only change the order of the non indexed vectors
+ // below. Indexed vectors are accessed by indices in other places, changing the sorting order will
+ // invalidate the existing indices and is not currently supported.
+ CollectionVector<DebugInfoItem> debug_info_items_;
+ CollectionVector<CodeItem> code_items_;
+ CollectionVector<ClassData> class_datas_;
+
+ uint32_t map_list_offset_ = 0;
+
+ // Link data.
+ std::vector<uint8_t> link_data_;
DISALLOW_COPY_AND_ASSIGN(Header);
};
diff --git a/dexlayout/dex_ir_builder.cc b/dexlayout/dex_ir_builder.cc
index 9468f76..a04a234 100644
--- a/dexlayout/dex_ir_builder.cc
+++ b/dexlayout/dex_ir_builder.cc
@@ -20,14 +20,226 @@
#include <vector>
#include "dex_ir_builder.h"
+
+#include "dex/code_item_accessors-inl.h"
+#include "dex/dex_file_exception_helpers.h"
#include "dexlayout.h"
namespace art {
namespace dex_ir {
-static void CheckAndSetRemainingOffsets(const DexFile& dex_file,
- Collections* collections,
- const Options& options);
+static uint64_t ReadVarWidth(const uint8_t** data, uint8_t length, bool sign_extend) {
+ uint64_t value = 0;
+ for (uint32_t i = 0; i <= length; i++) {
+ value |= static_cast<uint64_t>(*(*data)++) << (i * 8);
+ }
+ if (sign_extend) {
+ int shift = (7 - length) * 8;
+ return (static_cast<int64_t>(value) << shift) >> shift;
+ }
+ return value;
+}
+
+static uint32_t GetDebugInfoStreamSize(const uint8_t* debug_info_stream) {
+ const uint8_t* stream = debug_info_stream;
+ DecodeUnsignedLeb128(&stream); // line_start
+ uint32_t parameters_size = DecodeUnsignedLeb128(&stream);
+ for (uint32_t i = 0; i < parameters_size; ++i) {
+ DecodeUnsignedLeb128P1(&stream); // Parameter name.
+ }
+
+ for (;;) {
+ uint8_t opcode = *stream++;
+ switch (opcode) {
+ case DexFile::DBG_END_SEQUENCE:
+ return stream - debug_info_stream; // end of stream.
+ case DexFile::DBG_ADVANCE_PC:
+ DecodeUnsignedLeb128(&stream); // addr_diff
+ break;
+ case DexFile::DBG_ADVANCE_LINE:
+ DecodeSignedLeb128(&stream); // line_diff
+ break;
+ case DexFile::DBG_START_LOCAL:
+ DecodeUnsignedLeb128(&stream); // register_num
+ DecodeUnsignedLeb128P1(&stream); // name_idx
+ DecodeUnsignedLeb128P1(&stream); // type_idx
+ break;
+ case DexFile::DBG_START_LOCAL_EXTENDED:
+ DecodeUnsignedLeb128(&stream); // register_num
+ DecodeUnsignedLeb128P1(&stream); // name_idx
+ DecodeUnsignedLeb128P1(&stream); // type_idx
+ DecodeUnsignedLeb128P1(&stream); // sig_idx
+ break;
+ case DexFile::DBG_END_LOCAL:
+ case DexFile::DBG_RESTART_LOCAL:
+ DecodeUnsignedLeb128(&stream); // register_num
+ break;
+ case DexFile::DBG_SET_PROLOGUE_END:
+ case DexFile::DBG_SET_EPILOGUE_BEGIN:
+ break;
+ case DexFile::DBG_SET_FILE: {
+ DecodeUnsignedLeb128P1(&stream); // name_idx
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+ }
+}
+
+template<class T> class CollectionMap : public CollectionBase {
+ public:
+ CollectionMap() = default;
+ virtual ~CollectionMap() OVERRIDE { }
+
+ template <class... Args>
+ T* CreateAndAddItem(CollectionVector<T>& vector,
+ bool eagerly_assign_offsets,
+ uint32_t offset,
+ Args&&... args) {
+ T* item = vector.CreateAndAddItem(std::forward<Args>(args)...);
+ DCHECK(!GetExistingObject(offset));
+ DCHECK(!item->OffsetAssigned());
+ if (eagerly_assign_offsets) {
+ item->SetOffset(offset);
+ }
+ AddItem(item, offset);
+ return item;
+ }
+
+ // Returns the existing item if it is already inserted, null otherwise.
+ T* GetExistingObject(uint32_t offset) {
+ auto it = collection_.find(offset);
+ return it != collection_.end() ? it->second : nullptr;
+ }
+
+ // Lower case for template interop with std::map.
+ uint32_t size() const { return collection_.size(); }
+ std::map<uint32_t, T*>& Collection() { return collection_; }
+
+ private:
+ std::map<uint32_t, T*> collection_;
+
+ // CollectionMaps do not own the objects they contain, therefore AddItem is supported
+ // rather than CreateAndAddItem.
+ void AddItem(T* object, uint32_t offset) {
+ auto it = collection_.emplace(offset, object);
+ CHECK(it.second) << "CollectionMap already has an object with offset " << offset << " "
+ << " and address " << it.first->second;
+ }
+
+ DISALLOW_COPY_AND_ASSIGN(CollectionMap);
+};
+
+class BuilderMaps {
+ public:
+ BuilderMaps(Header* header, bool eagerly_assign_offsets)
+ : header_(header), eagerly_assign_offsets_(eagerly_assign_offsets) { }
+
+ void CreateStringId(const DexFile& dex_file, uint32_t i);
+ void CreateTypeId(const DexFile& dex_file, uint32_t i);
+ void CreateProtoId(const DexFile& dex_file, uint32_t i);
+ void CreateFieldId(const DexFile& dex_file, uint32_t i);
+ void CreateMethodId(const DexFile& dex_file, uint32_t i);
+ void CreateClassDef(const DexFile& dex_file, uint32_t i);
+ void CreateCallSiteId(const DexFile& dex_file, uint32_t i);
+ void CreateMethodHandleItem(const DexFile& dex_file, uint32_t i);
+
+ void CreateCallSitesAndMethodHandles(const DexFile& dex_file);
+
+ TypeList* CreateTypeList(const DexFile::TypeList* type_list, uint32_t offset);
+ EncodedArrayItem* CreateEncodedArrayItem(const DexFile& dex_file,
+ const uint8_t* static_data,
+ uint32_t offset);
+ AnnotationItem* CreateAnnotationItem(const DexFile& dex_file,
+ const DexFile::AnnotationItem* annotation);
+ AnnotationSetItem* CreateAnnotationSetItem(const DexFile& dex_file,
+ const DexFile::AnnotationSetItem* disk_annotations_item, uint32_t offset);
+ AnnotationsDirectoryItem* CreateAnnotationsDirectoryItem(const DexFile& dex_file,
+ const DexFile::AnnotationsDirectoryItem* disk_annotations_item, uint32_t offset);
+ CodeItem* DedupeOrCreateCodeItem(const DexFile& dex_file,
+ const DexFile::CodeItem* disk_code_item,
+ uint32_t offset,
+ uint32_t dex_method_index);
+ ClassData* CreateClassData(const DexFile& dex_file, const uint8_t* encoded_data, uint32_t offset);
+
+ void AddAnnotationsFromMapListSection(const DexFile& dex_file,
+ uint32_t start_offset,
+ uint32_t count);
+
+ void CheckAndSetRemainingOffsets(const DexFile& dex_file, const Options& options);
+
+ // Sort the vectors buy map order (same order that was used in the input file).
+ void SortVectorsByMapOrder();
+
+ private:
+ bool GetIdsFromByteCode(const CodeItem* code,
+ std::vector<TypeId*>* type_ids,
+ std::vector<StringId*>* string_ids,
+ std::vector<MethodId*>* method_ids,
+ std::vector<FieldId*>* field_ids);
+
+ bool GetIdFromInstruction(const Instruction* dec_insn,
+ std::vector<TypeId*>* type_ids,
+ std::vector<StringId*>* string_ids,
+ std::vector<MethodId*>* method_ids,
+ std::vector<FieldId*>* field_ids);
+
+ EncodedValue* ReadEncodedValue(const DexFile& dex_file, const uint8_t** data);
+ EncodedValue* ReadEncodedValue(const DexFile& dex_file,
+ const uint8_t** data,
+ uint8_t type,
+ uint8_t length);
+ void ReadEncodedValue(const DexFile& dex_file,
+ const uint8_t** data,
+ uint8_t type,
+ uint8_t length,
+ EncodedValue* item);
+
+ MethodItem GenerateMethodItem(const DexFile& dex_file, ClassDataItemIterator& cdii);
+
+ ParameterAnnotation* GenerateParameterAnnotation(
+ const DexFile& dex_file,
+ MethodId* method_id,
+ const DexFile::AnnotationSetRefList* annotation_set_ref_list,
+ uint32_t offset);
+
+ template <typename Type, class... Args>
+ Type* CreateAndAddIndexedItem(IndexedCollectionVector<Type>& vector,
+ uint32_t offset,
+ uint32_t index,
+ Args&&... args) {
+ Type* item = vector.CreateAndAddIndexedItem(index, std::forward<Args>(args)...);
+ DCHECK(!item->OffsetAssigned());
+ if (eagerly_assign_offsets_) {
+ item->SetOffset(offset);
+ }
+ return item;
+ }
+
+ Header* header_;
+ // If we eagerly assign offsets during IR building or later after layout. Must be false if
+ // changing the layout is enabled.
+ bool eagerly_assign_offsets_;
+
+ // Note: maps do not have ownership.
+ CollectionMap<StringData> string_datas_map_;
+ CollectionMap<TypeList> type_lists_map_;
+ CollectionMap<EncodedArrayItem> encoded_array_items_map_;
+ CollectionMap<AnnotationItem> annotation_items_map_;
+ CollectionMap<AnnotationSetItem> annotation_set_items_map_;
+ CollectionMap<AnnotationSetRefList> annotation_set_ref_lists_map_;
+ CollectionMap<AnnotationsDirectoryItem> annotations_directory_items_map_;
+ CollectionMap<DebugInfoItem> debug_info_items_map_;
+ // Code item maps need to check both the debug info offset and debug info offset, do not use
+ // CollectionMap.
+ // First offset is the code item offset, second is the debug info offset.
+ std::map<std::pair<uint32_t, uint32_t>, CodeItem*> code_items_map_;
+ CollectionMap<ClassData> class_datas_map_;
+
+ DISALLOW_COPY_AND_ASSIGN(BuilderMaps);
+};
Header* DexIrBuilder(const DexFile& dex_file,
bool eagerly_assign_offsets,
@@ -50,36 +262,35 @@
dex_file.NumFieldIds(),
dex_file.NumMethodIds(),
dex_file.NumClassDefs());
- Collections& collections = header->GetCollections();
- collections.SetEagerlyAssignOffsets(eagerly_assign_offsets);
+ BuilderMaps builder_maps(header, eagerly_assign_offsets);
// Walk the rest of the header fields.
// StringId table.
- collections.SetStringIdsOffset(disk_header.string_ids_off_);
+ header->StringIds().SetOffset(disk_header.string_ids_off_);
for (uint32_t i = 0; i < dex_file.NumStringIds(); ++i) {
- collections.CreateStringId(dex_file, i);
+ builder_maps.CreateStringId(dex_file, i);
}
// TypeId table.
- collections.SetTypeIdsOffset(disk_header.type_ids_off_);
+ header->TypeIds().SetOffset(disk_header.type_ids_off_);
for (uint32_t i = 0; i < dex_file.NumTypeIds(); ++i) {
- collections.CreateTypeId(dex_file, i);
+ builder_maps.CreateTypeId(dex_file, i);
}
// ProtoId table.
- collections.SetProtoIdsOffset(disk_header.proto_ids_off_);
+ header->ProtoIds().SetOffset(disk_header.proto_ids_off_);
for (uint32_t i = 0; i < dex_file.NumProtoIds(); ++i) {
- collections.CreateProtoId(dex_file, i);
+ builder_maps.CreateProtoId(dex_file, i);
}
// FieldId table.
- collections.SetFieldIdsOffset(disk_header.field_ids_off_);
+ header->FieldIds().SetOffset(disk_header.field_ids_off_);
for (uint32_t i = 0; i < dex_file.NumFieldIds(); ++i) {
- collections.CreateFieldId(dex_file, i);
+ builder_maps.CreateFieldId(dex_file, i);
}
// MethodId table.
- collections.SetMethodIdsOffset(disk_header.method_ids_off_);
+ header->MethodIds().SetOffset(disk_header.method_ids_off_);
for (uint32_t i = 0; i < dex_file.NumMethodIds(); ++i) {
- collections.CreateMethodId(dex_file, i);
+ builder_maps.CreateMethodId(dex_file, i);
}
// ClassDef table.
- collections.SetClassDefsOffset(disk_header.class_defs_off_);
+ header->ClassDefs().SetOffset(disk_header.class_defs_off_);
for (uint32_t i = 0; i < dex_file.NumClassDefs(); ++i) {
if (!options.class_filter_.empty()) {
// If the filter is enabled (not empty), filter out classes that don't have a matching
@@ -90,29 +301,29 @@
continue;
}
}
- collections.CreateClassDef(dex_file, i);
+ builder_maps.CreateClassDef(dex_file, i);
}
// MapItem.
- collections.SetMapListOffset(disk_header.map_off_);
+ header->SetMapListOffset(disk_header.map_off_);
// CallSiteIds and MethodHandleItems.
- collections.CreateCallSitesAndMethodHandles(dex_file);
- CheckAndSetRemainingOffsets(dex_file, &collections, options);
+ builder_maps.CreateCallSitesAndMethodHandles(dex_file);
+ builder_maps.CheckAndSetRemainingOffsets(dex_file, options);
// Sort the vectors by the map order (same order as the file).
- collections.SortVectorsByMapOrder();
- collections.ClearMaps();
+ builder_maps.SortVectorsByMapOrder();
// Load the link data if it exists.
- collections.SetLinkData(std::vector<uint8_t>(
+ header->SetLinkData(std::vector<uint8_t>(
dex_file.DataBegin() + dex_file.GetHeader().link_off_,
dex_file.DataBegin() + dex_file.GetHeader().link_off_ + dex_file.GetHeader().link_size_));
return header;
}
-static void CheckAndSetRemainingOffsets(const DexFile& dex_file,
- Collections* collections,
- const Options& options) {
+/*
+ * Get all the types, strings, methods, and fields referred to from bytecode.
+ */
+void BuilderMaps::CheckAndSetRemainingOffsets(const DexFile& dex_file, const Options& options) {
const DexFile::Header& disk_header = dex_file.GetHeader();
// Read MapItems and validate/set remaining offsets.
const DexFile::MapList* map = dex_file.GetMapList();
@@ -125,74 +336,74 @@
CHECK_EQ(item->offset_, 0u);
break;
case DexFile::kDexTypeStringIdItem:
- CHECK_EQ(item->size_, collections->StringIdsSize());
- CHECK_EQ(item->offset_, collections->StringIdsOffset());
+ CHECK_EQ(item->size_, header_->StringIds().Size());
+ CHECK_EQ(item->offset_, header_->StringIds().GetOffset());
break;
case DexFile::kDexTypeTypeIdItem:
- CHECK_EQ(item->size_, collections->TypeIdsSize());
- CHECK_EQ(item->offset_, collections->TypeIdsOffset());
+ CHECK_EQ(item->size_, header_->TypeIds().Size());
+ CHECK_EQ(item->offset_, header_->TypeIds().GetOffset());
break;
case DexFile::kDexTypeProtoIdItem:
- CHECK_EQ(item->size_, collections->ProtoIdsSize());
- CHECK_EQ(item->offset_, collections->ProtoIdsOffset());
+ CHECK_EQ(item->size_, header_->ProtoIds().Size());
+ CHECK_EQ(item->offset_, header_->ProtoIds().GetOffset());
break;
case DexFile::kDexTypeFieldIdItem:
- CHECK_EQ(item->size_, collections->FieldIdsSize());
- CHECK_EQ(item->offset_, collections->FieldIdsOffset());
+ CHECK_EQ(item->size_, header_->FieldIds().Size());
+ CHECK_EQ(item->offset_, header_->FieldIds().GetOffset());
break;
case DexFile::kDexTypeMethodIdItem:
- CHECK_EQ(item->size_, collections->MethodIdsSize());
- CHECK_EQ(item->offset_, collections->MethodIdsOffset());
+ CHECK_EQ(item->size_, header_->MethodIds().Size());
+ CHECK_EQ(item->offset_, header_->MethodIds().GetOffset());
break;
case DexFile::kDexTypeClassDefItem:
if (options.class_filter_.empty()) {
// The filter may have removed some classes, this will get fixed up during writing.
- CHECK_EQ(item->size_, collections->ClassDefsSize());
+ CHECK_EQ(item->size_, header_->ClassDefs().Size());
}
- CHECK_EQ(item->offset_, collections->ClassDefsOffset());
+ CHECK_EQ(item->offset_, header_->ClassDefs().GetOffset());
break;
case DexFile::kDexTypeCallSiteIdItem:
- CHECK_EQ(item->size_, collections->CallSiteIdsSize());
- CHECK_EQ(item->offset_, collections->CallSiteIdsOffset());
+ CHECK_EQ(item->size_, header_->CallSiteIds().Size());
+ CHECK_EQ(item->offset_, header_->CallSiteIds().GetOffset());
break;
case DexFile::kDexTypeMethodHandleItem:
- CHECK_EQ(item->size_, collections->MethodHandleItemsSize());
- CHECK_EQ(item->offset_, collections->MethodHandleItemsOffset());
+ CHECK_EQ(item->size_, header_->MethodHandleItems().Size());
+ CHECK_EQ(item->offset_, header_->MethodHandleItems().GetOffset());
break;
case DexFile::kDexTypeMapList:
CHECK_EQ(item->size_, 1u);
CHECK_EQ(item->offset_, disk_header.map_off_);
break;
case DexFile::kDexTypeTypeList:
- collections->SetTypeListsOffset(item->offset_);
+ header_->TypeLists().SetOffset(item->offset_);
break;
case DexFile::kDexTypeAnnotationSetRefList:
- collections->SetAnnotationSetRefListsOffset(item->offset_);
+ header_->AnnotationSetRefLists().SetOffset(item->offset_);
break;
case DexFile::kDexTypeAnnotationSetItem:
- collections->SetAnnotationSetItemsOffset(item->offset_);
+ header_->AnnotationSetItems().SetOffset(item->offset_);
break;
case DexFile::kDexTypeClassDataItem:
- collections->SetClassDatasOffset(item->offset_);
+ header_->ClassDatas().SetOffset(item->offset_);
break;
case DexFile::kDexTypeCodeItem:
- collections->SetCodeItemsOffset(item->offset_);
+ header_->CodeItems().SetOffset(item->offset_);
break;
case DexFile::kDexTypeStringDataItem:
- collections->SetStringDatasOffset(item->offset_);
+ header_->StringDatas().SetOffset(item->offset_);
break;
case DexFile::kDexTypeDebugInfoItem:
- collections->SetDebugInfoItemsOffset(item->offset_);
+ header_->DebugInfoItems().SetOffset(item->offset_);
break;
case DexFile::kDexTypeAnnotationItem:
- collections->SetAnnotationItemsOffset(item->offset_);
- collections->AddAnnotationsFromMapListSection(dex_file, item->offset_, item->size_);
+ header_->AnnotationItems().SetOffset(item->offset_);
+ AddAnnotationsFromMapListSection(dex_file, item->offset_, item->size_);
break;
case DexFile::kDexTypeEncodedArrayItem:
- collections->SetEncodedArrayItemsOffset(item->offset_);
+ header_->EncodedArrayItems().SetOffset(item->offset_);
break;
case DexFile::kDexTypeAnnotationsDirectoryItem:
- collections->SetAnnotationsDirectoryItemsOffset(item->offset_);
+ header_->AnnotationsDirectoryItems().SetOffset(item->offset_);
break;
default:
LOG(ERROR) << "Unknown map list item type.";
@@ -200,5 +411,798 @@
}
}
+void BuilderMaps::CreateStringId(const DexFile& dex_file, uint32_t i) {
+ const DexFile::StringId& disk_string_id = dex_file.GetStringId(dex::StringIndex(i));
+ StringData* string_data =
+ string_datas_map_.CreateAndAddItem(header_->StringDatas(),
+ eagerly_assign_offsets_,
+ disk_string_id.string_data_off_,
+ dex_file.GetStringData(disk_string_id));
+ CreateAndAddIndexedItem(header_->StringIds(),
+ header_->StringIds().GetOffset() + i * StringId::ItemSize(),
+ i,
+ string_data);
+}
+
+void BuilderMaps::CreateTypeId(const DexFile& dex_file, uint32_t i) {
+ const DexFile::TypeId& disk_type_id = dex_file.GetTypeId(dex::TypeIndex(i));
+ CreateAndAddIndexedItem(header_->TypeIds(),
+ header_->TypeIds().GetOffset() + i * TypeId::ItemSize(),
+ i,
+ header_->StringIds()[disk_type_id.descriptor_idx_.index_]);
+}
+
+void BuilderMaps::CreateProtoId(const DexFile& dex_file, uint32_t i) {
+ const DexFile::ProtoId& disk_proto_id = dex_file.GetProtoId(dex::ProtoIndex(i));
+ const DexFile::TypeList* type_list = dex_file.GetProtoParameters(disk_proto_id);
+ TypeList* parameter_type_list = CreateTypeList(type_list, disk_proto_id.parameters_off_);
+
+ CreateAndAddIndexedItem(header_->ProtoIds(),
+ header_->ProtoIds().GetOffset() + i * ProtoId::ItemSize(),
+ i,
+ header_->StringIds()[disk_proto_id.shorty_idx_.index_],
+ header_->TypeIds()[disk_proto_id.return_type_idx_.index_],
+ parameter_type_list);
+}
+
+void BuilderMaps::CreateFieldId(const DexFile& dex_file, uint32_t i) {
+ const DexFile::FieldId& disk_field_id = dex_file.GetFieldId(i);
+ CreateAndAddIndexedItem(header_->FieldIds(),
+ header_->FieldIds().GetOffset() + i * FieldId::ItemSize(),
+ i,
+ header_->TypeIds()[disk_field_id.class_idx_.index_],
+ header_->TypeIds()[disk_field_id.type_idx_.index_],
+ header_->StringIds()[disk_field_id.name_idx_.index_]);
+}
+
+void BuilderMaps::CreateMethodId(const DexFile& dex_file, uint32_t i) {
+ const DexFile::MethodId& disk_method_id = dex_file.GetMethodId(i);
+ CreateAndAddIndexedItem(header_->MethodIds(),
+ header_->MethodIds().GetOffset() + i * MethodId::ItemSize(),
+ i,
+ header_->TypeIds()[disk_method_id.class_idx_.index_],
+ header_->ProtoIds()[disk_method_id.proto_idx_.index_],
+ header_->StringIds()[disk_method_id.name_idx_.index_]);
+}
+
+void BuilderMaps::CreateClassDef(const DexFile& dex_file, uint32_t i) {
+ const DexFile::ClassDef& disk_class_def = dex_file.GetClassDef(i);
+ const TypeId* class_type = header_->TypeIds()[disk_class_def.class_idx_.index_];
+ uint32_t access_flags = disk_class_def.access_flags_;
+ const TypeId* superclass = header_->GetTypeIdOrNullPtr(disk_class_def.superclass_idx_.index_);
+
+ const DexFile::TypeList* type_list = dex_file.GetInterfacesList(disk_class_def);
+ TypeList* interfaces_type_list = CreateTypeList(type_list, disk_class_def.interfaces_off_);
+
+ const StringId* source_file =
+ header_->GetStringIdOrNullPtr(disk_class_def.source_file_idx_.index_);
+ // Annotations.
+ AnnotationsDirectoryItem* annotations = nullptr;
+ const DexFile::AnnotationsDirectoryItem* disk_annotations_directory_item =
+ dex_file.GetAnnotationsDirectory(disk_class_def);
+ if (disk_annotations_directory_item != nullptr) {
+ annotations = CreateAnnotationsDirectoryItem(
+ dex_file, disk_annotations_directory_item, disk_class_def.annotations_off_);
+ }
+ // Static field initializers.
+ const uint8_t* static_data = dex_file.GetEncodedStaticFieldValuesArray(disk_class_def);
+ EncodedArrayItem* static_values =
+ CreateEncodedArrayItem(dex_file, static_data, disk_class_def.static_values_off_);
+ ClassData* class_data = CreateClassData(
+ dex_file, dex_file.GetClassData(disk_class_def), disk_class_def.class_data_off_);
+ CreateAndAddIndexedItem(header_->ClassDefs(),
+ header_->ClassDefs().GetOffset() + i * ClassDef::ItemSize(),
+ i,
+ class_type,
+ access_flags,
+ superclass,
+ interfaces_type_list,
+ source_file,
+ annotations,
+ static_values,
+ class_data);
+}
+
+void BuilderMaps::CreateCallSiteId(const DexFile& dex_file, uint32_t i) {
+ const DexFile::CallSiteIdItem& disk_call_site_id = dex_file.GetCallSiteId(i);
+ const uint8_t* disk_call_item_ptr = dex_file.DataBegin() + disk_call_site_id.data_off_;
+ EncodedArrayItem* call_site_item =
+ CreateEncodedArrayItem(dex_file, disk_call_item_ptr, disk_call_site_id.data_off_);
+
+ CreateAndAddIndexedItem(header_->CallSiteIds(),
+ header_->CallSiteIds().GetOffset() + i * CallSiteId::ItemSize(),
+ i,
+ call_site_item);
+}
+
+void BuilderMaps::CreateMethodHandleItem(const DexFile& dex_file, uint32_t i) {
+ const DexFile::MethodHandleItem& disk_method_handle = dex_file.GetMethodHandle(i);
+ uint16_t index = disk_method_handle.field_or_method_idx_;
+ DexFile::MethodHandleType type =
+ static_cast<DexFile::MethodHandleType>(disk_method_handle.method_handle_type_);
+ bool is_invoke = type == DexFile::MethodHandleType::kInvokeStatic ||
+ type == DexFile::MethodHandleType::kInvokeInstance ||
+ type == DexFile::MethodHandleType::kInvokeConstructor ||
+ type == DexFile::MethodHandleType::kInvokeDirect ||
+ type == DexFile::MethodHandleType::kInvokeInterface;
+ static_assert(DexFile::MethodHandleType::kLast == DexFile::MethodHandleType::kInvokeInterface,
+ "Unexpected method handle types.");
+ IndexedItem* field_or_method_id;
+ if (is_invoke) {
+ field_or_method_id = header_->MethodIds()[index];
+ } else {
+ field_or_method_id = header_->FieldIds()[index];
+ }
+ CreateAndAddIndexedItem(header_->MethodHandleItems(),
+ header_->MethodHandleItems().GetOffset() +
+ i * MethodHandleItem::ItemSize(),
+ i,
+ type,
+ field_or_method_id);
+}
+
+void BuilderMaps::CreateCallSitesAndMethodHandles(const DexFile& dex_file) {
+ // Iterate through the map list and set the offset of the CallSiteIds and MethodHandleItems.
+ const DexFile::MapList* map = dex_file.GetMapList();
+ for (uint32_t i = 0; i < map->size_; ++i) {
+ const DexFile::MapItem* item = map->list_ + i;
+ switch (item->type_) {
+ case DexFile::kDexTypeCallSiteIdItem:
+ header_->CallSiteIds().SetOffset(item->offset_);
+ break;
+ case DexFile::kDexTypeMethodHandleItem:
+ header_->MethodHandleItems().SetOffset(item->offset_);
+ break;
+ default:
+ break;
+ }
+ }
+ // Populate MethodHandleItems first (CallSiteIds may depend on them).
+ for (uint32_t i = 0; i < dex_file.NumMethodHandles(); i++) {
+ CreateMethodHandleItem(dex_file, i);
+ }
+ // Populate CallSiteIds.
+ for (uint32_t i = 0; i < dex_file.NumCallSiteIds(); i++) {
+ CreateCallSiteId(dex_file, i);
+ }
+}
+
+TypeList* BuilderMaps::CreateTypeList(const DexFile::TypeList* dex_type_list, uint32_t offset) {
+ if (dex_type_list == nullptr) {
+ return nullptr;
+ }
+ TypeList* type_list = type_lists_map_.GetExistingObject(offset);
+ if (type_list == nullptr) {
+ TypeIdVector* type_vector = new TypeIdVector();
+ uint32_t size = dex_type_list->Size();
+ for (uint32_t index = 0; index < size; ++index) {
+ type_vector->push_back(header_->TypeIds()[
+ dex_type_list->GetTypeItem(index).type_idx_.index_]);
+ }
+ type_list = type_lists_map_.CreateAndAddItem(header_->TypeLists(),
+ eagerly_assign_offsets_,
+ offset,
+ type_vector);
+ }
+ return type_list;
+}
+
+EncodedArrayItem* BuilderMaps::CreateEncodedArrayItem(const DexFile& dex_file,
+ const uint8_t* static_data,
+ uint32_t offset) {
+ if (static_data == nullptr) {
+ return nullptr;
+ }
+ EncodedArrayItem* encoded_array_item = encoded_array_items_map_.GetExistingObject(offset);
+ if (encoded_array_item == nullptr) {
+ uint32_t size = DecodeUnsignedLeb128(&static_data);
+ EncodedValueVector* values = new EncodedValueVector();
+ for (uint32_t i = 0; i < size; ++i) {
+ values->push_back(std::unique_ptr<EncodedValue>(ReadEncodedValue(dex_file, &static_data)));
+ }
+ // TODO: Calculate the size of the encoded array.
+ encoded_array_item = encoded_array_items_map_.CreateAndAddItem(header_->EncodedArrayItems(),
+ eagerly_assign_offsets_,
+ offset,
+ values);
+ }
+ return encoded_array_item;
+}
+
+void BuilderMaps::AddAnnotationsFromMapListSection(const DexFile& dex_file,
+ uint32_t start_offset,
+ uint32_t count) {
+ uint32_t current_offset = start_offset;
+ for (size_t i = 0; i < count; ++i) {
+ // Annotation that we didn't process already, add it to the set.
+ const DexFile::AnnotationItem* annotation = dex_file.GetAnnotationItemAtOffset(current_offset);
+ AnnotationItem* annotation_item = CreateAnnotationItem(dex_file, annotation);
+ DCHECK(annotation_item != nullptr);
+ current_offset += annotation_item->GetSize();
+ }
+}
+
+AnnotationItem* BuilderMaps::CreateAnnotationItem(const DexFile& dex_file,
+ const DexFile::AnnotationItem* annotation) {
+ const uint8_t* const start_data = reinterpret_cast<const uint8_t*>(annotation);
+ const uint32_t offset = start_data - dex_file.DataBegin();
+ AnnotationItem* annotation_item = annotation_items_map_.GetExistingObject(offset);
+ if (annotation_item == nullptr) {
+ uint8_t visibility = annotation->visibility_;
+ const uint8_t* annotation_data = annotation->annotation_;
+ std::unique_ptr<EncodedValue> encoded_value(
+ ReadEncodedValue(dex_file, &annotation_data, DexFile::kDexAnnotationAnnotation, 0));
+ annotation_item =
+ annotation_items_map_.CreateAndAddItem(header_->AnnotationItems(),
+ eagerly_assign_offsets_,
+ offset,
+ visibility,
+ encoded_value->ReleaseEncodedAnnotation());
+ annotation_item->SetSize(annotation_data - start_data);
+ }
+ return annotation_item;
+}
+
+
+AnnotationSetItem* BuilderMaps::CreateAnnotationSetItem(const DexFile& dex_file,
+ const DexFile::AnnotationSetItem* disk_annotations_item, uint32_t offset) {
+ if (disk_annotations_item == nullptr || (disk_annotations_item->size_ == 0 && offset == 0)) {
+ return nullptr;
+ }
+ AnnotationSetItem* annotation_set_item = annotation_set_items_map_.GetExistingObject(offset);
+ if (annotation_set_item == nullptr) {
+ std::vector<AnnotationItem*>* items = new std::vector<AnnotationItem*>();
+ for (uint32_t i = 0; i < disk_annotations_item->size_; ++i) {
+ const DexFile::AnnotationItem* annotation =
+ dex_file.GetAnnotationItem(disk_annotations_item, i);
+ if (annotation == nullptr) {
+ continue;
+ }
+ AnnotationItem* annotation_item = CreateAnnotationItem(dex_file, annotation);
+ items->push_back(annotation_item);
+ }
+ annotation_set_item =
+ annotation_set_items_map_.CreateAndAddItem(header_->AnnotationSetItems(),
+ eagerly_assign_offsets_,
+ offset,
+ items);
+ }
+ return annotation_set_item;
+}
+
+AnnotationsDirectoryItem* BuilderMaps::CreateAnnotationsDirectoryItem(const DexFile& dex_file,
+ const DexFile::AnnotationsDirectoryItem* disk_annotations_item, uint32_t offset) {
+ AnnotationsDirectoryItem* annotations_directory_item =
+ annotations_directory_items_map_.GetExistingObject(offset);
+ if (annotations_directory_item != nullptr) {
+ return annotations_directory_item;
+ }
+ const DexFile::AnnotationSetItem* class_set_item =
+ dex_file.GetClassAnnotationSet(disk_annotations_item);
+ AnnotationSetItem* class_annotation = nullptr;
+ if (class_set_item != nullptr) {
+ uint32_t item_offset = disk_annotations_item->class_annotations_off_;
+ class_annotation = CreateAnnotationSetItem(dex_file, class_set_item, item_offset);
+ }
+ const DexFile::FieldAnnotationsItem* fields =
+ dex_file.GetFieldAnnotations(disk_annotations_item);
+ FieldAnnotationVector* field_annotations = nullptr;
+ if (fields != nullptr) {
+ field_annotations = new FieldAnnotationVector();
+ for (uint32_t i = 0; i < disk_annotations_item->fields_size_; ++i) {
+ FieldId* field_id = header_->FieldIds()[fields[i].field_idx_];
+ const DexFile::AnnotationSetItem* field_set_item =
+ dex_file.GetFieldAnnotationSetItem(fields[i]);
+ uint32_t annotation_set_offset = fields[i].annotations_off_;
+ AnnotationSetItem* annotation_set_item =
+ CreateAnnotationSetItem(dex_file, field_set_item, annotation_set_offset);
+ field_annotations->push_back(std::unique_ptr<FieldAnnotation>(
+ new FieldAnnotation(field_id, annotation_set_item)));
+ }
+ }
+ const DexFile::MethodAnnotationsItem* methods =
+ dex_file.GetMethodAnnotations(disk_annotations_item);
+ MethodAnnotationVector* method_annotations = nullptr;
+ if (methods != nullptr) {
+ method_annotations = new MethodAnnotationVector();
+ for (uint32_t i = 0; i < disk_annotations_item->methods_size_; ++i) {
+ MethodId* method_id = header_->MethodIds()[methods[i].method_idx_];
+ const DexFile::AnnotationSetItem* method_set_item =
+ dex_file.GetMethodAnnotationSetItem(methods[i]);
+ uint32_t annotation_set_offset = methods[i].annotations_off_;
+ AnnotationSetItem* annotation_set_item =
+ CreateAnnotationSetItem(dex_file, method_set_item, annotation_set_offset);
+ method_annotations->push_back(std::unique_ptr<MethodAnnotation>(
+ new MethodAnnotation(method_id, annotation_set_item)));
+ }
+ }
+ const DexFile::ParameterAnnotationsItem* parameters =
+ dex_file.GetParameterAnnotations(disk_annotations_item);
+ ParameterAnnotationVector* parameter_annotations = nullptr;
+ if (parameters != nullptr) {
+ parameter_annotations = new ParameterAnnotationVector();
+ for (uint32_t i = 0; i < disk_annotations_item->parameters_size_; ++i) {
+ MethodId* method_id = header_->MethodIds()[parameters[i].method_idx_];
+ const DexFile::AnnotationSetRefList* list =
+ dex_file.GetParameterAnnotationSetRefList(¶meters[i]);
+ parameter_annotations->push_back(std::unique_ptr<ParameterAnnotation>(
+ GenerateParameterAnnotation(dex_file, method_id, list, parameters[i].annotations_off_)));
+ }
+ }
+ // TODO: Calculate the size of the annotations directory.
+ return annotations_directory_items_map_.CreateAndAddItem(header_->AnnotationsDirectoryItems(),
+ eagerly_assign_offsets_,
+ offset,
+ class_annotation,
+ field_annotations,
+ method_annotations,
+ parameter_annotations);
+}
+
+CodeItem* BuilderMaps::DedupeOrCreateCodeItem(const DexFile& dex_file,
+ const DexFile::CodeItem* disk_code_item,
+ uint32_t offset,
+ uint32_t dex_method_index) {
+ if (disk_code_item == nullptr) {
+ return nullptr;
+ }
+ CodeItemDebugInfoAccessor accessor(dex_file, disk_code_item, dex_method_index);
+ const uint32_t debug_info_offset = accessor.DebugInfoOffset();
+
+ // Create the offsets pair and dedupe based on it.
+ std::pair<uint32_t, uint32_t> offsets_pair(offset, debug_info_offset);
+ auto existing = code_items_map_.find(offsets_pair);
+ if (existing != code_items_map_.end()) {
+ return existing->second;
+ }
+
+ const uint8_t* debug_info_stream = dex_file.GetDebugInfoStream(debug_info_offset);
+ DebugInfoItem* debug_info = nullptr;
+ if (debug_info_stream != nullptr) {
+ debug_info = debug_info_items_map_.GetExistingObject(debug_info_offset);
+ if (debug_info == nullptr) {
+ uint32_t debug_info_size = GetDebugInfoStreamSize(debug_info_stream);
+ uint8_t* debug_info_buffer = new uint8_t[debug_info_size];
+ memcpy(debug_info_buffer, debug_info_stream, debug_info_size);
+ debug_info = debug_info_items_map_.CreateAndAddItem(header_->DebugInfoItems(),
+ eagerly_assign_offsets_,
+ debug_info_offset,
+ debug_info_size,
+ debug_info_buffer);
+ }
+ }
+
+ uint32_t insns_size = accessor.InsnsSizeInCodeUnits();
+ uint16_t* insns = new uint16_t[insns_size];
+ memcpy(insns, accessor.Insns(), insns_size * sizeof(uint16_t));
+
+ TryItemVector* tries = nullptr;
+ CatchHandlerVector* handler_list = nullptr;
+ if (accessor.TriesSize() > 0) {
+ tries = new TryItemVector();
+ handler_list = new CatchHandlerVector();
+ for (const DexFile::TryItem& disk_try_item : accessor.TryItems()) {
+ uint32_t start_addr = disk_try_item.start_addr_;
+ uint16_t insn_count = disk_try_item.insn_count_;
+ uint16_t handler_off = disk_try_item.handler_off_;
+ const CatchHandler* handlers = nullptr;
+ for (std::unique_ptr<const CatchHandler>& existing_handlers : *handler_list) {
+ if (handler_off == existing_handlers->GetListOffset()) {
+ handlers = existing_handlers.get();
+ break;
+ }
+ }
+ if (handlers == nullptr) {
+ bool catch_all = false;
+ TypeAddrPairVector* addr_pairs = new TypeAddrPairVector();
+ for (CatchHandlerIterator it(accessor, disk_try_item); it.HasNext(); it.Next()) {
+ const dex::TypeIndex type_index = it.GetHandlerTypeIndex();
+ const TypeId* type_id = header_->GetTypeIdOrNullPtr(type_index.index_);
+ catch_all |= type_id == nullptr;
+ addr_pairs->push_back(std::unique_ptr<const TypeAddrPair>(
+ new TypeAddrPair(type_id, it.GetHandlerAddress())));
+ }
+ handlers = new CatchHandler(catch_all, handler_off, addr_pairs);
+ handler_list->push_back(std::unique_ptr<const CatchHandler>(handlers));
+ }
+ TryItem* try_item = new TryItem(start_addr, insn_count, handlers);
+ tries->push_back(std::unique_ptr<const TryItem>(try_item));
+ }
+ // Manually walk catch handlers list and add any missing handlers unreferenced by try items.
+ const uint8_t* handlers_base = accessor.GetCatchHandlerData();
+ const uint8_t* handlers_data = handlers_base;
+ uint32_t handlers_size = DecodeUnsignedLeb128(&handlers_data);
+ while (handlers_size > handler_list->size()) {
+ bool already_added = false;
+ uint16_t handler_off = handlers_data - handlers_base;
+ for (std::unique_ptr<const CatchHandler>& existing_handlers : *handler_list) {
+ if (handler_off == existing_handlers->GetListOffset()) {
+ already_added = true;
+ break;
+ }
+ }
+ int32_t size = DecodeSignedLeb128(&handlers_data);
+ bool has_catch_all = size <= 0;
+ if (has_catch_all) {
+ size = -size;
+ }
+ if (already_added) {
+ for (int32_t i = 0; i < size; i++) {
+ DecodeUnsignedLeb128(&handlers_data);
+ DecodeUnsignedLeb128(&handlers_data);
+ }
+ if (has_catch_all) {
+ DecodeUnsignedLeb128(&handlers_data);
+ }
+ continue;
+ }
+ TypeAddrPairVector* addr_pairs = new TypeAddrPairVector();
+ for (int32_t i = 0; i < size; i++) {
+ const TypeId* type_id =
+ header_->GetTypeIdOrNullPtr(DecodeUnsignedLeb128(&handlers_data));
+ uint32_t addr = DecodeUnsignedLeb128(&handlers_data);
+ addr_pairs->push_back(
+ std::unique_ptr<const TypeAddrPair>(new TypeAddrPair(type_id, addr)));
+ }
+ if (has_catch_all) {
+ uint32_t addr = DecodeUnsignedLeb128(&handlers_data);
+ addr_pairs->push_back(
+ std::unique_ptr<const TypeAddrPair>(new TypeAddrPair(nullptr, addr)));
+ }
+ const CatchHandler* handler = new CatchHandler(has_catch_all, handler_off, addr_pairs);
+ handler_list->push_back(std::unique_ptr<const CatchHandler>(handler));
+ }
+ }
+
+ uint32_t size = dex_file.GetCodeItemSize(*disk_code_item);
+ CodeItem* code_item = header_->CodeItems().CreateAndAddItem(accessor.RegistersSize(),
+ accessor.InsSize(),
+ accessor.OutsSize(),
+ debug_info,
+ insns_size,
+ insns,
+ tries,
+ handler_list);
+ code_item->SetSize(size);
+
+ // Add the code item to the map.
+ DCHECK(!code_item->OffsetAssigned());
+ if (eagerly_assign_offsets_) {
+ code_item->SetOffset(offset);
+ }
+ code_items_map_.emplace(offsets_pair, code_item);
+
+ // Add "fixup" references to types, strings, methods, and fields.
+ // This is temporary, as we will probably want more detailed parsing of the
+ // instructions here.
+ std::vector<TypeId*> type_ids;
+ std::vector<StringId*> string_ids;
+ std::vector<MethodId*> method_ids;
+ std::vector<FieldId*> field_ids;
+ if (GetIdsFromByteCode(code_item,
+ /*out*/ &type_ids,
+ /*out*/ &string_ids,
+ /*out*/ &method_ids,
+ /*out*/ &field_ids)) {
+ CodeFixups* fixups = new CodeFixups(std::move(type_ids),
+ std::move(string_ids),
+ std::move(method_ids),
+ std::move(field_ids));
+ code_item->SetCodeFixups(fixups);
+ }
+
+ return code_item;
+}
+
+ClassData* BuilderMaps::CreateClassData(
+ const DexFile& dex_file, const uint8_t* encoded_data, uint32_t offset) {
+ // Read the fields and methods defined by the class, resolving the circular reference from those
+ // to classes by setting class at the same time.
+ ClassData* class_data = class_datas_map_.GetExistingObject(offset);
+ if (class_data == nullptr && encoded_data != nullptr) {
+ ClassDataItemIterator cdii(dex_file, encoded_data);
+ // Static fields.
+ FieldItemVector* static_fields = new FieldItemVector();
+ for (; cdii.HasNextStaticField(); cdii.Next()) {
+ FieldId* field_item = header_->FieldIds()[cdii.GetMemberIndex()];
+ uint32_t access_flags = cdii.GetRawMemberAccessFlags();
+ static_fields->emplace_back(access_flags, field_item);
+ }
+ // Instance fields.
+ FieldItemVector* instance_fields = new FieldItemVector();
+ for (; cdii.HasNextInstanceField(); cdii.Next()) {
+ FieldId* field_item = header_->FieldIds()[cdii.GetMemberIndex()];
+ uint32_t access_flags = cdii.GetRawMemberAccessFlags();
+ instance_fields->emplace_back(access_flags, field_item);
+ }
+ // Direct methods.
+ MethodItemVector* direct_methods = new MethodItemVector();
+ for (; cdii.HasNextDirectMethod(); cdii.Next()) {
+ direct_methods->push_back(GenerateMethodItem(dex_file, cdii));
+ }
+ // Virtual methods.
+ MethodItemVector* virtual_methods = new MethodItemVector();
+ for (; cdii.HasNextVirtualMethod(); cdii.Next()) {
+ virtual_methods->push_back(GenerateMethodItem(dex_file, cdii));
+ }
+ class_data = class_datas_map_.CreateAndAddItem(header_->ClassDatas(),
+ eagerly_assign_offsets_,
+ offset,
+ static_fields,
+ instance_fields,
+ direct_methods,
+ virtual_methods);
+ class_data->SetSize(cdii.EndDataPointer() - encoded_data);
+ }
+ return class_data;
+}
+
+void BuilderMaps::SortVectorsByMapOrder() {
+ header_->StringDatas().SortByMapOrder(string_datas_map_.Collection());
+ header_->TypeLists().SortByMapOrder(type_lists_map_.Collection());
+ header_->EncodedArrayItems().SortByMapOrder(encoded_array_items_map_.Collection());
+ header_->AnnotationItems().SortByMapOrder(annotation_items_map_.Collection());
+ header_->AnnotationSetItems().SortByMapOrder(annotation_set_items_map_.Collection());
+ header_->AnnotationSetRefLists().SortByMapOrder(annotation_set_ref_lists_map_.Collection());
+ header_->AnnotationsDirectoryItems().SortByMapOrder(
+ annotations_directory_items_map_.Collection());
+ header_->DebugInfoItems().SortByMapOrder(debug_info_items_map_.Collection());
+ header_->CodeItems().SortByMapOrder(code_items_map_);
+ header_->ClassDatas().SortByMapOrder(class_datas_map_.Collection());
+}
+
+bool BuilderMaps::GetIdsFromByteCode(const CodeItem* code,
+ std::vector<TypeId*>* type_ids,
+ std::vector<StringId*>* string_ids,
+ std::vector<MethodId*>* method_ids,
+ std::vector<FieldId*>* field_ids) {
+ bool has_id = false;
+ IterationRange<DexInstructionIterator> instructions = code->Instructions();
+ SafeDexInstructionIterator it(instructions.begin(), instructions.end());
+ for (; !it.IsErrorState() && it < instructions.end(); ++it) {
+ // In case the instruction goes past the end of the code item, make sure to not process it.
+ SafeDexInstructionIterator next = it;
+ ++next;
+ if (next.IsErrorState()) {
+ break;
+ }
+ has_id |= GetIdFromInstruction(&it.Inst(), type_ids, string_ids, method_ids, field_ids);
+ } // for
+ return has_id;
+}
+
+bool BuilderMaps::GetIdFromInstruction(const Instruction* dec_insn,
+ std::vector<TypeId*>* type_ids,
+ std::vector<StringId*>* string_ids,
+ std::vector<MethodId*>* method_ids,
+ std::vector<FieldId*>* field_ids) {
+ // Determine index and width of the string.
+ uint32_t index = 0;
+ switch (Instruction::FormatOf(dec_insn->Opcode())) {
+ // SOME NOT SUPPORTED:
+ // case Instruction::k20bc:
+ case Instruction::k21c:
+ case Instruction::k35c:
+ // case Instruction::k35ms:
+ case Instruction::k3rc:
+ // case Instruction::k3rms:
+ // case Instruction::k35mi:
+ // case Instruction::k3rmi:
+ case Instruction::k45cc:
+ case Instruction::k4rcc:
+ index = dec_insn->VRegB();
+ break;
+ case Instruction::k31c:
+ index = dec_insn->VRegB();
+ break;
+ case Instruction::k22c:
+ // case Instruction::k22cs:
+ index = dec_insn->VRegC();
+ break;
+ default:
+ break;
+ } // switch
+
+ // Determine index type, and add reference to the appropriate collection.
+ switch (Instruction::IndexTypeOf(dec_insn->Opcode())) {
+ case Instruction::kIndexTypeRef:
+ if (index < header_->TypeIds().Size()) {
+ type_ids->push_back(header_->TypeIds()[index]);
+ return true;
+ }
+ break;
+ case Instruction::kIndexStringRef:
+ if (index < header_->StringIds().Size()) {
+ string_ids->push_back(header_->StringIds()[index]);
+ return true;
+ }
+ break;
+ case Instruction::kIndexMethodRef:
+ case Instruction::kIndexMethodAndProtoRef:
+ if (index < header_->MethodIds().Size()) {
+ method_ids->push_back(header_->MethodIds()[index]);
+ return true;
+ }
+ break;
+ case Instruction::kIndexFieldRef:
+ if (index < header_->FieldIds().Size()) {
+ field_ids->push_back(header_->FieldIds()[index]);
+ return true;
+ }
+ break;
+ case Instruction::kIndexUnknown:
+ case Instruction::kIndexNone:
+ case Instruction::kIndexVtableOffset:
+ case Instruction::kIndexFieldOffset:
+ default:
+ break;
+ } // switch
+ return false;
+}
+
+EncodedValue* BuilderMaps::ReadEncodedValue(const DexFile& dex_file, const uint8_t** data) {
+ const uint8_t encoded_value = *(*data)++;
+ const uint8_t type = encoded_value & 0x1f;
+ EncodedValue* item = new EncodedValue(type);
+ ReadEncodedValue(dex_file, data, type, encoded_value >> 5, item);
+ return item;
+}
+
+EncodedValue* BuilderMaps::ReadEncodedValue(const DexFile& dex_file,
+ const uint8_t** data,
+ uint8_t type,
+ uint8_t length) {
+ EncodedValue* item = new EncodedValue(type);
+ ReadEncodedValue(dex_file, data, type, length, item);
+ return item;
+}
+
+void BuilderMaps::ReadEncodedValue(const DexFile& dex_file,
+ const uint8_t** data,
+ uint8_t type,
+ uint8_t length,
+ EncodedValue* item) {
+ switch (type) {
+ case DexFile::kDexAnnotationByte:
+ item->SetByte(static_cast<int8_t>(ReadVarWidth(data, length, false)));
+ break;
+ case DexFile::kDexAnnotationShort:
+ item->SetShort(static_cast<int16_t>(ReadVarWidth(data, length, true)));
+ break;
+ case DexFile::kDexAnnotationChar:
+ item->SetChar(static_cast<uint16_t>(ReadVarWidth(data, length, false)));
+ break;
+ case DexFile::kDexAnnotationInt:
+ item->SetInt(static_cast<int32_t>(ReadVarWidth(data, length, true)));
+ break;
+ case DexFile::kDexAnnotationLong:
+ item->SetLong(static_cast<int64_t>(ReadVarWidth(data, length, true)));
+ break;
+ case DexFile::kDexAnnotationFloat: {
+ // Fill on right.
+ union {
+ float f;
+ uint32_t data;
+ } conv;
+ conv.data = static_cast<uint32_t>(ReadVarWidth(data, length, false)) << (3 - length) * 8;
+ item->SetFloat(conv.f);
+ break;
+ }
+ case DexFile::kDexAnnotationDouble: {
+ // Fill on right.
+ union {
+ double d;
+ uint64_t data;
+ } conv;
+ conv.data = ReadVarWidth(data, length, false) << (7 - length) * 8;
+ item->SetDouble(conv.d);
+ break;
+ }
+ case DexFile::kDexAnnotationMethodType: {
+ const uint32_t proto_index = static_cast<uint32_t>(ReadVarWidth(data, length, false));
+ item->SetProtoId(header_->ProtoIds()[proto_index]);
+ break;
+ }
+ case DexFile::kDexAnnotationMethodHandle: {
+ const uint32_t method_handle_index = static_cast<uint32_t>(ReadVarWidth(data, length, false));
+ item->SetMethodHandle(header_->MethodHandleItems()[method_handle_index]);
+ break;
+ }
+ case DexFile::kDexAnnotationString: {
+ const uint32_t string_index = static_cast<uint32_t>(ReadVarWidth(data, length, false));
+ item->SetStringId(header_->StringIds()[string_index]);
+ break;
+ }
+ case DexFile::kDexAnnotationType: {
+ const uint32_t string_index = static_cast<uint32_t>(ReadVarWidth(data, length, false));
+ item->SetTypeId(header_->TypeIds()[string_index]);
+ break;
+ }
+ case DexFile::kDexAnnotationField:
+ case DexFile::kDexAnnotationEnum: {
+ const uint32_t field_index = static_cast<uint32_t>(ReadVarWidth(data, length, false));
+ item->SetFieldId(header_->FieldIds()[field_index]);
+ break;
+ }
+ case DexFile::kDexAnnotationMethod: {
+ const uint32_t method_index = static_cast<uint32_t>(ReadVarWidth(data, length, false));
+ item->SetMethodId(header_->MethodIds()[method_index]);
+ break;
+ }
+ case DexFile::kDexAnnotationArray: {
+ EncodedValueVector* values = new EncodedValueVector();
+ const uint32_t offset = *data - dex_file.DataBegin();
+ const uint32_t size = DecodeUnsignedLeb128(data);
+ // Decode all elements.
+ for (uint32_t i = 0; i < size; i++) {
+ values->push_back(std::unique_ptr<EncodedValue>(ReadEncodedValue(dex_file, data)));
+ }
+ EncodedArrayItem* array_item = new EncodedArrayItem(values);
+ if (eagerly_assign_offsets_) {
+ array_item->SetOffset(offset);
+ }
+ item->SetEncodedArray(array_item);
+ break;
+ }
+ case DexFile::kDexAnnotationAnnotation: {
+ AnnotationElementVector* elements = new AnnotationElementVector();
+ const uint32_t type_idx = DecodeUnsignedLeb128(data);
+ const uint32_t size = DecodeUnsignedLeb128(data);
+ // Decode all name=value pairs.
+ for (uint32_t i = 0; i < size; i++) {
+ const uint32_t name_index = DecodeUnsignedLeb128(data);
+ elements->push_back(std::unique_ptr<AnnotationElement>(
+ new AnnotationElement(header_->StringIds()[name_index],
+ ReadEncodedValue(dex_file, data))));
+ }
+ item->SetEncodedAnnotation(new EncodedAnnotation(header_->TypeIds()[type_idx], elements));
+ break;
+ }
+ case DexFile::kDexAnnotationNull:
+ break;
+ case DexFile::kDexAnnotationBoolean:
+ item->SetBoolean(length != 0);
+ break;
+ default:
+ break;
+ }
+}
+
+MethodItem BuilderMaps::GenerateMethodItem(const DexFile& dex_file, ClassDataItemIterator& cdii) {
+ MethodId* method_id = header_->MethodIds()[cdii.GetMemberIndex()];
+ uint32_t access_flags = cdii.GetRawMemberAccessFlags();
+ const DexFile::CodeItem* disk_code_item = cdii.GetMethodCodeItem();
+ // Temporary hack to prevent incorrectly deduping code items if they have the same offset since
+ // they may have different debug info streams.
+ CodeItem* code_item = DedupeOrCreateCodeItem(dex_file,
+ disk_code_item,
+ cdii.GetMethodCodeItemOffset(),
+ cdii.GetMemberIndex());
+ return MethodItem(access_flags, method_id, code_item);
+}
+
+ParameterAnnotation* BuilderMaps::GenerateParameterAnnotation(
+ const DexFile& dex_file,
+ MethodId* method_id,
+ const DexFile::AnnotationSetRefList* annotation_set_ref_list,
+ uint32_t offset) {
+ AnnotationSetRefList* set_ref_list = annotation_set_ref_lists_map_.GetExistingObject(offset);
+ if (set_ref_list == nullptr) {
+ std::vector<AnnotationSetItem*>* annotations = new std::vector<AnnotationSetItem*>();
+ for (uint32_t i = 0; i < annotation_set_ref_list->size_; ++i) {
+ const DexFile::AnnotationSetItem* annotation_set_item =
+ dex_file.GetSetRefItemItem(&annotation_set_ref_list->list_[i]);
+ uint32_t set_offset = annotation_set_ref_list->list_[i].annotations_off_;
+ annotations->push_back(CreateAnnotationSetItem(dex_file, annotation_set_item, set_offset));
+ }
+ set_ref_list =
+ annotation_set_ref_lists_map_.CreateAndAddItem(header_->AnnotationSetRefLists(),
+ eagerly_assign_offsets_,
+ offset,
+ annotations);
+ }
+ return new ParameterAnnotation(method_id, set_ref_list);
+}
+
} // namespace dex_ir
} // namespace art
diff --git a/dexlayout/dex_verify.cc b/dexlayout/dex_verify.cc
index 2e4756b..962798d 100644
--- a/dexlayout/dex_verify.cc
+++ b/dexlayout/dex_verify.cc
@@ -31,38 +31,42 @@
bool VerifyOutputDexFile(dex_ir::Header* orig_header,
dex_ir::Header* output_header,
std::string* error_msg) {
- dex_ir::Collections& orig = orig_header->GetCollections();
- dex_ir::Collections& output = output_header->GetCollections();
-
// Compare all id sections. They have a defined order that can't be changed by dexlayout.
- if (!VerifyIds(orig.StringIds(), output.StringIds(), "string ids", error_msg) ||
- !VerifyIds(orig.TypeIds(), output.TypeIds(), "type ids", error_msg) ||
- !VerifyIds(orig.ProtoIds(), output.ProtoIds(), "proto ids", error_msg) ||
- !VerifyIds(orig.FieldIds(), output.FieldIds(), "field ids", error_msg) ||
- !VerifyIds(orig.MethodIds(), output.MethodIds(), "method ids", error_msg)) {
+ if (!VerifyIds(orig_header->StringIds(), output_header->StringIds(), "string ids", error_msg) ||
+ !VerifyIds(orig_header->TypeIds(), output_header->TypeIds(), "type ids", error_msg) ||
+ !VerifyIds(orig_header->ProtoIds(), output_header->ProtoIds(), "proto ids", error_msg) ||
+ !VerifyIds(orig_header->FieldIds(), output_header->FieldIds(), "field ids", error_msg) ||
+ !VerifyIds(orig_header->MethodIds(), output_header->MethodIds(), "method ids", error_msg)) {
return false;
}
// Compare class defs. The order may have been changed by dexlayout.
- if (!VerifyClassDefs(orig.ClassDefs(), output.ClassDefs(), error_msg)) {
+ if (!VerifyClassDefs(orig_header->ClassDefs(), output_header->ClassDefs(), error_msg)) {
return false;
}
return true;
}
-template<class T> bool VerifyIds(std::vector<std::unique_ptr<T>>& orig,
- std::vector<std::unique_ptr<T>>& output,
+template<class T> bool VerifyIds(dex_ir::CollectionVector<T>& orig,
+ dex_ir::CollectionVector<T>& output,
const char* section_name,
std::string* error_msg) {
- if (orig.size() != output.size()) {
- *error_msg = StringPrintf(
- "Mismatched size for %s section: %zu vs %zu.", section_name, orig.size(), output.size());
- return false;
- }
- for (size_t i = 0; i < orig.size(); ++i) {
- if (!VerifyId(orig[i].get(), output[i].get(), error_msg)) {
+ auto orig_iter = orig.begin();
+ auto output_iter = output.begin();
+ for (; orig_iter != orig.end() && output_iter != output.end(); ++orig_iter, ++output_iter) {
+ if (!VerifyId(orig_iter->get(), output_iter->get(), error_msg)) {
return false;
}
}
+ if (orig_iter != orig.end() || output_iter != output.end()) {
+ const char* longer;
+ if (orig_iter == orig.end()) {
+ longer = "output";
+ } else {
+ longer = "original";
+ }
+ *error_msg = StringPrintf("Mismatch for %s section: %s is longer.", section_name, longer);
+ return false;
+ }
return true;
}
@@ -181,29 +185,36 @@
// The class defs may have a new order due to dexlayout. Use the class's class_idx to uniquely
// identify them and sort them for comparison.
-bool VerifyClassDefs(std::vector<std::unique_ptr<dex_ir::ClassDef>>& orig,
- std::vector<std::unique_ptr<dex_ir::ClassDef>>& output,
+bool VerifyClassDefs(dex_ir::CollectionVector<dex_ir::ClassDef>& orig,
+ dex_ir::CollectionVector<dex_ir::ClassDef>& output,
std::string* error_msg) {
- if (orig.size() != output.size()) {
- *error_msg = StringPrintf(
- "Mismatched size for class defs section: %zu vs %zu.", orig.size(), output.size());
- return false;
- }
// Store the class defs into sets sorted by the class's type index.
std::set<dex_ir::ClassDef*, ClassDefCompare> orig_set;
std::set<dex_ir::ClassDef*, ClassDefCompare> output_set;
- for (size_t i = 0; i < orig.size(); ++i) {
- orig_set.insert(orig[i].get());
- output_set.insert(output[i].get());
+ auto orig_iter = orig.begin();
+ auto output_iter = output.begin();
+ for (; orig_iter != orig.end() && output_iter != output.end(); ++orig_iter, ++output_iter) {
+ orig_set.insert(orig_iter->get());
+ output_set.insert(output_iter->get());
}
- auto orig_iter = orig_set.begin();
- auto output_iter = output_set.begin();
- while (orig_iter != orig_set.end() && output_iter != output_set.end()) {
- if (!VerifyClassDef(*orig_iter, *output_iter, error_msg)) {
+ if (orig_iter != orig.end() || output_iter != output.end()) {
+ const char* longer;
+ if (orig_iter == orig.end()) {
+ longer = "output";
+ } else {
+ longer = "original";
+ }
+ *error_msg = StringPrintf("Mismatch for class defs section: %s is longer.", longer);
+ return false;
+ }
+ auto orig_set_iter = orig_set.begin();
+ auto output_set_iter = output_set.begin();
+ while (orig_set_iter != orig_set.end() && output_set_iter != output_set.end()) {
+ if (!VerifyClassDef(*orig_set_iter, *output_set_iter, error_msg)) {
return false;
}
- orig_iter++;
- output_iter++;
+ orig_set_iter++;
+ output_set_iter++;
}
return true;
}
diff --git a/dexlayout/dex_verify.h b/dexlayout/dex_verify.h
index 998939b..4943def 100644
--- a/dexlayout/dex_verify.h
+++ b/dexlayout/dex_verify.h
@@ -30,8 +30,8 @@
dex_ir::Header* output_header,
std::string* error_msg);
-template<class T> bool VerifyIds(std::vector<std::unique_ptr<T>>& orig,
- std::vector<std::unique_ptr<T>>& output,
+template<class T> bool VerifyIds(dex_ir::CollectionVector<T>& orig,
+ dex_ir::CollectionVector<T>& output,
const char* section_name,
std::string* error_msg);
bool VerifyId(dex_ir::StringId* orig, dex_ir::StringId* output, std::string* error_msg);
@@ -40,8 +40,8 @@
bool VerifyId(dex_ir::FieldId* orig, dex_ir::FieldId* output, std::string* error_msg);
bool VerifyId(dex_ir::MethodId* orig, dex_ir::MethodId* output, std::string* error_msg);
-bool VerifyClassDefs(std::vector<std::unique_ptr<dex_ir::ClassDef>>& orig,
- std::vector<std::unique_ptr<dex_ir::ClassDef>>& output,
+bool VerifyClassDefs(dex_ir::CollectionVector<dex_ir::ClassDef>& orig,
+ dex_ir::CollectionVector<dex_ir::ClassDef>& output,
std::string* error_msg);
bool VerifyClassDef(dex_ir::ClassDef* orig, dex_ir::ClassDef* output, std::string* error_msg);
diff --git a/dexlayout/dex_visualize.cc b/dexlayout/dex_visualize.cc
index 0e04c58..abcaffc 100644
--- a/dexlayout/dex_visualize.cc
+++ b/dexlayout/dex_visualize.cc
@@ -252,9 +252,9 @@
return;
}
- const uint32_t class_defs_size = header->GetCollections().ClassDefsSize();
+ const uint32_t class_defs_size = header->ClassDefs().Size();
for (uint32_t class_index = 0; class_index < class_defs_size; class_index++) {
- dex_ir::ClassDef* class_def = header->GetCollections().GetClassDef(class_index);
+ dex_ir::ClassDef* class_def = header->ClassDefs()[class_index];
dex::TypeIndex type_idx(class_def->ClassType()->GetIndex());
if (profile_info != nullptr && !profile_info->ContainsClass(*dex_file, type_idx)) {
continue;
diff --git a/dexlayout/dex_writer.cc b/dexlayout/dex_writer.cc
index 9ed1312..a4c5cda 100644
--- a/dexlayout/dex_writer.cc
+++ b/dexlayout/dex_writer.cc
@@ -231,7 +231,7 @@
// function that takes a CollectionVector<T> and uses overloading.
void DexWriter::WriteStringIds(Stream* stream, bool reserve_only) {
const uint32_t start = stream->Tell();
- for (std::unique_ptr<dex_ir::StringId>& string_id : header_->GetCollections().StringIds()) {
+ for (auto& string_id : header_->StringIds()) {
stream->AlignTo(SectionAlignment(DexFile::kDexTypeStringIdItem));
if (reserve_only) {
stream->Skip(string_id->GetSize());
@@ -241,7 +241,7 @@
}
}
if (compute_offsets_ && start != stream->Tell()) {
- header_->GetCollections().SetStringIdsOffset(start);
+ header_->StringIds().SetOffset(start);
}
}
@@ -256,25 +256,25 @@
void DexWriter::WriteStringDatas(Stream* stream) {
const uint32_t start = stream->Tell();
- for (std::unique_ptr<dex_ir::StringData>& string_data : header_->GetCollections().StringDatas()) {
+ for (auto& string_data : header_->StringDatas()) {
WriteStringData(stream, string_data.get());
}
if (compute_offsets_ && start != stream->Tell()) {
- header_->GetCollections().SetStringDatasOffset(start);
+ header_->StringDatas().SetOffset(start);
}
}
void DexWriter::WriteTypeIds(Stream* stream) {
uint32_t descriptor_idx[1];
const uint32_t start = stream->Tell();
- for (std::unique_ptr<dex_ir::TypeId>& type_id : header_->GetCollections().TypeIds()) {
+ for (auto& type_id : header_->TypeIds()) {
stream->AlignTo(SectionAlignment(DexFile::kDexTypeTypeIdItem));
ProcessOffset(stream, type_id.get());
descriptor_idx[0] = type_id->GetStringId()->GetIndex();
stream->Write(descriptor_idx, type_id->GetSize());
}
if (compute_offsets_ && start != stream->Tell()) {
- header_->GetCollections().SetTypeIdsOffset(start);
+ header_->TypeIds().SetOffset(start);
}
}
@@ -282,7 +282,7 @@
uint32_t size[1];
uint16_t list[1];
const uint32_t start = stream->Tell();
- for (std::unique_ptr<dex_ir::TypeList>& type_list : header_->GetCollections().TypeLists()) {
+ for (auto& type_list : header_->TypeLists()) {
stream->AlignTo(SectionAlignment(DexFile::kDexTypeTypeList));
size[0] = type_list->GetTypeList()->size();
ProcessOffset(stream, type_list.get());
@@ -293,14 +293,14 @@
}
}
if (compute_offsets_ && start != stream->Tell()) {
- header_->GetCollections().SetTypeListsOffset(start);
+ header_->TypeLists().SetOffset(start);
}
}
void DexWriter::WriteProtoIds(Stream* stream, bool reserve_only) {
uint32_t buffer[3];
const uint32_t start = stream->Tell();
- for (std::unique_ptr<dex_ir::ProtoId>& proto_id : header_->GetCollections().ProtoIds()) {
+ for (auto& proto_id : header_->ProtoIds()) {
stream->AlignTo(SectionAlignment(DexFile::kDexTypeProtoIdItem));
ProcessOffset(stream, proto_id.get());
if (reserve_only) {
@@ -313,14 +313,14 @@
}
}
if (compute_offsets_ && start != stream->Tell()) {
- header_->GetCollections().SetProtoIdsOffset(start);
+ header_->ProtoIds().SetOffset(start);
}
}
void DexWriter::WriteFieldIds(Stream* stream) {
uint16_t buffer[4];
const uint32_t start = stream->Tell();
- for (std::unique_ptr<dex_ir::FieldId>& field_id : header_->GetCollections().FieldIds()) {
+ for (auto& field_id : header_->FieldIds()) {
stream->AlignTo(SectionAlignment(DexFile::kDexTypeFieldIdItem));
ProcessOffset(stream, field_id.get());
buffer[0] = field_id->Class()->GetIndex();
@@ -330,14 +330,14 @@
stream->Write(buffer, field_id->GetSize());
}
if (compute_offsets_ && start != stream->Tell()) {
- header_->GetCollections().SetFieldIdsOffset(start);
+ header_->FieldIds().SetOffset(start);
}
}
void DexWriter::WriteMethodIds(Stream* stream) {
uint16_t buffer[4];
const uint32_t start = stream->Tell();
- for (std::unique_ptr<dex_ir::MethodId>& method_id : header_->GetCollections().MethodIds()) {
+ for (auto& method_id : header_->MethodIds()) {
stream->AlignTo(SectionAlignment(DexFile::kDexTypeMethodIdItem));
ProcessOffset(stream, method_id.get());
buffer[0] = method_id->Class()->GetIndex();
@@ -347,28 +347,26 @@
stream->Write(buffer, method_id->GetSize());
}
if (compute_offsets_ && start != stream->Tell()) {
- header_->GetCollections().SetMethodIdsOffset(start);
+ header_->MethodIds().SetOffset(start);
}
}
void DexWriter::WriteEncodedArrays(Stream* stream) {
const uint32_t start = stream->Tell();
- for (std::unique_ptr<dex_ir::EncodedArrayItem>& encoded_array :
- header_->GetCollections().EncodedArrayItems()) {
+ for (auto& encoded_array : header_->EncodedArrayItems()) {
stream->AlignTo(SectionAlignment(DexFile::kDexTypeEncodedArrayItem));
ProcessOffset(stream, encoded_array.get());
WriteEncodedArray(stream, encoded_array->GetEncodedValues());
}
if (compute_offsets_ && start != stream->Tell()) {
- header_->GetCollections().SetEncodedArrayItemsOffset(start);
+ header_->EncodedArrayItems().SetOffset(start);
}
}
void DexWriter::WriteAnnotations(Stream* stream) {
uint8_t visibility[1];
const uint32_t start = stream->Tell();
- for (std::unique_ptr<dex_ir::AnnotationItem>& annotation :
- header_->GetCollections().AnnotationItems()) {
+ for (auto& annotation : header_->AnnotationItems()) {
stream->AlignTo(SectionAlignment(DexFile::kDexTypeAnnotationItem));
visibility[0] = annotation->GetVisibility();
ProcessOffset(stream, annotation.get());
@@ -376,7 +374,7 @@
WriteEncodedAnnotation(stream, annotation->GetAnnotation());
}
if (compute_offsets_ && start != stream->Tell()) {
- header_->GetCollections().SetAnnotationItemsOffset(start);
+ header_->AnnotationItems().SetOffset(start);
}
}
@@ -384,8 +382,7 @@
uint32_t size[1];
uint32_t annotation_off[1];
const uint32_t start = stream->Tell();
- for (std::unique_ptr<dex_ir::AnnotationSetItem>& annotation_set :
- header_->GetCollections().AnnotationSetItems()) {
+ for (auto& annotation_set : header_->AnnotationSetItems()) {
stream->AlignTo(SectionAlignment(DexFile::kDexTypeAnnotationSetItem));
size[0] = annotation_set->GetItems()->size();
ProcessOffset(stream, annotation_set.get());
@@ -396,7 +393,7 @@
}
}
if (compute_offsets_ && start != stream->Tell()) {
- header_->GetCollections().SetAnnotationSetItemsOffset(start);
+ header_->AnnotationSetItems().SetOffset(start);
}
}
@@ -404,8 +401,7 @@
uint32_t size[1];
uint32_t annotations_off[1];
const uint32_t start = stream->Tell();
- for (std::unique_ptr<dex_ir::AnnotationSetRefList>& annotation_set_ref :
- header_->GetCollections().AnnotationSetRefLists()) {
+ for (auto& annotation_set_ref : header_->AnnotationSetRefLists()) {
stream->AlignTo(SectionAlignment(DexFile::kDexTypeAnnotationSetRefList));
size[0] = annotation_set_ref->GetItems()->size();
ProcessOffset(stream, annotation_set_ref.get());
@@ -416,7 +412,7 @@
}
}
if (compute_offsets_ && start != stream->Tell()) {
- header_->GetCollections().SetAnnotationSetRefListsOffset(start);
+ header_->AnnotationSetRefLists().SetOffset(start);
}
}
@@ -424,8 +420,7 @@
uint32_t directory_buffer[4];
uint32_t annotation_buffer[2];
const uint32_t start = stream->Tell();
- for (std::unique_ptr<dex_ir::AnnotationsDirectoryItem>& annotations_directory :
- header_->GetCollections().AnnotationsDirectoryItems()) {
+ for (auto& annotations_directory : header_->AnnotationsDirectoryItems()) {
stream->AlignTo(SectionAlignment(DexFile::kDexTypeAnnotationsDirectoryItem));
ProcessOffset(stream, annotations_directory.get());
directory_buffer[0] = annotations_directory->GetClassAnnotation() == nullptr ? 0 :
@@ -463,7 +458,7 @@
}
}
if (compute_offsets_ && start != stream->Tell()) {
- header_->GetCollections().SetAnnotationsDirectoryItemsOffset(start);
+ header_->AnnotationsDirectoryItems().SetOffset(start);
}
}
@@ -475,12 +470,11 @@
void DexWriter::WriteDebugInfoItems(Stream* stream) {
const uint32_t start = stream->Tell();
- for (std::unique_ptr<dex_ir::DebugInfoItem>& debug_info :
- header_->GetCollections().DebugInfoItems()) {
+ for (auto& debug_info : header_->DebugInfoItems()) {
WriteDebugInfoItem(stream, debug_info.get());
}
if (compute_offsets_ && start != stream->Tell()) {
- header_->GetCollections().SetDebugInfoItemsOffset(start);
+ header_->DebugInfoItems().SetOffset(start);
}
}
@@ -558,7 +552,7 @@
DexLayoutSections::SectionType::kSectionTypeCode)];
}
const uint32_t start = stream->Tell();
- for (auto& code_item : header_->GetCollections().CodeItems()) {
+ for (auto& code_item : header_->CodeItems()) {
uint32_t start_offset = stream->Tell();
WriteCodeItem(stream, code_item.get(), reserve_only);
// Only add the section hotness info once.
@@ -573,14 +567,14 @@
}
if (compute_offsets_ && start != stream->Tell()) {
- header_->GetCollections().SetCodeItemsOffset(start);
+ header_->CodeItems().SetOffset(start);
}
}
void DexWriter::WriteClassDefs(Stream* stream, bool reserve_only) {
const uint32_t start = stream->Tell();
uint32_t class_def_buffer[8];
- for (std::unique_ptr<dex_ir::ClassDef>& class_def : header_->GetCollections().ClassDefs()) {
+ for (auto& class_def : header_->ClassDefs()) {
stream->AlignTo(SectionAlignment(DexFile::kDexTypeClassDefItem));
if (reserve_only) {
stream->Skip(class_def->GetSize());
@@ -602,14 +596,14 @@
}
}
if (compute_offsets_ && start != stream->Tell()) {
- header_->GetCollections().SetClassDefsOffset(start);
+ header_->ClassDefs().SetOffset(start);
}
}
void DexWriter::WriteClassDatas(Stream* stream) {
const uint32_t start = stream->Tell();
for (const std::unique_ptr<dex_ir::ClassData>& class_data :
- header_->GetCollections().ClassDatas()) {
+ header_->ClassDatas()) {
stream->AlignTo(SectionAlignment(DexFile::kDexTypeClassDataItem));
ProcessOffset(stream, class_data.get());
stream->WriteUleb128(class_data->StaticFields()->size());
@@ -622,15 +616,14 @@
WriteEncodedMethods(stream, class_data->VirtualMethods());
}
if (compute_offsets_ && start != stream->Tell()) {
- header_->GetCollections().SetClassDatasOffset(start);
+ header_->ClassDatas().SetOffset(start);
}
}
void DexWriter::WriteCallSiteIds(Stream* stream, bool reserve_only) {
const uint32_t start = stream->Tell();
uint32_t call_site_off[1];
- for (std::unique_ptr<dex_ir::CallSiteId>& call_site_id :
- header_->GetCollections().CallSiteIds()) {
+ for (auto& call_site_id : header_->CallSiteIds()) {
stream->AlignTo(SectionAlignment(DexFile::kDexTypeCallSiteIdItem));
if (reserve_only) {
stream->Skip(call_site_id->GetSize());
@@ -640,15 +633,14 @@
}
}
if (compute_offsets_ && start != stream->Tell()) {
- header_->GetCollections().SetCallSiteIdsOffset(start);
+ header_->CallSiteIds().SetOffset(start);
}
}
void DexWriter::WriteMethodHandles(Stream* stream) {
const uint32_t start = stream->Tell();
uint16_t method_handle_buff[4];
- for (std::unique_ptr<dex_ir::MethodHandleItem>& method_handle :
- header_->GetCollections().MethodHandleItems()) {
+ for (auto& method_handle : header_->MethodHandleItems()) {
stream->AlignTo(SectionAlignment(DexFile::kDexTypeMethodHandleItem));
method_handle_buff[0] = static_cast<uint16_t>(method_handle->GetMethodHandleType());
method_handle_buff[1] = 0; // unused.
@@ -657,7 +649,7 @@
stream->Write(method_handle_buff, method_handle->GetSize());
}
if (compute_offsets_ && start != stream->Tell()) {
- header_->GetCollections().SetMethodHandleItemsOffset(start);
+ header_->MethodHandleItems().SetOffset(start);
}
}
@@ -678,67 +670,66 @@
}
void DexWriter::GenerateAndWriteMapItems(Stream* stream) {
- dex_ir::Collections& collection = header_->GetCollections();
MapItemQueue queue;
// Header and index section.
queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeHeaderItem, 1, 0));
queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeStringIdItem,
- collection.StringIdsSize(),
- collection.StringIdsOffset()));
+ header_->StringIds().Size(),
+ header_->StringIds().GetOffset()));
queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeTypeIdItem,
- collection.TypeIdsSize(),
- collection.TypeIdsOffset()));
+ header_->TypeIds().Size(),
+ header_->TypeIds().GetOffset()));
queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeProtoIdItem,
- collection.ProtoIdsSize(),
- collection.ProtoIdsOffset()));
+ header_->ProtoIds().Size(),
+ header_->ProtoIds().GetOffset()));
queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeFieldIdItem,
- collection.FieldIdsSize(),
- collection.FieldIdsOffset()));
+ header_->FieldIds().Size(),
+ header_->FieldIds().GetOffset()));
queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeMethodIdItem,
- collection.MethodIdsSize(),
- collection.MethodIdsOffset()));
+ header_->MethodIds().Size(),
+ header_->MethodIds().GetOffset()));
queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeClassDefItem,
- collection.ClassDefsSize(),
- collection.ClassDefsOffset()));
+ header_->ClassDefs().Size(),
+ header_->ClassDefs().GetOffset()));
queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeCallSiteIdItem,
- collection.CallSiteIdsSize(),
- collection.CallSiteIdsOffset()));
+ header_->CallSiteIds().Size(),
+ header_->CallSiteIds().GetOffset()));
queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeMethodHandleItem,
- collection.MethodHandleItemsSize(),
- collection.MethodHandleItemsOffset()));
+ header_->MethodHandleItems().Size(),
+ header_->MethodHandleItems().GetOffset()));
// Data section.
- queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeMapList, 1, collection.MapListOffset()));
+ queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeMapList, 1, header_->MapListOffset()));
queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeTypeList,
- collection.TypeListsSize(),
- collection.TypeListsOffset()));
+ header_->TypeLists().Size(),
+ header_->TypeLists().GetOffset()));
queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeAnnotationSetRefList,
- collection.AnnotationSetRefListsSize(),
- collection.AnnotationSetRefListsOffset()));
+ header_->AnnotationSetRefLists().Size(),
+ header_->AnnotationSetRefLists().GetOffset()));
queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeAnnotationSetItem,
- collection.AnnotationSetItemsSize(),
- collection.AnnotationSetItemsOffset()));
+ header_->AnnotationSetItems().Size(),
+ header_->AnnotationSetItems().GetOffset()));
queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeClassDataItem,
- collection.ClassDatasSize(),
- collection.ClassDatasOffset()));
+ header_->ClassDatas().Size(),
+ header_->ClassDatas().GetOffset()));
queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeCodeItem,
- collection.CodeItemsSize(),
- collection.CodeItemsOffset()));
+ header_->CodeItems().Size(),
+ header_->CodeItems().GetOffset()));
queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeStringDataItem,
- collection.StringDatasSize(),
- collection.StringDatasOffset()));
+ header_->StringDatas().Size(),
+ header_->StringDatas().GetOffset()));
queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeDebugInfoItem,
- collection.DebugInfoItemsSize(),
- collection.DebugInfoItemsOffset()));
+ header_->DebugInfoItems().Size(),
+ header_->DebugInfoItems().GetOffset()));
queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeAnnotationItem,
- collection.AnnotationItemsSize(),
- collection.AnnotationItemsOffset()));
+ header_->AnnotationItems().Size(),
+ header_->AnnotationItems().GetOffset()));
queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeEncodedArrayItem,
- collection.EncodedArrayItemsSize(),
- collection.EncodedArrayItemsOffset()));
+ header_->EncodedArrayItems().Size(),
+ header_->EncodedArrayItems().GetOffset()));
queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeAnnotationsDirectoryItem,
- collection.AnnotationsDirectoryItemsSize(),
- collection.AnnotationsDirectoryItemsOffset()));
+ header_->AnnotationsDirectoryItems().Size(),
+ header_->AnnotationsDirectoryItems().GetOffset()));
WriteMapItems(stream, &queue);
}
@@ -761,20 +752,19 @@
header.endian_tag_ = header_->EndianTag();
header.link_size_ = header_->LinkSize();
header.link_off_ = header_->LinkOffset();
- const dex_ir::Collections& collections = header_->GetCollections();
- header.map_off_ = collections.MapListOffset();
- header.string_ids_size_ = collections.StringIdsSize();
- header.string_ids_off_ = collections.StringIdsOffset();
- header.type_ids_size_ = collections.TypeIdsSize();
- header.type_ids_off_ = collections.TypeIdsOffset();
- header.proto_ids_size_ = collections.ProtoIdsSize();
- header.proto_ids_off_ = collections.ProtoIdsOffset();
- header.field_ids_size_ = collections.FieldIdsSize();
- header.field_ids_off_ = collections.FieldIdsOffset();
- header.method_ids_size_ = collections.MethodIdsSize();
- header.method_ids_off_ = collections.MethodIdsOffset();
- header.class_defs_size_ = collections.ClassDefsSize();
- header.class_defs_off_ = collections.ClassDefsOffset();
+ header.map_off_ = header_->MapListOffset();
+ header.string_ids_size_ = header_->StringIds().Size();
+ header.string_ids_off_ = header_->StringIds().GetOffset();
+ header.type_ids_size_ = header_->TypeIds().Size();
+ header.type_ids_off_ = header_->TypeIds().GetOffset();
+ header.proto_ids_size_ = header_->ProtoIds().Size();
+ header.proto_ids_off_ = header_->ProtoIds().GetOffset();
+ header.field_ids_size_ = header_->FieldIds().Size();
+ header.field_ids_off_ = header_->FieldIds().GetOffset();
+ header.method_ids_size_ = header_->MethodIds().Size();
+ header.method_ids_off_ = header_->MethodIds().GetOffset();
+ header.class_defs_size_ = header_->ClassDefs().Size();
+ header.class_defs_off_ = header_->ClassDefs().GetOffset();
header.data_size_ = header_->DataSize();
header.data_off_ = header_->DataOffset();
@@ -797,8 +787,6 @@
// Starting offset is right after the header.
stream->Seek(GetHeaderSize());
- dex_ir::Collections& collection = header_->GetCollections();
-
// Based on: https://source.android.com/devices/tech/dalvik/dex-format
// Since the offsets may not be calculated already, the writing must be done in the correct order.
const uint32_t string_ids_offset = stream->Tell();
@@ -863,9 +851,9 @@
// Write the map list.
if (compute_offsets_) {
stream->AlignTo(SectionAlignment(DexFile::kDexTypeMapList));
- collection.SetMapListOffset(stream->Tell());
+ header_->SetMapListOffset(stream->Tell());
} else {
- stream->Seek(collection.MapListOffset());
+ stream->Seek(header_->MapListOffset());
}
GenerateAndWriteMapItems(stream);
stream->AlignTo(kDataSectionAlignment);
@@ -882,7 +870,7 @@
}
// Write link data if it exists.
- const std::vector<uint8_t>& link_data = collection.LinkData();
+ const std::vector<uint8_t>& link_data = header_->LinkData();
if (link_data.size() > 0) {
CHECK_EQ(header_->LinkSize(), static_cast<uint32_t>(link_data.size()));
if (compute_offsets_) {
diff --git a/dexlayout/dexlayout.cc b/dexlayout/dexlayout.cc
index 39d93bf..d6dd9d1 100644
--- a/dexlayout/dexlayout.cc
+++ b/dexlayout/dexlayout.cc
@@ -417,24 +417,24 @@
outSize = snprintf(buf.get(), buf_size, "<no-index>");
break;
case Instruction::kIndexTypeRef:
- if (index < header->GetCollections().TypeIdsSize()) {
- const char* tp = header->GetCollections().GetTypeId(index)->GetStringId()->Data();
+ if (index < header->TypeIds().Size()) {
+ const char* tp = header->TypeIds()[index]->GetStringId()->Data();
outSize = snprintf(buf.get(), buf_size, "%s // type@%0*x", tp, width, index);
} else {
outSize = snprintf(buf.get(), buf_size, "<type?> // type@%0*x", width, index);
}
break;
case Instruction::kIndexStringRef:
- if (index < header->GetCollections().StringIdsSize()) {
- const char* st = header->GetCollections().GetStringId(index)->Data();
+ if (index < header->StringIds().Size()) {
+ const char* st = header->StringIds()[index]->Data();
outSize = snprintf(buf.get(), buf_size, "\"%s\" // string@%0*x", st, width, index);
} else {
outSize = snprintf(buf.get(), buf_size, "<string?> // string@%0*x", width, index);
}
break;
case Instruction::kIndexMethodRef:
- if (index < header->GetCollections().MethodIdsSize()) {
- dex_ir::MethodId* method_id = header->GetCollections().GetMethodId(index);
+ if (index < header->MethodIds().Size()) {
+ dex_ir::MethodId* method_id = header->MethodIds()[index];
const char* name = method_id->Name()->Data();
std::string type_descriptor = GetSignatureForProtoId(method_id->Proto());
const char* back_descriptor = method_id->Class()->GetStringId()->Data();
@@ -445,8 +445,8 @@
}
break;
case Instruction::kIndexFieldRef:
- if (index < header->GetCollections().FieldIdsSize()) {
- dex_ir::FieldId* field_id = header->GetCollections().GetFieldId(index);
+ if (index < header->FieldIds().Size()) {
+ dex_ir::FieldId* field_id = header->FieldIds()[index];
const char* name = field_id->Name()->Data();
const char* type_descriptor = field_id->Type()->GetStringId()->Data();
const char* back_descriptor = field_id->Class()->GetStringId()->Data();
@@ -466,15 +466,15 @@
case Instruction::kIndexMethodAndProtoRef: {
std::string method("<method?>");
std::string proto("<proto?>");
- if (index < header->GetCollections().MethodIdsSize()) {
- dex_ir::MethodId* method_id = header->GetCollections().GetMethodId(index);
+ if (index < header->MethodIds().Size()) {
+ dex_ir::MethodId* method_id = header->MethodIds()[index];
const char* name = method_id->Name()->Data();
std::string type_descriptor = GetSignatureForProtoId(method_id->Proto());
const char* back_descriptor = method_id->Class()->GetStringId()->Data();
method = StringPrintf("%s.%s:%s", back_descriptor, name, type_descriptor.c_str());
}
- if (secondary_index < header->GetCollections().ProtoIdsSize()) {
- dex_ir::ProtoId* proto_id = header->GetCollections().GetProtoId(secondary_index);
+ if (secondary_index < header->ProtoIds().Size()) {
+ dex_ir::ProtoId* proto_id = header->ProtoIds()[secondary_index];
proto = GetSignatureForProtoId(proto_id);
}
outSize = snprintf(buf.get(), buf_size, "%s, %s // method@%0*x, proto@%0*x",
@@ -596,7 +596,6 @@
*/
void DexLayout::DumpFileHeader() {
char sanitized[8 * 2 + 1];
- dex_ir::Collections& collections = header_->GetCollections();
fprintf(out_file_, "DEX file header:\n");
Asciify(sanitized, header_->Magic(), 8);
fprintf(out_file_, "magic : '%s'\n", sanitized);
@@ -610,24 +609,24 @@
fprintf(out_file_, "link_size : %d\n", header_->LinkSize());
fprintf(out_file_, "link_off : %d (0x%06x)\n",
header_->LinkOffset(), header_->LinkOffset());
- fprintf(out_file_, "string_ids_size : %d\n", collections.StringIdsSize());
+ fprintf(out_file_, "string_ids_size : %d\n", header_->StringIds().Size());
fprintf(out_file_, "string_ids_off : %d (0x%06x)\n",
- collections.StringIdsOffset(), collections.StringIdsOffset());
- fprintf(out_file_, "type_ids_size : %d\n", collections.TypeIdsSize());
+ header_->StringIds().GetOffset(), header_->StringIds().GetOffset());
+ fprintf(out_file_, "type_ids_size : %d\n", header_->TypeIds().Size());
fprintf(out_file_, "type_ids_off : %d (0x%06x)\n",
- collections.TypeIdsOffset(), collections.TypeIdsOffset());
- fprintf(out_file_, "proto_ids_size : %d\n", collections.ProtoIdsSize());
+ header_->TypeIds().GetOffset(), header_->TypeIds().GetOffset());
+ fprintf(out_file_, "proto_ids_size : %d\n", header_->ProtoIds().Size());
fprintf(out_file_, "proto_ids_off : %d (0x%06x)\n",
- collections.ProtoIdsOffset(), collections.ProtoIdsOffset());
- fprintf(out_file_, "field_ids_size : %d\n", collections.FieldIdsSize());
+ header_->ProtoIds().GetOffset(), header_->ProtoIds().GetOffset());
+ fprintf(out_file_, "field_ids_size : %d\n", header_->FieldIds().Size());
fprintf(out_file_, "field_ids_off : %d (0x%06x)\n",
- collections.FieldIdsOffset(), collections.FieldIdsOffset());
- fprintf(out_file_, "method_ids_size : %d\n", collections.MethodIdsSize());
+ header_->FieldIds().GetOffset(), header_->FieldIds().GetOffset());
+ fprintf(out_file_, "method_ids_size : %d\n", header_->MethodIds().Size());
fprintf(out_file_, "method_ids_off : %d (0x%06x)\n",
- collections.MethodIdsOffset(), collections.MethodIdsOffset());
- fprintf(out_file_, "class_defs_size : %d\n", collections.ClassDefsSize());
+ header_->MethodIds().GetOffset(), header_->MethodIds().GetOffset());
+ fprintf(out_file_, "class_defs_size : %d\n", header_->ClassDefs().Size());
fprintf(out_file_, "class_defs_off : %d (0x%06x)\n",
- collections.ClassDefsOffset(), collections.ClassDefsOffset());
+ header_->ClassDefs().GetOffset(), header_->ClassDefs().GetOffset());
fprintf(out_file_, "data_size : %d\n", header_->DataSize());
fprintf(out_file_, "data_off : %d (0x%06x)\n\n",
header_->DataOffset(), header_->DataOffset());
@@ -638,7 +637,7 @@
*/
void DexLayout::DumpClassDef(int idx) {
// General class information.
- dex_ir::ClassDef* class_def = header_->GetCollections().GetClassDef(idx);
+ dex_ir::ClassDef* class_def = header_->ClassDefs()[idx];
fprintf(out_file_, "Class #%d header:\n", idx);
fprintf(out_file_, "class_idx : %d\n", class_def->ClassType()->GetIndex());
fprintf(out_file_, "access_flags : %d (0x%04x)\n",
@@ -719,7 +718,7 @@
* Dumps class annotations.
*/
void DexLayout::DumpClassAnnotations(int idx) {
- dex_ir::ClassDef* class_def = header_->GetCollections().GetClassDef(idx);
+ dex_ir::ClassDef* class_def = header_->ClassDefs()[idx];
dex_ir::AnnotationsDirectoryItem* annotations_directory = class_def->Annotations();
if (annotations_directory == nullptr) {
return; // none
@@ -1039,7 +1038,7 @@
* Dumps a bytecode disassembly.
*/
void DexLayout::DumpBytecodes(uint32_t idx, const dex_ir::CodeItem* code, uint32_t code_offset) {
- dex_ir::MethodId* method_id = header_->GetCollections().GetMethodId(idx);
+ dex_ir::MethodId* method_id = header_->MethodIds()[idx];
const char* name = method_id->Name()->Data();
std::string type_descriptor = GetSignatureForProtoId(method_id->Proto());
const char* back_descriptor = method_id->Class()->GetStringId()->Data();
@@ -1083,16 +1082,16 @@
/*
* Lookup functions.
*/
-static const char* StringDataByIdx(uint32_t idx, dex_ir::Collections& collections) {
- dex_ir::StringId* string_id = collections.GetStringIdOrNullPtr(idx);
+static const char* StringDataByIdx(uint32_t idx, dex_ir::Header* header) {
+ dex_ir::StringId* string_id = header->GetStringIdOrNullPtr(idx);
if (string_id == nullptr) {
return nullptr;
}
return string_id->Data();
}
-static const char* StringDataByTypeIdx(uint16_t idx, dex_ir::Collections& collections) {
- dex_ir::TypeId* type_id = collections.GetTypeIdOrNullPtr(idx);
+static const char* StringDataByTypeIdx(uint16_t idx, dex_ir::Header* header) {
+ dex_ir::TypeId* type_id = header->GetTypeIdOrNullPtr(idx);
if (type_id == nullptr) {
return nullptr;
}
@@ -1134,7 +1133,7 @@
if (debug_info != nullptr) {
DexFile::DecodeDebugPositionInfo(debug_info->GetDebugInfo(),
[this](uint32_t idx) {
- return StringDataByIdx(idx, this->header_->GetCollections());
+ return StringDataByIdx(idx, this->header_);
},
DumpPositionsCb,
out_file_);
@@ -1161,12 +1160,12 @@
code->InsSize(),
code->InsnsSize(),
[this](uint32_t idx) {
- return StringDataByIdx(idx, this->header_->GetCollections());
+ return StringDataByIdx(idx, this->header_);
},
[this](uint32_t idx) {
return
StringDataByTypeIdx(dchecked_integral_cast<uint16_t>(idx),
- this->header_->GetCollections());
+ this->header_);
},
DumpLocalsCb,
out_file_);
@@ -1182,7 +1181,7 @@
return;
}
- dex_ir::MethodId* method_id = header_->GetCollections().GetMethodId(idx);
+ dex_ir::MethodId* method_id = header_->MethodIds()[idx];
const char* name = method_id->Name()->Data();
char* type_descriptor = strdup(GetSignatureForProtoId(method_id->Proto()).c_str());
const char* back_descriptor = method_id->Class()->GetStringId()->Data();
@@ -1292,7 +1291,7 @@
return;
}
- dex_ir::FieldId* field_id = header_->GetCollections().GetFieldId(idx);
+ dex_ir::FieldId* field_id = header_->FieldIds()[idx];
const char* name = field_id->Name()->Data();
const char* type_descriptor = field_id->Type()->GetStringId()->Data();
const char* back_descriptor = field_id->Class()->GetStringId()->Data();
@@ -1346,7 +1345,7 @@
* the value will be replaced with a newly-allocated string.
*/
void DexLayout::DumpClass(int idx, char** last_package) {
- dex_ir::ClassDef* class_def = header_->GetCollections().GetClassDef(idx);
+ dex_ir::ClassDef* class_def = header_->ClassDefs()[idx];
// Omitting non-public class.
if (options_.exports_only_ && (class_def->GetAccessFlags() & kAccPublic) == 0) {
return;
@@ -1364,8 +1363,7 @@
// up the classes, sort them, and dump them alphabetically so the
// package name wouldn't jump around, but that's not a great plan
// for something that needs to run on the device.
- const char* class_descriptor =
- header_->GetCollections().GetClassDef(idx)->ClassType()->GetStringId()->Data();
+ const char* class_descriptor = header_->ClassDefs()[idx]->ClassType()->GetStringId()->Data();
if (!(class_descriptor[0] == 'L' &&
class_descriptor[strlen(class_descriptor)-1] == ';')) {
// Arrays and primitives should not be defined explicitly. Keep going?
@@ -1543,7 +1541,7 @@
// Iterate over all classes.
char* package = nullptr;
- const uint32_t class_defs_size = header_->GetCollections().ClassDefsSize();
+ const uint32_t class_defs_size = header_->ClassDefs().Size();
for (uint32_t i = 0; i < class_defs_size; i++) {
DumpClass(i, &package);
} // for
@@ -1562,13 +1560,13 @@
void DexLayout::LayoutClassDefsAndClassData(const DexFile* dex_file) {
std::vector<dex_ir::ClassDef*> new_class_def_order;
- for (std::unique_ptr<dex_ir::ClassDef>& class_def : header_->GetCollections().ClassDefs()) {
+ for (auto& class_def : header_->ClassDefs()) {
dex::TypeIndex type_idx(class_def->ClassType()->GetIndex());
if (info_->ContainsClass(*dex_file, type_idx)) {
new_class_def_order.push_back(class_def.get());
}
}
- for (std::unique_ptr<dex_ir::ClassDef>& class_def : header_->GetCollections().ClassDefs()) {
+ for (auto& class_def : header_->ClassDefs()) {
dex::TypeIndex type_idx(class_def->ClassType()->GetIndex());
if (!info_->ContainsClass(*dex_file, type_idx)) {
new_class_def_order.push_back(class_def.get());
@@ -1576,8 +1574,7 @@
}
std::unordered_set<dex_ir::ClassData*> visited_class_data;
size_t class_data_index = 0;
- dex_ir::CollectionVector<dex_ir::ClassData>::Vector& class_datas =
- header_->GetCollections().ClassDatas();
+ auto& class_datas = header_->ClassDatas();
for (dex_ir::ClassDef* class_def : new_class_def_order) {
dex_ir::ClassData* class_data = class_def->GetClassData();
if (class_data != nullptr && visited_class_data.find(class_data) == visited_class_data.end()) {
@@ -1590,15 +1587,14 @@
++class_data_index;
}
}
- CHECK_EQ(class_data_index, class_datas.size());
+ CHECK_EQ(class_data_index, class_datas.Size());
if (DexLayout::kChangeClassDefOrder) {
// This currently produces dex files that violate the spec since the super class class_def is
// supposed to occur before any subclasses.
- dex_ir::CollectionVector<dex_ir::ClassDef>::Vector& class_defs =
- header_->GetCollections().ClassDefs();
- CHECK_EQ(new_class_def_order.size(), class_defs.size());
- for (size_t i = 0; i < class_defs.size(); ++i) {
+ dex_ir::CollectionVector<dex_ir::ClassDef>& class_defs = header_->ClassDefs();
+ CHECK_EQ(new_class_def_order.size(), class_defs.Size());
+ for (size_t i = 0; i < class_defs.Size(); ++i) {
// Overwrite the existing vector with the new ordering, note that the sets of objects are
// equivalent, but the order changes. This is why this is not a memory leak.
// TODO: Consider cleaning this up with a shared_ptr.
@@ -1609,10 +1605,10 @@
}
void DexLayout::LayoutStringData(const DexFile* dex_file) {
- const size_t num_strings = header_->GetCollections().StringIds().size();
+ const size_t num_strings = header_->StringIds().Size();
std::vector<bool> is_shorty(num_strings, false);
std::vector<bool> from_hot_method(num_strings, false);
- for (std::unique_ptr<dex_ir::ClassDef>& class_def : header_->GetCollections().ClassDefs()) {
+ for (auto& class_def : header_->ClassDefs()) {
// A name of a profile class is probably going to get looked up by ClassTable::Lookup, mark it
// as hot. Add its super class and interfaces as well, which can be used during initialization.
const bool is_profile_class =
@@ -1678,7 +1674,7 @@
}
// Sort string data by specified order.
std::vector<dex_ir::StringId*> string_ids;
- for (auto& string_id : header_->GetCollections().StringIds()) {
+ for (auto& string_id : header_->StringIds()) {
string_ids.push_back(string_id.get());
}
std::sort(string_ids.begin(),
@@ -1699,8 +1695,7 @@
// Order by index by default.
return a->GetIndex() < b->GetIndex();
});
- dex_ir::CollectionVector<dex_ir::StringData>::Vector& string_datas =
- header_->GetCollections().StringDatas();
+ auto& string_datas = header_->StringDatas();
// Now we know what order we want the string data, reorder them.
size_t data_index = 0;
for (dex_ir::StringId* string_id : string_ids) {
@@ -1713,11 +1708,11 @@
for (const std::unique_ptr<dex_ir::StringData>& data : string_datas) {
visited.insert(data.get());
}
- for (auto& string_id : header_->GetCollections().StringIds()) {
+ for (auto& string_id : header_->StringIds()) {
CHECK(visited.find(string_id->DataItem()) != visited.end());
}
}
- CHECK_EQ(data_index, string_datas.size());
+ CHECK_EQ(data_index, string_datas.Size());
}
// Orders code items according to specified class data ordering.
@@ -1732,7 +1727,7 @@
// Assign hotness flags to all code items.
for (InvokeType invoke_type : invoke_types) {
- for (std::unique_ptr<dex_ir::ClassDef>& class_def : header_->GetCollections().ClassDefs()) {
+ for (auto& class_def : header_->ClassDefs()) {
const bool is_profile_class =
info_->ContainsClass(*dex_file, dex::TypeIndex(class_def->ClassType()->GetIndex()));
@@ -1778,8 +1773,7 @@
}
}
- dex_ir::CollectionVector<dex_ir::CodeItem>::Vector& code_items =
- header_->GetCollections().CodeItems();
+ const auto& code_items = header_->CodeItems();
if (VLOG_IS_ON(dex)) {
size_t layout_count[static_cast<size_t>(LayoutType::kLayoutTypeCount)] = {};
for (const std::unique_ptr<dex_ir::CodeItem>& code_item : code_items) {
@@ -1871,7 +1865,7 @@
const bool has_output_container = dex_container != nullptr;
const bool output = options_.output_dex_directory_ != nullptr || has_output_container;
- // Try to avoid eagerly assigning offsets to find bugs since GetOffset will abort if the offset
+ // Try to avoid eagerly assigning offsets to find bugs since Offset will abort if the offset
// is unassigned.
bool eagerly_assign_offsets = false;
if (options_.visualize_pattern_ || options_.show_section_statistics_ || options_.dump_) {
diff --git a/libartbase/base/atomic.h b/libartbase/base/atomic.h
index b68f867..9de84cd 100644
--- a/libartbase/base/atomic.h
+++ b/libartbase/base/atomic.h
@@ -28,6 +28,11 @@
namespace art {
+enum class CASMode {
+ kStrong,
+ kWeak,
+};
+
template<typename T>
class PACKED(sizeof(T)) Atomic : public std::atomic<T> {
public:
@@ -100,6 +105,15 @@
return this->compare_exchange_weak(expected_value, desired_value, std::memory_order_release);
}
+ bool CompareAndSet(T expected_value,
+ T desired_value,
+ CASMode mode,
+ std::memory_order memory_order) {
+ return mode == CASMode::kStrong
+ ? this->compare_exchange_strong(expected_value, desired_value, memory_order)
+ : this->compare_exchange_weak(expected_value, desired_value, memory_order);
+ }
+
// Returns the address of the current atomic variable. This is only used by futex() which is
// declared to take a volatile address (see base/mutex-inl.h).
volatile T* Address() {
diff --git a/libartbase/base/common_art_test.h b/libartbase/base/common_art_test.h
index d9bea3d..0ace09d 100644
--- a/libartbase/base/common_art_test.h
+++ b/libartbase/base/common_art_test.h
@@ -222,4 +222,10 @@
}
} // namespace art
+#define TEST_DISABLED_FOR_MEMORY_TOOL_WITH_HEAP_POISONING() \
+ if (kRunningOnMemoryTool && kPoisonHeapReferences) { \
+ printf("WARNING: TEST DISABLED FOR MEMORY TOOL WITH HEAP POISONING\n"); \
+ return; \
+ }
+
#endif // ART_LIBARTBASE_BASE_COMMON_ART_TEST_H_
diff --git a/libartbase/base/mem_map.cc b/libartbase/base/mem_map.cc
index 9ba1d6c..d53480d 100644
--- a/libartbase/base/mem_map.cc
+++ b/libartbase/base/mem_map.cc
@@ -647,21 +647,11 @@
}
bool MemMap::Sync() {
- bool result;
- if (redzone_size_ != 0) {
- // To avoid errors when running on a memory tool, temporarily lift the lower-end noaccess
- // protection before passing it to msync() as it only accepts page-aligned base address,
- // and exclude the higher-end noaccess protection from the msync range. b/27552451.
- // TODO: Valgrind is no longer supported, but Address Sanitizer is:
- // check whether this special case is needed for ASan.
- uint8_t* base_begin = reinterpret_cast<uint8_t*>(base_begin_);
- MEMORY_TOOL_MAKE_DEFINED(base_begin, begin_ - base_begin);
- result = msync(BaseBegin(), End() - base_begin, MS_SYNC) == 0;
- MEMORY_TOOL_MAKE_NOACCESS(base_begin, begin_ - base_begin);
- } else {
- result = msync(BaseBegin(), BaseSize(), MS_SYNC) == 0;
- }
- return result;
+ // Historical note: To avoid Valgrind errors, we temporarily lifted the lower-end noaccess
+ // protection before passing it to msync() when `redzone_size_` was non-null, as Valgrind
+ // only accepts page-aligned base address, and excludes the higher-end noaccess protection
+ // from the msync range. b/27552451.
+ return msync(BaseBegin(), BaseSize(), MS_SYNC) == 0;
}
bool MemMap::Protect(int prot) {
diff --git a/libartbase/base/mem_map_test.cc b/libartbase/base/mem_map_test.cc
index 4a78bdc..c575c7a 100644
--- a/libartbase/base/mem_map_test.cc
+++ b/libartbase/base/mem_map_test.cc
@@ -471,9 +471,8 @@
// cannot allocate in the 2GB-4GB region.
TEST_DISABLED_FOR_MIPS();
- // This test may not work under Valgrind.
- // TODO: Valgrind is no longer supported, but Address Sanitizer is:
- // check whether this test works with ASan.
+ // This test does not work under AddressSanitizer.
+ // Historical note: This test did not work under Valgrind either.
TEST_DISABLED_FOR_MEMORY_TOOL();
CommonInit();
diff --git a/openjdkjvmti/ti_ddms.cc b/openjdkjvmti/ti_ddms.cc
index 0b4906d..bf063fa 100644
--- a/openjdkjvmti/ti_ddms.cc
+++ b/openjdkjvmti/ti_ddms.cc
@@ -60,7 +60,7 @@
*data_out = nullptr;
art::Thread* self = art::Thread::Current();
- art::ScopedThreadStateChange(self, art::ThreadState::kNative);
+ art::ScopedThreadStateChange stcs(self, art::ThreadState::kNative);
art::ArrayRef<const jbyte> data_arr(data_in, length_in);
std::vector<uint8_t> out_data;
diff --git a/runtime/Android.bp b/runtime/Android.bp
index 1168798..b347019 100644
--- a/runtime/Android.bp
+++ b/runtime/Android.bp
@@ -37,7 +37,6 @@
"base/quasi_atomic.cc",
"base/timing_logger.cc",
"cha.cc",
- "check_jni.cc",
"class_linker.cc",
"class_loader_context.cc",
"class_root.cc",
@@ -112,6 +111,7 @@
"jit/jit_code_cache.cc",
"jit/profiling_info.cc",
"jit/profile_saver.cc",
+ "jni/check_jni.cc",
"jni/java_vm_ext.cc",
"jni/jni_env_ext.cc",
"jni/jni_internal.cc",
diff --git a/runtime/exec_utils_test.cc b/runtime/exec_utils_test.cc
index a9c1ea2..c138ce3 100644
--- a/runtime/exec_utils_test.cc
+++ b/runtime/exec_utils_test.cc
@@ -36,12 +36,9 @@
command.push_back("/usr/bin/id");
}
std::string error_msg;
- if (!(kRunningOnMemoryTool && kMemoryToolDetectsLeaks)) {
- // Running on Valgrind fails due to some memory that leaks in thread alternate signal stacks.
- // TODO: Valgrind is no longer supported, but Address Sanitizer is:
- // check whether the following code works with ASan.
- EXPECT_TRUE(Exec(command, &error_msg));
- }
+ // Historical note: Running on Valgrind failed due to some memory
+ // that leaks in thread alternate signal stacks.
+ EXPECT_TRUE(Exec(command, &error_msg));
EXPECT_EQ(0U, error_msg.size()) << error_msg;
}
@@ -52,13 +49,10 @@
std::vector<std::string> command;
command.push_back("bogus");
std::string error_msg;
- if (!(kRunningOnMemoryTool && kMemoryToolDetectsLeaks)) {
- // Running on Valgrind fails due to some memory that leaks in thread alternate signal stacks.
- // TODO: Valgrind is no longer supported, but Address Sanitizer is:
- // check whether the following code works with ASan.
- EXPECT_FALSE(Exec(command, &error_msg));
- EXPECT_FALSE(error_msg.empty());
- }
+ // Historical note: Running on Valgrind failed due to some memory
+ // that leaks in thread alternate signal stacks.
+ EXPECT_FALSE(Exec(command, &error_msg));
+ EXPECT_FALSE(error_msg.empty());
}
TEST_F(ExecUtilsTest, EnvSnapshotAdditionsAreNotVisible) {
@@ -76,13 +70,10 @@
}
command.push_back(kModifiedVariable);
std::string error_msg;
- if (!(kRunningOnMemoryTool && kMemoryToolDetectsLeaks)) {
- // Running on Valgrind fails due to some memory that leaks in thread alternate signal stacks.
- // TODO: Valgrind is no longer supported, but Address Sanitizer is:
- // check whether the following code works with ASan.
- EXPECT_FALSE(Exec(command, &error_msg));
- EXPECT_NE(0U, error_msg.size()) << error_msg;
- }
+ // Historical note: Running on Valgrind failed due to some memory
+ // that leaks in thread alternate signal stacks.
+ EXPECT_FALSE(Exec(command, &error_msg));
+ EXPECT_NE(0U, error_msg.size()) << error_msg;
}
TEST_F(ExecUtilsTest, EnvSnapshotDeletionsAreNotVisible) {
@@ -103,13 +94,10 @@
}
command.push_back(kDeletedVariable);
std::string error_msg;
- if (!(kRunningOnMemoryTool && kMemoryToolDetectsLeaks)) {
- // Running on Valgrind fails due to some memory that leaks in thread alternate signal stacks.
- // TODO: Valgrind is no longer supported, but Address Sanitizer is:
- // check whether the following code works with ASan.
- EXPECT_TRUE(Exec(command, &error_msg));
- EXPECT_EQ(0U, error_msg.size()) << error_msg;
- }
+ // Historical note: Running on Valgrind failed due to some memory
+ // that leaks in thread alternate signal stacks.
+ EXPECT_TRUE(Exec(command, &error_msg));
+ EXPECT_EQ(0U, error_msg.size()) << error_msg;
// Restore the variable's value.
EXPECT_EQ(setenv(kDeletedVariable, save_value, kOverwrite), 0);
}
diff --git a/runtime/gc/collector/concurrent_copying.cc b/runtime/gc/collector/concurrent_copying.cc
index c4d2fdd..10fa8c5 100644
--- a/runtime/gc/collector/concurrent_copying.cc
+++ b/runtime/gc/collector/concurrent_copying.cc
@@ -1551,7 +1551,7 @@
// above IsInToSpace() evaluates to true and we change the color from gray to white here in this
// else block.
if (kUseBakerReadBarrier) {
- bool success = to_ref->AtomicSetReadBarrierState</*kCasRelease*/true>(
+ bool success = to_ref->AtomicSetReadBarrierState<std::memory_order_release>(
ReadBarrier::GrayState(),
ReadBarrier::WhiteState());
DCHECK(success) << "Must succeed as we won the race.";
@@ -2490,7 +2490,10 @@
LockWord new_lock_word = LockWord::FromForwardingAddress(reinterpret_cast<size_t>(to_ref));
// Try to atomically write the fwd ptr.
- bool success = from_ref->CasLockWordWeakRelaxed(old_lock_word, new_lock_word);
+ bool success = from_ref->CasLockWord(old_lock_word,
+ new_lock_word,
+ CASMode::kWeak,
+ std::memory_order_relaxed);
if (LIKELY(success)) {
// The CAS succeeded.
DCHECK(thread_running_gc_ != nullptr);
diff --git a/runtime/gc/heap_verification_test.cc b/runtime/gc/heap_verification_test.cc
index 3869533..6caca84 100644
--- a/runtime/gc/heap_verification_test.cc
+++ b/runtime/gc/heap_verification_test.cc
@@ -83,7 +83,7 @@
}
TEST_F(VerificationTest, IsValidClassInHeap) {
- TEST_DISABLED_FOR_MEMORY_TOOL();
+ TEST_DISABLED_FOR_MEMORY_TOOL_WITH_HEAP_POISONING();
ScopedObjectAccess soa(Thread::Current());
VariableSizedHandleScope hs(soa.Self());
Handle<mirror::String> string(
@@ -106,7 +106,7 @@
}
TEST_F(VerificationTest, DumpValidObjectInfo) {
- TEST_DISABLED_FOR_MEMORY_TOOL();
+ TEST_DISABLED_FOR_MEMORY_TOOL_WITH_HEAP_POISONING();
ScopedLogSeverity sls(LogSeverity::INFO);
ScopedObjectAccess soa(Thread::Current());
Runtime* const runtime = Runtime::Current();
@@ -126,7 +126,7 @@
}
TEST_F(VerificationTest, LogHeapCorruption) {
- TEST_DISABLED_FOR_MEMORY_TOOL();
+ TEST_DISABLED_FOR_MEMORY_TOOL_WITH_HEAP_POISONING();
ScopedLogSeverity sls(LogSeverity::INFO);
ScopedObjectAccess soa(Thread::Current());
Runtime* const runtime = Runtime::Current();
@@ -147,7 +147,6 @@
}
TEST_F(VerificationTest, FindPathFromRootSet) {
- TEST_DISABLED_FOR_MEMORY_TOOL();
ScopedLogSeverity sls(LogSeverity::INFO);
ScopedObjectAccess soa(Thread::Current());
Runtime* const runtime = Runtime::Current();
diff --git a/runtime/interpreter/unstarted_runtime.cc b/runtime/interpreter/unstarted_runtime.cc
index 667bd03..6a4cf56 100644
--- a/runtime/interpreter/unstarted_runtime.cc
+++ b/runtime/interpreter/unstarted_runtime.cc
@@ -1855,11 +1855,17 @@
jint newValue = args[4];
bool success;
if (Runtime::Current()->IsActiveTransaction()) {
- success = obj->CasFieldStrongSequentiallyConsistent32<true>(MemberOffset(offset),
- expectedValue, newValue);
+ success = obj->CasField32<true>(MemberOffset(offset),
+ expectedValue,
+ newValue,
+ CASMode::kStrong,
+ std::memory_order_seq_cst);
} else {
- success = obj->CasFieldStrongSequentiallyConsistent32<false>(MemberOffset(offset),
- expectedValue, newValue);
+ success = obj->CasField32<false>(MemberOffset(offset),
+ expectedValue,
+ newValue,
+ CASMode::kStrong,
+ std::memory_order_seq_cst);
}
result->SetZ(success ? JNI_TRUE : JNI_FALSE);
}
diff --git a/runtime/check_jni.cc b/runtime/jni/check_jni.cc
similarity index 99%
rename from runtime/check_jni.cc
rename to runtime/jni/check_jni.cc
index 0ff55ae..7919c32 100644
--- a/runtime/check_jni.cc
+++ b/runtime/jni/check_jni.cc
@@ -35,8 +35,8 @@
#include "dex/descriptors_names.h"
#include "dex/dex_file-inl.h"
#include "gc/space/space.h"
-#include "jni/java_vm_ext.h"
-#include "jni/jni_internal.h"
+#include "java_vm_ext.h"
+#include "jni_internal.h"
#include "mirror/class-inl.h"
#include "mirror/field.h"
#include "mirror/method.h"
@@ -2173,7 +2173,7 @@
return result;
}
- static jobject NewObjectA(JNIEnv* env, jclass c, jmethodID mid, jvalue* vargs) {
+ static jobject NewObjectA(JNIEnv* env, jclass c, jmethodID mid, const jvalue* vargs) {
CHECK_ATTACHED_THREAD(__FUNCTION__, nullptr);
ScopedObjectAccess soa(env);
ScopedCheck sc(kFlag_Default, __FUNCTION__);
@@ -2268,16 +2268,16 @@
FIELD_ACCESSORS(jdouble, Double, Primitive::kPrimDouble, D, D)
#undef FIELD_ACCESSORS
- static void CallVoidMethodA(JNIEnv* env, jobject obj, jmethodID mid, jvalue* vargs) {
+ static void CallVoidMethodA(JNIEnv* env, jobject obj, jmethodID mid, const jvalue* vargs) {
CallMethodA(__FUNCTION__, env, obj, nullptr, mid, vargs, Primitive::kPrimVoid, kVirtual);
}
static void CallNonvirtualVoidMethodA(JNIEnv* env, jobject obj, jclass c, jmethodID mid,
- jvalue* vargs) {
+ const jvalue* vargs) {
CallMethodA(__FUNCTION__, env, obj, c, mid, vargs, Primitive::kPrimVoid, kDirect);
}
- static void CallStaticVoidMethodA(JNIEnv* env, jclass c, jmethodID mid, jvalue* vargs) {
+ static void CallStaticVoidMethodA(JNIEnv* env, jclass c, jmethodID mid, const jvalue* vargs) {
CallMethodA(__FUNCTION__, env, nullptr, c, mid, vargs, Primitive::kPrimVoid, kStatic);
}
@@ -2316,16 +2316,16 @@
}
#define CALL(rtype, name, ptype, shorty) \
- static rtype Call##name##MethodA(JNIEnv* env, jobject obj, jmethodID mid, jvalue* vargs) { \
+ static rtype Call##name##MethodA(JNIEnv* env, jobject obj, jmethodID mid, const jvalue* vargs) { \
return CallMethodA(__FUNCTION__, env, obj, nullptr, mid, vargs, ptype, kVirtual).shorty; \
} \
\
static rtype CallNonvirtual##name##MethodA(JNIEnv* env, jobject obj, jclass c, jmethodID mid, \
- jvalue* vargs) { \
+ const jvalue* vargs) { \
return CallMethodA(__FUNCTION__, env, obj, c, mid, vargs, ptype, kDirect).shorty; \
} \
\
- static rtype CallStatic##name##MethodA(JNIEnv* env, jclass c, jmethodID mid, jvalue* vargs) { \
+ static rtype CallStatic##name##MethodA(JNIEnv* env, jclass c, jmethodID mid, const jvalue* vargs) { \
return CallMethodA(__FUNCTION__, env, nullptr, c, mid, vargs, ptype, kStatic).shorty; \
} \
\
@@ -3070,7 +3070,7 @@
}
static JniValueType CallMethodA(const char* function_name, JNIEnv* env, jobject obj, jclass c,
- jmethodID mid, jvalue* vargs, Primitive::Type type,
+ jmethodID mid, const jvalue* vargs, Primitive::Type type,
InvokeType invoke) {
CHECK_ATTACHED_THREAD(function_name, JniValueType());
ScopedObjectAccess soa(env);
diff --git a/runtime/check_jni.h b/runtime/jni/check_jni.h
similarity index 87%
rename from runtime/check_jni.h
rename to runtime/jni/check_jni.h
index f41abf8..10fdfe8 100644
--- a/runtime/check_jni.h
+++ b/runtime/jni/check_jni.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef ART_RUNTIME_CHECK_JNI_H_
-#define ART_RUNTIME_CHECK_JNI_H_
+#ifndef ART_RUNTIME_JNI_CHECK_JNI_H_
+#define ART_RUNTIME_JNI_CHECK_JNI_H_
#include <jni.h>
@@ -26,4 +26,4 @@
} // namespace art
-#endif // ART_RUNTIME_CHECK_JNI_H_
+#endif // ART_RUNTIME_JNI_CHECK_JNI_H_
diff --git a/runtime/jni/jni_internal.cc b/runtime/jni/jni_internal.cc
index 7290d63..a02e76a 100644
--- a/runtime/jni/jni_internal.cc
+++ b/runtime/jni/jni_internal.cc
@@ -761,7 +761,7 @@
return local_result;
}
- static jobject NewObjectA(JNIEnv* env, jclass java_class, jmethodID mid, jvalue* args) {
+ static jobject NewObjectA(JNIEnv* env, jclass java_class, jmethodID mid, const jvalue* args) {
CHECK_NON_NULL_ARGUMENT(java_class);
CHECK_NON_NULL_ARGUMENT(mid);
ScopedObjectAccess soa(env);
@@ -824,7 +824,7 @@
return soa.AddLocalReference<jobject>(result.GetL());
}
- static jobject CallObjectMethodA(JNIEnv* env, jobject obj, jmethodID mid, jvalue* args) {
+ static jobject CallObjectMethodA(JNIEnv* env, jobject obj, jmethodID mid, const jvalue* args) {
CHECK_NON_NULL_ARGUMENT(obj);
CHECK_NON_NULL_ARGUMENT(mid);
ScopedObjectAccess soa(env);
@@ -850,7 +850,7 @@
return InvokeVirtualOrInterfaceWithVarArgs(soa, obj, mid, args).GetZ();
}
- static jboolean CallBooleanMethodA(JNIEnv* env, jobject obj, jmethodID mid, jvalue* args) {
+ static jboolean CallBooleanMethodA(JNIEnv* env, jobject obj, jmethodID mid, const jvalue* args) {
CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
ScopedObjectAccess soa(env);
@@ -875,7 +875,7 @@
return InvokeVirtualOrInterfaceWithVarArgs(soa, obj, mid, args).GetB();
}
- static jbyte CallByteMethodA(JNIEnv* env, jobject obj, jmethodID mid, jvalue* args) {
+ static jbyte CallByteMethodA(JNIEnv* env, jobject obj, jmethodID mid, const jvalue* args) {
CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
ScopedObjectAccess soa(env);
@@ -900,7 +900,7 @@
return InvokeVirtualOrInterfaceWithVarArgs(soa, obj, mid, args).GetC();
}
- static jchar CallCharMethodA(JNIEnv* env, jobject obj, jmethodID mid, jvalue* args) {
+ static jchar CallCharMethodA(JNIEnv* env, jobject obj, jmethodID mid, const jvalue* args) {
CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
ScopedObjectAccess soa(env);
@@ -925,7 +925,7 @@
return InvokeVirtualOrInterfaceWithVarArgs(soa, obj, mid, args).GetD();
}
- static jdouble CallDoubleMethodA(JNIEnv* env, jobject obj, jmethodID mid, jvalue* args) {
+ static jdouble CallDoubleMethodA(JNIEnv* env, jobject obj, jmethodID mid, const jvalue* args) {
CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
ScopedObjectAccess soa(env);
@@ -950,7 +950,7 @@
return InvokeVirtualOrInterfaceWithVarArgs(soa, obj, mid, args).GetF();
}
- static jfloat CallFloatMethodA(JNIEnv* env, jobject obj, jmethodID mid, jvalue* args) {
+ static jfloat CallFloatMethodA(JNIEnv* env, jobject obj, jmethodID mid, const jvalue* args) {
CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
ScopedObjectAccess soa(env);
@@ -975,7 +975,7 @@
return InvokeVirtualOrInterfaceWithVarArgs(soa, obj, mid, args).GetI();
}
- static jint CallIntMethodA(JNIEnv* env, jobject obj, jmethodID mid, jvalue* args) {
+ static jint CallIntMethodA(JNIEnv* env, jobject obj, jmethodID mid, const jvalue* args) {
CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
ScopedObjectAccess soa(env);
@@ -1000,7 +1000,7 @@
return InvokeVirtualOrInterfaceWithVarArgs(soa, obj, mid, args).GetJ();
}
- static jlong CallLongMethodA(JNIEnv* env, jobject obj, jmethodID mid, jvalue* args) {
+ static jlong CallLongMethodA(JNIEnv* env, jobject obj, jmethodID mid, const jvalue* args) {
CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
ScopedObjectAccess soa(env);
@@ -1025,7 +1025,7 @@
return InvokeVirtualOrInterfaceWithVarArgs(soa, obj, mid, args).GetS();
}
- static jshort CallShortMethodA(JNIEnv* env, jobject obj, jmethodID mid, jvalue* args) {
+ static jshort CallShortMethodA(JNIEnv* env, jobject obj, jmethodID mid, const jvalue* args) {
CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
ScopedObjectAccess soa(env);
@@ -1049,7 +1049,7 @@
InvokeVirtualOrInterfaceWithVarArgs(soa, obj, mid, args);
}
- static void CallVoidMethodA(JNIEnv* env, jobject obj, jmethodID mid, jvalue* args) {
+ static void CallVoidMethodA(JNIEnv* env, jobject obj, jmethodID mid, const jvalue* args) {
CHECK_NON_NULL_ARGUMENT_RETURN_VOID(obj);
CHECK_NON_NULL_ARGUMENT_RETURN_VOID(mid);
ScopedObjectAccess soa(env);
@@ -1078,7 +1078,7 @@
}
static jobject CallNonvirtualObjectMethodA(JNIEnv* env, jobject obj, jclass, jmethodID mid,
- jvalue* args) {
+ const jvalue* args) {
CHECK_NON_NULL_ARGUMENT(obj);
CHECK_NON_NULL_ARGUMENT(mid);
ScopedObjectAccess soa(env);
@@ -1107,7 +1107,7 @@
}
static jboolean CallNonvirtualBooleanMethodA(JNIEnv* env, jobject obj, jclass, jmethodID mid,
- jvalue* args) {
+ const jvalue* args) {
CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
ScopedObjectAccess soa(env);
@@ -1134,7 +1134,7 @@
}
static jbyte CallNonvirtualByteMethodA(JNIEnv* env, jobject obj, jclass, jmethodID mid,
- jvalue* args) {
+ const jvalue* args) {
CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
ScopedObjectAccess soa(env);
@@ -1161,7 +1161,7 @@
}
static jchar CallNonvirtualCharMethodA(JNIEnv* env, jobject obj, jclass, jmethodID mid,
- jvalue* args) {
+ const jvalue* args) {
CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
ScopedObjectAccess soa(env);
@@ -1188,7 +1188,7 @@
}
static jshort CallNonvirtualShortMethodA(JNIEnv* env, jobject obj, jclass, jmethodID mid,
- jvalue* args) {
+ const jvalue* args) {
CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
ScopedObjectAccess soa(env);
@@ -1215,7 +1215,7 @@
}
static jint CallNonvirtualIntMethodA(JNIEnv* env, jobject obj, jclass, jmethodID mid,
- jvalue* args) {
+ const jvalue* args) {
CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
ScopedObjectAccess soa(env);
@@ -1242,7 +1242,7 @@
}
static jlong CallNonvirtualLongMethodA(JNIEnv* env, jobject obj, jclass, jmethodID mid,
- jvalue* args) {
+ const jvalue* args) {
CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
ScopedObjectAccess soa(env);
@@ -1269,7 +1269,7 @@
}
static jfloat CallNonvirtualFloatMethodA(JNIEnv* env, jobject obj, jclass, jmethodID mid,
- jvalue* args) {
+ const jvalue* args) {
CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
ScopedObjectAccess soa(env);
@@ -1296,7 +1296,7 @@
}
static jdouble CallNonvirtualDoubleMethodA(JNIEnv* env, jobject obj, jclass, jmethodID mid,
- jvalue* args) {
+ const jvalue* args) {
CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
ScopedObjectAccess soa(env);
@@ -1322,7 +1322,7 @@
}
static void CallNonvirtualVoidMethodA(JNIEnv* env, jobject obj, jclass, jmethodID mid,
- jvalue* args) {
+ const jvalue* args) {
CHECK_NON_NULL_ARGUMENT_RETURN_VOID(obj);
CHECK_NON_NULL_ARGUMENT_RETURN_VOID(mid);
ScopedObjectAccess soa(env);
@@ -1562,7 +1562,7 @@
return soa.AddLocalReference<jobject>(result.GetL());
}
- static jobject CallStaticObjectMethodA(JNIEnv* env, jclass, jmethodID mid, jvalue* args) {
+ static jobject CallStaticObjectMethodA(JNIEnv* env, jclass, jmethodID mid, const jvalue* args) {
CHECK_NON_NULL_ARGUMENT(mid);
ScopedObjectAccess soa(env);
JValue result(InvokeWithJValues(soa, nullptr, mid, args));
@@ -1585,7 +1585,7 @@
return InvokeWithVarArgs(soa, nullptr, mid, args).GetZ();
}
- static jboolean CallStaticBooleanMethodA(JNIEnv* env, jclass, jmethodID mid, jvalue* args) {
+ static jboolean CallStaticBooleanMethodA(JNIEnv* env, jclass, jmethodID mid, const jvalue* args) {
CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
ScopedObjectAccess soa(env);
return InvokeWithJValues(soa, nullptr, mid, args).GetZ();
@@ -1607,7 +1607,7 @@
return InvokeWithVarArgs(soa, nullptr, mid, args).GetB();
}
- static jbyte CallStaticByteMethodA(JNIEnv* env, jclass, jmethodID mid, jvalue* args) {
+ static jbyte CallStaticByteMethodA(JNIEnv* env, jclass, jmethodID mid, const jvalue* args) {
CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
ScopedObjectAccess soa(env);
return InvokeWithJValues(soa, nullptr, mid, args).GetB();
@@ -1629,7 +1629,7 @@
return InvokeWithVarArgs(soa, nullptr, mid, args).GetC();
}
- static jchar CallStaticCharMethodA(JNIEnv* env, jclass, jmethodID mid, jvalue* args) {
+ static jchar CallStaticCharMethodA(JNIEnv* env, jclass, jmethodID mid, const jvalue* args) {
CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
ScopedObjectAccess soa(env);
return InvokeWithJValues(soa, nullptr, mid, args).GetC();
@@ -1651,7 +1651,7 @@
return InvokeWithVarArgs(soa, nullptr, mid, args).GetS();
}
- static jshort CallStaticShortMethodA(JNIEnv* env, jclass, jmethodID mid, jvalue* args) {
+ static jshort CallStaticShortMethodA(JNIEnv* env, jclass, jmethodID mid, const jvalue* args) {
CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
ScopedObjectAccess soa(env);
return InvokeWithJValues(soa, nullptr, mid, args).GetS();
@@ -1673,7 +1673,7 @@
return InvokeWithVarArgs(soa, nullptr, mid, args).GetI();
}
- static jint CallStaticIntMethodA(JNIEnv* env, jclass, jmethodID mid, jvalue* args) {
+ static jint CallStaticIntMethodA(JNIEnv* env, jclass, jmethodID mid, const jvalue* args) {
CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
ScopedObjectAccess soa(env);
return InvokeWithJValues(soa, nullptr, mid, args).GetI();
@@ -1695,7 +1695,7 @@
return InvokeWithVarArgs(soa, nullptr, mid, args).GetJ();
}
- static jlong CallStaticLongMethodA(JNIEnv* env, jclass, jmethodID mid, jvalue* args) {
+ static jlong CallStaticLongMethodA(JNIEnv* env, jclass, jmethodID mid, const jvalue* args) {
CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
ScopedObjectAccess soa(env);
return InvokeWithJValues(soa, nullptr, mid, args).GetJ();
@@ -1717,7 +1717,7 @@
return InvokeWithVarArgs(soa, nullptr, mid, args).GetF();
}
- static jfloat CallStaticFloatMethodA(JNIEnv* env, jclass, jmethodID mid, jvalue* args) {
+ static jfloat CallStaticFloatMethodA(JNIEnv* env, jclass, jmethodID mid, const jvalue* args) {
CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
ScopedObjectAccess soa(env);
return InvokeWithJValues(soa, nullptr, mid, args).GetF();
@@ -1739,7 +1739,7 @@
return InvokeWithVarArgs(soa, nullptr, mid, args).GetD();
}
- static jdouble CallStaticDoubleMethodA(JNIEnv* env, jclass, jmethodID mid, jvalue* args) {
+ static jdouble CallStaticDoubleMethodA(JNIEnv* env, jclass, jmethodID mid, const jvalue* args) {
CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
ScopedObjectAccess soa(env);
return InvokeWithJValues(soa, nullptr, mid, args).GetD();
@@ -1760,7 +1760,7 @@
InvokeWithVarArgs(soa, nullptr, mid, args);
}
- static void CallStaticVoidMethodA(JNIEnv* env, jclass, jmethodID mid, jvalue* args) {
+ static void CallStaticVoidMethodA(JNIEnv* env, jclass, jmethodID mid, const jvalue* args) {
CHECK_NON_NULL_ARGUMENT_RETURN_VOID(mid);
ScopedObjectAccess soa(env);
InvokeWithJValues(soa, nullptr, mid, args);
diff --git a/runtime/mirror/object-inl.h b/runtime/mirror/object-inl.h
index ee4f53b..bb99c0c 100644
--- a/runtime/mirror/object-inl.h
+++ b/runtime/mirror/object-inl.h
@@ -78,18 +78,6 @@
}
}
-inline bool Object::CasLockWordWeakSequentiallyConsistent(LockWord old_val, LockWord new_val) {
- // Force use of non-transactional mode and do not check.
- return CasFieldWeakSequentiallyConsistent32<false, false>(
- OFFSET_OF_OBJECT_MEMBER(Object, monitor_), old_val.GetValue(), new_val.GetValue());
-}
-
-inline bool Object::CasLockWordWeakAcquire(LockWord old_val, LockWord new_val) {
- // Force use of non-transactional mode and do not check.
- return CasFieldWeakAcquire32<false, false>(
- OFFSET_OF_OBJECT_MEMBER(Object, monitor_), old_val.GetValue(), new_val.GetValue());
-}
-
inline uint32_t Object::GetLockOwnerThreadId() {
return Monitor::GetLockOwnerThreadId(this);
}
@@ -575,84 +563,6 @@
}
}
-// TODO: Pass memory_order_ and strong/weak as arguments to avoid code duplication?
-
-template<bool kTransactionActive, bool kCheckTransaction, VerifyObjectFlags kVerifyFlags>
-inline bool Object::CasFieldWeakSequentiallyConsistent32(MemberOffset field_offset,
- int32_t old_value,
- int32_t new_value) {
- if (kCheckTransaction) {
- DCHECK_EQ(kTransactionActive, Runtime::Current()->IsActiveTransaction());
- }
- if (kTransactionActive) {
- Runtime::Current()->RecordWriteField32(this, field_offset, old_value, true);
- }
- if (kVerifyFlags & kVerifyThis) {
- VerifyObject(this);
- }
- uint8_t* raw_addr = reinterpret_cast<uint8_t*>(this) + field_offset.Int32Value();
- AtomicInteger* atomic_addr = reinterpret_cast<AtomicInteger*>(raw_addr);
-
- return atomic_addr->CompareAndSetWeakSequentiallyConsistent(old_value, new_value);
-}
-
-template<bool kTransactionActive, bool kCheckTransaction, VerifyObjectFlags kVerifyFlags>
-inline bool Object::CasFieldWeakAcquire32(MemberOffset field_offset,
- int32_t old_value,
- int32_t new_value) {
- if (kCheckTransaction) {
- DCHECK_EQ(kTransactionActive, Runtime::Current()->IsActiveTransaction());
- }
- if (kTransactionActive) {
- Runtime::Current()->RecordWriteField32(this, field_offset, old_value, true);
- }
- if (kVerifyFlags & kVerifyThis) {
- VerifyObject(this);
- }
- uint8_t* raw_addr = reinterpret_cast<uint8_t*>(this) + field_offset.Int32Value();
- AtomicInteger* atomic_addr = reinterpret_cast<AtomicInteger*>(raw_addr);
-
- return atomic_addr->CompareAndSetWeakAcquire(old_value, new_value);
-}
-
-template<bool kTransactionActive, bool kCheckTransaction, VerifyObjectFlags kVerifyFlags>
-inline bool Object::CasFieldWeakRelease32(MemberOffset field_offset,
- int32_t old_value,
- int32_t new_value) {
- if (kCheckTransaction) {
- DCHECK_EQ(kTransactionActive, Runtime::Current()->IsActiveTransaction());
- }
- if (kTransactionActive) {
- Runtime::Current()->RecordWriteField32(this, field_offset, old_value, true);
- }
- if (kVerifyFlags & kVerifyThis) {
- VerifyObject(this);
- }
- uint8_t* raw_addr = reinterpret_cast<uint8_t*>(this) + field_offset.Int32Value();
- AtomicInteger* atomic_addr = reinterpret_cast<AtomicInteger*>(raw_addr);
-
- return atomic_addr->CompareAndSetWeakRelease(old_value, new_value);
-}
-
-template<bool kTransactionActive, bool kCheckTransaction, VerifyObjectFlags kVerifyFlags>
-inline bool Object::CasFieldStrongSequentiallyConsistent32(MemberOffset field_offset,
- int32_t old_value,
- int32_t new_value) {
- if (kCheckTransaction) {
- DCHECK_EQ(kTransactionActive, Runtime::Current()->IsActiveTransaction());
- }
- if (kTransactionActive) {
- Runtime::Current()->RecordWriteField32(this, field_offset, old_value, true);
- }
- if (kVerifyFlags & kVerifyThis) {
- VerifyObject(this);
- }
- uint8_t* raw_addr = reinterpret_cast<uint8_t*>(this) + field_offset.Int32Value();
- AtomicInteger* atomic_addr = reinterpret_cast<AtomicInteger*>(raw_addr);
-
- return atomic_addr->CompareAndSetStrongSequentiallyConsistent(old_value, new_value);
-}
-
template<bool kTransactionActive,
bool kCheckTransaction,
VerifyObjectFlags kVerifyFlags,
diff --git a/runtime/mirror/object-readbarrier-inl.h b/runtime/mirror/object-readbarrier-inl.h
index aeaa850..597ba67 100644
--- a/runtime/mirror/object-readbarrier-inl.h
+++ b/runtime/mirror/object-readbarrier-inl.h
@@ -32,14 +32,17 @@
template<VerifyObjectFlags kVerifyFlags>
inline LockWord Object::GetLockWord(bool as_volatile) {
if (as_volatile) {
- return LockWord(GetField32Volatile<kVerifyFlags>(OFFSET_OF_OBJECT_MEMBER(Object, monitor_)));
+ return LockWord(GetField32Volatile<kVerifyFlags>(MonitorOffset()));
}
- return LockWord(GetField32<kVerifyFlags>(OFFSET_OF_OBJECT_MEMBER(Object, monitor_)));
+ return LockWord(GetField32<kVerifyFlags>(MonitorOffset()));
}
template<bool kTransactionActive, bool kCheckTransaction, VerifyObjectFlags kVerifyFlags>
-inline bool Object::CasFieldWeakRelaxed32(MemberOffset field_offset,
- int32_t old_value, int32_t new_value) {
+inline bool Object::CasField32(MemberOffset field_offset,
+ int32_t old_value,
+ int32_t new_value,
+ CASMode mode,
+ std::memory_order memory_order) {
if (kCheckTransaction) {
DCHECK_EQ(kTransactionActive, Runtime::Current()->IsActiveTransaction());
}
@@ -52,19 +55,19 @@
uint8_t* raw_addr = reinterpret_cast<uint8_t*>(this) + field_offset.Int32Value();
AtomicInteger* atomic_addr = reinterpret_cast<AtomicInteger*>(raw_addr);
- return atomic_addr->CompareAndSetWeakRelaxed(old_value, new_value);
+ return atomic_addr->CompareAndSet(old_value, new_value, mode, memory_order);
}
-inline bool Object::CasLockWordWeakRelaxed(LockWord old_val, LockWord new_val) {
+inline bool Object::CasLockWord(LockWord old_val,
+ LockWord new_val,
+ CASMode mode,
+ std::memory_order memory_order) {
// Force use of non-transactional mode and do not check.
- return CasFieldWeakRelaxed32<false, false>(
- OFFSET_OF_OBJECT_MEMBER(Object, monitor_), old_val.GetValue(), new_val.GetValue());
-}
-
-inline bool Object::CasLockWordWeakRelease(LockWord old_val, LockWord new_val) {
- // Force use of non-transactional mode and do not check.
- return CasFieldWeakRelease32<false, false>(
- OFFSET_OF_OBJECT_MEMBER(Object, monitor_), old_val.GetValue(), new_val.GetValue());
+ return CasField32<false, false>(MonitorOffset(),
+ old_val.GetValue(),
+ new_val.GetValue(),
+ mode,
+ memory_order);
}
inline uint32_t Object::GetReadBarrierState(uintptr_t* fake_address_dependency) {
@@ -145,7 +148,7 @@
return rb_state;
}
-template<bool kCasRelease>
+template<std::memory_order kMemoryOrder>
inline bool Object::AtomicSetReadBarrierState(uint32_t expected_rb_state, uint32_t rb_state) {
if (!kUseBakerReadBarrier) {
LOG(FATAL) << "Unreachable";
@@ -169,9 +172,7 @@
// If kCasRelease == true, use a CAS release so that when GC updates all the fields of
// an object and then changes the object from gray to black, the field updates (stores) will be
// visible (won't be reordered after this CAS.)
- } while (!(kCasRelease ?
- CasLockWordWeakRelease(expected_lw, new_lw) :
- CasLockWordWeakRelaxed(expected_lw, new_lw)));
+ } while (!CasLockWord(expected_lw, new_lw, CASMode::kWeak, kMemoryOrder));
return true;
}
@@ -188,7 +189,7 @@
new_lw = lw;
new_lw.SetMarkBitState(mark_bit);
// Since this is only set from the mutator, we can use the non-release CAS.
- } while (!CasLockWordWeakRelaxed(expected_lw, new_lw));
+ } while (!CasLockWord(expected_lw, new_lw, CASMode::kWeak, std::memory_order_relaxed));
return true;
}
diff --git a/runtime/mirror/object.cc b/runtime/mirror/object.cc
index 4240e70..ce845bf 100644
--- a/runtime/mirror/object.cc
+++ b/runtime/mirror/object.cc
@@ -197,7 +197,9 @@
// loop iteration.
LockWord hash_word = LockWord::FromHashCode(GenerateIdentityHashCode(), lw.GCState());
DCHECK_EQ(hash_word.GetState(), LockWord::kHashCode);
- if (current_this->CasLockWordWeakRelaxed(lw, hash_word)) {
+ // Use a strong CAS to prevent spurious failures since these can make the boot image
+ // non-deterministic.
+ if (current_this->CasLockWord(lw, hash_word, CASMode::kStrong, std::memory_order_relaxed)) {
return hash_word.GetHashCode();
}
break;
diff --git a/runtime/mirror/object.h b/runtime/mirror/object.h
index a89d632..654fe95 100644
--- a/runtime/mirror/object.h
+++ b/runtime/mirror/object.h
@@ -111,7 +111,7 @@
#endif
ALWAYS_INLINE void SetReadBarrierState(uint32_t rb_state) REQUIRES_SHARED(Locks::mutator_lock_);
- template<bool kCasRelease = false>
+ template<std::memory_order kMemoryOrder = std::memory_order_relaxed>
ALWAYS_INLINE bool AtomicSetReadBarrierState(uint32_t expected_rb_state, uint32_t rb_state)
REQUIRES_SHARED(Locks::mutator_lock_);
@@ -151,13 +151,7 @@
LockWord GetLockWord(bool as_volatile) REQUIRES_SHARED(Locks::mutator_lock_);
template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
void SetLockWord(LockWord new_val, bool as_volatile) REQUIRES_SHARED(Locks::mutator_lock_);
- bool CasLockWordWeakSequentiallyConsistent(LockWord old_val, LockWord new_val)
- REQUIRES_SHARED(Locks::mutator_lock_);
- bool CasLockWordWeakRelaxed(LockWord old_val, LockWord new_val)
- REQUIRES_SHARED(Locks::mutator_lock_);
- bool CasLockWordWeakAcquire(LockWord old_val, LockWord new_val)
- REQUIRES_SHARED(Locks::mutator_lock_);
- bool CasLockWordWeakRelease(LockWord old_val, LockWord new_val)
+ bool CasLockWord(LockWord old_val, LockWord new_val, CASMode mode, std::memory_order memory_order)
REQUIRES_SHARED(Locks::mutator_lock_);
uint32_t GetLockOwnerThreadId();
@@ -523,41 +517,11 @@
template<bool kTransactionActive,
bool kCheckTransaction = true,
VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
- ALWAYS_INLINE bool CasFieldWeakSequentiallyConsistent32(MemberOffset field_offset,
- int32_t old_value,
- int32_t new_value)
- REQUIRES_SHARED(Locks::mutator_lock_);
-
- template<bool kTransactionActive,
- bool kCheckTransaction = true,
- VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
- ALWAYS_INLINE bool CasFieldWeakRelaxed32(MemberOffset field_offset,
- int32_t old_value,
- int32_t new_value)
- REQUIRES_SHARED(Locks::mutator_lock_);
-
- template<bool kTransactionActive,
- bool kCheckTransaction = true,
- VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
- ALWAYS_INLINE bool CasFieldWeakAcquire32(MemberOffset field_offset,
- int32_t old_value,
- int32_t new_value)
- REQUIRES_SHARED(Locks::mutator_lock_);
-
- template<bool kTransactionActive,
- bool kCheckTransaction = true,
- VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
- ALWAYS_INLINE bool CasFieldWeakRelease32(MemberOffset field_offset,
- int32_t old_value,
- int32_t new_value)
- REQUIRES_SHARED(Locks::mutator_lock_);
-
- template<bool kTransactionActive,
- bool kCheckTransaction = true,
- VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
- ALWAYS_INLINE bool CasFieldStrongSequentiallyConsistent32(MemberOffset field_offset,
- int32_t old_value,
- int32_t new_value)
+ ALWAYS_INLINE bool CasField32(MemberOffset field_offset,
+ int32_t old_value,
+ int32_t new_value,
+ CASMode mode,
+ std::memory_order memory_order)
REQUIRES_SHARED(Locks::mutator_lock_);
template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, bool kIsVolatile = false>
diff --git a/runtime/monitor.cc b/runtime/monitor.cc
index 2c38de5..d47bc0d 100644
--- a/runtime/monitor.cc
+++ b/runtime/monitor.cc
@@ -134,13 +134,15 @@
}
int32_t Monitor::GetHashCode() {
- while (!HasHashCode()) {
- if (hash_code_.CompareAndSetWeakRelaxed(0, mirror::Object::GenerateIdentityHashCode())) {
- break;
- }
+ int32_t hc = hash_code_.load(std::memory_order_relaxed);
+ if (!HasHashCode()) {
+ // Use a strong CAS to prevent spurious failures since these can make the boot image
+ // non-deterministic.
+ hash_code_.CompareAndSetStrongRelaxed(0, mirror::Object::GenerateIdentityHashCode());
+ hc = hash_code_.load(std::memory_order_relaxed);
}
DCHECK(HasHashCode());
- return hash_code_.load(std::memory_order_relaxed);
+ return hc;
}
bool Monitor::Install(Thread* self) {
@@ -173,7 +175,7 @@
}
LockWord fat(this, lw.GCState());
// Publish the updated lock word, which may race with other threads.
- bool success = GetObject()->CasLockWordWeakRelease(lw, fat);
+ bool success = GetObject()->CasLockWord(lw, fat, CASMode::kWeak, std::memory_order_release);
// Lock profiling.
if (success && owner_ != nullptr && lock_profiling_threshold_ != 0) {
// Do not abort on dex pc errors. This can easily happen when we want to dump a stack trace on
@@ -1039,7 +1041,7 @@
case LockWord::kUnlocked: {
// No ordering required for preceding lockword read, since we retest.
LockWord thin_locked(LockWord::FromThinLockId(thread_id, 0, lock_word.GCState()));
- if (h_obj->CasLockWordWeakAcquire(lock_word, thin_locked)) {
+ if (h_obj->CasLockWord(lock_word, thin_locked, CASMode::kWeak, std::memory_order_acquire)) {
AtraceMonitorLock(self, h_obj.Get(), false /* is_wait */);
return h_obj.Get(); // Success!
}
@@ -1063,7 +1065,10 @@
return h_obj.Get(); // Success!
} else {
// Use CAS to preserve the read barrier state.
- if (h_obj->CasLockWordWeakRelaxed(lock_word, thin_locked)) {
+ if (h_obj->CasLockWord(lock_word,
+ thin_locked,
+ CASMode::kWeak,
+ std::memory_order_relaxed)) {
AtraceMonitorLock(self, h_obj.Get(), false /* is_wait */);
return h_obj.Get(); // Success!
}
@@ -1165,7 +1170,7 @@
return true;
} else {
// Use CAS to preserve the read barrier state.
- if (h_obj->CasLockWordWeakRelease(lock_word, new_lw)) {
+ if (h_obj->CasLockWord(lock_word, new_lw, CASMode::kWeak, std::memory_order_release)) {
AtraceMonitorUnlock();
// Success!
return true;
diff --git a/runtime/native/sun_misc_Unsafe.cc b/runtime/native/sun_misc_Unsafe.cc
index d41a195..0f474d3 100644
--- a/runtime/native/sun_misc_Unsafe.cc
+++ b/runtime/native/sun_misc_Unsafe.cc
@@ -41,9 +41,11 @@
ScopedFastNativeObjectAccess soa(env);
ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(javaObj);
// JNI must use non transactional mode.
- bool success = obj->CasFieldStrongSequentiallyConsistent32<false>(MemberOffset(offset),
- expectedValue,
- newValue);
+ bool success = obj->CasField32<false>(MemberOffset(offset),
+ expectedValue,
+ newValue,
+ CASMode::kStrong,
+ std::memory_order_seq_cst);
return success ? JNI_TRUE : JNI_FALSE;
}
diff --git a/runtime/native_stack_dump.cc b/runtime/native_stack_dump.cc
index b3a47c3..ce295aa 100644
--- a/runtime/native_stack_dump.cc
+++ b/runtime/native_stack_dump.cc
@@ -290,11 +290,6 @@
void* ucontext_ptr,
bool skip_frames) {
// Historical note: This was disabled when running under Valgrind (b/18119146).
- // TODO: Valgrind is no longer supported, but Address Sanitizer is:
- // check whether this test works with ASan.
- if (kRunningOnMemoryTool) {
- return;
- }
BacktraceMap* map = existing_map;
std::unique_ptr<BacktraceMap> tmp_map;
diff --git a/runtime/reflection.cc b/runtime/reflection.cc
index 6aeedd4..9e9c33c 100644
--- a/runtime/reflection.cc
+++ b/runtime/reflection.cc
@@ -138,7 +138,7 @@
}
void BuildArgArrayFromJValues(const ScopedObjectAccessAlreadyRunnable& soa,
- ObjPtr<mirror::Object> receiver, jvalue* args)
+ ObjPtr<mirror::Object> receiver, const jvalue* args)
REQUIRES_SHARED(Locks::mutator_lock_) {
// Set receiver if non-null (method is not static)
if (receiver != nullptr) {
@@ -492,7 +492,7 @@
}
JValue InvokeWithJValues(const ScopedObjectAccessAlreadyRunnable& soa, jobject obj, jmethodID mid,
- jvalue* args) {
+ const jvalue* args) {
// We want to make sure that the stack is not within a small distance from the
// protected region in case we are calling into a leaf function whose stack
// check has been elided.
@@ -523,7 +523,7 @@
}
JValue InvokeVirtualOrInterfaceWithJValues(const ScopedObjectAccessAlreadyRunnable& soa,
- jobject obj, jmethodID mid, jvalue* args) {
+ jobject obj, jmethodID mid, const jvalue* args) {
// We want to make sure that the stack is not within a small distance from the
// protected region in case we are calling into a leaf function whose stack
// check has been elided.
diff --git a/runtime/reflection.h b/runtime/reflection.h
index 4560a39..4391bcd 100644
--- a/runtime/reflection.h
+++ b/runtime/reflection.h
@@ -69,13 +69,13 @@
JValue InvokeWithJValues(const ScopedObjectAccessAlreadyRunnable& soa,
jobject obj,
jmethodID mid,
- jvalue* args)
+ const jvalue* args)
REQUIRES_SHARED(Locks::mutator_lock_);
JValue InvokeVirtualOrInterfaceWithJValues(const ScopedObjectAccessAlreadyRunnable& soa,
jobject obj,
jmethodID mid,
- jvalue* args)
+ const jvalue* args)
REQUIRES_SHARED(Locks::mutator_lock_);
JValue InvokeVirtualOrInterfaceWithVarArgs(const ScopedObjectAccessAlreadyRunnable& soa,
diff --git a/runtime/runtime_callbacks_test.cc b/runtime/runtime_callbacks_test.cc
index 54769f9..794ac19 100644
--- a/runtime/runtime_callbacks_test.cc
+++ b/runtime/runtime_callbacks_test.cc
@@ -339,9 +339,6 @@
};
TEST_F(RuntimeSigQuitCallbackRuntimeCallbacksTest, SigQuit) {
- // SigQuit induces a dump. ASan isn't happy with libunwind reading memory.
- TEST_DISABLED_FOR_MEMORY_TOOL();
-
// The runtime needs to be started for the signal handler.
Thread* self = Thread::Current();
diff --git a/runtime/subtype_check.h b/runtime/subtype_check.h
index 1fe62e8..aac547e 100644
--- a/runtime/subtype_check.h
+++ b/runtime/subtype_check.h
@@ -542,15 +542,17 @@
int32_t new_value)
REQUIRES_SHARED(Locks::mutator_lock_) {
if (Runtime::Current() != nullptr && Runtime::Current()->IsActiveTransaction()) {
- return klass->template
- CasFieldWeakSequentiallyConsistent32</*kTransactionActive*/true>(offset,
- old_value,
- new_value);
+ return klass->template CasField32</*kTransactionActive*/true>(offset,
+ old_value,
+ new_value,
+ CASMode::kWeak,
+ std::memory_order_seq_cst);
} else {
- return klass->template
- CasFieldWeakSequentiallyConsistent32</*kTransactionActive*/false>(offset,
- old_value,
- new_value);
+ return klass->template CasField32</*kTransactionActive*/false>(offset,
+ old_value,
+ new_value,
+ CASMode::kWeak,
+ std::memory_order_seq_cst);
}
}
diff --git a/runtime/subtype_check_test.cc b/runtime/subtype_check_test.cc
index e297d0b..979fa42 100644
--- a/runtime/subtype_check_test.cc
+++ b/runtime/subtype_check_test.cc
@@ -86,9 +86,11 @@
}
template <bool kTransactionActive>
- bool CasFieldWeakSequentiallyConsistent32(art::MemberOffset offset,
- int32_t old_value,
- int32_t new_value)
+ bool CasField32(art::MemberOffset offset,
+ int32_t old_value,
+ int32_t new_value,
+ CASMode mode ATTRIBUTE_UNUSED,
+ std::memory_order memory_order ATTRIBUTE_UNUSED)
REQUIRES_SHARED(Locks::mutator_lock_) {
UNUSED(offset);
if (old_value == GetField32Volatile(offset)) {
diff --git a/test/004-ReferenceMap/build b/test/004-ReferenceMap/build
index 08987b5..3bb63ca 100644
--- a/test/004-ReferenceMap/build
+++ b/test/004-ReferenceMap/build
@@ -21,6 +21,5 @@
# (see b/19467889)
mkdir classes
${JAVAC} -d classes `find src -name '*.java'`
-${DX} -JXmx256m --debug --dex --dump-to=classes.lst --output=classes.dex \
- --dump-width=1000 ${DX_FLAGS} classes
+${DX} -JXmx256m --debug --dex --output=classes.dex ${DX_FLAGS} classes
zip $TEST_NAME.jar classes.dex
diff --git a/test/004-StackWalk/build b/test/004-StackWalk/build
index 08987b5..3bb63ca 100644
--- a/test/004-StackWalk/build
+++ b/test/004-StackWalk/build
@@ -21,6 +21,5 @@
# (see b/19467889)
mkdir classes
${JAVAC} -d classes `find src -name '*.java'`
-${DX} -JXmx256m --debug --dex --dump-to=classes.lst --output=classes.dex \
- --dump-width=1000 ${DX_FLAGS} classes
+${DX} -JXmx256m --debug --dex --output=classes.dex ${DX_FLAGS} classes
zip $TEST_NAME.jar classes.dex
diff --git a/test/022-interface/build b/test/022-interface/build
index f6aad91..ab1c822 100644
--- a/test/022-interface/build
+++ b/test/022-interface/build
@@ -17,6 +17,6 @@
# Stop if something fails.
set -e
-${DX} --debug --dex --dump-to=classes.lst --output=classes.dex classes
+${DX} --debug --dex --output=classes.dex classes
zip $TEST_NAME.jar classes.dex
diff --git a/test/091-override-package-private-method/build b/test/091-override-package-private-method/build
index ea12b3a..e5fa669 100755
--- a/test/091-override-package-private-method/build
+++ b/test/091-override-package-private-method/build
@@ -24,8 +24,8 @@
mv classes/OverridePackagePrivateMethodSuper.class classes-ex
if [ ${NEED_DEX} = "true" ]; then
- ${DX} -JXmx256m --debug --dex --dump-to=classes.lst --output=classes.dex --dump-width=1000 classes
+ ${DX} -JXmx256m --debug --dex --output=classes.dex classes
zip $TEST_NAME.jar classes.dex
- ${DX} -JXmx256m --debug --dex --dump-to=classes-ex.lst --output=classes.dex --dump-width=1000 classes-ex
+ ${DX} -JXmx256m --debug --dex --output=classes.dex classes-ex
zip ${TEST_NAME}-ex.jar classes.dex
fi
diff --git a/test/111-unresolvable-exception/build b/test/111-unresolvable-exception/build
index 6fe73af..f24c5b2 100644
--- a/test/111-unresolvable-exception/build
+++ b/test/111-unresolvable-exception/build
@@ -22,6 +22,6 @@
rm classes/TestException.class
if [ ${NEED_DEX} = "true" ]; then
- ${DX} -JXmx256m --debug --dex --dump-to=classes.lst --output=classes.dex classes
+ ${DX} -JXmx256m --debug --dex --output=classes.dex classes
zip $TEST_NAME.jar classes.dex
fi
diff --git a/test/113-multidex/build b/test/113-multidex/build
index f945563..4ad7cb9 100644
--- a/test/113-multidex/build
+++ b/test/113-multidex/build
@@ -29,9 +29,9 @@
if [ ${NEED_DEX} = "true" ]; then
# All except Main
- ${DX} -JXmx256m --debug --dex --dump-to=classes.lst --output=classes.dex classes
+ ${DX} -JXmx256m --debug --dex --output=classes.dex classes
# Only Main
- ${DX} -JXmx256m --debug --dex --dump-to=classes2.lst --output=classes2.dex classes2
+ ${DX} -JXmx256m --debug --dex --output=classes2.dex classes2
zip $TEST_NAME.jar classes.dex classes2.dex
fi
diff --git a/test/126-miranda-multidex/build b/test/126-miranda-multidex/build
index cf19855..b4bb88d 100644
--- a/test/126-miranda-multidex/build
+++ b/test/126-miranda-multidex/build
@@ -29,9 +29,9 @@
if [ ${NEED_DEX} = "true" ]; then
# All except Main
- ${DX} -JXmx256m --debug --dex --dump-to=classes.lst --output=classes.dex classes
+ ${DX} -JXmx256m --debug --dex --output=classes.dex classes
# Only Main
- ${DX} -JXmx256m --debug --dex --dump-to=classes2.lst --output=classes2.dex classes2
+ ${DX} -JXmx256m --debug --dex --output=classes2.dex classes2
zip $TEST_NAME.jar classes.dex classes2.dex
fi
diff --git a/test/127-checker-secondarydex/build b/test/127-checker-secondarydex/build
index 712774f..c23b761 100755
--- a/test/127-checker-secondarydex/build
+++ b/test/127-checker-secondarydex/build
@@ -24,8 +24,8 @@
mv classes/Super.class classes-ex
if [ ${NEED_DEX} = "true" ]; then
- ${DX} -JXmx256m --debug --dex --dump-to=classes.lst --output=classes.dex --dump-width=1000 classes
+ ${DX} -JXmx256m --debug --dex --output=classes.dex classes
zip $TEST_NAME.jar classes.dex
- ${DX} -JXmx256m --debug --dex --dump-to=classes-ex.lst --output=classes.dex --dump-width=1000 classes-ex
+ ${DX} -JXmx256m --debug --dex --output=classes.dex classes-ex
zip ${TEST_NAME}-ex.jar classes.dex
fi
diff --git a/test/137-cfi/cfi.cc b/test/137-cfi/cfi.cc
index a91d348..985d273 100644
--- a/test/137-cfi/cfi.cc
+++ b/test/137-cfi/cfi.cc
@@ -54,15 +54,38 @@
#endif
}
-extern "C" JNIEXPORT jboolean JNICALL Java_Main_sleep(JNIEnv*, jobject, jint, jboolean, jdouble) {
- // Keep pausing.
- struct timespec ts = { .tv_sec = 100, .tv_nsec = 0 };
- printf("Going to sleep\n");
- for (;;) {
- // Use nanosleep since it gets to the system call quickly and doesn't
- // have any points at which an unwind will fail.
- nanosleep(&ts, nullptr);
+extern "C" JNIEXPORT jint JNICALL Java_Main_startSecondaryProcess(JNIEnv*, jclass) {
+#if __linux__
+ // Get our command line so that we can use it to start identical process.
+ std::string cmdline; // null-separated and null-terminated arguments.
+ ReadFileToString("/proc/self/cmdline", &cmdline);
+ cmdline = cmdline + "--secondary" + '\0'; // Let the child know it is a helper.
+
+ // Split the string into individual arguments suitable for execv.
+ std::vector<char*> argv;
+ for (size_t i = 0; i < cmdline.size(); i += strlen(&cmdline[i]) + 1) {
+ argv.push_back(&cmdline[i]);
}
+ argv.push_back(nullptr); // Terminate the list.
+
+ pid_t pid = fork();
+ if (pid < 0) {
+ LOG(FATAL) << "Fork failed";
+ } else if (pid == 0) {
+ execv(argv[0], argv.data());
+ exit(1);
+ }
+ return pid;
+#else
+ return 0;
+#endif
+}
+
+extern "C" JNIEXPORT jboolean JNICALL Java_Main_sigstop(JNIEnv*, jclass) {
+#if __linux__
+ raise(SIGSTOP);
+#endif
+ return true; // Prevent the compiler from tail-call optimizing this method away.
}
// Helper to look for a sequence in the stack trace.
@@ -107,12 +130,7 @@
}
#endif
-extern "C" JNIEXPORT jboolean JNICALL Java_Main_unwindInProcess(
- JNIEnv*,
- jobject,
- jboolean,
- jint,
- jboolean) {
+extern "C" JNIEXPORT jboolean JNICALL Java_Main_unwindInProcess(JNIEnv*, jclass) {
#if __linux__
std::unique_ptr<Backtrace> bt(Backtrace::Create(BACKTRACE_CURRENT_PROCESS, GetTid()));
if (!bt->Unwind(0, nullptr)) {
@@ -128,10 +146,10 @@
// only unique functions are being expected.
// "mini-debug-info" does not include parameters to save space.
std::vector<std::string> seq = {
- "Java_Main_unwindInProcess", // This function.
- "java.util.Arrays.binarySearch0", // Framework method.
- "Base.runBase", // Method in other dex file.
- "Main.main" // The Java entry method.
+ "Java_Main_unwindInProcess", // This function.
+ "java.util.Arrays.binarySearch0", // Framework method.
+ "Base.runTest", // Method in other dex file.
+ "Main.main" // The Java entry method.
};
bool result = CheckStack(bt.get(), seq);
@@ -150,8 +168,8 @@
}
#if __linux__
-static constexpr int kSleepTimeMicroseconds = 50000; // 0.05 seconds
-static constexpr int kMaxTotalSleepTimeMicroseconds = 1000000; // 1 second
+static constexpr int kSleepTimeMicroseconds = 50000; // 0.05 seconds
+static constexpr int kMaxTotalSleepTimeMicroseconds = 10000000; // 10 seconds
// Wait for a sigstop. This code is copied from libbacktrace.
int wait_for_sigstop(pid_t tid, int* total_sleep_time_usec, bool* detach_failed ATTRIBUTE_UNUSED) {
@@ -183,17 +201,12 @@
}
#endif
-extern "C" JNIEXPORT jboolean JNICALL Java_Main_unwindOtherProcess(
- JNIEnv*,
- jobject,
- jboolean,
- jint pid_int) {
+extern "C" JNIEXPORT jboolean JNICALL Java_Main_unwindOtherProcess(JNIEnv*, jclass, jint pid_int) {
#if __linux__
pid_t pid = static_cast<pid_t>(pid_int);
- // OK, this is painful. debuggerd uses ptrace to unwind other processes.
-
- if (ptrace(PTRACE_ATTACH, pid, 0, 0)) {
+ // SEIZE is like ATTACH, but it does not stop the process (we let it stop itself).
+ if (ptrace(PTRACE_SEIZE, pid, 0, 0)) {
// Were not able to attach, bad.
printf("Failed to attach to other process.\n");
PLOG(ERROR) << "Failed to attach.";
@@ -201,13 +214,12 @@
return JNI_FALSE;
}
- kill(pid, SIGSTOP);
-
bool detach_failed = false;
int total_sleep_time_usec = 0;
int signal = wait_for_sigstop(pid, &total_sleep_time_usec, &detach_failed);
- if (signal == -1) {
+ if (signal != SIGSTOP) {
LOG(WARNING) << "wait_for_sigstop failed.";
+ return JNI_FALSE;
}
std::unique_ptr<Backtrace> bt(Backtrace::Create(pid, BACKTRACE_CURRENT_THREAD));
@@ -224,10 +236,10 @@
// See comment in unwindInProcess for non-exact stack matching.
// "mini-debug-info" does not include parameters to save space.
std::vector<std::string> seq = {
- "Java_Main_sleep", // The sleep function in the other process.
- "java.util.Arrays.binarySearch0", // Framework method.
- "Base.runBase", // Method in other dex file.
- "Main.main" // The Java entry method.
+ "Java_Main_sigstop", // The stop function in the other process.
+ "java.util.Arrays.binarySearch0", // Framework method.
+ "Base.runTest", // Method in other dex file.
+ "Main.main" // The Java entry method.
};
result = CheckStack(bt.get(), seq);
diff --git a/test/137-cfi/expected.txt b/test/137-cfi/expected.txt
index 8db7853..eedae8f 100644
--- a/test/137-cfi/expected.txt
+++ b/test/137-cfi/expected.txt
@@ -1,2 +1,7 @@
JNI_OnLoad called
+Unwind in process: PASS
JNI_OnLoad called
+Unwind other process: PASS
+JNI_OnLoad called
+JNI_OnLoad called
+Unwind other process: PASS
diff --git a/test/137-cfi/run b/test/137-cfi/run
index 9190b1c..4096b89 100755
--- a/test/137-cfi/run
+++ b/test/137-cfi/run
@@ -20,7 +20,7 @@
# there will be JITed frames on the callstack (it synchronously JITs on first use).
${RUN} "$@" -Xcompiler-option --generate-debug-info \
--runtime-option -Xjitthreshold:0 \
- --args --full-signatures --args --test-local --args --test-remote
+ --args --test-local --args --test-remote
return_status1=$?
# Test with minimal compressed debugging information.
diff --git a/test/137-cfi/src-multidex/Base.java b/test/137-cfi/src-multidex/Base.java
index d3f8a56..986a3c2 100644
--- a/test/137-cfi/src-multidex/Base.java
+++ b/test/137-cfi/src-multidex/Base.java
@@ -15,8 +15,12 @@
*/
public abstract class Base {
- abstract public void runImpl();
- public void runBase() {
- runImpl();
+ public void runTest() throws Exception {
+ // Conditionally throw exception to prevent the compiler from inlining the code.
+ if (!this.getClass().getName().equals("Main")) {
+ throw new Exception("Who is calling?");
+ }
+ test();
}
+ abstract public void test();
}
diff --git a/test/137-cfi/src/Main.java b/test/137-cfi/src/Main.java
index 9a2e352..5b32d8e 100644
--- a/test/137-cfi/src/Main.java
+++ b/test/137-cfi/src/Main.java
@@ -22,181 +22,68 @@
public class Main extends Base implements Comparator<Main> {
// Whether to test local unwinding.
- private boolean testLocal;
+ private static boolean testLocal;
// Unwinding another process, modelling debuggerd.
- private boolean testRemote;
+ private static boolean testRemote;
// We fork ourself to create the secondary process for remote unwinding.
- private boolean secondary;
-
- // Expect the symbols to contain full method signatures including parameters.
- private boolean fullSignatures;
-
- private boolean passed;
-
- public Main(String[] args) throws Exception {
- System.loadLibrary(args[0]);
- for (String arg : args) {
- if (arg.equals("--test-local")) {
- testLocal = true;
- }
- if (arg.equals("--test-remote")) {
- testRemote = true;
- }
- if (arg.equals("--secondary")) {
- secondary = true;
- }
- if (arg.equals("--full-signatures")) {
- fullSignatures = true;
- }
- }
- if (!testLocal && !testRemote) {
- System.out.println("No test selected.");
- }
- }
+ private static boolean secondary;
public static void main(String[] args) throws Exception {
- new Main(args).runBase();
- }
-
- public void runImpl() {
- if (secondary) {
- if (!testRemote) {
- throw new RuntimeException("Should not be running secondary!");
+ System.loadLibrary(args[0]);
+ for (int i = 1; i < args.length; i++) {
+ if (args[i].equals("--test-local")) {
+ testLocal = true;
+ } else if (args[i].equals("--test-remote")) {
+ testRemote = true;
+ } else if (args[i].equals("--secondary")) {
+ secondary = true;
+ } else {
+ System.out.println("Unknown argument: " + args[i]);
+ System.exit(1);
}
- runSecondary();
- } else {
- runPrimary();
}
+
+ // Call test() via base class to test unwinding through multidex.
+ new Main().runTest();
}
- private void runSecondary() {
- foo();
- throw new RuntimeException("Didn't expect to get back...");
- }
-
- private void runPrimary() {
- // First do the in-process unwinding.
- if (testLocal && !foo()) {
- System.out.println("Unwinding self failed.");
- }
-
- if (!testRemote) {
- // Skip the remote step.
- return;
- }
-
- // Fork the secondary.
- String[] cmdline = getCmdLine();
- String[] secCmdLine = new String[cmdline.length + 1];
- System.arraycopy(cmdline, 0, secCmdLine, 0, cmdline.length);
- secCmdLine[secCmdLine.length - 1] = "--secondary";
- Process p = exec(secCmdLine);
-
- try {
- int pid = getPid(p);
- if (pid <= 0) {
- throw new RuntimeException("Couldn't parse process");
- }
-
- // Wait until the forked process had time to run until its sleep phase.
- BufferedReader lineReader;
- try {
- InputStreamReader stdout = new InputStreamReader(p.getInputStream(), "UTF-8");
- lineReader = new BufferedReader(stdout);
- while (!lineReader.readLine().contains("Going to sleep")) {
- }
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
-
- if (!unwindOtherProcess(fullSignatures, pid)) {
- System.out.println("Unwinding other process failed.");
-
- // In this case, log all the output.
- // Note: this is potentially non-terminating code, if the secondary is totally stuck.
- // We rely on the run-test timeout infrastructure to terminate the primary in
- // such a case.
- try {
- String tmp;
- System.out.println("Output from the secondary:");
- while ((tmp = lineReader.readLine()) != null) {
- System.out.println("Secondary: " + tmp);
- }
- } catch (Exception e) {
- e.printStackTrace(System.out);
- }
- }
-
- try {
- lineReader.close();
- } catch (Exception e) {
- e.printStackTrace(System.out);
- }
- } finally {
- // Kill the forked process if it is not already dead.
- p.destroy();
- }
- }
-
- private static Process exec(String[] args) {
- try {
- return Runtime.getRuntime().exec(args);
- } catch (Exception exc) {
- throw new RuntimeException(exc);
- }
- }
-
- private static int getPid(Process p) {
- // Could do reflection for the private pid field, but String parsing is easier.
- String s = p.toString();
- if (s.startsWith("Process[pid=")) {
- return Integer.parseInt(s.substring("Process[pid=".length(), s.indexOf(",")));
- } else {
- return -1;
- }
- }
-
- // Read /proc/self/cmdline to find the invocation command line (so we can fork another runtime).
- private static String[] getCmdLine() {
- try {
- BufferedReader in = new BufferedReader(new FileReader("/proc/self/cmdline"));
- String s = in.readLine();
- in.close();
- return s.split("\0");
- } catch (Exception exc) {
- throw new RuntimeException(exc);
- }
- }
-
- public boolean foo() {
- // Call bar via Arrays.binarySearch.
- // This tests that we can unwind from framework code.
+ public void test() {
+ // Call unwind() via Arrays.binarySearch to test unwinding through framework.
Main[] array = { this, this, this };
Arrays.binarySearch(array, 0, 3, this /* value */, this /* comparator */);
- return passed;
}
public int compare(Main lhs, Main rhs) {
- passed = bar(secondary);
+ unwind();
// Returning "equal" ensures that we terminate search
- // after first item and thus call bar() only once.
+ // after first item and thus call unwind() only once.
return 0;
}
- public boolean bar(boolean b) {
- if (b) {
- return sleep(2, b, 1.0);
- } else {
- return unwindInProcess(fullSignatures, 1, b);
+ public void unwind() {
+ if (secondary) {
+ sigstop(); // This is helper child process. Stop and wait for unwinding.
+ return; // Don't run the tests again in the secondary helper process.
+ }
+
+ if (testLocal) {
+ String result = unwindInProcess() ? "PASS" : "FAIL";
+ System.out.println("Unwind in process: " + result);
+ }
+
+ if (testRemote) {
+ // Start a secondary helper process. It will stop itself when it is ready.
+ int pid = startSecondaryProcess();
+ // Wait for the secondary process to stop and then unwind it remotely.
+ String result = unwindOtherProcess(pid) ? "PASS" : "FAIL";
+ System.out.println("Unwind other process: " + result);
}
}
- // Native functions. Note: to avoid deduping, they must all have different signatures.
-
- public native boolean sleep(int i, boolean b, double dummy);
-
- public native boolean unwindInProcess(boolean fullSignatures, int i, boolean b);
- public native boolean unwindOtherProcess(boolean fullSignatures, int pid);
+ public static native int startSecondaryProcess();
+ public static native boolean sigstop();
+ public static native boolean unwindInProcess();
+ public static native boolean unwindOtherProcess(int pid);
}
diff --git a/test/138-duplicate-classes-check2/build b/test/138-duplicate-classes-check2/build
index 76d535a..3ff15aa 100755
--- a/test/138-duplicate-classes-check2/build
+++ b/test/138-duplicate-classes-check2/build
@@ -25,8 +25,8 @@
rm classes-ex/A.class
if [ ${NEED_DEX} = "true" ]; then
- ${DX} -JXmx256m --debug --dex --dump-to=classes.lst --output=classes.dex --dump-width=1000 classes
+ ${DX} -JXmx256m --debug --dex --output=classes.dex classes
zip ${TEST_NAME}.jar classes.dex
- ${DX} -JXmx256m --debug --dex --dump-to=classes-ex.lst --output=classes.dex --dump-width=1000 classes-ex
+ ${DX} -JXmx256m --debug --dex --output=classes.dex classes-ex
zip ${TEST_NAME}-ex.jar classes.dex
fi
diff --git a/test/466-get-live-vreg/get_live_vreg_jni.cc b/test/466-get-live-vreg/get_live_vreg_jni.cc
index 44ea0c9..58ffe04 100644
--- a/test/466-get-live-vreg/get_live_vreg_jni.cc
+++ b/test/466-get-live-vreg/get_live_vreg_jni.cc
@@ -36,32 +36,46 @@
ArtMethod* m = GetMethod();
std::string m_name(m->GetName());
- if (m_name.compare("testLiveArgument") == 0) {
+ if (m_name.compare("$noinline$testLiveArgument") == 0) {
found_method_ = true;
- uint32_t value = 0;
- CHECK(GetVReg(m, 0, kIntVReg, &value));
- CHECK_EQ(value, 42u);
- } else if (m_name.compare("$opt$noinline$testIntervalHole") == 0) {
+ CHECK_EQ(CodeItemDataAccessor(m->DexInstructionData()).RegistersSize(), 3u);
+ CheckOptimizedOutRegLiveness(m, 1, kIntVReg, true, 42);
+
+ uint32_t value;
+ CHECK(GetVReg(m, 2, kReferenceVReg, &value));
+ } else if (m_name.compare("$noinline$testIntervalHole") == 0) {
+ found_method_ = true;
uint32_t number_of_dex_registers =
CodeItemDataAccessor(m->DexInstructionData()).RegistersSize();
uint32_t dex_register_of_first_parameter = number_of_dex_registers - 2;
+ CheckOptimizedOutRegLiveness(m, dex_register_of_first_parameter, kIntVReg, true, 1);
+ } else if (m_name.compare("$noinline$testCodeSinking") == 0) {
found_method_ = true;
- uint32_t value = 0;
- if (GetCurrentQuickFrame() != nullptr &&
- GetCurrentOatQuickMethodHeader()->IsOptimized() &&
- !Runtime::Current()->IsJavaDebuggable()) {
- CHECK_EQ(GetVReg(m, dex_register_of_first_parameter, kIntVReg, &value), false);
- } else {
- CHECK(GetVReg(m, dex_register_of_first_parameter, kIntVReg, &value));
- CHECK_EQ(value, 1u);
- }
+ CheckOptimizedOutRegLiveness(m, 0, kReferenceVReg);
}
return true;
}
- // Value returned to Java to ensure the methods testSimpleVReg and testPairVReg
- // have been found and tested.
+ void CheckOptimizedOutRegLiveness(ArtMethod* m,
+ uint32_t dex_reg,
+ VRegKind vreg_kind,
+ bool check_val = false,
+ uint32_t expected = 0) REQUIRES_SHARED(Locks::mutator_lock_) {
+ uint32_t value = 0;
+ if (GetCurrentQuickFrame() != nullptr &&
+ GetCurrentOatQuickMethodHeader()->IsOptimized() &&
+ !Runtime::Current()->IsJavaDebuggable()) {
+ CHECK_EQ(GetVReg(m, dex_reg, vreg_kind, &value), false);
+ } else {
+ CHECK(GetVReg(m, dex_reg, vreg_kind, &value));
+ if (check_val) {
+ CHECK_EQ(value, expected);
+ }
+ }
+ }
+
+ // Value returned to Java to ensure the required methods have been found and tested.
bool found_method_ = false;
};
diff --git a/test/466-get-live-vreg/src/Main.java b/test/466-get-live-vreg/src/Main.java
index 1903260..29a6901 100644
--- a/test/466-get-live-vreg/src/Main.java
+++ b/test/466-get-live-vreg/src/Main.java
@@ -18,9 +18,9 @@
public Main() {
}
- static int testLiveArgument(int arg) {
+ static int $noinline$testLiveArgument(int arg1, Integer arg2) {
doStaticNativeCallLiveVreg();
- return arg;
+ return arg1 + arg2.intValue();
}
static void moveArgToCalleeSave() {
@@ -31,7 +31,7 @@
}
}
- static void $opt$noinline$testIntervalHole(int arg, boolean test) {
+ static void $noinline$testIntervalHole(int arg, boolean test) {
// Move the argument to callee save to ensure it is in
// a readable register.
moveArgToCalleeSave();
@@ -53,16 +53,18 @@
public static void main(String[] args) {
System.loadLibrary(args[0]);
- if (testLiveArgument(staticField3) != staticField3) {
- throw new Error("Expected " + staticField3);
+ if ($noinline$testLiveArgument(staticField3, Integer.valueOf(1)) != staticField3 + 1) {
+ throw new Error("Expected " + staticField3 + 1);
}
- if (testLiveArgument(staticField3) != staticField3) {
- throw new Error("Expected " + staticField3);
+ if ($noinline$testLiveArgument(staticField3,Integer.valueOf(1)) != staticField3 + 1) {
+ throw new Error("Expected " + staticField3 + 1);
}
testWrapperIntervalHole(1, true);
testWrapperIntervalHole(1, false);
+
+ $noinline$testCodeSinking(1);
}
// Wrapper method to avoid inlining, which affects liveness
@@ -70,12 +72,25 @@
static void testWrapperIntervalHole(int arg, boolean test) {
try {
Thread.sleep(0);
- $opt$noinline$testIntervalHole(arg, test);
+ $noinline$testIntervalHole(arg, test);
} catch (Exception e) {
throw new Error(e);
}
}
+ // The value of dex register which originally holded "Object[] o = new Object[1];" will not be
+ // live at the call to doStaticNativeCallLiveVreg after code sinking optimizizaion.
+ static void $noinline$testCodeSinking(int x) {
+ Object[] o = new Object[1];
+ o[0] = o;
+ doStaticNativeCallLiveVreg();
+ if (doThrow) {
+ throw new Error(o.toString());
+ }
+ }
+
+ static boolean doThrow;
+
static int staticField1;
static int staticField2;
static int staticField3 = 42;
diff --git a/test/477-checker-bound-type/src/Main.java b/test/477-checker-bound-type/src/Main.java
index 2504ab2..237e4da 100644
--- a/test/477-checker-bound-type/src/Main.java
+++ b/test/477-checker-bound-type/src/Main.java
@@ -57,5 +57,79 @@
}
}
- public static void main(String[] args) { }
+ /// CHECK-START: void Main.boundTypeInLoop(int[]) licm (before)
+ /// CHECK-DAG: <<Param:l\d+>> ParameterValue loop:none
+ /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<BoundT:l\d+>> BoundType [<<Param>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: ArrayLength [<<BoundT>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: ArrayGet loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
+
+ /// CHECK-START: void Main.boundTypeInLoop(int[]) licm (after)
+ /// CHECK-DAG: <<Param:l\d+>> ParameterValue loop:none
+ /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<BoundT:l\d+>> BoundType [<<Param>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: ArrayLength [<<BoundT>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: ArrayGet loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-NOT: BoundType
+
+ /// CHECK-START: void Main.boundTypeInLoop(int[]) loop_optimization (after)
+ /// CHECK-DAG: <<Param:l\d+>> ParameterValue loop:none
+ /// CHECK-DAG: <<BoundTA:l\d+>> BoundType [<<Param>>] loop:none
+ /// CHECK-DAG: ArrayLength [<<BoundTA>>] loop:none
+ /// CHECK-DAG: ArrayGet loop:none
+ /// CHECK-DAG: ArraySet loop:none
+ /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<BoundT:l\d+>> BoundType [<<Param>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: ArrayLength [<<BoundT>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: ArrayGet loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
+
+ /// CHECK-START: void Main.boundTypeInLoop(int[]) GVN$after_arch (after)
+ /// CHECK-DAG: <<Param:l\d+>> ParameterValue loop:none
+ /// CHECK-DAG: <<BoundTA:l\d+>> BoundType [<<Param>>] loop:none
+ /// CHECK-DAG: ArrayLength [<<BoundTA>>] loop:none
+ /// CHECK-DAG: ArrayGet loop:none
+ /// CHECK-DAG: ArraySet loop:none
+ /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: ArrayGet loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-NOT: BoundType
+ /// CHECK-NOT: ArrayLength
+ private static void boundTypeInLoop(int[] a) {
+ for (int i = 0; a != null && i < a.length; i++) {
+ a[i] += 1;
+ }
+ }
+
+ // BoundType must not be hoisted by LICM, in this example it leads to ArrayLength being
+ // hoisted as well which is invalid.
+ //
+ /// CHECK-START: void Main.BoundTypeNoLICM(java.lang.Object) licm (before)
+ /// CHECK-DAG: <<Param:l\d+>> ParameterValue loop:none
+ /// CHECK-DAG: SuspendCheck loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Bound1:l\d+>> BoundType [<<Param>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Bound2:l\d+>> BoundType [<<Bound1>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: ArrayLength [<<Bound2>>] loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START: void Main.BoundTypeNoLICM(java.lang.Object) licm (after)
+ /// CHECK-DAG: <<Param:l\d+>> ParameterValue loop:none
+ /// CHECK-DAG: SuspendCheck loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Bound1:l\d+>> BoundType [<<Param>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Bound2:l\d+>> BoundType [<<Bound1>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: ArrayLength [<<Bound2>>] loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-NOT: BoundType loop:none
+ private static void BoundTypeNoLICM(Object obj) {
+ int i = 0;
+ while (obj instanceof int[]) {
+ int[] a = (int[])obj;
+ a[0] = 1;
+ }
+ }
+
+ public static void main(String[] args) { }
}
diff --git a/test/530-checker-lse2/build b/test/530-checker-lse2/build
deleted file mode 100644
index d85147f..0000000
--- a/test/530-checker-lse2/build
+++ /dev/null
@@ -1,20 +0,0 @@
-#!/bin/bash
-#
-# Copyright 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# See b/65168732
-export USE_D8=false
-
-./default-build "$@"
diff --git a/test/565-checker-condition-liveness/info.txt b/test/565-checker-condition-liveness/info.txt
index 67b6ceb..e716c04 100644
--- a/test/565-checker-condition-liveness/info.txt
+++ b/test/565-checker-condition-liveness/info.txt
Binary files differ
diff --git a/test/565-checker-condition-liveness/src/Main.java b/test/565-checker-condition-liveness/src/Main.java
index acfcecd..6b6619f 100644
--- a/test/565-checker-condition-liveness/src/Main.java
+++ b/test/565-checker-condition-liveness/src/Main.java
@@ -31,6 +31,82 @@
return (arg > 5.0f) ? 0 : -1;
}
+ /// CHECK-START: void Main.testThrowIntoCatchBlock(int, java.lang.Object, int[]) liveness (after)
+ /// CHECK-DAG: <<IntArg:i\d+>> ParameterValue env_uses:[21,25]
+ /// CHECK-DAG: <<RefArg:l\d+>> ParameterValue env_uses:[11,21,25]
+ /// CHECK-DAG: <<Array:l\d+>> ParameterValue env_uses:[11,21,25]
+ /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 env_uses:[21,25]
+ /// CHECK-DAG: SuspendCheck env:[[_,<<IntArg>>,<<RefArg>>,<<Array>>]] liveness:10
+ /// CHECK-DAG: NullCheck env:[[<<Const1>>,<<IntArg>>,<<RefArg>>,<<Array>>]] liveness:20
+ /// CHECK-DAG: BoundsCheck env:[[<<Const1>>,<<IntArg>>,<<RefArg>>,<<Array>>]] liveness:24
+ /// CHECK-DAG: TryBoundary
+
+ /// CHECK-START-DEBUGGABLE: void Main.testThrowIntoCatchBlock(int, java.lang.Object, int[]) liveness (after)
+ /// CHECK-DAG: <<IntArg:i\d+>> ParameterValue env_uses:[11,21,25]
+ /// CHECK-DAG: <<RefArg:l\d+>> ParameterValue env_uses:[11,21,25]
+ /// CHECK-DAG: <<Array:l\d+>> ParameterValue env_uses:[11,21,25]
+ /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 env_uses:[21,25]
+ /// CHECK-DAG: SuspendCheck env:[[_,<<IntArg>>,<<RefArg>>,<<Array>>]] liveness:10
+ /// CHECK-DAG: NullCheck env:[[<<Const1>>,<<IntArg>>,<<RefArg>>,<<Array>>]] liveness:20
+ /// CHECK-DAG: BoundsCheck env:[[<<Const1>>,<<IntArg>>,<<RefArg>>,<<Array>>]] liveness:24
+ /// CHECK-DAG: TryBoundary
+ //
+ // A value live at a throwing instruction in a try block may be copied by
+ // the exception handler to its location at the top of the catch block.
+ public static void testThrowIntoCatchBlock(int x, Object y, int[] a) {
+ try {
+ a[1] = x;
+ } catch (ArrayIndexOutOfBoundsException exception) {
+ }
+ }
+
+ /// CHECK-START: void Main.testBoundsCheck(int, java.lang.Object, int[]) liveness (after)
+ /// CHECK-DAG: <<IntArg:i\d+>> ParameterValue env_uses:[]
+ /// CHECK-DAG: <<RefArg:l\d+>> ParameterValue env_uses:[11,17,21]
+ /// CHECK-DAG: <<Array:l\d+>> ParameterValue env_uses:[11,17,21]
+ /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 env_uses:[]
+ /// CHECK-DAG: SuspendCheck env:[[_,<<IntArg>>,<<RefArg>>,<<Array>>]] liveness:10
+ /// CHECK-DAG: NullCheck env:[[<<Const1>>,<<IntArg>>,<<RefArg>>,<<Array>>]] liveness:16
+ /// CHECK-DAG: BoundsCheck env:[[<<Const1>>,<<IntArg>>,<<RefArg>>,<<Array>>]] liveness:20
+
+ /// CHECK-START-DEBUGGABLE: void Main.testBoundsCheck(int, java.lang.Object, int[]) liveness (after)
+ /// CHECK-DAG: <<IntArg:i\d+>> ParameterValue env_uses:[11,17,21]
+ /// CHECK-DAG: <<RefArg:l\d+>> ParameterValue env_uses:[11,17,21]
+ /// CHECK-DAG: <<Array:l\d+>> ParameterValue env_uses:[11,17,21]
+ /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 env_uses:[17,21]
+ /// CHECK-DAG: SuspendCheck env:[[_,<<IntArg>>,<<RefArg>>,<<Array>>]] liveness:10
+ /// CHECK-DAG: NullCheck env:[[<<Const1>>,<<IntArg>>,<<RefArg>>,<<Array>>]] liveness:16
+ /// CHECK-DAG: BoundsCheck env:[[<<Const1>>,<<IntArg>>,<<RefArg>>,<<Array>>]] liveness:20
+ public static void testBoundsCheck(int x, Object y, int[] a) {
+ a[1] = x;
+ }
+
+ /// CHECK-START: void Main.testDeoptimize(int, java.lang.Object, int[]) liveness (after)
+ /// CHECK-DAG: <<IntArg:i\d+>> ParameterValue env_uses:[25]
+ /// CHECK-DAG: <<RefArg:l\d+>> ParameterValue env_uses:[13,19,25]
+ /// CHECK-DAG: <<Array:l\d+>> ParameterValue env_uses:[13,19,25]
+ /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0 env_uses:[25]
+ /// CHECK-DAG: SuspendCheck env:[[_,<<IntArg>>,<<RefArg>>,<<Array>>]] liveness:12
+ /// CHECK-DAG: NullCheck env:[[<<Const0>>,<<IntArg>>,<<RefArg>>,<<Array>>]] liveness:18
+ /// CHECK-DAG: Deoptimize env:[[<<Const0>>,<<IntArg>>,<<RefArg>>,<<Array>>]] liveness:24
+
+ /// CHECK-START-DEBUGGABLE: void Main.testDeoptimize(int, java.lang.Object, int[]) liveness (after)
+ /// CHECK-DAG: <<IntArg:i\d+>> ParameterValue env_uses:[13,19,25]
+ /// CHECK-DAG: <<RefArg:l\d+>> ParameterValue env_uses:[13,19,25]
+ /// CHECK-DAG: <<Array:l\d+>> ParameterValue env_uses:[13,19,25]
+ /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0 env_uses:[19,25]
+ /// CHECK-DAG: SuspendCheck env:[[_,<<IntArg>>,<<RefArg>>,<<Array>>]] liveness:12
+ /// CHECK-DAG: NullCheck env:[[<<Const0>>,<<IntArg>>,<<RefArg>>,<<Array>>]] liveness:18
+ /// CHECK-DAG: Deoptimize env:[[<<Const0>>,<<IntArg>>,<<RefArg>>,<<Array>>]] liveness:24
+ //
+ // A value that's not live in compiled code may still be needed in interpreter,
+ // due to code motion, etc.
+ public static void testDeoptimize(int x, Object y, int[] a) {
+ a[0] = x;
+ a[1] = x;
+ }
+
+
/// CHECK-START: void Main.main(java.lang.String[]) liveness (after)
/// CHECK: <<X:i\d+>> ArrayLength uses:[<<UseInput:\d+>>]
/// CHECK: <<Y:i\d+>> StaticFieldGet uses:[<<UseInput>>]
@@ -44,7 +120,15 @@
if (x > y) {
System.nanoTime();
}
+
+ int val = 14;
+ int[] array = new int[2];
+ Integer intObj = Integer.valueOf(0);
+ testThrowIntoCatchBlock(val, intObj, array);
+ testBoundsCheck(val, intObj, array);
+ testDeoptimize(val, intObj, array);
}
+
public static int field = 42;
}
diff --git a/test/565-checker-rotate/build b/test/565-checker-rotate/build
deleted file mode 100644
index 10ffcc5..0000000
--- a/test/565-checker-rotate/build
+++ /dev/null
@@ -1,20 +0,0 @@
-#!/bin/bash
-#
-# Copyright 2017 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# See b/65168732
-export USE_D8=false
-
-./default-build "$@"
diff --git a/test/565-checker-rotate/smali/Main2.smali b/test/565-checker-rotate/smali/Main2.smali
new file mode 100644
index 0000000..ca5027e
--- /dev/null
+++ b/test/565-checker-rotate/smali/Main2.smali
@@ -0,0 +1,165 @@
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+.class public LMain2;
+.super Ljava/lang/Object;
+
+## CHECK-START: int Main2.rotateLeftBoolean(boolean, int) intrinsics_recognition (after)
+## CHECK-DAG: <<Method:[ij]\d+>> CurrentMethod
+## CHECK: <<ArgVal:z\d+>> ParameterValue
+## CHECK: <<ArgDist:i\d+>> ParameterValue
+## CHECK-DAG: <<Zero:i\d+>> IntConstant 0
+## CHECK-DAG: <<One:i\d+>> IntConstant 1
+## CHECK-DAG: <<Val:i\d+>> Phi [<<One>>,<<Zero>>]
+## CHECK-DAG: <<Result:i\d+>> InvokeStaticOrDirect [<<Val>>,<<ArgDist>>,<<Method>>] intrinsic:IntegerRotateLeft
+## CHECK-DAG: Return [<<Result>>]
+
+## CHECK-START: int Main2.rotateLeftBoolean(boolean, int) instruction_simplifier (after)
+## CHECK: <<ArgVal:z\d+>> ParameterValue
+## CHECK: <<ArgDist:i\d+>> ParameterValue
+## CHECK-DAG: <<Zero:i\d+>> IntConstant 0
+## CHECK-DAG: <<One:i\d+>> IntConstant 1
+## CHECK-DAG: <<Val:i\d+>> Phi [<<One>>,<<Zero>>]
+## CHECK-DAG: <<NegDist:i\d+>> Neg [<<ArgDist>>]
+## CHECK-DAG: <<Result:i\d+>> Ror [<<Val>>,<<NegDist>>]
+## CHECK-DAG: Return [<<Result>>]
+
+## CHECK-START: int Main2.rotateLeftBoolean(boolean, int) instruction_simplifier (after)
+## CHECK-NOT: InvokeStaticOrDirect
+
+## CHECK-START: int Main2.rotateLeftBoolean(boolean, int) select_generator (after)
+## CHECK: <<ArgVal:z\d+>> ParameterValue
+## CHECK: <<ArgDist:i\d+>> ParameterValue
+## CHECK-DAG: <<Zero:i\d+>> IntConstant 0
+## CHECK-DAG: <<One:i\d+>> IntConstant 1
+## CHECK-DAG: <<SelVal:i\d+>> Select [<<Zero>>,<<One>>,<<ArgVal>>]
+## CHECK-DAG: <<NegDist:i\d+>> Neg [<<ArgDist>>]
+## CHECK-DAG: <<Result:i\d+>> Ror [<<SelVal>>,<<NegDist>>]
+## CHECK-DAG: Return [<<Result>>]
+
+## CHECK-START: int Main2.rotateLeftBoolean(boolean, int) select_generator (after)
+## CHECK-NOT: Phi
+
+## CHECK-START: int Main2.rotateLeftBoolean(boolean, int) instruction_simplifier$after_bce (after)
+## CHECK: <<ArgVal:z\d+>> ParameterValue
+## CHECK: <<ArgDist:i\d+>> ParameterValue
+## CHECK-DAG: <<NegDist:i\d+>> Neg [<<ArgDist>>]
+## CHECK-DAG: <<Result:i\d+>> Ror [<<ArgVal>>,<<NegDist>>]
+## CHECK-DAG: Return [<<Result>>]
+
+## CHECK-START: int Main2.rotateLeftBoolean(boolean, int) instruction_simplifier$after_bce (after)
+## CHECK-NOT: Select
+
+# Original java source
+#
+# private static int rotateLeftBoolean(boolean value, int distance) {
+# return Integer.rotateLeft(value ? 1 : 0, distance);
+# }
+
+.method public static rotateLeftBoolean(ZI)I
+ .registers 3
+ .param p0, "value" # Z
+ .param p1, "distance" # I
+
+ .prologue
+ .line 66
+ if-eqz p0, :cond_8
+
+ const/4 v0, 0x1
+
+ :goto_3
+ invoke-static {v0, p1}, Ljava/lang/Integer;->rotateLeft(II)I
+
+ move-result v0
+
+ return v0
+
+ :cond_8
+ const/4 v0, 0x0
+
+ goto :goto_3
+.end method
+
+## CHECK-START: int Main2.rotateRightBoolean(boolean, int) intrinsics_recognition (after)
+## CHECK-DAG: <<Method:[ij]\d+>> CurrentMethod
+## CHECK: <<ArgVal:z\d+>> ParameterValue
+## CHECK: <<ArgDist:i\d+>> ParameterValue
+## CHECK-DAG: <<Zero:i\d+>> IntConstant 0
+## CHECK-DAG: <<One:i\d+>> IntConstant 1
+## CHECK-DAG: <<Val:i\d+>> Phi [<<One>>,<<Zero>>]
+## CHECK-DAG: <<Result:i\d+>> InvokeStaticOrDirect [<<Val>>,<<ArgDist>>,<<Method>>] intrinsic:IntegerRotateRight
+## CHECK-DAG: Return [<<Result>>]
+
+## CHECK-START: int Main2.rotateRightBoolean(boolean, int) instruction_simplifier (after)
+## CHECK: <<ArgVal:z\d+>> ParameterValue
+## CHECK: <<ArgDist:i\d+>> ParameterValue
+## CHECK-DAG: <<Zero:i\d+>> IntConstant 0
+## CHECK-DAG: <<One:i\d+>> IntConstant 1
+## CHECK-DAG: <<Val:i\d+>> Phi [<<One>>,<<Zero>>]
+## CHECK-DAG: <<Result:i\d+>> Ror [<<Val>>,<<ArgDist>>]
+## CHECK-DAG: Return [<<Result>>]
+
+## CHECK-START: int Main2.rotateRightBoolean(boolean, int) instruction_simplifier (after)
+## CHECK-NOT: InvokeStaticOrDirect
+
+## CHECK-START: int Main2.rotateRightBoolean(boolean, int) select_generator (after)
+## CHECK: <<ArgVal:z\d+>> ParameterValue
+## CHECK: <<ArgDist:i\d+>> ParameterValue
+## CHECK-DAG: <<Zero:i\d+>> IntConstant 0
+## CHECK-DAG: <<One:i\d+>> IntConstant 1
+## CHECK-DAG: <<SelVal:i\d+>> Select [<<Zero>>,<<One>>,<<ArgVal>>]
+## CHECK-DAG: <<Result:i\d+>> Ror [<<SelVal>>,<<ArgDist>>]
+## CHECK-DAG: Return [<<Result>>]
+
+## CHECK-START: int Main2.rotateRightBoolean(boolean, int) select_generator (after)
+## CHECK-NOT: Phi
+
+## CHECK-START: int Main2.rotateRightBoolean(boolean, int) instruction_simplifier$after_bce (after)
+## CHECK: <<ArgVal:z\d+>> ParameterValue
+## CHECK: <<ArgDist:i\d+>> ParameterValue
+## CHECK-DAG: <<Result:i\d+>> Ror [<<ArgVal>>,<<ArgDist>>]
+## CHECK-DAG: Return [<<Result>>]
+
+## CHECK-START: int Main2.rotateRightBoolean(boolean, int) instruction_simplifier$after_bce (after)
+## CHECK-NOT: Select
+
+# Original java source:
+#
+# private static int rotateRightBoolean(boolean value, int distance) {
+# return Integer.rotateRight(value ? 1 : 0, distance);
+# }
+
+.method public static rotateRightBoolean(ZI)I
+ .registers 3
+ .param p0, "value" # Z
+ .param p1, "distance" # I
+
+ .prologue
+ .line 219
+ if-eqz p0, :cond_8
+
+ const/4 v0, 0x1
+
+ :goto_3
+ invoke-static {v0, p1}, Ljava/lang/Integer;->rotateRight(II)I
+
+ move-result v0
+
+ return v0
+
+ :cond_8
+ const/4 v0, 0x0
+
+ goto :goto_3
+.end method
diff --git a/test/565-checker-rotate/src-art/Main.java b/test/565-checker-rotate/src-art/Main.java
new file mode 100644
index 0000000..b9e1315
--- /dev/null
+++ b/test/565-checker-rotate/src-art/Main.java
@@ -0,0 +1,546 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.lang.reflect.Method;
+
+public class Main {
+
+ private static Class main2;
+
+ /// CHECK-START: int Main.rotateLeftByte(byte, int) intrinsics_recognition (after)
+ /// CHECK-DAG: <<Method:[ij]\d+>> CurrentMethod
+ /// CHECK: <<ArgVal:b\d+>> ParameterValue
+ /// CHECK: <<ArgDist:i\d+>> ParameterValue
+ /// CHECK-DAG: <<Result:i\d+>> InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>,<<Method>>] intrinsic:IntegerRotateLeft
+ /// CHECK-DAG: Return [<<Result>>]
+
+ /// CHECK-START: int Main.rotateLeftByte(byte, int) instruction_simplifier (after)
+ /// CHECK: <<ArgVal:b\d+>> ParameterValue
+ /// CHECK: <<ArgDist:i\d+>> ParameterValue
+ /// CHECK-DAG: <<NegDist:i\d+>> Neg [<<ArgDist>>]
+ /// CHECK-DAG: <<Result:i\d+>> Ror [<<ArgVal>>,<<NegDist>>]
+ /// CHECK-DAG: Return [<<Result>>]
+
+ /// CHECK-START: int Main.rotateLeftByte(byte, int) instruction_simplifier (after)
+ /// CHECK-NOT: InvokeStaticOrDirect
+
+ private static int rotateLeftByte(byte value, int distance) {
+ return Integer.rotateLeft(value, distance);
+ }
+
+ /// CHECK-START: int Main.rotateLeftShort(short, int) intrinsics_recognition (after)
+ /// CHECK-DAG: <<Method:[ij]\d+>> CurrentMethod
+ /// CHECK: <<ArgVal:s\d+>> ParameterValue
+ /// CHECK: <<ArgDist:i\d+>> ParameterValue
+ /// CHECK-DAG: <<Result:i\d+>> InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>,<<Method>>] intrinsic:IntegerRotateLeft
+ /// CHECK-DAG: Return [<<Result>>]
+
+ /// CHECK-START: int Main.rotateLeftShort(short, int) instruction_simplifier (after)
+ /// CHECK: <<ArgVal:s\d+>> ParameterValue
+ /// CHECK: <<ArgDist:i\d+>> ParameterValue
+ /// CHECK-DAG: <<NegDist:i\d+>> Neg [<<ArgDist>>]
+ /// CHECK-DAG: <<Result:i\d+>> Ror [<<ArgVal>>,<<NegDist>>]
+ /// CHECK-DAG: Return [<<Result>>]
+
+ /// CHECK-START: int Main.rotateLeftShort(short, int) instruction_simplifier (after)
+ /// CHECK-NOT: InvokeStaticOrDirect
+
+ private static int rotateLeftShort(short value, int distance) {
+ return Integer.rotateLeft(value, distance);
+ }
+
+ /// CHECK-START: int Main.rotateLeftChar(char, int) intrinsics_recognition (after)
+ /// CHECK-DAG: <<Method:[ij]\d+>> CurrentMethod
+ /// CHECK: <<ArgVal:c\d+>> ParameterValue
+ /// CHECK: <<ArgDist:i\d+>> ParameterValue
+ /// CHECK-DAG: <<Result:i\d+>> InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>,<<Method>>] intrinsic:IntegerRotateLeft
+ /// CHECK-DAG: Return [<<Result>>]
+
+ /// CHECK-START: int Main.rotateLeftChar(char, int) instruction_simplifier (after)
+ /// CHECK: <<ArgVal:c\d+>> ParameterValue
+ /// CHECK: <<ArgDist:i\d+>> ParameterValue
+ /// CHECK-DAG: <<NegDist:i\d+>> Neg [<<ArgDist>>]
+ /// CHECK-DAG: <<Result:i\d+>> Ror [<<ArgVal>>,<<NegDist>>]
+ /// CHECK-DAG: Return [<<Result>>]
+
+ /// CHECK-START: int Main.rotateLeftChar(char, int) instruction_simplifier (after)
+ /// CHECK-NOT: InvokeStaticOrDirect
+
+ private static int rotateLeftChar(char value, int distance) {
+ return Integer.rotateLeft(value, distance);
+ }
+
+ /// CHECK-START: int Main.rotateLeftInt(int, int) intrinsics_recognition (after)
+ /// CHECK-DAG: <<Method:[ij]\d+>> CurrentMethod
+ /// CHECK: <<ArgVal:i\d+>> ParameterValue
+ /// CHECK: <<ArgDist:i\d+>> ParameterValue
+ /// CHECK-DAG: <<Result:i\d+>> InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>,<<Method>>] intrinsic:IntegerRotateLeft
+ /// CHECK-DAG: Return [<<Result>>]
+
+ /// CHECK-START: int Main.rotateLeftInt(int, int) instruction_simplifier (after)
+ /// CHECK: <<ArgVal:i\d+>> ParameterValue
+ /// CHECK: <<ArgDist:i\d+>> ParameterValue
+ /// CHECK-DAG: <<NegDist:i\d+>> Neg [<<ArgDist>>]
+ /// CHECK-DAG: <<Result:i\d+>> Ror [<<ArgVal>>,<<NegDist>>]
+ /// CHECK-DAG: Return [<<Result>>]
+
+ /// CHECK-START: int Main.rotateLeftInt(int, int) instruction_simplifier (after)
+ /// CHECK-NOT: InvokeStaticOrDirect
+
+ private static int rotateLeftInt(int value, int distance) {
+ return Integer.rotateLeft(value, distance);
+ }
+
+ /// CHECK-START: long Main.rotateLeftLong(long, int) intrinsics_recognition (after)
+ /// CHECK-DAG: <<Method:[ij]\d+>> CurrentMethod
+ /// CHECK: <<ArgVal:j\d+>> ParameterValue
+ /// CHECK: <<ArgDist:i\d+>> ParameterValue
+ /// CHECK-DAG: <<Result:j\d+>> InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>,<<Method>>] intrinsic:LongRotateLeft
+ /// CHECK-DAG: Return [<<Result>>]
+
+ /// CHECK-START: long Main.rotateLeftLong(long, int) instruction_simplifier (after)
+ /// CHECK: <<ArgVal:j\d+>> ParameterValue
+ /// CHECK: <<ArgDist:i\d+>> ParameterValue
+ /// CHECK-DAG: <<NegDist:i\d+>> Neg [<<ArgDist>>]
+ /// CHECK-DAG: <<Result:j\d+>> Ror [<<ArgVal>>,<<NegDist>>]
+ /// CHECK-DAG: Return [<<Result>>]
+
+ /// CHECK-START: long Main.rotateLeftLong(long, int) instruction_simplifier (after)
+ /// CHECK-NOT: InvokeStaticOrDirect
+
+ private static long rotateLeftLong(long value, int distance) {
+ return Long.rotateLeft(value, distance);
+ }
+
+ /// CHECK-START: int Main.rotateRightByte(byte, int) intrinsics_recognition (after)
+ /// CHECK-DAG: <<Method:[ij]\d+>> CurrentMethod
+ /// CHECK: <<ArgVal:b\d+>> ParameterValue
+ /// CHECK: <<ArgDist:i\d+>> ParameterValue
+ /// CHECK-DAG: <<Result:i\d+>> InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>,<<Method>>] intrinsic:IntegerRotateRight
+ /// CHECK-DAG: Return [<<Result>>]
+
+ /// CHECK-START: int Main.rotateRightByte(byte, int) instruction_simplifier (after)
+ /// CHECK: <<ArgVal:b\d+>> ParameterValue
+ /// CHECK: <<ArgDist:i\d+>> ParameterValue
+ /// CHECK-DAG: <<Result:i\d+>> Ror [<<ArgVal>>,<<ArgDist>>]
+ /// CHECK-DAG: Return [<<Result>>]
+
+ /// CHECK-START: int Main.rotateRightByte(byte, int) instruction_simplifier (after)
+ /// CHECK-NOT: InvokeStaticOrDirect
+
+ private static int rotateRightByte(byte value, int distance) {
+ return Integer.rotateRight(value, distance);
+ }
+
+ /// CHECK-START: int Main.rotateRightShort(short, int) intrinsics_recognition (after)
+ /// CHECK-DAG: <<Method:[ij]\d+>> CurrentMethod
+ /// CHECK: <<ArgVal:s\d+>> ParameterValue
+ /// CHECK: <<ArgDist:i\d+>> ParameterValue
+ /// CHECK-DAG: <<Result:i\d+>> InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>,<<Method>>] intrinsic:IntegerRotateRight
+ /// CHECK-DAG: Return [<<Result>>]
+
+ /// CHECK-START: int Main.rotateRightShort(short, int) instruction_simplifier (after)
+ /// CHECK: <<ArgVal:s\d+>> ParameterValue
+ /// CHECK: <<ArgDist:i\d+>> ParameterValue
+ /// CHECK-DAG: <<Result:i\d+>> Ror [<<ArgVal>>,<<ArgDist>>]
+ /// CHECK-DAG: Return [<<Result>>]
+
+ /// CHECK-START: int Main.rotateRightShort(short, int) instruction_simplifier (after)
+ /// CHECK-NOT: InvokeStaticOrDirect
+
+ private static int rotateRightShort(short value, int distance) {
+ return Integer.rotateRight(value, distance);
+ }
+
+ /// CHECK-START: int Main.rotateRightChar(char, int) intrinsics_recognition (after)
+ /// CHECK-DAG: <<Method:[ij]\d+>> CurrentMethod
+ /// CHECK: <<ArgVal:c\d+>> ParameterValue
+ /// CHECK: <<ArgDist:i\d+>> ParameterValue
+ /// CHECK-DAG: <<Result:i\d+>> InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>,<<Method>>] intrinsic:IntegerRotateRight
+ /// CHECK-DAG: Return [<<Result>>]
+
+ /// CHECK-START: int Main.rotateRightChar(char, int) instruction_simplifier (after)
+ /// CHECK: <<ArgVal:c\d+>> ParameterValue
+ /// CHECK: <<ArgDist:i\d+>> ParameterValue
+ /// CHECK-DAG: <<Result:i\d+>> Ror [<<ArgVal>>,<<ArgDist>>]
+ /// CHECK-DAG: Return [<<Result>>]
+
+ /// CHECK-START: int Main.rotateRightChar(char, int) instruction_simplifier (after)
+ /// CHECK-NOT: InvokeStaticOrDirect
+
+ private static int rotateRightChar(char value, int distance) {
+ return Integer.rotateRight(value, distance);
+ }
+
+ /// CHECK-START: int Main.rotateRightInt(int, int) intrinsics_recognition (after)
+ /// CHECK-DAG: <<Method:[ij]\d+>> CurrentMethod
+ /// CHECK: <<ArgVal:i\d+>> ParameterValue
+ /// CHECK: <<ArgDist:i\d+>> ParameterValue
+ /// CHECK-DAG: <<Result:i\d+>> InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>,<<Method>>] intrinsic:IntegerRotateRight
+ /// CHECK-DAG: Return [<<Result>>]
+
+ /// CHECK-START: int Main.rotateRightInt(int, int) instruction_simplifier (after)
+ /// CHECK: <<ArgVal:i\d+>> ParameterValue
+ /// CHECK: <<ArgDist:i\d+>> ParameterValue
+ /// CHECK-DAG: <<Result:i\d+>> Ror [<<ArgVal>>,<<ArgDist>>]
+ /// CHECK-DAG: Return [<<Result>>]
+
+ /// CHECK-START: int Main.rotateRightInt(int, int) instruction_simplifier (after)
+ /// CHECK-NOT: InvokeStaticOrDirect
+
+ private static int rotateRightInt(int value, int distance) {
+ return Integer.rotateRight(value, distance);
+ }
+
+ /// CHECK-START: long Main.rotateRightLong(long, int) intrinsics_recognition (after)
+ /// CHECK-DAG: <<Method:[ij]\d+>> CurrentMethod
+ /// CHECK: <<ArgVal:j\d+>> ParameterValue
+ /// CHECK: <<ArgDist:i\d+>> ParameterValue
+ /// CHECK-DAG: <<Result:j\d+>> InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>,<<Method>>] intrinsic:LongRotateRight
+ /// CHECK-DAG: Return [<<Result>>]
+
+ /// CHECK-START: long Main.rotateRightLong(long, int) instruction_simplifier (after)
+ /// CHECK: <<ArgVal:j\d+>> ParameterValue
+ /// CHECK: <<ArgDist:i\d+>> ParameterValue
+ /// CHECK-DAG: <<Result:j\d+>> Ror [<<ArgVal>>,<<ArgDist>>]
+ /// CHECK-DAG: Return [<<Result>>]
+
+ /// CHECK-START: long Main.rotateRightLong(long, int) instruction_simplifier (after)
+ /// CHECK-NOT: InvokeStaticOrDirect
+
+ private static long rotateRightLong(long value, int distance) {
+ return Long.rotateRight(value, distance);
+ }
+
+
+ /// CHECK-START: int Main.rotateLeftIntWithByteDistance(int, byte) intrinsics_recognition (after)
+ /// CHECK-DAG: <<Method:[ij]\d+>> CurrentMethod
+ /// CHECK: <<ArgVal:i\d+>> ParameterValue
+ /// CHECK: <<ArgDist:b\d+>> ParameterValue
+ /// CHECK-DAG: <<Result:i\d+>> InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>,<<Method>>] intrinsic:IntegerRotateLeft
+ /// CHECK-DAG: Return [<<Result>>]
+
+ /// CHECK-START: int Main.rotateLeftIntWithByteDistance(int, byte) instruction_simplifier (after)
+ /// CHECK: <<ArgVal:i\d+>> ParameterValue
+ /// CHECK: <<ArgDist:b\d+>> ParameterValue
+ /// CHECK-DAG: <<NegDist:i\d+>> Neg [<<ArgDist>>]
+ /// CHECK-DAG: <<Result:i\d+>> Ror [<<ArgVal>>,<<NegDist>>]
+ /// CHECK-DAG: Return [<<Result>>]
+
+ /// CHECK-START: int Main.rotateLeftIntWithByteDistance(int, byte) instruction_simplifier (after)
+ /// CHECK-NOT: InvokeStaticOrDirect
+
+ private static int rotateLeftIntWithByteDistance(int value, byte distance) {
+ return Integer.rotateLeft(value, distance);
+ }
+
+ /// CHECK-START: int Main.rotateRightIntWithByteDistance(int, byte) intrinsics_recognition (after)
+ /// CHECK-DAG: <<Method:[ij]\d+>> CurrentMethod
+ /// CHECK: <<ArgVal:i\d+>> ParameterValue
+ /// CHECK: <<ArgDist:b\d+>> ParameterValue
+ /// CHECK-DAG: <<Result:i\d+>> InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>,<<Method>>] intrinsic:IntegerRotateRight
+ /// CHECK-DAG: Return [<<Result>>]
+
+ /// CHECK-START: int Main.rotateRightIntWithByteDistance(int, byte) instruction_simplifier (after)
+ /// CHECK: <<ArgVal:i\d+>> ParameterValue
+ /// CHECK: <<ArgDist:b\d+>> ParameterValue
+ /// CHECK-DAG: <<Result:i\d+>> Ror [<<ArgVal>>,<<ArgDist>>]
+ /// CHECK-DAG: Return [<<Result>>]
+
+ /// CHECK-START: int Main.rotateRightIntWithByteDistance(int, byte) instruction_simplifier (after)
+ /// CHECK-NOT: InvokeStaticOrDirect
+
+ private static int rotateRightIntWithByteDistance(int value, byte distance) {
+ return Integer.rotateRight(value, distance);
+ }
+
+
+ public static void testRotateLeftBoolean() throws Exception {
+ Method rotateLeftBoolean = main2.getMethod("rotateLeftBoolean", boolean.class, int.class);
+ for (int i = 0; i < 40; i++) { // overshoot a bit
+ int j = i & 31;
+ expectEqualsInt(0, (int)rotateLeftBoolean.invoke(null, false, i));
+ expectEqualsInt(1 << i, (int)rotateLeftBoolean.invoke(null, true, i));
+ }
+ }
+
+ public static void testRotateLeftByte() {
+ expectEqualsInt(0x00000001, rotateLeftByte((byte)0x01, 0));
+ expectEqualsInt(0x00000002, rotateLeftByte((byte)0x01, 1));
+ expectEqualsInt(0x80000000, rotateLeftByte((byte)0x01, 31));
+ expectEqualsInt(0x00000001, rotateLeftByte((byte)0x01, 32)); // overshoot
+ expectEqualsInt(0xFFFFFF03, rotateLeftByte((byte)0x81, 1));
+ expectEqualsInt(0xFFFFFE07, rotateLeftByte((byte)0x81, 2));
+ expectEqualsInt(0x00000120, rotateLeftByte((byte)0x12, 4));
+ expectEqualsInt(0xFFFF9AFF, rotateLeftByte((byte)0x9A, 8));
+ for (int i = 0; i < 40; i++) { // overshoot a bit
+ int j = i & 31;
+ expectEqualsInt(0x00000000, rotateLeftByte((byte)0x0000, i));
+ expectEqualsInt(0xFFFFFFFF, rotateLeftByte((byte)0xFFFF, i));
+ expectEqualsInt((1 << j), rotateLeftByte((byte)0x0001, i));
+ expectEqualsInt((0x12 << j) | (0x12 >>> -j), rotateLeftByte((byte)0x12, i));
+ }
+ }
+
+ public static void testRotateLeftShort() {
+ expectEqualsInt(0x00000001, rotateLeftShort((short)0x0001, 0));
+ expectEqualsInt(0x00000002, rotateLeftShort((short)0x0001, 1));
+ expectEqualsInt(0x80000000, rotateLeftShort((short)0x0001, 31));
+ expectEqualsInt(0x00000001, rotateLeftShort((short)0x0001, 32)); // overshoot
+ expectEqualsInt(0xFFFF0003, rotateLeftShort((short)0x8001, 1));
+ expectEqualsInt(0xFFFE0007, rotateLeftShort((short)0x8001, 2));
+ expectEqualsInt(0x00012340, rotateLeftShort((short)0x1234, 4));
+ expectEqualsInt(0xFF9ABCFF, rotateLeftShort((short)0x9ABC, 8));
+ for (int i = 0; i < 40; i++) { // overshoot a bit
+ int j = i & 31;
+ expectEqualsInt(0x00000000, rotateLeftShort((short)0x0000, i));
+ expectEqualsInt(0xFFFFFFFF, rotateLeftShort((short)0xFFFF, i));
+ expectEqualsInt((1 << j), rotateLeftShort((short)0x0001, i));
+ expectEqualsInt((0x1234 << j) | (0x1234 >>> -j), rotateLeftShort((short)0x1234, i));
+ }
+ }
+
+ public static void testRotateLeftChar() {
+ expectEqualsInt(0x00000001, rotateLeftChar((char)0x0001, 0));
+ expectEqualsInt(0x00000002, rotateLeftChar((char)0x0001, 1));
+ expectEqualsInt(0x80000000, rotateLeftChar((char)0x0001, 31));
+ expectEqualsInt(0x00000001, rotateLeftChar((char)0x0001, 32)); // overshoot
+ expectEqualsInt(0x00010002, rotateLeftChar((char)0x8001, 1));
+ expectEqualsInt(0x00020004, rotateLeftChar((char)0x8001, 2));
+ expectEqualsInt(0x00012340, rotateLeftChar((char)0x1234, 4));
+ expectEqualsInt(0x009ABC00, rotateLeftChar((char)0x9ABC, 8));
+ expectEqualsInt(0x00FF0000, rotateLeftChar((char)0xFF00, 8));
+ for (int i = 0; i < 40; i++) { // overshoot a bit
+ int j = i & 31;
+ expectEqualsInt(0x00000000, rotateLeftChar((char)0x0000, i));
+ expectEqualsInt((1 << j), rotateLeftChar((char)0x0001, i));
+ expectEqualsInt((0x1234 << j) | (0x1234 >>> -j), rotateLeftChar((char)0x1234, i));
+ }
+ }
+
+ public static void testRotateLeftInt() {
+ expectEqualsInt(0x00000001, rotateLeftInt(0x00000001, 0));
+ expectEqualsInt(0x00000002, rotateLeftInt(0x00000001, 1));
+ expectEqualsInt(0x80000000, rotateLeftInt(0x00000001, 31));
+ expectEqualsInt(0x00000001, rotateLeftInt(0x00000001, 32)); // overshoot
+ expectEqualsInt(0x00000003, rotateLeftInt(0x80000001, 1));
+ expectEqualsInt(0x00000006, rotateLeftInt(0x80000001, 2));
+ expectEqualsInt(0x23456781, rotateLeftInt(0x12345678, 4));
+ expectEqualsInt(0xBCDEF09A, rotateLeftInt(0x9ABCDEF0, 8));
+ for (int i = 0; i < 40; i++) { // overshoot a bit
+ int j = i & 31;
+ expectEqualsInt(0x00000000, rotateLeftInt(0x00000000, i));
+ expectEqualsInt(0xFFFFFFFF, rotateLeftInt(0xFFFFFFFF, i));
+ expectEqualsInt(1 << j, rotateLeftInt(0x00000001, i));
+ expectEqualsInt((0x12345678 << j) | (0x12345678 >>> -j), rotateLeftInt(0x12345678, i));
+ }
+ }
+
+ public static void testRotateLeftLong() {
+ expectEqualsLong(0x0000000000000001L, rotateLeftLong(0x0000000000000001L, 0));
+ expectEqualsLong(0x0000000000000002L, rotateLeftLong(0x0000000000000001L, 1));
+ expectEqualsLong(0x8000000000000000L, rotateLeftLong(0x0000000000000001L, 63));
+ expectEqualsLong(0x0000000000000001L, rotateLeftLong(0x0000000000000001L, 64)); // overshoot
+ expectEqualsLong(0x0000000000000003L, rotateLeftLong(0x8000000000000001L, 1));
+ expectEqualsLong(0x0000000000000006L, rotateLeftLong(0x8000000000000001L, 2));
+ expectEqualsLong(0x23456789ABCDEF01L, rotateLeftLong(0x123456789ABCDEF0L, 4));
+ expectEqualsLong(0x3456789ABCDEF012L, rotateLeftLong(0x123456789ABCDEF0L, 8));
+ for (int i = 0; i < 70; i++) { // overshoot a bit
+ int j = i & 63;
+ expectEqualsLong(0x0000000000000000L, rotateLeftLong(0x0000000000000000L, i));
+ expectEqualsLong(0xFFFFFFFFFFFFFFFFL, rotateLeftLong(0xFFFFFFFFFFFFFFFFL, i));
+ expectEqualsLong(1L << j, rotateLeftLong(0x0000000000000001, i));
+ expectEqualsLong((0x123456789ABCDEF0L << j) | (0x123456789ABCDEF0L >>> -j),
+ rotateLeftLong(0x123456789ABCDEF0L, i));
+ }
+ }
+
+ public static void testRotateRightBoolean() throws Exception {
+ Method rotateRightBoolean = main2.getMethod("rotateRightBoolean", boolean.class, int.class);
+ for (int i = 0; i < 40; i++) { // overshoot a bit
+ int j = i & 31;
+ expectEqualsInt(0, (int)rotateRightBoolean.invoke(null, false, i));
+ expectEqualsInt(1 << (32 - i), (int)rotateRightBoolean.invoke(null, true, i));
+ }
+ }
+
+ public static void testRotateRightByte() {
+ expectEqualsInt(0xFFFFFF80, rotateRightByte((byte)0x80, 0));
+ expectEqualsInt(0x7FFFFFC0, rotateRightByte((byte)0x80, 1));
+ expectEqualsInt(0xFFFFFF01, rotateRightByte((byte)0x80, 31));
+ expectEqualsInt(0xFFFFFF80, rotateRightByte((byte)0x80, 32)); // overshoot
+ expectEqualsInt(0xFFFFFFC0, rotateRightByte((byte)0x81, 1));
+ expectEqualsInt(0x7FFFFFE0, rotateRightByte((byte)0x81, 2));
+ expectEqualsInt(0x20000001, rotateRightByte((byte)0x12, 4));
+ expectEqualsInt(0x9AFFFFFF, rotateRightByte((byte)0x9A, 8));
+ for (int i = 0; i < 40; i++) { // overshoot a bit
+ int j = i & 31;
+ expectEqualsInt(0x00000000, rotateRightByte((byte)0x00, i));
+ expectEqualsInt(0xFFFFFFFF, rotateRightByte((byte)0xFF, i));
+ expectEqualsInt(1 << (32 - j), rotateRightByte((byte)0x01, i));
+ expectEqualsInt((0x12 >>> j) | (0x12 << -j), rotateRightByte((byte)0x12, i));
+ }
+ }
+
+ public static void testRotateRightShort() {
+ expectEqualsInt(0xFFFF8000, rotateRightShort((short)0x8000, 0));
+ expectEqualsInt(0x7FFFC000, rotateRightShort((short)0x8000, 1));
+ expectEqualsInt(0xFFFF0001, rotateRightShort((short)0x8000, 31));
+ expectEqualsInt(0xFFFF8000, rotateRightShort((short)0x8000, 32)); // overshoot
+ expectEqualsInt(0xFFFFC000, rotateRightShort((short)0x8001, 1));
+ expectEqualsInt(0x7FFFE000, rotateRightShort((short)0x8001, 2));
+ expectEqualsInt(0x40000123, rotateRightShort((short)0x1234, 4));
+ expectEqualsInt(0xBCFFFF9A, rotateRightShort((short)0x9ABC, 8));
+ for (int i = 0; i < 40; i++) { // overshoot a bit
+ int j = i & 31;
+ expectEqualsInt(0x00000000, rotateRightShort((short)0x0000, i));
+ expectEqualsInt(0xFFFFFFFF, rotateRightShort((short)0xFFFF, i));
+ expectEqualsInt(1 << (32 - j), rotateRightShort((short)0x0001, i));
+ expectEqualsInt((0x1234 >>> j) | (0x1234 << -j), rotateRightShort((short)0x1234, i));
+ }
+ }
+
+ public static void testRotateRightChar() {
+ expectEqualsInt(0x00008000, rotateRightChar((char)0x8000, 0));
+ expectEqualsInt(0x00004000, rotateRightChar((char)0x8000, 1));
+ expectEqualsInt(0x00010000, rotateRightChar((char)0x8000, 31));
+ expectEqualsInt(0x00008000, rotateRightChar((char)0x8000, 32)); // overshoot
+ expectEqualsInt(0x80004000, rotateRightChar((char)0x8001, 1));
+ expectEqualsInt(0x40002000, rotateRightChar((char)0x8001, 2));
+ expectEqualsInt(0x40000123, rotateRightChar((char)0x1234, 4));
+ expectEqualsInt(0xBC00009A, rotateRightChar((char)0x9ABC, 8));
+ for (int i = 0; i < 40; i++) { // overshoot a bit
+ int j = i & 31;
+ expectEqualsInt(0x00000000, rotateRightChar((char)0x0000, i));
+ expectEqualsInt(1 << (32 - j), rotateRightChar((char)0x0001, i));
+ expectEqualsInt((0x1234 >>> j) | (0x1234 << -j), rotateRightChar((char)0x1234, i));
+ }
+ }
+
+ public static void testRotateRightInt() {
+ expectEqualsInt(0x80000000, rotateRightInt(0x80000000, 0));
+ expectEqualsInt(0x40000000, rotateRightInt(0x80000000, 1));
+ expectEqualsInt(0x00000001, rotateRightInt(0x80000000, 31));
+ expectEqualsInt(0x80000000, rotateRightInt(0x80000000, 32)); // overshoot
+ expectEqualsInt(0xC0000000, rotateRightInt(0x80000001, 1));
+ expectEqualsInt(0x60000000, rotateRightInt(0x80000001, 2));
+ expectEqualsInt(0x81234567, rotateRightInt(0x12345678, 4));
+ expectEqualsInt(0xF09ABCDE, rotateRightInt(0x9ABCDEF0, 8));
+ for (int i = 0; i < 40; i++) { // overshoot a bit
+ int j = i & 31;
+ expectEqualsInt(0x00000000, rotateRightInt(0x00000000, i));
+ expectEqualsInt(0xFFFFFFFF, rotateRightInt(0xFFFFFFFF, i));
+ expectEqualsInt(0x80000000 >>> j, rotateRightInt(0x80000000, i));
+ expectEqualsInt((0x12345678 >>> j) | (0x12345678 << -j), rotateRightInt(0x12345678, i));
+ }
+ }
+
+ public static void testRotateRightLong() {
+ expectEqualsLong(0x8000000000000000L, rotateRightLong(0x8000000000000000L, 0));
+ expectEqualsLong(0x4000000000000000L, rotateRightLong(0x8000000000000000L, 1));
+ expectEqualsLong(0x0000000000000001L, rotateRightLong(0x8000000000000000L, 63));
+ expectEqualsLong(0x8000000000000000L, rotateRightLong(0x8000000000000000L, 64)); // overshoot
+ expectEqualsLong(0xC000000000000000L, rotateRightLong(0x8000000000000001L, 1));
+ expectEqualsLong(0x6000000000000000L, rotateRightLong(0x8000000000000001L, 2));
+ expectEqualsLong(0x0123456789ABCDEFL, rotateRightLong(0x123456789ABCDEF0L, 4));
+ expectEqualsLong(0xF0123456789ABCDEL, rotateRightLong(0x123456789ABCDEF0L, 8));
+ for (int i = 0; i < 70; i++) { // overshoot a bit
+ int j = i & 63;
+ expectEqualsLong(0x0000000000000000L, rotateRightLong(0x0000000000000000L, i));
+ expectEqualsLong(0xFFFFFFFFFFFFFFFFL, rotateRightLong(0xFFFFFFFFFFFFFFFFL, i));
+ expectEqualsLong(0x8000000000000000L >>> j, rotateRightLong(0x8000000000000000L, i));
+ expectEqualsLong((0x123456789ABCDEF0L >>> j) | (0x123456789ABCDEF0L << -j),
+ rotateRightLong(0x123456789ABCDEF0L, i));
+ }
+ }
+
+
+ public static void testRotateLeftIntWithByteDistance() {
+ expectEqualsInt(0x00000001, rotateLeftIntWithByteDistance(0x00000001, (byte)0));
+ expectEqualsInt(0x00000002, rotateLeftIntWithByteDistance(0x00000001, (byte)1));
+ expectEqualsInt(0x80000000, rotateLeftIntWithByteDistance(0x00000001, (byte)31));
+ expectEqualsInt(0x00000001, rotateLeftIntWithByteDistance(0x00000001, (byte)32)); // overshoot
+ expectEqualsInt(0x00000003, rotateLeftIntWithByteDistance(0x80000001, (byte)1));
+ expectEqualsInt(0x00000006, rotateLeftIntWithByteDistance(0x80000001, (byte)2));
+ expectEqualsInt(0x23456781, rotateLeftIntWithByteDistance(0x12345678, (byte)4));
+ expectEqualsInt(0xBCDEF09A, rotateLeftIntWithByteDistance(0x9ABCDEF0, (byte)8));
+ for (byte i = 0; i < 40; i++) { // overshoot a bit
+ byte j = (byte)(i & 31);
+ expectEqualsInt(0x00000000, rotateLeftIntWithByteDistance(0x00000000, i));
+ expectEqualsInt(0xFFFFFFFF, rotateLeftIntWithByteDistance(0xFFFFFFFF, i));
+ expectEqualsInt(1 << j, rotateLeftIntWithByteDistance(0x00000001, i));
+ expectEqualsInt((0x12345678 << j) | (0x12345678 >>> -j),
+ rotateLeftIntWithByteDistance(0x12345678, i));
+ }
+ }
+
+ public static void testRotateRightIntWithByteDistance() {
+ expectEqualsInt(0x80000000, rotateRightIntWithByteDistance(0x80000000, (byte)0));
+ expectEqualsInt(0x40000000, rotateRightIntWithByteDistance(0x80000000, (byte)1));
+ expectEqualsInt(0x00000001, rotateRightIntWithByteDistance(0x80000000, (byte)31));
+ expectEqualsInt(0x80000000, rotateRightIntWithByteDistance(0x80000000, (byte)32)); // overshoot
+ expectEqualsInt(0xC0000000, rotateRightIntWithByteDistance(0x80000001, (byte)1));
+ expectEqualsInt(0x60000000, rotateRightIntWithByteDistance(0x80000001, (byte)2));
+ expectEqualsInt(0x81234567, rotateRightIntWithByteDistance(0x12345678, (byte)4));
+ expectEqualsInt(0xF09ABCDE, rotateRightIntWithByteDistance(0x9ABCDEF0, (byte)8));
+ for (byte i = 0; i < 40; i++) { // overshoot a bit
+ byte j = (byte)(i & 31);
+ expectEqualsInt(0x00000000, rotateRightIntWithByteDistance(0x00000000, i));
+ expectEqualsInt(0xFFFFFFFF, rotateRightIntWithByteDistance(0xFFFFFFFF, i));
+ expectEqualsInt(0x80000000 >>> j, rotateRightIntWithByteDistance(0x80000000, i));
+ expectEqualsInt((0x12345678 >>> j) | (0x12345678 << -j),
+ rotateRightIntWithByteDistance(0x12345678, i));
+ }
+ }
+
+
+ public static void main(String args[]) throws Exception {
+ main2 = Class.forName("Main2");
+
+ testRotateLeftBoolean();
+ testRotateLeftByte();
+ testRotateLeftShort();
+ testRotateLeftChar();
+ testRotateLeftInt();
+ testRotateLeftLong();
+
+ testRotateRightBoolean();
+ testRotateRightByte();
+ testRotateRightShort();
+ testRotateRightChar();
+ testRotateRightInt();
+ testRotateRightLong();
+
+ // Also exercise distance values with types other than int.
+ testRotateLeftIntWithByteDistance();
+ testRotateRightIntWithByteDistance();
+
+ System.out.println("passed");
+ }
+
+
+ private static void expectEqualsInt(int expected, int result) {
+ if (expected != result) {
+ throw new Error("Expected: " + expected + ", found: " + result);
+ }
+ }
+
+ private static void expectEqualsLong(long expected, long result) {
+ if (expected != result) {
+ throw new Error("Expected: " + expected + ", found: " + result);
+ }
+ }
+}
diff --git a/test/565-checker-rotate/src/Main.java b/test/565-checker-rotate/src/Main.java
index eb0e868..79b8555 100644
--- a/test/565-checker-rotate/src/Main.java
+++ b/test/565-checker-rotate/src/Main.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,623 +14,9 @@
* limitations under the License.
*/
+// This file is just for running on the RI as the test is ART specific.
public class Main {
-
- /// CHECK-START: int Main.rotateLeftBoolean(boolean, int) intrinsics_recognition (after)
- /// CHECK-DAG: <<Method:[ij]\d+>> CurrentMethod
- /// CHECK: <<ArgVal:z\d+>> ParameterValue
- /// CHECK: <<ArgDist:i\d+>> ParameterValue
- /// CHECK-DAG: <<Zero:i\d+>> IntConstant 0
- /// CHECK-DAG: <<One:i\d+>> IntConstant 1
- /// CHECK-DAG: <<Val:i\d+>> Phi [<<One>>,<<Zero>>]
- /// CHECK-DAG: <<Result:i\d+>> InvokeStaticOrDirect [<<Val>>,<<ArgDist>>,<<Method>>] intrinsic:IntegerRotateLeft
- /// CHECK-DAG: Return [<<Result>>]
-
- /// CHECK-START: int Main.rotateLeftBoolean(boolean, int) instruction_simplifier (after)
- /// CHECK: <<ArgVal:z\d+>> ParameterValue
- /// CHECK: <<ArgDist:i\d+>> ParameterValue
- /// CHECK-DAG: <<Zero:i\d+>> IntConstant 0
- /// CHECK-DAG: <<One:i\d+>> IntConstant 1
- /// CHECK-DAG: <<Val:i\d+>> Phi [<<One>>,<<Zero>>]
- /// CHECK-DAG: <<NegDist:i\d+>> Neg [<<ArgDist>>]
- /// CHECK-DAG: <<Result:i\d+>> Ror [<<Val>>,<<NegDist>>]
- /// CHECK-DAG: Return [<<Result>>]
-
- /// CHECK-START: int Main.rotateLeftBoolean(boolean, int) instruction_simplifier (after)
- /// CHECK-NOT: InvokeStaticOrDirect
-
- /// CHECK-START: int Main.rotateLeftBoolean(boolean, int) select_generator (after)
- /// CHECK: <<ArgVal:z\d+>> ParameterValue
- /// CHECK: <<ArgDist:i\d+>> ParameterValue
- /// CHECK-DAG: <<Zero:i\d+>> IntConstant 0
- /// CHECK-DAG: <<One:i\d+>> IntConstant 1
- /// CHECK-DAG: <<SelVal:i\d+>> Select [<<Zero>>,<<One>>,<<ArgVal>>]
- /// CHECK-DAG: <<NegDist:i\d+>> Neg [<<ArgDist>>]
- /// CHECK-DAG: <<Result:i\d+>> Ror [<<SelVal>>,<<NegDist>>]
- /// CHECK-DAG: Return [<<Result>>]
-
- /// CHECK-START: int Main.rotateLeftBoolean(boolean, int) select_generator (after)
- /// CHECK-NOT: Phi
-
- /// CHECK-START: int Main.rotateLeftBoolean(boolean, int) instruction_simplifier$after_bce (after)
- /// CHECK: <<ArgVal:z\d+>> ParameterValue
- /// CHECK: <<ArgDist:i\d+>> ParameterValue
- /// CHECK-DAG: <<NegDist:i\d+>> Neg [<<ArgDist>>]
- /// CHECK-DAG: <<Result:i\d+>> Ror [<<ArgVal>>,<<NegDist>>]
- /// CHECK-DAG: Return [<<Result>>]
-
- /// CHECK-START: int Main.rotateLeftBoolean(boolean, int) instruction_simplifier$after_bce (after)
- /// CHECK-NOT: Select
-
- private static int rotateLeftBoolean(boolean value, int distance) {
- return Integer.rotateLeft(value ? 1 : 0, distance);
- }
-
- /// CHECK-START: int Main.rotateLeftByte(byte, int) intrinsics_recognition (after)
- /// CHECK-DAG: <<Method:[ij]\d+>> CurrentMethod
- /// CHECK: <<ArgVal:b\d+>> ParameterValue
- /// CHECK: <<ArgDist:i\d+>> ParameterValue
- /// CHECK-DAG: <<Result:i\d+>> InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>,<<Method>>] intrinsic:IntegerRotateLeft
- /// CHECK-DAG: Return [<<Result>>]
-
- /// CHECK-START: int Main.rotateLeftByte(byte, int) instruction_simplifier (after)
- /// CHECK: <<ArgVal:b\d+>> ParameterValue
- /// CHECK: <<ArgDist:i\d+>> ParameterValue
- /// CHECK-DAG: <<NegDist:i\d+>> Neg [<<ArgDist>>]
- /// CHECK-DAG: <<Result:i\d+>> Ror [<<ArgVal>>,<<NegDist>>]
- /// CHECK-DAG: Return [<<Result>>]
-
- /// CHECK-START: int Main.rotateLeftByte(byte, int) instruction_simplifier (after)
- /// CHECK-NOT: InvokeStaticOrDirect
-
- private static int rotateLeftByte(byte value, int distance) {
- return Integer.rotateLeft(value, distance);
- }
-
- /// CHECK-START: int Main.rotateLeftShort(short, int) intrinsics_recognition (after)
- /// CHECK-DAG: <<Method:[ij]\d+>> CurrentMethod
- /// CHECK: <<ArgVal:s\d+>> ParameterValue
- /// CHECK: <<ArgDist:i\d+>> ParameterValue
- /// CHECK-DAG: <<Result:i\d+>> InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>,<<Method>>] intrinsic:IntegerRotateLeft
- /// CHECK-DAG: Return [<<Result>>]
-
- /// CHECK-START: int Main.rotateLeftShort(short, int) instruction_simplifier (after)
- /// CHECK: <<ArgVal:s\d+>> ParameterValue
- /// CHECK: <<ArgDist:i\d+>> ParameterValue
- /// CHECK-DAG: <<NegDist:i\d+>> Neg [<<ArgDist>>]
- /// CHECK-DAG: <<Result:i\d+>> Ror [<<ArgVal>>,<<NegDist>>]
- /// CHECK-DAG: Return [<<Result>>]
-
- /// CHECK-START: int Main.rotateLeftShort(short, int) instruction_simplifier (after)
- /// CHECK-NOT: InvokeStaticOrDirect
-
- private static int rotateLeftShort(short value, int distance) {
- return Integer.rotateLeft(value, distance);
- }
-
- /// CHECK-START: int Main.rotateLeftChar(char, int) intrinsics_recognition (after)
- /// CHECK-DAG: <<Method:[ij]\d+>> CurrentMethod
- /// CHECK: <<ArgVal:c\d+>> ParameterValue
- /// CHECK: <<ArgDist:i\d+>> ParameterValue
- /// CHECK-DAG: <<Result:i\d+>> InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>,<<Method>>] intrinsic:IntegerRotateLeft
- /// CHECK-DAG: Return [<<Result>>]
-
- /// CHECK-START: int Main.rotateLeftChar(char, int) instruction_simplifier (after)
- /// CHECK: <<ArgVal:c\d+>> ParameterValue
- /// CHECK: <<ArgDist:i\d+>> ParameterValue
- /// CHECK-DAG: <<NegDist:i\d+>> Neg [<<ArgDist>>]
- /// CHECK-DAG: <<Result:i\d+>> Ror [<<ArgVal>>,<<NegDist>>]
- /// CHECK-DAG: Return [<<Result>>]
-
- /// CHECK-START: int Main.rotateLeftChar(char, int) instruction_simplifier (after)
- /// CHECK-NOT: InvokeStaticOrDirect
-
- private static int rotateLeftChar(char value, int distance) {
- return Integer.rotateLeft(value, distance);
- }
-
- /// CHECK-START: int Main.rotateLeftInt(int, int) intrinsics_recognition (after)
- /// CHECK-DAG: <<Method:[ij]\d+>> CurrentMethod
- /// CHECK: <<ArgVal:i\d+>> ParameterValue
- /// CHECK: <<ArgDist:i\d+>> ParameterValue
- /// CHECK-DAG: <<Result:i\d+>> InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>,<<Method>>] intrinsic:IntegerRotateLeft
- /// CHECK-DAG: Return [<<Result>>]
-
- /// CHECK-START: int Main.rotateLeftInt(int, int) instruction_simplifier (after)
- /// CHECK: <<ArgVal:i\d+>> ParameterValue
- /// CHECK: <<ArgDist:i\d+>> ParameterValue
- /// CHECK-DAG: <<NegDist:i\d+>> Neg [<<ArgDist>>]
- /// CHECK-DAG: <<Result:i\d+>> Ror [<<ArgVal>>,<<NegDist>>]
- /// CHECK-DAG: Return [<<Result>>]
-
- /// CHECK-START: int Main.rotateLeftInt(int, int) instruction_simplifier (after)
- /// CHECK-NOT: InvokeStaticOrDirect
-
- private static int rotateLeftInt(int value, int distance) {
- return Integer.rotateLeft(value, distance);
- }
-
- /// CHECK-START: long Main.rotateLeftLong(long, int) intrinsics_recognition (after)
- /// CHECK-DAG: <<Method:[ij]\d+>> CurrentMethod
- /// CHECK: <<ArgVal:j\d+>> ParameterValue
- /// CHECK: <<ArgDist:i\d+>> ParameterValue
- /// CHECK-DAG: <<Result:j\d+>> InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>,<<Method>>] intrinsic:LongRotateLeft
- /// CHECK-DAG: Return [<<Result>>]
-
- /// CHECK-START: long Main.rotateLeftLong(long, int) instruction_simplifier (after)
- /// CHECK: <<ArgVal:j\d+>> ParameterValue
- /// CHECK: <<ArgDist:i\d+>> ParameterValue
- /// CHECK-DAG: <<NegDist:i\d+>> Neg [<<ArgDist>>]
- /// CHECK-DAG: <<Result:j\d+>> Ror [<<ArgVal>>,<<NegDist>>]
- /// CHECK-DAG: Return [<<Result>>]
-
- /// CHECK-START: long Main.rotateLeftLong(long, int) instruction_simplifier (after)
- /// CHECK-NOT: InvokeStaticOrDirect
-
- private static long rotateLeftLong(long value, int distance) {
- return Long.rotateLeft(value, distance);
- }
-
-
- /// CHECK-START: int Main.rotateRightBoolean(boolean, int) intrinsics_recognition (after)
- /// CHECK-DAG: <<Method:[ij]\d+>> CurrentMethod
- /// CHECK: <<ArgVal:z\d+>> ParameterValue
- /// CHECK: <<ArgDist:i\d+>> ParameterValue
- /// CHECK-DAG: <<Zero:i\d+>> IntConstant 0
- /// CHECK-DAG: <<One:i\d+>> IntConstant 1
- /// CHECK-DAG: <<Val:i\d+>> Phi [<<One>>,<<Zero>>]
- /// CHECK-DAG: <<Result:i\d+>> InvokeStaticOrDirect [<<Val>>,<<ArgDist>>,<<Method>>] intrinsic:IntegerRotateRight
- /// CHECK-DAG: Return [<<Result>>]
-
- /// CHECK-START: int Main.rotateRightBoolean(boolean, int) instruction_simplifier (after)
- /// CHECK: <<ArgVal:z\d+>> ParameterValue
- /// CHECK: <<ArgDist:i\d+>> ParameterValue
- /// CHECK-DAG: <<Zero:i\d+>> IntConstant 0
- /// CHECK-DAG: <<One:i\d+>> IntConstant 1
- /// CHECK-DAG: <<Val:i\d+>> Phi [<<One>>,<<Zero>>]
- /// CHECK-DAG: <<Result:i\d+>> Ror [<<Val>>,<<ArgDist>>]
- /// CHECK-DAG: Return [<<Result>>]
-
- /// CHECK-START: int Main.rotateRightBoolean(boolean, int) instruction_simplifier (after)
- /// CHECK-NOT: InvokeStaticOrDirect
-
- /// CHECK-START: int Main.rotateRightBoolean(boolean, int) select_generator (after)
- /// CHECK: <<ArgVal:z\d+>> ParameterValue
- /// CHECK: <<ArgDist:i\d+>> ParameterValue
- /// CHECK-DAG: <<Zero:i\d+>> IntConstant 0
- /// CHECK-DAG: <<One:i\d+>> IntConstant 1
- /// CHECK-DAG: <<SelVal:i\d+>> Select [<<Zero>>,<<One>>,<<ArgVal>>]
- /// CHECK-DAG: <<Result:i\d+>> Ror [<<SelVal>>,<<ArgDist>>]
- /// CHECK-DAG: Return [<<Result>>]
-
- /// CHECK-START: int Main.rotateRightBoolean(boolean, int) select_generator (after)
- /// CHECK-NOT: Phi
-
- /// CHECK-START: int Main.rotateRightBoolean(boolean, int) instruction_simplifier$after_bce (after)
- /// CHECK: <<ArgVal:z\d+>> ParameterValue
- /// CHECK: <<ArgDist:i\d+>> ParameterValue
- /// CHECK-DAG: <<Result:i\d+>> Ror [<<ArgVal>>,<<ArgDist>>]
- /// CHECK-DAG: Return [<<Result>>]
-
- /// CHECK-START: int Main.rotateRightBoolean(boolean, int) instruction_simplifier$after_bce (after)
- /// CHECK-NOT: Select
-
- private static int rotateRightBoolean(boolean value, int distance) {
- return Integer.rotateRight(value ? 1 : 0, distance);
- }
-
- /// CHECK-START: int Main.rotateRightByte(byte, int) intrinsics_recognition (after)
- /// CHECK-DAG: <<Method:[ij]\d+>> CurrentMethod
- /// CHECK: <<ArgVal:b\d+>> ParameterValue
- /// CHECK: <<ArgDist:i\d+>> ParameterValue
- /// CHECK-DAG: <<Result:i\d+>> InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>,<<Method>>] intrinsic:IntegerRotateRight
- /// CHECK-DAG: Return [<<Result>>]
-
- /// CHECK-START: int Main.rotateRightByte(byte, int) instruction_simplifier (after)
- /// CHECK: <<ArgVal:b\d+>> ParameterValue
- /// CHECK: <<ArgDist:i\d+>> ParameterValue
- /// CHECK-DAG: <<Result:i\d+>> Ror [<<ArgVal>>,<<ArgDist>>]
- /// CHECK-DAG: Return [<<Result>>]
-
- /// CHECK-START: int Main.rotateRightByte(byte, int) instruction_simplifier (after)
- /// CHECK-NOT: InvokeStaticOrDirect
-
- private static int rotateRightByte(byte value, int distance) {
- return Integer.rotateRight(value, distance);
- }
-
- /// CHECK-START: int Main.rotateRightShort(short, int) intrinsics_recognition (after)
- /// CHECK-DAG: <<Method:[ij]\d+>> CurrentMethod
- /// CHECK: <<ArgVal:s\d+>> ParameterValue
- /// CHECK: <<ArgDist:i\d+>> ParameterValue
- /// CHECK-DAG: <<Result:i\d+>> InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>,<<Method>>] intrinsic:IntegerRotateRight
- /// CHECK-DAG: Return [<<Result>>]
-
- /// CHECK-START: int Main.rotateRightShort(short, int) instruction_simplifier (after)
- /// CHECK: <<ArgVal:s\d+>> ParameterValue
- /// CHECK: <<ArgDist:i\d+>> ParameterValue
- /// CHECK-DAG: <<Result:i\d+>> Ror [<<ArgVal>>,<<ArgDist>>]
- /// CHECK-DAG: Return [<<Result>>]
-
- /// CHECK-START: int Main.rotateRightShort(short, int) instruction_simplifier (after)
- /// CHECK-NOT: InvokeStaticOrDirect
-
- private static int rotateRightShort(short value, int distance) {
- return Integer.rotateRight(value, distance);
- }
-
- /// CHECK-START: int Main.rotateRightChar(char, int) intrinsics_recognition (after)
- /// CHECK-DAG: <<Method:[ij]\d+>> CurrentMethod
- /// CHECK: <<ArgVal:c\d+>> ParameterValue
- /// CHECK: <<ArgDist:i\d+>> ParameterValue
- /// CHECK-DAG: <<Result:i\d+>> InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>,<<Method>>] intrinsic:IntegerRotateRight
- /// CHECK-DAG: Return [<<Result>>]
-
- /// CHECK-START: int Main.rotateRightChar(char, int) instruction_simplifier (after)
- /// CHECK: <<ArgVal:c\d+>> ParameterValue
- /// CHECK: <<ArgDist:i\d+>> ParameterValue
- /// CHECK-DAG: <<Result:i\d+>> Ror [<<ArgVal>>,<<ArgDist>>]
- /// CHECK-DAG: Return [<<Result>>]
-
- /// CHECK-START: int Main.rotateRightChar(char, int) instruction_simplifier (after)
- /// CHECK-NOT: InvokeStaticOrDirect
-
- private static int rotateRightChar(char value, int distance) {
- return Integer.rotateRight(value, distance);
- }
-
- /// CHECK-START: int Main.rotateRightInt(int, int) intrinsics_recognition (after)
- /// CHECK-DAG: <<Method:[ij]\d+>> CurrentMethod
- /// CHECK: <<ArgVal:i\d+>> ParameterValue
- /// CHECK: <<ArgDist:i\d+>> ParameterValue
- /// CHECK-DAG: <<Result:i\d+>> InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>,<<Method>>] intrinsic:IntegerRotateRight
- /// CHECK-DAG: Return [<<Result>>]
-
- /// CHECK-START: int Main.rotateRightInt(int, int) instruction_simplifier (after)
- /// CHECK: <<ArgVal:i\d+>> ParameterValue
- /// CHECK: <<ArgDist:i\d+>> ParameterValue
- /// CHECK-DAG: <<Result:i\d+>> Ror [<<ArgVal>>,<<ArgDist>>]
- /// CHECK-DAG: Return [<<Result>>]
-
- /// CHECK-START: int Main.rotateRightInt(int, int) instruction_simplifier (after)
- /// CHECK-NOT: InvokeStaticOrDirect
-
- private static int rotateRightInt(int value, int distance) {
- return Integer.rotateRight(value, distance);
- }
-
- /// CHECK-START: long Main.rotateRightLong(long, int) intrinsics_recognition (after)
- /// CHECK-DAG: <<Method:[ij]\d+>> CurrentMethod
- /// CHECK: <<ArgVal:j\d+>> ParameterValue
- /// CHECK: <<ArgDist:i\d+>> ParameterValue
- /// CHECK-DAG: <<Result:j\d+>> InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>,<<Method>>] intrinsic:LongRotateRight
- /// CHECK-DAG: Return [<<Result>>]
-
- /// CHECK-START: long Main.rotateRightLong(long, int) instruction_simplifier (after)
- /// CHECK: <<ArgVal:j\d+>> ParameterValue
- /// CHECK: <<ArgDist:i\d+>> ParameterValue
- /// CHECK-DAG: <<Result:j\d+>> Ror [<<ArgVal>>,<<ArgDist>>]
- /// CHECK-DAG: Return [<<Result>>]
-
- /// CHECK-START: long Main.rotateRightLong(long, int) instruction_simplifier (after)
- /// CHECK-NOT: InvokeStaticOrDirect
-
- private static long rotateRightLong(long value, int distance) {
- return Long.rotateRight(value, distance);
- }
-
-
- /// CHECK-START: int Main.rotateLeftIntWithByteDistance(int, byte) intrinsics_recognition (after)
- /// CHECK-DAG: <<Method:[ij]\d+>> CurrentMethod
- /// CHECK: <<ArgVal:i\d+>> ParameterValue
- /// CHECK: <<ArgDist:b\d+>> ParameterValue
- /// CHECK-DAG: <<Result:i\d+>> InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>,<<Method>>] intrinsic:IntegerRotateLeft
- /// CHECK-DAG: Return [<<Result>>]
-
- /// CHECK-START: int Main.rotateLeftIntWithByteDistance(int, byte) instruction_simplifier (after)
- /// CHECK: <<ArgVal:i\d+>> ParameterValue
- /// CHECK: <<ArgDist:b\d+>> ParameterValue
- /// CHECK-DAG: <<NegDist:i\d+>> Neg [<<ArgDist>>]
- /// CHECK-DAG: <<Result:i\d+>> Ror [<<ArgVal>>,<<NegDist>>]
- /// CHECK-DAG: Return [<<Result>>]
-
- /// CHECK-START: int Main.rotateLeftIntWithByteDistance(int, byte) instruction_simplifier (after)
- /// CHECK-NOT: InvokeStaticOrDirect
-
- private static int rotateLeftIntWithByteDistance(int value, byte distance) {
- return Integer.rotateLeft(value, distance);
- }
-
- /// CHECK-START: int Main.rotateRightIntWithByteDistance(int, byte) intrinsics_recognition (after)
- /// CHECK-DAG: <<Method:[ij]\d+>> CurrentMethod
- /// CHECK: <<ArgVal:i\d+>> ParameterValue
- /// CHECK: <<ArgDist:b\d+>> ParameterValue
- /// CHECK-DAG: <<Result:i\d+>> InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>,<<Method>>] intrinsic:IntegerRotateRight
- /// CHECK-DAG: Return [<<Result>>]
-
- /// CHECK-START: int Main.rotateRightIntWithByteDistance(int, byte) instruction_simplifier (after)
- /// CHECK: <<ArgVal:i\d+>> ParameterValue
- /// CHECK: <<ArgDist:b\d+>> ParameterValue
- /// CHECK-DAG: <<Result:i\d+>> Ror [<<ArgVal>>,<<ArgDist>>]
- /// CHECK-DAG: Return [<<Result>>]
-
- /// CHECK-START: int Main.rotateRightIntWithByteDistance(int, byte) instruction_simplifier (after)
- /// CHECK-NOT: InvokeStaticOrDirect
-
- private static int rotateRightIntWithByteDistance(int value, byte distance) {
- return Integer.rotateRight(value, distance);
- }
-
-
- public static void testRotateLeftBoolean() {
- for (int i = 0; i < 40; i++) { // overshoot a bit
- int j = i & 31;
- expectEqualsInt(0, rotateLeftBoolean(false, i));
- expectEqualsInt(1 << i, rotateLeftBoolean(true, i));
- }
- }
-
- public static void testRotateLeftByte() {
- expectEqualsInt(0x00000001, rotateLeftByte((byte)0x01, 0));
- expectEqualsInt(0x00000002, rotateLeftByte((byte)0x01, 1));
- expectEqualsInt(0x80000000, rotateLeftByte((byte)0x01, 31));
- expectEqualsInt(0x00000001, rotateLeftByte((byte)0x01, 32)); // overshoot
- expectEqualsInt(0xFFFFFF03, rotateLeftByte((byte)0x81, 1));
- expectEqualsInt(0xFFFFFE07, rotateLeftByte((byte)0x81, 2));
- expectEqualsInt(0x00000120, rotateLeftByte((byte)0x12, 4));
- expectEqualsInt(0xFFFF9AFF, rotateLeftByte((byte)0x9A, 8));
- for (int i = 0; i < 40; i++) { // overshoot a bit
- int j = i & 31;
- expectEqualsInt(0x00000000, rotateLeftByte((byte)0x0000, i));
- expectEqualsInt(0xFFFFFFFF, rotateLeftByte((byte)0xFFFF, i));
- expectEqualsInt((1 << j), rotateLeftByte((byte)0x0001, i));
- expectEqualsInt((0x12 << j) | (0x12 >>> -j), rotateLeftByte((byte)0x12, i));
- }
- }
-
- public static void testRotateLeftShort() {
- expectEqualsInt(0x00000001, rotateLeftShort((short)0x0001, 0));
- expectEqualsInt(0x00000002, rotateLeftShort((short)0x0001, 1));
- expectEqualsInt(0x80000000, rotateLeftShort((short)0x0001, 31));
- expectEqualsInt(0x00000001, rotateLeftShort((short)0x0001, 32)); // overshoot
- expectEqualsInt(0xFFFF0003, rotateLeftShort((short)0x8001, 1));
- expectEqualsInt(0xFFFE0007, rotateLeftShort((short)0x8001, 2));
- expectEqualsInt(0x00012340, rotateLeftShort((short)0x1234, 4));
- expectEqualsInt(0xFF9ABCFF, rotateLeftShort((short)0x9ABC, 8));
- for (int i = 0; i < 40; i++) { // overshoot a bit
- int j = i & 31;
- expectEqualsInt(0x00000000, rotateLeftShort((short)0x0000, i));
- expectEqualsInt(0xFFFFFFFF, rotateLeftShort((short)0xFFFF, i));
- expectEqualsInt((1 << j), rotateLeftShort((short)0x0001, i));
- expectEqualsInt((0x1234 << j) | (0x1234 >>> -j), rotateLeftShort((short)0x1234, i));
- }
- }
-
- public static void testRotateLeftChar() {
- expectEqualsInt(0x00000001, rotateLeftChar((char)0x0001, 0));
- expectEqualsInt(0x00000002, rotateLeftChar((char)0x0001, 1));
- expectEqualsInt(0x80000000, rotateLeftChar((char)0x0001, 31));
- expectEqualsInt(0x00000001, rotateLeftChar((char)0x0001, 32)); // overshoot
- expectEqualsInt(0x00010002, rotateLeftChar((char)0x8001, 1));
- expectEqualsInt(0x00020004, rotateLeftChar((char)0x8001, 2));
- expectEqualsInt(0x00012340, rotateLeftChar((char)0x1234, 4));
- expectEqualsInt(0x009ABC00, rotateLeftChar((char)0x9ABC, 8));
- expectEqualsInt(0x00FF0000, rotateLeftChar((char)0xFF00, 8));
- for (int i = 0; i < 40; i++) { // overshoot a bit
- int j = i & 31;
- expectEqualsInt(0x00000000, rotateLeftChar((char)0x0000, i));
- expectEqualsInt((1 << j), rotateLeftChar((char)0x0001, i));
- expectEqualsInt((0x1234 << j) | (0x1234 >>> -j), rotateLeftChar((char)0x1234, i));
- }
- }
-
- public static void testRotateLeftInt() {
- expectEqualsInt(0x00000001, rotateLeftInt(0x00000001, 0));
- expectEqualsInt(0x00000002, rotateLeftInt(0x00000001, 1));
- expectEqualsInt(0x80000000, rotateLeftInt(0x00000001, 31));
- expectEqualsInt(0x00000001, rotateLeftInt(0x00000001, 32)); // overshoot
- expectEqualsInt(0x00000003, rotateLeftInt(0x80000001, 1));
- expectEqualsInt(0x00000006, rotateLeftInt(0x80000001, 2));
- expectEqualsInt(0x23456781, rotateLeftInt(0x12345678, 4));
- expectEqualsInt(0xBCDEF09A, rotateLeftInt(0x9ABCDEF0, 8));
- for (int i = 0; i < 40; i++) { // overshoot a bit
- int j = i & 31;
- expectEqualsInt(0x00000000, rotateLeftInt(0x00000000, i));
- expectEqualsInt(0xFFFFFFFF, rotateLeftInt(0xFFFFFFFF, i));
- expectEqualsInt(1 << j, rotateLeftInt(0x00000001, i));
- expectEqualsInt((0x12345678 << j) | (0x12345678 >>> -j), rotateLeftInt(0x12345678, i));
- }
- }
-
- public static void testRotateLeftLong() {
- expectEqualsLong(0x0000000000000001L, rotateLeftLong(0x0000000000000001L, 0));
- expectEqualsLong(0x0000000000000002L, rotateLeftLong(0x0000000000000001L, 1));
- expectEqualsLong(0x8000000000000000L, rotateLeftLong(0x0000000000000001L, 63));
- expectEqualsLong(0x0000000000000001L, rotateLeftLong(0x0000000000000001L, 64)); // overshoot
- expectEqualsLong(0x0000000000000003L, rotateLeftLong(0x8000000000000001L, 1));
- expectEqualsLong(0x0000000000000006L, rotateLeftLong(0x8000000000000001L, 2));
- expectEqualsLong(0x23456789ABCDEF01L, rotateLeftLong(0x123456789ABCDEF0L, 4));
- expectEqualsLong(0x3456789ABCDEF012L, rotateLeftLong(0x123456789ABCDEF0L, 8));
- for (int i = 0; i < 70; i++) { // overshoot a bit
- int j = i & 63;
- expectEqualsLong(0x0000000000000000L, rotateLeftLong(0x0000000000000000L, i));
- expectEqualsLong(0xFFFFFFFFFFFFFFFFL, rotateLeftLong(0xFFFFFFFFFFFFFFFFL, i));
- expectEqualsLong(1L << j, rotateLeftLong(0x0000000000000001, i));
- expectEqualsLong((0x123456789ABCDEF0L << j) | (0x123456789ABCDEF0L >>> -j),
- rotateLeftLong(0x123456789ABCDEF0L, i));
- }
- }
-
- public static void testRotateRightBoolean() {
- for (int i = 0; i < 40; i++) { // overshoot a bit
- int j = i & 31;
- expectEqualsInt(0, rotateRightBoolean(false, i));
- expectEqualsInt(1 << (32 - i), rotateRightBoolean(true, i));
- }
- }
-
- public static void testRotateRightByte() {
- expectEqualsInt(0xFFFFFF80, rotateRightByte((byte)0x80, 0));
- expectEqualsInt(0x7FFFFFC0, rotateRightByte((byte)0x80, 1));
- expectEqualsInt(0xFFFFFF01, rotateRightByte((byte)0x80, 31));
- expectEqualsInt(0xFFFFFF80, rotateRightByte((byte)0x80, 32)); // overshoot
- expectEqualsInt(0xFFFFFFC0, rotateRightByte((byte)0x81, 1));
- expectEqualsInt(0x7FFFFFE0, rotateRightByte((byte)0x81, 2));
- expectEqualsInt(0x20000001, rotateRightByte((byte)0x12, 4));
- expectEqualsInt(0x9AFFFFFF, rotateRightByte((byte)0x9A, 8));
- for (int i = 0; i < 40; i++) { // overshoot a bit
- int j = i & 31;
- expectEqualsInt(0x00000000, rotateRightByte((byte)0x00, i));
- expectEqualsInt(0xFFFFFFFF, rotateRightByte((byte)0xFF, i));
- expectEqualsInt(1 << (32 - j), rotateRightByte((byte)0x01, i));
- expectEqualsInt((0x12 >>> j) | (0x12 << -j), rotateRightByte((byte)0x12, i));
- }
- }
-
- public static void testRotateRightShort() {
- expectEqualsInt(0xFFFF8000, rotateRightShort((short)0x8000, 0));
- expectEqualsInt(0x7FFFC000, rotateRightShort((short)0x8000, 1));
- expectEqualsInt(0xFFFF0001, rotateRightShort((short)0x8000, 31));
- expectEqualsInt(0xFFFF8000, rotateRightShort((short)0x8000, 32)); // overshoot
- expectEqualsInt(0xFFFFC000, rotateRightShort((short)0x8001, 1));
- expectEqualsInt(0x7FFFE000, rotateRightShort((short)0x8001, 2));
- expectEqualsInt(0x40000123, rotateRightShort((short)0x1234, 4));
- expectEqualsInt(0xBCFFFF9A, rotateRightShort((short)0x9ABC, 8));
- for (int i = 0; i < 40; i++) { // overshoot a bit
- int j = i & 31;
- expectEqualsInt(0x00000000, rotateRightShort((short)0x0000, i));
- expectEqualsInt(0xFFFFFFFF, rotateRightShort((short)0xFFFF, i));
- expectEqualsInt(1 << (32 - j), rotateRightShort((short)0x0001, i));
- expectEqualsInt((0x1234 >>> j) | (0x1234 << -j), rotateRightShort((short)0x1234, i));
- }
- }
-
- public static void testRotateRightChar() {
- expectEqualsInt(0x00008000, rotateRightChar((char)0x8000, 0));
- expectEqualsInt(0x00004000, rotateRightChar((char)0x8000, 1));
- expectEqualsInt(0x00010000, rotateRightChar((char)0x8000, 31));
- expectEqualsInt(0x00008000, rotateRightChar((char)0x8000, 32)); // overshoot
- expectEqualsInt(0x80004000, rotateRightChar((char)0x8001, 1));
- expectEqualsInt(0x40002000, rotateRightChar((char)0x8001, 2));
- expectEqualsInt(0x40000123, rotateRightChar((char)0x1234, 4));
- expectEqualsInt(0xBC00009A, rotateRightChar((char)0x9ABC, 8));
- for (int i = 0; i < 40; i++) { // overshoot a bit
- int j = i & 31;
- expectEqualsInt(0x00000000, rotateRightChar((char)0x0000, i));
- expectEqualsInt(1 << (32 - j), rotateRightChar((char)0x0001, i));
- expectEqualsInt((0x1234 >>> j) | (0x1234 << -j), rotateRightChar((char)0x1234, i));
- }
- }
-
- public static void testRotateRightInt() {
- expectEqualsInt(0x80000000, rotateRightInt(0x80000000, 0));
- expectEqualsInt(0x40000000, rotateRightInt(0x80000000, 1));
- expectEqualsInt(0x00000001, rotateRightInt(0x80000000, 31));
- expectEqualsInt(0x80000000, rotateRightInt(0x80000000, 32)); // overshoot
- expectEqualsInt(0xC0000000, rotateRightInt(0x80000001, 1));
- expectEqualsInt(0x60000000, rotateRightInt(0x80000001, 2));
- expectEqualsInt(0x81234567, rotateRightInt(0x12345678, 4));
- expectEqualsInt(0xF09ABCDE, rotateRightInt(0x9ABCDEF0, 8));
- for (int i = 0; i < 40; i++) { // overshoot a bit
- int j = i & 31;
- expectEqualsInt(0x00000000, rotateRightInt(0x00000000, i));
- expectEqualsInt(0xFFFFFFFF, rotateRightInt(0xFFFFFFFF, i));
- expectEqualsInt(0x80000000 >>> j, rotateRightInt(0x80000000, i));
- expectEqualsInt((0x12345678 >>> j) | (0x12345678 << -j), rotateRightInt(0x12345678, i));
- }
- }
-
- public static void testRotateRightLong() {
- expectEqualsLong(0x8000000000000000L, rotateRightLong(0x8000000000000000L, 0));
- expectEqualsLong(0x4000000000000000L, rotateRightLong(0x8000000000000000L, 1));
- expectEqualsLong(0x0000000000000001L, rotateRightLong(0x8000000000000000L, 63));
- expectEqualsLong(0x8000000000000000L, rotateRightLong(0x8000000000000000L, 64)); // overshoot
- expectEqualsLong(0xC000000000000000L, rotateRightLong(0x8000000000000001L, 1));
- expectEqualsLong(0x6000000000000000L, rotateRightLong(0x8000000000000001L, 2));
- expectEqualsLong(0x0123456789ABCDEFL, rotateRightLong(0x123456789ABCDEF0L, 4));
- expectEqualsLong(0xF0123456789ABCDEL, rotateRightLong(0x123456789ABCDEF0L, 8));
- for (int i = 0; i < 70; i++) { // overshoot a bit
- int j = i & 63;
- expectEqualsLong(0x0000000000000000L, rotateRightLong(0x0000000000000000L, i));
- expectEqualsLong(0xFFFFFFFFFFFFFFFFL, rotateRightLong(0xFFFFFFFFFFFFFFFFL, i));
- expectEqualsLong(0x8000000000000000L >>> j, rotateRightLong(0x8000000000000000L, i));
- expectEqualsLong((0x123456789ABCDEF0L >>> j) | (0x123456789ABCDEF0L << -j),
- rotateRightLong(0x123456789ABCDEF0L, i));
- }
- }
-
-
- public static void testRotateLeftIntWithByteDistance() {
- expectEqualsInt(0x00000001, rotateLeftIntWithByteDistance(0x00000001, (byte)0));
- expectEqualsInt(0x00000002, rotateLeftIntWithByteDistance(0x00000001, (byte)1));
- expectEqualsInt(0x80000000, rotateLeftIntWithByteDistance(0x00000001, (byte)31));
- expectEqualsInt(0x00000001, rotateLeftIntWithByteDistance(0x00000001, (byte)32)); // overshoot
- expectEqualsInt(0x00000003, rotateLeftIntWithByteDistance(0x80000001, (byte)1));
- expectEqualsInt(0x00000006, rotateLeftIntWithByteDistance(0x80000001, (byte)2));
- expectEqualsInt(0x23456781, rotateLeftIntWithByteDistance(0x12345678, (byte)4));
- expectEqualsInt(0xBCDEF09A, rotateLeftIntWithByteDistance(0x9ABCDEF0, (byte)8));
- for (byte i = 0; i < 40; i++) { // overshoot a bit
- byte j = (byte)(i & 31);
- expectEqualsInt(0x00000000, rotateLeftIntWithByteDistance(0x00000000, i));
- expectEqualsInt(0xFFFFFFFF, rotateLeftIntWithByteDistance(0xFFFFFFFF, i));
- expectEqualsInt(1 << j, rotateLeftIntWithByteDistance(0x00000001, i));
- expectEqualsInt((0x12345678 << j) | (0x12345678 >>> -j),
- rotateLeftIntWithByteDistance(0x12345678, i));
- }
- }
-
- public static void testRotateRightIntWithByteDistance() {
- expectEqualsInt(0x80000000, rotateRightIntWithByteDistance(0x80000000, (byte)0));
- expectEqualsInt(0x40000000, rotateRightIntWithByteDistance(0x80000000, (byte)1));
- expectEqualsInt(0x00000001, rotateRightIntWithByteDistance(0x80000000, (byte)31));
- expectEqualsInt(0x80000000, rotateRightIntWithByteDistance(0x80000000, (byte)32)); // overshoot
- expectEqualsInt(0xC0000000, rotateRightIntWithByteDistance(0x80000001, (byte)1));
- expectEqualsInt(0x60000000, rotateRightIntWithByteDistance(0x80000001, (byte)2));
- expectEqualsInt(0x81234567, rotateRightIntWithByteDistance(0x12345678, (byte)4));
- expectEqualsInt(0xF09ABCDE, rotateRightIntWithByteDistance(0x9ABCDEF0, (byte)8));
- for (byte i = 0; i < 40; i++) { // overshoot a bit
- byte j = (byte)(i & 31);
- expectEqualsInt(0x00000000, rotateRightIntWithByteDistance(0x00000000, i));
- expectEqualsInt(0xFFFFFFFF, rotateRightIntWithByteDistance(0xFFFFFFFF, i));
- expectEqualsInt(0x80000000 >>> j, rotateRightIntWithByteDistance(0x80000000, i));
- expectEqualsInt((0x12345678 >>> j) | (0x12345678 << -j),
- rotateRightIntWithByteDistance(0x12345678, i));
- }
- }
-
-
public static void main(String args[]) {
- testRotateLeftBoolean();
- testRotateLeftByte();
- testRotateLeftShort();
- testRotateLeftChar();
- testRotateLeftInt();
- testRotateLeftLong();
-
- testRotateRightBoolean();
- testRotateRightByte();
- testRotateRightShort();
- testRotateRightChar();
- testRotateRightInt();
- testRotateRightLong();
-
- // Also exercise distance values with types other than int.
- testRotateLeftIntWithByteDistance();
- testRotateRightIntWithByteDistance();
-
System.out.println("passed");
}
-
-
- private static void expectEqualsInt(int expected, int result) {
- if (expected != result) {
- throw new Error("Expected: " + expected + ", found: " + result);
- }
- }
-
- private static void expectEqualsLong(long expected, long result) {
- if (expected != result) {
- throw new Error("Expected: " + expected + ", found: " + result);
- }
- }
-}
+}
\ No newline at end of file
diff --git a/test/569-checker-pattern-replacement/build b/test/569-checker-pattern-replacement/build
deleted file mode 100644
index d85147f..0000000
--- a/test/569-checker-pattern-replacement/build
+++ /dev/null
@@ -1,20 +0,0 @@
-#!/bin/bash
-#
-# Copyright 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# See b/65168732
-export USE_D8=false
-
-./default-build "$@"
diff --git a/test/583-checker-zero/build b/test/583-checker-zero/build
deleted file mode 100644
index d85147f..0000000
--- a/test/583-checker-zero/build
+++ /dev/null
@@ -1,20 +0,0 @@
-#!/bin/bash
-#
-# Copyright 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# See b/65168732
-export USE_D8=false
-
-./default-build "$@"
diff --git a/test/639-checker-code-sinking/src/Main.java b/test/639-checker-code-sinking/src/Main.java
index a1c30f7..8efac92 100644
--- a/test/639-checker-code-sinking/src/Main.java
+++ b/test/639-checker-code-sinking/src/Main.java
@@ -343,6 +343,37 @@
}
}
+ static native void doStaticNativeCallLiveVreg();
+
+ // Test ensures that 'o' has been moved into the if despite the InvokeStaticOrDirect.
+ //
+ /// CHECK-START: void Main.testSinkingOverInvoke() code_sinking (before)
+ /// CHECK: <<Int1:i\d+>> IntConstant 1
+ /// CHECK: <<Int0:i\d+>> IntConstant 0
+ /// CHECK: <<LoadClass:l\d+>> LoadClass class_name:java.lang.Object[]
+ /// CHECK-NOT: begin_block
+ /// CHECK: NewArray [<<LoadClass>>,<<Int1>>]
+ /// CHECK: If
+ /// CHECK: begin_block
+ /// CHECK: Throw
+
+ /// CHECK-START: void Main.testSinkingOverInvoke() code_sinking (after)
+ /// CHECK: <<Int1:i\d+>> IntConstant 1
+ /// CHECK: <<Int0:i\d+>> IntConstant 0
+ /// CHECK: If
+ /// CHECK: begin_block
+ /// CHECK: <<LoadClass:l\d+>> LoadClass class_name:java.lang.Object[]
+ /// CHECK: NewArray [<<LoadClass>>,<<Int1>>]
+ /// CHECK: Throw
+ static void testSinkingOverInvoke() {
+ Object[] o = new Object[1];
+ o[0] = o;
+ doStaticNativeCallLiveVreg();
+ if (doThrow) {
+ throw new Error(o.toString());
+ }
+ }
+
public String $opt$noinline$toString() {
return "" + intField;
}
diff --git a/test/646-checker-hadd-alt-char/build b/test/646-checker-hadd-alt-char/build
deleted file mode 100644
index d85147f..0000000
--- a/test/646-checker-hadd-alt-char/build
+++ /dev/null
@@ -1,20 +0,0 @@
-#!/bin/bash
-#
-# Copyright 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# See b/65168732
-export USE_D8=false
-
-./default-build "$@"
diff --git a/test/646-checker-hadd-alt-char/src/Main.java b/test/646-checker-hadd-alt-char/src/Main.java
index 2a1382d..79904ce 100644
--- a/test/646-checker-hadd-alt-char/src/Main.java
+++ b/test/646-checker-hadd-alt-char/src/Main.java
@@ -58,7 +58,7 @@
/// CHECK-DAG: <<Get1:c\d+>> ArrayGet loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Get2:c\d+>> ArrayGet loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<And1:i\d+>> And [<<Get1>>,<<IMAX>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<And2:i\d+>> And [<<Get2>>,<<IMAX>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<And2:i\d+>> And [<<IMAX>>,<<Get2>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Add:i\d+>> Add [<<And1>>,<<And2>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<UShr:i\d+>> UShr [<<Add>>,<<I1>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Cnv:c\d+>> TypeConversion [<<UShr>>] loop:<<Loop>> outer_loop:none
@@ -120,7 +120,7 @@
/// CHECK-DAG: <<Get1:c\d+>> ArrayGet loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Get2:c\d+>> ArrayGet loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<And1:i\d+>> And [<<Get1>>,<<IMAX>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<And2:i\d+>> And [<<Get2>>,<<IMAX>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<And2:i\d+>> And [<<IMAX>>,<<Get2>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Add1:i\d+>> Add [<<And1>>,<<And2>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Add2:i\d+>> Add [<<Add1>>,<<I1>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<UShr:i\d+>> UShr [<<Add2>>,<<I1>>] loop:<<Loop>> outer_loop:none
diff --git a/test/646-checker-hadd-alt-short/build b/test/646-checker-hadd-alt-short/build
deleted file mode 100644
index d85147f..0000000
--- a/test/646-checker-hadd-alt-short/build
+++ /dev/null
@@ -1,20 +0,0 @@
-#!/bin/bash
-#
-# Copyright 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# See b/65168732
-export USE_D8=false
-
-./default-build "$@"
diff --git a/test/646-checker-hadd-alt-short/src/Main.java b/test/646-checker-hadd-alt-short/src/Main.java
index 4035b97..1ecb1d82 100644
--- a/test/646-checker-hadd-alt-short/src/Main.java
+++ b/test/646-checker-hadd-alt-short/src/Main.java
@@ -58,7 +58,7 @@
/// CHECK-DAG: <<Get1:s\d+>> ArrayGet loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Get2:s\d+>> ArrayGet loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<And1:i\d+>> And [<<Get1>>,<<UMAX>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<And2:i\d+>> And [<<Get2>>,<<UMAX>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<And2:i\d+>> And [<<UMAX>>,<<Get2>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Add:i\d+>> Add [<<And1>>,<<And2>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<UShr:i\d+>> UShr [<<Add>>,<<I1>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Cnv:s\d+>> TypeConversion [<<UShr>>] loop:<<Loop>> outer_loop:none
@@ -82,7 +82,9 @@
private static void halving_add_unsigned(short[] b1, short[] b2, short[] bo) {
int min_length = Math.min(bo.length, Math.min(b1.length, b2.length));
for (int i = 0; i < min_length; i++) {
- bo[i] = (short) (((b1[i] & 0xffff) + (b2[i] & 0xffff)) >>> 1);
+ int v1 = b1[i] & 0xffff;
+ int v2 = b2[i] & 0xffff;
+ bo[i] = (short) ((v1 + v2) >>> 1);
}
}
@@ -116,7 +118,7 @@
/// CHECK-DAG: <<Get1:s\d+>> ArrayGet loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Get2:s\d+>> ArrayGet loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<And1:i\d+>> And [<<Get1>>,<<UMAX>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<And2:i\d+>> And [<<Get2>>,<<UMAX>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<And2:i\d+>> And [<<UMAX>>,<<Get2>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Add1:i\d+>> Add [<<And1>>,<<And2>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Add2:i\d+>> Add [<<Add1>>,<<I1>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<UShr:i\d+>> UShr [<<Add2>>,<<I1>>] loop:<<Loop>> outer_loop:none
@@ -142,7 +144,9 @@
private static void rounding_halving_add_unsigned(short[] b1, short[] b2, short[] bo) {
int min_length = Math.min(bo.length, Math.min(b1.length, b2.length));
for (int i = 0; i < min_length; i++) {
- bo[i] = (short) (((b1[i] & 0xffff) + (b2[i] & 0xffff) + 1) >>> 1);
+ int v1 = b1[i] & 0xffff;
+ int v2 = b2[i] & 0xffff;
+ bo[i] = (short) ((v1 + v2 + 1) >>> 1);
}
}
diff --git a/test/646-checker-hadd-char/build b/test/646-checker-hadd-char/build
deleted file mode 100644
index d85147f..0000000
--- a/test/646-checker-hadd-char/build
+++ /dev/null
@@ -1,20 +0,0 @@
-#!/bin/bash
-#
-# Copyright 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# See b/65168732
-export USE_D8=false
-
-./default-build "$@"
diff --git a/test/646-checker-hadd-char/src/Main.java b/test/646-checker-hadd-char/src/Main.java
index 6549dab..cbe6297 100644
--- a/test/646-checker-hadd-char/src/Main.java
+++ b/test/646-checker-hadd-char/src/Main.java
@@ -67,7 +67,7 @@
/// CHECK-DAG: <<Get1:c\d+>> ArrayGet loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Get2:c\d+>> ArrayGet loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<And1:i\d+>> And [<<Get1>>,<<IMAX>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<And2:i\d+>> And [<<Get2>>,<<IMAX>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<And2:i\d+>> And [<<IMAX>>,<<Get2>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Add:i\d+>> Add [<<And1>>,<<And2>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Shr:i\d+>> Shr [<<Add>>,<<I1>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Cnv:c\d+>> TypeConversion [<<Shr>>] loop:<<Loop>> outer_loop:none
@@ -152,7 +152,7 @@
/// CHECK-DAG: <<Get1:c\d+>> ArrayGet loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Get2:c\d+>> ArrayGet loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<And1:i\d+>> And [<<Get1>>,<<IMAX>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<And2:i\d+>> And [<<Get2>>,<<IMAX>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<And2:i\d+>> And [<<IMAX>>,<<Get2>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Add1:i\d+>> Add [<<And1>>,<<And2>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Add2:i\d+>> Add [<<Add1>>,<<I1>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Shr:i\d+>> Shr [<<Add2>>,<<I1>>] loop:<<Loop>> outer_loop:none
diff --git a/test/646-checker-hadd-short/build b/test/646-checker-hadd-short/build
deleted file mode 100644
index d85147f..0000000
--- a/test/646-checker-hadd-short/build
+++ /dev/null
@@ -1,20 +0,0 @@
-#!/bin/bash
-#
-# Copyright 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# See b/65168732
-export USE_D8=false
-
-./default-build "$@"
diff --git a/test/646-checker-hadd-short/src/Main.java b/test/646-checker-hadd-short/src/Main.java
index c09da81..d78a678 100644
--- a/test/646-checker-hadd-short/src/Main.java
+++ b/test/646-checker-hadd-short/src/Main.java
@@ -86,7 +86,7 @@
/// CHECK-DAG: <<Get1:s\d+>> ArrayGet loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Get2:s\d+>> ArrayGet loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<And1:i\d+>> And [<<Get1>>,<<UMAX>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<And2:i\d+>> And [<<Get2>>,<<UMAX>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<And2:i\d+>> And [<<UMAX>>,<<Get2>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Add:i\d+>> Add [<<And1>>,<<And2>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Shr:i\d+>> Shr [<<Add>>,<<I1>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Cnv:s\d+>> TypeConversion [<<Shr>>] loop:<<Loop>> outer_loop:none
@@ -110,7 +110,9 @@
private static void halving_add_unsigned(short[] b1, short[] b2, short[] bo) {
int min_length = Math.min(bo.length, Math.min(b1.length, b2.length));
for (int i = 0; i < min_length; i++) {
- bo[i] = (short) (((b1[i] & 0xffff) + (b2[i] & 0xffff)) >> 1);
+ int v1 = b1[i] & 0xffff;
+ int v2 = b2[i] & 0xffff;
+ bo[i] = (short) ((v1 + v2) >> 1);
}
}
@@ -224,7 +226,7 @@
/// CHECK-DAG: <<Get1:s\d+>> ArrayGet loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Get2:s\d+>> ArrayGet loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<And1:i\d+>> And [<<Get1>>,<<UMAX>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<And2:i\d+>> And [<<Get2>>,<<UMAX>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<And2:i\d+>> And [<<UMAX>>,<<Get2>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Add1:i\d+>> Add [<<And1>>,<<And2>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Add2:i\d+>> Add [<<Add1>>,<<I1>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Shr:i\d+>> Shr [<<Add2>>,<<I1>>] loop:<<Loop>> outer_loop:none
@@ -250,7 +252,9 @@
private static void rounding_halving_add_unsigned(short[] b1, short[] b2, short[] bo) {
int min_length = Math.min(bo.length, Math.min(b1.length, b2.length));
for (int i = 0; i < min_length; i++) {
- bo[i] = (short) (((b1[i] & 0xffff) + (b2[i] & 0xffff) + 1) >> 1);
+ int v1 = b1[i] & 0xffff;
+ int v2 = b2[i] & 0xffff;
+ bo[i] = (short) ((v1 + v2 + 1) >> 1);
}
}
@@ -261,9 +265,9 @@
/// CHECK-DAG: <<Get1:s\d+>> ArrayGet loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Get2:s\d+>> ArrayGet loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<And1:i\d+>> And [<<Get1>>,<<UMAX>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<And2:i\d+>> And [<<Get2>>,<<UMAX>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<And2:i\d+>> And [<<UMAX>>,<<Get2>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Add1:i\d+>> Add [<<And2>>,<<I1>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<Add2:i\d+>> Add [<<And1>>,<<Add1>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Add2:i\d+>> Add [<<Add1>>,<<And1>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Shr:i\d+>> Shr [<<Add2>>,<<I1>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Cnv:s\d+>> TypeConversion [<<Shr>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: ArraySet [{{l\d+}},{{i\d+}},<<Cnv>>] loop:<<Loop>> outer_loop:none
@@ -288,7 +292,9 @@
int min_length = Math.min(bo.length, Math.min(b1.length, b2.length));
for (int i = 0; i < min_length; i++) {
// Slightly different order in idiom does not confuse recognition.
- bo[i] = (short) ((b1[i] & 0xffff) + ((b2[i] & 0xffff) + 1) >> 1);
+ int v1 = b1[i] & 0xffff;
+ int v2 = b2[i] & 0xffff;
+ bo[i] = (short) (v1 + (v2 + 1) >> 1);
}
}
diff --git a/test/660-checker-simd-sad-byte/build b/test/660-checker-simd-sad-byte/build
deleted file mode 100644
index d85147f..0000000
--- a/test/660-checker-simd-sad-byte/build
+++ /dev/null
@@ -1,20 +0,0 @@
-#!/bin/bash
-#
-# Copyright 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# See b/65168732
-export USE_D8=false
-
-./default-build "$@"
diff --git a/test/660-checker-simd-sad-byte/src/Main.java b/test/660-checker-simd-sad-byte/src/Main.java
index 778d55c..38003d1 100644
--- a/test/660-checker-simd-sad-byte/src/Main.java
+++ b/test/660-checker-simd-sad-byte/src/Main.java
@@ -90,8 +90,8 @@
/// CHECK-START: int Main.sadByte2Int(byte[], byte[]) loop_optimization (before)
/// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
/// CHECK-DAG: <<Cons1:i\d+>> IntConstant 1 loop:none
- /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Phi2:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Phi2:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Get1:b\d+>> ArrayGet [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Get2:b\d+>> ArrayGet [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Sub:i\d+>> Sub [<<Get1>>,<<Get2>>] loop:<<Loop>> outer_loop:none
@@ -121,8 +121,8 @@
/// CHECK-START: int Main.sadByte2IntAlt(byte[], byte[]) loop_optimization (before)
/// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
/// CHECK-DAG: <<Cons1:i\d+>> IntConstant 1 loop:none
- /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Phi2:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Phi2:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Get1:b\d+>> ArrayGet [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Get2:b\d+>> ArrayGet [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Sub:i\d+>> Sub [<<Get2>>,<<Get1>>] loop:<<Loop>> outer_loop:none
@@ -154,8 +154,8 @@
/// CHECK-START: int Main.sadByte2IntAlt2(byte[], byte[]) loop_optimization (before)
/// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
/// CHECK-DAG: <<Cons1:i\d+>> IntConstant 1 loop:none
- /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Phi2:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Phi2:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Get1:b\d+>> ArrayGet [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Get2:b\d+>> ArrayGet [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Sub:i\d+>> Sub [<<Get1>>,<<Get2>>] loop:<<Loop>> outer_loop:none
diff --git a/test/660-checker-simd-sad-char/build b/test/660-checker-simd-sad-char/build
deleted file mode 100644
index d85147f..0000000
--- a/test/660-checker-simd-sad-char/build
+++ /dev/null
@@ -1,20 +0,0 @@
-#!/bin/bash
-#
-# Copyright 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# See b/65168732
-export USE_D8=false
-
-./default-build "$@"
diff --git a/test/660-checker-simd-sad-char/src/Main.java b/test/660-checker-simd-sad-char/src/Main.java
index 91c92f1..18ae024 100644
--- a/test/660-checker-simd-sad-char/src/Main.java
+++ b/test/660-checker-simd-sad-char/src/Main.java
@@ -59,8 +59,8 @@
/// CHECK-START: int Main.sadChar2Int(char[], char[]) loop_optimization (before)
/// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
/// CHECK-DAG: <<Cons1:i\d+>> IntConstant 1 loop:none
- /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Phi2:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Phi2:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Get1:c\d+>> ArrayGet [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Get2:c\d+>> ArrayGet [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Sub:i\d+>> Sub [<<Get1>>,<<Get2>>] loop:<<Loop>> outer_loop:none
@@ -82,8 +82,8 @@
/// CHECK-START: int Main.sadChar2IntAlt(char[], char[]) loop_optimization (before)
/// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
/// CHECK-DAG: <<Cons1:i\d+>> IntConstant 1 loop:none
- /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Phi2:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Phi2:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Get1:c\d+>> ArrayGet [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Get2:c\d+>> ArrayGet [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Sub:i\d+>> Sub [<<Get2>>,<<Get1>>] loop:<<Loop>> outer_loop:none
@@ -107,8 +107,8 @@
/// CHECK-START: int Main.sadChar2IntAlt2(char[], char[]) loop_optimization (before)
/// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
/// CHECK-DAG: <<Cons1:i\d+>> IntConstant 1 loop:none
- /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Phi2:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Phi2:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Get1:c\d+>> ArrayGet [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Get2:c\d+>> ArrayGet [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Sub:i\d+>> Sub [<<Get1>>,<<Get2>>] loop:<<Loop>> outer_loop:none
diff --git a/test/660-checker-simd-sad-int/build b/test/660-checker-simd-sad-int/build
deleted file mode 100644
index d85147f..0000000
--- a/test/660-checker-simd-sad-int/build
+++ /dev/null
@@ -1,20 +0,0 @@
-#!/bin/bash
-#
-# Copyright 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# See b/65168732
-export USE_D8=false
-
-./default-build "$@"
diff --git a/test/660-checker-simd-sad-int/src/Main.java b/test/660-checker-simd-sad-int/src/Main.java
index 29415fd..5952c41 100644
--- a/test/660-checker-simd-sad-int/src/Main.java
+++ b/test/660-checker-simd-sad-int/src/Main.java
@@ -22,8 +22,8 @@
/// CHECK-START: int Main.sadInt2Int(int[], int[]) loop_optimization (before)
/// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
/// CHECK-DAG: <<Cons1:i\d+>> IntConstant 1 loop:none
- /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Phi2:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Phi2:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Get1:i\d+>> ArrayGet [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Get2:i\d+>> ArrayGet [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Sub:i\d+>> Sub [<<Get1>>,<<Get2>>] loop:<<Loop>> outer_loop:none
@@ -51,8 +51,8 @@
/// CHECK-START: int Main.sadInt2IntAlt(int[], int[]) loop_optimization (before)
/// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
/// CHECK-DAG: <<Cons1:i\d+>> IntConstant 1 loop:none
- /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Phi2:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Phi2:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Get1:i\d+>> ArrayGet [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Get2:i\d+>> ArrayGet [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Sub1:i\d+>> Sub [<<Get2>>,<<Get1>>] loop:<<Loop>> outer_loop:none
@@ -79,8 +79,8 @@
/// CHECK-START: int Main.sadInt2IntAlt2(int[], int[]) loop_optimization (before)
/// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
/// CHECK-DAG: <<Cons1:i\d+>> IntConstant 1 loop:none
- /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Phi2:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Phi2:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Get1:i\d+>> ArrayGet [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Get2:i\d+>> ArrayGet [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Sub:i\d+>> Sub [<<Get1>>,<<Get2>>] loop:<<Loop>> outer_loop:none
diff --git a/test/660-checker-simd-sad-short/build b/test/660-checker-simd-sad-short/build
deleted file mode 100644
index d85147f..0000000
--- a/test/660-checker-simd-sad-short/build
+++ /dev/null
@@ -1,20 +0,0 @@
-#!/bin/bash
-#
-# Copyright 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# See b/65168732
-export USE_D8=false
-
-./default-build "$@"
diff --git a/test/660-checker-simd-sad-short/src/Main.java b/test/660-checker-simd-sad-short/src/Main.java
index 77c9e53..ff74559 100644
--- a/test/660-checker-simd-sad-short/src/Main.java
+++ b/test/660-checker-simd-sad-short/src/Main.java
@@ -61,8 +61,8 @@
/// CHECK-START: int Main.sadShort2Int(short[], short[]) loop_optimization (before)
/// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
/// CHECK-DAG: <<Cons1:i\d+>> IntConstant 1 loop:none
- /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Phi2:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Phi2:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Get1:s\d+>> ArrayGet [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Get2:s\d+>> ArrayGet [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Sub:i\d+>> Sub [<<Get1>>,<<Get2>>] loop:<<Loop>> outer_loop:none
@@ -92,8 +92,8 @@
/// CHECK-START: int Main.sadShort2IntAlt(short[], short[]) loop_optimization (before)
/// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
/// CHECK-DAG: <<Cons1:i\d+>> IntConstant 1 loop:none
- /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Phi2:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Phi2:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Get1:s\d+>> ArrayGet [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Get2:s\d+>> ArrayGet [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Sub:i\d+>> Sub [<<Get2>>,<<Get1>>] loop:<<Loop>> outer_loop:none
@@ -125,8 +125,8 @@
/// CHECK-START: int Main.sadShort2IntAlt2(short[], short[]) loop_optimization (before)
/// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
/// CHECK-DAG: <<Cons1:i\d+>> IntConstant 1 loop:none
- /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Phi2:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Phi2:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Get1:s\d+>> ArrayGet [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Get2:s\d+>> ArrayGet [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Sub:i\d+>> Sub [<<Get1>>,<<Get2>>] loop:<<Loop>> outer_loop:none
@@ -161,8 +161,8 @@
/// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
/// CHECK-DAG: <<Cons1:i\d+>> IntConstant 1 loop:none
/// CHECK-DAG: <<Cons:i\d+>> IntConstant -7 loop:none
- /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Phi2:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Phi2:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Get1:s\d+>> ArrayGet [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Add:i\d+>> Add [<<Get1>>,<<Cons>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Intrin:i\d+>> Abs [<<Add>>] loop:<<Loop>> outer_loop:none
@@ -193,8 +193,8 @@
/// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
/// CHECK-DAG: <<Cons1:i\d+>> IntConstant 1 loop:none
/// CHECK-DAG: <<Cons:i\d+>> IntConstant 7 loop:none
- /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Phi2:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Phi2:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Get1:s\d+>> ArrayGet [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Sub:i\d+>> Sub [<<Get1>>,<<Cons>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Intrin:i\d+>> Abs [<<Sub>>] loop:<<Loop>> outer_loop:none
@@ -225,8 +225,8 @@
/// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
/// CHECK-DAG: <<Cons1:i\d+>> IntConstant 1 loop:none
/// CHECK-DAG: <<Cons:i\d+>> IntConstant 7 loop:none
- /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Phi2:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Phi2:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Get1:s\d+>> ArrayGet [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Add:i\d+>> Add [<<Get1>>,<<Cons>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Intrin:i\d+>> Abs [<<Add>>] loop:<<Loop>> outer_loop:none
diff --git a/test/660-checker-simd-sad-short2/build b/test/660-checker-simd-sad-short2/build
deleted file mode 100644
index d85147f..0000000
--- a/test/660-checker-simd-sad-short2/build
+++ /dev/null
@@ -1,20 +0,0 @@
-#!/bin/bash
-#
-# Copyright 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# See b/65168732
-export USE_D8=false
-
-./default-build "$@"
diff --git a/test/660-checker-simd-sad-short2/src/Main.java b/test/660-checker-simd-sad-short2/src/Main.java
index a1f9829..1ce0e2a 100644
--- a/test/660-checker-simd-sad-short2/src/Main.java
+++ b/test/660-checker-simd-sad-short2/src/Main.java
@@ -59,8 +59,8 @@
/// CHECK-START: int Main.sadCastedChar2Int(char[], char[]) instruction_simplifier (before)
/// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
/// CHECK-DAG: <<Cons1:i\d+>> IntConstant 1 loop:none
- /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Phi2:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Phi2:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<BC1:i\d+>> BoundsCheck [<<Phi1>>,{{i\d+}}] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<BC2:i\d+>> BoundsCheck [<<Phi1>>,{{i\d+}}] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Get1:c\d+>> ArrayGet [{{l\d+}},<<BC1>>] loop:<<Loop>> outer_loop:none
@@ -75,8 +75,8 @@
/// CHECK-START: int Main.sadCastedChar2Int(char[], char[]) loop_optimization (before)
/// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
/// CHECK-DAG: <<Cons1:i\d+>> IntConstant 1 loop:none
- /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Phi2:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Phi2:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Get1:s\d+>> ArrayGet [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Get2:s\d+>> ArrayGet [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Sub:i\d+>> Sub [<<Get1>>,<<Get2>>] loop:<<Loop>> outer_loop:none
@@ -106,8 +106,8 @@
/// CHECK-START: int Main.sadCastedChar2IntAlt(char[], char[]) instruction_simplifier (before)
/// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
/// CHECK-DAG: <<Cons1:i\d+>> IntConstant 1 loop:none
- /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Phi2:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Phi2:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<BC1:i\d+>> BoundsCheck [<<Phi1>>,{{i\d+}}] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<BC2:i\d+>> BoundsCheck [<<Phi1>>,{{i\d+}}] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Get1:c\d+>> ArrayGet [{{l\d+}},<<BC1>>] loop:<<Loop>> outer_loop:none
@@ -123,13 +123,11 @@
/// CHECK-START: int Main.sadCastedChar2IntAlt(char[], char[]) loop_optimization (before)
/// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
/// CHECK-DAG: <<Cons1:i\d+>> IntConstant 1 loop:none
- /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Phi2:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop>> outer_loop:none
- // Note: Get1+Cnv1 not simplified yet due to env use of Get1 in NullCheck for s2[i].
- /// CHECK-DAG: <<Get1:c\d+>> ArrayGet [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Phi2:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Get1:s\d+>> ArrayGet [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Get2:s\d+>> ArrayGet [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<Cnv1:s\d+>> TypeConversion [<<Get1>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<Sub:i\d+>> Sub [<<Get2>>,<<Cnv1>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Sub:i\d+>> Sub [<<Get2>>,<<Get1>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Intrin:i\d+>> Abs [<<Sub>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: Add [<<Phi2>>,<<Intrin>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: Add [<<Phi1>>,<<Cons1>>] loop:<<Loop>> outer_loop:none
@@ -158,8 +156,8 @@
/// CHECK-START: int Main.sadCastedChar2IntAlt2(char[], char[]) instruction_simplifier (before)
/// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
/// CHECK-DAG: <<Cons1:i\d+>> IntConstant 1 loop:none
- /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Phi2:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Phi2:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<BC1:\i\d+>> BoundsCheck [<<Phi1>>,{{i\d+}}] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<BC2:\i\d+>> BoundsCheck [<<Phi1>>,{{i\d+}}] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Get1:c\d+>> ArrayGet [{{l\d+}},<<BC1>>] loop:<<Loop>> outer_loop:none
@@ -175,13 +173,11 @@
/// CHECK-START: int Main.sadCastedChar2IntAlt2(char[], char[]) loop_optimization (before)
/// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
/// CHECK-DAG: <<Cons1:i\d+>> IntConstant 1 loop:none
- /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Phi2:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop>> outer_loop:none
- // Note: Get1+Cnv1 not simplified yet due to env use of Get1 in NullCheck for s2[i].
- /// CHECK-DAG: <<Get1:c\d+>> ArrayGet [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Phi2:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Get1:s\d+>> ArrayGet [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Get2:s\d+>> ArrayGet [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<Cnv1:s\d+>> TypeConversion [<<Get1>>] loop:<<Loop>> outer_loop:none
- /// CHECK-DAG: <<Sub:i\d+>> Sub [<<Cnv1>>,<<Get2>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Sub:i\d+>> Sub [<<Get1>>,<<Get2>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Intrin:i\d+>> Abs [<<Sub>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: Add [<<Phi2>>,<<Intrin>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: Add [<<Phi1>>,<<Cons1>>] loop:<<Loop>> outer_loop:none
diff --git a/test/660-checker-simd-sad-short3/build b/test/660-checker-simd-sad-short3/build
deleted file mode 100644
index d85147f..0000000
--- a/test/660-checker-simd-sad-short3/build
+++ /dev/null
@@ -1,20 +0,0 @@
-#!/bin/bash
-#
-# Copyright 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# See b/65168732
-export USE_D8=false
-
-./default-build "$@"
diff --git a/test/660-checker-simd-sad-short3/src/Main.java b/test/660-checker-simd-sad-short3/src/Main.java
index 877a536..d0892c3 100644
--- a/test/660-checker-simd-sad-short3/src/Main.java
+++ b/test/660-checker-simd-sad-short3/src/Main.java
@@ -25,8 +25,8 @@
/// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
/// CHECK-DAG: <<Cons1:i\d+>> IntConstant 1 loop:none
/// CHECK-DAG: <<Param:s\d+>> ParameterValue loop:none
- /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Phi2:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Phi2:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Get:s\d+>> ArrayGet [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Sub:i\d+>> Sub [<<Get>>,<<Param>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Intrin:i\d+>> Abs [<<Sub>>] loop:<<Loop>> outer_loop:none
@@ -56,8 +56,8 @@
/// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
/// CHECK-DAG: <<Cons1:i\d+>> IntConstant 1 loop:none
/// CHECK-DAG: <<Param:s\d+>> ParameterValue loop:none
- /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Phi2:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Phi2:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Get:s\d+>> ArrayGet [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Sub:i\d+>> Sub [<<Param>>,<<Get>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Intrin:i\d+>> Abs [<<Sub>>] loop:<<Loop>> outer_loop:none
@@ -87,8 +87,8 @@
/// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
/// CHECK-DAG: <<Cons1:i\d+>> IntConstant 1 loop:none
/// CHECK-DAG: <<ConsI:i\d+>> IntConstant -32767 loop:none
- /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Phi2:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Phi2:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Get:s\d+>> ArrayGet [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Add:i\d+>> Add [<<Get>>,<<ConsI>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Intrin:i\d+>> Abs [<<Add>>] loop:<<Loop>> outer_loop:none
@@ -118,8 +118,8 @@
/// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
/// CHECK-DAG: <<Cons1:i\d+>> IntConstant 1 loop:none
/// CHECK-DAG: <<ConsI:i\d+>> IntConstant 32767 loop:none
- /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Phi2:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Phi2:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Get:s\d+>> ArrayGet [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Sub:i\d+>> Sub [<<ConsI>>,<<Get>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Intrin:i\d+>> Abs [<<Sub>>] loop:<<Loop>> outer_loop:none
@@ -149,8 +149,8 @@
/// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
/// CHECK-DAG: <<Cons1:i\d+>> IntConstant 1 loop:none
/// CHECK-DAG: <<Conv:s\d+>> TypeConversion [{{i\d+}}] loop:none
- /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Phi2:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Phi2:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Get:s\d+>> ArrayGet [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Sub:i\d+>> Sub [<<Get>>,<<Conv>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Intrin:i\d+>> Abs [<<Sub>>] loop:<<Loop>> outer_loop:none
@@ -181,8 +181,8 @@
/// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
/// CHECK-DAG: <<Cons1:i\d+>> IntConstant 1 loop:none
/// CHECK-DAG: <<Conv:s\d+>> TypeConversion [{{i\d+}}] loop:none
- /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Phi2:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Phi2:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Get:s\d+>> ArrayGet [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Sub:i\d+>> Sub [<<Conv>>,<<Get>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Intrin:i\d+>> Abs [<<Sub>>] loop:<<Loop>> outer_loop:none
@@ -213,8 +213,8 @@
/// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
/// CHECK-DAG: <<Cons1:i\d+>> IntConstant 1 loop:none
/// CHECK-DAG: <<ConsI:i\d+>> IntConstant 110 loop:none
- /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Phi2:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Phi2:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Get:s\d+>> ArrayGet [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Add:i\d+>> [<<Get>>,<<ConsI>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Conv:s\d+>> TypeConversion [<<Add>>] loop:<<Loop>> outer_loop:none
@@ -248,8 +248,8 @@
/// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
/// CHECK-DAG: <<Cons1:i\d+>> IntConstant 1 loop:none
/// CHECK-DAG: <<ConsI:i\d+>> IntConstant 110 loop:none
- /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Phi2:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Phi2:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Get:s\d+>> ArrayGet [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Add:i\d+>> [<<Get>>,<<ConsI>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Conv:s\d+>> TypeConversion [<<Add>>] loop:<<Loop>> outer_loop:none
diff --git a/test/661-checker-simd-reduc/build b/test/661-checker-simd-reduc/build
deleted file mode 100644
index d85147f..0000000
--- a/test/661-checker-simd-reduc/build
+++ /dev/null
@@ -1,20 +0,0 @@
-#!/bin/bash
-#
-# Copyright 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# See b/65168732
-export USE_D8=false
-
-./default-build "$@"
diff --git a/test/661-checker-simd-reduc/src/Main.java b/test/661-checker-simd-reduc/src/Main.java
index eff2018..7b6f957 100644
--- a/test/661-checker-simd-reduc/src/Main.java
+++ b/test/661-checker-simd-reduc/src/Main.java
@@ -55,8 +55,8 @@
/// CHECK-START: int Main.reductionInt(int[]) loop_optimization (before)
/// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
/// CHECK-DAG: <<Cons1:i\d+>> IntConstant 1 loop:none
- /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Phi2:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Phi2:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Get:i\d+>> ArrayGet [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: Add [<<Phi2>>,<<Get>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: Add [<<Phi1>>,<<Cons1>>] loop:<<Loop>> outer_loop:none
@@ -130,8 +130,8 @@
/// CHECK-START: int Main.reductionIntToLoop(int[]) loop_optimization (before)
/// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
/// CHECK-DAG: <<Cons1:i\d+>> IntConstant 1 loop:none
- /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop1:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Phi2:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop1>> outer_loop:none
+ /// CHECK-DAG: <<Phi2:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop1:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop1>> outer_loop:none
/// CHECK-DAG: <<Get:i\d+>> ArrayGet [{{l\d+}},<<Phi1>>] loop:<<Loop1>> outer_loop:none
/// CHECK-DAG: Add [<<Phi2>>,<<Get>>] loop:<<Loop1>> outer_loop:none
/// CHECK-DAG: Add [<<Phi1>>,<<Cons1>>] loop:<<Loop1>> outer_loop:none
@@ -295,8 +295,8 @@
/// CHECK-START: int Main.reductionMinusInt(int[]) loop_optimization (before)
/// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
/// CHECK-DAG: <<Cons1:i\d+>> IntConstant 1 loop:none
- /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: <<Phi2:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Phi2:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Get:i\d+>> ArrayGet [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: Sub [<<Phi2>>,<<Get>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: Add [<<Phi1>>,<<Cons1>>] loop:<<Loop>> outer_loop:none
diff --git a/test/672-checker-throw-method/build b/test/672-checker-throw-method/build
deleted file mode 100644
index d85147f..0000000
--- a/test/672-checker-throw-method/build
+++ /dev/null
@@ -1,20 +0,0 @@
-#!/bin/bash
-#
-# Copyright 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# See b/65168732
-export USE_D8=false
-
-./default-build "$@"
diff --git a/test/672-checker-throw-method/src/Main.java b/test/672-checker-throw-method/src/Main.java
index a507133..360b52c 100644
--- a/test/672-checker-throw-method/src/Main.java
+++ b/test/672-checker-throw-method/src/Main.java
@@ -51,7 +51,7 @@
/// CHECK-START: void Main.doit1(int[]) code_sinking (before)
/// CHECK: begin_block
/// CHECK: <<Str:l\d+>> LoadString
- /// CHECK: <<Tst:z\d+>> NotEqual
+ /// CHECK: <<Tst:z\d+>> Equal
/// CHECK: If [<<Tst>>]
/// CHECK: end_block
/// CHECK: begin_block
@@ -61,7 +61,7 @@
//
/// CHECK-START: void Main.doit1(int[]) code_sinking (after)
/// CHECK: begin_block
- /// CHECK: <<Tst:z\d+>> NotEqual
+ /// CHECK: <<Tst:z\d+>> Equal
/// CHECK: If [<<Tst>>]
/// CHECK: end_block
/// CHECK: begin_block
@@ -109,7 +109,7 @@
/// CHECK-START: void Main.doit3(int[]) code_sinking (before)
/// CHECK: begin_block
/// CHECK: <<Str:l\d+>> LoadString
- /// CHECK: <<Tst:z\d+>> NotEqual
+ /// CHECK: <<Tst:z\d+>> Equal
/// CHECK: If [<<Tst>>]
/// CHECK: end_block
/// CHECK: begin_block
@@ -119,7 +119,7 @@
//
/// CHECK-START: void Main.doit3(int[]) code_sinking (after)
/// CHECK: begin_block
- /// CHECK: <<Tst:z\d+>> NotEqual
+ /// CHECK: <<Tst:z\d+>> Equal
/// CHECK: If [<<Tst>>]
/// CHECK: end_block
/// CHECK: begin_block
diff --git a/test/673-checker-throw-vmethod/build b/test/673-checker-throw-vmethod/build
deleted file mode 100644
index d85147f..0000000
--- a/test/673-checker-throw-vmethod/build
+++ /dev/null
@@ -1,20 +0,0 @@
-#!/bin/bash
-#
-# Copyright 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# See b/65168732
-export USE_D8=false
-
-./default-build "$@"
diff --git a/test/673-checker-throw-vmethod/src/Main.java b/test/673-checker-throw-vmethod/src/Main.java
index d0e1591..206dfaf 100644
--- a/test/673-checker-throw-vmethod/src/Main.java
+++ b/test/673-checker-throw-vmethod/src/Main.java
@@ -45,7 +45,7 @@
/// CHECK-START: void Main.doit1(int[]) code_sinking (before)
/// CHECK: begin_block
/// CHECK: <<Str:l\d+>> LoadString
- /// CHECK: <<Tst:z\d+>> NotEqual
+ /// CHECK: <<Tst:z\d+>> Equal
/// CHECK: If [<<Tst>>]
/// CHECK: end_block
/// CHECK: begin_block
@@ -55,7 +55,7 @@
//
/// CHECK-START: void Main.doit1(int[]) code_sinking (after)
/// CHECK: begin_block
- /// CHECK: <<Tst:z\d+>> NotEqual
+ /// CHECK: <<Tst:z\d+>> Equal
/// CHECK: If [<<Tst>>]
/// CHECK: end_block
/// CHECK: begin_block
@@ -103,7 +103,7 @@
/// CHECK-START: void Main.doit3(int[]) code_sinking (before)
/// CHECK: begin_block
/// CHECK: <<Str:l\d+>> LoadString
- /// CHECK: <<Tst:z\d+>> NotEqual
+ /// CHECK: <<Tst:z\d+>> Equal
/// CHECK: If [<<Tst>>]
/// CHECK: end_block
/// CHECK: begin_block
@@ -113,7 +113,7 @@
//
/// CHECK-START: void Main.doit3(int[]) code_sinking (after)
/// CHECK: begin_block
- /// CHECK: <<Tst:z\d+>> NotEqual
+ /// CHECK: <<Tst:z\d+>> Equal
/// CHECK: If [<<Tst>>]
/// CHECK: end_block
/// CHECK: begin_block
diff --git a/test/952-invoke-custom/build b/test/952-invoke-custom/build
index 2caca94..53d8228 100755
--- a/test/952-invoke-custom/build
+++ b/test/952-invoke-custom/build
@@ -21,11 +21,6 @@
INTERMEDIATE_CLASSES=classes-intermediate
CLASSES=classes
-DEXER="${DX:-dx}"
-if [ "${USE_D8=false}" = "true" ]; then
- DEXER="${ANDROID_HOST_OUT}/bin/d8-compat-dx"
-fi
-
# Create directory for intermediate classes
rm -rf "${INTERMEDIATE_CLASSES}"
mkdir "${INTERMEDIATE_CLASSES}"
@@ -46,7 +41,7 @@
# Create DEX
DX_FLAGS="${DX_FLAGS} --min-sdk-version=26 --debug --dump-width=1000"
-${DEXER} -JXmx256m --dex ${DX_FLAGS} --dump-to=${CLASSES}.lst --output=classes.dex ${CLASSES}
+${DX} -JXmx256m --dex ${DX_FLAGS} --output=classes.dex ${CLASSES}
# Zip DEX to file name expected by test runner
zip ${TEST_NAME:-classes-dex}.jar classes.dex
diff --git a/test/979-const-method-handle/build b/test/979-const-method-handle/build
index ce931a9..67fc2a6 100755
--- a/test/979-const-method-handle/build
+++ b/test/979-const-method-handle/build
@@ -22,11 +22,6 @@
TRANSFORMER_CLASSES=classes-transformer
CLASSES=classes
-DEXER="${DX:-dx}"
-if [ "${USE_D8=false}" = "true" ]; then
- DEXER="${ANDROID_HOST_OUT}/bin/d8-compat-dx"
-fi
-
# Create directories for classes
for class_dir in "${INTERMEDIATE_CLASSES}" "${TRANSFORMER_CLASSES}" "${CLASSES}"; do
rm -rf "${class_dir}"
@@ -49,7 +44,7 @@
# Create DEX
DX_FLAGS="${DX_FLAGS} --min-sdk-version=28 --debug --dump-width=1000"
-${DEXER} -JXmx256m --dex ${DX_FLAGS} --dump-to=${CLASSES}.lst --output=classes.dex ${CLASSES} ${TRANSFORMER_CLASSES}
+${DX} -JXmx256m --dex ${DX_FLAGS} --output=classes.dex ${CLASSES} ${TRANSFORMER_CLASSES}
# Zip DEX to file name expected by test runner
zip ${TEST_NAME:-classes-dex}.jar classes.dex
diff --git a/test/Android.run-test.mk b/test/Android.run-test.mk
index f8bebdd..ad292fd 100644
--- a/test/Android.run-test.mk
+++ b/test/Android.run-test.mk
@@ -140,8 +140,11 @@
$(call core-image-dependencies,$(target),$(image),$(compiler),$(address_size)))))))
test-art-host-run-test-dependencies : $(host_prereq_rules)
+.PHONY: test-art-host-run-test-dependencies
test-art-target-run-test-dependencies : $(target_prereq_rules)
+.PHONY: test-art-target-run-test-dependencies
test-art-run-test-dependencies : test-art-host-run-test-dependencies test-art-target-run-test-dependencies
+.PHONY: test-art-run-test-dependencies
# Create a rule to build and run a test group of the following form:
# test-art-{1: host target}-run-test
diff --git a/test/etc/default-build b/test/etc/default-build
index 9dbc73c..39f1a25 100755
--- a/test/etc/default-build
+++ b/test/etc/default-build
@@ -119,12 +119,13 @@
# The key for default arguments if no experimental things are enabled.
DEFAULT_EXPERIMENT="no-experiment"
-# Setup experimental flag mappings in a bash associative array.
-declare -A SMALI_EXPERIMENTAL_ARGS
-SMALI_EXPERIMENTAL_ARGS["default-methods"]="--api 24"
-SMALI_EXPERIMENTAL_ARGS["method-handles"]="--api 26"
-SMALI_EXPERIMENTAL_ARGS["var-handles"]="--api 26"
-SMALI_EXPERIMENTAL_ARGS["agents"]="--api 26"
+# Setup experimental API level mappings in a bash associative array.
+declare -A EXPERIMENTAL_API_LEVEL
+EXPERIMENTAL_API_LEVEL["default-methods"]="24"
+EXPERIMENTAL_API_LEVEL["parameter-annotations"]="25"
+EXPERIMENTAL_API_LEVEL["agents"]="26"
+EXPERIMENTAL_API_LEVEL["method-handles"]="26"
+EXPERIMENTAL_API_LEVEL["var-handles"]="28"
declare -A JAVAC_EXPERIMENTAL_ARGS
JAVAC_EXPERIMENTAL_ARGS["default-methods"]="-source 1.8 -target 1.8"
@@ -135,11 +136,6 @@
JAVAC_EXPERIMENTAL_ARGS[${DEFAULT_EXPERIMENT}]="-source 1.8 -target 1.8"
JAVAC_EXPERIMENTAL_ARGS["agents"]="-source 1.8 -target 1.8"
-declare -A DX_EXPERIMENTAL_ARGS
-DX_EXPERIMENTAL_ARGS["method-handles"]="--min-sdk-version=26"
-DX_EXPERIMENTAL_ARGS["parameter-annotations"]="--min-sdk-version=25"
-DX_EXPERIMENTAL_ARGS["var-handles"]="--min-sdk-version=28"
-
while true; do
if [ "x$1" = "x--dx-option" ]; then
shift
@@ -216,14 +212,15 @@
HAS_SRC_ART=false
fi
-# Be sure to get any default arguments if not doing any experiments.
-EXPERIMENTAL="${EXPERIMENTAL} ${DEFAULT_EXPERIMENT}"
-
# Add args from the experimental mappings.
-for experiment in ${EXPERIMENTAL}; do
- SMALI_ARGS="${SMALI_ARGS} ${SMALI_EXPERIMENTAL_ARGS[${experiment}]}"
+for experiment in ${EXPERIMENTAL} ${DEFAULT_EXPERIMENT}; do
JAVAC_ARGS="${JAVAC_ARGS} ${JAVAC_EXPERIMENTAL_ARGS[${experiment}]}"
- DX_FLAGS="${DX_FLAGS} ${DX_EXPERIMENTAL_ARGS[${experiment}]}"
+done
+
+for experiment in ${EXPERIMENTAL}; do
+ SMALI_ARGS="${SMALI_ARGS} --api ${EXPERIMENTAL_API_LEVEL[${experiment}]}"
+ DX_FLAGS="${DX_FLAGS} --min-sdk-version=${EXPERIMENTAL_API_LEVEL[${experiment}]}"
+ D8_FLAGS="--min-api ${EXPERIMENTAL_API_LEVEL[${experiment}]}"
done
#########################################
@@ -289,25 +286,33 @@
local name="$1"
local dx_input
- if [[ "$USE_DESUGAR" == "true" ]]; then
- # Make a jar first so desugar doesn't need every .class file individually.
- jar cf "$name.before-desugar.jar" -C "$name" .
-
- dx_input="${name}.desugar.jar"
-
- # Make desugared JAR.
- desugar --input "$name.before-desugar.jar" --output "$dx_input"
- else
- dx_input="${name}"
+ if [[ "$USE_DESUGAR" != "true" ]]; then
+ # Use d8 with --no-desugaring for the 3 tests that opt out of desugaring (b/110150973).
+ local d8_inputs=$(find classes -name '*.class' -type f)
+ ${D8} ${D8_FLAGS} --debug --no-desugaring --output ${name}.jar $d8_inputs && \
+ jar -xf ${name}.jar ${name}.dex && \
+ rm ${name}.jar
+ return $?
fi
+ # Make a jar first so desugar doesn't need every .class file individually.
+ jar cf "$name.before-desugar.jar" -C "$name" .
+
+ # Make desugared JAR.
+ dx_input="${name}.desugar.jar"
+ desugar --input "$name.before-desugar.jar" --output "$dx_input"
+
local dexer="${DX}"
if [[ "${USE_D8}" != "false" ]]; then
dexer="${ANDROID_HOST_OUT}/bin/d8-compat-dx"
fi
# Make dex file from desugared JAR.
- ${dexer} -JXmx256m ${DX_VM_FLAGS} --debug --dex --dump-to=${name}.lst --output=${name}.dex --dump-width=1000 ${DX_FLAGS} "${dx_input}"
+ local dexer_flags="${DX_FLAGS} --debug --dex"
+ if [ $DEV_MODE = "yes" ]; then
+ echo ${dexer} -JXmx256m ${DX_VM_FLAGS} $dexer_flags --output=${name}.dex "${dx_input}"
+ fi
+ ${dexer} -JXmx256m ${DX_VM_FLAGS} $dexer_flags --output=${name}.dex "${dx_input}"
}
# Merge all the dex files in $1..$N into $1. Skip non-existing files, but at least 1 file must exist.
@@ -432,8 +437,7 @@
# Compile Jasmin classes as if they were part of the classes.dex file.
make_jasmin jasmin_classes $(find 'jasmin' -name '*.j')
if [[ "${NEED_DEX}" == "true" ]]; then
- # Disable desugar because it won't handle intentional linkage errors.
- USE_DESUGAR=false make_dex jasmin_classes
+ make_dex jasmin_classes
make_dexmerge classes.dex jasmin_classes.dex
else
# Move jasmin classes into classes directory so that they are picked up with -cp classes.
@@ -458,10 +462,7 @@
make_jasmin jasmin_classes2 $(find 'jasmin-multidex' -name '*.j')
if [[ "${NEED_DEX}" == "true" ]]; then
- # Disable desugar because it won't handle intentional linkage errors.
- USE_DESUGAR=false make_dex jasmin_classes2
-
- # Merge jasmin_classes2.dex into classes2.dex
+ make_dex jasmin_classes2
make_dexmerge classes2.dex jasmin_classes2.dex
else
# Move jasmin classes into classes2 directory so that they are picked up with -cp classes2.
diff --git a/test/run-test b/test/run-test
index 5bd8b3b..b5b4285 100755
--- a/test/run-test
+++ b/test/run-test
@@ -529,12 +529,27 @@
# Most interesting target architecture variables are Makefile variables, not environment variables.
# Try to map the suffix64 flag and what we find in ${ANDROID_PRODUCT_OUT}/data/art-test to an architecture name.
function guess_target_arch_name() {
- grep32bit=`ls ${ANDROID_PRODUCT_OUT}/data/art-test | grep -E '^(arm|x86|mips)$'`
- grep64bit=`ls ${ANDROID_PRODUCT_OUT}/data/art-test | grep -E '^(arm64|x86_64|mips64)$'`
- if [ "x${suffix64}" = "x64" ]; then
- target_arch_name=${grep64bit}
+ # Check whether this is a device with native bridge. Currently this is hardcoded
+ # to x86 + arm.
+ x86_arm=`ls ${ANDROID_PRODUCT_OUT}/data/art-test | sort | grep -E '^(arm|x86)$'`
+ # Collapse line-breaks into spaces
+ x86_arm=$(echo $x86_arm)
+ if [ "x$x86_arm" = "xarm x86" ] ; then
+ err_echo "Native-bridge configuration detected."
+ # We only support the main arch for tests.
+ if [ "x${suffix64}" = "x64" ]; then
+ target_arch_name=""
+ else
+ target_arch_name=x86
+ fi
else
- target_arch_name=${grep32bit}
+ grep32bit=`ls ${ANDROID_PRODUCT_OUT}/data/art-test | grep -E '^(arm|x86|mips)$'`
+ grep64bit=`ls ${ANDROID_PRODUCT_OUT}/data/art-test | grep -E '^(arm64|x86_64|mips64)$'`
+ if [ "x${suffix64}" = "x64" ]; then
+ target_arch_name=${grep64bit}
+ else
+ target_arch_name=${grep32bit}
+ fi
fi
}
diff --git a/test/testrunner/target_config.py b/test/testrunner/target_config.py
index 68efcaf..1924cee 100644
--- a/test/testrunner/target_config.py
+++ b/test/testrunner/target_config.py
@@ -265,14 +265,8 @@
'ART_USE_READ_BARRIER' : 'false'
}
},
- 'art-gtest-valgrind32': {
- # Disabled: Valgrind is no longer supported.
- # Historical note: This was already disabled, as x86 valgrind did not understand SSE4.x
- # 'make' : 'valgrind-test-art-host32',
- 'env': {
- 'ART_USE_READ_BARRIER' : 'false'
- }
- },
+ # TODO: Remove this configuration, when the ART Buildbot is no
+ # longer using it for 'host-x86_64-valgrind'.
'art-gtest-valgrind64': {
# Disabled: Valgrind is no longer supported.
# 'make' : 'valgrind-test-art-host64',
@@ -293,10 +287,12 @@
'ASAN_OPTIONS' : 'detect_leaks=0'
}
},
+ # TODO: Also exercise '--interp-ac' in 'art-asan', when b/109813469 is addressed.
'art-asan': {
'run-test' : ['--interpreter',
'--optimizing',
- '--jit'],
+ '--jit',
+ '--speed-profile'],
'env': {
'SANITIZE_HOST' : 'address',
'ASAN_OPTIONS' : 'detect_leaks=0'
diff --git a/tools/ahat/Android.mk b/tools/ahat/Android.mk
index 9f423ba..2741a92 100644
--- a/tools/ahat/Android.mk
+++ b/tools/ahat/Android.mk
@@ -28,9 +28,6 @@
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE := ahat
-# Let users with Java 7 run ahat (b/28303627)
-LOCAL_JAVA_LANGUAGE_VERSION := 1.7
-
# Make this available on the classpath of the general-tests tradefed suite.
# It is used by libcore tests that run there.
LOCAL_COMPATIBILITY_SUITE := general-tests
diff --git a/tools/ahat/AndroidTest.xml b/tools/ahat/AndroidTest.xml
index 867658c..b07905a 100644
--- a/tools/ahat/AndroidTest.xml
+++ b/tools/ahat/AndroidTest.xml
@@ -14,6 +14,8 @@
limitations under the License.
-->
<configuration description="Runs the ahat unit tests">
+ <option name="test-suite-tag" value="ahat" />
+ <option name="test-suite-tag" value="art-tools" />
<option name="null-device" value="true" />
<test class="com.android.tradefed.testtype.HostTest" >
<option name="class" value="com.android.ahat.AhatTestSuite" />
diff --git a/tools/ahat/etc/ahat_api.txt b/tools/ahat/etc/ahat_api.txt
index 93fe46b..6fc62e7 100644
--- a/tools/ahat/etc/ahat_api.txt
+++ b/tools/ahat/etc/ahat_api.txt
@@ -10,6 +10,7 @@
public class DominatorsComputation {
method public static void computeDominators(com.android.ahat.dominators.DominatorsComputation.Node);
+ method public static void computeDominators(com.android.ahat.dominators.DominatorsComputation.Node, com.android.ahat.progress.Progress, long);
}
public static abstract interface DominatorsComputation.Node {
@@ -27,12 +28,10 @@
method public int getLength();
method public com.android.ahat.heapdump.Value getValue(int);
method public java.util.List<com.android.ahat.heapdump.Value> getValues();
- method public java.lang.String toString();
}
public class AhatClassInstance extends com.android.ahat.heapdump.AhatInstance {
method public java.lang.Iterable<com.android.ahat.heapdump.FieldValue> getInstanceFields();
- method public java.lang.String toString();
}
public class AhatClassObj extends com.android.ahat.heapdump.AhatInstance {
@@ -42,7 +41,6 @@
method public java.lang.String getName();
method public java.util.List<com.android.ahat.heapdump.FieldValue> getStaticFieldValues();
method public com.android.ahat.heapdump.AhatClassObj getSuperClassObj();
- method public java.lang.String toString();
}
public class AhatHeap implements com.android.ahat.heapdump.Diffable {
@@ -157,8 +155,13 @@
}
public class Parser {
+ ctor public Parser(java.nio.ByteBuffer);
+ ctor public Parser(java.io.File) throws java.io.IOException;
+ method public com.android.ahat.heapdump.Parser map(com.android.ahat.proguard.ProguardMap);
+ method public com.android.ahat.heapdump.AhatSnapshot parse() throws com.android.ahat.heapdump.HprofFormatException, java.io.IOException;
method public static com.android.ahat.heapdump.AhatSnapshot parseHeapDump(java.io.File, com.android.ahat.proguard.ProguardMap) throws com.android.ahat.heapdump.HprofFormatException, java.io.IOException;
method public static com.android.ahat.heapdump.AhatSnapshot parseHeapDump(java.nio.ByteBuffer, com.android.ahat.proguard.ProguardMap) throws com.android.ahat.heapdump.HprofFormatException, java.io.IOException;
+ method public com.android.ahat.heapdump.Parser progress(com.android.ahat.progress.Progress);
}
public class PathElement implements com.android.ahat.heapdump.Diffable {
@@ -284,6 +287,26 @@
}
+package com.android.ahat.progress {
+
+ public class NullProgress implements com.android.ahat.progress.Progress {
+ ctor public NullProgress();
+ method public void advance(long);
+ method public void done();
+ method public void start(java.lang.String, long);
+ method public void update(long);
+ }
+
+ public abstract interface Progress {
+ method public default void advance();
+ method public abstract void advance(long);
+ method public abstract void done();
+ method public abstract void start(java.lang.String, long);
+ method public abstract void update(long);
+ }
+
+}
+
package com.android.ahat.proguard {
public class ProguardMap {
diff --git a/tools/ahat/src/main/com/android/ahat/AsciiProgress.java b/tools/ahat/src/main/com/android/ahat/AsciiProgress.java
new file mode 100644
index 0000000..3ac98a4
--- /dev/null
+++ b/tools/ahat/src/main/com/android/ahat/AsciiProgress.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ahat;
+
+import com.android.ahat.progress.Progress;
+
+/**
+ * A progress bar that prints ascii to System.out.
+ * <p>
+ * For best results, have System.out positioned at a new line before using
+ * this progress indicator.
+ */
+class AsciiProgress implements Progress {
+ private String description;
+ private long duration;
+ private long progress;
+
+ private static void display(String description, long percent) {
+ System.out.print(String.format("\r[ %3d%% ] %s ...", percent, description));
+ System.out.flush();
+ }
+
+ @Override
+ public void start(String description, long duration) {
+ assert this.description == null;
+ this.description = description;
+ this.duration = duration;
+ this.progress = 0;
+ display(description, 0);
+ }
+
+ @Override
+ public void advance(long n) {
+ update(progress + n);
+ }
+
+ @Override
+ public void update(long current) {
+ assert description != null;
+ long oldPercent = progress * 100 / duration;
+ long newPercent = current * 100 / duration;
+ progress = current;
+
+ if (newPercent > oldPercent) {
+ display(description, newPercent);
+ }
+ }
+
+ @Override
+ public void done() {
+ update(duration);
+ System.out.println();
+ this.description = null;
+ }
+}
diff --git a/tools/ahat/src/main/com/android/ahat/Main.java b/tools/ahat/src/main/com/android/ahat/Main.java
index af197d4..d3cfcf9 100644
--- a/tools/ahat/src/main/com/android/ahat/Main.java
+++ b/tools/ahat/src/main/com/android/ahat/Main.java
@@ -20,6 +20,7 @@
import com.android.ahat.heapdump.Diff;
import com.android.ahat.heapdump.HprofFormatException;
import com.android.ahat.heapdump.Parser;
+import com.android.ahat.progress.Progress;
import com.android.ahat.proguard.ProguardMap;
import com.sun.net.httpserver.HttpServer;
import java.io.File;
@@ -58,10 +59,10 @@
* Prints an error message and exits the application on failure to load the
* heap dump.
*/
- private static AhatSnapshot loadHeapDump(File hprof, ProguardMap map) {
+ private static AhatSnapshot loadHeapDump(File hprof, ProguardMap map, Progress progress) {
System.out.println("Processing '" + hprof + "' ...");
try {
- return Parser.parseHeapDump(hprof, map);
+ return new Parser(hprof).map(map).progress(progress).parse();
} catch (IOException e) {
System.err.println("Unable to load '" + hprof + "':");
e.printStackTrace();
@@ -152,9 +153,9 @@
System.exit(1);
}
- AhatSnapshot ahat = loadHeapDump(hprof, map);
+ AhatSnapshot ahat = loadHeapDump(hprof, map, new AsciiProgress());
if (hprofbase != null) {
- AhatSnapshot base = loadHeapDump(hprofbase, mapbase);
+ AhatSnapshot base = loadHeapDump(hprofbase, mapbase, new AsciiProgress());
System.out.println("Diffing heap dumps ...");
Diff.snapshots(ahat, base);
diff --git a/tools/ahat/src/main/com/android/ahat/dominators/DominatorsComputation.java b/tools/ahat/src/main/com/android/ahat/dominators/DominatorsComputation.java
index 6185dee..903211e 100644
--- a/tools/ahat/src/main/com/android/ahat/dominators/DominatorsComputation.java
+++ b/tools/ahat/src/main/com/android/ahat/dominators/DominatorsComputation.java
@@ -16,6 +16,8 @@
package com.android.ahat.dominators;
+import com.android.ahat.progress.NullProgress;
+import com.android.ahat.progress.Progress;
import java.util.ArrayDeque;
import java.util.Arrays;
import java.util.Deque;
@@ -146,6 +148,10 @@
// If revisit != null, this node is on the global list of nodes to be
// revisited.
public NodeSet revisit = null;
+
+ // Distance from the root to this node. Used for purposes of tracking
+ // progress only.
+ public long depth;
}
// A collection of node ids.
@@ -245,6 +251,23 @@
* @see Node
*/
public static void computeDominators(Node root) {
+ computeDominators(root, new NullProgress(), 0);
+ }
+
+ /**
+ * Computes the immediate dominators of all nodes reachable from the <code>root</code> node.
+ * There must not be any incoming references to the <code>root</code> node.
+ * <p>
+ * The result of this function is to call the {@link Node#setDominator}
+ * function on every node reachable from the root node.
+ *
+ * @param root the root node of the dominators computation
+ * @param progress progress tracker.
+ * @param numNodes upper bound on the number of reachable nodes in the
+ * graph, for progress tracking purposes only.
+ * @see Node
+ */
+ public static void computeDominators(Node root, Progress progress, long numNodes) {
long id = 0;
// The set of nodes xS such that xS.revisit != null.
@@ -257,6 +280,7 @@
NodeS rootS = new NodeS();
rootS.node = root;
rootS.id = id++;
+ rootS.depth = 0;
root.setDominatorsComputationState(rootS);
Deque<Link> dfs = new ArrayDeque<Link>();
@@ -265,8 +289,14 @@
dfs.push(new Link(rootS, child));
}
+ // workBound is an upper bound on the amount of work required in the
+ // second phase of dominators computation, used solely for the purposes of
+ // tracking progress.
+ long workBound = 0;
+
// 1. Do a depth first search of the nodes, label them with ids and come
// up with initial candidate dominators for them.
+ progress.start("Initializing dominators", numNodes);
while (!dfs.isEmpty()) {
Link link = dfs.pop();
@@ -274,6 +304,7 @@
// This is the marker link indicating we have now visited all
// nodes reachable from link.srcS.
link.srcS.maxReachableId = id - 1;
+ progress.advance();
} else {
NodeS dstS = (NodeS)link.dst.getDominatorsComputationState();
if (dstS == null) {
@@ -288,6 +319,7 @@
dstS.domS = link.srcS;
dstS.domS.dominated.add(dstS);
dstS.oldDomS = link.srcS;
+ dstS.depth = link.srcS.depth + 1;
dfs.push(new Link(dstS));
for (Node child : link.dst.getReferencesForDominators()) {
@@ -296,6 +328,10 @@
} else {
// We have seen the destination node before. Update the state based
// on the new potential dominator.
+ if (dstS.inRefIds.size == 1) {
+ workBound += dstS.oldDomS.depth;
+ }
+
long seenid = dstS.inRefIds.last();
dstS.inRefIds.add(link.srcS.id);
@@ -330,9 +366,11 @@
}
}
}
+ progress.done();
// 2. Continue revisiting nodes until every node satisfies the requirement
// that domS.id == oldDomS.id.
+ progress.start("Resolving dominators", workBound);
while (!revisit.isEmpty()) {
NodeS oldDomS = revisit.poll();
assert oldDomS.revisit != null;
@@ -388,7 +426,10 @@
nodeS.oldDomS.revisit.add(nodeS);
}
}
+ progress.advance((oldDomS.depth - oldDomS.oldDomS.depth) * nodes.size);
}
+ progress.done();
+
// 3. We have figured out the correct dominator for each node. Notify the
// user of the results by doing one last traversal of the nodes.
diff --git a/tools/ahat/src/main/com/android/ahat/heapdump/AhatInstance.java b/tools/ahat/src/main/com/android/ahat/heapdump/AhatInstance.java
index 67253bf..95553a2 100644
--- a/tools/ahat/src/main/com/android/ahat/heapdump/AhatInstance.java
+++ b/tools/ahat/src/main/com/android/ahat/heapdump/AhatInstance.java
@@ -17,6 +17,7 @@
package com.android.ahat.heapdump;
import com.android.ahat.dominators.DominatorsComputation;
+import com.android.ahat.progress.Progress;
import java.awt.image.BufferedImage;
import java.util.ArrayDeque;
import java.util.ArrayList;
@@ -603,10 +604,16 @@
* mNextInstanceToGcRootField
* mHardReverseReferences
* mSoftReverseReferences
+ *
+ * @param progress used to track progress of the traversal.
+ * @param numInsts upper bound on the total number of instances reachable
+ * from the root, solely used for the purposes of tracking
+ * progress.
*/
- static void computeReverseReferences(SuperRoot root) {
+ static void computeReverseReferences(SuperRoot root, Progress progress, long numInsts) {
// Start by doing a breadth first search through strong references.
// Then continue the breadth first search through weak references.
+ progress.start("Reversing references", numInsts);
Queue<Reference> strong = new ArrayDeque<Reference>();
Queue<Reference> weak = new ArrayDeque<Reference>();
@@ -620,6 +627,7 @@
if (ref.ref.mNextInstanceToGcRoot == null) {
// This is the first time we have seen ref.ref.
+ progress.advance();
ref.ref.mNextInstanceToGcRoot = ref.src;
ref.ref.mNextInstanceToGcRootField = ref.field;
ref.ref.mHardReverseReferences = new ArrayList<AhatInstance>();
@@ -646,6 +654,7 @@
if (ref.ref.mNextInstanceToGcRoot == null) {
// This is the first time we have seen ref.ref.
+ progress.advance();
ref.ref.mNextInstanceToGcRoot = ref.src;
ref.ref.mNextInstanceToGcRootField = ref.field;
ref.ref.mHardReverseReferences = new ArrayList<AhatInstance>();
@@ -664,6 +673,8 @@
ref.ref.mSoftReverseReferences.add(ref.src);
}
}
+
+ progress.done();
}
/**
diff --git a/tools/ahat/src/main/com/android/ahat/heapdump/AhatSnapshot.java b/tools/ahat/src/main/com/android/ahat/heapdump/AhatSnapshot.java
index 535db08..bc94047 100644
--- a/tools/ahat/src/main/com/android/ahat/heapdump/AhatSnapshot.java
+++ b/tools/ahat/src/main/com/android/ahat/heapdump/AhatSnapshot.java
@@ -17,6 +17,7 @@
package com.android.ahat.heapdump;
import com.android.ahat.dominators.DominatorsComputation;
+import com.android.ahat.progress.Progress;
import java.util.List;
/**
@@ -39,7 +40,8 @@
AhatSnapshot(SuperRoot root,
Instances<AhatInstance> instances,
List<AhatHeap> heaps,
- Site rootSite) {
+ Site rootSite,
+ Progress progress) {
mSuperRoot = root;
mInstances = instances;
mHeaps = heaps;
@@ -53,8 +55,8 @@
}
}
- AhatInstance.computeReverseReferences(mSuperRoot);
- DominatorsComputation.computeDominators(mSuperRoot);
+ AhatInstance.computeReverseReferences(mSuperRoot, progress, mInstances.size());
+ DominatorsComputation.computeDominators(mSuperRoot, progress, mInstances.size());
AhatInstance.computeRetainedSize(mSuperRoot, mHeaps.size());
for (AhatHeap heap : mHeaps) {
diff --git a/tools/ahat/src/main/com/android/ahat/heapdump/Instances.java b/tools/ahat/src/main/com/android/ahat/heapdump/Instances.java
index 0851446..7bb19a2 100644
--- a/tools/ahat/src/main/com/android/ahat/heapdump/Instances.java
+++ b/tools/ahat/src/main/com/android/ahat/heapdump/Instances.java
@@ -67,6 +67,10 @@
return null;
}
+ public int size() {
+ return mInstances.size();
+ }
+
@Override
public Iterator<T> iterator() {
return mInstances.iterator();
diff --git a/tools/ahat/src/main/com/android/ahat/heapdump/Parser.java b/tools/ahat/src/main/com/android/ahat/heapdump/Parser.java
index 13be57d..597a260 100644
--- a/tools/ahat/src/main/com/android/ahat/heapdump/Parser.java
+++ b/tools/ahat/src/main/com/android/ahat/heapdump/Parser.java
@@ -16,6 +16,8 @@
package com.android.ahat.heapdump;
+import com.android.ahat.progress.NullProgress;
+import com.android.ahat.progress.Progress;
import com.android.ahat.proguard.ProguardMap;
import java.io.File;
import java.io.IOException;
@@ -33,35 +35,95 @@
/**
* Provides methods for parsing heap dumps.
+ * <p>
+ * The heap dump should be a heap dump in the J2SE HPROF format optionally
+ * with Android extensions and satisfying the following additional
+ * constraints:
+ * <ul>
+ * <li>
+ * Class serial numbers, stack frames, and stack traces individually satisfy
+ * the following:
+ * <ul>
+ * <li> All elements are defined before they are referenced.
+ * <li> Ids are densely packed in some range [a, b] where a is not necessarily 0.
+ * <li> There are not more than 2^31 elements defined.
+ * </ul>
+ * <li> All classes are defined via a LOAD CLASS record before the first
+ * heap dump segment.
+ * <li> The ID size used in the heap dump is 4 bytes.
+ * </ul>
*/
public class Parser {
private static final int ID_SIZE = 4;
- private Parser() {
+ private HprofBuffer hprof = null;
+ private ProguardMap map = new ProguardMap();
+ private Progress progress = new NullProgress();
+
+ /**
+ * Creates an hprof Parser that parses a heap dump from a byte buffer.
+ *
+ * @param hprof byte buffer to parse the heap dump from.
+ */
+ public Parser(ByteBuffer hprof) {
+ this.hprof = new HprofBuffer(hprof);
}
/**
- * Parses a heap dump from a File.
- * <p>
- * The heap dump should be a heap dump in the J2SE HPROF format optionally
- * with Android extensions and satisfying the following additional
- * constraints:
- * <ul>
- * <li>
- * Class serial numbers, stack frames, and stack traces individually satisfy
- * the following:
- * <ul>
- * <li> All elements are defined before they are referenced.
- * <li> Ids are densely packed in some range [a, b] where a is not necessarily 0.
- * <li> There are not more than 2^31 elements defined.
- * </ul>
- * <li> All classes are defined via a LOAD CLASS record before the first
- * heap dump segment.
- * <li> The ID size used in the heap dump is 4 bytes.
- * </ul>
- * <p>
- * The given proguard map will be used to deobfuscate class names, field
- * names, and stack traces in the heap dump.
+ * Creates an hprof Parser that parses a heap dump from a file.
+ *
+ * @param hprof file to parse the heap dump from.
+ * @throws IOException if the file cannot be accessed.
+ */
+ public Parser(File hprof) throws IOException {
+ this.hprof = new HprofBuffer(hprof);
+ }
+
+ /**
+ * Sets the proguard map to use for deobfuscating the heap.
+ *
+ * @param map proguard map to use to deobfuscate the heap.
+ * @return this Parser instance.
+ */
+ public Parser map(ProguardMap map) {
+ if (map == null) {
+ throw new NullPointerException("map == null");
+ }
+ this.map = map;
+ return this;
+ }
+
+ /**
+ * Sets the progress indicator to use when parsing the heap.
+ *
+ * @param progress progress indicator to use when parsing the heap.
+ * @return this Parser instance.
+ */
+ public Parser progress(Progress progress) {
+ if (progress == null) {
+ throw new NullPointerException("progress == null");
+ }
+ this.progress = progress;
+ return this;
+ }
+
+ /**
+ * Parse the heap dump.
+ *
+ * @throws IOException if the heap dump could not be read
+ * @throws HprofFormatException if the heap dump is not properly formatted
+ * @return the parsed heap dump
+ */
+ public AhatSnapshot parse() throws IOException, HprofFormatException {
+ try {
+ return parseInternal();
+ } catch (BufferUnderflowException e) {
+ throw new HprofFormatException("Unexpected end of file", e);
+ }
+ }
+
+ /**
+ * Parses a heap dump from a File with given proguard map.
*
* @param hprof the hprof file to parse
* @param map the proguard map for deobfuscation
@@ -71,35 +133,11 @@
*/
public static AhatSnapshot parseHeapDump(File hprof, ProguardMap map)
throws IOException, HprofFormatException {
- try {
- return parseHeapDump(new HprofBuffer(hprof), map);
- } catch (BufferUnderflowException e) {
- throw new HprofFormatException("Unexpected end of file", e);
- }
+ return new Parser(hprof).map(map).parse();
}
/**
- * Parses a heap dump from a byte buffer.
- * <p>
- * The heap dump should be a heap dump in the J2SE HPROF format optionally
- * with Android extensions and satisfying the following additional
- * constraints:
- * <ul>
- * <li>
- * Class serial numbers, stack frames, and stack traces individually satisfy
- * the following:
- * <ul>
- * <li> All elements are defined before they are referenced.
- * <li> Ids are densely packed in some range [a, b] where a is not necessarily 0.
- * <li> There are not more than 2^31 elements defined.
- * </ul>
- * <li> All classes are defined via a LOAD CLASS record before the first
- * heap dump segment.
- * <li> The ID size used in the heap dump is 4 bytes.
- * </ul>
- * <p>
- * The given proguard map will be used to deobfuscate class names, field
- * names, and stack traces in the heap dump.
+ * Parses a heap dump from a byte buffer with given proguard map.
*
* @param hprof the bytes of the hprof file to parse
* @param map the proguard map for deobfuscation
@@ -109,15 +147,10 @@
*/
public static AhatSnapshot parseHeapDump(ByteBuffer hprof, ProguardMap map)
throws IOException, HprofFormatException {
- try {
- return parseHeapDump(new HprofBuffer(hprof), map);
- } catch (BufferUnderflowException e) {
- throw new HprofFormatException("Unexpected end of file", e);
- }
+ return new Parser(hprof).map(map).parse();
}
- private static AhatSnapshot parseHeapDump(HprofBuffer hprof, ProguardMap map)
- throws IOException, HprofFormatException, BufferUnderflowException {
+ private AhatSnapshot parseInternal() throws IOException, HprofFormatException {
// Read, and mostly ignore, the hprof header info.
{
StringBuilder format = new StringBuilder();
@@ -154,7 +187,9 @@
ArrayList<AhatClassObj> classes = new ArrayList<AhatClassObj>();
Instances<AhatClassObj> classById = null;
+ progress.start("Reading hprof", hprof.size());
while (hprof.hasRemaining()) {
+ progress.update(hprof.tell());
int tag = hprof.getU1();
int time = hprof.getU4();
int recordLength = hprof.getU4();
@@ -230,6 +265,7 @@
}
int subtag;
while (!isEndOfHeapDumpSegment(subtag = hprof.getU1())) {
+ progress.update(hprof.tell());
switch (subtag) {
case 0x01: { // ROOT JNI GLOBAL
long objectId = hprof.getId();
@@ -524,6 +560,7 @@
break;
}
}
+ progress.done();
instances.addAll(classes);
}
@@ -542,9 +579,11 @@
// that we couldn't previously resolve.
SuperRoot superRoot = new SuperRoot();
{
+ progress.start("Resolving references", mInstances.size());
Iterator<RootData> ri = roots.iterator();
RootData root = ri.next();
for (AhatInstance inst : mInstances) {
+ progress.advance();
long id = inst.getId();
// Skip past any roots that don't have associated instances.
@@ -613,11 +652,12 @@
((AhatArrayInstance)inst).initialize(array);
}
}
+ progress.done();
}
hprof = null;
roots = null;
- return new AhatSnapshot(superRoot, mInstances, heaps.heaps, rootSite);
+ return new AhatSnapshot(superRoot, mInstances, heaps.heaps, rootSite, progress);
}
private static boolean isEndOfHeapDumpSegment(int subtag) {
@@ -867,6 +907,13 @@
}
/**
+ * Returns the size of the file in bytes.
+ */
+ public int size() {
+ return mBuffer.capacity();
+ }
+
+ /**
* Return the current absolution position in the file.
*/
public int tell() {
diff --git a/tools/ahat/src/main/com/android/ahat/heapdump/Value.java b/tools/ahat/src/main/com/android/ahat/heapdump/Value.java
index b219bf1..d78f95b 100644
--- a/tools/ahat/src/main/com/android/ahat/heapdump/Value.java
+++ b/tools/ahat/src/main/com/android/ahat/heapdump/Value.java
@@ -209,7 +209,7 @@
@Override
public abstract String toString();
- private Value getBaseline() {
+ Value getBaseline() {
return this;
}
@@ -396,7 +396,8 @@
return mInstance.toString();
}
- public Value getBaseline() {
+ @Override
+ Value getBaseline() {
return InstanceValue.pack(mInstance.getBaseline());
}
diff --git a/tools/ahat/src/main/com/android/ahat/progress/NullProgress.java b/tools/ahat/src/main/com/android/ahat/progress/NullProgress.java
new file mode 100644
index 0000000..a0ca084
--- /dev/null
+++ b/tools/ahat/src/main/com/android/ahat/progress/NullProgress.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ahat.progress;
+
+/**
+ * Null progress tracker that ignores all updates.
+ */
+public class NullProgress implements Progress {
+ @Override public void start(String description, long duration) { }
+ @Override public void advance() { }
+ @Override public void advance(long n) { }
+ @Override public void update(long current) { }
+ @Override public void done() { }
+}
diff --git a/tools/ahat/src/main/com/android/ahat/progress/Progress.java b/tools/ahat/src/main/com/android/ahat/progress/Progress.java
new file mode 100644
index 0000000..a10379d
--- /dev/null
+++ b/tools/ahat/src/main/com/android/ahat/progress/Progress.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ahat.progress;
+
+/**
+ * Interface for notifying users of progress during long operations.
+ */
+public interface Progress {
+ /**
+ * Called to indicate the start of a new phase of work with the given
+ * duration. Behavior is undefined if there is a current phase in progress.
+ *
+ * @param description human readable description of the work to be done.
+ * @param duration the maximum duration of the phase, in arbitrary units
+ * appropriate for the work in question.
+ */
+ void start(String description, long duration);
+
+ /**
+ * Called to indicate the current phase has advanced a single unit of its
+ * overall duration towards completion. Behavior is undefined if there is no
+ * current phase in progress.
+ */
+ default void advance() {
+ advance(1);
+ }
+
+ /**
+ * Called to indicate the current phase has advanced <code>n</code> units of
+ * its overall duration towards completion. Behavior is undefined if there
+ * is no current phase in progress.
+ *
+ * @param n number of units of progress that have advanced.
+ */
+ void advance(long n);
+
+ /**
+ * Called to indicate the current phase has completed <code>current</code>
+ * absolute units of its overall duration. Behavior is undefined if there is
+ * no current phase in progress.
+ *
+ * @param current progress towards duration
+ */
+ void update(long current);
+
+ /**
+ * Called to indicates that the current phase has been completed. Behavior
+ * is undefined if there is no current phase in progress.
+ */
+ void done();
+}
diff --git a/tools/ahat/src/test/com/android/ahat/DiffTest.java b/tools/ahat/src/test/com/android/ahat/DiffTest.java
index 585f29a..b1952b2 100644
--- a/tools/ahat/src/test/com/android/ahat/DiffTest.java
+++ b/tools/ahat/src/test/com/android/ahat/DiffTest.java
@@ -18,6 +18,7 @@
import com.android.ahat.heapdump.AhatHeap;
import com.android.ahat.heapdump.AhatInstance;
+import com.android.ahat.heapdump.Value;
import java.io.IOException;
import org.junit.Test;
@@ -51,6 +52,9 @@
assertEquals(b, a.getBaseline());
assertEquals(a.getSite(), b.getSite().getBaseline());
assertEquals(b.getSite(), a.getSite().getBaseline());
+
+ Value va = Value.pack(a);
+ assertEquals(b, Value.getBaseline(va).asAhatInstance());
}
@Test
diff --git a/tools/teardown-buildbot-device.sh b/tools/teardown-buildbot-device.sh
index d25dd2b..be68b9f 100755
--- a/tools/teardown-buildbot-device.sh
+++ b/tools/teardown-buildbot-device.sh
@@ -34,17 +34,36 @@
echo -e "${green}List open files under chroot dir $ART_TEST_CHROOT${nc}"
adb shell lsof | grep "$ART_TEST_CHROOT"
- echo -e "${green}List processes running from binaries under chroot dir $ART_TEST_CHROOT${nc}"
- for link in $(adb shell ls -d "/proc/*/root"); do
- root=$(adb shell readlink "$link")
- if [[ "x$root" = "x$ART_TEST_CHROOT" ]]; then
- dir=$(dirname "$link")
- pid=$(basename "$dir")
- cmdline=$(adb shell cat "$dir"/cmdline | tr -d '\000')
- echo "$cmdline (PID: $pid)"
- fi
- done
+ # for_all_chroot_process ACTION
+ # -----------------------------
+ # Execute ACTION on all processes running from binaries located
+ # under the chroot directory. ACTION is passed two arguments: the
+ # PID of the process, and a string containing the command line
+ # that started this process.
+ for_all_chroot_process() {
+ local action=$1
+ for link in $(adb shell ls -d "/proc/*/root"); do
+ local root=$(adb shell readlink "$link")
+ if [[ "x$root" = "x$ART_TEST_CHROOT" ]]; then
+ local dir=$(dirname "$link")
+ local pid=$(basename "$dir")
+ local cmdline=$(adb shell cat "$dir"/cmdline | tr '\000' ' ')
+ $action "$pid" "$cmdline"
+ fi
+ done
+ }
+ # display_process PID CMDLINE
+ # ---------------------------
+ # Display information about process with given PID, that was started with CMDLINE.
+ display_process() {
+ local pid=$1
+ local cmdline=$2
+ echo "$cmdline (PID: $pid)"
+ }
+
+ echo -e "${green}List processes running from binaries under chroot dir $ART_TEST_CHROOT${nc}"
+ for_all_chroot_process display_process
# Tear down the chroot dir.
@@ -102,5 +121,22 @@
for f in $property_context_files; do
adb shell rm -f "$ART_TEST_CHROOT$f"
done
+
+
+ # Kill processes still running in the chroot.
+
+ # kill_process PID CMDLINE
+ # ------------------------
+ # Kill process with given PID, that was started with CMDLINE.
+ kill_process() {
+ local pid=$1
+ local cmdline=$2
+ echo "Killing $cmdline (PID: $pid)"
+ adb shell kill -9 "$pid"
+ }
+
+ echo -e "${green}Kill processes still running from binaries under" \
+ "chroot dir $ART_TEST_CHROOT (if any)${nc} "
+ for_all_chroot_process kill_process
fi
fi