diff options
96 files changed, 4045 insertions, 2417 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 b3feb787a9..2589869859 100644 --- a/compiler/optimizing/code_generator.cc +++ b/compiler/optimizing/code_generator.cc @@ -1055,7 +1055,8 @@ void CodeGenerator::BuildStackMaps(MemoryRegion stack_map_region, void CodeGenerator::RecordPcInfo(HInstruction* instruction, uint32_t dex_pc, - SlowPathCode* slow_path) { + SlowPathCode* slow_path, + bool native_debug_info) { if (instruction != nullptr) { // The code generated for some type conversions // may call the runtime, thus normally requiring a subsequent @@ -1120,12 +1121,23 @@ void CodeGenerator::RecordPcInfo(HInstruction* instruction, outer_dex_pc = outer_environment->GetDexPc(); outer_environment_size = outer_environment->Size(); } + + HLoopInformation* info = instruction->GetBlock()->GetLoopInformation(); + bool osr = + instruction->IsSuspendCheck() && + (info != nullptr) && + graph_->IsCompilingOsr() && + (inlining_depth == 0); + StackMap::Kind kind = native_debug_info + ? StackMap::Kind::Debug + : (osr ? StackMap::Kind::OSR : StackMap::Kind::Default); stack_map_stream->BeginStackMapEntry(outer_dex_pc, native_pc, register_mask, locations->GetStackMask(), outer_environment_size, - inlining_depth); + inlining_depth, + kind); EmitEnvironment(environment, slow_path); // Record invoke info, the common case for the trampoline is super and static invokes. Only // record these to reduce oat file size. @@ -1138,19 +1150,9 @@ void CodeGenerator::RecordPcInfo(HInstruction* instruction, } stack_map_stream->EndStackMapEntry(); - HLoopInformation* info = instruction->GetBlock()->GetLoopInformation(); - if (instruction->IsSuspendCheck() && - (info != nullptr) && - graph_->IsCompilingOsr() && - (inlining_depth == 0)) { + if (osr) { DCHECK_EQ(info->GetSuspendCheck(), instruction); - // We duplicate the stack map as a marker that this stack map can be an OSR entry. - // Duplicating it avoids having the runtime recognize and skip an OSR stack map. DCHECK(info->IsIrreducible()); - stack_map_stream->BeginStackMapEntry( - dex_pc, native_pc, register_mask, locations->GetStackMask(), outer_environment_size, 0); - EmitEnvironment(instruction->GetEnvironment(), slow_path); - stack_map_stream->EndStackMapEntry(); if (kIsDebugBuild) { for (size_t i = 0, environment_size = environment->Size(); i < environment_size; ++i) { HInstruction* in_environment = environment->GetInstructionAt(i); @@ -1167,14 +1169,6 @@ void CodeGenerator::RecordPcInfo(HInstruction* instruction, } } } - } else if (kIsDebugBuild) { - // Ensure stack maps are unique, by checking that the native pc in the stack map - // last emitted is different than the native pc of the stack map just emitted. - size_t number_of_stack_maps = stack_map_stream->GetNumberOfStackMaps(); - if (number_of_stack_maps > 1) { - DCHECK_NE(stack_map_stream->GetStackMapNativePcOffset(number_of_stack_maps - 1), - stack_map_stream->GetStackMapNativePcOffset(number_of_stack_maps - 2)); - } } } @@ -1196,12 +1190,11 @@ void CodeGenerator::MaybeRecordNativeDebugInfo(HInstruction* instruction, // Ensure that we do not collide with the stack map of the previous instruction. GenerateNop(); } - RecordPcInfo(instruction, dex_pc, slow_path); + RecordPcInfo(instruction, dex_pc, slow_path, /* native_debug_info */ true); } } void CodeGenerator::RecordCatchBlockInfo() { - ArenaAllocator* allocator = graph_->GetAllocator(); StackMapStream* stack_map_stream = GetStackMapStream(); for (HBasicBlock* block : *block_order_) { @@ -1213,28 +1206,24 @@ void CodeGenerator::RecordCatchBlockInfo() { uint32_t num_vregs = graph_->GetNumberOfVRegs(); uint32_t inlining_depth = 0; // Inlining of catch blocks is not supported at the moment. uint32_t native_pc = GetAddressOf(block); - uint32_t register_mask = 0; // Not used. - - // The stack mask is not used, so we leave it empty. - ArenaBitVector* stack_mask = - ArenaBitVector::Create(allocator, 0, /* expandable */ true, kArenaAllocCodeGenerator); stack_map_stream->BeginStackMapEntry(dex_pc, native_pc, - register_mask, - stack_mask, + /* register_mask */ 0, + /* stack_mask */ nullptr, num_vregs, - inlining_depth); + inlining_depth, + StackMap::Kind::Catch); HInstruction* current_phi = block->GetFirstPhi(); for (size_t vreg = 0; vreg < num_vregs; ++vreg) { - while (current_phi != nullptr && current_phi->AsPhi()->GetRegNumber() < vreg) { - HInstruction* next_phi = current_phi->GetNext(); - DCHECK(next_phi == nullptr || - current_phi->AsPhi()->GetRegNumber() <= next_phi->AsPhi()->GetRegNumber()) - << "Phis need to be sorted by vreg number to keep this a linear-time loop."; - current_phi = next_phi; - } + while (current_phi != nullptr && current_phi->AsPhi()->GetRegNumber() < vreg) { + HInstruction* next_phi = current_phi->GetNext(); + DCHECK(next_phi == nullptr || + current_phi->AsPhi()->GetRegNumber() <= next_phi->AsPhi()->GetRegNumber()) + << "Phis need to be sorted by vreg number to keep this a linear-time loop."; + current_phi = next_phi; + } if (current_phi == nullptr || current_phi->AsPhi()->GetRegNumber() != vreg) { stack_map_stream->AddDexRegisterEntry(DexRegisterLocation::Kind::kNone, 0); @@ -1294,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; @@ -1347,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); } @@ -1369,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); } @@ -1393,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); @@ -1414,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); @@ -1430,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/code_generator.h b/compiler/optimizing/code_generator.h index b3c29aa804..03ae4983d4 100644 --- a/compiler/optimizing/code_generator.h +++ b/compiler/optimizing/code_generator.h @@ -323,7 +323,10 @@ class CodeGenerator : public DeletableArenaObject<kArenaAllocCodeGenerator> { } // Record native to dex mapping for a suspend point. Required by runtime. - void RecordPcInfo(HInstruction* instruction, uint32_t dex_pc, SlowPathCode* slow_path = nullptr); + void RecordPcInfo(HInstruction* instruction, + uint32_t dex_pc, + SlowPathCode* slow_path = nullptr, + bool native_debug_info = false); // Check whether we have already recorded mapping at this PC. bool HasStackMapAtCurrentPc(); // Record extra stack maps if we support native debugging. diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc index 5f0533cbe9..8aa790db34 100644 --- a/compiler/optimizing/code_generator_arm64.cc +++ b/compiler/optimizing/code_generator_arm64.cc @@ -2459,6 +2459,9 @@ void InstructionCodeGeneratorARM64::HandleBinaryOp(HBinaryOperation* instr) { // all & reg_bits - 1. __ Ror(dst, lhs, RegisterFrom(instr->GetLocations()->InAt(1), type)); } + } else if (instr->IsMin() || instr->IsMax()) { + __ Cmp(lhs, rhs); + __ Csel(dst, lhs, rhs, instr->IsMin() ? lt : gt); } else { DCHECK(instr->IsXor()); __ Eor(dst, lhs, rhs); @@ -2474,6 +2477,10 @@ void InstructionCodeGeneratorARM64::HandleBinaryOp(HBinaryOperation* instr) { __ Fadd(dst, lhs, rhs); } else if (instr->IsSub()) { __ Fsub(dst, lhs, rhs); + } else if (instr->IsMin()) { + __ Fmin(dst, lhs, rhs); + } else if (instr->IsMax()) { + __ Fmax(dst, lhs, rhs); } else { LOG(FATAL) << "Unexpected floating-point binary operation"; } @@ -5671,111 +5678,20 @@ void InstructionCodeGeneratorARM64::VisitRem(HRem* rem) { } } -// TODO: integrate with HandleBinaryOp? -static void CreateMinMaxLocations(ArenaAllocator* allocator, HBinaryOperation* minmax) { - LocationSummary* locations = new (allocator) LocationSummary(minmax); - switch (minmax->GetResultType()) { - case DataType::Type::kInt32: - case DataType::Type::kInt64: - locations->SetInAt(0, Location::RequiresRegister()); - locations->SetInAt(1, Location::RequiresRegister()); - locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); - break; - case DataType::Type::kFloat32: - case DataType::Type::kFloat64: - locations->SetInAt(0, Location::RequiresFpuRegister()); - locations->SetInAt(1, Location::RequiresFpuRegister()); - locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap); - break; - default: - LOG(FATAL) << "Unexpected type for HMinMax " << minmax->GetResultType(); - } -} - -void InstructionCodeGeneratorARM64::GenerateMinMaxInt(LocationSummary* locations, - bool is_min, - DataType::Type type) { - Location op1 = locations->InAt(0); - Location op2 = locations->InAt(1); - Location out = locations->Out(); - - Register op1_reg; - Register op2_reg; - Register out_reg; - if (type == DataType::Type::kInt64) { - op1_reg = XRegisterFrom(op1); - op2_reg = XRegisterFrom(op2); - out_reg = XRegisterFrom(out); - } else { - DCHECK_EQ(type, DataType::Type::kInt32); - op1_reg = WRegisterFrom(op1); - op2_reg = WRegisterFrom(op2); - out_reg = WRegisterFrom(out); - } - - __ Cmp(op1_reg, op2_reg); - __ Csel(out_reg, op1_reg, op2_reg, is_min ? lt : gt); -} - -void InstructionCodeGeneratorARM64::GenerateMinMaxFP(LocationSummary* locations, - bool is_min, - DataType::Type type) { - Location op1 = locations->InAt(0); - Location op2 = locations->InAt(1); - Location out = locations->Out(); - - FPRegister op1_reg; - FPRegister op2_reg; - FPRegister out_reg; - if (type == DataType::Type::kFloat64) { - op1_reg = DRegisterFrom(op1); - op2_reg = DRegisterFrom(op2); - out_reg = DRegisterFrom(out); - } else { - DCHECK_EQ(type, DataType::Type::kFloat32); - op1_reg = SRegisterFrom(op1); - op2_reg = SRegisterFrom(op2); - out_reg = SRegisterFrom(out); - } - - if (is_min) { - __ Fmin(out_reg, op1_reg, op2_reg); - } else { - __ Fmax(out_reg, op1_reg, op2_reg); - } -} - -// TODO: integrate with HandleBinaryOp? -void InstructionCodeGeneratorARM64::GenerateMinMax(HBinaryOperation* minmax, bool is_min) { - DataType::Type type = minmax->GetResultType(); - switch (type) { - case DataType::Type::kInt32: - case DataType::Type::kInt64: - GenerateMinMaxInt(minmax->GetLocations(), is_min, type); - break; - case DataType::Type::kFloat32: - case DataType::Type::kFloat64: - GenerateMinMaxFP(minmax->GetLocations(), is_min, type); - break; - default: - LOG(FATAL) << "Unexpected type for HMinMax " << type; - } -} - void LocationsBuilderARM64::VisitMin(HMin* min) { - CreateMinMaxLocations(GetGraph()->GetAllocator(), min); + HandleBinaryOp(min); } void InstructionCodeGeneratorARM64::VisitMin(HMin* min) { - GenerateMinMax(min, /*is_min*/ true); + HandleBinaryOp(min); } void LocationsBuilderARM64::VisitMax(HMax* max) { - CreateMinMaxLocations(GetGraph()->GetAllocator(), max); + HandleBinaryOp(max); } void InstructionCodeGeneratorARM64::VisitMax(HMax* max) { - GenerateMinMax(max, /*is_min*/ false); + HandleBinaryOp(max); } void LocationsBuilderARM64::VisitAbs(HAbs* abs) { diff --git a/compiler/optimizing/code_generator_arm64.h b/compiler/optimizing/code_generator_arm64.h index e7fe5b71b7..5afb712d17 100644 --- a/compiler/optimizing/code_generator_arm64.h +++ b/compiler/optimizing/code_generator_arm64.h @@ -280,10 +280,6 @@ class InstructionCodeGeneratorARM64 : public InstructionCodeGenerator { void HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info); void HandleCondition(HCondition* instruction); - void GenerateMinMaxInt(LocationSummary* locations, bool is_min, DataType::Type type); - void GenerateMinMaxFP(LocationSummary* locations, bool is_min, DataType::Type type); - void GenerateMinMax(HBinaryOperation* minmax, bool is_min); - // Generate a heap reference load using one register `out`: // // out <- *(out + offset) diff --git a/compiler/optimizing/common_arm64.h b/compiler/optimizing/common_arm64.h index ed2f8e995d..5191ee2b1e 100644 --- a/compiler/optimizing/common_arm64.h +++ b/compiler/optimizing/common_arm64.h @@ -234,6 +234,13 @@ inline vixl::aarch64::Operand OperandFromMemOperand( } } +inline bool AddSubCanEncodeAsImmediate(int64_t value) { + // If `value` does not fit but `-value` does, VIXL will automatically use + // the 'opposite' instruction. + return vixl::aarch64::Assembler::IsImmAddSub(value) + || vixl::aarch64::Assembler::IsImmAddSub(-value); +} + inline bool Arm64CanEncodeConstantAsImmediate(HConstant* constant, HInstruction* instr) { int64_t value = CodeGenerator::GetInt64ValueOf(constant); @@ -249,6 +256,20 @@ inline bool Arm64CanEncodeConstantAsImmediate(HConstant* constant, HInstruction* return IsUint<8>(value); } + // Code generation for Min/Max: + // Cmp left_op, right_op + // Csel dst, left_op, right_op, cond + if (instr->IsMin() || instr->IsMax()) { + if (constant->GetUses().HasExactlyOneElement()) { + // If value can be encoded as immediate for the Cmp, then let VIXL handle + // the constant generation for the Csel. + return AddSubCanEncodeAsImmediate(value); + } + // These values are encodable as immediates for Cmp and VIXL will use csinc and csinv + // with the zr register as right_op, hence no constant generation is required. + return constant->IsZeroBitPattern() || constant->IsOne() || constant->IsMinusOne(); + } + // For single uses we let VIXL handle the constant generation since it will // use registers that are not managed by the register allocator (wip0, wip1). if (constant->GetUses().HasExactlyOneElement()) { @@ -275,10 +296,7 @@ inline bool Arm64CanEncodeConstantAsImmediate(HConstant* constant, HInstruction* instr->IsSub()) << instr->DebugName(); // Uses aliases of ADD/SUB instructions. - // If `value` does not fit but `-value` does, VIXL will automatically use - // the 'opposite' instruction. - return vixl::aarch64::Assembler::IsImmAddSub(value) - || vixl::aarch64::Assembler::IsImmAddSub(-value); + return AddSubCanEncodeAsImmediate(value); } } 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/stack_map_stream.cc b/compiler/optimizing/stack_map_stream.cc index 094b75de69..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, @@ -43,7 +44,8 @@ void StackMapStream::BeginStackMapEntry(uint32_t dex_pc, uint32_t register_mask, BitVector* stack_mask, uint32_t num_dex_registers, - uint8_t inlining_depth) { + uint8_t inlining_depth, + StackMap::Kind kind) { DCHECK(!in_stack_map_) << "Mismatched Begin/End calls"; in_stack_map_ = true; // num_dex_registers_ is the constant per-method number of registers. @@ -54,19 +56,17 @@ void StackMapStream::BeginStackMapEntry(uint32_t dex_pc, DCHECK_EQ(num_dex_registers_, num_dex_registers) << "Inconsistent register count"; } - current_stack_map_ = StackMapEntry { - .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. @@ -81,8 +81,17 @@ void StackMapStream::BeginStackMapEntry(uint32_t dex_pc, // Create lambda method, which will be executed at the very end to verify data. // Parameters and local variables will be captured(stored) by the lambda "[=]". dchecks_.emplace_back([=](const CodeInfo& code_info) { + if (kind == StackMap::Kind::Default || kind == StackMap::Kind::OSR) { + StackMap stack_map = code_info.GetStackMapForNativePcOffset(native_pc_offset, + instruction_set_); + CHECK_EQ(stack_map.Row(), stack_map_index); + } else if (kind == StackMap::Kind::Catch) { + StackMap stack_map = code_info.GetCatchStackMapForDexPc(dex_pc); + CHECK_EQ(stack_map.Row(), stack_map_index); + } StackMap stack_map = code_info.GetStackMapAt(stack_map_index); CHECK_EQ(stack_map.GetNativePcOffset(instruction_set_), native_pc_offset); + CHECK_EQ(stack_map.GetKind(), static_cast<uint32_t>(kind)); CHECK_EQ(stack_map.GetDexPc(), dex_pc); CHECK_EQ(code_info.GetRegisterMaskOf(stack_map), register_mask); BitMemoryRegion seen_stack_mask = code_info.GetStackMaskOf(stack_map); @@ -103,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()); } @@ -114,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) { @@ -133,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); }); } } @@ -148,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); @@ -181,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()); } }); @@ -214,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(); } @@ -228,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()); } @@ -264,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) { @@ -273,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 02fb6cb434..6842d9fd7e 100644 --- a/compiler/optimizing/stack_map_stream.h +++ b/compiler/optimizing/stack_map_stream.h @@ -27,11 +27,10 @@ #include "dex_register_location.h" #include "method_info.h" #include "nodes.h" +#include "stack_map.h" namespace art { -class CodeInfo; - /** * Collects and builds stack maps for a method. All the stack maps * for a method are placed in a CodeInfo object. @@ -53,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)), @@ -66,10 +66,13 @@ class StackMapStream : public ValueObject { uint32_t register_mask, BitVector* sp_mask, uint32_t num_dex_registers, - uint8_t inlining_depth); + uint8_t inlining_depth, + 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,69 +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 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. @@ -168,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 9adc4c5ba6..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()); @@ -425,12 +425,12 @@ TEST(StackMapTest, TestShareDexRegisterMap) { stream.AddDexRegisterEntry(Kind::kConstant, -2); // Large location. stream.EndStackMapEntry(); // Second stack map, which should share the same dex register map. - stream.BeginStackMapEntry(0, 64 * kPcAlign, 0x3, &sp_mask, number_of_dex_registers, 0); + stream.BeginStackMapEntry(0, 65 * kPcAlign, 0x3, &sp_mask, number_of_dex_registers, 0); stream.AddDexRegisterEntry(Kind::kInRegister, 0); // Short location. stream.AddDexRegisterEntry(Kind::kConstant, -2); // Large location. stream.EndStackMapEntry(); // Third stack map (doesn't share the dex register map). - stream.BeginStackMapEntry(0, 64 * kPcAlign, 0x3, &sp_mask, number_of_dex_registers, 0); + stream.BeginStackMapEntry(0, 66 * kPcAlign, 0x3, &sp_mask, number_of_dex_registers, 0); stream.AddDexRegisterEntry(Kind::kInRegister, 2); // Short location. stream.AddDexRegisterEntry(Kind::kConstant, -2); // Large location. stream.EndStackMapEntry(); @@ -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. @@ -528,7 +528,7 @@ TEST(StackMapTest, InlineTest) { sp_mask1.SetBit(4); // First stack map. - stream.BeginStackMapEntry(0, 64 * kPcAlign, 0x3, &sp_mask1, 2, 2); + stream.BeginStackMapEntry(0, 10 * kPcAlign, 0x3, &sp_mask1, 2, 2); stream.AddDexRegisterEntry(Kind::kInStack, 0); stream.AddDexRegisterEntry(Kind::kConstant, 4); @@ -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 2b4144c611..3f5dbcfce5 100644 --- a/dexlayout/compact_dex_writer.cc +++ b/dexlayout/compact_dex_writer.cc @@ -59,8 +59,8 @@ uint32_t CompactDexWriter::WriteDebugInfoOffsetTable(Stream* stream) { for (auto& method : *(invoke_type == InvokeType::kDirect ? class_data->DirectMethods() : class_data->VirtualMethods())) { - const dex_ir::MethodId* method_id = method->GetMethodId(); - dex_ir::CodeItem* code_item = method->GetCodeItem(); + const dex_ir::MethodId* method_id = method.GetMethodId(); + dex_ir::CodeItem* code_item = method.GetCodeItem(); if (code_item != nullptr && code_item->DebugInfo() != nullptr) { const uint32_t debug_info_offset = code_item->DebugInfo()->GetOffset(); const uint32_t method_idx = method_id->GetIndex(); @@ -248,8 +248,8 @@ void CompactDexWriter::SortDebugInfosByMethodIndex() { for (auto& method : *(invoke_type == InvokeType::kDirect ? class_data->DirectMethods() : class_data->VirtualMethods())) { - const dex_ir::MethodId* method_id = method->GetMethodId(); - dex_ir::CodeItem* code_item = method->GetCodeItem(); + const dex_ir::MethodId* method_id = method.GetMethodId(); + dex_ir::CodeItem* code_item = method.GetCodeItem(); if (code_item != nullptr && code_item->DebugInfo() != nullptr) { const dex_ir::DebugInfoItem* debug_item = code_item->DebugInfo(); method_idx_map.insert(std::make_pair(debug_item, method_id->GetIndex())); @@ -350,8 +350,8 @@ bool CompactDexWriter::CanGenerateCompactDex(std::string* error_msg) { for (auto& method : *(invoke_type == InvokeType::kDirect ? class_data->DirectMethods() : class_data->VirtualMethods())) { - const uint32_t idx = method->GetMethodId()->GetIndex(); - dex_ir::CodeItem* code_item = method->GetCodeItem(); + const uint32_t idx = method.GetMethodId()->GetIndex(); + dex_ir::CodeItem* code_item = method.GetCodeItem(); dex_ir:: DebugInfoItem* debug_info_item = nullptr; if (code_item != nullptr) { debug_info_item = code_item->DebugInfo(); diff --git a/dexlayout/dex_ir.cc b/dexlayout/dex_ir.cc index b7d9db6da5..15e3baf18a 100644 --- a/dexlayout/dex_ir.cc +++ b/dexlayout/dex_ir.cc @@ -318,17 +318,22 @@ void Collections::ReadEncodedValue(const DexFile& dex_file, 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 = new StringData(dex_file.GetStringData(disk_string_id)); - AddItem(string_datas_map_, string_datas_, string_data, disk_string_id.string_data_off_); - - StringId* string_id = new StringId(string_data); - AddIndexedItem(string_ids_, string_id, StringIdsOffset() + i * StringId::ItemSize(), 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)); - TypeId* type_id = new TypeId(GetStringId(disk_type_id.descriptor_idx_.index_)); - AddIndexedItem(type_ids_, type_id, TypeIdsOffset() + i * TypeId::ItemSize(), 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) { @@ -336,26 +341,32 @@ void Collections::CreateProtoId(const DexFile& dex_file, uint32_t i) { const DexFile::TypeList* type_list = dex_file.GetProtoParameters(disk_proto_id); TypeList* parameter_type_list = CreateTypeList(type_list, disk_proto_id.parameters_off_); - ProtoId* proto_id = new ProtoId(GetStringId(disk_proto_id.shorty_idx_.index_), - GetTypeId(disk_proto_id.return_type_idx_.index_), - parameter_type_list); - AddIndexedItem(proto_ids_, proto_id, ProtoIdsOffset() + i * ProtoId::ItemSize(), i); + 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); - FieldId* field_id = new FieldId(GetTypeId(disk_field_id.class_idx_.index_), - GetTypeId(disk_field_id.type_idx_.index_), - GetStringId(disk_field_id.name_idx_.index_)); - AddIndexedItem(field_ids_, field_id, FieldIdsOffset() + i * FieldId::ItemSize(), 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); - MethodId* method_id = new MethodId(GetTypeId(disk_method_id.class_idx_.index_), - GetProtoId(disk_method_id.proto_idx_.index_), - GetStringId(disk_method_id.name_idx_.index_)); - AddIndexedItem(method_ids_, method_id, MethodIdsOffset() + i * MethodId::ItemSize(), 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) { @@ -382,9 +393,17 @@ void Collections::CreateClassDef(const DexFile& dex_file, uint32_t i) { 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_); - ClassDef* class_def = new ClassDef(class_type, access_flags, superclass, interfaces_type_list, - source_file, annotations, static_values, class_data); - AddIndexedItem(class_defs_, class_def, ClassDefsOffset() + i * ClassDef::ItemSize(), i); + 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) { @@ -398,8 +417,7 @@ TypeList* Collections::CreateTypeList(const DexFile::TypeList* dex_type_list, ui for (uint32_t index = 0; index < size; ++index) { type_vector->push_back(GetTypeId(dex_type_list->GetTypeItem(index).type_idx_.index_)); } - type_list = new TypeList(type_vector); - AddItem(type_lists_map_, type_lists_, type_list, offset); + type_list = CreateAndAddItem(type_lists_map_, type_lists_, offset, type_vector); } return type_list; } @@ -418,8 +436,10 @@ EncodedArrayItem* Collections::CreateEncodedArrayItem(const DexFile& dex_file, values->push_back(std::unique_ptr<EncodedValue>(ReadEncodedValue(dex_file, &static_data))); } // TODO: Calculate the size of the encoded array. - encoded_array_item = new EncodedArrayItem(values); - AddItem(encoded_array_items_map_, encoded_array_items_, encoded_array_item, offset); + encoded_array_item = CreateAndAddItem(encoded_array_items_map_, + encoded_array_items_, + offset, + values); } return encoded_array_item; } @@ -447,9 +467,12 @@ AnnotationItem* Collections::CreateAnnotationItem(const DexFile& dex_file, const uint8_t* annotation_data = annotation->annotation_; std::unique_ptr<EncodedValue> encoded_value( ReadEncodedValue(dex_file, &annotation_data, DexFile::kDexAnnotationAnnotation, 0)); - annotation_item = new AnnotationItem(visibility, encoded_value->ReleaseEncodedAnnotation()); + annotation_item = CreateAndAddItem(annotation_items_map_, + annotation_items_, + offset, + visibility, + encoded_value->ReleaseEncodedAnnotation()); annotation_item->SetSize(annotation_data - start_data); - AddItem(annotation_items_map_, annotation_items_, annotation_item, offset); } return annotation_item; } @@ -472,8 +495,10 @@ AnnotationSetItem* Collections::CreateAnnotationSetItem(const DexFile& dex_file, AnnotationItem* annotation_item = CreateAnnotationItem(dex_file, annotation); items->push_back(annotation_item); } - annotation_set_item = new AnnotationSetItem(items); - AddItem(annotation_set_items_map_, annotation_set_items_, annotation_set_item, offset); + annotation_set_item = CreateAndAddItem(annotation_set_items_map_, + annotation_set_items_, + offset, + items); } return annotation_set_item; } @@ -538,13 +563,13 @@ AnnotationsDirectoryItem* Collections::CreateAnnotationsDirectoryItem(const DexF } } // TODO: Calculate the size of the annotations directory. -annotations_directory_item = new AnnotationsDirectoryItem( - class_annotation, field_annotations, method_annotations, parameter_annotations); - AddItem(annotations_directory_items_map_, - annotations_directory_items_, - annotations_directory_item, - offset); - return annotations_directory_item; + return CreateAndAddItem(annotations_directory_items_map_, + annotations_directory_items_, + offset, + class_annotation, + field_annotations, + method_annotations, + parameter_annotations); } ParameterAnnotation* Collections::GenerateParameterAnnotation( @@ -559,8 +584,10 @@ ParameterAnnotation* Collections::GenerateParameterAnnotation( 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 = new AnnotationSetRefList(annotations); - AddItem(annotation_set_ref_lists_map_, annotation_set_ref_lists_, set_ref_list, offset); + set_ref_list = CreateAndAddItem(annotation_set_ref_lists_map_, + annotation_set_ref_lists_, + offset, + annotations); } return new ParameterAnnotation(method_id, set_ref_list); } @@ -590,8 +617,11 @@ CodeItem* Collections::DedupeOrCreateCodeItem(const DexFile& dex_file, 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 = new DebugInfoItem(debug_info_size, debug_info_buffer); - AddItem(debug_info_items_map_, debug_info_items_, debug_info, debug_info_offset); + debug_info = CreateAndAddItem(debug_info_items_map_, + debug_info_items_, + debug_info_offset, + debug_info_size, + debug_info_buffer); } } @@ -677,14 +707,14 @@ CodeItem* Collections::DedupeOrCreateCodeItem(const DexFile& dex_file, } uint32_t size = dex_file.GetCodeItemSize(*disk_code_item); - CodeItem* code_item = new CodeItem(accessor.RegistersSize(), - accessor.InsSize(), - accessor.OutsSize(), - debug_info, - insns_size, - insns, - tries, - handler_list); + 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. @@ -693,7 +723,6 @@ CodeItem* Collections::DedupeOrCreateCodeItem(const DexFile& dex_file, code_item->SetOffset(offset); } code_items_map_.emplace(offsets_pair, code_item); - code_items_.AddItem(code_item); // Add "fixup" references to types, strings, methods, and fields. // This is temporary, as we will probably want more detailed parsing of the @@ -718,7 +747,7 @@ CodeItem* Collections::DedupeOrCreateCodeItem(const DexFile& dex_file, return code_item; } -MethodItem* Collections::GenerateMethodItem(const DexFile& dex_file, ClassDataItemIterator& cdii) { +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(); @@ -728,7 +757,7 @@ MethodItem* Collections::GenerateMethodItem(const DexFile& dex_file, ClassDataIt disk_code_item, cdii.GetMethodCodeItemOffset(), cdii.GetMemberIndex()); - return new MethodItem(access_flags, method_id, code_item); + return MethodItem(access_flags, method_id, code_item); } ClassData* Collections::CreateClassData( @@ -743,29 +772,33 @@ ClassData* Collections::CreateClassData( for (; cdii.HasNextStaticField(); cdii.Next()) { FieldId* field_item = GetFieldId(cdii.GetMemberIndex()); uint32_t access_flags = cdii.GetRawMemberAccessFlags(); - static_fields->push_back(std::unique_ptr<FieldItem>(new FieldItem(access_flags, field_item))); + 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->push_back( - std::unique_ptr<FieldItem>(new FieldItem(access_flags, field_item))); + instance_fields->emplace_back(access_flags, field_item); } // Direct methods. MethodItemVector* direct_methods = new MethodItemVector(); for (; cdii.HasNextDirectMethod(); cdii.Next()) { - direct_methods->push_back(std::unique_ptr<MethodItem>(GenerateMethodItem(dex_file, cdii))); + direct_methods->push_back(GenerateMethodItem(dex_file, cdii)); } // Virtual methods. MethodItemVector* virtual_methods = new MethodItemVector(); for (; cdii.HasNextVirtualMethod(); cdii.Next()) { - virtual_methods->push_back(std::unique_ptr<MethodItem>(GenerateMethodItem(dex_file, cdii))); + virtual_methods->push_back(GenerateMethodItem(dex_file, cdii)); } - class_data = new ClassData(static_fields, instance_fields, direct_methods, virtual_methods); + class_data = CreateAndAddItem(class_datas_map_, + class_datas_, + offset, + static_fields, + instance_fields, + direct_methods, + virtual_methods); class_data->SetSize(cdii.EndDataPointer() - encoded_data); - AddItem(class_datas_map_, class_datas_, class_data, offset); } return class_data; } @@ -802,8 +835,10 @@ void Collections::CreateCallSiteId(const DexFile& dex_file, uint32_t i) { EncodedArrayItem* call_site_item = CreateEncodedArrayItem(dex_file, disk_call_item_ptr, disk_call_site_id.data_off_); - CallSiteId* call_site_id = new CallSiteId(call_site_item); - AddIndexedItem(call_site_ids_, call_site_id, CallSiteIdsOffset() + i * CallSiteId::ItemSize(), i); + CreateAndAddIndexedItem(call_site_ids_, + CallSiteIdsOffset() + i * CallSiteId::ItemSize(), + i, + call_site_item); } void Collections::CreateMethodHandleItem(const DexFile& dex_file, uint32_t i) { @@ -824,11 +859,11 @@ void Collections::CreateMethodHandleItem(const DexFile& dex_file, uint32_t i) { } else { field_or_method_id = GetFieldId(index); } - MethodHandleItem* method_handle = new MethodHandleItem(type, field_or_method_id); - AddIndexedItem(method_handle_items_, - method_handle, - MethodHandleItemsOffset() + i * MethodHandleItem::ItemSize(), - i); + CreateAndAddIndexedItem(method_handle_items_, + MethodHandleItemsOffset() + i * MethodHandleItem::ItemSize(), + i, + type, + field_or_method_id); } void Collections::SortVectorsByMapOrder() { @@ -844,6 +879,19 @@ void Collections::SortVectorsByMapOrder() { 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) { return 0; } diff --git a/dexlayout/dex_ir.h b/dexlayout/dex_ir.h index 5ecad2bf87..54ff105820 100644 --- a/dexlayout/dex_ir.h +++ b/dexlayout/dex_ir.h @@ -129,7 +129,11 @@ template<class T> class CollectionBase { template<class T> class CollectionVector : public CollectionBase<T> { public: using Vector = std::vector<std::unique_ptr<T>>; - CollectionVector() = default; + CollectionVector() { } + explicit CollectionVector(size_t size) { + // Preallocate so that assignment does not invalidate pointers into the vector. + collection_.reserve(size); + } uint32_t Size() const { return collection_.size(); } Vector& Collection() { return collection_; } @@ -152,8 +156,11 @@ template<class T> class CollectionVector : public CollectionBase<T> { protected: Vector collection_; - void AddItem(T* object) { + 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; } private: @@ -165,11 +172,20 @@ template<class T> class IndexedCollectionVector : public CollectionVector<T> { public: using Vector = std::vector<std::unique_ptr<T>>; IndexedCollectionVector() = default; + explicit IndexedCollectionVector(size_t size) : CollectionVector<T>(size) { } private: - void AddIndexedItem(T* object, uint32_t index) { + template <class... Args> + T* CreateAndAddIndexedItem(uint32_t index, Args&&... args) { + T* object = CollectionVector<T>::CreateAndAddItem(std::forward<Args>(args)...); object->SetIndex(index); - CollectionVector<T>::collection_.push_back(std::unique_ptr<T>(object)); + return object; + } + + T* GetElement(uint32_t index) { + DCHECK_LT(index, CollectionVector<T>::Size()); + DCHECK_NE(CollectionVector<T>::collection_[index].get(), static_cast<T*>(nullptr)); + return CollectionVector<T>::collection_[index].get(); } friend class Collections; @@ -193,6 +209,8 @@ template<class T> class CollectionMap : public CollectionBase<T> { 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 << " " @@ -206,13 +224,25 @@ template<class T> class CollectionMap : public CollectionBase<T> { class Collections { public: Collections() = default; - - CollectionVector<StringId>::Vector& StringIds() { return string_ids_.Collection(); } - CollectionVector<TypeId>::Vector& TypeIds() { return type_ids_.Collection(); } - CollectionVector<ProtoId>::Vector& ProtoIds() { return proto_ids_.Collection(); } - CollectionVector<FieldId>::Vector& FieldIds() { return field_ids_.Collection(); } - CollectionVector<MethodId>::Vector& MethodIds() { return method_ids_.Collection(); } - CollectionVector<ClassDef>::Vector& ClassDefs() { return class_defs_.Collection(); } + 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(); } @@ -266,28 +296,22 @@ class Collections { uint32_t count); StringId* GetStringId(uint32_t index) { - CHECK_LT(index, StringIdsSize()); - return StringIds()[index].get(); + return string_ids_.GetElement(index); } TypeId* GetTypeId(uint32_t index) { - CHECK_LT(index, TypeIdsSize()); - return TypeIds()[index].get(); + return type_ids_.GetElement(index); } ProtoId* GetProtoId(uint32_t index) { - CHECK_LT(index, ProtoIdsSize()); - return ProtoIds()[index].get(); + return proto_ids_.GetElement(index); } FieldId* GetFieldId(uint32_t index) { - CHECK_LT(index, FieldIdsSize()); - return FieldIds()[index].get(); + return field_ids_.GetElement(index); } MethodId* GetMethodId(uint32_t index) { - CHECK_LT(index, MethodIdsSize()); - return MethodIds()[index].get(); + return method_ids_.GetElement(index); } ClassDef* GetClassDef(uint32_t index) { - CHECK_LT(index, ClassDefsSize()); - return ClassDefs()[index].get(); + return class_defs_.GetElement(index); } CallSiteId* GetCallSiteId(uint32_t index) { CHECK_LT(index, CallSiteIdsSize()); @@ -372,31 +396,35 @@ class Collections { // Sort the vectors buy map order (same order that was used in the input file). void SortVectorsByMapOrder(); - - template <typename Type> - void AddItem(CollectionMap<Type>& map, - CollectionVector<Type>& vector, - Type* item, - uint32_t offset) { + // 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); - vector.AddItem(item); + return item; } - template <typename Type> - void AddIndexedItem(IndexedCollectionVector<Type>& vector, - Type* item, - uint32_t offset, - uint32_t index) { + 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); } - vector.AddIndexedItem(item, index); + return item; } void SetEagerlyAssignOffsets(bool eagerly_assign_offsets) { @@ -425,7 +453,7 @@ class Collections { 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); + MethodItem GenerateMethodItem(const DexFile& dex_file, ClassDataItemIterator& cdii); // Collection vectors own the IR data. IndexedCollectionVector<StringId> string_ids_; @@ -433,6 +461,7 @@ class Collections { 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_; @@ -442,7 +471,6 @@ class Collections { IndexedCollectionVector<AnnotationSetItem> annotation_set_items_; IndexedCollectionVector<AnnotationSetRefList> annotation_set_ref_lists_; IndexedCollectionVector<AnnotationsDirectoryItem> annotations_directory_items_; - IndexedCollectionVector<ClassDef> class_defs_; // 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 @@ -485,6 +513,8 @@ class Item { Item() { } virtual ~Item() { } + Item(Item&&) = default; + // Return the assigned offset. uint32_t GetOffset() const WARN_UNUSED { CHECK(OffsetAssigned()); @@ -536,18 +566,54 @@ class Header : public Item { uint32_t data_size, uint32_t data_offset, bool support_default_methods) + : Item(0, kHeaderItemSize), support_default_methods_(support_default_methods) { + ConstructorHelper(magic, + checksum, + signature, + endian_tag, + file_size, + header_size, + link_size, + link_offset, + data_size, + data_offset); + } + + Header(const uint8_t* magic, + uint32_t checksum, + const uint8_t* signature, + uint32_t endian_tag, + uint32_t file_size, + uint32_t header_size, + uint32_t link_size, + uint32_t link_offset, + uint32_t data_size, + uint32_t data_offset, + bool support_default_methods, + 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) : Item(0, kHeaderItemSize), - checksum_(checksum), - endian_tag_(endian_tag), - file_size_(file_size), - header_size_(header_size), - link_size_(link_size), - link_offset_(link_offset), - data_size_(data_size), - data_offset_(data_offset), - support_default_methods_(support_default_methods) { - memcpy(magic_, magic, sizeof(magic_)); - memcpy(signature_, signature, sizeof(signature_)); + 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) { + ConstructorHelper(magic, + checksum, + signature, + endian_tag, + file_size, + header_size, + link_size, + link_offset, + data_size, + data_offset); } ~Header() OVERRIDE { } @@ -596,6 +662,27 @@ class Header : public Item { uint32_t data_offset_; const bool support_default_methods_; + void ConstructorHelper(const uint8_t* magic, + uint32_t checksum, + const uint8_t* signature, + uint32_t endian_tag, + uint32_t file_size, + uint32_t header_size, + uint32_t link_size, + uint32_t link_offset, + uint32_t data_size, + uint32_t data_offset) { + checksum_ = checksum; + endian_tag_ = endian_tag; + file_size_ = file_size; + header_size_ = header_size; + link_size_ = link_size; + link_offset_ = link_offset; + data_size_ = data_size; + data_offset_ = data_offset; + memcpy(magic_, magic, sizeof(magic_)); + memcpy(signature_, signature, sizeof(signature_)); + } Collections collections_; DISALLOW_COPY_AND_ASSIGN(Header); @@ -744,6 +831,8 @@ class FieldItem : public Item { : access_flags_(access_flags), field_id_(field_id) { } ~FieldItem() OVERRIDE { } + FieldItem(FieldItem&&) = default; + uint32_t GetAccessFlags() const { return access_flags_; } const FieldId* GetFieldId() const { return field_id_; } @@ -756,7 +845,7 @@ class FieldItem : public Item { DISALLOW_COPY_AND_ASSIGN(FieldItem); }; -using FieldItemVector = std::vector<std::unique_ptr<FieldItem>>; +using FieldItemVector = std::vector<FieldItem>; class MethodItem : public Item { public: @@ -764,6 +853,8 @@ class MethodItem : public Item { : access_flags_(access_flags), method_id_(method_id), code_(code) { } ~MethodItem() OVERRIDE { } + MethodItem(MethodItem&&) = default; + uint32_t GetAccessFlags() const { return access_flags_; } const MethodId* GetMethodId() const { return method_id_; } CodeItem* GetCodeItem() { return code_; } @@ -778,7 +869,7 @@ class MethodItem : public Item { DISALLOW_COPY_AND_ASSIGN(MethodItem); }; -using MethodItemVector = std::vector<std::unique_ptr<MethodItem>>; +using MethodItemVector = std::vector<MethodItem>; class EncodedValue { public: diff --git a/dexlayout/dex_ir_builder.cc b/dexlayout/dex_ir_builder.cc index 4f9bcdd742..9468f763d6 100644 --- a/dexlayout/dex_ir_builder.cc +++ b/dexlayout/dex_ir_builder.cc @@ -43,7 +43,13 @@ Header* DexIrBuilder(const DexFile& dex_file, disk_header.link_off_, disk_header.data_size_, disk_header.data_off_, - dex_file.SupportsDefaultMethods()); + dex_file.SupportsDefaultMethods(), + dex_file.NumStringIds(), + dex_file.NumTypeIds(), + dex_file.NumProtoIds(), + dex_file.NumFieldIds(), + dex_file.NumMethodIds(), + dex_file.NumClassDefs()); Collections& collections = header->GetCollections(); collections.SetEagerlyAssignOffsets(eagerly_assign_offsets); // Walk the rest of the header fields. @@ -94,6 +100,7 @@ Header* DexIrBuilder(const DexFile& dex_file, // Sort the vectors by the map order (same order as the file). collections.SortVectorsByMapOrder(); + collections.ClearMaps(); // Load the link data if it exists. collections.SetLinkData(std::vector<uint8_t>( diff --git a/dexlayout/dex_verify.cc b/dexlayout/dex_verify.cc index 18ddc86e0c..2e4756b482 100644 --- a/dexlayout/dex_verify.cc +++ b/dexlayout/dex_verify.cc @@ -769,8 +769,8 @@ bool VerifyFields(dex_ir::FieldItemVector* orig, return false; } for (size_t i = 0; i < orig->size(); ++i) { - dex_ir::FieldItem* orig_field = (*orig)[i].get(); - dex_ir::FieldItem* output_field = (*output)[i].get(); + dex_ir::FieldItem* orig_field = &(*orig)[i]; + dex_ir::FieldItem* output_field = &(*output)[i]; if (orig_field->GetFieldId()->GetIndex() != output_field->GetFieldId()->GetIndex()) { *error_msg = StringPrintf("Mismatched field index for class data at offset %x: %u vs %u.", orig_offset, @@ -802,8 +802,8 @@ bool VerifyMethods(dex_ir::MethodItemVector* orig, return false; } for (size_t i = 0; i < orig->size(); ++i) { - dex_ir::MethodItem* orig_method = (*orig)[i].get(); - dex_ir::MethodItem* output_method = (*output)[i].get(); + dex_ir::MethodItem* orig_method = &(*orig)[i]; + dex_ir::MethodItem* output_method = &(*output)[i]; if (orig_method->GetMethodId()->GetIndex() != output_method->GetMethodId()->GetIndex()) { *error_msg = StringPrintf("Mismatched method index for class data at offset %x: %u vs %u.", orig_offset, diff --git a/dexlayout/dex_visualize.cc b/dexlayout/dex_visualize.cc index c8aac941ff..0e04c587e7 100644 --- a/dexlayout/dex_visualize.cc +++ b/dexlayout/dex_visualize.cc @@ -279,22 +279,22 @@ void VisualizeDexLayout(dex_ir::Header* header, dumper->DumpAddressRange(class_data, class_index); if (class_data->StaticFields()) { for (auto& field_item : *class_data->StaticFields()) { - dumper->DumpFieldItem(field_item.get(), class_index); + dumper->DumpFieldItem(&field_item, class_index); } } if (class_data->InstanceFields()) { for (auto& field_item : *class_data->InstanceFields()) { - dumper->DumpFieldItem(field_item.get(), class_index); + dumper->DumpFieldItem(&field_item, class_index); } } if (class_data->DirectMethods()) { for (auto& method_item : *class_data->DirectMethods()) { - dumper->DumpMethodItem(method_item.get(), dex_file, class_index, profile_info); + dumper->DumpMethodItem(&method_item, dex_file, class_index, profile_info); } } if (class_data->VirtualMethods()) { for (auto& method_item : *class_data->VirtualMethods()) { - dumper->DumpMethodItem(method_item.get(), dex_file, class_index, profile_info); + dumper->DumpMethodItem(&method_item, dex_file, class_index, profile_info); } } } diff --git a/dexlayout/dex_writer.cc b/dexlayout/dex_writer.cc index eead13f69a..9ed1312983 100644 --- a/dexlayout/dex_writer.cc +++ b/dexlayout/dex_writer.cc @@ -207,21 +207,21 @@ void DexWriter::WriteEncodedAnnotation(Stream* stream, dex_ir::EncodedAnnotation void DexWriter::WriteEncodedFields(Stream* stream, dex_ir::FieldItemVector* fields) { uint32_t prev_index = 0; - for (std::unique_ptr<dex_ir::FieldItem>& field : *fields) { - uint32_t index = field->GetFieldId()->GetIndex(); + for (auto& field : *fields) { + uint32_t index = field.GetFieldId()->GetIndex(); stream->WriteUleb128(index - prev_index); - stream->WriteUleb128(field->GetAccessFlags()); + stream->WriteUleb128(field.GetAccessFlags()); prev_index = index; } } void DexWriter::WriteEncodedMethods(Stream* stream, dex_ir::MethodItemVector* methods) { uint32_t prev_index = 0; - for (std::unique_ptr<dex_ir::MethodItem>& method : *methods) { - uint32_t index = method->GetMethodId()->GetIndex(); - uint32_t code_off = method->GetCodeItem() == nullptr ? 0 : method->GetCodeItem()->GetOffset(); + for (auto& method : *methods) { + uint32_t index = method.GetMethodId()->GetIndex(); + uint32_t code_off = method.GetCodeItem() == nullptr ? 0 : method.GetCodeItem()->GetOffset(); stream->WriteUleb128(index - prev_index); - stream->WriteUleb128(method->GetAccessFlags()); + stream->WriteUleb128(method.GetAccessFlags()); stream->WriteUleb128(code_off); prev_index = index; } diff --git a/dexlayout/dexlayout.cc b/dexlayout/dexlayout.cc index 62dd1a9554..39d93bfc77 100644 --- a/dexlayout/dexlayout.cc +++ b/dexlayout/dexlayout.cc @@ -1459,8 +1459,8 @@ void DexLayout::DumpClass(int idx, char** last_package) { dex_ir::FieldItemVector* static_fields = class_data->StaticFields(); if (static_fields != nullptr) { for (uint32_t i = 0; i < static_fields->size(); i++) { - DumpSField((*static_fields)[i]->GetFieldId()->GetIndex(), - (*static_fields)[i]->GetAccessFlags(), + DumpSField((*static_fields)[i].GetFieldId()->GetIndex(), + (*static_fields)[i].GetAccessFlags(), i, i < encoded_values_size ? (*encoded_values)[i].get() : nullptr); } // for @@ -1475,8 +1475,8 @@ void DexLayout::DumpClass(int idx, char** last_package) { dex_ir::FieldItemVector* instance_fields = class_data->InstanceFields(); if (instance_fields != nullptr) { for (uint32_t i = 0; i < instance_fields->size(); i++) { - DumpIField((*instance_fields)[i]->GetFieldId()->GetIndex(), - (*instance_fields)[i]->GetAccessFlags(), + DumpIField((*instance_fields)[i].GetFieldId()->GetIndex(), + (*instance_fields)[i].GetAccessFlags(), i); } // for } @@ -1490,9 +1490,9 @@ void DexLayout::DumpClass(int idx, char** last_package) { dex_ir::MethodItemVector* direct_methods = class_data->DirectMethods(); if (direct_methods != nullptr) { for (uint32_t i = 0; i < direct_methods->size(); i++) { - DumpMethod((*direct_methods)[i]->GetMethodId()->GetIndex(), - (*direct_methods)[i]->GetAccessFlags(), - (*direct_methods)[i]->GetCodeItem(), + DumpMethod((*direct_methods)[i].GetMethodId()->GetIndex(), + (*direct_methods)[i].GetAccessFlags(), + (*direct_methods)[i].GetCodeItem(), i); } // for } @@ -1506,9 +1506,9 @@ void DexLayout::DumpClass(int idx, char** last_package) { dex_ir::MethodItemVector* virtual_methods = class_data->VirtualMethods(); if (virtual_methods != nullptr) { for (uint32_t i = 0; i < virtual_methods->size(); i++) { - DumpMethod((*virtual_methods)[i]->GetMethodId()->GetIndex(), - (*virtual_methods)[i]->GetAccessFlags(), - (*virtual_methods)[i]->GetCodeItem(), + DumpMethod((*virtual_methods)[i].GetMethodId()->GetIndex(), + (*virtual_methods)[i].GetAccessFlags(), + (*virtual_methods)[i].GetCodeItem(), i); } // for } @@ -1636,14 +1636,14 @@ void DexLayout::LayoutStringData(const DexFile* dex_file) { } for (size_t i = 0; i < 2; ++i) { for (auto& method : *(i == 0 ? data->DirectMethods() : data->VirtualMethods())) { - const dex_ir::MethodId* method_id = method->GetMethodId(); - dex_ir::CodeItem* code_item = method->GetCodeItem(); + const dex_ir::MethodId* method_id = method.GetMethodId(); + dex_ir::CodeItem* code_item = method.GetCodeItem(); if (code_item == nullptr) { continue; } const bool is_clinit = is_profile_class && - (method->GetAccessFlags() & kAccConstructor) != 0 && - (method->GetAccessFlags() & kAccStatic) != 0; + (method.GetAccessFlags() & kAccConstructor) != 0 && + (method.GetAccessFlags() & kAccStatic) != 0; const bool method_executed = is_clinit || info_->GetMethodHotness(MethodReference(dex_file, method_id->GetIndex())).IsInProfile(); if (!method_executed) { @@ -1744,14 +1744,14 @@ void DexLayout::LayoutCodeItems(const DexFile* dex_file) { for (auto& method : *(invoke_type == InvokeType::kDirect ? class_data->DirectMethods() : class_data->VirtualMethods())) { - const dex_ir::MethodId *method_id = method->GetMethodId(); - dex_ir::CodeItem *code_item = method->GetCodeItem(); + const dex_ir::MethodId *method_id = method.GetMethodId(); + dex_ir::CodeItem *code_item = method.GetCodeItem(); if (code_item == nullptr) { continue; } // Separate executed methods (clinits and profiled methods) from unexecuted methods. - const bool is_clinit = (method->GetAccessFlags() & kAccConstructor) != 0 && - (method->GetAccessFlags() & kAccStatic) != 0; + const bool is_clinit = (method.GetAccessFlags() & kAccConstructor) != 0 && + (method.GetAccessFlags() & kAccStatic) != 0; const bool is_startup_clinit = is_profile_class && is_clinit; using Hotness = ProfileCompilationInfo::MethodHotness; Hotness hotness = info_->GetMethodHotness(MethodReference(dex_file, method_id->GetIndex())); diff --git a/libartbase/base/bit_table.h b/libartbase/base/bit_table.h index 0ae60b9070..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> @@ -120,6 +121,7 @@ class BitTable { ALWAYS_INLINE void Decode(BitMemoryRegion region, size_t* bit_offset) { // Decode row count and column sizes from the table header. + size_t initial_bit_offset = *bit_offset; num_rows_ = DecodeVarintBits(region, bit_offset); if (num_rows_ != 0) { column_offset_[0] = 0; @@ -128,6 +130,7 @@ class BitTable { column_offset_[i + 1] = dchecked_integral_cast<uint16_t>(column_end); } } + header_bit_size_ = *bit_offset - initial_bit_offset; // Record the region which contains the table data and skip past it. table_data_ = region.Subregion(*bit_offset, num_rows_ * NumRowBits()); @@ -158,55 +161,78 @@ class BitTable { return column_offset_[column + 1] - column_offset_[column]; } - size_t DataBitSize() const { return num_rows_ * column_offset_[kNumColumns]; } + size_t HeaderBitSize() const { return header_bit_size_; } + size_t BitSize() const { return header_bit_size_ + table_data_.size_in_bits(); } protected: BitMemoryRegion table_data_; size_t num_rows_ = 0; uint16_t column_offset_[kNumColumns + 1] = {}; + uint16_t header_bit_size_ = 0; }; // Template meta-programming helper. template<typename Accessor, size_t... Columns> -static const char** GetBitTableColumnNamesImpl(std::index_sequence<Columns...>) { +static const char* const* GetBitTableColumnNamesImpl(std::index_sequence<Columns...>) { static const char* names[] = { Accessor::template ColumnName<Columns, 0>::Value... }; return names; } template<typename Accessor> -static const char** GetBitTableColumnNames() { +static const char* const* GetBitTableColumnNames() { return GetBitTableColumnNamesImpl<Accessor>(std::make_index_sequence<Accessor::kCount>()); } // 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); @@ -216,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; } @@ -230,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. @@ -243,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++) { @@ -272,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]); } } } @@ -288,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/libartbase/base/indenter.h b/libartbase/base/indenter.h index 06e7340d36..a479b7d650 100644 --- a/libartbase/base/indenter.h +++ b/libartbase/base/indenter.h @@ -122,6 +122,10 @@ class VariableIndentationOutputStream { return indented_os_; } + size_t GetIndentation() const { + return indenter_.count_; + } + void IncreaseIndentation(size_t adjustment) { indenter_.count_ += adjustment; } diff --git a/libartbase/base/mem_map.cc b/libartbase/base/mem_map.cc index 9ba1d6c139..d53480d4ca 100644 --- a/libartbase/base/mem_map.cc +++ b/libartbase/base/mem_map.cc @@ -647,21 +647,11 @@ void MemMap::MadviseDontNeedAndZero() { } bool MemMap::Sync() { - bool result; - if (redzone_size_ != 0) { - // To avoid errors when running on a memory tool, temporarily lift the lower-end noaccess - // protection before passing it to msync() as it only accepts page-aligned base address, - // and exclude the higher-end noaccess protection from the msync range. b/27552451. - // TODO: Valgrind is no longer supported, but Address Sanitizer is: - // check whether this special case is needed for ASan. - uint8_t* base_begin = reinterpret_cast<uint8_t*>(base_begin_); - MEMORY_TOOL_MAKE_DEFINED(base_begin, begin_ - base_begin); - result = msync(BaseBegin(), End() - base_begin, MS_SYNC) == 0; - MEMORY_TOOL_MAKE_NOACCESS(base_begin, begin_ - base_begin); - } else { - result = msync(BaseBegin(), BaseSize(), MS_SYNC) == 0; - } - return result; + // Historical note: To avoid Valgrind errors, we temporarily lifted the lower-end noaccess + // protection before passing it to msync() when `redzone_size_` was non-null, as Valgrind + // only accepts page-aligned base address, and excludes the higher-end noaccess protection + // from the msync range. b/27552451. + return msync(BaseBegin(), BaseSize(), MS_SYNC) == 0; } bool MemMap::Protect(int prot) { diff --git a/libartbase/base/mem_map_test.cc b/libartbase/base/mem_map_test.cc index 4a78bdcabe..c575c7a31f 100644 --- a/libartbase/base/mem_map_test.cc +++ b/libartbase/base/mem_map_test.cc @@ -471,9 +471,8 @@ TEST_F(MemMapTest, MapAnonymousExactAddr32bitHighAddr) { // cannot allocate in the 2GB-4GB region. TEST_DISABLED_FOR_MIPS(); - // This test may not work under Valgrind. - // TODO: Valgrind is no longer supported, but Address Sanitizer is: - // check whether this test works with ASan. + // This test does not work under AddressSanitizer. + // Historical note: This test did not work under Valgrind either. TEST_DISABLED_FOR_MEMORY_TOOL(); CommonInit(); diff --git a/libartbase/base/stats.h b/libartbase/base/stats.h new file mode 100644 index 0000000000..4dcbfe81c6 --- /dev/null +++ b/libartbase/base/stats.h @@ -0,0 +1,60 @@ +/* + * 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. + */ + +#ifndef ART_LIBARTBASE_BASE_STATS_H_ +#define ART_LIBARTBASE_BASE_STATS_H_ + +#include <unordered_map> + +#include "globals.h" + +namespace art { + +// Simple structure to record tree of statistical values. +class Stats { + public: + double Value() const { return value_; } + size_t Count() const { return count_; } + Stats* Child(const char* name) { return &children_[name]; } + const std::unordered_map<const char*, Stats>& Children() const { return children_; } + + void AddBytes(double bytes, size_t count = 1) { Add(bytes, count); } + void AddBits(double bits, size_t count = 1) { Add(bits / kBitsPerByte, count); } + void AddSeconds(double s, size_t count = 1) { Add(s, count); } + void AddNanoSeconds(double ns, size_t count = 1) { Add(ns / 1000000000.0, count); } + + double SumChildrenValues() const { + double sum = 0.0; + for (auto it : children_) { + sum += it.second.Value(); + } + return sum; + } + + private: + void Add(double value, size_t count = 1) { + value_ += value; + count_ += count; + } + + double value_ = 0.0; // Commutative sum of the collected statistic in basic units. + size_t count_ = 0; // The number of samples for this node. + std::unordered_map<const char*, Stats> children_; +}; + +} // namespace art + +#endif // ART_LIBARTBASE_BASE_STATS_H_ diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc index 453e9da106..2b0095ce27 100644 --- a/oatdump/oatdump.cc +++ b/oatdump/oatdump.cc @@ -18,6 +18,7 @@ #include <stdlib.h> #include <fstream> +#include <iomanip> #include <iostream> #include <map> #include <set> @@ -37,6 +38,7 @@ #include "base/indenter.h" #include "base/os.h" #include "base/safe_map.h" +#include "base/stats.h" #include "base/stl_util.h" #include "base/unix_file/fd_file.h" #include "class_linker-inl.h" @@ -544,28 +546,30 @@ class OatDumper { os << "\n"; } - // Dump .bss entries. - DumpBssEntries( - os, - "ArtMethod", - oat_dex_file->GetMethodBssMapping(), - dex_file->NumMethodIds(), - static_cast<size_t>(GetInstructionSetPointerSize(instruction_set_)), - [=](uint32_t index) { return dex_file->PrettyMethod(index); }); - DumpBssEntries( - os, - "Class", - oat_dex_file->GetTypeBssMapping(), - dex_file->NumTypeIds(), - sizeof(GcRoot<mirror::Class>), - [=](uint32_t index) { return dex_file->PrettyType(dex::TypeIndex(index)); }); - DumpBssEntries( - os, - "String", - oat_dex_file->GetStringBssMapping(), - dex_file->NumStringIds(), - sizeof(GcRoot<mirror::Class>), - [=](uint32_t index) { return dex_file->StringDataByIdx(dex::StringIndex(index)); }); + if (!options_.dump_header_only_) { + // Dump .bss entries. + DumpBssEntries( + os, + "ArtMethod", + oat_dex_file->GetMethodBssMapping(), + dex_file->NumMethodIds(), + static_cast<size_t>(GetInstructionSetPointerSize(instruction_set_)), + [=](uint32_t index) { return dex_file->PrettyMethod(index); }); + DumpBssEntries( + os, + "Class", + oat_dex_file->GetTypeBssMapping(), + dex_file->NumTypeIds(), + sizeof(GcRoot<mirror::Class>), + [=](uint32_t index) { return dex_file->PrettyType(dex::TypeIndex(index)); }); + DumpBssEntries( + os, + "String", + oat_dex_file->GetStringBssMapping(), + dex_file->NumStringIds(), + sizeof(GcRoot<mirror::Class>), + [=](uint32_t index) { return dex_file->StringDataByIdx(dex::StringIndex(index)); }); + } } if (!options_.dump_header_only_) { @@ -639,7 +643,8 @@ class OatDumper { { os << "OAT FILE STATS:\n"; VariableIndentationOutputStream vios(&os); - stats_.Dump(vios); + stats_.AddBytes(oat_file_.Size()); + DumpStats(vios, "OatFile", stats_, stats_.Value()); } os << std::flush; @@ -737,156 +742,42 @@ class OatDumper { return vdex_file; } - struct Stats { - enum ByteKind { - kByteKindCode, - kByteKindQuickMethodHeader, - kByteKindCodeInfoLocationCatalog, - kByteKindCodeInfoDexRegisterMask, - kByteKindCodeInfoDexRegisterMap, - kByteKindCodeInfo, - kByteKindCodeInfoInvokeInfo, - kByteKindCodeInfoStackMasks, - kByteKindCodeInfoRegisterMasks, - kByteKindStackMapNativePc, - kByteKindStackMapDexPc, - kByteKindStackMapDexRegisterMap, - kByteKindStackMapInlineInfoIndex, - kByteKindStackMapRegisterMaskIndex, - kByteKindStackMapStackMaskIndex, - kByteKindInlineInfoMethodIndexIdx, - kByteKindInlineInfoDexPc, - kByteKindInlineInfoArtMethod, - kByteKindInlineInfoNumDexRegisters, - kByteKindInlineInfoIsLast, - kByteKindCount, - // Special ranges for std::accumulate convenience. - kByteKindStackMapFirst = kByteKindStackMapNativePc, - kByteKindStackMapLast = kByteKindStackMapStackMaskIndex, - kByteKindInlineInfoFirst = kByteKindInlineInfoMethodIndexIdx, - kByteKindInlineInfoLast = kByteKindInlineInfoIsLast, - }; - int64_t bits[kByteKindCount] = {}; - // Since code has deduplication, seen tracks already seen pointers to avoid double counting - // deduplicated code and tables. - std::unordered_set<const void*> seen; - - // Returns true if it was newly added. - bool AddBitsIfUnique(ByteKind kind, int64_t count, const void* address) { - if (seen.insert(address).second == true) { - // True means the address was not already in the set. - AddBits(kind, count); - return true; + bool AddStatsObject(const void* address) { + return seen_stats_objects_.insert(address).second; // Inserted new entry. + } + + void DumpStats(VariableIndentationOutputStream& os, + const std::string& name, + const Stats& stats, + double total) { + if (std::fabs(stats.Value()) > 0 || !stats.Children().empty()) { + double percent = 100.0 * stats.Value() / total; + os.Stream() + << std::setw(40 - os.GetIndentation()) << std::left << name << std::right << " " + << std::setw(8) << stats.Count() << " " + << std::setw(12) << std::fixed << std::setprecision(3) << stats.Value() / KB << "KB " + << std::setw(8) << std::fixed << std::setprecision(1) << percent << "%\n"; + + // Sort all children by largest value first, than by name. + std::map<std::pair<double, std::string>, const Stats&> sorted_children; + for (const auto& it : stats.Children()) { + sorted_children.emplace(std::make_pair(-it.second.Value(), it.first), it.second); } - return false; - } - void AddBits(ByteKind kind, int64_t count) { - bits[kind] += count; - } - - void Dump(VariableIndentationOutputStream& os) { - const int64_t sum = std::accumulate(bits, bits + kByteKindCount, 0u); - os.Stream() << "Dumping cumulative use of " << sum / kBitsPerByte << " accounted bytes\n"; - if (sum > 0) { - Dump(os, "Code ", bits[kByteKindCode], sum); - Dump(os, "QuickMethodHeader ", bits[kByteKindQuickMethodHeader], sum); - Dump(os, "CodeInfo ", bits[kByteKindCodeInfo], sum); - Dump(os, "CodeInfoLocationCatalog ", bits[kByteKindCodeInfoLocationCatalog], sum); - Dump(os, "CodeInfoDexRegisterMask ", bits[kByteKindCodeInfoDexRegisterMask], sum); - Dump(os, "CodeInfoDexRegisterMap ", bits[kByteKindCodeInfoDexRegisterMap], sum); - Dump(os, "CodeInfoStackMasks ", bits[kByteKindCodeInfoStackMasks], sum); - Dump(os, "CodeInfoRegisterMasks ", bits[kByteKindCodeInfoRegisterMasks], sum); - Dump(os, "CodeInfoInvokeInfo ", bits[kByteKindCodeInfoInvokeInfo], sum); - // Stack map section. - const int64_t stack_map_bits = std::accumulate(bits + kByteKindStackMapFirst, - bits + kByteKindStackMapLast + 1, - 0u); - Dump(os, "CodeInfoStackMap ", stack_map_bits, sum); - { - ScopedIndentation indent1(&os); - Dump(os, - "StackMapNativePc ", - bits[kByteKindStackMapNativePc], - stack_map_bits, - "stack map"); - Dump(os, - "StackMapDexPc ", - bits[kByteKindStackMapDexPc], - stack_map_bits, - "stack map"); - Dump(os, - "StackMapDexRegisterMap ", - bits[kByteKindStackMapDexRegisterMap], - stack_map_bits, - "stack map"); - Dump(os, - "StackMapInlineInfoIndex ", - bits[kByteKindStackMapInlineInfoIndex], - stack_map_bits, - "stack map"); - Dump(os, - "StackMapRegisterMaskIndex ", - bits[kByteKindStackMapRegisterMaskIndex], - stack_map_bits, - "stack map"); - Dump(os, - "StackMapStackMaskIndex ", - bits[kByteKindStackMapStackMaskIndex], - stack_map_bits, - "stack map"); - } - // Inline info section. - const int64_t inline_info_bits = std::accumulate(bits + kByteKindInlineInfoFirst, - bits + kByteKindInlineInfoLast + 1, - 0u); - Dump(os, "CodeInfoInlineInfo ", inline_info_bits, sum); - { - ScopedIndentation indent1(&os); - Dump(os, - "InlineInfoMethodIndexIdx ", - bits[kByteKindInlineInfoMethodIndexIdx], - inline_info_bits, - "inline info"); - Dump(os, - "InlineInfoDexPc ", - bits[kByteKindStackMapDexPc], - inline_info_bits, - "inline info"); - Dump(os, - "InlineInfoArtMethod ", - bits[kByteKindInlineInfoArtMethod], - inline_info_bits, - "inline info"); - Dump(os, - "InlineInfoNumDexRegisters ", - bits[kByteKindInlineInfoNumDexRegisters], - inline_info_bits, - "inline info"); - Dump(os, - "InlineInfoIsLast ", - bits[kByteKindInlineInfoIsLast], - inline_info_bits, - "inline info"); - } + // Add "other" row to represent any amount not account for by the children. + Stats other; + other.AddBytes(stats.Value() - stats.SumChildrenValues(), stats.Count()); + if (std::fabs(other.Value()) > 0 && !stats.Children().empty()) { + sorted_children.emplace(std::make_pair(-other.Value(), "(other)"), other); } - os.Stream() << "\n" << std::flush; - } - private: - void Dump(VariableIndentationOutputStream& os, - const char* name, - int64_t size, - int64_t total, - const char* sum_of = "total") { - const double percent = (static_cast<double>(size) / static_cast<double>(total)) * 100; - os.Stream() << StringPrintf("%s = %8" PRId64 " (%2.0f%% of %s)\n", - name, - size / kBitsPerByte, - percent, - sum_of); + // Print the data. + ScopedIndentation indent1(&os); + for (const auto& it : sorted_children) { + DumpStats(os, it.first.second, it.second, total); + } } - }; + } private: void AddAllOffsets() { @@ -1266,9 +1157,9 @@ class OatDumper { vios->Stream() << "OatQuickMethodHeader "; uint32_t method_header_offset = oat_method.GetOatQuickMethodHeaderOffset(); const OatQuickMethodHeader* method_header = oat_method.GetOatQuickMethodHeader(); - stats_.AddBitsIfUnique(Stats::kByteKindQuickMethodHeader, - sizeof(*method_header) * kBitsPerByte, - method_header); + if (AddStatsObject(method_header)) { + stats_.Child("QuickMethodHeader")->AddBytes(sizeof(*method_header)); + } if (options_.absolute_addresses_) { vios->Stream() << StringPrintf("%p ", method_header); } @@ -1340,7 +1231,9 @@ class OatDumper { const void* code = oat_method.GetQuickCode(); uint32_t aligned_code_begin = AlignCodeOffset(code_offset); uint64_t aligned_code_end = aligned_code_begin + code_size; - stats_.AddBitsIfUnique(Stats::kByteKindCode, code_size * kBitsPerByte, code); + if (AddStatsObject(code)) { + stats_.Child("Code")->AddBytes(code_size); + } if (options_.absolute_addresses_) { vios->Stream() << StringPrintf("%p ", code); @@ -1690,78 +1583,15 @@ class OatDumper { } else if (!bad_input && IsMethodGeneratedByOptimizingCompiler(oat_method, code_item_accessor)) { // The optimizing compiler outputs its CodeInfo data in the vmap table. + const OatQuickMethodHeader* method_header = oat_method.GetOatQuickMethodHeader(); StackMapsHelper helper(oat_method.GetVmapTable(), instruction_set_); - MethodInfo method_info(oat_method.GetOatQuickMethodHeader()->GetOptimizedMethodInfo()); - { - const CodeInfo code_info = helper.GetCodeInfo(); - const BitTable<StackMap::kCount>& stack_maps = code_info.stack_maps_; - const size_t num_stack_maps = stack_maps.NumRows(); - if (stats_.AddBitsIfUnique(Stats::kByteKindCodeInfo, - code_info.size_ * kBitsPerByte, - oat_method.GetVmapTable())) { - // Stack maps - stats_.AddBits( - Stats::kByteKindStackMapNativePc, - stack_maps.NumColumnBits(StackMap::kPackedNativePc) * num_stack_maps); - stats_.AddBits( - Stats::kByteKindStackMapDexPc, - stack_maps.NumColumnBits(StackMap::kDexPc) * num_stack_maps); - stats_.AddBits( - Stats::kByteKindStackMapDexRegisterMap, - stack_maps.NumColumnBits(StackMap::kDexRegisterMapIndex) * num_stack_maps); - stats_.AddBits( - Stats::kByteKindStackMapInlineInfoIndex, - stack_maps.NumColumnBits(StackMap::kInlineInfoIndex) * num_stack_maps); - stats_.AddBits( - Stats::kByteKindStackMapRegisterMaskIndex, - stack_maps.NumColumnBits(StackMap::kRegisterMaskIndex) * num_stack_maps); - stats_.AddBits( - Stats::kByteKindStackMapStackMaskIndex, - stack_maps.NumColumnBits(StackMap::kStackMaskIndex) * num_stack_maps); - - // Stack masks - stats_.AddBits( - Stats::kByteKindCodeInfoStackMasks, - code_info.stack_masks_.DataBitSize()); - - // Register masks - stats_.AddBits( - Stats::kByteKindCodeInfoRegisterMasks, - code_info.register_masks_.DataBitSize()); - - // Invoke infos - stats_.AddBits( - Stats::kByteKindCodeInfoInvokeInfo, - code_info.invoke_infos_.DataBitSize()); - - // Location catalog - stats_.AddBits(Stats::kByteKindCodeInfoLocationCatalog, - code_info.dex_register_catalog_.DataBitSize()); - stats_.AddBits(Stats::kByteKindCodeInfoDexRegisterMask, - code_info.dex_register_masks_.DataBitSize()); - stats_.AddBits(Stats::kByteKindCodeInfoDexRegisterMap, - code_info.dex_register_maps_.DataBitSize()); - - // Inline infos. - const BitTable<InlineInfo::kCount>& inline_infos = code_info.inline_infos_; - const size_t num_inline_infos = inline_infos.NumRows(); - if (num_inline_infos > 0u) { - stats_.AddBits( - Stats::kByteKindInlineInfoMethodIndexIdx, - inline_infos.NumColumnBits(InlineInfo::kMethodInfoIndex) * num_inline_infos); - stats_.AddBits( - Stats::kByteKindInlineInfoDexPc, - inline_infos.NumColumnBits(InlineInfo::kDexPc) * num_inline_infos); - stats_.AddBits( - Stats::kByteKindInlineInfoArtMethod, - inline_infos.NumColumnBits(InlineInfo::kArtMethodHi) * num_inline_infos + - inline_infos.NumColumnBits(InlineInfo::kArtMethodLo) * num_inline_infos); - stats_.AddBits( - Stats::kByteKindInlineInfoNumDexRegisters, - inline_infos.NumColumnBits(InlineInfo::kNumberOfDexRegisters) * num_inline_infos); - stats_.AddBits(Stats::kByteKindInlineInfoIsLast, num_inline_infos); - } - } + if (AddStatsObject(oat_method.GetVmapTable())) { + helper.GetCodeInfo().AddSizeStats(&stats_); + } + MethodInfo method_info(method_header->GetOptimizedMethodInfo()); + if (AddStatsObject(method_header->GetOptimizedMethodInfoPtr())) { + size_t method_info_size = MethodInfo::ComputeSize(method_info.NumMethodIndices()); + stats_.Child("MethodInfo")->AddBytes(method_info_size); } const uint8_t* quick_native_pc = reinterpret_cast<const uint8_t*>(quick_code); size_t offset = 0; @@ -1894,6 +1724,7 @@ class OatDumper { std::set<uintptr_t> offsets_; Disassembler* disassembler_; Stats stats_; + std::unordered_set<const void*> seen_stats_objects_; }; class ImageDumper { diff --git a/oatdump/oatdump_test.h b/oatdump/oatdump_test.h index 293acdc3a6..231163b674 100644 --- a/oatdump/oatdump_test.h +++ b/oatdump/oatdump_test.h @@ -158,7 +158,7 @@ class OatDumpTest : public CommonRuntimeTest { // Code and dex code do not show up if list only. expected_prefixes.push_back("DEX CODE:"); expected_prefixes.push_back("CODE:"); - expected_prefixes.push_back("CodeInfoInlineInfo"); + expected_prefixes.push_back("InlineInfos"); } if (mode == kModeArt) { exec_argv.push_back("--image=" + core_art_location_); 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_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/class_linker.cc b/runtime/class_linker.cc index 1710e788ef..c374e03ed7 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -4440,8 +4440,8 @@ void ClassLinker::CreateProxyConstructor(Handle<mirror::Class> klass, ArtMethod* // Find the <init>(InvocationHandler)V method. The exact method offset varies depending // on which front-end compiler was used to build the libcore DEX files. - ArtMethod* proxy_constructor = proxy_class->FindConstructor( - "(Ljava/lang/reflect/InvocationHandler;)V", image_pointer_size_); + ArtMethod* proxy_constructor = + jni::DecodeArtMethod(WellKnownClasses::java_lang_reflect_Proxy_init); DCHECK(proxy_constructor != nullptr) << "Could not find <init> method in java.lang.reflect.Proxy"; 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/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc index 2b1623ac5a..3ccfa556f1 100644 --- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc +++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc @@ -1101,11 +1101,14 @@ extern "C" const void* artInstrumentationMethodEntryFromCode(ArtMethod* method, // that part. ScopedQuickEntrypointChecks sqec(self, kIsDebugBuild, false); instrumentation::Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation(); + DCHECK(!method->IsProxyMethod()) + << "Proxy method " << method->PrettyMethod() + << " (declaring class: " << method->GetDeclaringClass()->PrettyClass() << ")" + << " should not hit instrumentation entrypoint."; if (instrumentation->IsDeoptimized(method)) { result = GetQuickToInterpreterBridge(); } else { result = instrumentation->GetQuickCodeFor(method, kRuntimePointerSize); - DCHECK(!Runtime::Current()->GetClassLinker()->IsQuickToInterpreterBridge(result)); } bool interpreter_entry = (result == GetQuickToInterpreterBridge()); diff --git a/runtime/exec_utils_test.cc b/runtime/exec_utils_test.cc index a9c1ea2ae0..c138ce3f9e 100644 --- a/runtime/exec_utils_test.cc +++ b/runtime/exec_utils_test.cc @@ -36,12 +36,9 @@ TEST_F(ExecUtilsTest, ExecSuccess) { command.push_back("/usr/bin/id"); } std::string error_msg; - if (!(kRunningOnMemoryTool && kMemoryToolDetectsLeaks)) { - // Running on Valgrind fails due to some memory that leaks in thread alternate signal stacks. - // TODO: Valgrind is no longer supported, but Address Sanitizer is: - // check whether the following code works with ASan. - EXPECT_TRUE(Exec(command, &error_msg)); - } + // Historical note: Running on Valgrind failed due to some memory + // that leaks in thread alternate signal stacks. + EXPECT_TRUE(Exec(command, &error_msg)); EXPECT_EQ(0U, error_msg.size()) << error_msg; } @@ -52,13 +49,10 @@ TEST_F(ExecUtilsTest, ExecError) { std::vector<std::string> command; command.push_back("bogus"); std::string error_msg; - if (!(kRunningOnMemoryTool && kMemoryToolDetectsLeaks)) { - // Running on Valgrind fails due to some memory that leaks in thread alternate signal stacks. - // TODO: Valgrind is no longer supported, but Address Sanitizer is: - // check whether the following code works with ASan. - EXPECT_FALSE(Exec(command, &error_msg)); - EXPECT_FALSE(error_msg.empty()); - } + // Historical note: Running on Valgrind failed due to some memory + // that leaks in thread alternate signal stacks. + EXPECT_FALSE(Exec(command, &error_msg)); + EXPECT_FALSE(error_msg.empty()); } TEST_F(ExecUtilsTest, EnvSnapshotAdditionsAreNotVisible) { @@ -76,13 +70,10 @@ TEST_F(ExecUtilsTest, EnvSnapshotAdditionsAreNotVisible) { } command.push_back(kModifiedVariable); std::string error_msg; - if (!(kRunningOnMemoryTool && kMemoryToolDetectsLeaks)) { - // Running on Valgrind fails due to some memory that leaks in thread alternate signal stacks. - // TODO: Valgrind is no longer supported, but Address Sanitizer is: - // check whether the following code works with ASan. - EXPECT_FALSE(Exec(command, &error_msg)); - EXPECT_NE(0U, error_msg.size()) << error_msg; - } + // Historical note: Running on Valgrind failed due to some memory + // that leaks in thread alternate signal stacks. + EXPECT_FALSE(Exec(command, &error_msg)); + EXPECT_NE(0U, error_msg.size()) << error_msg; } TEST_F(ExecUtilsTest, EnvSnapshotDeletionsAreNotVisible) { @@ -103,13 +94,10 @@ TEST_F(ExecUtilsTest, EnvSnapshotDeletionsAreNotVisible) { } command.push_back(kDeletedVariable); std::string error_msg; - if (!(kRunningOnMemoryTool && kMemoryToolDetectsLeaks)) { - // Running on Valgrind fails due to some memory that leaks in thread alternate signal stacks. - // TODO: Valgrind is no longer supported, but Address Sanitizer is: - // check whether the following code works with ASan. - EXPECT_TRUE(Exec(command, &error_msg)); - EXPECT_EQ(0U, error_msg.size()) << error_msg; - } + // Historical note: Running on Valgrind failed due to some memory + // that leaks in thread alternate signal stacks. + EXPECT_TRUE(Exec(command, &error_msg)); + EXPECT_EQ(0U, error_msg.size()) << error_msg; // Restore the variable's value. EXPECT_EQ(setenv(kDeletedVariable, save_value, kOverwrite), 0); } diff --git a/runtime/instrumentation.cc b/runtime/instrumentation.cc index d7f33d5e43..d752805d02 100644 --- a/runtime/instrumentation.cc +++ b/runtime/instrumentation.cc @@ -154,8 +154,16 @@ void Instrumentation::InstallStubsForMethod(ArtMethod* method) { return; } // Don't stub Proxy.<init>. Note that the Proxy class itself is not a proxy class. - if (method->IsConstructor() && - method->GetDeclaringClass()->DescriptorEquals("Ljava/lang/reflect/Proxy;")) { + // TODO We should remove the need for this since it means we cannot always correctly detect calls + // to Proxy.<init> + // Annoyingly this can be called before we have actually initialized WellKnownClasses so therefore + // we also need to check this based on the declaring-class descriptor. The check is valid because + // Proxy only has a single constructor. + ArtMethod* well_known_proxy_init = jni::DecodeArtMethod( + WellKnownClasses::java_lang_reflect_Proxy_init); + if ((LIKELY(well_known_proxy_init != nullptr) && UNLIKELY(method == well_known_proxy_init)) || + UNLIKELY(method->IsConstructor() && + method->GetDeclaringClass()->DescriptorEquals("Ljava/lang/reflect/Proxy;"))) { return; } const void* new_quick_code; @@ -354,7 +362,7 @@ static void InstrumentationInstallStack(Thread* thread, void* arg) } uint32_t dex_pc = visitor.dex_pcs_.back(); visitor.dex_pcs_.pop_back(); - if (!isi->interpreter_entry_) { + if (!isi->interpreter_entry_ && !isi->method_->IsRuntimeMethod()) { instrumentation->MethodEnterEvent(thread, (*isi).this_object_, (*isi).method_, dex_pc); } } @@ -785,7 +793,13 @@ void Instrumentation::UpdateMethodsCodeImpl(ArtMethod* method, const void* quick if (class_linker->IsQuickResolutionStub(quick_code) || class_linker->IsQuickToInterpreterBridge(quick_code)) { new_quick_code = quick_code; - } else if (entry_exit_stubs_installed_) { + } else if (entry_exit_stubs_installed_ && + // We need to make sure not to replace anything that InstallStubsForMethod + // wouldn't. Specifically we cannot stub out Proxy.<init> since subtypes copy the + // implementation directly and this will confuse the instrumentation trampolines. + // TODO We should remove the need for this since it makes it impossible to profile + // Proxy.<init> correctly in all cases. + method != jni::DecodeArtMethod(WellKnownClasses::java_lang_reflect_Proxy_init)) { new_quick_code = GetQuickInstrumentationEntryPoint(); } else { new_quick_code = quick_code; @@ -912,7 +926,7 @@ void Instrumentation::Undeoptimize(ArtMethod* method) { } // If there is no deoptimized method left, we can restore the stack of each thread. - if (empty) { + if (empty && !entry_exit_stubs_installed_) { MutexLock mu(self, *Locks::thread_list_lock_); Runtime::Current()->GetThreadList()->ForEach(InstrumentationRestoreStack, this); instrumentation_stubs_installed_ = false; 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/native_stack_dump.cc b/runtime/native_stack_dump.cc index b3a47c3053..ce295aacde 100644 --- a/runtime/native_stack_dump.cc +++ b/runtime/native_stack_dump.cc @@ -290,11 +290,6 @@ void DumpNativeStack(std::ostream& os, void* ucontext_ptr, bool skip_frames) { // Historical note: This was disabled when running under Valgrind (b/18119146). - // TODO: Valgrind is no longer supported, but Address Sanitizer is: - // check whether this test works with ASan. - if (kRunningOnMemoryTool) { - return; - } BacktraceMap* map = existing_map; std::unique_ptr<BacktraceMap> tmp_map; diff --git a/runtime/oat.h b/runtime/oat.h index 40f4edd8bb..22c6a39e09 100644 --- a/runtime/oat.h +++ b/runtime/oat.h @@ -32,8 +32,8 @@ class InstructionSetFeatures; class PACKED(4) OatHeader { public: static constexpr uint8_t kOatMagic[] = { 'o', 'a', 't', '\n' }; - // Last oat version changed reason: compiler support invoke-custom - static constexpr uint8_t kOatVersion[] = { '1', '4', '8', '\0' }; + // Last oat version changed reason: Add Kind column to stack maps. + static constexpr uint8_t kOatVersion[] = { '1', '4', '9', '\0' }; static constexpr const char* kImageLocationKey = "image-location"; static constexpr const char* kDex2OatCmdLineKey = "dex2oat-cmdline"; diff --git a/runtime/proxy_test.cc b/runtime/proxy_test.cc index 946ea018f3..36dea60367 100644 --- a/runtime/proxy_test.cc +++ b/runtime/proxy_test.cc @@ -23,11 +23,24 @@ #include "mirror/field-inl.h" #include "proxy_test.h" #include "scoped_thread_state_change-inl.h" +#include "well_known_classes.h" namespace art { namespace proxy_test { -class ProxyTest : public CommonRuntimeTest {}; +class ProxyTest : public CommonRuntimeTest { + protected: + void SetUp() OVERRIDE { + CommonRuntimeTest::SetUp(); + // The creation of a Proxy class uses WellKnownClasses. These are not normally initialized by + // CommonRuntimeTest so we need to do that now. + WellKnownClasses::Clear(); + WellKnownClasses::Init(art::Thread::Current()->GetJniEnv()); + // Since we aren't actually calling any of the native functions we can just immediately call + // LateInit after calling Init. + WellKnownClasses::LateInit(art::Thread::Current()->GetJniEnv()); + } +}; // Creates a proxy class and check ClassHelper works correctly. TEST_F(ProxyTest, ProxyClassHelper) { 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/stack.cc b/runtime/stack.cc index 56e47b9c77..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(); } } @@ -851,7 +849,8 @@ void StackVisitor::WalkStack(bool include_transitions) { uint8_t* return_pc_addr = reinterpret_cast<uint8_t*>(cur_quick_frame_) + return_pc_offset; uintptr_t return_pc = *reinterpret_cast<uintptr_t*>(return_pc_addr); - if (UNLIKELY(exit_stubs_installed)) { + if (UNLIKELY(exit_stubs_installed || + reinterpret_cast<uintptr_t>(GetQuickInstrumentationExitPc()) == return_pc)) { // While profiling, the return pc is restored from the side stack, except when walking // the stack for an exception where the side stack will be unwound in VisitFrame. if (reinterpret_cast<uintptr_t>(GetQuickInstrumentationExitPc()) == return_pc) { diff --git a/runtime/stack_map.cc b/runtime/stack_map.cc index a25c9fdee0..43609e80bd 100644 --- a/runtime/stack_map.cc +++ b/runtime/stack_map.cc @@ -21,6 +21,7 @@ #include "art_method.h" #include "base/indenter.h" +#include "base/stats.h" #include "scoped_thread_state_change-inl.h" namespace art { @@ -88,56 +89,62 @@ 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, + /*out*/ Stats* parent) { + Stats* table_stats = parent->Child(table_name); + table_stats->AddBits(table.BitSize()); + table_stats->Child("Header")->AddBits(table.HeaderBitSize()); + const char* const* column_names = GetBitTableColumnNames<Accessor>(); + for (size_t c = 0; c < table.NumColumns(); c++) { + if (table.NumColumnBits(c) > 0) { + Stats* column_stats = table_stats->Child(column_names[c]); + column_stats->AddBits(table.NumRows() * table.NumColumnBits(c), table.NumRows()); + } } } -static void DumpDexRegisterMap(VariableIndentationOutputStream* vios, - const DexRegisterMap& map) { - if (!map.empty()) { +void CodeInfo::AddSizeStats(/*out*/ Stats* parent) const { + Stats* stats = parent->Child("CodeInfo"); + stats->AddBytes(size_); + stats->Child("Header")->AddBytes(UnsignedLeb128Size(size_)); + AddTableSizeStats<StackMap>("StackMaps", stack_maps_, stats); + AddTableSizeStats<RegisterMask>("RegisterMasks", register_masks_, stats); + AddTableSizeStats<MaskInfo>("StackMasks", stack_masks_, stats); + AddTableSizeStats<InvokeInfo>("InvokeInfos", invoke_infos_, stats); + AddTableSizeStats<InlineInfo>("InlineInfos", inline_infos_, stats); + AddTableSizeStats<MaskInfo>("DexRegisterMasks", dex_register_masks_, stats); + AddTableSizeStats<DexRegisterMapInfo>("DexRegisterMaps", dex_register_maps_, stats); + AddTableSizeStats<DexRegisterInfo>("DexRegisterCatalog", dex_register_catalog_, stats); +} + +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"; } } -template<uint32_t kNumColumns> +template<typename Accessor> static void DumpTable(VariableIndentationOutputStream* vios, const char* table_name, - const BitTable<kNumColumns>& table, + const BitTable<Accessor::kCount>& table, bool verbose, bool is_mask = false) { if (table.NumRows() != 0) { - vios->Stream() << table_name << " BitSize=" << table.NumRows() * table.NumRowBits(); + vios->Stream() << table_name << " BitSize=" << table.BitSize(); vios->Stream() << " Rows=" << table.NumRows() << " Bits={"; + const char* const* column_names = GetBitTableColumnNames<Accessor>(); for (size_t c = 0; c < table.NumColumns(); c++) { vios->Stream() << (c != 0 ? " " : ""); - vios->Stream() << table.NumColumnBits(c); + vios->Stream() << column_names[c] << "=" << table.NumColumnBits(c); } vios->Stream() << "}\n"; if (verbose) { @@ -171,14 +178,14 @@ void CodeInfo::Dump(VariableIndentationOutputStream* vios, << " BitSize=" << size_ * kBitsPerByte << "\n"; ScopedIndentation indent1(vios); - DumpTable(vios, "StackMaps", stack_maps_, verbose); - DumpTable(vios, "RegisterMasks", register_masks_, verbose); - DumpTable(vios, "StackMasks", stack_masks_, verbose, true /* is_mask */); - DumpTable(vios, "InvokeInfos", invoke_infos_, verbose); - DumpTable(vios, "InlineInfos", inline_infos_, verbose); - DumpTable(vios, "DexRegisterMasks", dex_register_masks_, verbose, true /* is_mask */); - DumpTable(vios, "DexRegisterMaps", dex_register_maps_, verbose); - DumpTable(vios, "DexRegisterCatalog", dex_register_catalog_, verbose); + DumpTable<StackMap>(vios, "StackMaps", stack_maps_, verbose); + DumpTable<RegisterMask>(vios, "RegisterMasks", register_masks_, verbose); + DumpTable<MaskInfo>(vios, "StackMasks", stack_masks_, verbose, true /* is_mask */); + DumpTable<InvokeInfo>(vios, "InvokeInfos", invoke_infos_, verbose); + DumpTable<InlineInfo>(vios, "InlineInfos", inline_infos_, verbose); + DumpTable<MaskInfo>(vios, "DexRegisterMasks", dex_register_masks_, verbose, true /* is_mask */); + DumpTable<DexRegisterMapInfo>(vios, "DexRegisterMaps", dex_register_maps_, verbose); + DumpTable<DexRegisterInfo>(vios, "DexRegisterCatalog", dex_register_catalog_, verbose); // Display stack maps along with (live) Dex register maps. if (verbose) { @@ -208,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); @@ -235,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 53f80e5203..8af73e9e10 100644 --- a/runtime/stack_map.h +++ b/runtime/stack_map.h @@ -47,15 +47,18 @@ static constexpr size_t kMaxDexRegisterMapSearchDistance = 32; class ArtMethod; class CodeInfo; +class Stats; 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_{} { @@ -69,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. @@ -156,16 +119,23 @@ class DexRegisterMap { * - Knowing the inlining information, * - Knowing the values of dex registers. */ -class StackMap : public BitTable<7>::Accessor { +class StackMap : public BitTable<8>::Accessor { public: + enum Kind { + Default = -1, + Catch = 0, + OSR = 1, + Debug = 2, + }; BIT_TABLE_HEADER() - BIT_TABLE_COLUMN(0, PackedNativePc) - BIT_TABLE_COLUMN(1, DexPc) - BIT_TABLE_COLUMN(2, RegisterMaskIndex) - BIT_TABLE_COLUMN(3, StackMaskIndex) - BIT_TABLE_COLUMN(4, InlineInfoIndex) - BIT_TABLE_COLUMN(5, DexRegisterMaskIndex) - BIT_TABLE_COLUMN(6, DexRegisterMapIndex) + BIT_TABLE_COLUMN(0, Kind) + BIT_TABLE_COLUMN(1, PackedNativePc) + BIT_TABLE_COLUMN(2, DexPc) + BIT_TABLE_COLUMN(3, RegisterMaskIndex) + BIT_TABLE_COLUMN(4, StackMaskIndex) + BIT_TABLE_COLUMN(5, InlineInfoIndex) + BIT_TABLE_COLUMN(6, DexRegisterMaskIndex) + BIT_TABLE_COLUMN(7, DexRegisterMapIndex) ALWAYS_INLINE uint32_t GetNativePcOffset(InstructionSet instruction_set) const { return UnpackNativePc(Get<kPackedNativePc>(), instruction_set); @@ -252,6 +222,18 @@ class InvokeInfo : public BitTable<3>::Accessor { } }; +class MaskInfo : public BitTable<1>::Accessor { + public: + BIT_TABLE_HEADER() + BIT_TABLE_COLUMN(0, Mask) +}; + +class DexRegisterMapInfo : public BitTable<1>::Accessor { + public: + BIT_TABLE_HEADER() + BIT_TABLE_COLUMN(0, CatalogueIndex) +}; + class DexRegisterInfo : public BitTable<2>::Accessor { public: BIT_TABLE_HEADER() @@ -402,19 +384,18 @@ class CodeInfo { StackMap GetStackMapForDexPc(uint32_t dex_pc) const { for (size_t i = 0, e = GetNumberOfStackMaps(); i < e; ++i) { StackMap stack_map = GetStackMapAt(i); - if (stack_map.GetDexPc() == dex_pc) { + if (stack_map.GetDexPc() == dex_pc && stack_map.GetKind() != StackMap::Kind::Debug) { return stack_map; } } return StackMap(); } - // Searches the stack map list backwards because catch stack maps are stored - // at the end. + // Searches the stack map list backwards because catch stack maps are stored at the end. StackMap GetCatchStackMapForDexPc(uint32_t dex_pc) const { for (size_t i = GetNumberOfStackMaps(); i > 0; --i) { StackMap stack_map = GetStackMapAt(i - 1); - if (stack_map.GetDexPc() == dex_pc) { + if (stack_map.GetDexPc() == dex_pc && stack_map.GetKind() == StackMap::Kind::Catch) { return stack_map; } } @@ -422,41 +403,26 @@ class CodeInfo { } StackMap GetOsrStackMapForDexPc(uint32_t dex_pc) const { - size_t e = GetNumberOfStackMaps(); - if (e == 0) { - // There cannot be OSR stack map if there is no stack map. - return StackMap(); - } - // Walk over all stack maps. If two consecutive stack maps are identical, then we - // have found a stack map suitable for OSR. - for (size_t i = 0; i < e - 1; ++i) { + for (size_t i = 0, e = GetNumberOfStackMaps(); i < e; ++i) { StackMap stack_map = GetStackMapAt(i); - if (stack_map.GetDexPc() == dex_pc) { - StackMap other = GetStackMapAt(i + 1); - if (other.GetDexPc() == dex_pc && - other.GetNativePcOffset(kRuntimeISA) == - stack_map.GetNativePcOffset(kRuntimeISA)) { - if (i < e - 2) { - // Make sure there are not three identical stack maps following each other. - DCHECK_NE( - stack_map.GetNativePcOffset(kRuntimeISA), - GetStackMapAt(i + 2).GetNativePcOffset(kRuntimeISA)); - } - return stack_map; - } + if (stack_map.GetDexPc() == dex_pc && stack_map.GetKind() == StackMap::Kind::OSR) { + return stack_map; } } return StackMap(); } - StackMap GetStackMapForNativePcOffset(uint32_t native_pc_offset) const { + StackMap GetStackMapForNativePcOffset(uint32_t pc, InstructionSet isa = kRuntimeISA) const { // TODO: Safepoint stack maps are sorted by native_pc_offset but catch stack // maps are not. If we knew that the method does not have try/catch, // we could do binary search. for (size_t i = 0, e = GetNumberOfStackMaps(); i < e; ++i) { StackMap stack_map = GetStackMapAt(i); - if (stack_map.GetNativePcOffset(kRuntimeISA) == native_pc_offset) { - return stack_map; + if (stack_map.GetNativePcOffset(isa) == pc) { + StackMap::Kind kind = static_cast<StackMap::Kind>(stack_map.GetKind()); + if (kind == StackMap::Kind::Default || kind == StackMap::Kind::OSR) { + return stack_map; + } } } return StackMap(); @@ -480,6 +446,9 @@ class CodeInfo { InstructionSet instruction_set, const MethodInfo& method_info) const; + // Accumulate code info size statistics into the given Stats tree. + void AddSizeStats(/*out*/ Stats* parent) const; + private: // Scan backward to determine dex register locations at given stack map. void DecodeDexRegisterMap(uint32_t stack_map_index, @@ -506,15 +475,13 @@ class CodeInfo { size_t size_; BitTable<StackMap::kCount> stack_maps_; BitTable<RegisterMask::kCount> register_masks_; - BitTable<1> stack_masks_; + BitTable<MaskInfo::kCount> stack_masks_; BitTable<InvokeInfo::kCount> invoke_infos_; BitTable<InlineInfo::kCount> inline_infos_; - BitTable<1> dex_register_masks_; - BitTable<1> dex_register_maps_; + BitTable<MaskInfo::kCount> dex_register_masks_; + BitTable<DexRegisterMapInfo::kCount> dex_register_maps_; BitTable<DexRegisterInfo::kCount> dex_register_catalog_; uint32_t number_of_dex_registers_; // Excludes any inlined methods. - - friend class OatDumper; }; #undef ELEMENT_BYTE_OFFSET_AFTER 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/runtime/well_known_classes.cc b/runtime/well_known_classes.cc index c64e7bbca1..206418fbc6 100644 --- a/runtime/well_known_classes.cc +++ b/runtime/well_known_classes.cc @@ -26,6 +26,7 @@ #include "base/enums.h" #include "class_linker.h" #include "entrypoints/quick/quick_entrypoints_enum.h" +#include "entrypoints/runtime_asm_entrypoints.h" #include "hidden_api.h" #include "jni/jni_internal.h" #include "mirror/class.h" @@ -98,6 +99,7 @@ jmethodID WellKnownClasses::java_lang_Long_valueOf; jmethodID WellKnownClasses::java_lang_ref_FinalizerReference_add; jmethodID WellKnownClasses::java_lang_ref_ReferenceQueue_add; jmethodID WellKnownClasses::java_lang_reflect_Parameter_init; +jmethodID WellKnownClasses::java_lang_reflect_Proxy_init; jmethodID WellKnownClasses::java_lang_reflect_Proxy_invoke; jmethodID WellKnownClasses::java_lang_Runtime_nativeLoad; jmethodID WellKnownClasses::java_lang_Short_valueOf; @@ -418,6 +420,14 @@ void WellKnownClasses::LateInit(JNIEnv* env) { CacheMethod(env, java_lang_Runtime.get(), true, "nativeLoad", "(Ljava/lang/String;Ljava/lang/ClassLoader;)" "Ljava/lang/String;"); + java_lang_reflect_Proxy_init = + CacheMethod(env, java_lang_reflect_Proxy, false, "<init>", + "(Ljava/lang/reflect/InvocationHandler;)V"); + // This invariant is important since otherwise we will have the entire proxy invoke system + // confused. + DCHECK_NE( + jni::DecodeArtMethod(java_lang_reflect_Proxy_init)->GetEntryPointFromQuickCompiledCode(), + GetQuickInstrumentationEntryPoint()); java_lang_reflect_Proxy_invoke = CacheMethod(env, java_lang_reflect_Proxy, true, "invoke", "(Ljava/lang/reflect/Proxy;Ljava/lang/reflect/Method;" @@ -484,6 +494,7 @@ void WellKnownClasses::Clear() { java_lang_ref_FinalizerReference_add = nullptr; java_lang_ref_ReferenceQueue_add = nullptr; java_lang_reflect_Parameter_init = nullptr; + java_lang_reflect_Proxy_init = nullptr; java_lang_reflect_Proxy_invoke = nullptr; java_lang_Runtime_nativeLoad = nullptr; java_lang_Short_valueOf = nullptr; diff --git a/runtime/well_known_classes.h b/runtime/well_known_classes.h index c81062f594..ce5ab1df84 100644 --- a/runtime/well_known_classes.h +++ b/runtime/well_known_classes.h @@ -108,6 +108,7 @@ struct WellKnownClasses { static jmethodID java_lang_ref_FinalizerReference_add; static jmethodID java_lang_ref_ReferenceQueue_add; static jmethodID java_lang_reflect_Parameter_init; + static jmethodID java_lang_reflect_Proxy_init; static jmethodID java_lang_reflect_Proxy_invoke; static jmethodID java_lang_Runtime_nativeLoad; static jmethodID java_lang_Short_valueOf; 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/004-ThreadStress/run b/test/004-ThreadStress/run index 8004036868..067e0d0407 100755 --- a/test/004-ThreadStress/run +++ b/test/004-ThreadStress/run @@ -15,7 +15,29 @@ # limitations under the License. # Enable lock contention logging. -${RUN} --runtime-option -Xlockprofthreshold:10 "${@}" +if [[ "x$ART_DEFAULT_GC_TYPE" = xGSS ]]; then + # NonMovingAlloc operations fail an assertion with the Generational + # Semi-Space (GSS) collector (see b/72738921); disable them for now + # by explicitly assigning frequencies to operations when the GSS + # collector is used. + # + # Note: The trick to use command substitution to have comments within + # a multi-line command is from https://stackoverflow.com/a/12797512. + ${RUN} --runtime-option -Xlockprofthreshold:10 "${@}" Main \ + -oom:0.005 `# 1/200` \ + -sigquit:0.095 `# 19/200` \ + -alloc:0.225 `# 45/200` \ + -largealloc:0.05 `# 10/200` \ + -nonmovingalloc:0.0 `# 0/200` \ + -stacktrace:0.1 `# 20/200` \ + -exit:0.225 `# 45/200` \ + -sleep:0.125 `# 25/200` \ + -timedwait:0.05 `# 10/200` \ + -wait:0.075 `# 15/200` \ + -queuedwait:0.05 `# 10/200` +else + ${RUN} --runtime-option -Xlockprofthreshold:10 "${@}" +fi return_status1=$? # Run locks-only mode with stack-dump lock profiling. Reduce the number of total operations from diff --git a/test/004-ThreadStress/src-art/Main.java b/test/004-ThreadStress/src-art/Main.java index a142934638..3a89f4f166 100644 --- a/test/004-ThreadStress/src-art/Main.java +++ b/test/004-ThreadStress/src-art/Main.java @@ -315,11 +315,9 @@ public class Main implements Runnable { Map<Operation, Double> frequencyMap = new HashMap<Operation, Double>(); frequencyMap.put(new OOM(), 0.005); // 1/200 frequencyMap.put(new SigQuit(), 0.095); // 19/200 - frequencyMap.put(new Alloc(), 0.225); // 45/200 + frequencyMap.put(new Alloc(), 0.2); // 40/200 frequencyMap.put(new LargeAlloc(), 0.05); // 10/200 - // TODO: NonMovingAlloc operations fail an assertion with the - // GSS collector (see b/72738921); disable them for now. - frequencyMap.put(new NonMovingAlloc(), 0.0); // 0/200 + frequencyMap.put(new NonMovingAlloc(), 0.025); // 5/200 frequencyMap.put(new StackTrace(), 0.1); // 20/200 frequencyMap.put(new Exit(), 0.225); // 45/200 frequencyMap.put(new Sleep(), 0.125); // 25/200 @@ -379,6 +377,8 @@ public class Main implements Runnable { op = new Alloc(); } else if (split[0].equals("-largealloc")) { op = new LargeAlloc(); + } else if (split[0].equals("-nonmovingalloc")) { + op = new NonMovingAlloc(); } else if (split[0].equals("-stacktrace")) { op = new StackTrace(); } else if (split[0].equals("-exit")) { 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/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/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-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/626-checker-arm64-scratch-register/build b/test/626-checker-arm64-scratch-register/build deleted file mode 100644 index d85147f17b..0000000000 --- a/test/626-checker-arm64-scratch-register/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/626-checker-arm64-scratch-register/smali/Main2.smali b/test/626-checker-arm64-scratch-register/smali/Main2.smali new file mode 100644 index 0000000000..914ae6eeaf --- /dev/null +++ b/test/626-checker-arm64-scratch-register/smali/Main2.smali @@ -0,0 +1,1768 @@ +# 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. + +.class public LMain2; +.super Ljava/lang/Object; + + +# instance fields +.field b00:Z + +.field b01:Z + +.field b02:Z + +.field b03:Z + +.field b04:Z + +.field b05:Z + +.field b06:Z + +.field b07:Z + +.field b08:Z + +.field b09:Z + +.field b10:Z + +.field b11:Z + +.field b12:Z + +.field b13:Z + +.field b14:Z + +.field b15:Z + +.field b16:Z + +.field b17:Z + +.field b18:Z + +.field b19:Z + +.field b20:Z + +.field b21:Z + +.field b22:Z + +.field b23:Z + +.field b24:Z + +.field b25:Z + +.field b26:Z + +.field b27:Z + +.field b28:Z + +.field b29:Z + +.field b30:Z + +.field b31:Z + +.field b32:Z + +.field b33:Z + +.field b34:Z + +.field b35:Z + +.field b36:Z + +.field conditionA:Z + +.field conditionB:Z + +.field conditionC:Z + + +# direct methods +.method public constructor <init>()V + .registers 1 + + .prologue + .line 17 + invoke-direct {p0}, Ljava/lang/Object;-><init>()V + + return-void +.end method + +## CHECK-START-ARM64: void Main2.test() register (after) +## CHECK: begin_block +## CHECK: name "B0" +## CHECK: <<This:l\d+>> ParameterValue +## CHECK: end_block +## CHECK: begin_block +## CHECK: successors "<<ThenBlock:B\d+>>" "<<ElseBlock:B\d+>>" +## CHECK: <<CondB:z\d+>> InstanceFieldGet [<<This>>] field_name:Main2.conditionB +## CHECK: If [<<CondB>>] +## CHECK: end_block +## CHECK: begin_block +## CHECK: name "<<ElseBlock>>" +## CHECK: ParallelMove moves:[40(sp)->d0,24(sp)->32(sp),28(sp)->36(sp),d0->d3,d3->d4,d2->d5,d4->d6,d5->d7,d6->d18,d7->d19,d18->d20,d19->d21,d20->d22,d21->d23,d22->d10,d23->d11,16(sp)->24(sp),20(sp)->28(sp),d10->d14,d11->d12,d12->d13,d13->d1,d14->d2,32(sp)->16(sp),36(sp)->20(sp)] +## CHECK: end_block + +## CHECK-START-ARM64: void Main2.test() disassembly (after) +## CHECK: begin_block +## CHECK: name "B0" +## CHECK: <<This:l\d+>> ParameterValue +## CHECK: end_block +## CHECK: begin_block +## CHECK: successors "<<ThenBlock:B\d+>>" "<<ElseBlock:B\d+>>" +## CHECK: <<CondB:z\d+>> InstanceFieldGet [<<This>>] field_name:Main2.conditionB +## CHECK: If [<<CondB>>] +## CHECK: end_block +## CHECK: begin_block +## CHECK: name "<<ElseBlock>>" +## CHECK: ParallelMove moves:[invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid] +## CHECK: fmov d31, d2 +## CHECK: ldr s2, [sp, #36] +## CHECK: ldr w16, [sp, #16] +## CHECK: str w16, [sp, #36] +## CHECK: str s14, [sp, #16] +## CHECK: ldr s14, [sp, #28] +## CHECK: str s1, [sp, #28] +## CHECK: ldr s1, [sp, #32] +## CHECK: str s31, [sp, #32] +## CHECK: ldr s31, [sp, #20] +## CHECK: str s31, [sp, #40] +## CHECK: str s12, [sp, #20] +## CHECK: fmov d12, d11 +## CHECK: fmov d11, d10 +## CHECK: fmov d10, d23 +## CHECK: fmov d23, d22 +## CHECK: fmov d22, d21 +## CHECK: fmov d21, d20 +## CHECK: fmov d20, d19 +## CHECK: fmov d19, d18 +## CHECK: fmov d18, d7 +## CHECK: fmov d7, d6 +## CHECK: fmov d6, d5 +## CHECK: fmov d5, d4 +## CHECK: fmov d4, d3 +## CHECK: fmov d3, d13 +## CHECK: ldr s13, [sp, #24] +## CHECK: str s3, [sp, #24] +## CHECK: ldr s3, pc+{{\d+}} (addr {{0x[0-9a-f]+}}) (100) +## CHECK: end_block + +# Original java source: +# +# public void test() { +# String r = ""; +# +# // For the purpose of this regression test, the order of +# // definition of these float variable matters. Likewise with the +# // order of the instructions where these variables are used below. +# // Reordering these lines make make the original (b/32545705) +# // issue vanish. +# float f17 = b17 ? 0.0f : 1.0f; +# float f16 = b16 ? 0.0f : 1.0f; +# float f18 = b18 ? 0.0f : 1.0f; +# float f19 = b19 ? 0.0f : 1.0f; +# float f20 = b20 ? 0.0f : 1.0f; +# float f21 = b21 ? 0.0f : 1.0f; +# float f15 = b15 ? 0.0f : 1.0f; +# float f00 = b00 ? 0.0f : 1.0f; +# float f22 = b22 ? 0.0f : 1.0f; +# float f23 = b23 ? 0.0f : 1.0f; +# float f24 = b24 ? 0.0f : 1.0f; +# float f25 = b25 ? 0.0f : 1.0f; +# float f26 = b26 ? 0.0f : 1.0f; +# float f27 = b27 ? 0.0f : 1.0f; +# float f29 = b29 ? 0.0f : 1.0f; +# float f28 = b28 ? 0.0f : 1.0f; +# float f01 = b01 ? 0.0f : 1.0f; +# float f02 = b02 ? 0.0f : 1.0f; +# float f03 = b03 ? 0.0f : 1.0f; +# float f04 = b04 ? 0.0f : 1.0f; +# float f05 = b05 ? 0.0f : 1.0f; +# float f07 = b07 ? 0.0f : 1.0f; +# float f06 = b06 ? 0.0f : 1.0f; +# float f30 = b30 ? 0.0f : 1.0f; +# float f31 = b31 ? 0.0f : 1.0f; +# float f32 = b32 ? 0.0f : 1.0f; +# float f33 = b33 ? 0.0f : 1.0f; +# float f34 = b34 ? 0.0f : 1.0f; +# float f36 = b36 ? 0.0f : 1.0f; +# float f35 = b35 ? 0.0f : 1.0f; +# float f08 = b08 ? 0.0f : 1.0f; +# float f09 = b09 ? 0.0f : 1.0f; +# float f10 = b10 ? 0.0f : 1.0f; +# float f11 = b11 ? 0.0f : 1.0f; +# float f12 = b12 ? 0.0f : 1.0f; +# float f14 = b14 ? 0.0f : 1.0f; +# float f13 = b13 ? 0.0f : 1.0f; +# +# if (conditionA) { +# f16 /= 1000.0f; +# f17 /= 1000.0f; +# f18 /= 1000.0f; +# f19 /= 1000.0f; +# f20 /= 1000.0f; +# f21 /= 1000.0f; +# f15 /= 1000.0f; +# f08 /= 1000.0f; +# f09 /= 1000.0f; +# f10 /= 1000.0f; +# f11 /= 1000.0f; +# f12 /= 1000.0f; +# f30 /= 1000.0f; +# f31 /= 1000.0f; +# f32 /= 1000.0f; +# f33 /= 1000.0f; +# f34 /= 1000.0f; +# f01 /= 1000.0f; +# f02 /= 1000.0f; +# f03 /= 1000.0f; +# f04 /= 1000.0f; +# f05 /= 1000.0f; +# f23 /= 1000.0f; +# f24 /= 1000.0f; +# f25 /= 1000.0f; +# f26 /= 1000.0f; +# f27 /= 1000.0f; +# f22 /= 1000.0f; +# f00 /= 1000.0f; +# f14 /= 1000.0f; +# f13 /= 1000.0f; +# f36 /= 1000.0f; +# f35 /= 1000.0f; +# f07 /= 1000.0f; +# f06 /= 1000.0f; +# f29 /= 1000.0f; +# f28 /= 1000.0f; +# } +# // The parallel move that used to exhaust the ARM64 parallel move +# // resolver's scratch register pool (provided by VIXL) was in the +# // "else" branch of the following condition generated by ART's +# // compiler. +# if (conditionB) { +# f16 /= 100.0f; +# f17 /= 100.0f; +# f18 /= 100.0f; +# f19 /= 100.0f; +# f20 /= 100.0f; +# f21 /= 100.0f; +# f15 /= 100.0f; +# f08 /= 100.0f; +# f09 /= 100.0f; +# f10 /= 100.0f; +# f11 /= 100.0f; +# f12 /= 100.0f; +# f30 /= 100.0f; +# f31 /= 100.0f; +# f32 /= 100.0f; +# f33 /= 100.0f; +# f34 /= 100.0f; +# f01 /= 100.0f; +# f02 /= 100.0f; +# f03 /= 100.0f; +# f04 /= 100.0f; +# f05 /= 100.0f; +# f23 /= 100.0f; +# f24 /= 100.0f; +# f25 /= 100.0f; +# f26 /= 100.0f; +# f27 /= 100.0f; +# f22 /= 100.0f; +# f00 /= 100.0f; +# f14 /= 100.0f; +# f13 /= 100.0f; +# f36 /= 100.0f; +# f35 /= 100.0f; +# f07 /= 100.0f; +# f06 /= 100.0f; +# f29 /= 100.0f; +# f28 /= 100.0f; +# } +# if (conditionC) { +# f16 /= 12.0f; +# f17 /= 12.0f; +# f18 /= 12.0f; +# f19 /= 12.0f; +# f20 /= 12.0f; +# f21 /= 12.0f; +# f15 /= 12.0f; +# f08 /= 12.0f; +# f09 /= 12.0f; +# f10 /= 12.0f; +# f11 /= 12.0f; +# f12 /= 12.0f; +# f30 /= 12.0f; +# f31 /= 12.0f; +# f32 /= 12.0f; +# f33 /= 12.0f; +# f34 /= 12.0f; +# f01 /= 12.0f; +# f02 /= 12.0f; +# f03 /= 12.0f; +# f04 /= 12.0f; +# f05 /= 12.0f; +# f23 /= 12.0f; +# f24 /= 12.0f; +# f25 /= 12.0f; +# f26 /= 12.0f; +# f27 /= 12.0f; +# f22 /= 12.0f; +# f00 /= 12.0f; +# f14 /= 12.0f; +# f13 /= 12.0f; +# f36 /= 12.0f; +# f35 /= 12.0f; +# f07 /= 12.0f; +# f06 /= 12.0f; +# f29 /= 12.0f; +# f28 /= 12.0f; +# } +# float s = 0.0f; +# s = ((float) Math.round(100.0f * s)) / 100.0f; +# String res = s + r; +# } + +# virtual methods +.method public test()V + .registers 45 + + .prologue + .line 121 + const-string v39, "" + + .line 128 + .local v39, "r":Ljava/lang/String; + move-object/from16 v0, p0 + + iget-boolean v0, v0, LMain2;->b17:Z + + move/from16 v42, v0 + + if-eqz v42, :cond_367 + + const/16 v19, 0x0 + + .line 129 + .local v19, "f17":F + :goto_c + move-object/from16 v0, p0 + + iget-boolean v0, v0, LMain2;->b16:Z + + move/from16 v42, v0 + + if-eqz v42, :cond_36b + + const/16 v18, 0x0 + + .line 130 + .local v18, "f16":F + :goto_16 + move-object/from16 v0, p0 + + iget-boolean v0, v0, LMain2;->b18:Z + + move/from16 v42, v0 + + if-eqz v42, :cond_36f + + const/16 v20, 0x0 + + .line 131 + .local v20, "f18":F + :goto_20 + move-object/from16 v0, p0 + + iget-boolean v0, v0, LMain2;->b19:Z + + move/from16 v42, v0 + + if-eqz v42, :cond_373 + + const/16 v21, 0x0 + + .line 132 + .local v21, "f19":F + :goto_2a + move-object/from16 v0, p0 + + iget-boolean v0, v0, LMain2;->b20:Z + + move/from16 v42, v0 + + if-eqz v42, :cond_377 + + const/16 v22, 0x0 + + .line 133 + .local v22, "f20":F + :goto_34 + move-object/from16 v0, p0 + + iget-boolean v0, v0, LMain2;->b21:Z + + move/from16 v42, v0 + + if-eqz v42, :cond_37b + + const/16 v23, 0x0 + + .line 134 + .local v23, "f21":F + :goto_3e + move-object/from16 v0, p0 + + iget-boolean v0, v0, LMain2;->b15:Z + + move/from16 v42, v0 + + if-eqz v42, :cond_37f + + const/16 v17, 0x0 + + .line 135 + .local v17, "f15":F + :goto_48 + move-object/from16 v0, p0 + + iget-boolean v0, v0, LMain2;->b00:Z + + move/from16 v42, v0 + + if-eqz v42, :cond_383 + + const/4 v2, 0x0 + + .line 136 + .local v2, "f00":F + :goto_51 + move-object/from16 v0, p0 + + iget-boolean v0, v0, LMain2;->b22:Z + + move/from16 v42, v0 + + if-eqz v42, :cond_387 + + const/16 v24, 0x0 + + .line 137 + .local v24, "f22":F + :goto_5b + move-object/from16 v0, p0 + + iget-boolean v0, v0, LMain2;->b23:Z + + move/from16 v42, v0 + + if-eqz v42, :cond_38b + + const/16 v25, 0x0 + + .line 138 + .local v25, "f23":F + :goto_65 + move-object/from16 v0, p0 + + iget-boolean v0, v0, LMain2;->b24:Z + + move/from16 v42, v0 + + if-eqz v42, :cond_38f + + const/16 v26, 0x0 + + .line 139 + .local v26, "f24":F + :goto_6f + move-object/from16 v0, p0 + + iget-boolean v0, v0, LMain2;->b25:Z + + move/from16 v42, v0 + + if-eqz v42, :cond_393 + + const/16 v27, 0x0 + + .line 140 + .local v27, "f25":F + :goto_79 + move-object/from16 v0, p0 + + iget-boolean v0, v0, LMain2;->b26:Z + + move/from16 v42, v0 + + if-eqz v42, :cond_397 + + const/16 v28, 0x0 + + .line 141 + .local v28, "f26":F + :goto_83 + move-object/from16 v0, p0 + + iget-boolean v0, v0, LMain2;->b27:Z + + move/from16 v42, v0 + + if-eqz v42, :cond_39b + + const/16 v29, 0x0 + + .line 142 + .local v29, "f27":F + :goto_8d + move-object/from16 v0, p0 + + iget-boolean v0, v0, LMain2;->b29:Z + + move/from16 v42, v0 + + if-eqz v42, :cond_39f + + const/16 v31, 0x0 + + .line 143 + .local v31, "f29":F + :goto_97 + move-object/from16 v0, p0 + + iget-boolean v0, v0, LMain2;->b28:Z + + move/from16 v42, v0 + + if-eqz v42, :cond_3a3 + + const/16 v30, 0x0 + + .line 144 + .local v30, "f28":F + :goto_a1 + move-object/from16 v0, p0 + + iget-boolean v0, v0, LMain2;->b01:Z + + move/from16 v42, v0 + + if-eqz v42, :cond_3a7 + + const/4 v3, 0x0 + + .line 145 + .local v3, "f01":F + :goto_aa + move-object/from16 v0, p0 + + iget-boolean v0, v0, LMain2;->b02:Z + + move/from16 v42, v0 + + if-eqz v42, :cond_3ab + + const/4 v4, 0x0 + + .line 146 + .local v4, "f02":F + :goto_b3 + move-object/from16 v0, p0 + + iget-boolean v0, v0, LMain2;->b03:Z + + move/from16 v42, v0 + + if-eqz v42, :cond_3af + + const/4 v5, 0x0 + + .line 147 + .local v5, "f03":F + :goto_bc + move-object/from16 v0, p0 + + iget-boolean v0, v0, LMain2;->b04:Z + + move/from16 v42, v0 + + if-eqz v42, :cond_3b3 + + const/4 v6, 0x0 + + .line 148 + .local v6, "f04":F + :goto_c5 + move-object/from16 v0, p0 + + iget-boolean v0, v0, LMain2;->b05:Z + + move/from16 v42, v0 + + if-eqz v42, :cond_3b7 + + const/4 v7, 0x0 + + .line 149 + .local v7, "f05":F + :goto_ce + move-object/from16 v0, p0 + + iget-boolean v0, v0, LMain2;->b07:Z + + move/from16 v42, v0 + + if-eqz v42, :cond_3bb + + const/4 v9, 0x0 + + .line 150 + .local v9, "f07":F + :goto_d7 + move-object/from16 v0, p0 + + iget-boolean v0, v0, LMain2;->b06:Z + + move/from16 v42, v0 + + if-eqz v42, :cond_3bf + + const/4 v8, 0x0 + + .line 151 + .local v8, "f06":F + :goto_e0 + move-object/from16 v0, p0 + + iget-boolean v0, v0, LMain2;->b30:Z + + move/from16 v42, v0 + + if-eqz v42, :cond_3c3 + + const/16 v32, 0x0 + + .line 152 + .local v32, "f30":F + :goto_ea + move-object/from16 v0, p0 + + iget-boolean v0, v0, LMain2;->b31:Z + + move/from16 v42, v0 + + if-eqz v42, :cond_3c7 + + const/16 v33, 0x0 + + .line 153 + .local v33, "f31":F + :goto_f4 + move-object/from16 v0, p0 + + iget-boolean v0, v0, LMain2;->b32:Z + + move/from16 v42, v0 + + if-eqz v42, :cond_3cb + + const/16 v34, 0x0 + + .line 154 + .local v34, "f32":F + :goto_fe + move-object/from16 v0, p0 + + iget-boolean v0, v0, LMain2;->b33:Z + + move/from16 v42, v0 + + if-eqz v42, :cond_3cf + + const/16 v35, 0x0 + + .line 155 + .local v35, "f33":F + :goto_108 + move-object/from16 v0, p0 + + iget-boolean v0, v0, LMain2;->b34:Z + + move/from16 v42, v0 + + if-eqz v42, :cond_3d3 + + const/16 v36, 0x0 + + .line 156 + .local v36, "f34":F + :goto_112 + move-object/from16 v0, p0 + + iget-boolean v0, v0, LMain2;->b36:Z + + move/from16 v42, v0 + + if-eqz v42, :cond_3d7 + + const/16 v38, 0x0 + + .line 157 + .local v38, "f36":F + :goto_11c + move-object/from16 v0, p0 + + iget-boolean v0, v0, LMain2;->b35:Z + + move/from16 v42, v0 + + if-eqz v42, :cond_3db + + const/16 v37, 0x0 + + .line 158 + .local v37, "f35":F + :goto_126 + move-object/from16 v0, p0 + + iget-boolean v0, v0, LMain2;->b08:Z + + move/from16 v42, v0 + + if-eqz v42, :cond_3df + + const/4 v10, 0x0 + + .line 159 + .local v10, "f08":F + :goto_12f + move-object/from16 v0, p0 + + iget-boolean v0, v0, LMain2;->b09:Z + + move/from16 v42, v0 + + if-eqz v42, :cond_3e3 + + const/4 v11, 0x0 + + .line 160 + .local v11, "f09":F + :goto_138 + move-object/from16 v0, p0 + + iget-boolean v0, v0, LMain2;->b10:Z + + move/from16 v42, v0 + + if-eqz v42, :cond_3e7 + + const/4 v12, 0x0 + + .line 161 + .local v12, "f10":F + :goto_141 + move-object/from16 v0, p0 + + iget-boolean v0, v0, LMain2;->b11:Z + + move/from16 v42, v0 + + if-eqz v42, :cond_3eb + + const/4 v13, 0x0 + + .line 162 + .local v13, "f11":F + :goto_14a + move-object/from16 v0, p0 + + iget-boolean v0, v0, LMain2;->b12:Z + + move/from16 v42, v0 + + if-eqz v42, :cond_3ef + + const/4 v14, 0x0 + + .line 163 + .local v14, "f12":F + :goto_153 + move-object/from16 v0, p0 + + iget-boolean v0, v0, LMain2;->b14:Z + + move/from16 v42, v0 + + if-eqz v42, :cond_3f3 + + const/16 v16, 0x0 + + .line 164 + .local v16, "f14":F + :goto_15d + move-object/from16 v0, p0 + + iget-boolean v0, v0, LMain2;->b13:Z + + move/from16 v42, v0 + + if-eqz v42, :cond_3f7 + + const/4 v15, 0x0 + + .line 166 + .local v15, "f13":F + :goto_166 + move-object/from16 v0, p0 + + iget-boolean v0, v0, LMain2;->conditionA:Z + + move/from16 v42, v0 + + if-eqz v42, :cond_202 + + .line 167 + const/high16 v42, 0x447a0000 # 1000.0f + + div-float v18, v18, v42 + + .line 168 + const/high16 v42, 0x447a0000 # 1000.0f + + div-float v19, v19, v42 + + .line 169 + const/high16 v42, 0x447a0000 # 1000.0f + + div-float v20, v20, v42 + + .line 170 + const/high16 v42, 0x447a0000 # 1000.0f + + div-float v21, v21, v42 + + .line 171 + const/high16 v42, 0x447a0000 # 1000.0f + + div-float v22, v22, v42 + + .line 172 + const/high16 v42, 0x447a0000 # 1000.0f + + div-float v23, v23, v42 + + .line 173 + const/high16 v42, 0x447a0000 # 1000.0f + + div-float v17, v17, v42 + + .line 174 + const/high16 v42, 0x447a0000 # 1000.0f + + div-float v10, v10, v42 + + .line 175 + const/high16 v42, 0x447a0000 # 1000.0f + + div-float v11, v11, v42 + + .line 176 + const/high16 v42, 0x447a0000 # 1000.0f + + div-float v12, v12, v42 + + .line 177 + const/high16 v42, 0x447a0000 # 1000.0f + + div-float v13, v13, v42 + + .line 178 + const/high16 v42, 0x447a0000 # 1000.0f + + div-float v14, v14, v42 + + .line 179 + const/high16 v42, 0x447a0000 # 1000.0f + + div-float v32, v32, v42 + + .line 180 + const/high16 v42, 0x447a0000 # 1000.0f + + div-float v33, v33, v42 + + .line 181 + const/high16 v42, 0x447a0000 # 1000.0f + + div-float v34, v34, v42 + + .line 182 + const/high16 v42, 0x447a0000 # 1000.0f + + div-float v35, v35, v42 + + .line 183 + const/high16 v42, 0x447a0000 # 1000.0f + + div-float v36, v36, v42 + + .line 184 + const/high16 v42, 0x447a0000 # 1000.0f + + div-float v3, v3, v42 + + .line 185 + const/high16 v42, 0x447a0000 # 1000.0f + + div-float v4, v4, v42 + + .line 186 + const/high16 v42, 0x447a0000 # 1000.0f + + div-float v5, v5, v42 + + .line 187 + const/high16 v42, 0x447a0000 # 1000.0f + + div-float v6, v6, v42 + + .line 188 + const/high16 v42, 0x447a0000 # 1000.0f + + div-float v7, v7, v42 + + .line 189 + const/high16 v42, 0x447a0000 # 1000.0f + + div-float v25, v25, v42 + + .line 190 + const/high16 v42, 0x447a0000 # 1000.0f + + div-float v26, v26, v42 + + .line 191 + const/high16 v42, 0x447a0000 # 1000.0f + + div-float v27, v27, v42 + + .line 192 + const/high16 v42, 0x447a0000 # 1000.0f + + div-float v28, v28, v42 + + .line 193 + const/high16 v42, 0x447a0000 # 1000.0f + + div-float v29, v29, v42 + + .line 194 + const/high16 v42, 0x447a0000 # 1000.0f + + div-float v24, v24, v42 + + .line 195 + const/high16 v42, 0x447a0000 # 1000.0f + + div-float v2, v2, v42 + + .line 196 + const/high16 v42, 0x447a0000 # 1000.0f + + div-float v16, v16, v42 + + .line 197 + const/high16 v42, 0x447a0000 # 1000.0f + + div-float v15, v15, v42 + + .line 198 + const/high16 v42, 0x447a0000 # 1000.0f + + div-float v38, v38, v42 + + .line 199 + const/high16 v42, 0x447a0000 # 1000.0f + + div-float v37, v37, v42 + + .line 200 + const/high16 v42, 0x447a0000 # 1000.0f + + div-float v9, v9, v42 + + .line 201 + const/high16 v42, 0x447a0000 # 1000.0f + + div-float v8, v8, v42 + + .line 202 + const/high16 v42, 0x447a0000 # 1000.0f + + div-float v31, v31, v42 + + .line 203 + const/high16 v42, 0x447a0000 # 1000.0f + + div-float v30, v30, v42 + + .line 209 + :cond_202 + move-object/from16 v0, p0 + + iget-boolean v0, v0, LMain2;->conditionB:Z + + move/from16 v42, v0 + + if-eqz v42, :cond_29e + + .line 210 + const/high16 v42, 0x42c80000 # 100.0f + + div-float v18, v18, v42 + + .line 211 + const/high16 v42, 0x42c80000 # 100.0f + + div-float v19, v19, v42 + + .line 212 + const/high16 v42, 0x42c80000 # 100.0f + + div-float v20, v20, v42 + + .line 213 + const/high16 v42, 0x42c80000 # 100.0f + + div-float v21, v21, v42 + + .line 214 + const/high16 v42, 0x42c80000 # 100.0f + + div-float v22, v22, v42 + + .line 215 + const/high16 v42, 0x42c80000 # 100.0f + + div-float v23, v23, v42 + + .line 216 + const/high16 v42, 0x42c80000 # 100.0f + + div-float v17, v17, v42 + + .line 217 + const/high16 v42, 0x42c80000 # 100.0f + + div-float v10, v10, v42 + + .line 218 + const/high16 v42, 0x42c80000 # 100.0f + + div-float v11, v11, v42 + + .line 219 + const/high16 v42, 0x42c80000 # 100.0f + + div-float v12, v12, v42 + + .line 220 + const/high16 v42, 0x42c80000 # 100.0f + + div-float v13, v13, v42 + + .line 221 + const/high16 v42, 0x42c80000 # 100.0f + + div-float v14, v14, v42 + + .line 222 + const/high16 v42, 0x42c80000 # 100.0f + + div-float v32, v32, v42 + + .line 223 + const/high16 v42, 0x42c80000 # 100.0f + + div-float v33, v33, v42 + + .line 224 + const/high16 v42, 0x42c80000 # 100.0f + + div-float v34, v34, v42 + + .line 225 + const/high16 v42, 0x42c80000 # 100.0f + + div-float v35, v35, v42 + + .line 226 + const/high16 v42, 0x42c80000 # 100.0f + + div-float v36, v36, v42 + + .line 227 + const/high16 v42, 0x42c80000 # 100.0f + + div-float v3, v3, v42 + + .line 228 + const/high16 v42, 0x42c80000 # 100.0f + + div-float v4, v4, v42 + + .line 229 + const/high16 v42, 0x42c80000 # 100.0f + + div-float v5, v5, v42 + + .line 230 + const/high16 v42, 0x42c80000 # 100.0f + + div-float v6, v6, v42 + + .line 231 + const/high16 v42, 0x42c80000 # 100.0f + + div-float v7, v7, v42 + + .line 232 + const/high16 v42, 0x42c80000 # 100.0f + + div-float v25, v25, v42 + + .line 233 + const/high16 v42, 0x42c80000 # 100.0f + + div-float v26, v26, v42 + + .line 234 + const/high16 v42, 0x42c80000 # 100.0f + + div-float v27, v27, v42 + + .line 235 + const/high16 v42, 0x42c80000 # 100.0f + + div-float v28, v28, v42 + + .line 236 + const/high16 v42, 0x42c80000 # 100.0f + + div-float v29, v29, v42 + + .line 237 + const/high16 v42, 0x42c80000 # 100.0f + + div-float v24, v24, v42 + + .line 238 + const/high16 v42, 0x42c80000 # 100.0f + + div-float v2, v2, v42 + + .line 239 + const/high16 v42, 0x42c80000 # 100.0f + + div-float v16, v16, v42 + + .line 240 + const/high16 v42, 0x42c80000 # 100.0f + + div-float v15, v15, v42 + + .line 241 + const/high16 v42, 0x42c80000 # 100.0f + + div-float v38, v38, v42 + + .line 242 + const/high16 v42, 0x42c80000 # 100.0f + + div-float v37, v37, v42 + + .line 243 + const/high16 v42, 0x42c80000 # 100.0f + + div-float v9, v9, v42 + + .line 244 + const/high16 v42, 0x42c80000 # 100.0f + + div-float v8, v8, v42 + + .line 245 + const/high16 v42, 0x42c80000 # 100.0f + + div-float v31, v31, v42 + + .line 246 + const/high16 v42, 0x42c80000 # 100.0f + + div-float v30, v30, v42 + + .line 248 + :cond_29e + move-object/from16 v0, p0 + + iget-boolean v0, v0, LMain2;->conditionC:Z + + move/from16 v42, v0 + + if-eqz v42, :cond_33a + + .line 249 + const/high16 v42, 0x41400000 # 12.0f + + div-float v18, v18, v42 + + .line 250 + const/high16 v42, 0x41400000 # 12.0f + + div-float v19, v19, v42 + + .line 251 + const/high16 v42, 0x41400000 # 12.0f + + div-float v20, v20, v42 + + .line 252 + const/high16 v42, 0x41400000 # 12.0f + + div-float v21, v21, v42 + + .line 253 + const/high16 v42, 0x41400000 # 12.0f + + div-float v22, v22, v42 + + .line 254 + const/high16 v42, 0x41400000 # 12.0f + + div-float v23, v23, v42 + + .line 255 + const/high16 v42, 0x41400000 # 12.0f + + div-float v17, v17, v42 + + .line 256 + const/high16 v42, 0x41400000 # 12.0f + + div-float v10, v10, v42 + + .line 257 + const/high16 v42, 0x41400000 # 12.0f + + div-float v11, v11, v42 + + .line 258 + const/high16 v42, 0x41400000 # 12.0f + + div-float v12, v12, v42 + + .line 259 + const/high16 v42, 0x41400000 # 12.0f + + div-float v13, v13, v42 + + .line 260 + const/high16 v42, 0x41400000 # 12.0f + + div-float v14, v14, v42 + + .line 261 + const/high16 v42, 0x41400000 # 12.0f + + div-float v32, v32, v42 + + .line 262 + const/high16 v42, 0x41400000 # 12.0f + + div-float v33, v33, v42 + + .line 263 + const/high16 v42, 0x41400000 # 12.0f + + div-float v34, v34, v42 + + .line 264 + const/high16 v42, 0x41400000 # 12.0f + + div-float v35, v35, v42 + + .line 265 + const/high16 v42, 0x41400000 # 12.0f + + div-float v36, v36, v42 + + .line 266 + const/high16 v42, 0x41400000 # 12.0f + + div-float v3, v3, v42 + + .line 267 + const/high16 v42, 0x41400000 # 12.0f + + div-float v4, v4, v42 + + .line 268 + const/high16 v42, 0x41400000 # 12.0f + + div-float v5, v5, v42 + + .line 269 + const/high16 v42, 0x41400000 # 12.0f + + div-float v6, v6, v42 + + .line 270 + const/high16 v42, 0x41400000 # 12.0f + + div-float v7, v7, v42 + + .line 271 + const/high16 v42, 0x41400000 # 12.0f + + div-float v25, v25, v42 + + .line 272 + const/high16 v42, 0x41400000 # 12.0f + + div-float v26, v26, v42 + + .line 273 + const/high16 v42, 0x41400000 # 12.0f + + div-float v27, v27, v42 + + .line 274 + const/high16 v42, 0x41400000 # 12.0f + + div-float v28, v28, v42 + + .line 275 + const/high16 v42, 0x41400000 # 12.0f + + div-float v29, v29, v42 + + .line 276 + const/high16 v42, 0x41400000 # 12.0f + + div-float v24, v24, v42 + + .line 277 + const/high16 v42, 0x41400000 # 12.0f + + div-float v2, v2, v42 + + .line 278 + const/high16 v42, 0x41400000 # 12.0f + + div-float v16, v16, v42 + + .line 279 + const/high16 v42, 0x41400000 # 12.0f + + div-float v15, v15, v42 + + .line 280 + const/high16 v42, 0x41400000 # 12.0f + + div-float v38, v38, v42 + + .line 281 + const/high16 v42, 0x41400000 # 12.0f + + div-float v37, v37, v42 + + .line 282 + const/high16 v42, 0x41400000 # 12.0f + + div-float v9, v9, v42 + + .line 283 + const/high16 v42, 0x41400000 # 12.0f + + div-float v8, v8, v42 + + .line 284 + const/high16 v42, 0x41400000 # 12.0f + + div-float v31, v31, v42 + + .line 285 + const/high16 v42, 0x41400000 # 12.0f + + div-float v30, v30, v42 + + .line 287 + :cond_33a + const/16 v41, 0x0 + + .line 288 + .local v41, "s":F + const/high16 v42, 0x42c80000 # 100.0f + + mul-float v42, v42, v41 + + invoke-static/range {v42 .. v42}, Ljava/lang/Math;->round(F)I + + move-result v42 + + move/from16 v0, v42 + + int-to-float v0, v0 + + move/from16 v42, v0 + + const/high16 v43, 0x42c80000 # 100.0f + + div-float v41, v42, v43 + + .line 289 + new-instance v42, Ljava/lang/StringBuilder; + + invoke-direct/range {v42 .. v42}, Ljava/lang/StringBuilder;-><init>()V + + move-object/from16 v0, v42 + + move/from16 v1, v41 + + invoke-virtual {v0, v1}, Ljava/lang/StringBuilder;->append(F)Ljava/lang/StringBuilder; + + move-result-object v42 + + move-object/from16 v0, v42 + + move-object/from16 v1, v39 + + invoke-virtual {v0, v1}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder; + + move-result-object v42 + + invoke-virtual/range {v42 .. v42}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String; + + move-result-object v40 + + .line 290 + .local v40, "res":Ljava/lang/String; + return-void + + .line 128 + .end local v2 # "f00":F + .end local v3 # "f01":F + .end local v4 # "f02":F + .end local v5 # "f03":F + .end local v6 # "f04":F + .end local v7 # "f05":F + .end local v8 # "f06":F + .end local v9 # "f07":F + .end local v10 # "f08":F + .end local v11 # "f09":F + .end local v12 # "f10":F + .end local v13 # "f11":F + .end local v14 # "f12":F + .end local v15 # "f13":F + .end local v16 # "f14":F + .end local v17 # "f15":F + .end local v18 # "f16":F + .end local v19 # "f17":F + .end local v20 # "f18":F + .end local v21 # "f19":F + .end local v22 # "f20":F + .end local v23 # "f21":F + .end local v24 # "f22":F + .end local v25 # "f23":F + .end local v26 # "f24":F + .end local v27 # "f25":F + .end local v28 # "f26":F + .end local v29 # "f27":F + .end local v30 # "f28":F + .end local v31 # "f29":F + .end local v32 # "f30":F + .end local v33 # "f31":F + .end local v34 # "f32":F + .end local v35 # "f33":F + .end local v36 # "f34":F + .end local v37 # "f35":F + .end local v38 # "f36":F + .end local v40 # "res":Ljava/lang/String; + .end local v41 # "s":F + :cond_367 + const/high16 v19, 0x3f800000 # 1.0f + + goto/16 :goto_c + + .line 129 + .restart local v19 # "f17":F + :cond_36b + const/high16 v18, 0x3f800000 # 1.0f + + goto/16 :goto_16 + + .line 130 + .restart local v18 # "f16":F + :cond_36f + const/high16 v20, 0x3f800000 # 1.0f + + goto/16 :goto_20 + + .line 131 + .restart local v20 # "f18":F + :cond_373 + const/high16 v21, 0x3f800000 # 1.0f + + goto/16 :goto_2a + + .line 132 + .restart local v21 # "f19":F + :cond_377 + const/high16 v22, 0x3f800000 # 1.0f + + goto/16 :goto_34 + + .line 133 + .restart local v22 # "f20":F + :cond_37b + const/high16 v23, 0x3f800000 # 1.0f + + goto/16 :goto_3e + + .line 134 + .restart local v23 # "f21":F + :cond_37f + const/high16 v17, 0x3f800000 # 1.0f + + goto/16 :goto_48 + + .line 135 + .restart local v17 # "f15":F + :cond_383 + const/high16 v2, 0x3f800000 # 1.0f + + goto/16 :goto_51 + + .line 136 + .restart local v2 # "f00":F + :cond_387 + const/high16 v24, 0x3f800000 # 1.0f + + goto/16 :goto_5b + + .line 137 + .restart local v24 # "f22":F + :cond_38b + const/high16 v25, 0x3f800000 # 1.0f + + goto/16 :goto_65 + + .line 138 + .restart local v25 # "f23":F + :cond_38f + const/high16 v26, 0x3f800000 # 1.0f + + goto/16 :goto_6f + + .line 139 + .restart local v26 # "f24":F + :cond_393 + const/high16 v27, 0x3f800000 # 1.0f + + goto/16 :goto_79 + + .line 140 + .restart local v27 # "f25":F + :cond_397 + const/high16 v28, 0x3f800000 # 1.0f + + goto/16 :goto_83 + + .line 141 + .restart local v28 # "f26":F + :cond_39b + const/high16 v29, 0x3f800000 # 1.0f + + goto/16 :goto_8d + + .line 142 + .restart local v29 # "f27":F + :cond_39f + const/high16 v31, 0x3f800000 # 1.0f + + goto/16 :goto_97 + + .line 143 + .restart local v31 # "f29":F + :cond_3a3 + const/high16 v30, 0x3f800000 # 1.0f + + goto/16 :goto_a1 + + .line 144 + .restart local v30 # "f28":F + :cond_3a7 + const/high16 v3, 0x3f800000 # 1.0f + + goto/16 :goto_aa + + .line 145 + .restart local v3 # "f01":F + :cond_3ab + const/high16 v4, 0x3f800000 # 1.0f + + goto/16 :goto_b3 + + .line 146 + .restart local v4 # "f02":F + :cond_3af + const/high16 v5, 0x3f800000 # 1.0f + + goto/16 :goto_bc + + .line 147 + .restart local v5 # "f03":F + :cond_3b3 + const/high16 v6, 0x3f800000 # 1.0f + + goto/16 :goto_c5 + + .line 148 + .restart local v6 # "f04":F + :cond_3b7 + const/high16 v7, 0x3f800000 # 1.0f + + goto/16 :goto_ce + + .line 149 + .restart local v7 # "f05":F + :cond_3bb + const/high16 v9, 0x3f800000 # 1.0f + + goto/16 :goto_d7 + + .line 150 + .restart local v9 # "f07":F + :cond_3bf + const/high16 v8, 0x3f800000 # 1.0f + + goto/16 :goto_e0 + + .line 151 + .restart local v8 # "f06":F + :cond_3c3 + const/high16 v32, 0x3f800000 # 1.0f + + goto/16 :goto_ea + + .line 152 + .restart local v32 # "f30":F + :cond_3c7 + const/high16 v33, 0x3f800000 # 1.0f + + goto/16 :goto_f4 + + .line 153 + .restart local v33 # "f31":F + :cond_3cb + const/high16 v34, 0x3f800000 # 1.0f + + goto/16 :goto_fe + + .line 154 + .restart local v34 # "f32":F + :cond_3cf + const/high16 v35, 0x3f800000 # 1.0f + + goto/16 :goto_108 + + .line 155 + .restart local v35 # "f33":F + :cond_3d3 + const/high16 v36, 0x3f800000 # 1.0f + + goto/16 :goto_112 + + .line 156 + .restart local v36 # "f34":F + :cond_3d7 + const/high16 v38, 0x3f800000 # 1.0f + + goto/16 :goto_11c + + .line 157 + .restart local v38 # "f36":F + :cond_3db + const/high16 v37, 0x3f800000 # 1.0f + + goto/16 :goto_126 + + .line 158 + .restart local v37 # "f35":F + :cond_3df + const/high16 v10, 0x3f800000 # 1.0f + + goto/16 :goto_12f + + .line 159 + .restart local v10 # "f08":F + :cond_3e3 + const/high16 v11, 0x3f800000 # 1.0f + + goto/16 :goto_138 + + .line 160 + .restart local v11 # "f09":F + :cond_3e7 + const/high16 v12, 0x3f800000 # 1.0f + + goto/16 :goto_141 + + .line 161 + .restart local v12 # "f10":F + :cond_3eb + const/high16 v13, 0x3f800000 # 1.0f + + goto/16 :goto_14a + + .line 162 + .restart local v13 # "f11":F + :cond_3ef + const/high16 v14, 0x3f800000 # 1.0f + + goto/16 :goto_153 + + .line 163 + .restart local v14 # "f12":F + :cond_3f3 + const/high16 v16, 0x3f800000 # 1.0f + + goto/16 :goto_15d + + .line 164 + .restart local v16 # "f14":F + :cond_3f7 + const/high16 v15, 0x3f800000 # 1.0f + + goto/16 :goto_166 +.end method diff --git a/test/626-checker-arm64-scratch-register/src-art/Main.java b/test/626-checker-arm64-scratch-register/src-art/Main.java new file mode 100644 index 0000000000..b816586c84 --- /dev/null +++ b/test/626-checker-arm64-scratch-register/src-art/Main.java @@ -0,0 +1,23 @@ +/* + * 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. + */ + +public class Main { + public static void main(String[] args) throws Exception { + Class main2 = Class.forName("Main2"); + main2.getMethod("test").invoke(main2.newInstance()); + System.out.println("passed"); + } +} diff --git a/test/626-checker-arm64-scratch-register/src/Main.java b/test/626-checker-arm64-scratch-register/src/Main.java index 139491769e..fa8e5cd1fe 100644 --- a/test/626-checker-arm64-scratch-register/src/Main.java +++ b/test/626-checker-arm64-scratch-register/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,284 +14,9 @@ * limitations under the License. */ +// This file is just for running on the RI as the test is ART specific. public class Main { - - boolean b00; - boolean b01; - boolean b02; - boolean b03; - boolean b04; - boolean b05; - boolean b06; - boolean b07; - boolean b08; - boolean b09; - boolean b10; - boolean b11; - boolean b12; - boolean b13; - boolean b14; - boolean b15; - boolean b16; - boolean b17; - boolean b18; - boolean b19; - boolean b20; - boolean b21; - boolean b22; - boolean b23; - boolean b24; - boolean b25; - boolean b26; - boolean b27; - boolean b28; - boolean b29; - boolean b30; - boolean b31; - boolean b32; - boolean b33; - boolean b34; - boolean b35; - boolean b36; - - boolean conditionA; - boolean conditionB; - boolean conditionC; - - /// CHECK-START-ARM64: void Main.test() register (after) - /// CHECK: begin_block - /// CHECK: name "B0" - /// CHECK: <<This:l\d+>> ParameterValue - /// CHECK: end_block - /// CHECK: begin_block - /// CHECK: successors "<<ThenBlock:B\d+>>" "<<ElseBlock:B\d+>>" - /// CHECK: <<CondB:z\d+>> InstanceFieldGet [<<This>>] field_name:Main.conditionB - /// CHECK: If [<<CondB>>] - /// CHECK: end_block - /// CHECK: begin_block - /// CHECK: name "<<ElseBlock>>" - /// CHECK: ParallelMove moves:[40(sp)->d0,24(sp)->32(sp),28(sp)->36(sp),d0->d3,d3->d4,d2->d5,d4->d6,d5->d7,d6->d18,d7->d19,d18->d20,d19->d21,d20->d22,d21->d23,d22->d10,d23->d11,16(sp)->24(sp),20(sp)->28(sp),d10->d14,d11->d12,d12->d13,d13->d1,d14->d2,32(sp)->16(sp),36(sp)->20(sp)] - /// CHECK: end_block - - /// CHECK-START-ARM64: void Main.test() disassembly (after) - /// CHECK: begin_block - /// CHECK: name "B0" - /// CHECK: <<This:l\d+>> ParameterValue - /// CHECK: end_block - /// CHECK: begin_block - /// CHECK: successors "<<ThenBlock:B\d+>>" "<<ElseBlock:B\d+>>" - /// CHECK: <<CondB:z\d+>> InstanceFieldGet [<<This>>] field_name:Main.conditionB - /// CHECK: If [<<CondB>>] - /// CHECK: end_block - /// CHECK: begin_block - /// CHECK: name "<<ElseBlock>>" - /// CHECK: ParallelMove moves:[invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid] - /// CHECK: fmov d31, d2 - /// CHECK: ldr s2, [sp, #36] - /// CHECK: ldr w16, [sp, #16] - /// CHECK: str w16, [sp, #36] - /// CHECK: str s14, [sp, #16] - /// CHECK: ldr s14, [sp, #28] - /// CHECK: str s1, [sp, #28] - /// CHECK: ldr s1, [sp, #32] - /// CHECK: str s31, [sp, #32] - /// CHECK: ldr s31, [sp, #20] - /// CHECK: str s31, [sp, #40] - /// CHECK: str s12, [sp, #20] - /// CHECK: fmov d12, d11 - /// CHECK: fmov d11, d10 - /// CHECK: fmov d10, d23 - /// CHECK: fmov d23, d22 - /// CHECK: fmov d22, d21 - /// CHECK: fmov d21, d20 - /// CHECK: fmov d20, d19 - /// CHECK: fmov d19, d18 - /// CHECK: fmov d18, d7 - /// CHECK: fmov d7, d6 - /// CHECK: fmov d6, d5 - /// CHECK: fmov d5, d4 - /// CHECK: fmov d4, d3 - /// CHECK: fmov d3, d13 - /// CHECK: ldr s13, [sp, #24] - /// CHECK: str s3, [sp, #24] - /// CHECK: ldr s3, pc+{{\d+}} (addr {{0x[0-9a-f]+}}) (100) - /// CHECK: end_block - - public void test() { - String r = ""; - - // For the purpose of this regression test, the order of - // definition of these float variable matters. Likewise with the - // order of the instructions where these variables are used below. - // Reordering these lines make make the original (b/32545705) - // issue vanish. - float f17 = b17 ? 0.0f : 1.0f; - float f16 = b16 ? 0.0f : 1.0f; - float f18 = b18 ? 0.0f : 1.0f; - float f19 = b19 ? 0.0f : 1.0f; - float f20 = b20 ? 0.0f : 1.0f; - float f21 = b21 ? 0.0f : 1.0f; - float f15 = b15 ? 0.0f : 1.0f; - float f00 = b00 ? 0.0f : 1.0f; - float f22 = b22 ? 0.0f : 1.0f; - float f23 = b23 ? 0.0f : 1.0f; - float f24 = b24 ? 0.0f : 1.0f; - float f25 = b25 ? 0.0f : 1.0f; - float f26 = b26 ? 0.0f : 1.0f; - float f27 = b27 ? 0.0f : 1.0f; - float f29 = b29 ? 0.0f : 1.0f; - float f28 = b28 ? 0.0f : 1.0f; - float f01 = b01 ? 0.0f : 1.0f; - float f02 = b02 ? 0.0f : 1.0f; - float f03 = b03 ? 0.0f : 1.0f; - float f04 = b04 ? 0.0f : 1.0f; - float f05 = b05 ? 0.0f : 1.0f; - float f07 = b07 ? 0.0f : 1.0f; - float f06 = b06 ? 0.0f : 1.0f; - float f30 = b30 ? 0.0f : 1.0f; - float f31 = b31 ? 0.0f : 1.0f; - float f32 = b32 ? 0.0f : 1.0f; - float f33 = b33 ? 0.0f : 1.0f; - float f34 = b34 ? 0.0f : 1.0f; - float f36 = b36 ? 0.0f : 1.0f; - float f35 = b35 ? 0.0f : 1.0f; - float f08 = b08 ? 0.0f : 1.0f; - float f09 = b09 ? 0.0f : 1.0f; - float f10 = b10 ? 0.0f : 1.0f; - float f11 = b11 ? 0.0f : 1.0f; - float f12 = b12 ? 0.0f : 1.0f; - float f14 = b14 ? 0.0f : 1.0f; - float f13 = b13 ? 0.0f : 1.0f; - - if (conditionA) { - f16 /= 1000.0f; - f17 /= 1000.0f; - f18 /= 1000.0f; - f19 /= 1000.0f; - f20 /= 1000.0f; - f21 /= 1000.0f; - f15 /= 1000.0f; - f08 /= 1000.0f; - f09 /= 1000.0f; - f10 /= 1000.0f; - f11 /= 1000.0f; - f12 /= 1000.0f; - f30 /= 1000.0f; - f31 /= 1000.0f; - f32 /= 1000.0f; - f33 /= 1000.0f; - f34 /= 1000.0f; - f01 /= 1000.0f; - f02 /= 1000.0f; - f03 /= 1000.0f; - f04 /= 1000.0f; - f05 /= 1000.0f; - f23 /= 1000.0f; - f24 /= 1000.0f; - f25 /= 1000.0f; - f26 /= 1000.0f; - f27 /= 1000.0f; - f22 /= 1000.0f; - f00 /= 1000.0f; - f14 /= 1000.0f; - f13 /= 1000.0f; - f36 /= 1000.0f; - f35 /= 1000.0f; - f07 /= 1000.0f; - f06 /= 1000.0f; - f29 /= 1000.0f; - f28 /= 1000.0f; - } - // The parallel move that used to exhaust the ARM64 parallel move - // resolver's scratch register pool (provided by VIXL) was in the - // "else" branch of the following condition generated by ART's - // compiler. - if (conditionB) { - f16 /= 100.0f; - f17 /= 100.0f; - f18 /= 100.0f; - f19 /= 100.0f; - f20 /= 100.0f; - f21 /= 100.0f; - f15 /= 100.0f; - f08 /= 100.0f; - f09 /= 100.0f; - f10 /= 100.0f; - f11 /= 100.0f; - f12 /= 100.0f; - f30 /= 100.0f; - f31 /= 100.0f; - f32 /= 100.0f; - f33 /= 100.0f; - f34 /= 100.0f; - f01 /= 100.0f; - f02 /= 100.0f; - f03 /= 100.0f; - f04 /= 100.0f; - f05 /= 100.0f; - f23 /= 100.0f; - f24 /= 100.0f; - f25 /= 100.0f; - f26 /= 100.0f; - f27 /= 100.0f; - f22 /= 100.0f; - f00 /= 100.0f; - f14 /= 100.0f; - f13 /= 100.0f; - f36 /= 100.0f; - f35 /= 100.0f; - f07 /= 100.0f; - f06 /= 100.0f; - f29 /= 100.0f; - f28 /= 100.0f; - } - if (conditionC) { - f16 /= 12.0f; - f17 /= 12.0f; - f18 /= 12.0f; - f19 /= 12.0f; - f20 /= 12.0f; - f21 /= 12.0f; - f15 /= 12.0f; - f08 /= 12.0f; - f09 /= 12.0f; - f10 /= 12.0f; - f11 /= 12.0f; - f12 /= 12.0f; - f30 /= 12.0f; - f31 /= 12.0f; - f32 /= 12.0f; - f33 /= 12.0f; - f34 /= 12.0f; - f01 /= 12.0f; - f02 /= 12.0f; - f03 /= 12.0f; - f04 /= 12.0f; - f05 /= 12.0f; - f23 /= 12.0f; - f24 /= 12.0f; - f25 /= 12.0f; - f26 /= 12.0f; - f27 /= 12.0f; - f22 /= 12.0f; - f00 /= 12.0f; - f14 /= 12.0f; - f13 /= 12.0f; - f36 /= 12.0f; - f35 /= 12.0f; - f07 /= 12.0f; - f06 /= 12.0f; - f29 /= 12.0f; - f28 /= 12.0f; - } - float s = 0.0f; - s = ((float) Math.round(100.0f * s)) / 100.0f; - String res = s + r; - } - public static void main(String[] args) { - Main main = new Main(); - main.test(); System.out.println("passed"); } } 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/679-checker-minmax/src/Main.java b/test/679-checker-minmax/src/Main.java index abf8c279da..4b7265642a 100644 --- a/test/679-checker-minmax/src/Main.java +++ b/test/679-checker-minmax/src/Main.java @@ -37,6 +37,13 @@ public class Main { // /// CHECK-START: int Main.minI(int) instruction_simplifier (after) /// CHECK-NOT: InvokeStaticOrDirect + // + /// CHECK-START-ARM64: int Main.minI(int) disassembly (after) + /// CHECK-NOT: mov {{w\d+}}, #0x14 + /// CHECK: cmp {{w\d+}}, #0x14 + // Check that the constant generation was handled by VIXL. + /// CHECK: mov w16, #0x14 + /// CHECK: csel {{w\d+}}, {{w\d+}}, w16, lt public static int minI(int a) { return Math.min(a, 20); } @@ -55,6 +62,13 @@ public class Main { // /// CHECK-START: long Main.minL(long) instruction_simplifier (after) /// CHECK-NOT: InvokeStaticOrDirect + // + /// CHECK-START-ARM64: long Main.minL(long) disassembly (after) + /// CHECK-NOT: mov {{x\d+}}, #0x14 + /// CHECK: cmp {{x\d+}}, #0x14 + // Check that the constant generation was handled by VIXL. + /// CHECK: mov x16, #0x14 + /// CHECK: csel {{x\d+}}, {{x\d+}}, x16, lt public static long minL(long a) { return Math.min(a, 20L); } @@ -73,6 +87,13 @@ public class Main { // /// CHECK-START: int Main.maxI(int) instruction_simplifier (after) /// CHECK-NOT: InvokeStaticOrDirect + // + /// CHECK-START-ARM64: int Main.maxI(int) disassembly (after) + /// CHECK-NOT: mov {{w\d+}}, #0x14 + /// CHECK: cmp {{w\d+}}, #0x14 + // Check that the constant generation was handled by VIXL. + /// CHECK: mov w16, #0x14 + /// CHECK: csel {{w\d+}}, {{w\d+}}, w16, gt public static int maxI(int a) { return Math.max(a, 20); } @@ -91,11 +112,166 @@ public class Main { // /// CHECK-START: long Main.maxL(long) instruction_simplifier (after) /// CHECK-NOT: InvokeStaticOrDirect + // + /// CHECK-START-ARM64: long Main.maxL(long) disassembly (after) + /// CHECK-NOT: mov {{x\d+}}, #0x14 + /// CHECK: cmp {{x\d+}}, #0x14 + // Check that the constant generation was handled by VIXL. + /// CHECK: mov x16, #0x14 + /// CHECK: csel {{x\d+}}, {{x\d+}}, x16, gt public static long maxL(long a) { return Math.max(a, 20L); } // + // Special Cases + // + + /// CHECK-START-ARM64: int Main.minIntConstantZero(int) disassembly (after) + /// CHECK-NOT: InvokeStaticOrDirect + /// CHECK-NOT: mov {{w\d+}}, #0x0 + /// CHECK: cmp {{w\d+}}, #0x0 (0) + /// CHECK: csel {{w\d+}}, {{w\d+}}, wzr, lt + /// CHECK: ret + public static int minIntConstantZero(int a) { + return Math.min(a, 0); + } + + /// CHECK-START-ARM64: int Main.minIntConstantOne(int) disassembly (after) + /// CHECK-NOT: InvokeStaticOrDirect + /// CHECK-NOT: mov {{w\d+}}, #0x1 + /// CHECK: cmp {{w\d+}}, #0x1 (1) + /// CHECK: csinc {{w\d+}}, {{w\d+}}, wzr, lt + /// CHECK: ret + public static int minIntConstantOne(int a) { + return Math.min(a, 1); + } + + /// CHECK-START-ARM64: int Main.minIntConstantMinusOne(int) disassembly (after) + /// CHECK-NOT: InvokeStaticOrDirect + /// CHECK-NOT: mov {{w\d+}}, #0xffffffff + /// CHECK: cmn {{w\d+}}, #0x1 (1) + /// CHECK: csinv {{w\d+}}, {{w\d+}}, wzr, lt + /// CHECK: ret + public static int minIntConstantMinusOne(int a) { + return Math.min(a, -1); + } + + /// CHECK-START-ARM64: long Main.minLongConstantZero(long) disassembly (after) + /// CHECK-NOT: InvokeStaticOrDirect + /// CHECK-NOT: mov {{x\d+}}, #0x0 + /// CHECK: cmp {{x\d+}}, #0x0 (0) + /// CHECK: csel {{x\d+}}, {{x\d+}}, xzr, lt + /// CHECK: ret + public static long minLongConstantZero(long a) { + return Math.min(a, 0L); + } + + /// CHECK-START-ARM64: long Main.minLongConstantOne(long) disassembly (after) + /// CHECK-NOT: InvokeStaticOrDirect + /// CHECK-NOT: mov {{x\d+}}, #0x1 + /// CHECK: cmp {{x\d+}}, #0x1 (1) + /// CHECK: csinc {{x\d+}}, {{x\d+}}, xzr, lt + /// CHECK: ret + public static long minLongConstantOne(long a) { + return Math.min(a, 1L); + } + + /// CHECK-START-ARM64: long Main.minLongConstantMinusOne(long) disassembly (after) + /// CHECK-NOT: InvokeStaticOrDirect + /// CHECK-NOT: mov {{x\d+}}, #0xffffffffffffffff + /// CHECK: cmn {{x\d+}}, #0x1 (1) + /// CHECK: csinv {{x\d+}}, {{x\d+}}, xzr, lt + /// CHECK: ret + public static long minLongConstantMinusOne(long a) { + return Math.min(a, -1L); + } + + /// CHECK-START-ARM64: int Main.maxIntConstantZero(int) disassembly (after) + /// CHECK-NOT: InvokeStaticOrDirect + /// CHECK-NOT: mov {{w\d+}}, #0x0 + /// CHECK: cmp {{w\d+}}, #0x0 (0) + /// CHECK: csel {{w\d+}}, {{w\d+}}, wzr, gt + /// CHECK: ret + public static int maxIntConstantZero(int a) { + return Math.max(a, 0); + } + + /// CHECK-START-ARM64: int Main.maxIntConstantOne(int) disassembly (after) + /// CHECK-NOT: InvokeStaticOrDirect + /// CHECK-NOT: mov {{w\d+}}, #0x1 + /// CHECK: cmp {{w\d+}}, #0x1 (1) + /// CHECK: csinc {{w\d+}}, {{w\d+}}, wzr, gt + /// CHECK: ret + public static int maxIntConstantOne(int a) { + return Math.max(a, 1); + } + + /// CHECK-START-ARM64: int Main.maxIntConstantMinusOne(int) disassembly (after) + /// CHECK-NOT: InvokeStaticOrDirect + /// CHECK-NOT: mov {{w\d+}}, #0xffffffff + /// CHECK: cmn {{w\d+}}, #0x1 (1) + /// CHECK: csinv {{w\d+}}, {{w\d+}}, wzr, gt + /// CHECK: ret + public static int maxIntConstantMinusOne(int a) { + return Math.max(a, -1); + } + + /// CHECK-START-ARM64: int Main.maxIntLargeConstant(int) disassembly (after) + /// CHECK-NOT: InvokeStaticOrDirect + /// CHECK: mov {{w\d+}}, #0x2001 + /// CHECK: cmp {{w\d+}}, {{w\d+}} + // Check that constant generation was not handled by VIXL. + /// CHECK-NOT: mov {{w\d+}}, #0x2001 + /// CHECK: csel {{w\d+}}, {{w\d+}}, {{w\d+}}, gt + /// CHECK: ret + public static int maxIntLargeConstant(int a) { + return Math.max(a, 8193); + } + + /// CHECK-START-ARM64: long Main.maxLongConstantZero(long) disassembly (after) + /// CHECK-NOT: InvokeStaticOrDirect + /// CHECK-NOT: mov {{x\d+}}, #0x0 + /// CHECK: cmp {{x\d+}}, #0x0 (0) + /// CHECK: csel {{x\d+}}, {{x\d+}}, xzr, gt + /// CHECK: ret + public static long maxLongConstantZero(long a) { + return Math.max(a, 0L); + } + + /// CHECK-START-ARM64: long Main.maxLongConstantOne(long) disassembly (after) + /// CHECK-NOT: InvokeStaticOrDirect + /// CHECK-NOT: mov {{x\d+}}, #0x1 + /// CHECK: cmp {{x\d+}}, #0x1 (1) + /// CHECK: csinc {{x\d+}}, {{x\d+}}, xzr, gt + /// CHECK: ret + public static long maxLongConstantOne(long a) { + return Math.max(a, 1L); + } + + /// CHECK-START-ARM64: long Main.maxLongConstantMinusOne(long) disassembly (after) + /// CHECK-NOT: InvokeStaticOrDirect + /// CHECK-NOT: mov {{x\d+}}, #0xffffffffffffffff + /// CHECK: cmn {{x\d+}}, #0x1 (1) + /// CHECK: csinv {{x\d+}}, {{x\d+}}, xzr, gt + /// CHECK: ret + public static long maxLongConstantMinusOne(long a) { + return Math.max(a, -1L); + } + + /// CHECK-START-ARM64: long Main.maxLongLargeConstant(long) disassembly (after) + /// CHECK-NOT: InvokeStaticOrDirect + /// CHECK: mov {{x\d+}}, #0x2001 + /// CHECK: cmp {{x\d+}}, {{x\d+}} + // Check that constant generation was not handled by VIXL. + /// CHECK-NOT: mov {{x\d+}}, #0x2001 + /// CHECK: csel {{x\d+}}, {{x\d+}}, {{x\d+}}, gt + /// CHECK: ret + public static long maxLongLargeConstant(long a) { + return Math.max(a, 8193L); + } + + // // Different types. // @@ -538,12 +714,40 @@ public class Main { // Intrinsics. expectEquals(10, minI(10)); expectEquals(20, minI(25)); + expectEquals(-1, minIntConstantZero(-1)); + expectEquals(0, minIntConstantZero(1)); + expectEquals(0, minIntConstantOne(0)); + expectEquals(1, minIntConstantOne(2)); + expectEquals(-2, minIntConstantMinusOne(-2)); + expectEquals(-1, minIntConstantMinusOne(0)); expectEquals(10L, minL(10L)); expectEquals(20L, minL(25L)); + expectEquals(-1L, minLongConstantZero(-1L)); + expectEquals(0L, minLongConstantZero(1L)); + expectEquals(0L, minLongConstantOne(0L)); + expectEquals(1L, minLongConstantOne(2L)); + expectEquals(-2L, minLongConstantMinusOne(-2L)); + expectEquals(-1L, minLongConstantMinusOne(0L)); expectEquals(20, maxI(10)); expectEquals(25, maxI(25)); + expectEquals(0, maxIntConstantZero(-1)); + expectEquals(1, maxIntConstantZero(1)); + expectEquals(1, maxIntConstantOne(0)); + expectEquals(2, maxIntConstantOne(2)); + expectEquals(-1, maxIntConstantMinusOne(-2)); + expectEquals(0, maxIntConstantMinusOne(0)); + expectEquals(8193, maxIntLargeConstant(8192)); + expectEquals(9000, maxIntLargeConstant(9000)); expectEquals(20L, maxL(10L)); expectEquals(25L, maxL(25L)); + expectEquals(0L, maxLongConstantZero(-1L)); + expectEquals(1L, maxLongConstantZero(1L)); + expectEquals(1L, maxLongConstantOne(0L)); + expectEquals(2L, maxLongConstantOne(2L)); + expectEquals(-1L, maxLongConstantMinusOne(-2L)); + expectEquals(0L, maxLongConstantMinusOne(0L)); + expectEquals(8193L, maxLongLargeConstant(8192L)); + expectEquals(9000L, maxLongLargeConstant(9000L)); // Types. expectEquals(10, min1(10, 20)); expectEquals(10, min2(10, 20)); 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/teardown-buildbot-device.sh b/tools/teardown-buildbot-device.sh index bf14ca4f9f..d25dd2b15f 100755 --- a/tools/teardown-buildbot-device.sh +++ b/tools/teardown-buildbot-device.sh @@ -25,62 +25,82 @@ adb root adb wait-for-device if [[ -n "$ART_TEST_CHROOT" ]]; then - - # remove_filesystem_from_chroot DIR-IN-CHROOT FSTYPE REMOVE-DIR-IN-CHROOT - # ----------------------------------------------------------------------- - # Unmount filesystem with type FSTYPE mounted in directory DIR-IN-CHROOT - # under the chroot directory. - # Remove DIR-IN-CHROOT under the chroot if REMOVE-DIR-IN-CHROOT is - # true. - remove_filesystem_from_chroot() { - local dir_in_chroot=$1 - local fstype=$2 - local remove_dir=$3 - local dir="$ART_TEST_CHROOT/$dir_in_chroot" - adb shell test -d "$dir" \ - && adb shell mount | grep -q "^$fstype on $dir type $fstype " \ - && if adb shell umount "$dir"; then - $remove_dir && adb shell rmdir "$dir" - else - adb shell lsof "$dir" - fi - } - - # Tear down the chroot dir. - echo -e "${green}Tear down the chroot dir in $ART_TEST_CHROOT${nc}" - # Check that ART_TEST_CHROOT is correctly defined. [[ "x$ART_TEST_CHROOT" = x/* ]] || { echo "$ART_TEST_CHROOT is not an absolute path"; exit 1; } - # Remove /dev from chroot. - remove_filesystem_from_chroot dev tmpfs true - - # Remove /sys/kernel/debug from chroot. - # The /sys/kernel/debug directory under the chroot dir cannot be - # deleted, as it is part of the host device's /sys filesystem. - remove_filesystem_from_chroot sys/kernel/debug debugfs false - # Remove /sys from chroot. - remove_filesystem_from_chroot sys sysfs true - - # Remove /proc from chroot. - remove_filesystem_from_chroot proc proc true - - # Remove /etc from chroot. - adb shell rm -f "$ART_TEST_CHROOT/etc" - adb shell rm -rf "$ART_TEST_CHROOT/system/etc" - - # Remove directories used for ART testing in chroot. - adb shell rm -rf "$ART_TEST_CHROOT/data/local/tmp" - adb shell rm -rf "$ART_TEST_CHROOT/data/dalvik-cache" - adb shell rm -rf "$ART_TEST_CHROOT/tmp" - - # Remove property_contexts file(s) from chroot. - property_context_files="/property_contexts \ - /system/etc/selinux/plat_property_contexts \ - /vendor/etc/selinux/nonplat_property_context \ - /plat_property_contexts \ - /nonplat_property_contexts" - for f in $property_context_files; do - adb shell rm -f "$ART_TEST_CHROOT$f" - done + if adb shell test -d "$ART_TEST_CHROOT"; then + # Display users of the chroot dir. + + 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 + + + # Tear down the chroot dir. + + echo -e "${green}Tear down the chroot set up in $ART_TEST_CHROOT${nc}" + + # remove_filesystem_from_chroot DIR-IN-CHROOT FSTYPE REMOVE-DIR-IN-CHROOT + # ----------------------------------------------------------------------- + # Unmount filesystem with type FSTYPE mounted in directory DIR-IN-CHROOT + # under the chroot directory. + # Remove DIR-IN-CHROOT under the chroot if REMOVE-DIR-IN-CHROOT is + # true. + remove_filesystem_from_chroot() { + local dir_in_chroot=$1 + local fstype=$2 + local remove_dir=$3 + local dir="$ART_TEST_CHROOT/$dir_in_chroot" + adb shell test -d "$dir" \ + && adb shell mount | grep -q "^$fstype on $dir type $fstype " \ + && if adb shell umount "$dir"; then + $remove_dir && adb shell rmdir "$dir" + else + echo "Files still open in $dir:" + adb shell lsof | grep "$dir" + fi + } + + # Remove /dev from chroot. + remove_filesystem_from_chroot dev tmpfs true + + # Remove /sys/kernel/debug from chroot. + # The /sys/kernel/debug directory under the chroot dir cannot be + # deleted, as it is part of the host device's /sys filesystem. + remove_filesystem_from_chroot sys/kernel/debug debugfs false + # Remove /sys from chroot. + remove_filesystem_from_chroot sys sysfs true + + # Remove /proc from chroot. + remove_filesystem_from_chroot proc proc true + + # Remove /etc from chroot. + adb shell rm -f "$ART_TEST_CHROOT/etc" + adb shell rm -rf "$ART_TEST_CHROOT/system/etc" + + # Remove directories used for ART testing in chroot. + adb shell rm -rf "$ART_TEST_CHROOT/data/local/tmp" + adb shell rm -rf "$ART_TEST_CHROOT/data/dalvik-cache" + adb shell rm -rf "$ART_TEST_CHROOT/tmp" + + # Remove property_contexts file(s) from chroot. + property_context_files="/property_contexts \ + /system/etc/selinux/plat_property_contexts \ + /vendor/etc/selinux/nonplat_property_context \ + /plat_property_contexts \ + /nonplat_property_contexts" + for f in $property_context_files; do + adb shell rm -f "$ART_TEST_CHROOT$f" + done + fi fi |