Snap for 4731145 from 9f3a0c3d5171f49111e11a62b6ff746a7838afe0 to pi-release
Change-Id: Ib54d754d01cf7358ae989f56e75ea06377900a09
diff --git a/adbconnection/adbconnection.cc b/adbconnection/adbconnection.cc
index 06ded26..ee89717 100644
--- a/adbconnection/adbconnection.cc
+++ b/adbconnection/adbconnection.cc
@@ -824,11 +824,21 @@
}
void AdbConnectionState::AttachJdwpAgent(art::Thread* self) {
+ art::Runtime* runtime = art::Runtime::Current();
+ if (runtime->GetJit() == nullptr && !runtime->GetInstrumentation()->IsForcedInterpretOnly()) {
+ // If we don't have a JIT we should try to start the jit for performance reasons.
+ runtime->CreateJit();
+ if (runtime->GetJit() == nullptr) {
+ LOG(WARNING) << "Could not start jit for debugging. This process might be quite slow as it "
+ << "is running entirely in the interpreter. Try running 'setenforce 0' and "
+ << "starting the debugging session over.";
+ }
+ }
self->AssertNoPendingException();
- art::Runtime::Current()->AttachAgent(/* JNIEnv */ nullptr,
- MakeAgentArg(),
- /* classloader */ nullptr,
- /*allow_non_debuggable_tooling*/ true);
+ runtime->AttachAgent(/* JNIEnv */ nullptr,
+ MakeAgentArg(),
+ /* classloader */ nullptr,
+ /*allow_non_debuggable_tooling*/ true);
if (self->IsExceptionPending()) {
LOG(ERROR) << "Failed to load agent " << agent_name_;
art::ScopedObjectAccess soa(self);
diff --git a/compiler/optimizing/nodes_vector.h b/compiler/optimizing/nodes_vector.h
index 0d38d57..d1eaf5c 100644
--- a/compiler/optimizing/nodes_vector.h
+++ b/compiler/optimizing/nodes_vector.h
@@ -171,9 +171,12 @@
if (instruction->IsVecOperation()) {
return !instruction->IsVecExtractScalar(); // only scalar returning vec op
} else if (instruction->IsPhi()) {
+ // Vectorizer only uses Phis in reductions, so checking for a 2-way phi
+ // with a direct vector operand as second argument suffices.
return
instruction->GetType() == kSIMDType &&
- instruction->InputAt(1)->IsVecOperation(); // vectorizer does not go deeper
+ instruction->InputCount() == 2 &&
+ instruction->InputAt(1)->IsVecOperation();
}
return false;
}
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index 1e4ed58..fe927bb 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -428,6 +428,10 @@
UsageError(" --class-loader-context=<string spec>: a string specifying the intended");
UsageError(" runtime loading context for the compiled dex files.");
UsageError("");
+ UsageError(" --stored-class-loader-context=<string spec>: a string specifying the intended");
+ UsageError(" runtime loading context that is stored in the oat file. Overrides");
+ UsageError(" --class-loader-context. Note that this ignores the classpath_dir arg.");
+ UsageError("");
UsageError(" It describes how the class loader chain should be built in order to ensure");
UsageError(" classes are resolved during dex2aot as they would be resolved at runtime.");
UsageError(" This spec will be encoded in the oat file. If at runtime the dex file is");
@@ -1260,11 +1264,31 @@
ParseInstructionSetFeatures(*args.Get(M::TargetInstructionSetFeatures), parser_options.get());
}
if (args.Exists(M::ClassLoaderContext)) {
- class_loader_context_ = ClassLoaderContext::Create(*args.Get(M::ClassLoaderContext));
+ std::string class_loader_context_arg = *args.Get(M::ClassLoaderContext);
+ class_loader_context_ = ClassLoaderContext::Create(class_loader_context_arg);
if (class_loader_context_ == nullptr) {
Usage("Option --class-loader-context has an incorrect format: %s",
- args.Get(M::ClassLoaderContext)->c_str());
+ class_loader_context_arg.c_str());
}
+ if (args.Exists(M::StoredClassLoaderContext)) {
+ const std::string stored_context_arg = *args.Get(M::StoredClassLoaderContext);
+ stored_class_loader_context_ = ClassLoaderContext::Create(stored_context_arg);
+ if (stored_class_loader_context_ == nullptr) {
+ Usage("Option --stored-class-loader-context has an incorrect format: %s",
+ stored_context_arg.c_str());
+ } else if (!class_loader_context_->VerifyClassLoaderContextMatch(
+ stored_context_arg,
+ /*verify_names*/ false,
+ /*verify_checksums*/ false)) {
+ Usage(
+ "Option --stored-class-loader-context '%s' mismatches --class-loader-context '%s'",
+ stored_context_arg.c_str(),
+ class_loader_context_arg.c_str());
+ }
+ }
+ } else if (args.Exists(M::StoredClassLoaderContext)) {
+ Usage("Option --stored-class-loader-context should only be used if "
+ "--class-loader-context is also specified");
}
if (!ReadCompilerOptions(args, compiler_options_.get(), &error_msg)) {
@@ -1579,7 +1603,7 @@
if (class_loader_context_ == nullptr) {
// If no context was specified use the default one (which is an empty PathClassLoader).
- class_loader_context_ = std::unique_ptr<ClassLoaderContext>(ClassLoaderContext::Default());
+ class_loader_context_ = ClassLoaderContext::Default();
}
DCHECK_EQ(oat_writers_.size(), 1u);
@@ -1605,8 +1629,12 @@
}
// Store the class loader context in the oat header.
- key_value_store_->Put(OatHeader::kClassPathKey,
- class_loader_context_->EncodeContextForOatFile(classpath_dir_));
+ // TODO: deprecate this since store_class_loader_context should be enough to cover the users
+ // of classpath_dir as well.
+ std::string class_path_key =
+ class_loader_context_->EncodeContextForOatFile(classpath_dir_,
+ stored_class_loader_context_.get());
+ key_value_store_->Put(OatHeader::kClassPathKey, class_path_key);
}
// Now that we have finalized key_value_store_, start writing the oat file.
@@ -2845,6 +2873,9 @@
// The spec describing how the class loader should be setup for compilation.
std::unique_ptr<ClassLoaderContext> class_loader_context_;
+ // The class loader context stored in the oat file. May be equal to class_loader_context_.
+ std::unique_ptr<ClassLoaderContext> stored_class_loader_context_;
+
size_t thread_count_;
uint64_t start_ns_;
uint64_t start_cputime_ns_;
diff --git a/dex2oat/dex2oat_options.cc b/dex2oat/dex2oat_options.cc
index 0d68f4f..5843691 100644
--- a/dex2oat/dex2oat_options.cc
+++ b/dex2oat/dex2oat_options.cc
@@ -245,6 +245,9 @@
.Define("--class-loader-context=_")
.WithType<std::string>()
.IntoKey(M::ClassLoaderContext)
+ .Define("--stored-class-loader-context=_")
+ .WithType<std::string>()
+ .IntoKey(M::StoredClassLoaderContext)
.Define("--compact-dex-level=_")
.WithType<CompactDexLevel>()
.WithValueMap({{"none", CompactDexLevel::kCompactDexLevelNone},
diff --git a/dex2oat/dex2oat_options.def b/dex2oat/dex2oat_options.def
index 01f9d94..1a913a9 100644
--- a/dex2oat/dex2oat_options.def
+++ b/dex2oat/dex2oat_options.def
@@ -88,6 +88,7 @@
DEX2OAT_OPTIONS_KEY (Unit, ForceDeterminism)
DEX2OAT_OPTIONS_KEY (std::string, ClasspathDir)
DEX2OAT_OPTIONS_KEY (std::string, ClassLoaderContext)
+DEX2OAT_OPTIONS_KEY (std::string, StoredClassLoaderContext)
DEX2OAT_OPTIONS_KEY (std::string, DirtyImageObjects)
DEX2OAT_OPTIONS_KEY (std::vector<std::string>, RuntimeOptions)
DEX2OAT_OPTIONS_KEY (std::string, CompilationReason)
diff --git a/dex2oat/dex2oat_test.cc b/dex2oat/dex2oat_test.cc
index c890f8b..bc8468e 100644
--- a/dex2oat/dex2oat_test.cc
+++ b/dex2oat/dex2oat_test.cc
@@ -2125,4 +2125,49 @@
EXPECT_EQ(header.GetImageSection(ImageHeader::kSectionArtFields).Size(), 0u);
}
+TEST_F(Dex2oatClassLoaderContextTest, StoredClassLoaderContext) {
+ std::vector<std::unique_ptr<const DexFile>> dex_files = OpenTestDexFiles("MultiDex");
+ const std::string out_dir = GetScratchDir();
+ const std::string odex_location = out_dir + "/base.odex";
+ const std::string valid_context = "PCL[" + dex_files[0]->GetLocation() + "]";
+ const std::string stored_context = "PCL[/system/not_real_lib.jar]";
+ std::string expected_stored_context = "PCL[";
+ size_t index = 1;
+ for (const std::unique_ptr<const DexFile>& dex_file : dex_files) {
+ const bool is_first = index == 1u;
+ if (!is_first) {
+ expected_stored_context += ":";
+ }
+ expected_stored_context += "/system/not_real_lib.jar";
+ if (!is_first) {
+ expected_stored_context += "!classes" + std::to_string(index) + ".dex";
+ }
+ expected_stored_context += "*" + std::to_string(dex_file->GetLocationChecksum());
+ ++index;
+ }
+ expected_stored_context += + "]";
+ // The class path should not be valid and should fail being stored.
+ GenerateOdexForTest(GetTestDexFileName("ManyMethods"),
+ odex_location,
+ CompilerFilter::Filter::kQuicken,
+ { "--class-loader-context=" + stored_context },
+ true, // expect_success
+ false, // use_fd
+ [&](const OatFile& oat_file) {
+ EXPECT_NE(oat_file.GetClassLoaderContext(), stored_context) << output_;
+ EXPECT_NE(oat_file.GetClassLoaderContext(), valid_context) << output_;
+ });
+ // The stored context should match what we expect even though it's invalid.
+ GenerateOdexForTest(GetTestDexFileName("ManyMethods"),
+ odex_location,
+ CompilerFilter::Filter::kQuicken,
+ { "--class-loader-context=" + valid_context,
+ "--stored-class-loader-context=" + stored_context },
+ true, // expect_success
+ false, // use_fd
+ [&](const OatFile& oat_file) {
+ EXPECT_EQ(oat_file.GetClassLoaderContext(), expected_stored_context) << output_;
+ });
+}
+
} // namespace art
diff --git a/runtime/class_loader_context.cc b/runtime/class_loader_context.cc
index e646520..4afc44c 100644
--- a/runtime/class_loader_context.cc
+++ b/runtime/class_loader_context.cc
@@ -254,6 +254,7 @@
// This will allow the context to VerifyClassLoaderContextMatch which expects or multidex
// location in the class paths.
// Note that this will also remove the paths that could not be opened.
+ info.original_classpath = std::move(info.classpath);
info.classpath.clear();
info.checksums.clear();
for (size_t k = opened_dex_files_index; k < info.opened_dex_files.size(); k++) {
@@ -294,20 +295,26 @@
}
std::string ClassLoaderContext::EncodeContextForDex2oat(const std::string& base_dir) const {
- return EncodeContext(base_dir, /*for_dex2oat*/ true);
+ return EncodeContext(base_dir, /*for_dex2oat*/ true, /*stored_context*/ nullptr);
}
-std::string ClassLoaderContext::EncodeContextForOatFile(const std::string& base_dir) const {
- return EncodeContext(base_dir, /*for_dex2oat*/ false);
+std::string ClassLoaderContext::EncodeContextForOatFile(const std::string& base_dir,
+ ClassLoaderContext* stored_context) const {
+ return EncodeContext(base_dir, /*for_dex2oat*/ false, stored_context);
}
std::string ClassLoaderContext::EncodeContext(const std::string& base_dir,
- bool for_dex2oat) const {
+ bool for_dex2oat,
+ ClassLoaderContext* stored_context) const {
CheckDexFilesOpened("EncodeContextForOatFile");
if (special_shared_library_) {
return OatFile::kSpecialSharedLibrary;
}
+ if (stored_context != nullptr) {
+ DCHECK_EQ(class_loader_chain_.size(), stored_context->class_loader_chain_.size());
+ }
+
std::ostringstream out;
if (class_loader_chain_.empty()) {
// We can get in this situation if the context was created with a class path containing the
@@ -326,6 +333,15 @@
out << GetClassLoaderTypeName(info.type);
out << kClassLoaderOpeningMark;
std::set<std::string> seen_locations;
+ SafeMap<std::string, std::string> remap;
+ if (stored_context != nullptr) {
+ DCHECK_EQ(info.original_classpath.size(),
+ stored_context->class_loader_chain_[i].classpath.size());
+ for (size_t k = 0; k < info.original_classpath.size(); ++k) {
+ // Note that we don't care if the same name appears twice.
+ remap.Put(info.original_classpath[k], stored_context->class_loader_chain_[i].classpath[k]);
+ }
+ }
for (size_t k = 0; k < info.opened_dex_files.size(); k++) {
const std::unique_ptr<const DexFile>& dex_file = info.opened_dex_files[k];
if (for_dex2oat) {
@@ -337,7 +353,14 @@
continue;
}
}
- const std::string& location = dex_file->GetLocation();
+ std::string location = dex_file->GetLocation();
+ // If there is a stored class loader remap, fix up the multidex strings.
+ if (!remap.empty()) {
+ std::string base_dex_location = DexFileLoader::GetBaseLocation(location);
+ auto it = remap.find(base_dex_location);
+ CHECK(it != remap.end()) << base_dex_location;
+ location = it->second + DexFileLoader::GetMultiDexSuffix(location);
+ }
if (k > 0) {
out << kClasspathSeparator;
}
@@ -345,7 +368,7 @@
if (!base_dir.empty() && location.substr(0, base_dir.length()) == base_dir) {
out << location.substr(base_dir.length() + 1).c_str();
} else {
- out << dex_file->GetLocation().c_str();
+ out << location.c_str();
}
// dex2oat does not need the checksums.
if (!for_dex2oat) {
@@ -649,12 +672,16 @@
return !location.empty() && location[0] == '/';
}
-bool ClassLoaderContext::VerifyClassLoaderContextMatch(const std::string& context_spec) const {
- DCHECK(dex_files_open_attempted_);
- DCHECK(dex_files_open_result_);
+bool ClassLoaderContext::VerifyClassLoaderContextMatch(const std::string& context_spec,
+ bool verify_names,
+ bool verify_checksums) const {
+ if (verify_names || verify_checksums) {
+ DCHECK(dex_files_open_attempted_);
+ DCHECK(dex_files_open_result_);
+ }
ClassLoaderContext expected_context;
- if (!expected_context.Parse(context_spec, /*parse_checksums*/ true)) {
+ if (!expected_context.Parse(context_spec, verify_checksums)) {
LOG(WARNING) << "Invalid class loader context: " << context_spec;
return false;
}
@@ -693,8 +720,14 @@
return false;
}
- DCHECK_EQ(info.classpath.size(), info.checksums.size());
- DCHECK_EQ(expected_info.classpath.size(), expected_info.checksums.size());
+ if (verify_checksums) {
+ DCHECK_EQ(info.classpath.size(), info.checksums.size());
+ DCHECK_EQ(expected_info.classpath.size(), expected_info.checksums.size());
+ }
+
+ if (!verify_names) {
+ continue;
+ }
for (size_t k = 0; k < info.classpath.size(); k++) {
// Compute the dex location that must be compared.
@@ -766,4 +799,3 @@
}
} // namespace art
-
diff --git a/runtime/class_loader_context.h b/runtime/class_loader_context.h
index 692a6cd..1c83007 100644
--- a/runtime/class_loader_context.h
+++ b/runtime/class_loader_context.h
@@ -84,9 +84,12 @@
// (so that it can be read and verified at runtime against the actual class
// loader hierarchy).
// Should only be called if OpenDexFiles() returned true.
+ // If stored context is non-null, the stored names are overwritten by the class path from the
+ // stored context.
// E.g. if the context is PCL[a.dex:b.dex] this will return
// "PCL[a.dex*a_checksum*b.dex*a_checksum]".
- std::string EncodeContextForOatFile(const std::string& base_dir) const;
+ std::string EncodeContextForOatFile(const std::string& base_dir,
+ ClassLoaderContext* stored_context = nullptr) const;
// Encodes the context as a string suitable to be passed to dex2oat.
// This is the same as EncodeContextForOatFile but without adding the checksums
@@ -104,7 +107,11 @@
// - the class loader from the same position have the same classpath
// (the order and checksum of the dex files matches)
// This should be called after OpenDexFiles().
- bool VerifyClassLoaderContextMatch(const std::string& context_spec) const;
+ // Names are only verified if verify_names is true.
+ // Checksums are only verified if verify_checksums is true.
+ bool VerifyClassLoaderContextMatch(const std::string& context_spec,
+ bool verify_names = true,
+ bool verify_checksums = true) const;
// Creates the class loader context from the given string.
// The format: ClassLoaderType1[ClasspathElem1:ClasspathElem2...];ClassLoaderType2[...]...
@@ -146,6 +153,8 @@
// The list of class path elements that this loader loads.
// Note that this list may contain relative paths.
std::vector<std::string> classpath;
+ // Original opened class path (ignoring multidex).
+ std::vector<std::string> original_classpath;
// The list of class path elements checksums.
// May be empty if the checksums are not given when the context is created.
std::vector<uint32_t> checksums;
@@ -198,7 +207,9 @@
// location). Otherwise, for oat files, the encoding adds all the dex files (including multidex)
// together with their checksums.
// Should only be called if OpenDexFiles() returned true.
- std::string EncodeContext(const std::string& base_dir, bool for_dex2oat) const;
+ std::string EncodeContext(const std::string& base_dir,
+ bool for_dex2oat,
+ ClassLoaderContext* stored_context) const;
// Extracts the class loader type from the given spec.
// Return ClassLoaderContext::kInvalidClassLoader if the class loader type is not
diff --git a/runtime/debug_print.cc b/runtime/debug_print.cc
index 6048767..7e075ce 100644
--- a/runtime/debug_print.cc
+++ b/runtime/debug_print.cc
@@ -97,14 +97,27 @@
StackHandleScope<1> hs(soa.Self());
Handle<mirror::ClassLoader> handle(hs.NewHandle(loader));
const char* path_separator = "";
- VisitClassLoaderDexFiles(soa,
- handle,
- [&](const DexFile* dex_file) {
- oss << path_separator << dex_file->GetLocation()
- << "/" << static_cast<const void*>(dex_file);
- path_separator = ":";
- return true; // Continue with the next DexFile.
- });
+ const DexFile* base_dex_file = nullptr;
+ VisitClassLoaderDexFiles(
+ soa,
+ handle,
+ [&](const DexFile* dex_file) {
+ oss << path_separator;
+ path_separator = ":";
+ if (base_dex_file != nullptr &&
+ dex_file->GetLocation().length() > base_dex_file->GetLocation().length() &&
+ dex_file->GetLocation().compare(0u,
+ base_dex_file->GetLocation().length(),
+ base_dex_file->GetLocation()) == 0) {
+ // Replace the base location with "+" to shorten the output.
+ oss << "+" << dex_file->GetLocation().substr(base_dex_file->GetLocation().length());
+ } else {
+ oss << dex_file->GetLocation();
+ base_dex_file = dex_file;
+ }
+ oss << "/" << static_cast<const void*>(dex_file);
+ return true; // Continue with the next DexFile.
+ });
oss << ")";
}
}
@@ -132,13 +145,13 @@
std::string source_descriptor_storage;
const char* source_descriptor = src_class->GetDescriptor(&source_descriptor_storage);
+ LOG(ERROR) << "Maybe bug 77342775, looking for " << target_descriptor
+ << " with loader " << DescribeLoaders(target_class->GetClassLoader(), target_descriptor);
if (target_class->IsInterface()) {
ObjPtr<mirror::IfTable> iftable = src_class->GetIfTable();
CHECK(iftable != nullptr);
size_t ifcount = iftable->Count();
- LOG(ERROR) << "Maybe bug 77342775, looking for " << target_descriptor
- << " with loader " << DescribeLoaders(target_class->GetClassLoader(), target_descriptor)
- << " in interface table for " << source_descriptor << " ifcount=" << ifcount
+ LOG(ERROR) << " in interface table for " << source_descriptor << " ifcount=" << ifcount
<< " with loader " << DescribeLoaders(src_class->GetClassLoader(), source_descriptor);
for (size_t i = 0; i != ifcount; ++i) {
ObjPtr<mirror::Class> iface = iftable->GetInterface(i);
@@ -147,9 +160,7 @@
matcher(iface);
}
} else {
- LOG(ERROR) << "Maybe bug 77342775, looking for " << target_descriptor
- << " with loader " << DescribeLoaders(target_class->GetClassLoader(), target_descriptor)
- << " in superclass chain for " << source_descriptor
+ LOG(ERROR) << " in superclass chain for " << source_descriptor
<< " with loader " << DescribeLoaders(src_class->GetClassLoader(), source_descriptor);
for (ObjPtr<mirror::Class> klass = src_class;
klass != nullptr;
diff --git a/test/682-double-catch-phi/expected.txt b/test/682-double-catch-phi/expected.txt
new file mode 100644
index 0000000..b0aad4d
--- /dev/null
+++ b/test/682-double-catch-phi/expected.txt
@@ -0,0 +1 @@
+passed
diff --git a/test/682-double-catch-phi/info.txt b/test/682-double-catch-phi/info.txt
new file mode 100644
index 0000000..0ef2e59
--- /dev/null
+++ b/test/682-double-catch-phi/info.txt
@@ -0,0 +1 @@
+Regression test on double-typed catch phi
diff --git a/test/682-double-catch-phi/smali/DoubleCatchPhi.smali b/test/682-double-catch-phi/smali/DoubleCatchPhi.smali
new file mode 100644
index 0000000..1d3f927
--- /dev/null
+++ b/test/682-double-catch-phi/smali/DoubleCatchPhi.smali
@@ -0,0 +1,47 @@
+# Copyright (C) 2018 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.
+
+.class public LDoubleCatchPhi;
+
+.super Ljava/lang/Object;
+
+.field public mValue:D
+
+.method public constructor <init>()V
+.registers 1
+ invoke-direct {v0}, Ljava/lang/Object;-><init>()V
+ return-void
+.end method
+
+.method public strangeMethod(F)V
+.registers 6
+ move-object v2, v4
+ monitor-enter v4
+:try_start1
+ float-to-double v0, v5
+ iput-wide v0, v4, LDoubleCatchPhi;->mValue:D
+ monitor-exit v2
+:try_end1
+ goto :end_catch
+:catch
+:try_start2
+ move-exception v3
+ monitor-exit v2
+:try_end2
+ throw v3
+:end_catch
+ return-void
+.catchall {:try_start1 .. :try_end1} :catch
+.catchall {:try_start2 .. :try_end2} :catch
+.end method
diff --git a/test/682-double-catch-phi/src/Main.java b/test/682-double-catch-phi/src/Main.java
new file mode 100644
index 0000000..e65bf0d
--- /dev/null
+++ b/test/682-double-catch-phi/src/Main.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+import java.lang.reflect.Method;
+
+public class Main {
+ public static void main(String[] args) throws Exception {
+ if (System.getProperty("java.vm.name").equals("Dalvik")) {
+ Class<?> c = Class.forName("DoubleCatchPhi");
+ }
+ System.out.println("passed");
+ }
+}
diff --git a/tools/veridex/flow_analysis.cc b/tools/veridex/flow_analysis.cc
index abd0b9b..a4553f9 100644
--- a/tools/veridex/flow_analysis.cc
+++ b/tools/veridex/flow_analysis.cc
@@ -41,7 +41,11 @@
bool VeriFlowAnalysis::MergeRegisterValues(uint32_t dex_pc) {
// TODO: Do the merging. Right now, just return that we should continue
// the iteration if the instruction has not been visited.
- return !instruction_infos_[dex_pc].has_been_visited;
+ if (!instruction_infos_[dex_pc].has_been_visited) {
+ dex_registers_[dex_pc]->assign(current_registers_.begin(), current_registers_.end());
+ return true;
+ }
+ return false;
}
void VeriFlowAnalysis::SetVisited(uint32_t dex_pc) {
@@ -260,6 +264,10 @@
RegisterValue obj = GetRegister(args[0]);
last_result_ = RegisterValue(
obj.GetSource(), obj.GetDexFileReference(), VeriClass::class_);
+ } else if (method == VeriClass::loadClass_) {
+ RegisterValue value = GetRegister(args[1]);
+ last_result_ = RegisterValue(
+ value.GetSource(), value.GetDexFileReference(), VeriClass::class_);
} else {
last_result_ = GetReturnType(instruction.VRegB_35c());
}
diff --git a/tools/veridex/flow_analysis.h b/tools/veridex/flow_analysis.h
index c065fb8..80ae5fc 100644
--- a/tools/veridex/flow_analysis.h
+++ b/tools/veridex/flow_analysis.h
@@ -20,6 +20,7 @@
#include "dex/code_item_accessors.h"
#include "dex/dex_file_reference.h"
#include "dex/method_reference.h"
+#include "hidden_api.h"
#include "veridex.h"
namespace art {
@@ -52,10 +53,19 @@
DexFileReference GetDexFileReference() const { return reference_; }
const VeriClass* GetType() const { return type_; }
- const char* ToString() const {
+ std::string ToString() const {
switch (source_) {
- case RegisterSource::kString:
- return reference_.dex_file->StringDataByIdx(dex::StringIndex(reference_.index));
+ case RegisterSource::kString: {
+ const char* str = reference_.dex_file->StringDataByIdx(dex::StringIndex(reference_.index));
+ if (type_ == VeriClass::class_) {
+ // Class names at the Java level are of the form x.y.z, but the list encodes
+ // them of the form Lx/y/z;. Inner classes have '$' for both Java level class
+ // names in strings, and hidden API lists.
+ return HiddenApi::ToInternalName(str);
+ } else {
+ return str;
+ }
+ }
case RegisterSource::kClass:
return reference_.dex_file->StringByTypeIdx(dex::TypeIndex(reference_.index));
default:
diff --git a/tools/veridex/hidden_api.h b/tools/veridex/hidden_api.h
index 4c67768..b1c8559 100644
--- a/tools/veridex/hidden_api.h
+++ b/tools/veridex/hidden_api.h
@@ -63,6 +63,12 @@
return HiddenApi::GetApiMethodName(*ref.dex_file, ref.index);
}
+ static std::string ToInternalName(const std::string& str) {
+ std::string val = str;
+ std::replace(val.begin(), val.end(), '.', '/');
+ return "L" + val + ";";
+ }
+
private:
static bool IsInList(const std::string& name, const std::set<std::string>& list) {
return list.find(name) != list.end();
diff --git a/tools/veridex/hidden_api_finder.cc b/tools/veridex/hidden_api_finder.cc
index b9be618..b1ae7dd 100644
--- a/tools/veridex/hidden_api_finder.cc
+++ b/tools/veridex/hidden_api_finder.cc
@@ -95,9 +95,7 @@
// Class names at the Java level are of the form x.y.z, but the list encodes
// them of the form Lx/y/z;. Inner classes have '$' for both Java level class
// names in strings, and hidden API lists.
- std::string str = name;
- std::replace(str.begin(), str.end(), '.', '/');
- str = "L" + str + ";";
+ std::string str = HiddenApi::ToInternalName(name);
// Note: we can query the lists directly, as HiddenApi added classes that own
// private methods and fields in them.
// We don't add class names to the `strings_` set as we know method/field names
diff --git a/tools/veridex/veridex.cc b/tools/veridex/veridex.cc
index 6e72faa..dc7ea94 100644
--- a/tools/veridex/veridex.cc
+++ b/tools/veridex/veridex.cc
@@ -52,6 +52,7 @@
// Will be set after boot classpath has been resolved.
VeriClass* VeriClass::object_ = nullptr;
VeriClass* VeriClass::class_ = nullptr;
+VeriClass* VeriClass::class_loader_ = nullptr;
VeriClass* VeriClass::string_ = nullptr;
VeriClass* VeriClass::throwable_ = nullptr;
VeriMethod VeriClass::forName_ = nullptr;
@@ -60,6 +61,7 @@
VeriMethod VeriClass::getMethod_ = nullptr;
VeriMethod VeriClass::getDeclaredMethod_ = nullptr;
VeriMethod VeriClass::getClass_ = nullptr;
+VeriMethod VeriClass::loadClass_ = nullptr;
struct VeridexOptions {
const char* dex_file = nullptr;
@@ -176,6 +178,7 @@
// methods.
VeriClass::object_ = type_map["Ljava/lang/Object;"];
VeriClass::class_ = type_map["Ljava/lang/Class;"];
+ VeriClass::class_loader_ = type_map["Ljava/lang/ClassLoader;"];
VeriClass::string_ = type_map["Ljava/lang/String;"];
VeriClass::throwable_ = type_map["Ljava/lang/Throwable;"];
VeriClass::forName_ = boot_resolvers[0]->LookupDeclaredMethodIn(
@@ -194,6 +197,8 @@
"(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;");
VeriClass::getClass_ = boot_resolvers[0]->LookupDeclaredMethodIn(
*VeriClass::object_, "getClass", "()Ljava/lang/Class;");
+ VeriClass::loadClass_ = boot_resolvers[0]->LookupDeclaredMethodIn(
+ *VeriClass::class_loader_, "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;");
std::vector<std::unique_ptr<VeridexResolver>> app_resolvers;
Resolve(app_dex_files, resolver_map, type_map, &app_resolvers);
diff --git a/tools/veridex/veridex.h b/tools/veridex/veridex.h
index 75e4845..9c0a158 100644
--- a/tools/veridex/veridex.h
+++ b/tools/veridex/veridex.h
@@ -65,6 +65,7 @@
static VeriClass* object_;
static VeriClass* class_;
+ static VeriClass* class_loader_;
static VeriClass* string_;
static VeriClass* throwable_;
static VeriClass* boolean_;
@@ -83,6 +84,7 @@
static VeriMethod getMethod_;
static VeriMethod getDeclaredMethod_;
static VeriMethod getClass_;
+ static VeriMethod loadClass_;
private:
Primitive::Type kind_;