Fix a bug in ClassTableGet code generation for IMTs.
Introduced by:
https://android-review.googlesource.com/#/c/244980/
test:566-polymorphic-inling for fixing x86 crash. Also
fixes a performance regression.
bug:29188168
(cherry picked from commit ff484b95b25a5181a6a8a191cbd11da501c97651)
Change-Id: Iae5a63cb24017222c3fefda695a0a39673719f51
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc
index 3fe4e73..45e9b58 100644
--- a/compiler/optimizing/code_generator_arm.cc
+++ b/compiler/optimizing/code_generator_arm.cc
@@ -6772,21 +6772,25 @@
void InstructionCodeGeneratorARM::VisitClassTableGet(HClassTableGet* instruction) {
LocationSummary* locations = instruction->GetLocations();
- uint32_t method_offset = 0;
if (instruction->GetTableKind() == HClassTableGet::TableKind::kVTable) {
- method_offset = mirror::Class::EmbeddedVTableEntryOffset(
+ uint32_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
instruction->GetIndex(), kArmPointerSize).SizeValue();
+ __ LoadFromOffset(kLoadWord,
+ locations->Out().AsRegister<Register>(),
+ locations->InAt(0).AsRegister<Register>(),
+ method_offset);
} else {
- __ LoadFromOffset(kLoadWord, locations->Out().AsRegister<Register>(),
- locations->InAt(0).AsRegister<Register>(),
- mirror::Class::ImtPtrOffset(kArmPointerSize).Uint32Value());
- method_offset = static_cast<uint32_t>(ImTable::OffsetOfElement(
+ uint32_t method_offset = static_cast<uint32_t>(ImTable::OffsetOfElement(
instruction->GetIndex() % ImTable::kSize, kArmPointerSize));
+ __ LoadFromOffset(kLoadWord,
+ locations->Out().AsRegister<Register>(),
+ locations->InAt(0).AsRegister<Register>(),
+ mirror::Class::ImtPtrOffset(kArmPointerSize).Uint32Value());
+ __ LoadFromOffset(kLoadWord,
+ locations->Out().AsRegister<Register>(),
+ locations->Out().AsRegister<Register>(),
+ method_offset);
}
- __ LoadFromOffset(kLoadWord,
- locations->Out().AsRegister<Register>(),
- locations->InAt(0).AsRegister<Register>(),
- method_offset);
}
#undef __
diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc
index d956aa5..8e58b15 100644
--- a/compiler/optimizing/code_generator_arm64.cc
+++ b/compiler/optimizing/code_generator_arm64.cc
@@ -5182,18 +5182,19 @@
void InstructionCodeGeneratorARM64::VisitClassTableGet(HClassTableGet* instruction) {
LocationSummary* locations = instruction->GetLocations();
- uint32_t method_offset = 0;
if (instruction->GetTableKind() == HClassTableGet::TableKind::kVTable) {
- method_offset = mirror::Class::EmbeddedVTableEntryOffset(
+ uint32_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
instruction->GetIndex(), kArm64PointerSize).SizeValue();
+ __ Ldr(XRegisterFrom(locations->Out()),
+ MemOperand(XRegisterFrom(locations->InAt(0)), method_offset));
} else {
+ uint32_t method_offset = static_cast<uint32_t>(ImTable::OffsetOfElement(
+ instruction->GetIndex() % ImTable::kSize, kArm64PointerSize));
__ Ldr(XRegisterFrom(locations->Out()), MemOperand(XRegisterFrom(locations->InAt(0)),
mirror::Class::ImtPtrOffset(kArm64PointerSize).Uint32Value()));
- method_offset = static_cast<uint32_t>(ImTable::OffsetOfElement(
- instruction->GetIndex() % ImTable::kSize, kArm64PointerSize));
+ __ Ldr(XRegisterFrom(locations->Out()),
+ MemOperand(XRegisterFrom(locations->Out()), method_offset));
}
- __ Ldr(XRegisterFrom(locations->Out()),
- MemOperand(XRegisterFrom(locations->InAt(0)), method_offset));
}
diff --git a/compiler/optimizing/code_generator_mips.cc b/compiler/optimizing/code_generator_mips.cc
index c79834d1..06248a3 100644
--- a/compiler/optimizing/code_generator_mips.cc
+++ b/compiler/optimizing/code_generator_mips.cc
@@ -5189,22 +5189,25 @@
void InstructionCodeGeneratorMIPS::VisitClassTableGet(HClassTableGet* instruction) {
LocationSummary* locations = instruction->GetLocations();
- uint32_t method_offset = 0;
if (instruction->GetTableKind() == HClassTableGet::TableKind::kVTable) {
- method_offset = mirror::Class::EmbeddedVTableEntryOffset(
+ uint32_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
instruction->GetIndex(), kMipsPointerSize).SizeValue();
+ __ LoadFromOffset(kLoadWord,
+ locations->Out().AsRegister<Register>(),
+ locations->InAt(0).AsRegister<Register>(),
+ method_offset);
} else {
+ uint32_t method_offset = static_cast<uint32_t>(ImTable::OffsetOfElement(
+ instruction->GetIndex() % ImTable::kSize, kMipsPointerSize));
__ LoadFromOffset(kLoadWord,
locations->Out().AsRegister<Register>(),
locations->InAt(0).AsRegister<Register>(),
mirror::Class::ImtPtrOffset(kMipsPointerSize).Uint32Value());
- method_offset = static_cast<uint32_t>(ImTable::OffsetOfElement(
- instruction->GetIndex() % ImTable::kSize, kMipsPointerSize));
+ __ LoadFromOffset(kLoadWord,
+ locations->Out().AsRegister<Register>(),
+ locations->Out().AsRegister<Register>(),
+ method_offset);
}
- __ LoadFromOffset(kLoadWord,
- locations->Out().AsRegister<Register>(),
- locations->InAt(0).AsRegister<Register>(),
- method_offset);
}
#undef __
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index df8c041..51d9b7c 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -4068,20 +4068,21 @@
void InstructionCodeGeneratorX86::VisitClassTableGet(HClassTableGet* instruction) {
LocationSummary* locations = instruction->GetLocations();
- uint32_t method_offset = 0;
if (instruction->GetTableKind() == HClassTableGet::TableKind::kVTable) {
- method_offset = mirror::Class::EmbeddedVTableEntryOffset(
+ uint32_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
instruction->GetIndex(), kX86PointerSize).SizeValue();
+ __ movl(locations->Out().AsRegister<Register>(),
+ Address(locations->InAt(0).AsRegister<Register>(), method_offset));
} else {
- __ movl(locations->InAt(0).AsRegister<Register>(),
- Address(locations->InAt(0).AsRegister<Register>(),
- mirror::Class::ImtPtrOffset(kX86PointerSize).Uint32Value()));
- // temp = temp->GetImtEntryAt(method_offset);
- method_offset = static_cast<uint32_t>(ImTable::OffsetOfElement(
+ uint32_t method_offset = static_cast<uint32_t>(ImTable::OffsetOfElement(
instruction->GetIndex() % ImTable::kSize, kX86PointerSize));
+ __ movl(locations->Out().AsRegister<Register>(),
+ Address(locations->InAt(0).AsRegister<Register>(),
+ mirror::Class::ImtPtrOffset(kX86PointerSize).Uint32Value()));
+ // temp = temp->GetImtEntryAt(method_offset);
+ __ movl(locations->Out().AsRegister<Register>(),
+ Address(locations->Out().AsRegister<Register>(), method_offset));
}
- __ movl(locations->Out().AsRegister<Register>(),
- Address(locations->InAt(0).AsRegister<Register>(), method_offset));
}
void LocationsBuilderX86::VisitNot(HNot* not_) {
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc
index 40df1b9..28b52a1 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -3980,19 +3980,20 @@
void InstructionCodeGeneratorX86_64::VisitClassTableGet(HClassTableGet* instruction) {
LocationSummary* locations = instruction->GetLocations();
- uint32_t method_offset = 0;
if (instruction->GetTableKind() == HClassTableGet::TableKind::kVTable) {
- method_offset = mirror::Class::EmbeddedVTableEntryOffset(
+ uint32_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
instruction->GetIndex(), kX86_64PointerSize).SizeValue();
+ __ movq(locations->Out().AsRegister<CpuRegister>(),
+ Address(locations->InAt(0).AsRegister<CpuRegister>(), method_offset));
} else {
+ uint32_t method_offset = static_cast<uint32_t>(ImTable::OffsetOfElement(
+ instruction->GetIndex() % ImTable::kSize, kX86_64PointerSize));
__ movq(locations->Out().AsRegister<CpuRegister>(),
Address(locations->InAt(0).AsRegister<CpuRegister>(),
mirror::Class::ImtPtrOffset(kX86_64PointerSize).Uint32Value()));
- method_offset = static_cast<uint32_t>(ImTable::OffsetOfElement(
- instruction->GetIndex() % ImTable::kSize, kX86_64PointerSize));
+ __ movq(locations->Out().AsRegister<CpuRegister>(),
+ Address(locations->Out().AsRegister<CpuRegister>(), method_offset));
}
- __ movq(locations->Out().AsRegister<CpuRegister>(),
- Address(locations->InAt(0).AsRegister<CpuRegister>(), method_offset));
}
void LocationsBuilderX86_64::VisitNot(HNot* not_) {
diff --git a/test/566-polymorphic-inlining/polymorphic_inline.cc b/test/566-polymorphic-inlining/polymorphic_inline.cc
index 7b2c6cb..c1651e5 100644
--- a/test/566-polymorphic-inlining/polymorphic_inline.cc
+++ b/test/566-polymorphic-inlining/polymorphic_inline.cc
@@ -60,6 +60,7 @@
do_checks(cls, "testInvokeVirtual");
do_checks(cls, "testInvokeInterface");
+ do_checks(cls, "testInvokeInterface2");
do_checks(cls, "$noinline$testInlineToSameTarget");
}
diff --git a/test/566-polymorphic-inlining/src/Main.java b/test/566-polymorphic-inlining/src/Main.java
index 286f0d9..411264d 100644
--- a/test/566-polymorphic-inlining/src/Main.java
+++ b/test/566-polymorphic-inlining/src/Main.java
@@ -16,6 +16,8 @@
interface Itf {
public Class sameInvokeInterface();
+ public Class sameInvokeInterface2();
+ public Class sameInvokeInterface3();
}
public class Main implements Itf {
@@ -47,6 +49,8 @@
testInvokeVirtual(mains[1]);
testInvokeInterface(itfs[0]);
testInvokeInterface(itfs[1]);
+ testInvokeInterface2(itfs[0]);
+ testInvokeInterface2(itfs[1]);
$noinline$testInlineToSameTarget(mains[0]);
$noinline$testInlineToSameTarget(mains[1]);
}
@@ -61,9 +65,13 @@
assertEquals(Itf.class, testInvokeInterface(itfs[0]));
assertEquals(Itf.class, testInvokeInterface(itfs[1]));
+ assertEquals(Itf.class, testInvokeInterface2(itfs[0]));
+ assertEquals(Itf.class, testInvokeInterface2(itfs[1]));
+
// This will trigger a deoptimization of the compiled code.
assertEquals(OtherSubclass.class, testInvokeVirtual(mains[2]));
assertEquals(OtherSubclass.class, testInvokeInterface(itfs[2]));
+ assertEquals(null, testInvokeInterface2(itfs[2]));
// Run this once to make sure we execute the JITted code.
$noinline$testInlineToSameTarget(mains[0]);
@@ -80,10 +88,28 @@
return Itf.class;
}
+ public Class sameInvokeInterface2() {
+ field.getClass(); // null check to ensure we get an inlined frame in the CodeInfo.
+ return Itf.class;
+ }
+
+ public Class sameInvokeInterface3() {
+ field.getClass(); // null check to ensure we get an inlined frame in the CodeInfo.
+ return Itf.class;
+ }
+
public static Class testInvokeInterface(Itf i) {
return i.sameInvokeInterface();
}
+ public static Class testInvokeInterface2(Itf i) {
+ // Make three interface calls that will do a ClassTableGet to ensure bogus code
+ // generation of ClassTableGet will crash.
+ i.sameInvokeInterface();
+ i.sameInvokeInterface2();
+ return i.sameInvokeInterface3();
+ }
+
public static Class testInvokeVirtual(Main m) {
return m.sameInvokeVirtual();
}
@@ -115,4 +141,11 @@
public Class sameInvokeInterface() {
return OtherSubclass.class;
}
+
+ public Class sameInvokeInterface2() {
+ return null;
+ }
+ public Class sameInvokeInterface3() {
+ return null;
+ }
}