Merge "Use the rel_pc instead of computing it."
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index b3160dd..f3718c4 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -291,7 +291,6 @@
instruction_set_(instruction_set == kArm ? kThumb2 : instruction_set),
instruction_set_features_(instruction_set_features),
requires_constructor_barrier_lock_("constructor barrier lock"),
- compiled_classes_lock_("compiled classes lock"),
non_relative_linker_patch_count_(0u),
image_classes_(image_classes),
classes_to_compile_(compiled_classes),
@@ -1947,7 +1946,12 @@
if (compiler_only_verifies) {
// Just update the compiled_classes_ map. The compiler doesn't need to resolve
// the type.
- compiled_classes_.Overwrite(ClassReference(dex_file, i), mirror::Class::kStatusVerified);
+ DexFileReference ref(dex_file, i);
+ mirror::Class::Status existing = mirror::Class::kStatusNotReady;
+ DCHECK(compiled_classes_.Get(ref, &existing)) << ref.dex_file->GetLocation();
+ ClassStateTable::InsertResult result =
+ compiled_classes_.Insert(ref, existing, mirror::Class::kStatusVerified);
+ CHECK_EQ(result, ClassStateTable::kInsertResultSuccess);
} else {
// Update the class status, so later compilation stages know they don't need to verify
// the class.
@@ -1978,6 +1982,13 @@
void CompilerDriver::Verify(jobject jclass_loader,
const std::vector<const DexFile*>& dex_files,
TimingLogger* timings) {
+ // Always add the dex files to compiled_classes_. This happens for all compiler filters.
+ for (const DexFile* dex_file : dex_files) {
+ if (!compiled_classes_.HaveDexFile(dex_file)) {
+ compiled_classes_.AddDexFile(dex_file, dex_file->NumClassDefs());
+ }
+ }
+
if (FastVerify(jclass_loader, dex_files, timings)) {
return;
}
@@ -2202,6 +2213,9 @@
size_t thread_count,
TimingLogger* timings) {
TimingLogger::ScopedTiming t("Verify Dex File", timings);
+ if (!compiled_classes_.HaveDexFile(&dex_file)) {
+ compiled_classes_.AddDexFile(&dex_file, dex_file.NumClassDefs());
+ }
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
ParallelCompilationManager context(class_linker, class_loader, this, &dex_file, dex_files,
thread_pool);
@@ -2248,12 +2262,13 @@
const bool is_app_image = manager_->GetCompiler()->GetCompilerOptions().IsAppImage();
mirror::Class::Status old_status = klass->GetStatus();
+ // Don't initialize classes in boot space when compiling app image
+ if (is_app_image && klass->IsBootStrapClassLoaded()) {
+ // Also return early and don't store the class status in the recorded class status.
+ return;
+ }
// Only try to initialize classes that were successfully verified.
if (klass->IsVerified()) {
- // Don't initialize classes in boot space when compiling app image
- if (is_app_image && klass->IsBootStrapClassLoaded()) {
- return;
- }
// Attempt to initialize the class but bail if we either need to initialize the super-class
// or static fields.
manager_->GetClassLinker()->EnsureInitialized(soa.Self(), klass, false, false);
@@ -2860,12 +2875,12 @@
bool CompilerDriver::GetCompiledClass(ClassReference ref, mirror::Class::Status* status) const {
DCHECK(status != nullptr);
- MutexLock mu(Thread::Current(), compiled_classes_lock_);
- ClassStateTable::const_iterator it = compiled_classes_.find(ref);
- if (it == compiled_classes_.end()) {
+ // The table doesn't know if something wasn't inserted. For this case it will return
+ // kStatusNotReady. To handle this, just assume anything not verified is not compiled.
+ if (!compiled_classes_.Get(DexFileReference(ref.first, ref.second), status) ||
+ *status < mirror::Class::kStatusVerified) {
return false;
}
- *status = it->second;
return true;
}
@@ -2886,15 +2901,20 @@
<< " of " << status;
}
- MutexLock mu(Thread::Current(), compiled_classes_lock_);
- auto it = compiled_classes_.find(ref);
- if (it == compiled_classes_.end()) {
- compiled_classes_.Overwrite(ref, status);
- } else if (status > it->second) {
+ ClassStateTable::InsertResult result;
+ do {
+ DexFileReference dex_ref(ref.first, ref.second);
+ mirror::Class::Status existing = mirror::Class::kStatusNotReady;
+ CHECK(compiled_classes_.Get(dex_ref, &existing)) << dex_ref.dex_file->GetLocation();
+ if (existing >= status) {
+ // Existing status is already better than we expect, break.
+ break;
+ }
// Update the status if we now have a greater one. This happens with vdex,
// which records a class is verified, but does not resolve it.
- it->second = status;
- }
+ result = compiled_classes_.Insert(dex_ref, existing, status);
+ CHECK(result != ClassStateTable::kInsertResultInvalidDexFile);
+ } while (result != ClassStateTable::kInsertResultSuccess);
}
CompiledMethod* CompilerDriver::GetCompiledMethod(MethodReference ref) const {
diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h
index a3272d3..93234cb 100644
--- a/compiler/driver/compiler_driver.h
+++ b/compiler/driver/compiler_driver.h
@@ -117,12 +117,12 @@
void CompileAll(jobject class_loader,
const std::vector<const DexFile*>& dex_files,
TimingLogger* timings)
- REQUIRES(!Locks::mutator_lock_, !compiled_classes_lock_, !dex_to_dex_references_lock_);
+ REQUIRES(!Locks::mutator_lock_, !dex_to_dex_references_lock_);
// Compile a single Method.
void CompileOne(Thread* self, ArtMethod* method, TimingLogger* timings)
REQUIRES_SHARED(Locks::mutator_lock_)
- REQUIRES(!compiled_classes_lock_, !dex_to_dex_references_lock_);
+ REQUIRES(!dex_to_dex_references_lock_);
VerificationResults* GetVerificationResults() const;
@@ -153,8 +153,7 @@
std::unique_ptr<const std::vector<uint8_t>> CreateQuickResolutionTrampoline() const;
std::unique_ptr<const std::vector<uint8_t>> CreateQuickToInterpreterBridge() const;
- bool GetCompiledClass(ClassReference ref, mirror::Class::Status* status) const
- REQUIRES(!compiled_classes_lock_);
+ bool GetCompiledClass(ClassReference ref, mirror::Class::Status* status) const;
CompiledMethod* GetCompiledMethod(MethodReference ref) const;
size_t GetNonRelativeLinkerPatchCount() const;
@@ -337,8 +336,7 @@
// according to the profile file.
bool ShouldVerifyClassBasedOnProfile(const DexFile& dex_file, uint16_t class_idx) const;
- void RecordClassStatus(ClassReference ref, mirror::Class::Status status)
- REQUIRES(!compiled_classes_lock_);
+ void RecordClassStatus(ClassReference ref, mirror::Class::Status status);
// Checks if the specified method has been verified without failures. Returns
// false if the method is not in the verification results (GetVerificationResults).
@@ -387,7 +385,7 @@
void PreCompile(jobject class_loader,
const std::vector<const DexFile*>& dex_files,
TimingLogger* timings)
- REQUIRES(!Locks::mutator_lock_, !compiled_classes_lock_);
+ REQUIRES(!Locks::mutator_lock_);
void LoadImageClasses(TimingLogger* timings) REQUIRES(!Locks::mutator_lock_);
@@ -408,12 +406,9 @@
// Do fast verification through VerifierDeps if possible. Return whether
// verification was successful.
- // NO_THREAD_SAFETY_ANALYSIS as the method accesses a guarded value in a
- // single-threaded way.
bool FastVerify(jobject class_loader,
const std::vector<const DexFile*>& dex_files,
- TimingLogger* timings)
- NO_THREAD_SAFETY_ANALYSIS;
+ TimingLogger* timings);
void Verify(jobject class_loader,
const std::vector<const DexFile*>& dex_files,
@@ -441,12 +436,12 @@
void InitializeClasses(jobject class_loader,
const std::vector<const DexFile*>& dex_files,
TimingLogger* timings)
- REQUIRES(!Locks::mutator_lock_, !compiled_classes_lock_);
+ REQUIRES(!Locks::mutator_lock_);
void InitializeClasses(jobject class_loader,
const DexFile& dex_file,
const std::vector<const DexFile*>& dex_files,
TimingLogger* timings)
- REQUIRES(!Locks::mutator_lock_, !compiled_classes_lock_);
+ REQUIRES(!Locks::mutator_lock_);
void UpdateImageClasses(TimingLogger* timings) REQUIRES(!Locks::mutator_lock_);
@@ -484,10 +479,9 @@
std::map<ClassReference, bool> requires_constructor_barrier_
GUARDED_BY(requires_constructor_barrier_lock_);
- using ClassStateTable = SafeMap<const ClassReference, mirror::Class::Status>;
- // All class references that this compiler has compiled.
- mutable Mutex compiled_classes_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
- ClassStateTable compiled_classes_ GUARDED_BY(compiled_classes_lock_);
+ // All class references that this compiler has compiled. Indexed by class defs.
+ using ClassStateTable = AtomicDexRefMap<mirror::Class::Status>;
+ ClassStateTable compiled_classes_;
typedef AtomicDexRefMap<CompiledMethod*> MethodTable;
diff --git a/dalvikvm/dalvikvm.cc b/dalvikvm/dalvikvm.cc
index dcb49a0..e735e2f 100644
--- a/dalvikvm/dalvikvm.cc
+++ b/dalvikvm/dalvikvm.cc
@@ -21,8 +21,8 @@
#include <algorithm>
#include <memory>
-#include "JniInvocation.h"
#include "jni.h"
+#include "nativehelper/JniInvocation.h"
#include "nativehelper/ScopedLocalRef.h"
#include "nativehelper/toStringArray.h"
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index b5d3736..0ef496f 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -1787,7 +1787,7 @@
for (const DexFile* dex_file : *dex_file_vector) {
for (const std::string& filter : no_inline_filters) {
// Use dex_file->GetLocation() rather than dex_file->GetBaseLocation(). This
- // allows tests to specify <test-dexfile>:classes2.dex if needed but if the
+ // allows tests to specify <test-dexfile>!classes2.dex if needed but if the
// base location passes the StartsWith() test, so do all extra locations.
std::string dex_location = dex_file->GetLocation();
if (filter.find('/') == std::string::npos) {
diff --git a/runtime/atomic.h b/runtime/atomic.h
index 25dd1a3..09eae40 100644
--- a/runtime/atomic.h
+++ b/runtime/atomic.h
@@ -187,7 +187,7 @@
template<typename T>
class PACKED(sizeof(T)) Atomic : public std::atomic<T> {
public:
- Atomic<T>() : std::atomic<T>(0) { }
+ Atomic<T>() : std::atomic<T>(T()) { }
explicit Atomic<T>(T value) : std::atomic<T>(value) { }
diff --git a/runtime/class_loader_context_test.cc b/runtime/class_loader_context_test.cc
index 1b46f67..a87552d 100644
--- a/runtime/class_loader_context_test.cc
+++ b/runtime/class_loader_context_test.cc
@@ -488,4 +488,12 @@
ASSERT_TRUE(context->VerifyClassLoaderContextMatch(context->EncodeContextForOatFile("")));
}
+TEST_F(ClassLoaderContextTest, VerifyClassLoaderContextMatchAfterEncodingMultidex) {
+ jobject class_loader = LoadDexInPathClassLoader("MultiDex", nullptr);
+
+ std::unique_ptr<ClassLoaderContext> context = CreateContextForClassLoader(class_loader);
+
+ ASSERT_TRUE(context->VerifyClassLoaderContextMatch(context->EncodeContextForOatFile("")));
+}
+
} // namespace art
diff --git a/runtime/dex_file.h b/runtime/dex_file.h
index eb3b210..990ab11 100644
--- a/runtime/dex_file.h
+++ b/runtime/dex_file.h
@@ -62,11 +62,11 @@
static const uint16_t kDexNoIndex16 = 0xFFFF;
// The separator character in MultiDex locations.
- static constexpr char kMultiDexSeparator = ':';
+ static constexpr char kMultiDexSeparator = '!';
// A string version of the previous. This is a define so that we can merge string literals in the
// preprocessor.
- #define kMultiDexSeparatorString ":"
+ #define kMultiDexSeparatorString "!"
// Raw header_item.
struct Header {
@@ -499,7 +499,7 @@
return GetBaseLocation(location.c_str());
}
- // Returns the ':classes*.dex' part of the dex location. Returns an empty
+ // Returns the '!classes*.dex' part of the dex location. Returns an empty
// string if there is no multidex suffix for the given location.
// The kMultiDexSeparator is included in the returned suffix.
static std::string GetMultiDexSuffix(const std::string& location) {
diff --git a/runtime/dex_file_test.cc b/runtime/dex_file_test.cc
index 78d5c5f..1a73062 100644
--- a/runtime/dex_file_test.cc
+++ b/runtime/dex_file_test.cc
@@ -535,9 +535,9 @@
std::string dex_location_str = "/system/app/framework.jar";
const char* dex_location = dex_location_str.c_str();
ASSERT_EQ("/system/app/framework.jar", DexFile::GetMultiDexLocation(0, dex_location));
- ASSERT_EQ("/system/app/framework.jar:classes2.dex",
+ ASSERT_EQ("/system/app/framework.jar!classes2.dex",
DexFile::GetMultiDexLocation(1, dex_location));
- ASSERT_EQ("/system/app/framework.jar:classes101.dex",
+ ASSERT_EQ("/system/app/framework.jar!classes101.dex",
DexFile::GetMultiDexLocation(100, dex_location));
}
@@ -563,11 +563,11 @@
TEST(DexFileUtilsTest, GetBaseLocationAndMultiDexSuffix) {
EXPECT_EQ("/foo/bar/baz.jar", DexFile::GetBaseLocation("/foo/bar/baz.jar"));
- EXPECT_EQ("/foo/bar/baz.jar", DexFile::GetBaseLocation("/foo/bar/baz.jar:classes2.dex"));
- EXPECT_EQ("/foo/bar/baz.jar", DexFile::GetBaseLocation("/foo/bar/baz.jar:classes8.dex"));
+ EXPECT_EQ("/foo/bar/baz.jar", DexFile::GetBaseLocation("/foo/bar/baz.jar!classes2.dex"));
+ EXPECT_EQ("/foo/bar/baz.jar", DexFile::GetBaseLocation("/foo/bar/baz.jar!classes8.dex"));
EXPECT_EQ("", DexFile::GetMultiDexSuffix("/foo/bar/baz.jar"));
- EXPECT_EQ(":classes2.dex", DexFile::GetMultiDexSuffix("/foo/bar/baz.jar:classes2.dex"));
- EXPECT_EQ(":classes8.dex", DexFile::GetMultiDexSuffix("/foo/bar/baz.jar:classes8.dex"));
+ EXPECT_EQ("!classes2.dex", DexFile::GetMultiDexSuffix("/foo/bar/baz.jar!classes2.dex"));
+ EXPECT_EQ("!classes8.dex", DexFile::GetMultiDexSuffix("/foo/bar/baz.jar!classes8.dex"));
}
TEST_F(DexFileTest, ZipOpenClassesPresent) {
diff --git a/runtime/jit/jit.cc b/runtime/jit/jit.cc
index 969a570..7abf52e 100644
--- a/runtime/jit/jit.cc
+++ b/runtime/jit/jit.cc
@@ -20,6 +20,7 @@
#include "art_method-inl.h"
#include "base/enums.h"
+#include "base/logging.h"
#include "base/memory_tool.h"
#include "debugger.h"
#include "entrypoints/runtime_asm_entrypoints.h"
@@ -45,6 +46,11 @@
// At what priority to schedule jit threads. 9 is the lowest foreground priority on device.
static constexpr int kJitPoolThreadPthreadPriority = 9;
+// Different compilation threshold constants. These can be overridden on the command line.
+static constexpr size_t kJitDefaultCompileThreshold = 10000; // Non-debug default.
+static constexpr size_t kJitStressDefaultCompileThreshold = 100; // Fast-debug build.
+static constexpr size_t kJitSlowStressDefaultCompileThreshold = 2; // Slow-debug build.
+
// JIT compiler
void* Jit::jit_library_handle_= nullptr;
void* Jit::jit_compiler_handle_ = nullptr;
@@ -54,6 +60,11 @@
void (*Jit::jit_types_loaded_)(void*, mirror::Class**, size_t count) = nullptr;
bool Jit::generate_debug_info_ = false;
+struct StressModeHelper {
+ DECLARE_RUNTIME_DEBUG_FLAG(kSlowMode);
+};
+DEFINE_RUNTIME_DEBUG_FLAG(StressModeHelper, kSlowMode);
+
JitOptions* JitOptions::CreateFromRuntimeArguments(const RuntimeArgumentMap& options) {
auto* jit_options = new JitOptions;
jit_options->use_jit_compilation_ = options.GetOrDefault(RuntimeArgumentMap::UseJitCompilation);
@@ -67,7 +78,16 @@
jit_options->profile_saver_options_ =
options.GetOrDefault(RuntimeArgumentMap::ProfileSaverOpts);
- jit_options->compile_threshold_ = options.GetOrDefault(RuntimeArgumentMap::JITCompileThreshold);
+ if (options.Exists(RuntimeArgumentMap::JITCompileThreshold)) {
+ jit_options->compile_threshold_ = *options.Get(RuntimeArgumentMap::JITCompileThreshold);
+ } else {
+ jit_options->compile_threshold_ =
+ kIsDebugBuild
+ ? (StressModeHelper::kSlowMode
+ ? kJitSlowStressDefaultCompileThreshold
+ : kJitStressDefaultCompileThreshold)
+ : kJitDefaultCompileThreshold;
+ }
if (jit_options->compile_threshold_ > std::numeric_limits<uint16_t>::max()) {
LOG(FATAL) << "Method compilation threshold is above its internal limit.";
}
diff --git a/runtime/jit/jit.h b/runtime/jit/jit.h
index f898d41..51e49ec 100644
--- a/runtime/jit/jit.h
+++ b/runtime/jit/jit.h
@@ -48,8 +48,6 @@
class Jit {
public:
- static constexpr bool kStressMode = kIsDebugBuild;
- static constexpr size_t kDefaultCompileThreshold = kStressMode ? 2 : 10000;
static constexpr size_t kDefaultPriorityThreadWeightRatio = 1000;
static constexpr size_t kDefaultInvokeTransitionWeightRatio = 500;
// How frequently should the interpreter check to see if OSR compilation is ready.
diff --git a/runtime/jit/profile_compilation_info.cc b/runtime/jit/profile_compilation_info.cc
index a247b56..45c3792 100644
--- a/runtime/jit/profile_compilation_info.cc
+++ b/runtime/jit/profile_compilation_info.cc
@@ -47,9 +47,8 @@
namespace art {
const uint8_t ProfileCompilationInfo::kProfileMagic[] = { 'p', 'r', 'o', '\0' };
-// Last profile version: Move startup methods to use a bitmap. Also add support for post-startup
-// methods.
-const uint8_t ProfileCompilationInfo::kProfileVersion[] = { '0', '0', '8', '\0' };
+// Last profile version: update the multidex separator.
+const uint8_t ProfileCompilationInfo::kProfileVersion[] = { '0', '0', '9', '\0' };
static constexpr uint16_t kMaxDexFileKeyLength = PATH_MAX;
@@ -1341,7 +1340,7 @@
os << "ProfileInfo:";
- const std::string kFirstDexFileKeySubstitute = ":classes.dex";
+ const std::string kFirstDexFileKeySubstitute = "!classes.dex";
for (const DexFileData* dex_data : info_) {
os << "\n";
diff --git a/runtime/native/java_lang_VMClassLoader.cc b/runtime/native/java_lang_VMClassLoader.cc
index 745d09d..4034e8c 100644
--- a/runtime/native/java_lang_VMClassLoader.cc
+++ b/runtime/native/java_lang_VMClassLoader.cc
@@ -134,7 +134,7 @@
for (size_t i = 0; i < path.size(); ++i) {
const DexFile* dex_file = path[i];
- // For multidex locations, e.g., x.jar:classes2.dex, we want to look into x.jar.
+ // For multidex locations, e.g., x.jar!classes2.dex, we want to look into x.jar.
const std::string& location(dex_file->GetBaseLocation());
ScopedLocalRef<jstring> javaPath(env, env->NewStringUTF(location.c_str()));
diff --git a/runtime/oat.h b/runtime/oat.h
index f4edb16..de4b942 100644
--- a/runtime/oat.h
+++ b/runtime/oat.h
@@ -32,8 +32,8 @@
class PACKED(4) OatHeader {
public:
static constexpr uint8_t kOatMagic[] = { 'o', 'a', 't', '\n' };
- // Last oat version changed reason: add new class status to skip superclass validation.
- static constexpr uint8_t kOatVersion[] = { '1', '2', '9', '\0' };
+ // Last oat version changed reason: update kMultiDexSeparator from ':' to '!'.
+ static constexpr uint8_t kOatVersion[] = { '1', '3', '0', '\0' };
static constexpr const char* kImageLocationKey = "image-location";
static constexpr const char* kDex2OatCmdLineKey = "dex2oat-cmdline";
diff --git a/runtime/oat_file.h b/runtime/oat_file.h
index b112b84..be7d495 100644
--- a/runtime/oat_file.h
+++ b/runtime/oat_file.h
@@ -289,8 +289,8 @@
// If not null, abs_dex_location is used to resolve the absolute dex
// location of relative dex locations encoded in the oat file.
// For example, given absolute location "/data/app/foo/base.apk", encoded
- // dex locations "base.apk", "base.apk:classes2.dex", etc. would be resolved
- // to "/data/app/foo/base.apk", "/data/app/foo/base.apk:classes2.dex", etc.
+ // dex locations "base.apk", "base.apk!classes2.dex", etc. would be resolved
+ // to "/data/app/foo/base.apk", "/data/app/foo/base.apk!classes2.dex", etc.
// Relative encoded dex locations that don't match the given abs_dex_location
// are left unchanged.
static std::string ResolveRelativeEncodedDexLocation(
diff --git a/runtime/oat_file_test.cc b/runtime/oat_file_test.cc
index d5fe1f3..7bf0f84 100644
--- a/runtime/oat_file_test.cc
+++ b/runtime/oat_file_test.cc
@@ -45,13 +45,13 @@
OatFile::ResolveRelativeEncodedDexLocation(
"/data/app/foo/base.apk", "foo/base.apk"));
- EXPECT_EQ(std::string("/data/app/foo/base.apk:classes2.dex"),
+ EXPECT_EQ(std::string("/data/app/foo/base.apk!classes2.dex"),
OatFile::ResolveRelativeEncodedDexLocation(
- "/data/app/foo/base.apk", "base.apk:classes2.dex"));
+ "/data/app/foo/base.apk", "base.apk!classes2.dex"));
- EXPECT_EQ(std::string("/data/app/foo/base.apk:classes11.dex"),
+ EXPECT_EQ(std::string("/data/app/foo/base.apk!classes11.dex"),
OatFile::ResolveRelativeEncodedDexLocation(
- "/data/app/foo/base.apk", "base.apk:classes11.dex"));
+ "/data/app/foo/base.apk", "base.apk!classes11.dex"));
EXPECT_EQ(std::string("base.apk"),
OatFile::ResolveRelativeEncodedDexLocation(
diff --git a/runtime/openjdkjvmti/ti_redefine.cc b/runtime/openjdkjvmti/ti_redefine.cc
index e68a657..533a3c8 100644
--- a/runtime/openjdkjvmti/ti_redefine.cc
+++ b/runtime/openjdkjvmti/ti_redefine.cc
@@ -1368,7 +1368,7 @@
const art::DexFile::TypeId& declaring_class_id = dex_file_->GetTypeId(class_def.class_idx_);
const art::DexFile& old_dex_file = mclass->GetDexFile();
// Update methods.
- for (art::ArtMethod& method : mclass->GetMethods(image_pointer_size)) {
+ for (art::ArtMethod& method : mclass->GetDeclaredMethods(image_pointer_size)) {
const art::DexFile::StringId* new_name_id = dex_file_->FindStringId(method.GetName());
art::dex::TypeIndex method_return_idx =
dex_file_->GetIndexForTypeId(*dex_file_->FindTypeId(method.GetReturnTypeDescriptor()));
diff --git a/runtime/runtime_options.def b/runtime/runtime_options.def
index 09a200a..78a60fa 100644
--- a/runtime/runtime_options.def
+++ b/runtime/runtime_options.def
@@ -70,7 +70,7 @@
RUNTIME_OPTIONS_KEY (bool, EnableHSpaceCompactForOOM, true)
RUNTIME_OPTIONS_KEY (bool, UseJitCompilation, false)
RUNTIME_OPTIONS_KEY (bool, DumpNativeStackOnSigQuit, true)
-RUNTIME_OPTIONS_KEY (unsigned int, JITCompileThreshold, jit::Jit::kDefaultCompileThreshold)
+RUNTIME_OPTIONS_KEY (unsigned int, JITCompileThreshold)
RUNTIME_OPTIONS_KEY (unsigned int, JITWarmupThreshold)
RUNTIME_OPTIONS_KEY (unsigned int, JITOsrThreshold)
RUNTIME_OPTIONS_KEY (unsigned int, JITPriorityThreadWeight)
diff --git a/test/1910-transform-with-default/expected.txt b/test/1910-transform-with-default/expected.txt
new file mode 100644
index 0000000..f43ef61
--- /dev/null
+++ b/test/1910-transform-with-default/expected.txt
@@ -0,0 +1,4 @@
+hello
+hello
+Goodbye
+Goodbye
diff --git a/test/1910-transform-with-default/info.txt b/test/1910-transform-with-default/info.txt
new file mode 100644
index 0000000..96ebddd
--- /dev/null
+++ b/test/1910-transform-with-default/info.txt
@@ -0,0 +1,4 @@
+Tests basic functions in the jvmti plugin.
+
+Tests that we we can redefine classes that have default methods inherited from
+interfaces.
diff --git a/test/1910-transform-with-default/run b/test/1910-transform-with-default/run
new file mode 100755
index 0000000..c6e62ae
--- /dev/null
+++ b/test/1910-transform-with-default/run
@@ -0,0 +1,17 @@
+#!/bin/bash
+#
+# Copyright 2016 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.
+
+./default-run "$@" --jvmti
diff --git a/test/1910-transform-with-default/src/Main.java b/test/1910-transform-with-default/src/Main.java
new file mode 100644
index 0000000..fd8b3c7
--- /dev/null
+++ b/test/1910-transform-with-default/src/Main.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+public class Main {
+ public static void main(String[] args) throws Exception {
+ art.Test1910.run();
+ }
+}
diff --git a/test/1910-transform-with-default/src/art/Redefinition.java b/test/1910-transform-with-default/src/art/Redefinition.java
new file mode 100644
index 0000000..56d2938
--- /dev/null
+++ b/test/1910-transform-with-default/src/art/Redefinition.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+package art;
+
+import java.util.ArrayList;
+// Common Redefinition functions. Placed here for use by CTS
+public class Redefinition {
+ public static final class CommonClassDefinition {
+ public final Class<?> target;
+ public final byte[] class_file_bytes;
+ public final byte[] dex_file_bytes;
+
+ public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) {
+ this.target = target;
+ this.class_file_bytes = class_file_bytes;
+ this.dex_file_bytes = dex_file_bytes;
+ }
+ }
+
+ // A set of possible test configurations. Test should set this if they need to.
+ // This must be kept in sync with the defines in ti-agent/common_helper.cc
+ public static enum Config {
+ COMMON_REDEFINE(0),
+ COMMON_RETRANSFORM(1),
+ COMMON_TRANSFORM(2);
+
+ private final int val;
+ private Config(int val) {
+ this.val = val;
+ }
+ }
+
+ public static void setTestConfiguration(Config type) {
+ nativeSetTestConfiguration(type.val);
+ }
+
+ private static native void nativeSetTestConfiguration(int type);
+
+ // Transforms the class
+ public static native void doCommonClassRedefinition(Class<?> target,
+ byte[] classfile,
+ byte[] dexfile);
+
+ public static void doMultiClassRedefinition(CommonClassDefinition... defs) {
+ ArrayList<Class<?>> classes = new ArrayList<>();
+ ArrayList<byte[]> class_files = new ArrayList<>();
+ ArrayList<byte[]> dex_files = new ArrayList<>();
+
+ for (CommonClassDefinition d : defs) {
+ classes.add(d.target);
+ class_files.add(d.class_file_bytes);
+ dex_files.add(d.dex_file_bytes);
+ }
+ doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]),
+ class_files.toArray(new byte[0][]),
+ dex_files.toArray(new byte[0][]));
+ }
+
+ public static void addMultiTransformationResults(CommonClassDefinition... defs) {
+ for (CommonClassDefinition d : defs) {
+ addCommonTransformationResult(d.target.getCanonicalName(),
+ d.class_file_bytes,
+ d.dex_file_bytes);
+ }
+ }
+
+ public static native void doCommonMultiClassRedefinition(Class<?>[] targets,
+ byte[][] classfiles,
+ byte[][] dexfiles);
+ public static native void doCommonClassRetransformation(Class<?>... target);
+ public static native void setPopRetransformations(boolean pop);
+ public static native void popTransformationFor(String name);
+ public static native void enableCommonRetransformation(boolean enable);
+ public static native void addCommonTransformationResult(String target_name,
+ byte[] class_bytes,
+ byte[] dex_bytes);
+}
diff --git a/test/1910-transform-with-default/src/art/Test1910.java b/test/1910-transform-with-default/src/art/Test1910.java
new file mode 100644
index 0000000..775fe63
--- /dev/null
+++ b/test/1910-transform-with-default/src/art/Test1910.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+package art;
+
+import java.util.Base64;
+public class Test1910 {
+ static interface TestInterface {
+ public void sayHi();
+ public default void sayHiTwice() {
+ sayHi();
+ sayHi();
+ }
+ }
+
+ static class Transform implements TestInterface {
+ public void sayHi() {
+ System.out.println("hello");
+ }
+ }
+
+ /**
+ * base64 encoded class/dex file for
+ * class Transform implements TestInterface {
+ * public void sayHi() {
+ * System.out.println("Goodbye");
+ * }
+ * }
+ */
+ private static final byte[] CLASS_BYTES = Base64.getDecoder().decode(
+ "yv66vgAAADQAIwoABgAPCQAQABEIABIKABMAFAcAFgcAGQcAGgEABjxpbml0PgEAAygpVgEABENv" +
+ "ZGUBAA9MaW5lTnVtYmVyVGFibGUBAAVzYXlIaQEAClNvdXJjZUZpbGUBAA1UZXN0MTkxMC5qYXZh" +
+ "DAAIAAkHABwMAB0AHgEAB0dvb2RieWUHAB8MACAAIQcAIgEAFmFydC9UZXN0MTkxMCRUcmFuc2Zv" +
+ "cm0BAAlUcmFuc2Zvcm0BAAxJbm5lckNsYXNzZXMBABBqYXZhL2xhbmcvT2JqZWN0AQAaYXJ0L1Rl" +
+ "c3QxOTEwJFRlc3RJbnRlcmZhY2UBAA1UZXN0SW50ZXJmYWNlAQAQamF2YS9sYW5nL1N5c3RlbQEA" +
+ "A291dAEAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwEAE2phdmEvaW8vUHJpbnRTdHJlYW0BAAdwcmlu" +
+ "dGxuAQAVKExqYXZhL2xhbmcvU3RyaW5nOylWAQAMYXJ0L1Rlc3QxOTEwACAABQAGAAEABwAAAAIA" +
+ "AAAIAAkAAQAKAAAAHQABAAEAAAAFKrcAAbEAAAABAAsAAAAGAAEAAAAdAAEADAAJAAEACgAAACUA" +
+ "AgABAAAACbIAAhIDtgAEsQAAAAEACwAAAAoAAgAAAB8ACAAgAAIADQAAAAIADgAYAAAAEgACAAUA" +
+ "FQAXAAgABwAVABsGCA==");
+ private static final byte[] DEX_BYTES = Base64.getDecoder().decode(
+ "ZGV4CjAzNQCimuj5gqsyBEhWaMcfKWwG9eiBycoK3JfcAwAAcAAAAHhWNBIAAAAAAAAAABgDAAAV" +
+ "AAAAcAAAAAoAAADEAAAAAgAAAOwAAAABAAAABAEAAAQAAAAMAQAAAQAAACwBAACQAgAATAEAAK4B" +
+ "AAC2AQAAvwEAAN0BAAD3AQAABwIAACsCAABLAgAAYgIAAHYCAACKAgAAngIAAK0CAAC4AgAAuwIA" +
+ "AL8CAADMAgAA0gIAANcCAADgAgAA5wIAAAIAAAADAAAABAAAAAUAAAAGAAAABwAAAAgAAAAJAAAA" +
+ "CgAAAA0AAAANAAAACQAAAAAAAAAOAAAACQAAAKgBAAAIAAUAEQAAAAEAAAAAAAAAAQAAABMAAAAF" +
+ "AAEAEgAAAAYAAAAAAAAAAQAAAAAAAAAGAAAAoAEAAAsAAACQAQAACAMAAAAAAAACAAAA+QIAAP8C" +
+ "AAABAAEAAQAAAO4CAAAEAAAAcBADAAAADgADAAEAAgAAAPMCAAAIAAAAYgAAABoBAQBuIAIAEAAO" +
+ "AEwBAAAAAAAAAAAAAAAAAAABAAAAAAAAAAEAAAAHAAY8aW5pdD4AB0dvb2RieWUAHExhcnQvVGVz" +
+ "dDE5MTAkVGVzdEludGVyZmFjZTsAGExhcnQvVGVzdDE5MTAkVHJhbnNmb3JtOwAOTGFydC9UZXN0" +
+ "MTkxMDsAIkxkYWx2aWsvYW5ub3RhdGlvbi9FbmNsb3NpbmdDbGFzczsAHkxkYWx2aWsvYW5ub3Rh" +
+ "dGlvbi9Jbm5lckNsYXNzOwAVTGphdmEvaW8vUHJpbnRTdHJlYW07ABJMamF2YS9sYW5nL09iamVj" +
+ "dDsAEkxqYXZhL2xhbmcvU3RyaW5nOwASTGphdmEvbGFuZy9TeXN0ZW07AA1UZXN0MTkxMC5qYXZh" +
+ "AAlUcmFuc2Zvcm0AAVYAAlZMAAthY2Nlc3NGbGFncwAEbmFtZQADb3V0AAdwcmludGxuAAVzYXlI" +
+ "aQAFdmFsdWUAHQAHDgAfAAcOeAACAwEUGAICBAIPBAgQFwwAAAEBAICABNgCAQHwAgAAEAAAAAAA" +
+ "AAABAAAAAAAAAAEAAAAVAAAAcAAAAAIAAAAKAAAAxAAAAAMAAAACAAAA7AAAAAQAAAABAAAABAEA" +
+ "AAUAAAAEAAAADAEAAAYAAAABAAAALAEAAAMQAAABAAAATAEAAAEgAAACAAAAWAEAAAYgAAABAAAA" +
+ "kAEAAAEQAAACAAAAoAEAAAIgAAAVAAAArgEAAAMgAAACAAAA7gIAAAQgAAACAAAA+QIAAAAgAAAB" +
+ "AAAACAMAAAAQAAABAAAAGAMAAA==");
+
+ public static void run() {
+ Redefinition.setTestConfiguration(Redefinition.Config.COMMON_REDEFINE);
+ doTest(new Transform());
+ }
+
+ public static void doTest(TestInterface t) {
+ t.sayHiTwice();
+ Redefinition.doCommonClassRedefinition(Transform.class, CLASS_BYTES, DEX_BYTES);
+ t.sayHiTwice();
+ }
+}
diff --git a/test/569-checker-pattern-replacement/run b/test/569-checker-pattern-replacement/run
index f7e9df2..8ab6527 100755
--- a/test/569-checker-pattern-replacement/run
+++ b/test/569-checker-pattern-replacement/run
@@ -15,4 +15,4 @@
# limitations under the License.
exec ${RUN} "$@" \
- -Xcompiler-option --no-inline-from=core-oj,569-checker-pattern-replacement.jar:classes2.dex
+ -Xcompiler-option --no-inline-from="core-oj,569-checker-pattern-replacement.jar!classes2.dex"
diff --git a/test/921-hello-failure/expected.txt b/test/921-hello-failure/expected.txt
index fdbfbe2..f36d1a3 100644
--- a/test/921-hello-failure/expected.txt
+++ b/test/921-hello-failure/expected.txt
@@ -53,3 +53,6 @@
hello - Unmodifiable
Transformation error : java.lang.Exception(Failed to redefine class <[LTransform;> due to JVMTI_ERROR_UNMODIFIABLE_CLASS)
hello - Unmodifiable
+hello - Undefault
+Transformation error : java.lang.Exception(Failed to redefine class <LTransform5;> due to JVMTI_ERROR_UNSUPPORTED_REDEFINITION_METHOD_ADDED)
+hello - Undefault
diff --git a/test/921-hello-failure/src/Iface4.java b/test/921-hello-failure/src/Iface4.java
new file mode 100644
index 0000000..66804c2
--- /dev/null
+++ b/test/921-hello-failure/src/Iface4.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+interface Iface4 {
+ default void sayHiTwice(String s) {
+ sayHi(s);
+ sayHi(s);
+ }
+ void sayHi(String s);
+}
diff --git a/test/921-hello-failure/src/Main.java b/test/921-hello-failure/src/Main.java
index cfdcdc2..fb481bd 100644
--- a/test/921-hello-failure/src/Main.java
+++ b/test/921-hello-failure/src/Main.java
@@ -35,6 +35,7 @@
MissingField.doTest(new Transform4("there"));
FieldChange.doTest(new Transform4("there again"));
Unmodifiable.doTest(new Transform[] { new Transform(), });
+ Undefault.doTest(new Transform5());
}
// TODO Replace this shim with a better re-write of this test.
diff --git a/test/921-hello-failure/src/Transform5.java b/test/921-hello-failure/src/Transform5.java
new file mode 100644
index 0000000..cf7b20a
--- /dev/null
+++ b/test/921-hello-failure/src/Transform5.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2017 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 Transform5 implements Iface4 {
+ public void sayHi(String name) {
+ System.out.println("hello - " + name);
+ }
+}
diff --git a/test/921-hello-failure/src/Undefault.java b/test/921-hello-failure/src/Undefault.java
new file mode 100644
index 0000000..8303a84
--- /dev/null
+++ b/test/921-hello-failure/src/Undefault.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2017 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.util.Base64;
+
+class Undefault {
+ // The following is a base64 encoding of the following class.
+ // class Transform5 implements Iface4 {
+ // public void sayHiTwice(String s) {
+ // throw new Error("Should not be called");
+ // }
+ // public void sayHi(String name) {
+ // throw new Error("Should not be called!");
+ // }
+ // }
+ private static final byte[] CLASS_BYTES = Base64.getDecoder().decode(
+ "yv66vgAAADQAGgoABwASBwATCAAUCgACABUIABYHABcHABgHABkBAAY8aW5pdD4BAAMoKVYBAARD" +
+ "b2RlAQAPTGluZU51bWJlclRhYmxlAQAKc2F5SGlUd2ljZQEAFShMamF2YS9sYW5nL1N0cmluZzsp" +
+ "VgEABXNheUhpAQAKU291cmNlRmlsZQEAD1RyYW5zZm9ybTUuamF2YQwACQAKAQAPamF2YS9sYW5n" +
+ "L0Vycm9yAQAUU2hvdWxkIG5vdCBiZSBjYWxsZWQMAAkADgEAFVNob3VsZCBub3QgYmUgY2FsbGVk" +
+ "IQEAClRyYW5zZm9ybTUBABBqYXZhL2xhbmcvT2JqZWN0AQAGSWZhY2U0ACAABgAHAAEACAAAAAMA" +
+ "AAAJAAoAAQALAAAAHQABAAEAAAAFKrcAAbEAAAABAAwAAAAGAAEAAAABAAEADQAOAAEACwAAACIA" +
+ "AwACAAAACrsAAlkSA7cABL8AAAABAAwAAAAGAAEAAAADAAEADwAOAAEACwAAACIAAwACAAAACrsA" +
+ "AlkSBbcABL8AAAABAAwAAAAGAAEAAAAGAAEAEAAAAAIAEQ==");
+ private static final byte[] DEX_BYTES = Base64.getDecoder().decode(
+ "ZGV4CjAzNQD5XbJiwMAcY0cucJ5gcVhFu7tMG0dZX8PsAgAAcAAAAHhWNBIAAAAAAAAAAFgCAAAN" +
+ "AAAAcAAAAAYAAACkAAAAAgAAALwAAAAAAAAAAAAAAAUAAADUAAAAAQAAAPwAAADQAQAAHAEAAIIB" +
+ "AACKAQAAlAEAAKIBAAC1AQAAyQEAAN0BAADzAQAACgIAABsCAAAeAgAAIgIAACkCAAABAAAAAgAA" +
+ "AAMAAAAEAAAABQAAAAkAAAAJAAAABQAAAAAAAAAKAAAABQAAAHwBAAABAAAAAAAAAAEAAQALAAAA" +
+ "AQABAAwAAAACAAEAAAAAAAMAAAAAAAAAAQAAAAAAAAADAAAAdAEAAAgAAAAAAAAARgIAAAAAAAAB" +
+ "AAEAAQAAADUCAAAEAAAAcBAEAAAADgAEAAIAAgAAADoCAAAIAAAAIgACABoBBwBwIAMAEAAnAAQA" +
+ "AgACAAAAQAIAAAgAAAAiAAIAGgEGAHAgAwAQACcAAQAAAAAAAAABAAAABAAGPGluaXQ+AAhMSWZh" +
+ "Y2U0OwAMTFRyYW5zZm9ybTU7ABFMamF2YS9sYW5nL0Vycm9yOwASTGphdmEvbGFuZy9PYmplY3Q7" +
+ "ABJMamF2YS9sYW5nL1N0cmluZzsAFFNob3VsZCBub3QgYmUgY2FsbGVkABVTaG91bGQgbm90IGJl" +
+ "IGNhbGxlZCEAD1RyYW5zZm9ybTUuamF2YQABVgACVkwABXNheUhpAApzYXlIaVR3aWNlAAEABw4A" +
+ "BgEABw4AAwEABw4AAAABAgCAgAScAgEBtAIBAdQCDAAAAAAAAAABAAAAAAAAAAEAAAANAAAAcAAA" +
+ "AAIAAAAGAAAApAAAAAMAAAACAAAAvAAAAAUAAAAFAAAA1AAAAAYAAAABAAAA/AAAAAEgAAADAAAA" +
+ "HAEAAAEQAAACAAAAdAEAAAIgAAANAAAAggEAAAMgAAADAAAANQIAAAAgAAABAAAARgIAAAAQAAAB" +
+ "AAAAWAIAAA==");
+
+ public static void doTest(Transform5 t) {
+ t.sayHi("Undefault");
+ try {
+ Main.doCommonClassRedefinition(Transform5.class, CLASS_BYTES, DEX_BYTES);
+ } catch (Exception e) {
+ System.out.println(
+ "Transformation error : " + e.getClass().getName() + "(" + e.getMessage() + ")");
+ }
+ t.sayHi("Undefault");
+ }
+}
diff --git a/test/testrunner/env.py b/test/testrunner/env.py
index a0c4ea8..6596ff4 100644
--- a/test/testrunner/env.py
+++ b/test/testrunner/env.py
@@ -233,8 +233,8 @@
HOST_OUT_EXECUTABLES = os.path.join(ANDROID_BUILD_TOP,
_get_build_var("HOST_OUT_EXECUTABLES"))
-os.environ['JACK'] = HOST_OUT_EXECUTABLES + '/jack'
-os.environ['DX'] = HOST_OUT_EXECUTABLES + '/dx'
-os.environ['SMALI'] = HOST_OUT_EXECUTABLES + '/smali'
-os.environ['JASMIN'] = HOST_OUT_EXECUTABLES + '/jasmin'
-os.environ['DXMERGER'] = HOST_OUT_EXECUTABLES + '/dexmerger'
+
+# Set up default values for $JACK, $DX, $SMALI, etc to the $HOST_OUT_EXECUTABLES/$name path.
+for tool in ['jack', 'dx', 'smali', 'jasmin', 'dxmerger']:
+ binary = tool if tool != 'dxmerger' else 'dexmerger'
+ os.environ.setdefault(tool.upper(), HOST_OUT_EXECUTABLES + '/' + binary)