From abfcf18fa2fe723bd683edcb685ed5058d9c7cf3 Mon Sep 17 00:00:00 2001 From: Nicolas Geoffray Date: Mon, 21 Sep 2015 18:41:21 +0100 Subject: [PATCH] Further refinements to checkcast/instanceof. - Use setcc when possible. - Do an exact check in the Object[] case before checking the component type. Change-Id: Ic11c60643af9b41fe4ef2beb59dfe7769bef388f --- compiler/optimizing/code_generator_arm.cc | 17 ++++++++---- compiler/optimizing/code_generator_arm64.cc | 17 ++++++++---- compiler/optimizing/code_generator_x86.cc | 30 ++++++++++++++++---- compiler/optimizing/code_generator_x86_64.cc | 41 ++++++++++++++++++++++------ 4 files changed, 80 insertions(+), 25 deletions(-) diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc index d431acfb5..411e05f44 100644 --- a/compiler/optimizing/code_generator_arm.cc +++ b/compiler/optimizing/code_generator_arm.cc @@ -4477,7 +4477,11 @@ void InstructionCodeGeneratorARM::VisitInstanceOf(HInstanceOf* instruction) { break; } case TypeCheckKind::kArrayObjectCheck: { - // Just need to check that the object's class is a non primitive array. + // Do an exact check. + Label exact_check; + __ cmp(out, ShifterOperand(cls)); + __ b(&exact_check, EQ); + // Otherwise, we need to check that the object's class is a non primitive array. __ LoadFromOffset(kLoadWord, out, out, component_offset); __ MaybeUnpoisonHeapReference(out); // If `out` is null, we use it for the result, and jump to `done`. @@ -4485,6 +4489,7 @@ void InstructionCodeGeneratorARM::VisitInstanceOf(HInstanceOf* instruction) { __ LoadFromOffset(kLoadUnsignedHalfword, out, out, primitive_offset); static_assert(Primitive::kPrimNot == 0, "Expected 0 for kPrimNot"); __ CompareAndBranchIfNonZero(out, &zero); + __ Bind(&exact_check); __ LoadImmediate(out, 1); __ b(&done); break; @@ -4623,20 +4628,22 @@ void InstructionCodeGeneratorARM::VisitCheckCast(HCheckCast* instruction) { } case TypeCheckKind::kClassHierarchyCheck: { // Walk over the class hierarchy to find a match. - Label loop, success; + Label loop; __ Bind(&loop); __ cmp(temp, ShifterOperand(cls)); - __ b(&success, EQ); + __ b(&done, EQ); __ LoadFromOffset(kLoadWord, temp, temp, super_offset); __ MaybeUnpoisonHeapReference(temp); __ CompareAndBranchIfNonZero(temp, &loop); // Jump to the slow path to throw the exception. __ b(slow_path->GetEntryLabel()); - __ Bind(&success); break; } case TypeCheckKind::kArrayObjectCheck: { - // Just need to check that the object's class is a non primitive array. + // Do an exact check. + __ cmp(temp, ShifterOperand(cls)); + __ b(&done, EQ); + // Otherwise, we need to check that the object's class is a non primitive array. __ LoadFromOffset(kLoadWord, temp, temp, component_offset); __ MaybeUnpoisonHeapReference(temp); __ CompareAndBranchIfZero(temp, slow_path->GetEntryLabel()); diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc index 580e93e9c..8e1260e82 100644 --- a/compiler/optimizing/code_generator_arm64.cc +++ b/compiler/optimizing/code_generator_arm64.cc @@ -2342,7 +2342,11 @@ void InstructionCodeGeneratorARM64::VisitInstanceOf(HInstanceOf* instruction) { break; } case TypeCheckKind::kArrayObjectCheck: { - // Just need to check that the object's class is a non primitive array. + // Do an exact check. + vixl::Label exact_check; + __ Cmp(out, cls); + __ B(eq, &exact_check); + // Otherwise, we need to check that the object's class is a non primitive array. __ Ldr(out, HeapOperand(out, component_offset)); GetAssembler()->MaybeUnpoisonHeapReference(out); // If `out` is null, we use it for the result, and jump to `done`. @@ -2350,6 +2354,7 @@ void InstructionCodeGeneratorARM64::VisitInstanceOf(HInstanceOf* instruction) { __ Ldrh(out, HeapOperand(out, primitive_offset)); static_assert(Primitive::kPrimNot == 0, "Expected 0 for kPrimNot"); __ Cbnz(out, &zero); + __ Bind(&exact_check); __ Mov(out, 1); __ B(&done); break; @@ -2489,20 +2494,22 @@ void InstructionCodeGeneratorARM64::VisitCheckCast(HCheckCast* instruction) { } case TypeCheckKind::kClassHierarchyCheck: { // Walk over the class hierarchy to find a match. - vixl::Label loop, success; + vixl::Label loop; __ Bind(&loop); __ Cmp(temp, cls); - __ B(eq, &success); + __ B(eq, &done); __ Ldr(temp, HeapOperand(temp, super_offset)); GetAssembler()->MaybeUnpoisonHeapReference(temp); __ Cbnz(temp, &loop); // Jump to the slow path to throw the exception. __ B(slow_path->GetEntryLabel()); - __ Bind(&success); break; } case TypeCheckKind::kArrayObjectCheck: { - // Just need to check that the object's class is a non primitive array. + // Do an exact check. + __ Cmp(temp, cls); + __ B(eq, &done); + // Otherwise, we need to check that the object's class is a non primitive array. __ Ldr(temp, HeapOperand(temp, component_offset)); GetAssembler()->MaybeUnpoisonHeapReference(temp); __ Cbz(temp, slow_path->GetEntryLabel()); diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc index 3d03dd814..86cdbdde8 100644 --- a/compiler/optimizing/code_generator_x86.cc +++ b/compiler/optimizing/code_generator_x86.cc @@ -1314,7 +1314,7 @@ void InstructionCodeGeneratorX86::VisitCondition(HCondition* cond) { default: { // Integer case. - // Clear output register: setcc only sets the low byte. + // Clear output register: setb only sets the low byte. __ xorl(reg, reg); if (rhs.IsRegister()) { @@ -5038,6 +5038,7 @@ void InstructionCodeGeneratorX86::VisitInstanceOf(HInstanceOf* instruction) { DCHECK(cls.IsStackSlot()) << cls; __ cmpl(out, Address(ESP, cls.GetStackIndex())); } + // Classes must be equal for the instanceof to succeed. __ j(kNotEqual, &zero); __ movl(out, Immediate(1)); @@ -5092,7 +5093,16 @@ void InstructionCodeGeneratorX86::VisitInstanceOf(HInstanceOf* instruction) { break; } case TypeCheckKind::kArrayObjectCheck: { - // Just need to check that the object's class is a non primitive array. + // Do an exact check. + NearLabel exact_check; + if (cls.IsRegister()) { + __ cmpl(out, cls.AsRegister()); + } else { + DCHECK(cls.IsStackSlot()) << cls; + __ cmpl(out, Address(ESP, cls.GetStackIndex())); + } + __ j(kEqual, &exact_check); + // Otherwise, we need to check that the object's class is a non primitive array. __ movl(out, Address(out, component_offset)); __ MaybeUnpoisonHeapReference(out); __ testl(out, out); @@ -5100,6 +5110,7 @@ void InstructionCodeGeneratorX86::VisitInstanceOf(HInstanceOf* instruction) { __ j(kEqual, &done); __ cmpw(Address(out, primitive_offset), Immediate(Primitive::kPrimNot)); __ j(kNotEqual, &zero); + __ Bind(&exact_check); __ movl(out, Immediate(1)); __ jmp(&done); break; @@ -5255,7 +5266,7 @@ void InstructionCodeGeneratorX86::VisitCheckCast(HCheckCast* instruction) { } case TypeCheckKind::kClassHierarchyCheck: { // Walk over the class hierarchy to find a match. - NearLabel loop, success; + NearLabel loop; __ Bind(&loop); if (cls.IsRegister()) { __ cmpl(temp, cls.AsRegister()); @@ -5263,18 +5274,25 @@ void InstructionCodeGeneratorX86::VisitCheckCast(HCheckCast* instruction) { DCHECK(cls.IsStackSlot()) << cls; __ cmpl(temp, Address(ESP, cls.GetStackIndex())); } - __ j(kEqual, &success); + __ j(kEqual, &done); __ movl(temp, Address(temp, super_offset)); __ MaybeUnpoisonHeapReference(temp); __ testl(temp, temp); __ j(kNotEqual, &loop); // Jump to the slow path to throw the exception. __ jmp(slow_path->GetEntryLabel()); - __ Bind(&success); break; } case TypeCheckKind::kArrayObjectCheck: { - // Just need to check that the object's class is a non primitive array. + // Do an exact check. + if (cls.IsRegister()) { + __ cmpl(temp, cls.AsRegister()); + } else { + DCHECK(cls.IsStackSlot()) << cls; + __ cmpl(temp, Address(ESP, cls.GetStackIndex())); + } + __ j(kEqual, &done); + // Otherwise, we need to check that the object's class is a non primitive array. __ movl(temp, Address(temp, component_offset)); __ MaybeUnpoisonHeapReference(temp); __ testl(temp, temp); diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc index 32a1db547..b78b017e2 100644 --- a/compiler/optimizing/code_generator_x86_64.cc +++ b/compiler/optimizing/code_generator_x86_64.cc @@ -4766,10 +4766,16 @@ void InstructionCodeGeneratorX86_64::VisitInstanceOf(HInstanceOf* instruction) { DCHECK(cls.IsStackSlot()) << cls; __ cmpl(out, Address(CpuRegister(RSP), cls.GetStackIndex())); } - // Classes must be equal for the instanceof to succeed. - __ j(kNotEqual, &zero); - __ movl(out, Immediate(1)); - __ jmp(&done); + if (zero.IsLinked()) { + // Classes must be equal for the instanceof to succeed. + __ j(kNotEqual, &zero); + __ movl(out, Immediate(1)); + __ jmp(&done); + } else { + __ setcc(kEqual, out); + // setcc only sets the low byte. + __ andl(out, Immediate(1)); + } break; } case TypeCheckKind::kAbstractClassCheck: { @@ -4820,7 +4826,16 @@ void InstructionCodeGeneratorX86_64::VisitInstanceOf(HInstanceOf* instruction) { break; } case TypeCheckKind::kArrayObjectCheck: { - // Just need to check that the object's class is a non primitive array. + // Do an exact check. + NearLabel exact_check; + if (cls.IsRegister()) { + __ cmpl(out, cls.AsRegister()); + } else { + DCHECK(cls.IsStackSlot()) << cls; + __ cmpl(out, Address(CpuRegister(RSP), cls.GetStackIndex())); + } + __ j(kEqual, &exact_check); + // Otherwise, we need to check that the object's class is a non primitive array. __ movl(out, Address(out, component_offset)); __ MaybeUnpoisonHeapReference(out); __ testl(out, out); @@ -4828,6 +4843,7 @@ void InstructionCodeGeneratorX86_64::VisitInstanceOf(HInstanceOf* instruction) { __ j(kEqual, &done); __ cmpw(Address(out, primitive_offset), Immediate(Primitive::kPrimNot)); __ j(kNotEqual, &zero); + __ Bind(&exact_check); __ movl(out, Immediate(1)); __ jmp(&done); break; @@ -4983,7 +4999,7 @@ void InstructionCodeGeneratorX86_64::VisitCheckCast(HCheckCast* instruction) { } case TypeCheckKind::kClassHierarchyCheck: { // Walk over the class hierarchy to find a match. - NearLabel loop, success; + NearLabel loop; __ Bind(&loop); if (cls.IsRegister()) { __ cmpl(temp, cls.AsRegister()); @@ -4991,18 +5007,25 @@ void InstructionCodeGeneratorX86_64::VisitCheckCast(HCheckCast* instruction) { DCHECK(cls.IsStackSlot()) << cls; __ cmpl(temp, Address(CpuRegister(RSP), cls.GetStackIndex())); } - __ j(kEqual, &success); + __ j(kEqual, &done); __ movl(temp, Address(temp, super_offset)); __ MaybeUnpoisonHeapReference(temp); __ testl(temp, temp); __ j(kNotEqual, &loop); // Jump to the slow path to throw the exception. __ jmp(slow_path->GetEntryLabel()); - __ Bind(&success); break; } case TypeCheckKind::kArrayObjectCheck: { - // Just need to check that the object's class is a non primitive array. + // Do an exact check. + if (cls.IsRegister()) { + __ cmpl(temp, cls.AsRegister()); + } else { + DCHECK(cls.IsStackSlot()) << cls; + __ cmpl(temp, Address(CpuRegister(RSP), cls.GetStackIndex())); + } + __ j(kEqual, &done); + // Otherwise, we need to check that the object's class is a non primitive array. __ movl(temp, Address(temp, component_offset)); __ MaybeUnpoisonHeapReference(temp); __ testl(temp, temp); -- 2.11.0