OSDN Git Service

Add support for unresolved classes in optimizing.
authorCalin Juravle <calin@google.com>
Fri, 2 Oct 2015 20:05:03 +0000 (21:05 +0100)
committerCalin Juravle <calin@google.com>
Tue, 6 Oct 2015 12:42:55 +0000 (13:42 +0100)
Change-Id: I0e299a81e560eb9cb0737ec46125dffc99333b54

16 files changed:
compiler/optimizing/builder.cc
compiler/optimizing/builder.h
compiler/optimizing/code_generator.cc
compiler/optimizing/code_generator.h
compiler/optimizing/code_generator_arm.cc
compiler/optimizing/code_generator_arm64.cc
compiler/optimizing/code_generator_mips64.cc
compiler/optimizing/code_generator_x86.cc
compiler/optimizing/code_generator_x86_64.cc
compiler/optimizing/graph_visualizer.cc
compiler/optimizing/instruction_simplifier.cc
compiler/optimizing/nodes.h
compiler/optimizing/reference_type_propagation.cc
test/529-checker-unresolved/expected.txt
test/529-checker-unresolved/src/Main.java
test/529-checker-unresolved/src/Unresolved.java

index ebbfb14..5acc5fd 100644 (file)
@@ -940,7 +940,8 @@ HClinitCheck* HGraphBuilder::ProcessClinitCheckForInvoke(
           storage_index,
           *dex_compilation_unit_->GetDexFile(),
           is_outer_class,
-          dex_pc);
+          dex_pc,
+          /*needs_access_check*/ false);
       current_block_->AddInstruction(load_class);
       clinit_check = new (arena_) HClinitCheck(load_class, dex_pc);
       current_block_->AddInstruction(clinit_check);
@@ -1384,7 +1385,8 @@ bool HGraphBuilder::BuildStaticFieldAccess(const Instruction& instruction,
                                                  storage_index,
                                                  *dex_compilation_unit_->GetDexFile(),
                                                  is_outer_class,
-                                                 dex_pc);
+                                                 dex_pc,
+                                                 /*needs_access_check*/ false);
   current_block_->AddInstruction(constant);
 
   HInstruction* cls = constant;
@@ -1615,7 +1617,9 @@ void HGraphBuilder::BuildFillWideArrayData(HInstruction* object,
 
 static TypeCheckKind ComputeTypeCheckKind(Handle<mirror::Class> cls)
     SHARED_REQUIRES(Locks::mutator_lock_) {
-  if (cls->IsInterface()) {
+  if (cls.Get() == nullptr) {
+    return TypeCheckKind::kUnresolvedCheck;
+  } else if (cls->IsInterface()) {
     return TypeCheckKind::kInterfaceCheck;
   } else if (cls->IsArrayClass()) {
     if (cls->GetComponentType()->IsObjectClass()) {
@@ -1634,11 +1638,20 @@ static TypeCheckKind ComputeTypeCheckKind(Handle<mirror::Class> cls)
   }
 }
 
-bool HGraphBuilder::BuildTypeCheck(const Instruction& instruction,
+void HGraphBuilder::BuildTypeCheck(const Instruction& instruction,
                                    uint8_t destination,
                                    uint8_t reference,
                                    uint16_t type_index,
                                    uint32_t dex_pc) {
+  bool type_known_final, type_known_abstract, use_declaring_class;
+  bool can_access = compiler_driver_->CanAccessTypeWithoutChecks(
+      dex_compilation_unit_->GetDexMethodIndex(),
+      *dex_compilation_unit_->GetDexFile(),
+      type_index,
+      &type_known_final,
+      &type_known_abstract,
+      &use_declaring_class);
+
   ScopedObjectAccess soa(Thread::Current());
   StackHandleScope<2> hs(soa.Self());
   Handle<mirror::DexCache> dex_cache(hs.NewHandle(
@@ -1646,22 +1659,14 @@ bool HGraphBuilder::BuildTypeCheck(const Instruction& instruction,
           soa.Self(), *dex_compilation_unit_->GetDexFile())));
   Handle<mirror::Class> resolved_class(hs.NewHandle(dex_cache->GetResolvedType(type_index)));
 
-  if ((resolved_class.Get() == nullptr) ||
-       // TODO: Remove this check once the compiler actually knows which
-       // ArtMethod it is compiling.
-      (GetCompilingClass() == nullptr) ||
-      !GetCompilingClass()->CanAccess(resolved_class.Get())) {
-    MaybeRecordStat(MethodCompilationStat::kNotCompiledCantAccesType);
-    return false;
-  }
-
   HInstruction* object = LoadLocal(reference, Primitive::kPrimNot, dex_pc);
   HLoadClass* cls = new (arena_) HLoadClass(
       graph_->GetCurrentMethod(),
       type_index,
       *dex_compilation_unit_->GetDexFile(),
       IsOutermostCompilingClass(type_index),
-      dex_pc);
+      dex_pc,
+      !can_access);
   current_block_->AddInstruction(cls);
 
   // The class needs a temporary before being used by the type check.
@@ -1676,7 +1681,6 @@ bool HGraphBuilder::BuildTypeCheck(const Instruction& instruction,
     DCHECK_EQ(instruction.Opcode(), Instruction::CHECK_CAST);
     current_block_->AddInstruction(new (arena_) HCheckCast(object, cls, check_kind, dex_pc));
   }
-  return true;
 }
 
 bool HGraphBuilder::NeedsAccessCheck(uint32_t type_index) const {
@@ -2791,16 +2795,13 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32
       bool can_access = compiler_driver_->CanAccessTypeWithoutChecks(
           dex_compilation_unit_->GetDexMethodIndex(), *dex_file_, type_index,
           &type_known_final, &type_known_abstract, &dont_use_is_referrers_class);
-      if (!can_access) {
-        MaybeRecordStat(MethodCompilationStat::kNotCompiledCantAccesType);
-        return false;
-      }
       current_block_->AddInstruction(new (arena_) HLoadClass(
           graph_->GetCurrentMethod(),
           type_index,
           *dex_compilation_unit_->GetDexFile(),
           IsOutermostCompilingClass(type_index),
-          dex_pc));
+          dex_pc,
+          !can_access));
       UpdateLocal(instruction.VRegA_21c(), current_block_->GetLastInstruction(), dex_pc);
       break;
     }
@@ -2827,18 +2828,14 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32
       uint8_t destination = instruction.VRegA_22c();
       uint8_t reference = instruction.VRegB_22c();
       uint16_t type_index = instruction.VRegC_22c();
-      if (!BuildTypeCheck(instruction, destination, reference, type_index, dex_pc)) {
-        return false;
-      }
+      BuildTypeCheck(instruction, destination, reference, type_index, dex_pc);
       break;
     }
 
     case Instruction::CHECK_CAST: {
       uint8_t reference = instruction.VRegA_21c();
       uint16_t type_index = instruction.VRegB_21c();
-      if (!BuildTypeCheck(instruction, -1, reference, type_index, dex_pc)) {
-        return false;
-      }
+      BuildTypeCheck(instruction, -1, reference, type_index, dex_pc);
       break;
     }
 
index b2dc241..6910d51 100644 (file)
@@ -236,8 +236,7 @@ class HGraphBuilder : public ValueObject {
                               uint32_t dex_pc);
 
   // Builds a `HInstanceOf`, or a `HCheckCast` instruction.
-  // Returns whether we succeeded in building the instruction.
-  bool BuildTypeCheck(const Instruction& instruction,
+  void BuildTypeCheck(const Instruction& instruction,
                       uint8_t destination,
                       uint8_t reference,
                       uint16_t type_index,
index 8254277..00f316c 100644 (file)
@@ -537,6 +537,26 @@ void CodeGenerator::GenerateUnresolvedFieldAccess(
   }
 }
 
+void CodeGenerator::CreateLoadClassLocationSummary(HLoadClass* cls,
+                                                   Location runtime_type_index_location,
+                                                   Location runtime_return_location) {
+  ArenaAllocator* allocator = cls->GetBlock()->GetGraph()->GetArena();
+  LocationSummary::CallKind call_kind = cls->NeedsAccessCheck()
+      ? LocationSummary::kCall
+      : (cls->CanCallRuntime()
+          ? LocationSummary::kCallOnSlowPath
+          : LocationSummary::kNoCall);
+  LocationSummary* locations = new (allocator) LocationSummary(cls, call_kind);
+  locations->SetInAt(0, Location::RequiresRegister());
+  if (cls->NeedsAccessCheck()) {
+    locations->AddTemp(runtime_type_index_location);
+    locations->SetOut(runtime_return_location);
+  } else {
+    locations->SetOut(Location::RequiresRegister());
+  }
+}
+
+
 void CodeGenerator::BlockIfInRegister(Location location, bool is_out) const {
   // The DCHECKS below check that a register is not specified twice in
   // the summary. The out location can overlap with an input, so we need
index a3ebc43..0a36989 100644 (file)
@@ -416,6 +416,11 @@ class CodeGenerator {
       uint32_t dex_pc,
       const FieldAccessCallingConvention& calling_convention);
 
+  // TODO: This overlaps a bit with MoveFromReturnRegister. Refactor for a better design.
+  static void CreateLoadClassLocationSummary(HLoadClass* cls,
+                                             Location runtime_type_index_location,
+                                             Location runtime_return_location);
+
   void SetDisassemblyInformation(DisassemblyInformation* info) { disasm_info_ = info; }
   DisassemblyInformation* GetDisassemblyInformation() const { return disasm_info_; }
 
index 299350b..54af41d 100644 (file)
@@ -4468,20 +4468,24 @@ void ParallelMoveResolverARM::RestoreScratch(int reg) {
 }
 
 void LocationsBuilderARM::VisitLoadClass(HLoadClass* cls) {
-  LocationSummary::CallKind call_kind = cls->CanCallRuntime()
-      ? LocationSummary::kCallOnSlowPath
-      : LocationSummary::kNoCall;
-  LocationSummary* locations =
-      new (GetGraph()->GetArena()) LocationSummary(cls, call_kind);
-  locations->SetInAt(0, Location::RequiresRegister());
-  locations->SetOut(Location::RequiresRegister());
+  InvokeRuntimeCallingConvention calling_convention;
+  CodeGenerator::CreateLoadClassLocationSummary(
+      cls,
+      Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
+      Location::RegisterLocation(R0));
 }
 
 void InstructionCodeGeneratorARM::VisitLoadClass(HLoadClass* cls) {
   LocationSummary* locations = cls->GetLocations();
   Register out = locations->Out().AsRegister<Register>();
   Register current_method = locations->InAt(0).AsRegister<Register>();
-  if (cls->IsReferrersClass()) {
+  if (cls->NeedsAccessCheck()) {
+    codegen_->MoveConstant(locations->GetTemp(0), cls->GetTypeIndex());
+    codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pInitializeTypeAndVerifyAccess),
+                            cls,
+                            cls->GetDexPc(),
+                            nullptr);
+  } else if (cls->IsReferrersClass()) {
     DCHECK(!cls->CanCallRuntime());
     DCHECK(!cls->MustGenerateClinitCheck());
     __ LoadFromOffset(
@@ -4604,6 +4608,7 @@ void LocationsBuilderARM::VisitInstanceOf(HInstanceOf* instruction) {
     case TypeCheckKind::kArrayObjectCheck:
       call_kind = LocationSummary::kNoCall;
       break;
+    case TypeCheckKind::kUnresolvedCheck:
     case TypeCheckKind::kInterfaceCheck:
       call_kind = LocationSummary::kCall;
       break;
@@ -4644,10 +4649,11 @@ void InstructionCodeGeneratorARM::VisitInstanceOf(HInstanceOf* instruction) {
     __ CompareAndBranchIfZero(obj, &zero);
   }
 
-  // In case of an interface check, we put the object class into the object register.
+  // In case of an interface/unresolved check, we put the object class into the object register.
   // This is safe, as the register is caller-save, and the object must be in another
   // register if it survives the runtime call.
-  Register target = (instruction->GetTypeCheckKind() == TypeCheckKind::kInterfaceCheck)
+  Register target = (instruction->GetTypeCheckKind() == TypeCheckKind::kInterfaceCheck) ||
+      (instruction->GetTypeCheckKind() == TypeCheckKind::kUnresolvedCheck)
       ? obj
       : out;
   __ LoadFromOffset(kLoadWord, target, obj, class_offset);
@@ -4728,7 +4734,7 @@ void InstructionCodeGeneratorARM::VisitInstanceOf(HInstanceOf* instruction) {
       }
       break;
     }
-
+    case TypeCheckKind::kUnresolvedCheck:
     case TypeCheckKind::kInterfaceCheck:
     default: {
       codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pInstanceofNonTrivial),
@@ -4769,6 +4775,7 @@ void LocationsBuilderARM::VisitCheckCast(HCheckCast* instruction) {
           ? LocationSummary::kCallOnSlowPath
           : LocationSummary::kNoCall;
       break;
+    case TypeCheckKind::kUnresolvedCheck:
     case TypeCheckKind::kInterfaceCheck:
       call_kind = LocationSummary::kCall;
       break;
@@ -4873,6 +4880,7 @@ void InstructionCodeGeneratorARM::VisitCheckCast(HCheckCast* instruction) {
       __ CompareAndBranchIfNonZero(temp, slow_path->GetEntryLabel());
       break;
     }
+    case TypeCheckKind::kUnresolvedCheck:
     case TypeCheckKind::kInterfaceCheck:
     default:
       codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pCheckCast),
index c7ade65..07758e9 100644 (file)
@@ -2388,6 +2388,7 @@ void LocationsBuilderARM64::VisitInstanceOf(HInstanceOf* instruction) {
     case TypeCheckKind::kArrayObjectCheck:
       call_kind = LocationSummary::kNoCall;
       break;
+    case TypeCheckKind::kUnresolvedCheck:
     case TypeCheckKind::kInterfaceCheck:
       call_kind = LocationSummary::kCall;
       break;
@@ -2429,10 +2430,11 @@ void InstructionCodeGeneratorARM64::VisitInstanceOf(HInstanceOf* instruction) {
     __ Cbz(obj, &zero);
   }
 
-  // In case of an interface check, we put the object class into the object register.
+  // In case of an interface/unresolved check, we put the object class into the object register.
   // This is safe, as the register is caller-save, and the object must be in another
   // register if it survives the runtime call.
-  Register target = (instruction->GetTypeCheckKind() == TypeCheckKind::kInterfaceCheck)
+  Register target = (instruction->GetTypeCheckKind() == TypeCheckKind::kInterfaceCheck) ||
+      (instruction->GetTypeCheckKind() == TypeCheckKind::kUnresolvedCheck)
       ? obj
       : out;
   __ Ldr(target, HeapOperand(obj.W(), class_offset));
@@ -2513,7 +2515,7 @@ void InstructionCodeGeneratorARM64::VisitInstanceOf(HInstanceOf* instruction) {
       }
       break;
     }
-
+    case TypeCheckKind::kUnresolvedCheck:
     case TypeCheckKind::kInterfaceCheck:
     default: {
       codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pInstanceofNonTrivial),
@@ -2554,6 +2556,7 @@ void LocationsBuilderARM64::VisitCheckCast(HCheckCast* instruction) {
           ? LocationSummary::kCallOnSlowPath
           : LocationSummary::kNoCall;
       break;
+    case TypeCheckKind::kUnresolvedCheck:
     case TypeCheckKind::kInterfaceCheck:
       call_kind = LocationSummary::kCall;
       break;
@@ -2659,6 +2662,7 @@ void InstructionCodeGeneratorARM64::VisitCheckCast(HCheckCast* instruction) {
       __ Cbnz(temp, slow_path->GetEntryLabel());
       break;
     }
+    case TypeCheckKind::kUnresolvedCheck:
     case TypeCheckKind::kInterfaceCheck:
     default:
       codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pCheckCast),
@@ -3014,17 +3018,23 @@ void InstructionCodeGeneratorARM64::VisitInvokeVirtual(HInvokeVirtual* invoke) {
 }
 
 void LocationsBuilderARM64::VisitLoadClass(HLoadClass* cls) {
-  LocationSummary::CallKind call_kind = cls->CanCallRuntime() ? LocationSummary::kCallOnSlowPath
-                                                              : LocationSummary::kNoCall;
-  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(cls, call_kind);
-  locations->SetInAt(0, Location::RequiresRegister());
-  locations->SetOut(Location::RequiresRegister());
+  InvokeRuntimeCallingConvention calling_convention;
+  CodeGenerator::CreateLoadClassLocationSummary(
+      cls,
+      LocationFrom(calling_convention.GetRegisterAt(0)),
+      LocationFrom(vixl::x0));
 }
 
 void InstructionCodeGeneratorARM64::VisitLoadClass(HLoadClass* cls) {
   Register out = OutputRegister(cls);
   Register current_method = InputRegisterAt(cls, 0);
-  if (cls->IsReferrersClass()) {
+  if (cls->NeedsAccessCheck()) {
+    codegen_->MoveConstant(cls->GetLocations()->GetTemp(0), cls->GetTypeIndex());
+    codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pInitializeTypeAndVerifyAccess),
+                            cls,
+                            cls->GetDexPc(),
+                            nullptr);
+  } else if (cls->IsReferrersClass()) {
     DCHECK(!cls->CanCallRuntime());
     DCHECK(!cls->MustGenerateClinitCheck());
     __ Ldr(out, MemOperand(current_method, ArtMethod::DeclaringClassOffset().Int32Value()));
index e95d283..00bb505 100644 (file)
@@ -2590,18 +2590,24 @@ void InstructionCodeGeneratorMIPS64::VisitInvokeVirtual(HInvokeVirtual* invoke)
 }
 
 void LocationsBuilderMIPS64::VisitLoadClass(HLoadClass* cls) {
-  LocationSummary::CallKind call_kind = cls->CanCallRuntime() ? LocationSummary::kCallOnSlowPath
-                                                              : LocationSummary::kNoCall;
-  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(cls, call_kind);
-  locations->SetInAt(0, Location::RequiresRegister());
-  locations->SetOut(Location::RequiresRegister());
+  InvokeRuntimeCallingConvention calling_convention;
+  CodeGenerator::CreateLoadClassLocationSummary(
+      cls,
+      Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
+      Location::RegisterLocation(A0));
 }
 
 void InstructionCodeGeneratorMIPS64::VisitLoadClass(HLoadClass* cls) {
   LocationSummary* locations = cls->GetLocations();
   GpuRegister out = locations->Out().AsRegister<GpuRegister>();
   GpuRegister current_method = locations->InAt(0).AsRegister<GpuRegister>();
-  if (cls->IsReferrersClass()) {
+  if (cls->NeedsAccessCheck()) {
+    codegen_->MoveConstant(locations->GetTemp(0), cls->GetTypeIndex());
+    codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pInitializeTypeAndVerifyAccess),
+                            cls,
+                            cls->GetDexPc(),
+                            nullptr);
+  } else if (cls->IsReferrersClass()) {
     DCHECK(!cls->CanCallRuntime());
     DCHECK(!cls->MustGenerateClinitCheck());
     __ LoadFromOffset(kLoadUnsignedWord, out, current_method,
index 5078456..b89ca11 100644 (file)
@@ -4989,20 +4989,24 @@ void ParallelMoveResolverX86::RestoreScratch(int reg) {
 }
 
 void LocationsBuilderX86::VisitLoadClass(HLoadClass* cls) {
-  LocationSummary::CallKind call_kind = cls->CanCallRuntime()
-      ? LocationSummary::kCallOnSlowPath
-      : LocationSummary::kNoCall;
-  LocationSummary* locations =
-      new (GetGraph()->GetArena()) LocationSummary(cls, call_kind);
-  locations->SetInAt(0, Location::RequiresRegister());
-  locations->SetOut(Location::RequiresRegister());
+  InvokeRuntimeCallingConvention calling_convention;
+  CodeGenerator::CreateLoadClassLocationSummary(
+      cls,
+      Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
+      Location::RegisterLocation(EAX));
 }
 
 void InstructionCodeGeneratorX86::VisitLoadClass(HLoadClass* cls) {
   LocationSummary* locations = cls->GetLocations();
   Register out = locations->Out().AsRegister<Register>();
   Register current_method = locations->InAt(0).AsRegister<Register>();
-  if (cls->IsReferrersClass()) {
+  if (cls->NeedsAccessCheck()) {
+    codegen_->MoveConstant(locations->GetTemp(0), cls->GetTypeIndex());
+    codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pInitializeTypeAndVerifyAccess),
+                            cls,
+                            cls->GetDexPc(),
+                            nullptr);
+  } else if (cls->IsReferrersClass()) {
     DCHECK(!cls->CanCallRuntime());
     DCHECK(!cls->MustGenerateClinitCheck());
     __ movl(out, Address(current_method, ArtMethod::DeclaringClassOffset().Int32Value()));
@@ -5121,6 +5125,7 @@ void LocationsBuilderX86::VisitInstanceOf(HInstanceOf* instruction) {
     case TypeCheckKind::kArrayObjectCheck:
       call_kind = LocationSummary::kNoCall;
       break;
+    case TypeCheckKind::kUnresolvedCheck:
     case TypeCheckKind::kInterfaceCheck:
       call_kind = LocationSummary::kCall;
       break;
@@ -5161,10 +5166,11 @@ void InstructionCodeGeneratorX86::VisitInstanceOf(HInstanceOf* instruction) {
     __ j(kEqual, &zero);
   }
 
-  // In case of an interface check, we put the object class into the object register.
+  // In case of an interface/unresolved check, we put the object class into the object register.
   // This is safe, as the register is caller-save, and the object must be in another
   // register if it survives the runtime call.
-  Register target = (instruction->GetTypeCheckKind() == TypeCheckKind::kInterfaceCheck)
+  Register target = (instruction->GetTypeCheckKind() == TypeCheckKind::kInterfaceCheck) ||
+      (instruction->GetTypeCheckKind() == TypeCheckKind::kUnresolvedCheck)
       ? obj
       : out;
   __ movl(target, Address(obj, class_offset));
@@ -5273,7 +5279,7 @@ void InstructionCodeGeneratorX86::VisitInstanceOf(HInstanceOf* instruction) {
       }
       break;
     }
-
+    case TypeCheckKind::kUnresolvedCheck:
     case TypeCheckKind::kInterfaceCheck:
     default: {
       codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pInstanceofNonTrivial),
@@ -5315,6 +5321,7 @@ void LocationsBuilderX86::VisitCheckCast(HCheckCast* instruction) {
           : LocationSummary::kNoCall;
       break;
     case TypeCheckKind::kInterfaceCheck:
+    case TypeCheckKind::kUnresolvedCheck:
       call_kind = LocationSummary::kCall;
       break;
     case TypeCheckKind::kArrayCheck:
@@ -5441,6 +5448,7 @@ void InstructionCodeGeneratorX86::VisitCheckCast(HCheckCast* instruction) {
       __ j(kNotEqual, slow_path->GetEntryLabel());
       break;
     }
+    case TypeCheckKind::kUnresolvedCheck:
     case TypeCheckKind::kInterfaceCheck:
     default:
       codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pCheckCast),
index 791bb9e..ad6588c 100644 (file)
@@ -4694,20 +4694,24 @@ void InstructionCodeGeneratorX86_64::GenerateClassInitializationCheck(
 }
 
 void LocationsBuilderX86_64::VisitLoadClass(HLoadClass* cls) {
-  LocationSummary::CallKind call_kind = cls->CanCallRuntime()
-      ? LocationSummary::kCallOnSlowPath
-      : LocationSummary::kNoCall;
-  LocationSummary* locations =
-      new (GetGraph()->GetArena()) LocationSummary(cls, call_kind);
-  locations->SetInAt(0, Location::RequiresRegister());
-  locations->SetOut(Location::RequiresRegister());
+  InvokeRuntimeCallingConvention calling_convention;
+  CodeGenerator::CreateLoadClassLocationSummary(
+      cls,
+      Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
+      Location::RegisterLocation(RAX));
 }
 
 void InstructionCodeGeneratorX86_64::VisitLoadClass(HLoadClass* cls) {
   LocationSummary* locations = cls->GetLocations();
   CpuRegister out = locations->Out().AsRegister<CpuRegister>();
   CpuRegister current_method = locations->InAt(0).AsRegister<CpuRegister>();
-  if (cls->IsReferrersClass()) {
+  if (cls->NeedsAccessCheck()) {
+    codegen_->MoveConstant(locations->GetTemp(0), cls->GetTypeIndex());
+    codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pInitializeTypeAndVerifyAccess),
+                            cls,
+                            cls->GetDexPc(),
+                            nullptr);
+  } else if (cls->IsReferrersClass()) {
     DCHECK(!cls->CanCallRuntime());
     DCHECK(!cls->MustGenerateClinitCheck());
     __ movl(out, Address(current_method, ArtMethod::DeclaringClassOffset().Int32Value()));
@@ -4817,6 +4821,7 @@ void LocationsBuilderX86_64::VisitInstanceOf(HInstanceOf* instruction) {
     case TypeCheckKind::kArrayObjectCheck:
       call_kind = LocationSummary::kNoCall;
       break;
+    case TypeCheckKind::kUnresolvedCheck:
     case TypeCheckKind::kInterfaceCheck:
       call_kind = LocationSummary::kCall;
       break;
@@ -4857,10 +4862,11 @@ void InstructionCodeGeneratorX86_64::VisitInstanceOf(HInstanceOf* instruction) {
     __ j(kEqual, &zero);
   }
 
-  // In case of an interface check, we put the object class into the object register.
+  // In case of an interface/unresolved check, we put the object class into the object register.
   // This is safe, as the register is caller-save, and the object must be in another
   // register if it survives the runtime call.
-  CpuRegister target = (instruction->GetTypeCheckKind() == TypeCheckKind::kInterfaceCheck)
+  CpuRegister target = (instruction->GetTypeCheckKind() == TypeCheckKind::kInterfaceCheck) ||
+      (instruction->GetTypeCheckKind() == TypeCheckKind::kUnresolvedCheck)
       ? obj
       : out;
   __ movl(target, Address(obj, class_offset));
@@ -4974,7 +4980,7 @@ void InstructionCodeGeneratorX86_64::VisitInstanceOf(HInstanceOf* instruction) {
       }
       break;
     }
-
+    case TypeCheckKind::kUnresolvedCheck:
     case TypeCheckKind::kInterfaceCheck:
     default: {
       codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pInstanceofNonTrivial),
@@ -5015,6 +5021,7 @@ void LocationsBuilderX86_64::VisitCheckCast(HCheckCast* instruction) {
           ? LocationSummary::kCallOnSlowPath
           : LocationSummary::kNoCall;
       break;
+    case TypeCheckKind::kUnresolvedCheck:
     case TypeCheckKind::kInterfaceCheck:
       call_kind = LocationSummary::kCall;
       break;
@@ -5142,6 +5149,7 @@ void InstructionCodeGeneratorX86_64::VisitCheckCast(HCheckCast* instruction) {
       __ j(kNotEqual, slow_path->GetEntryLabel());
       break;
     }
+    case TypeCheckKind::kUnresolvedCheck:
     case TypeCheckKind::kInterfaceCheck:
     default:
       codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pCheckCast),
index 7a83662..d38f4c8 100644 (file)
@@ -501,8 +501,11 @@ class HGraphVisualizerPrinter : public HGraphDelegateVisitor {
         StartAttributeStream("can_be_null")
             << std::boolalpha << instruction->CanBeNull() << std::noboolalpha;
         StartAttributeStream("exact") << std::boolalpha << info.IsExact() << std::noboolalpha;
+      } else if (instruction->IsLoadClass()) {
+        StartAttributeStream("klass") << "unresolved";
       } else {
-        DCHECK(!is_after_pass_) << "Type info should be valid after reference type propagation";
+        DCHECK(!is_after_pass_)
+            << "Expected a valid rti after reference type propagation";
       }
     }
     if (disasm_info_ != nullptr) {
index 3287a0a..86a3ad9 100644 (file)
@@ -216,7 +216,11 @@ static bool TypeCheckHasKnownOutcome(HLoadClass* klass, HInstruction* object, bo
   }
 
   ReferenceTypeInfo class_rti = klass->GetLoadedClassRTI();
-  DCHECK(class_rti.IsValid() && class_rti.IsExact());
+  if (!class_rti.IsValid()) {
+    // Happens when the loaded class is unresolved.
+    return false;
+  }
+  DCHECK(class_rti.IsExact());
   if (class_rti.IsSupertypeOf(obj_rti)) {
     *outcome = true;
     return true;
index 849f876..489f71d 100644 (file)
@@ -4513,12 +4513,14 @@ class HLoadClass : public HExpression<1> {
              uint16_t type_index,
              const DexFile& dex_file,
              bool is_referrers_class,
-             uint32_t dex_pc)
+             uint32_t dex_pc,
+             bool needs_access_check)
       : HExpression(Primitive::kPrimNot, SideEffectsForArchRuntimeCalls(), dex_pc),
         type_index_(type_index),
         dex_file_(dex_file),
         is_referrers_class_(is_referrers_class),
         generate_clinit_check_(false),
+        needs_access_check_(needs_access_check),
         loaded_class_rti_(ReferenceTypeInfo::CreateInvalid()) {
     SetRawInputAt(0, current_method);
   }
@@ -4538,19 +4540,22 @@ class HLoadClass : public HExpression<1> {
   bool NeedsEnvironment() const OVERRIDE {
     // Will call runtime and load the class if the class is not loaded yet.
     // TODO: finer grain decision.
-    return !is_referrers_class_;
+    return !is_referrers_class_ || needs_access_check_;
   }
 
   bool MustGenerateClinitCheck() const {
     return generate_clinit_check_;
   }
-
   void SetMustGenerateClinitCheck(bool generate_clinit_check) {
     generate_clinit_check_ = generate_clinit_check;
   }
 
   bool CanCallRuntime() const {
-    return MustGenerateClinitCheck() || !is_referrers_class_;
+    return MustGenerateClinitCheck() || !is_referrers_class_ || needs_access_check_;
+  }
+
+  bool NeedsAccessCheck() const {
+    return needs_access_check_;
   }
 
   bool CanThrow() const OVERRIDE {
@@ -4586,6 +4591,7 @@ class HLoadClass : public HExpression<1> {
   // Whether this instruction must generate the initialization check.
   // Used for code generation.
   bool generate_clinit_check_;
+  bool needs_access_check_;
 
   ReferenceTypeInfo loaded_class_rti_;
 
@@ -4897,6 +4903,7 @@ class HThrow : public HTemplateInstruction<1> {
  * or `HCheckCast`.
  */
 enum class TypeCheckKind {
+  kUnresolvedCheck,       // Check against an unresolved type.
   kExactCheck,            // Can do a single class compare.
   kClassHierarchyCheck,   // Can just walk the super class chain.
   kAbstractClassCheck,    // Can just walk the super class chain, starting one up.
index d22f254..f7a7e42 100644 (file)
@@ -121,8 +121,9 @@ void ReferenceTypePropagation::Run() {
           if (instr->IsBoundType()) {
             DCHECK(instr->AsBoundType()->GetUpperBound().IsValid());
           } else if (instr->IsLoadClass()) {
-            DCHECK(instr->AsLoadClass()->GetReferenceTypeInfo().IsExact());
-            DCHECK(instr->AsLoadClass()->GetLoadedClassRTI().IsValid());
+            HLoadClass* cls = instr->AsLoadClass();
+            DCHECK(cls->GetReferenceTypeInfo().IsExact());
+            DCHECK(!cls->GetLoadedClassRTI().IsValid() || cls->GetLoadedClassRTI().IsExact());
           } else if (instr->IsNullCheck()) {
             DCHECK(instr->GetReferenceTypeInfo().IsEqual(instr->InputAt(0)->GetReferenceTypeInfo()))
                 << "NullCheck " << instr->GetReferenceTypeInfo()
@@ -168,6 +169,7 @@ static HBoundType* CreateBoundType(ArenaAllocator* arena,
       SHARED_REQUIRES(Locks::mutator_lock_) {
   ReferenceTypeInfo obj_rti = obj->GetReferenceTypeInfo();
   ReferenceTypeInfo class_rti = load_class->GetLoadedClassRTI();
+  DCHECK(class_rti.IsValid());
   HBoundType* bound_type = new (arena) HBoundType(obj, class_rti, upper_can_be_null);
   // Narrow the type as much as possible.
   if (class_rti.GetTypeHandle()->CannotBeAssignedFromOtherTypes()) {
@@ -316,6 +318,15 @@ void ReferenceTypePropagation::BoundTypeForIfInstanceOf(HBasicBlock* block) {
     return;
   }
 
+  HLoadClass* load_class = instanceOf->InputAt(1)->AsLoadClass();
+  ReferenceTypeInfo class_rti = load_class->GetLoadedClassRTI();
+  {
+    ScopedObjectAccess soa(Thread::Current());
+    if (!class_rti.IsValid()) {
+      // He have loaded an unresolved class. Don't bother bounding the type.
+      return;
+    }
+  }
   // We only need to bound the type if we have uses in the relevant block.
   // So start with null and create the HBoundType lazily, only if it's needed.
   HBoundType* bound_type = nullptr;
@@ -336,8 +347,6 @@ void ReferenceTypePropagation::BoundTypeForIfInstanceOf(HBasicBlock* block) {
     if (instanceOfTrueBlock->Dominates(user->GetBlock())) {
       if (bound_type == nullptr) {
         ScopedObjectAccess soa(Thread::Current());
-        HLoadClass* load_class = instanceOf->InputAt(1)->AsLoadClass();
-        ReferenceTypeInfo class_rti = load_class->GetLoadedClassRTI();
         HInstruction* insert_point = instanceOfTrueBlock->GetFirstInstruction();
         if (ShouldCreateBoundType(insert_point, obj, class_rti, nullptr, instanceOfTrueBlock)) {
           bound_type = CreateBoundType(
@@ -475,10 +484,10 @@ void RTPVisitor::VisitLoadClass(HLoadClass* instr) {
   // Get type from dex cache assuming it was populated by the verifier.
   mirror::Class* resolved_class = dex_cache->GetResolvedType(instr->GetTypeIndex());
   // TODO: investigating why we are still getting unresolved classes: b/22821472.
-  ReferenceTypeInfo::TypeHandle handle = (resolved_class != nullptr)
-    ? handles_->NewHandle(resolved_class)
-    : object_class_handle_;
-  instr->SetLoadedClassRTI(ReferenceTypeInfo::Create(handle, /* is_exact */ true));
+  if (resolved_class != nullptr) {
+    instr->SetLoadedClassRTI(ReferenceTypeInfo::Create(
+        handles_->NewHandle(resolved_class), /* is_exact */ true));
+  }
   instr->SetReferenceTypeInfo(ReferenceTypeInfo::Create(class_class_handle_, /* is_exact */ true));
 }
 
@@ -517,6 +526,15 @@ void RTPVisitor::VisitFakeString(HFakeString* instr) {
 }
 
 void RTPVisitor::VisitCheckCast(HCheckCast* check_cast) {
+  HLoadClass* load_class = check_cast->InputAt(1)->AsLoadClass();
+  ReferenceTypeInfo class_rti = load_class->GetLoadedClassRTI();
+  {
+    ScopedObjectAccess soa(Thread::Current());
+    if (!class_rti.IsValid()) {
+      // He have loaded an unresolved class. Don't bother bounding the type.
+      return;
+    }
+  }
   HInstruction* obj = check_cast->InputAt(0);
   HBoundType* bound_type = nullptr;
   for (HUseIterator<HInstruction*> it(obj->GetUses()); !it.Done(); it.Advance()) {
@@ -524,8 +542,6 @@ void RTPVisitor::VisitCheckCast(HCheckCast* check_cast) {
     if (check_cast->StrictlyDominates(user)) {
       if (bound_type == nullptr) {
         ScopedObjectAccess soa(Thread::Current());
-        HLoadClass* load_class = check_cast->InputAt(1)->AsLoadClass();
-        ReferenceTypeInfo class_rti = load_class->GetLoadedClassRTI();
         if (ShouldCreateBoundType(check_cast->GetNext(), obj, class_rti, check_cast, nullptr)) {
           bound_type = CreateBoundType(
               GetGraph()->GetArena(),
index 358048c..1e7dbfe 100644 (file)
@@ -3,3 +3,5 @@ UnresolvedClass.staticMethod()
 UnresolvedClass.virtualMethod()
 UnresolvedClass.interfaceMethod()
 UnresolvedClass.superMethod()
+instanceof ok
+checkcast ok
index adb5ada..5219c04 100644 (file)
@@ -114,16 +114,30 @@ public class Main extends UnresolvedSuperClass {
     expectEquals(o, c.instanceObject);
   }
 
+  static public void testInstanceOf(Object o) {
+    if (o instanceof UnresolvedSuperClass) {
+      System.out.println("instanceof ok");
+    }
+  }
+
+  static public UnresolvedSuperClass testCheckCast(Object o) {
+    UnresolvedSuperClass c = (UnresolvedSuperClass) o;
+    System.out.println("checkcast ok");
+    return c;
+  }
   /// CHECK-START: void Main.main(java.lang.String[]) register (before)
   /// CHECK:        InvokeUnresolved invoke_type:direct
   static public void main(String[] args) {
     UnresolvedClass c = new UnresolvedClass();
+    Main m = new Main();
     callInvokeUnresolvedStatic();
     callInvokeUnresolvedVirtual(c);
     callInvokeUnresolvedInterface(c);
-    callInvokeUnresolvedSuper(new Main());
+    callInvokeUnresolvedSuper(m);
     callUnresolvedStaticFieldAccess();
     callUnresolvedInstanceFieldAccess(c);
+    testInstanceOf(m);
+    testCheckCast(m);
   }
 
   public static void expectEquals(byte expected, byte result) {
index 03ceb68..20ac6e0 100644 (file)
@@ -58,13 +58,3 @@ class UnresolvedClass extends UnresolvedSuperClass implements UnresolvedInterfac
   public Object instanceObject;
 }
 
-final class UnresolvedFinalClass {
-  public void directMethod() {
-    System.out.println("UnresolvedFinalClass.directMethod()");
-  }
-}
-
-class UnresolvedAtRuntime {
-  public void unresolvedAtRuntime() { }
-}
-