diff options
23 files changed, 748 insertions, 687 deletions
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc index 93d0e5b2bf..672e55ea0b 100644 --- a/compiler/optimizing/code_generator_arm.cc +++ b/compiler/optimizing/code_generator_arm.cc @@ -17,6 +17,7 @@ #include "code_generator_arm.h" #include "arch/arm/instruction_set_features_arm.h" +#include "code_generator_utils.h" #include "entrypoints/quick/quick_entrypoints.h" #include "gc/accounting/card_table.h" #include "intrinsics.h" @@ -2185,11 +2186,134 @@ void InstructionCodeGeneratorARM::VisitMul(HMul* mul) { } } +void InstructionCodeGeneratorARM::DivRemOneOrMinusOne(HBinaryOperation* instruction) { + DCHECK(instruction->IsDiv() || instruction->IsRem()); + DCHECK(instruction->GetResultType() == Primitive::kPrimInt); + + LocationSummary* locations = instruction->GetLocations(); + Location second = locations->InAt(1); + DCHECK(second.IsConstant()); + + Register out = locations->Out().AsRegister<Register>(); + Register dividend = locations->InAt(0).AsRegister<Register>(); + int32_t imm = second.GetConstant()->AsIntConstant()->GetValue(); + DCHECK(imm == 1 || imm == -1); + + if (instruction->IsRem()) { + __ LoadImmediate(out, 0); + } else { + if (imm == 1) { + __ Mov(out, dividend); + } else { + __ rsb(out, dividend, ShifterOperand(0)); + } + } +} + +void InstructionCodeGeneratorARM::DivRemByPowerOfTwo(HBinaryOperation* instruction) { + DCHECK(instruction->IsDiv() || instruction->IsRem()); + DCHECK(instruction->GetResultType() == Primitive::kPrimInt); + + LocationSummary* locations = instruction->GetLocations(); + Location second = locations->InAt(1); + DCHECK(second.IsConstant()); + + Register out = locations->Out().AsRegister<Register>(); + Register dividend = locations->InAt(0).AsRegister<Register>(); + Register temp = locations->GetTemp(0).AsRegister<Register>(); + int32_t imm = second.GetConstant()->AsIntConstant()->GetValue(); + int32_t abs_imm = std::abs(imm); + DCHECK(IsPowerOfTwo(abs_imm)); + int ctz_imm = CTZ(abs_imm); + + if (ctz_imm == 1) { + __ Lsr(temp, dividend, 32 - ctz_imm); + } else { + __ Asr(temp, dividend, 31); + __ Lsr(temp, temp, 32 - ctz_imm); + } + __ add(out, temp, ShifterOperand(dividend)); + + if (instruction->IsDiv()) { + __ Asr(out, out, ctz_imm); + if (imm < 0) { + __ rsb(out, out, ShifterOperand(0)); + } + } else { + __ ubfx(out, out, 0, ctz_imm); + __ sub(out, out, ShifterOperand(temp)); + } +} + +void InstructionCodeGeneratorARM::GenerateDivRemWithAnyConstant(HBinaryOperation* instruction) { + DCHECK(instruction->IsDiv() || instruction->IsRem()); + DCHECK(instruction->GetResultType() == Primitive::kPrimInt); + + LocationSummary* locations = instruction->GetLocations(); + Location second = locations->InAt(1); + DCHECK(second.IsConstant()); + + Register out = locations->Out().AsRegister<Register>(); + Register dividend = locations->InAt(0).AsRegister<Register>(); + Register temp1 = locations->GetTemp(0).AsRegister<Register>(); + Register temp2 = locations->GetTemp(1).AsRegister<Register>(); + int64_t imm = second.GetConstant()->AsIntConstant()->GetValue(); + + int64_t magic; + int shift; + CalculateMagicAndShiftForDivRem(imm, false /* is_long */, &magic, &shift); + + __ LoadImmediate(temp1, magic); + __ smull(temp2, temp1, dividend, temp1); + + if (imm > 0 && magic < 0) { + __ add(temp1, temp1, ShifterOperand(dividend)); + } else if (imm < 0 && magic > 0) { + __ sub(temp1, temp1, ShifterOperand(dividend)); + } + + if (shift != 0) { + __ Asr(temp1, temp1, shift); + } + + if (instruction->IsDiv()) { + __ sub(out, temp1, ShifterOperand(temp1, ASR, 31)); + } else { + __ sub(temp1, temp1, ShifterOperand(temp1, ASR, 31)); + // TODO: Strength reduction for mls. + __ LoadImmediate(temp2, imm); + __ mls(out, temp1, temp2, dividend); + } +} + +void InstructionCodeGeneratorARM::GenerateDivRemConstantIntegral(HBinaryOperation* instruction) { + DCHECK(instruction->IsDiv() || instruction->IsRem()); + DCHECK(instruction->GetResultType() == Primitive::kPrimInt); + + LocationSummary* locations = instruction->GetLocations(); + Location second = locations->InAt(1); + DCHECK(second.IsConstant()); + + int32_t imm = second.GetConstant()->AsIntConstant()->GetValue(); + if (imm == 0) { + // Do not generate anything. DivZeroCheck would prevent any code to be executed. + } else if (imm == 1 || imm == -1) { + DivRemOneOrMinusOne(instruction); + } else if (IsPowerOfTwo(std::abs(imm))) { + DivRemByPowerOfTwo(instruction); + } else { + DCHECK(imm <= -2 || imm >= 2); + GenerateDivRemWithAnyConstant(instruction); + } +} + void LocationsBuilderARM::VisitDiv(HDiv* div) { LocationSummary::CallKind call_kind = LocationSummary::kNoCall; if (div->GetResultType() == Primitive::kPrimLong) { // pLdiv runtime call. call_kind = LocationSummary::kCall; + } else if (div->GetResultType() == Primitive::kPrimInt && div->InputAt(1)->IsConstant()) { + // sdiv will be replaced by other instruction sequence. } else if (div->GetResultType() == Primitive::kPrimInt && !codegen_->GetInstructionSetFeatures().HasDivideInstruction()) { // pIdivmod runtime call. @@ -2200,7 +2324,20 @@ void LocationsBuilderARM::VisitDiv(HDiv* div) { switch (div->GetResultType()) { case Primitive::kPrimInt: { - if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) { + if (div->InputAt(1)->IsConstant()) { + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetInAt(1, Location::RegisterOrConstant(div->InputAt(1))); + locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); + int32_t abs_imm = std::abs(div->InputAt(1)->AsIntConstant()->GetValue()); + if (abs_imm <= 1) { + // No temp register required. + } else { + locations->AddTemp(Location::RequiresRegister()); + if (!IsPowerOfTwo(abs_imm)) { + locations->AddTemp(Location::RequiresRegister()); + } + } + } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) { locations->SetInAt(0, Location::RequiresRegister()); locations->SetInAt(1, Location::RequiresRegister()); locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); @@ -2244,7 +2381,9 @@ void InstructionCodeGeneratorARM::VisitDiv(HDiv* div) { switch (div->GetResultType()) { case Primitive::kPrimInt: { - if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) { + if (second.IsConstant()) { + GenerateDivRemConstantIntegral(div); + } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) { __ sdiv(out.AsRegister<Register>(), first.AsRegister<Register>(), second.AsRegister<Register>()); @@ -2296,8 +2435,11 @@ void LocationsBuilderARM::VisitRem(HRem* rem) { // Most remainders are implemented in the runtime. LocationSummary::CallKind call_kind = LocationSummary::kCall; - if (rem->GetResultType() == Primitive::kPrimInt && - codegen_->GetInstructionSetFeatures().HasDivideInstruction()) { + if (rem->GetResultType() == Primitive::kPrimInt && rem->InputAt(1)->IsConstant()) { + // sdiv will be replaced by other instruction sequence. + call_kind = LocationSummary::kNoCall; + } else if ((rem->GetResultType() == Primitive::kPrimInt) + && codegen_->GetInstructionSetFeatures().HasDivideInstruction()) { // Have hardware divide instruction for int, do it with three instructions. call_kind = LocationSummary::kNoCall; } @@ -2306,7 +2448,20 @@ void LocationsBuilderARM::VisitRem(HRem* rem) { switch (type) { case Primitive::kPrimInt: { - if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) { + if (rem->InputAt(1)->IsConstant()) { + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetInAt(1, Location::RegisterOrConstant(rem->InputAt(1))); + locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); + int32_t abs_imm = std::abs(rem->InputAt(1)->AsIntConstant()->GetValue()); + if (abs_imm <= 1) { + // No temp register required. + } else { + locations->AddTemp(Location::RequiresRegister()); + if (!IsPowerOfTwo(abs_imm)) { + locations->AddTemp(Location::RequiresRegister()); + } + } + } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) { locations->SetInAt(0, Location::RequiresRegister()); locations->SetInAt(1, Location::RequiresRegister()); locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); @@ -2363,7 +2518,9 @@ void InstructionCodeGeneratorARM::VisitRem(HRem* rem) { Primitive::Type type = rem->GetResultType(); switch (type) { case Primitive::kPrimInt: { - if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) { + if (second.IsConstant()) { + GenerateDivRemConstantIntegral(rem); + } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) { Register reg1 = first.AsRegister<Register>(); Register reg2 = second.AsRegister<Register>(); Register temp = locations->GetTemp(0).AsRegister<Register>(); diff --git a/compiler/optimizing/code_generator_arm.h b/compiler/optimizing/code_generator_arm.h index 1a498e1148..2edbcf8ad7 100644 --- a/compiler/optimizing/code_generator_arm.h +++ b/compiler/optimizing/code_generator_arm.h @@ -189,6 +189,10 @@ class InstructionCodeGeneratorARM : public HGraphVisitor { Label* true_target, Label* false_target, Label* always_true_target); + void DivRemOneOrMinusOne(HBinaryOperation* instruction); + void DivRemByPowerOfTwo(HBinaryOperation* instruction); + void GenerateDivRemWithAnyConstant(HBinaryOperation* instruction); + void GenerateDivRemConstantIntegral(HBinaryOperation* instruction); ArmAssembler* const assembler_; CodeGeneratorARM* const codegen_; diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc index 0a0902b0e9..f51ea41ddf 100644 --- a/compiler/optimizing/code_generator_arm64.cc +++ b/compiler/optimizing/code_generator_arm64.cc @@ -17,6 +17,7 @@ #include "code_generator_arm64.h" #include "arch/arm64/instruction_set_features_arm64.h" +#include "code_generator_utils.h" #include "common_arm64.h" #include "entrypoints/quick/quick_entrypoints.h" #include "entrypoints/quick/quick_entrypoints_enum.h" @@ -1603,6 +1604,152 @@ FOR_EACH_CONDITION_INSTRUCTION(DEFINE_CONDITION_VISITORS) #undef DEFINE_CONDITION_VISITORS #undef FOR_EACH_CONDITION_INSTRUCTION +void InstructionCodeGeneratorARM64::DivRemOneOrMinusOne(HBinaryOperation* instruction) { + DCHECK(instruction->IsDiv() || instruction->IsRem()); + + LocationSummary* locations = instruction->GetLocations(); + Location second = locations->InAt(1); + DCHECK(second.IsConstant()); + + Register out = OutputRegister(instruction); + Register dividend = InputRegisterAt(instruction, 0); + int64_t imm = Int64FromConstant(second.GetConstant()); + DCHECK(imm == 1 || imm == -1); + + if (instruction->IsRem()) { + __ Mov(out, 0); + } else { + if (imm == 1) { + __ Mov(out, dividend); + } else { + __ Neg(out, dividend); + } + } +} + +void InstructionCodeGeneratorARM64::DivRemByPowerOfTwo(HBinaryOperation* instruction) { + DCHECK(instruction->IsDiv() || instruction->IsRem()); + + LocationSummary* locations = instruction->GetLocations(); + Location second = locations->InAt(1); + DCHECK(second.IsConstant()); + + Register out = OutputRegister(instruction); + Register dividend = InputRegisterAt(instruction, 0); + int64_t imm = Int64FromConstant(second.GetConstant()); + int64_t abs_imm = std::abs(imm); + DCHECK(IsPowerOfTwo(abs_imm)); + int ctz_imm = CTZ(abs_imm); + + UseScratchRegisterScope temps(GetVIXLAssembler()); + Register temp = temps.AcquireSameSizeAs(out); + + if (instruction->IsDiv()) { + __ Add(temp, dividend, abs_imm - 1); + __ Cmp(dividend, 0); + __ Csel(out, temp, dividend, lt); + if (imm > 0) { + __ Asr(out, out, ctz_imm); + } else { + __ Neg(out, Operand(out, ASR, ctz_imm)); + } + } else { + int bits = instruction->GetResultType() == Primitive::kPrimInt ? 32 : 64; + __ Asr(temp, dividend, bits - 1); + __ Lsr(temp, temp, bits - ctz_imm); + __ Add(out, dividend, temp); + __ And(out, out, abs_imm - 1); + __ Sub(out, out, temp); + } +} + +void InstructionCodeGeneratorARM64::GenerateDivRemWithAnyConstant(HBinaryOperation* instruction) { + DCHECK(instruction->IsDiv() || instruction->IsRem()); + + LocationSummary* locations = instruction->GetLocations(); + Location second = locations->InAt(1); + DCHECK(second.IsConstant()); + + Register out = OutputRegister(instruction); + Register dividend = InputRegisterAt(instruction, 0); + int64_t imm = Int64FromConstant(second.GetConstant()); + + Primitive::Type type = instruction->GetResultType(); + DCHECK(type == Primitive::kPrimInt || type == Primitive::kPrimLong); + + int64_t magic; + int shift; + CalculateMagicAndShiftForDivRem(imm, type == Primitive::kPrimLong /* is_long */, &magic, &shift); + + UseScratchRegisterScope temps(GetVIXLAssembler()); + Register temp = temps.AcquireSameSizeAs(out); + + // temp = get_high(dividend * magic) + __ Mov(temp, magic); + if (type == Primitive::kPrimLong) { + __ Smulh(temp, dividend, temp); + } else { + __ Smull(temp.X(), dividend, temp); + __ Lsr(temp.X(), temp.X(), 32); + } + + if (imm > 0 && magic < 0) { + __ Add(temp, temp, dividend); + } else if (imm < 0 && magic > 0) { + __ Sub(temp, temp, dividend); + } + + if (shift != 0) { + __ Asr(temp, temp, shift); + } + + if (instruction->IsDiv()) { + __ Sub(out, temp, Operand(temp, ASR, type == Primitive::kPrimLong ? 63 : 31)); + } else { + __ Sub(temp, temp, Operand(temp, ASR, type == Primitive::kPrimLong ? 63 : 31)); + // TODO: Strength reduction for msub. + Register temp_imm = temps.AcquireSameSizeAs(out); + __ Mov(temp_imm, imm); + __ Msub(out, temp, temp_imm, dividend); + } +} + +void InstructionCodeGeneratorARM64::GenerateDivRemIntegral(HBinaryOperation* instruction) { + DCHECK(instruction->IsDiv() || instruction->IsRem()); + Primitive::Type type = instruction->GetResultType(); + DCHECK(type == Primitive::kPrimInt || Primitive::kPrimLong); + + LocationSummary* locations = instruction->GetLocations(); + Register out = OutputRegister(instruction); + Location second = locations->InAt(1); + + if (second.IsConstant()) { + int64_t imm = Int64FromConstant(second.GetConstant()); + + if (imm == 0) { + // Do not generate anything. DivZeroCheck would prevent any code to be executed. + } else if (imm == 1 || imm == -1) { + DivRemOneOrMinusOne(instruction); + } else if (IsPowerOfTwo(std::abs(imm))) { + DivRemByPowerOfTwo(instruction); + } else { + DCHECK(imm <= -2 || imm >= 2); + GenerateDivRemWithAnyConstant(instruction); + } + } else { + Register dividend = InputRegisterAt(instruction, 0); + Register divisor = InputRegisterAt(instruction, 1); + if (instruction->IsDiv()) { + __ Sdiv(out, dividend, divisor); + } else { + UseScratchRegisterScope temps(GetVIXLAssembler()); + Register temp = temps.AcquireSameSizeAs(out); + __ Sdiv(temp, dividend, divisor); + __ Msub(out, temp, divisor, dividend); + } + } +} + void LocationsBuilderARM64::VisitDiv(HDiv* div) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(div, LocationSummary::kNoCall); @@ -1610,7 +1757,7 @@ void LocationsBuilderARM64::VisitDiv(HDiv* div) { case Primitive::kPrimInt: case Primitive::kPrimLong: locations->SetInAt(0, Location::RequiresRegister()); - locations->SetInAt(1, Location::RequiresRegister()); + locations->SetInAt(1, Location::RegisterOrConstant(div->InputAt(1))); locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); break; @@ -1631,7 +1778,7 @@ void InstructionCodeGeneratorARM64::VisitDiv(HDiv* div) { switch (type) { case Primitive::kPrimInt: case Primitive::kPrimLong: - __ Sdiv(OutputRegister(div), InputRegisterAt(div, 0), InputRegisterAt(div, 1)); + GenerateDivRemIntegral(div); break; case Primitive::kPrimFloat: @@ -2454,7 +2601,7 @@ void LocationsBuilderARM64::VisitRem(HRem* rem) { case Primitive::kPrimInt: case Primitive::kPrimLong: locations->SetInAt(0, Location::RequiresRegister()); - locations->SetInAt(1, Location::RequiresRegister()); + locations->SetInAt(1, Location::RegisterOrConstant(rem->InputAt(1))); locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); break; @@ -2479,14 +2626,7 @@ void InstructionCodeGeneratorARM64::VisitRem(HRem* rem) { switch (type) { case Primitive::kPrimInt: case Primitive::kPrimLong: { - UseScratchRegisterScope temps(GetVIXLAssembler()); - Register dividend = InputRegisterAt(rem, 0); - Register divisor = InputRegisterAt(rem, 1); - Register output = OutputRegister(rem); - Register temp = temps.AcquireSameSizeAs(output); - - __ Sdiv(temp, dividend, divisor); - __ Msub(output, temp, divisor, dividend); + GenerateDivRemIntegral(rem); break; } diff --git a/compiler/optimizing/code_generator_arm64.h b/compiler/optimizing/code_generator_arm64.h index 8aeea5400f..0dc0918c5e 100644 --- a/compiler/optimizing/code_generator_arm64.h +++ b/compiler/optimizing/code_generator_arm64.h @@ -163,6 +163,11 @@ class InstructionCodeGeneratorARM64 : public HGraphVisitor { vixl::Label* true_target, vixl::Label* false_target, vixl::Label* always_true_target); + void DivRemOneOrMinusOne(HBinaryOperation* instruction); + void DivRemByPowerOfTwo(HBinaryOperation* instruction); + void GenerateDivRemWithAnyConstant(HBinaryOperation* instruction); + void GenerateDivRemIntegral(HBinaryOperation* instruction); + Arm64Assembler* const assembler_; CodeGeneratorARM64* const codegen_; diff --git a/compiler/utils/arm/assembler_arm.h b/compiler/utils/arm/assembler_arm.h index 313f365df6..dee8287e67 100644 --- a/compiler/utils/arm/assembler_arm.h +++ b/compiler/utils/arm/assembler_arm.h @@ -398,6 +398,8 @@ class ArmAssembler : public Assembler { Condition cond = AL) = 0; virtual void mls(Register rd, Register rn, Register rm, Register ra, Condition cond = AL) = 0; + virtual void smull(Register rd_lo, Register rd_hi, Register rn, Register rm, + Condition cond = AL) = 0; virtual void umull(Register rd_lo, Register rd_hi, Register rn, Register rm, Condition cond = AL) = 0; diff --git a/compiler/utils/arm/assembler_arm32.cc b/compiler/utils/arm/assembler_arm32.cc index 95796916b4..6e165fc151 100644 --- a/compiler/utils/arm/assembler_arm32.cc +++ b/compiler/utils/arm/assembler_arm32.cc @@ -200,6 +200,13 @@ void Arm32Assembler::mls(Register rd, Register rn, Register rm, Register ra, } +void Arm32Assembler::smull(Register rd_lo, Register rd_hi, Register rn, + Register rm, Condition cond) { + // Assembler registers rd_lo, rd_hi, rn, rm are encoded as rd, rn, rm, rs. + EmitMulOp(cond, B23 | B22, rd_lo, rd_hi, rn, rm); +} + + void Arm32Assembler::umull(Register rd_lo, Register rd_hi, Register rn, Register rm, Condition cond) { // Assembler registers rd_lo, rd_hi, rn, rm are encoded as rd, rn, rm, rs. diff --git a/compiler/utils/arm/assembler_arm32.h b/compiler/utils/arm/assembler_arm32.h index b922d66513..55ec7b46d8 100644 --- a/compiler/utils/arm/assembler_arm32.h +++ b/compiler/utils/arm/assembler_arm32.h @@ -90,6 +90,8 @@ class Arm32Assembler FINAL : public ArmAssembler { Condition cond = AL) OVERRIDE; void mls(Register rd, Register rn, Register rm, Register ra, Condition cond = AL) OVERRIDE; + void smull(Register rd_lo, Register rd_hi, Register rn, Register rm, + Condition cond = AL) OVERRIDE; void umull(Register rd_lo, Register rd_hi, Register rn, Register rm, Condition cond = AL) OVERRIDE; diff --git a/compiler/utils/arm/assembler_arm32_test.cc b/compiler/utils/arm/assembler_arm32_test.cc index 4a0ae0ba99..efd517b83a 100644 --- a/compiler/utils/arm/assembler_arm32_test.cc +++ b/compiler/utils/arm/assembler_arm32_test.cc @@ -293,12 +293,29 @@ class AssemblerArm32Test : public AssemblerArmTest<arm::Arm32Assembler, f(); } + // NOTE: Only support simple test like "aaa=bbb" + bool EvalFilterString(std::string filter) { + if (filter.compare("") == 0) { + return false; + } + + size_t equal_sign_index = filter.find('='); + if (equal_sign_index == std::string::npos) { + EXPECT_TRUE(false) << "Unsupported filter string."; + } + + std::string lhs = filter.substr(0, equal_sign_index); + std::string rhs = filter.substr(equal_sign_index + 1, std::string::npos); + return lhs.compare(rhs) == 0; + } + void TemplateHelper(std::function<void(arm::Register)> f, int depth ATTRIBUTE_UNUSED, - bool without_pc, - std::string fmt, std::ostringstream& oss) { + bool without_pc, std::string fmt, std::string filter, + std::ostringstream& oss) { std::vector<arm::Register*> registers = without_pc ? GetRegistersWithoutPC() : GetRegisters(); for (auto reg : registers) { std::string after_reg = fmt; + std::string after_reg_filter = filter; std::string reg_string = GetRegName<RegisterView::kUsePrimaryName>(*reg); size_t reg_index; @@ -308,14 +325,23 @@ class AssemblerArm32Test : public AssemblerArmTest<arm::Arm32Assembler, after_reg.replace(reg_index, strlen(reg_token), reg_string); } + while ((reg_index = after_reg_filter.find(reg_token)) != std::string::npos) { + after_reg_filter.replace(reg_index, strlen(reg_token), reg_string); + } + if (EvalFilterString(after_reg_filter)) { + continue; + } + ExecuteAndPrint([&] () { f(*reg); }, after_reg, oss); } } void TemplateHelper(std::function<void(const arm::ShifterOperand&)> f, int depth ATTRIBUTE_UNUSED, - bool without_pc ATTRIBUTE_UNUSED, std::string fmt, std::ostringstream& oss) { + bool without_pc ATTRIBUTE_UNUSED, std::string fmt, std::string filter, + std::ostringstream& oss) { for (const arm::ShifterOperand& shift : GetShiftOperands()) { std::string after_shift = fmt; + std::string after_shift_filter = filter; std::string shift_string = GetShiftString(shift); size_t shift_index; @@ -323,30 +349,48 @@ class AssemblerArm32Test : public AssemblerArmTest<arm::Arm32Assembler, after_shift.replace(shift_index, ConstexprStrLen(SHIFT_TOKEN), shift_string); } + while ((shift_index = after_shift_filter.find(SHIFT_TOKEN)) != std::string::npos) { + after_shift_filter.replace(shift_index, ConstexprStrLen(SHIFT_TOKEN), shift_string); + } + if (EvalFilterString(after_shift_filter)) { + continue; + } + ExecuteAndPrint([&] () { f(shift); }, after_shift, oss); } } void TemplateHelper(std::function<void(arm::Condition)> f, int depth ATTRIBUTE_UNUSED, - bool without_pc ATTRIBUTE_UNUSED, std::string fmt, std::ostringstream& oss) { + bool without_pc ATTRIBUTE_UNUSED, std::string fmt, std::string filter, + std::ostringstream& oss) { for (arm::Condition c : GetConditions()) { std::string after_cond = fmt; + std::string after_cond_filter = filter; size_t cond_index = after_cond.find(COND_TOKEN); if (cond_index != std::string::npos) { after_cond.replace(cond_index, ConstexprStrLen(IMM1_TOKEN), GetConditionString(c)); } + cond_index = after_cond_filter.find(COND_TOKEN); + if (cond_index != std::string::npos) { + after_cond_filter.replace(cond_index, ConstexprStrLen(IMM1_TOKEN), GetConditionString(c)); + } + if (EvalFilterString(after_cond_filter)) { + continue; + } + ExecuteAndPrint([&] () { f(c); }, after_cond, oss); } } template <typename... Args> void TemplateHelper(std::function<void(arm::Register, Args...)> f, int depth, bool without_pc, - std::string fmt, std::ostringstream& oss) { + std::string fmt, std::string filter, std::ostringstream& oss) { std::vector<arm::Register*> registers = without_pc ? GetRegistersWithoutPC() : GetRegisters(); for (auto reg : registers) { std::string after_reg = fmt; + std::string after_reg_filter = filter; std::string reg_string = GetRegName<RegisterView::kUsePrimaryName>(*reg); size_t reg_index; @@ -356,17 +400,26 @@ class AssemblerArm32Test : public AssemblerArmTest<arm::Arm32Assembler, after_reg.replace(reg_index, strlen(reg_token), reg_string); } + while ((reg_index = after_reg_filter.find(reg_token)) != std::string::npos) { + after_reg_filter.replace(reg_index, strlen(reg_token), reg_string); + } + if (EvalFilterString(after_reg_filter)) { + continue; + } + auto lambda = [&] (Args... args) { f(*reg, args...); }; // NOLINT [readability/braces] [4] TemplateHelper(std::function<void(Args...)>(lambda), depth + 1, without_pc, - after_reg, oss); + after_reg, after_reg_filter, oss); } } template <typename... Args> void TemplateHelper(std::function<void(const arm::ShifterOperand&, Args...)> f, int depth, - bool without_pc, std::string fmt, std::ostringstream& oss) { + bool without_pc, std::string fmt, std::string filter, + std::ostringstream& oss) { for (const arm::ShifterOperand& shift : GetShiftOperands()) { std::string after_shift = fmt; + std::string after_shift_filter = filter; std::string shift_string = GetShiftString(shift); size_t shift_index; @@ -374,26 +427,42 @@ class AssemblerArm32Test : public AssemblerArmTest<arm::Arm32Assembler, after_shift.replace(shift_index, ConstexprStrLen(SHIFT_TOKEN), shift_string); } + while ((shift_index = after_shift_filter.find(SHIFT_TOKEN)) != std::string::npos) { + after_shift_filter.replace(shift_index, ConstexprStrLen(SHIFT_TOKEN), shift_string); + } + if (EvalFilterString(after_shift_filter)) { + continue; + } + auto lambda = [&] (Args... args) { f(shift, args...); }; // NOLINT [readability/braces] [4] TemplateHelper(std::function<void(Args...)>(lambda), depth, without_pc, - after_shift, oss); + after_shift, after_shift_filter, oss); } } template <typename... Args> void TemplateHelper(std::function<void(arm::Condition, Args...)> f, int depth, bool without_pc, - std::string fmt, std::ostringstream& oss) { + std::string fmt, std::string filter, std::ostringstream& oss) { for (arm::Condition c : GetConditions()) { std::string after_cond = fmt; + std::string after_cond_filter = filter; size_t cond_index = after_cond.find(COND_TOKEN); if (cond_index != std::string::npos) { after_cond.replace(cond_index, ConstexprStrLen(IMM1_TOKEN), GetConditionString(c)); } + cond_index = after_cond_filter.find(COND_TOKEN); + if (cond_index != std::string::npos) { + after_cond_filter.replace(cond_index, ConstexprStrLen(IMM1_TOKEN), GetConditionString(c)); + } + if (EvalFilterString(after_cond_filter)) { + continue; + } + auto lambda = [&] (Args... args) { f(c, args...); }; // NOLINT [readability/braces] [4] TemplateHelper(std::function<void(Args...)>(lambda), depth, without_pc, - after_cond, oss); + after_cond, after_cond_filter, oss); } } @@ -421,13 +490,13 @@ class AssemblerArm32Test : public AssemblerArmTest<arm::Arm32Assembler, template <typename... Args> void GenericTemplateHelper(std::function<void(Args...)> f, bool without_pc, - std::string fmt, std::string test_name) { + std::string fmt, std::string test_name, std::string filter) { first_ = false; WarnOnCombinations(CountHelper<Args...>(without_pc)); std::ostringstream oss; - TemplateHelper(f, 0, without_pc, fmt, oss); + TemplateHelper(f, 0, without_pc, fmt, filter, oss); oss << "\n"; // Trailing newline. @@ -436,26 +505,26 @@ class AssemblerArm32Test : public AssemblerArmTest<arm::Arm32Assembler, template <typename... Args> void T2Helper(void (arm::Arm32Assembler::*f)(Args...), bool without_pc, std::string fmt, - std::string test_name) { - GenericTemplateHelper(GetBoundFunction2(f), without_pc, fmt, test_name); + std::string test_name, std::string filter = "") { + GenericTemplateHelper(GetBoundFunction2(f), without_pc, fmt, test_name, filter); } template <typename... Args> void T3Helper(void (arm::Arm32Assembler::*f)(Args...), bool without_pc, std::string fmt, - std::string test_name) { - GenericTemplateHelper(GetBoundFunction3(f), without_pc, fmt, test_name); + std::string test_name, std::string filter = "") { + GenericTemplateHelper(GetBoundFunction3(f), without_pc, fmt, test_name, filter); } template <typename... Args> void T4Helper(void (arm::Arm32Assembler::*f)(Args...), bool without_pc, std::string fmt, - std::string test_name) { - GenericTemplateHelper(GetBoundFunction4(f), without_pc, fmt, test_name); + std::string test_name, std::string filter = "") { + GenericTemplateHelper(GetBoundFunction4(f), without_pc, fmt, test_name, filter); } template <typename... Args> void T5Helper(void (arm::Arm32Assembler::*f)(Args...), bool without_pc, std::string fmt, - std::string test_name) { - GenericTemplateHelper(GetBoundFunction5(f), without_pc, fmt, test_name); + std::string test_name, std::string filter = "") { + GenericTemplateHelper(GetBoundFunction5(f), without_pc, fmt, test_name, filter); } private: @@ -565,15 +634,18 @@ TEST_F(AssemblerArm32Test, Mul) { } TEST_F(AssemblerArm32Test, Mla) { - T5Helper(&arm::Arm32Assembler::mla, true, "mla{cond} {reg1}, {reg2}, {reg3}, {reg4}", "mul"); + T5Helper(&arm::Arm32Assembler::mla, true, "mla{cond} {reg1}, {reg2}, {reg3}, {reg4}", "mla"); } -/* TODO: Needs support to filter out register combinations, as rdhi must not be equal to rdlo. TEST_F(AssemblerArm32Test, Umull) { T5Helper(&arm::Arm32Assembler::umull, true, "umull{cond} {reg1}, {reg2}, {reg3}, {reg4}", - "umull"); + "umull", "{reg1}={reg2}"); // Skip the cases where reg1 == reg2. +} + +TEST_F(AssemblerArm32Test, Smull) { + T5Helper(&arm::Arm32Assembler::smull, true, "smull{cond} {reg1}, {reg2}, {reg3}, {reg4}", + "smull", "{reg1}={reg2}"); // Skip the cases where reg1 == reg2. } -*/ TEST_F(AssemblerArm32Test, Sdiv) { T4Helper(&arm::Arm32Assembler::sdiv, true, "sdiv{cond} {reg1}, {reg2}, {reg3}", "sdiv"); @@ -655,9 +727,10 @@ TEST_F(AssemblerArm32Test, Rsc) { T4Helper(&arm::Arm32Assembler::rsc, true, "rsc{cond} {reg1}, {reg2}, {shift}", "rsc"); } -/* TODO: Needs support to filter out register combinations, as reg1 must not be equal to reg3. +/* TODO: Need better filter support. TEST_F(AssemblerArm32Test, Strex) { - RRRCWithoutPCHelper(&arm::Arm32Assembler::strex, "strex{cond} {reg1}, {reg2}, [{reg3}]", "strex"); + T4Helper(&arm::Arm32Assembler::strex, "strex{cond} {reg1}, {reg2}, [{reg3}]", "strex", + "{reg1}={reg2}||{reg1}={reg3}"); // Skip the cases where reg1 == reg2 || reg1 == reg3. } */ diff --git a/compiler/utils/arm/assembler_thumb2.cc b/compiler/utils/arm/assembler_thumb2.cc index 3b42f63509..e7cf26eee2 100644 --- a/compiler/utils/arm/assembler_thumb2.cc +++ b/compiler/utils/arm/assembler_thumb2.cc @@ -238,6 +238,24 @@ void Thumb2Assembler::mls(Register rd, Register rn, Register rm, Register ra, } +void Thumb2Assembler::smull(Register rd_lo, Register rd_hi, Register rn, + Register rm, Condition cond) { + CheckCondition(cond); + + uint32_t op1 = 0U /* 0b000; */; + uint32_t op2 = 0U /* 0b0000 */; + int32_t encoding = B31 | B30 | B29 | B28 | B27 | B25 | B24 | B23 | + op1 << 20 | + op2 << 4 | + static_cast<uint32_t>(rd_lo) << 12 | + static_cast<uint32_t>(rd_hi) << 8 | + static_cast<uint32_t>(rn) << 16 | + static_cast<uint32_t>(rm); + + Emit32(encoding); +} + + void Thumb2Assembler::umull(Register rd_lo, Register rd_hi, Register rn, Register rm, Condition cond) { CheckCondition(cond); @@ -740,13 +758,6 @@ bool Thumb2Assembler::Is32BitDataProcessing(Condition cond ATTRIBUTE_UNUSED, return true; } - // Check for MOV with an ROR. - if (opcode == MOV && so.IsRegister() && so.IsShift() && so.GetShift() == ROR) { - if (so.GetImmediate() != 0) { - return true; - } - } - bool rn_is_valid = true; // Check for single operand instructions and ADD/SUB. @@ -792,6 +803,19 @@ bool Thumb2Assembler::Is32BitDataProcessing(Condition cond ATTRIBUTE_UNUSED, } } + // Check for register shift operand. + if (so.IsRegister() && so.IsShift()) { + if (opcode != MOV) { + return true; + } + // Check for MOV with an ROR. + if (so.GetShift() == ROR) { + if (so.GetImmediate() != 0) { + return true; + } + } + } + // The instruction can be encoded in 16 bits. return false; } diff --git a/compiler/utils/arm/assembler_thumb2.h b/compiler/utils/arm/assembler_thumb2.h index e33c240dbf..17eae8be0c 100644 --- a/compiler/utils/arm/assembler_thumb2.h +++ b/compiler/utils/arm/assembler_thumb2.h @@ -112,6 +112,8 @@ class Thumb2Assembler FINAL : public ArmAssembler { Condition cond = AL) OVERRIDE; void mls(Register rd, Register rn, Register rm, Register ra, Condition cond = AL) OVERRIDE; + void smull(Register rd_lo, Register rd_hi, Register rn, Register rm, + Condition cond = AL) OVERRIDE; void umull(Register rd_lo, Register rd_hi, Register rn, Register rm, Condition cond = AL) OVERRIDE; diff --git a/compiler/utils/arm/assembler_thumb2_test.cc b/compiler/utils/arm/assembler_thumb2_test.cc index 5f5561a499..733441b889 100644 --- a/compiler/utils/arm/assembler_thumb2_test.cc +++ b/compiler/utils/arm/assembler_thumb2_test.cc @@ -89,23 +89,24 @@ TEST_F(AssemblerThumb2Test, Toolchain) { EXPECT_TRUE(CheckTools()); } +#define __ GetAssembler()-> TEST_F(AssemblerThumb2Test, Sbfx) { - GetAssembler()->sbfx(arm::R0, arm::R1, 0, 1); - GetAssembler()->sbfx(arm::R0, arm::R1, 0, 8); - GetAssembler()->sbfx(arm::R0, arm::R1, 0, 16); - GetAssembler()->sbfx(arm::R0, arm::R1, 0, 32); + __ sbfx(arm::R0, arm::R1, 0, 1); + __ sbfx(arm::R0, arm::R1, 0, 8); + __ sbfx(arm::R0, arm::R1, 0, 16); + __ sbfx(arm::R0, arm::R1, 0, 32); - GetAssembler()->sbfx(arm::R0, arm::R1, 8, 1); - GetAssembler()->sbfx(arm::R0, arm::R1, 8, 8); - GetAssembler()->sbfx(arm::R0, arm::R1, 8, 16); - GetAssembler()->sbfx(arm::R0, arm::R1, 8, 24); + __ sbfx(arm::R0, arm::R1, 8, 1); + __ sbfx(arm::R0, arm::R1, 8, 8); + __ sbfx(arm::R0, arm::R1, 8, 16); + __ sbfx(arm::R0, arm::R1, 8, 24); - GetAssembler()->sbfx(arm::R0, arm::R1, 16, 1); - GetAssembler()->sbfx(arm::R0, arm::R1, 16, 8); - GetAssembler()->sbfx(arm::R0, arm::R1, 16, 16); + __ sbfx(arm::R0, arm::R1, 16, 1); + __ sbfx(arm::R0, arm::R1, 16, 8); + __ sbfx(arm::R0, arm::R1, 16, 16); - GetAssembler()->sbfx(arm::R0, arm::R1, 31, 1); + __ sbfx(arm::R0, arm::R1, 31, 1); const char* expected = "sbfx r0, r1, #0, #1\n" @@ -127,21 +128,21 @@ TEST_F(AssemblerThumb2Test, Sbfx) { } TEST_F(AssemblerThumb2Test, Ubfx) { - GetAssembler()->ubfx(arm::R0, arm::R1, 0, 1); - GetAssembler()->ubfx(arm::R0, arm::R1, 0, 8); - GetAssembler()->ubfx(arm::R0, arm::R1, 0, 16); - GetAssembler()->ubfx(arm::R0, arm::R1, 0, 32); + __ ubfx(arm::R0, arm::R1, 0, 1); + __ ubfx(arm::R0, arm::R1, 0, 8); + __ ubfx(arm::R0, arm::R1, 0, 16); + __ ubfx(arm::R0, arm::R1, 0, 32); - GetAssembler()->ubfx(arm::R0, arm::R1, 8, 1); - GetAssembler()->ubfx(arm::R0, arm::R1, 8, 8); - GetAssembler()->ubfx(arm::R0, arm::R1, 8, 16); - GetAssembler()->ubfx(arm::R0, arm::R1, 8, 24); + __ ubfx(arm::R0, arm::R1, 8, 1); + __ ubfx(arm::R0, arm::R1, 8, 8); + __ ubfx(arm::R0, arm::R1, 8, 16); + __ ubfx(arm::R0, arm::R1, 8, 24); - GetAssembler()->ubfx(arm::R0, arm::R1, 16, 1); - GetAssembler()->ubfx(arm::R0, arm::R1, 16, 8); - GetAssembler()->ubfx(arm::R0, arm::R1, 16, 16); + __ ubfx(arm::R0, arm::R1, 16, 1); + __ ubfx(arm::R0, arm::R1, 16, 8); + __ ubfx(arm::R0, arm::R1, 16, 16); - GetAssembler()->ubfx(arm::R0, arm::R1, 31, 1); + __ ubfx(arm::R0, arm::R1, 31, 1); const char* expected = "ubfx r0, r1, #0, #1\n" @@ -163,7 +164,7 @@ TEST_F(AssemblerThumb2Test, Ubfx) { } TEST_F(AssemblerThumb2Test, Vmstat) { - GetAssembler()->vmstat(); + __ vmstat(); const char* expected = "vmrs APSR_nzcv, FPSCR\n"; @@ -171,10 +172,10 @@ TEST_F(AssemblerThumb2Test, Vmstat) { } TEST_F(AssemblerThumb2Test, ldrexd) { - GetAssembler()->ldrexd(arm::R0, arm::R1, arm::R0); - GetAssembler()->ldrexd(arm::R0, arm::R1, arm::R1); - GetAssembler()->ldrexd(arm::R0, arm::R1, arm::R2); - GetAssembler()->ldrexd(arm::R5, arm::R3, arm::R7); + __ ldrexd(arm::R0, arm::R1, arm::R0); + __ ldrexd(arm::R0, arm::R1, arm::R1); + __ ldrexd(arm::R0, arm::R1, arm::R2); + __ ldrexd(arm::R5, arm::R3, arm::R7); const char* expected = "ldrexd r0, r1, [r0]\n" @@ -185,10 +186,10 @@ TEST_F(AssemblerThumb2Test, ldrexd) { } TEST_F(AssemblerThumb2Test, strexd) { - GetAssembler()->strexd(arm::R9, arm::R0, arm::R1, arm::R0); - GetAssembler()->strexd(arm::R9, arm::R0, arm::R1, arm::R1); - GetAssembler()->strexd(arm::R9, arm::R0, arm::R1, arm::R2); - GetAssembler()->strexd(arm::R9, arm::R5, arm::R3, arm::R7); + __ strexd(arm::R9, arm::R0, arm::R1, arm::R0); + __ strexd(arm::R9, arm::R0, arm::R1, arm::R1); + __ strexd(arm::R9, arm::R0, arm::R1, arm::R2); + __ strexd(arm::R9, arm::R5, arm::R3, arm::R7); const char* expected = "strexd r9, r0, r1, [r0]\n" @@ -199,9 +200,9 @@ TEST_F(AssemblerThumb2Test, strexd) { } TEST_F(AssemblerThumb2Test, LdrdStrd) { - GetAssembler()->ldrd(arm::R0, arm::Address(arm::R2, 8)); - GetAssembler()->ldrd(arm::R0, arm::Address(arm::R12)); - GetAssembler()->strd(arm::R0, arm::Address(arm::R2, 8)); + __ ldrd(arm::R0, arm::Address(arm::R2, 8)); + __ ldrd(arm::R0, arm::Address(arm::R12)); + __ strd(arm::R0, arm::Address(arm::R2, 8)); const char* expected = "ldrd r0, r1, [r2, #8]\n" @@ -211,7 +212,6 @@ TEST_F(AssemblerThumb2Test, LdrdStrd) { } TEST_F(AssemblerThumb2Test, eor) { -#define __ GetAssembler()-> __ eor(arm::R1, arm::R1, arm::ShifterOperand(arm::R0)); __ eor(arm::R1, arm::R0, arm::ShifterOperand(arm::R1)); __ eor(arm::R1, arm::R8, arm::ShifterOperand(arm::R0)); @@ -230,23 +230,47 @@ TEST_F(AssemblerThumb2Test, eor) { TEST_F(AssemblerThumb2Test, sub) { __ subs(arm::R1, arm::R0, arm::ShifterOperand(42)); __ sub(arm::R1, arm::R0, arm::ShifterOperand(42)); + __ subs(arm::R1, arm::R0, arm::ShifterOperand(arm::R2, arm::ASR, 31)); + __ sub(arm::R1, arm::R0, arm::ShifterOperand(arm::R2, arm::ASR, 31)); const char* expected = "subs r1, r0, #42\n" - "subw r1, r0, #42\n"; + "subw r1, r0, #42\n" + "subs r1, r0, r2, asr #31\n" + "sub r1, r0, r2, asr #31\n"; DriverStr(expected, "sub"); } TEST_F(AssemblerThumb2Test, add) { __ adds(arm::R1, arm::R0, arm::ShifterOperand(42)); __ add(arm::R1, arm::R0, arm::ShifterOperand(42)); + __ adds(arm::R1, arm::R0, arm::ShifterOperand(arm::R2, arm::ASR, 31)); + __ add(arm::R1, arm::R0, arm::ShifterOperand(arm::R2, arm::ASR, 31)); const char* expected = "adds r1, r0, #42\n" - "addw r1, r0, #42\n"; + "addw r1, r0, #42\n" + "adds r1, r0, r2, asr #31\n" + "add r1, r0, r2, asr #31\n"; DriverStr(expected, "add"); } +TEST_F(AssemblerThumb2Test, umull) { + __ umull(arm::R0, arm::R1, arm::R2, arm::R3); + + const char* expected = + "umull r0, r1, r2, r3\n"; + DriverStr(expected, "umull"); +} + +TEST_F(AssemblerThumb2Test, smull) { + __ smull(arm::R0, arm::R1, arm::R2, arm::R3); + + const char* expected = + "smull r0, r1, r2, r3\n"; + DriverStr(expected, "smull"); +} + TEST_F(AssemblerThumb2Test, StoreWordToThumbOffset) { arm::StoreOperandType type = arm::kStoreWord; int32_t offset = 4092; diff --git a/runtime/base/unix_file/fd_file.cc b/runtime/base/unix_file/fd_file.cc index f272d88807..07cadc48d6 100644 --- a/runtime/base/unix_file/fd_file.cc +++ b/runtime/base/unix_file/fd_file.cc @@ -107,7 +107,7 @@ bool FdFile::Open(const std::string& path, int flags, mode_t mode) { } int FdFile::Close() { - int result = TEMP_FAILURE_RETRY(close(fd_)); + int result = close(fd_); // Test here, so the file is closed and not leaked. if (kCheckSafeUsage) { diff --git a/runtime/debugger.cc b/runtime/debugger.cc index 4bc9f98dfe..852ba49cd2 100644 --- a/runtime/debugger.cc +++ b/runtime/debugger.cc @@ -411,7 +411,7 @@ void DebugInvokeReq::VisitRoots(RootVisitor* visitor, const RootInfo& root_info) } void SingleStepControl::VisitRoots(RootVisitor* visitor, const RootInfo& root_info) { - visitor->VisitRootIfNonNull(reinterpret_cast<mirror::Object**>(&method_), root_info); + method_.VisitRootIfNonNull(visitor, root_info); } void SingleStepControl::AddDexPc(uint32_t dex_pc) { @@ -2929,10 +2929,11 @@ void Dbg::PostException(mirror::Throwable* exception_object) { if (!IsDebuggerActive()) { return; } - StackHandleScope<1> handle_scope(Thread::Current()); + Thread* const self = Thread::Current(); + StackHandleScope<1> handle_scope(self); Handle<mirror::Throwable> h_exception(handle_scope.NewHandle(exception_object)); std::unique_ptr<Context> context(Context::Create()); - CatchLocationFinder clf(Thread::Current(), h_exception, context.get()); + CatchLocationFinder clf(self, h_exception, context.get()); clf.WalkStack(/* include_transitions */ false); JDWP::EventLocation exception_throw_location; SetEventLocation(&exception_throw_location, clf.GetThrowMethod(), clf.GetThrowDexPc()); @@ -3981,7 +3982,7 @@ void Dbg::ExecuteMethod(DebugInvokeReq* pReq) { Handle<mirror::Object> object_result = hs.NewHandle(is_object_result ? result.GetL() : nullptr); Handle<mirror::Throwable> exception = hs.NewHandle(soa.Self()->GetException()); soa.Self()->ClearException(); - pReq->exception = gRegistry->Add(exception.Get()); + pReq->exception = gRegistry->Add(exception); if (pReq->exception != 0) { VLOG(jdwp) << " JDWP invocation returning with exception=" << exception.Get() << " " << exception->Dump(); diff --git a/runtime/debugger.h b/runtime/debugger.h index 789a0a4dca..811d345262 100644 --- a/runtime/debugger.h +++ b/runtime/debugger.h @@ -109,8 +109,8 @@ class SingleStepControl { return stack_depth_; } - mirror::ArtMethod* GetMethod() const { - return method_; + mirror::ArtMethod* GetMethod() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + return method_.Read(); } const std::set<uint32_t>& GetDexPcs() const { @@ -138,7 +138,7 @@ class SingleStepControl { // set of DEX pcs associated to the source line number where the suspension occurred. // This is used to support SD_INTO and SD_OVER single-step depths so we detect when a single-step // causes the execution of an instruction in a different method or at a different line number. - mirror::ArtMethod* method_; + GcRoot<mirror::ArtMethod> method_; std::set<uint32_t> dex_pcs_; DISALLOW_COPY_AND_ASSIGN(SingleStepControl); diff --git a/runtime/interpreter/unstarted_runtime.cc b/runtime/interpreter/unstarted_runtime.cc index 9006257d00..317106bb16 100644 --- a/runtime/interpreter/unstarted_runtime.cc +++ b/runtime/interpreter/unstarted_runtime.cc @@ -767,8 +767,12 @@ static void UnstartedStringGetCharsNoCheck( AbortTransactionOrFail(self, "String.getCharsNoCheck with null object"); return; } + DCHECK_GE(start, 0); + DCHECK_GE(end, string->GetLength()); StackHandleScope<1> hs(self); Handle<mirror::CharArray> h_char_array(hs.NewHandle(shadow_frame->GetVRegReference(arg_offset + 3)->AsCharArray())); + DCHECK_LE(index, h_char_array->GetLength()); + DCHECK_LE(end - start, h_char_array->GetLength() - index); string->GetChars(start, end, h_char_array, index); } @@ -785,6 +789,20 @@ static void UnstartedStringCharAt( result->SetC(string->CharAt(index)); } +// This allows setting chars from the new style of String objects during compilation. +static void UnstartedStringSetCharAt( + Thread* self, ShadowFrame* shadow_frame, JValue* result ATTRIBUTE_UNUSED, size_t arg_offset) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + jint index = shadow_frame->GetVReg(arg_offset + 1); + jchar c = shadow_frame->GetVReg(arg_offset + 2); + mirror::String* string = shadow_frame->GetVRegReference(arg_offset)->AsString(); + if (string == nullptr) { + AbortTransactionOrFail(self, "String.setCharAt with null object"); + return; + } + string->SetCharAt(index, c); +} + // This allows creating the new style of String objects during compilation. static void UnstartedStringFactoryNewStringFromChars( Thread* self, ShadowFrame* shadow_frame, JValue* result, size_t arg_offset) @@ -800,19 +818,51 @@ static void UnstartedStringFactoryNewStringFromChars( } // This allows creating the new style of String objects during compilation. +static void UnstartedStringFactoryNewStringFromString( + Thread* self, ShadowFrame* shadow_frame, JValue* result, size_t arg_offset) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + mirror::String* to_copy = shadow_frame->GetVRegReference(arg_offset)->AsString(); + if (to_copy == nullptr) { + AbortTransactionOrFail(self, "StringFactory.newStringFromString with null object"); + return; + } + StackHandleScope<1> hs(self); + Handle<mirror::String> h_string(hs.NewHandle(to_copy)); + Runtime* runtime = Runtime::Current(); + gc::AllocatorType allocator = runtime->GetHeap()->GetCurrentAllocator(); + result->SetL(mirror::String::AllocFromString<true>(self, h_string->GetLength(), h_string, 0, + allocator)); +} + +// This allows creating the new style of String objects during compilation. static void UnstartedStringFastSubstring( Thread* self, ShadowFrame* shadow_frame, JValue* result, size_t arg_offset) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { jint start = shadow_frame->GetVReg(arg_offset + 1); jint length = shadow_frame->GetVReg(arg_offset + 2); + DCHECK_GE(start, 0); DCHECK_GE(length, 0); StackHandleScope<1> hs(self); Handle<mirror::String> h_string(hs.NewHandle(shadow_frame->GetVRegReference(arg_offset)->AsString())); + DCHECK_LE(start, h_string->GetLength()); + DCHECK_LE(start + length, h_string->GetLength()); Runtime* runtime = Runtime::Current(); gc::AllocatorType allocator = runtime->GetHeap()->GetCurrentAllocator(); result->SetL(mirror::String::AllocFromString<true>(self, length, h_string, start, allocator)); } +// This allows getting the char array for new style of String objects during compilation. +static void UnstartedStringToCharArray( + Thread* self, ShadowFrame* shadow_frame, JValue* result, size_t arg_offset) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + mirror::String* string = shadow_frame->GetVRegReference(arg_offset)->AsString(); + if (string == nullptr) { + AbortTransactionOrFail(self, "String.charAt with null object"); + return; + } + result->SetL(string->ToCharArray(self)); +} + static void UnstartedJNIVMRuntimeNewUnpaddedArray(Thread* self, mirror::ArtMethod* method ATTRIBUTE_UNUSED, mirror::Object* receiver ATTRIBUTE_UNUSED, @@ -1141,10 +1191,16 @@ static void UnstartedRuntimeInitializeInvokeHandlers() { &UnstartedStringGetCharsNoCheck }, { "char java.lang.String.charAt(int)", &UnstartedStringCharAt }, + { "void java.lang.String.setCharAt(int, char)", + &UnstartedStringSetCharAt }, { "java.lang.String java.lang.StringFactory.newStringFromChars(int, int, char[])", &UnstartedStringFactoryNewStringFromChars }, + { "java.lang.String java.lang.StringFactory.newStringFromString(java.lang.String)", + &UnstartedStringFactoryNewStringFromString }, { "java.lang.String java.lang.String.fastSubstring(int, int)", &UnstartedStringFastSubstring }, + { "char[] java.lang.String.toCharArray()", + &UnstartedStringToCharArray }, }; for (auto& def : defs) { @@ -1228,6 +1284,8 @@ void UnstartedRuntimeInvoke(Thread* self, const DexFile::CodeItem* code_item, std::string name(PrettyMethod(shadow_frame->GetMethod())); const auto& iter = invoke_handlers_.find(name); if (iter != invoke_handlers_.end()) { + // Clear out the result in case it's not zeroed out. + result->SetL(0); (*iter->second)(self, shadow_frame, result, arg_offset); } else { // Not special, continue with regular interpreter execution. @@ -1241,6 +1299,8 @@ void UnstartedRuntimeJni(Thread* self, mirror::ArtMethod* method, mirror::Object std::string name(PrettyMethod(method)); const auto& iter = jni_handlers_.find(name); if (iter != jni_handlers_.end()) { + // Clear out the result in case it's not zeroed out. + result->SetL(0); (*iter->second)(self, method, receiver, args, result); } else if (Runtime::Current()->IsActiveTransaction()) { AbortTransactionF(self, "Attempt to invoke native method in non-started runtime: %s", diff --git a/runtime/jdwp/jdwp_event.cc b/runtime/jdwp/jdwp_event.cc index ab3f2e4ddd..ff75268daa 100644 --- a/runtime/jdwp/jdwp_event.cc +++ b/runtime/jdwp/jdwp_event.cc @@ -32,6 +32,8 @@ #include "scoped_thread_state_change.h" #include "thread-inl.h" +#include "handle_scope-inl.h" + /* General notes: @@ -108,20 +110,32 @@ namespace JDWP { * Stuff to compare against when deciding if a mod matches. Only the * values for mods valid for the event being evaluated will be filled in. * The rest will be zeroed. + * Must be allocated on the stack only. This is enforced by removing the + * operator new. */ struct ModBasket { - ModBasket() : pLoc(nullptr), thread(nullptr), locationClass(nullptr), exceptionClass(nullptr), - caught(false), field(nullptr), thisPtr(nullptr) { } - - const EventLocation* pLoc; /* LocationOnly */ - std::string className; /* ClassMatch/ClassExclude */ - Thread* thread; /* ThreadOnly */ - mirror::Class* locationClass; /* ClassOnly */ - mirror::Class* exceptionClass; /* ExceptionOnly */ - bool caught; /* ExceptionOnly */ - ArtField* field; /* FieldOnly */ - mirror::Object* thisPtr; /* InstanceOnly */ + explicit ModBasket(Thread* self) + : hs(self), pLoc(nullptr), thread(self), + locationClass(hs.NewHandle<mirror::Class>(nullptr)), + exceptionClass(hs.NewHandle<mirror::Class>(nullptr)), + caught(false), + field(nullptr), + thisPtr(hs.NewHandle<mirror::Object>(nullptr)) { } + + StackHandleScope<3> hs; + const EventLocation* pLoc; /* LocationOnly */ + std::string className; /* ClassMatch/ClassExclude */ + Thread* const thread; /* ThreadOnly */ + MutableHandle<mirror::Class> locationClass; /* ClassOnly */ + MutableHandle<mirror::Class> exceptionClass; /* ExceptionOnly */ + bool caught; /* ExceptionOnly */ + ArtField* field; /* FieldOnly */ + MutableHandle<mirror::Object> thisPtr; /* InstanceOnly */ /* nothing for StepOnly -- handled differently */ + + private: + DISALLOW_ALLOCATION(); // forbids allocation on the heap. + DISALLOW_IMPLICIT_CONSTRUCTORS(ModBasket); }; static bool NeedsFullDeoptimization(JdwpEventKind eventKind) { @@ -457,7 +471,7 @@ static bool ModsMatch(JdwpEvent* pEvent, const ModBasket& basket) } break; case MK_CLASS_ONLY: - if (!Dbg::MatchType(basket.locationClass, pMod->classOnly.refTypeId)) { + if (!Dbg::MatchType(basket.locationClass.Get(), pMod->classOnly.refTypeId)) { return false; } break; @@ -478,7 +492,7 @@ static bool ModsMatch(JdwpEvent* pEvent, const ModBasket& basket) break; case MK_EXCEPTION_ONLY: if (pMod->exceptionOnly.refTypeId != 0 && - !Dbg::MatchType(basket.exceptionClass, pMod->exceptionOnly.refTypeId)) { + !Dbg::MatchType(basket.exceptionClass.Get(), pMod->exceptionOnly.refTypeId)) { return false; } if ((basket.caught && !pMod->exceptionOnly.caught) || @@ -497,7 +511,7 @@ static bool ModsMatch(JdwpEvent* pEvent, const ModBasket& basket) } break; case MK_INSTANCE_ONLY: - if (!Dbg::MatchInstance(pMod->instanceOnly.objectId, basket.thisPtr)) { + if (!Dbg::MatchInstance(pMod->instanceOnly.objectId, basket.thisPtr.Get())) { return false; } break; @@ -825,12 +839,11 @@ void JdwpState::PostLocationEvent(const EventLocation* pLoc, mirror::Object* thi DCHECK(pLoc->method != nullptr); DCHECK_EQ(pLoc->method->IsStatic(), thisPtr == nullptr); - ModBasket basket; + ModBasket basket(Thread::Current()); basket.pLoc = pLoc; - basket.locationClass = pLoc->method->GetDeclaringClass(); - basket.thisPtr = thisPtr; - basket.thread = Thread::Current(); - basket.className = Dbg::GetClassName(basket.locationClass); + basket.locationClass.Assign(pLoc->method->GetDeclaringClass()); + basket.thisPtr.Assign(thisPtr); + basket.className = Dbg::GetClassName(basket.locationClass.Get()); /* * On rare occasions we may need to execute interpreted code in the VM @@ -924,16 +937,15 @@ void JdwpState::PostFieldEvent(const EventLocation* pLoc, ArtField* field, DCHECK_EQ(fieldValue != nullptr, is_modification); DCHECK_EQ(field->IsStatic(), this_object == nullptr); - ModBasket basket; + ModBasket basket(Thread::Current()); basket.pLoc = pLoc; - basket.locationClass = pLoc->method->GetDeclaringClass(); - basket.thisPtr = this_object; - basket.thread = Thread::Current(); - basket.className = Dbg::GetClassName(basket.locationClass); + basket.locationClass.Assign(pLoc->method->GetDeclaringClass()); + basket.thisPtr.Assign(this_object); + basket.className = Dbg::GetClassName(basket.locationClass.Get()); basket.field = field; if (InvokeInProgress()) { - VLOG(jdwp) << "Not posting field event during invoke"; + VLOG(jdwp) << "Not posting field event during invoke (" << basket.className << ")"; return; } @@ -975,7 +987,7 @@ void JdwpState::PostFieldEvent(const EventLocation* pLoc, ArtField* field, uint8_t tag; { ScopedObjectAccessUnchecked soa(Thread::Current()); - tag = Dbg::TagFromObject(soa, basket.thisPtr); + tag = Dbg::TagFromObject(soa, basket.thisPtr.Get()); } for (const JdwpEvent* pEvent : match_list) { @@ -1028,8 +1040,7 @@ void JdwpState::PostThreadChange(Thread* thread, bool start) { return; } - ModBasket basket; - basket.thread = thread; + ModBasket basket(thread); std::vector<JdwpEvent*> match_list; const JdwpEventKind match_kind = (start) ? EK_THREAD_START : EK_THREAD_DEATH; @@ -1106,18 +1117,15 @@ void JdwpState::PostException(const EventLocation* pThrowLoc, mirror::Throwable* VLOG(jdwp) << "Unexpected: exception event with empty throw location"; } - ModBasket basket; + ModBasket basket(Thread::Current()); basket.pLoc = pThrowLoc; if (pThrowLoc->method != nullptr) { - basket.locationClass = pThrowLoc->method->GetDeclaringClass(); - } else { - basket.locationClass = nullptr; + basket.locationClass.Assign(pThrowLoc->method->GetDeclaringClass()); } - basket.thread = Thread::Current(); - basket.className = Dbg::GetClassName(basket.locationClass); - basket.exceptionClass = exception_object->GetClass(); + basket.className = Dbg::GetClassName(basket.locationClass.Get()); + basket.exceptionClass.Assign(exception_object->GetClass()); basket.caught = (pCatchLoc->method != 0); - basket.thisPtr = thisPtr; + basket.thisPtr.Assign(thisPtr); /* don't try to post an exception caused by the debugger */ if (InvokeInProgress()) { @@ -1188,10 +1196,9 @@ void JdwpState::PostException(const EventLocation* pThrowLoc, mirror::Throwable* void JdwpState::PostClassPrepare(mirror::Class* klass) { DCHECK(klass != nullptr); - ModBasket basket; - basket.locationClass = klass; - basket.thread = Thread::Current(); - basket.className = Dbg::GetClassName(basket.locationClass); + ModBasket basket(Thread::Current()); + basket.locationClass.Assign(klass); + basket.className = Dbg::GetClassName(basket.locationClass.Get()); /* suppress class prep caused by debugger */ if (InvokeInProgress()) { @@ -1214,7 +1221,7 @@ void JdwpState::PostClassPrepare(mirror::Class* klass) { // debuggers seem to like that. There might be some advantage to honesty, // since the class may not yet be verified. int status = JDWP::CS_VERIFIED | JDWP::CS_PREPARED; - JDWP::JdwpTypeTag tag = Dbg::GetTypeTag(basket.locationClass); + JDWP::JdwpTypeTag tag = Dbg::GetTypeTag(basket.locationClass.Get()); std::string temp; std::string signature(basket.locationClass->GetDescriptor(&temp)); diff --git a/runtime/jdwp/object_registry.cc b/runtime/jdwp/object_registry.cc index a42a58f601..2b28f7df5a 100644 --- a/runtime/jdwp/object_registry.cc +++ b/runtime/jdwp/object_registry.cc @@ -36,17 +36,45 @@ ObjectRegistry::ObjectRegistry() } JDWP::RefTypeId ObjectRegistry::AddRefType(mirror::Class* c) { - return InternalAdd(c); + return Add(c); } -JDWP::ObjectId ObjectRegistry::Add(mirror::Object* o) { - return InternalAdd(o); +JDWP::RefTypeId ObjectRegistry::AddRefType(Handle<mirror::Class> c_h) { + return Add(c_h); } -JDWP::ObjectId ObjectRegistry::InternalAdd(mirror::Object* o) { +JDWP::ObjectId ObjectRegistry::Add(mirror::Object* o) { if (o == nullptr) { return 0; } + Thread* const self = Thread::Current(); + StackHandleScope<1> hs(self); + return InternalAdd(hs.NewHandle(o)); +} + +// Template instantiations must be declared below. +template<class T> +JDWP::ObjectId ObjectRegistry::Add(Handle<T> obj_h) { + if (obj_h.Get() == nullptr) { + return 0; + } + return InternalAdd(obj_h); +} + +// Explicit template instantiation. +template +SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) +LOCKS_EXCLUDED(Locks::thread_list_lock_, Locks::thread_suspend_count_lock_) +JDWP::ObjectId ObjectRegistry::Add(Handle<mirror::Object> obj_h); + +template +SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) +LOCKS_EXCLUDED(Locks::thread_list_lock_, Locks::thread_suspend_count_lock_) +JDWP::ObjectId ObjectRegistry::Add(Handle<mirror::Throwable> obj_h); + +template<class T> +JDWP::ObjectId ObjectRegistry::InternalAdd(Handle<T> obj_h) { + CHECK(obj_h.Get() != nullptr); Thread* const self = Thread::Current(); self->AssertNoPendingException(); @@ -55,9 +83,6 @@ JDWP::ObjectId ObjectRegistry::InternalAdd(mirror::Object* o) { Locks::thread_list_lock_->AssertNotHeld(self); Locks::thread_suspend_count_lock_->AssertNotHeld(self); - StackHandleScope<1> hs(self); - Handle<mirror::Object> obj_h(hs.NewHandle(o)); - // Call IdentityHashCode here to avoid a lock level violation between lock_ and monitor_lock. int32_t identity_hash_code = obj_h->IdentityHashCode(); diff --git a/runtime/jdwp/object_registry.h b/runtime/jdwp/object_registry.h index 27a4e55f41..4c149cdac7 100644 --- a/runtime/jdwp/object_registry.h +++ b/runtime/jdwp/object_registry.h @@ -23,6 +23,7 @@ #include <map> #include "base/casts.h" +#include "handle.h" #include "jdwp/jdwp.h" #include "safe_map.h" @@ -65,11 +66,23 @@ class ObjectRegistry { SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) LOCKS_EXCLUDED(Locks::thread_list_lock_, Locks::thread_suspend_count_lock_); + JDWP::RefTypeId AddRefType(mirror::Class* c) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) LOCKS_EXCLUDED(Locks::thread_list_lock_, Locks::thread_suspend_count_lock_); + template<class T> + JDWP::ObjectId Add(Handle<T> obj_h) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) + LOCKS_EXCLUDED(Locks::thread_list_lock_, + Locks::thread_suspend_count_lock_); + + JDWP::RefTypeId AddRefType(Handle<mirror::Class> c_h) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) + LOCKS_EXCLUDED(Locks::thread_list_lock_, + Locks::thread_suspend_count_lock_); + template<typename T> T Get(JDWP::ObjectId id, JDWP::JdwpError* error) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { if (id == 0) { @@ -98,7 +111,8 @@ class ObjectRegistry { jobject GetJObject(JDWP::ObjectId id) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); private: - JDWP::ObjectId InternalAdd(mirror::Object* o) + template<class T> + JDWP::ObjectId InternalAdd(Handle<T> obj_h) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) LOCKS_EXCLUDED(lock_, Locks::thread_list_lock_, diff --git a/test/701-easy-div-rem/build b/test/701-easy-div-rem/build new file mode 100644 index 0000000000..1dc8452d91 --- /dev/null +++ b/test/701-easy-div-rem/build @@ -0,0 +1,28 @@ +#!/bin/bash +# +# Copyright (C) 2014 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. + +# Stop if something fails. +set -e + +# Write out the source file. +mkdir src +python ./genMain.py + +# Increase the file size limitation for classes.lst as the machine generated +# source file contains a lot of methods and is quite large. +ulimit -S 4096 + +./default-build diff --git a/test/701-easy-div-rem/genMain.py b/test/701-easy-div-rem/genMain.py index 80eac34463..75eee17fe6 100644 --- a/test/701-easy-div-rem/genMain.py +++ b/test/701-easy-div-rem/genMain.py @@ -12,15 +12,28 @@ # See the License for the specific language governing permissions and # limitations under the License. +upper_bound_int_pow2 = 31 +upper_bound_long_pow2 = 63 +upper_bound_constant = 100 all_tests = [ ({'@INT@': 'int', '@SUFFIX@':''}, - [('CheckDiv', 'idiv_by_pow2_', [2**i for i in range(31)]), - ('CheckDiv', 'idiv_by_small_', [i for i in range(3, 16) if i not in (4, 8)]), - ('CheckRem', 'irem_by_pow2_', [2**i for i in range(31)])]), + [('CheckDiv', 'idiv_by_pow2_', [2**i for i in range(upper_bound_int_pow2)]), + ('CheckDiv', 'idiv_by_pow2_neg_', [-2**i for i in range(upper_bound_int_pow2)]), + ('CheckDiv', 'idiv_by_constant_', [i for i in range(1, upper_bound_constant)]), + ('CheckDiv', 'idiv_by_constant_neg_', [-i for i in range(1, upper_bound_constant)]), + ('CheckRem', 'irem_by_pow2_', [2**i for i in range(upper_bound_int_pow2)]), + ('CheckRem', 'irem_by_pow2_neg_', [-2**i for i in range(upper_bound_int_pow2)]), + ('CheckRem', 'irem_by_constant_', [i for i in range(1, upper_bound_constant)]), + ('CheckRem', 'irem_by_constant_neg_', [-i for i in range(1, upper_bound_constant)])]), ({'@INT@': 'long', '@SUFFIX@': 'l'}, - [('CheckDiv', 'ldiv_by_pow2_', [2**i for i in range(63)]), - ('CheckDiv', 'ldiv_by_small_', [i for i in range(3, 16) if i not in (4, 8)]), - ('CheckRem', 'lrem_by_pow2_', [2**i for i in range(63)])]) + [('CheckDiv', 'ldiv_by_pow2_', [2**i for i in range(upper_bound_long_pow2)]), + ('CheckDiv', 'ldiv_by_pow2_neg_', [-2**i for i in range(upper_bound_long_pow2)]), + ('CheckDiv', 'ldiv_by_constant_', [i for i in range(1, upper_bound_constant)]), + ('CheckDiv', 'ldiv_by_constant_neg_', [-i for i in range(1, upper_bound_constant)]), + ('CheckRem', 'lrem_by_pow2_', [2**i for i in range(upper_bound_long_pow2)]), + ('CheckRem', 'lrem_by_pow2_neg_', [-2**i for i in range(upper_bound_long_pow2)]), + ('CheckRem', 'lrem_by_constant_', [i for i in range(1, upper_bound_constant)]), + ('CheckRem', 'lrem_by_constant_neg_', [-i for i in range(1, upper_bound_constant)])]) ] def subst_vars(variables, text): diff --git a/test/701-easy-div-rem/src/Main.java b/test/701-easy-div-rem/src/Main.java deleted file mode 100644 index f995f61953..0000000000 --- a/test/701-easy-div-rem/src/Main.java +++ /dev/null @@ -1,529 +0,0 @@ -/* - * Copyright (C) 2014 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 int num_errors = 0; - - public static void reportError(String message) { - if (num_errors == 10) { - System.out.println("Omitting other error messages..."); - } else if (num_errors < 10) { - System.out.println(message); - } - num_errors += 1; - } - - public static void intCheckDiv(String desc, int result, int dividend, int divisor) { - int correct_result = dividend / divisor; - if (result != correct_result) { - reportError(desc + "(" + dividend + ") == " + result + - " should be " + correct_result); - } - } - public static void intCheckRem(String desc, int result, int dividend, int divisor) { - int correct_result = dividend % divisor; - if (result != correct_result) { - reportError(desc + "(" + dividend + ") == " + result + - " should be " + correct_result); - } - } - public static void longCheckDiv(String desc, long result, long dividend, long divisor) { - long correct_result = dividend / divisor; - if (result != correct_result) { - reportError(desc + "(" + dividend + ") == " + result + - " should be " + correct_result); - } - } - public static void longCheckRem(String desc, long result, long dividend, long divisor) { - long correct_result = dividend % divisor; - if (result != correct_result) { - reportError(desc + "(" + dividend + ") == " + result + - " should be " + correct_result); - } - } - - public static int idiv_by_pow2_0(int x) {return x / 1;} - public static int idiv_by_pow2_1(int x) {return x / 2;} - public static int idiv_by_pow2_2(int x) {return x / 4;} - public static int idiv_by_pow2_3(int x) {return x / 8;} - public static int idiv_by_pow2_4(int x) {return x / 16;} - public static int idiv_by_pow2_5(int x) {return x / 32;} - public static int idiv_by_pow2_6(int x) {return x / 64;} - public static int idiv_by_pow2_7(int x) {return x / 128;} - public static int idiv_by_pow2_8(int x) {return x / 256;} - public static int idiv_by_pow2_9(int x) {return x / 512;} - public static int idiv_by_pow2_10(int x) {return x / 1024;} - public static int idiv_by_pow2_11(int x) {return x / 2048;} - public static int idiv_by_pow2_12(int x) {return x / 4096;} - public static int idiv_by_pow2_13(int x) {return x / 8192;} - public static int idiv_by_pow2_14(int x) {return x / 16384;} - public static int idiv_by_pow2_15(int x) {return x / 32768;} - public static int idiv_by_pow2_16(int x) {return x / 65536;} - public static int idiv_by_pow2_17(int x) {return x / 131072;} - public static int idiv_by_pow2_18(int x) {return x / 262144;} - public static int idiv_by_pow2_19(int x) {return x / 524288;} - public static int idiv_by_pow2_20(int x) {return x / 1048576;} - public static int idiv_by_pow2_21(int x) {return x / 2097152;} - public static int idiv_by_pow2_22(int x) {return x / 4194304;} - public static int idiv_by_pow2_23(int x) {return x / 8388608;} - public static int idiv_by_pow2_24(int x) {return x / 16777216;} - public static int idiv_by_pow2_25(int x) {return x / 33554432;} - public static int idiv_by_pow2_26(int x) {return x / 67108864;} - public static int idiv_by_pow2_27(int x) {return x / 134217728;} - public static int idiv_by_pow2_28(int x) {return x / 268435456;} - public static int idiv_by_pow2_29(int x) {return x / 536870912;} - public static int idiv_by_pow2_30(int x) {return x / 1073741824;} - public static int idiv_by_small_0(int x) {return x / 3;} - public static int idiv_by_small_1(int x) {return x / 5;} - public static int idiv_by_small_2(int x) {return x / 6;} - public static int idiv_by_small_3(int x) {return x / 7;} - public static int idiv_by_small_4(int x) {return x / 9;} - public static int idiv_by_small_5(int x) {return x / 10;} - public static int idiv_by_small_6(int x) {return x / 11;} - public static int idiv_by_small_7(int x) {return x / 12;} - public static int idiv_by_small_8(int x) {return x / 13;} - public static int idiv_by_small_9(int x) {return x / 14;} - public static int idiv_by_small_10(int x) {return x / 15;} - public static int irem_by_pow2_0(int x) {return x % 1;} - public static int irem_by_pow2_1(int x) {return x % 2;} - public static int irem_by_pow2_2(int x) {return x % 4;} - public static int irem_by_pow2_3(int x) {return x % 8;} - public static int irem_by_pow2_4(int x) {return x % 16;} - public static int irem_by_pow2_5(int x) {return x % 32;} - public static int irem_by_pow2_6(int x) {return x % 64;} - public static int irem_by_pow2_7(int x) {return x % 128;} - public static int irem_by_pow2_8(int x) {return x % 256;} - public static int irem_by_pow2_9(int x) {return x % 512;} - public static int irem_by_pow2_10(int x) {return x % 1024;} - public static int irem_by_pow2_11(int x) {return x % 2048;} - public static int irem_by_pow2_12(int x) {return x % 4096;} - public static int irem_by_pow2_13(int x) {return x % 8192;} - public static int irem_by_pow2_14(int x) {return x % 16384;} - public static int irem_by_pow2_15(int x) {return x % 32768;} - public static int irem_by_pow2_16(int x) {return x % 65536;} - public static int irem_by_pow2_17(int x) {return x % 131072;} - public static int irem_by_pow2_18(int x) {return x % 262144;} - public static int irem_by_pow2_19(int x) {return x % 524288;} - public static int irem_by_pow2_20(int x) {return x % 1048576;} - public static int irem_by_pow2_21(int x) {return x % 2097152;} - public static int irem_by_pow2_22(int x) {return x % 4194304;} - public static int irem_by_pow2_23(int x) {return x % 8388608;} - public static int irem_by_pow2_24(int x) {return x % 16777216;} - public static int irem_by_pow2_25(int x) {return x % 33554432;} - public static int irem_by_pow2_26(int x) {return x % 67108864;} - public static int irem_by_pow2_27(int x) {return x % 134217728;} - public static int irem_by_pow2_28(int x) {return x % 268435456;} - public static int irem_by_pow2_29(int x) {return x % 536870912;} - public static int irem_by_pow2_30(int x) {return x % 1073741824;} - public static long ldiv_by_pow2_0(long x) {return x / 1l;} - public static long ldiv_by_pow2_1(long x) {return x / 2l;} - public static long ldiv_by_pow2_2(long x) {return x / 4l;} - public static long ldiv_by_pow2_3(long x) {return x / 8l;} - public static long ldiv_by_pow2_4(long x) {return x / 16l;} - public static long ldiv_by_pow2_5(long x) {return x / 32l;} - public static long ldiv_by_pow2_6(long x) {return x / 64l;} - public static long ldiv_by_pow2_7(long x) {return x / 128l;} - public static long ldiv_by_pow2_8(long x) {return x / 256l;} - public static long ldiv_by_pow2_9(long x) {return x / 512l;} - public static long ldiv_by_pow2_10(long x) {return x / 1024l;} - public static long ldiv_by_pow2_11(long x) {return x / 2048l;} - public static long ldiv_by_pow2_12(long x) {return x / 4096l;} - public static long ldiv_by_pow2_13(long x) {return x / 8192l;} - public static long ldiv_by_pow2_14(long x) {return x / 16384l;} - public static long ldiv_by_pow2_15(long x) {return x / 32768l;} - public static long ldiv_by_pow2_16(long x) {return x / 65536l;} - public static long ldiv_by_pow2_17(long x) {return x / 131072l;} - public static long ldiv_by_pow2_18(long x) {return x / 262144l;} - public static long ldiv_by_pow2_19(long x) {return x / 524288l;} - public static long ldiv_by_pow2_20(long x) {return x / 1048576l;} - public static long ldiv_by_pow2_21(long x) {return x / 2097152l;} - public static long ldiv_by_pow2_22(long x) {return x / 4194304l;} - public static long ldiv_by_pow2_23(long x) {return x / 8388608l;} - public static long ldiv_by_pow2_24(long x) {return x / 16777216l;} - public static long ldiv_by_pow2_25(long x) {return x / 33554432l;} - public static long ldiv_by_pow2_26(long x) {return x / 67108864l;} - public static long ldiv_by_pow2_27(long x) {return x / 134217728l;} - public static long ldiv_by_pow2_28(long x) {return x / 268435456l;} - public static long ldiv_by_pow2_29(long x) {return x / 536870912l;} - public static long ldiv_by_pow2_30(long x) {return x / 1073741824l;} - public static long ldiv_by_pow2_31(long x) {return x / 2147483648l;} - public static long ldiv_by_pow2_32(long x) {return x / 4294967296l;} - public static long ldiv_by_pow2_33(long x) {return x / 8589934592l;} - public static long ldiv_by_pow2_34(long x) {return x / 17179869184l;} - public static long ldiv_by_pow2_35(long x) {return x / 34359738368l;} - public static long ldiv_by_pow2_36(long x) {return x / 68719476736l;} - public static long ldiv_by_pow2_37(long x) {return x / 137438953472l;} - public static long ldiv_by_pow2_38(long x) {return x / 274877906944l;} - public static long ldiv_by_pow2_39(long x) {return x / 549755813888l;} - public static long ldiv_by_pow2_40(long x) {return x / 1099511627776l;} - public static long ldiv_by_pow2_41(long x) {return x / 2199023255552l;} - public static long ldiv_by_pow2_42(long x) {return x / 4398046511104l;} - public static long ldiv_by_pow2_43(long x) {return x / 8796093022208l;} - public static long ldiv_by_pow2_44(long x) {return x / 17592186044416l;} - public static long ldiv_by_pow2_45(long x) {return x / 35184372088832l;} - public static long ldiv_by_pow2_46(long x) {return x / 70368744177664l;} - public static long ldiv_by_pow2_47(long x) {return x / 140737488355328l;} - public static long ldiv_by_pow2_48(long x) {return x / 281474976710656l;} - public static long ldiv_by_pow2_49(long x) {return x / 562949953421312l;} - public static long ldiv_by_pow2_50(long x) {return x / 1125899906842624l;} - public static long ldiv_by_pow2_51(long x) {return x / 2251799813685248l;} - public static long ldiv_by_pow2_52(long x) {return x / 4503599627370496l;} - public static long ldiv_by_pow2_53(long x) {return x / 9007199254740992l;} - public static long ldiv_by_pow2_54(long x) {return x / 18014398509481984l;} - public static long ldiv_by_pow2_55(long x) {return x / 36028797018963968l;} - public static long ldiv_by_pow2_56(long x) {return x / 72057594037927936l;} - public static long ldiv_by_pow2_57(long x) {return x / 144115188075855872l;} - public static long ldiv_by_pow2_58(long x) {return x / 288230376151711744l;} - public static long ldiv_by_pow2_59(long x) {return x / 576460752303423488l;} - public static long ldiv_by_pow2_60(long x) {return x / 1152921504606846976l;} - public static long ldiv_by_pow2_61(long x) {return x / 2305843009213693952l;} - public static long ldiv_by_pow2_62(long x) {return x / 4611686018427387904l;} - public static long ldiv_by_small_0(long x) {return x / 3l;} - public static long ldiv_by_small_1(long x) {return x / 5l;} - public static long ldiv_by_small_2(long x) {return x / 6l;} - public static long ldiv_by_small_3(long x) {return x / 7l;} - public static long ldiv_by_small_4(long x) {return x / 9l;} - public static long ldiv_by_small_5(long x) {return x / 10l;} - public static long ldiv_by_small_6(long x) {return x / 11l;} - public static long ldiv_by_small_7(long x) {return x / 12l;} - public static long ldiv_by_small_8(long x) {return x / 13l;} - public static long ldiv_by_small_9(long x) {return x / 14l;} - public static long ldiv_by_small_10(long x) {return x / 15l;} - public static long lrem_by_pow2_0(long x) {return x % 1l;} - public static long lrem_by_pow2_1(long x) {return x % 2l;} - public static long lrem_by_pow2_2(long x) {return x % 4l;} - public static long lrem_by_pow2_3(long x) {return x % 8l;} - public static long lrem_by_pow2_4(long x) {return x % 16l;} - public static long lrem_by_pow2_5(long x) {return x % 32l;} - public static long lrem_by_pow2_6(long x) {return x % 64l;} - public static long lrem_by_pow2_7(long x) {return x % 128l;} - public static long lrem_by_pow2_8(long x) {return x % 256l;} - public static long lrem_by_pow2_9(long x) {return x % 512l;} - public static long lrem_by_pow2_10(long x) {return x % 1024l;} - public static long lrem_by_pow2_11(long x) {return x % 2048l;} - public static long lrem_by_pow2_12(long x) {return x % 4096l;} - public static long lrem_by_pow2_13(long x) {return x % 8192l;} - public static long lrem_by_pow2_14(long x) {return x % 16384l;} - public static long lrem_by_pow2_15(long x) {return x % 32768l;} - public static long lrem_by_pow2_16(long x) {return x % 65536l;} - public static long lrem_by_pow2_17(long x) {return x % 131072l;} - public static long lrem_by_pow2_18(long x) {return x % 262144l;} - public static long lrem_by_pow2_19(long x) {return x % 524288l;} - public static long lrem_by_pow2_20(long x) {return x % 1048576l;} - public static long lrem_by_pow2_21(long x) {return x % 2097152l;} - public static long lrem_by_pow2_22(long x) {return x % 4194304l;} - public static long lrem_by_pow2_23(long x) {return x % 8388608l;} - public static long lrem_by_pow2_24(long x) {return x % 16777216l;} - public static long lrem_by_pow2_25(long x) {return x % 33554432l;} - public static long lrem_by_pow2_26(long x) {return x % 67108864l;} - public static long lrem_by_pow2_27(long x) {return x % 134217728l;} - public static long lrem_by_pow2_28(long x) {return x % 268435456l;} - public static long lrem_by_pow2_29(long x) {return x % 536870912l;} - public static long lrem_by_pow2_30(long x) {return x % 1073741824l;} - public static long lrem_by_pow2_31(long x) {return x % 2147483648l;} - public static long lrem_by_pow2_32(long x) {return x % 4294967296l;} - public static long lrem_by_pow2_33(long x) {return x % 8589934592l;} - public static long lrem_by_pow2_34(long x) {return x % 17179869184l;} - public static long lrem_by_pow2_35(long x) {return x % 34359738368l;} - public static long lrem_by_pow2_36(long x) {return x % 68719476736l;} - public static long lrem_by_pow2_37(long x) {return x % 137438953472l;} - public static long lrem_by_pow2_38(long x) {return x % 274877906944l;} - public static long lrem_by_pow2_39(long x) {return x % 549755813888l;} - public static long lrem_by_pow2_40(long x) {return x % 1099511627776l;} - public static long lrem_by_pow2_41(long x) {return x % 2199023255552l;} - public static long lrem_by_pow2_42(long x) {return x % 4398046511104l;} - public static long lrem_by_pow2_43(long x) {return x % 8796093022208l;} - public static long lrem_by_pow2_44(long x) {return x % 17592186044416l;} - public static long lrem_by_pow2_45(long x) {return x % 35184372088832l;} - public static long lrem_by_pow2_46(long x) {return x % 70368744177664l;} - public static long lrem_by_pow2_47(long x) {return x % 140737488355328l;} - public static long lrem_by_pow2_48(long x) {return x % 281474976710656l;} - public static long lrem_by_pow2_49(long x) {return x % 562949953421312l;} - public static long lrem_by_pow2_50(long x) {return x % 1125899906842624l;} - public static long lrem_by_pow2_51(long x) {return x % 2251799813685248l;} - public static long lrem_by_pow2_52(long x) {return x % 4503599627370496l;} - public static long lrem_by_pow2_53(long x) {return x % 9007199254740992l;} - public static long lrem_by_pow2_54(long x) {return x % 18014398509481984l;} - public static long lrem_by_pow2_55(long x) {return x % 36028797018963968l;} - public static long lrem_by_pow2_56(long x) {return x % 72057594037927936l;} - public static long lrem_by_pow2_57(long x) {return x % 144115188075855872l;} - public static long lrem_by_pow2_58(long x) {return x % 288230376151711744l;} - public static long lrem_by_pow2_59(long x) {return x % 576460752303423488l;} - public static long lrem_by_pow2_60(long x) {return x % 1152921504606846976l;} - public static long lrem_by_pow2_61(long x) {return x % 2305843009213693952l;} - public static long lrem_by_pow2_62(long x) {return x % 4611686018427387904l;} - - public static void intCheckAll(int x) { - intCheckDiv("idiv_by_pow2_0", idiv_by_pow2_0(x), x, 1); - intCheckDiv("idiv_by_pow2_1", idiv_by_pow2_1(x), x, 2); - intCheckDiv("idiv_by_pow2_2", idiv_by_pow2_2(x), x, 4); - intCheckDiv("idiv_by_pow2_3", idiv_by_pow2_3(x), x, 8); - intCheckDiv("idiv_by_pow2_4", idiv_by_pow2_4(x), x, 16); - intCheckDiv("idiv_by_pow2_5", idiv_by_pow2_5(x), x, 32); - intCheckDiv("idiv_by_pow2_6", idiv_by_pow2_6(x), x, 64); - intCheckDiv("idiv_by_pow2_7", idiv_by_pow2_7(x), x, 128); - intCheckDiv("idiv_by_pow2_8", idiv_by_pow2_8(x), x, 256); - intCheckDiv("idiv_by_pow2_9", idiv_by_pow2_9(x), x, 512); - intCheckDiv("idiv_by_pow2_10", idiv_by_pow2_10(x), x, 1024); - intCheckDiv("idiv_by_pow2_11", idiv_by_pow2_11(x), x, 2048); - intCheckDiv("idiv_by_pow2_12", idiv_by_pow2_12(x), x, 4096); - intCheckDiv("idiv_by_pow2_13", idiv_by_pow2_13(x), x, 8192); - intCheckDiv("idiv_by_pow2_14", idiv_by_pow2_14(x), x, 16384); - intCheckDiv("idiv_by_pow2_15", idiv_by_pow2_15(x), x, 32768); - intCheckDiv("idiv_by_pow2_16", idiv_by_pow2_16(x), x, 65536); - intCheckDiv("idiv_by_pow2_17", idiv_by_pow2_17(x), x, 131072); - intCheckDiv("idiv_by_pow2_18", idiv_by_pow2_18(x), x, 262144); - intCheckDiv("idiv_by_pow2_19", idiv_by_pow2_19(x), x, 524288); - intCheckDiv("idiv_by_pow2_20", idiv_by_pow2_20(x), x, 1048576); - intCheckDiv("idiv_by_pow2_21", idiv_by_pow2_21(x), x, 2097152); - intCheckDiv("idiv_by_pow2_22", idiv_by_pow2_22(x), x, 4194304); - intCheckDiv("idiv_by_pow2_23", idiv_by_pow2_23(x), x, 8388608); - intCheckDiv("idiv_by_pow2_24", idiv_by_pow2_24(x), x, 16777216); - intCheckDiv("idiv_by_pow2_25", idiv_by_pow2_25(x), x, 33554432); - intCheckDiv("idiv_by_pow2_26", idiv_by_pow2_26(x), x, 67108864); - intCheckDiv("idiv_by_pow2_27", idiv_by_pow2_27(x), x, 134217728); - intCheckDiv("idiv_by_pow2_28", idiv_by_pow2_28(x), x, 268435456); - intCheckDiv("idiv_by_pow2_29", idiv_by_pow2_29(x), x, 536870912); - intCheckDiv("idiv_by_pow2_30", idiv_by_pow2_30(x), x, 1073741824); - intCheckDiv("idiv_by_small_0", idiv_by_small_0(x), x, 3); - intCheckDiv("idiv_by_small_1", idiv_by_small_1(x), x, 5); - intCheckDiv("idiv_by_small_2", idiv_by_small_2(x), x, 6); - intCheckDiv("idiv_by_small_3", idiv_by_small_3(x), x, 7); - intCheckDiv("idiv_by_small_4", idiv_by_small_4(x), x, 9); - intCheckDiv("idiv_by_small_5", idiv_by_small_5(x), x, 10); - intCheckDiv("idiv_by_small_6", idiv_by_small_6(x), x, 11); - intCheckDiv("idiv_by_small_7", idiv_by_small_7(x), x, 12); - intCheckDiv("idiv_by_small_8", idiv_by_small_8(x), x, 13); - intCheckDiv("idiv_by_small_9", idiv_by_small_9(x), x, 14); - intCheckDiv("idiv_by_small_10", idiv_by_small_10(x), x, 15); - intCheckRem("irem_by_pow2_0", irem_by_pow2_0(x), x, 1); - intCheckRem("irem_by_pow2_1", irem_by_pow2_1(x), x, 2); - intCheckRem("irem_by_pow2_2", irem_by_pow2_2(x), x, 4); - intCheckRem("irem_by_pow2_3", irem_by_pow2_3(x), x, 8); - intCheckRem("irem_by_pow2_4", irem_by_pow2_4(x), x, 16); - intCheckRem("irem_by_pow2_5", irem_by_pow2_5(x), x, 32); - intCheckRem("irem_by_pow2_6", irem_by_pow2_6(x), x, 64); - intCheckRem("irem_by_pow2_7", irem_by_pow2_7(x), x, 128); - intCheckRem("irem_by_pow2_8", irem_by_pow2_8(x), x, 256); - intCheckRem("irem_by_pow2_9", irem_by_pow2_9(x), x, 512); - intCheckRem("irem_by_pow2_10", irem_by_pow2_10(x), x, 1024); - intCheckRem("irem_by_pow2_11", irem_by_pow2_11(x), x, 2048); - intCheckRem("irem_by_pow2_12", irem_by_pow2_12(x), x, 4096); - intCheckRem("irem_by_pow2_13", irem_by_pow2_13(x), x, 8192); - intCheckRem("irem_by_pow2_14", irem_by_pow2_14(x), x, 16384); - intCheckRem("irem_by_pow2_15", irem_by_pow2_15(x), x, 32768); - intCheckRem("irem_by_pow2_16", irem_by_pow2_16(x), x, 65536); - intCheckRem("irem_by_pow2_17", irem_by_pow2_17(x), x, 131072); - intCheckRem("irem_by_pow2_18", irem_by_pow2_18(x), x, 262144); - intCheckRem("irem_by_pow2_19", irem_by_pow2_19(x), x, 524288); - intCheckRem("irem_by_pow2_20", irem_by_pow2_20(x), x, 1048576); - intCheckRem("irem_by_pow2_21", irem_by_pow2_21(x), x, 2097152); - intCheckRem("irem_by_pow2_22", irem_by_pow2_22(x), x, 4194304); - intCheckRem("irem_by_pow2_23", irem_by_pow2_23(x), x, 8388608); - intCheckRem("irem_by_pow2_24", irem_by_pow2_24(x), x, 16777216); - intCheckRem("irem_by_pow2_25", irem_by_pow2_25(x), x, 33554432); - intCheckRem("irem_by_pow2_26", irem_by_pow2_26(x), x, 67108864); - intCheckRem("irem_by_pow2_27", irem_by_pow2_27(x), x, 134217728); - intCheckRem("irem_by_pow2_28", irem_by_pow2_28(x), x, 268435456); - intCheckRem("irem_by_pow2_29", irem_by_pow2_29(x), x, 536870912); - intCheckRem("irem_by_pow2_30", irem_by_pow2_30(x), x, 1073741824); - } - - public static void longCheckAll(long x) { - longCheckDiv("ldiv_by_pow2_0", ldiv_by_pow2_0(x), x, 1l); - longCheckDiv("ldiv_by_pow2_1", ldiv_by_pow2_1(x), x, 2l); - longCheckDiv("ldiv_by_pow2_2", ldiv_by_pow2_2(x), x, 4l); - longCheckDiv("ldiv_by_pow2_3", ldiv_by_pow2_3(x), x, 8l); - longCheckDiv("ldiv_by_pow2_4", ldiv_by_pow2_4(x), x, 16l); - longCheckDiv("ldiv_by_pow2_5", ldiv_by_pow2_5(x), x, 32l); - longCheckDiv("ldiv_by_pow2_6", ldiv_by_pow2_6(x), x, 64l); - longCheckDiv("ldiv_by_pow2_7", ldiv_by_pow2_7(x), x, 128l); - longCheckDiv("ldiv_by_pow2_8", ldiv_by_pow2_8(x), x, 256l); - longCheckDiv("ldiv_by_pow2_9", ldiv_by_pow2_9(x), x, 512l); - longCheckDiv("ldiv_by_pow2_10", ldiv_by_pow2_10(x), x, 1024l); - longCheckDiv("ldiv_by_pow2_11", ldiv_by_pow2_11(x), x, 2048l); - longCheckDiv("ldiv_by_pow2_12", ldiv_by_pow2_12(x), x, 4096l); - longCheckDiv("ldiv_by_pow2_13", ldiv_by_pow2_13(x), x, 8192l); - longCheckDiv("ldiv_by_pow2_14", ldiv_by_pow2_14(x), x, 16384l); - longCheckDiv("ldiv_by_pow2_15", ldiv_by_pow2_15(x), x, 32768l); - longCheckDiv("ldiv_by_pow2_16", ldiv_by_pow2_16(x), x, 65536l); - longCheckDiv("ldiv_by_pow2_17", ldiv_by_pow2_17(x), x, 131072l); - longCheckDiv("ldiv_by_pow2_18", ldiv_by_pow2_18(x), x, 262144l); - longCheckDiv("ldiv_by_pow2_19", ldiv_by_pow2_19(x), x, 524288l); - longCheckDiv("ldiv_by_pow2_20", ldiv_by_pow2_20(x), x, 1048576l); - longCheckDiv("ldiv_by_pow2_21", ldiv_by_pow2_21(x), x, 2097152l); - longCheckDiv("ldiv_by_pow2_22", ldiv_by_pow2_22(x), x, 4194304l); - longCheckDiv("ldiv_by_pow2_23", ldiv_by_pow2_23(x), x, 8388608l); - longCheckDiv("ldiv_by_pow2_24", ldiv_by_pow2_24(x), x, 16777216l); - longCheckDiv("ldiv_by_pow2_25", ldiv_by_pow2_25(x), x, 33554432l); - longCheckDiv("ldiv_by_pow2_26", ldiv_by_pow2_26(x), x, 67108864l); - longCheckDiv("ldiv_by_pow2_27", ldiv_by_pow2_27(x), x, 134217728l); - longCheckDiv("ldiv_by_pow2_28", ldiv_by_pow2_28(x), x, 268435456l); - longCheckDiv("ldiv_by_pow2_29", ldiv_by_pow2_29(x), x, 536870912l); - longCheckDiv("ldiv_by_pow2_30", ldiv_by_pow2_30(x), x, 1073741824l); - longCheckDiv("ldiv_by_pow2_31", ldiv_by_pow2_31(x), x, 2147483648l); - longCheckDiv("ldiv_by_pow2_32", ldiv_by_pow2_32(x), x, 4294967296l); - longCheckDiv("ldiv_by_pow2_33", ldiv_by_pow2_33(x), x, 8589934592l); - longCheckDiv("ldiv_by_pow2_34", ldiv_by_pow2_34(x), x, 17179869184l); - longCheckDiv("ldiv_by_pow2_35", ldiv_by_pow2_35(x), x, 34359738368l); - longCheckDiv("ldiv_by_pow2_36", ldiv_by_pow2_36(x), x, 68719476736l); - longCheckDiv("ldiv_by_pow2_37", ldiv_by_pow2_37(x), x, 137438953472l); - longCheckDiv("ldiv_by_pow2_38", ldiv_by_pow2_38(x), x, 274877906944l); - longCheckDiv("ldiv_by_pow2_39", ldiv_by_pow2_39(x), x, 549755813888l); - longCheckDiv("ldiv_by_pow2_40", ldiv_by_pow2_40(x), x, 1099511627776l); - longCheckDiv("ldiv_by_pow2_41", ldiv_by_pow2_41(x), x, 2199023255552l); - longCheckDiv("ldiv_by_pow2_42", ldiv_by_pow2_42(x), x, 4398046511104l); - longCheckDiv("ldiv_by_pow2_43", ldiv_by_pow2_43(x), x, 8796093022208l); - longCheckDiv("ldiv_by_pow2_44", ldiv_by_pow2_44(x), x, 17592186044416l); - longCheckDiv("ldiv_by_pow2_45", ldiv_by_pow2_45(x), x, 35184372088832l); - longCheckDiv("ldiv_by_pow2_46", ldiv_by_pow2_46(x), x, 70368744177664l); - longCheckDiv("ldiv_by_pow2_47", ldiv_by_pow2_47(x), x, 140737488355328l); - longCheckDiv("ldiv_by_pow2_48", ldiv_by_pow2_48(x), x, 281474976710656l); - longCheckDiv("ldiv_by_pow2_49", ldiv_by_pow2_49(x), x, 562949953421312l); - longCheckDiv("ldiv_by_pow2_50", ldiv_by_pow2_50(x), x, 1125899906842624l); - longCheckDiv("ldiv_by_pow2_51", ldiv_by_pow2_51(x), x, 2251799813685248l); - longCheckDiv("ldiv_by_pow2_52", ldiv_by_pow2_52(x), x, 4503599627370496l); - longCheckDiv("ldiv_by_pow2_53", ldiv_by_pow2_53(x), x, 9007199254740992l); - longCheckDiv("ldiv_by_pow2_54", ldiv_by_pow2_54(x), x, 18014398509481984l); - longCheckDiv("ldiv_by_pow2_55", ldiv_by_pow2_55(x), x, 36028797018963968l); - longCheckDiv("ldiv_by_pow2_56", ldiv_by_pow2_56(x), x, 72057594037927936l); - longCheckDiv("ldiv_by_pow2_57", ldiv_by_pow2_57(x), x, 144115188075855872l); - longCheckDiv("ldiv_by_pow2_58", ldiv_by_pow2_58(x), x, 288230376151711744l); - longCheckDiv("ldiv_by_pow2_59", ldiv_by_pow2_59(x), x, 576460752303423488l); - longCheckDiv("ldiv_by_pow2_60", ldiv_by_pow2_60(x), x, 1152921504606846976l); - longCheckDiv("ldiv_by_pow2_61", ldiv_by_pow2_61(x), x, 2305843009213693952l); - longCheckDiv("ldiv_by_pow2_62", ldiv_by_pow2_62(x), x, 4611686018427387904l); - longCheckDiv("ldiv_by_small_0", ldiv_by_small_0(x), x, 3l); - longCheckDiv("ldiv_by_small_1", ldiv_by_small_1(x), x, 5l); - longCheckDiv("ldiv_by_small_2", ldiv_by_small_2(x), x, 6l); - longCheckDiv("ldiv_by_small_3", ldiv_by_small_3(x), x, 7l); - longCheckDiv("ldiv_by_small_4", ldiv_by_small_4(x), x, 9l); - longCheckDiv("ldiv_by_small_5", ldiv_by_small_5(x), x, 10l); - longCheckDiv("ldiv_by_small_6", ldiv_by_small_6(x), x, 11l); - longCheckDiv("ldiv_by_small_7", ldiv_by_small_7(x), x, 12l); - longCheckDiv("ldiv_by_small_8", ldiv_by_small_8(x), x, 13l); - longCheckDiv("ldiv_by_small_9", ldiv_by_small_9(x), x, 14l); - longCheckDiv("ldiv_by_small_10", ldiv_by_small_10(x), x, 15l); - longCheckRem("lrem_by_pow2_0", lrem_by_pow2_0(x), x, 1l); - longCheckRem("lrem_by_pow2_1", lrem_by_pow2_1(x), x, 2l); - longCheckRem("lrem_by_pow2_2", lrem_by_pow2_2(x), x, 4l); - longCheckRem("lrem_by_pow2_3", lrem_by_pow2_3(x), x, 8l); - longCheckRem("lrem_by_pow2_4", lrem_by_pow2_4(x), x, 16l); - longCheckRem("lrem_by_pow2_5", lrem_by_pow2_5(x), x, 32l); - longCheckRem("lrem_by_pow2_6", lrem_by_pow2_6(x), x, 64l); - longCheckRem("lrem_by_pow2_7", lrem_by_pow2_7(x), x, 128l); - longCheckRem("lrem_by_pow2_8", lrem_by_pow2_8(x), x, 256l); - longCheckRem("lrem_by_pow2_9", lrem_by_pow2_9(x), x, 512l); - longCheckRem("lrem_by_pow2_10", lrem_by_pow2_10(x), x, 1024l); - longCheckRem("lrem_by_pow2_11", lrem_by_pow2_11(x), x, 2048l); - longCheckRem("lrem_by_pow2_12", lrem_by_pow2_12(x), x, 4096l); - longCheckRem("lrem_by_pow2_13", lrem_by_pow2_13(x), x, 8192l); - longCheckRem("lrem_by_pow2_14", lrem_by_pow2_14(x), x, 16384l); - longCheckRem("lrem_by_pow2_15", lrem_by_pow2_15(x), x, 32768l); - longCheckRem("lrem_by_pow2_16", lrem_by_pow2_16(x), x, 65536l); - longCheckRem("lrem_by_pow2_17", lrem_by_pow2_17(x), x, 131072l); - longCheckRem("lrem_by_pow2_18", lrem_by_pow2_18(x), x, 262144l); - longCheckRem("lrem_by_pow2_19", lrem_by_pow2_19(x), x, 524288l); - longCheckRem("lrem_by_pow2_20", lrem_by_pow2_20(x), x, 1048576l); - longCheckRem("lrem_by_pow2_21", lrem_by_pow2_21(x), x, 2097152l); - longCheckRem("lrem_by_pow2_22", lrem_by_pow2_22(x), x, 4194304l); - longCheckRem("lrem_by_pow2_23", lrem_by_pow2_23(x), x, 8388608l); - longCheckRem("lrem_by_pow2_24", lrem_by_pow2_24(x), x, 16777216l); - longCheckRem("lrem_by_pow2_25", lrem_by_pow2_25(x), x, 33554432l); - longCheckRem("lrem_by_pow2_26", lrem_by_pow2_26(x), x, 67108864l); - longCheckRem("lrem_by_pow2_27", lrem_by_pow2_27(x), x, 134217728l); - longCheckRem("lrem_by_pow2_28", lrem_by_pow2_28(x), x, 268435456l); - longCheckRem("lrem_by_pow2_29", lrem_by_pow2_29(x), x, 536870912l); - longCheckRem("lrem_by_pow2_30", lrem_by_pow2_30(x), x, 1073741824l); - longCheckRem("lrem_by_pow2_31", lrem_by_pow2_31(x), x, 2147483648l); - longCheckRem("lrem_by_pow2_32", lrem_by_pow2_32(x), x, 4294967296l); - longCheckRem("lrem_by_pow2_33", lrem_by_pow2_33(x), x, 8589934592l); - longCheckRem("lrem_by_pow2_34", lrem_by_pow2_34(x), x, 17179869184l); - longCheckRem("lrem_by_pow2_35", lrem_by_pow2_35(x), x, 34359738368l); - longCheckRem("lrem_by_pow2_36", lrem_by_pow2_36(x), x, 68719476736l); - longCheckRem("lrem_by_pow2_37", lrem_by_pow2_37(x), x, 137438953472l); - longCheckRem("lrem_by_pow2_38", lrem_by_pow2_38(x), x, 274877906944l); - longCheckRem("lrem_by_pow2_39", lrem_by_pow2_39(x), x, 549755813888l); - longCheckRem("lrem_by_pow2_40", lrem_by_pow2_40(x), x, 1099511627776l); - longCheckRem("lrem_by_pow2_41", lrem_by_pow2_41(x), x, 2199023255552l); - longCheckRem("lrem_by_pow2_42", lrem_by_pow2_42(x), x, 4398046511104l); - longCheckRem("lrem_by_pow2_43", lrem_by_pow2_43(x), x, 8796093022208l); - longCheckRem("lrem_by_pow2_44", lrem_by_pow2_44(x), x, 17592186044416l); - longCheckRem("lrem_by_pow2_45", lrem_by_pow2_45(x), x, 35184372088832l); - longCheckRem("lrem_by_pow2_46", lrem_by_pow2_46(x), x, 70368744177664l); - longCheckRem("lrem_by_pow2_47", lrem_by_pow2_47(x), x, 140737488355328l); - longCheckRem("lrem_by_pow2_48", lrem_by_pow2_48(x), x, 281474976710656l); - longCheckRem("lrem_by_pow2_49", lrem_by_pow2_49(x), x, 562949953421312l); - longCheckRem("lrem_by_pow2_50", lrem_by_pow2_50(x), x, 1125899906842624l); - longCheckRem("lrem_by_pow2_51", lrem_by_pow2_51(x), x, 2251799813685248l); - longCheckRem("lrem_by_pow2_52", lrem_by_pow2_52(x), x, 4503599627370496l); - longCheckRem("lrem_by_pow2_53", lrem_by_pow2_53(x), x, 9007199254740992l); - longCheckRem("lrem_by_pow2_54", lrem_by_pow2_54(x), x, 18014398509481984l); - longCheckRem("lrem_by_pow2_55", lrem_by_pow2_55(x), x, 36028797018963968l); - longCheckRem("lrem_by_pow2_56", lrem_by_pow2_56(x), x, 72057594037927936l); - longCheckRem("lrem_by_pow2_57", lrem_by_pow2_57(x), x, 144115188075855872l); - longCheckRem("lrem_by_pow2_58", lrem_by_pow2_58(x), x, 288230376151711744l); - longCheckRem("lrem_by_pow2_59", lrem_by_pow2_59(x), x, 576460752303423488l); - longCheckRem("lrem_by_pow2_60", lrem_by_pow2_60(x), x, 1152921504606846976l); - longCheckRem("lrem_by_pow2_61", lrem_by_pow2_61(x), x, 2305843009213693952l); - longCheckRem("lrem_by_pow2_62", lrem_by_pow2_62(x), x, 4611686018427387904l); - } - - public static void main(String[] args) { - int i; - long l; - - System.out.println("Begin"); - - System.out.println("Int: checking some equally spaced dividends..."); - for (i = -1000; i < 1000; i += 300) { - intCheckAll(i); - intCheckAll(-i); - } - - System.out.println("Int: checking small dividends..."); - for (i = 1; i < 100; i += 1) { - intCheckAll(i); - intCheckAll(-i); - } - - System.out.println("Int: checking big dividends..."); - for (i = 0; i < 100; i += 1) { - intCheckAll(Integer.MAX_VALUE - i); - intCheckAll(Integer.MIN_VALUE + i); - } - - System.out.println("Long: checking some equally spaced dividends..."); - for (l = 0l; l < 1000000000000l; l += 300000000000l) { - longCheckAll(l); - longCheckAll(-l); - } - - System.out.println("Long: checking small dividends..."); - for (l = 1l; l < 100l; l += 1l) { - longCheckAll(l); - longCheckAll(-l); - } - - System.out.println("Long: checking big dividends..."); - for (l = 0l; l < 100l; l += 1l) { - longCheckAll(Long.MAX_VALUE - l); - longCheckAll(Long.MIN_VALUE + l); - } - - System.out.println("End"); - } -} diff --git a/test/702-LargeBranchOffset/build b/test/702-LargeBranchOffset/build index eacf730cb9..20030fa466 100644 --- a/test/702-LargeBranchOffset/build +++ b/test/702-LargeBranchOffset/build @@ -17,11 +17,7 @@ # Stop if something fails. set -e -# Write out a bunch of source files. +# Write out the source file. cpp -P src/Main.java.in src/Main.java -mkdir classes -${JAVAC} -d classes src/*.java - -${DX} --debug --dex --output=classes.dex classes -zip $TEST_NAME.jar classes.dex +./default-build diff --git a/test/run-test b/test/run-test index 239681ff4e..54c6bbda12 100755 --- a/test/run-test +++ b/test/run-test @@ -501,14 +501,20 @@ cd "$tmp_dir" if [ '!' -r "$build" ]; then cp "${progdir}/etc/default-build" build +else + cp "${progdir}/etc/default-build" . fi if [ '!' -r "$run" ]; then cp "${progdir}/etc/default-run" run +else + cp "${progdir}/etc/default-run" . fi if [ '!' -r "$check_cmd" ]; then cp "${progdir}/etc/default-check" check +else + cp "${progdir}/etc/default-check" . fi chmod 755 "$build" |