ART: Adds an entrypoint for invoke-custom

Add support for the compiler to call into the runtime for
invoke-custom bytecodes.

Bug: 35337872
Test: art/test.py --host -r -t 952
Test: art/test.py --target --64 -r -t 952
Test: art/test.py --target --32 -r -t 952
Change-Id: I821432e7e5248c91b8e1d36c3112974c34171803
diff --git a/compiler/optimizing/code_generator.cc b/compiler/optimizing/code_generator.cc
index 9f2346d..b3feb78 100644
--- a/compiler/optimizing/code_generator.cc
+++ b/compiler/optimizing/code_generator.cc
@@ -544,6 +544,7 @@
     case kVirtual:
     case kInterface:
     case kPolymorphic:
+    case kCustom:
       LOG(FATAL) << "Unexpected invoke type: " << invoke->GetInvokeType();
       UNREACHABLE();
   }
@@ -572,6 +573,7 @@
       entrypoint = kQuickInvokeInterfaceTrampolineWithAccessCheck;
       break;
     case kPolymorphic:
+    case kCustom:
       LOG(FATAL) << "Unexpected invoke type: " << invoke->GetInvokeType();
       UNREACHABLE();
   }
@@ -586,6 +588,12 @@
   InvokeRuntime(entrypoint, invoke, invoke->GetDexPc(), nullptr);
 }
 
+void CodeGenerator::GenerateInvokeCustomCall(HInvokeCustom* invoke) {
+  MoveConstant(invoke->GetLocations()->GetTemp(0), invoke->GetCallSiteIndex());
+  QuickEntrypointEnum entrypoint = kQuickInvokeCustom;
+  InvokeRuntime(entrypoint, invoke, invoke->GetDexPc(), nullptr);
+}
+
 void CodeGenerator::CreateUnresolvedFieldLocationSummary(
     HInstruction* field_access,
     DataType::Type field_type,
diff --git a/compiler/optimizing/code_generator.h b/compiler/optimizing/code_generator.h
index a340446..b3c29aa 100644
--- a/compiler/optimizing/code_generator.h
+++ b/compiler/optimizing/code_generator.h
@@ -542,10 +542,13 @@
 
   void GenerateInvokeStaticOrDirectRuntimeCall(
       HInvokeStaticOrDirect* invoke, Location temp, SlowPathCode* slow_path);
+
   void GenerateInvokeUnresolvedRuntimeCall(HInvokeUnresolved* invoke);
 
   void GenerateInvokePolymorphicCall(HInvokePolymorphic* invoke);
 
+  void GenerateInvokeCustomCall(HInvokeCustom* invoke);
+
   void CreateUnresolvedFieldLocationSummary(
       HInstruction* field_access,
       DataType::Type field_type,
diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc
index 6f173e1..5f0533c 100644
--- a/compiler/optimizing/code_generator_arm64.cc
+++ b/compiler/optimizing/code_generator_arm64.cc
@@ -4695,6 +4695,15 @@
   codegen_->MaybeGenerateMarkingRegisterCheck(/* code */ __LINE__);
 }
 
+void LocationsBuilderARM64::VisitInvokeCustom(HInvokeCustom* invoke) {
+  HandleInvoke(invoke);
+}
+
+void InstructionCodeGeneratorARM64::VisitInvokeCustom(HInvokeCustom* invoke) {
+  codegen_->GenerateInvokeCustomCall(invoke);
+  codegen_->MaybeGenerateMarkingRegisterCheck(/* code */ __LINE__);
+}
+
 vixl::aarch64::Label* CodeGeneratorARM64::NewBootImageRelRoPatch(
     uint32_t boot_image_offset,
     vixl::aarch64::Label* adrp_label) {
diff --git a/compiler/optimizing/code_generator_arm_vixl.cc b/compiler/optimizing/code_generator_arm_vixl.cc
index 859e159..91c1315 100644
--- a/compiler/optimizing/code_generator_arm_vixl.cc
+++ b/compiler/optimizing/code_generator_arm_vixl.cc
@@ -3742,6 +3742,15 @@
   codegen_->MaybeGenerateMarkingRegisterCheck(/* code */ 9);
 }
 
+void LocationsBuilderARMVIXL::VisitInvokeCustom(HInvokeCustom* invoke) {
+  HandleInvoke(invoke);
+}
+
+void InstructionCodeGeneratorARMVIXL::VisitInvokeCustom(HInvokeCustom* invoke) {
+  codegen_->GenerateInvokeCustomCall(invoke);
+  codegen_->MaybeGenerateMarkingRegisterCheck(/* code */ 10);
+}
+
 void LocationsBuilderARMVIXL::VisitNeg(HNeg* neg) {
   LocationSummary* locations =
       new (GetGraph()->GetAllocator()) LocationSummary(neg, LocationSummary::kNoCall);
@@ -5493,7 +5502,7 @@
     codegen_->InvokeRuntime(instruction->GetEntrypoint(), instruction, instruction->GetDexPc());
     CheckEntrypointTypes<kQuickAllocObjectWithChecks, void*, mirror::Class*>();
   }
-  codegen_->MaybeGenerateMarkingRegisterCheck(/* code */ 10);
+  codegen_->MaybeGenerateMarkingRegisterCheck(/* code */ 11);
 }
 
 void LocationsBuilderARMVIXL::VisitNewArray(HNewArray* instruction) {
@@ -5513,7 +5522,7 @@
   codegen_->InvokeRuntime(entrypoint, instruction, instruction->GetDexPc());
   CheckEntrypointTypes<kQuickAllocArrayResolved, void*, mirror::Class*, int32_t>();
   DCHECK(!codegen_->IsLeafMethod());
-  codegen_->MaybeGenerateMarkingRegisterCheck(/* code */ 11);
+  codegen_->MaybeGenerateMarkingRegisterCheck(/* code */ 12);
 }
 
 void LocationsBuilderARMVIXL::VisitParameterValue(HParameterValue* instruction) {
@@ -7084,7 +7093,7 @@
     return;
   }
   GenerateSuspendCheck(instruction, nullptr);
-  codegen_->MaybeGenerateMarkingRegisterCheck(/* code */ 12);
+  codegen_->MaybeGenerateMarkingRegisterCheck(/* code */ 13);
 }
 
 void InstructionCodeGeneratorARMVIXL::GenerateSuspendCheck(HSuspendCheck* instruction,
@@ -7437,7 +7446,7 @@
   HLoadClass::LoadKind load_kind = cls->GetLoadKind();
   if (load_kind == HLoadClass::LoadKind::kRuntimeCall) {
     codegen_->GenerateLoadClassRuntimeCall(cls);
-    codegen_->MaybeGenerateMarkingRegisterCheck(/* code */ 13);
+    codegen_->MaybeGenerateMarkingRegisterCheck(/* code */ 14);
     return;
   }
   DCHECK(!cls->NeedsAccessCheck());
@@ -7523,7 +7532,7 @@
     } else {
       __ Bind(slow_path->GetExitLabel());
     }
-    codegen_->MaybeGenerateMarkingRegisterCheck(/* code */ 14);
+    codegen_->MaybeGenerateMarkingRegisterCheck(/* code */ 15);
   }
 }
 
@@ -7732,7 +7741,7 @@
       codegen_->AddSlowPath(slow_path);
       __ CompareAndBranchIfZero(out, slow_path->GetEntryLabel());
       __ Bind(slow_path->GetExitLabel());
-      codegen_->MaybeGenerateMarkingRegisterCheck(/* code */ 15);
+      codegen_->MaybeGenerateMarkingRegisterCheck(/* code */ 16);
       return;
     }
     case HLoadString::LoadKind::kJitTableAddress: {
@@ -7754,7 +7763,7 @@
   __ Mov(calling_convention.GetRegisterAt(0), load->GetStringIndex().index_);
   codegen_->InvokeRuntime(kQuickResolveString, load, load->GetDexPc());
   CheckEntrypointTypes<kQuickResolveString, void*, uint32_t>();
-  codegen_->MaybeGenerateMarkingRegisterCheck(/* code */ 16);
+  codegen_->MaybeGenerateMarkingRegisterCheck(/* code */ 17);
 }
 
 static int32_t GetExceptionTlsOffset() {
@@ -8384,7 +8393,7 @@
   } else {
     CheckEntrypointTypes<kQuickUnlockObject, void, mirror::Object*>();
   }
-  codegen_->MaybeGenerateMarkingRegisterCheck(/* code */ 17);
+  codegen_->MaybeGenerateMarkingRegisterCheck(/* code */ 18);
 }
 
 void LocationsBuilderARMVIXL::VisitAnd(HAnd* instruction) {
@@ -8883,7 +8892,7 @@
     // Note that GC roots are not affected by heap poisoning, thus we
     // do not have to unpoison `root_reg` here.
   }
-  MaybeGenerateMarkingRegisterCheck(/* code */ 18);
+  MaybeGenerateMarkingRegisterCheck(/* code */ 19);
 }
 
 void CodeGeneratorARMVIXL::GenerateFieldLoadWithBakerReadBarrier(HInstruction* instruction,
@@ -8963,7 +8972,7 @@
                 narrow ? BAKER_MARK_INTROSPECTION_FIELD_LDR_NARROW_OFFSET
                        : BAKER_MARK_INTROSPECTION_FIELD_LDR_WIDE_OFFSET);
     }
-    MaybeGenerateMarkingRegisterCheck(/* code */ 19, /* temp_loc */ LocationFrom(ip));
+    MaybeGenerateMarkingRegisterCheck(/* code */ 20, /* temp_loc */ LocationFrom(ip));
     return;
   }
 
@@ -9041,7 +9050,7 @@
       DCHECK_EQ(old_offset - GetVIXLAssembler()->GetBuffer()->GetCursorOffset(),
                 BAKER_MARK_INTROSPECTION_ARRAY_LDR_OFFSET);
     }
-    MaybeGenerateMarkingRegisterCheck(/* code */ 20, /* temp_loc */ LocationFrom(ip));
+    MaybeGenerateMarkingRegisterCheck(/* code */ 21, /* temp_loc */ LocationFrom(ip));
     return;
   }
 
@@ -9095,7 +9104,7 @@
   // Fast path: the GC is not marking: just load the reference.
   GenerateRawReferenceLoad(instruction, ref, obj, offset, index, scale_factor, needs_null_check);
   __ Bind(slow_path->GetExitLabel());
-  MaybeGenerateMarkingRegisterCheck(/* code */ 21);
+  MaybeGenerateMarkingRegisterCheck(/* code */ 22);
 }
 
 void CodeGeneratorARMVIXL::UpdateReferenceFieldWithBakerReadBarrier(HInstruction* instruction,
@@ -9150,7 +9159,7 @@
   // Fast path: the GC is not marking: nothing to do (the field is
   // up-to-date, and we don't need to load the reference).
   __ Bind(slow_path->GetExitLabel());
-  MaybeGenerateMarkingRegisterCheck(/* code */ 22);
+  MaybeGenerateMarkingRegisterCheck(/* code */ 23);
 }
 
 void CodeGeneratorARMVIXL::GenerateRawReferenceLoad(HInstruction* instruction,
diff --git a/compiler/optimizing/code_generator_mips.cc b/compiler/optimizing/code_generator_mips.cc
index 8be84a1..507db36 100644
--- a/compiler/optimizing/code_generator_mips.cc
+++ b/compiler/optimizing/code_generator_mips.cc
@@ -7795,6 +7795,14 @@
   codegen_->GenerateInvokePolymorphicCall(invoke);
 }
 
+void LocationsBuilderMIPS::VisitInvokeCustom(HInvokeCustom* invoke) {
+  HandleInvoke(invoke);
+}
+
+void InstructionCodeGeneratorMIPS::VisitInvokeCustom(HInvokeCustom* invoke) {
+  codegen_->GenerateInvokeCustomCall(invoke);
+}
+
 static bool TryGenerateIntrinsicCode(HInvoke* invoke, CodeGeneratorMIPS* codegen) {
   if (invoke->GetLocations()->Intrinsified()) {
     IntrinsicCodeGeneratorMIPS intrinsic(codegen);
diff --git a/compiler/optimizing/code_generator_mips64.cc b/compiler/optimizing/code_generator_mips64.cc
index cd9e0e5..08a6512 100644
--- a/compiler/optimizing/code_generator_mips64.cc
+++ b/compiler/optimizing/code_generator_mips64.cc
@@ -5908,6 +5908,14 @@
   codegen_->GenerateInvokePolymorphicCall(invoke);
 }
 
+void LocationsBuilderMIPS64::VisitInvokeCustom(HInvokeCustom* invoke) {
+  HandleInvoke(invoke);
+}
+
+void InstructionCodeGeneratorMIPS64::VisitInvokeCustom(HInvokeCustom* invoke) {
+  codegen_->GenerateInvokeCustomCall(invoke);
+}
+
 static bool TryGenerateIntrinsicCode(HInvoke* invoke, CodeGeneratorMIPS64* codegen) {
   if (invoke->GetLocations()->Intrinsified()) {
     IntrinsicCodeGeneratorMIPS64 intrinsic(codegen);
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index 9e31538..9f42ac7 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -2311,6 +2311,14 @@
   codegen_->GenerateInvokePolymorphicCall(invoke);
 }
 
+void LocationsBuilderX86::VisitInvokeCustom(HInvokeCustom* invoke) {
+  HandleInvoke(invoke);
+}
+
+void InstructionCodeGeneratorX86::VisitInvokeCustom(HInvokeCustom* invoke) {
+  codegen_->GenerateInvokeCustomCall(invoke);
+}
+
 void LocationsBuilderX86::VisitNeg(HNeg* neg) {
   LocationSummary* locations =
       new (GetGraph()->GetAllocator()) LocationSummary(neg, LocationSummary::kNoCall);
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc
index f739704..05194b1 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -2501,6 +2501,14 @@
   codegen_->GenerateInvokePolymorphicCall(invoke);
 }
 
+void LocationsBuilderX86_64::VisitInvokeCustom(HInvokeCustom* invoke) {
+  HandleInvoke(invoke);
+}
+
+void InstructionCodeGeneratorX86_64::VisitInvokeCustom(HInvokeCustom* invoke) {
+  codegen_->GenerateInvokeCustomCall(invoke);
+}
+
 void LocationsBuilderX86_64::VisitNeg(HNeg* neg) {
   LocationSummary* locations =
       new (GetGraph()->GetAllocator()) LocationSummary(neg, LocationSummary::kNoCall);
diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc
index 6900cd8..7dd756e 100644
--- a/compiler/optimizing/inliner.cc
+++ b/compiler/optimizing/inliner.cc
@@ -460,9 +460,10 @@
 
 bool HInliner::TryInline(HInvoke* invoke_instruction) {
   if (invoke_instruction->IsInvokeUnresolved() ||
-      invoke_instruction->IsInvokePolymorphic()) {
-    return false;  // Don't bother to move further if we know the method is unresolved or an
-                   // invoke-polymorphic.
+      invoke_instruction->IsInvokePolymorphic() ||
+      invoke_instruction->IsInvokeCustom()) {
+    return false;  // Don't bother to move further if we know the method is unresolved or the
+                   // invocation is polymorphic (invoke-{polymorphic,custom}).
   }
 
   ScopedObjectAccess soa(Thread::Current());
diff --git a/compiler/optimizing/instruction_builder.cc b/compiler/optimizing/instruction_builder.cc
index 24dc2ee..be8f2b1 100644
--- a/compiler/optimizing/instruction_builder.cc
+++ b/compiler/optimizing/instruction_builder.cc
@@ -449,11 +449,7 @@
       target_method,
       HInvokeStaticOrDirect::ClinitCheckRequirement::kNone);
   RangeInstructionOperands operands(graph_->GetNumberOfVRegs() - in_vregs, in_vregs);
-  HandleInvoke(invoke,
-               operands,
-               dex_file_->GetMethodShorty(method_idx),
-               /* clinit_check */ nullptr,
-               /* is_unresolved */ false);
+  HandleInvoke(invoke, operands, dex_file_->GetMethodShorty(method_idx), /* is_unresolved */ false);
 
   // Add the return instruction.
   if (return_type_ == DataType::Type::kVoid) {
@@ -916,11 +912,11 @@
                                       uint32_t method_idx,
                                       const InstructionOperands& operands) {
   InvokeType invoke_type = GetInvokeTypeFromOpCode(instruction.Opcode());
-  const char* descriptor = dex_file_->GetMethodShorty(method_idx);
-  DataType::Type return_type = DataType::FromShorty(descriptor[0]);
+  const char* shorty = dex_file_->GetMethodShorty(method_idx);
+  DataType::Type return_type = DataType::FromShorty(shorty[0]);
 
   // Remove the return type from the 'proto'.
-  size_t number_of_arguments = strlen(descriptor) - 1;
+  size_t number_of_arguments = strlen(shorty) - 1;
   if (invoke_type != kStatic) {  // instance call
     // One extra argument for 'this'.
     number_of_arguments++;
@@ -937,11 +933,7 @@
                                                          dex_pc,
                                                          method_idx,
                                                          invoke_type);
-    return HandleInvoke(invoke,
-                        operands,
-                        descriptor,
-                        nullptr /* clinit_check */,
-                        true /* is_unresolved */);
+    return HandleInvoke(invoke, operands, shorty, /* is_unresolved */ true);
   }
 
   // Replace calls to String.<init> with StringFactory.
@@ -968,7 +960,7 @@
         invoke_type,
         target_method,
         HInvokeStaticOrDirect::ClinitCheckRequirement::kImplicit);
-    return HandleStringInit(invoke, operands, descriptor);
+    return HandleStringInit(invoke, operands, shorty);
   }
 
   // Potential class initialization check, in the case of a static method call.
@@ -1028,29 +1020,39 @@
                                                resolved_method,
                                                ImTable::GetImtIndex(resolved_method));
   }
-
-  return HandleInvoke(invoke, operands, descriptor, clinit_check, false /* is_unresolved */);
+  return HandleInvoke(invoke, operands, shorty, /* is_unresolved */ false, clinit_check);
 }
 
-bool HInstructionBuilder::BuildInvokePolymorphic(const Instruction& instruction ATTRIBUTE_UNUSED,
-                                                 uint32_t dex_pc,
+bool HInstructionBuilder::BuildInvokePolymorphic(uint32_t dex_pc,
                                                  uint32_t method_idx,
                                                  dex::ProtoIndex proto_idx,
                                                  const InstructionOperands& operands) {
-  const char* descriptor = dex_file_->GetShorty(proto_idx);
-  DCHECK_EQ(1 + ArtMethod::NumArgRegisters(descriptor), operands.GetNumberOfOperands());
-  DataType::Type return_type = DataType::FromShorty(descriptor[0]);
-  size_t number_of_arguments = strlen(descriptor);
+  const char* shorty = dex_file_->GetShorty(proto_idx);
+  DCHECK_EQ(1 + ArtMethod::NumArgRegisters(shorty), operands.GetNumberOfOperands());
+  DataType::Type return_type = DataType::FromShorty(shorty[0]);
+  size_t number_of_arguments = strlen(shorty);
   HInvoke* invoke = new (allocator_) HInvokePolymorphic(allocator_,
                                                         number_of_arguments,
                                                         return_type,
                                                         dex_pc,
                                                         method_idx);
-  return HandleInvoke(invoke,
-                      operands,
-                      descriptor,
-                      nullptr /* clinit_check */,
-                      false /* is_unresolved */);
+  return HandleInvoke(invoke, operands, shorty, /* is_unresolved */ false);
+}
+
+
+bool HInstructionBuilder::BuildInvokeCustom(uint32_t dex_pc,
+                                            uint32_t call_site_idx,
+                                            const InstructionOperands& operands) {
+  dex::ProtoIndex proto_idx = dex_file_->GetProtoIndexForCallSite(call_site_idx);
+  const char* shorty = dex_file_->GetShorty(proto_idx);
+  DataType::Type return_type = DataType::FromShorty(shorty[0]);
+  size_t number_of_arguments = strlen(shorty) - 1;
+  HInvoke* invoke = new (allocator_) HInvokeCustom(allocator_,
+                                                   number_of_arguments,
+                                                   call_site_idx,
+                                                   return_type,
+                                                   dex_pc);
+  return HandleInvoke(invoke, operands, shorty, /* is_unresolved */ false);
 }
 
 HNewInstance* HInstructionBuilder::BuildNewInstance(dex::TypeIndex type_index, uint32_t dex_pc) {
@@ -1197,10 +1199,10 @@
 
 bool HInstructionBuilder::SetupInvokeArguments(HInvoke* invoke,
                                                const InstructionOperands& operands,
-                                               const char* descriptor,
+                                               const char* shorty,
                                                size_t start_index,
                                                size_t* argument_index) {
-  uint32_t descriptor_index = 1;  // Skip the return type.
+  uint32_t shorty_index = 1;  // Skip the return type.
   const size_t number_of_operands = operands.GetNumberOfOperands();
   for (size_t i = start_index;
        // Make sure we don't go over the expected arguments or over the number of
@@ -1208,7 +1210,7 @@
        // it hasn't been properly checked.
        (i < number_of_operands) && (*argument_index < invoke->GetNumberOfArguments());
        i++, (*argument_index)++) {
-    DataType::Type type = DataType::FromShorty(descriptor[descriptor_index++]);
+    DataType::Type type = DataType::FromShorty(shorty[shorty_index++]);
     bool is_wide = (type == DataType::Type::kInt64) || (type == DataType::Type::kFloat64);
     if (is_wide && ((i + 1 == number_of_operands) ||
                     (operands.GetOperand(i) + 1 != operands.GetOperand(i + 1)))) {
@@ -1250,9 +1252,9 @@
 
 bool HInstructionBuilder::HandleInvoke(HInvoke* invoke,
                                        const InstructionOperands& operands,
-                                       const char* descriptor,
-                                       HClinitCheck* clinit_check,
-                                       bool is_unresolved) {
+                                       const char* shorty,
+                                       bool is_unresolved,
+                                       HClinitCheck* clinit_check) {
   DCHECK(!invoke->IsInvokeStaticOrDirect() || !invoke->AsInvokeStaticOrDirect()->IsStringInit());
 
   size_t start_index = 0;
@@ -1267,7 +1269,7 @@
     argument_index = 1;
   }
 
-  if (!SetupInvokeArguments(invoke, operands, descriptor, start_index, &argument_index)) {
+  if (!SetupInvokeArguments(invoke, operands, shorty, start_index, &argument_index)) {
     return false;
   }
 
@@ -1288,13 +1290,13 @@
 
 bool HInstructionBuilder::HandleStringInit(HInvoke* invoke,
                                            const InstructionOperands& operands,
-                                           const char* descriptor) {
+                                           const char* shorty) {
   DCHECK(invoke->IsInvokeStaticOrDirect());
   DCHECK(invoke->AsInvokeStaticOrDirect()->IsStringInit());
 
   size_t start_index = 1;
   size_t argument_index = 0;
-  if (!SetupInvokeArguments(invoke, operands, descriptor, start_index, &argument_index)) {
+  if (!SetupInvokeArguments(invoke, operands, shorty, start_index, &argument_index)) {
     return false;
   }
 
@@ -2144,14 +2146,28 @@
       uint32_t args[5];
       uint32_t number_of_vreg_arguments = instruction.GetVarArgs(args);
       VarArgsInstructionOperands operands(args, number_of_vreg_arguments);
-      return BuildInvokePolymorphic(instruction, dex_pc, method_idx, proto_idx, operands);
+      return BuildInvokePolymorphic(dex_pc, method_idx, proto_idx, operands);
     }
 
     case Instruction::INVOKE_POLYMORPHIC_RANGE: {
       uint16_t method_idx = instruction.VRegB_4rcc();
       dex::ProtoIndex proto_idx(instruction.VRegH_4rcc());
       RangeInstructionOperands operands(instruction.VRegC_4rcc(), instruction.VRegA_4rcc());
-      return BuildInvokePolymorphic(instruction, dex_pc, method_idx, proto_idx, operands);
+      return BuildInvokePolymorphic(dex_pc, method_idx, proto_idx, operands);
+    }
+
+    case Instruction::INVOKE_CUSTOM: {
+      uint16_t call_site_idx = instruction.VRegB_35c();
+      uint32_t args[5];
+      uint32_t number_of_vreg_arguments = instruction.GetVarArgs(args);
+      VarArgsInstructionOperands operands(args, number_of_vreg_arguments);
+      return BuildInvokeCustom(dex_pc, call_site_idx, operands);
+    }
+
+    case Instruction::INVOKE_CUSTOM_RANGE: {
+      uint16_t call_site_idx = instruction.VRegB_3rc();
+      RangeInstructionOperands operands(instruction.VRegC_3rc(), instruction.VRegA_3rc());
+      return BuildInvokeCustom(dex_pc, call_site_idx, operands);
     }
 
     case Instruction::NEG_INT: {
@@ -2933,7 +2949,21 @@
       break;
     }
 
-    default:
+    case Instruction::UNUSED_3E:
+    case Instruction::UNUSED_3F:
+    case Instruction::UNUSED_40:
+    case Instruction::UNUSED_41:
+    case Instruction::UNUSED_42:
+    case Instruction::UNUSED_43:
+    case Instruction::UNUSED_79:
+    case Instruction::UNUSED_7A:
+    case Instruction::UNUSED_F3:
+    case Instruction::UNUSED_F4:
+    case Instruction::UNUSED_F5:
+    case Instruction::UNUSED_F6:
+    case Instruction::UNUSED_F7:
+    case Instruction::UNUSED_F8:
+    case Instruction::UNUSED_F9: {
       VLOG(compiler) << "Did not compile "
                      << dex_file_->PrettyMethod(dex_compilation_unit_->GetDexMethodIndex())
                      << " because of unhandled instruction "
@@ -2941,6 +2971,7 @@
       MaybeRecordStat(compilation_stats_,
                       MethodCompilationStat::kNotCompiledUnhandledInstruction);
       return false;
+    }
   }
   return true;
 }  // NOLINT(readability/fn_size)
diff --git a/compiler/optimizing/instruction_builder.h b/compiler/optimizing/instruction_builder.h
index 2218a69..af7092a 100644
--- a/compiler/optimizing/instruction_builder.h
+++ b/compiler/optimizing/instruction_builder.h
@@ -173,12 +173,17 @@
 
   // Builds an invocation node for invoke-polymorphic and returns whether the
   // instruction is supported.
-  bool BuildInvokePolymorphic(const Instruction& instruction,
-                              uint32_t dex_pc,
+  bool BuildInvokePolymorphic(uint32_t dex_pc,
                               uint32_t method_idx,
                               dex::ProtoIndex proto_idx,
                               const InstructionOperands& operands);
 
+  // Builds an invocation node for invoke-custom and returns whether the
+  // instruction is supported.
+  bool BuildInvokeCustom(uint32_t dex_pc,
+                         uint32_t call_site_idx,
+                         const InstructionOperands& operands);
+
   // Builds a new array node and the instructions that fill it.
   HNewArray* BuildFilledNewArray(uint32_t dex_pc,
                                  dex::TypeIndex type_index,
@@ -253,19 +258,19 @@
 
   bool SetupInvokeArguments(HInvoke* invoke,
                             const InstructionOperands& operands,
-                            const char* descriptor,
+                            const char* shorty,
                             size_t start_index,
                             size_t* argument_index);
 
   bool HandleInvoke(HInvoke* invoke,
                     const InstructionOperands& operands,
-                    const char* descriptor,
-                    HClinitCheck* clinit_check,
-                    bool is_unresolved);
+                    const char* shorty,
+                    bool is_unresolved,
+                    HClinitCheck* clinit_check = nullptr);
 
   bool HandleStringInit(HInvoke* invoke,
                         const InstructionOperands& operands,
-                        const char* descriptor);
+                        const char* shorty);
   void HandleStringInitResult(HInvokeStaticOrDirect* invoke);
 
   HClinitCheck* ProcessClinitCheckForInvoke(
diff --git a/compiler/optimizing/intrinsics.cc b/compiler/optimizing/intrinsics.cc
index 056f533..4ffde7b 100644
--- a/compiler/optimizing/intrinsics.cc
+++ b/compiler/optimizing/intrinsics.cc
@@ -142,6 +142,7 @@
     case kSuper:
     case kInterface:
     case kPolymorphic:
+    case kCustom:
       return false;
   }
   LOG(FATAL) << "Unknown intrinsic invoke type: " << intrinsic_type;
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index 3fd5b6b..2037879 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -1380,6 +1380,7 @@
   M(InvokeStaticOrDirect, Invoke)                                       \
   M(InvokeVirtual, Invoke)                                              \
   M(InvokePolymorphic, Invoke)                                          \
+  M(InvokeCustom, Invoke)                                               \
   M(LessThan, Condition)                                                \
   M(LessThanOrEqual, Condition)                                         \
   M(LoadClass, Instruction)                                             \
@@ -4382,6 +4383,38 @@
   DEFAULT_COPY_CONSTRUCTOR(InvokePolymorphic);
 };
 
+class HInvokeCustom FINAL : public HInvoke {
+ public:
+  HInvokeCustom(ArenaAllocator* allocator,
+                uint32_t number_of_arguments,
+                uint32_t call_site_index,
+                DataType::Type return_type,
+                uint32_t dex_pc)
+      : HInvoke(kInvokeCustom,
+                allocator,
+                number_of_arguments,
+                /* number_of_other_inputs */ 0u,
+                return_type,
+                dex_pc,
+                /* dex_method_index */ dex::kDexNoIndex,
+                /* resolved_method */ nullptr,
+                kStatic),
+      call_site_index_(call_site_index) {
+  }
+
+  uint32_t GetCallSiteIndex() const { return call_site_index_; }
+
+  bool IsClonable() const OVERRIDE { return true; }
+
+  DECLARE_INSTRUCTION(InvokeCustom);
+
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(InvokeCustom);
+
+ private:
+  uint32_t call_site_index_;
+};
+
 class HInvokeStaticOrDirect FINAL : public HInvoke {
  public:
   // Requirements of this method call regarding the class
@@ -6510,9 +6543,9 @@
 class HLoadMethodHandle FINAL : public HInstruction {
  public:
   HLoadMethodHandle(HCurrentMethod* current_method,
-                  uint16_t method_handle_idx,
-                  const DexFile& dex_file,
-                  uint32_t dex_pc)
+                    uint16_t method_handle_idx,
+                    const DexFile& dex_file,
+                    uint32_t dex_pc)
       : HInstruction(kLoadMethodHandle,
                      DataType::Type::kReference,
                      SideEffectsForArchRuntimeCalls(),
diff --git a/compiler/utils/assembler_thumb_test_expected.cc.inc b/compiler/utils/assembler_thumb_test_expected.cc.inc
index 19c405e..e76e98a 100644
--- a/compiler/utils/assembler_thumb_test_expected.cc.inc
+++ b/compiler/utils/assembler_thumb_test_expected.cc.inc
@@ -153,7 +153,7 @@
   " 21c:	f8d9 8034 	ldr.w	r8, [r9, #52]	; 0x34\n",
   " 220:	4770      	bx	lr\n",
   " 222:	4660      	mov	r0, ip\n",
-  " 224:	f8d9 c2cc 	ldr.w	ip, [r9, #716]	; 0x2cc\n",
+  " 224:	f8d9 c2d0 	ldr.w	ip, [r9, #720]	; 0x2d0\n",
   " 228:	47e0      	blx	ip\n",
   nullptr
 };