diff options
author | Nicolas Geoffray <ngeoffray@google.com> | 2014-11-07 17:47:25 +0000 |
---|---|---|
committer | Nicolas Geoffray <ngeoffray@google.com> | 2014-11-10 10:33:37 +0000 |
commit | 52839d17c06175e19ca4a093fb878450d1c4310d (patch) | |
tree | 552ea632ad4d1f688bdfd04b66102e25312bd237 | |
parent | a453307957afdc3ef0a7988025539ab8919464bc (diff) | |
download | art-52839d17c06175e19ca4a093fb878450d1c4310d.zip art-52839d17c06175e19ca4a093fb878450d1c4310d.tar.gz art-52839d17c06175e19ca4a093fb878450d1c4310d.tar.bz2 |
Support invoke-interface in optimizing.
Change-Id: Ic18d7c3d2810557231caf0571956e0c431f5d384
-rw-r--r-- | compiler/optimizing/builder.cc | 26 | ||||
-rw-r--r-- | compiler/optimizing/code_generator.cc | 6 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_arm.cc | 43 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_arm64.cc | 1 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_x86.cc | 35 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_x86_64.cc | 43 | ||||
-rw-r--r-- | compiler/optimizing/nodes.h | 25 | ||||
-rw-r--r-- | compiler/optimizing/register_allocator.cc | 3 | ||||
-rw-r--r-- | test/423-invoke-interface/expected.txt | 0 | ||||
-rw-r--r-- | test/423-invoke-interface/info.txt | 2 | ||||
-rw-r--r-- | test/423-invoke-interface/src/Main.java | 120 | ||||
-rw-r--r-- | test/Android.run-test.mk | 1 |
12 files changed, 287 insertions, 18 deletions
diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc index 64fb764..8baf3c5 100644 --- a/compiler/optimizing/builder.cc +++ b/compiler/optimizing/builder.cc @@ -381,20 +381,28 @@ bool HGraphBuilder::BuildInvoke(const Instruction& instruction, const size_t number_of_arguments = strlen(descriptor) - (is_instance_call ? 0 : 1); HInvoke* invoke = nullptr; - if (invoke_type == kVirtual) { + if (invoke_type == kVirtual || invoke_type == kInterface) { MethodReference target_method(dex_file_, method_idx); uintptr_t direct_code; uintptr_t direct_method; - int vtable_index; + int table_index; + InvokeType optimized_invoke_type = invoke_type; // TODO: Add devirtualization support. compiler_driver_->ComputeInvokeInfo(dex_compilation_unit_, dex_offset, true, true, - &invoke_type, &target_method, &vtable_index, + &optimized_invoke_type, &target_method, &table_index, &direct_code, &direct_method); - if (vtable_index == -1) { + if (table_index == -1) { return false; } - invoke = new (arena_) HInvokeVirtual( - arena_, number_of_arguments, return_type, dex_offset, vtable_index); + + if (invoke_type == kVirtual) { + invoke = new (arena_) HInvokeVirtual( + arena_, number_of_arguments, return_type, dex_offset, table_index); + } else { + DCHECK_EQ(invoke_type, kInterface); + invoke = new (arena_) HInvokeInterface( + arena_, number_of_arguments, return_type, dex_offset, method_idx, table_index); + } } else { // Treat invoke-direct like static calls for now. invoke = new (arena_) HInvokeStatic( @@ -870,7 +878,8 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32 case Instruction::INVOKE_STATIC: case Instruction::INVOKE_DIRECT: - case Instruction::INVOKE_VIRTUAL: { + case Instruction::INVOKE_VIRTUAL: + case Instruction::INVOKE_INTERFACE: { uint32_t method_idx = instruction.VRegB_35c(); uint32_t number_of_vreg_arguments = instruction.VRegA_35c(); uint32_t args[5]; @@ -883,7 +892,8 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32 case Instruction::INVOKE_STATIC_RANGE: case Instruction::INVOKE_DIRECT_RANGE: - case Instruction::INVOKE_VIRTUAL_RANGE: { + case Instruction::INVOKE_VIRTUAL_RANGE: + case Instruction::INVOKE_INTERFACE_RANGE: { uint32_t method_idx = instruction.VRegB_3rc(); uint32_t number_of_vreg_arguments = instruction.VRegA_3rc(); uint32_t register_index = instruction.VRegC(); diff --git a/compiler/optimizing/code_generator.cc b/compiler/optimizing/code_generator.cc index c75980d..c965489 100644 --- a/compiler/optimizing/code_generator.cc +++ b/compiler/optimizing/code_generator.cc @@ -216,10 +216,14 @@ void CodeGenerator::AllocateRegistersLocally(HInstruction* instruction) const { for (size_t i = 0, e = locations->GetTempCount(); i < e; ++i) { Location loc = locations->GetTemp(i); + // The DCHECKS below check that a register is not specified twice in + // the summary. if (loc.IsRegister()) { - // Check that a register is not specified twice in the summary. DCHECK(!blocked_core_registers_[loc.reg()]); blocked_core_registers_[loc.reg()] = true; + } else if (loc.IsFpuRegister()) { + DCHECK(!blocked_fpu_registers_[loc.reg()]); + blocked_fpu_registers_[loc.reg()] = true; } else { DCHECK_EQ(loc.GetPolicy(), Location::kRequiresRegister); } diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc index fef7f0e..8c54cdf 100644 --- a/compiler/optimizing/code_generator_arm.cc +++ b/compiler/optimizing/code_generator_arm.cc @@ -1131,10 +1131,6 @@ void InstructionCodeGeneratorARM::VisitInvokeStatic(HInvokeStatic* invoke) { DCHECK(!codegen_->IsLeafMethod()); } -void LocationsBuilderARM::VisitInvokeVirtual(HInvokeVirtual* invoke) { - HandleInvoke(invoke); -} - void LocationsBuilderARM::HandleInvoke(HInvoke* invoke) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(invoke, LocationSummary::kCall); @@ -1149,6 +1145,9 @@ void LocationsBuilderARM::HandleInvoke(HInvoke* invoke) { locations->SetOut(calling_convention_visitor.GetReturnLocation(invoke->GetType())); } +void LocationsBuilderARM::VisitInvokeVirtual(HInvokeVirtual* invoke) { + HandleInvoke(invoke); +} void InstructionCodeGeneratorARM::VisitInvokeVirtual(HInvokeVirtual* invoke) { Register temp = invoke->GetLocations()->GetTemp(0).As<Register>(); @@ -1175,6 +1174,42 @@ void InstructionCodeGeneratorARM::VisitInvokeVirtual(HInvokeVirtual* invoke) { codegen_->RecordPcInfo(invoke, invoke->GetDexPc()); } +void LocationsBuilderARM::VisitInvokeInterface(HInvokeInterface* invoke) { + HandleInvoke(invoke); + // Add the hidden argument. + invoke->GetLocations()->AddTemp(Location::RegisterLocation(R12)); +} + +void InstructionCodeGeneratorARM::VisitInvokeInterface(HInvokeInterface* invoke) { + // TODO: b/18116999, our IMTs can miss an IncompatibleClassChangeError. + Register temp = invoke->GetLocations()->GetTemp(0).As<Register>(); + uint32_t method_offset = mirror::Class::EmbeddedImTableOffset().Uint32Value() + + (invoke->GetImtIndex() % mirror::Class::kImtSize) * sizeof(mirror::Class::ImTableEntry); + LocationSummary* locations = invoke->GetLocations(); + Location receiver = locations->InAt(0); + uint32_t class_offset = mirror::Object::ClassOffset().Int32Value(); + + // Set the hidden argument. + __ LoadImmediate(invoke->GetLocations()->GetTemp(1).As<Register>(), invoke->GetDexMethodIndex()); + + // temp = object->GetClass(); + if (receiver.IsStackSlot()) { + __ LoadFromOffset(kLoadWord, temp, SP, receiver.GetStackIndex()); + __ LoadFromOffset(kLoadWord, temp, temp, class_offset); + } else { + __ LoadFromOffset(kLoadWord, temp, receiver.As<Register>(), class_offset); + } + // temp = temp->GetImtEntryAt(method_offset); + uint32_t entry_point = mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value(); + __ LoadFromOffset(kLoadWord, temp, temp, method_offset); + // LR = temp->GetEntryPoint(); + __ LoadFromOffset(kLoadWord, LR, temp, entry_point); + // LR(); + __ blx(LR); + DCHECK(!codegen_->IsLeafMethod()); + codegen_->RecordPcInfo(invoke, invoke->GetDexPc()); +} + void LocationsBuilderARM::VisitNeg(HNeg* neg) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall); diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc index 1be5717..667b075 100644 --- a/compiler/optimizing/code_generator_arm64.cc +++ b/compiler/optimizing/code_generator_arm64.cc @@ -539,6 +539,7 @@ InstructionCodeGeneratorARM64::InstructionCodeGeneratorARM64(HGraph* graph, M(Div) \ M(DivZeroCheck) \ M(FloatConstant) \ + M(InvokeInterface) \ M(LoadClass) \ M(LoadException) \ M(LoadString) \ diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc index 127ddbe..91aa269 100644 --- a/compiler/optimizing/code_generator_x86.cc +++ b/compiler/optimizing/code_generator_x86.cc @@ -1104,6 +1104,41 @@ void InstructionCodeGeneratorX86::VisitInvokeVirtual(HInvokeVirtual* invoke) { codegen_->RecordPcInfo(invoke, invoke->GetDexPc()); } +void LocationsBuilderX86::VisitInvokeInterface(HInvokeInterface* invoke) { + HandleInvoke(invoke); + // Add the hidden argument. + invoke->GetLocations()->AddTemp(Location::FpuRegisterLocation(XMM0)); +} + +void InstructionCodeGeneratorX86::VisitInvokeInterface(HInvokeInterface* invoke) { + // TODO: b/18116999, our IMTs can miss an IncompatibleClassChangeError. + Register temp = invoke->GetLocations()->GetTemp(0).As<Register>(); + uint32_t method_offset = mirror::Class::EmbeddedImTableOffset().Uint32Value() + + (invoke->GetImtIndex() % mirror::Class::kImtSize) * sizeof(mirror::Class::ImTableEntry); + LocationSummary* locations = invoke->GetLocations(); + Location receiver = locations->InAt(0); + uint32_t class_offset = mirror::Object::ClassOffset().Int32Value(); + + // Set the hidden argument. + __ movl(temp, Immediate(invoke->GetDexMethodIndex())); + __ movd(invoke->GetLocations()->GetTemp(1).As<XmmRegister>(), temp); + + // temp = object->GetClass(); + if (receiver.IsStackSlot()) { + __ movl(temp, Address(ESP, receiver.GetStackIndex())); + __ movl(temp, Address(temp, class_offset)); + } else { + __ movl(temp, Address(receiver.As<Register>(), class_offset)); + } + // temp = temp->GetImtEntryAt(method_offset); + __ movl(temp, Address(temp, method_offset)); + // call temp->GetEntryPoint(); + __ call(Address(temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value())); + + DCHECK(!codegen_->IsLeafMethod()); + codegen_->RecordPcInfo(invoke, invoke->GetDexPc()); +} + void LocationsBuilderX86::VisitNeg(HNeg* neg) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall); diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc index 8c0842c..1130b4c 100644 --- a/compiler/optimizing/code_generator_x86_64.cc +++ b/compiler/optimizing/code_generator_x86_64.cc @@ -1031,10 +1031,6 @@ void InstructionCodeGeneratorX86_64::VisitInvokeStatic(HInvokeStatic* invoke) { codegen_->RecordPcInfo(invoke, invoke->GetDexPc()); } -void LocationsBuilderX86_64::VisitInvokeVirtual(HInvokeVirtual* invoke) { - HandleInvoke(invoke); -} - void LocationsBuilderX86_64::HandleInvoke(HInvoke* invoke) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(invoke, LocationSummary::kCall); @@ -1067,6 +1063,10 @@ void LocationsBuilderX86_64::HandleInvoke(HInvoke* invoke) { } } +void LocationsBuilderX86_64::VisitInvokeVirtual(HInvokeVirtual* invoke) { + HandleInvoke(invoke); +} + void InstructionCodeGeneratorX86_64::VisitInvokeVirtual(HInvokeVirtual* invoke) { CpuRegister temp = invoke->GetLocations()->GetTemp(0).As<CpuRegister>(); size_t method_offset = mirror::Class::EmbeddedVTableOffset().SizeValue() + @@ -1090,6 +1090,41 @@ void InstructionCodeGeneratorX86_64::VisitInvokeVirtual(HInvokeVirtual* invoke) codegen_->RecordPcInfo(invoke, invoke->GetDexPc()); } +void LocationsBuilderX86_64::VisitInvokeInterface(HInvokeInterface* invoke) { + HandleInvoke(invoke); + // Add the hidden argument. + invoke->GetLocations()->AddTemp(Location::RegisterLocation(RAX)); +} + +void InstructionCodeGeneratorX86_64::VisitInvokeInterface(HInvokeInterface* invoke) { + // TODO: b/18116999, our IMTs can miss an IncompatibleClassChangeError. + CpuRegister temp = invoke->GetLocations()->GetTemp(0).As<CpuRegister>(); + uint32_t method_offset = mirror::Class::EmbeddedImTableOffset().Uint32Value() + + (invoke->GetImtIndex() % mirror::Class::kImtSize) * sizeof(mirror::Class::ImTableEntry); + LocationSummary* locations = invoke->GetLocations(); + Location receiver = locations->InAt(0); + size_t class_offset = mirror::Object::ClassOffset().SizeValue(); + + // Set the hidden argument. + __ movq(invoke->GetLocations()->GetTemp(1).As<CpuRegister>(), + Immediate(invoke->GetDexMethodIndex())); + + // temp = object->GetClass(); + if (receiver.IsStackSlot()) { + __ movl(temp, Address(CpuRegister(RSP), receiver.GetStackIndex())); + __ movl(temp, Address(temp, class_offset)); + } else { + __ movl(temp, Address(receiver.As<CpuRegister>(), class_offset)); + } + // temp = temp->GetImtEntryAt(method_offset); + __ movl(temp, Address(temp, method_offset)); + // call temp->GetEntryPoint(); + __ call(Address(temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().SizeValue())); + + DCHECK(!codegen_->IsLeafMethod()); + codegen_->RecordPcInfo(invoke, invoke->GetDexPc()); +} + void LocationsBuilderX86_64::VisitNeg(HNeg* neg) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall); diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h index 37e5e6b..9253f0b 100644 --- a/compiler/optimizing/nodes.h +++ b/compiler/optimizing/nodes.h @@ -495,6 +495,7 @@ class HBasicBlock : public ArenaObject<kArenaAllocMisc> { M(InstanceFieldGet, Instruction) \ M(InstanceFieldSet, Instruction) \ M(IntConstant, Constant) \ + M(InvokeInterface, Invoke) \ M(InvokeStatic, Invoke) \ M(InvokeVirtual, Invoke) \ M(LessThan, Condition) \ @@ -1603,6 +1604,30 @@ class HInvokeVirtual : public HInvoke { DISALLOW_COPY_AND_ASSIGN(HInvokeVirtual); }; +class HInvokeInterface : public HInvoke { + public: + HInvokeInterface(ArenaAllocator* arena, + uint32_t number_of_arguments, + Primitive::Type return_type, + uint32_t dex_pc, + uint32_t dex_method_index, + uint32_t imt_index) + : HInvoke(arena, number_of_arguments, return_type, dex_pc), + dex_method_index_(dex_method_index), + imt_index_(imt_index) {} + + uint32_t GetImtIndex() const { return imt_index_; } + uint32_t GetDexMethodIndex() const { return dex_method_index_; } + + DECLARE_INSTRUCTION(InvokeInterface); + + private: + const uint32_t dex_method_index_; + const uint32_t imt_index_; + + DISALLOW_COPY_AND_ASSIGN(HInvokeInterface); +}; + class HNewInstance : public HExpression<0> { public: HNewInstance(uint32_t dex_pc, uint16_t type_index) diff --git a/compiler/optimizing/register_allocator.cc b/compiler/optimizing/register_allocator.cc index 0745f9c..bef4af4 100644 --- a/compiler/optimizing/register_allocator.cc +++ b/compiler/optimizing/register_allocator.cc @@ -185,10 +185,11 @@ void RegisterAllocator::ProcessInstruction(HInstruction* instruction) { // Create synthesized intervals for temporaries. for (size_t i = 0; i < locations->GetTempCount(); ++i) { Location temp = locations->GetTemp(i); - if (temp.IsRegister()) { + if (temp.IsRegister() || temp.IsFpuRegister()) { BlockRegister(temp, position, position + 1); } else { DCHECK(temp.IsUnallocated()); + DCHECK(temp.GetPolicy() == Location::kRequiresRegister); LiveInterval* interval = LiveInterval::MakeTempInterval(allocator_, Primitive::kPrimInt); temp_intervals_.Add(interval); interval->AddRange(position, position + 1); diff --git a/test/423-invoke-interface/expected.txt b/test/423-invoke-interface/expected.txt new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/423-invoke-interface/expected.txt diff --git a/test/423-invoke-interface/info.txt b/test/423-invoke-interface/info.txt new file mode 100644 index 0000000..a496ffe --- /dev/null +++ b/test/423-invoke-interface/info.txt @@ -0,0 +1,2 @@ +invoke-interface test with hopefully enough interface methods to trigger +a conflict in our imt table. diff --git a/test/423-invoke-interface/src/Main.java b/test/423-invoke-interface/src/Main.java new file mode 100644 index 0000000..fae857a --- /dev/null +++ b/test/423-invoke-interface/src/Main.java @@ -0,0 +1,120 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +public class Main { + static interface Itf { + public int return1(); + public int return2(); + public int return3(); + public int return4(); + public int return5(); + public int return6(); + public int return7(); + public int return8(); + public int return9(); + public int return10(); + public int return11(); + public int return12(); + public int return13(); + public int return14(); + public int return15(); + public int return16(); + public int return17(); + public int return18(); + public int return19(); + public int return20(); + } + + static class ItfImpl1 implements Itf { + public int return1() { return 1; } + public int return2() { return 2; } + public int return3() { return 3; } + public int return4() { return 4; } + public int return5() { return 5; } + public int return6() { return 6; } + public int return7() { return 7; } + public int return8() { return 8; } + public int return9() { return 9; } + public int return10() { return 10; } + public int return11() { return 11; } + public int return12() { return 12; } + public int return13() { return 13; } + public int return14() { return 14; } + public int return15() { return 15; } + public int return16() { return 16; } + public int return17() { return 17; } + public int return18() { return 18; } + public int return19() { return 19; } + public int return20() { return 20; } + } + + static class ItfImpl2 implements Itf { + public int return1() { return -1; } + public int return2() { return -2; } + public int return3() { return -3; } + public int return4() { return -4; } + public int return5() { return -5; } + public int return6() { return -6; } + public int return7() { return -7; } + public int return8() { return -8; } + public int return9() { return -9; } + public int return10() { return -10; } + public int return11() { return -11; } + public int return12() { return -12; } + public int return13() { return -13; } + public int return14() { return -14; } + public int return15() { return -15; } + public int return16() { return -16; } + public int return17() { return -17; } + public int return18() { return -18; } + public int return19() { return -19; } + public int return20() { return -20; } + } + + public static void main(String[] args) { + $opt$InvokeInterface(new ItfImpl1(), 1); + $opt$InvokeInterface(new ItfImpl2(), -1); + } + + public static void assertEquals(int expected, int value) { + if (expected != value) { + throw new Error("Expected " + expected + ", got " + value); + } + } + + public static void $opt$InvokeInterface(Itf object, int factor) { + assertEquals(factor * 1, object.return1()); + assertEquals(factor * 2, object.return2()); + assertEquals(factor * 3, object.return3()); + assertEquals(factor * 4, object.return4()); + assertEquals(factor * 5, object.return5()); + assertEquals(factor * 6, object.return6()); + assertEquals(factor * 7, object.return7()); + assertEquals(factor * 8, object.return8()); + assertEquals(factor * 9, object.return9()); + assertEquals(factor * 10, object.return10()); + assertEquals(factor * 11, object.return11()); + assertEquals(factor * 12, object.return12()); + assertEquals(factor * 13, object.return13()); + assertEquals(factor * 14, object.return14()); + assertEquals(factor * 15, object.return15()); + assertEquals(factor * 16, object.return16()); + assertEquals(factor * 17, object.return17()); + assertEquals(factor * 18, object.return18()); + assertEquals(factor * 19, object.return19()); + assertEquals(factor * 20, object.return20()); + } +} diff --git a/test/Android.run-test.mk b/test/Android.run-test.mk index e460f39..e5b36dd 100644 --- a/test/Android.run-test.mk +++ b/test/Android.run-test.mk @@ -440,6 +440,7 @@ TEST_ART_BROKEN_OPTIMIZING_ARM64_RUN_TESTS := \ 421-exceptions \ 421-large-frame \ 422-type-conversion \ + 423-invoke-interface \ 700-LoadArgRegs \ 701-easy-div-rem \ 702-LargeBranchOffset \ |