diff options
102 files changed, 3261 insertions, 3315 deletions
diff --git a/compiler/debug/elf_debug_loc_writer.h b/compiler/debug/elf_debug_loc_writer.h index 4009acb992..b663291b4d 100644 --- a/compiler/debug/elf_debug_loc_writer.h +++ b/compiler/debug/elf_debug_loc_writer.h @@ -149,9 +149,9 @@ static std::vector<VariableLocation> GetVariableLocations( DexRegisterMap dex_register_map = dex_register_maps[stack_map_index]; DCHECK(!dex_register_map.empty()); CodeItemDataAccessor accessor(*method_info->dex_file, method_info->code_item); - reg_lo = dex_register_map.GetDexRegisterLocation(vreg); + reg_lo = dex_register_map[vreg]; if (is64bitValue) { - reg_hi = dex_register_map.GetDexRegisterLocation(vreg + 1); + reg_hi = dex_register_map[vreg + 1]; } // Add location entry for this address range. diff --git a/compiler/optimizing/code_generator.cc b/compiler/optimizing/code_generator.cc index 45a81cf26d..2589869859 100644 --- a/compiler/optimizing/code_generator.cc +++ b/compiler/optimizing/code_generator.cc @@ -1283,50 +1283,45 @@ void CodeGenerator::EmitEnvironment(HEnvironment* environment, SlowPathCode* slo continue; } + using Kind = DexRegisterLocation::Kind; Location location = environment->GetLocationAt(i); switch (location.GetKind()) { case Location::kConstant: { DCHECK_EQ(current, location.GetConstant()); if (current->IsLongConstant()) { int64_t value = current->AsLongConstant()->GetValue(); - stack_map_stream->AddDexRegisterEntry( - DexRegisterLocation::Kind::kConstant, Low32Bits(value)); - stack_map_stream->AddDexRegisterEntry( - DexRegisterLocation::Kind::kConstant, High32Bits(value)); + stack_map_stream->AddDexRegisterEntry(Kind::kConstant, Low32Bits(value)); + stack_map_stream->AddDexRegisterEntry(Kind::kConstant, High32Bits(value)); ++i; DCHECK_LT(i, environment_size); } else if (current->IsDoubleConstant()) { int64_t value = bit_cast<int64_t, double>(current->AsDoubleConstant()->GetValue()); - stack_map_stream->AddDexRegisterEntry( - DexRegisterLocation::Kind::kConstant, Low32Bits(value)); - stack_map_stream->AddDexRegisterEntry( - DexRegisterLocation::Kind::kConstant, High32Bits(value)); + stack_map_stream->AddDexRegisterEntry(Kind::kConstant, Low32Bits(value)); + stack_map_stream->AddDexRegisterEntry(Kind::kConstant, High32Bits(value)); ++i; DCHECK_LT(i, environment_size); } else if (current->IsIntConstant()) { int32_t value = current->AsIntConstant()->GetValue(); - stack_map_stream->AddDexRegisterEntry(DexRegisterLocation::Kind::kConstant, value); + stack_map_stream->AddDexRegisterEntry(Kind::kConstant, value); } else if (current->IsNullConstant()) { - stack_map_stream->AddDexRegisterEntry(DexRegisterLocation::Kind::kConstant, 0); + stack_map_stream->AddDexRegisterEntry(Kind::kConstant, 0); } else { DCHECK(current->IsFloatConstant()) << current->DebugName(); int32_t value = bit_cast<int32_t, float>(current->AsFloatConstant()->GetValue()); - stack_map_stream->AddDexRegisterEntry(DexRegisterLocation::Kind::kConstant, value); + stack_map_stream->AddDexRegisterEntry(Kind::kConstant, value); } break; } case Location::kStackSlot: { - stack_map_stream->AddDexRegisterEntry( - DexRegisterLocation::Kind::kInStack, location.GetStackIndex()); + stack_map_stream->AddDexRegisterEntry(Kind::kInStack, location.GetStackIndex()); break; } case Location::kDoubleStackSlot: { + stack_map_stream->AddDexRegisterEntry(Kind::kInStack, location.GetStackIndex()); stack_map_stream->AddDexRegisterEntry( - DexRegisterLocation::Kind::kInStack, location.GetStackIndex()); - stack_map_stream->AddDexRegisterEntry( - DexRegisterLocation::Kind::kInStack, location.GetHighStackIndex(kVRegSize)); + Kind::kInStack, location.GetHighStackIndex(kVRegSize)); ++i; DCHECK_LT(i, environment_size); break; @@ -1336,17 +1331,16 @@ void CodeGenerator::EmitEnvironment(HEnvironment* environment, SlowPathCode* slo int id = location.reg(); if (slow_path != nullptr && slow_path->IsCoreRegisterSaved(id)) { uint32_t offset = slow_path->GetStackOffsetOfCoreRegister(id); - stack_map_stream->AddDexRegisterEntry(DexRegisterLocation::Kind::kInStack, offset); + stack_map_stream->AddDexRegisterEntry(Kind::kInStack, offset); if (current->GetType() == DataType::Type::kInt64) { - stack_map_stream->AddDexRegisterEntry( - DexRegisterLocation::Kind::kInStack, offset + kVRegSize); + stack_map_stream->AddDexRegisterEntry(Kind::kInStack, offset + kVRegSize); ++i; DCHECK_LT(i, environment_size); } } else { - stack_map_stream->AddDexRegisterEntry(DexRegisterLocation::Kind::kInRegister, id); + stack_map_stream->AddDexRegisterEntry(Kind::kInRegister, id); if (current->GetType() == DataType::Type::kInt64) { - stack_map_stream->AddDexRegisterEntry(DexRegisterLocation::Kind::kInRegisterHigh, id); + stack_map_stream->AddDexRegisterEntry(Kind::kInRegisterHigh, id); ++i; DCHECK_LT(i, environment_size); } @@ -1358,18 +1352,16 @@ void CodeGenerator::EmitEnvironment(HEnvironment* environment, SlowPathCode* slo int id = location.reg(); if (slow_path != nullptr && slow_path->IsFpuRegisterSaved(id)) { uint32_t offset = slow_path->GetStackOffsetOfFpuRegister(id); - stack_map_stream->AddDexRegisterEntry(DexRegisterLocation::Kind::kInStack, offset); + stack_map_stream->AddDexRegisterEntry(Kind::kInStack, offset); if (current->GetType() == DataType::Type::kFloat64) { - stack_map_stream->AddDexRegisterEntry( - DexRegisterLocation::Kind::kInStack, offset + kVRegSize); + stack_map_stream->AddDexRegisterEntry(Kind::kInStack, offset + kVRegSize); ++i; DCHECK_LT(i, environment_size); } } else { - stack_map_stream->AddDexRegisterEntry(DexRegisterLocation::Kind::kInFpuRegister, id); + stack_map_stream->AddDexRegisterEntry(Kind::kInFpuRegister, id); if (current->GetType() == DataType::Type::kFloat64) { - stack_map_stream->AddDexRegisterEntry( - DexRegisterLocation::Kind::kInFpuRegisterHigh, id); + stack_map_stream->AddDexRegisterEntry(Kind::kInFpuRegisterHigh, id); ++i; DCHECK_LT(i, environment_size); } @@ -1382,16 +1374,16 @@ void CodeGenerator::EmitEnvironment(HEnvironment* environment, SlowPathCode* slo int high = location.high(); if (slow_path != nullptr && slow_path->IsFpuRegisterSaved(low)) { uint32_t offset = slow_path->GetStackOffsetOfFpuRegister(low); - stack_map_stream->AddDexRegisterEntry(DexRegisterLocation::Kind::kInStack, offset); + stack_map_stream->AddDexRegisterEntry(Kind::kInStack, offset); } else { - stack_map_stream->AddDexRegisterEntry(DexRegisterLocation::Kind::kInFpuRegister, low); + stack_map_stream->AddDexRegisterEntry(Kind::kInFpuRegister, low); } if (slow_path != nullptr && slow_path->IsFpuRegisterSaved(high)) { uint32_t offset = slow_path->GetStackOffsetOfFpuRegister(high); - stack_map_stream->AddDexRegisterEntry(DexRegisterLocation::Kind::kInStack, offset); + stack_map_stream->AddDexRegisterEntry(Kind::kInStack, offset); ++i; } else { - stack_map_stream->AddDexRegisterEntry(DexRegisterLocation::Kind::kInFpuRegister, high); + stack_map_stream->AddDexRegisterEntry(Kind::kInFpuRegister, high); ++i; } DCHECK_LT(i, environment_size); @@ -1403,15 +1395,15 @@ void CodeGenerator::EmitEnvironment(HEnvironment* environment, SlowPathCode* slo int high = location.high(); if (slow_path != nullptr && slow_path->IsCoreRegisterSaved(low)) { uint32_t offset = slow_path->GetStackOffsetOfCoreRegister(low); - stack_map_stream->AddDexRegisterEntry(DexRegisterLocation::Kind::kInStack, offset); + stack_map_stream->AddDexRegisterEntry(Kind::kInStack, offset); } else { - stack_map_stream->AddDexRegisterEntry(DexRegisterLocation::Kind::kInRegister, low); + stack_map_stream->AddDexRegisterEntry(Kind::kInRegister, low); } if (slow_path != nullptr && slow_path->IsCoreRegisterSaved(high)) { uint32_t offset = slow_path->GetStackOffsetOfCoreRegister(high); - stack_map_stream->AddDexRegisterEntry(DexRegisterLocation::Kind::kInStack, offset); + stack_map_stream->AddDexRegisterEntry(Kind::kInStack, offset); } else { - stack_map_stream->AddDexRegisterEntry(DexRegisterLocation::Kind::kInRegister, high); + stack_map_stream->AddDexRegisterEntry(Kind::kInRegister, high); } ++i; DCHECK_LT(i, environment_size); @@ -1419,7 +1411,7 @@ void CodeGenerator::EmitEnvironment(HEnvironment* environment, SlowPathCode* slo } case Location::kInvalid: { - stack_map_stream->AddDexRegisterEntry(DexRegisterLocation::Kind::kNone, 0); + stack_map_stream->AddDexRegisterEntry(Kind::kNone, 0); break; } diff --git a/compiler/optimizing/gvn.cc b/compiler/optimizing/gvn.cc index 4863718518..e6b6326726 100644 --- a/compiler/optimizing/gvn.cc +++ b/compiler/optimizing/gvn.cc @@ -479,7 +479,10 @@ void GlobalValueNumberer::VisitBasicBlock(HBasicBlock* block) { 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 ef8a757ad0..661f66a34c 100644 --- a/compiler/optimizing/nodes.cc +++ b/compiler/optimizing/nodes.cc @@ -2786,6 +2786,14 @@ void HInstruction::SetReferenceTypeInfo(ReferenceTypeInfo rti) { 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 2037879726..975ad1c324 100644 --- a/compiler/optimizing/nodes.h +++ b/compiler/optimizing/nodes.h @@ -7142,6 +7142,7 @@ class HBoundType FINAL : public HExpression<1> { 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 f6bd05269e..2f782f39fc 100644 --- a/compiler/optimizing/ssa_liveness_analysis.cc +++ b/compiler/optimizing/ssa_liveness_analysis.cc @@ -195,14 +195,19 @@ void SsaLivenessAnalysis::ComputeLiveRanges() { // 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 f83bb52b69..83ca5bd5fa 100644 --- a/compiler/optimizing/ssa_liveness_analysis.h +++ b/compiler/optimizing/ssa_liveness_analysis.h @@ -300,8 +300,7 @@ class LiveInterval : public ArenaObject<kArenaAllocSsaLiveness> { 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 @@ class LiveInterval : public ArenaObject<kArenaAllocSsaLiveness> { 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 @@ class LiveInterval : public ArenaObject<kArenaAllocSsaLiveness> { * 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 @@ class SsaLivenessAnalysis : public ValueObject { // 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 b9bfbaa173..ae5e4e7176 100644 --- a/compiler/optimizing/ssa_liveness_analysis_test.cc +++ b/compiler/optimizing/ssa_liveness_analysis_test.cc @@ -134,12 +134,12 @@ TEST_F(SsaLivenessAnalysisTest, TestAput) { 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 @@ TEST_F(SsaLivenessAnalysisTest, TestDeoptimize) { 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/compiler/optimizing/stack_map_stream.cc b/compiler/optimizing/stack_map_stream.cc index cd115499a6..58a35dde8e 100644 --- a/compiler/optimizing/stack_map_stream.cc +++ b/compiler/optimizing/stack_map_stream.cc @@ -31,11 +31,12 @@ namespace art { constexpr static bool kVerifyStackMaps = kIsDebugBuild; uint32_t StackMapStream::GetStackMapNativePcOffset(size_t i) { - return StackMap::UnpackNativePc(stack_maps_[i].packed_native_pc, instruction_set_); + return StackMap::UnpackNativePc(stack_maps_[i][StackMap::kPackedNativePc], instruction_set_); } void StackMapStream::SetStackMapNativePcOffset(size_t i, uint32_t native_pc_offset) { - stack_maps_[i].packed_native_pc = StackMap::PackNativePc(native_pc_offset, instruction_set_); + stack_maps_[i][StackMap::kPackedNativePc] = + StackMap::PackNativePc(native_pc_offset, instruction_set_); } void StackMapStream::BeginStackMapEntry(uint32_t dex_pc, @@ -55,20 +56,17 @@ void StackMapStream::BeginStackMapEntry(uint32_t dex_pc, DCHECK_EQ(num_dex_registers_, num_dex_registers) << "Inconsistent register count"; } - current_stack_map_ = StackMapEntry { - .kind = static_cast<uint32_t>(kind), - .packed_native_pc = StackMap::PackNativePc(native_pc_offset, instruction_set_), - .dex_pc = dex_pc, - .register_mask_index = kNoValue, - .stack_mask_index = kNoValue, - .inline_info_index = kNoValue, - .dex_register_mask_index = kNoValue, - .dex_register_map_index = kNoValue, - }; + current_stack_map_ = BitTableBuilder<StackMap::kCount>::Entry(); + current_stack_map_[StackMap::kKind] = static_cast<uint32_t>(kind); + current_stack_map_[StackMap::kPackedNativePc] = + StackMap::PackNativePc(native_pc_offset, instruction_set_); + current_stack_map_[StackMap::kDexPc] = dex_pc; if (register_mask != 0) { uint32_t shift = LeastSignificantBit(register_mask); - RegisterMaskEntry entry = { register_mask >> shift, shift }; - current_stack_map_.register_mask_index = register_masks_.Dedup(&entry); + BitTableBuilder<RegisterMask::kCount>::Entry entry; + entry[RegisterMask::kValue] = register_mask >> shift; + entry[RegisterMask::kShift] = shift; + current_stack_map_[StackMap::kRegisterMaskIndex] = register_masks_.Dedup(&entry); } // The compiler assumes the bit vector will be read during PrepareForFillIn(), // and it might modify the data before that. Therefore, just store the pointer. @@ -114,8 +112,8 @@ void StackMapStream::EndStackMapEntry() { // Generate index into the InlineInfo table. if (!current_inline_infos_.empty()) { - current_inline_infos_.back().is_last = InlineInfo::kLast; - current_stack_map_.inline_info_index = + current_inline_infos_.back()[InlineInfo::kIsLast] = InlineInfo::kLast; + current_stack_map_[StackMap::kInlineInfoIndex] = inline_infos_.Dedup(current_inline_infos_.data(), current_inline_infos_.size()); } @@ -125,18 +123,14 @@ void StackMapStream::EndStackMapEntry() { stack_maps_.Add(current_stack_map_); } -void StackMapStream::AddDexRegisterEntry(DexRegisterLocation::Kind kind, int32_t value) { - current_dex_registers_.push_back(DexRegisterLocation(kind, value)); -} - void StackMapStream::AddInvoke(InvokeType invoke_type, uint32_t dex_method_index) { - uint32_t packed_native_pc = current_stack_map_.packed_native_pc; + uint32_t packed_native_pc = current_stack_map_[StackMap::kPackedNativePc]; size_t invoke_info_index = invoke_infos_.size(); - invoke_infos_.Add(InvokeInfoEntry { - .packed_native_pc = packed_native_pc, - .invoke_type = invoke_type, - .method_info_index = method_infos_.Dedup(&dex_method_index), - }); + BitTableBuilder<InvokeInfo::kCount>::Entry entry; + entry[InvokeInfo::kPackedNativePc] = packed_native_pc; + entry[InvokeInfo::kInvokeType] = invoke_type; + entry[InvokeInfo::kMethodInfoIndex] = method_infos_.Dedup({dex_method_index}); + invoke_infos_.Add(entry); if (kVerifyStackMaps) { dchecks_.emplace_back([=](const CodeInfo& code_info) { @@ -144,7 +138,7 @@ void StackMapStream::AddInvoke(InvokeType invoke_type, uint32_t dex_method_index CHECK_EQ(invoke_info.GetNativePcOffset(instruction_set_), StackMap::UnpackNativePc(packed_native_pc, instruction_set_)); CHECK_EQ(invoke_info.GetInvokeType(), invoke_type); - CHECK_EQ(method_infos_[invoke_info.GetMethodInfoIndex()], dex_method_index); + CHECK_EQ(method_infos_[invoke_info.GetMethodInfoIndex()][0], dex_method_index); }); } } @@ -159,24 +153,20 @@ void StackMapStream::BeginInlineInfoEntry(ArtMethod* method, expected_num_dex_registers_ += num_dex_registers; - InlineInfoEntry entry = { - .is_last = InlineInfo::kMore, - .dex_pc = dex_pc, - .method_info_index = kNoValue, - .art_method_hi = kNoValue, - .art_method_lo = kNoValue, - .num_dex_registers = static_cast<uint32_t>(expected_num_dex_registers_), - }; + BitTableBuilder<InlineInfo::kCount>::Entry entry; + entry[InlineInfo::kIsLast] = InlineInfo::kMore; + entry[InlineInfo::kDexPc] = dex_pc; + entry[InlineInfo::kNumberOfDexRegisters] = static_cast<uint32_t>(expected_num_dex_registers_); if (EncodeArtMethodInInlineInfo(method)) { - entry.art_method_hi = High32Bits(reinterpret_cast<uintptr_t>(method)); - entry.art_method_lo = Low32Bits(reinterpret_cast<uintptr_t>(method)); + entry[InlineInfo::kArtMethodHi] = High32Bits(reinterpret_cast<uintptr_t>(method)); + entry[InlineInfo::kArtMethodLo] = Low32Bits(reinterpret_cast<uintptr_t>(method)); } else { if (dex_pc != static_cast<uint32_t>(-1) && kIsDebugBuild) { ScopedObjectAccess soa(Thread::Current()); DCHECK(IsSameDexFile(*outer_dex_file, *method->GetDexFile())); } uint32_t dex_method_index = method->GetDexMethodIndexUnchecked(); - entry.method_info_index = method_infos_.Dedup(&dex_method_index); + entry[InlineInfo::kMethodInfoIndex] = method_infos_.Dedup({dex_method_index}); } current_inline_infos_.push_back(entry); @@ -192,7 +182,7 @@ void StackMapStream::BeginInlineInfoEntry(ArtMethod* method, if (encode_art_method) { CHECK_EQ(inline_info.GetArtMethod(), method); } else { - CHECK_EQ(method_infos_[inline_info.GetMethodInfoIndex()], + CHECK_EQ(method_infos_[inline_info.GetMethodInfoIndex()][0], method->GetDexMethodIndexUnchecked()); } }); @@ -225,13 +215,13 @@ void StackMapStream::CreateDexRegisterMap() { // Distance is difference between this index and the index of last modification. uint32_t distance = stack_maps_.size() - dex_register_timestamp_[i]; if (previous_dex_registers_[i] != reg || distance > kMaxDexRegisterMapSearchDistance) { - DexRegisterEntry entry = DexRegisterEntry{ - .kind = static_cast<uint32_t>(reg.GetKind()), - .packed_value = DexRegisterInfo::PackValue(reg.GetKind(), reg.GetValue()), - }; + BitTableBuilder<DexRegisterInfo::kCount>::Entry entry; + entry[DexRegisterInfo::kKind] = static_cast<uint32_t>(reg.GetKind()); + entry[DexRegisterInfo::kPackedValue] = + DexRegisterInfo::PackValue(reg.GetKind(), reg.GetValue()); uint32_t index = reg.IsLive() ? dex_register_catalog_.Dedup(&entry) : kNoValue; temp_dex_register_mask_.SetBit(i); - temp_dex_register_map_.push_back(index); + temp_dex_register_map_.push_back({index}); previous_dex_registers_[i] = reg; dex_register_timestamp_[i] = stack_maps_.size(); } @@ -239,12 +229,12 @@ void StackMapStream::CreateDexRegisterMap() { // Set the mask and map for the current StackMap (which includes inlined registers). if (temp_dex_register_mask_.GetNumberOfBits() != 0) { - current_stack_map_.dex_register_mask_index = + current_stack_map_[StackMap::kDexRegisterMaskIndex] = dex_register_masks_.Dedup(temp_dex_register_mask_.GetRawStorage(), temp_dex_register_mask_.GetNumberOfBits()); } if (!current_dex_registers_.empty()) { - current_stack_map_.dex_register_map_index = + current_stack_map_[StackMap::kDexRegisterMapIndex] = dex_register_maps_.Dedup(temp_dex_register_map_.data(), temp_dex_register_map_.size()); } @@ -275,7 +265,7 @@ void StackMapStream::FillInMethodInfo(MemoryRegion region) { { MethodInfo info(region.begin(), method_infos_.size()); for (size_t i = 0; i < method_infos_.size(); ++i) { - info.SetMethodIndex(i, method_infos_[i]); + info.SetMethodIndex(i, method_infos_[i][0]); } } if (kVerifyStackMaps) { @@ -284,23 +274,19 @@ void StackMapStream::FillInMethodInfo(MemoryRegion region) { const size_t count = info.NumMethodIndices(); DCHECK_EQ(count, method_infos_.size()); for (size_t i = 0; i < count; ++i) { - DCHECK_EQ(info.GetMethodIndex(i), method_infos_[i]); + DCHECK_EQ(info.GetMethodIndex(i), method_infos_[i][0]); } } } size_t StackMapStream::PrepareForFillIn() { - static_assert(sizeof(StackMapEntry) == StackMap::kCount * sizeof(uint32_t), "Layout"); - static_assert(sizeof(InvokeInfoEntry) == InvokeInfo::kCount * sizeof(uint32_t), "Layout"); - static_assert(sizeof(InlineInfoEntry) == InlineInfo::kCount * sizeof(uint32_t), "Layout"); - static_assert(sizeof(DexRegisterEntry) == DexRegisterInfo::kCount * sizeof(uint32_t), "Layout"); DCHECK_EQ(out_.size(), 0u); // Read the stack masks now. The compiler might have updated them. for (size_t i = 0; i < lazy_stack_masks_.size(); i++) { BitVector* stack_mask = lazy_stack_masks_[i]; if (stack_mask != nullptr && stack_mask->GetNumberOfBits() != 0) { - stack_maps_[i].stack_mask_index = + stack_maps_[i][StackMap::kStackMaskIndex] = stack_masks_.Dedup(stack_mask->GetRawStorage(), stack_mask->GetNumberOfBits()); } } diff --git a/compiler/optimizing/stack_map_stream.h b/compiler/optimizing/stack_map_stream.h index 06868476bc..6842d9fd7e 100644 --- a/compiler/optimizing/stack_map_stream.h +++ b/compiler/optimizing/stack_map_stream.h @@ -52,6 +52,7 @@ class StackMapStream : public ValueObject { lazy_stack_masks_(allocator->Adapter(kArenaAllocStackMapStream)), in_stack_map_(false), in_inline_info_(false), + current_stack_map_(), current_inline_infos_(allocator->Adapter(kArenaAllocStackMapStream)), current_dex_registers_(allocator->Adapter(kArenaAllocStackMapStream)), previous_dex_registers_(allocator->Adapter(kArenaAllocStackMapStream)), @@ -69,7 +70,9 @@ class StackMapStream : public ValueObject { StackMap::Kind kind = StackMap::Kind::Default); void EndStackMapEntry(); - void AddDexRegisterEntry(DexRegisterLocation::Kind kind, int32_t value); + void AddDexRegisterEntry(DexRegisterLocation::Kind kind, int32_t value) { + current_dex_registers_.push_back(DexRegisterLocation(kind, value)); + } void AddInvoke(InvokeType type, uint32_t dex_method_index); @@ -97,70 +100,29 @@ class StackMapStream : public ValueObject { private: static constexpr uint32_t kNoValue = -1; - // The fields must be uint32_t and mirror the StackMap accessor in stack_map.h! - struct StackMapEntry { - uint32_t kind; - uint32_t packed_native_pc; - uint32_t dex_pc; - uint32_t register_mask_index; - uint32_t stack_mask_index; - uint32_t inline_info_index; - uint32_t dex_register_mask_index; - uint32_t dex_register_map_index; - }; - - // The fields must be uint32_t and mirror the InlineInfo accessor in stack_map.h! - struct InlineInfoEntry { - uint32_t is_last; - uint32_t dex_pc; - uint32_t method_info_index; - uint32_t art_method_hi; - uint32_t art_method_lo; - uint32_t num_dex_registers; - }; - - // The fields must be uint32_t and mirror the InvokeInfo accessor in stack_map.h! - struct InvokeInfoEntry { - uint32_t packed_native_pc; - uint32_t invoke_type; - uint32_t method_info_index; - }; - - // The fields must be uint32_t and mirror the DexRegisterInfo accessor in stack_map.h! - struct DexRegisterEntry { - uint32_t kind; - uint32_t packed_value; - }; - - // The fields must be uint32_t and mirror the RegisterMask accessor in stack_map.h! - struct RegisterMaskEntry { - uint32_t value; - uint32_t shift; - }; - void CreateDexRegisterMap(); const InstructionSet instruction_set_; - BitTableBuilder<StackMapEntry> stack_maps_; - BitTableBuilder<RegisterMaskEntry> register_masks_; + BitTableBuilder<StackMap::kCount> stack_maps_; + BitTableBuilder<RegisterMask::kCount> register_masks_; BitmapTableBuilder stack_masks_; - BitTableBuilder<InvokeInfoEntry> invoke_infos_; - BitTableBuilder<InlineInfoEntry> inline_infos_; + BitTableBuilder<InvokeInfo::kCount> invoke_infos_; + BitTableBuilder<InlineInfo::kCount> inline_infos_; BitmapTableBuilder dex_register_masks_; - BitTableBuilder<uint32_t> dex_register_maps_; - BitTableBuilder<DexRegisterEntry> dex_register_catalog_; + BitTableBuilder<MaskInfo::kCount> dex_register_maps_; + BitTableBuilder<DexRegisterInfo::kCount> dex_register_catalog_; uint32_t num_dex_registers_ = 0; // TODO: Make this const and get the value in constructor. ScopedArenaVector<uint8_t> out_; - BitTableBuilder<uint32_t> method_infos_; + BitTableBuilder<1> method_infos_; ScopedArenaVector<BitVector*> lazy_stack_masks_; // Variables which track the current state between Begin/End calls; bool in_stack_map_; bool in_inline_info_; - StackMapEntry current_stack_map_; - ScopedArenaVector<InlineInfoEntry> current_inline_infos_; + BitTableBuilder<StackMap::kCount>::Entry current_stack_map_; + ScopedArenaVector<BitTableBuilder<InlineInfo::kCount>::Entry> current_inline_infos_; ScopedArenaVector<DexRegisterLocation> current_dex_registers_; ScopedArenaVector<DexRegisterLocation> previous_dex_registers_; ScopedArenaVector<uint32_t> dex_register_timestamp_; // Stack map index of last change. @@ -169,7 +131,7 @@ class StackMapStream : public ValueObject { // Temporary variables used in CreateDexRegisterMap. // They are here so that we can reuse the reserved memory. ArenaBitVector temp_dex_register_mask_; - ScopedArenaVector<uint32_t> temp_dex_register_map_; + ScopedArenaVector<BitTableBuilder<DexRegisterMapInfo::kCount>::Entry> temp_dex_register_map_; // A set of lambda functions to be executed at the end to verify // the encoded data. It is generally only used in debug builds. diff --git a/compiler/optimizing/stack_map_test.cc b/compiler/optimizing/stack_map_test.cc index 2594faffc2..fd856671ba 100644 --- a/compiler/optimizing/stack_map_test.cc +++ b/compiler/optimizing/stack_map_test.cc @@ -83,14 +83,14 @@ TEST(StackMapTest, Test1) { ASSERT_TRUE(stack_map.HasDexRegisterMap()); DexRegisterMap dex_register_map = code_info.GetDexRegisterMapOf(stack_map); ASSERT_EQ(number_of_dex_registers, dex_register_map.size()); - ASSERT_TRUE(dex_register_map.IsDexRegisterLive(0)); - ASSERT_TRUE(dex_register_map.IsDexRegisterLive(1)); + ASSERT_TRUE(dex_register_map[0].IsLive()); + ASSERT_TRUE(dex_register_map[1].IsLive()); ASSERT_EQ(2u, dex_register_map.GetNumberOfLiveDexRegisters()); - ASSERT_EQ(Kind::kInStack, dex_register_map.GetLocationKind(0)); - ASSERT_EQ(Kind::kConstant, dex_register_map.GetLocationKind(1)); - ASSERT_EQ(0, dex_register_map.GetStackOffsetInBytes(0)); - ASSERT_EQ(-2, dex_register_map.GetConstant(1)); + ASSERT_EQ(Kind::kInStack, dex_register_map[0].GetKind()); + ASSERT_EQ(Kind::kConstant, dex_register_map[1].GetKind()); + ASSERT_EQ(0, dex_register_map[0].GetStackOffsetInBytes()); + ASSERT_EQ(-2, dex_register_map[1].GetConstant()); DexRegisterLocation location0 = code_info.GetDexRegisterCatalogEntry(0); DexRegisterLocation location1 = code_info.GetDexRegisterCatalogEntry(1); @@ -172,14 +172,14 @@ TEST(StackMapTest, Test2) { ASSERT_TRUE(stack_map.HasDexRegisterMap()); DexRegisterMap dex_register_map = code_info.GetDexRegisterMapOf(stack_map); ASSERT_EQ(number_of_dex_registers, dex_register_map.size()); - ASSERT_TRUE(dex_register_map.IsDexRegisterLive(0)); - ASSERT_TRUE(dex_register_map.IsDexRegisterLive(1)); + ASSERT_TRUE(dex_register_map[0].IsLive()); + ASSERT_TRUE(dex_register_map[1].IsLive()); ASSERT_EQ(2u, dex_register_map.GetNumberOfLiveDexRegisters()); - ASSERT_EQ(Kind::kInStack, dex_register_map.GetLocationKind(0)); - ASSERT_EQ(Kind::kConstant, dex_register_map.GetLocationKind(1)); - ASSERT_EQ(0, dex_register_map.GetStackOffsetInBytes(0)); - ASSERT_EQ(-2, dex_register_map.GetConstant(1)); + ASSERT_EQ(Kind::kInStack, dex_register_map[0].GetKind()); + ASSERT_EQ(Kind::kConstant, dex_register_map[1].GetKind()); + ASSERT_EQ(0, dex_register_map[0].GetStackOffsetInBytes()); + ASSERT_EQ(-2, dex_register_map[1].GetConstant()); DexRegisterLocation location0 = code_info.GetDexRegisterCatalogEntry(0); DexRegisterLocation location1 = code_info.GetDexRegisterCatalogEntry(1); @@ -212,14 +212,14 @@ TEST(StackMapTest, Test2) { ASSERT_TRUE(stack_map.HasDexRegisterMap()); DexRegisterMap dex_register_map = code_info.GetDexRegisterMapOf(stack_map); ASSERT_EQ(number_of_dex_registers, dex_register_map.size()); - ASSERT_TRUE(dex_register_map.IsDexRegisterLive(0)); - ASSERT_TRUE(dex_register_map.IsDexRegisterLive(1)); + ASSERT_TRUE(dex_register_map[0].IsLive()); + ASSERT_TRUE(dex_register_map[1].IsLive()); ASSERT_EQ(2u, dex_register_map.GetNumberOfLiveDexRegisters()); - ASSERT_EQ(Kind::kInRegister, dex_register_map.GetLocationKind(0)); - ASSERT_EQ(Kind::kInFpuRegister, dex_register_map.GetLocationKind(1)); - ASSERT_EQ(18, dex_register_map.GetMachineRegister(0)); - ASSERT_EQ(3, dex_register_map.GetMachineRegister(1)); + ASSERT_EQ(Kind::kInRegister, dex_register_map[0].GetKind()); + ASSERT_EQ(Kind::kInFpuRegister, dex_register_map[1].GetKind()); + ASSERT_EQ(18, dex_register_map[0].GetMachineRegister()); + ASSERT_EQ(3, dex_register_map[1].GetMachineRegister()); DexRegisterLocation location0 = code_info.GetDexRegisterCatalogEntry(2); DexRegisterLocation location1 = code_info.GetDexRegisterCatalogEntry(3); @@ -245,14 +245,14 @@ TEST(StackMapTest, Test2) { ASSERT_TRUE(stack_map.HasDexRegisterMap()); DexRegisterMap dex_register_map = code_info.GetDexRegisterMapOf(stack_map); ASSERT_EQ(number_of_dex_registers, dex_register_map.size()); - ASSERT_TRUE(dex_register_map.IsDexRegisterLive(0)); - ASSERT_TRUE(dex_register_map.IsDexRegisterLive(1)); + ASSERT_TRUE(dex_register_map[0].IsLive()); + ASSERT_TRUE(dex_register_map[1].IsLive()); ASSERT_EQ(2u, dex_register_map.GetNumberOfLiveDexRegisters()); - ASSERT_EQ(Kind::kInRegister, dex_register_map.GetLocationKind(0)); - ASSERT_EQ(Kind::kInRegisterHigh, dex_register_map.GetLocationKind(1)); - ASSERT_EQ(6, dex_register_map.GetMachineRegister(0)); - ASSERT_EQ(8, dex_register_map.GetMachineRegister(1)); + ASSERT_EQ(Kind::kInRegister, dex_register_map[0].GetKind()); + ASSERT_EQ(Kind::kInRegisterHigh, dex_register_map[1].GetKind()); + ASSERT_EQ(6, dex_register_map[0].GetMachineRegister()); + ASSERT_EQ(8, dex_register_map[1].GetMachineRegister()); DexRegisterLocation location0 = code_info.GetDexRegisterCatalogEntry(4); DexRegisterLocation location1 = code_info.GetDexRegisterCatalogEntry(5); @@ -278,14 +278,14 @@ TEST(StackMapTest, Test2) { ASSERT_TRUE(stack_map.HasDexRegisterMap()); DexRegisterMap dex_register_map = code_info.GetDexRegisterMapOf(stack_map); ASSERT_EQ(number_of_dex_registers, dex_register_map.size()); - ASSERT_TRUE(dex_register_map.IsDexRegisterLive(0)); - ASSERT_TRUE(dex_register_map.IsDexRegisterLive(1)); + ASSERT_TRUE(dex_register_map[0].IsLive()); + ASSERT_TRUE(dex_register_map[1].IsLive()); ASSERT_EQ(2u, dex_register_map.GetNumberOfLiveDexRegisters()); - ASSERT_EQ(Kind::kInFpuRegister, dex_register_map.GetLocationKind(0)); - ASSERT_EQ(Kind::kInFpuRegisterHigh, dex_register_map.GetLocationKind(1)); - ASSERT_EQ(3, dex_register_map.GetMachineRegister(0)); - ASSERT_EQ(1, dex_register_map.GetMachineRegister(1)); + ASSERT_EQ(Kind::kInFpuRegister, dex_register_map[0].GetKind()); + ASSERT_EQ(Kind::kInFpuRegisterHigh, dex_register_map[1].GetKind()); + ASSERT_EQ(3, dex_register_map[0].GetMachineRegister()); + ASSERT_EQ(1, dex_register_map[1].GetMachineRegister()); DexRegisterLocation location0 = code_info.GetDexRegisterCatalogEntry(3); DexRegisterLocation location1 = code_info.GetDexRegisterCatalogEntry(6); @@ -344,14 +344,14 @@ TEST(StackMapTest, TestDeduplicateInlineInfoDexRegisterMap) { ASSERT_TRUE(stack_map.HasDexRegisterMap()); DexRegisterMap map(code_info.GetDexRegisterMapOf(stack_map)); ASSERT_EQ(number_of_dex_registers, map.size()); - ASSERT_TRUE(map.IsDexRegisterLive(0)); - ASSERT_TRUE(map.IsDexRegisterLive(1)); + ASSERT_TRUE(map[0].IsLive()); + ASSERT_TRUE(map[1].IsLive()); ASSERT_EQ(2u, map.GetNumberOfLiveDexRegisters()); - ASSERT_EQ(Kind::kInStack, map.GetLocationKind(0)); - ASSERT_EQ(Kind::kConstant, map.GetLocationKind(1)); - ASSERT_EQ(0, map.GetStackOffsetInBytes(0)); - ASSERT_EQ(-2, map.GetConstant(1)); + ASSERT_EQ(Kind::kInStack, map[0].GetKind()); + ASSERT_EQ(Kind::kConstant, map[1].GetKind()); + ASSERT_EQ(0, map[0].GetStackOffsetInBytes()); + ASSERT_EQ(-2, map[1].GetConstant()); DexRegisterLocation location0 = code_info.GetDexRegisterCatalogEntry(0); DexRegisterLocation location1 = code_info.GetDexRegisterCatalogEntry(1); @@ -396,13 +396,13 @@ TEST(StackMapTest, TestNonLiveDexRegisters) { ASSERT_TRUE(stack_map.HasDexRegisterMap()); DexRegisterMap dex_register_map = code_info.GetDexRegisterMapOf(stack_map); ASSERT_EQ(number_of_dex_registers, dex_register_map.size()); - ASSERT_FALSE(dex_register_map.IsDexRegisterLive(0)); - ASSERT_TRUE(dex_register_map.IsDexRegisterLive(1)); + ASSERT_FALSE(dex_register_map[0].IsLive()); + ASSERT_TRUE(dex_register_map[1].IsLive()); ASSERT_EQ(1u, dex_register_map.GetNumberOfLiveDexRegisters()); - ASSERT_EQ(Kind::kNone, dex_register_map.GetLocationKind(0)); - ASSERT_EQ(Kind::kConstant, dex_register_map.GetLocationKind(1)); - ASSERT_EQ(-2, dex_register_map.GetConstant(1)); + ASSERT_EQ(Kind::kNone, dex_register_map[0].GetKind()); + ASSERT_EQ(Kind::kConstant, dex_register_map[1].GetKind()); + ASSERT_EQ(-2, dex_register_map[1].GetConstant()); DexRegisterLocation location1 = code_info.GetDexRegisterCatalogEntry(0); ASSERT_EQ(Kind::kConstant, location1.GetKind()); @@ -446,22 +446,22 @@ TEST(StackMapTest, TestShareDexRegisterMap) { StackMap sm0 = ci.GetStackMapAt(0); DexRegisterMap dex_registers0 = ci.GetDexRegisterMapOf(sm0); ASSERT_EQ(number_of_dex_registers, dex_registers0.size()); - ASSERT_EQ(0, dex_registers0.GetMachineRegister(0)); - ASSERT_EQ(-2, dex_registers0.GetConstant(1)); + ASSERT_EQ(0, dex_registers0[0].GetMachineRegister()); + ASSERT_EQ(-2, dex_registers0[1].GetConstant()); // Verify second stack map. StackMap sm1 = ci.GetStackMapAt(1); DexRegisterMap dex_registers1 = ci.GetDexRegisterMapOf(sm1); ASSERT_EQ(number_of_dex_registers, dex_registers1.size()); - ASSERT_EQ(0, dex_registers1.GetMachineRegister(0)); - ASSERT_EQ(-2, dex_registers1.GetConstant(1)); + ASSERT_EQ(0, dex_registers1[0].GetMachineRegister()); + ASSERT_EQ(-2, dex_registers1[1].GetConstant()); // Verify third stack map. StackMap sm2 = ci.GetStackMapAt(2); DexRegisterMap dex_registers2 = ci.GetDexRegisterMapOf(sm2); ASSERT_EQ(number_of_dex_registers, dex_registers2.size()); - ASSERT_EQ(2, dex_registers2.GetMachineRegister(0)); - ASSERT_EQ(-2, dex_registers2.GetConstant(1)); + ASSERT_EQ(2, dex_registers2[0].GetMachineRegister()); + ASSERT_EQ(-2, dex_registers2[1].GetConstant()); // Verify dex register mask offsets. ASSERT_FALSE(sm1.HasDexRegisterMaskIndex()); // No delta. @@ -597,8 +597,8 @@ TEST(StackMapTest, InlineTest) { DexRegisterMap dex_registers0 = ci.GetDexRegisterMapOf(sm0); ASSERT_EQ(2u, dex_registers0.size()); - ASSERT_EQ(0, dex_registers0.GetStackOffsetInBytes(0)); - ASSERT_EQ(4, dex_registers0.GetConstant(1)); + ASSERT_EQ(0, dex_registers0[0].GetStackOffsetInBytes()); + ASSERT_EQ(4, dex_registers0[1].GetConstant()); InlineInfo if0_0 = ci.GetInlineInfoAtDepth(sm0, 0); InlineInfo if0_1 = ci.GetInlineInfoAtDepth(sm0, 1); @@ -610,13 +610,13 @@ TEST(StackMapTest, InlineTest) { DexRegisterMap dex_registers1 = ci.GetDexRegisterMapAtDepth(0, sm0); ASSERT_EQ(1u, dex_registers1.size()); - ASSERT_EQ(8, dex_registers1.GetStackOffsetInBytes(0)); + ASSERT_EQ(8, dex_registers1[0].GetStackOffsetInBytes()); DexRegisterMap dex_registers2 = ci.GetDexRegisterMapAtDepth(1, sm0); ASSERT_EQ(3u, dex_registers2.size()); - ASSERT_EQ(16, dex_registers2.GetStackOffsetInBytes(0)); - ASSERT_EQ(20, dex_registers2.GetConstant(1)); - ASSERT_EQ(15, dex_registers2.GetMachineRegister(2)); + ASSERT_EQ(16, dex_registers2[0].GetStackOffsetInBytes()); + ASSERT_EQ(20, dex_registers2[1].GetConstant()); + ASSERT_EQ(15, dex_registers2[2].GetMachineRegister()); } { @@ -625,8 +625,8 @@ TEST(StackMapTest, InlineTest) { DexRegisterMap dex_registers0 = ci.GetDexRegisterMapOf(sm1); ASSERT_EQ(2u, dex_registers0.size()); - ASSERT_EQ(56, dex_registers0.GetStackOffsetInBytes(0)); - ASSERT_EQ(0, dex_registers0.GetConstant(1)); + ASSERT_EQ(56, dex_registers0[0].GetStackOffsetInBytes()); + ASSERT_EQ(0, dex_registers0[1].GetConstant()); InlineInfo if1_0 = ci.GetInlineInfoAtDepth(sm1, 0); InlineInfo if1_1 = ci.GetInlineInfoAtDepth(sm1, 1); @@ -641,13 +641,13 @@ TEST(StackMapTest, InlineTest) { DexRegisterMap dex_registers1 = ci.GetDexRegisterMapAtDepth(0, sm1); ASSERT_EQ(1u, dex_registers1.size()); - ASSERT_EQ(12, dex_registers1.GetStackOffsetInBytes(0)); + ASSERT_EQ(12, dex_registers1[0].GetStackOffsetInBytes()); DexRegisterMap dex_registers2 = ci.GetDexRegisterMapAtDepth(1, sm1); ASSERT_EQ(3u, dex_registers2.size()); - ASSERT_EQ(80, dex_registers2.GetStackOffsetInBytes(0)); - ASSERT_EQ(10, dex_registers2.GetConstant(1)); - ASSERT_EQ(5, dex_registers2.GetMachineRegister(2)); + ASSERT_EQ(80, dex_registers2[0].GetStackOffsetInBytes()); + ASSERT_EQ(10, dex_registers2[1].GetConstant()); + ASSERT_EQ(5, dex_registers2[2].GetMachineRegister()); } { @@ -656,8 +656,8 @@ TEST(StackMapTest, InlineTest) { DexRegisterMap dex_registers0 = ci.GetDexRegisterMapOf(sm2); ASSERT_EQ(2u, dex_registers0.size()); - ASSERT_FALSE(dex_registers0.IsDexRegisterLive(0)); - ASSERT_EQ(4, dex_registers0.GetConstant(1)); + ASSERT_FALSE(dex_registers0[0].IsLive()); + ASSERT_EQ(4, dex_registers0[1].GetConstant()); ASSERT_FALSE(sm2.HasInlineInfo()); } @@ -667,8 +667,8 @@ TEST(StackMapTest, InlineTest) { DexRegisterMap dex_registers0 = ci.GetDexRegisterMapOf(sm3); ASSERT_EQ(2u, dex_registers0.size()); - ASSERT_EQ(56, dex_registers0.GetStackOffsetInBytes(0)); - ASSERT_EQ(0, dex_registers0.GetConstant(1)); + ASSERT_EQ(56, dex_registers0[0].GetStackOffsetInBytes()); + ASSERT_EQ(0, dex_registers0[1].GetConstant()); InlineInfo if2_0 = ci.GetInlineInfoAtDepth(sm3, 0); InlineInfo if2_1 = ci.GetInlineInfoAtDepth(sm3, 1); @@ -683,12 +683,12 @@ TEST(StackMapTest, InlineTest) { DexRegisterMap dex_registers1 = ci.GetDexRegisterMapAtDepth(1, sm3); ASSERT_EQ(1u, dex_registers1.size()); - ASSERT_EQ(2, dex_registers1.GetMachineRegister(0)); + ASSERT_EQ(2, dex_registers1[0].GetMachineRegister()); DexRegisterMap dex_registers2 = ci.GetDexRegisterMapAtDepth(2, sm3); ASSERT_EQ(2u, dex_registers2.size()); - ASSERT_FALSE(dex_registers2.IsDexRegisterLive(0)); - ASSERT_EQ(3, dex_registers2.GetMachineRegister(1)); + ASSERT_FALSE(dex_registers2[0].IsLive()); + ASSERT_EQ(3, dex_registers2[1].GetMachineRegister()); } } diff --git a/dexlayout/compact_dex_writer.cc b/dexlayout/compact_dex_writer.cc index 3f5dbcfce5..00fb0af710 100644 --- a/dexlayout/compact_dex_writer.cc +++ b/dexlayout/compact_dex_writer.cc @@ -40,9 +40,8 @@ CompactDexWriter::Container::Container(bool dedupe_code_items) 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 @@ uint32_t CompactDexWriter::WriteDebugInfoOffsetTable(Stream* stream) { }; 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 @@ uint32_t CompactDexWriter::Deduper::Dedupe(uint32_t data_start, } 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 @@ void CompactDexWriter::SortDebugInfosByMethodIndex() { } } } - 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 @@ void CompactDexWriter::WriteHeader(Stream* stream) { 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 @@ void CompactDexWriter::WriteStringData(Stream* stream, dex_ir::StringData* strin } 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 @@ bool CompactDexWriter::Write(DexContainer* output, std::string* error_msg) { // 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 @@ bool CompactDexWriter::Write(DexContainer* output, std::string* error_msg) { // 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 15e3baf18a..3917847ea7 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 @@ struct FileSectionDescriptor { 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 @@ static const FileSectionDescriptor kFileSectionDescriptors[] = { }, { "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 54ff105820..9f355ba9e8 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,37 +108,153 @@ class AbstractDispatcher { DISALLOW_COPY_AND_ASSIGN(AbstractDispatcher); }; -// Collections become owners of the objects added by moving them into unique pointers. -template<class T> class CollectionBase { +template<class T> class Iterator : public std::iterator<std::random_access_iterator_tag, T> { public: - CollectionBase() = default; + 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; + } - uint32_t GetOffset() const { - return offset_; + 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; } - void SetOffset(uint32_t new_offset) { - offset_ = new_offset; + + 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. +class CollectionBase { + public: + CollectionBase() = default; + virtual ~CollectionBase() { } + + 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. uint32_t offset_ = 0u; 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 @@ template<class T> class CollectionVector : public CollectionBase<T> { 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 @@ template<class T> class IndexedCollectionVector : public CollectionVector<T> { 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,330 +290,13 @@ template<class T> class IndexedCollectionVector : public CollectionVector<T> { 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; - 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); + DISALLOW_COPY_AND_ASSIGN(IndexedCollectionVector); }; class Item { @@ -598,12 +389,12 @@ class Header : public Item { 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 @@ class Header : public Item { 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 @@ class Header : public Item { 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 9468f763d6..a04a2349c4 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 @@ Header* DexIrBuilder(const DexFile& dex_file, 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 @@ Header* DexIrBuilder(const DexFile& dex_file, 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 @@ static void CheckAndSetRemainingOffsets(const DexFile& dex_file, 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 @@ static void CheckAndSetRemainingOffsets(const DexFile& dex_file, } } +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 2e4756b482..962798d6f4 100644 --- a/dexlayout/dex_verify.cc +++ b/dexlayout/dex_verify.cc @@ -31,38 +31,42 @@ using android::base::StringPrintf; 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 @@ struct ClassDefCompare { // 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_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)) { + 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()); + } + 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 998939bbce..4943defe16 100644 --- a/dexlayout/dex_verify.h +++ b/dexlayout/dex_verify.h @@ -30,8 +30,8 @@ bool VerifyOutputDexFile(dex_ir::Header* orig_header, 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::ProtoId* orig, dex_ir::ProtoId* output, std::string* error 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 0e04c587e7..abcaffc434 100644 --- a/dexlayout/dex_visualize.cc +++ b/dexlayout/dex_visualize.cc @@ -252,9 +252,9 @@ void VisualizeDexLayout(dex_ir::Header* header, 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 9ed1312983..a4c5cda4ba 100644 --- a/dexlayout/dex_writer.cc +++ b/dexlayout/dex_writer.cc @@ -231,7 +231,7 @@ void DexWriter::WriteEncodedMethods(Stream* stream, dex_ir::MethodItemVector* me // 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 @@ void DexWriter::WriteStringIds(Stream* stream, bool reserve_only) { } } if (compute_offsets_ && start != stream->Tell()) { - header_->GetCollections().SetStringIdsOffset(start); + header_->StringIds().SetOffset(start); } } @@ -256,25 +256,25 @@ void DexWriter::WriteStringData(Stream* stream, dex_ir::StringData* string_data) 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 @@ void DexWriter::WriteTypeLists(Stream* stream) { 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 @@ void DexWriter::WriteTypeLists(Stream* stream) { } } 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 @@ void DexWriter::WriteProtoIds(Stream* stream, bool reserve_only) { } } 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 @@ void DexWriter::WriteFieldIds(Stream* stream) { 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 @@ void DexWriter::WriteMethodIds(Stream* stream) { 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 @@ void DexWriter::WriteAnnotations(Stream* stream) { WriteEncodedAnnotation(stream, annotation->GetAnnotation()); } if (compute_offsets_ && start != stream->Tell()) { - header_->GetCollections().SetAnnotationItemsOffset(start); + header_->AnnotationItems().SetOffset(start); } } @@ -384,8 +382,7 @@ void DexWriter::WriteAnnotationSets(Stream* stream) { 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 @@ void DexWriter::WriteAnnotationSets(Stream* stream) { } } if (compute_offsets_ && start != stream->Tell()) { - header_->GetCollections().SetAnnotationSetItemsOffset(start); + header_->AnnotationSetItems().SetOffset(start); } } @@ -404,8 +401,7 @@ void DexWriter::WriteAnnotationSetRefs(Stream* stream) { 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 @@ void DexWriter::WriteAnnotationSetRefs(Stream* stream) { } } if (compute_offsets_ && start != stream->Tell()) { - header_->GetCollections().SetAnnotationSetRefListsOffset(start); + header_->AnnotationSetRefLists().SetOffset(start); } } @@ -424,8 +420,7 @@ void DexWriter::WriteAnnotationsDirectories(Stream* stream) { 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 @@ void DexWriter::WriteAnnotationsDirectories(Stream* stream) { } } if (compute_offsets_ && start != stream->Tell()) { - header_->GetCollections().SetAnnotationsDirectoryItemsOffset(start); + header_->AnnotationsDirectoryItems().SetOffset(start); } } @@ -475,12 +470,11 @@ void DexWriter::WriteDebugInfoItem(Stream* stream, dex_ir::DebugInfoItem* debug_ 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 @@ void DexWriter::WriteCodeItems(Stream* stream, bool reserve_only) { 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 @@ void DexWriter::WriteCodeItems(Stream* stream, bool reserve_only) { } 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 @@ void DexWriter::WriteClassDefs(Stream* stream, bool reserve_only) { } } 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 @@ void DexWriter::WriteClassDatas(Stream* stream) { 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 @@ void DexWriter::WriteCallSiteIds(Stream* stream, bool reserve_only) { } } 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 @@ void DexWriter::WriteMethodHandles(Stream* stream) { 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::WriteMapItems(Stream* stream, MapItemQueue* queue) { } 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 @@ void DexWriter::WriteHeader(Stream* stream) { 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 @@ bool DexWriter::Write(DexContainer* output, std::string* error_msg) { // 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 @@ bool DexWriter::Write(DexContainer* output, std::string* error_msg) { // 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 @@ bool DexWriter::Write(DexContainer* output, std::string* error_msg) { } // 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 39d93bfc77..d6dd9d1829 100644 --- a/dexlayout/dexlayout.cc +++ b/dexlayout/dexlayout.cc @@ -417,24 +417,24 @@ static std::unique_ptr<char[]> IndexString(dex_ir::Header* header, 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 @@ static std::unique_ptr<char[]> IndexString(dex_ir::Header* header, } 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 @@ static std::unique_ptr<char[]> IndexString(dex_ir::Header* header, 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::DumpEncodedValue(const dex_ir::EncodedValue* data) { */ 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 @@ void DexLayout::DumpFileHeader() { 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::DumpFileHeader() { */ 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 @@ void DexLayout::DumpAnnotationSetItem(dex_ir::AnnotationSetItem* set_item) { * 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 @@ void DexLayout::DumpInstruction(const dex_ir::CodeItem* code, * 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 @@ static void DumpLocalsCb(void* context, const DexFile::LocalInfo& entry) { /* * 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 @@ void DexLayout::DumpCode(uint32_t idx, 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 @@ void DexLayout::DumpCode(uint32_t idx, 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 @@ void DexLayout::DumpMethod(uint32_t idx, uint32_t flags, const dex_ir::CodeItem* 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 @@ void DexLayout::DumpSField(uint32_t idx, uint32_t flags, int i, dex_ir::EncodedV 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 @@ void DexLayout::DumpIField(uint32_t idx, uint32_t flags, int i) { * 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 @@ void DexLayout::DumpClass(int idx, char** last_package) { // 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 @@ void DexLayout::DumpDexFile() { // 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::DumpDexFile() { 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 @@ void DexLayout::LayoutClassDefsAndClassData(const DexFile* dex_file) { } 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 @@ void DexLayout::LayoutClassDefsAndClassData(const DexFile* dex_file) { ++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::LayoutClassDefsAndClassData(const DexFile* dex_file) { } 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 @@ void DexLayout::LayoutStringData(const DexFile* dex_file) { } // 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 @@ void DexLayout::LayoutStringData(const DexFile* dex_file) { // 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 @@ void DexLayout::LayoutStringData(const DexFile* dex_file) { 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 @@ void DexLayout::LayoutCodeItems(const DexFile* dex_file) { // 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 @@ void DexLayout::LayoutCodeItems(const DexFile* dex_file) { } } - 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 @@ bool DexLayout::ProcessDexFile(const char* file_name, 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/bit_table.h b/libartbase/base/bit_table.h index 6a714e6b9d..2cc1a31ade 100644 --- a/libartbase/base/bit_table.h +++ b/libartbase/base/bit_table.h @@ -18,6 +18,7 @@ #define ART_LIBARTBASE_BASE_BIT_TABLE_H_ #include <array> +#include <initializer_list> #include <numeric> #include <string.h> #include <type_traits> @@ -184,33 +185,54 @@ static const char* const* GetBitTableColumnNames() { } // Helper class for encoding BitTable. It can optionally de-duplicate the inputs. -// Type 'T' must be POD type consisting of uint32_t fields (one for each column). -template<typename T> +template<uint32_t kNumColumns> class BitTableBuilder { public: - static_assert(std::is_pod<T>::value, "Type 'T' must be POD"); - static constexpr size_t kNumColumns = sizeof(T) / sizeof(uint32_t); + class Entry { + public: + Entry() { + std::fill_n(data_, kNumColumns, BitTable<kNumColumns>::Accessor::kNoValue); + } + + Entry(std::initializer_list<uint32_t> values) { + DCHECK_EQ(values.size(), kNumColumns); + std::copy(values.begin(), values.end(), data_); + } + + uint32_t& operator[](size_t column) { + DCHECK_LT(column, kNumColumns); + return data_[column]; + } + + uint32_t operator[](size_t column) const { + DCHECK_LT(column, kNumColumns); + return data_[column]; + } + + private: + uint32_t data_[kNumColumns]; + }; explicit BitTableBuilder(ScopedArenaAllocator* allocator) : rows_(allocator->Adapter(kArenaAllocBitTableBuilder)), dedup_(8, allocator->Adapter(kArenaAllocBitTableBuilder)) { } - T& operator[](size_t row) { return rows_[row]; } - const T& operator[](size_t row) const { return rows_[row]; } + Entry& operator[](size_t row) { return rows_[row]; } + const Entry& operator[](size_t row) const { return rows_[row]; } size_t size() const { return rows_.size(); } // Append given value to the vector without de-duplication. // This will not add the element to the dedup map to avoid its associated costs. - void Add(T value) { + void Add(Entry value) { rows_.push_back(value); } // Append given list of values and return the index of the first value. // If the exact same set of values was already added, return the old index. - uint32_t Dedup(T* values, size_t count = 1) { + uint32_t Dedup(Entry* values, size_t count = 1) { FNVHash<MemoryRegion> hasher; - uint32_t hash = hasher(MemoryRegion(values, sizeof(T) * count)); + uint32_t hash = hasher(MemoryRegion(values, sizeof(Entry) * count)); // Check if we have already added identical set of values. auto range = dedup_.equal_range(hash); @@ -220,8 +242,8 @@ class BitTableBuilder { std::equal(values, values + count, rows_.begin() + index, - [](const T& lhs, const T& rhs) { - return memcmp(&lhs, &rhs, sizeof(T)) == 0; + [](const Entry& lhs, const Entry& rhs) { + return memcmp(&lhs, &rhs, sizeof(Entry)) == 0; })) { return index; } @@ -234,11 +256,8 @@ class BitTableBuilder { return index; } - ALWAYS_INLINE uint32_t Get(uint32_t row, uint32_t column) const { - DCHECK_LT(row, size()); - DCHECK_LT(column, kNumColumns); - const uint32_t* data = reinterpret_cast<const uint32_t*>(&rows_[row]); - return data[column]; + uint32_t Dedup(Entry value) { + return Dedup(&value, /* count */ 1); } // Calculate the column bit widths based on the current data. @@ -247,7 +266,7 @@ class BitTableBuilder { std::fill_n(max_column_value, kNumColumns, 0); for (uint32_t r = 0; r < size(); r++) { for (uint32_t c = 0; c < kNumColumns; c++) { - max_column_value[c] |= Get(r, c) - BitTable<kNumColumns>::kValueBias; + max_column_value[c] |= rows_[r][c] - BitTable<kNumColumns>::kValueBias; } } for (uint32_t c = 0; c < kNumColumns; c++) { @@ -276,7 +295,7 @@ class BitTableBuilder { BitMemoryRegion region(MemoryRegion(out->data(), out->size())); for (uint32_t r = 0; r < size(); r++) { for (uint32_t c = 0; c < kNumColumns; c++) { - region.StoreBitsAndAdvance(bit_offset, Get(r, c) - bias, column_bits[c]); + region.StoreBitsAndAdvance(bit_offset, rows_[r][c] - bias, column_bits[c]); } } } @@ -292,14 +311,14 @@ class BitTableBuilder { } for (uint32_t r = 0; r < size(); r++) { for (uint32_t c = 0; c < kNumColumns; c++) { - DCHECK_EQ(Get(r, c), table.Get(r, c)) << " (" << r << ", " << c << ")"; + DCHECK_EQ(rows_[r][c], table.Get(r, c)) << " (" << r << ", " << c << ")"; } } } } protected: - ScopedArenaDeque<T> rows_; + ScopedArenaDeque<Entry> rows_; ScopedArenaUnorderedMultimap<uint32_t, uint32_t> dedup_; // Hash -> row index. }; diff --git a/libartbase/base/bit_table_test.cc b/libartbase/base/bit_table_test.cc index 8abf0da9d9..969940fe39 100644 --- a/libartbase/base/bit_table_test.cc +++ b/libartbase/base/bit_table_test.cc @@ -50,7 +50,7 @@ TEST(BitTableTest, TestEmptyTable) { std::vector<uint8_t> buffer; size_t encode_bit_offset = 0; - BitTableBuilder<uint32_t> builder(&allocator); + BitTableBuilder<1> builder(&allocator); builder.Encode(&buffer, &encode_bit_offset); size_t decode_bit_offset = 0; @@ -67,11 +67,11 @@ TEST(BitTableTest, TestSingleColumnTable) { constexpr uint32_t kNoValue = -1; std::vector<uint8_t> buffer; size_t encode_bit_offset = 0; - BitTableBuilder<uint32_t> builder(&allocator); - builder.Add(42u); - builder.Add(kNoValue); - builder.Add(1000u); - builder.Add(kNoValue); + BitTableBuilder<1> builder(&allocator); + builder.Add({42u}); + builder.Add({kNoValue}); + builder.Add({1000u}); + builder.Add({kNoValue}); builder.Encode(&buffer, &encode_bit_offset); size_t decode_bit_offset = 0; @@ -93,8 +93,8 @@ TEST(BitTableTest, TestUnalignedTable) { for (size_t start_bit_offset = 0; start_bit_offset <= 32; start_bit_offset++) { std::vector<uint8_t> buffer; size_t encode_bit_offset = start_bit_offset; - BitTableBuilder<uint32_t> builder(&allocator); - builder.Add(42u); + BitTableBuilder<1> builder(&allocator); + builder.Add({42u}); builder.Encode(&buffer, &encode_bit_offset); size_t decode_bit_offset = start_bit_offset; @@ -113,15 +113,9 @@ TEST(BitTableTest, TestBigTable) { constexpr uint32_t kNoValue = -1; std::vector<uint8_t> buffer; size_t encode_bit_offset = 0; - struct RowData { - uint32_t a; - uint32_t b; - uint32_t c; - uint32_t d; - }; - BitTableBuilder<RowData> builder(&allocator); - builder.Add(RowData{42u, kNoValue, 0u, static_cast<uint32_t>(-2)}); - builder.Add(RowData{62u, kNoValue, 63u, static_cast<uint32_t>(-3)}); + BitTableBuilder<4> builder(&allocator); + builder.Add({42u, kNoValue, 0u, static_cast<uint32_t>(-2)}); + builder.Add({62u, kNoValue, 63u, static_cast<uint32_t>(-3)}); builder.Encode(&buffer, &encode_bit_offset); size_t decode_bit_offset = 0; @@ -147,13 +141,9 @@ TEST(BitTableTest, TestDedup) { ArenaStack arena_stack(&pool); ScopedArenaAllocator allocator(&arena_stack); - struct RowData { - uint32_t a; - uint32_t b; - }; - BitTableBuilder<RowData> builder(&allocator); - RowData value0{1, 2}; - RowData value1{3, 4}; + BitTableBuilder<2> builder(&allocator); + BitTableBuilder<2>::Entry value0{1, 2}; + BitTableBuilder<2>::Entry value1{3, 4}; EXPECT_EQ(0u, builder.Dedup(&value0)); EXPECT_EQ(1u, builder.Dedup(&value1)); EXPECT_EQ(0u, builder.Dedup(&value0)); @@ -197,16 +187,12 @@ TEST(BitTableTest, TestCollisions) { ScopedArenaAllocator allocator(&arena_stack); FNVHash<MemoryRegion> hasher; - struct RowData { - uint32_t a; - uint32_t b; - }; - RowData value0{56948505, 0}; - RowData value1{67108869, 0}; + BitTableBuilder<2>::Entry value0{56948505, 0}; + BitTableBuilder<2>::Entry value1{67108869, 0}; - BitTableBuilder<RowData> builder(&allocator); - EXPECT_EQ(hasher(MemoryRegion(&value0, sizeof(RowData))), - hasher(MemoryRegion(&value1, sizeof(RowData)))); + BitTableBuilder<2> builder(&allocator); + EXPECT_EQ(hasher(MemoryRegion(&value0, sizeof(value0))), + hasher(MemoryRegion(&value1, sizeof(value1)))); EXPECT_EQ(0u, builder.Dedup(&value0)); EXPECT_EQ(1u, builder.Dedup(&value1)); EXPECT_EQ(0u, builder.Dedup(&value0)); @@ -214,12 +200,12 @@ TEST(BitTableTest, TestCollisions) { EXPECT_EQ(2u, builder.size()); BitmapTableBuilder builder2(&allocator); - EXPECT_EQ(hasher(MemoryRegion(&value0, BitsToBytesRoundUp(MinimumBitsToStore(value0.a)))), - hasher(MemoryRegion(&value1, BitsToBytesRoundUp(MinimumBitsToStore(value1.a))))); - EXPECT_EQ(0u, builder2.Dedup(&value0.a, MinimumBitsToStore(value0.a))); - EXPECT_EQ(1u, builder2.Dedup(&value1.a, MinimumBitsToStore(value1.a))); - EXPECT_EQ(0u, builder2.Dedup(&value0.a, MinimumBitsToStore(value0.a))); - EXPECT_EQ(1u, builder2.Dedup(&value1.a, MinimumBitsToStore(value1.a))); + EXPECT_EQ(hasher(MemoryRegion(&value0, BitsToBytesRoundUp(MinimumBitsToStore(value0[0])))), + hasher(MemoryRegion(&value1, BitsToBytesRoundUp(MinimumBitsToStore(value1[0]))))); + EXPECT_EQ(0u, builder2.Dedup(&value0[0], MinimumBitsToStore(value0[0]))); + EXPECT_EQ(1u, builder2.Dedup(&value1[0], MinimumBitsToStore(value1[0]))); + EXPECT_EQ(0u, builder2.Dedup(&value0[0], MinimumBitsToStore(value0[0]))); + EXPECT_EQ(1u, builder2.Dedup(&value1[0], MinimumBitsToStore(value1[0]))); EXPECT_EQ(2u, builder2.size()); } diff --git a/openjdkjvmti/ti_ddms.cc b/openjdkjvmti/ti_ddms.cc index 0b4906d798..bf063faf7b 100644 --- a/openjdkjvmti/ti_ddms.cc +++ b/openjdkjvmti/ti_ddms.cc @@ -60,7 +60,7 @@ jvmtiError DDMSUtil::HandleChunk(jvmtiEnv* env, *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 777a1fc5ee..1168798f38 100644 --- a/runtime/Android.bp +++ b/runtime/Android.bp @@ -47,6 +47,7 @@ libart_cc_defaults { "debug_print.cc", "debugger.cc", "dex/dex_file_annotations.cc", + "dex_register_location.cc", "dex_to_dex_decompiler.cc", "elf_file.cc", "exec_utils.cc", diff --git a/runtime/check_jni.cc b/runtime/check_jni.cc index 0ff55ae25b..a875498f74 100644 --- a/runtime/check_jni.cc +++ b/runtime/check_jni.cc @@ -2173,7 +2173,7 @@ class CheckJNI { 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 @@ class CheckJNI { 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 @@ class CheckJNI { } #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 @@ class CheckJNI { } 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_reference_map_visitor.h b/runtime/check_reference_map_visitor.h index 8a2a70e7ab..8f9f45c30b 100644 --- a/runtime/check_reference_map_visitor.h +++ b/runtime/check_reference_map_visitor.h @@ -75,7 +75,7 @@ class CheckReferenceMapVisitor : public StackVisitor { for (int i = 0; i < number_of_references; ++i) { int reg = registers[i]; CHECK_LT(reg, accessor.RegistersSize()); - DexRegisterLocation location = dex_register_map.GetDexRegisterLocation(reg); + DexRegisterLocation location = dex_register_map[reg]; switch (location.GetKind()) { case DexRegisterLocation::Kind::kNone: // Not set, should not be a reference. @@ -98,7 +98,7 @@ class CheckReferenceMapVisitor : public StackVisitor { CHECK_EQ(location.GetValue(), 0); break; default: - LOG(FATAL) << "Unexpected location kind " << location.GetInternalKind(); + LOG(FATAL) << "Unexpected location kind " << location.GetKind(); } } } diff --git a/runtime/dex_register_location.cc b/runtime/dex_register_location.cc new file mode 100644 index 0000000000..f3b09733b9 --- /dev/null +++ b/runtime/dex_register_location.cc @@ -0,0 +1,50 @@ +/* + * 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. + */ + +#include "dex_register_location.h" + +namespace art { + +std::ostream& operator<<(std::ostream& stream, DexRegisterLocation::Kind kind) { + return stream << "Kind<" << static_cast<int32_t>(kind) << ">"; +} + +std::ostream& operator<<(std::ostream& stream, const DexRegisterLocation& reg) { + using Kind = DexRegisterLocation::Kind; + switch (reg.GetKind()) { + case Kind::kInvalid: + return stream << "Invalid"; + case Kind::kNone: + return stream << "None"; + case Kind::kInStack: + return stream << "sp+" << reg.GetValue(); + case Kind::kInRegister: + return stream << "r" << reg.GetValue(); + case Kind::kInRegisterHigh: + return stream << "r" << reg.GetValue() << "/hi"; + case Kind::kInFpuRegister: + return stream << "f" << reg.GetValue(); + case Kind::kInFpuRegisterHigh: + return stream << "f" << reg.GetValue() << "/hi"; + case Kind::kConstant: + return stream << "#" << reg.GetValue(); + default: + return stream << "DexRegisterLocation(" << static_cast<uint32_t>(reg.GetKind()) + << "," << reg.GetValue() << ")"; + } +} + +} // namespace art diff --git a/runtime/dex_register_location.h b/runtime/dex_register_location.h index a20dccbc12..98b4d41e2d 100644 --- a/runtime/dex_register_location.h +++ b/runtime/dex_register_location.h @@ -48,9 +48,6 @@ class DexRegisterLocation { Kind GetKind() const { return kind_; } - // TODO: Remove. - Kind GetInternalKind() const { return kind_; } - int32_t GetValue() const { return value_; } bool operator==(DexRegisterLocation other) const { @@ -61,6 +58,24 @@ class DexRegisterLocation { return !(*this == other); } + int32_t GetStackOffsetInBytes() const { + DCHECK(kind_ == Kind::kInStack); + return value_; + } + + int32_t GetConstant() const { + DCHECK(kind_ == Kind::kConstant); + return value_; + } + + int32_t GetMachineRegister() const { + DCHECK(kind_ == Kind::kInRegister || + kind_ == Kind::kInRegisterHigh || + kind_ == Kind::kInFpuRegister || + kind_ == Kind::kInFpuRegisterHigh); + return value_; + } + private: DexRegisterLocation() {} @@ -70,9 +85,8 @@ class DexRegisterLocation { friend class DexRegisterMap; // Allow creation of uninitialized array of locations. }; -static inline std::ostream& operator<<(std::ostream& stream, DexRegisterLocation::Kind kind) { - return stream << "Kind<" << static_cast<int32_t>(kind) << ">"; -} +std::ostream& operator<<(std::ostream& stream, DexRegisterLocation::Kind kind); +std::ostream& operator<<(std::ostream& stream, const DexRegisterLocation& reg); } // namespace art diff --git a/runtime/jit/jit.cc b/runtime/jit/jit.cc index 0a8e0cd64f..5e736035f8 100644 --- a/runtime/jit/jit.cc +++ b/runtime/jit/jit.cc @@ -515,7 +515,7 @@ bool Jit::MaybeDoOnStackReplacement(Thread* thread, } else { DCHECK_EQ(vreg_map.size(), number_of_vregs); for (uint16_t vreg = 0; vreg < number_of_vregs; ++vreg) { - DexRegisterLocation::Kind location = vreg_map.GetLocationKind(vreg); + DexRegisterLocation::Kind location = vreg_map[vreg].GetKind(); if (location == DexRegisterLocation::Kind::kNone) { // Dex register is dead or uninitialized. continue; @@ -529,7 +529,7 @@ bool Jit::MaybeDoOnStackReplacement(Thread* thread, DCHECK_EQ(location, DexRegisterLocation::Kind::kInStack); int32_t vreg_value = shadow_frame->GetVReg(vreg); - int32_t slot_offset = vreg_map.GetStackOffsetInBytes(vreg); + int32_t slot_offset = vreg_map[vreg].GetStackOffsetInBytes(); DCHECK_LT(slot_offset, static_cast<int32_t>(frame_size)); DCHECK_GT(slot_offset, 0); (reinterpret_cast<int32_t*>(memory))[slot_offset / sizeof(int32_t)] = vreg_value; diff --git a/runtime/jni/jni_internal.cc b/runtime/jni/jni_internal.cc index 7290d638f3..a02e76ae54 100644 --- a/runtime/jni/jni_internal.cc +++ b/runtime/jni/jni_internal.cc @@ -761,7 +761,7 @@ class JNI { 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 @@ class JNI { 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 @@ class JNI { 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 @@ class JNI { 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 @@ class JNI { 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 @@ class JNI { 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 @@ class JNI { 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 @@ class JNI { 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 @@ class JNI { 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 @@ class JNI { 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 @@ class JNI { 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 @@ class JNI { } 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 @@ class JNI { } 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 @@ class JNI { } 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 @@ class JNI { } 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 @@ class JNI { } 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 @@ class JNI { } 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 @@ class JNI { } 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 @@ class JNI { } 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 @@ class JNI { } 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 @@ class JNI { } 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 @@ class JNI { 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 @@ class JNI { 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 @@ class JNI { 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 @@ class JNI { 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 @@ class JNI { 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 @@ class JNI { 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 @@ class JNI { 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 @@ class JNI { 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 @@ class JNI { 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 @@ class JNI { 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-readbarrier-inl.h b/runtime/mirror/object-readbarrier-inl.h index aeaa850abe..2988d06d96 100644 --- a/runtime/mirror/object-readbarrier-inl.h +++ b/runtime/mirror/object-readbarrier-inl.h @@ -39,7 +39,8 @@ inline LockWord Object::GetLockWord(bool as_volatile) { template<bool kTransactionActive, bool kCheckTransaction, VerifyObjectFlags kVerifyFlags> inline bool Object::CasFieldWeakRelaxed32(MemberOffset field_offset, - int32_t old_value, int32_t new_value) { + int32_t old_value, + int32_t new_value) { if (kCheckTransaction) { DCHECK_EQ(kTransactionActive, Runtime::Current()->IsActiveTransaction()); } @@ -55,10 +56,37 @@ inline bool Object::CasFieldWeakRelaxed32(MemberOffset field_offset, return atomic_addr->CompareAndSetWeakRelaxed(old_value, new_value); } +template<bool kTransactionActive, bool kCheckTransaction, VerifyObjectFlags kVerifyFlags> +inline bool Object::CasFieldStrongRelaxed32(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->CompareAndSetStrongRelaxed(old_value, new_value); +} + inline bool Object::CasLockWordWeakRelaxed(LockWord old_val, LockWord new_val) { // 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()); + return CasFieldWeakRelaxed32<false, false>(OFFSET_OF_OBJECT_MEMBER(Object, monitor_), + old_val.GetValue(), + new_val.GetValue()); +} + +inline bool Object::CasLockWordStrongRelaxed(LockWord old_val, LockWord new_val) { + // Force use of non-transactional mode and do not check. + return CasFieldStrongRelaxed32<false, false>(OFFSET_OF_OBJECT_MEMBER(Object, monitor_), + old_val.GetValue(), + new_val.GetValue()); } inline bool Object::CasLockWordWeakRelease(LockWord old_val, LockWord new_val) { diff --git a/runtime/mirror/object.cc b/runtime/mirror/object.cc index 4240e702b5..200bc471b8 100644 --- a/runtime/mirror/object.cc +++ b/runtime/mirror/object.cc @@ -197,7 +197,9 @@ int32_t Object::IdentityHashCode() { // 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->CasLockWordStrongRelaxed(lw, hash_word)) { return hash_word.GetHashCode(); } break; diff --git a/runtime/mirror/object.h b/runtime/mirror/object.h index a89d6323a5..f92ff1e2af 100644 --- a/runtime/mirror/object.h +++ b/runtime/mirror/object.h @@ -159,6 +159,8 @@ class MANAGED LOCKABLE Object { REQUIRES_SHARED(Locks::mutator_lock_); bool CasLockWordWeakRelease(LockWord old_val, LockWord new_val) REQUIRES_SHARED(Locks::mutator_lock_); + bool CasLockWordStrongRelaxed(LockWord old_val, LockWord new_val) + REQUIRES_SHARED(Locks::mutator_lock_); uint32_t GetLockOwnerThreadId(); // Try to enter the monitor, returns non null if we succeeded. @@ -539,6 +541,14 @@ class MANAGED LOCKABLE Object { template<bool kTransactionActive, bool kCheckTransaction = true, VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> + ALWAYS_INLINE bool CasFieldStrongRelaxed32(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) diff --git a/runtime/monitor.cc b/runtime/monitor.cc index 2c38de5dae..e723169ac2 100644 --- a/runtime/monitor.cc +++ b/runtime/monitor.cc @@ -134,13 +134,15 @@ Monitor::Monitor(Thread* self, Thread* owner, mirror::Object* obj, int32_t hash_ } 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) { diff --git a/runtime/quick_exception_handler.cc b/runtime/quick_exception_handler.cc index cf1cbe7f7b..8b99b9f9c8 100644 --- a/runtime/quick_exception_handler.cc +++ b/runtime/quick_exception_handler.cc @@ -245,7 +245,7 @@ void QuickExceptionHandler::SetCatchEnvironmentForOptimizedHandler(StackVisitor* // Copy values between them. for (uint16_t vreg = 0; vreg < number_of_vregs; ++vreg) { - DexRegisterLocation::Kind catch_location = catch_vreg_map.GetLocationKind(vreg); + DexRegisterLocation::Kind catch_location = catch_vreg_map[vreg].GetKind(); if (catch_location == DexRegisterLocation::Kind::kNone) { continue; } @@ -253,7 +253,7 @@ void QuickExceptionHandler::SetCatchEnvironmentForOptimizedHandler(StackVisitor* // Get vreg value from its current location. uint32_t vreg_value; - VRegKind vreg_kind = ToVRegKind(throw_vreg_map.GetLocationKind(vreg)); + VRegKind vreg_kind = ToVRegKind(throw_vreg_map[vreg].GetKind()); bool get_vreg_success = stack_visitor->GetVReg(stack_visitor->GetMethod(), vreg, vreg_kind, @@ -264,7 +264,7 @@ void QuickExceptionHandler::SetCatchEnvironmentForOptimizedHandler(StackVisitor* << "native_pc_offset=" << stack_visitor->GetNativePcOffset() << ")"; // Copy value to the catch phi's stack slot. - int32_t slot_offset = catch_vreg_map.GetStackOffsetInBytes(vreg); + int32_t slot_offset = catch_vreg_map[vreg].GetStackOffsetInBytes(); ArtMethod** frame_top = stack_visitor->GetCurrentQuickFrame(); uint8_t* slot_address = reinterpret_cast<uint8_t*>(frame_top) + slot_offset; uint32_t* slot_ptr = reinterpret_cast<uint32_t*>(slot_address); @@ -417,14 +417,14 @@ class DeoptimizeStackVisitor FINAL : public StackVisitor { continue; } - DexRegisterLocation::Kind location = vreg_map.GetLocationKind(vreg); + DexRegisterLocation::Kind location = vreg_map[vreg].GetKind(); static constexpr uint32_t kDeadValue = 0xEBADDE09; uint32_t value = kDeadValue; bool is_reference = false; switch (location) { case DexRegisterLocation::Kind::kInStack: { - const int32_t offset = vreg_map.GetStackOffsetInBytes(vreg); + const int32_t offset = vreg_map[vreg].GetStackOffsetInBytes(); const uint8_t* addr = reinterpret_cast<const uint8_t*>(GetCurrentQuickFrame()) + offset; value = *reinterpret_cast<const uint32_t*>(addr); uint32_t bit = (offset >> 2); @@ -437,7 +437,7 @@ class DeoptimizeStackVisitor FINAL : public StackVisitor { case DexRegisterLocation::Kind::kInRegisterHigh: case DexRegisterLocation::Kind::kInFpuRegister: case DexRegisterLocation::Kind::kInFpuRegisterHigh: { - uint32_t reg = vreg_map.GetMachineRegister(vreg); + uint32_t reg = vreg_map[vreg].GetMachineRegister(); bool result = GetRegisterIfAccessible(reg, ToVRegKind(location), &value); CHECK(result); if (location == DexRegisterLocation::Kind::kInRegister) { @@ -448,7 +448,7 @@ class DeoptimizeStackVisitor FINAL : public StackVisitor { break; } case DexRegisterLocation::Kind::kConstant: { - value = vreg_map.GetConstant(vreg); + value = vreg_map[vreg].GetConstant(); if (value == 0) { // Make it a reference for extra safety. is_reference = true; @@ -459,9 +459,7 @@ class DeoptimizeStackVisitor FINAL : public StackVisitor { break; } default: { - LOG(FATAL) - << "Unexpected location kind " - << vreg_map.GetLocationInternalKind(vreg); + LOG(FATAL) << "Unexpected location kind " << vreg_map[vreg].GetKind(); UNREACHABLE(); } } diff --git a/runtime/reflection.cc b/runtime/reflection.cc index 6aeedd4f02..9e9c33caa8 100644 --- a/runtime/reflection.cc +++ b/runtime/reflection.cc @@ -138,7 +138,7 @@ class ArgArray { } 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 InvokeWithVarArgs(const ScopedObjectAccessAlreadyRunnable& soa, jobject o } 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 InvokeWithJValues(const ScopedObjectAccessAlreadyRunnable& soa, jobject o } 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 4560a3969e..4391bcd60b 100644 --- a/runtime/reflection.h +++ b/runtime/reflection.h @@ -69,13 +69,13 @@ JValue InvokeWithVarArgs(const ScopedObjectAccessAlreadyRunnable& soa, 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/stack.cc b/runtime/stack.cc index 275e3e3d87..a181bfe091 100644 --- a/runtime/stack.cc +++ b/runtime/stack.cc @@ -242,10 +242,10 @@ bool StackVisitor::GetVRegFromOptimizedCode(ArtMethod* m, uint16_t vreg, VRegKin return false; } DCHECK_EQ(dex_register_map.size(), number_of_dex_registers); - DexRegisterLocation::Kind location_kind = dex_register_map.GetLocationKind(vreg); + DexRegisterLocation::Kind location_kind = dex_register_map[vreg].GetKind(); switch (location_kind) { case DexRegisterLocation::Kind::kInStack: { - const int32_t offset = dex_register_map.GetStackOffsetInBytes(vreg); + const int32_t offset = dex_register_map[vreg].GetStackOffsetInBytes(); const uint8_t* addr = reinterpret_cast<const uint8_t*>(cur_quick_frame_) + offset; *val = *reinterpret_cast<const uint32_t*>(addr); return true; @@ -254,18 +254,16 @@ bool StackVisitor::GetVRegFromOptimizedCode(ArtMethod* m, uint16_t vreg, VRegKin case DexRegisterLocation::Kind::kInRegisterHigh: case DexRegisterLocation::Kind::kInFpuRegister: case DexRegisterLocation::Kind::kInFpuRegisterHigh: { - uint32_t reg = dex_register_map.GetMachineRegister(vreg); + uint32_t reg = dex_register_map[vreg].GetMachineRegister(); return GetRegisterIfAccessible(reg, kind, val); } case DexRegisterLocation::Kind::kConstant: - *val = dex_register_map.GetConstant(vreg); + *val = dex_register_map[vreg].GetConstant(); return true; case DexRegisterLocation::Kind::kNone: return false; default: - LOG(FATAL) - << "Unexpected location kind " - << dex_register_map.GetLocationInternalKind(vreg); + LOG(FATAL) << "Unexpected location kind " << dex_register_map[vreg].GetKind(); UNREACHABLE(); } } diff --git a/runtime/stack_map.cc b/runtime/stack_map.cc index 23cc1d6358..43609e80bd 100644 --- a/runtime/stack_map.cc +++ b/runtime/stack_map.cc @@ -89,31 +89,6 @@ void CodeInfo::DecodeDexRegisterMap(uint32_t stack_map_index, } } -std::ostream& operator<<(std::ostream& stream, const DexRegisterLocation& reg) { - using Kind = DexRegisterLocation::Kind; - switch (reg.GetKind()) { - case Kind::kNone: - return stream << "None"; - case Kind::kInStack: - return stream << "sp+" << reg.GetValue(); - case Kind::kInRegister: - return stream << "r" << reg.GetValue(); - case Kind::kInRegisterHigh: - return stream << "r" << reg.GetValue() << "/hi"; - case Kind::kInFpuRegister: - return stream << "f" << reg.GetValue(); - case Kind::kInFpuRegisterHigh: - return stream << "f" << reg.GetValue() << "/hi"; - case Kind::kConstant: - return stream << "#" << reg.GetValue(); - case Kind::kInvalid: - return stream << "Invalid"; - default: - return stream << "DexRegisterLocation(" << static_cast<uint32_t>(reg.GetKind()) - << "," << reg.GetValue() << ")"; - } -} - template<typename Accessor> static void AddTableSizeStats(const char* table_name, const BitTable<Accessor::kCount>& table, @@ -144,13 +119,13 @@ void CodeInfo::AddSizeStats(/*out*/ Stats* parent) const { AddTableSizeStats<DexRegisterInfo>("DexRegisterCatalog", dex_register_catalog_, stats); } -static void DumpDexRegisterMap(VariableIndentationOutputStream* vios, - const DexRegisterMap& map) { - if (map.HasAnyLiveDexRegisters()) { +void DexRegisterMap::Dump(VariableIndentationOutputStream* vios) const { + if (HasAnyLiveDexRegisters()) { ScopedIndentation indent1(vios); - for (size_t i = 0; i < map.size(); ++i) { - if (map.IsDexRegisterLive(i)) { - vios->Stream() << "v" << i << ":" << map.Get(i) << " "; + for (size_t i = 0; i < size(); ++i) { + DexRegisterLocation reg = (*this)[i]; + if (reg.IsLive()) { + vios->Stream() << "v" << i << ":" << reg << " "; } } vios->Stream() << "\n"; @@ -240,7 +215,7 @@ void StackMap::Dump(VariableIndentationOutputStream* vios, vios->Stream() << stack_mask.LoadBit(e - i - 1); } vios->Stream() << ")\n"; - DumpDexRegisterMap(vios, code_info.GetDexRegisterMapOf(*this)); + code_info.GetDexRegisterMapOf(*this).Dump(vios); uint32_t depth = code_info.GetInlineDepthOf(*this); for (size_t d = 0; d < depth; d++) { InlineInfo inline_info = code_info.GetInlineInfoAtDepth(*this, d); @@ -267,7 +242,7 @@ void InlineInfo::Dump(VariableIndentationOutputStream* vios, << ", method_index=" << GetMethodIndex(method_info); } vios->Stream() << ")\n"; - DumpDexRegisterMap(vios, code_info.GetDexRegisterMapAtDepth(depth, stack_map)); + code_info.GetDexRegisterMapAtDepth(depth, stack_map).Dump(vios); } } // namespace art diff --git a/runtime/stack_map.h b/runtime/stack_map.h index faa196f28e..8af73e9e10 100644 --- a/runtime/stack_map.h +++ b/runtime/stack_map.h @@ -54,9 +54,11 @@ std::ostream& operator<<(std::ostream& stream, const DexRegisterLocation& reg); // Information on Dex register locations for a specific PC. // Effectively just a convenience wrapper for DexRegisterLocation vector. // If the size is small enough, it keeps the data on the stack. +// TODO: Replace this with generic purpose "small-vector" implementation. class DexRegisterMap { public: using iterator = DexRegisterLocation*; + using const_iterator = const DexRegisterLocation*; // Create map for given number of registers and initialize them to the given value. DexRegisterMap(size_t count, DexRegisterLocation value) : count_(count), regs_small_{} { @@ -70,76 +72,36 @@ class DexRegisterMap { DexRegisterLocation* data() { return count_ <= kSmallCount ? regs_small_.data() : regs_large_.data(); } + const DexRegisterLocation* data() const { + return count_ <= kSmallCount ? regs_small_.data() : regs_large_.data(); + } iterator begin() { return data(); } iterator end() { return data() + count_; } - + const_iterator begin() const { return data(); } + const_iterator end() const { return data() + count_; } size_t size() const { return count_; } - bool empty() const { return count_ == 0; } - DexRegisterLocation Get(size_t index) const { + DexRegisterLocation& operator[](size_t index) { DCHECK_LT(index, count_); - return count_ <= kSmallCount ? regs_small_[index] : regs_large_[index]; - } - - DexRegisterLocation::Kind GetLocationKind(uint16_t dex_register_number) const { - return Get(dex_register_number).GetKind(); - } - - // TODO: Remove. - DexRegisterLocation::Kind GetLocationInternalKind(uint16_t dex_register_number) const { - return Get(dex_register_number).GetKind(); - } - - DexRegisterLocation GetDexRegisterLocation(uint16_t dex_register_number) const { - return Get(dex_register_number); - } - - int32_t GetStackOffsetInBytes(uint16_t dex_register_number) const { - DexRegisterLocation location = Get(dex_register_number); - DCHECK(location.GetKind() == DexRegisterLocation::Kind::kInStack); - return location.GetValue(); + return data()[index]; } - - int32_t GetConstant(uint16_t dex_register_number) const { - DexRegisterLocation location = Get(dex_register_number); - DCHECK(location.GetKind() == DexRegisterLocation::Kind::kConstant); - return location.GetValue(); - } - - int32_t GetMachineRegister(uint16_t dex_register_number) const { - DexRegisterLocation location = Get(dex_register_number); - DCHECK(location.GetKind() == DexRegisterLocation::Kind::kInRegister || - location.GetKind() == DexRegisterLocation::Kind::kInRegisterHigh || - location.GetKind() == DexRegisterLocation::Kind::kInFpuRegister || - location.GetKind() == DexRegisterLocation::Kind::kInFpuRegisterHigh); - return location.GetValue(); - } - - ALWAYS_INLINE bool IsDexRegisterLive(uint16_t dex_register_number) const { - return Get(dex_register_number).IsLive(); + const DexRegisterLocation& operator[](size_t index) const { + DCHECK_LT(index, count_); + return data()[index]; } size_t GetNumberOfLiveDexRegisters() const { - size_t number_of_live_dex_registers = 0; - for (size_t i = 0; i < count_; ++i) { - if (IsDexRegisterLive(i)) { - ++number_of_live_dex_registers; - } - } - return number_of_live_dex_registers; + return std::count_if(begin(), end(), [](auto& loc) { return loc.IsLive(); }); } bool HasAnyLiveDexRegisters() const { - for (size_t i = 0; i < count_; ++i) { - if (IsDexRegisterLive(i)) { - return true; - } - } - return false; + return std::any_of(begin(), end(), [](auto& loc) { return loc.IsLive(); }); } + void Dump(VariableIndentationOutputStream* vios) const; + private: // Store the data inline if the number of registers is small to avoid memory allocations. // If count_ <= kSmallCount, we use the regs_small_ array, and regs_large_ otherwise. diff --git a/runtime/thread.cc b/runtime/thread.cc index 4a53425477..7a7a80e4b6 100644 --- a/runtime/thread.cc +++ b/runtime/thread.cc @@ -3658,7 +3658,7 @@ class ReferenceMapVisitor : public StackVisitor { REQUIRES_SHARED(Locks::mutator_lock_) { bool found = false; for (size_t dex_reg = 0; dex_reg != number_of_dex_registers; ++dex_reg) { - DexRegisterLocation location = dex_register_map.GetDexRegisterLocation(dex_reg); + DexRegisterLocation location = dex_register_map[dex_reg]; if (location.GetKind() == kind && static_cast<size_t>(location.GetValue()) == index) { visitor(ref, dex_reg, stack_visitor); found = true; diff --git a/test/004-ReferenceMap/build b/test/004-ReferenceMap/build index 08987b556c..3bb63ca624 100644 --- a/test/004-ReferenceMap/build +++ b/test/004-ReferenceMap/build @@ -21,6 +21,5 @@ set -e # (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 08987b556c..3bb63ca624 100644 --- a/test/004-StackWalk/build +++ b/test/004-StackWalk/build @@ -21,6 +21,5 @@ set -e # (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 f6aad91e97..ab1c822ebf 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 ea12b3a540..e5fa6693a3 100755 --- a/test/091-override-package-private-method/build +++ b/test/091-override-package-private-method/build @@ -24,8 +24,8 @@ mkdir classes-ex 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 6fe73af8d8..f24c5b2004 100644 --- a/test/111-unresolvable-exception/build +++ b/test/111-unresolvable-exception/build @@ -22,6 +22,6 @@ ${JAVAC} -d classes `find src -name '*.java'` 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 f945563939..4ad7cb9134 100644 --- a/test/113-multidex/build +++ b/test/113-multidex/build @@ -29,9 +29,9 @@ rm classes2/Second.class classes2/FillerA.class classes2/FillerB.class classes2/ 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 cf19855316..b4bb88d644 100644 --- a/test/126-miranda-multidex/build +++ b/test/126-miranda-multidex/build @@ -29,9 +29,9 @@ rm classes2/Main.class classes2/MirandaAbstract.class classes2/MirandaClass*.cla 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 712774f7ef..c23b7613b9 100755 --- a/test/127-checker-secondarydex/build +++ b/test/127-checker-secondarydex/build @@ -24,8 +24,8 @@ mkdir classes-ex 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 a91d348441..985d27309e 100644 --- a/test/137-cfi/cfi.cc +++ b/test/137-cfi/cfi.cc @@ -54,15 +54,38 @@ static void CauseSegfault() { #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 @@ static void MoreErrorInfo(pid_t pid, bool sig_quit_on_fail) { } #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 @@ extern "C" JNIEXPORT jboolean JNICALL Java_Main_unwindInProcess( // 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 @@ extern "C" JNIEXPORT jboolean JNICALL Java_Main_unwindInProcess( } #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 @@ int wait_for_sigstop(pid_t tid, int* total_sleep_time_usec, bool* detach_failed } #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 @@ extern "C" JNIEXPORT jboolean JNICALL Java_Main_unwindOtherProcess( 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 @@ extern "C" JNIEXPORT jboolean JNICALL Java_Main_unwindOtherProcess( // 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 8db7853696..eedae8f51f 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 9190b1cf10..4096b895ee 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 d3f8a5681d..986a3c2226 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 9a2e352b8c..5b32d8e1fe 100644 --- a/test/137-cfi/src/Main.java +++ b/test/137-cfi/src/Main.java @@ -22,181 +22,68 @@ import java.util.Comparator; 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; + private static boolean secondary; - // Expect the symbols to contain full method signatures including parameters. - private boolean fullSignatures; - - private boolean passed; - - public Main(String[] args) throws Exception { + public static void main(String[] args) throws Exception { System.loadLibrary(args[0]); - for (String arg : args) { - if (arg.equals("--test-local")) { + for (int i = 1; i < args.length; i++) { + if (args[i].equals("--test-local")) { testLocal = true; - } - if (arg.equals("--test-remote")) { + } else if (args[i].equals("--test-remote")) { testRemote = true; - } - if (arg.equals("--secondary")) { + } else if (args[i].equals("--secondary")) { secondary = true; + } else { + System.out.println("Unknown argument: " + args[i]); + System.exit(1); } - if (arg.equals("--full-signatures")) { - fullSignatures = true; - } - } - if (!testLocal && !testRemote) { - System.out.println("No test selected."); - } - } - - 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!"); - } - runSecondary(); - } else { - runPrimary(); - } - } - - 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); - } + // Call test() via base class to test unwinding through multidex. + new Main().runTest(); } - 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. } - } - // Native functions. Note: to avoid deduping, they must all have different signatures. + if (testLocal) { + String result = unwindInProcess() ? "PASS" : "FAIL"; + System.out.println("Unwind in process: " + result); + } - public native boolean sleep(int i, boolean b, double dummy); + 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); + } + } - 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 76d535abf1..3ff15aae38 100755 --- a/test/138-duplicate-classes-check2/build +++ b/test/138-duplicate-classes-check2/build @@ -25,8 +25,8 @@ ${JAVAC} -d classes-ex `find src-ex -name '*.java'` 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 44ea0c9877..58ffe04fee 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 @@ class TestVisitor : public StackVisitor { 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; + 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 value = 0; - CHECK(GetVReg(m, 0, kIntVReg, &value)); - CHECK_EQ(value, 42u); - } else if (m_name.compare("$opt$noinline$testIntervalHole") == 0) { 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 19032601fa..29a6901a70 100644 --- a/test/466-get-live-vreg/src/Main.java +++ b/test/466-get-live-vreg/src/Main.java @@ -18,9 +18,9 @@ public class Main { 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 @@ public class Main { } } - 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 class Main { 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 @@ public class Main { 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 2504ab2839..237e4dafb6 100644 --- a/test/477-checker-bound-type/src/Main.java +++ b/test/477-checker-bound-type/src/Main.java @@ -57,5 +57,79 @@ public class Main { } } - 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 d85147f17b..0000000000 --- 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 67b6ceb53f..e716c04491 100644 --- a/test/565-checker-condition-liveness/info.txt +++ b/test/565-checker-condition-liveness/info.txt @@ -1 +1 @@ -Test the use positions of inputs of non-materialized conditions.
\ No newline at end of file +Test the results of liveness analysis e.g. use positions of inputs of non-materialized conditions.
\ No newline at end of file diff --git a/test/565-checker-condition-liveness/src/Main.java b/test/565-checker-condition-liveness/src/Main.java index acfcecdba8..6b6619fa43 100644 --- a/test/565-checker-condition-liveness/src/Main.java +++ b/test/565-checker-condition-liveness/src/Main.java @@ -31,6 +31,82 @@ public class Main { 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 @@ public class Main { 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 10ffcc537d..0000000000 --- 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 0000000000..ca5027e971 --- /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 0000000000..b9e1315bd4 --- /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 eb0e8688c0..79b8555878 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 d85147f17b..0000000000 --- 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 d85147f17b..0000000000 --- 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 a1c30f7b4e..8efac92c34 100644 --- a/test/639-checker-code-sinking/src/Main.java +++ b/test/639-checker-code-sinking/src/Main.java @@ -343,6 +343,37 @@ public class Main { } } + 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 d85147f17b..0000000000 --- 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 2a1382dfde..79904ce74f 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 @@ public class Main { /// 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 @@ public class Main { /// 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 d85147f17b..0000000000 --- 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 4035b97209..1ecb1d8273 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 @@ public class Main { /// 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 @@ public class Main { 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 @@ public class Main { /// 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 @@ public class Main { 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 d85147f17b..0000000000 --- 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 6549dab9ff..cbe629711f 100644 --- a/test/646-checker-hadd-char/src/Main.java +++ b/test/646-checker-hadd-char/src/Main.java @@ -67,7 +67,7 @@ public class Main { /// 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 @@ public class Main { /// 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 d85147f17b..0000000000 --- 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 c09da8125b..d78a678dc8 100644 --- a/test/646-checker-hadd-short/src/Main.java +++ b/test/646-checker-hadd-short/src/Main.java @@ -86,7 +86,7 @@ public class Main { /// 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 @@ public class Main { 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 @@ public class Main { /// 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 @@ public class Main { 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 @@ public class Main { /// 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 @@ public class Main { 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 d85147f17b..0000000000 --- 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 778d55c3ce..38003d18c6 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 @@ public class Main { /// 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 @@ public class Main { /// 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 @@ public class Main { /// 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 d85147f17b..0000000000 --- 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 91c92f1179..18ae024231 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 @@ public class Main { /// 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 @@ public class Main { /// 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 @@ public class Main { /// 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 d85147f17b..0000000000 --- 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 29415fd2cf..5952c41c2d 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 @@ public class Main { /// 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 @@ public class Main { /// 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 @@ public class Main { /// 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 d85147f17b..0000000000 --- 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 77c9e53e0c..ff74559292 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 @@ public class Main { /// 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 @@ public class Main { /// 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 @@ public class Main { /// 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 @@ public class Main { /// 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 @@ public class Main { /// 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 @@ public class Main { /// 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 d85147f17b..0000000000 --- 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 a1f98297c5..1ce0e2a266 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 @@ public class Main { /// 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 @@ public class Main { /// 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 @@ public class Main { /// 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 @@ public class Main { /// 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 @@ public class Main { /// 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 @@ public class Main { /// 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 d85147f17b..0000000000 --- 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 877a5362ce..d0892c37c8 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 @@ public class Main { /// 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 @@ public class Main { /// 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 @@ public class Main { /// 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 @@ public class Main { /// 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 @@ public class Main { /// 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 @@ public class Main { /// 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 @@ public class Main { /// 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 @@ public class Main { /// 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 d85147f17b..0000000000 --- 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 eff2018078..7b6f957b2a 100644 --- a/test/661-checker-simd-reduc/src/Main.java +++ b/test/661-checker-simd-reduc/src/Main.java @@ -55,8 +55,8 @@ public class Main { /// 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 @@ public class Main { /// 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 @@ public class Main { /// 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 d85147f17b..0000000000 --- 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 a507133b91..360b52c79d 100644 --- a/test/672-checker-throw-method/src/Main.java +++ b/test/672-checker-throw-method/src/Main.java @@ -51,7 +51,7 @@ public class Main { /// 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 @@ public class Main { // /// 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 @@ public class Main { /// 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 @@ public class Main { // /// 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 d85147f17b..0000000000 --- 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 d0e1591bdb..206dfaf330 100644 --- a/test/673-checker-throw-vmethod/src/Main.java +++ b/test/673-checker-throw-vmethod/src/Main.java @@ -45,7 +45,7 @@ public class Main { /// 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 @@ public class Main { // /// 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 @@ public class Main { /// 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 @@ public class Main { // /// 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 2caca94d7f..53d8228808 100755 --- a/test/952-invoke-custom/build +++ b/test/952-invoke-custom/build @@ -21,11 +21,6 @@ ASM_JAR="${ANDROID_BUILD_TOP}/prebuilts/misc/common/asm/asm-6.0.jar" 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 @@ done # 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 ce931a96d1..67fc2a6339 100755 --- a/test/979-const-method-handle/build +++ b/test/979-const-method-handle/build @@ -22,11 +22,6 @@ INTERMEDIATE_CLASSES=classes-intermediate 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 @@ done # 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/etc/default-build b/test/etc/default-build index 9dbc73c6b4..c8993c6611 100755 --- a/test/etc/default-build +++ b/test/etc/default-build @@ -307,7 +307,7 @@ function make_dex() { 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}" + ${dexer} -JXmx256m ${DX_VM_FLAGS} --debug --dex --output=${name}.dex ${DX_FLAGS} "${dx_input}" } # Merge all the dex files in $1..$N into $1. Skip non-existing files, but at least 1 file must exist. diff --git a/test/run-test b/test/run-test index 5bd8b3b348..b5b42854e5 100755 --- a/test/run-test +++ b/test/run-test @@ -529,12 +529,27 @@ fi # 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/tools/ahat/AndroidTest.xml b/tools/ahat/AndroidTest.xml index 867658cf5e..b07905a9a7 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/src/main/com/android/ahat/heapdump/Value.java b/tools/ahat/src/main/com/android/ahat/heapdump/Value.java index b219bf1564..d78f95b548 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 @@ public abstract class Value { @Override public abstract String toString(); - private Value getBaseline() { + Value getBaseline() { return this; } @@ -396,7 +396,8 @@ public abstract class Value { return mInstance.toString(); } - public Value getBaseline() { + @Override + Value getBaseline() { return InstanceValue.pack(mInstance.getBaseline()); } diff --git a/tools/ahat/src/test/com/android/ahat/DiffTest.java b/tools/ahat/src/test/com/android/ahat/DiffTest.java index 585f29ae61..b1952b28b0 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 @@ package com.android.ahat; 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 @@ public class DiffTest { 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 d25dd2b15f..be68b9f490 100755 --- a/tools/teardown-buildbot-device.sh +++ b/tools/teardown-buildbot-device.sh @@ -34,17 +34,36 @@ if [[ -n "$ART_TEST_CHROOT" ]]; then 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 @@ if [[ -n "$ART_TEST_CHROOT" ]]; then 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 |