Enable compilation of members with access check failures.

Change-Id: I0de73099b53612072c3e6f1235c22f96339fe440
diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc
index 7ef79ec..ebbfb14 100644
--- a/compiler/optimizing/builder.cc
+++ b/compiler/optimizing/builder.cc
@@ -1305,6 +1305,23 @@
   return outer_class.Get() == cls.Get();
 }
 
+void HGraphBuilder::BuildUnresolvedStaticFieldAccess(const Instruction& instruction,
+                                                     uint32_t dex_pc,
+                                                     bool is_put,
+                                                     Primitive::Type field_type) {
+  uint32_t source_or_dest_reg = instruction.VRegA_21c();
+  uint16_t field_index = instruction.VRegB_21c();
+
+  if (is_put) {
+    HInstruction* value = LoadLocal(source_or_dest_reg, field_type, dex_pc);
+    current_block_->AddInstruction(
+        new (arena_) HUnresolvedStaticFieldSet(value, field_type, field_index, dex_pc));
+  } else {
+    current_block_->AddInstruction(
+        new (arena_) HUnresolvedStaticFieldGet(field_type, field_index, dex_pc));
+    UpdateLocal(source_or_dest_reg, current_block_->GetLastInstruction(), dex_pc);
+  }
+}
 bool HGraphBuilder::BuildStaticFieldAccess(const Instruction& instruction,
                                            uint32_t dex_pc,
                                            bool is_put) {
@@ -1324,18 +1341,11 @@
   if (resolved_field == nullptr) {
     MaybeRecordStat(MethodCompilationStat::kUnresolvedField);
     Primitive::Type field_type = GetFieldAccessType(*dex_file_, field_index);
-    if (is_put) {
-      HInstruction* value = LoadLocal(source_or_dest_reg, field_type, dex_pc);
-      current_block_->AddInstruction(
-          new (arena_) HUnresolvedStaticFieldSet(value, field_type, field_index, dex_pc));
-    } else {
-      current_block_->AddInstruction(
-          new (arena_) HUnresolvedStaticFieldGet(field_type, field_index, dex_pc));
-      UpdateLocal(source_or_dest_reg, current_block_->GetLastInstruction(), dex_pc);
-    }
+    BuildUnresolvedStaticFieldAccess(instruction, dex_pc, is_put, field_type);
     return true;
   }
 
+  Primitive::Type field_type = resolved_field->GetTypeAsPrimitiveType();
   const DexFile& outer_dex_file = *outer_compilation_unit_->GetDexFile();
   Handle<mirror::DexCache> outer_dex_cache(hs.NewHandle(
       outer_compilation_unit_->GetClassLinker()->FindDexCache(soa.Self(), outer_dex_file)));
@@ -1350,6 +1360,7 @@
     // The compiler driver cannot currently understand multiple dex caches involved. Just bailout.
     return false;
   } else {
+    // TODO: This is rather expensive. Perf it and cache the results if needed.
     std::pair<bool, bool> pair = compiler_driver_->IsFastStaticField(
         outer_dex_cache.Get(),
         GetCompilingClass(),
@@ -1358,7 +1369,9 @@
         &storage_index);
     bool can_easily_access = is_put ? pair.second : pair.first;
     if (!can_easily_access) {
-      return false;
+      MaybeRecordStat(MethodCompilationStat::kUnresolvedFieldNotAFastAccess);
+      BuildUnresolvedStaticFieldAccess(instruction, dex_pc, is_put, field_type);
+      return true;
     }
   }
 
@@ -1379,8 +1392,6 @@
     cls = new (arena_) HClinitCheck(constant, dex_pc);
     current_block_->AddInstruction(cls);
   }
-
-  Primitive::Type field_type = resolved_field->GetTypeAsPrimitiveType();
   if (is_put) {
     // We need to keep the class alive before loading the value.
     Temporaries temps(graph_);
diff --git a/compiler/optimizing/builder.h b/compiler/optimizing/builder.h
index 4c8e3d0..b2dc241 100644
--- a/compiler/optimizing/builder.h
+++ b/compiler/optimizing/builder.h
@@ -187,6 +187,10 @@
   // Builds an instance field access node and returns whether the instruction is supported.
   bool BuildInstanceFieldAccess(const Instruction& instruction, uint32_t dex_pc, bool is_put);
 
+  void BuildUnresolvedStaticFieldAccess(const Instruction& instruction,
+                                        uint32_t dex_pc,
+                                        bool is_put,
+                                        Primitive::Type field_type);
   // Builds a static field access node and returns whether the instruction is supported.
   bool BuildStaticFieldAccess(const Instruction& instruction, uint32_t dex_pc, bool is_put);
 
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index dbfbd96..3e982dc 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -829,8 +829,12 @@
   return compiled_method;
 }
 
-static bool HasOnlyUnresolvedFailures(const VerifiedMethod* verified_method) {
-  uint32_t unresolved_mask = verifier::VerifyError::VERIFY_ERROR_NO_CLASS;
+static bool CanHandleVerificationFailure(const VerifiedMethod* verified_method) {
+  // For access errors the compiler will use the unresolved helpers (e.g. HInvokeUnresolved).
+  uint32_t unresolved_mask = verifier::VerifyError::VERIFY_ERROR_NO_CLASS
+      | verifier::VerifyError::VERIFY_ERROR_ACCESS_CLASS
+      | verifier::VerifyError::VERIFY_ERROR_ACCESS_FIELD
+      | verifier::VerifyError::VERIFY_ERROR_ACCESS_METHOD;
   return (verified_method->GetEncounteredVerificationFailures() & (~unresolved_mask)) == 0;
 }
 
@@ -847,7 +851,7 @@
   const VerifiedMethod* verified_method = compiler_driver->GetVerifiedMethod(&dex_file, method_idx);
   DCHECK(!verified_method->HasRuntimeThrow());
   if (compiler_driver->IsMethodVerifiedWithoutFailures(method_idx, class_def_idx, dex_file)
-      || HasOnlyUnresolvedFailures(verified_method)) {
+      || CanHandleVerificationFailure(verified_method)) {
      method = TryCompile(code_item, access_flags, invoke_type, class_def_idx,
                          method_idx, jclass_loader, dex_file, dex_cache);
   } else {
diff --git a/compiler/optimizing/optimizing_compiler_stats.h b/compiler/optimizing/optimizing_compiler_stats.h
index f1d2970..df45c8e 100644
--- a/compiler/optimizing/optimizing_compiler_stats.h
+++ b/compiler/optimizing/optimizing_compiler_stats.h
@@ -35,6 +35,7 @@
   kInstructionSimplificationsArch,
   kUnresolvedMethod,
   kUnresolvedField,
+  kUnresolvedFieldNotAFastAccess,
   kNotCompiledBranchOutsideMethodCode,
   kNotCompiledCannotBuildSSA,
   kNotCompiledCantAccesType,
@@ -105,6 +106,7 @@
       case kInstructionSimplificationsArch: return "kInstructionSimplificationsArch";
       case kUnresolvedMethod : return "kUnresolvedMethod";
       case kUnresolvedField : return "kUnresolvedField";
+      case kUnresolvedFieldNotAFastAccess : return "kUnresolvedFieldNotAFastAccess";
       case kNotCompiledBranchOutsideMethodCode: return "kNotCompiledBranchOutsideMethodCode";
       case kNotCompiledCannotBuildSSA : return "kNotCompiledCannotBuildSSA";
       case kNotCompiledCantAccesType : return "kNotCompiledCantAccesType";
diff --git a/test/024-illegal-access/expected.txt b/test/024-illegal-access/expected.txt
index 5f951f4..0ae4a77 100644
--- a/test/024-illegal-access/expected.txt
+++ b/test/024-illegal-access/expected.txt
@@ -1,2 +1,5 @@
 Got expected failure 1
 Got expected failure 2
+Got expected failure 3
+Got expected failure 4
+Got expected failure 5
diff --git a/test/024-illegal-access/src/Main.java b/test/024-illegal-access/src/Main.java
index bde73e9..84c7114 100644
--- a/test/024-illegal-access/src/Main.java
+++ b/test/024-illegal-access/src/Main.java
@@ -17,7 +17,7 @@
 public class Main {
     static public void main(String[] args) {
         try {
-            PublicAccess.main();
+            PublicAccess.accessStaticField();
             System.err.println("ERROR: call 1 not expected to succeed");
         } catch (VerifyError ve) {
             // dalvik
@@ -28,14 +28,41 @@
         }
 
         try {
-            CheckInstanceof.main(new Object());
+            PublicAccess.accessStaticMethod();
             System.err.println("ERROR: call 2 not expected to succeed");
-        } catch (VerifyError ve) {
-            // dalvik
-            System.out.println("Got expected failure 2");
         } catch (IllegalAccessError iae) {
             // reference
             System.out.println("Got expected failure 2");
         }
+
+        try {
+            PublicAccess.accessInstanceField();
+            System.err.println("ERROR: call 3 not expected to succeed");
+        } catch (VerifyError ve) {
+            // dalvik
+            System.out.println("Got expected failure 3");
+        } catch (IllegalAccessError iae) {
+            // reference
+            System.out.println("Got expected failure 3");
+        }
+
+        try {
+            PublicAccess.accessInstanceMethod();
+            System.err.println("ERROR: call 4 not expected to succeed");
+        } catch (IllegalAccessError iae) {
+            // reference
+            System.out.println("Got expected failure 4");
+        }
+
+        try {
+            CheckInstanceof.main(new Object());
+            System.err.println("ERROR: call 5 not expected to succeed");
+        } catch (VerifyError ve) {
+            // dalvik
+            System.out.println("Got expected failure 5");
+        } catch (IllegalAccessError iae) {
+            // reference
+            System.out.println("Got expected failure 5");
+        }
     }
 }
diff --git a/test/024-illegal-access/src/PublicAccess.java b/test/024-illegal-access/src/PublicAccess.java
index 4e72cd4..e3fef85 100644
--- a/test/024-illegal-access/src/PublicAccess.java
+++ b/test/024-illegal-access/src/PublicAccess.java
@@ -18,8 +18,20 @@
  * Some stuff for access checks.
  */
 public class PublicAccess {
-    public static void main() {
-        String shouldFail = SemiPrivate.mPrivvy;
+    public static void accessStaticField() {
+        String shouldFail = SemiPrivate.mStaticPrivvy;
+        System.out.println("Got " + shouldFail);
+    }
+    public static void accessStaticMethod() {
+        String shouldFail = SemiPrivate.privvyStaticMethod();
+        System.out.println("Got " + shouldFail);
+    }
+    public static void accessInstanceField() {
+        String shouldFail = new SemiPrivate().mInstancePrivvy;
+        System.out.println("Got " + shouldFail);
+    }
+    public static void accessInstanceMethod() {
+        String shouldFail = new SemiPrivate().privvyInstanceMethod();
         System.out.println("Got " + shouldFail);
     }
 }
diff --git a/test/024-illegal-access/src/SemiPrivate.java b/test/024-illegal-access/src/SemiPrivate.java
index 06b16c4..62e0d05 100644
--- a/test/024-illegal-access/src/SemiPrivate.java
+++ b/test/024-illegal-access/src/SemiPrivate.java
@@ -18,5 +18,15 @@
  * Version with package scope access.
  */
 public class SemiPrivate {
-    /* not private */ static String mPrivvy = "stuff";
+    /* not private */ static String mStaticPrivvy = "stuff";
+
+    /* not private */ static String privvyStaticMethod() {
+      return "stuff";
+    }
+
+    /* not private */ String mInstancePrivvy = "stuff";
+
+    /* not private */ String privvyInstanceMethod() {
+      return "stuff";
+    }
 }
diff --git a/test/024-illegal-access/src2/SemiPrivate.java b/test/024-illegal-access/src2/SemiPrivate.java
index 064265a..4f36a07 100644
--- a/test/024-illegal-access/src2/SemiPrivate.java
+++ b/test/024-illegal-access/src2/SemiPrivate.java
@@ -18,5 +18,15 @@
  * Version with private access.
  */
 public class SemiPrivate {
-    private static String mPrivvy = "stuff";
+    private static String mStaticPrivvy = "stuff";
+
+    private static String privvyStaticMethod() {
+      return "stuff";
+    }
+
+    private String mInstancePrivvy = "stuff";
+
+    private String privvyInstanceMethod() {
+      return "stuff";
+    }
 }