Merge "SIMD pcmpgtb,w,d,q for x86/x86_64"
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index cf1832b..0ed230c 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -1,2 +1,3 @@
[Hook Scripts]
check_generated_files_up_to_date = tools/cpp-define-generator/presubmit-check-files-up-to-date
+check_cpplint_on_changed_files = tools/cpplint_presubmit.py
diff --git a/compiler/utils/assembler_test.h b/compiler/utils/assembler_test.h
index d265a44..f655994 100644
--- a/compiler/utils/assembler_test.h
+++ b/compiler/utils/assembler_test.h
@@ -309,7 +309,7 @@
template <typename RegType, typename ImmType>
std::string RepeatTemplatedRegisterImmBits(void (Ass::*f)(RegType, ImmType),
int imm_bits,
- const std::vector<Reg*> registers,
+ const std::vector<RegType*> registers,
std::string (AssemblerTest::*GetName)(const RegType&),
const std::string& fmt,
int bias) {
@@ -573,6 +573,19 @@
}
template <typename ImmType>
+ std::string RepeatVIb(void (Ass::*f)(VecReg, ImmType),
+ int imm_bits,
+ std::string fmt,
+ int bias = 0) {
+ return RepeatTemplatedRegisterImmBits<VecReg, ImmType>(f,
+ imm_bits,
+ GetVectorRegisters(),
+ &AssemblerTest::GetVecRegName,
+ fmt,
+ bias);
+ }
+
+ template <typename ImmType>
std::string RepeatVRIb(void (Ass::*f)(VecReg, Reg, ImmType),
int imm_bits,
const std::string& fmt,
diff --git a/compiler/utils/mips64/assembler_mips64.cc b/compiler/utils/mips64/assembler_mips64.cc
index 7d6a7f8..0cff44d 100644
--- a/compiler/utils/mips64/assembler_mips64.cc
+++ b/compiler/utils/mips64/assembler_mips64.cc
@@ -252,6 +252,22 @@
Emit(encoding);
}
+void Mips64Assembler::EmitMsaI10(int operation,
+ int df,
+ int i10,
+ VectorRegister wd,
+ int minor_opcode) {
+ CHECK_NE(wd, kNoVectorRegister);
+ CHECK(IsUint<10>(i10)) << i10;
+ uint32_t encoding = static_cast<uint32_t>(kMsaMajorOpcode) << kOpcodeShift |
+ operation << kMsaOperationShift |
+ df << kDfShift |
+ i10 << kI10Shift |
+ static_cast<uint32_t>(wd) << kWdShift |
+ minor_opcode;
+ Emit(encoding);
+}
+
void Mips64Assembler::EmitMsa2R(int operation,
int df,
VectorRegister ws,
@@ -1581,6 +1597,30 @@
EmitMsa2R(0xc0, 0x3, static_cast<VectorRegister>(rs), wd, 0x1e);
}
+void Mips64Assembler::LdiB(VectorRegister wd, int imm8) {
+ CHECK(HasMsa());
+ CHECK(IsInt<8>(imm8)) << imm8;
+ EmitMsaI10(0x6, 0x0, imm8 & kMsaS10Mask, wd, 0x7);
+}
+
+void Mips64Assembler::LdiH(VectorRegister wd, int imm10) {
+ CHECK(HasMsa());
+ CHECK(IsInt<10>(imm10)) << imm10;
+ EmitMsaI10(0x6, 0x1, imm10 & kMsaS10Mask, wd, 0x7);
+}
+
+void Mips64Assembler::LdiW(VectorRegister wd, int imm10) {
+ CHECK(HasMsa());
+ CHECK(IsInt<10>(imm10)) << imm10;
+ EmitMsaI10(0x6, 0x2, imm10 & kMsaS10Mask, wd, 0x7);
+}
+
+void Mips64Assembler::LdiD(VectorRegister wd, int imm10) {
+ CHECK(HasMsa());
+ CHECK(IsInt<10>(imm10)) << imm10;
+ EmitMsaI10(0x6, 0x3, imm10 & kMsaS10Mask, wd, 0x7);
+}
+
void Mips64Assembler::LdB(VectorRegister wd, GpuRegister rs, int offset) {
CHECK(HasMsa());
CHECK(IsInt<10>(offset)) << offset;
diff --git a/compiler/utils/mips64/assembler_mips64.h b/compiler/utils/mips64/assembler_mips64.h
index a8035b6..666c693 100644
--- a/compiler/utils/mips64/assembler_mips64.h
+++ b/compiler/utils/mips64/assembler_mips64.h
@@ -734,6 +734,10 @@
void FillW(VectorRegister wd, GpuRegister rs);
void FillD(VectorRegister wd, GpuRegister rs);
+ void LdiB(VectorRegister wd, int imm8);
+ void LdiH(VectorRegister wd, int imm10);
+ void LdiW(VectorRegister wd, int imm10);
+ void LdiD(VectorRegister wd, int imm10);
void LdB(VectorRegister wd, GpuRegister rs, int offset);
void LdH(VectorRegister wd, GpuRegister rs, int offset);
void LdW(VectorRegister wd, GpuRegister rs, int offset);
@@ -1457,6 +1461,7 @@
void EmitMsaBIT(int operation, int df_m, VectorRegister ws, VectorRegister wd, int minor_opcode);
void EmitMsaELM(int operation, int df_n, VectorRegister ws, VectorRegister wd, int minor_opcode);
void EmitMsaMI10(int s10, GpuRegister rs, VectorRegister wd, int minor_opcode, int df);
+ void EmitMsaI10(int operation, int df, int i10, VectorRegister wd, int minor_opcode);
void EmitMsa2R(int operation, int df, VectorRegister ws, VectorRegister wd, int minor_opcode);
void EmitMsa2RF(int operation, int df, VectorRegister ws, VectorRegister wd, int minor_opcode);
diff --git a/compiler/utils/mips64/assembler_mips64_test.cc b/compiler/utils/mips64/assembler_mips64_test.cc
index cadbe27..f2e3b16 100644
--- a/compiler/utils/mips64/assembler_mips64_test.cc
+++ b/compiler/utils/mips64/assembler_mips64_test.cc
@@ -2836,6 +2836,22 @@
DriverStr(RepeatVR(&mips64::Mips64Assembler::FillD, "fill.d ${reg1}, ${reg2}"), "fill.d");
}
+TEST_F(AssemblerMIPS64Test, LdiB) {
+ DriverStr(RepeatVIb(&mips64::Mips64Assembler::LdiB, -8, "ldi.b ${reg}, {imm}"), "ldi.b");
+}
+
+TEST_F(AssemblerMIPS64Test, LdiH) {
+ DriverStr(RepeatVIb(&mips64::Mips64Assembler::LdiH, -10, "ldi.h ${reg}, {imm}"), "ldi.h");
+}
+
+TEST_F(AssemblerMIPS64Test, LdiW) {
+ DriverStr(RepeatVIb(&mips64::Mips64Assembler::LdiW, -10, "ldi.w ${reg}, {imm}"), "ldi.w");
+}
+
+TEST_F(AssemblerMIPS64Test, LdiD) {
+ DriverStr(RepeatVIb(&mips64::Mips64Assembler::LdiD, -10, "ldi.d ${reg}, {imm}"), "ldi.d");
+}
+
TEST_F(AssemblerMIPS64Test, LdB) {
DriverStr(RepeatVRIb(&mips64::Mips64Assembler::LdB, -10, "ld.b ${reg1}, {imm}(${reg2})"), "ld.b");
}
diff --git a/compiler/utils/mips64/constants_mips64.h b/compiler/utils/mips64/constants_mips64.h
index 5ae9c73..bc8e40b 100644
--- a/compiler/utils/mips64/constants_mips64.h
+++ b/compiler/utils/mips64/constants_mips64.h
@@ -66,6 +66,7 @@
kWdShift = 6,
kWdBits = 5,
kS10Shift = 16,
+ kI10Shift = 11,
kS10MinorShift = 2,
kBranchOffsetMask = 0x0000ffff,
diff --git a/dexlayout/Android.bp b/dexlayout/Android.bp
index cf523ec..e26d051 100644
--- a/dexlayout/Android.bp
+++ b/dexlayout/Android.bp
@@ -56,3 +56,16 @@
defaults: ["art_gtest_defaults"],
srcs: ["dexlayout_test.cc"],
}
+
+art_cc_binary {
+ name: "dexdiag",
+ host_supported: false,
+ srcs: ["dexdiag.cc"],
+ cflags: ["-Wall"],
+ shared_libs: [
+ "libart",
+ "libart-dexlayout",
+ "libpagemap",
+ ],
+}
+
diff --git a/dexlayout/dexdiag.cc b/dexlayout/dexdiag.cc
new file mode 100644
index 0000000..211bfdf
--- /dev/null
+++ b/dexlayout/dexdiag.cc
@@ -0,0 +1,405 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <errno.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <iostream>
+#include <memory>
+
+#include "android-base/stringprintf.h"
+
+#include "dex_file.h"
+#include "dex_ir.h"
+#include "dex_ir_builder.h"
+#include "pagemap/pagemap.h"
+#include "runtime.h"
+#include "vdex_file.h"
+
+namespace art {
+
+using android::base::StringPrintf;
+
+static constexpr size_t kLineLength = 32;
+
+static bool g_show_key = false;
+static bool g_verbose = false;
+static bool g_show_statistics = false;
+
+struct DexSectionInfo {
+ public:
+ std::string name;
+ char letter;
+};
+
+static const std::map<uint16_t, DexSectionInfo> kDexSectionInfoMap = {
+ { DexFile::kDexTypeHeaderItem, { "Header", 'H' } },
+ { DexFile::kDexTypeStringIdItem, { "StringId", 'S' } },
+ { DexFile::kDexTypeTypeIdItem, { "TypeId", 'T' } },
+ { DexFile::kDexTypeProtoIdItem, { "ProtoId", 'P' } },
+ { DexFile::kDexTypeFieldIdItem, { "FieldId", 'F' } },
+ { DexFile::kDexTypeMethodIdItem, { "MethodId", 'M' } },
+ { DexFile::kDexTypeClassDefItem, { "ClassDef", 'C' } },
+ { DexFile::kDexTypeCallSiteIdItem, { "CallSiteId", 'z' } },
+ { DexFile::kDexTypeMethodHandleItem, { "MethodHandle", 'Z' } },
+ { DexFile::kDexTypeMapList, { "TypeMap", 'L' } },
+ { DexFile::kDexTypeTypeList, { "TypeList", 't' } },
+ { DexFile::kDexTypeAnnotationSetRefList, { "AnnotationSetReferenceItem", '1' } },
+ { DexFile::kDexTypeAnnotationSetItem, { "AnnotationSetItem", '2' } },
+ { DexFile::kDexTypeClassDataItem, { "ClassData", 'c' } },
+ { DexFile::kDexTypeCodeItem, { "CodeItem", 'X' } },
+ { DexFile::kDexTypeStringDataItem, { "StringData", 's' } },
+ { DexFile::kDexTypeDebugInfoItem, { "DebugInfo", 'D' } },
+ { DexFile::kDexTypeAnnotationItem, { "AnnotationItem", '3' } },
+ { DexFile::kDexTypeEncodedArrayItem, { "EncodedArrayItem", 'E' } },
+ { DexFile::kDexTypeAnnotationsDirectoryItem, { "AnnotationsDirectoryItem", '4' } }
+};
+
+class PageCount {
+ public:
+ PageCount() {
+ for (auto it = kDexSectionInfoMap.begin(); it != kDexSectionInfoMap.end(); ++it) {
+ map_[it->first] = 0;
+ }
+ }
+ void Increment(uint16_t type) {
+ map_[type]++;
+ }
+ size_t Get(uint16_t type) const {
+ return map_.at(type);
+ }
+ private:
+ std::map<uint16_t, size_t> map_;
+ DISALLOW_COPY_AND_ASSIGN(PageCount);
+};
+
+static void PrintLetterKey() {
+ std::cout << "letter section_type" << std::endl;
+ for (const auto& p : kDexSectionInfoMap) {
+ const DexSectionInfo& section_info = p.second;
+ std::cout << section_info.letter << " " << section_info.name.c_str() << std::endl;
+ }
+}
+
+static char PageTypeChar(uint16_t type) {
+ if (kDexSectionInfoMap.find(type) == kDexSectionInfoMap.end()) {
+ return '-';
+ }
+ return kDexSectionInfoMap.find(type)->second.letter;
+}
+
+static uint16_t FindSectionTypeForPage(size_t page,
+ const std::vector<dex_ir::DexFileSection>& sections) {
+ for (const auto& section : sections) {
+ size_t first_page_of_section = section.offset / kPageSize;
+ // Only consider non-empty sections.
+ if (section.size == 0) {
+ continue;
+ }
+ // Attribute the page to the highest-offset section that starts before the page.
+ if (first_page_of_section <= page) {
+ return section.type;
+ }
+ }
+ // If there's no non-zero sized section with an offset below offset we're looking for, it
+ // must be the header.
+ return DexFile::kDexTypeHeaderItem;
+}
+
+static void ProcessPageMap(uint64_t* pagemap,
+ size_t start,
+ size_t end,
+ const std::vector<dex_ir::DexFileSection>& sections,
+ PageCount* page_counts) {
+ for (size_t page = start; page < end; ++page) {
+ char type_char = '.';
+ if (PM_PAGEMAP_PRESENT(pagemap[page])) {
+ uint16_t type = FindSectionTypeForPage(page, sections);
+ page_counts->Increment(type);
+ type_char = PageTypeChar(type);
+ }
+ if (g_verbose) {
+ std::cout << type_char;
+ if ((page - start) % kLineLength == kLineLength - 1) {
+ std::cout << std::endl;
+ }
+ }
+ }
+ if (g_verbose) {
+ if ((end - start) % kLineLength != 0) {
+ std::cout << std::endl;
+ }
+ }
+}
+
+static void DisplayDexStatistics(size_t start,
+ size_t end,
+ const PageCount& resident_pages,
+ const std::vector<dex_ir::DexFileSection>& sections) {
+ // Compute the total possible sizes for sections.
+ PageCount mapped_pages;
+ DCHECK_GE(end, start);
+ size_t total_mapped_pages = end - start;
+ if (total_mapped_pages == 0) {
+ return;
+ }
+ for (size_t page = start; page < end; ++page) {
+ mapped_pages.Increment(FindSectionTypeForPage(page, sections));
+ }
+ size_t total_resident_pages = 0;
+ // Compute the width of the section header column in the table (for fixed formatting).
+ int section_header_width = 0;
+ for (const auto& section_info : kDexSectionInfoMap) {
+ section_header_width = std::max(section_header_width,
+ static_cast<int>(section_info.second.name.length()));
+ }
+ // The width needed to print a file page offset (32-bit).
+ static constexpr int kPageCountWidth =
+ static_cast<int>(std::numeric_limits<uint32_t>::digits10);
+ // Display the sections.
+ static constexpr char kSectionHeader[] = "Section name";
+ std::cout << StringPrintf("%-*s %*s %*s %% of %% of",
+ section_header_width,
+ kSectionHeader,
+ kPageCountWidth,
+ "resident",
+ kPageCountWidth,
+ "total"
+ )
+ << std::endl;
+ std::cout << StringPrintf("%-*s %*s %*s sect. total",
+ section_header_width,
+ "",
+ kPageCountWidth,
+ "pages",
+ kPageCountWidth,
+ "pages")
+ << std::endl;
+ for (size_t i = sections.size(); i > 0; --i) {
+ const dex_ir::DexFileSection& section = sections[i - 1];
+ const uint16_t type = section.type;
+ const DexSectionInfo& section_info = kDexSectionInfoMap.find(type)->second;
+ size_t pages_resident = resident_pages.Get(type);
+ double percent_resident = 0;
+ if (mapped_pages.Get(type) > 0) {
+ percent_resident = 100.0 * pages_resident / mapped_pages.Get(type);
+ }
+ // 6.2 is sufficient to print 0-100% with two decimal places of accuracy.
+ std::cout << StringPrintf("%-*s %*zd %*zd %6.2f %6.2f",
+ section_header_width,
+ section_info.name.c_str(),
+ kPageCountWidth,
+ pages_resident,
+ kPageCountWidth,
+ mapped_pages.Get(type),
+ percent_resident,
+ 100.0 * pages_resident / total_mapped_pages)
+ << std::endl;
+ total_resident_pages += pages_resident;
+ }
+ std::cout << StringPrintf("%-*s %*zd %*zd %6.2f",
+ section_header_width,
+ "GRAND TOTAL",
+ kPageCountWidth,
+ total_resident_pages,
+ kPageCountWidth,
+ total_mapped_pages,
+ 100.0 * total_resident_pages / total_mapped_pages)
+ << std::endl
+ << std::endl;
+}
+
+static void ProcessOneDexMapping(uint64_t* pagemap,
+ uint64_t map_start,
+ const DexFile* dex_file,
+ uint64_t vdex_start) {
+ uint64_t dex_file_start = reinterpret_cast<uint64_t>(dex_file->Begin());
+ size_t dex_file_size = dex_file->Size();
+ if (dex_file_start < vdex_start) {
+ std::cerr << "Dex file start offset for "
+ << dex_file->GetLocation().c_str()
+ << " is incorrect: map start "
+ << StringPrintf("%zx > dex start %zx\n", map_start, dex_file_start)
+ << std::endl;
+ return;
+ }
+ uint64_t start = (dex_file_start - vdex_start) / kPageSize;
+ uint64_t end = RoundUp(start + dex_file_size, kPageSize) / kPageSize;
+ std::cout << "DEX "
+ << dex_file->GetLocation().c_str()
+ << StringPrintf(": %zx-%zx",
+ map_start + start * kPageSize,
+ map_start + end * kPageSize)
+ << std::endl;
+ // Build a list of the dex file section types, sorted from highest offset to lowest.
+ std::vector<dex_ir::DexFileSection> sections;
+ {
+ std::unique_ptr<dex_ir::Header> header(dex_ir::DexIrBuilder(*dex_file));
+ sections = dex_ir::GetSortedDexFileSections(header.get(),
+ dex_ir::SortDirection::kSortDescending);
+ }
+ PageCount section_resident_pages;
+ ProcessPageMap(pagemap, start, end, sections, §ion_resident_pages);
+ if (g_show_statistics) {
+ DisplayDexStatistics(start, end, section_resident_pages, sections);
+ }
+}
+
+static bool DisplayMappingIfFromVdexFile(pm_map_t* map) {
+ // Confirm that the map is from a vdex file.
+ static const char* suffixes[] = { ".vdex" };
+ std::string vdex_name;
+ bool found = false;
+ for (size_t j = 0; j < sizeof(suffixes) / sizeof(suffixes[0]); ++j) {
+ if (strstr(pm_map_name(map), suffixes[j]) != nullptr) {
+ vdex_name = pm_map_name(map);
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ return true;
+ }
+ // Extract all the dex files from the vdex file.
+ std::string error_msg;
+ std::unique_ptr<VdexFile> vdex(VdexFile::Open(vdex_name,
+ false /*writeable*/,
+ false /*low_4gb*/,
+ &error_msg /*out*/));
+ if (vdex == nullptr) {
+ std::cerr << "Could not open vdex file "
+ << vdex_name.c_str()
+ << ": error "
+ << error_msg.c_str()
+ << std::endl;
+ return false;
+ }
+
+ std::vector<std::unique_ptr<const DexFile>> dex_files;
+ if (!vdex->OpenAllDexFiles(&dex_files, &error_msg)) {
+ std::cerr << "Dex files could not be opened for "
+ << vdex_name.c_str()
+ << ": error "
+ << error_msg.c_str()
+ << std::endl;
+ }
+ // Open the page mapping (one uint64_t per page) for the entire vdex mapping.
+ uint64_t* pagemap;
+ size_t len;
+ if (pm_map_pagemap(map, &pagemap, &len) != 0) {
+ std::cerr << "Error creating pagemap." << std::endl;
+ return false;
+ }
+ // Process the dex files.
+ std::cout << "MAPPING "
+ << pm_map_name(map)
+ << StringPrintf(": %zx-%zx", pm_map_start(map), pm_map_end(map))
+ << std::endl;
+ for (const auto& dex_file : dex_files) {
+ ProcessOneDexMapping(pagemap,
+ pm_map_start(map),
+ dex_file.get(),
+ reinterpret_cast<uint64_t>(vdex->Begin()));
+ }
+ free(pagemap);
+ return true;
+}
+
+
+static void Usage(const char* cmd) {
+ std::cerr << "Usage: " << cmd << " [-k] [-s] [-v] pid" << std::endl
+ << " -k Shows a key to verbose display characters." << std::endl
+ << " -s Shows section statistics for individual dex files." << std::endl
+ << " -v Verbosely displays resident pages for dex files." << std::endl;
+}
+
+static int DexDiagMain(int argc, char* argv[]) {
+ if (argc < 2) {
+ Usage(argv[0]);
+ return EXIT_FAILURE;
+ }
+
+ // TODO: add option to track usage by class name, etc.
+ for (int i = 1; i < argc - 1; ++i) {
+ if (strcmp(argv[i], "-k") == 0) {
+ g_show_key = true;
+ } else if (strcmp(argv[i], "-s") == 0) {
+ g_show_statistics = true;
+ } else if (strcmp(argv[i], "-v") == 0) {
+ g_verbose = true;
+ } else {
+ Usage(argv[0]);
+ return EXIT_FAILURE;
+ }
+ }
+
+ // Art specific set up.
+ InitLogging(argv, Runtime::Aborter);
+ MemMap::Init();
+
+ pid_t pid;
+ char* endptr;
+ pid = (pid_t)strtol(argv[argc - 1], &endptr, 10);
+ if (*endptr != '\0' || kill(pid, 0) != 0) {
+ std::cerr << StringPrintf("Invalid PID \"%s\".\n", argv[argc - 1]) << std::endl;
+ return EXIT_FAILURE;
+ }
+
+ // get libpagemap kernel information.
+ pm_kernel_t* ker;
+ if (pm_kernel_create(&ker) != 0) {
+ std::cerr << "Error creating kernel interface -- does this kernel have pagemap?" << std::endl;
+ return EXIT_FAILURE;
+ }
+
+ // get libpagemap process information.
+ pm_process_t* proc;
+ if (pm_process_create(ker, pid, &proc) != 0) {
+ std::cerr << "Error creating process interface -- does process "
+ << pid
+ << " really exist?"
+ << std::endl;
+ return EXIT_FAILURE;
+ }
+
+ // Get the set of mappings by the specified process.
+ pm_map_t** maps;
+ size_t num_maps;
+ if (pm_process_maps(proc, &maps, &num_maps) != 0) {
+ std::cerr << "Error listing maps." << std::endl;
+ return EXIT_FAILURE;
+ }
+
+ // Process the mappings that are due to DEX files.
+ for (size_t i = 0; i < num_maps; ++i) {
+ if (!DisplayMappingIfFromVdexFile(maps[i])) {
+ return EXIT_FAILURE;
+ }
+ }
+
+ if (g_show_key) {
+ PrintLetterKey();
+ }
+ return 0;
+}
+
+} // namespace art
+
+int main(int argc, char* argv[]) {
+ return art::DexDiagMain(argc, argv);
+}
diff --git a/disassembler/disassembler_mips.cc b/disassembler/disassembler_mips.cc
index fc6c18b..eb57d33 100644
--- a/disassembler/disassembler_mips.cc
+++ b/disassembler/disassembler_mips.cc
@@ -448,6 +448,7 @@
{ kMsaMask | (0x3ff << 16), kMsa | (0xbe << 16) | 0x19, "move.v", "km" },
{ kMsaMask | (0xf << 22), kMsa | (0x1 << 22) | 0x19, "splati", "kX" },
{ kMsaMask | (0xff << 18), kMsa | (0xc0 << 18) | 0x1e, "fill", "vkD" },
+ { kMsaMask | (0x7 << 23), kMsa | (0x6 << 23) | 0x7, "ldi", "kx" },
{ kMsaSpecialMask | (0xf << 2), kMsa | (0x8 << 2), "ld", "kw" },
{ kMsaSpecialMask | (0xf << 2), kMsa | (0x9 << 2), "st", "kw" },
};
@@ -697,6 +698,20 @@
}
break;
}
+ case 'x': // MSA i10.
+ {
+ int32_t df = (instruction >> 21) & 0x3;
+ int32_t i10 = (instruction >> 11) & 0x3ff;
+ i10 -= (i10 & 0x200) << 1; // Sign-extend i10.
+ switch (df) {
+ case 0: opcode += ".b"; break;
+ case 1: opcode += ".h"; break;
+ case 2: opcode += ".w"; break;
+ case 3: opcode += ".d"; break;
+ }
+ args << i10;
+ break;
+ }
}
if (*(args_fmt + 1)) {
args << ", ";
diff --git a/runtime/common_runtime_test.cc b/runtime/common_runtime_test.cc
index 78ba6e7..15724a1 100644
--- a/runtime/common_runtime_test.cc
+++ b/runtime/common_runtime_test.cc
@@ -68,6 +68,74 @@
using android::base::StringPrintf;
+static const uint8_t kBase64Map[256] = {
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 62, 255, 255, 255, 63,
+ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255,
+ 255, 254, 255, 255, 255, 0, 1, 2, 3, 4, 5, 6,
+ 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, // NOLINT
+ 19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, 255, // NOLINT
+ 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,
+ 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, // NOLINT
+ 49, 50, 51, 255, 255, 255, 255, 255, 255, 255, 255, 255, // NOLINT
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255
+};
+
+uint8_t* DecodeBase64(const char* src, size_t* dst_size) {
+ CHECK(dst_size != nullptr);
+ std::vector<uint8_t> tmp;
+ uint32_t t = 0, y = 0;
+ int g = 3;
+ for (size_t i = 0; src[i] != '\0'; ++i) {
+ uint8_t c = kBase64Map[src[i] & 0xFF];
+ if (c == 255) continue;
+ // the final = symbols are read and used to trim the remaining bytes
+ if (c == 254) {
+ c = 0;
+ // prevent g < 0 which would potentially allow an overflow later
+ if (--g < 0) {
+ *dst_size = 0;
+ return nullptr;
+ }
+ } else if (g != 3) {
+ // we only allow = to be at the end
+ *dst_size = 0;
+ return nullptr;
+ }
+ t = (t << 6) | c;
+ if (++y == 4) {
+ tmp.push_back((t >> 16) & 255);
+ if (g > 1) {
+ tmp.push_back((t >> 8) & 255);
+ }
+ if (g > 2) {
+ tmp.push_back(t & 255);
+ }
+ y = t = 0;
+ }
+ }
+ if (y != 0) {
+ *dst_size = 0;
+ return nullptr;
+ }
+ std::unique_ptr<uint8_t[]> dst(new uint8_t[tmp.size()]);
+ *dst_size = tmp.size();
+ std::copy(tmp.begin(), tmp.end(), dst.get());
+ return dst.release();
+}
+
ScratchFile::ScratchFile() {
// ANDROID_DATA needs to be set
CHECK_NE(static_cast<char*>(nullptr), getenv("ANDROID_DATA")) <<
diff --git a/runtime/common_runtime_test.h b/runtime/common_runtime_test.h
index d7abe2a..bfa273d 100644
--- a/runtime/common_runtime_test.h
+++ b/runtime/common_runtime_test.h
@@ -44,6 +44,8 @@
class Runtime;
typedef std::vector<std::pair<std::string, const void*>> RuntimeOptions;
+uint8_t* DecodeBase64(const char* src, size_t* dst_size);
+
class ScratchFile {
public:
ScratchFile();
diff --git a/runtime/jit/profile_saver.cc b/runtime/jit/profile_saver.cc
index e2bd1cb..9d6cd95 100644
--- a/runtime/jit/profile_saver.cc
+++ b/runtime/jit/profile_saver.cc
@@ -451,9 +451,6 @@
return;
}
instance_->shutting_down_ = true;
- if (dump_info) {
- instance_->DumpInfo(LOG_STREAM(INFO));
- }
}
{
@@ -470,6 +467,9 @@
{
MutexLock profiler_mutex(Thread::Current(), *Locks::profiler_lock_);
+ if (dump_info) {
+ instance_->DumpInfo(LOG_STREAM(INFO));
+ }
instance_ = nullptr;
profiler_pthread_ = 0U;
}
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 44f8281..48efbe5 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -806,11 +806,11 @@
// before fork aren't attributed to an app.
heap_->ResetGcPerformanceInfo();
-
- if (!is_system_server &&
+ // We may want to collect profiling samples for system server, but we never want to JIT there.
+ if ((!is_system_server || !jit_options_->UseJitCompilation()) &&
!safe_mode_ &&
(jit_options_->UseJitCompilation() || jit_options_->GetSaveProfilingInfo()) &&
- jit_.get() == nullptr) {
+ jit_ == nullptr) {
// Note that when running ART standalone (not zygote, nor zygote fork),
// the jit may have already been created.
CreateJit();
diff --git a/runtime/utils.cc b/runtime/utils.cc
index 6a20eaf..8d216ce 100644
--- a/runtime/utils.cc
+++ b/runtime/utils.cc
@@ -52,77 +52,6 @@
using android::base::StringAppendF;
using android::base::StringPrintf;
-static const uint8_t kBase64Map[256] = {
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 62, 255, 255, 255, 63,
- 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255,
- 255, 254, 255, 255, 255, 0, 1, 2, 3, 4, 5, 6,
- 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, // NOLINT
- 19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, 255, // NOLINT
- 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,
- 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, // NOLINT
- 49, 50, 51, 255, 255, 255, 255, 255, 255, 255, 255, 255, // NOLINT
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255
-};
-
-uint8_t* DecodeBase64(const char* src, size_t* dst_size) {
- std::vector<uint8_t> tmp;
- uint32_t t = 0, y = 0;
- int g = 3;
- for (size_t i = 0; src[i] != '\0'; ++i) {
- uint8_t c = kBase64Map[src[i] & 0xFF];
- if (c == 255) continue;
- // the final = symbols are read and used to trim the remaining bytes
- if (c == 254) {
- c = 0;
- // prevent g < 0 which would potentially allow an overflow later
- if (--g < 0) {
- *dst_size = 0;
- return nullptr;
- }
- } else if (g != 3) {
- // we only allow = to be at the end
- *dst_size = 0;
- return nullptr;
- }
- t = (t << 6) | c;
- if (++y == 4) {
- tmp.push_back((t >> 16) & 255);
- if (g > 1) {
- tmp.push_back((t >> 8) & 255);
- }
- if (g > 2) {
- tmp.push_back(t & 255);
- }
- y = t = 0;
- }
- }
- if (y != 0) {
- *dst_size = 0;
- return nullptr;
- }
- std::unique_ptr<uint8_t[]> dst(new uint8_t[tmp.size()]);
- if (dst_size != nullptr) {
- *dst_size = tmp.size();
- } else {
- *dst_size = 0;
- }
- std::copy(tmp.begin(), tmp.end(), dst.get());
- return dst.release();
-}
-
pid_t GetTid() {
#if defined(__APPLE__)
uint64_t owner;
diff --git a/runtime/utils.h b/runtime/utils.h
index 24fd205..2011d9e 100644
--- a/runtime/utils.h
+++ b/runtime/utils.h
@@ -70,8 +70,6 @@
return intp & 0xFFFFFFFFU;
}
-uint8_t* DecodeBase64(const char* src, size_t* dst_size);
-
std::string PrintableChar(uint16_t ch);
// Returns an ASCII string corresponding to the given UTF-8 string.
diff --git a/runtime/vdex_file.cc b/runtime/vdex_file.cc
index 2481c8b..9ff104b 100644
--- a/runtime/vdex_file.cc
+++ b/runtime/vdex_file.cc
@@ -120,4 +120,30 @@
}
}
+bool VdexFile::OpenAllDexFiles(std::vector<std::unique_ptr<const DexFile>>* dex_files,
+ std::string* error_msg) {
+ size_t i = 0;
+ for (const uint8_t* dex_file_start = GetNextDexFileData(nullptr);
+ dex_file_start != nullptr;
+ dex_file_start = GetNextDexFileData(dex_file_start), ++i) {
+ size_t size = reinterpret_cast<const DexFile::Header*>(dex_file_start)->file_size_;
+ // TODO: Supply the location information for a vdex file.
+ static constexpr char kVdexLocation[] = "";
+ std::string location = DexFile::GetMultiDexLocation(i, kVdexLocation);
+ std::unique_ptr<const DexFile> dex(DexFile::Open(dex_file_start,
+ size,
+ location,
+ GetLocationChecksum(i),
+ nullptr /*oat_dex_file*/,
+ false /*verify*/,
+ false /*verify_checksum*/,
+ error_msg));
+ if (dex == nullptr) {
+ return false;
+ }
+ dex_files->push_back(std::move(dex));
+ }
+ return true;
+}
+
} // namespace art
diff --git a/runtime/vdex_file.h b/runtime/vdex_file.h
index 898d07d..9840555 100644
--- a/runtime/vdex_file.h
+++ b/runtime/vdex_file.h
@@ -27,6 +27,8 @@
namespace art {
+class DexFile;
+
// VDEX files contain extracted DEX files. The VdexFile class maps the file to
// memory and provides tools for accessing its individual sections.
//
@@ -122,6 +124,12 @@
return reinterpret_cast<const uint32_t*>(Begin() + sizeof(Header))[dex_file_index];
}
+ // Opens all the dex files contained in this vdex file. This is currently
+ // used for dumping tools only, and has not been tested for use by the
+ // remainder of the runtime.
+ bool OpenAllDexFiles(std::vector<std::unique_ptr<const DexFile>>* dex_files,
+ std::string* error_msg);
+
private:
explicit VdexFile(MemMap* mmap) : mmap_(mmap) {}
diff --git a/test/901-hello-ti-agent/basics.cc b/test/901-hello-ti-agent/basics.cc
index 00776ca..20b227a 100644
--- a/test/901-hello-ti-agent/basics.cc
+++ b/test/901-hello-ti-agent/basics.cc
@@ -21,7 +21,7 @@
#include <jni.h>
#include <stdio.h>
#include <string.h>
-#include "base/macros.h"
+#include "android-base/macros.h"
#include "jvmti.h"
// Test infrastructure
diff --git a/test/903-hello-tagging/tagging.cc b/test/903-hello-tagging/tagging.cc
index 7f079a2..701b0c3 100644
--- a/test/903-hello-tagging/tagging.cc
+++ b/test/903-hello-tagging/tagging.cc
@@ -19,14 +19,12 @@
#include <stdio.h>
#include <vector>
+#include "android-base/logging.h"
#include "jni.h"
-#include "ScopedLocalRef.h"
-#include "ScopedPrimitiveArray.h"
+#include "scoped_local_ref.h"
+#include "scoped_primitive_array.h"
-#include "art_method-inl.h"
-#include "base/logging.h"
#include "jvmti.h"
-#include "utils.h"
// Test infrastructure
#include "jvmti_helper.h"
diff --git a/test/904-object-allocation/tracking.cc b/test/904-object-allocation/tracking.cc
index 303f954..c829496 100644
--- a/test/904-object-allocation/tracking.cc
+++ b/test/904-object-allocation/tracking.cc
@@ -19,12 +19,11 @@
#include <stdio.h>
#include <vector>
-#include "base/logging.h"
+#include "android-base/logging.h"
#include "jni.h"
#include "jvmti.h"
-#include "ScopedLocalRef.h"
-#include "ScopedUtfChars.h"
-#include "utils.h"
+#include "scoped_local_ref.h"
+#include "scoped_utf_chars.h"
// Test infrastructure
#include "jvmti_helper.h"
diff --git a/test/905-object-free/tracking_free.cc b/test/905-object-free/tracking_free.cc
index 68ce38d..59b429c 100644
--- a/test/905-object-free/tracking_free.cc
+++ b/test/905-object-free/tracking_free.cc
@@ -19,12 +19,11 @@
#include <stdio.h>
#include <vector>
-#include "base/logging.h"
+#include "android-base/logging.h"
#include "jni.h"
#include "jvmti.h"
-#include "ScopedLocalRef.h"
-#include "ScopedUtfChars.h"
-#include "utils.h"
+#include "scoped_local_ref.h"
+#include "scoped_utf_chars.h"
// Test infrastructure
#include "jvmti_helper.h"
diff --git a/test/906-iterate-heap/iterate_heap.cc b/test/906-iterate-heap/iterate_heap.cc
index 74cb1e9..bb30074 100644
--- a/test/906-iterate-heap/iterate_heap.cc
+++ b/test/906-iterate-heap/iterate_heap.cc
@@ -23,16 +23,18 @@
#include <stdio.h>
#include <vector>
+#include "android-base/logging.h"
#include "android-base/stringprintf.h"
-#include "base/logging.h"
+
#include "jni.h"
#include "jvmti.h"
-#include "ScopedPrimitiveArray.h"
-#include "utf.h"
+#include "scoped_primitive_array.h"
// Test infrastructure
#include "jvmti_helper.h"
#include "test_env.h"
+#include "ti_macros.h"
+#include "ti_utf.h"
namespace art {
namespace Test906IterateHeap {
@@ -197,10 +199,10 @@
void* user_data) {
FindStringCallbacks* p = reinterpret_cast<FindStringCallbacks*>(user_data);
if (*tag_ptr == p->tag_to_find) {
- size_t utf_byte_count = CountUtf8Bytes(value, value_length);
+ size_t utf_byte_count = ti::CountUtf8Bytes(value, value_length);
std::unique_ptr<char[]> mod_utf(new char[utf_byte_count + 1]);
memset(mod_utf.get(), 0, utf_byte_count + 1);
- ConvertUtf16ToModifiedUtf8(mod_utf.get(), utf_byte_count, value, value_length);
+ ti::ConvertUtf16ToModifiedUtf8(mod_utf.get(), utf_byte_count, value, value_length);
if (!p->data.empty()) {
p->data += "\n";
}
diff --git a/test/907-get-loaded-classes/get_loaded_classes.cc b/test/907-get-loaded-classes/get_loaded_classes.cc
index 1b973bf..5ec56c4 100644
--- a/test/907-get-loaded-classes/get_loaded_classes.cc
+++ b/test/907-get-loaded-classes/get_loaded_classes.cc
@@ -19,11 +19,12 @@
#include <stdio.h>
#include <vector>
-#include "base/macros.h"
+#include "android-base/macros.h"
+
#include "jni.h"
#include "jvmti.h"
-#include "ScopedLocalRef.h"
-#include "ScopedUtfChars.h"
+#include "scoped_local_ref.h"
+#include "scoped_utf_chars.h"
// Test infrastructure
#include "jni_helper.h"
diff --git a/test/908-gc-start-finish/gc_callbacks.cc b/test/908-gc-start-finish/gc_callbacks.cc
index 4b9a23c..f186895 100644
--- a/test/908-gc-start-finish/gc_callbacks.cc
+++ b/test/908-gc-start-finish/gc_callbacks.cc
@@ -17,7 +17,8 @@
#include <stdio.h>
#include <string.h>
-#include "base/macros.h"
+#include "android-base/macros.h"
+
#include "jni.h"
#include "jvmti.h"
diff --git a/test/909-attach-agent/attach.cc b/test/909-attach-agent/attach.cc
index 67c7567..0150e09 100644
--- a/test/909-attach-agent/attach.cc
+++ b/test/909-attach-agent/attach.cc
@@ -19,7 +19,9 @@
#include <jni.h>
#include <stdio.h>
#include <string.h>
-#include "base/macros.h"
+
+#include "android-base/macros.h"
+
#include "jvmti.h"
namespace art {
diff --git a/test/910-methods/methods.cc b/test/910-methods/methods.cc
index 429076c..ded4f09 100644
--- a/test/910-methods/methods.cc
+++ b/test/910-methods/methods.cc
@@ -16,10 +16,11 @@
#include <stdio.h>
-#include "base/macros.h"
+#include "android-base/macros.h"
+
#include "jni.h"
#include "jvmti.h"
-#include "ScopedLocalRef.h"
+#include "scoped_local_ref.h"
// Test infrastructure
#include "jni_helper.h"
diff --git a/test/911-get-stack-trace/stack_trace.cc b/test/911-get-stack-trace/stack_trace.cc
index 49cbb7e..a499e90 100644
--- a/test/911-get-stack-trace/stack_trace.cc
+++ b/test/911-get-stack-trace/stack_trace.cc
@@ -18,20 +18,19 @@
#include <memory>
#include <stdio.h>
+#include "android-base/logging.h"
#include "android-base/stringprintf.h"
-#include "android-base/stringprintf.h"
-#include "base/logging.h"
-#include "base/macros.h"
#include "jni.h"
#include "jvmti.h"
-#include "ScopedLocalRef.h"
+#include "scoped_local_ref.h"
// Test infrastructure
#include "jni_binder.h"
#include "jni_helper.h"
#include "jvmti_helper.h"
#include "test_env.h"
+#include "ti_macros.h"
namespace art {
namespace Test911GetStackTrace {
diff --git a/test/912-classes/classes.cc b/test/912-classes/classes.cc
index 4d84e39..2636367 100644
--- a/test/912-classes/classes.cc
+++ b/test/912-classes/classes.cc
@@ -16,14 +16,15 @@
#include <stdio.h>
-#include "base/macros.h"
+#include "android-base/macros.h"
+
#include "class_linker.h"
#include "jni.h"
#include "mirror/class_loader.h"
#include "jvmti.h"
#include "runtime.h"
-#include "ScopedLocalRef.h"
-#include "ScopedUtfChars.h"
+#include "scoped_local_ref.h"
+#include "scoped_utf_chars.h"
#include "scoped_thread_state_change-inl.h"
#include "thread-inl.h"
diff --git a/test/913-heaps/heaps.cc b/test/913-heaps/heaps.cc
index 999467f..6a47ca1 100644
--- a/test/913-heaps/heaps.cc
+++ b/test/913-heaps/heaps.cc
@@ -21,10 +21,10 @@
#include <iostream>
#include <vector>
+#include "android-base/macros.h"
+#include "android-base/logging.h"
#include "android-base/stringprintf.h"
-#include "base/logging.h"
-#include "base/macros.h"
#include "jit/jit.h"
#include "jni.h"
#include "native_stack_dump.h"
diff --git a/test/918-fields/fields.cc b/test/918-fields/fields.cc
index 0c019e3..726c5cf 100644
--- a/test/918-fields/fields.cc
+++ b/test/918-fields/fields.cc
@@ -16,10 +16,10 @@
#include <stdio.h>
-#include "base/macros.h"
+#include "android-base/macros.h"
#include "jni.h"
#include "jvmti.h"
-#include "ScopedLocalRef.h"
+#include "scoped_local_ref.h"
// Test infrastructure
#include "jni_helper.h"
diff --git a/test/920-objects/objects.cc b/test/920-objects/objects.cc
index 1dfb516..5263e75 100644
--- a/test/920-objects/objects.cc
+++ b/test/920-objects/objects.cc
@@ -16,10 +16,10 @@
#include <stdio.h>
-#include "base/macros.h"
+#include "android-base/macros.h"
#include "jni.h"
#include "jvmti.h"
-#include "ScopedLocalRef.h"
+#include "scoped_local_ref.h"
// Test infrastructure
#include "test_env.h"
diff --git a/test/922-properties/properties.cc b/test/922-properties/properties.cc
index 948da6a..896e4c3 100644
--- a/test/922-properties/properties.cc
+++ b/test/922-properties/properties.cc
@@ -16,10 +16,10 @@
#include <stdio.h>
-#include "base/macros.h"
+#include "android-base/macros.h"
#include "jni.h"
#include "jvmti.h"
-#include "ScopedUtfChars.h"
+#include "scoped_utf_chars.h"
// Test infrastructure
#include "jni_helper.h"
diff --git a/test/923-monitors/monitors.cc b/test/923-monitors/monitors.cc
index 60d5b5a..6369a74 100644
--- a/test/923-monitors/monitors.cc
+++ b/test/923-monitors/monitors.cc
@@ -16,10 +16,10 @@
#include <stdio.h>
-#include "base/macros.h"
+#include "android-base/macros.h"
#include "jni.h"
#include "jvmti.h"
-#include "ScopedUtfChars.h"
+#include "scoped_utf_chars.h"
// Test infrastructure
#include "jvmti_helper.h"
diff --git a/test/924-threads/threads.cc b/test/924-threads/threads.cc
index bb040bd..a8b37ec 100644
--- a/test/924-threads/threads.cc
+++ b/test/924-threads/threads.cc
@@ -16,17 +16,17 @@
#include <stdio.h>
+#include "android-base/logging.h"
#include "android-base/stringprintf.h"
-#include "base/macros.h"
-#include "base/logging.h"
#include "jni.h"
#include "jvmti.h"
-#include "ScopedLocalRef.h"
+#include "scoped_local_ref.h"
// Test infrastructure
#include "jni_helper.h"
#include "jvmti_helper.h"
#include "test_env.h"
+#include "ti_macros.h"
namespace art {
namespace Test924Threads {
diff --git a/test/925-threadgroups/threadgroups.cc b/test/925-threadgroups/threadgroups.cc
index 1cd93be..d555553 100644
--- a/test/925-threadgroups/threadgroups.cc
+++ b/test/925-threadgroups/threadgroups.cc
@@ -16,17 +16,17 @@
#include <stdio.h>
+#include "android-base/logging.h"
#include "android-base/stringprintf.h"
-#include "base/macros.h"
-#include "base/logging.h"
#include "jni.h"
#include "jvmti.h"
-#include "ScopedLocalRef.h"
+#include "scoped_local_ref.h"
// Test infrastructure
#include "jni_helper.h"
#include "jvmti_helper.h"
#include "test_env.h"
+#include "ti_macros.h"
namespace art {
namespace Test925ThreadGroups {
diff --git a/test/927-timers/timers.cc b/test/927-timers/timers.cc
index a67f5b4..55d3921 100644
--- a/test/927-timers/timers.cc
+++ b/test/927-timers/timers.cc
@@ -16,9 +16,9 @@
#include <inttypes.h>
+#include "android-base/logging.h"
#include "android-base/stringprintf.h"
-#include "base/logging.h"
-#include "base/macros.h"
+
#include "jni.h"
#include "jvmti.h"
@@ -26,6 +26,7 @@
#include "jni_helper.h"
#include "jvmti_helper.h"
#include "test_env.h"
+#include "ti_macros.h"
namespace art {
namespace Test926Timers {
diff --git a/test/928-jni-table/jni_table.cc b/test/928-jni-table/jni_table.cc
index 3f4a93e..26a6707 100644
--- a/test/928-jni-table/jni_table.cc
+++ b/test/928-jni-table/jni_table.cc
@@ -19,8 +19,8 @@
#include "jni.h"
#include "jvmti.h"
-#include "base/logging.h"
-#include "base/macros.h"
+#include "android-base/logging.h"
+#include "android-base/macros.h"
// Test infrastructure
#include "jvmti_helper.h"
diff --git a/test/929-search/search.cc b/test/929-search/search.cc
index bed4dfe..5516105 100644
--- a/test/929-search/search.cc
+++ b/test/929-search/search.cc
@@ -16,12 +16,12 @@
#include <inttypes.h>
+#include "android-base/logging.h"
+#include "android-base/macros.h"
#include "android-base/stringprintf.h"
-#include "base/logging.h"
-#include "base/macros.h"
#include "jni.h"
#include "jvmti.h"
-#include "ScopedUtfChars.h"
+#include "scoped_utf_chars.h"
// Test infrastructure
#include "jvmti_helper.h"
diff --git a/test/931-agent-thread/agent_thread.cc b/test/931-agent-thread/agent_thread.cc
index 3ec8793..f9af8cf 100644
--- a/test/931-agent-thread/agent_thread.cc
+++ b/test/931-agent-thread/agent_thread.cc
@@ -15,17 +15,14 @@
*/
#include <inttypes.h>
+#include <pthread.h>
#include <sched.h>
-#include "barrier.h"
-#include "base/logging.h"
-#include "base/macros.h"
+#include "android-base/logging.h"
+#include "android-base/macros.h"
#include "jni.h"
#include "jvmti.h"
-#include "runtime.h"
-#include "ScopedLocalRef.h"
-#include "thread-inl.h"
-#include "well_known_classes.h"
+#include "scoped_local_ref.h"
// Test infrastructure
#include "jvmti_helper.h"
@@ -37,13 +34,12 @@
struct AgentData {
AgentData() : main_thread(nullptr),
jvmti_env(nullptr),
- b(2),
priority(0) {
}
jthread main_thread;
jvmtiEnv* jvmti_env;
- Barrier b;
+ pthread_barrier_t b;
jint priority;
};
@@ -54,14 +50,21 @@
// This thread is not the main thread.
jthread this_thread;
jvmtiError this_thread_result = jenv->GetCurrentThread(&this_thread);
- CHECK(!JvmtiErrorToException(env, jenv, this_thread_result));
+ CheckJvmtiError(jenv, this_thread_result);
CHECK(!env->IsSameObject(this_thread, data->main_thread));
// The thread is a daemon.
jvmtiThreadInfo info;
jvmtiError info_result = jenv->GetThreadInfo(this_thread, &info);
- CHECK(!JvmtiErrorToException(env, jenv, info_result));
+ CheckJvmtiError(jenv, info_result);
CHECK(info.is_daemon);
+ CheckJvmtiError(jenv, jenv->Deallocate(reinterpret_cast<unsigned char*>(info.name)));
+ if (info.thread_group != nullptr) {
+ env->DeleteLocalRef(info.thread_group);
+ }
+ if (info.context_class_loader != nullptr) {
+ env->DeleteLocalRef(info.context_class_loader);
+ }
// The thread has the requested priority.
// TODO: Our thread priorities do not work on the host.
@@ -71,7 +74,7 @@
jint thread_count;
jthread* threads;
jvmtiError threads_result = jenv->GetAllThreads(&thread_count, &threads);
- CHECK(!JvmtiErrorToException(env, jenv, threads_result));
+ CheckJvmtiError(jenv, threads_result);
bool found = false;
for (jint i = 0; i != thread_count; ++i) {
if (env->IsSameObject(threads[i], this_thread)) {
@@ -82,29 +85,53 @@
CHECK(found);
// Done, let the main thread progress.
- data->b.Pass(Thread::Current());
+ int wait_result = pthread_barrier_wait(&data->b);
+ CHECK(wait_result == PTHREAD_BARRIER_SERIAL_THREAD || wait_result == 0);
}
extern "C" JNIEXPORT void JNICALL Java_Main_testAgentThread(
JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED) {
// Create a Thread object.
- ScopedLocalRef<jobject> thread_name(env,
- env->NewStringUTF("Agent Thread"));
+ ScopedLocalRef<jobject> thread_name(env, env->NewStringUTF("Agent Thread"));
if (thread_name.get() == nullptr) {
return;
}
- ScopedLocalRef<jobject> thread(env, env->AllocObject(WellKnownClasses::java_lang_Thread));
+ ScopedLocalRef<jclass> thread_klass(env, env->FindClass("java/lang/Thread"));
+ if (thread_klass.get() == nullptr) {
+ return;
+ }
+ ScopedLocalRef<jobject> thread(env, env->AllocObject(thread_klass.get()));
if (thread.get() == nullptr) {
return;
}
+ // Get a ThreadGroup from the current thread. We need a non-null one as we're gonna call a
+ // runtime-only constructor (so we can set priority and daemon state).
+ jvmtiThreadInfo cur_thread_info;
+ jvmtiError info_result = jvmti_env->GetThreadInfo(nullptr, &cur_thread_info);
+ if (JvmtiErrorToException(env, jvmti_env, info_result)) {
+ return;
+ }
+ CheckJvmtiError(jvmti_env,
+ jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(cur_thread_info.name)));
+ ScopedLocalRef<jobject> thread_group(env, cur_thread_info.thread_group);
+ if (cur_thread_info.context_class_loader != nullptr) {
+ env->DeleteLocalRef(cur_thread_info.context_class_loader);
+ }
+
+ jmethodID initID = env->GetMethodID(thread_klass.get(),
+ "<init>",
+ "(Ljava/lang/ThreadGroup;Ljava/lang/String;IZ)V");
+ if (initID == nullptr) {
+ return;
+ }
env->CallNonvirtualVoidMethod(thread.get(),
- WellKnownClasses::java_lang_Thread,
- WellKnownClasses::java_lang_Thread_init,
- Runtime::Current()->GetMainThreadGroup(),
+ thread_klass.get(),
+ initID,
+ thread_group.get(),
thread_name.get(),
- kMinThreadPriority,
+ 0,
JNI_FALSE);
if (env->ExceptionCheck()) {
return;
@@ -120,18 +147,20 @@
data.main_thread = env->NewGlobalRef(main_thread);
data.jvmti_env = jvmti_env;
data.priority = JVMTI_THREAD_MIN_PRIORITY;
+ CHECK_EQ(0, pthread_barrier_init(&data.b, nullptr, 2));
jvmtiError result = jvmti_env->RunAgentThread(thread.get(), AgentMain, &data, data.priority);
if (JvmtiErrorToException(env, jvmti_env, result)) {
return;
}
- data.b.Wait(Thread::Current());
+ int wait_result = pthread_barrier_wait(&data.b);
+ CHECK(wait_result == PTHREAD_BARRIER_SERIAL_THREAD || wait_result == 0);
// Scheduling may mean that the agent thread is put to sleep. Wait until it's dead in an effort
// to not unload the plugin and crash.
for (;;) {
- NanoSleep(1000 * 1000);
+ sleep(1);
jint thread_state;
jvmtiError state_result = jvmti_env->GetThreadState(thread.get(), &thread_state);
if (JvmtiErrorToException(env, jvmti_env, state_result)) {
@@ -144,9 +173,11 @@
}
// Yield and sleep a bit more, to give the plugin time to tear down the native thread structure.
sched_yield();
- NanoSleep(100 * 1000 * 1000);
+ sleep(1);
env->DeleteGlobalRef(data.main_thread);
+
+ pthread_barrier_destroy(&data.b);
}
} // namespace Test930AgentThread
diff --git a/test/933-misc-events/misc_events.cc b/test/933-misc-events/misc_events.cc
index 7b6c64d..2b74c40 100644
--- a/test/933-misc-events/misc_events.cc
+++ b/test/933-misc-events/misc_events.cc
@@ -18,8 +18,8 @@
#include <signal.h>
#include <sys/types.h>
-#include "base/logging.h"
-#include "base/macros.h"
+#include "android-base/logging.h"
+#include "android-base/macros.h"
#include "jni.h"
#include "jvmti.h"
diff --git a/test/936-search-onload/search_onload.cc b/test/936-search-onload/search_onload.cc
index 72987eb..b2ef056 100644
--- a/test/936-search-onload/search_onload.cc
+++ b/test/936-search-onload/search_onload.cc
@@ -23,7 +23,7 @@
#include "base/macros.h"
#include "jni.h"
#include "jvmti.h"
-#include "ScopedUtfChars.h"
+#include "scoped_utf_chars.h"
// Test infrastructure
#include "jvmti_helper.h"
diff --git a/test/944-transform-classloaders/classloader.cc b/test/944-transform-classloaders/classloader.cc
index f46763c..698e023 100644
--- a/test/944-transform-classloaders/classloader.cc
+++ b/test/944-transform-classloaders/classloader.cc
@@ -14,11 +14,11 @@
* limitations under the License.
*/
-#include "base/macros.h"
+#include "android-base/macros.h"
#include "jni.h"
#include "jvmti.h"
#include "mirror/class-inl.h"
-#include "ScopedLocalRef.h"
+#include "scoped_local_ref.h"
// Test infrastructure
#include "test_env.h"
@@ -26,7 +26,6 @@
namespace art {
namespace Test944TransformClassloaders {
-
extern "C" JNIEXPORT jlong JNICALL Java_Main_getDexFilePointer(JNIEnv* env, jclass, jclass klass) {
if (Runtime::Current() == nullptr) {
env->ThrowNew(env->FindClass("java/lang/Exception"),
diff --git a/test/945-obsolete-native/obsolete_native.cc b/test/945-obsolete-native/obsolete_native.cc
index b9303dd..ee653a4 100644
--- a/test/945-obsolete-native/obsolete_native.cc
+++ b/test/945-obsolete-native/obsolete_native.cc
@@ -25,7 +25,7 @@
#include "base/macros.h"
#include "jni.h"
#include "jvmti.h"
-#include "ScopedLocalRef.h"
+#include "scoped_local_ref.h"
// Test infrastructure
#include "jni_binder.h"
diff --git a/test/980-redefine-object/redefine_object.cc b/test/980-redefine-object/redefine_object.cc
index 6c8c4bd..1faf1a1 100644
--- a/test/980-redefine-object/redefine_object.cc
+++ b/test/980-redefine-object/redefine_object.cc
@@ -22,7 +22,7 @@
#include "base/macros.h"
#include "jni.h"
#include "jvmti.h"
-#include "ScopedUtfChars.h"
+#include "scoped_utf_chars.h"
// Test infrastructure
#include "jni_binder.h"
diff --git a/test/Android.bp b/test/Android.bp
index 2e8f5bb..40f7edd 100644
--- a/test/Android.bp
+++ b/test/Android.bp
@@ -241,29 +241,24 @@
}
art_cc_defaults {
- name: "libtiagent-defaults",
+ name: "libtiagent-base-defaults",
defaults: ["libartagent-defaults"],
srcs: [
- // This is to get the IsInterpreted native method.
- "common/stack_inspect.cc",
- "common/runtime_state.cc",
- "ti-agent/common_load.cc",
- "ti-agent/common_helper.cc",
+ // These are the ART-independent parts.
+ "ti-agent/agent_startup.cc",
"ti-agent/jni_binder.cc",
"ti-agent/jvmti_helper.cc",
"ti-agent/test_env.cc",
- "901-hello-ti-agent/basics.cc",
+ // This is the list of non-special OnLoad things and excludes BCI and anything that depends
+ // on ART internals.
"903-hello-tagging/tagging.cc",
"904-object-allocation/tracking.cc",
"905-object-free/tracking_free.cc",
"906-iterate-heap/iterate_heap.cc",
"907-get-loaded-classes/get_loaded_classes.cc",
"908-gc-start-finish/gc_callbacks.cc",
- "909-attach-agent/attach.cc",
"910-methods/methods.cc",
"911-get-stack-trace/stack_trace.cc",
- "912-classes/classes.cc",
- "913-heaps/heaps.cc",
"918-fields/fields.cc",
"920-objects/objects.cc",
"922-properties/properties.cc",
@@ -275,11 +270,6 @@
"929-search/search.cc",
"931-agent-thread/agent_thread.cc",
"933-misc-events/misc_events.cc",
- "936-search-onload/search_onload.cc",
- "944-transform-classloaders/classloader.cc",
- "945-obsolete-native/obsolete_native.cc",
- "980-redefine-object/redefine_object.cc",
- "983-source-transform-verify/source_transform.cc",
],
shared_libs: [
"libbase",
@@ -288,6 +278,29 @@
include_dirs: ["art/test/ti-agent"],
}
+art_cc_defaults {
+ name: "libtiagent-defaults",
+ defaults: ["libtiagent-base-defaults"],
+ srcs: [
+ // This is to get the IsInterpreted native method.
+ "common/stack_inspect.cc",
+ "common/runtime_state.cc",
+ // This includes the remaining test functions. We should try to refactor things to
+ // make this list smaller.
+ "ti-agent/common_helper.cc",
+ "ti-agent/common_load.cc",
+ "901-hello-ti-agent/basics.cc",
+ "909-attach-agent/attach.cc",
+ "912-classes/classes.cc",
+ "913-heaps/heaps.cc",
+ "936-search-onload/search_onload.cc",
+ "944-transform-classloaders/classloader.cc",
+ "945-obsolete-native/obsolete_native.cc",
+ "980-redefine-object/redefine_object.cc",
+ "983-source-transform-verify/source_transform.cc",
+ ],
+}
+
art_cc_test_library {
name: "libtiagent",
defaults: ["libtiagent-defaults"],
@@ -303,6 +316,12 @@
shared_libs: ["libartd"],
}
+art_cc_test_library {
+ name: "libctstiagent",
+ defaults: ["libtiagent-base-defaults"],
+ export_include_dirs: ["ti-agent"],
+}
+
cc_defaults {
name: "libarttest-defaults",
defaults: [
diff --git a/test/ti-agent/agent_startup.cc b/test/ti-agent/agent_startup.cc
new file mode 100644
index 0000000..b55db7b
--- /dev/null
+++ b/test/ti-agent/agent_startup.cc
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "agent_startup.h"
+
+#include "android-base/logging.h"
+#include "android-base/macros.h"
+
+#include "jni_binder.h"
+#include "jvmti_helper.h"
+
+namespace art {
+
+static constexpr const char* kMainClass = "Main";
+
+static StartCallback gCallback = nullptr;
+
+// TODO: Check this. This may not work on device. The classloader containing the app's classes
+// may not have been created at this point (i.e., if it's not the system classloader).
+static void JNICALL VMInitCallback(jvmtiEnv* jvmti_env,
+ JNIEnv* jni_env,
+ jthread thread ATTRIBUTE_UNUSED) {
+ // Bind kMainClass native methods.
+ BindFunctions(jvmti_env, jni_env, kMainClass);
+
+ if (gCallback != nullptr) {
+ gCallback(jvmti_env, jni_env);
+ gCallback = nullptr;
+ }
+
+ // And delete the jvmtiEnv.
+ jvmti_env->DisposeEnvironment();
+}
+
+// Install a phase callback that will bind JNI functions on VMInit.
+void BindOnLoad(JavaVM* vm, StartCallback callback) {
+ // Use a new jvmtiEnv. Otherwise we might collide with table changes.
+ jvmtiEnv* install_env;
+ if (vm->GetEnv(reinterpret_cast<void**>(&install_env), JVMTI_VERSION_1_0) != 0) {
+ LOG(FATAL) << "Could not get jvmtiEnv";
+ }
+ SetAllCapabilities(install_env);
+
+ {
+ jvmtiEventCallbacks callbacks;
+ memset(&callbacks, 0, sizeof(jvmtiEventCallbacks));
+ callbacks.VMInit = VMInitCallback;
+
+ CheckJvmtiError(install_env, install_env->SetEventCallbacks(&callbacks, sizeof(callbacks)));
+ }
+
+ CheckJvmtiError(install_env, install_env->SetEventNotificationMode(JVMTI_ENABLE,
+ JVMTI_EVENT_VM_INIT,
+ nullptr));
+
+ gCallback = callback;
+}
+
+// Ensure binding of the Main class when the agent is started through OnAttach.
+void BindOnAttach(JavaVM* vm, StartCallback callback) {
+ // Get a JNIEnv. As the thread is attached, we must not destroy it.
+ JNIEnv* env;
+ CHECK_EQ(0, vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6))
+ << "Could not get JNIEnv";
+
+ jvmtiEnv* jvmti_env;
+ CHECK_EQ(0, vm->GetEnv(reinterpret_cast<void**>(&jvmti_env), JVMTI_VERSION_1_0))
+ << "Could not get jvmtiEnv";
+ SetAllCapabilities(jvmti_env);
+
+ BindFunctions(jvmti_env, env, kMainClass);
+
+ if (callback != nullptr) {
+ callback(jvmti_env, env);
+ }
+
+ if (jvmti_env->DisposeEnvironment() != JVMTI_ERROR_NONE) {
+ LOG(FATAL) << "Could not dispose temporary jvmtiEnv";
+ }
+}
+
+} // namespace art
diff --git a/test/ti-agent/agent_startup.h b/test/ti-agent/agent_startup.h
new file mode 100644
index 0000000..4963320
--- /dev/null
+++ b/test/ti-agent/agent_startup.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_TEST_TI_AGENT_AGENT_STARTUP_H_
+#define ART_TEST_TI_AGENT_AGENT_STARTUP_H_
+
+#include <functional>
+
+#include "jni.h"
+#include "jvmti.h"
+
+namespace art {
+
+using StartCallback = void(*)(jvmtiEnv*, JNIEnv*);
+
+// Ensure binding of the Main class when the agent is started through OnLoad.
+void BindOnLoad(JavaVM* vm, StartCallback callback);
+
+// Ensure binding of the Main class when the agent is started through OnAttach.
+void BindOnAttach(JavaVM* vm, StartCallback callback);
+
+} // namespace art
+
+#endif // ART_TEST_TI_AGENT_AGENT_STARTUP_H_
diff --git a/test/ti-agent/common_load.cc b/test/ti-agent/common_load.cc
index c5d75c9..9e7b75d 100644
--- a/test/ti-agent/common_load.cc
+++ b/test/ti-agent/common_load.cc
@@ -19,6 +19,8 @@
#include "base/logging.h"
#include "base/macros.h"
+
+#include "agent_startup.h"
#include "common_helper.h"
#include "jni_binder.h"
#include "jvmti_helper.h"
@@ -42,45 +44,6 @@
OnAttach attach;
};
-static void JNICALL VMInitCallback(jvmtiEnv *jvmti_env,
- JNIEnv* jni_env,
- jthread thread ATTRIBUTE_UNUSED) {
- // Bind Main native methods.
- BindFunctions(jvmti_env, jni_env, "Main");
-}
-
-// Install a phase callback that will bind JNI functions on VMInit.
-bool InstallBindCallback(JavaVM* vm) {
- // Use a new jvmtiEnv. Otherwise we might collide with table changes.
- jvmtiEnv* install_env;
- if (vm->GetEnv(reinterpret_cast<void**>(&install_env), JVMTI_VERSION_1_0) != 0) {
- return false;
- }
- SetAllCapabilities(install_env);
-
- {
- jvmtiEventCallbacks callbacks;
- memset(&callbacks, 0, sizeof(jvmtiEventCallbacks));
- callbacks.VMInit = VMInitCallback;
-
- jvmtiError install_error = install_env->SetEventCallbacks(&callbacks, sizeof(callbacks));
- if (install_error != JVMTI_ERROR_NONE) {
- return false;
- }
- }
-
- {
- jvmtiError enable_error = install_env->SetEventNotificationMode(JVMTI_ENABLE,
- JVMTI_EVENT_VM_INIT,
- nullptr);
- if (enable_error != JVMTI_ERROR_NONE) {
- return false;
- }
- }
-
- return true;
-}
-
// A trivial OnLoad implementation that only initializes the global jvmti_env.
static jint MinimalOnLoad(JavaVM* vm,
char* options ATTRIBUTE_UNUSED,
@@ -156,26 +119,6 @@
SetJVM(strncmp(options, "jvm", 3) == 0);
}
-static bool BindFunctionsAttached(JavaVM* vm, const char* class_name) {
- // Get a JNIEnv. As the thread is attached, we must not destroy it.
- JNIEnv* env;
- if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != 0) {
- printf("Unable to get JNI env!\n");
- return false;
- }
-
- jvmtiEnv* jenv;
- if (vm->GetEnv(reinterpret_cast<void**>(&jenv), JVMTI_VERSION_1_0) != 0) {
- printf("Unable to get jvmti env!\n");
- return false;
- }
- SetAllCapabilities(jenv);
-
- BindFunctions(jenv, env, class_name);
-
- return true;
-}
-
} // namespace
extern "C" JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM* vm, char* options, void* reserved) {
@@ -188,9 +131,7 @@
SetIsJVM(remaining_options);
- if (!InstallBindCallback(vm)) {
- return 1;
- }
+ BindOnLoad(vm, nullptr);
AgentLib* lib = FindAgent(name_option);
OnLoad fn = nullptr;
@@ -214,7 +155,7 @@
return -1;
}
- BindFunctionsAttached(vm, "Main");
+ BindOnAttach(vm, nullptr);
AgentLib* lib = FindAgent(name_option);
if (lib == nullptr) {
diff --git a/test/ti-agent/jni_binder.cc b/test/ti-agent/jni_binder.cc
index efc2af8..b66c2c7 100644
--- a/test/ti-agent/jni_binder.cc
+++ b/test/ti-agent/jni_binder.cc
@@ -26,94 +26,16 @@
#include "jvmti_helper.h"
#include "scoped_local_ref.h"
#include "scoped_utf_chars.h"
+#include "ti_utf.h"
namespace art {
-size_t CountModifiedUtf8Chars(const char* utf8, size_t byte_count) {
- DCHECK_LE(byte_count, strlen(utf8));
- size_t len = 0;
- const char* end = utf8 + byte_count;
- for (; utf8 < end; ++utf8) {
- int ic = *utf8;
- len++;
- if (LIKELY((ic & 0x80) == 0)) {
- // One-byte encoding.
- continue;
- }
- // Two- or three-byte encoding.
- utf8++;
- if ((ic & 0x20) == 0) {
- // Two-byte encoding.
- continue;
- }
- utf8++;
- if ((ic & 0x10) == 0) {
- // Three-byte encoding.
- continue;
- }
-
- // Four-byte encoding: needs to be converted into a surrogate
- // pair.
- utf8++;
- len++;
- }
- return len;
-}
-
-static uint16_t GetTrailingUtf16Char(uint32_t maybe_pair) {
- return static_cast<uint16_t>(maybe_pair >> 16);
-}
-
-static uint16_t GetLeadingUtf16Char(uint32_t maybe_pair) {
- return static_cast<uint16_t>(maybe_pair & 0x0000FFFF);
-}
-
-static uint32_t GetUtf16FromUtf8(const char** utf8_data_in) {
- const uint8_t one = *(*utf8_data_in)++;
- if ((one & 0x80) == 0) {
- // one-byte encoding
- return one;
- }
-
- const uint8_t two = *(*utf8_data_in)++;
- if ((one & 0x20) == 0) {
- // two-byte encoding
- return ((one & 0x1f) << 6) | (two & 0x3f);
- }
-
- const uint8_t three = *(*utf8_data_in)++;
- if ((one & 0x10) == 0) {
- return ((one & 0x0f) << 12) | ((two & 0x3f) << 6) | (three & 0x3f);
- }
-
- // Four byte encodings need special handling. We'll have
- // to convert them into a surrogate pair.
- const uint8_t four = *(*utf8_data_in)++;
-
- // Since this is a 4 byte UTF-8 sequence, it will lie between
- // U+10000 and U+1FFFFF.
- //
- // TODO: What do we do about values in (U+10FFFF, U+1FFFFF) ? The
- // spec says they're invalid but nobody appears to check for them.
- const uint32_t code_point = ((one & 0x0f) << 18) | ((two & 0x3f) << 12)
- | ((three & 0x3f) << 6) | (four & 0x3f);
-
- uint32_t surrogate_pair = 0;
- // Step two: Write out the high (leading) surrogate to the bottom 16 bits
- // of the of the 32 bit type.
- surrogate_pair |= ((code_point >> 10) + 0xd7c0) & 0xffff;
- // Step three : Write out the low (trailing) surrogate to the top 16 bits.
- surrogate_pair |= ((code_point & 0x03ff) + 0xdc00) << 16;
-
- return surrogate_pair;
-}
-
static std::string MangleForJni(const std::string& s) {
std::string result;
- size_t char_count = CountModifiedUtf8Chars(s.c_str(), s.length());
+ size_t char_count = ti::CountModifiedUtf8Chars(s.c_str(), s.length());
const char* cp = &s[0];
for (size_t i = 0; i < char_count; ++i) {
- uint32_t ch = GetUtf16FromUtf8(&cp);
+ uint32_t ch = ti::GetUtf16FromUtf8(&cp);
if ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9')) {
result.push_back(ch);
} else if (ch == '.' || ch == '/') {
@@ -125,8 +47,8 @@
} else if (ch == '[') {
result += "_3";
} else {
- const uint16_t leading = GetLeadingUtf16Char(ch);
- const uint32_t trailing = GetTrailingUtf16Char(ch);
+ const uint16_t leading = ti::GetLeadingUtf16Char(ch);
+ const uint32_t trailing = ti::GetTrailingUtf16Char(ch);
android::base::StringAppendF(&result, "_0%04x", leading);
if (trailing != 0) {
diff --git a/test/ti-agent/jni_helper.h b/test/ti-agent/jni_helper.h
index c48b0c0..0cbc634 100644
--- a/test/ti-agent/jni_helper.h
+++ b/test/ti-agent/jni_helper.h
@@ -54,6 +54,19 @@
return ret.release();
}
+inline bool JniThrowNullPointerException(JNIEnv* env, const char* msg) {
+ if (env->ExceptionCheck()) {
+ env->ExceptionClear();
+ }
+
+ ScopedLocalRef<jclass> exc_class(env, env->FindClass("java/lang/NullPointerException"));
+ if (exc_class.get() == nullptr) {
+ return -1;
+ }
+
+ return env->ThrowNew(exc_class.get(), msg) == JNI_OK;
+}
+
} // namespace art
#endif // ART_TEST_TI_AGENT_JNI_HELPER_H_
diff --git a/test/ti-agent/scoped_local_ref.h b/test/ti-agent/scoped_local_ref.h
index 0cd9891..daa1583 100644
--- a/test/ti-agent/scoped_local_ref.h
+++ b/test/ti-agent/scoped_local_ref.h
@@ -35,9 +35,9 @@
reset();
}
- void reset(T ptr = NULL) {
+ void reset(T ptr = nullptr) {
if (ptr != mLocalRef) {
- if (mLocalRef != NULL) {
+ if (mLocalRef != nullptr) {
mEnv->DeleteLocalRef(mLocalRef);
}
mLocalRef = ptr;
@@ -46,7 +46,7 @@
T release() __attribute__((warn_unused_result)) {
T localRef = mLocalRef;
- mLocalRef = NULL;
+ mLocalRef = nullptr;
return localRef;
}
diff --git a/test/ti-agent/scoped_primitive_array.h b/test/ti-agent/scoped_primitive_array.h
new file mode 100644
index 0000000..1649ed9
--- /dev/null
+++ b/test/ti-agent/scoped_primitive_array.h
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2010 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_TEST_TI_AGENT_SCOPED_PRIMITIVE_ARRAY_H_
+#define ART_TEST_TI_AGENT_SCOPED_PRIMITIVE_ARRAY_H_
+
+#include "jni.h"
+
+#include "android-base/macros.h"
+
+#include "jni_helper.h"
+
+namespace art {
+
+#ifdef POINTER_TYPE
+#error POINTER_TYPE is defined.
+#else
+#define POINTER_TYPE(T) T* /* NOLINT */
+#endif
+
+#ifdef REFERENCE_TYPE
+#error REFERENCE_TYPE is defined.
+#else
+#define REFERENCE_TYPE(T) T& /* NOLINT */
+#endif
+
+// ScopedBooleanArrayRO, ScopedByteArrayRO, ScopedCharArrayRO, ScopedDoubleArrayRO,
+// ScopedFloatArrayRO, ScopedIntArrayRO, ScopedLongArrayRO, and ScopedShortArrayRO provide
+// convenient read-only access to Java arrays from JNI code. This is cheaper than read-write
+// access and should be used by default.
+#define INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RO(PRIMITIVE_TYPE, NAME) \
+ class Scoped ## NAME ## ArrayRO { \
+ public: \
+ explicit Scoped ## NAME ## ArrayRO(JNIEnv* env) \
+ : mEnv(env), mJavaArray(nullptr), mRawArray(nullptr), mSize(0) {} \
+ Scoped ## NAME ## ArrayRO(JNIEnv* env, PRIMITIVE_TYPE ## Array javaArray) \
+ : mEnv(env) { \
+ if (javaArray == nullptr) { \
+ mJavaArray = nullptr; \
+ mSize = 0; \
+ mRawArray = nullptr; \
+ JniThrowNullPointerException(env, nullptr); \
+ } else { \
+ reset(javaArray); \
+ } \
+ } \
+ ~Scoped ## NAME ## ArrayRO() { \
+ if (mRawArray != nullptr && mRawArray != mBuffer) { \
+ mEnv->Release ## NAME ## ArrayElements(mJavaArray, mRawArray, JNI_ABORT); \
+ } \
+ } \
+ void reset(PRIMITIVE_TYPE ## Array javaArray) { \
+ mJavaArray = javaArray; \
+ mSize = mEnv->GetArrayLength(mJavaArray); \
+ if (mSize <= kBufferSize) { \
+ mEnv->Get ## NAME ## ArrayRegion(mJavaArray, 0, mSize, mBuffer); \
+ mRawArray = mBuffer; \
+ } else { \
+ mRawArray = mEnv->Get ## NAME ## ArrayElements(mJavaArray, nullptr); \
+ } \
+ } \
+ const PRIMITIVE_TYPE* get() const { return mRawArray; } \
+ PRIMITIVE_TYPE ## Array getJavaArray() const { return mJavaArray; } \
+ const PRIMITIVE_TYPE& operator[](size_t n) const { return mRawArray[n]; } \
+ size_t size() const { return mSize; } \
+ private: \
+ static constexpr jsize kBufferSize = 1024; \
+ JNIEnv* const mEnv; \
+ PRIMITIVE_TYPE ## Array mJavaArray; \
+ POINTER_TYPE(PRIMITIVE_TYPE) mRawArray; \
+ jsize mSize; \
+ PRIMITIVE_TYPE mBuffer[kBufferSize]; \
+ DISALLOW_COPY_AND_ASSIGN(Scoped ## NAME ## ArrayRO); \
+ }
+
+INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RO(jboolean, Boolean);
+INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RO(jbyte, Byte);
+INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RO(jchar, Char);
+INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RO(jdouble, Double);
+INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RO(jfloat, Float);
+INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RO(jint, Int);
+INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RO(jlong, Long);
+INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RO(jshort, Short);
+
+#undef INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RO
+
+// ScopedBooleanArrayRW, ScopedByteArrayRW, ScopedCharArrayRW, ScopedDoubleArrayRW,
+// ScopedFloatArrayRW, ScopedIntArrayRW, ScopedLongArrayRW, and ScopedShortArrayRW provide
+// convenient read-write access to Java arrays from JNI code. These are more expensive,
+// since they entail a copy back onto the Java heap, and should only be used when necessary.
+#define INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RW(PRIMITIVE_TYPE, NAME) \
+ class Scoped ## NAME ## ArrayRW { \
+ public: \
+ explicit Scoped ## NAME ## ArrayRW(JNIEnv* env) \
+ : mEnv(env), mJavaArray(nullptr), mRawArray(nullptr) {} \
+ Scoped ## NAME ## ArrayRW(JNIEnv* env, PRIMITIVE_TYPE ## Array javaArray) \
+ : mEnv(env), mJavaArray(javaArray), mRawArray(nullptr) { \
+ if (mJavaArray == nullptr) { \
+ JniThrowNullPointerException(env, nullptr); \
+ } else { \
+ mRawArray = mEnv->Get ## NAME ## ArrayElements(mJavaArray, nullptr); \
+ } \
+ } \
+ ~Scoped ## NAME ## ArrayRW() { \
+ if (mRawArray) { \
+ mEnv->Release ## NAME ## ArrayElements(mJavaArray, mRawArray, 0); \
+ } \
+ } \
+ void reset(PRIMITIVE_TYPE ## Array javaArray) { \
+ mJavaArray = javaArray; \
+ mRawArray = mEnv->Get ## NAME ## ArrayElements(mJavaArray, nullptr); \
+ } \
+ const PRIMITIVE_TYPE* get() const { return mRawArray; } \
+ PRIMITIVE_TYPE ## Array getJavaArray() const { return mJavaArray; } \
+ const PRIMITIVE_TYPE& operator[](size_t n) const { return mRawArray[n]; } \
+ POINTER_TYPE(PRIMITIVE_TYPE) get() { return mRawArray; } \
+ REFERENCE_TYPE(PRIMITIVE_TYPE) operator[](size_t n) { return mRawArray[n]; } \
+ size_t size() const { return mEnv->GetArrayLength(mJavaArray); } \
+ private: \
+ JNIEnv* const mEnv; \
+ PRIMITIVE_TYPE ## Array mJavaArray; \
+ POINTER_TYPE(PRIMITIVE_TYPE) mRawArray; \
+ DISALLOW_COPY_AND_ASSIGN(Scoped ## NAME ## ArrayRW); \
+ }
+
+INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RW(jboolean, Boolean);
+INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RW(jbyte, Byte);
+INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RW(jchar, Char);
+INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RW(jdouble, Double);
+INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RW(jfloat, Float);
+INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RW(jint, Int);
+INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RW(jlong, Long);
+INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RW(jshort, Short);
+
+#undef INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RW
+#undef POINTER_TYPE
+#undef REFERENCE_TYPE
+
+} // namespace art
+
+#endif // ART_TEST_TI_AGENT_SCOPED_PRIMITIVE_ARRAY_H_
diff --git a/test/ti-agent/scoped_utf_chars.h b/test/ti-agent/scoped_utf_chars.h
index e8c9a11..422caaf 100644
--- a/test/ti-agent/scoped_utf_chars.h
+++ b/test/ti-agent/scoped_utf_chars.h
@@ -23,6 +23,8 @@
#include "android-base/macros.h"
+#include "jni_helper.h"
+
namespace art {
class ScopedUtfChars {
@@ -30,7 +32,7 @@
ScopedUtfChars(JNIEnv* env, jstring s) : env_(env), string_(s) {
if (s == nullptr) {
utf_chars_ = nullptr;
- // TODO: JniThrowNullPointerException(env, nullptr);
+ JniThrowNullPointerException(env, nullptr);
} else {
utf_chars_ = env->GetStringUTFChars(s, nullptr);
}
diff --git a/test/ti-agent/ti_macros.h b/test/ti-agent/ti_macros.h
new file mode 100644
index 0000000..d913383
--- /dev/null
+++ b/test/ti-agent/ti_macros.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_TEST_TI_AGENT_TI_MACROS_H_
+#define ART_TEST_TI_AGENT_TI_MACROS_H_
+
+#include "android-base/macros.h"
+
+#define FINAL final
+#define OVERRIDE override
+#define UNREACHABLE __builtin_unreachable
+
+#endif // ART_TEST_TI_AGENT_TI_MACROS_H_
diff --git a/test/ti-agent/ti_utf.h b/test/ti-agent/ti_utf.h
new file mode 100644
index 0000000..341e106
--- /dev/null
+++ b/test/ti-agent/ti_utf.h
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_TEST_TI_AGENT_TI_UTF_H_
+#define ART_TEST_TI_AGENT_TI_UTF_H_
+
+#include <inttypes.h>
+#include <string.h>
+
+#include "android-base/logging.h"
+
+namespace art {
+namespace ti {
+
+inline size_t CountModifiedUtf8Chars(const char* utf8, size_t byte_count) {
+ DCHECK_LE(byte_count, strlen(utf8));
+ size_t len = 0;
+ const char* end = utf8 + byte_count;
+ for (; utf8 < end; ++utf8) {
+ int ic = *utf8;
+ len++;
+ if (LIKELY((ic & 0x80) == 0)) {
+ // One-byte encoding.
+ continue;
+ }
+ // Two- or three-byte encoding.
+ utf8++;
+ if ((ic & 0x20) == 0) {
+ // Two-byte encoding.
+ continue;
+ }
+ utf8++;
+ if ((ic & 0x10) == 0) {
+ // Three-byte encoding.
+ continue;
+ }
+
+ // Four-byte encoding: needs to be converted into a surrogate
+ // pair.
+ utf8++;
+ len++;
+ }
+ return len;
+}
+
+inline uint16_t GetTrailingUtf16Char(uint32_t maybe_pair) {
+ return static_cast<uint16_t>(maybe_pair >> 16);
+}
+
+inline uint16_t GetLeadingUtf16Char(uint32_t maybe_pair) {
+ return static_cast<uint16_t>(maybe_pair & 0x0000FFFF);
+}
+
+inline uint32_t GetUtf16FromUtf8(const char** utf8_data_in) {
+ const uint8_t one = *(*utf8_data_in)++;
+ if ((one & 0x80) == 0) {
+ // one-byte encoding
+ return one;
+ }
+
+ const uint8_t two = *(*utf8_data_in)++;
+ if ((one & 0x20) == 0) {
+ // two-byte encoding
+ return ((one & 0x1f) << 6) | (two & 0x3f);
+ }
+
+ const uint8_t three = *(*utf8_data_in)++;
+ if ((one & 0x10) == 0) {
+ return ((one & 0x0f) << 12) | ((two & 0x3f) << 6) | (three & 0x3f);
+ }
+
+ // Four byte encodings need special handling. We'll have
+ // to convert them into a surrogate pair.
+ const uint8_t four = *(*utf8_data_in)++;
+
+ // Since this is a 4 byte UTF-8 sequence, it will lie between
+ // U+10000 and U+1FFFFF.
+ //
+ // TODO: What do we do about values in (U+10FFFF, U+1FFFFF) ? The
+ // spec says they're invalid but nobody appears to check for them.
+ const uint32_t code_point = ((one & 0x0f) << 18) | ((two & 0x3f) << 12)
+ | ((three & 0x3f) << 6) | (four & 0x3f);
+
+ uint32_t surrogate_pair = 0;
+ // Step two: Write out the high (leading) surrogate to the bottom 16 bits
+ // of the of the 32 bit type.
+ surrogate_pair |= ((code_point >> 10) + 0xd7c0) & 0xffff;
+ // Step three : Write out the low (trailing) surrogate to the top 16 bits.
+ surrogate_pair |= ((code_point & 0x03ff) + 0xdc00) << 16;
+
+ return surrogate_pair;
+}
+
+inline void ConvertUtf16ToModifiedUtf8(char* utf8_out,
+ size_t byte_count,
+ const uint16_t* utf16_in,
+ size_t char_count) {
+ if (LIKELY(byte_count == char_count)) {
+ // Common case where all characters are ASCII.
+ const uint16_t *utf16_end = utf16_in + char_count;
+ for (const uint16_t *p = utf16_in; p < utf16_end;) {
+ *utf8_out++ = static_cast<char>(*p++);
+ }
+ return;
+ }
+
+ // String contains non-ASCII characters.
+ while (char_count--) {
+ const uint16_t ch = *utf16_in++;
+ if (ch > 0 && ch <= 0x7f) {
+ *utf8_out++ = ch;
+ } else {
+ // Char_count == 0 here implies we've encountered an unpaired
+ // surrogate and we have no choice but to encode it as 3-byte UTF
+ // sequence. Note that unpaired surrogates can occur as a part of
+ // "normal" operation.
+ if ((ch >= 0xd800 && ch <= 0xdbff) && (char_count > 0)) {
+ const uint16_t ch2 = *utf16_in;
+
+ // Check if the other half of the pair is within the expected
+ // range. If it isn't, we will have to emit both "halves" as
+ // separate 3 byte sequences.
+ if (ch2 >= 0xdc00 && ch2 <= 0xdfff) {
+ utf16_in++;
+ char_count--;
+ const uint32_t code_point = (ch << 10) + ch2 - 0x035fdc00;
+ *utf8_out++ = (code_point >> 18) | 0xf0;
+ *utf8_out++ = ((code_point >> 12) & 0x3f) | 0x80;
+ *utf8_out++ = ((code_point >> 6) & 0x3f) | 0x80;
+ *utf8_out++ = (code_point & 0x3f) | 0x80;
+ continue;
+ }
+ }
+
+ if (ch > 0x07ff) {
+ // Three byte encoding.
+ *utf8_out++ = (ch >> 12) | 0xe0;
+ *utf8_out++ = ((ch >> 6) & 0x3f) | 0x80;
+ *utf8_out++ = (ch & 0x3f) | 0x80;
+ } else /*(ch > 0x7f || ch == 0)*/ {
+ // Two byte encoding.
+ *utf8_out++ = (ch >> 6) | 0xc0;
+ *utf8_out++ = (ch & 0x3f) | 0x80;
+ }
+ }
+ }
+}
+
+inline size_t CountUtf8Bytes(const uint16_t* chars, size_t char_count) {
+ size_t result = 0;
+ const uint16_t *end = chars + char_count;
+ while (chars < end) {
+ const uint16_t ch = *chars++;
+ if (LIKELY(ch != 0 && ch < 0x80)) {
+ result++;
+ continue;
+ }
+ if (ch < 0x800) {
+ result += 2;
+ continue;
+ }
+ if (ch >= 0xd800 && ch < 0xdc00) {
+ if (chars < end) {
+ const uint16_t ch2 = *chars;
+ // If we find a properly paired surrogate, we emit it as a 4 byte
+ // UTF sequence. If we find an unpaired leading or trailing surrogate,
+ // we emit it as a 3 byte sequence like would have done earlier.
+ if (ch2 >= 0xdc00 && ch2 < 0xe000) {
+ chars++;
+ result += 4;
+ continue;
+ }
+ }
+ }
+ result += 3;
+ }
+ return result;
+}
+
+} // namespace ti
+} // namespace art
+
+#endif // ART_TEST_TI_AGENT_TI_UTF_H_
diff --git a/tools/art b/tools/art
index 6e62ad1..933ad7a 100644
--- a/tools/art
+++ b/tools/art
@@ -230,8 +230,8 @@
replace_compiler_filter_with_interepret_only "$@"
run_art -Xjitsaveprofilinginfo \
- -Xps-min-methods-to-save:0 \
- -Xps-min-classes-to-save:0 \
+ -Xps-min-methods-to-save:1 \
+ -Xps-min-classes-to-save:1 \
-Xps-min-notification-before-wake:10 \
-Xps-profile-path:$PROFILE_PATH \
-Xusejit:true \
diff --git a/tools/cpplint_presubmit.py b/tools/cpplint_presubmit.py
new file mode 100755
index 0000000..4781517
--- /dev/null
+++ b/tools/cpplint_presubmit.py
@@ -0,0 +1,67 @@
+#!/usr/bin/python3
+#
+# Copyright 2017, The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# TODO We should unify this with build/Android.cpplint.mk.
+
+import os
+import pathlib
+import subprocess
+import sys
+
+IGNORED_FILES = {"runtime/elf.h", "runtime/openjdkjvmti/include/jvmti.h"}
+
+INTERESTING_SUFFIXES = {".h", ".cc"}
+
+CPPLINT_FLAGS = [
+ '--filter=-whitespace/line_length,-build/include,-readability/function,-readability/streams,-readability/todo,-runtime/references,-runtime/sizeof,-runtime/threadsafe_fn,-runtime/printf',
+ '--quiet',
+]
+
+def is_interesting(f):
+ """
+ Returns true if this is a file we want to run through cpplint before uploading. False otherwise.
+ """
+ path = pathlib.Path(f)
+ return f not in IGNORED_FILES and path.suffix in INTERESTING_SUFFIXES and path.exists()
+
+def get_changed_files(commit):
+ """
+ Gets the files changed in the given commit.
+ """
+ return subprocess.check_output(
+ ["git", 'diff-tree', '--no-commit-id', '--name-only', '-r', commit],
+ stderr=subprocess.STDOUT,
+ universal_newlines=True).split()
+
+def run_cpplint(files):
+ """
+ Runs cpplint on the given files.
+ """
+ if len(files) == 0:
+ return
+ sys.exit(subprocess.call(['tools/cpplint.py'] + CPPLINT_FLAGS + files))
+
+def main():
+ if 'PREUPLOAD_COMMIT' in os.environ:
+ commit = os.environ['PREUPLOAD_COMMIT']
+ else:
+ print("WARNING: Not running as a pre-upload hook. Assuming commit to check = 'HEAD'")
+ commit = "HEAD"
+ files_to_check = [f for f in get_changed_files(commit) if is_interesting(f)]
+ run_cpplint(files_to_check)
+
+if __name__ == '__main__':
+ main()