Merge "Refine the DexOptNeeded codes."
diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc
index 59e1784..a78b3da 100644
--- a/compiler/optimizing/code_generator_arm64.cc
+++ b/compiler/optimizing/code_generator_arm64.cc
@@ -572,8 +572,10 @@
// We are about to use the assembler to place literals directly. Make sure we have enough
// underlying code buffer and we have generated the jump table with right size.
- CodeBufferCheckScope scope(codegen->GetVIXLAssembler(), num_entries * sizeof(int32_t),
- CodeBufferCheckScope::kCheck, CodeBufferCheckScope::kExactSize);
+ vixl::CodeBufferCheckScope scope(codegen->GetVIXLAssembler(),
+ num_entries * sizeof(int32_t),
+ vixl::CodeBufferCheckScope::kReserveBufferSpace,
+ vixl::CodeBufferCheckScope::kExactSize);
__ Bind(&table_start_);
const ArenaVector<HBasicBlock*>& successors = switch_instr_->GetBlock()->GetSuccessors();
@@ -2260,10 +2262,10 @@
masm->GetCursorAddress<vixl::aarch64::Instruction*>() - kInstructionSize;
if (prev->IsLoadOrStore()) {
// Make sure we emit only exactly one nop.
- vixl::aarch64::CodeBufferCheckScope scope(masm,
- kInstructionSize,
- vixl::aarch64::CodeBufferCheckScope::kCheck,
- vixl::aarch64::CodeBufferCheckScope::kExactSize);
+ vixl::CodeBufferCheckScope scope(masm,
+ kInstructionSize,
+ vixl::CodeBufferCheckScope::kReserveBufferSpace,
+ vixl::CodeBufferCheckScope::kExactSize);
__ nop();
}
}
@@ -4036,7 +4038,8 @@
vixl::aarch64::Label* label = &relative_call_patches_.back().label;
SingleEmissionCheckScope guard(GetVIXLAssembler());
__ Bind(label);
- __ bl(0); // Branch and link to itself. This will be overriden at link time.
+ // Branch and link to itself. This will be overriden at link time.
+ __ bl(static_cast<int64_t>(0));
break;
}
case HInvokeStaticOrDirect::CodePtrLocation::kCallDirectWithFixup:
@@ -4167,7 +4170,7 @@
DCHECK(reg.IsX());
SingleEmissionCheckScope guard(GetVIXLAssembler());
__ Bind(fixup_label);
- __ adrp(reg, /* offset placeholder */ 0);
+ __ adrp(reg, /* offset placeholder */ static_cast<int64_t>(0));
}
void CodeGeneratorARM64::EmitAddPlaceholder(vixl::aarch64::Label* fixup_label,
diff --git a/compiler/optimizing/code_generator_arm_vixl.cc b/compiler/optimizing/code_generator_arm_vixl.cc
index 7aea616..e399f32 100644
--- a/compiler/optimizing/code_generator_arm_vixl.cc
+++ b/compiler/optimizing/code_generator_arm_vixl.cc
@@ -47,6 +47,7 @@
using helpers::InputRegisterAt;
using helpers::InputSRegisterAt;
using helpers::InputVRegisterAt;
+using helpers::Int32ConstantFrom;
using helpers::LocationFrom;
using helpers::LowRegisterFrom;
using helpers::LowSRegisterFrom;
@@ -132,7 +133,7 @@
vixl32::Register base = sp;
if (stack_offset != 0) {
base = temps.Acquire();
- __ Add(base, sp, stack_offset);
+ __ Add(base, sp, Operand::From(stack_offset));
}
__ Vstm(F64, base, NO_WRITE_BACK, DRegisterList(d_reg, number_of_d_regs));
}
@@ -180,7 +181,7 @@
vixl32::Register base = sp;
if (stack_offset != 0) {
base = temps.Acquire();
- __ Add(base, sp, stack_offset);
+ __ Add(base, sp, Operand::From(stack_offset));
}
__ Vldm(F64, base, NO_WRITE_BACK, DRegisterList(d_reg, number_of_d_regs));
}
@@ -673,8 +674,8 @@
DCHECK_GE(num_entries, kPackedSwitchCompareJumpThreshold);
// We are about to use the assembler to place literals directly. Make sure we have enough
- // underlying code buffer and we have generated the jump table with right size.
- codegen->GetVIXLAssembler()->GetBuffer().Align();
+ // underlying code buffer and we have generated a jump table of the right size, using
+ // codegen->GetVIXLAssembler()->GetBuffer().Align();
AssemblerAccurateScope aas(codegen->GetVIXLAssembler(),
num_entries * sizeof(int32_t),
CodeBufferCheckScope::kMaximumSize);
@@ -701,7 +702,7 @@
DCHECK_GT(jump_offset, std::numeric_limits<int32_t>::min());
DCHECK_LE(jump_offset, std::numeric_limits<int32_t>::max());
- bb_addresses_[i].get()->UpdateValue(jump_offset, &codegen->GetVIXLAssembler()->GetBuffer());
+ bb_addresses_[i].get()->UpdateValue(jump_offset, codegen->GetVIXLAssembler()->GetBuffer());
}
}
@@ -1667,7 +1668,20 @@
// Set the hidden (in r12) argument. It is done here, right before a BLX to prevent other
// instruction from clobbering it as they might use r12 as a scratch register.
DCHECK(hidden_reg.Is(r12));
- __ Mov(hidden_reg, invoke->GetDexMethodIndex());
+
+ {
+ // The VIXL macro assembler may clobber any of the scratch registers that are available to it,
+ // so it checks if the application is using them (by passing them to the macro assembler
+ // methods). The following application of UseScratchRegisterScope corrects VIXL's notion of
+ // what is available, and is the opposite of the standard usage: Instead of requesting a
+ // temporary location, it imposes an external constraint (i.e. a specific register is reserved
+ // for the hidden argument). Note that this works even if VIXL needs a scratch register itself
+ // (to materialize the constant), since the destination register becomes available for such use
+ // internally for the duration of the macro instruction.
+ UseScratchRegisterScope temps(GetVIXLAssembler());
+ temps.Exclude(hidden_reg);
+ __ Mov(hidden_reg, invoke->GetDexMethodIndex());
+ }
{
AssemblerAccurateScope aas(GetVIXLAssembler(),
@@ -2458,13 +2472,13 @@
vixl32::Register dividend = InputRegisterAt(instruction, 0);
vixl32::Register temp1 = RegisterFrom(locations->GetTemp(0));
vixl32::Register temp2 = RegisterFrom(locations->GetTemp(1));
- int64_t imm = second.GetConstant()->AsIntConstant()->GetValue();
+ int32_t imm = Int32ConstantFrom(second);
int64_t magic;
int shift;
CalculateMagicAndShiftForDivRem(imm, false /* is_long */, &magic, &shift);
- __ Mov(temp1, magic);
+ __ Mov(temp1, Operand::From(magic));
__ Smull(temp2, temp1, dividend, temp1);
if (imm > 0 && magic < 0) {
@@ -2857,9 +2871,9 @@
}
// Rotate, or mov to out for zero or word size rotations.
if (rot != 0u) {
- __ Lsr(out_reg_hi, in_reg_hi, rot);
+ __ Lsr(out_reg_hi, in_reg_hi, Operand::From(rot));
__ Orr(out_reg_hi, out_reg_hi, Operand(in_reg_lo, ShiftType::LSL, kArmBitsPerWord - rot));
- __ Lsr(out_reg_lo, in_reg_lo, rot);
+ __ Lsr(out_reg_lo, in_reg_lo, Operand::From(rot));
__ Orr(out_reg_lo, out_reg_lo, Operand(in_reg_hi, ShiftType::LSL, kArmBitsPerWord - rot));
} else {
__ Mov(out_reg_lo, in_reg_lo);
@@ -2874,7 +2888,7 @@
__ And(shift_right, RegisterFrom(rhs), 0x1F);
__ Lsrs(shift_left, RegisterFrom(rhs), 6);
// TODO(VIXL): Check that flags are kept after "vixl32::LeaveFlags" enabled.
- __ Rsb(shift_left, shift_right, kArmBitsPerWord);
+ __ Rsb(shift_left, shift_right, Operand::From(kArmBitsPerWord));
__ B(cc, &shift_by_32_plus_shift_right);
// out_reg_hi = (reg_hi << shift_left) | (reg_lo >> shift_right).
@@ -3040,11 +3054,11 @@
// Shift the high part
__ Lsl(o_h, high, o_l);
// Shift the low part and `or` what overflew on the high part
- __ Rsb(temp, o_l, kArmBitsPerWord);
+ __ Rsb(temp, o_l, Operand::From(kArmBitsPerWord));
__ Lsr(temp, low, temp);
__ Orr(o_h, o_h, temp);
// If the shift is > 32 bits, override the high part
- __ Subs(temp, o_l, kArmBitsPerWord);
+ __ Subs(temp, o_l, Operand::From(kArmBitsPerWord));
{
AssemblerAccurateScope guard(GetVIXLAssembler(),
3 * kArmInstrMaxSizeInBytes,
@@ -3059,11 +3073,11 @@
// Shift the low part
__ Lsr(o_l, low, o_h);
// Shift the high part and `or` what underflew on the low part
- __ Rsb(temp, o_h, kArmBitsPerWord);
+ __ Rsb(temp, o_h, Operand::From(kArmBitsPerWord));
__ Lsl(temp, high, temp);
__ Orr(o_l, o_l, temp);
// If the shift is > 32 bits, override the low part
- __ Subs(temp, o_h, kArmBitsPerWord);
+ __ Subs(temp, o_h, Operand::From(kArmBitsPerWord));
{
AssemblerAccurateScope guard(GetVIXLAssembler(),
3 * kArmInstrMaxSizeInBytes,
@@ -3077,10 +3091,10 @@
__ And(o_h, second_reg, kMaxLongShiftDistance);
// same as Shr except we use `Lsr`s and not `Asr`s
__ Lsr(o_l, low, o_h);
- __ Rsb(temp, o_h, kArmBitsPerWord);
+ __ Rsb(temp, o_h, Operand::From(kArmBitsPerWord));
__ Lsl(temp, high, temp);
__ Orr(o_l, o_l, temp);
- __ Subs(temp, o_h, kArmBitsPerWord);
+ __ Subs(temp, o_h, Operand::From(kArmBitsPerWord));
{
AssemblerAccurateScope guard(GetVIXLAssembler(),
3 * kArmInstrMaxSizeInBytes,
@@ -3424,7 +3438,7 @@
__ Add(temp, addr, offset);
addr = temp;
}
- __ Ldrexd(out_lo, out_hi, addr);
+ __ Ldrexd(out_lo, out_hi, MemOperand(addr));
}
void InstructionCodeGeneratorARMVIXL::GenerateWideAtomicStore(vixl32::Register addr,
@@ -3444,9 +3458,9 @@
__ Bind(&fail);
// We need a load followed by store. (The address used in a STREX instruction must
// be the same as the address in the most recently executed LDREX instruction.)
- __ Ldrexd(temp1, temp2, addr);
+ __ Ldrexd(temp1, temp2, MemOperand(addr));
codegen_->MaybeRecordImplicitNullCheck(instruction);
- __ Strexd(temp1, value_lo, value_hi, addr);
+ __ Strexd(temp1, value_lo, value_hi, MemOperand(addr));
__ CompareAndBranchIfNonZero(temp1, &fail);
}
@@ -4648,7 +4662,7 @@
}
GetAssembler()->LoadFromOffset(
kLoadWord, card, tr, Thread::CardTableOffset<kArmPointerSize>().Int32Value());
- __ Lsr(temp, object, gc::accounting::CardTable::kCardShift);
+ __ Lsr(temp, object, Operand::From(gc::accounting::CardTable::kCardShift));
__ Strb(card, MemOperand(card, temp));
if (can_be_null) {
__ Bind(&is_null);
diff --git a/compiler/optimizing/common_arm.h b/compiler/optimizing/common_arm.h
index 5129daf..d3623f1 100644
--- a/compiler/optimizing/common_arm.h
+++ b/compiler/optimizing/common_arm.h
@@ -139,9 +139,14 @@
HConstant* instr = location.GetConstant();
if (instr->IsIntConstant()) {
return instr->AsIntConstant()->GetValue();
- } else {
- DCHECK(instr->IsNullConstant()) << instr->DebugName();
+ } else if (instr->IsNullConstant()) {
return 0;
+ } else {
+ DCHECK(instr->IsLongConstant()) << instr->DebugName();
+ const int64_t ret = instr->AsLongConstant()->GetValue();
+ DCHECK_GE(ret, std::numeric_limits<int32_t>::min());
+ DCHECK_LE(ret, std::numeric_limits<int32_t>::max());
+ return ret;
}
}
@@ -161,7 +166,7 @@
if (location.IsRegister()) {
return vixl::aarch32::Operand(RegisterFrom(location, type));
} else {
- return vixl::aarch32::Operand(Int64ConstantFrom(location));
+ return vixl::aarch32::Operand(Int32ConstantFrom(location));
}
}
diff --git a/compiler/optimizing/intrinsics_arm_vixl.cc b/compiler/optimizing/intrinsics_arm_vixl.cc
index 7a1ec9f..c8e3534 100644
--- a/compiler/optimizing/intrinsics_arm_vixl.cc
+++ b/compiler/optimizing/intrinsics_arm_vixl.cc
@@ -518,7 +518,7 @@
void IntrinsicCodeGeneratorARMVIXL::VisitMemoryPeekByte(HInvoke* invoke) {
ArmVIXLAssembler* assembler = GetAssembler();
// Ignore upper 4B of long address.
- __ Ldrsb(OutputRegister(invoke), LowRegisterFrom(invoke->GetLocations()->InAt(0)));
+ __ Ldrsb(OutputRegister(invoke), MemOperand(LowRegisterFrom(invoke->GetLocations()->InAt(0))));
}
void IntrinsicLocationsBuilderARMVIXL::VisitMemoryPeekIntNative(HInvoke* invoke) {
@@ -528,7 +528,7 @@
void IntrinsicCodeGeneratorARMVIXL::VisitMemoryPeekIntNative(HInvoke* invoke) {
ArmVIXLAssembler* assembler = GetAssembler();
// Ignore upper 4B of long address.
- __ Ldr(OutputRegister(invoke), LowRegisterFrom(invoke->GetLocations()->InAt(0)));
+ __ Ldr(OutputRegister(invoke), MemOperand(LowRegisterFrom(invoke->GetLocations()->InAt(0))));
}
void IntrinsicLocationsBuilderARMVIXL::VisitMemoryPeekLongNative(HInvoke* invoke) {
@@ -545,9 +545,9 @@
vixl32::Register hi = HighRegisterFrom(invoke->GetLocations()->Out());
if (addr.Is(lo)) {
__ Ldr(hi, MemOperand(addr, 4));
- __ Ldr(lo, addr);
+ __ Ldr(lo, MemOperand(addr));
} else {
- __ Ldr(lo, addr);
+ __ Ldr(lo, MemOperand(addr));
__ Ldr(hi, MemOperand(addr, 4));
}
}
@@ -559,7 +559,7 @@
void IntrinsicCodeGeneratorARMVIXL::VisitMemoryPeekShortNative(HInvoke* invoke) {
ArmVIXLAssembler* assembler = GetAssembler();
// Ignore upper 4B of long address.
- __ Ldrsh(OutputRegister(invoke), LowRegisterFrom(invoke->GetLocations()->InAt(0)));
+ __ Ldrsh(OutputRegister(invoke), MemOperand(LowRegisterFrom(invoke->GetLocations()->InAt(0))));
}
static void CreateIntIntToVoidLocations(ArenaAllocator* arena, HInvoke* invoke) {
@@ -576,7 +576,7 @@
void IntrinsicCodeGeneratorARMVIXL::VisitMemoryPokeByte(HInvoke* invoke) {
ArmVIXLAssembler* assembler = GetAssembler();
- __ Strb(InputRegisterAt(invoke, 1), LowRegisterFrom(invoke->GetLocations()->InAt(0)));
+ __ Strb(InputRegisterAt(invoke, 1), MemOperand(LowRegisterFrom(invoke->GetLocations()->InAt(0))));
}
void IntrinsicLocationsBuilderARMVIXL::VisitMemoryPokeIntNative(HInvoke* invoke) {
@@ -585,7 +585,7 @@
void IntrinsicCodeGeneratorARMVIXL::VisitMemoryPokeIntNative(HInvoke* invoke) {
ArmVIXLAssembler* assembler = GetAssembler();
- __ Str(InputRegisterAt(invoke, 1), LowRegisterFrom(invoke->GetLocations()->InAt(0)));
+ __ Str(InputRegisterAt(invoke, 1), MemOperand(LowRegisterFrom(invoke->GetLocations()->InAt(0))));
}
void IntrinsicLocationsBuilderARMVIXL::VisitMemoryPokeLongNative(HInvoke* invoke) {
@@ -598,7 +598,7 @@
vixl32::Register addr = LowRegisterFrom(invoke->GetLocations()->InAt(0));
// Worst case: Control register bit SCTLR.A = 0. Then unaligned accesses throw a processor
// exception. So we can't use ldrd as addr may be unaligned.
- __ Str(LowRegisterFrom(invoke->GetLocations()->InAt(1)), addr);
+ __ Str(LowRegisterFrom(invoke->GetLocations()->InAt(1)), MemOperand(addr));
__ Str(HighRegisterFrom(invoke->GetLocations()->InAt(1)), MemOperand(addr, 4));
}
@@ -608,7 +608,7 @@
void IntrinsicCodeGeneratorARMVIXL::VisitMemoryPokeShortNative(HInvoke* invoke) {
ArmVIXLAssembler* assembler = GetAssembler();
- __ Strh(InputRegisterAt(invoke, 1), LowRegisterFrom(invoke->GetLocations()->InAt(0)));
+ __ Strh(InputRegisterAt(invoke, 1), MemOperand(LowRegisterFrom(invoke->GetLocations()->InAt(0))));
}
void IntrinsicLocationsBuilderARMVIXL::VisitThreadCurrentThread(HInvoke* invoke) {
@@ -842,8 +842,8 @@
__ Add(temp_reg, base, offset);
vixl32::Label loop_head;
__ Bind(&loop_head);
- __ Ldrexd(temp_lo, temp_hi, temp_reg);
- __ Strexd(temp_lo, value_lo, value_hi, temp_reg);
+ __ Ldrexd(temp_lo, temp_hi, MemOperand(temp_reg));
+ __ Strexd(temp_lo, value_lo, value_hi, MemOperand(temp_reg));
__ Cmp(temp_lo, 0);
__ B(ne, &loop_head);
} else {
@@ -1042,7 +1042,7 @@
vixl32::Label loop_head;
__ Bind(&loop_head);
- __ Ldrex(tmp, tmp_ptr);
+ __ Ldrex(tmp, MemOperand(tmp_ptr));
__ Subs(tmp, tmp, expected);
@@ -1052,7 +1052,7 @@
CodeBufferCheckScope::kMaximumSize);
__ itt(eq);
- __ strex(eq, tmp, value, tmp_ptr);
+ __ strex(eq, tmp, value, MemOperand(tmp_ptr));
__ cmp(eq, tmp, 1);
}
@@ -1220,7 +1220,7 @@
static_assert(IsAligned<8>(kObjectAlignment),
"String data must be 8-byte aligned for unrolled CompareTo loop.");
- const size_t char_size = Primitive::ComponentSize(Primitive::kPrimChar);
+ const unsigned char_size = Primitive::ComponentSize(Primitive::kPrimChar);
DCHECK_EQ(char_size, 2u);
UseScratchRegisterScope temps(assembler->GetVIXLAssembler());
@@ -1469,7 +1469,7 @@
__ Bind(&loop);
__ Ldr(out, MemOperand(str, temp1));
__ Ldr(temp2, MemOperand(arg, temp1));
- __ Add(temp1, temp1, sizeof(uint32_t));
+ __ Add(temp1, temp1, Operand::From(sizeof(uint32_t)));
__ Cmp(out, temp2);
__ B(ne, &return_false);
// With string compression, we have compared 4 bytes, otherwise 2 chars.
diff --git a/compiler/utils/arm/assembler_arm_vixl.cc b/compiler/utils/arm/assembler_arm_vixl.cc
index 1aaa231..c35c393 100644
--- a/compiler/utils/arm/assembler_arm_vixl.cc
+++ b/compiler/utils/arm/assembler_arm_vixl.cc
@@ -43,12 +43,12 @@
}
const uint8_t* ArmVIXLAssembler::CodeBufferBaseAddress() const {
- return vixl_masm_.GetStartAddress<uint8_t*>();
+ return vixl_masm_.GetBuffer().GetStartAddress<const uint8_t*>();
}
void ArmVIXLAssembler::FinalizeInstructions(const MemoryRegion& region) {
// Copy the instructions from the buffer.
- MemoryRegion from(vixl_masm_.GetStartAddress<void*>(), CodeSize());
+ MemoryRegion from(vixl_masm_.GetBuffer()->GetStartAddress<void*>(), CodeSize());
region.CopyFrom(0, from);
}
@@ -365,7 +365,7 @@
if (stack_offset != 0) {
base = temps.Acquire();
DCHECK_EQ(regs & (1u << base.GetCode()), 0u);
- ___ Add(base, sp, stack_offset);
+ ___ Add(base, sp, Operand::From(stack_offset));
}
___ Stm(base, NO_WRITE_BACK, RegisterList(regs));
} else {
@@ -385,7 +385,7 @@
vixl32::Register base = sp;
if (stack_offset != 0) {
base = temps.Acquire();
- ___ Add(base, sp, stack_offset);
+ ___ Add(base, sp, Operand::From(stack_offset));
}
___ Ldm(base, NO_WRITE_BACK, RegisterList(regs));
} else {
diff --git a/compiler/utils/arm/jni_macro_assembler_arm_vixl.cc b/compiler/utils/arm/jni_macro_assembler_arm_vixl.cc
index b2bbd72..f20ed0a 100644
--- a/compiler/utils/arm/jni_macro_assembler_arm_vixl.cc
+++ b/compiler/utils/arm/jni_macro_assembler_arm_vixl.cc
@@ -168,6 +168,8 @@
CHECK_EQ(0u, size);
} else if (src.IsCoreRegister()) {
CHECK_EQ(4u, size);
+ UseScratchRegisterScope temps(asm_.GetVIXLAssembler());
+ temps.Exclude(src.AsVIXLRegister());
asm_.StoreToOffset(kStoreWord, src.AsVIXLRegister(), sp, dest.Int32Value());
} else if (src.IsRegisterPair()) {
CHECK_EQ(8u, size);
@@ -186,12 +188,16 @@
void ArmVIXLJNIMacroAssembler::StoreRef(FrameOffset dest, ManagedRegister msrc) {
ArmManagedRegister src = msrc.AsArm();
CHECK(src.IsCoreRegister()) << src;
+ UseScratchRegisterScope temps(asm_.GetVIXLAssembler());
+ temps.Exclude(src.AsVIXLRegister());
asm_.StoreToOffset(kStoreWord, src.AsVIXLRegister(), sp, dest.Int32Value());
}
void ArmVIXLJNIMacroAssembler::StoreRawPtr(FrameOffset dest, ManagedRegister msrc) {
ArmManagedRegister src = msrc.AsArm();
CHECK(src.IsCoreRegister()) << src;
+ UseScratchRegisterScope temps(asm_.GetVIXLAssembler());
+ temps.Exclude(src.AsVIXLRegister());
asm_.StoreToOffset(kStoreWord, src.AsVIXLRegister(), sp, dest.Int32Value());
}
@@ -202,6 +208,8 @@
ArmManagedRegister src = msrc.AsArm();
ArmManagedRegister scratch = mscratch.AsArm();
asm_.StoreToOffset(kStoreWord, src.AsVIXLRegister(), sp, dest.Int32Value());
+ UseScratchRegisterScope temps(asm_.GetVIXLAssembler());
+ temps.Exclude(scratch.AsVIXLRegister());
asm_.LoadFromOffset(kLoadWord, scratch.AsVIXLRegister(), sp, in_off.Int32Value());
asm_.StoreToOffset(kStoreWord, scratch.AsVIXLRegister(), sp, dest.Int32Value() + 4);
}
@@ -210,6 +218,8 @@
FrameOffset src,
ManagedRegister mscratch) {
ArmManagedRegister scratch = mscratch.AsArm();
+ UseScratchRegisterScope temps(asm_.GetVIXLAssembler());
+ temps.Exclude(scratch.AsVIXLRegister());
asm_.LoadFromOffset(kLoadWord, scratch.AsVIXLRegister(), sp, src.Int32Value());
asm_.StoreToOffset(kStoreWord, scratch.AsVIXLRegister(), sp, dest.Int32Value());
}
@@ -220,6 +230,8 @@
bool unpoison_reference) {
ArmManagedRegister dst = dest.AsArm();
CHECK(dst.IsCoreRegister() && dst.IsCoreRegister()) << dst;
+ UseScratchRegisterScope temps(asm_.GetVIXLAssembler());
+ temps.Exclude(dst.AsVIXLRegister(), base.AsArm().AsVIXLRegister());
asm_.LoadFromOffset(kLoadWord,
dst.AsVIXLRegister(),
base.AsArm().AsVIXLRegister(),
@@ -246,6 +258,8 @@
ManagedRegister scratch) {
ArmManagedRegister mscratch = scratch.AsArm();
CHECK(mscratch.IsCoreRegister()) << mscratch;
+ UseScratchRegisterScope temps(asm_.GetVIXLAssembler());
+ temps.Exclude(mscratch.AsVIXLRegister());
asm_.LoadImmediate(mscratch.AsVIXLRegister(), imm);
asm_.StoreToOffset(kStoreWord, mscratch.AsVIXLRegister(), sp, dest.Int32Value());
}
@@ -263,6 +277,8 @@
void ArmVIXLJNIMacroAssembler::LoadRawPtrFromThread(ManagedRegister m_dst, ThreadOffset32 offs) {
ArmManagedRegister dst = m_dst.AsArm();
CHECK(dst.IsCoreRegister()) << dst;
+ UseScratchRegisterScope temps(asm_.GetVIXLAssembler());
+ temps.Exclude(dst.AsVIXLRegister());
asm_.LoadFromOffset(kLoadWord, dst.AsVIXLRegister(), tr, offs.Int32Value());
}
@@ -271,6 +287,8 @@
ManagedRegister mscratch) {
ArmManagedRegister scratch = mscratch.AsArm();
CHECK(scratch.IsCoreRegister()) << scratch;
+ UseScratchRegisterScope temps(asm_.GetVIXLAssembler());
+ temps.Exclude(scratch.AsVIXLRegister());
asm_.LoadFromOffset(kLoadWord, scratch.AsVIXLRegister(), tr, thr_offs.Int32Value());
asm_.StoreToOffset(kStoreWord, scratch.AsVIXLRegister(), sp, fr_offs.Int32Value());
}
@@ -286,6 +304,8 @@
ManagedRegister mscratch) {
ArmManagedRegister scratch = mscratch.AsArm();
CHECK(scratch.IsCoreRegister()) << scratch;
+ UseScratchRegisterScope temps(asm_.GetVIXLAssembler());
+ temps.Exclude(scratch.AsVIXLRegister());
asm_.AddConstant(scratch.AsVIXLRegister(), sp, fr_offs.Int32Value());
asm_.StoreToOffset(kStoreWord, scratch.AsVIXLRegister(), tr, thr_offs.Int32Value());
}
@@ -312,6 +332,8 @@
if (!dst.Equals(src)) {
if (dst.IsCoreRegister()) {
CHECK(src.IsCoreRegister()) << src;
+ UseScratchRegisterScope temps(asm_.GetVIXLAssembler());
+ temps.Exclude(dst.AsVIXLRegister());
___ Mov(dst.AsVIXLRegister(), src.AsVIXLRegister());
} else if (dst.IsDRegister()) {
if (src.IsDRegister()) {
@@ -351,6 +373,8 @@
ArmManagedRegister temp = scratch.AsArm();
CHECK(temp.IsCoreRegister()) << temp;
CHECK(size == 4 || size == 8) << size;
+ UseScratchRegisterScope temps(asm_.GetVIXLAssembler());
+ temps.Exclude(temp.AsVIXLRegister());
if (size == 4) {
asm_.LoadFromOffset(kLoadWord, temp.AsVIXLRegister(), sp, src.Int32Value());
asm_.StoreToOffset(kStoreWord, temp.AsVIXLRegister(), sp, dest.Int32Value());
@@ -414,6 +438,8 @@
ArmManagedRegister in_reg = min_reg.AsArm();
CHECK(in_reg.IsNoRegister() || in_reg.IsCoreRegister()) << in_reg;
CHECK(out_reg.IsCoreRegister()) << out_reg;
+ UseScratchRegisterScope temps(asm_.GetVIXLAssembler());
+ temps.Exclude(out_reg.AsVIXLRegister());
if (null_allowed) {
// Null values get a handle scope entry value of 0. Otherwise, the handle scope entry is
// the address in the handle scope holding the reference.
@@ -425,6 +451,8 @@
handle_scope_offset.Int32Value());
in_reg = out_reg;
}
+
+ temps.Exclude(in_reg.AsVIXLRegister());
___ Cmp(in_reg.AsVIXLRegister(), 0);
if (asm_.ShifterOperandCanHold(ADD, handle_scope_offset.Int32Value(), kCcDontCare)) {
@@ -457,6 +485,8 @@
bool null_allowed) {
ArmManagedRegister scratch = mscratch.AsArm();
CHECK(scratch.IsCoreRegister()) << scratch;
+ UseScratchRegisterScope temps(asm_.GetVIXLAssembler());
+ temps.Exclude(scratch.AsVIXLRegister());
if (null_allowed) {
asm_.LoadFromOffset(kLoadWord, scratch.AsVIXLRegister(), sp, handle_scope_offset.Int32Value());
// Null values get a handle scope entry value of 0. Otherwise, the handle scope entry is
@@ -503,6 +533,8 @@
ArmManagedRegister scratch = mscratch.AsArm();
CHECK(base.IsCoreRegister()) << base;
CHECK(scratch.IsCoreRegister()) << scratch;
+ UseScratchRegisterScope temps(asm_.GetVIXLAssembler());
+ temps.Exclude(scratch.AsVIXLRegister());
asm_.LoadFromOffset(kLoadWord,
scratch.AsVIXLRegister(),
base.AsVIXLRegister(),
@@ -514,6 +546,8 @@
void ArmVIXLJNIMacroAssembler::Call(FrameOffset base, Offset offset, ManagedRegister mscratch) {
ArmManagedRegister scratch = mscratch.AsArm();
CHECK(scratch.IsCoreRegister()) << scratch;
+ UseScratchRegisterScope temps(asm_.GetVIXLAssembler());
+ temps.Exclude(scratch.AsVIXLRegister());
// Call *(*(SP + base) + offset)
asm_.LoadFromOffset(kLoadWord, scratch.AsVIXLRegister(), sp, base.Int32Value());
asm_.LoadFromOffset(kLoadWord,
@@ -541,6 +575,8 @@
void ArmVIXLJNIMacroAssembler::ExceptionPoll(ManagedRegister m_scratch, size_t stack_adjust) {
CHECK_ALIGNED(stack_adjust, kStackAlignment);
ArmManagedRegister scratch = m_scratch.AsArm();
+ UseScratchRegisterScope temps(asm_.GetVIXLAssembler());
+ temps.Exclude(scratch.AsVIXLRegister());
exception_blocks_.emplace_back(
new ArmVIXLJNIMacroAssembler::ArmException(scratch, stack_adjust));
asm_.LoadFromOffset(kLoadWord,
@@ -598,11 +634,14 @@
if (exception->stack_adjust_ != 0) { // Fix up the frame.
DecreaseFrameSize(exception->stack_adjust_);
}
+
+ UseScratchRegisterScope temps(asm_.GetVIXLAssembler());
+ temps.Exclude(exception->scratch_.AsVIXLRegister());
// Pass exception object as argument.
// Don't care about preserving r0 as this won't return.
___ Mov(r0, exception->scratch_.AsVIXLRegister());
+ temps.Include(exception->scratch_.AsVIXLRegister());
// TODO: check that exception->scratch_ is dead by this point.
- UseScratchRegisterScope temps(asm_.GetVIXLAssembler());
vixl32::Register temp = temps.Acquire();
___ Ldr(temp,
MemOperand(tr,
@@ -624,6 +663,9 @@
} else if (dest.IsCoreRegister()) {
CHECK(!dest.AsVIXLRegister().Is(sp)) << dest;
+ UseScratchRegisterScope temps(asm_.GetVIXLAssembler());
+ temps.Exclude(dest.AsVIXLRegister());
+
if (size == 1u) {
___ Ldrb(dest.AsVIXLRegister(), MemOperand(base, offset));
} else {
diff --git a/compiler/utils/arm64/assembler_arm64.cc b/compiler/utils/arm64/assembler_arm64.cc
index f91bcfa..6ed0e9b 100644
--- a/compiler/utils/arm64/assembler_arm64.cc
+++ b/compiler/utils/arm64/assembler_arm64.cc
@@ -40,12 +40,12 @@
}
const uint8_t* Arm64Assembler::CodeBufferBaseAddress() const {
- return vixl_masm_.GetStartAddress<uint8_t*>();
+ return vixl_masm_.GetBuffer().GetStartAddress<const uint8_t*>();
}
void Arm64Assembler::FinalizeInstructions(const MemoryRegion& region) {
// Copy the instructions from the buffer.
- MemoryRegion from(vixl_masm_.GetStartAddress<void*>(), CodeSize());
+ MemoryRegion from(vixl_masm_.GetBuffer()->GetStartAddress<void*>(), CodeSize());
region.CopyFrom(0, from);
}
diff --git a/compiler/utils/assembler_thumb_test.cc b/compiler/utils/assembler_thumb_test.cc
index 10bed13..50a1d9f 100644
--- a/compiler/utils/assembler_thumb_test.cc
+++ b/compiler/utils/assembler_thumb_test.cc
@@ -1753,7 +1753,10 @@
__ LoadFromOffset(kLoadWordPair, R2, R4, 0x40400);
__ LoadFromOffset(kLoadWordPair, R4, R4, 0x40400);
+ vixl::aarch32::UseScratchRegisterScope temps(assembler.asm_.GetVIXLAssembler());
+ temps.Exclude(R12);
__ LoadFromOffset(kLoadWord, R0, R12, 12); // 32-bit because of R12.
+ temps.Include(R12);
__ LoadFromOffset(kLoadWord, R2, R4, 0xa4 - 0x100000);
__ LoadFromOffset(kLoadSignedByte, R2, R4, 12);
@@ -1783,7 +1786,10 @@
__ StoreToOffset(kStoreWordPair, R2, R4, 0x40400);
__ StoreToOffset(kStoreWordPair, R4, R4, 0x40400);
+ vixl::aarch32::UseScratchRegisterScope temps(assembler.asm_.GetVIXLAssembler());
+ temps.Exclude(R12);
__ StoreToOffset(kStoreWord, R0, R12, 12); // 32-bit because of R12.
+ temps.Include(R12);
__ StoreToOffset(kStoreWord, R2, R4, 0xa4 - 0x100000);
__ StoreToOffset(kStoreByte, R2, R4, 12);
diff --git a/disassembler/disassembler_arm.cc b/disassembler/disassembler_arm.cc
index 30b708c..3347dac 100644
--- a/disassembler/disassembler_arm.cc
+++ b/disassembler/disassembler_arm.cc
@@ -63,9 +63,7 @@
case kVld2Location:
case kVld3Location:
case kVld4Location: {
- const uintptr_t pc_delta = disasm_->IsT32()
- ? vixl::aarch32::kT32PcDelta
- : vixl::aarch32::kA32PcDelta;
+ const uintptr_t pc_delta = label.GetLabel()->GetPcOffset();
const int32_t offset = label.GetLabel()->GetLocation();
os() << "[pc, #" << offset - pc_delta << "]";
@@ -77,7 +75,7 @@
}
}
- DisassemblerStream& operator<<(const vixl::aarch32::Register reg) OVERRIDE {
+ DisassemblerStream& operator<<(vixl::aarch32::Register reg) OVERRIDE {
if (reg.Is(tr)) {
os() << "tr";
return *this;
@@ -118,20 +116,11 @@
CustomDisassembler(std::ostream& os, const DisassemblerOptions* options)
: PrintDisassembler(&disassembler_stream_), disassembler_stream_(os, this, options) {}
- void PrintPc(uint32_t prog_ctr) OVERRIDE {
+ void PrintCodeAddress(uint32_t prog_ctr) OVERRIDE {
os() << "0x" << std::hex << std::setw(8) << std::setfill('0') << prog_ctr << ": ";
}
- bool IsT32() const {
- return is_t32_;
- }
-
- void SetT32(bool is_t32) {
- is_t32_ = is_t32;
- }
-
private:
- bool is_t32_;
CustomDisassemblerStream disassembler_stream_;
};
@@ -152,7 +141,7 @@
sizeof(unaligned_float), sizeof(unaligned_double)};
const uintptr_t begin = reinterpret_cast<uintptr_t>(options_->base_address_);
const uintptr_t end = reinterpret_cast<uintptr_t>(options_->end_address_);
- uintptr_t literal_addr = RoundDown(disasm_->GetPc(), vixl::aarch32::kRegSizeInBytes) + offset;
+ uintptr_t literal_addr = RoundDown(disasm_->GetCodeAddress(), vixl::aarch32::kRegSizeInBytes) + offset;
if (!options_->absolute_addresses_) {
literal_addr += begin;
@@ -208,12 +197,14 @@
// Remove the Thumb specifier bit; no effect if begin does not point to T32 code.
const uintptr_t instr_ptr = reinterpret_cast<uintptr_t>(begin) & ~1;
- disasm_->SetT32((reinterpret_cast<uintptr_t>(begin) & 1) != 0);
- disasm_->JumpToPc(GetPc(instr_ptr));
+ const bool is_t32 = (reinterpret_cast<uintptr_t>(begin) & 1) != 0;
+ disasm_->SetCodeAddress(GetPc(instr_ptr));
- if (disasm_->IsT32()) {
+ if (is_t32) {
const uint16_t* const ip = reinterpret_cast<const uint16_t*>(instr_ptr);
- next = reinterpret_cast<uintptr_t>(disasm_->DecodeT32At(ip));
+ const uint16_t* const end_address = reinterpret_cast<const uint16_t*>(
+ GetDisassemblerOptions()->end_address_);
+ next = reinterpret_cast<uintptr_t>(disasm_->DecodeT32At(ip, end_address));
} else {
const uint32_t* const ip = reinterpret_cast<const uint32_t*>(instr_ptr);
next = reinterpret_cast<uintptr_t>(disasm_->DecodeA32At(ip));
@@ -230,10 +221,10 @@
// Remove the Thumb specifier bit; no effect if begin does not point to T32 code.
const uintptr_t base = reinterpret_cast<uintptr_t>(begin) & ~1;
- disasm_->SetT32((reinterpret_cast<uintptr_t>(begin) & 1) != 0);
- disasm_->JumpToPc(GetPc(base));
+ const bool is_t32 = (reinterpret_cast<uintptr_t>(begin) & 1) != 0;
+ disasm_->SetCodeAddress(GetPc(base));
- if (disasm_->IsT32()) {
+ if (is_t32) {
// The Thumb specifier bits cancel each other.
disasm_->DisassembleT32Buffer(reinterpret_cast<const uint16_t*>(base), end - begin);
} else {
diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc
index 05f74d6..72dbe6a 100644
--- a/runtime/interpreter/interpreter_common.cc
+++ b/runtime/interpreter/interpreter_common.cc
@@ -427,7 +427,7 @@
if (!reg->VerifierInstanceOf(field_class.Ptr())) {
// This should never happen.
std::string temp1, temp2, temp3;
- self->ThrowNewExceptionF("Ljava/lang/VirtualMachineError;",
+ self->ThrowNewExceptionF("Ljava/lang/InternalError;",
"Put '%s' that is not instance of field '%s' in '%s'",
reg->GetClass()->GetDescriptor(&temp1),
field_class->GetDescriptor(&temp2),
@@ -922,7 +922,7 @@
ThrowWrongMethodTypeException(check_type.Ptr(), callsite_type.Get());
return false;
}
- } else {
+ } else if (!IsInvokeTransform(handle_kind)) {
if (UNLIKELY(!IsCallerTransformer(callsite_type) &&
!callsite_type->IsConvertible(check_type.Ptr()))) {
ThrowWrongMethodTypeException(check_type.Ptr(), callsite_type.Get());
@@ -990,33 +990,37 @@
CHECK(called_method != nullptr);
}
- bool call_success;
- if (handle_kind == kInvokeTransform) {
- call_success = DoCallTransform<is_range>(called_method,
- callsite_type,
- handle_type,
- self,
- shadow_frame,
- method_handle /* receiver */,
- result,
- arg,
- first_src_reg);
+ if (IsInvokeTransform(handle_kind)) {
+ // There are two cases here - method handles representing regular
+ // transforms and those representing call site transforms. Method
+ // handles for call site transforms adapt their MethodType to match
+ // the call site. For these, the |callee_type| is the same as the
+ // |callsite_type|. The VarargsCollector is such a tranform, its
+ // method type depends on the call site, ie. x(a) or x(a, b), or
+ // x(a, b, c). The VarargsCollector invokes a variable arity method
+ // with the arity arguments in an array.
+ Handle<mirror::MethodType> callee_type =
+ (handle_kind == kInvokeCallSiteTransform) ? callsite_type : handle_type;
+ return DoCallTransform<is_range>(called_method,
+ callsite_type,
+ callee_type,
+ self,
+ shadow_frame,
+ method_handle /* receiver */,
+ result,
+ arg,
+ first_src_reg);
} else {
- call_success = DoCallPolymorphic<is_range>(called_method,
- callsite_type,
- handle_type,
- self,
- shadow_frame,
- result,
- arg,
- first_src_reg,
- handle_kind);
+ return DoCallPolymorphic<is_range>(called_method,
+ callsite_type,
+ handle_type,
+ self,
+ shadow_frame,
+ result,
+ arg,
+ first_src_reg,
+ handle_kind);
}
- if (LIKELY(call_success && ConvertReturnValue(callsite_type, handle_type, result))) {
- return true;
- }
- DCHECK(self->IsExceptionPending());
- return false;
} else {
DCHECK(!is_range);
ArtField* field = method_handle->GetTargetField();
@@ -1097,7 +1101,6 @@
return num_ins;
}
-
inline void PerformCall(Thread* self,
const DexFile::CodeItem* code_item,
ArtMethod* caller_method,
@@ -1251,18 +1254,31 @@
}
PerformCall(self, code_item, shadow_frame.GetMethod(), first_dest_reg, new_shadow_frame, result);
+ if (self->IsExceptionPending()) {
+ return false;
+ }
// If the caller of this signature polymorphic method was a transformer,
// we need to copy the result back out to the emulated stack frame.
- if (is_caller_transformer && !self->IsExceptionPending()) {
- ObjPtr<mirror::EmulatedStackFrame> emulated_stack_frame(
- reinterpret_cast<mirror::EmulatedStackFrame*>(
- shadow_frame.GetVRegReference(first_src_reg)));
+ if (is_caller_transformer) {
+ StackHandleScope<2> hs(self);
+ Handle<mirror::EmulatedStackFrame> emulated_stack_frame(
+ hs.NewHandle(reinterpret_cast<mirror::EmulatedStackFrame*>(
+ shadow_frame.GetVRegReference(first_src_reg))));
+ Handle<mirror::MethodType> emulated_stack_type(hs.NewHandle(emulated_stack_frame->GetType()));
+ JValue local_result;
+ local_result.SetJ(result->GetJ());
- emulated_stack_frame->SetReturnValue(self, *result);
+ if (ConvertReturnValue(emulated_stack_type, target_type, &local_result)) {
+ emulated_stack_frame->SetReturnValue(self, local_result);
+ return true;
+ } else {
+ DCHECK(self->IsExceptionPending());
+ return false;
+ }
+ } else {
+ return ConvertReturnValue(callsite_type, target_type, result);
}
-
- return !self->IsExceptionPending();
}
template <bool is_range>
@@ -1329,14 +1345,14 @@
0 /* first dest reg */,
new_shadow_frame,
result);
+ if (self->IsExceptionPending()) {
+ return false;
+ }
// If the called transformer method we called has returned a value, then we
// need to copy it back to |result|.
- if (!self->IsExceptionPending()) {
- sf->GetReturnValue(self, result);
- }
-
- return !self->IsExceptionPending();
+ sf->GetReturnValue(self, result);
+ return ConvertReturnValue(callsite_type, callee_type, result);
}
template <bool is_range,
@@ -1477,7 +1493,7 @@
if (!o->VerifierInstanceOf(arg_type)) {
// This should never happen.
std::string temp1, temp2;
- self->ThrowNewExceptionF("Ljava/lang/VirtualMachineError;",
+ self->ThrowNewExceptionF("Ljava/lang/InternalError;",
"Invoking %s with bad arg %d, type '%s' not instance of '%s'",
new_shadow_frame->GetMethod()->GetName(), shorty_pos,
o->GetClass()->GetDescriptor(&temp1),
diff --git a/runtime/interpreter/interpreter_switch_impl.cc b/runtime/interpreter/interpreter_switch_impl.cc
index 989b7da..22c0fe0 100644
--- a/runtime/interpreter/interpreter_switch_impl.cc
+++ b/runtime/interpreter/interpreter_switch_impl.cc
@@ -287,7 +287,7 @@
if (!obj_result->VerifierInstanceOf(return_type)) {
// This should never happen.
std::string temp1, temp2;
- self->ThrowNewExceptionF("Ljava/lang/VirtualMachineError;",
+ self->ThrowNewExceptionF("Ljava/lang/InternalError;",
"Returning '%s' that is not instance of return type '%s'",
obj_result->GetClass()->GetDescriptor(&temp1),
return_type->GetDescriptor(&temp2));
@@ -577,7 +577,7 @@
} else if (do_assignability_check && !exception->GetClass()->IsThrowableClass()) {
// This should never happen.
std::string temp;
- self->ThrowNewExceptionF("Ljava/lang/VirtualMachineError;",
+ self->ThrowNewExceptionF("Ljava/lang/InternalError;",
"Throwing '%s' that is not instance of Throwable",
exception->GetClass()->GetDescriptor(&temp));
} else {
diff --git a/runtime/jit/jit_code_cache.cc b/runtime/jit/jit_code_cache.cc
index f0ed237..3531852 100644
--- a/runtime/jit/jit_code_cache.cc
+++ b/runtime/jit/jit_code_cache.cc
@@ -428,10 +428,16 @@
core_spill_mask,
fp_spill_mask,
code_size);
+ // Flush caches before we remove write permission because on some ARMv8 hardware,
+ // flushing caches require write permissions.
+ //
+ // For reference, here are kernel patches discussing about this issue:
+ // https://android.googlesource.com/kernel/msm/%2B/0e7f7bcc3fc87489cda5aa6aff8ce40eed912279
+ // https://patchwork.kernel.org/patch/9047921/
+ FlushInstructionCache(reinterpret_cast<char*>(code_ptr),
+ reinterpret_cast<char*>(code_ptr + code_size));
}
- FlushInstructionCache(reinterpret_cast<char*>(code_ptr),
- reinterpret_cast<char*>(code_ptr + code_size));
number_of_compilations_++;
}
// We need to update the entry point in the runnable state for the instrumentation.
diff --git a/runtime/method_handles.h b/runtime/method_handles.h
index 54c772a..d0a4902 100644
--- a/runtime/method_handles.h
+++ b/runtime/method_handles.h
@@ -46,12 +46,13 @@
kInvokeStatic,
kInvokeInterface,
kInvokeTransform,
+ kInvokeCallSiteTransform,
kInstanceGet,
kInstancePut,
kStaticGet,
kStaticPut,
kLastValidKind = kStaticPut,
- kLastInvokeKind = kInvokeTransform
+ kLastInvokeKind = kInvokeCallSiteTransform
};
// Whether the given method handle kind is some variant of an invoke.
@@ -59,6 +60,11 @@
return handle_kind <= kLastInvokeKind;
}
+// Whether the given method handle kind is some variant of a tranform.
+inline bool IsInvokeTransform(const MethodHandleKind handle_kind) {
+ return handle_kind == kInvokeTransform || handle_kind == kInvokeCallSiteTransform;
+}
+
// Returns true if there is a possible conversion from |from| to |to|
// for a MethodHandle parameter.
bool IsParameterTypeConvertible(ObjPtr<mirror::Class> from,
diff --git a/runtime/mirror/emulated_stack_frame.h b/runtime/mirror/emulated_stack_frame.h
index 9fa06b7..d83a536 100644
--- a/runtime/mirror/emulated_stack_frame.h
+++ b/runtime/mirror/emulated_stack_frame.h
@@ -58,6 +58,10 @@
// Sets the return value slot of this emulated stack frame to |value|.
void SetReturnValue(Thread* self, const JValue& value) REQUIRES_SHARED(Locks::mutator_lock_);
+ mirror::MethodType* GetType() REQUIRES_SHARED(Locks::mutator_lock_) {
+ return GetFieldObject<MethodType>(OFFSET_OF_OBJECT_MEMBER(EmulatedStackFrame, type_));
+ }
+
static void SetClass(Class* klass) REQUIRES_SHARED(Locks::mutator_lock_);
static void ResetClass() REQUIRES_SHARED(Locks::mutator_lock_);
static void VisitRoots(RootVisitor* visitor) REQUIRES_SHARED(Locks::mutator_lock_);
@@ -67,10 +71,6 @@
return static_class_.Read();
}
- mirror::MethodType* GetType() REQUIRES_SHARED(Locks::mutator_lock_) {
- return GetFieldObject<MethodType>(OFFSET_OF_OBJECT_MEMBER(EmulatedStackFrame, type_));
- }
-
mirror::ObjectArray<mirror::Object>* GetReferences() REQUIRES_SHARED(Locks::mutator_lock_) {
return GetFieldObject<mirror::ObjectArray<mirror::Object>>(
OFFSET_OF_OBJECT_MEMBER(EmulatedStackFrame, references_));
diff --git a/test/538-checker-embed-constants/src/Main.java b/test/538-checker-embed-constants/src/Main.java
index 02c609e..6b25747 100644
--- a/test/538-checker-embed-constants/src/Main.java
+++ b/test/538-checker-embed-constants/src/Main.java
@@ -30,7 +30,7 @@
/// CHECK-START-ARM: int Main.and255(int) disassembly (after)
/// CHECK-NOT: movs {{r\d+}}, #255
- /// CHECK: and {{r\d+}}, {{r\d+}}, #255
+ /// CHECK: and {{r\d+}}, {{r\d+}}, #0xff
public static int and255(int arg) {
return arg & 255;
@@ -46,7 +46,7 @@
/// CHECK-START-ARM: int Main.andNot15(int) disassembly (after)
/// CHECK-NOT: mvn {{r\d+}}, #15
- /// CHECK: bic {{r\d+}}, {{r\d+}}, #15
+ /// CHECK: bic {{r\d+}}, {{r\d+}}, #0xf
public static int andNot15(int arg) {
return arg & ~15;
@@ -54,7 +54,7 @@
/// CHECK-START-ARM: int Main.or255(int) disassembly (after)
/// CHECK-NOT: movs {{r\d+}}, #255
- /// CHECK: orr {{r\d+}}, {{r\d+}}, #255
+ /// CHECK: orr {{r\d+}}, {{r\d+}}, #0xff
public static int or255(int arg) {
return arg | 255;
@@ -70,7 +70,7 @@
/// CHECK-START-ARM: int Main.orNot15(int) disassembly (after)
/// CHECK-NOT: mvn {{r\d+}}, #15
- /// CHECK: orn {{r\d+}}, {{r\d+}}, #15
+ /// CHECK: orn {{r\d+}}, {{r\d+}}, #0xf
public static int orNot15(int arg) {
return arg | ~15;
@@ -78,7 +78,7 @@
/// CHECK-START-ARM: int Main.xor255(int) disassembly (after)
/// CHECK-NOT: movs {{r\d+}}, #255
- /// CHECK: eor {{r\d+}}, {{r\d+}}, #255
+ /// CHECK: eor {{r\d+}}, {{r\d+}}, #0xff
public static int xor255(int arg) {
return arg ^ 255;
@@ -104,7 +104,7 @@
/// CHECK-NOT: movs {{r\d+}}, #255
/// CHECK-NOT: and{{(\.w)?}}
/// CHECK-NOT: bic{{(\.w)?}}
- /// CHECK-DAG: and {{r\d+}}, {{r\d+}}, #255
+ /// CHECK-DAG: and {{r\d+}}, {{r\d+}}, #0xff
/// CHECK-DAG: movs {{r\d+}}, #0
/// CHECK-NOT: and{{(\.w)?}}
/// CHECK-NOT: bic{{(\.w)?}}
@@ -131,7 +131,7 @@
/// CHECK-NOT: mvn {{r\d+}}, #15
/// CHECK-NOT: and{{(\.w)?}}
/// CHECK-NOT: bic{{(\.w)?}}
- /// CHECK: bic {{r\d+}}, {{r\d+}}, #15
+ /// CHECK: bic {{r\d+}}, {{r\d+}}, #0xf
/// CHECK-NOT: and{{(\.w)?}}
/// CHECK-NOT: bic{{(\.w)?}}
@@ -144,8 +144,8 @@
/// CHECK-NOT: mvn {{r\d+}}, #15
/// CHECK-NOT: and{{(\.w)?}}
/// CHECK-NOT: bic{{(\.w)?}}
- /// CHECK-DAG: and {{r\d+}}, {{r\d+}}, #15
- /// CHECK-DAG: bic {{r\d+}}, {{r\d+}}, #15
+ /// CHECK-DAG: and {{r\d+}}, {{r\d+}}, #0xf
+ /// CHECK-DAG: bic {{r\d+}}, {{r\d+}}, #0xf
/// CHECK-NOT: and{{(\.w)?}}
/// CHECK-NOT: bic{{(\.w)?}}
@@ -157,7 +157,7 @@
/// CHECK-NOT: movs {{r\d+}}, #255
/// CHECK-NOT: orr{{(\.w)?}}
/// CHECK-NOT: orn
- /// CHECK: orr {{r\d+}}, {{r\d+}}, #255
+ /// CHECK: orr {{r\d+}}, {{r\d+}}, #0xff
/// CHECK-NOT: orr{{(\.w)?}}
/// CHECK-NOT: orn
@@ -183,7 +183,7 @@
/// CHECK-NOT: mvn {{r\d+}}, #15
/// CHECK-NOT: orr{{(\.w)?}}
/// CHECK-NOT: orn
- /// CHECK-DAG: orn {{r\d+}}, {{r\d+}}, #15
+ /// CHECK-DAG: orn {{r\d+}}, {{r\d+}}, #0xf
/// CHECK-DAG: mvn {{r\d+}}, #0
/// CHECK-NOT: orr{{(\.w)?}}
/// CHECK-NOT: orn
@@ -197,8 +197,8 @@
/// CHECK-NOT: mvn {{r\d+}}, #15
/// CHECK-NOT: orr{{(\.w)?}}
/// CHECK-NOT: orn
- /// CHECK-DAG: orr {{r\d+}}, {{r\d+}}, #15
- /// CHECK-DAG: orn {{r\d+}}, {{r\d+}}, #15
+ /// CHECK-DAG: orr {{r\d+}}, {{r\d+}}, #0xf
+ /// CHECK-DAG: orn {{r\d+}}, {{r\d+}}, #0xf
/// CHECK-NOT: orr{{(\.w)?}}
/// CHECK-NOT: orn
@@ -209,7 +209,7 @@
/// CHECK-START-ARM: long Main.xor255(long) disassembly (after)
/// CHECK-NOT: movs {{r\d+}}, #255
/// CHECK-NOT: eor{{(\.w)?}}
- /// CHECK: eor {{r\d+}}, {{r\d+}}, #255
+ /// CHECK: eor {{r\d+}}, {{r\d+}}, #0xff
/// CHECK-NOT: eor{{(\.w)?}}
public static long xor255(long arg) {
@@ -257,8 +257,8 @@
/// CHECK-NOT: movs {{r\d+}}, #15
/// CHECK-NOT: mov.w {{r\d+}}, #-268435456
/// CHECK-NOT: eor{{(\.w)?}}
- /// CHECK-DAG: eor {{r\d+}}, {{r\d+}}, #15
- /// CHECK-DAG: eor {{r\d+}}, {{r\d+}}, #4026531840
+ /// CHECK-DAG: eor {{r\d+}}, {{r\d+}}, #0xf
+ /// CHECK-DAG: eor {{r\d+}}, {{r\d+}}, #0xf0000000
/// CHECK-NOT: eor{{(\.w)?}}
public static long xor0xf00000000000000f(long arg) {
diff --git a/test/956-methodhandles/expected.txt b/test/956-methodhandles/expected.txt
index 0a5caa1..9b09327 100644
--- a/test/956-methodhandles/expected.txt
+++ b/test/956-methodhandles/expected.txt
@@ -7,3 +7,11 @@
String constructors done.
testReferenceReturnValueConversions done.
testPrimitiveReturnValueConversions done.
+Hi
+Hi
+Hi
+Hi
+Expect Hi here: Hi
+Don't expect Hi now
+[3, 2, 1]
+[1, 2, 3]
diff --git a/test/956-methodhandles/src/Main.java b/test/956-methodhandles/src/Main.java
index 8713caa..ee9c436 100644
--- a/test/956-methodhandles/src/Main.java
+++ b/test/956-methodhandles/src/Main.java
@@ -19,13 +19,14 @@
import java.lang.invoke.MethodHandles.Lookup;
import java.lang.invoke.MethodType;
import java.lang.invoke.WrongMethodTypeException;
-import java.nio.charset.Charset;
-import java.nio.charset.StandardCharsets;
-
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
import java.util.Arrays;
+import java.util.List;
public class Main {
@@ -74,6 +75,7 @@
testConstructors();
testStringConstructors();
testReturnValueConversions();
+ testVariableArity();
}
public static void testfindSpecial_invokeSuperBehaviour() throws Throwable {
@@ -555,6 +557,34 @@
}
}
+ public static void assertTrue(boolean value) {
+ if (!value) {
+ throw new AssertionError("assertTrue value: " + value);
+ }
+ }
+
+ public static void assertFalse(boolean value) {
+ if (value) {
+ throw new AssertionError("assertTrue value: " + value);
+ }
+ }
+
+ public static void assertEquals(int i1, int i2) {
+ if (i1 == i2) { return; }
+ throw new AssertionError("assertEquals i1: " + i1 + ", i2: " + i2);
+ }
+
+ public static void assertEquals(long i1, long i2) {
+ if (i1 == i2) { return; }
+ throw new AssertionError("assertEquals l1: " + i1 + ", l2: " + i2);
+ }
+
+ public static void assertEquals(Object o, Object p) {
+ if (o == p) { return; }
+ if (o != null && p != null && o.equals(p)) { return; }
+ throw new AssertionError("assertEquals: o1: " + o + ", o2: " + p);
+ }
+
public static void assertEquals(String s1, String s2) {
if (s1 == s2) {
return;
@@ -960,4 +990,480 @@
testReferenceReturnValueConversions();
testPrimitiveReturnValueConversions();
}
+
+ public static class BaseVariableArityTester {
+ public String update(Float f0, Float... floats) {
+ return "base " + f0 + ", " + Arrays.toString(floats);
+ }
+ }
+
+ public static class VariableArityTester extends BaseVariableArityTester {
+ private String lastResult;
+
+ // Constructors
+ public VariableArityTester() {}
+ public VariableArityTester(boolean... booleans) { update(booleans); }
+ public VariableArityTester(byte... bytes) { update(bytes); }
+ public VariableArityTester(char... chars) { update(chars); }
+ public VariableArityTester(short... shorts) { update(shorts); }
+ public VariableArityTester(int... ints) { update(ints); }
+ public VariableArityTester(long... longs) { update(longs); }
+ public VariableArityTester(float... floats) { update(floats); }
+ public VariableArityTester(double... doubles) { update(doubles); }
+ public VariableArityTester(Float f0, Float... floats) { update(f0, floats); }
+ public VariableArityTester(String s0, String... strings) { update(s0, strings); }
+ public VariableArityTester(char c, Number... numbers) { update(c, numbers); }
+ @SafeVarargs
+ public VariableArityTester(ArrayList<Integer> l0, ArrayList<Integer>... lists) {
+ update(l0, lists);
+ }
+ public VariableArityTester(List l0, List... lists) { update(l0, lists); }
+
+ // Methods
+ public String update(boolean... booleans) { return lastResult = tally(booleans); }
+ public String update(byte... bytes) { return lastResult = tally(bytes); }
+ public String update(char... chars) { return lastResult = tally(chars); }
+ public String update(short... shorts) { return lastResult = tally(shorts); }
+ public String update(int... ints) {
+ lastResult = tally(ints);
+ return lastResult;
+ }
+ public String update(long... longs) { return lastResult = tally(longs); }
+ public String update(float... floats) { return lastResult = tally(floats); }
+ public String update(double... doubles) { return lastResult = tally(doubles); }
+ @Override
+ public String update(Float f0, Float... floats) { return lastResult = tally(f0, floats); }
+ public String update(String s0, String... strings) { return lastResult = tally(s0, strings); }
+ public String update(char c, Number... numbers) { return lastResult = tally(c, numbers); }
+ @SafeVarargs
+ public final String update(ArrayList<Integer> l0, ArrayList<Integer>... lists) {
+ lastResult = tally(l0, lists);
+ return lastResult;
+ }
+ public String update(List l0, List... lists) { return lastResult = tally(l0, lists); }
+
+ public String arrayMethod(Object[] o) {
+ return Arrays.deepToString(o);
+ }
+
+ public String lastResult() { return lastResult; }
+
+ // Static Methods
+ public static String tally(boolean... booleans) { return Arrays.toString(booleans); }
+ public static String tally(byte... bytes) { return Arrays.toString(bytes); }
+ public static String tally(char... chars) { return Arrays.toString(chars); }
+ public static String tally(short... shorts) { return Arrays.toString(shorts); }
+ public static String tally(int... ints) { return Arrays.toString(ints); }
+ public static String tally(long... longs) { return Arrays.toString(longs); }
+ public static String tally(float... floats) { return Arrays.toString(floats); }
+ public static String tally(double... doubles) { return Arrays.toString(doubles); }
+ public static String tally(Float f0, Float... floats) {
+ return f0 + ", " + Arrays.toString(floats);
+ }
+ public static String tally(String s0, String... strings) {
+ return s0 + ", " + Arrays.toString(strings);
+ }
+ public static String tally(char c, Number... numbers) {
+ return c + ", " + Arrays.toString(numbers);
+ }
+ @SafeVarargs
+ public static String tally(ArrayList<Integer> l0, ArrayList<Integer>... lists) {
+ return Arrays.toString(l0.toArray()) + ", " + Arrays.deepToString(lists);
+ }
+ public static String tally(List l0, List... lists) {
+ return Arrays.deepToString(l0.toArray()) + ", " + Arrays.deepToString(lists);
+ }
+ public static void foo(int... ints) { System.out.println(Arrays.toString(ints)); }
+ public static long sumToPrimitive(int... ints) {
+ long result = 0;
+ for (int i : ints) result += i;
+ return result;
+ }
+ public static Long sumToReference(int... ints) {
+ System.err.println("Hi");
+ return new Long(sumToPrimitive(ints));
+ }
+ public static MethodHandles.Lookup lookup() {
+ return MethodHandles.lookup();
+ }
+ }
+
+ // This method only exists to fool Jack's handling of types. See b/32536744.
+ public static Object getAsObject(String[] strings) {
+ return (Object) strings;
+ }
+
+ public static void testVariableArity() throws Throwable {
+ MethodHandle mh;
+ VariableArityTester vat = new VariableArityTester();
+
+ assertEquals("[1]", vat.update(1));
+ assertEquals("[1, 1]", vat.update(1, 1));
+ assertEquals("[1, 1, 1]", vat.update(1, 1, 1));
+
+ // Methods - boolean
+ mh = MethodHandles.lookup().findVirtual(VariableArityTester.class, "update",
+ MethodType.methodType(String.class, boolean[].class));
+ assertTrue(mh.isVarargsCollector());
+ assertFalse(mh.asFixedArity().isVarargsCollector());
+ assertEquals("[]", mh.invoke(vat));
+ assertEquals("[true, false, true]", mh.invoke(vat, true, false, true));
+ assertEquals("[true, false, true]", mh.invoke(vat, new boolean[] { true, false, true}));
+ assertEquals("[false, true]", mh.invoke(vat, Boolean.valueOf(false), Boolean.valueOf(true)));
+ try {
+ mh.invoke(vat, true, true, 0);
+ fail();
+ } catch (WrongMethodTypeException e) {}
+ try {
+ assertEquals("[false, true]", mh.invoke(vat, Boolean.valueOf(false), (Boolean) null));
+ fail();
+ } catch (NullPointerException e) {}
+
+ // Methods - byte
+ mh = MethodHandles.lookup().findVirtual(VariableArityTester.class, "update",
+ MethodType.methodType(String.class, byte[].class));
+ assertTrue(mh.isVarargsCollector());
+ assertEquals("[]", mh.invoke(vat));
+ assertEquals("[32, 64, 97]", mh.invoke(vat, (byte) 32, Byte.valueOf((byte) 64), (byte) 97));
+ assertEquals("[32, 64, 97]", mh.invoke(vat, new byte[] {(byte) 32, (byte) 64, (byte) 97}));
+ try {
+ mh.invoke(vat, (byte) 1, Integer.valueOf(3), (byte) 0);
+ fail();
+ } catch (WrongMethodTypeException e) {}
+
+ // Methods - char
+ mh = MethodHandles.lookup().findVirtual(VariableArityTester.class, "update",
+ MethodType.methodType(String.class, char[].class));
+ assertTrue(mh.isVarargsCollector());
+ assertEquals("[]", mh.invoke(vat));
+ assertEquals("[A, B, C]", mh.invoke(vat, 'A', Character.valueOf('B'), 'C'));
+ assertEquals("[W, X, Y, Z]", mh.invoke(vat, new char[] { 'W', 'X', 'Y', 'Z' }));
+
+ // Methods - short
+ mh = MethodHandles.lookup().findVirtual(VariableArityTester.class, "update",
+ MethodType.methodType(String.class, short[].class));
+ assertTrue(mh.isVarargsCollector());
+ assertEquals("[]", mh.invoke(vat));
+ assertEquals("[32767, -32768, 0]",
+ mh.invoke(vat, Short.MAX_VALUE, Short.MIN_VALUE, Short.valueOf((short) 0)));
+ assertEquals("[1, -1]", mh.invoke(vat, new short[] { (short) 1, (short) -1 }));
+
+ // Methods - int
+ mh = MethodHandles.lookup().findVirtual(VariableArityTester.class, "update",
+ MethodType.methodType(String.class, int[].class));
+ assertTrue(mh.isVarargsCollector());
+ assertEquals("[]", mh.invoke(vat));
+ assertEquals("[0, 2147483647, -2147483648, 0]",
+ mh.invoke(vat, Integer.valueOf(0), Integer.MAX_VALUE, Integer.MIN_VALUE, 0));
+ assertEquals("[0, -1, 1, 0]", mh.invoke(vat, new int[] { 0, -1, 1, 0 }));
+
+ assertEquals("[5, 4, 3, 2, 1]", (String) mh.invokeExact(vat, new int [] { 5, 4, 3, 2, 1 }));
+ try {
+ assertEquals("[5, 4, 3, 2, 1]", (String) mh.invokeExact(vat, 5, 4, 3, 2, 1));
+ fail();
+ } catch (WrongMethodTypeException e) {}
+ assertEquals("[5, 4, 3, 2, 1]", (String) mh.invoke(vat, 5, 4, 3, 2, 1));
+
+ // Methods - long
+ mh = MethodHandles.lookup().findVirtual(VariableArityTester.class, "update",
+ MethodType.methodType(String.class, long[].class));
+ assertTrue(mh.isVarargsCollector());
+ assertEquals("[]", mh.invoke(vat));
+ assertEquals("[0, 9223372036854775807, -9223372036854775808]",
+ mh.invoke(vat, Long.valueOf(0), Long.MAX_VALUE, Long.MIN_VALUE));
+ assertEquals("[0, -1, 1, 0]", mh.invoke(vat, new long[] { 0, -1, 1, 0 }));
+
+ // Methods - float
+ mh = MethodHandles.lookup().findVirtual(VariableArityTester.class, "update",
+ MethodType.methodType(String.class, float[].class));
+ assertTrue(mh.isVarargsCollector());
+ assertEquals("[]", mh.invoke(vat));
+ assertEquals("[0.0, 1.25, -1.25]",
+ mh.invoke(vat, 0.0f, Float.valueOf(1.25f), Float.valueOf(-1.25f)));
+ assertEquals("[0.0, -1.0, 1.0, 0.0]",
+ mh.invoke(vat, new float[] { 0.0f, -1.0f, 1.0f, 0.0f }));
+
+ // Methods - double
+ mh = MethodHandles.lookup().findVirtual(VariableArityTester.class, "update",
+ MethodType.methodType(String.class, double[].class));
+ assertTrue(mh.isVarargsCollector());
+ assertEquals("[]", mh.invoke(vat));
+ assertEquals("[0.0, 1.25, -1.25]",
+ mh.invoke(vat, 0.0, Double.valueOf(1.25), Double.valueOf(-1.25)));
+ assertEquals("[0.0, -1.0, 1.0, 0.0]",
+ mh.invoke(vat, new double[] { 0.0, -1.0, 1.0, 0.0 }));
+ mh.invoke(vat, 0.3f, 1.33, 1.33);
+
+ // Methods - String
+ mh = MethodHandles.lookup().
+ findVirtual(VariableArityTester.class, "update",
+ MethodType.methodType(String.class, String.class, String[].class));
+ assertTrue(mh.isVarargsCollector());
+ assertEquals("Echidna, []", mh.invoke(vat, "Echidna"));
+ assertEquals("Bongo, [Jerboa, Okapi]",
+ mh.invoke(vat, "Bongo", "Jerboa", "Okapi"));
+
+ // Methods - Float
+ mh = MethodHandles.lookup().
+ findVirtual(VariableArityTester.class, "update",
+ MethodType.methodType(String.class, Float.class, Float[].class));
+ assertTrue(mh.isVarargsCollector());
+ assertEquals("9.99, [0.0, 0.1, 1.1]",
+ (String) mh.invoke(vat, Float.valueOf(9.99f),
+ new Float[] { Float.valueOf(0.0f),
+ Float.valueOf(0.1f),
+ Float.valueOf(1.1f) }));
+ assertEquals("9.99, [0.0, 0.1, 1.1]",
+ (String) mh.invoke(vat, Float.valueOf(9.99f), Float.valueOf(0.0f),
+ Float.valueOf(0.1f), Float.valueOf(1.1f)));
+ assertEquals("9.99, [0.0, 0.1, 1.1]",
+ (String) mh.invoke(vat, Float.valueOf(9.99f), 0.0f, 0.1f, 1.1f));
+ try {
+ assertEquals("9.99, [77.0, 33.0, 64.0]",
+ (String) mh.invoke(vat, Float.valueOf(9.99f), 77, 33, 64));
+ fail();
+ } catch (WrongMethodTypeException e) {}
+ assertEquals("9.99, [0.0, 0.1, 1.1]",
+ (String) mh.invokeExact(vat, Float.valueOf(9.99f),
+ new Float[] { Float.valueOf(0.0f),
+ Float.valueOf(0.1f),
+ Float.valueOf(1.1f) }));
+ assertEquals("9.99, [0.0, null, 1.1]",
+ (String) mh.invokeExact(vat, Float.valueOf(9.99f),
+ new Float[] { Float.valueOf(0.0f),
+ null,
+ Float.valueOf(1.1f) }));
+ try {
+ assertEquals("9.99, [0.0, 0.1, 1.1]",
+ (String) mh.invokeExact(vat, Float.valueOf(9.99f), 0.0f, 0.1f, 1.1f));
+ fail();
+ } catch (WrongMethodTypeException e) {}
+
+ // Methods - Number
+ mh = MethodHandles.lookup().
+ findVirtual(VariableArityTester.class, "update",
+ MethodType.methodType(String.class, char.class, Number[].class));
+ assertTrue(mh.isVarargsCollector());
+ assertFalse(mh.asFixedArity().isVarargsCollector());
+ assertEquals("x, []", (String) mh.invoke(vat, 'x'));
+ assertEquals("x, [3.141]", (String) mh.invoke(vat, 'x', 3.141));
+ assertEquals("x, [null, 3.131, 37]",
+ (String) mh.invoke(vat, 'x', null, 3.131, new Integer(37)));
+ try {
+ assertEquals("x, [null, 3.131, bad, 37]",
+ (String) mh.invoke(vat, 'x', null, 3.131, "bad", new Integer(37)));
+ assertTrue(false);
+ fail();
+ } catch (ClassCastException e) {}
+ try {
+ assertEquals("x, [null, 3.131, bad, 37]",
+ (String) mh.invoke(
+ vat, 'x', (Process) null, 3.131, "bad", new Integer(37)));
+ assertTrue(false);
+ fail();
+ } catch (ClassCastException e) {}
+
+ // Methods - an array method that is not variable arity.
+ mh = MethodHandles.lookup().findVirtual(
+ VariableArityTester.class, "arrayMethod",
+ MethodType.methodType(String.class, Object[].class));
+ assertFalse(mh.isVarargsCollector());
+ mh.invoke(vat, new Object[] { "123" });
+ try {
+ assertEquals("-", mh.invoke(vat, new Float(3), new Float(4)));
+ fail();
+ } catch (WrongMethodTypeException e) {}
+ mh = mh.asVarargsCollector(Object[].class);
+ assertTrue(mh.isVarargsCollector());
+ assertEquals("[3.0, 4.0]", (String) mh.invoke(vat, new Float(3), new Float(4)));
+
+ // Constructors - default
+ mh = MethodHandles.lookup().findConstructor(
+ VariableArityTester.class, MethodType.methodType(void.class));
+ assertFalse(mh.isVarargsCollector());
+
+ // Constructors - boolean
+ mh = MethodHandles.lookup().findConstructor(
+ VariableArityTester.class, MethodType.methodType(void.class, boolean[].class));
+ assertTrue(mh.isVarargsCollector());
+ assertEquals("[true, true, false]",
+ ((VariableArityTester) mh.invoke(new boolean[] {true, true, false})).lastResult());
+ assertEquals("[true, true, false]",
+ ((VariableArityTester) mh.invoke(true, true, false)).lastResult());
+ try {
+ assertEquals("[true, true, false]",
+ ((VariableArityTester) mh.invokeExact(true, true, false)).lastResult());
+ fail();
+ } catch (WrongMethodTypeException e) {}
+
+ // Constructors - byte
+ mh = MethodHandles.lookup().findConstructor(
+ VariableArityTester.class, MethodType.methodType(void.class, byte[].class));
+ assertTrue(mh.isVarargsCollector());
+ assertEquals("[55, 66, 60]",
+ ((VariableArityTester)
+ mh.invoke(new byte[] {(byte) 55, (byte) 66, (byte) 60})).lastResult());
+ assertEquals("[55, 66, 60]",
+ ((VariableArityTester) mh.invoke(
+ (byte) 55, (byte) 66, (byte) 60)).lastResult());
+ try {
+ assertEquals("[55, 66, 60]",
+ ((VariableArityTester) mh.invokeExact(
+ (byte) 55, (byte) 66, (byte) 60)).lastResult());
+ fail();
+ } catch (WrongMethodTypeException e) {}
+ try {
+ assertEquals("[3, 3]",
+ ((VariableArityTester) mh.invoke(
+ new Number[] { Byte.valueOf((byte) 3), (byte) 3})).lastResult());
+ fail();
+ } catch (WrongMethodTypeException e) {}
+
+ // Constructors - String (have a different path than other reference types).
+ mh = MethodHandles.lookup().findConstructor(
+ VariableArityTester.class, MethodType.methodType(void.class, String.class, String[].class));
+ assertTrue(mh.isVarargsCollector());
+ assertEquals("x, []", ((VariableArityTester) mh.invoke("x")).lastResult());
+ assertEquals("x, [y]", ((VariableArityTester) mh.invoke("x", "y")).lastResult());
+ assertEquals("x, [y, z]",
+ ((VariableArityTester) mh.invoke("x", new String[] { "y", "z" })).lastResult());
+ try {
+ assertEquals("x, [y]", ((VariableArityTester) mh.invokeExact("x", "y")).lastResult());
+ fail();
+ } catch (WrongMethodTypeException e) {}
+ assertEquals("x, [null, z]",
+ ((VariableArityTester) mh.invoke("x", new String[] { null, "z" })).lastResult());
+
+ // Constructors - Number
+ mh = MethodHandles.lookup().findConstructor(
+ VariableArityTester.class, MethodType.methodType(void.class, char.class, Number[].class));
+ assertTrue(mh.isVarargsCollector());
+ assertFalse(mh.asFixedArity().isVarargsCollector());
+ assertEquals("x, []", ((VariableArityTester) mh.invoke('x')).lastResult());
+ assertEquals("x, [3.141]", ((VariableArityTester) mh.invoke('x', 3.141)).lastResult());
+ assertEquals("x, [null, 3.131, 37]",
+ ((VariableArityTester) mh.invoke('x', null, 3.131, new Integer(37))).lastResult());
+ try {
+ assertEquals("x, [null, 3.131, bad, 37]",
+ ((VariableArityTester) mh.invoke(
+ 'x', null, 3.131, "bad", new Integer(37))).lastResult());
+ assertTrue(false);
+ fail();
+ } catch (ClassCastException e) {}
+ try {
+ assertEquals("x, [null, 3.131, bad, 37]",
+ ((VariableArityTester) mh.invoke(
+ 'x', (Process) null, 3.131, "bad", new Integer(37))).lastResult());
+ assertTrue(false);
+ fail();
+ } catch (ClassCastException e) {}
+
+ // Static Methods - Float
+ mh = MethodHandles.lookup().
+ findStatic(VariableArityTester.class, "tally",
+ MethodType.methodType(String.class, Float.class, Float[].class));
+ assertTrue(mh.isVarargsCollector());
+ assertEquals("9.99, [0.0, 0.1, 1.1]",
+ (String) mh.invoke(Float.valueOf(9.99f),
+ new Float[] { Float.valueOf(0.0f),
+ Float.valueOf(0.1f),
+ Float.valueOf(1.1f) }));
+ assertEquals("9.99, [0.0, 0.1, 1.1]",
+ (String) mh.invoke(Float.valueOf(9.99f), Float.valueOf(0.0f),
+ Float.valueOf(0.1f), Float.valueOf(1.1f)));
+ assertEquals("9.99, [0.0, 0.1, 1.1]",
+ (String) mh.invoke(Float.valueOf(9.99f), 0.0f, 0.1f, 1.1f));
+ try {
+ assertEquals("9.99, [77.0, 33.0, 64.0]",
+ (String) mh.invoke(Float.valueOf(9.99f), 77, 33, 64));
+ fail();
+ } catch (WrongMethodTypeException e) {}
+ assertEquals("9.99, [0.0, 0.1, 1.1]",
+ (String) mh.invokeExact(Float.valueOf(9.99f),
+ new Float[] { Float.valueOf(0.0f),
+ Float.valueOf(0.1f),
+ Float.valueOf(1.1f) }));
+ assertEquals("9.99, [0.0, null, 1.1]",
+ (String) mh.invokeExact(Float.valueOf(9.99f),
+ new Float[] { Float.valueOf(0.0f),
+ null,
+ Float.valueOf(1.1f) }));
+ try {
+ assertEquals("9.99, [0.0, 0.1, 1.1]",
+ (String) mh.invokeExact(Float.valueOf(9.99f), 0.0f, 0.1f, 1.1f));
+ fail();
+ } catch (WrongMethodTypeException e) {}
+
+ // Special methods - Float
+ mh = VariableArityTester.lookup().
+ findSpecial(BaseVariableArityTester.class, "update",
+ MethodType.methodType(String.class, Float.class, Float[].class),
+ VariableArityTester.class);
+ assertTrue(mh.isVarargsCollector());
+ assertEquals("base 9.99, [0.0, 0.1, 1.1]",
+ (String) mh.invoke(vat,
+ Float.valueOf(9.99f),
+ new Float[] { Float.valueOf(0.0f),
+ Float.valueOf(0.1f),
+ Float.valueOf(1.1f) }));
+ assertEquals("base 9.99, [0.0, 0.1, 1.1]",
+ (String) mh.invoke(vat, Float.valueOf(9.99f), Float.valueOf(0.0f),
+ Float.valueOf(0.1f), Float.valueOf(1.1f)));
+
+ // Return value conversions.
+ mh = MethodHandles.lookup().findVirtual(VariableArityTester.class, "update",
+ MethodType.methodType(String.class, int[].class));
+ assertEquals("[1, 2, 3]", (String) mh.invoke(vat, 1, 2, 3));
+ assertEquals("[1, 2, 3]", (Object) mh.invoke(vat, 1, 2, 3));
+ try {
+ assertEquals("[1, 2, 3, 4]", (long) mh.invoke(vat, 1, 2, 3));
+ fail();
+ } catch (WrongMethodTypeException e) {}
+ assertEquals("[1, 2, 3]", vat.lastResult());
+ mh = MethodHandles.lookup().findStatic(VariableArityTester.class, "sumToPrimitive",
+ MethodType.methodType(long.class, int[].class));
+ assertEquals(10l, (long) mh.invoke(1, 2, 3, 4));
+ assertEquals(Long.valueOf(10l), (Long) mh.invoke(1, 2, 3, 4));
+ mh = MethodHandles.lookup().findStatic(VariableArityTester.class, "sumToReference",
+ MethodType.methodType(Long.class, int[].class));
+ Object o = mh.invoke(1, 2, 3, 4);
+ long l = (long) mh.invoke(1, 2, 3, 4);
+ assertEquals(10l, (long) mh.invoke(1, 2, 3, 4));
+ assertEquals(Long.valueOf(10l), (Long) mh.invoke(1, 2, 3, 4));
+ try {
+ // WrongMethodTypeException should be raised before invoke here.
+ System.err.print("Expect Hi here: ");
+ assertEquals(Long.valueOf(10l), (Byte) mh.invoke(1, 2, 3, 4));
+ fail();
+ } catch (ClassCastException e) {}
+ try {
+ // WrongMethodTypeException should be raised before invoke here.
+ System.err.println("Don't expect Hi now");
+ byte b = (byte) mh.invoke(1, 2, 3, 4);
+ fail();
+ } catch (WrongMethodTypeException e) {}
+
+ // Return void produces 0 / null.
+ mh = MethodHandles.lookup().findStatic(VariableArityTester.class, "foo",
+ MethodType.methodType(void.class, int[].class));
+ assertEquals(null, (Object) mh.invoke(3, 2, 1));
+ assertEquals(0l, (long) mh.invoke(1, 2, 3));
+
+ // Combinators
+ mh = MethodHandles.lookup().findVirtual(VariableArityTester.class, "update",
+ MethodType.methodType(String.class, boolean[].class));
+ assertTrue(mh.isVarargsCollector());
+ mh = mh.bindTo(vat);
+ assertFalse(mh.isVarargsCollector());
+ mh = mh.asVarargsCollector(boolean[].class);
+ assertTrue(mh.isVarargsCollector());
+ assertEquals("[]", mh.invoke());
+ assertEquals("[true, false, true]", mh.invoke(true, false, true));
+ assertEquals("[true, false, true]", mh.invoke(new boolean[] { true, false, true}));
+ assertEquals("[false, true]", mh.invoke(Boolean.valueOf(false), Boolean.valueOf(true)));
+ try {
+ mh.invoke(true, true, 0);
+ fail();
+ } catch (WrongMethodTypeException e) {}
+ }
}