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
Change-Id: Id90cb819c88e7ba3db1cb3c50c517a112ab7d784
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc
index 97645f3..a22cfe8 100644
--- a/compiler/optimizing/code_generator_arm.cc
+++ b/compiler/optimizing/code_generator_arm.cc
@@ -6950,21 +6950,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 7cdcea2..f76ba4b 100644
--- a/compiler/optimizing/code_generator_arm64.cc
+++ b/compiler/optimizing/code_generator_arm64.cc
@@ -5343,18 +5343,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 1038b2d..2b71da0 100644
--- a/compiler/optimizing/code_generator_mips.cc
+++ b/compiler/optimizing/code_generator_mips.cc
@@ -5380,22 +5380,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 2ded562..96c2857 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -4073,20 +4073,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 fd7d483..41b62a4 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -4006,19 +4006,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 c0d93dd..9f4c6c9 100644
--- a/test/566-polymorphic-inlining/polymorphic_inline.cc
+++ b/test/566-polymorphic-inlining/polymorphic_inline.cc
@@ -81,6 +81,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 d39e6ed..53852a4 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 {
@@ -50,6 +52,8 @@
testInvokeVirtual(mains[1]);
testInvokeInterface(itfs[0]);
testInvokeInterface(itfs[1]);
+ testInvokeInterface2(itfs[0]);
+ testInvokeInterface2(itfs[1]);
$noinline$testInlineToSameTarget(mains[0]);
$noinline$testInlineToSameTarget(mains[1]);
}
@@ -64,9 +68,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]);
@@ -83,10 +91,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();
}
@@ -120,4 +146,11 @@
public Class sameInvokeInterface() {
return OtherSubclass.class;
}
+
+ public Class sameInvokeInterface2() {
+ return null;
+ }
+ public Class sameInvokeInterface3() {
+ return null;
+ }
}