Merge "Move startup thread pool back into runtime"
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk
index 1bcca7c..a926d9a 100644
--- a/build/Android.gtest.mk
+++ b/build/Android.gtest.mk
@@ -525,7 +525,7 @@
ifeq (,$(SANITIZE_HOST))
$$(gtest_output): $$(gtest_exe) $$(gtest_deps)
$(hide) ($$(call ART_TEST_SKIP,$$(NAME)) && \
- timeout -k 120s -s SIGRTMIN+2 2400s $(HOST_OUT_EXECUTABLES)/timeout_dumper \
+ timeout --foreground -k 120s -s SIGRTMIN+2 2400s $(HOST_OUT_EXECUTABLES)/timeout_dumper \
$$< --gtest_output=xml:$$@ && \
$$(call ART_TEST_PASSED,$$(NAME))) || $$(call ART_TEST_FAILED,$$(NAME))
else
@@ -538,7 +538,7 @@
# under ASAN.
$$(gtest_output): $$(gtest_exe) $$(gtest_deps)
$(hide) ($$(call ART_TEST_SKIP,$$(NAME)) && set -o pipefail && \
- ASAN_OPTIONS=detect_leaks=1 timeout -k 120s -s SIGRTMIN+2 3600s \
+ ASAN_OPTIONS=detect_leaks=1 timeout --foreground -k 120s -s SIGRTMIN+2 3600s \
$(HOST_OUT_EXECUTABLES)/timeout_dumper \
$$< --gtest_output=xml:$$@ 2>&1 | tee $$<.tmp.out >&2 && \
{ $$(call ART_TEST_PASSED,$$(NAME)) ; rm $$<.tmp.out ; }) || \
diff --git a/compiler/debug/dwarf/headers.h b/compiler/debug/dwarf/headers.h
index 28f1084..4a27178 100644
--- a/compiler/debug/dwarf/headers.h
+++ b/compiler/debug/dwarf/headers.h
@@ -107,7 +107,9 @@
} else {
DCHECK(format == DW_DEBUG_FRAME_FORMAT);
// Relocate code_address if it has absolute value.
- patch_locations->push_back(buffer_address + buffer->size() - section_address);
+ if (patch_locations != nullptr) {
+ patch_locations->push_back(buffer_address + buffer->size() - section_address);
+ }
}
if (is64bit) {
writer.PushUint64(code_address);
@@ -122,6 +124,30 @@
writer.UpdateUint32(fde_header_start, writer.data()->size() - fde_header_start - 4);
}
+// Read singe FDE entry from 'data' (which is advanced).
+template<typename Addr>
+bool ReadFDE(const uint8_t** data, Addr* addr, Addr* size, ArrayRef<const uint8_t>* opcodes) {
+ struct Header {
+ uint32_t length;
+ int32_t cie_pointer;
+ Addr addr;
+ Addr size;
+ uint8_t augmentaion;
+ uint8_t opcodes[];
+ } PACKED(1);
+ const Header* header = reinterpret_cast<const Header*>(*data);
+ const size_t length = 4 + header->length;
+ *data += length;
+ if (header->cie_pointer == -1) {
+ return false; // Not an FDE entry.
+ }
+ DCHECK_EQ(header->cie_pointer, 0); // Expects single CIE. Assumes DW_DEBUG_FRAME_FORMAT.
+ *addr = header->addr;
+ *size = header->size;
+ *opcodes = ArrayRef<const uint8_t>(header->opcodes, length - offsetof(Header, opcodes));
+ return true;
+}
+
// Write compilation unit (CU) to .debug_info section.
template<typename Vector>
void WriteDebugInfoCU(uint32_t debug_abbrev_offset,
diff --git a/compiler/debug/elf_debug_frame_writer.h b/compiler/debug/elf_debug_frame_writer.h
index 27b70c8..e0116c6 100644
--- a/compiler/debug/elf_debug_frame_writer.h
+++ b/compiler/debug/elf_debug_frame_writer.h
@@ -182,7 +182,7 @@
std::vector<const MethodDebugInfo*> sorted_method_infos;
sorted_method_infos.reserve(method_infos.size());
for (size_t i = 0; i < method_infos.size(); i++) {
- if (!method_infos[i].cfi.empty() && !method_infos[i].deduped) {
+ if (!method_infos[i].deduped) {
sorted_method_infos.push_back(&method_infos[i]);
}
}
@@ -222,7 +222,6 @@
buffer.clear();
for (const MethodDebugInfo* mi : sorted_method_infos) {
DCHECK(!mi->deduped);
- DCHECK(!mi->cfi.empty());
const Elf_Addr code_address = mi->code_address +
(mi->is_code_address_text_relative ? builder->GetText()->GetAddress() : 0);
if (format == dwarf::DW_EH_FRAME_FORMAT) {
diff --git a/compiler/debug/elf_debug_reader.h b/compiler/debug/elf_debug_reader.h
new file mode 100644
index 0000000..91b1b3e
--- /dev/null
+++ b/compiler/debug/elf_debug_reader.h
@@ -0,0 +1,104 @@
+/*
+ * 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.
+ */
+
+#ifndef ART_COMPILER_DEBUG_ELF_DEBUG_READER_H_
+#define ART_COMPILER_DEBUG_ELF_DEBUG_READER_H_
+
+#include "base/array_ref.h"
+#include "debug/dwarf/headers.h"
+#include "elf.h"
+#include "xz_utils.h"
+
+namespace art {
+namespace debug {
+
+// Trivial ELF file reader.
+//
+// It is the bare minimum needed to read mini-debug-info symbols for unwinding.
+// We use it to merge JIT mini-debug-infos together or to prune them after GC.
+// The consumed ELF file comes from ART JIT.
+template <typename ElfTypes, typename VisitSym, typename VisitFde>
+static void ReadElfSymbols(const uint8_t* elf, VisitSym visit_sym, VisitFde visit_fde) {
+ // Note that the input buffer might be misaligned.
+ typedef typename ElfTypes::Ehdr ALIGNED(1) Elf_Ehdr;
+ typedef typename ElfTypes::Shdr ALIGNED(1) Elf_Shdr;
+ typedef typename ElfTypes::Sym ALIGNED(1) Elf_Sym;
+ typedef typename ElfTypes::Addr ALIGNED(1) Elf_Addr;
+
+ // Read and check the elf header.
+ const Elf_Ehdr* header = reinterpret_cast<const Elf_Ehdr*>(elf);
+ CHECK(header->checkMagic());
+
+ // Find sections that we are interested in.
+ const Elf_Shdr* sections = reinterpret_cast<const Elf_Shdr*>(elf + header->e_shoff);
+ const Elf_Shdr* strtab = nullptr;
+ const Elf_Shdr* symtab = nullptr;
+ const Elf_Shdr* debug_frame = nullptr;
+ const Elf_Shdr* gnu_debugdata = nullptr;
+ for (size_t i = 1 /* skip null section */; i < header->e_shnum; i++) {
+ const Elf_Shdr* section = sections + i;
+ const char* name = reinterpret_cast<const char*>(
+ elf + sections[header->e_shstrndx].sh_offset + section->sh_name);
+ if (strcmp(name, ".strtab") == 0) {
+ strtab = section;
+ } else if (strcmp(name, ".symtab") == 0) {
+ symtab = section;
+ } else if (strcmp(name, ".debug_frame") == 0) {
+ debug_frame = section;
+ } else if (strcmp(name, ".gnu_debugdata") == 0) {
+ gnu_debugdata = section;
+ }
+ }
+
+ // Visit symbols.
+ if (symtab != nullptr && strtab != nullptr) {
+ const Elf_Sym* symbols = reinterpret_cast<const Elf_Sym*>(elf + symtab->sh_offset);
+ DCHECK_EQ(symtab->sh_entsize, sizeof(Elf_Sym));
+ size_t count = symtab->sh_size / sizeof(Elf_Sym);
+ for (size_t i = 1 /* skip null symbol */; i < count; i++) {
+ Elf_Sym symbol = symbols[i];
+ if (symbol.getBinding() != STB_LOCAL) { // Ignore local symbols (e.g. "$t").
+ const uint8_t* name = elf + strtab->sh_offset + symbol.st_name;
+ visit_sym(symbol, reinterpret_cast<const char*>(name));
+ }
+ }
+ }
+
+ // Visit CFI (unwind) data.
+ if (debug_frame != nullptr) {
+ const uint8_t* data = elf + debug_frame->sh_offset;
+ const uint8_t* end = data + debug_frame->sh_size;
+ while (data < end) {
+ Elf_Addr addr, size;
+ ArrayRef<const uint8_t> opcodes;
+ if (dwarf::ReadFDE<Elf_Addr>(&data, &addr, &size, &opcodes)) {
+ visit_fde(addr, size, opcodes);
+ }
+ }
+ }
+
+ // Process embedded compressed ELF file.
+ if (gnu_debugdata != nullptr) {
+ ArrayRef<const uint8_t> compressed(elf + gnu_debugdata->sh_offset, gnu_debugdata->sh_size);
+ std::vector<uint8_t> decompressed;
+ XzDecompress(compressed, &decompressed);
+ ReadElfSymbols<ElfTypes>(decompressed.data(), visit_sym, visit_fde);
+ }
+}
+
+} // namespace debug
+} // namespace art
+#endif // ART_COMPILER_DEBUG_ELF_DEBUG_READER_H_
diff --git a/compiler/debug/elf_debug_writer.cc b/compiler/debug/elf_debug_writer.cc
index 1ecb1d8e..56d773f 100644
--- a/compiler/debug/elf_debug_writer.cc
+++ b/compiler/debug/elf_debug_writer.cc
@@ -21,12 +21,14 @@
#include <vector>
#include "base/array_ref.h"
+#include "base/stl_util.h"
#include "debug/dwarf/dwarf_constants.h"
#include "debug/elf_compilation_unit.h"
#include "debug/elf_debug_frame_writer.h"
#include "debug/elf_debug_info_writer.h"
#include "debug/elf_debug_line_writer.h"
#include "debug/elf_debug_loc_writer.h"
+#include "debug/elf_debug_reader.h"
#include "debug/elf_symtab_writer.h"
#include "debug/method_debug_info.h"
#include "debug/xz_utils.h"
@@ -203,9 +205,147 @@
}
builder->End();
CHECK(builder->Good());
+ // Verify the ELF file by reading it back using the trivial reader.
+ if (kIsDebugBuild) {
+ using Elf_Sym = typename ElfTypes::Sym;
+ using Elf_Addr = typename ElfTypes::Addr;
+ size_t num_syms = 0;
+ size_t num_cfis = 0;
+ ReadElfSymbols<ElfTypes>(
+ buffer.data(),
+ [&](Elf_Sym sym, const char*) {
+ DCHECK_EQ(sym.st_value, method_info.code_address + CompiledMethod::CodeDelta(isa));
+ DCHECK_EQ(sym.st_size, method_info.code_size);
+ num_syms++;
+ },
+ [&](Elf_Addr addr, Elf_Addr size, ArrayRef<const uint8_t> opcodes) {
+ DCHECK_EQ(addr, method_info.code_address);
+ DCHECK_EQ(size, method_info.code_size);
+ DCHECK_GE(opcodes.size(), method_info.cfi.size());
+ DCHECK_EQ(memcmp(opcodes.data(), method_info.cfi.data(), method_info.cfi.size()), 0);
+ num_cfis++;
+ });
+ DCHECK_EQ(num_syms, 1u);
+ DCHECK_EQ(num_cfis, 1u);
+ }
return buffer;
}
+// Combine several mini-debug-info ELF files into one, while filtering some symbols.
+std::vector<uint8_t> PackElfFileForJIT(
+ InstructionSet isa,
+ const InstructionSetFeatures* features,
+ std::vector<const uint8_t*>& added_elf_files,
+ std::vector<const void*>& removed_symbols,
+ /*out*/ size_t* num_symbols) {
+ using ElfTypes = ElfRuntimeTypes;
+ using Elf_Addr = typename ElfTypes::Addr;
+ using Elf_Sym = typename ElfTypes::Sym;
+ CHECK_EQ(sizeof(Elf_Addr), static_cast<size_t>(GetInstructionSetPointerSize(isa)));
+ const bool is64bit = Is64BitInstructionSet(isa);
+ auto is_removed_symbol = [&removed_symbols](Elf_Addr addr) {
+ const void* code_ptr = reinterpret_cast<const void*>(addr);
+ return std::binary_search(removed_symbols.begin(), removed_symbols.end(), code_ptr);
+ };
+ uint64_t min_address = std::numeric_limits<uint64_t>::max();
+ uint64_t max_address = 0;
+
+ // Produce the inner ELF file.
+ // It will contain the symbols (.symtab) and unwind information (.debug_frame).
+ std::vector<uint8_t> inner_elf_file;
+ {
+ inner_elf_file.reserve(1 * KB); // Approximate size of ELF file with a single symbol.
+ linker::VectorOutputStream out("Mini-debug-info ELF file for JIT", &inner_elf_file);
+ std::unique_ptr<linker::ElfBuilder<ElfTypes>> builder(
+ new linker::ElfBuilder<ElfTypes>(isa, features, &out));
+ builder->Start(/*write_program_headers=*/ false);
+ auto* text = builder->GetText();
+ auto* strtab = builder->GetStrTab();
+ auto* symtab = builder->GetSymTab();
+ auto* debug_frame = builder->GetDebugFrame();
+ std::deque<Elf_Sym> symbols;
+ std::vector<uint8_t> debug_frame_buffer;
+ WriteCIE(isa, dwarf::DW_DEBUG_FRAME_FORMAT, &debug_frame_buffer);
+
+ // Write symbols names. All other data is buffered.
+ strtab->Start();
+ strtab->Write(""); // strtab should start with empty string.
+ for (const uint8_t* added_elf_file : added_elf_files) {
+ ReadElfSymbols<ElfTypes>(
+ added_elf_file,
+ [&](Elf_Sym sym, const char* name) {
+ if (is_removed_symbol(sym.st_value)) {
+ return;
+ }
+ sym.st_name = strtab->Write(name);
+ symbols.push_back(sym);
+ min_address = std::min<uint64_t>(min_address, sym.st_value);
+ max_address = std::max<uint64_t>(max_address, sym.st_value + sym.st_size);
+ },
+ [&](Elf_Addr addr, Elf_Addr size, ArrayRef<const uint8_t> opcodes) {
+ if (is_removed_symbol(addr)) {
+ return;
+ }
+ WriteFDE(is64bit,
+ /*section_address=*/ 0,
+ /*cie_address=*/ 0,
+ addr,
+ size,
+ opcodes,
+ dwarf::DW_DEBUG_FRAME_FORMAT,
+ debug_frame_buffer.size(),
+ &debug_frame_buffer,
+ /*patch_locations=*/ nullptr);
+ });
+ }
+ strtab->End();
+
+ // Create .text covering the code range. Needed for gdb to find the symbols.
+ if (max_address > min_address) {
+ text->AllocateVirtualMemory(min_address, max_address - min_address);
+ }
+
+ // Add the symbols.
+ *num_symbols = symbols.size();
+ for (; !symbols.empty(); symbols.pop_front()) {
+ symtab->Add(symbols.front(), text);
+ }
+ symtab->WriteCachedSection();
+
+ // Add the CFI/unwind section.
+ debug_frame->Start();
+ debug_frame->WriteFully(debug_frame_buffer.data(), debug_frame_buffer.size());
+ debug_frame->End();
+
+ builder->End();
+ CHECK(builder->Good());
+ }
+
+ // Produce the outer ELF file.
+ // It contains only the inner ELF file compressed as .gnu_debugdata section.
+ // This extra wrapping is not necessary but the compression saves space.
+ std::vector<uint8_t> outer_elf_file;
+ {
+ std::vector<uint8_t> gnu_debugdata;
+ gnu_debugdata.reserve(inner_elf_file.size() / 4);
+ XzCompress(ArrayRef<const uint8_t>(inner_elf_file), &gnu_debugdata);
+
+ outer_elf_file.reserve(KB + gnu_debugdata.size());
+ linker::VectorOutputStream out("Mini-debug-info ELF file for JIT", &outer_elf_file);
+ std::unique_ptr<linker::ElfBuilder<ElfTypes>> builder(
+ new linker::ElfBuilder<ElfTypes>(isa, features, &out));
+ builder->Start(/*write_program_headers=*/ false);
+ if (max_address > min_address) {
+ builder->GetText()->AllocateVirtualMemory(min_address, max_address - min_address);
+ }
+ builder->WriteSection(".gnu_debugdata", &gnu_debugdata);
+ builder->End();
+ CHECK(builder->Good());
+ }
+
+ return outer_elf_file;
+}
+
std::vector<uint8_t> WriteDebugElfFileForClasses(
InstructionSet isa,
const InstructionSetFeatures* features,
diff --git a/compiler/debug/elf_debug_writer.h b/compiler/debug/elf_debug_writer.h
index 8ad0c42..85ab356 100644
--- a/compiler/debug/elf_debug_writer.h
+++ b/compiler/debug/elf_debug_writer.h
@@ -56,6 +56,13 @@
bool mini_debug_info,
const MethodDebugInfo& method_info);
+std::vector<uint8_t> PackElfFileForJIT(
+ InstructionSet isa,
+ const InstructionSetFeatures* features,
+ std::vector<const uint8_t*>& added_elf_files,
+ std::vector<const void*>& removed_symbols,
+ /*out*/ size_t* num_symbols);
+
std::vector<uint8_t> WriteDebugElfFileForClasses(
InstructionSet isa,
const InstructionSetFeatures* features,
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index 0039be0..f52c566 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -1231,8 +1231,15 @@
bool operator()(ObjPtr<mirror::Class> klass) override REQUIRES_SHARED(Locks::mutator_lock_) {
std::string temp;
StringPiece name(klass->GetDescriptor(&temp));
- if (data_->image_class_descriptors_->find(name) != data_->image_class_descriptors_->end()) {
- data_->image_classes_.push_back(hs_.NewHandle(klass));
+ auto it = data_->image_class_descriptors_->find(name);
+ if (it != data_->image_class_descriptors_->end()) {
+ if (LIKELY(klass->IsResolved())) {
+ data_->image_classes_.push_back(hs_.NewHandle(klass));
+ } else {
+ DCHECK(klass->IsErroneousUnresolved());
+ VLOG(compiler) << "Removing unresolved class from image classes: " << name;
+ data_->image_class_descriptors_->erase(it);
+ }
} else {
// Check whether it is initialized and has a clinit. They must be kept, too.
if (klass->IsInitialized() && klass->FindClassInitializer(
diff --git a/compiler/jit/jit_compiler.cc b/compiler/jit/jit_compiler.cc
index e57bbfa..93575d7 100644
--- a/compiler/jit/jit_compiler.cc
+++ b/compiler/jit/jit_compiler.cc
@@ -146,7 +146,10 @@
// (which would have been otherwise used as identifier to remove it later).
AddNativeDebugInfoForJit(Thread::Current(),
/*code_ptr=*/ nullptr,
- elf_file);
+ elf_file,
+ debug::PackElfFileForJIT,
+ compiler_options.GetInstructionSet(),
+ compiler_options.GetInstructionSetFeatures());
}
}
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index c9b4d36..4936a6d 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -1456,8 +1456,8 @@
return true;
}
-void OptimizingCompiler::GenerateJitDebugInfo(
- ArtMethod* method, const debug::MethodDebugInfo& info) {
+void OptimizingCompiler::GenerateJitDebugInfo(ArtMethod* method ATTRIBUTE_UNUSED,
+ const debug::MethodDebugInfo& info) {
const CompilerOptions& compiler_options = GetCompilerDriver()->GetCompilerOptions();
DCHECK(compiler_options.GenerateAnyDebugInfo());
@@ -1472,12 +1472,10 @@
info);
AddNativeDebugInfoForJit(Thread::Current(),
reinterpret_cast<const void*>(info.code_address),
- elf_file);
-
- VLOG(jit)
- << "JIT mini-debug-info added for " << ArtMethod::PrettyMethod(method)
- << " size=" << PrettySize(elf_file.size())
- << " total_size=" << PrettySize(GetJitMiniDebugInfoMemUsage());
+ elf_file,
+ debug::PackElfFileForJIT,
+ compiler_options.GetInstructionSet(),
+ compiler_options.GetInstructionSetFeatures());
}
} // namespace art
diff --git a/dexdump/Android.bp b/dexdump/Android.bp
index d15bbda..434cb35 100644
--- a/dexdump/Android.bp
+++ b/dexdump/Android.bp
@@ -49,6 +49,9 @@
darwin: {
enabled: false,
},
+ windows: {
+ enabled: true,
+ },
},
}
diff --git a/libartbase/Android.bp b/libartbase/Android.bp
index c3fb5fd..0fcd6a5 100644
--- a/libartbase/Android.bp
+++ b/libartbase/Android.bp
@@ -35,7 +35,6 @@
"base/memory_region.cc",
"base/mem_map.cc",
// "base/mem_map_fuchsia.cc", put in target when fuchsia supported by soong
- "base/mem_map_unix.cc",
"base/os_linux.cc",
"base/runtime_debug.cc",
"base/safe_copy.cc",
@@ -50,20 +49,38 @@
],
target: {
android: {
+ srcs: [
+ "base/mem_map_unix.cc",
+ ],
static_libs: [
// ZipArchive support, the order matters here to get all symbols.
"libziparchive",
"libz",
],
+ shared_libs: [
+ "liblog",
+ // For ashmem.
+ "libcutils",
+ // For common macros.
+ "libbase",
+ ],
// Exclude the version script from Darwin host since it's not
// supported by the linker there. That means ASan checks on Darwin
// might trigger ODR violations.
version_script: "libartbase.map",
},
- host: {
+ not_windows: {
+ srcs: [
+ "base/mem_map_unix.cc",
+ ],
shared_libs: [
"libziparchive",
"libz",
+ "liblog",
+ // For ashmem.
+ "libcutils",
+ // For common macros.
+ "libbase",
],
},
linux_glibc: {
@@ -71,17 +88,20 @@
},
windows: {
version_script: "libartbase.map",
+ static_libs: [
+ "libziparchive",
+ "libz",
+ "liblog",
+ // For ashmem.
+ "libcutils",
+ // For common macros.
+ "libbase",
+ ],
+ cflags: ["-Wno-thread-safety"],
},
},
generated_sources: ["art_libartbase_operator_srcs"],
cflags: ["-DBUILDING_LIBART=1"],
- shared_libs: [
- "liblog",
- // For ashmem.
- "libcutils",
- // For common macros.
- "libbase",
- ],
// Utilities used by various ART libs and tools are linked in statically
// here to avoid shared lib dependencies outside the ART APEX. No target
@@ -147,6 +167,14 @@
"libziparchive",
],
export_shared_lib_headers: ["libbase"],
+ target: {
+ windows: {
+ enabled: true,
+ shared: {
+ enabled: false,
+ },
+ },
+ },
}
art_cc_library {
@@ -160,6 +188,14 @@
"libziparchive",
],
export_shared_lib_headers: ["libbase"],
+ target: {
+ windows: {
+ enabled: true,
+ shared: {
+ enabled: false,
+ },
+ },
+ },
}
art_cc_library {
diff --git a/libartbase/base/arena_allocator.cc b/libartbase/base/arena_allocator.cc
index df3deba..0e7f6cc 100644
--- a/libartbase/base/arena_allocator.cc
+++ b/libartbase/base/arena_allocator.cc
@@ -16,7 +16,6 @@
#include "arena_allocator-inl.h"
-#include <sys/mman.h>
#include <algorithm>
#include <cstddef>
@@ -25,6 +24,8 @@
#include <android-base/logging.h>
+#include "mman.h"
+
namespace art {
constexpr size_t kMemoryToolRedZoneBytes = 8;
diff --git a/libartbase/base/file_utils.cc b/libartbase/base/file_utils.cc
index f8d6016..9490798 100644
--- a/libartbase/base/file_utils.cc
+++ b/libartbase/base/file_utils.cc
@@ -19,11 +19,13 @@
#include <inttypes.h>
#include <sys/stat.h>
#include <sys/types.h>
+#ifndef _WIN32
#include <sys/wait.h>
+#endif
#include <unistd.h>
// We need dladdr.
-#ifndef __APPLE__
+#if !defined(__APPLE__) && !defined(_WIN32)
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#define DEFINED_GNU_SOURCE
@@ -84,6 +86,10 @@
}
std::string GetAndroidRootSafe(std::string* error_msg) {
+#ifdef _WIN32
+ *error_msg = "GetAndroidRootSafe unsupported for Windows.";
+ return "";
+#else
// Prefer ANDROID_ROOT if it's set.
const char* android_dir = getenv("ANDROID_ROOT");
if (android_dir != nullptr) {
@@ -118,6 +124,7 @@
return "";
}
return "/system";
+#endif
}
std::string GetAndroidRoot() {
@@ -179,6 +186,15 @@
void GetDalvikCache(const char* subdir, const bool create_if_absent, std::string* dalvik_cache,
bool* have_android_data, bool* dalvik_cache_exists, bool* is_global_cache) {
+#ifdef _WIN32
+ UNUSED(subdir);
+ UNUSED(create_if_absent);
+ UNUSED(dalvik_cache);
+ UNUSED(have_android_data);
+ UNUSED(dalvik_cache_exists);
+ UNUSED(is_global_cache);
+ LOG(FATAL) << "GetDalvikCache unsupported on Windows.";
+#else
CHECK(subdir != nullptr);
std::string error_msg;
const char* android_data = GetAndroidDataSafe(&error_msg);
@@ -199,6 +215,7 @@
*dalvik_cache_exists = ((mkdir(dalvik_cache_root.c_str(), 0700) == 0 || errno == EEXIST) &&
(mkdir(dalvik_cache->c_str(), 0700) == 0 || errno == EEXIST));
}
+#endif
}
std::string GetDalvikCache(const char* subdir) {
@@ -262,9 +279,15 @@
}
bool LocationIsOnSystem(const char* path) {
+#ifdef _WIN32
+ UNUSED(path);
+ LOG(FATAL) << "LocationIsOnSystem is unsupported on Windows.";
+ return false;
+#else
UniqueCPtr<const char[]> full_path(realpath(path, nullptr));
return full_path != nullptr &&
android::base::StartsWith(full_path.get(), GetAndroidRoot().c_str());
+#endif
}
bool LocationIsOnSystemFramework(const char* full_path) {
diff --git a/libartbase/base/malloc_arena_pool.cc b/libartbase/base/malloc_arena_pool.cc
index 02e29f1..4de34b5 100644
--- a/libartbase/base/malloc_arena_pool.cc
+++ b/libartbase/base/malloc_arena_pool.cc
@@ -16,7 +16,6 @@
#include "malloc_arena_pool.h"
-#include <sys/mman.h>
#include <algorithm>
#include <cstddef>
@@ -25,6 +24,7 @@
#include <android-base/logging.h>
#include "arena_allocator-inl.h"
+#include "mman.h"
namespace art {
diff --git a/libartbase/base/mem_map.cc b/libartbase/base/mem_map.cc
index 532ca28..2833750 100644
--- a/libartbase/base/mem_map.cc
+++ b/libartbase/base/mem_map.cc
@@ -18,8 +18,7 @@
#include <inttypes.h>
#include <stdlib.h>
-#include <sys/mman.h> // For the PROT_* and MAP_* constants.
-#if !defined(ANDROID_OS) && !defined(__Fuchsia__)
+#if !defined(ANDROID_OS) && !defined(__Fuchsia__) && !defined(_WIN32)
#include <sys/resource.h>
#endif
@@ -39,6 +38,7 @@
#include "globals.h"
#include "logging.h" // For VLOG_IS_ON.
#include "memory_tool.h"
+#include "mman.h" // For the PROT_* and MAP_* constants.
#include "utils.h"
#ifndef MAP_ANONYMOUS
@@ -811,19 +811,30 @@
if (!kMadviseZeroes) {
memset(base_begin_, 0, base_size_);
}
+#ifdef _WIN32
+ // It is benign not to madvise away the pages here.
+ PLOG(WARNING) << "MemMap::MadviseDontNeedAndZero does not madvise on Windows.";
+#else
int result = madvise(base_begin_, base_size_, MADV_DONTNEED);
if (result == -1) {
PLOG(WARNING) << "madvise failed";
}
+#endif
}
}
bool MemMap::Sync() {
+#ifdef _WIN32
+ // TODO: add FlushViewOfFile support.
+ PLOG(ERROR) << "MemMap::Sync unsupported on Windows.";
+ return false;
+#else
// Historical note: To avoid Valgrind errors, we temporarily lifted the lower-end noaccess
// protection before passing it to msync() when `redzone_size_` was non-null, as Valgrind
// only accepts page-aligned base address, and excludes the higher-end noaccess protection
// from the msync range. b/27552451.
return msync(BaseBegin(), BaseSize(), MS_SYNC) == 0;
+#endif
}
bool MemMap::Protect(int prot) {
@@ -832,10 +843,12 @@
return true;
}
+#ifndef _WIN32
if (mprotect(base_begin_, base_size_, prot) == 0) {
prot_ = prot;
return true;
}
+#endif
PLOG(ERROR) << "mprotect(" << reinterpret_cast<void*>(base_begin_) << ", " << base_size_ << ", "
<< prot << ") failed";
@@ -1206,7 +1219,11 @@
DCHECK_LE(page_begin, page_end);
DCHECK_LE(page_end, mem_end);
std::fill(mem_begin, page_begin, 0);
+#ifdef _WIN32
+ LOG(WARNING) << "ZeroAndReleasePages does not madvise on Windows.";
+#else
CHECK_NE(madvise(page_begin, page_end - page_begin, MADV_DONTNEED), -1) << "madvise failed";
+#endif
std::fill(page_end, mem_end, 0);
}
}
diff --git a/libartbase/base/mem_map_fuchsia.cc b/libartbase/base/mem_map_fuchsia.cc
index d1c92ce..6b0e06c 100644
--- a/libartbase/base/mem_map_fuchsia.cc
+++ b/libartbase/base/mem_map_fuchsia.cc
@@ -15,8 +15,8 @@
*/
#include "mem_map.h"
-#include <sys/mman.h>
#include "logging.h"
+#include "mman.h"
#include <zircon/process.h>
#include <zircon/syscalls.h>
diff --git a/libartbase/base/mem_map_test.cc b/libartbase/base/mem_map_test.cc
index 074d4c2..bf39fd1 100644
--- a/libartbase/base/mem_map_test.cc
+++ b/libartbase/base/mem_map_test.cc
@@ -16,8 +16,6 @@
#include "mem_map.h"
-#include <sys/mman.h>
-
#include <memory>
#include <random>
@@ -25,6 +23,7 @@
#include "common_runtime_test.h" // For TEST_DISABLED_FOR_MIPS
#include "logging.h"
#include "memory_tool.h"
+#include "mman.h"
#include "unix_file/fd_file.h"
namespace art {
diff --git a/libartbase/base/mem_map_unix.cc b/libartbase/base/mem_map_unix.cc
index 601b049..ac854df 100644
--- a/libartbase/base/mem_map_unix.cc
+++ b/libartbase/base/mem_map_unix.cc
@@ -16,7 +16,7 @@
#include "mem_map.h"
-#include <sys/mman.h>
+#include "mman.h"
namespace art {
diff --git a/libartbase/base/membarrier.cc b/libartbase/base/membarrier.cc
index 4c86b6b..abb36bc 100644
--- a/libartbase/base/membarrier.cc
+++ b/libartbase/base/membarrier.cc
@@ -18,8 +18,10 @@
#include <errno.h>
+#if !defined(_WIN32)
#include <sys/syscall.h>
#include <unistd.h>
+#endif
#include "macros.h"
#if defined(__BIONIC__)
diff --git a/libartbase/base/memfd.cc b/libartbase/base/memfd.cc
index 7c20401..780be32 100644
--- a/libartbase/base/memfd.cc
+++ b/libartbase/base/memfd.cc
@@ -18,9 +18,11 @@
#include <errno.h>
#include <stdio.h>
+#if !defined(_WIN32)
#include <sys/syscall.h>
#include <sys/utsname.h>
#include <unistd.h>
+#endif
#include "macros.h"
diff --git a/libartbase/base/mman.h b/libartbase/base/mman.h
new file mode 100644
index 0000000..bd63f65
--- /dev/null
+++ b/libartbase/base/mman.h
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ */
+
+#ifndef ART_LIBARTBASE_BASE_MMAN_H_
+#define ART_LIBARTBASE_BASE_MMAN_H_
+
+#ifdef _WIN32
+
+// There is no sys/mman.h in mingw.
+// As these are just placeholders for the APIs, all values are stubbed out.
+
+#define PROT_READ 0 // 0x1
+#define PROT_WRITE 0 // 0x2
+#define PROT_EXEC 0 // 0x4
+#define PROT_NONE 0 // 0x0
+
+#define MAP_SHARED 0 // 0x01
+#define MAP_PRIVATE 0 // 0x02
+
+#define MAP_FAILED nullptr // ((void*) -1)
+#define MAP_FIXED 0 // 0x10
+#define MAP_ANONYMOUS 0 // 0x20
+
+#else
+
+#include <sys/mman.h>
+
+#endif
+
+
+#endif // ART_LIBARTBASE_BASE_MMAN_H_
diff --git a/libartbase/base/os_linux.cc b/libartbase/base/os_linux.cc
index f8b31cf..a00779e 100644
--- a/libartbase/base/os_linux.cc
+++ b/libartbase/base/os_linux.cc
@@ -50,7 +50,12 @@
}
File* OS::CreateEmptyFileWriteOnly(const char* name) {
- return art::CreateEmptyFile(name, O_WRONLY | O_TRUNC | O_NOFOLLOW | O_CLOEXEC);
+#ifdef _WIN32
+ int flags = O_WRONLY | O_TRUNC;
+#else
+ int flags = O_WRONLY | O_TRUNC | O_NOFOLLOW | O_CLOEXEC;
+#endif
+ return art::CreateEmptyFile(name, flags);
}
File* OS::OpenFileWithFlags(const char* name, int flags, bool auto_flush) {
diff --git a/libartbase/base/safe_copy.cc b/libartbase/base/safe_copy.cc
index b46b921..ad75aa7 100644
--- a/libartbase/base/safe_copy.cc
+++ b/libartbase/base/safe_copy.cc
@@ -16,8 +16,10 @@
#include "safe_copy.h"
+#ifdef __linux__
#include <sys/uio.h>
#include <sys/user.h>
+#endif
#include <unistd.h>
#include <algorithm>
diff --git a/libartbase/base/safe_copy_test.cc b/libartbase/base/safe_copy_test.cc
index c23651f..9f7d409 100644
--- a/libartbase/base/safe_copy_test.cc
+++ b/libartbase/base/safe_copy_test.cc
@@ -18,12 +18,12 @@
#include <errno.h>
#include <string.h>
-#include <sys/mman.h>
#include <sys/user.h>
#include "android-base/logging.h"
#include "globals.h"
#include "gtest/gtest.h"
+#include "mman.h"
namespace art {
diff --git a/libartbase/base/scoped_flock.cc b/libartbase/base/scoped_flock.cc
index 2f16fb2..b16a45a 100644
--- a/libartbase/base/scoped_flock.cc
+++ b/libartbase/base/scoped_flock.cc
@@ -35,6 +35,14 @@
/* static */ ScopedFlock LockedFile::Open(const char* filename, int flags, bool block,
std::string* error_msg) {
+#ifdef _WIN32
+ // TODO: implement file locking for Windows.
+ UNUSED(filename);
+ UNUSED(flags);
+ UNUSED(block);
+ *error_msg = "flock is unsupported on Windows";
+ return nullptr;
+#else
while (true) {
// NOTE: We don't check usage here because the ScopedFlock should *never* be
// responsible for flushing its underlying FD. Its only purpose should be
@@ -89,10 +97,19 @@
return ScopedFlock(new LockedFile(std::move((*file.get()))));
}
+#endif
}
ScopedFlock LockedFile::DupOf(const int fd, const std::string& path,
const bool read_only_mode, std::string* error_msg) {
+#ifdef _WIN32
+ // TODO: implement file locking for Windows.
+ UNUSED(fd);
+ UNUSED(path);
+ UNUSED(read_only_mode);
+ *error_msg = "flock is unsupported on Windows.";
+ return nullptr;
+#else
// NOTE: We don't check usage here because the ScopedFlock should *never* be
// responsible for flushing its underlying FD. Its only purpose should be
// to acquire a lock, and the unlock / close in the corresponding
@@ -112,9 +129,11 @@
}
return locked_file;
+#endif
}
void LockedFile::ReleaseLock() {
+#ifndef _WIN32
if (this->Fd() != -1) {
int flock_result = TEMP_FAILURE_RETRY(flock(this->Fd(), LOCK_UN));
if (flock_result != 0) {
@@ -126,6 +145,7 @@
PLOG(WARNING) << "Unable to unlock file " << this->GetPath();
}
}
+#endif
}
} // namespace art
diff --git a/libartbase/base/socket_peer_is_trusted.cc b/libartbase/base/socket_peer_is_trusted.cc
index 440054e..3996d90 100644
--- a/libartbase/base/socket_peer_is_trusted.cc
+++ b/libartbase/base/socket_peer_is_trusted.cc
@@ -16,8 +16,10 @@
#include "socket_peer_is_trusted.h"
+#if !defined(_WIN32)
#include <pwd.h>
#include <sys/socket.h>
+#endif
#include <android-base/logging.h>
diff --git a/libartbase/base/time_utils.cc b/libartbase/base/time_utils.cc
index cb30246..aa6c987 100644
--- a/libartbase/base/time_utils.cc
+++ b/libartbase/base/time_utils.cc
@@ -14,12 +14,14 @@
* limitations under the License.
*/
+#include "time_utils.h"
+
#include <inttypes.h>
+#include <stdio.h>
+
#include <limits>
#include <sstream>
-#include "time_utils.h"
-
#include "android-base/stringprintf.h"
#include "logging.h"
@@ -30,6 +32,20 @@
namespace art {
+namespace {
+
+#if !defined(__linux__)
+int GetTimeOfDay(struct timeval* tv, struct timezone* tz) {
+#ifdef _WIN32
+ return mingw_gettimeofday(tv, tz);
+#else
+ return gettimeofday(tv, tz);
+#endif
+}
+#endif
+
+} // namespace
+
using android::base::StringPrintf;
std::string PrettyDuration(uint64_t nano_duration, size_t max_fraction_digits) {
@@ -117,7 +133,12 @@
std::string GetIsoDate() {
time_t now = time(nullptr);
tm tmbuf;
+#ifdef _WIN32
+ localtime_s(&tmbuf, &now);
+ tm* ptm = &tmbuf;
+#else
tm* ptm = localtime_r(&now, &tmbuf);
+#endif
return StringPrintf("%04d-%02d-%02d %02d:%02d:%02d",
ptm->tm_year + 1900, ptm->tm_mon+1, ptm->tm_mday,
ptm->tm_hour, ptm->tm_min, ptm->tm_sec);
@@ -130,7 +151,7 @@
return static_cast<uint64_t>(now.tv_sec) * UINT64_C(1000) + now.tv_nsec / UINT64_C(1000000);
#else
timeval now;
- gettimeofday(&now, nullptr);
+ GetTimeOfDay(&now, nullptr);
return static_cast<uint64_t>(now.tv_sec) * UINT64_C(1000) + now.tv_usec / UINT64_C(1000);
#endif
}
@@ -142,7 +163,7 @@
return static_cast<uint64_t>(now.tv_sec) * UINT64_C(1000000) + now.tv_nsec / UINT64_C(1000);
#else
timeval now;
- gettimeofday(&now, nullptr);
+ GetTimeOfDay(&now, nullptr);
return static_cast<uint64_t>(now.tv_sec) * UINT64_C(1000000) + now.tv_usec;
#endif
}
@@ -154,7 +175,7 @@
return static_cast<uint64_t>(now.tv_sec) * UINT64_C(1000000000) + now.tv_nsec;
#else
timeval now;
- gettimeofday(&now, nullptr);
+ GetTimeOfDay(&now, nullptr);
return static_cast<uint64_t>(now.tv_sec) * UINT64_C(1000000000) + now.tv_usec * UINT64_C(1000);
#endif
}
@@ -195,12 +216,12 @@
void InitTimeSpec(bool absolute, int clock, int64_t ms, int32_t ns, timespec* ts) {
if (absolute) {
-#if !defined(__APPLE__)
+#if defined(__linux__)
clock_gettime(clock, ts);
#else
UNUSED(clock);
timeval tv;
- gettimeofday(&tv, nullptr);
+ GetTimeOfDay(&tv, nullptr);
ts->tv_sec = tv.tv_sec;
ts->tv_nsec = tv.tv_usec * 1000;
#endif
diff --git a/libartbase/base/time_utils.h b/libartbase/base/time_utils.h
index 431d3e1..15805f3 100644
--- a/libartbase/base/time_utils.h
+++ b/libartbase/base/time_utils.h
@@ -18,6 +18,7 @@
#define ART_LIBARTBASE_BASE_TIME_UTILS_H_
#include <stdint.h>
+#include <stdio.h> // Needed for correct _WIN32 build.
#include <time.h>
#include <string>
diff --git a/libartbase/base/unix_file/fd_file.cc b/libartbase/base/unix_file/fd_file.cc
index 76894c6..8831b9c 100644
--- a/libartbase/base/unix_file/fd_file.cc
+++ b/libartbase/base/unix_file/fd_file.cc
@@ -25,8 +25,13 @@
#include <android/fdsan.h>
#endif
+#if defined(_WIN32)
+#include <windows.h>
+#endif
+
#include <limits>
+#include <android-base/file.h>
#include <android-base/logging.h>
// Includes needed for FdFile::Copy().
@@ -40,6 +45,96 @@
namespace unix_file {
+#if defined(_WIN32)
+// RAII wrapper for an event object to allow asynchronous I/O to correctly signal completion.
+class ScopedEvent {
+ public:
+ ScopedEvent() {
+ handle_ = CreateEventA(/*lpEventAttributes*/ nullptr,
+ /*bManualReset*/ true,
+ /*bInitialState*/ false,
+ /*lpName*/ nullptr);
+ }
+
+ ~ScopedEvent() { CloseHandle(handle_); }
+
+ HANDLE handle() { return handle_; }
+
+ private:
+ HANDLE handle_;
+ DISALLOW_COPY_AND_ASSIGN(ScopedEvent);
+};
+
+// Windows implementation of pread/pwrite. Note that these DO move the file descriptor's read/write
+// position, but do so atomically.
+static ssize_t pread(int fd, void* data, size_t byte_count, off64_t offset) {
+ ScopedEvent event;
+ if (event.handle() == INVALID_HANDLE_VALUE) {
+ PLOG(ERROR) << "Could not create event handle.";
+ errno = EIO;
+ return static_cast<ssize_t>(-1);
+ }
+
+ auto handle = reinterpret_cast<HANDLE>(_get_osfhandle(fd));
+ DWORD bytes_read = 0;
+ OVERLAPPED overlapped = {};
+ overlapped.Offset = static_cast<DWORD>(offset);
+ overlapped.OffsetHigh = static_cast<DWORD>(offset >> 32);
+ overlapped.hEvent = event.handle();
+ if (!ReadFile(handle, data, static_cast<DWORD>(byte_count), &bytes_read, &overlapped)) {
+ // If the read failed with other than ERROR_IO_PENDING, return an error.
+ // ERROR_IO_PENDING signals the write was begun asynchronously.
+ // Block until the asynchronous operation has finished or fails, and return
+ // result accordingly.
+ if (::GetLastError() != ERROR_IO_PENDING ||
+ !::GetOverlappedResult(handle, &overlapped, &bytes_read, TRUE)) {
+ // In case someone tries to read errno (since this is masquerading as a POSIX call).
+ errno = EIO;
+ return static_cast<ssize_t>(-1);
+ }
+ }
+ return static_cast<ssize_t>(bytes_read);
+}
+
+static ssize_t pwrite(int fd, const void* buf, size_t count, off64_t offset) {
+ ScopedEvent event;
+ if (event.handle() == INVALID_HANDLE_VALUE) {
+ PLOG(ERROR) << "Could not create event handle.";
+ errno = EIO;
+ return static_cast<ssize_t>(-1);
+ }
+
+ auto handle = reinterpret_cast<HANDLE>(_get_osfhandle(fd));
+ DWORD bytes_written = 0;
+ OVERLAPPED overlapped = {};
+ overlapped.Offset = static_cast<DWORD>(offset);
+ overlapped.OffsetHigh = static_cast<DWORD>(offset >> 32);
+ overlapped.hEvent = event.handle();
+ if (!::WriteFile(handle, buf, count, &bytes_written, &overlapped)) {
+ // If the write failed with other than ERROR_IO_PENDING, return an error.
+ // ERROR_IO_PENDING signals the write was begun asynchronously.
+ // Block until the asynchronous operation has finished or fails, and return
+ // result accordingly.
+ if (::GetLastError() != ERROR_IO_PENDING ||
+ !::GetOverlappedResult(handle, &overlapped, &bytes_written, TRUE)) {
+ // In case someone tries to read errno (since this is masquerading as a POSIX call).
+ errno = EIO;
+ return static_cast<ssize_t>(-1);
+ }
+ }
+ return static_cast<ssize_t>(bytes_written);
+}
+
+static int fsync(int fd) {
+ auto handle = reinterpret_cast<HANDLE>(_get_osfhandle(fd));
+ if (handle != INVALID_HANDLE_VALUE && ::FlushFileBuffers(handle)) {
+ return 0;
+ }
+ errno = EINVAL;
+ return -1;
+}
+#endif
+
#if defined(__BIONIC__)
static uint64_t GetFdFileOwnerTag(FdFile* fd_file) {
return android_fdsan_create_owner_tag(ANDROID_FDSAN_OWNER_TYPE_ART_FDFILE,
diff --git a/libartbase/base/utils.cc b/libartbase/base/utils.cc
index 0f172fd..58d8575 100644
--- a/libartbase/base/utils.cc
+++ b/libartbase/base/utils.cc
@@ -19,9 +19,7 @@
#include <inttypes.h>
#include <pthread.h>
#include <sys/stat.h>
-#include <sys/syscall.h>
#include <sys/types.h>
-#include <sys/wait.h>
#include <unistd.h>
#include <fstream>
@@ -47,6 +45,16 @@
#if defined(__linux__)
#include <linux/unistd.h>
+#include <sys/syscall.h>
+#endif
+
+#if defined(_WIN32)
+#include <windows.h>
+// This include needs to be here due to our coding conventions. Unfortunately
+// it drags in the definition of the dread ERROR macro.
+#ifdef ERROR
+#undef ERROR
+#endif
#endif
namespace art {
@@ -61,6 +69,8 @@
return owner;
#elif defined(__BIONIC__)
return gettid();
+#elif defined(_WIN32)
+ return static_cast<pid_t>(::GetCurrentThreadId());
#else
return syscall(__NR_gettid);
#endif
@@ -68,12 +78,17 @@
std::string GetThreadName(pid_t tid) {
std::string result;
+#ifdef _WIN32
+ UNUSED(tid);
+ result = "<unknown>";
+#else
// TODO: make this less Linux-specific.
if (ReadFileToString(StringPrintf("/proc/self/task/%d/comm", tid), &result)) {
result.resize(result.size() - 1); // Lose the trailing '\n'.
} else {
result = "<unknown>";
}
+#endif
return result;
}
@@ -137,7 +152,7 @@
} else {
s = thread_name + len - 15;
}
-#if defined(__linux__)
+#if defined(__linux__) || defined(_WIN32)
// pthread_setname_np fails rather than truncating long strings.
char buf[16]; // MAX_TASK_COMM_LEN=16 is hard-coded in the kernel.
strncpy(buf, s, sizeof(buf)-1);
@@ -153,6 +168,11 @@
void GetTaskStats(pid_t tid, char* state, int* utime, int* stime, int* task_cpu) {
*utime = *stime = *task_cpu = 0;
+#ifdef _WIN32
+ // TODO: implement this.
+ UNUSED(tid);
+ *state = 'S';
+#else
std::string stats;
// TODO: make this less Linux-specific.
if (!ReadFileToString(StringPrintf("/proc/self/task/%d/stat", tid), &stats)) {
@@ -167,6 +187,7 @@
*utime = strtoull(fields[11].c_str(), nullptr, 10);
*stime = strtoull(fields[12].c_str(), nullptr, 10);
*task_cpu = strtoull(fields[36].c_str(), nullptr, 10);
+#endif
}
static void ParseStringAfterChar(const std::string& s,
diff --git a/libartbase/base/zip_archive.cc b/libartbase/base/zip_archive.cc
index a7f4b28..5056edc 100644
--- a/libartbase/base/zip_archive.cc
+++ b/libartbase/base/zip_archive.cc
@@ -18,7 +18,6 @@
#include <fcntl.h>
#include <stdio.h>
-#include <sys/mman.h> // For the PROT_* and MAP_* constants.
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
@@ -27,6 +26,7 @@
#include "android-base/stringprintf.h"
#include "ziparchive/zip_archive.h"
+#include "base/mman.h"
#include "bit_utils.h"
#include "unix_file/fd_file.h"
@@ -203,6 +203,11 @@
}
static void SetCloseOnExec(int fd) {
+#ifdef _WIN32
+ // Exec is not supported on Windows.
+ UNUSED(fd);
+ PLOG(ERROR) << "SetCloseOnExec is not supported on Windows.";
+#else
// This dance is more portable than Linux's O_CLOEXEC open(2) flag.
int flags = fcntl(fd, F_GETFD);
if (flags == -1) {
@@ -214,6 +219,7 @@
PLOG(WARNING) << "fcntl(" << fd << ", F_SETFD, " << flags << ") failed";
return;
}
+#endif
}
ZipArchive* ZipArchive::Open(const char* filename, std::string* error_msg) {
diff --git a/libdexfile/Android.bp b/libdexfile/Android.bp
index 4d6aa5c..a4f7e25 100644
--- a/libdexfile/Android.bp
+++ b/libdexfile/Android.bp
@@ -43,30 +43,58 @@
"libziparchive",
"libz",
],
+ shared_libs: [
+ // For MemMap.
+ "libartbase",
+ "liblog",
+ // For atrace.
+ "libcutils",
+ // For common macros.
+ "libbase",
+ ],
+ export_shared_lib_headers: [
+ "libartbase",
+ "libbase",
+ ],
},
- host: {
+ not_windows: {
shared_libs: [
"libziparchive",
"libz",
+ // For MemMap.
+ "libartbase",
+ "liblog",
+ // For atrace.
+ "libcutils",
+ // For common macros.
+ "libbase",
],
+ export_shared_lib_headers: [
+ "libartbase",
+ "libbase",
+ ],
+ },
+ windows: {
+ static_libs: [
+ "libziparchive",
+ "libz",
+ // For MemMap.
+ "libartbase",
+ "liblog",
+ // For atrace.
+ "libcutils",
+ // For common macros.
+ "libbase",
+ ],
+ export_static_lib_headers: [
+ "libartbase",
+ "libbase",
+ ],
+ cflags: ["-Wno-thread-safety"],
},
},
generated_sources: ["dexfile_operator_srcs"],
- shared_libs: [
- // For MemMap.
- "libartbase",
- "liblog",
- // For atrace.
- "libcutils",
- // For common macros.
- "libbase",
- "libz",
- ],
export_include_dirs: ["."],
- export_shared_lib_headers: [
- "libartbase",
- "libbase",
- ],
}
cc_defaults {
@@ -121,6 +149,14 @@
strip: {
keep_symbols: true,
},
+ target: {
+ windows: {
+ enabled: true,
+ shared: {
+ enabled: false,
+ },
+ },
+ },
}
art_cc_library {
@@ -129,6 +165,14 @@
"art_debug_defaults",
"libdexfile_defaults",
],
+ target: {
+ windows: {
+ enabled: true,
+ shared: {
+ enabled: false,
+ },
+ },
+ },
}
cc_library_headers {
diff --git a/libdexfile/dex/art_dex_file_loader.cc b/libdexfile/dex/art_dex_file_loader.cc
index ae1322d..57e838f 100644
--- a/libdexfile/dex/art_dex_file_loader.cc
+++ b/libdexfile/dex/art_dex_file_loader.cc
@@ -16,7 +16,6 @@
#include "art_dex_file_loader.h"
-#include <sys/mman.h> // For the PROT_* and MAP_* constants.
#include <sys/stat.h>
#include "android-base/stringprintf.h"
@@ -24,6 +23,7 @@
#include "base/file_magic.h"
#include "base/file_utils.h"
#include "base/mem_map.h"
+#include "base/mman.h" // For the PROT_* and MAP_* constants.
#include "base/stl_util.h"
#include "base/systrace.h"
#include "base/unix_file/fd_file.h"
diff --git a/libdexfile/dex/dex_file_layout.cc b/libdexfile/dex/dex_file_layout.cc
index 75a3111..929025a 100644
--- a/libdexfile/dex/dex_file_layout.cc
+++ b/libdexfile/dex/dex_file_layout.cc
@@ -16,9 +16,9 @@
#include "dex_file_layout.h"
-#include <sys/mman.h>
#include "base/bit_utils.h"
+#include "base/mman.h"
#include "dex_file.h"
namespace art {
@@ -26,6 +26,12 @@
int DexLayoutSection::MadviseLargestPageAlignedRegion(const uint8_t* begin,
const uint8_t* end,
int advice) {
+#ifdef _WIN32
+ UNUSED(begin);
+ UNUSED(end);
+ UNUSED(advice);
+ PLOG(WARNING) << "madvise is unsupported on Windows.";
+#else
DCHECK_LE(begin, end);
begin = AlignUp(begin, kPageSize);
end = AlignDown(end, kPageSize);
@@ -37,6 +43,7 @@
}
return result;
}
+#endif
return 0;
}
@@ -50,6 +57,11 @@
}
void DexLayoutSections::Madvise(const DexFile* dex_file, MadviseState state) const {
+#ifdef _WIN32
+ UNUSED(dex_file);
+ UNUSED(state);
+ PLOG(WARNING) << "madvise is unsupported on Windows.";
+#else
// The dex file is already defaulted to random access everywhere.
for (const DexLayoutSection& section : sections_) {
switch (state) {
@@ -79,6 +91,7 @@
}
}
}
+#endif
}
std::ostream& operator<<(std::ostream& os, const DexLayoutSection& section) {
diff --git a/libdexfile/dex/dex_file_loader.cc b/libdexfile/dex/dex_file_loader.cc
index 1884bcf..a719d41 100644
--- a/libdexfile/dex/dex_file_loader.cc
+++ b/libdexfile/dex/dex_file_loader.cc
@@ -187,12 +187,18 @@
std::string base_location = GetBaseLocation(dex_location);
const char* suffix = dex_location + base_location.size();
DCHECK(suffix[0] == 0 || suffix[0] == kMultiDexSeparator);
+#ifdef _WIN32
+ // Warning: No symbolic link processing here.
+ PLOG(WARNING) << "realpath is unsupported on Windows.";
+#else
// Warning: Bionic implementation of realpath() allocates > 12KB on the stack.
// Do not run this code on a small stack, e.g. in signal handler.
UniqueCPtr<const char[]> path(realpath(base_location.c_str(), nullptr));
if (path != nullptr && path.get() != base_location) {
return std::string(path.get()) + suffix;
- } else if (suffix[0] == 0) {
+ }
+#endif
+ if (suffix[0] == 0) {
return base_location;
} else {
return dex_location;
diff --git a/runtime/interpreter/interpreter.cc b/runtime/interpreter/interpreter.cc
index 2e41a9d..067c1fa 100644
--- a/runtime/interpreter/interpreter.cc
+++ b/runtime/interpreter/interpreter.cc
@@ -253,13 +253,6 @@
DCHECK(!shadow_frame.GetMethod()->IsAbstract());
DCHECK(!shadow_frame.GetMethod()->IsNative());
- // Check that we are using the right interpreter.
- if (kIsDebugBuild && self->UseMterp() != CanUseMterp()) {
- // The flag might be currently being updated on all threads. Retry with lock.
- MutexLock tll_mu(self, *Locks::thread_list_lock_);
- DCHECK_EQ(self->UseMterp(), CanUseMterp());
- }
-
if (LIKELY(!from_deoptimize)) { // Entering the method, but not via deoptimization.
if (kIsDebugBuild) {
CHECK_EQ(shadow_frame.GetDexPC(), 0u);
diff --git a/runtime/interpreter/interpreter_common.h b/runtime/interpreter/interpreter_common.h
index a633a63..62f5d91 100644
--- a/runtime/interpreter/interpreter_common.h
+++ b/runtime/interpreter/interpreter_common.h
@@ -140,8 +140,10 @@
uint16_t inst_data,
JValue* result)
REQUIRES_SHARED(Locks::mutator_lock_) {
+ DCHECK_EQ(self->UseMterp(), CanUseMterp());
// Make sure to check for async exceptions before anything else.
- if (is_mterp && self->UseMterp()) {
+ if (is_mterp) {
+ DCHECK(self->UseMterp());
DCHECK(!self->ObserveAsyncException());
} else if (UNLIKELY(self->ObserveAsyncException())) {
return false;
@@ -219,7 +221,7 @@
// If the bit is not set, we explicitly recheck all the conditions.
// If any of the conditions get falsified, it is important to clear the bit.
bool use_fast_path = false;
- if (is_mterp && self->UseMterp()) {
+ if (is_mterp) {
use_fast_path = called_method->UseFastInterpreterToInterpreterInvoke();
if (!use_fast_path) {
use_fast_path = UseFastInterpreterToInterpreterInvoke(called_method);
diff --git a/runtime/interpreter/mterp/mterp.cc b/runtime/interpreter/mterp/mterp.cc
index 912c444..fd1430a 100644
--- a/runtime/interpreter/mterp/mterp.cc
+++ b/runtime/interpreter/mterp/mterp.cc
@@ -546,12 +546,7 @@
extern "C" void MterpCheckBefore(Thread* self, ShadowFrame* shadow_frame, uint16_t* dex_pc_ptr)
REQUIRES_SHARED(Locks::mutator_lock_) {
- // Check that we are using the right interpreter.
- if (kIsDebugBuild && self->UseMterp() != CanUseMterp()) {
- // The flag might be currently being updated on all threads. Retry with lock.
- MutexLock tll_mu(self, *Locks::thread_list_lock_);
- DCHECK_EQ(self->UseMterp(), CanUseMterp());
- }
+ DCHECK(self->UseMterp());
DCHECK(!Runtime::Current()->IsActiveTransaction());
const Instruction* inst = Instruction::At(dex_pc_ptr);
uint16_t inst_data = inst->Fetch16(0);
diff --git a/runtime/jit/debugger_interface.cc b/runtime/jit/debugger_interface.cc
index 853c0ca..7aa6ddf 100644
--- a/runtime/jit/debugger_interface.cc
+++ b/runtime/jit/debugger_interface.cc
@@ -19,14 +19,17 @@
#include <android-base/logging.h>
#include "base/array_ref.h"
+#include "base/logging.h"
#include "base/mutex.h"
#include "base/time_utils.h"
+#include "base/utils.h"
#include "dex/dex_file.h"
#include "thread-current-inl.h"
#include "thread.h"
#include <atomic>
#include <cstddef>
+#include <deque>
#include <map>
//
@@ -77,6 +80,10 @@
//
namespace art {
+
+static Mutex g_jit_debug_lock("JIT native debug entries", kNativeDebugInterfaceLock);
+static Mutex g_dex_debug_lock("DEX native debug entries", kNativeDebugInterfaceLock);
+
extern "C" {
enum JITAction {
JIT_NOACTION = 0,
@@ -127,14 +134,14 @@
void (*__jit_debug_register_code_ptr)() = __jit_debug_register_code;
// The root data structure describing of all JITed methods.
- JITDescriptor __jit_debug_descriptor GUARDED_BY(*Locks::native_debug_interface_lock_) {};
+ JITDescriptor __jit_debug_descriptor GUARDED_BY(g_jit_debug_lock) {};
// The following globals mirror the ones above, but are used to register dex files.
void __attribute__((noinline)) __dex_debug_register_code() {
__asm__("");
}
void (*__dex_debug_register_code_ptr)() = __dex_debug_register_code;
- JITDescriptor __dex_debug_descriptor GUARDED_BY(*Locks::native_debug_interface_lock_) {};
+ JITDescriptor __dex_debug_descriptor GUARDED_BY(g_dex_debug_lock) {};
}
// Mark the descriptor as "locked", so native tools know the data is being modified.
@@ -157,8 +164,7 @@
JITDescriptor& descriptor,
void (*register_code_ptr)(),
ArrayRef<const uint8_t> symfile,
- bool copy_symfile)
- REQUIRES(Locks::native_debug_interface_lock_) {
+ bool copy_symfile) {
// Make a copy of the buffer to shrink it and to pass ownership to JITCodeEntry.
if (copy_symfile) {
uint8_t* copy = new uint8_t[symfile.size()];
@@ -199,8 +205,7 @@
JITDescriptor& descriptor,
void (*register_code_ptr)(),
JITCodeEntry* entry,
- bool free_symfile)
- REQUIRES(Locks::native_debug_interface_lock_) {
+ bool free_symfile) {
CHECK(entry != nullptr);
const uint8_t* symfile = entry->symfile_addr_;
@@ -238,11 +243,10 @@
}
}
-static std::map<const DexFile*, JITCodeEntry*> g_dex_debug_entries
- GUARDED_BY(*Locks::native_debug_interface_lock_);
+static std::map<const DexFile*, JITCodeEntry*> g_dex_debug_entries GUARDED_BY(g_dex_debug_lock);
void AddNativeDebugInfoForDex(Thread* self, const DexFile* dexfile) {
- MutexLock mu(self, *Locks::native_debug_interface_lock_);
+ MutexLock mu(self, g_dex_debug_lock);
DCHECK(dexfile != nullptr);
// This is just defensive check. The class linker should not register the dex file twice.
if (g_dex_debug_entries.count(dexfile) == 0) {
@@ -256,7 +260,7 @@
}
void RemoveNativeDebugInfoForDex(Thread* self, const DexFile* dexfile) {
- MutexLock mu(self, *Locks::native_debug_interface_lock_);
+ MutexLock mu(self, g_dex_debug_lock);
auto it = g_dex_debug_entries.find(dexfile);
// We register dex files in the class linker and free them in DexFile_closeDexFile, but
// there might be cases where we load the dex file without using it in the class linker.
@@ -270,46 +274,134 @@
}
// Mapping from handle to entry. Used to manage life-time of the entries.
-static std::map<const void*, JITCodeEntry*> g_jit_debug_entries
- GUARDED_BY(*Locks::native_debug_interface_lock_);
+static std::map<const void*, JITCodeEntry*> g_jit_debug_entries GUARDED_BY(g_jit_debug_lock);
+
+// Number of entries added since last packing. Used to pack entries in bulk.
+static size_t g_jit_num_unpacked_entries GUARDED_BY(g_jit_debug_lock) = 0;
+
+// We postpone removal so that it is done in bulk.
+static std::deque<const void*> g_jit_removed_entries GUARDED_BY(g_jit_debug_lock);
+
+// Split the JIT code cache into groups of fixed size and create singe JITCodeEntry for each group.
+// The start address of method's code determines which group it belongs to. The end is irrelevant.
+// As a consequnce, newly added mini debug infos will be merged and old ones (GCed) will be pruned.
+static void MaybePackJitMiniDebugInfo(PackElfFileForJITFunction pack,
+ InstructionSet isa,
+ const InstructionSetFeatures* features)
+ REQUIRES(g_jit_debug_lock) {
+ // Size of memory range covered by each JITCodeEntry.
+ // The number of methods per entry is variable (depending on how many fit in that range).
+ constexpr uint32_t kGroupSize = 64 * KB;
+ // Even if there are no removed entries, we want to pack new entries on regular basis.
+ constexpr uint32_t kPackFrequency = 64;
+
+ std::deque<const void*>& removed_entries = g_jit_removed_entries;
+ std::sort(removed_entries.begin(), removed_entries.end());
+ if (removed_entries.empty() && g_jit_num_unpacked_entries < kPackFrequency) {
+ return; // Nothing to do.
+ }
+
+ std::vector<const uint8_t*> added_elf_files;
+ std::vector<const void*> removed_symbols;
+ auto added_it = g_jit_debug_entries.begin();
+ auto removed_it = removed_entries.begin();
+ while (added_it != g_jit_debug_entries.end()) {
+ // Collect all entries that have been added or removed within our memory range.
+ const void* group_ptr = AlignDown(added_it->first, kGroupSize);
+ added_elf_files.clear();
+ auto added_begin = added_it;
+ while (added_it != g_jit_debug_entries.end() &&
+ AlignDown(added_it->first, kGroupSize) == group_ptr) {
+ added_elf_files.push_back((added_it++)->second->symfile_addr_);
+ }
+ removed_symbols.clear();
+ while (removed_it != removed_entries.end() &&
+ AlignDown(*removed_it, kGroupSize) == group_ptr) {
+ removed_symbols.push_back(*(removed_it++));
+ }
+
+ // Create new singe JITCodeEntry that covers this memory range.
+ if (added_elf_files.size() == 1 && removed_symbols.size() == 0) {
+ continue; // Nothing changed in this memory range.
+ }
+ uint64_t start_time = MilliTime();
+ size_t symbols;
+ std::vector<uint8_t> packed = pack(isa, features, added_elf_files, removed_symbols, &symbols);
+ VLOG(jit)
+ << "JIT mini-debug-info packed"
+ << " for " << group_ptr
+ << " in " << MilliTime() - start_time << "ms"
+ << " files=" << added_elf_files.size()
+ << " removed=" << removed_symbols.size()
+ << " symbols=" << symbols
+ << " size=" << PrettySize(packed.size());
+
+ // Replace the old entries with the new one (with their lifetime temporally overlapping).
+ JITCodeEntry* packed_entry = CreateJITCodeEntryInternal(
+ __jit_debug_descriptor,
+ __jit_debug_register_code_ptr,
+ ArrayRef<const uint8_t>(packed),
+ /*copy_symfile=*/ true);
+ for (auto it = added_begin; it != added_it; ++it) {
+ DeleteJITCodeEntryInternal(__jit_debug_descriptor,
+ __jit_debug_register_code_ptr,
+ /*entry=*/ it->second,
+ /*free_symfile=*/ true);
+ }
+ g_jit_debug_entries.erase(added_begin, added_it);
+ g_jit_debug_entries.emplace(group_ptr, packed_entry);
+ }
+ CHECK(added_it == g_jit_debug_entries.end());
+ CHECK(removed_it == removed_entries.end());
+ removed_entries.clear();
+ g_jit_num_unpacked_entries = 0;
+}
void AddNativeDebugInfoForJit(Thread* self,
const void* code_ptr,
- const std::vector<uint8_t>& symfile) {
- MutexLock mu(self, *Locks::native_debug_interface_lock_);
+ const std::vector<uint8_t>& symfile,
+ PackElfFileForJITFunction pack,
+ InstructionSet isa,
+ const InstructionSetFeatures* features) {
+ MutexLock mu(self, g_jit_debug_lock);
DCHECK_NE(symfile.size(), 0u);
+ MaybePackJitMiniDebugInfo(pack, isa, features);
+
JITCodeEntry* entry = CreateJITCodeEntryInternal(
__jit_debug_descriptor,
__jit_debug_register_code_ptr,
ArrayRef<const uint8_t>(symfile),
/*copy_symfile=*/ true);
+ VLOG(jit)
+ << "JIT mini-debug-info added"
+ << " for " << code_ptr
+ << " size=" << PrettySize(symfile.size());
+
// We don't provide code_ptr for type debug info, which means we cannot free it later.
// (this only happens when --generate-debug-info flag is enabled for the purpose
// of being debugged with gdb; it does not happen for debuggable apps by default).
if (code_ptr != nullptr) {
bool ok = g_jit_debug_entries.emplace(code_ptr, entry).second;
DCHECK(ok) << "Native debug entry already exists for " << std::hex << code_ptr;
+ // Count how many entries we have added since the last mini-debug-info packing.
+ // We avoid g_jit_debug_entries.size() here because it can shrink during packing.
+ g_jit_num_unpacked_entries++;
}
}
void RemoveNativeDebugInfoForJit(Thread* self, const void* code_ptr) {
- MutexLock mu(self, *Locks::native_debug_interface_lock_);
- auto it = g_jit_debug_entries.find(code_ptr);
+ MutexLock mu(self, g_jit_debug_lock);
// We generate JIT native debug info only if the right runtime flags are enabled,
// but we try to remove it unconditionally whenever code is freed from JIT cache.
- if (it != g_jit_debug_entries.end()) {
- DeleteJITCodeEntryInternal(__jit_debug_descriptor,
- __jit_debug_register_code_ptr,
- it->second,
- /*free_symfile=*/ true);
- g_jit_debug_entries.erase(it);
+ if (!g_jit_debug_entries.empty()) {
+ g_jit_removed_entries.push_back(code_ptr);
}
}
size_t GetJitMiniDebugInfoMemUsage() {
- MutexLock mu(Thread::Current(), *Locks::native_debug_interface_lock_);
+ MutexLock mu(Thread::Current(), g_jit_debug_lock);
size_t size = 0;
for (auto entry : g_jit_debug_entries) {
size += sizeof(JITCodeEntry) + entry.second->symfile_size_ + /*map entry*/ 4 * sizeof(void*);
diff --git a/runtime/jit/debugger_interface.h b/runtime/jit/debugger_interface.h
index 4b0d011..17beb4b 100644
--- a/runtime/jit/debugger_interface.h
+++ b/runtime/jit/debugger_interface.h
@@ -20,6 +20,7 @@
#include <inttypes.h>
#include <vector>
+#include "arch/instruction_set_features.h"
#include "base/locks.h"
namespace art {
@@ -27,28 +28,35 @@
class DexFile;
class Thread;
+// This method is declared in the compiler library.
+// We need to pass it by pointer to be able to call it from runtime.
+typedef std::vector<uint8_t> PackElfFileForJITFunction(
+ InstructionSet isa,
+ const InstructionSetFeatures* features,
+ std::vector<const uint8_t*>& added_elf_files,
+ std::vector<const void*>& removed_symbols,
+ /*out*/ size_t* num_symbols);
+
// Notify native tools (e.g. libunwind) that DEX file has been opened.
-void AddNativeDebugInfoForDex(Thread* self, const DexFile* dexfile)
- REQUIRES(!Locks::native_debug_interface_lock_);
+void AddNativeDebugInfoForDex(Thread* self, const DexFile* dexfile);
// Notify native tools (e.g. libunwind) that DEX file has been closed.
-void RemoveNativeDebugInfoForDex(Thread* self, const DexFile* dexfile)
- REQUIRES(!Locks::native_debug_interface_lock_);
+void RemoveNativeDebugInfoForDex(Thread* self, const DexFile* dexfile);
// Notify native tools (e.g. libunwind) that JIT has compiled a new method.
// The method will make copy of the passed ELF file (to shrink it to the minimum size).
void AddNativeDebugInfoForJit(Thread* self,
const void* code_ptr,
- const std::vector<uint8_t>& symfile)
- REQUIRES(!Locks::native_debug_interface_lock_);
+ const std::vector<uint8_t>& symfile,
+ PackElfFileForJITFunction pack,
+ InstructionSet isa,
+ const InstructionSetFeatures* features);
// Notify native tools (e.g. libunwind) that JIT code has been garbage collected.
-void RemoveNativeDebugInfoForJit(Thread* self, const void* code_ptr)
- REQUIRES(!Locks::native_debug_interface_lock_);
+void RemoveNativeDebugInfoForJit(Thread* self, const void* code_ptr);
// Returns approximate memory used by debug info for JIT code.
-size_t GetJitMiniDebugInfoMemUsage()
- REQUIRES(!Locks::native_debug_interface_lock_);
+size_t GetJitMiniDebugInfoMemUsage();
} // namespace art
diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc
index 5c5523d..de4826f 100644
--- a/runtime/oat_file.cc
+++ b/runtime/oat_file.cc
@@ -581,9 +581,9 @@
const char* dex_file_location_data = reinterpret_cast<const char*>(oat);
oat += dex_file_location_size;
- std::string dex_file_location = ResolveRelativeEncodedDexLocation(
- abs_dex_location,
- std::string(dex_file_location_data, dex_file_location_size));
+ std::string dex_file_location(dex_file_location_data, dex_file_location_size);
+ std::string dex_file_name =
+ ResolveRelativeEncodedDexLocation(abs_dex_location, dex_file_location);
uint32_t dex_file_checksum;
if (UNLIKELY(!ReadOatDexFileData(*this, &oat, &dex_file_checksum))) {
@@ -638,7 +638,7 @@
error_msg,
uncompressed_dex_files_.get());
} else {
- loaded = dex_file_loader.Open(dex_file_location.c_str(),
+ loaded = dex_file_loader.Open(dex_file_name.c_str(),
dex_file_location,
/*verify=*/ false,
/*verify_checksum=*/ false,
@@ -819,7 +819,7 @@
this, header->string_ids_size_, sizeof(GcRoot<mirror::String>), string_bss_mapping);
std::string canonical_location =
- DexFileLoader::GetDexCanonicalLocation(dex_file_location.c_str());
+ DexFileLoader::GetDexCanonicalLocation(dex_file_name.c_str());
// Create the OatDexFile and add it to the owning container.
OatDexFile* oat_dex_file = new OatDexFile(this,
diff --git a/runtime/runtime-inl.h b/runtime/runtime-inl.h
index 2ffaf98..c7731f4 100644
--- a/runtime/runtime-inl.h
+++ b/runtime/runtime-inl.h
@@ -28,6 +28,7 @@
#include "gc_root-inl.h"
#include "interpreter/mterp/mterp.h"
#include "obj_ptr-inl.h"
+#include "scoped_thread_state_change-inl.h"
#include "thread_list.h"
namespace art {
@@ -90,12 +91,23 @@
}
template<typename Action>
-void Runtime::DoAndMaybeSwitchInterpreter(Action lamda) {
- MutexLock tll_mu(Thread::Current(), *Locks::thread_list_lock_);
- lamda();
- Runtime::Current()->GetThreadList()->ForEach([](Thread* thread, void*) {
- thread->tls32_.use_mterp.store(interpreter::CanUseMterp());
- }, nullptr);
+void Runtime::DoAndMaybeSwitchInterpreter(Action lambda) {
+ Thread* self = Thread::Current();
+ if (Runtime::Current()->IsShuttingDown(self) || Locks::mutator_lock_->IsExclusiveHeld(self)) {
+ MutexLock tll_mu(self, *Locks::thread_list_lock_);
+ lambda();
+ Runtime::Current()->GetThreadList()->ForEach([](Thread* thread, void*) {
+ thread->tls32_.use_mterp.store(interpreter::CanUseMterp());
+ }, nullptr);
+ } else {
+ ScopedThreadStateChange tsc(self, kSuspended);
+ ScopedSuspendAll ssa(__FUNCTION__);
+ MutexLock tll_mu(self, *Locks::thread_list_lock_);
+ lambda();
+ Runtime::Current()->GetThreadList()->ForEach([](Thread* thread, void*) {
+ thread->tls32_.use_mterp.store(interpreter::CanUseMterp());
+ }, nullptr);
+ }
}
} // namespace art
diff --git a/runtime/runtime.h b/runtime/runtime.h
index a2d519d..00158b8 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -669,7 +669,7 @@
// It ensures that two calls do not interfere with each other and
// it makes it possible to DCHECK that thread local flag is correct.
template<typename Action>
- static void DoAndMaybeSwitchInterpreter(Action lamda);
+ static void DoAndMaybeSwitchInterpreter(Action lambda);
// Returns the build fingerprint, if set. Otherwise an empty string is returned.
std::string GetFingerprint() {
diff --git a/runtime/thread.cc b/runtime/thread.cc
index f459f9c..a97e4cc 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -4168,7 +4168,11 @@
void Thread::SetAsyncException(ObjPtr<mirror::Throwable> new_exception) {
CHECK(new_exception != nullptr);
- Runtime::Current()->SetAsyncExceptionsThrown();
+ {
+ StackHandleScope<1> hs(Thread::Current());
+ auto h_exception = hs.NewHandleWrapper(&new_exception);
+ Runtime::Current()->SetAsyncExceptionsThrown();
+ }
if (kIsDebugBuild) {
// Make sure we are in a checkpoint.
MutexLock mu(Thread::Current(), *Locks::thread_suspend_count_lock_);
diff --git a/test/etc/run-test-jar b/test/etc/run-test-jar
index 0674f52..25b8b4b 100755
--- a/test/etc/run-test-jar
+++ b/test/etc/run-test-jar
@@ -1032,7 +1032,8 @@
# Note: We first send SIGRTMIN+2 (usually 36) to ART, which will induce a full thread dump
# before abort. However, dumping threads might deadlock, so we also use the "-k"
# option to definitely kill the child.
- cmdline="timeout -k 120s -s SIGRTMIN+2 ${TIME_OUT_VALUE}s ${TIMEOUT_DUMPER} $cmdline"
+ # Note: Using "--foreground" to not propagate the signal to children, i.e., the runtime.
+ cmdline="timeout --foreground -k 120s -s SIGRTMIN+2 ${TIME_OUT_VALUE}s ${TIMEOUT_DUMPER} $cmdline"
fi
if [ "$DEV_MODE" = "y" ]; then
diff --git a/tools/veridex/veridex.cc b/tools/veridex/veridex.cc
index 96100b2..46ab8aa 100644
--- a/tools/veridex/veridex.cc
+++ b/tools/veridex/veridex.cc
@@ -126,6 +126,7 @@
static int Run(int argc, char** argv) {
VeridexOptions options;
ParseArgs(&options, argc, argv);
+ android::base::InitLogging(argv);
if (!options.dex_file) {
LOG(ERROR) << "Required argument '" << kDexFileOption << "' not provided.";