Merge "Prevent UAF issues caused by static destructors"
diff --git a/adbconnection/adbconnection.cc b/adbconnection/adbconnection.cc
index 6b82be6..a0c9966 100644
--- a/adbconnection/adbconnection.cc
+++ b/adbconnection/adbconnection.cc
@@ -555,7 +555,10 @@
void AdbConnectionState::RunPollLoop(art::Thread* self) {
CHECK_NE(agent_name_, "");
CHECK_EQ(self->GetState(), art::kNative);
- art::Locks::mutator_lock_->AssertNotHeld(self);
+ // TODO: Clang prebuilt for r316199 produces bogus thread safety analysis warning for holding both
+ // exclusive and shared lock in the same scope. Remove the assertion as a temporary workaround.
+ // http://b/71769596
+ // art::Locks::mutator_lock_->AssertNotHeld(self);
self->SetState(art::kWaitingInMainDebuggerLoop);
// shutting_down_ set by StopDebuggerThreads
while (!shutting_down_) {
diff --git a/compiler/compiled_method.cc b/compiler/compiled_method.cc
index 0f69dba..e413718 100644
--- a/compiler/compiled_method.cc
+++ b/compiler/compiled_method.cc
@@ -159,10 +159,4 @@
storage->ReleaseMethodInfo(method_info_);
}
-void CompiledMethod::ReleaseVMapTable() {
- CompiledMethodStorage* storage = GetCompilerDriver()->GetCompiledMethodStorage();
- storage->ReleaseVMapTable(vmap_table_);
- vmap_table_ = nullptr;
-}
-
} // namespace art
diff --git a/compiler/compiled_method.h b/compiler/compiled_method.h
index 4e8f3ef..acdce26 100644
--- a/compiler/compiled_method.h
+++ b/compiler/compiled_method.h
@@ -168,10 +168,6 @@
ArrayRef<const linker::LinkerPatch> GetPatches() const;
- // The compiler sometimes unquickens shared code items. In that case, we need to clear the vmap
- // table to avoid writing the quicken info to the vdex file.
- void ReleaseVMapTable();
-
private:
static constexpr size_t kIsIntrinsicLsb = kNumberOfCompiledCodePackedBits;
static constexpr size_t kIsIntrinsicSize = 1u;
@@ -190,7 +186,7 @@
// For quick code, method specific information that is not very dedupe friendly (method indices).
const LengthPrefixedArray<uint8_t>* const method_info_;
// For quick code, holds code infos which contain stack maps, inline information, and etc.
- const LengthPrefixedArray<uint8_t>* vmap_table_;
+ const LengthPrefixedArray<uint8_t>* const vmap_table_;
// For quick code, a FDE entry for the debug_frame section.
const LengthPrefixedArray<uint8_t>* const cfi_info_;
// For quick code, linker patches needed by the method.
diff --git a/compiler/debug/elf_symtab_writer.h b/compiler/debug/elf_symtab_writer.h
index 9c9e8b3..4b19547 100644
--- a/compiler/debug/elf_symtab_writer.h
+++ b/compiler/debug/elf_symtab_writer.h
@@ -101,7 +101,7 @@
}
}
}
- // Add symbols for interpreted methods (with address range of the method's bytecode).
+ // Add symbols for dex files.
if (!debug_info.dex_files.empty() && builder->GetDex()->Exists()) {
auto dex = builder->GetDex();
for (auto it : debug_info.dex_files) {
@@ -109,33 +109,6 @@
const DexFile* dex_file = it.second;
typename ElfTypes::Word dex_name = strtab->Write(kDexFileSymbolName);
symtab->Add(dex_name, dex, dex_address, dex_file->Size(), STB_GLOBAL, STT_FUNC);
- if (mini_debug_info) {
- continue; // Don't add interpreter method names to mini-debug-info for now.
- }
- for (uint32_t i = 0; i < dex_file->NumClassDefs(); ++i) {
- const DexFile::ClassDef& class_def = dex_file->GetClassDef(i);
- const uint8_t* class_data = dex_file->GetClassData(class_def);
- if (class_data == nullptr) {
- continue;
- }
- for (ClassDataItemIterator item(*dex_file, class_data); item.HasNext(); item.Next()) {
- if (!item.IsAtMethod()) {
- continue;
- }
- const DexFile::CodeItem* code_item = item.GetMethodCodeItem();
- if (code_item == nullptr) {
- continue;
- }
- CodeItemInstructionAccessor code(*dex_file, code_item);
- DCHECK(code.HasCodeItem());
- std::string name = dex_file->PrettyMethod(item.GetMemberIndex(), !mini_debug_info);
- size_t name_offset = strtab->Write(name);
- uint64_t offset = reinterpret_cast<const uint8_t*>(code.Insns()) - dex_file->Begin();
- uint64_t address = dex_address + offset;
- size_t size = code.InsnsSizeInCodeUnits() * sizeof(uint16_t);
- symtab->Add(name_offset, dex, address, size, STB_GLOBAL, STT_FUNC);
- }
- }
}
}
strtab->End();
diff --git a/compiler/dex/dex_to_dex_compiler.cc b/compiler/dex/dex_to_dex_compiler.cc
index 28c7fe2..9f0aaa4 100644
--- a/compiler/dex/dex_to_dex_compiler.cc
+++ b/compiler/dex/dex_to_dex_compiler.cc
@@ -45,6 +45,85 @@
// Control check-cast elision.
const bool kEnableCheckCastEllision = true;
+// Holds the state for compiling a single method.
+struct DexToDexCompiler::CompilationState {
+ struct QuickenedInfo {
+ QuickenedInfo(uint32_t pc, uint16_t index) : dex_pc(pc), dex_member_index(index) {}
+
+ uint32_t dex_pc;
+ uint16_t dex_member_index;
+ };
+
+ CompilationState(DexToDexCompiler* compiler,
+ const DexCompilationUnit& unit,
+ const CompilationLevel compilation_level,
+ const std::vector<uint8_t>* quicken_data);
+
+ const std::vector<QuickenedInfo>& GetQuickenedInfo() const {
+ return quickened_info_;
+ }
+
+ // Returns the quickening info, or an empty array if it was not quickened.
+ // If already_quickened is true, then don't change anything but still return what the quicken
+ // data would have been.
+ std::vector<uint8_t> Compile();
+
+ const DexFile& GetDexFile() const;
+
+ // Compiles a RETURN-VOID into a RETURN-VOID-BARRIER within a constructor where
+ // a barrier is required.
+ void CompileReturnVoid(Instruction* inst, uint32_t dex_pc);
+
+ // Compiles a CHECK-CAST into 2 NOP instructions if it is known to be safe. In
+ // this case, returns the second NOP instruction pointer. Otherwise, returns
+ // the given "inst".
+ Instruction* CompileCheckCast(Instruction* inst, uint32_t dex_pc);
+
+ // Compiles a field access into a quick field access.
+ // The field index is replaced by an offset within an Object where we can read
+ // from / write to this field. Therefore, this does not involve any resolution
+ // at runtime.
+ // Since the field index is encoded with 16 bits, we can replace it only if the
+ // field offset can be encoded with 16 bits too.
+ void CompileInstanceFieldAccess(Instruction* inst, uint32_t dex_pc,
+ Instruction::Code new_opcode, bool is_put);
+
+ // Compiles a virtual method invocation into a quick virtual method invocation.
+ // The method index is replaced by the vtable index where the corresponding
+ // executable can be found. Therefore, this does not involve any resolution
+ // at runtime.
+ // Since the method index is encoded with 16 bits, we can replace it only if the
+ // vtable index can be encoded with 16 bits too.
+ void CompileInvokeVirtual(Instruction* inst, uint32_t dex_pc,
+ Instruction::Code new_opcode, bool is_range);
+
+ // Return the next index.
+ uint16_t NextIndex();
+
+ // Returns the dequickened index if an instruction is quickened, otherwise return index.
+ uint16_t GetIndexForInstruction(const Instruction* inst, uint32_t index);
+
+ DexToDexCompiler* const compiler_;
+ CompilerDriver& driver_;
+ const DexCompilationUnit& unit_;
+ const CompilationLevel compilation_level_;
+
+ // Filled by the compiler when quickening, in order to encode that information
+ // in the .oat file. The runtime will use that information to get to the original
+ // opcodes.
+ std::vector<QuickenedInfo> quickened_info_;
+
+ // True if we optimized a return void to a return void no barrier.
+ bool optimized_return_void_ = false;
+
+ // If the code item was already quickened previously.
+ const bool already_quickened_;
+ const QuickenInfoTable existing_quicken_info_;
+ uint32_t quicken_index_ = 0u;
+
+ DISALLOW_COPY_AND_ASSIGN(CompilationState);
+};
+
DexToDexCompiler::DexToDexCompiler(CompilerDriver* driver)
: driver_(driver),
lock_("Quicken lock", kDexToDexCompilerLock) {
@@ -55,16 +134,13 @@
MutexLock lock(Thread::Current(), lock_);
active_dex_file_ = nullptr;
active_bit_vector_ = nullptr;
- seen_code_items_.clear();
should_quicken_.clear();
- shared_code_items_.clear();
- blacklisted_code_items_.clear();
shared_code_item_quicken_info_.clear();
}
-size_t DexToDexCompiler::NumUniqueCodeItems(Thread* self) const {
+size_t DexToDexCompiler::NumCodeItemsToQuicken(Thread* self) const {
MutexLock lock(self, lock_);
- return seen_code_items_.size();
+ return num_code_items_;
}
BitVector* DexToDexCompiler::GetOrAddBitVectorForDex(const DexFile* dex_file) {
@@ -80,17 +156,13 @@
}
void DexToDexCompiler::MarkForCompilation(Thread* self,
- const MethodReference& method_ref,
- const DexFile::CodeItem* code_item) {
+ const MethodReference& method_ref) {
MutexLock lock(self, lock_);
BitVector* const bitmap = GetOrAddBitVectorForDex(method_ref.dex_file);
DCHECK(bitmap != nullptr);
DCHECK(!bitmap->IsBitSet(method_ref.index));
bitmap->SetBit(method_ref.index);
- // Detect the shared code items.
- if (!seen_code_items_.insert(code_item).second) {
- shared_code_items_.insert(code_item);
- }
+ ++num_code_items_;
}
DexToDexCompiler::CompilationState::CompilationState(DexToDexCompiler* compiler,
@@ -316,6 +388,7 @@
<< " at dex pc " << StringPrintf("0x%x", dex_pc) << " in method "
<< GetDexFile().PrettyMethod(unit_.GetDexMethodIndex(), true);
inst->SetOpcode(Instruction::RETURN_VOID_NO_BARRIER);
+ optimized_return_void_ = true;
}
Instruction* DexToDexCompiler::CompilationState::CompileCheckCast(Instruction* inst,
@@ -464,51 +537,48 @@
// If the code item is shared with multiple different method ids, make sure that we quicken only
// once and verify that all the dequicken maps match.
if (UNLIKELY(shared_code_items_.find(code_item) != shared_code_items_.end())) {
- // For shared code items, use a lock to prevent races.
- MutexLock mu(soa.Self(), lock_);
- // Blacklisted means there was a quickening conflict previously, bail early.
- if (blacklisted_code_items_.find(code_item) != blacklisted_code_items_.end()) {
+ // Avoid quickening the shared code items for now because the existing conflict detection logic
+ // does not currently handle cases where the code item is quickened in one place but
+ // compiled in another.
+ static constexpr bool kAvoidQuickeningSharedCodeItems = true;
+ if (kAvoidQuickeningSharedCodeItems) {
return nullptr;
}
+ // For shared code items, use a lock to prevent races.
+ MutexLock mu(soa.Self(), lock_);
auto existing = shared_code_item_quicken_info_.find(code_item);
- const bool already_quickened = existing != shared_code_item_quicken_info_.end();
+ QuickenState* existing_data = nullptr;
+ std::vector<uint8_t>* existing_quicken_data = nullptr;
+ if (existing != shared_code_item_quicken_info_.end()) {
+ existing_data = &existing->second;
+ if (existing_data->conflict_) {
+ return nullptr;
+ }
+ existing_quicken_data = &existing_data->quicken_data_;
+ }
+ bool optimized_return_void;
{
- CompilationState state(this,
- unit,
- compilation_level,
- already_quickened ? &existing->second.quicken_data_ : nullptr);
+ CompilationState state(this, unit, compilation_level, existing_quicken_data);
quicken_data = state.Compile();
+ optimized_return_void = state.optimized_return_void_;
}
// Already quickened, check that the data matches what was previously seen.
MethodReference method_ref(&dex_file, method_idx);
- if (already_quickened) {
- QuickenState* const existing_data = &existing->second;
- if (existing_data->quicken_data_ != quicken_data) {
- VLOG(compiler) << "Quicken data mismatch, dequickening method "
+ if (existing_data != nullptr) {
+ if (*existing_quicken_data != quicken_data ||
+ existing_data->optimized_return_void_ != optimized_return_void) {
+ VLOG(compiler) << "Quicken data mismatch, for method "
<< dex_file.PrettyMethod(method_idx);
- // Unquicken using the existing quicken data.
- optimizer::ArtDecompileDEX(dex_file,
- *code_item,
- ArrayRef<const uint8_t>(existing_data->quicken_data_),
- /* decompile_return_instruction*/ false);
- // Go clear the vmaps for all the methods that were already quickened to avoid writing them
- // out during oat writing.
- for (const MethodReference& ref : existing_data->methods_) {
- CompiledMethod* method = driver_->GetCompiledMethod(ref);
- DCHECK(method != nullptr);
- method->ReleaseVMapTable();
- }
- // Blacklist the method to never attempt to quicken it in the future.
- blacklisted_code_items_.insert(code_item);
- shared_code_item_quicken_info_.erase(existing);
- return nullptr;
+ // Mark the method as a conflict to never attempt to quicken it in the future.
+ existing_data->conflict_ = true;
}
existing_data->methods_.push_back(method_ref);
} else {
QuickenState new_state;
new_state.methods_.push_back(method_ref);
new_state.quicken_data_ = quicken_data;
+ new_state.optimized_return_void_ = optimized_return_void;
bool inserted = shared_code_item_quicken_info_.emplace(code_item, new_state).second;
CHECK(inserted) << "Failed to insert " << dex_file.PrettyMethod(method_idx);
}
@@ -556,9 +626,65 @@
ArrayRef<const uint8_t>(quicken_data), // vmap_table
ArrayRef<const uint8_t>(), // cfi data
ArrayRef<const linker::LinkerPatch>());
+ DCHECK(ret != nullptr);
return ret;
}
+void DexToDexCompiler::SetDexFiles(const std::vector<const DexFile*>& dex_files) {
+ // Record what code items are already seen to detect when multiple methods have the same code
+ // item.
+ std::unordered_set<const DexFile::CodeItem*> seen_code_items;
+ for (const DexFile* dex_file : dex_files) {
+ for (size_t i = 0; i < dex_file->NumClassDefs(); ++i) {
+ const DexFile::ClassDef& class_def = dex_file->GetClassDef(i);
+ const uint8_t* class_data = dex_file->GetClassData(class_def);
+ if (class_data == nullptr) {
+ continue;
+ }
+ ClassDataItemIterator it(*dex_file, class_data);
+ it.SkipAllFields();
+ for (; it.HasNextMethod(); it.Next()) {
+ const DexFile::CodeItem* code_item = it.GetMethodCodeItem();
+ // Detect the shared code items.
+ if (!seen_code_items.insert(code_item).second) {
+ shared_code_items_.insert(code_item);
+ }
+ }
+ }
+ }
+ VLOG(compiler) << "Shared code items " << shared_code_items_.size();
+}
+
+void DexToDexCompiler::UnquickenConflictingMethods() {
+ MutexLock mu(Thread::Current(), lock_);
+ size_t unquicken_count = 0;
+ for (const auto& pair : shared_code_item_quicken_info_) {
+ const DexFile::CodeItem* code_item = pair.first;
+ const QuickenState& state = pair.second;
+ CHECK_GE(state.methods_.size(), 1u);
+ if (state.conflict_) {
+ // Unquicken using the existing quicken data.
+ // TODO: Do we really need to pass a dex file in?
+ optimizer::ArtDecompileDEX(*state.methods_[0].dex_file,
+ *code_item,
+ ArrayRef<const uint8_t>(state.quicken_data_),
+ /* decompile_return_instruction*/ true);
+ ++unquicken_count;
+ // Go clear the vmaps for all the methods that were already quickened to avoid writing them
+ // out during oat writing.
+ for (const MethodReference& ref : state.methods_) {
+ CompiledMethod* method = driver_->RemoveCompiledMethod(ref);
+ if (method != nullptr) {
+ // There is up to one compiled method for each method ref. Releasing it leaves the
+ // deduped data intact, this means its safe to do even when other threads might be
+ // compiling.
+ CompiledMethod::ReleaseSwapAllocatedCompiledMethod(driver_, method);
+ }
+ }
+ }
+ }
+}
+
} // namespace optimizer
} // namespace art
diff --git a/compiler/dex/dex_to_dex_compiler.h b/compiler/dex/dex_to_dex_compiler.h
index 2105a9d..7df09f1 100644
--- a/compiler/dex/dex_to_dex_compiler.h
+++ b/compiler/dex/dex_to_dex_compiler.h
@@ -59,99 +59,35 @@
const CompilationLevel compilation_level) WARN_UNUSED;
void MarkForCompilation(Thread* self,
- const MethodReference& method_ref,
- const DexFile::CodeItem* code_item);
+ const MethodReference& method_ref);
void ClearState();
+ // Unquicken all methods that have conflicting quicken info. This is not done during the
+ // quickening process to avoid race conditions.
+ void UnquickenConflictingMethods();
+
CompilerDriver* GetDriver() {
return driver_;
}
bool ShouldCompileMethod(const MethodReference& ref);
- size_t NumUniqueCodeItems(Thread* self) const;
+ // Return the number of code items to quicken.
+ size_t NumCodeItemsToQuicken(Thread* self) const;
+
+ void SetDexFiles(const std::vector<const DexFile*>& dex_files);
private:
// Holds the state for compiling a single method.
- struct CompilationState {
- struct QuickenedInfo {
- QuickenedInfo(uint32_t pc, uint16_t index) : dex_pc(pc), dex_member_index(index) {}
+ struct CompilationState;
- uint32_t dex_pc;
- uint16_t dex_member_index;
- };
-
- CompilationState(DexToDexCompiler* compiler,
- const DexCompilationUnit& unit,
- const CompilationLevel compilation_level,
- const std::vector<uint8_t>* quicken_data);
-
- const std::vector<QuickenedInfo>& GetQuickenedInfo() const {
- return quickened_info_;
- }
-
- // Returns the quickening info, or an empty array if it was not quickened.
- // If already_quickened is true, then don't change anything but still return what the quicken
- // data would have been.
- std::vector<uint8_t> Compile();
-
- const DexFile& GetDexFile() const;
-
- // Compiles a RETURN-VOID into a RETURN-VOID-BARRIER within a constructor where
- // a barrier is required.
- void CompileReturnVoid(Instruction* inst, uint32_t dex_pc);
-
- // Compiles a CHECK-CAST into 2 NOP instructions if it is known to be safe. In
- // this case, returns the second NOP instruction pointer. Otherwise, returns
- // the given "inst".
- Instruction* CompileCheckCast(Instruction* inst, uint32_t dex_pc);
-
- // Compiles a field access into a quick field access.
- // The field index is replaced by an offset within an Object where we can read
- // from / write to this field. Therefore, this does not involve any resolution
- // at runtime.
- // Since the field index is encoded with 16 bits, we can replace it only if the
- // field offset can be encoded with 16 bits too.
- void CompileInstanceFieldAccess(Instruction* inst, uint32_t dex_pc,
- Instruction::Code new_opcode, bool is_put);
-
- // Compiles a virtual method invocation into a quick virtual method invocation.
- // The method index is replaced by the vtable index where the corresponding
- // executable can be found. Therefore, this does not involve any resolution
- // at runtime.
- // Since the method index is encoded with 16 bits, we can replace it only if the
- // vtable index can be encoded with 16 bits too.
- void CompileInvokeVirtual(Instruction* inst, uint32_t dex_pc,
- Instruction::Code new_opcode, bool is_range);
-
- // Return the next index.
- uint16_t NextIndex();
-
- // Returns the dequickened index if an instruction is quickened, otherwise return index.
- uint16_t GetIndexForInstruction(const Instruction* inst, uint32_t index);
-
- DexToDexCompiler* const compiler_;
- CompilerDriver& driver_;
- const DexCompilationUnit& unit_;
- const CompilationLevel compilation_level_;
-
- // Filled by the compiler when quickening, in order to encode that information
- // in the .oat file. The runtime will use that information to get to the original
- // opcodes.
- std::vector<QuickenedInfo> quickened_info_;
-
- // If the code item was already quickened previously.
- const bool already_quickened_;
- const QuickenInfoTable existing_quicken_info_;
- uint32_t quicken_index_ = 0u;
-
- DISALLOW_COPY_AND_ASSIGN(CompilationState);
- };
-
+ // Quicken state for a code item, may be referenced by multiple methods.
struct QuickenState {
std::vector<MethodReference> methods_;
std::vector<uint8_t> quicken_data_;
+ bool optimized_return_void_ = false;
+ bool conflict_ = false;
};
BitVector* GetOrAddBitVectorForDex(const DexFile* dex_file) REQUIRES(lock_);
@@ -166,15 +102,14 @@
mutable Mutex lock_;
// Record what method references are going to get quickened.
std::unordered_map<const DexFile*, BitVector> should_quicken_;
- // Record what code items are already seen to detect when multiple methods have the same code
- // item.
- std::unordered_set<const DexFile::CodeItem*> seen_code_items_ GUARDED_BY(lock_);
// Guarded by lock_ during writing, accessed without a lock during quickening.
// This is safe because no thread is adding to the shared code items during the quickening phase.
std::unordered_set<const DexFile::CodeItem*> shared_code_items_;
- std::unordered_set<const DexFile::CodeItem*> blacklisted_code_items_ GUARDED_BY(lock_);
+ // Blacklisted code items are unquickened in UnquickenConflictingMethods.
std::unordered_map<const DexFile::CodeItem*, QuickenState> shared_code_item_quicken_info_
GUARDED_BY(lock_);
+ // Number of added code items.
+ size_t num_code_items_ GUARDED_BY(lock_) = 0u;
};
std::ostream& operator<<(std::ostream& os, const DexToDexCompiler::CompilationLevel& rhs);
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index b3adf10..fb428b8 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -656,7 +656,7 @@
optimizer::DexToDexCompiler::CompilationLevel::kDontDexToDexCompile) {
DCHECK(!Runtime::Current()->UseJitCompilation());
// TODO: add a command-line option to disable DEX-to-DEX compilation ?
- driver->GetDexToDexCompiler().MarkForCompilation(self, method_ref, code_item);
+ driver->GetDexToDexCompiler().MarkForCompilation(self, method_ref);
}
}
return compiled_method;
@@ -730,7 +730,7 @@
true,
dex_cache);
- const size_t num_methods = dex_to_dex_compiler_.NumUniqueCodeItems(self);
+ const size_t num_methods = dex_to_dex_compiler_.NumCodeItemsToQuicken(self);
if (num_methods != 0) {
DCHECK_EQ(num_methods, 1u);
CompileMethodDex2Dex(self,
@@ -2808,7 +2808,7 @@
Runtime::Current()->ReclaimArenaPoolMemory();
}
- if (dex_to_dex_compiler_.NumUniqueCodeItems(Thread::Current()) > 0u) {
+ if (dex_to_dex_compiler_.NumCodeItemsToQuicken(Thread::Current()) > 0u) {
// TODO: Not visit all of the dex files, its probably rare that only one would have quickened
// methods though.
for (const DexFile* dex_file : dex_files) {
@@ -2840,6 +2840,12 @@
DCHECK(GetCompiledMethod(method_ref) != nullptr) << method_ref.PrettyMethod();
}
+CompiledMethod* CompilerDriver::RemoveCompiledMethod(const MethodReference& method_ref) {
+ CompiledMethod* ret = nullptr;
+ CHECK(compiled_methods_.Remove(method_ref, &ret));
+ return ret;
+}
+
bool CompilerDriver::GetCompiledClass(const ClassReference& ref, ClassStatus* status) const {
DCHECK(status != nullptr);
// The table doesn't know if something wasn't inserted. For this case it will return
@@ -3013,6 +3019,7 @@
void CompilerDriver::SetDexFilesForOatFile(const std::vector<const DexFile*>& dex_files) {
dex_files_for_oat_file_ = dex_files;
compiled_classes_.AddDexFiles(dex_files);
+ dex_to_dex_compiler_.SetDexFiles(dex_files);
}
void CompilerDriver::SetClasspathDexFiles(const std::vector<const DexFile*>& dex_files) {
diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h
index e32b5c4..2b524a3 100644
--- a/compiler/driver/compiler_driver.h
+++ b/compiler/driver/compiler_driver.h
@@ -165,6 +165,7 @@
void AddCompiledMethod(const MethodReference& method_ref,
CompiledMethod* const compiled_method,
size_t non_relative_linker_patch_count);
+ CompiledMethod* RemoveCompiledMethod(const MethodReference& method_ref);
void SetRequiresConstructorBarrier(Thread* self,
const DexFile* dex_file,
diff --git a/compiler/linker/elf_builder.h b/compiler/linker/elf_builder.h
index 1c87518..3145497 100644
--- a/compiler/linker/elf_builder.h
+++ b/compiler/linker/elf_builder.h
@@ -18,7 +18,6 @@
#define ART_COMPILER_LINKER_ELF_BUILDER_H_
#include <vector>
-#include <unordered_map>
#include "arch/instruction_set.h"
#include "arch/mips/instruction_set_features_mips.h"
@@ -310,24 +309,27 @@
/* info */ 0,
align,
/* entsize */ 0),
- current_offset_(0) {
+ current_offset_(0),
+ last_offset_(0) {
}
Elf_Word Write(const std::string& name) {
if (current_offset_ == 0) {
DCHECK(name.empty());
+ } else if (name == last_name_) {
+ return last_offset_; // Very simple string de-duplication.
}
- auto res = written_names_.emplace(name, current_offset_);
- if (res.second) { // Inserted.
- this->WriteFully(name.c_str(), name.length() + 1);
- current_offset_ += name.length() + 1;
- }
- return res.first->second; // Offset.
+ last_name_ = name;
+ last_offset_ = current_offset_;
+ this->WriteFully(name.c_str(), name.length() + 1);
+ current_offset_ += name.length() + 1;
+ return last_offset_;
}
private:
Elf_Word current_offset_;
- std::unordered_map<std::string, Elf_Word> written_names_; // Dedup strings.
+ std::string last_name_;
+ Elf_Word last_offset_;
};
// Writer of .dynsym and .symtab sections.
diff --git a/compiler/utils/atomic_dex_ref_map-inl.h b/compiler/utils/atomic_dex_ref_map-inl.h
index 203e484..7023b9a 100644
--- a/compiler/utils/atomic_dex_ref_map-inl.h
+++ b/compiler/utils/atomic_dex_ref_map-inl.h
@@ -75,6 +75,18 @@
}
template <typename DexFileReferenceType, typename Value>
+inline bool AtomicDexRefMap<DexFileReferenceType, Value>::Remove(const DexFileReferenceType& ref,
+ Value* out) {
+ ElementArray* const array = GetArray(ref.dex_file);
+ if (array == nullptr) {
+ return false;
+ }
+ *out = (*array)[ref.index].LoadRelaxed();
+ (*array)[ref.index].StoreSequentiallyConsistent(nullptr);
+ return true;
+}
+
+template <typename DexFileReferenceType, typename Value>
inline void AtomicDexRefMap<DexFileReferenceType, Value>::AddDexFile(const DexFile* dex_file) {
arrays_.Put(dex_file, std::move(ElementArray(NumberOfDexIndices(dex_file))));
}
diff --git a/compiler/utils/atomic_dex_ref_map.h b/compiler/utils/atomic_dex_ref_map.h
index 9ff506d..3474e16 100644
--- a/compiler/utils/atomic_dex_ref_map.h
+++ b/compiler/utils/atomic_dex_ref_map.h
@@ -45,6 +45,9 @@
// Retreive an item, returns false if the dex file is not added.
bool Get(const DexFileReferenceType& ref, Value* out) const;
+ // Remove an item and return the existing value. Returns false if the dex file is not added.
+ bool Remove(const DexFileReferenceType& ref, Value* out);
+
// Dex files must be added before method references belonging to them can be used as keys. Not
// thread safe.
void AddDexFile(const DexFile* dex_file);
diff --git a/dex2oat/linker/oat_writer.cc b/dex2oat/linker/oat_writer.cc
index d245cd1..0953e08 100644
--- a/dex2oat/linker/oat_writer.cc
+++ b/dex2oat/linker/oat_writer.cc
@@ -4364,12 +4364,15 @@
debug::DebugInfo OatWriter::GetDebugInfo() const {
debug::DebugInfo debug_info{};
debug_info.compiled_methods = ArrayRef<const debug::MethodDebugInfo>(method_info_);
- if (dex_files_ != nullptr) {
+ if (VdexWillContainDexFiles()) {
DCHECK_EQ(dex_files_->size(), oat_dex_files_.size());
for (size_t i = 0, size = dex_files_->size(); i != size; ++i) {
const DexFile* dex_file = (*dex_files_)[i];
const OatDexFile& oat_dex_file = oat_dex_files_[i];
- debug_info.dex_files.emplace(oat_dex_file.dex_file_offset_, dex_file);
+ uint32_t dex_file_offset = oat_dex_file.dex_file_offset_;
+ if (dex_file_offset != 0) {
+ debug_info.dex_files.emplace(dex_file_offset, dex_file);
+ }
}
}
return debug_info;
diff --git a/dex2oat/linker/oat_writer.h b/dex2oat/linker/oat_writer.h
index dfcaafc..7edb032 100644
--- a/dex2oat/linker/oat_writer.h
+++ b/dex2oat/linker/oat_writer.h
@@ -340,6 +340,10 @@
bool MayHaveCompiledMethods() const;
+ bool VdexWillContainDexFiles() const {
+ return dex_files_ != nullptr && !only_contains_uncompressed_zip_entries_;
+ }
+
// Find the address of the GcRoot<String> in the InternTable for a boot image string.
const uint8_t* LookupBootImageInternTableSlot(const DexFile& dex_file,
dex::StringIndex string_idx);
diff --git a/dexdump/dexdump.cc b/dexdump/dexdump.cc
index 01b28b5..8778b12 100644
--- a/dexdump/dexdump.cc
+++ b/dexdump/dexdump.cc
@@ -1176,14 +1176,20 @@
// Iterate over all instructions.
CodeItemDataAccessor accessor(*pDexFile, pCode);
+ const u4 maxPc = accessor.InsnsSizeInCodeUnits();
for (const DexInstructionPcPair& pair : accessor) {
+ const u4 dexPc = pair.DexPc();
+ if (dexPc >= maxPc) {
+ LOG(WARNING) << "GLITCH: run-away instruction at idx=0x" << std::hex << dexPc;
+ break;
+ }
const Instruction* instruction = &pair.Inst();
const u4 insnWidth = instruction->SizeInCodeUnits();
if (insnWidth == 0) {
- LOG(WARNING) << "GLITCH: zero-width instruction at idx=0x" << std::hex << pair.DexPc();
+ LOG(WARNING) << "GLITCH: zero-width instruction at idx=0x" << std::hex << dexPc;
break;
}
- dumpInstruction(pDexFile, pCode, codeOffset, pair.DexPc(), insnWidth, instruction);
+ dumpInstruction(pDexFile, pCode, codeOffset, dexPc, insnWidth, instruction);
} // for
}
diff --git a/dexlayout/compact_dex_writer.cc b/dexlayout/compact_dex_writer.cc
index 08438c4..ca13f758 100644
--- a/dexlayout/compact_dex_writer.cc
+++ b/dexlayout/compact_dex_writer.cc
@@ -162,11 +162,18 @@
static constexpr size_t kPayloadInstructionRequiredAlignment = 4;
const uint32_t current_code_item_start = stream->Tell() + preheader_bytes;
- if (!IsAlignedParam(current_code_item_start, kPayloadInstructionRequiredAlignment)) {
+ if (!IsAlignedParam(current_code_item_start, kPayloadInstructionRequiredAlignment) ||
+ kIsDebugBuild) {
// If the preheader is going to make the code unaligned, consider adding 2 bytes of padding
// before if required.
- for (const DexInstructionPcPair& instruction : code_item->Instructions()) {
- const Instruction::Code opcode = instruction->Opcode();
+ IterationRange<DexInstructionIterator> instructions = code_item->Instructions();
+ SafeDexInstructionIterator it(instructions.begin(), instructions.end());
+ for (; !it.IsErrorState() && it < instructions.end(); ++it) {
+ // In case the instruction goes past the end of the code item, make sure to not process it.
+ if (std::next(it).IsErrorState()) {
+ break;
+ }
+ const Instruction::Code opcode = it->Opcode();
// Payload instructions possibly require special alignment for their data.
if (opcode == Instruction::FILL_ARRAY_DATA ||
opcode == Instruction::PACKED_SWITCH ||
@@ -460,6 +467,11 @@
// Rewrite the header with the calculated checksum.
WriteHeader(main_stream);
}
+
+ // Clear the dedupe to prevent interdex code item deduping. This does not currently work well with
+ // dex2oat's class unloading. The issue is that verification encounters quickened opcodes after
+ // the first dex gets unloaded.
+ code_item_dedupe_->Clear();
}
std::unique_ptr<DexContainer> CompactDexWriter::CreateDexContainer() const {
diff --git a/dexlayout/compact_dex_writer.h b/dexlayout/compact_dex_writer.h
index 24d0fbf..ea9f7d1 100644
--- a/dexlayout/compact_dex_writer.h
+++ b/dexlayout/compact_dex_writer.h
@@ -44,6 +44,11 @@
// Returns the offset of the deduplicated data or kDidNotDedupe did deduplication did not occur.
uint32_t Dedupe(uint32_t data_start, uint32_t data_end, uint32_t item_offset);
+ // Clear dedupe state to prevent deduplication against existing items in the future.
+ void Clear() {
+ dedupe_map_.clear();
+ }
+
private:
class HashedMemoryRange {
public:
diff --git a/dexlayout/dexlayout.h b/dexlayout/dexlayout.h
index d2f9cb9..5635271 100644
--- a/dexlayout/dexlayout.h
+++ b/dexlayout/dexlayout.h
@@ -66,8 +66,7 @@
bool visualize_pattern_ = false;
bool update_checksum_ = false;
CompactDexLevel compact_dex_level_ = CompactDexLevel::kCompactDexLevelNone;
- // Disabled until dex2oat properly handles quickening of deduped code items.
- bool dedupe_code_items_ = false;
+ bool dedupe_code_items_ = true;
OutputFormat output_format_ = kOutputPlain;
const char* output_dex_directory_ = nullptr;
const char* output_file_name_ = nullptr;
diff --git a/dexlayout/dexlayout_test.cc b/dexlayout/dexlayout_test.cc
index be272fc..bebdc20 100644
--- a/dexlayout/dexlayout_test.cc
+++ b/dexlayout/dexlayout_test.cc
@@ -221,6 +221,12 @@
"AHAAAAACAAAAAwAAAIwAAAADAAAAAQAAAJgAAAAFAAAABAAAAKQAAAAGAAAAAQAAAMQAAAABIAAA"
"AwAAAOQAAAACIAAABwAAACQBAAADIAAAAwAAAFYBAAAAIAAAAQAAAGUBAAAAEAAAAQAAAHgBAAA=";
+// Returns the default compact dex option for dexlayout based on kDefaultCompactDexLevel.
+static std::vector<std::string> DefaultCompactDexOption() {
+ return (kDefaultCompactDexLevel == CompactDexLevel::kCompactDexLevelFast) ?
+ std::vector<std::string>{"-x", "fast"} : std::vector<std::string>{"-x", "none"};
+}
+
static void WriteBase64ToFile(const char* base64, File* file) {
// Decode base64.
CHECK(base64 != nullptr);
@@ -289,7 +295,7 @@
for (const std::string &dex_file : GetLibCoreDexFileNames()) {
std::vector<std::string> dexlayout_args =
{ "-w", tmp_dir, "-o", tmp_name, dex_file };
- if (!DexLayoutExec(dexlayout_args, error_msg)) {
+ if (!DexLayoutExec(dexlayout_args, error_msg, /*pass_default_cdex_option*/ false)) {
return false;
}
size_t dex_file_last_slash = dex_file.rfind('/');
@@ -304,12 +310,10 @@
if (!::art::Exec(diff_exec_argv, error_msg)) {
return false;
}
- std::vector<std::string> rm_zip_exec_argv = { "/bin/rm", tmp_dir + "classes.dex" };
- if (!::art::Exec(rm_zip_exec_argv, error_msg)) {
+ if (!UnlinkFile(tmp_dir + "classes.dex")) {
return false;
}
- std::vector<std::string> rm_out_exec_argv = { "/bin/rm", tmp_dir + dex_file_name };
- if (!::art::Exec(rm_out_exec_argv, error_msg)) {
+ if (!UnlinkFile(tmp_dir + dex_file_name)) {
return false;
}
}
@@ -426,10 +430,7 @@
}
// -v makes sure that the layout did not corrupt the dex file.
-
- std::vector<std::string> rm_exec_argv =
- { "/bin/rm", dex_file, profile_file, output_dex };
- if (!::art::Exec(rm_exec_argv, error_msg)) {
+ if (!UnlinkFile(dex_file) || !UnlinkFile(profile_file) || !UnlinkFile(output_dex)) {
return false;
}
return true;
@@ -467,7 +468,7 @@
// -v makes sure that the layout did not corrupt the dex file.
std::vector<std::string> dexlayout_args =
{ "-i", "-v", "-w", tmp_dir, "-o", tmp_name, "-p", profile_file, dex_file };
- if (!DexLayoutExec(dexlayout_args, error_msg)) {
+ if (!DexLayoutExec(dexlayout_args, error_msg, /*pass_default_cdex_option*/ false)) {
return false;
}
@@ -479,7 +480,7 @@
// -i since the checksum won't match from the first layout.
std::vector<std::string> second_dexlayout_args =
{ "-i", "-v", "-w", tmp_dir, "-o", tmp_name, "-p", profile_file, output_dex };
- if (!DexLayoutExec(second_dexlayout_args, error_msg)) {
+ if (!DexLayoutExec(second_dexlayout_args, error_msg, /*pass_default_cdex_option*/ false)) {
return false;
}
@@ -490,10 +491,11 @@
diff_result = false;
}
- std::vector<std::string> rm_exec_argv =
- { "/bin/rm", dex_file, profile_file, output_dex, second_output_dex };
- if (!::art::Exec(rm_exec_argv, error_msg)) {
- return false;
+ std::vector<std::string> test_files = { dex_file, profile_file, output_dex, second_output_dex };
+ for (auto test_file : test_files) {
+ if (!UnlinkFile(test_file)) {
+ return false;
+ }
}
return diff_result;
@@ -512,7 +514,7 @@
std::string output_dex = tmp_dir + "classes.dex.new";
std::vector<std::string> dexlayout_args = { "-w", tmp_dir, "-o", "/dev/null", input_dex };
- if (!DexLayoutExec(dexlayout_args, error_msg)) {
+ if (!DexLayoutExec(dexlayout_args, error_msg, /*pass_default_cdex_option*/ false)) {
return false;
}
@@ -522,9 +524,11 @@
return false;
}
- std::vector<std::string> rm_exec_argv = { "/bin/rm", input_dex, output_dex };
- if (!::art::Exec(rm_exec_argv, error_msg)) {
- return false;
+ std::vector<std::string> dex_files = { input_dex, output_dex };
+ for (auto dex_file : dex_files) {
+ if (!UnlinkFile(dex_file)) {
+ return false;
+ }
}
return true;
}
@@ -550,17 +554,27 @@
return true;
}
- bool DexLayoutExec(const std::vector<std::string>& dexlayout_args, std::string* error_msg) {
+ bool DexLayoutExec(const std::vector<std::string>& dexlayout_args,
+ std::string* error_msg,
+ bool pass_default_cdex_option = true) {
std::vector<std::string> argv;
std::string dexlayout = GetDexLayoutPath();
CHECK(OS::FileExists(dexlayout.c_str())) << dexlayout << " should be a valid file path";
argv.push_back(dexlayout);
+ if (pass_default_cdex_option) {
+ std::vector<std::string> cdex_level = DefaultCompactDexOption();
+ argv.insert(argv.end(), cdex_level.begin(), cdex_level.end());
+ }
argv.insert(argv.end(), dexlayout_args.begin(), dexlayout_args.end());
return ::art::Exec(argv, error_msg);
}
+
+ bool UnlinkFile(const std::string& file_path) {
+ return unix_file::FdFile(file_path, 0, false).Unlink();
+ }
};
@@ -730,11 +744,29 @@
CHECK(mutated_successfully)
<< "Failed to find candidate code item with only one code unit in last instruction.";
});
- std::vector<std::string> dexlayout_args = { "-i", "-o", "/dev/null", temp_dex.GetFilename() };
+
+ std::string error_msg;
+
+ ScratchFile tmp_file;
+ const std::string& tmp_name = tmp_file.GetFilename();
+ size_t tmp_last_slash = tmp_name.rfind('/');
+ std::string tmp_dir = tmp_name.substr(0, tmp_last_slash + 1);
+ ScratchFile profile_file;
+
+ std::vector<std::string> dexlayout_args =
+ { "-i",
+ "-v",
+ "-w", tmp_dir,
+ "-o", tmp_name,
+ "-p", profile_file.GetFilename(),
+ temp_dex.GetFilename()
+ };
+ // -v makes sure that the layout did not corrupt the dex file.
ASSERT_TRUE(DexLayoutExec(&temp_dex,
/*dex_filename*/ nullptr,
- nullptr /* profile_file */,
+ &profile_file,
dexlayout_args));
+ ASSERT_TRUE(UnlinkFile(temp_dex.GetFilename() + ".new"));
}
// Test that link data is written out (or at least the header is updated).
@@ -772,11 +804,7 @@
/*dex_filename*/ nullptr,
&profile_file,
dexlayout_args));
-
- std::string output_dex = temp_dex.GetFilename() + ".new";
- std::vector<std::string> rm_exec_argv =
- { "/bin/rm", output_dex };
- ASSERT_TRUE(::art::Exec(rm_exec_argv, &error_msg));
+ ASSERT_TRUE(UnlinkFile(temp_dex.GetFilename() + ".new"));
}
TEST_F(DexLayoutTest, ClassFilter) {
diff --git a/openjdkjvmti/ti_class_definition.h b/openjdkjvmti/ti_class_definition.h
index e0b9b31..31c3611 100644
--- a/openjdkjvmti/ti_class_definition.h
+++ b/openjdkjvmti/ti_class_definition.h
@@ -49,8 +49,7 @@
class ArtClassDefinition {
public:
// If we support doing a on-demand dex-dequickening using signal handlers.
- // TODO Make this true. We currently have some ASAN issues with this.
- static constexpr bool kEnableOnDemandDexDequicken = false;
+ static constexpr bool kEnableOnDemandDexDequicken = true;
ArtClassDefinition()
: klass_(nullptr),
diff --git a/openjdkjvmti/transform.cc b/openjdkjvmti/transform.cc
index 7b19a24..dc9f69a 100644
--- a/openjdkjvmti/transform.cc
+++ b/openjdkjvmti/transform.cc
@@ -128,6 +128,11 @@
}
}
+ if (LIKELY(self != nullptr)) {
+ CHECK_EQ(self->GetState(), art::ThreadState::kNative)
+ << "Transformation fault handler occurred outside of native mode";
+ }
+
VLOG(signals) << "Lazy initialization of dex file for transformation of " << res->GetName()
<< " during SEGV";
res->InitializeMemory();
@@ -250,6 +255,10 @@
static_assert(kEvent == ArtJvmtiEvent::kClassFileLoadHookNonRetransformable ||
kEvent == ArtJvmtiEvent::kClassFileLoadHookRetransformable,
"bad event type");
+ // We don't want to do transitions between calling the event and setting the new data so change to
+ // native state early. This also avoids any problems that the FaultHandler might have in
+ // determining if an access to the dex_data is from generated code or not.
+ art::ScopedThreadStateChange stsc(self, art::ThreadState::kNative);
ScopedDefinitionHandler handler(def);
jint new_len = -1;
unsigned char* new_data = nullptr;
diff --git a/runtime/dex/dex_file_layout.h b/runtime/dex/dex_file_layout.h
index a7b9051..793e3b5 100644
--- a/runtime/dex/dex_file_layout.h
+++ b/runtime/dex/dex_file_layout.h
@@ -83,7 +83,7 @@
}
void CombineSection(uint32_t start_offset, uint32_t end_offset) {
- DCHECK_LT(start_offset, end_offset);
+ DCHECK_LE(start_offset, end_offset);
if (start_offset_ == end_offset_) {
start_offset_ = start_offset;
end_offset_ = end_offset;
diff --git a/runtime/gc/allocator/dlmalloc.cc b/runtime/gc/allocator/dlmalloc.cc
index 6506220..4570e9c 100644
--- a/runtime/gc/allocator/dlmalloc.cc
+++ b/runtime/gc/allocator/dlmalloc.cc
@@ -37,6 +37,7 @@
#pragma GCC diagnostic ignored "-Wredundant-decls"
#pragma GCC diagnostic ignored "-Wempty-body"
#pragma GCC diagnostic ignored "-Wstrict-aliasing"
+#pragma GCC diagnostic ignored "-Wnull-pointer-arithmetic"
#include "../../../external/dlmalloc/malloc.c"
// Note: malloc.c uses a DEBUG define to drive debug code. This interferes with the DEBUG severity
// of libbase, so undefine it now.
diff --git a/runtime/gc/allocator/dlmalloc.h b/runtime/gc/allocator/dlmalloc.h
index 29b96ee..b12691a 100644
--- a/runtime/gc/allocator/dlmalloc.h
+++ b/runtime/gc/allocator/dlmalloc.h
@@ -32,6 +32,7 @@
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wredundant-decls"
+#pragma GCC diagnostic ignored "-Wnull-pointer-arithmetic"
#include "../../external/dlmalloc/malloc.h"
#pragma GCC diagnostic pop
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index b1932d1..cf5bd4a 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -1890,7 +1890,10 @@
count_requested_homogeneous_space_compaction_++;
// Store performed homogeneous space compaction at a new request arrival.
ScopedThreadStateChange tsc(self, kWaitingPerformingGc);
- Locks::mutator_lock_->AssertNotHeld(self);
+ // TODO: Clang prebuilt for r316199 produces bogus thread safety analysis warning for holding both
+ // exclusive and shared lock in the same scope. Remove the assertion as a temporary workaround.
+ // http://b/71769596
+ // Locks::mutator_lock_->AssertNotHeld(self);
{
ScopedThreadStateChange tsc2(self, kWaitingForGcToComplete);
MutexLock mu(self, *gc_complete_lock_);
@@ -1968,7 +1971,10 @@
Runtime* const runtime = Runtime::Current();
Thread* const self = Thread::Current();
ScopedThreadStateChange tsc(self, kWaitingPerformingGc);
- Locks::mutator_lock_->AssertNotHeld(self);
+ // TODO: Clang prebuilt for r316199 produces bogus thread safety analysis warning for holding both
+ // exclusive and shared lock in the same scope. Remove the assertion as a temporary workaround.
+ // http://b/71769596
+ // Locks::mutator_lock_->AssertNotHeld(self);
// Busy wait until we can GC (StartGC can fail if we have a non-zero
// compacting_gc_disable_count_, this should rarely occurs).
for (;;) {
@@ -2511,7 +2517,10 @@
}
}
ScopedThreadStateChange tsc(self, kWaitingPerformingGc);
- Locks::mutator_lock_->AssertNotHeld(self);
+ // TODO: Clang prebuilt for r316199 produces bogus thread safety analysis warning for holding both
+ // exclusive and shared lock in the same scope. Remove the assertion as a temporary workaround.
+ // http://b/71769596
+ // Locks::mutator_lock_->AssertNotHeld(self);
if (self->IsHandlingStackOverflow()) {
// If we are throwing a stack overflow error we probably don't have enough remaining stack
// space to run the GC.
diff --git a/runtime/gc/heap_test.cc b/runtime/gc/heap_test.cc
index 6d426c2..9d8e5d2 100644
--- a/runtime/gc/heap_test.cc
+++ b/runtime/gc/heap_test.cc
@@ -81,6 +81,7 @@
void SetUpRuntimeOptions(RuntimeOptions* options) {
CommonRuntimeTest::SetUpRuntimeOptions(options);
options->push_back(std::make_pair("-Xzygote", nullptr));
+ options->push_back(std::make_pair("-Xno-hidden-api-checks", nullptr));
}
};
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 25d83df..3afd320 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -1172,11 +1172,15 @@
target_sdk_version_ = runtime_options.GetOrDefault(Opt::TargetSdkVersion);
- // Check whether to enforce hidden API access checks. Zygote needs to be exempt
- // but checks may be enabled for forked processes (see dalvik_system_ZygoteHooks).
- if (is_zygote_ || runtime_options.Exists(Opt::NoHiddenApiChecks)) {
- do_hidden_api_checks_ = false;
- }
+ // Check whether to enforce hidden API access checks. The checks are disabled
+ // by default and we only enable them if:
+ // (a) runtime was started with a flag that enables the checks, or
+ // (b) Zygote forked a new process that is not exempt (see ZygoteHooks).
+ // TODO(dbrazdil): Turn the NoHiddenApiChecks negative flag into a positive one
+ // to clean up this logic.
+ do_hidden_api_checks_ = IsAotCompiler() && !runtime_options.Exists(Opt::NoHiddenApiChecks);
+ DCHECK(!is_zygote_ || !do_hidden_api_checks_)
+ << "Zygote should not be started with hidden API checks";
no_sig_chain_ = runtime_options.Exists(Opt::NoSigChain);
force_native_bridge_ = runtime_options.Exists(Opt::ForceNativeBridge);
diff --git a/test/137-cfi/cfi.cc b/test/137-cfi/cfi.cc
index bdfb44a..83234f0 100644
--- a/test/137-cfi/cfi.cc
+++ b/test/137-cfi/cfi.cc
@@ -83,7 +83,7 @@
printf("Cannot find %s in backtrace:\n", seq[cur_search_index].c_str());
for (Backtrace::const_iterator it = bt->begin(); it != bt->end(); ++it) {
if (BacktraceMap::IsValid(it->map)) {
- printf(" %s\n", it->func_name.c_str());
+ printf(" %s\n", Backtrace::FormatFrameData(&*it).c_str());
}
}
@@ -130,6 +130,7 @@
"Java_Main_unwindInProcess", // This function.
"Main.unwindInProcess", // The corresponding Java native method frame.
"java.util.Arrays.binarySearch0", // Framework method.
+ "Base.runBase", // Method in other dex file.
"Main.main" // The Java entry method.
};
@@ -230,6 +231,7 @@
// resolved, so don't look for it right now.
"Main.sleep", // The corresponding Java native method frame.
"java.util.Arrays.binarySearch0", // Framework method.
+ "Base.runBase", // Method in other dex file.
"Main.main" // The Java entry method.
};
diff --git a/test/137-cfi/src-multidex/Base.java b/test/137-cfi/src-multidex/Base.java
new file mode 100644
index 0000000..d3f8a56
--- /dev/null
+++ b/test/137-cfi/src-multidex/Base.java
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ */
+
+public abstract class Base {
+ abstract public void runImpl();
+ public void runBase() {
+ runImpl();
+ }
+}
diff --git a/test/137-cfi/src/Main.java b/test/137-cfi/src/Main.java
index 1ec7072..9a2e352 100644
--- a/test/137-cfi/src/Main.java
+++ b/test/137-cfi/src/Main.java
@@ -20,7 +20,7 @@
import java.util.Arrays;
import java.util.Comparator;
-public class Main implements Comparator<Main> {
+public class Main extends Base implements Comparator<Main> {
// Whether to test local unwinding.
private boolean testLocal;
@@ -57,10 +57,10 @@
}
public static void main(String[] args) throws Exception {
- new Main(args).run();
+ new Main(args).runBase();
}
- private void run() {
+ public void runImpl() {
if (secondary) {
if (!testRemote) {
throw new RuntimeException("Should not be running secondary!");
diff --git a/test/ManyMethods/ManyMethods.java b/test/ManyMethods/ManyMethods.java
index b3a57f6..98b9faf 100644
--- a/test/ManyMethods/ManyMethods.java
+++ b/test/ManyMethods/ManyMethods.java
@@ -26,6 +26,8 @@
public static String msg7 = "Hello World7";
public static String msg8 = "Hello World8";
public static String msg9 = "Hello World9";
+ public static String msg10 = "Hello World10";
+ public static String msg11 = "Hello World11";
}
static class Printer {
@@ -57,35 +59,35 @@
}
public static void Print4() {
- Printer.Print(Strings.msg2);
+ Printer.Print(Strings.msg4);
}
public static void Print5() {
- Printer.Print(Strings.msg3);
- }
-
- public static void Print6() {
- Printer2.Print(Strings.msg4);
- }
-
- public static void Print7() {
Printer.Print(Strings.msg5);
}
+ public static void Print6() {
+ Printer2.Print(Strings.msg6);
+ }
+
+ public static void Print7() {
+ Printer.Print(Strings.msg7);
+ }
+
public static void Print8() {
- Printer.Print(Strings.msg6);
+ Printer.Print(Strings.msg8);
}
public static void Print9() {
- Printer2.Print(Strings.msg7);
+ Printer2.Print(Strings.msg9);
}
public static void Print10() {
- Printer2.Print(Strings.msg8);
+ Printer2.Print(Strings.msg10);
}
public static void Print11() {
- Printer.Print(Strings.msg9);
+ Printer.Print(Strings.msg11);
}
public static void main(String args[]) {
diff --git a/test/ti-stress/stress.cc b/test/ti-stress/stress.cc
index 6e29e36..7fc289f 100644
--- a/test/ti-stress/stress.cc
+++ b/test/ti-stress/stress.cc
@@ -809,7 +809,7 @@
.can_signal_thread = 0,
.can_get_source_file_name = 1,
.can_get_line_numbers = 1,
- .can_get_source_debug_extension = 0,
+ .can_get_source_debug_extension = 1,
.can_access_local_variables = 0,
.can_maintain_original_method_order = 0,
.can_generate_single_step_events = 1,