diff options
| -rw-r--r-- | compiler/optimizing/builder.cc | 35 | ||||
| -rw-r--r-- | compiler/optimizing/builder.h | 4 | ||||
| -rw-r--r-- | compiler/optimizing/optimizing_compiler.cc | 10 | ||||
| -rw-r--r-- | compiler/optimizing/optimizing_compiler_stats.h | 2 | ||||
| -rw-r--r-- | test/024-illegal-access/expected.txt | 3 | ||||
| -rw-r--r-- | test/024-illegal-access/src/Main.java | 35 | ||||
| -rw-r--r-- | test/024-illegal-access/src/PublicAccess.java | 16 | ||||
| -rw-r--r-- | test/024-illegal-access/src/SemiPrivate.java | 12 | ||||
| -rw-r--r-- | test/024-illegal-access/src2/SemiPrivate.java | 12 |
9 files changed, 106 insertions, 23 deletions
diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc index 7ef79ec111..ebbfb14190 100644 --- a/compiler/optimizing/builder.cc +++ b/compiler/optimizing/builder.cc @@ -1305,6 +1305,23 @@ bool HGraphBuilder::IsOutermostCompilingClass(uint16_t type_index) const { 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 @@ bool HGraphBuilder::BuildStaticFieldAccess(const Instruction& instruction, 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 @@ bool HGraphBuilder::BuildStaticFieldAccess(const Instruction& instruction, // 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 @@ bool HGraphBuilder::BuildStaticFieldAccess(const Instruction& instruction, &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 @@ bool HGraphBuilder::BuildStaticFieldAccess(const Instruction& instruction, 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 4c8e3d0442..b2dc24169e 100644 --- a/compiler/optimizing/builder.h +++ b/compiler/optimizing/builder.h @@ -187,6 +187,10 @@ class HGraphBuilder : public ValueObject { // 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 dbfbd96e39..3e982dca23 100644 --- a/compiler/optimizing/optimizing_compiler.cc +++ b/compiler/optimizing/optimizing_compiler.cc @@ -829,8 +829,12 @@ CompiledMethod* OptimizingCompiler::TryCompile(const DexFile::CodeItem* code_ite 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 @@ CompiledMethod* OptimizingCompiler::Compile(const DexFile::CodeItem* code_item, 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 f1d29700d9..df45c8e890 100644 --- a/compiler/optimizing/optimizing_compiler_stats.h +++ b/compiler/optimizing/optimizing_compiler_stats.h @@ -35,6 +35,7 @@ enum MethodCompilationStat { kInstructionSimplificationsArch, kUnresolvedMethod, kUnresolvedField, + kUnresolvedFieldNotAFastAccess, kNotCompiledBranchOutsideMethodCode, kNotCompiledCannotBuildSSA, kNotCompiledCantAccesType, @@ -105,6 +106,7 @@ class OptimizingCompilerStats { 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 5f951f4939..0ae4a774f3 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 bde73e9452..84c7114cb4 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 @@ public class Main { } try { - CheckInstanceof.main(new Object()); + PublicAccess.accessStaticMethod(); System.err.println("ERROR: call 2 not expected to succeed"); + } 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 2"); + System.out.println("Got expected failure 3"); } catch (IllegalAccessError iae) { // reference - System.out.println("Got expected failure 2"); + 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 4e72cd4dce..e3fef855e2 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 06b16c40b9..62e0d05213 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 064265ab37..4f36a07418 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"; + } } |