summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.bp1
-rw-r--r--compiler/Android.bp1
-rw-r--r--compiler/dex/inline_method_analyser.cc8
-rw-r--r--compiler/driver/compiler_driver.cc2
-rw-r--r--compiler/driver/compiler_options.cc1
-rw-r--r--compiler/driver/compiler_options.h8
-rw-r--r--compiler/driver/compiler_options_map-inl.h6
-rw-r--r--compiler/driver/compiler_options_map.def1
-rw-r--r--compiler/optimizing/code_generator_arm64.cc17
-rw-r--r--compiler/optimizing/code_generator_arm_vixl.cc18
-rw-r--r--compiler/optimizing/code_generator_mips.cc4
-rw-r--r--compiler/optimizing/code_generator_mips64.cc4
-rw-r--r--compiler/optimizing/code_generator_x86.cc11
-rw-r--r--compiler/optimizing/code_generator_x86_64.cc11
-rw-r--r--compiler/optimizing/inliner.cc9
-rw-r--r--dex2oat/Android.bp3
-rw-r--r--dex2oat/dex2oat.cc49
-rw-r--r--dex2oat/dex2oat_options.cc6
-rw-r--r--dex2oat/dex2oat_options.def2
-rw-r--r--dex2oat/dex2oat_test.cc4
-rw-r--r--dex2oat/linker/oat_writer.cc35
-rw-r--r--dexdump/Android.bp1
-rw-r--r--dexdump/dexdump.cc2
-rw-r--r--dexdump/dexdump_cfg.cc2
-rw-r--r--dexlayout/Android.bp5
-rw-r--r--dexlayout/dex_ir.h2
-rw-r--r--dexlayout/dex_writer.cc2
-rw-r--r--dexlist/dexlist.cc2
-rw-r--r--oatdump/Android.bp2
-rw-r--r--oatdump/oatdump.cc2
-rw-r--r--openjdkjvmti/Android.bp1
-rw-r--r--openjdkjvmti/ti_class_loader.h2
-rw-r--r--openjdkjvmti/ti_method.cc14
-rw-r--r--openjdkjvmti/ti_redefine.h2
-rw-r--r--openjdkjvmti/ti_stack.cc2
-rw-r--r--openjdkjvmti/transform.cc2
-rw-r--r--profman/Android.bp1
-rw-r--r--runtime/Android.bp24
-rw-r--r--runtime/art_method-inl.h38
-rw-r--r--runtime/art_method.cc2
-rw-r--r--runtime/art_method.h17
-rw-r--r--runtime/base/file_utils.cc2
-rw-r--r--runtime/check_reference_map_visitor.h2
-rw-r--r--runtime/class_linker.cc4
-rw-r--r--runtime/common_throws.cc2
-rw-r--r--runtime/debugger.cc14
-rw-r--r--runtime/dex/code_item_accessors-inl.h183
-rw-r--r--runtime/dex/code_item_accessors-no_art-inl.h185
-rw-r--r--runtime/dex/code_item_accessors.h2
-rw-r--r--runtime/dex/code_item_accessors_test.cc1
-rw-r--r--runtime/dex/compact_dex_file.cc2
-rw-r--r--runtime/dex/descriptors_names.cc426
-rw-r--r--runtime/dex/descriptors_names.h63
-rw-r--r--runtime/dex/dex_file.cc2
-rw-r--r--runtime/dex/dex_file_annotations.cc2
-rw-r--r--runtime/dex/dex_file_exception_helpers.cc2
-rw-r--r--runtime/dex/dex_file_layout.cc2
-rw-r--r--runtime/dex/dex_file_test.cc2
-rw-r--r--runtime/dex/dex_file_verifier.cc6
-rw-r--r--runtime/dex/dex_file_verifier_test.cc2
-rw-r--r--runtime/dex/dex_instruction.cc2
-rw-r--r--runtime/dex/standard_dex_file.cc2
-rw-r--r--runtime/dex/utf-inl.h (renamed from runtime/utf-inl.h)6
-rw-r--r--runtime/dex/utf.cc (renamed from runtime/utf.cc)56
-rw-r--r--runtime/dex/utf.h (renamed from runtime/utf.h)15
-rw-r--r--runtime/dex/utf_test.cc (renamed from runtime/utf_test.cc)0
-rw-r--r--runtime/entrypoints/quick/quick_throw_entrypoints.cc1
-rw-r--r--runtime/entrypoints/quick/quick_trampoline_entrypoints.cc4
-rw-r--r--runtime/imtable-inl.h2
-rw-r--r--runtime/intern_table.cc2
-rw-r--r--runtime/intern_table_test.cc2
-rw-r--r--runtime/interpreter/interpreter.cc4
-rw-r--r--runtime/interpreter/interpreter_common.cc2
-rw-r--r--runtime/interpreter/shadow_frame.cc2
-rw-r--r--runtime/jdwp/jdwp_handler.cc2
-rw-r--r--runtime/jit/jit.cc2
-rw-r--r--runtime/jni_internal.cc2
-rw-r--r--runtime/method_handles.cc6
-rw-r--r--runtime/mirror/string-inl.h2
-rw-r--r--runtime/mirror/string.cc2
-rw-r--r--runtime/monitor.cc2
-rw-r--r--runtime/native/dalvik_system_ZygoteHooks.cc25
-rw-r--r--runtime/native/java_lang_Class.cc2
-rw-r--r--runtime/oat_file.cc2
-rw-r--r--runtime/oat_file.h2
-rw-r--r--runtime/quick_exception_handler.cc6
-rw-r--r--runtime/stack.cc8
-rw-r--r--runtime/string_reference.h2
-rw-r--r--runtime/thread.cc2
-rw-r--r--runtime/type_lookup_table.cc2
-rw-r--r--runtime/type_lookup_table.h2
-rw-r--r--runtime/type_lookup_table_test.cc2
-rw-r--r--runtime/utils.cc53
-rw-r--r--runtime/utils.h6
-rw-r--r--runtime/vdex_file.h7
-rw-r--r--test/004-ThreadStress/src-art/Main.java (renamed from test/004-ThreadStress/src/Main.java)66
-rw-r--r--test/044-proxy/src/Main.java4
-rw-r--r--test/044-proxy/src/OOMEOnDispatch.java18
-rw-r--r--test/141-class-unload/jni_unload.cc14
-rw-r--r--test/466-get-live-vreg/get_live_vreg_jni.cc3
-rw-r--r--test/674-HelloWorld-Dm/expected.txt1
-rw-r--r--test/674-HelloWorld-Dm/info.txt1
-rw-r--r--test/674-HelloWorld-Dm/run17
-rw-r--r--test/674-HelloWorld-Dm/src/Main.java21
-rw-r--r--test/674-hotness-compiled/expected.txt1
-rw-r--r--test/674-hotness-compiled/info.txt1
-rwxr-xr-xtest/674-hotness-compiled/run17
-rw-r--r--test/674-hotness-compiled/src/Main.java46
-rw-r--r--test/Android.bp6
-rw-r--r--test/common/runtime_state.cc28
-rwxr-xr-xtest/etc/run-test-jar14
-rwxr-xr-xtest/run-test3
-rw-r--r--tools/hiddenapi/Android.bp1
-rw-r--r--tools/public.libraries.buildbot.txt1
-rwxr-xr-xtools/run-jdwp-tests.sh4
115 files changed, 1290 insertions, 446 deletions
diff --git a/Android.bp b/Android.bp
index caf4f9a325..4bcceffcd1 100644
--- a/Android.bp
+++ b/Android.bp
@@ -1,6 +1,7 @@
// TODO: These should be handled with transitive static library dependencies
art_static_dependencies = [
// Note: the order is important because of static linking resolution.
+ "libdexfile",
"libziparchive",
"libnativehelper",
"libnativebridge",
diff --git a/compiler/Android.bp b/compiler/Android.bp
index 2e60e7d658..453965947d 100644
--- a/compiler/Android.bp
+++ b/compiler/Android.bp
@@ -184,6 +184,7 @@ art_cc_defaults {
},
generated_sources: ["art_compiler_operator_srcs"],
shared_libs: [
+ "libdexfile",
"libbase",
"libcutils", // for atrace.
"liblzma",
diff --git a/compiler/dex/inline_method_analyser.cc b/compiler/dex/inline_method_analyser.cc
index ce67b85b99..dc044c1210 100644
--- a/compiler/dex/inline_method_analyser.cc
+++ b/compiler/dex/inline_method_analyser.cc
@@ -142,7 +142,7 @@ ArtMethod* GetTargetConstructor(ArtMethod* method, const Instruction* invoke_dir
REQUIRES_SHARED(Locks::mutator_lock_) {
DCHECK_EQ(invoke_direct->Opcode(), Instruction::INVOKE_DIRECT);
if (kIsDebugBuild) {
- CodeItemDataAccessor accessor(method);
+ CodeItemDataAccessor accessor(method->DexInstructionData());
DCHECK_EQ(invoke_direct->VRegC_35c(),
accessor.RegistersSize() - accessor.InsSize());
}
@@ -324,9 +324,9 @@ bool DoAnalyseConstructor(const CodeItemDataAccessor* code_item,
return false;
}
if (target_method->GetDeclaringClass()->IsObjectClass()) {
- DCHECK_EQ(CodeItemDataAccessor(target_method).begin()->Opcode(), Instruction::RETURN_VOID);
+ DCHECK_EQ(target_method->DexInstructionData().begin()->Opcode(), Instruction::RETURN_VOID);
} else {
- CodeItemDataAccessor target_code_item(target_method);
+ CodeItemDataAccessor target_code_item(target_method->DexInstructionData());
if (!target_code_item.HasCodeItem()) {
return false; // Native constructor?
}
@@ -430,7 +430,7 @@ static_assert(InlineMethodAnalyser::IGetVariant(Instruction::IGET_SHORT) ==
InlineMethodAnalyser::IPutVariant(Instruction::IPUT_SHORT), "iget/iput_short variant");
bool InlineMethodAnalyser::AnalyseMethodCode(ArtMethod* method, InlineMethod* result) {
- CodeItemDataAccessor code_item(method);
+ CodeItemDataAccessor code_item(method->DexInstructionData());
if (!code_item.HasCodeItem()) {
// Native or abstract.
return false;
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index 60537fd5c8..c617f54f55 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -932,7 +932,7 @@ class ResolveCatchBlockExceptionsClassVisitor : public ClassVisitor {
if (method->GetCodeItem() == nullptr) {
return; // native or abstract method
}
- CodeItemDataAccessor accessor(method);
+ CodeItemDataAccessor accessor(method->DexInstructionData());
if (accessor.TriesSize() == 0) {
return; // nothing to process
}
diff --git a/compiler/driver/compiler_options.cc b/compiler/driver/compiler_options.cc
index 1780b1d7ed..2d82d79c4a 100644
--- a/compiler/driver/compiler_options.cc
+++ b/compiler/driver/compiler_options.cc
@@ -60,6 +60,7 @@ CompilerOptions::CompilerOptions()
dump_cfg_append_(false),
force_determinism_(false),
deduplicate_code_(true),
+ count_hotness_in_compiled_code_(false),
register_allocation_strategy_(RegisterAllocator::kRegisterAllocatorDefault),
passes_to_run_(nullptr) {
}
diff --git a/compiler/driver/compiler_options.h b/compiler/driver/compiler_options.h
index 3f660293d2..18b0913430 100644
--- a/compiler/driver/compiler_options.h
+++ b/compiler/driver/compiler_options.h
@@ -274,6 +274,10 @@ class CompilerOptions FINAL {
return dump_stats_;
}
+ bool CountHotnessInCompiledCode() const {
+ return count_hotness_in_compiled_code_;
+ }
+
private:
bool ParseDumpInitFailures(const std::string& option, std::string* error_msg);
void ParseDumpCfgPasses(const StringPiece& option, UsageFn Usage);
@@ -336,6 +340,10 @@ class CompilerOptions FINAL {
// Whether code should be deduplicated.
bool deduplicate_code_;
+ // Whether compiled code should increment the hotness count of ArtMethod. Note that the increments
+ // won't be atomic for performance reasons, so we accept races, just like in interpreter.
+ bool count_hotness_in_compiled_code_;
+
RegisterAllocator::Strategy register_allocation_strategy_;
// If not null, specifies optimization passes which will be run instead of defaults.
diff --git a/compiler/driver/compiler_options_map-inl.h b/compiler/driver/compiler_options_map-inl.h
index f97ab08600..3b18db09fc 100644
--- a/compiler/driver/compiler_options_map-inl.h
+++ b/compiler/driver/compiler_options_map-inl.h
@@ -77,6 +77,9 @@ inline bool ReadCompilerOptions(Base& map, CompilerOptions* options, std::string
}
map.AssignIfExists(Base::VerboseMethods, &options->verbose_methods_);
options->deduplicate_code_ = map.GetOrDefault(Base::DeduplicateCode);
+ if (map.Exists(Base::CountHotnessInCompiledCode)) {
+ options->count_hotness_in_compiled_code_ = true;
+ }
if (map.Exists(Base::DumpTimings)) {
options->dump_timings_ = true;
@@ -137,6 +140,9 @@ inline void AddCompilerOptionsArgumentParserOptions(Builder& b) {
.WithValueMap({{"false", false}, {"true", true}})
.IntoKey(Map::DeduplicateCode)
+ .Define({"--count-hotness-in-compiled-code"})
+ .IntoKey(Map::CountHotnessInCompiledCode)
+
.Define({"--dump-timings"})
.IntoKey(Map::DumpTimings)
diff --git a/compiler/driver/compiler_options_map.def b/compiler/driver/compiler_options_map.def
index 2c56fd7974..acddae7299 100644
--- a/compiler/driver/compiler_options_map.def
+++ b/compiler/driver/compiler_options_map.def
@@ -58,6 +58,7 @@ COMPILER_OPTIONS_KEY (Unit, DumpCFGAppend)
COMPILER_OPTIONS_KEY (std::string, RegisterAllocationStrategy)
COMPILER_OPTIONS_KEY (ParseStringList<','>, VerboseMethods)
COMPILER_OPTIONS_KEY (bool, DeduplicateCode, true)
+COMPILER_OPTIONS_KEY (Unit, CountHotnessInCompiledCode)
COMPILER_OPTIONS_KEY (Unit, DumpTimings)
COMPILER_OPTIONS_KEY (Unit, DumpStats)
diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc
index 13bbffa1e3..1380596ab2 100644
--- a/compiler/optimizing/code_generator_arm64.cc
+++ b/compiler/optimizing/code_generator_arm64.cc
@@ -1488,6 +1488,14 @@ void CodeGeneratorARM64::GenerateFrameEntry() {
MacroAssembler* masm = GetVIXLAssembler();
__ Bind(&frame_entry_label_);
+ if (GetCompilerOptions().CountHotnessInCompiledCode()) {
+ UseScratchRegisterScope temps(masm);
+ Register temp = temps.AcquireX();
+ __ Ldrh(temp, MemOperand(kArtMethodRegister, ArtMethod::HotnessCountOffset().Int32Value()));
+ __ Add(temp, temp, 1);
+ __ Strh(temp, MemOperand(kArtMethodRegister, ArtMethod::HotnessCountOffset().Int32Value()));
+ }
+
bool do_overflow_check =
FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kArm64) || !IsLeafMethod();
if (do_overflow_check) {
@@ -3501,6 +3509,15 @@ void InstructionCodeGeneratorARM64::HandleGoto(HInstruction* got, HBasicBlock* s
HLoopInformation* info = block->GetLoopInformation();
if (info != nullptr && info->IsBackEdge(*block) && info->HasSuspendCheck()) {
+ if (codegen_->GetCompilerOptions().CountHotnessInCompiledCode()) {
+ UseScratchRegisterScope temps(GetVIXLAssembler());
+ Register temp1 = temps.AcquireX();
+ Register temp2 = temps.AcquireX();
+ __ Ldr(temp1, MemOperand(sp, 0));
+ __ Ldrh(temp2, MemOperand(temp1, ArtMethod::HotnessCountOffset().Int32Value()));
+ __ Add(temp2, temp2, 1);
+ __ Strh(temp2, MemOperand(temp1, ArtMethod::HotnessCountOffset().Int32Value()));
+ }
GenerateSuspendCheck(info->GetSuspendCheck(), successor);
return;
}
diff --git a/compiler/optimizing/code_generator_arm_vixl.cc b/compiler/optimizing/code_generator_arm_vixl.cc
index 577fe00dcd..18e7d1cc46 100644
--- a/compiler/optimizing/code_generator_arm_vixl.cc
+++ b/compiler/optimizing/code_generator_arm_vixl.cc
@@ -2485,6 +2485,14 @@ void CodeGeneratorARMVIXL::GenerateFrameEntry() {
DCHECK(GetCompilerOptions().GetImplicitStackOverflowChecks());
__ Bind(&frame_entry_label_);
+ if (GetCompilerOptions().CountHotnessInCompiledCode()) {
+ UseScratchRegisterScope temps(GetVIXLAssembler());
+ vixl32::Register temp = temps.Acquire();
+ __ Ldrh(temp, MemOperand(kMethodRegister, ArtMethod::HotnessCountOffset().Int32Value()));
+ __ Add(temp, temp, 1);
+ __ Strh(temp, MemOperand(kMethodRegister, ArtMethod::HotnessCountOffset().Int32Value()));
+ }
+
if (HasEmptyFrame()) {
return;
}
@@ -2786,6 +2794,16 @@ void InstructionCodeGeneratorARMVIXL::HandleGoto(HInstruction* got, HBasicBlock*
HLoopInformation* info = block->GetLoopInformation();
if (info != nullptr && info->IsBackEdge(*block) && info->HasSuspendCheck()) {
+ if (codegen_->GetCompilerOptions().CountHotnessInCompiledCode()) {
+ UseScratchRegisterScope temps(GetVIXLAssembler());
+ vixl32::Register temp = temps.Acquire();
+ __ Push(vixl32::Register(kMethodRegister));
+ GetAssembler()->LoadFromOffset(kLoadWord, kMethodRegister, sp, kArmWordSize);
+ __ Ldrh(temp, MemOperand(kMethodRegister, ArtMethod::HotnessCountOffset().Int32Value()));
+ __ Add(temp, temp, 1);
+ __ Strh(temp, MemOperand(kMethodRegister, ArtMethod::HotnessCountOffset().Int32Value()));
+ __ Pop(vixl32::Register(kMethodRegister));
+ }
GenerateSuspendCheck(info->GetSuspendCheck(), successor);
return;
}
diff --git a/compiler/optimizing/code_generator_mips.cc b/compiler/optimizing/code_generator_mips.cc
index 5c8e46ed19..51fb4dacfd 100644
--- a/compiler/optimizing/code_generator_mips.cc
+++ b/compiler/optimizing/code_generator_mips.cc
@@ -1276,6 +1276,10 @@ static dwarf::Reg DWARFReg(Register reg) {
void CodeGeneratorMIPS::GenerateFrameEntry() {
__ Bind(&frame_entry_label_);
+ if (GetCompilerOptions().CountHotnessInCompiledCode()) {
+ LOG(WARNING) << "Unimplemented hotness update in mips backend";
+ }
+
bool do_overflow_check =
FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kMips) || !IsLeafMethod();
diff --git a/compiler/optimizing/code_generator_mips64.cc b/compiler/optimizing/code_generator_mips64.cc
index bcfe051c90..480b9178d2 100644
--- a/compiler/optimizing/code_generator_mips64.cc
+++ b/compiler/optimizing/code_generator_mips64.cc
@@ -1079,6 +1079,10 @@ static dwarf::Reg DWARFReg(FpuRegister reg) {
void CodeGeneratorMIPS64::GenerateFrameEntry() {
__ Bind(&frame_entry_label_);
+ if (GetCompilerOptions().CountHotnessInCompiledCode()) {
+ LOG(WARNING) << "Unimplemented hotness update in mips64 backend";
+ }
+
bool do_overflow_check =
FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kMips64) || !IsLeafMethod();
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index cbe9e0a35c..c52c7ff7f1 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -1061,6 +1061,11 @@ void CodeGeneratorX86::GenerateFrameEntry() {
IsLeafMethod() && !FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kX86);
DCHECK(GetCompilerOptions().GetImplicitStackOverflowChecks());
+ if (GetCompilerOptions().CountHotnessInCompiledCode()) {
+ __ addw(Address(kMethodRegisterArgument, ArtMethod::HotnessCountOffset().Int32Value()),
+ Immediate(1));
+ }
+
if (!skip_overflow_check) {
size_t reserved_bytes = GetStackOverflowReservedBytes(InstructionSet::kX86);
__ testl(EAX, Address(ESP, -static_cast<int32_t>(reserved_bytes)));
@@ -1357,6 +1362,12 @@ void InstructionCodeGeneratorX86::HandleGoto(HInstruction* got, HBasicBlock* suc
HLoopInformation* info = block->GetLoopInformation();
if (info != nullptr && info->IsBackEdge(*block) && info->HasSuspendCheck()) {
+ if (codegen_->GetCompilerOptions().CountHotnessInCompiledCode()) {
+ __ pushl(EAX);
+ __ movl(EAX, Address(ESP, kX86WordSize));
+ __ addw(Address(EAX, ArtMethod::HotnessCountOffset().Int32Value()), Immediate(1));
+ __ popl(EAX);
+ }
GenerateSuspendCheck(info->GetSuspendCheck(), successor);
return;
}
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc
index 510eec4f30..ee5918de71 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -1268,6 +1268,12 @@ void CodeGeneratorX86_64::GenerateFrameEntry() {
&& !FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kX86_64);
DCHECK(GetCompilerOptions().GetImplicitStackOverflowChecks());
+ if (GetCompilerOptions().CountHotnessInCompiledCode()) {
+ __ addw(Address(CpuRegister(kMethodRegisterArgument),
+ ArtMethod::HotnessCountOffset().Int32Value()),
+ Immediate(1));
+ }
+
if (!skip_overflow_check) {
size_t reserved_bytes = GetStackOverflowReservedBytes(InstructionSet::kX86_64);
__ testq(CpuRegister(RAX), Address(CpuRegister(RSP), -static_cast<int32_t>(reserved_bytes)));
@@ -1459,6 +1465,11 @@ void InstructionCodeGeneratorX86_64::HandleGoto(HInstruction* got, HBasicBlock*
HLoopInformation* info = block->GetLoopInformation();
if (info != nullptr && info->IsBackEdge(*block) && info->HasSuspendCheck()) {
+ if (codegen_->GetCompilerOptions().CountHotnessInCompiledCode()) {
+ __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), 0));
+ __ addw(Address(CpuRegister(TMP), ArtMethod::HotnessCountOffset().Int32Value()),
+ Immediate(1));
+ }
GenerateSuspendCheck(info->GetSuspendCheck(), successor);
return;
}
diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc
index 452be6feae..035e5ce3e1 100644
--- a/compiler/optimizing/inliner.cc
+++ b/compiler/optimizing/inliner.cc
@@ -392,8 +392,9 @@ ArtMethod* HInliner::TryCHADevirtualization(ArtMethod* resolved_method) {
return single_impl;
}
-static bool AlwaysThrows(ArtMethod* method) {
- CodeItemDataAccessor accessor(method);
+static bool AlwaysThrows(ArtMethod* method)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ CodeItemDataAccessor accessor(method->DexInstructionData());
// Skip native methods, methods with try blocks, and methods that are too large.
if (!accessor.HasCodeItem() ||
accessor.TriesSize() != 0 ||
@@ -1418,7 +1419,7 @@ bool HInliner::TryBuildAndInline(HInvoke* invoke_instruction,
bool same_dex_file = IsSameDexFile(*outer_compilation_unit_.GetDexFile(), *method->GetDexFile());
- CodeItemDataAccessor accessor(method);
+ CodeItemDataAccessor accessor(method->DexInstructionData());
if (!accessor.HasCodeItem()) {
LOG_FAIL_NO_STAT()
@@ -1697,7 +1698,7 @@ bool HInliner::TryBuildAndInlineHelper(HInvoke* invoke_instruction,
const DexFile::CodeItem* code_item = resolved_method->GetCodeItem();
const DexFile& callee_dex_file = *resolved_method->GetDexFile();
uint32_t method_index = resolved_method->GetDexMethodIndex();
- CodeItemDebugInfoAccessor code_item_accessor(resolved_method);
+ CodeItemDebugInfoAccessor code_item_accessor(resolved_method->DexInstructionDebugInfo());
ClassLinker* class_linker = caller_compilation_unit_.GetClassLinker();
Handle<mirror::DexCache> dex_cache = NewHandleIfDifferent(resolved_method->GetDexCache(),
caller_compilation_unit_.GetDexCache(),
diff --git a/dex2oat/Android.bp b/dex2oat/Android.bp
index 9876febfc5..ab06ddda2d 100644
--- a/dex2oat/Android.bp
+++ b/dex2oat/Android.bp
@@ -106,7 +106,6 @@ cc_defaults {
compile_multilib: "prefer32",
},
},
-
header_libs: [
"dex2oat_headers",
"art_cmdlineparser_headers",
@@ -122,6 +121,7 @@ art_cc_binary {
"libart-compiler",
"libart-dexlayout",
"libart",
+ "libdexfile",
"libbase",
"liblz4",
"libsigchain",
@@ -152,6 +152,7 @@ art_cc_binary {
"libartd-compiler",
"libartd-dexlayout",
"libartd",
+ "libdexfile",
"libbase",
"liblz4",
"libsigchain",
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index 8555abf9fd..c4e53987eb 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -605,6 +605,7 @@ class Dex2Oat FINAL {
input_vdex_fd_(-1),
output_vdex_fd_(-1),
input_vdex_file_(nullptr),
+ dm_fd_(-1),
zip_fd_(-1),
image_base_(0U),
image_classes_zip_filename_(nullptr),
@@ -757,6 +758,11 @@ class Dex2Oat FINAL {
Usage("--oat-fd should not be used with --image");
}
+ if ((input_vdex_fd_ != -1 || !input_vdex_.empty()) &&
+ (dm_fd_ != -1 || !dm_file_location_.empty())) {
+ Usage("An input vdex should not be passed with a .dm file");
+ }
+
if (!parser_options->oat_symbols.empty() &&
parser_options->oat_symbols.size() != oat_filenames_.size()) {
Usage("--oat-file arguments do not match --oat-symbols arguments");
@@ -1176,6 +1182,8 @@ class Dex2Oat FINAL {
AssignIfExists(args, M::OutputVdexFd, &output_vdex_fd_);
AssignIfExists(args, M::InputVdex, &input_vdex_);
AssignIfExists(args, M::OutputVdex, &output_vdex_);
+ AssignIfExists(args, M::DmFd, &dm_fd_);
+ AssignIfExists(args, M::DmFile, &dm_file_location_);
AssignIfExists(args, M::OatFd, &oat_fd_);
AssignIfExists(args, M::OatLocation, &oat_location_);
AssignIfExists(args, M::Watchdog, &parser_options->watch_dog_enabled);
@@ -1389,6 +1397,42 @@ class Dex2Oat FINAL {
}
}
+ if (dm_fd_ != -1 || !dm_file_location_.empty()) {
+ std::string error_msg;
+ if (dm_fd_ != -1) {
+ dm_file_.reset(ZipArchive::OpenFromFd(dm_fd_, "DexMetadata", &error_msg));
+ } else {
+ dm_file_.reset(ZipArchive::Open(dm_file_location_.c_str(), &error_msg));
+ }
+ if (dm_file_ == nullptr) {
+ LOG(WARNING) << "Could not open DexMetadata archive " << error_msg;
+ }
+ }
+
+ if (dm_file_ != nullptr) {
+ DCHECK(input_vdex_file_ == nullptr);
+ std::string error_msg;
+ static const char* kDexMetadata = "DexMetadata";
+ std::unique_ptr<ZipEntry> zip_entry(dm_file_->Find(VdexFile::kVdexNameInDmFile, &error_msg));
+ if (zip_entry == nullptr) {
+ LOG(INFO) << "No " << VdexFile::kVdexNameInDmFile << " file in DexMetadata archive. "
+ << "Not doing fast verification.";
+ } else {
+ std::unique_ptr<MemMap> input_file;
+ if (zip_entry->IsUncompressed()) {
+ input_file.reset(zip_entry->MapDirectlyFromFile(VdexFile::kVdexNameInDmFile, &error_msg));
+ } else {
+ input_file.reset(zip_entry->ExtractToMemMap(
+ kDexMetadata, VdexFile::kVdexNameInDmFile, &error_msg));
+ }
+ if (input_file == nullptr) {
+ LOG(WARNING) << "Could not open vdex file in DexMetadata archive: " << error_msg;
+ } else {
+ input_vdex_file_ = std::make_unique<VdexFile>(input_file.release());
+ }
+ }
+ }
+
// Swap file handling
//
// If the swap fd is not -1, we assume this is the file descriptor of an open but unlinked file
@@ -2240,7 +2284,7 @@ class Dex2Oat FINAL {
}
bool DoEagerUnquickeningOfVdex() const {
- return MayInvalidateVdexMetadata();
+ return MayInvalidateVdexMetadata() && dm_file_ == nullptr;
}
bool LoadProfile() {
@@ -2790,6 +2834,9 @@ class Dex2Oat FINAL {
std::string input_vdex_;
std::string output_vdex_;
std::unique_ptr<VdexFile> input_vdex_file_;
+ int dm_fd_;
+ std::string dm_file_location_;
+ std::unique_ptr<ZipArchive> dm_file_;
std::vector<const char*> dex_filenames_;
std::vector<const char*> dex_locations_;
int zip_fd_;
diff --git a/dex2oat/dex2oat_options.cc b/dex2oat/dex2oat_options.cc
index a2e2b48956..0eecc84605 100644
--- a/dex2oat/dex2oat_options.cc
+++ b/dex2oat/dex2oat_options.cc
@@ -86,6 +86,12 @@ static void AddGeneratedArtifactMappings(Builder& builder) {
.Define("--output-vdex=_")
.WithType<std::string>()
.IntoKey(M::OutputVdex)
+ .Define("--dm-fd=_")
+ .WithType<int>()
+ .IntoKey(M::DmFd)
+ .Define("--dm-file=_")
+ .WithType<std::string>()
+ .IntoKey(M::DmFile)
.Define("--oat-file=_")
.WithType<std::vector<std::string>>().AppendValues()
.IntoKey(M::OatFiles)
diff --git a/dex2oat/dex2oat_options.def b/dex2oat/dex2oat_options.def
index 9362a3df6f..9a8bdf4aee 100644
--- a/dex2oat/dex2oat_options.def
+++ b/dex2oat/dex2oat_options.def
@@ -43,6 +43,8 @@ DEX2OAT_OPTIONS_KEY (int, InputVdexFd)
DEX2OAT_OPTIONS_KEY (std::string, InputVdex)
DEX2OAT_OPTIONS_KEY (int, OutputVdexFd)
DEX2OAT_OPTIONS_KEY (std::string, OutputVdex)
+DEX2OAT_OPTIONS_KEY (int, DmFd)
+DEX2OAT_OPTIONS_KEY (std::string, DmFile)
DEX2OAT_OPTIONS_KEY (std::vector<std::string>, OatFiles)
DEX2OAT_OPTIONS_KEY (std::vector<std::string>, OatSymbols)
DEX2OAT_OPTIONS_KEY (int, OatFd)
diff --git a/dex2oat/dex2oat_test.cc b/dex2oat/dex2oat_test.cc
index 6fcf6952e8..5614ac6458 100644
--- a/dex2oat/dex2oat_test.cc
+++ b/dex2oat/dex2oat_test.cc
@@ -783,7 +783,7 @@ class Dex2oatLayoutTest : public Dex2oatTest {
app_image_file_name,
/* use_fd */ true,
/* num_profile_classes */ 1,
- { input_vdex, output_vdex, kDisableCompactDex });
+ { input_vdex, output_vdex });
EXPECT_GT(vdex_file1->GetLength(), 0u);
}
{
@@ -904,7 +904,7 @@ class Dex2oatUnquickenTest : public Dex2oatTest {
GenerateOdexForTest(dex_location,
odex_location,
CompilerFilter::kQuicken,
- { input_vdex, output_vdex, kDisableCompactDex },
+ { input_vdex, output_vdex },
/* expect_success */ true,
/* use_fd */ true);
EXPECT_GT(vdex_file1->GetLength(), 0u);
diff --git a/dex2oat/linker/oat_writer.cc b/dex2oat/linker/oat_writer.cc
index c7e9cdaae0..d245cd1c63 100644
--- a/dex2oat/linker/oat_writer.cc
+++ b/dex2oat/linker/oat_writer.cc
@@ -3367,7 +3367,10 @@ bool OatWriter::WriteDexFiles(OutputStream* out, File* file, bool update_input_v
// Write shared dex file data section and fix up the dex file headers.
vdex_dex_shared_data_offset_ = vdex_size_;
+ uint32_t shared_data_size = 0u;
+
if (dex_container_ != nullptr) {
+ CHECK(!update_input_vdex) << "Update input vdex should have empty dex container";
DexContainer::Section* const section = dex_container_->GetDataSection();
if (section->Size() > 0) {
const uint32_t shared_data_offset = vdex_size_;
@@ -3376,7 +3379,7 @@ bool OatWriter::WriteDexFiles(OutputStream* out, File* file, bool update_input_v
LOG(ERROR) << "Expected offset " << shared_data_offset << " but got " << existing_offset;
return false;
}
- const uint32_t shared_data_size = section->Size();
+ shared_data_size = section->Size();
if (!out->WriteFully(section->Begin(), shared_data_size)) {
LOG(ERROR) << "Failed to write shared data!";
return false;
@@ -3400,8 +3403,6 @@ bool OatWriter::WriteDexFiles(OutputStream* out, File* file, bool update_input_v
return false;
}
}
- vdex_size_ += shared_data_size;
- size_dex_file_ += shared_data_size;
section->Clear();
if (!out->Flush()) {
PLOG(ERROR) << "Failed to flush after writing shared dex section.";
@@ -3409,9 +3410,35 @@ bool OatWriter::WriteDexFiles(OutputStream* out, File* file, bool update_input_v
}
}
dex_container_.reset();
+ } else {
+ if (update_input_vdex) {
+ for (OatDexFile& oat_dex_file : oat_dex_files_) {
+ DexFile::Header header;
+ if (!file->PreadFully(&header, sizeof(header), oat_dex_file.dex_file_offset_)) {
+ PLOG(ERROR) << "Failed to read dex header";
+ return false;
+ }
+ if (!CompactDexFile::IsMagicValid(header.magic_)) {
+ // Non compact dex does not have shared data section.
+ continue;
+ }
+ const uint32_t expected_data_off = vdex_dex_shared_data_offset_ -
+ oat_dex_file.dex_file_offset_;
+ if (header.data_off_ != expected_data_off) {
+ PLOG(ERROR) << "Shared data section offset " << header.data_off_
+ << " does not match expected value " << expected_data_off;
+ return false;
+ }
+ // The different dex files currently can have different data sizes since
+ // the dex writer writes them one at a time into the shared section.:w
+ shared_data_size = std::max(shared_data_size, header.data_size_);
+ }
+ }
}
+ vdex_size_ += shared_data_size;
+ size_dex_file_ += shared_data_size;
} else {
- vdex_dex_shared_data_offset_ = vdex_size_;
+ vdex_dex_shared_data_offset_ = vdex_size_;
}
return true;
diff --git a/dexdump/Android.bp b/dexdump/Android.bp
index eca08448bc..f6b7a6b68a 100644
--- a/dexdump/Android.bp
+++ b/dexdump/Android.bp
@@ -45,7 +45,6 @@ art_cc_binary {
host_supported: true,
device_supported: false,
static_libs: [
- "libdexfile",
"libbase",
] + art_static_dependencies,
target: {
diff --git a/dexdump/dexdump.cc b/dexdump/dexdump.cc
index 24f41aba2e..01b28b55cf 100644
--- a/dexdump/dexdump.cc
+++ b/dexdump/dexdump.cc
@@ -50,7 +50,7 @@
#include "android-base/logging.h"
#include "android-base/stringprintf.h"
-#include "dex/code_item_accessors-no_art-inl.h"
+#include "dex/code_item_accessors-inl.h"
#include "dex/dex_file-inl.h"
#include "dex/dex_file_exception_helpers.h"
#include "dex/dex_file_loader.h"
diff --git a/dexdump/dexdump_cfg.cc b/dexdump/dexdump_cfg.cc
index 0e313572bc..69ee0682a3 100644
--- a/dexdump/dexdump_cfg.cc
+++ b/dexdump/dexdump_cfg.cc
@@ -25,7 +25,7 @@
#include <set>
#include <sstream>
-#include "dex/code_item_accessors-no_art-inl.h"
+#include "dex/code_item_accessors-inl.h"
#include "dex/dex_file-inl.h"
#include "dex/dex_file_exception_helpers.h"
#include "dex/dex_instruction-inl.h"
diff --git a/dexlayout/Android.bp b/dexlayout/Android.bp
index 63650bf121..3ea7f4ba82 100644
--- a/dexlayout/Android.bp
+++ b/dexlayout/Android.bp
@@ -26,7 +26,10 @@ art_cc_defaults {
"dex_writer.cc",
],
export_include_dirs: ["."],
- shared_libs: ["libbase"],
+ shared_libs: [
+ "libdexfile",
+ "libbase",
+ ],
static_libs: ["libz"],
}
diff --git a/dexlayout/dex_ir.h b/dexlayout/dex_ir.h
index 1a84d2307d..d28b824c7b 100644
--- a/dexlayout/dex_ir.h
+++ b/dexlayout/dex_ir.h
@@ -27,8 +27,8 @@
#include "base/stl_util.h"
#include "dex/dex_file-inl.h"
#include "dex/dex_file_types.h"
+#include "dex/utf.h"
#include "leb128.h"
-#include "utf.h"
namespace art {
namespace dex_ir {
diff --git a/dexlayout/dex_writer.cc b/dexlayout/dex_writer.cc
index 778681e7b7..808bfad029 100644
--- a/dexlayout/dex_writer.cc
+++ b/dexlayout/dex_writer.cc
@@ -25,8 +25,8 @@
#include "dex/dex_file_layout.h"
#include "dex/dex_file_types.h"
#include "dex/standard_dex_file.h"
+#include "dex/utf.h"
#include "dexlayout.h"
-#include "utf.h"
namespace art {
diff --git a/dexlist/dexlist.cc b/dexlist/dexlist.cc
index ca02052299..31a146d90e 100644
--- a/dexlist/dexlist.cc
+++ b/dexlist/dexlist.cc
@@ -34,7 +34,7 @@
#include <android-base/logging.h>
-#include "dex/code_item_accessors-no_art-inl.h"
+#include "dex/code_item_accessors-inl.h"
#include "dex/dex_file-inl.h"
#include "dex/dex_file_loader.h"
diff --git a/oatdump/Android.bp b/oatdump/Android.bp
index 4851722734..c93c172eb4 100644
--- a/oatdump/Android.bp
+++ b/oatdump/Android.bp
@@ -36,6 +36,7 @@ art_cc_binary {
"libart",
"libart-compiler",
"libart-disassembler",
+ "libdexfile",
"libbase",
],
}
@@ -50,6 +51,7 @@ art_cc_binary {
"libartd",
"libartd-compiler",
"libartd-disassembler",
+ "libdexfile",
"libbase",
],
}
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index 4324dbad65..6c9f569b19 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -2548,7 +2548,7 @@ class ImageDumper {
}
}
} else {
- CodeItemDataAccessor code_item_accessor(method);
+ CodeItemDataAccessor code_item_accessor(method->DexInstructionData());
size_t dex_instruction_bytes = code_item_accessor.InsnsSizeInCodeUnits() * 2;
stats_.dex_instruction_bytes += dex_instruction_bytes;
diff --git a/openjdkjvmti/Android.bp b/openjdkjvmti/Android.bp
index 0283999d54..1500bcae24 100644
--- a/openjdkjvmti/Android.bp
+++ b/openjdkjvmti/Android.bp
@@ -58,6 +58,7 @@ cc_defaults {
"libopenjdkjvmti_headers",
],
shared_libs: [
+ "libdexfile",
"libbase",
],
}
diff --git a/openjdkjvmti/ti_class_loader.h b/openjdkjvmti/ti_class_loader.h
index 27ea3f5191..ceb7b331de 100644
--- a/openjdkjvmti/ti_class_loader.h
+++ b/openjdkjvmti/ti_class_loader.h
@@ -41,6 +41,7 @@
#include "base/array_slice.h"
#include "class_linker.h"
#include "dex/dex_file.h"
+#include "dex/utf.h"
#include "gc_root-inl.h"
#include "globals.h"
#include "jni_env_ext-inl.h"
@@ -60,7 +61,6 @@
#include "thread_list.h"
#include "ti_class_definition.h"
#include "transform.h"
-#include "utf.h"
#include "utils/dex_cache_arrays_layout-inl.h"
namespace openjdkjvmti {
diff --git a/openjdkjvmti/ti_method.cc b/openjdkjvmti/ti_method.cc
index 3f144c8f0f..83d64ef1d8 100644
--- a/openjdkjvmti/ti_method.cc
+++ b/openjdkjvmti/ti_method.cc
@@ -123,7 +123,7 @@ jvmtiError MethodUtil::GetBytecodes(jvmtiEnv* env,
}
art::ScopedObjectAccess soa(art::Thread::Current());
- art::CodeItemInstructionAccessor accessor(art_method);
+ art::CodeItemInstructionAccessor accessor(art_method->DexInstructions());
if (!accessor.HasCodeItem()) {
*size_ptr = 0;
*bytecode_ptr = nullptr;
@@ -168,7 +168,7 @@ jvmtiError MethodUtil::GetArgumentsSize(jvmtiEnv* env ATTRIBUTE_UNUSED,
}
DCHECK_NE(art_method->GetCodeItemOffset(), 0u);
- *size_ptr = art::CodeItemDataAccessor(art_method).InsSize();
+ *size_ptr = art_method->DexInstructionData().InsSize();
return ERR(NONE);
}
@@ -200,7 +200,7 @@ jvmtiError MethodUtil::GetLocalVariableTable(jvmtiEnv* env,
// TODO HasCodeItem == false means that the method is abstract (or native, but we check that
// earlier). We should check what is returned by the RI in this situation since it's not clear
// what the appropriate return value is from the spec.
- art::CodeItemDebugInfoAccessor accessor(art_method);
+ art::CodeItemDebugInfoAccessor accessor(art_method->DexInstructionDebugInfo());
if (!accessor.HasCodeItem()) {
return ERR(ABSENT_INFORMATION);
}
@@ -301,7 +301,7 @@ jvmtiError MethodUtil::GetMaxLocals(jvmtiEnv* env ATTRIBUTE_UNUSED,
}
DCHECK_NE(art_method->GetCodeItemOffset(), 0u);
- *max_ptr = art::CodeItemDataAccessor(art_method).RegistersSize();
+ *max_ptr = art_method->DexInstructionData().RegistersSize();
return ERR(NONE);
}
@@ -480,7 +480,7 @@ jvmtiError MethodUtil::GetLineNumberTable(jvmtiEnv* env,
return ERR(NULL_POINTER);
}
- accessor = art::CodeItemDebugInfoAccessor(art_method);
+ accessor = art::CodeItemDebugInfoAccessor(art_method->DexInstructionDebugInfo());
dex_file = art_method->GetDexFile();
DCHECK(accessor.HasCodeItem()) << art_method->PrettyMethod() << " " << dex_file->GetLocation();
}
@@ -567,7 +567,7 @@ class CommonLocalVariableClosure : public art::Closure {
// TODO It might be useful to fake up support for get at least on proxy frames.
result_ = ERR(OPAQUE_FRAME);
return;
- } else if (art::CodeItemDataAccessor(method).RegistersSize() <= slot_) {
+ } else if (method->DexInstructionData().RegistersSize() <= slot_) {
result_ = ERR(INVALID_SLOT);
return;
}
@@ -618,7 +618,7 @@ class CommonLocalVariableClosure : public art::Closure {
if (dex_file == nullptr) {
return ERR(OPAQUE_FRAME);
}
- art::CodeItemDebugInfoAccessor accessor(method);
+ art::CodeItemDebugInfoAccessor accessor(method->DexInstructionDebugInfo());
if (!accessor.HasCodeItem()) {
return ERR(OPAQUE_FRAME);
}
diff --git a/openjdkjvmti/ti_redefine.h b/openjdkjvmti/ti_redefine.h
index b537e1b01c..c920707afd 100644
--- a/openjdkjvmti/ti_redefine.h
+++ b/openjdkjvmti/ti_redefine.h
@@ -41,6 +41,7 @@
#include "base/array_ref.h"
#include "class_linker.h"
#include "dex/dex_file.h"
+#include "dex/utf.h"
#include "gc_root-inl.h"
#include "globals.h"
#include "jni_env_ext-inl.h"
@@ -60,7 +61,6 @@
#include "thread_list.h"
#include "ti_class_definition.h"
#include "transform.h"
-#include "utf.h"
#include "utils/dex_cache_arrays_layout-inl.h"
namespace openjdkjvmti {
diff --git a/openjdkjvmti/ti_stack.cc b/openjdkjvmti/ti_stack.cc
index bc77753f8f..373944f179 100644
--- a/openjdkjvmti/ti_stack.cc
+++ b/openjdkjvmti/ti_stack.cc
@@ -1045,7 +1045,7 @@ jvmtiError StackUtil::NotifyFramePop(jvmtiEnv* env, jthread thread, jint depth)
if (shadow_frame == nullptr) {
needs_instrument = true;
const size_t frame_id = visitor.GetFrameId();
- const uint16_t num_regs = art::CodeItemDataAccessor(method).RegistersSize();
+ const uint16_t num_regs = method->DexInstructionData().RegistersSize();
shadow_frame = target->FindOrCreateDebuggerShadowFrame(frame_id,
num_regs,
method,
diff --git a/openjdkjvmti/transform.cc b/openjdkjvmti/transform.cc
index 8445ecab16..af838d62b9 100644
--- a/openjdkjvmti/transform.cc
+++ b/openjdkjvmti/transform.cc
@@ -39,6 +39,7 @@
#include "class_linker.h"
#include "dex/dex_file.h"
#include "dex/dex_file_types.h"
+#include "dex/utf.h"
#include "events-inl.h"
#include "gc_root-inl.h"
#include "globals.h"
@@ -58,7 +59,6 @@
#include "thread_list.h"
#include "ti_redefine.h"
#include "transform.h"
-#include "utf.h"
#include "utils/dex_cache_arrays_layout-inl.h"
namespace openjdkjvmti {
diff --git a/profman/Android.bp b/profman/Android.bp
index ea682b40a0..6592b9dec0 100644
--- a/profman/Android.bp
+++ b/profman/Android.bp
@@ -31,6 +31,7 @@ cc_defaults {
},
shared_libs: [
+ "libdexfile",
"libbase",
],
}
diff --git a/runtime/Android.bp b/runtime/Android.bp
index a759cf700f..db9bceaf29 100644
--- a/runtime/Android.bp
+++ b/runtime/Android.bp
@@ -21,6 +21,7 @@ cc_defaults {
srcs: [
"dex/compact_dex_debug_info.cc",
"dex/compact_dex_file.cc",
+ "dex/descriptors_names.cc",
"dex/dex_file.cc",
"dex/dex_file_exception_helpers.cc",
"dex/dex_file_loader.cc",
@@ -29,8 +30,7 @@ cc_defaults {
"dex/dex_instruction.cc",
"dex/modifiers.cc",
"dex/standard_dex_file.cc",
- "utf.cc",
- "utils.cc",
+ "dex/utf.cc",
],
target: {
@@ -51,7 +51,7 @@ cc_defaults {
],
},
},
- generated_sources: ["art_operator_srcs"],
+ generated_sources: ["dexfile_operator_srcs"],
include_dirs: [
"external/zlib",
],
@@ -133,19 +133,9 @@ cc_defaults {
"common_throws.cc",
"compiler_filter.cc",
"debugger.cc",
- "dex/compact_dex_debug_info.cc",
- "dex/compact_dex_file.cc",
- "dex/dex_file.cc",
"dex/dex_file_annotations.cc",
- "dex/dex_file_exception_helpers.cc",
"dex/dex_file_layout.cc",
- "dex/dex_file_loader.cc",
"dex/art_dex_file_loader.cc",
- "dex/dex_file_tracking_registrar.cc",
- "dex/dex_file_verifier.cc",
- "dex/dex_instruction.cc",
- "dex/modifiers.cc",
- "dex/standard_dex_file.cc",
"dex_to_dex_decompiler.cc",
"elf_file.cc",
"exec_utils.cc",
@@ -302,7 +292,6 @@ cc_defaults {
"trace.cc",
"transaction.cc",
"type_lookup_table.cc",
- "utf.cc",
"utils.cc",
"vdex_file.cc",
"verifier/instruction_flags.cc",
@@ -498,6 +487,7 @@ cc_defaults {
"jni_platform_headers",
],
shared_libs: [
+ "libdexfile",
"libnativebridge",
"libnativeloader",
"libbacktrace",
@@ -534,11 +524,7 @@ gensrcs {
"debugger.h",
"base/unix_file/fd_file.h",
"class_status.h",
- "dex/dex_file.h",
"dex/dex_file_layout.h",
- "dex/dex_instruction.h",
- "dex/dex_instruction_utils.h",
- "dex/invoke_type.h",
"gc_root.h",
"gc/allocator_type.h",
"gc/allocator/rosalloc.h",
@@ -657,6 +643,7 @@ art_cc_test {
"dex/dex_file_test.cc",
"dex/dex_file_verifier_test.cc",
"dex/dex_instruction_test.cc",
+ "dex/utf_test.cc",
"entrypoints/math_entrypoints_test.cc",
"entrypoints/quick/quick_trampoline_entrypoints_test.cc",
"entrypoints_order_test.cc",
@@ -710,7 +697,6 @@ art_cc_test {
"thread_pool_test.cc",
"transaction_test.cc",
"type_lookup_table_test.cc",
- "utf_test.cc",
"utils_test.cc",
"vdex_file_test.cc",
"verifier/method_verifier_test.cc",
diff --git a/runtime/art_method-inl.h b/runtime/art_method-inl.h
index 65bacd8237..e6e35c89c9 100644
--- a/runtime/art_method-inl.h
+++ b/runtime/art_method-inl.h
@@ -377,6 +377,22 @@ inline bool ArtMethod::HasSingleImplementation() {
return (GetAccessFlags() & kAccSingleImplementation) != 0;
}
+inline bool ArtMethod::IsHiddenIntrinsic(uint32_t ordinal) {
+ switch (static_cast<Intrinsics>(ordinal)) {
+ case Intrinsics::kReferenceGetReferent:
+ case Intrinsics::kSystemArrayCopyChar:
+ case Intrinsics::kStringGetCharsNoCheck:
+ case Intrinsics::kVarHandleFullFence:
+ case Intrinsics::kVarHandleAcquireFence:
+ case Intrinsics::kVarHandleReleaseFence:
+ case Intrinsics::kVarHandleLoadLoadFence:
+ case Intrinsics::kVarHandleStoreStoreFence:
+ return true;
+ default:
+ return false;
+ }
+}
+
inline void ArtMethod::SetIntrinsic(uint32_t intrinsic) {
// Currently we only do intrinsics for static/final methods or methods of final
// classes. We don't set kHasSingleImplementation for those methods.
@@ -413,10 +429,14 @@ inline void ArtMethod::SetIntrinsic(uint32_t intrinsic) {
DCHECK_EQ(is_default_conflict, IsDefaultConflicting());
DCHECK_EQ(is_compilable, IsCompilable());
DCHECK_EQ(must_count_locks, MustCountLocks());
- // We need to special case java.lang.ref.Reference.getRefererent. The Java method
- // is hidden but we do not yet have a way of making intrinsics hidden.
- if (intrinsic != static_cast<uint32_t>(Intrinsics::kReferenceGetReferent)) {
- DCHECK_EQ(hidden_api_list, GetHiddenApiAccessFlags());
+ if (kIsDebugBuild) {
+ if (IsHiddenIntrinsic(intrinsic)) {
+ // Special case some of our intrinsics because the access flags clash
+ // with the intrinsics ordinal.
+ DCHECK_EQ(HiddenApiAccessFlags::kWhitelist, GetHiddenApiAccessFlags());
+ } else {
+ DCHECK_EQ(hidden_api_list, GetHiddenApiAccessFlags());
+ }
}
} else {
SetAccessFlags(new_value);
@@ -466,7 +486,15 @@ inline void ArtMethod::UpdateEntrypoints(const Visitor& visitor, PointerSize poi
}
inline CodeItemInstructionAccessor ArtMethod::DexInstructions() {
- return CodeItemInstructionAccessor(this);
+ return CodeItemInstructionAccessor(*GetDexFile(), GetCodeItem());
+}
+
+inline CodeItemDataAccessor ArtMethod::DexInstructionData() {
+ return CodeItemDataAccessor(*GetDexFile(), GetCodeItem());
+}
+
+inline CodeItemDebugInfoAccessor ArtMethod::DexInstructionDebugInfo() {
+ return CodeItemDebugInfoAccessor(*GetDexFile(), GetCodeItem(), GetDexMethodIndex());
}
} // namespace art
diff --git a/runtime/art_method.cc b/runtime/art_method.cc
index 96468bba60..efdf5991ec 100644
--- a/runtime/art_method.cc
+++ b/runtime/art_method.cc
@@ -272,7 +272,7 @@ uint32_t ArtMethod::FindCatchBlock(Handle<mirror::Class> exception_type,
// Default to handler not found.
uint32_t found_dex_pc = dex::kDexNoIndex;
// Iterate over the catch handlers associated with dex_pc.
- CodeItemDataAccessor accessor(this);
+ CodeItemDataAccessor accessor(DexInstructionData());
for (CatchHandlerIterator it(accessor, dex_pc); it.HasNext(); it.Next()) {
dex::TypeIndex iter_type_idx = it.GetHandlerTypeIndex();
// Catch all case
diff --git a/runtime/art_method.h b/runtime/art_method.h
index ce8e8ac612..cec2ec4df2 100644
--- a/runtime/art_method.h
+++ b/runtime/art_method.h
@@ -667,6 +667,10 @@ class ArtMethod FINAL {
return hotness_count_;
}
+ static MemberOffset HotnessCountOffset() {
+ return MemberOffset(OFFSETOF_MEMBER(ArtMethod, hotness_count_));
+ }
+
ArrayRef<const uint8_t> GetQuickenedInfo() REQUIRES_SHARED(Locks::mutator_lock_);
// Returns the method header for the compiled code containing 'pc'. Note that runtime
@@ -727,6 +731,14 @@ class ArtMethod FINAL {
ALWAYS_INLINE CodeItemInstructionAccessor DexInstructions()
REQUIRES_SHARED(Locks::mutator_lock_);
+ // Returns the dex code item data section of the DexFile for the art method.
+ ALWAYS_INLINE CodeItemDataAccessor DexInstructionData()
+ REQUIRES_SHARED(Locks::mutator_lock_);
+
+ // Returns the dex code item debug info section of the DexFile for the art method.
+ ALWAYS_INLINE CodeItemDebugInfoAccessor DexInstructionDebugInfo()
+ REQUIRES_SHARED(Locks::mutator_lock_);
+
protected:
// Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses".
// The class we are a part of.
@@ -753,7 +765,7 @@ class ArtMethod FINAL {
// ifTable.
uint16_t method_index_;
- // The hotness we measure for this method. Managed by the interpreter. Not atomic, as we allow
+ // The hotness we measure for this method. Not atomic, as we allow
// missing increments: if the method is hot, we will see it eventually.
uint16_t hotness_count_;
@@ -846,6 +858,9 @@ class ArtMethod FINAL {
} while (!access_flags_.compare_exchange_weak(old_access_flags, new_access_flags));
}
+ // Returns true if the given intrinsic is considered hidden.
+ bool IsHiddenIntrinsic(uint32_t ordinal);
+
DISALLOW_COPY_AND_ASSIGN(ArtMethod); // Need to use CopyFrom to deal with 32 vs 64 bits.
};
diff --git a/runtime/base/file_utils.cc b/runtime/base/file_utils.cc
index d22fd994ee..58990f344b 100644
--- a/runtime/base/file_utils.cc
+++ b/runtime/base/file_utils.cc
@@ -50,10 +50,10 @@
#include "dex/dex_file-inl.h"
#include "dex/dex_file_loader.h"
#include "dex/dex_instruction.h"
+#include "dex/utf-inl.h"
#include "oat_quick_method_header.h"
#include "os.h"
#include "scoped_thread_state_change-inl.h"
-#include "utf-inl.h"
#if defined(__APPLE__)
#include <crt_externs.h>
diff --git a/runtime/check_reference_map_visitor.h b/runtime/check_reference_map_visitor.h
index 0c29e257a1..e2ad7fd83f 100644
--- a/runtime/check_reference_map_visitor.h
+++ b/runtime/check_reference_map_visitor.h
@@ -67,7 +67,7 @@ class CheckReferenceMapVisitor : public StackVisitor {
CodeInfo code_info = GetCurrentOatQuickMethodHeader()->GetOptimizedCodeInfo();
CodeInfoEncoding encoding = code_info.ExtractEncoding();
StackMap stack_map = code_info.GetStackMapForNativePcOffset(native_pc_offset, encoding);
- CodeItemDataAccessor accessor(m);
+ CodeItemDataAccessor accessor(m->DexInstructionData());
uint16_t number_of_dex_registers = accessor.RegistersSize();
DexRegisterMap dex_register_map =
code_info.GetDexRegisterMapOf(stack_map, encoding, number_of_dex_registers);
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index af45a69bd5..32d304073c 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -53,6 +53,7 @@
#include "dex/dex_file-inl.h"
#include "dex/dex_file_exception_helpers.h"
#include "dex/dex_file_loader.h"
+#include "dex/utf.h"
#include "entrypoints/entrypoint_utils.h"
#include "entrypoints/runtime_asm_entrypoints.h"
#include "experimental_flags.h"
@@ -115,7 +116,6 @@
#include "thread-inl.h"
#include "thread_list.h"
#include "trace.h"
-#include "utf.h"
#include "utils.h"
#include "utils/dex_cache_arrays_layout-inl.h"
#include "verifier/method_verifier.h"
@@ -4329,7 +4329,7 @@ void ClassLinker::ResolveClassExceptionHandlerTypes(Handle<mirror::Class> klass)
void ClassLinker::ResolveMethodExceptionHandlerTypes(ArtMethod* method) {
// similar to DexVerifier::ScanTryCatchBlocks and dex2oat's ResolveExceptionsForMethod.
- CodeItemDataAccessor accessor(method);
+ CodeItemDataAccessor accessor(method->DexInstructionData());
if (!accessor.HasCodeItem()) {
return; // native or abstract method
}
diff --git a/runtime/common_throws.cc b/runtime/common_throws.cc
index 03774f45cd..19e7f7686d 100644
--- a/runtime/common_throws.cc
+++ b/runtime/common_throws.cc
@@ -551,7 +551,7 @@ static bool IsValidImplicitCheck(uintptr_t addr, const Instruction& instr)
void ThrowNullPointerExceptionFromDexPC(bool check_address, uintptr_t addr) {
uint32_t throw_dex_pc;
ArtMethod* method = Thread::Current()->GetCurrentMethod(&throw_dex_pc);
- CodeItemInstructionAccessor accessor(method);
+ CodeItemInstructionAccessor accessor(method->DexInstructions());
CHECK_LT(throw_dex_pc, accessor.InsnsSizeInCodeUnits());
const Instruction& instr = accessor.InstructionAt(throw_dex_pc);
if (check_address && !IsValidImplicitCheck(addr, instr)) {
diff --git a/runtime/debugger.cc b/runtime/debugger.cc
index 842cd7330c..61ad725b79 100644
--- a/runtime/debugger.cc
+++ b/runtime/debugger.cc
@@ -37,6 +37,7 @@
#include "dex/dex_file_annotations.h"
#include "dex/dex_file_types.h"
#include "dex/dex_instruction.h"
+#include "dex/utf.h"
#include "entrypoints/runtime_asm_entrypoints.h"
#include "gc/accounting/card_table-inl.h"
#include "gc/allocation_record.h"
@@ -66,7 +67,6 @@
#include "scoped_thread_state_change-inl.h"
#include "stack.h"
#include "thread_list.h"
-#include "utf.h"
#include "well_known_classes.h"
namespace art {
@@ -1533,7 +1533,7 @@ static uint32_t MangleAccessFlags(uint32_t accessFlags) {
*/
static uint16_t MangleSlot(uint16_t slot, ArtMethod* m)
REQUIRES_SHARED(Locks::mutator_lock_) {
- CodeItemDataAccessor accessor(m);
+ CodeItemDataAccessor accessor(m->DexInstructionData());
if (!accessor.HasCodeItem()) {
// We should not get here for a method without code (native, proxy or abstract). Log it and
// return the slot as is since all registers are arguments.
@@ -1564,7 +1564,7 @@ static size_t GetMethodNumArgRegistersIncludingThis(ArtMethod* method)
*/
static uint16_t DemangleSlot(uint16_t slot, ArtMethod* m, JDWP::JdwpError* error)
REQUIRES_SHARED(Locks::mutator_lock_) {
- CodeItemDataAccessor accessor(m);
+ CodeItemDataAccessor accessor(m->DexInstructionData());
if (!accessor.HasCodeItem()) {
// We should not get here for a method without code (native, proxy or abstract). Log it and
// return the slot as is since all registers are arguments.
@@ -1675,7 +1675,7 @@ void Dbg::OutputLineTable(JDWP::RefTypeId, JDWP::MethodId method_id, JDWP::Expan
}
};
ArtMethod* m = FromMethodId(method_id);
- CodeItemDebugInfoAccessor accessor(m);
+ CodeItemDebugInfoAccessor accessor(m->DexInstructionDebugInfo());
uint64_t start, end;
if (!accessor.HasCodeItem()) {
DCHECK(m->IsNative() || m->IsProxyMethod());
@@ -1741,7 +1741,7 @@ void Dbg::OutputVariableTable(JDWP::RefTypeId, JDWP::MethodId method_id, bool wi
}
};
ArtMethod* m = FromMethodId(method_id);
- CodeItemDebugInfoAccessor accessor(m);
+ CodeItemDebugInfoAccessor accessor(m->DexInstructionDebugInfo());
// arg_count considers doubles and longs to take 2 units.
// variable_count considers everything to take 1 unit.
@@ -1791,7 +1791,7 @@ JDWP::JdwpError Dbg::GetBytecodes(JDWP::RefTypeId, JDWP::MethodId method_id,
if (m == nullptr) {
return JDWP::ERR_INVALID_METHODID;
}
- CodeItemDataAccessor accessor(m);
+ CodeItemDataAccessor accessor(m->DexInstructionData());
size_t byte_count = accessor.InsnsSizeInCodeUnits() * 2;
const uint8_t* begin = reinterpret_cast<const uint8_t*>(accessor.Insns());
const uint8_t* end = begin + byte_count;
@@ -3908,7 +3908,7 @@ JDWP::JdwpError Dbg::ConfigureStep(JDWP::ObjectId thread_id, JDWP::JdwpStepSize
// Note: if the thread is not running Java code (pure native thread), there is no "current"
// method on the stack (and no line number either).
if (m != nullptr && !m->IsNative()) {
- CodeItemDebugInfoAccessor accessor(m);
+ CodeItemDebugInfoAccessor accessor(m->DexInstructionDebugInfo());
DebugCallbackContext context(single_step_control, line_number, accessor.InsnsSizeInCodeUnits());
m->GetDexFile()->DecodeDebugPositionInfo(accessor.DebugInfoOffset(),
DebugCallbackContext::Callback,
diff --git a/runtime/dex/code_item_accessors-inl.h b/runtime/dex/code_item_accessors-inl.h
index 63fd120991..9c39935d3b 100644
--- a/runtime/dex/code_item_accessors-inl.h
+++ b/runtime/dex/code_item_accessors-inl.h
@@ -17,26 +17,187 @@
#ifndef ART_RUNTIME_DEX_CODE_ITEM_ACCESSORS_INL_H_
#define ART_RUNTIME_DEX_CODE_ITEM_ACCESSORS_INL_H_
-#include "code_item_accessors-no_art-inl.h"
+#include "code_item_accessors.h"
-#include "art_method-inl.h"
#include "compact_dex_file.h"
#include "dex_file-inl.h"
-#include "oat_file.h"
#include "standard_dex_file.h"
+// The no ART version is used by binaries that don't include the whole runtime.
namespace art {
-inline CodeItemInstructionAccessor::CodeItemInstructionAccessor(ArtMethod* method)
- : CodeItemInstructionAccessor(*method->GetDexFile(), method->GetCodeItem()) {}
+inline void CodeItemInstructionAccessor::Init(uint32_t insns_size_in_code_units,
+ const uint16_t* insns) {
+ insns_size_in_code_units_ = insns_size_in_code_units;
+ insns_ = insns;
+}
-inline CodeItemDataAccessor::CodeItemDataAccessor(ArtMethod* method)
- : CodeItemDataAccessor(*method->GetDexFile(), method->GetCodeItem()) {}
+inline void CodeItemInstructionAccessor::Init(const CompactDexFile::CodeItem& code_item) {
+ uint32_t insns_size_in_code_units;
+ code_item.DecodeFields</*kDecodeOnlyInstructionCount*/ true>(
+ &insns_size_in_code_units,
+ /*registers_size*/ nullptr,
+ /*ins_size*/ nullptr,
+ /*outs_size*/ nullptr,
+ /*tries_size*/ nullptr);
+ Init(insns_size_in_code_units, code_item.insns_);
+}
-inline CodeItemDebugInfoAccessor::CodeItemDebugInfoAccessor(ArtMethod* method)
- : CodeItemDebugInfoAccessor(*method->GetDexFile(),
- method->GetCodeItem(),
- method->GetDexMethodIndex()) {}
+inline void CodeItemInstructionAccessor::Init(const StandardDexFile::CodeItem& code_item) {
+ Init(code_item.insns_size_in_code_units_, code_item.insns_);
+}
+
+inline void CodeItemInstructionAccessor::Init(const DexFile& dex_file,
+ const DexFile::CodeItem* code_item) {
+ if (code_item != nullptr) {
+ DCHECK(dex_file.IsInDataSection(code_item));
+ if (dex_file.IsCompactDexFile()) {
+ Init(down_cast<const CompactDexFile::CodeItem&>(*code_item));
+ } else {
+ DCHECK(dex_file.IsStandardDexFile());
+ Init(down_cast<const StandardDexFile::CodeItem&>(*code_item));
+ }
+ }
+}
+
+inline CodeItemInstructionAccessor::CodeItemInstructionAccessor(
+ const DexFile& dex_file,
+ const DexFile::CodeItem* code_item) {
+ Init(dex_file, code_item);
+}
+
+inline DexInstructionIterator CodeItemInstructionAccessor::begin() const {
+ return DexInstructionIterator(insns_, 0u);
+}
+
+inline DexInstructionIterator CodeItemInstructionAccessor::end() const {
+ return DexInstructionIterator(insns_, insns_size_in_code_units_);
+}
+
+inline IterationRange<DexInstructionIterator> CodeItemInstructionAccessor::InstructionsFrom(
+ uint32_t start_dex_pc) const {
+ DCHECK_LT(start_dex_pc, InsnsSizeInCodeUnits());
+ return {
+ DexInstructionIterator(insns_, start_dex_pc),
+ DexInstructionIterator(insns_, insns_size_in_code_units_) };
+}
+
+inline void CodeItemDataAccessor::Init(const CompactDexFile::CodeItem& code_item) {
+ uint32_t insns_size_in_code_units;
+ code_item.DecodeFields</*kDecodeOnlyInstructionCount*/ false>(&insns_size_in_code_units,
+ &registers_size_,
+ &ins_size_,
+ &outs_size_,
+ &tries_size_);
+ CodeItemInstructionAccessor::Init(insns_size_in_code_units, code_item.insns_);
+}
+
+inline void CodeItemDataAccessor::Init(const StandardDexFile::CodeItem& code_item) {
+ CodeItemInstructionAccessor::Init(code_item);
+ registers_size_ = code_item.registers_size_;
+ ins_size_ = code_item.ins_size_;
+ outs_size_ = code_item.outs_size_;
+ tries_size_ = code_item.tries_size_;
+}
+
+inline void CodeItemDataAccessor::Init(const DexFile& dex_file,
+ const DexFile::CodeItem* code_item) {
+ if (code_item != nullptr) {
+ if (dex_file.IsCompactDexFile()) {
+ CodeItemDataAccessor::Init(down_cast<const CompactDexFile::CodeItem&>(*code_item));
+ } else {
+ DCHECK(dex_file.IsStandardDexFile());
+ CodeItemDataAccessor::Init(down_cast<const StandardDexFile::CodeItem&>(*code_item));
+ }
+ }
+}
+
+inline CodeItemDataAccessor::CodeItemDataAccessor(const DexFile& dex_file,
+ const DexFile::CodeItem* code_item) {
+ Init(dex_file, code_item);
+}
+
+inline IterationRange<const DexFile::TryItem*> CodeItemDataAccessor::TryItems() const {
+ const DexFile::TryItem* try_items = DexFile::GetTryItems(end(), 0u);
+ return {
+ try_items,
+ try_items + TriesSize() };
+}
+
+inline const uint8_t* CodeItemDataAccessor::GetCatchHandlerData(size_t offset) const {
+ return DexFile::GetCatchHandlerData(end(), TriesSize(), offset);
+}
+
+inline const DexFile::TryItem* CodeItemDataAccessor::FindTryItem(uint32_t try_dex_pc) const {
+ IterationRange<const DexFile::TryItem*> try_items(TryItems());
+ int32_t index = DexFile::FindTryItem(try_items.begin(),
+ try_items.end() - try_items.begin(),
+ try_dex_pc);
+ return index != -1 ? &try_items.begin()[index] : nullptr;
+}
+
+inline const void* CodeItemDataAccessor::CodeItemDataEnd() const {
+ const uint8_t* handler_data = GetCatchHandlerData();
+
+ if (TriesSize() == 0 || handler_data == nullptr) {
+ return &end().Inst();
+ }
+ // Get the start of the handler data.
+ const uint32_t handlers_size = DecodeUnsignedLeb128(&handler_data);
+ // Manually read each handler.
+ for (uint32_t i = 0; i < handlers_size; ++i) {
+ int32_t uleb128_count = DecodeSignedLeb128(&handler_data) * 2;
+ if (uleb128_count <= 0) {
+ uleb128_count = -uleb128_count + 1;
+ }
+ for (int32_t j = 0; j < uleb128_count; ++j) {
+ DecodeUnsignedLeb128(&handler_data);
+ }
+ }
+ return reinterpret_cast<const void*>(handler_data);
+}
+
+inline void CodeItemDebugInfoAccessor::Init(const DexFile& dex_file,
+ const DexFile::CodeItem* code_item,
+ uint32_t dex_method_index) {
+ if (code_item == nullptr) {
+ return;
+ }
+ dex_file_ = &dex_file;
+ if (dex_file.IsCompactDexFile()) {
+ Init(down_cast<const CompactDexFile::CodeItem&>(*code_item), dex_method_index);
+ } else {
+ DCHECK(dex_file.IsStandardDexFile());
+ Init(down_cast<const StandardDexFile::CodeItem&>(*code_item));
+ }
+}
+
+inline void CodeItemDebugInfoAccessor::Init(const CompactDexFile::CodeItem& code_item,
+ uint32_t dex_method_index) {
+ debug_info_offset_ = down_cast<const CompactDexFile*>(dex_file_)->GetDebugInfoOffset(
+ dex_method_index);
+ CodeItemDataAccessor::Init(code_item);
+}
+
+inline void CodeItemDebugInfoAccessor::Init(const StandardDexFile::CodeItem& code_item) {
+ debug_info_offset_ = code_item.debug_info_off_;
+ CodeItemDataAccessor::Init(code_item);
+}
+
+template<typename NewLocalCallback>
+inline bool CodeItemDebugInfoAccessor::DecodeDebugLocalInfo(bool is_static,
+ uint32_t method_idx,
+ NewLocalCallback new_local,
+ void* context) const {
+ return dex_file_->DecodeDebugLocalInfo(RegistersSize(),
+ InsSize(),
+ InsnsSizeInCodeUnits(),
+ DebugInfoOffset(),
+ is_static,
+ method_idx,
+ new_local,
+ context);
+}
} // namespace art
diff --git a/runtime/dex/code_item_accessors-no_art-inl.h b/runtime/dex/code_item_accessors-no_art-inl.h
index a243a4a6f4..8082be3818 100644
--- a/runtime/dex/code_item_accessors-no_art-inl.h
+++ b/runtime/dex/code_item_accessors-no_art-inl.h
@@ -17,188 +17,7 @@
#ifndef ART_RUNTIME_DEX_CODE_ITEM_ACCESSORS_NO_ART_INL_H_
#define ART_RUNTIME_DEX_CODE_ITEM_ACCESSORS_NO_ART_INL_H_
-#include "code_item_accessors.h"
-
-#include "compact_dex_file.h"
-#include "dex_file-inl.h"
-#include "standard_dex_file.h"
-
-// The no ART version is used by binaries that don't include the whole runtime.
-namespace art {
-
-inline void CodeItemInstructionAccessor::Init(uint32_t insns_size_in_code_units,
- const uint16_t* insns) {
- insns_size_in_code_units_ = insns_size_in_code_units;
- insns_ = insns;
-}
-
-inline void CodeItemInstructionAccessor::Init(const CompactDexFile::CodeItem& code_item) {
- uint32_t insns_size_in_code_units;
- code_item.DecodeFields</*kDecodeOnlyInstructionCount*/ true>(
- &insns_size_in_code_units,
- /*registers_size*/ nullptr,
- /*ins_size*/ nullptr,
- /*outs_size*/ nullptr,
- /*tries_size*/ nullptr);
- Init(insns_size_in_code_units, code_item.insns_);
-}
-
-inline void CodeItemInstructionAccessor::Init(const StandardDexFile::CodeItem& code_item) {
- Init(code_item.insns_size_in_code_units_, code_item.insns_);
-}
-
-inline void CodeItemInstructionAccessor::Init(const DexFile& dex_file,
- const DexFile::CodeItem* code_item) {
- if (code_item != nullptr) {
- DCHECK(dex_file.IsInDataSection(code_item));
- if (dex_file.IsCompactDexFile()) {
- Init(down_cast<const CompactDexFile::CodeItem&>(*code_item));
- } else {
- DCHECK(dex_file.IsStandardDexFile());
- Init(down_cast<const StandardDexFile::CodeItem&>(*code_item));
- }
- }
-}
-
-inline CodeItemInstructionAccessor::CodeItemInstructionAccessor(
- const DexFile& dex_file,
- const DexFile::CodeItem* code_item) {
- Init(dex_file, code_item);
-}
-
-inline DexInstructionIterator CodeItemInstructionAccessor::begin() const {
- return DexInstructionIterator(insns_, 0u);
-}
-
-inline DexInstructionIterator CodeItemInstructionAccessor::end() const {
- return DexInstructionIterator(insns_, insns_size_in_code_units_);
-}
-
-inline IterationRange<DexInstructionIterator> CodeItemInstructionAccessor::InstructionsFrom(
- uint32_t start_dex_pc) const {
- DCHECK_LT(start_dex_pc, InsnsSizeInCodeUnits());
- return {
- DexInstructionIterator(insns_, start_dex_pc),
- DexInstructionIterator(insns_, insns_size_in_code_units_) };
-}
-
-inline void CodeItemDataAccessor::Init(const CompactDexFile::CodeItem& code_item) {
- uint32_t insns_size_in_code_units;
- code_item.DecodeFields</*kDecodeOnlyInstructionCount*/ false>(&insns_size_in_code_units,
- &registers_size_,
- &ins_size_,
- &outs_size_,
- &tries_size_);
- CodeItemInstructionAccessor::Init(insns_size_in_code_units, code_item.insns_);
-}
-
-inline void CodeItemDataAccessor::Init(const StandardDexFile::CodeItem& code_item) {
- CodeItemInstructionAccessor::Init(code_item);
- registers_size_ = code_item.registers_size_;
- ins_size_ = code_item.ins_size_;
- outs_size_ = code_item.outs_size_;
- tries_size_ = code_item.tries_size_;
-}
-
-inline void CodeItemDataAccessor::Init(const DexFile& dex_file,
- const DexFile::CodeItem* code_item) {
- if (code_item != nullptr) {
- if (dex_file.IsCompactDexFile()) {
- CodeItemDataAccessor::Init(down_cast<const CompactDexFile::CodeItem&>(*code_item));
- } else {
- DCHECK(dex_file.IsStandardDexFile());
- CodeItemDataAccessor::Init(down_cast<const StandardDexFile::CodeItem&>(*code_item));
- }
- }
-}
-
-inline CodeItemDataAccessor::CodeItemDataAccessor(const DexFile& dex_file,
- const DexFile::CodeItem* code_item) {
- Init(dex_file, code_item);
-}
-
-inline IterationRange<const DexFile::TryItem*> CodeItemDataAccessor::TryItems() const {
- const DexFile::TryItem* try_items = DexFile::GetTryItems(end(), 0u);
- return {
- try_items,
- try_items + TriesSize() };
-}
-
-inline const uint8_t* CodeItemDataAccessor::GetCatchHandlerData(size_t offset) const {
- return DexFile::GetCatchHandlerData(end(), TriesSize(), offset);
-}
-
-inline const DexFile::TryItem* CodeItemDataAccessor::FindTryItem(uint32_t try_dex_pc) const {
- IterationRange<const DexFile::TryItem*> try_items(TryItems());
- int32_t index = DexFile::FindTryItem(try_items.begin(),
- try_items.end() - try_items.begin(),
- try_dex_pc);
- return index != -1 ? &try_items.begin()[index] : nullptr;
-}
-
-inline const void* CodeItemDataAccessor::CodeItemDataEnd() const {
- const uint8_t* handler_data = GetCatchHandlerData();
-
- if (TriesSize() == 0 || handler_data == nullptr) {
- return &end().Inst();
- }
- // Get the start of the handler data.
- const uint32_t handlers_size = DecodeUnsignedLeb128(&handler_data);
- // Manually read each handler.
- for (uint32_t i = 0; i < handlers_size; ++i) {
- int32_t uleb128_count = DecodeSignedLeb128(&handler_data) * 2;
- if (uleb128_count <= 0) {
- uleb128_count = -uleb128_count + 1;
- }
- for (int32_t j = 0; j < uleb128_count; ++j) {
- DecodeUnsignedLeb128(&handler_data);
- }
- }
- return reinterpret_cast<const void*>(handler_data);
-}
-
-inline void CodeItemDebugInfoAccessor::Init(const DexFile& dex_file,
- const DexFile::CodeItem* code_item,
- uint32_t dex_method_index) {
- if (code_item == nullptr) {
- return;
- }
- dex_file_ = &dex_file;
- if (dex_file.IsCompactDexFile()) {
- Init(down_cast<const CompactDexFile::CodeItem&>(*code_item), dex_method_index);
- } else {
- DCHECK(dex_file.IsStandardDexFile());
- Init(down_cast<const StandardDexFile::CodeItem&>(*code_item));
- }
-}
-
-inline void CodeItemDebugInfoAccessor::Init(const CompactDexFile::CodeItem& code_item,
- uint32_t dex_method_index) {
- debug_info_offset_ = down_cast<const CompactDexFile*>(dex_file_)->GetDebugInfoOffset(
- dex_method_index);
- CodeItemDataAccessor::Init(code_item);
-}
-
-inline void CodeItemDebugInfoAccessor::Init(const StandardDexFile::CodeItem& code_item) {
- debug_info_offset_ = code_item.debug_info_off_;
- CodeItemDataAccessor::Init(code_item);
-}
-
-template<typename NewLocalCallback>
-inline bool CodeItemDebugInfoAccessor::DecodeDebugLocalInfo(bool is_static,
- uint32_t method_idx,
- NewLocalCallback new_local,
- void* context) const {
- return dex_file_->DecodeDebugLocalInfo(RegistersSize(),
- InsSize(),
- InsnsSizeInCodeUnits(),
- DebugInfoOffset(),
- is_static,
- method_idx,
- new_local,
- context);
-}
-
-} // namespace art
+// TODO: delete this file once system/core is updated.
+#include "code_item_accessors-inl.h"
#endif // ART_RUNTIME_DEX_CODE_ITEM_ACCESSORS_NO_ART_INL_H_
diff --git a/runtime/dex/code_item_accessors.h b/runtime/dex/code_item_accessors.h
index 08f823cae8..beb78f6e4f 100644
--- a/runtime/dex/code_item_accessors.h
+++ b/runtime/dex/code_item_accessors.h
@@ -85,8 +85,6 @@ class CodeItemDataAccessor : public CodeItemInstructionAccessor {
public:
ALWAYS_INLINE CodeItemDataAccessor(const DexFile& dex_file, const DexFile::CodeItem* code_item);
- ALWAYS_INLINE explicit CodeItemDataAccessor(ArtMethod* method);
-
uint16_t RegistersSize() const {
return registers_size_;
}
diff --git a/runtime/dex/code_item_accessors_test.cc b/runtime/dex/code_item_accessors_test.cc
index 8e2548bf3d..1bd12a6f09 100644
--- a/runtime/dex/code_item_accessors_test.cc
+++ b/runtime/dex/code_item_accessors_test.cc
@@ -16,6 +16,7 @@
#include "code_item_accessors-inl.h"
+#include <sys/mman.h>
#include <memory>
#include "common_runtime_test.h"
diff --git a/runtime/dex/compact_dex_file.cc b/runtime/dex/compact_dex_file.cc
index 37f5d0074c..ce289d4d7b 100644
--- a/runtime/dex/compact_dex_file.cc
+++ b/runtime/dex/compact_dex_file.cc
@@ -16,7 +16,7 @@
#include "compact_dex_file.h"
-#include "code_item_accessors-no_art-inl.h"
+#include "code_item_accessors-inl.h"
#include "dex_file-inl.h"
#include "leb128.h"
diff --git a/runtime/dex/descriptors_names.cc b/runtime/dex/descriptors_names.cc
new file mode 100644
index 0000000000..8124e7256f
--- /dev/null
+++ b/runtime/dex/descriptors_names.cc
@@ -0,0 +1,426 @@
+/*
+ * Copyright (C) 2011 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 "descriptors_names.h"
+
+#include "android-base/stringprintf.h"
+#include "android-base/strings.h"
+
+#include "dex/utf-inl.h"
+
+namespace art {
+
+using android::base::StringAppendF;
+using android::base::StringPrintf;
+
+void AppendPrettyDescriptor(const char* descriptor, std::string* result) {
+ // Count the number of '['s to get the dimensionality.
+ const char* c = descriptor;
+ size_t dim = 0;
+ while (*c == '[') {
+ dim++;
+ c++;
+ }
+
+ // Reference or primitive?
+ if (*c == 'L') {
+ // "[[La/b/C;" -> "a.b.C[][]".
+ c++; // Skip the 'L'.
+ } else {
+ // "[[B" -> "byte[][]".
+ // To make life easier, we make primitives look like unqualified
+ // reference types.
+ switch (*c) {
+ case 'B': c = "byte;"; break;
+ case 'C': c = "char;"; break;
+ case 'D': c = "double;"; break;
+ case 'F': c = "float;"; break;
+ case 'I': c = "int;"; break;
+ case 'J': c = "long;"; break;
+ case 'S': c = "short;"; break;
+ case 'Z': c = "boolean;"; break;
+ case 'V': c = "void;"; break; // Used when decoding return types.
+ default: result->append(descriptor); return;
+ }
+ }
+
+ // At this point, 'c' is a string of the form "fully/qualified/Type;"
+ // or "primitive;". Rewrite the type with '.' instead of '/':
+ const char* p = c;
+ while (*p != ';') {
+ char ch = *p++;
+ if (ch == '/') {
+ ch = '.';
+ }
+ result->push_back(ch);
+ }
+ // ...and replace the semicolon with 'dim' "[]" pairs:
+ for (size_t i = 0; i < dim; ++i) {
+ result->append("[]");
+ }
+}
+
+std::string PrettyDescriptor(const char* descriptor) {
+ std::string result;
+ AppendPrettyDescriptor(descriptor, &result);
+ return result;
+}
+
+std::string GetJniShortName(const std::string& class_descriptor, const std::string& method) {
+ // Remove the leading 'L' and trailing ';'...
+ std::string class_name(class_descriptor);
+ CHECK_EQ(class_name[0], 'L') << class_name;
+ CHECK_EQ(class_name[class_name.size() - 1], ';') << class_name;
+ class_name.erase(0, 1);
+ class_name.erase(class_name.size() - 1, 1);
+
+ std::string short_name;
+ short_name += "Java_";
+ short_name += MangleForJni(class_name);
+ short_name += "_";
+ short_name += MangleForJni(method);
+ return short_name;
+}
+
+// See http://java.sun.com/j2se/1.5.0/docs/guide/jni/spec/design.html#wp615 for the full rules.
+std::string MangleForJni(const std::string& s) {
+ std::string result;
+ size_t char_count = CountModifiedUtf8Chars(s.c_str());
+ const char* cp = &s[0];
+ for (size_t i = 0; i < char_count; ++i) {
+ uint32_t ch = GetUtf16FromUtf8(&cp);
+ if ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9')) {
+ result.push_back(ch);
+ } else if (ch == '.' || ch == '/') {
+ result += "_";
+ } else if (ch == '_') {
+ result += "_1";
+ } else if (ch == ';') {
+ result += "_2";
+ } else if (ch == '[') {
+ result += "_3";
+ } else {
+ const uint16_t leading = GetLeadingUtf16Char(ch);
+ const uint32_t trailing = GetTrailingUtf16Char(ch);
+
+ StringAppendF(&result, "_0%04x", leading);
+ if (trailing != 0) {
+ StringAppendF(&result, "_0%04x", trailing);
+ }
+ }
+ }
+ return result;
+}
+
+std::string DotToDescriptor(const char* class_name) {
+ std::string descriptor(class_name);
+ std::replace(descriptor.begin(), descriptor.end(), '.', '/');
+ if (descriptor.length() > 0 && descriptor[0] != '[') {
+ descriptor = "L" + descriptor + ";";
+ }
+ return descriptor;
+}
+
+std::string DescriptorToDot(const char* descriptor) {
+ size_t length = strlen(descriptor);
+ if (length > 1) {
+ if (descriptor[0] == 'L' && descriptor[length - 1] == ';') {
+ // Descriptors have the leading 'L' and trailing ';' stripped.
+ std::string result(descriptor + 1, length - 2);
+ std::replace(result.begin(), result.end(), '/', '.');
+ return result;
+ } else {
+ // For arrays the 'L' and ';' remain intact.
+ std::string result(descriptor);
+ std::replace(result.begin(), result.end(), '/', '.');
+ return result;
+ }
+ }
+ // Do nothing for non-class/array descriptors.
+ return descriptor;
+}
+
+std::string DescriptorToName(const char* descriptor) {
+ size_t length = strlen(descriptor);
+ if (descriptor[0] == 'L' && descriptor[length - 1] == ';') {
+ std::string result(descriptor + 1, length - 2);
+ return result;
+ }
+ return descriptor;
+}
+
+// Helper for IsValidPartOfMemberNameUtf8(), a bit vector indicating valid low ascii.
+static uint32_t DEX_MEMBER_VALID_LOW_ASCII[4] = {
+ 0x00000000, // 00..1f low control characters; nothing valid
+ 0x03ff2010, // 20..3f digits and symbols; valid: '0'..'9', '$', '-'
+ 0x87fffffe, // 40..5f uppercase etc.; valid: 'A'..'Z', '_'
+ 0x07fffffe // 60..7f lowercase etc.; valid: 'a'..'z'
+};
+
+// Helper for IsValidPartOfMemberNameUtf8(); do not call directly.
+static bool IsValidPartOfMemberNameUtf8Slow(const char** pUtf8Ptr) {
+ /*
+ * It's a multibyte encoded character. Decode it and analyze. We
+ * accept anything that isn't (a) an improperly encoded low value,
+ * (b) an improper surrogate pair, (c) an encoded '\0', (d) a high
+ * control character, or (e) a high space, layout, or special
+ * character (U+00a0, U+2000..U+200f, U+2028..U+202f,
+ * U+fff0..U+ffff). This is all specified in the dex format
+ * document.
+ */
+
+ const uint32_t pair = GetUtf16FromUtf8(pUtf8Ptr);
+ const uint16_t leading = GetLeadingUtf16Char(pair);
+
+ // We have a surrogate pair resulting from a valid 4 byte UTF sequence.
+ // No further checks are necessary because 4 byte sequences span code
+ // points [U+10000, U+1FFFFF], which are valid codepoints in a dex
+ // identifier. Furthermore, GetUtf16FromUtf8 guarantees that each of
+ // the surrogate halves are valid and well formed in this instance.
+ if (GetTrailingUtf16Char(pair) != 0) {
+ return true;
+ }
+
+
+ // We've encountered a one, two or three byte UTF-8 sequence. The
+ // three byte UTF-8 sequence could be one half of a surrogate pair.
+ switch (leading >> 8) {
+ case 0x00:
+ // It's only valid if it's above the ISO-8859-1 high space (0xa0).
+ return (leading > 0x00a0);
+ case 0xd8:
+ case 0xd9:
+ case 0xda:
+ case 0xdb:
+ {
+ // We found a three byte sequence encoding one half of a surrogate.
+ // Look for the other half.
+ const uint32_t pair2 = GetUtf16FromUtf8(pUtf8Ptr);
+ const uint16_t trailing = GetLeadingUtf16Char(pair2);
+
+ return (GetTrailingUtf16Char(pair2) == 0) && (0xdc00 <= trailing && trailing <= 0xdfff);
+ }
+ case 0xdc:
+ case 0xdd:
+ case 0xde:
+ case 0xdf:
+ // It's a trailing surrogate, which is not valid at this point.
+ return false;
+ case 0x20:
+ case 0xff:
+ // It's in the range that has spaces, controls, and specials.
+ switch (leading & 0xfff8) {
+ case 0x2000:
+ case 0x2008:
+ case 0x2028:
+ case 0xfff0:
+ case 0xfff8:
+ return false;
+ }
+ return true;
+ default:
+ return true;
+ }
+
+ UNREACHABLE();
+}
+
+/* Return whether the pointed-at modified-UTF-8 encoded character is
+ * valid as part of a member name, updating the pointer to point past
+ * the consumed character. This will consume two encoded UTF-16 code
+ * points if the character is encoded as a surrogate pair. Also, if
+ * this function returns false, then the given pointer may only have
+ * been partially advanced.
+ */
+static bool IsValidPartOfMemberNameUtf8(const char** pUtf8Ptr) {
+ uint8_t c = (uint8_t) **pUtf8Ptr;
+ if (LIKELY(c <= 0x7f)) {
+ // It's low-ascii, so check the table.
+ uint32_t wordIdx = c >> 5;
+ uint32_t bitIdx = c & 0x1f;
+ (*pUtf8Ptr)++;
+ return (DEX_MEMBER_VALID_LOW_ASCII[wordIdx] & (1 << bitIdx)) != 0;
+ }
+
+ // It's a multibyte encoded character. Call a non-inline function
+ // for the heavy lifting.
+ return IsValidPartOfMemberNameUtf8Slow(pUtf8Ptr);
+}
+
+bool IsValidMemberName(const char* s) {
+ bool angle_name = false;
+
+ switch (*s) {
+ case '\0':
+ // The empty string is not a valid name.
+ return false;
+ case '<':
+ angle_name = true;
+ s++;
+ break;
+ }
+
+ while (true) {
+ switch (*s) {
+ case '\0':
+ return !angle_name;
+ case '>':
+ return angle_name && s[1] == '\0';
+ }
+
+ if (!IsValidPartOfMemberNameUtf8(&s)) {
+ return false;
+ }
+ }
+}
+
+enum ClassNameType { kName, kDescriptor };
+template<ClassNameType kType, char kSeparator>
+static bool IsValidClassName(const char* s) {
+ int arrayCount = 0;
+ while (*s == '[') {
+ arrayCount++;
+ s++;
+ }
+
+ if (arrayCount > 255) {
+ // Arrays may have no more than 255 dimensions.
+ return false;
+ }
+
+ ClassNameType type = kType;
+ if (type != kDescriptor && arrayCount != 0) {
+ /*
+ * If we're looking at an array of some sort, then it doesn't
+ * matter if what is being asked for is a class name; the
+ * format looks the same as a type descriptor in that case, so
+ * treat it as such.
+ */
+ type = kDescriptor;
+ }
+
+ if (type == kDescriptor) {
+ /*
+ * We are looking for a descriptor. Either validate it as a
+ * single-character primitive type, or continue on to check the
+ * embedded class name (bracketed by "L" and ";").
+ */
+ switch (*(s++)) {
+ case 'B':
+ case 'C':
+ case 'D':
+ case 'F':
+ case 'I':
+ case 'J':
+ case 'S':
+ case 'Z':
+ // These are all single-character descriptors for primitive types.
+ return (*s == '\0');
+ case 'V':
+ // Non-array void is valid, but you can't have an array of void.
+ return (arrayCount == 0) && (*s == '\0');
+ case 'L':
+ // Class name: Break out and continue below.
+ break;
+ default:
+ // Oddball descriptor character.
+ return false;
+ }
+ }
+
+ /*
+ * We just consumed the 'L' that introduces a class name as part
+ * of a type descriptor, or we are looking for an unadorned class
+ * name.
+ */
+
+ bool sepOrFirst = true; // first character or just encountered a separator.
+ for (;;) {
+ uint8_t c = (uint8_t) *s;
+ switch (c) {
+ case '\0':
+ /*
+ * Premature end for a type descriptor, but valid for
+ * a class name as long as we haven't encountered an
+ * empty component (including the degenerate case of
+ * the empty string "").
+ */
+ return (type == kName) && !sepOrFirst;
+ case ';':
+ /*
+ * Invalid character for a class name, but the
+ * legitimate end of a type descriptor. In the latter
+ * case, make sure that this is the end of the string
+ * and that it doesn't end with an empty component
+ * (including the degenerate case of "L;").
+ */
+ return (type == kDescriptor) && !sepOrFirst && (s[1] == '\0');
+ case '/':
+ case '.':
+ if (c != kSeparator) {
+ // The wrong separator character.
+ return false;
+ }
+ if (sepOrFirst) {
+ // Separator at start or two separators in a row.
+ return false;
+ }
+ sepOrFirst = true;
+ s++;
+ break;
+ default:
+ if (!IsValidPartOfMemberNameUtf8(&s)) {
+ return false;
+ }
+ sepOrFirst = false;
+ break;
+ }
+ }
+}
+
+bool IsValidBinaryClassName(const char* s) {
+ return IsValidClassName<kName, '.'>(s);
+}
+
+bool IsValidJniClassName(const char* s) {
+ return IsValidClassName<kName, '/'>(s);
+}
+
+bool IsValidDescriptor(const char* s) {
+ return IsValidClassName<kDescriptor, '/'>(s);
+}
+
+void Split(const std::string& s, char separator, std::vector<std::string>* result) {
+ const char* p = s.data();
+ const char* end = p + s.size();
+ while (p != end) {
+ if (*p == separator) {
+ ++p;
+ } else {
+ const char* start = p;
+ while (++p != end && *p != separator) {
+ // Skip to the next occurrence of the separator.
+ }
+ result->push_back(std::string(start, p - start));
+ }
+ }
+}
+
+std::string PrettyDescriptor(Primitive::Type type) {
+ return PrettyDescriptor(Primitive::Descriptor(type));
+}
+
+} // namespace art
diff --git a/runtime/dex/descriptors_names.h b/runtime/dex/descriptors_names.h
new file mode 100644
index 0000000000..22e9573556
--- /dev/null
+++ b/runtime/dex/descriptors_names.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2011 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_RUNTIME_DEX_DESCRIPTORS_NAMES_H_
+#define ART_RUNTIME_DEX_DESCRIPTORS_NAMES_H_
+
+#include <string>
+
+#include "primitive.h"
+
+namespace art {
+
+// Used to implement PrettyClass, PrettyField, PrettyMethod, and PrettyTypeOf,
+// one of which is probably more useful to you.
+// Returns a human-readable equivalent of 'descriptor'. So "I" would be "int",
+// "[[I" would be "int[][]", "[Ljava/lang/String;" would be
+// "java.lang.String[]", and so forth.
+void AppendPrettyDescriptor(const char* descriptor, std::string* result);
+std::string PrettyDescriptor(const char* descriptor);
+std::string PrettyDescriptor(Primitive::Type type);
+
+// Performs JNI name mangling as described in section 11.3 "Linking Native Methods"
+// of the JNI spec.
+std::string MangleForJni(const std::string& s);
+
+std::string GetJniShortName(const std::string& class_name, const std::string& method_name);
+
+// Turn "java.lang.String" into "Ljava/lang/String;".
+std::string DotToDescriptor(const char* class_name);
+
+// Turn "Ljava/lang/String;" into "java.lang.String" using the conventions of
+// java.lang.Class.getName().
+std::string DescriptorToDot(const char* descriptor);
+
+// Turn "Ljava/lang/String;" into "java/lang/String" using the opposite conventions of
+// java.lang.Class.getName().
+std::string DescriptorToName(const char* descriptor);
+
+// Tests for whether 's' is a valid class name in the three common forms:
+bool IsValidBinaryClassName(const char* s); // "java.lang.String"
+bool IsValidJniClassName(const char* s); // "java/lang/String"
+bool IsValidDescriptor(const char* s); // "Ljava/lang/String;"
+
+// Returns whether the given string is a valid field or method name,
+// additionally allowing names that begin with '<' and end with '>'.
+bool IsValidMemberName(const char* s);
+
+} // namespace art
+
+#endif // ART_RUNTIME_DEX_DESCRIPTORS_NAMES_H_
diff --git a/runtime/dex/dex_file.cc b/runtime/dex/dex_file.cc
index f0209f7bec..18eb903551 100644
--- a/runtime/dex/dex_file.cc
+++ b/runtime/dex/dex_file.cc
@@ -30,11 +30,11 @@
#include "base/enums.h"
#include "base/stl_util.h"
+#include "descriptors_names.h"
#include "dex_file-inl.h"
#include "leb128.h"
#include "standard_dex_file.h"
#include "utf-inl.h"
-#include "utils.h"
namespace art {
diff --git a/runtime/dex/dex_file_annotations.cc b/runtime/dex/dex_file_annotations.cc
index 72b18fb420..e01890f541 100644
--- a/runtime/dex/dex_file_annotations.cc
+++ b/runtime/dex/dex_file_annotations.cc
@@ -1559,7 +1559,7 @@ int32_t GetLineNumFromPC(const DexFile* dex_file, ArtMethod* method, uint32_t re
return -2;
}
- CodeItemDebugInfoAccessor accessor(method);
+ CodeItemDebugInfoAccessor accessor(method->DexInstructionDebugInfo());
DCHECK(accessor.HasCodeItem()) << method->PrettyMethod() << " " << dex_file->GetLocation();
// A method with no line number info should return -1
diff --git a/runtime/dex/dex_file_exception_helpers.cc b/runtime/dex/dex_file_exception_helpers.cc
index ad56eb0a0b..8e597fd3dd 100644
--- a/runtime/dex/dex_file_exception_helpers.cc
+++ b/runtime/dex/dex_file_exception_helpers.cc
@@ -16,7 +16,7 @@
#include "dex_file_exception_helpers.h"
-#include "code_item_accessors-no_art-inl.h"
+#include "code_item_accessors-inl.h"
namespace art {
diff --git a/runtime/dex/dex_file_layout.cc b/runtime/dex/dex_file_layout.cc
index 1973440d55..312898d82f 100644
--- a/runtime/dex/dex_file_layout.cc
+++ b/runtime/dex/dex_file_layout.cc
@@ -19,8 +19,8 @@
#include <sys/mman.h>
#include "base/file_utils.h"
+#include "descriptors_names.h"
#include "dex_file.h"
-#include "utils.h"
namespace art {
diff --git a/runtime/dex/dex_file_test.cc b/runtime/dex/dex_file_test.cc
index cb721af754..998bfd6c7f 100644
--- a/runtime/dex/dex_file_test.cc
+++ b/runtime/dex/dex_file_test.cc
@@ -25,13 +25,13 @@
#include "base/unix_file/fd_file.h"
#include "code_item_accessors-inl.h"
#include "common_runtime_test.h"
+#include "descriptors_names.h"
#include "dex_file-inl.h"
#include "dex_file_loader.h"
#include "mem_map.h"
#include "os.h"
#include "scoped_thread_state_change-inl.h"
#include "thread-current-inl.h"
-#include "utils.h"
namespace art {
diff --git a/runtime/dex/dex_file_verifier.cc b/runtime/dex/dex_file_verifier.cc
index f7fdbb027c..62667052ad 100644
--- a/runtime/dex/dex_file_verifier.cc
+++ b/runtime/dex/dex_file_verifier.cc
@@ -23,14 +23,12 @@
#include "android-base/stringprintf.h"
-#include "code_item_accessors-no_art-inl.h"
+#include "code_item_accessors-inl.h"
+#include "descriptors_names.h"
#include "dex_file-inl.h"
-#include "experimental_flags.h"
#include "leb128.h"
#include "modifiers.h"
-#include "safe_map.h"
#include "utf-inl.h"
-#include "utils.h"
namespace art {
diff --git a/runtime/dex/dex_file_verifier_test.cc b/runtime/dex/dex_file_verifier_test.cc
index 9759685961..d73a7fbfa3 100644
--- a/runtime/dex/dex_file_verifier_test.cc
+++ b/runtime/dex/dex_file_verifier_test.cc
@@ -27,6 +27,7 @@
#include "base/macros.h"
#include "base/unix_file/fd_file.h"
#include "common_runtime_test.h"
+#include "descriptors_names.h"
#include "dex_file-inl.h"
#include "dex_file_loader.h"
#include "dex_file_types.h"
@@ -34,7 +35,6 @@
#include "scoped_thread_state_change-inl.h"
#include "standard_dex_file.h"
#include "thread-current-inl.h"
-#include "utils.h"
namespace art {
diff --git a/runtime/dex/dex_instruction.cc b/runtime/dex/dex_instruction.cc
index 6ebe2286e8..b84791ffae 100644
--- a/runtime/dex/dex_instruction.cc
+++ b/runtime/dex/dex_instruction.cc
@@ -24,7 +24,7 @@
#include "android-base/stringprintf.h"
#include "dex_file-inl.h"
-#include "utils.h"
+#include "utf.h"
namespace art {
diff --git a/runtime/dex/standard_dex_file.cc b/runtime/dex/standard_dex_file.cc
index 024f73b4e5..f7317eb997 100644
--- a/runtime/dex/standard_dex_file.cc
+++ b/runtime/dex/standard_dex_file.cc
@@ -17,7 +17,7 @@
#include "standard_dex_file.h"
#include "base/casts.h"
-#include "code_item_accessors-no_art-inl.h"
+#include "code_item_accessors-inl.h"
#include "dex_file-inl.h"
#include "leb128.h"
diff --git a/runtime/utf-inl.h b/runtime/dex/utf-inl.h
index b2d6765fb0..4f626a8580 100644
--- a/runtime/utf-inl.h
+++ b/runtime/dex/utf-inl.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef ART_RUNTIME_UTF_INL_H_
-#define ART_RUNTIME_UTF_INL_H_
+#ifndef ART_RUNTIME_DEX_UTF_INL_H_
+#define ART_RUNTIME_DEX_UTF_INL_H_
#include "utf.h"
@@ -96,4 +96,4 @@ inline int CompareModifiedUtf8ToModifiedUtf8AsUtf16CodePointValues(const char* u
} // namespace art
-#endif // ART_RUNTIME_UTF_INL_H_
+#endif // ART_RUNTIME_DEX_UTF_INL_H_
diff --git a/runtime/utf.cc b/runtime/dex/utf.cc
index 32ae187297..772a610140 100644
--- a/runtime/utf.cc
+++ b/runtime/dex/utf.cc
@@ -17,12 +17,17 @@
#include "utf.h"
#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
#include "base/casts.h"
#include "utf-inl.h"
namespace art {
+using android::base::StringAppendF;
+using android::base::StringPrintf;
+
// This is used only from debugger and test code.
size_t CountModifiedUtf8Chars(const char* utf8) {
return CountModifiedUtf8Chars(utf8, strlen(utf8));
@@ -262,4 +267,55 @@ size_t CountUtf8Bytes(const uint16_t* chars, size_t char_count) {
return result;
}
+static inline constexpr bool NeedsEscaping(uint16_t ch) {
+ return (ch < ' ' || ch > '~');
+}
+
+std::string PrintableChar(uint16_t ch) {
+ std::string result;
+ result += '\'';
+ if (NeedsEscaping(ch)) {
+ StringAppendF(&result, "\\u%04x", ch);
+ } else {
+ result += static_cast<std::string::value_type>(ch);
+ }
+ result += '\'';
+ return result;
+}
+
+std::string PrintableString(const char* utf) {
+ std::string result;
+ result += '"';
+ const char* p = utf;
+ size_t char_count = CountModifiedUtf8Chars(p);
+ for (size_t i = 0; i < char_count; ++i) {
+ uint32_t ch = GetUtf16FromUtf8(&p);
+ if (ch == '\\') {
+ result += "\\\\";
+ } else if (ch == '\n') {
+ result += "\\n";
+ } else if (ch == '\r') {
+ result += "\\r";
+ } else if (ch == '\t') {
+ result += "\\t";
+ } else {
+ const uint16_t leading = GetLeadingUtf16Char(ch);
+
+ if (NeedsEscaping(leading)) {
+ StringAppendF(&result, "\\u%04x", leading);
+ } else {
+ result += static_cast<std::string::value_type>(leading);
+ }
+
+ const uint32_t trailing = GetTrailingUtf16Char(ch);
+ if (trailing != 0) {
+ // All high surrogates will need escaping.
+ StringAppendF(&result, "\\u%04x", trailing);
+ }
+ }
+ }
+ result += '"';
+ return result;
+}
+
} // namespace art
diff --git a/runtime/utf.h b/runtime/dex/utf.h
index cbb32fa6cd..4adfc4af8c 100644
--- a/runtime/utf.h
+++ b/runtime/dex/utf.h
@@ -14,14 +14,16 @@
* limitations under the License.
*/
-#ifndef ART_RUNTIME_UTF_H_
-#define ART_RUNTIME_UTF_H_
+#ifndef ART_RUNTIME_DEX_UTF_H_
+#define ART_RUNTIME_DEX_UTF_H_
#include "base/macros.h"
#include <stddef.h>
#include <stdint.h>
+#include <string>
+
/*
* All UTF-8 in art is actually modified UTF-8. Mostly, this distinction
* doesn't matter.
@@ -121,6 +123,13 @@ ALWAYS_INLINE uint16_t GetLeadingUtf16Char(uint32_t maybe_pair);
*/
ALWAYS_INLINE uint16_t GetTrailingUtf16Char(uint32_t maybe_pair);
+// Returns a printable (escaped) version of a character.
+std::string PrintableChar(uint16_t ch);
+
+// Returns an ASCII string corresponding to the given UTF-8 string.
+// Java escapes are used for non-ASCII characters.
+std::string PrintableString(const char* utf8);
+
} // namespace art
-#endif // ART_RUNTIME_UTF_H_
+#endif // ART_RUNTIME_DEX_UTF_H_
diff --git a/runtime/utf_test.cc b/runtime/dex/utf_test.cc
index d1e97515d3..d1e97515d3 100644
--- a/runtime/utf_test.cc
+++ b/runtime/dex/utf_test.cc
diff --git a/runtime/entrypoints/quick/quick_throw_entrypoints.cc b/runtime/entrypoints/quick/quick_throw_entrypoints.cc
index 565b4edcc3..9b0756b529 100644
--- a/runtime/entrypoints/quick/quick_throw_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_throw_entrypoints.cc
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include "art_method-inl.h"
#include "callee_save_frame.h"
#include "common_throws.h"
#include "mirror/object-inl.h"
diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
index f727690c11..c5157ce9f4 100644
--- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
@@ -785,7 +785,7 @@ extern "C" uint64_t artQuickToInterpreterBridge(ArtMethod* method, Thread* self,
uint32_t shorty_len = 0;
ArtMethod* non_proxy_method = method->GetInterfaceMethodIfProxy(kRuntimePointerSize);
DCHECK(non_proxy_method->GetCodeItem() != nullptr) << method->PrettyMethod();
- CodeItemDataAccessor accessor(non_proxy_method);
+ CodeItemDataAccessor accessor(non_proxy_method->DexInstructionData());
const char* shorty = non_proxy_method->GetShorty(&shorty_len);
JValue result;
@@ -1121,7 +1121,7 @@ extern "C" const void* artQuickResolutionTrampoline(
// code.
if (!found_stack_map || kIsDebugBuild) {
uint32_t dex_pc = QuickArgumentVisitor::GetCallingDexPc(sp);
- CodeItemInstructionAccessor accessor(caller);
+ CodeItemInstructionAccessor accessor(caller->DexInstructions());
CHECK_LT(dex_pc, accessor.InsnsSizeInCodeUnits());
const Instruction& instr = accessor.InstructionAt(dex_pc);
Instruction::Code instr_code = instr.Opcode();
diff --git a/runtime/imtable-inl.h b/runtime/imtable-inl.h
index 6237cca9e4..93346f6151 100644
--- a/runtime/imtable-inl.h
+++ b/runtime/imtable-inl.h
@@ -21,7 +21,7 @@
#include "art_method-inl.h"
#include "dex/dex_file.h"
-#include "utf.h"
+#include "dex/utf.h"
namespace art {
diff --git a/runtime/intern_table.cc b/runtime/intern_table.cc
index 5b93d3b873..4b964f648b 100644
--- a/runtime/intern_table.cc
+++ b/runtime/intern_table.cc
@@ -18,6 +18,7 @@
#include <memory>
+#include "dex/utf.h"
#include "gc/collector/garbage_collector.h"
#include "gc/space/image_space.h"
#include "gc/weak_root_state.h"
@@ -30,7 +31,6 @@
#include "object_callbacks.h"
#include "scoped_thread_state_change-inl.h"
#include "thread.h"
-#include "utf.h"
namespace art {
diff --git a/runtime/intern_table_test.cc b/runtime/intern_table_test.cc
index 9c3ea8d864..b56c48d78c 100644
--- a/runtime/intern_table_test.cc
+++ b/runtime/intern_table_test.cc
@@ -18,12 +18,12 @@
#include "base/hash_set.h"
#include "common_runtime_test.h"
+#include "dex/utf.h"
#include "gc_root-inl.h"
#include "handle_scope-inl.h"
#include "mirror/object.h"
#include "mirror/string.h"
#include "scoped_thread_state_change-inl.h"
-#include "utf.h"
namespace art {
diff --git a/runtime/interpreter/interpreter.cc b/runtime/interpreter/interpreter.cc
index 54db87297d..735c0e815a 100644
--- a/runtime/interpreter/interpreter.cc
+++ b/runtime/interpreter/interpreter.cc
@@ -389,7 +389,7 @@ void EnterInterpreterFromInvoke(Thread* self,
}
const char* old_cause = self->StartAssertNoThreadSuspension("EnterInterpreterFromInvoke");
- CodeItemDataAccessor accessor(method);
+ CodeItemDataAccessor accessor(method->DexInstructionData());
uint16_t num_regs;
uint16_t num_ins;
if (accessor.HasCodeItem()) {
@@ -499,7 +499,7 @@ void EnterInterpreterFromDeoptimize(Thread* self,
DCHECK(!shadow_frame->GetMethod()->MustCountLocks());
self->SetTopOfShadowStack(shadow_frame);
- CodeItemDataAccessor accessor(shadow_frame->GetMethod());
+ CodeItemDataAccessor accessor(shadow_frame->GetMethod()->DexInstructionData());
const uint32_t dex_pc = shadow_frame->GetDexPC();
uint32_t new_dex_pc = dex_pc;
if (UNLIKELY(self->IsExceptionPending())) {
diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc
index 475f93803d..d53da215a2 100644
--- a/runtime/interpreter/interpreter_common.cc
+++ b/runtime/interpreter/interpreter_common.cc
@@ -1320,7 +1320,7 @@ static inline bool DoCallCommon(ArtMethod* called_method,
}
// Compute method information.
- CodeItemDataAccessor accessor(called_method);
+ CodeItemDataAccessor accessor(called_method->DexInstructionData());
// Number of registers for the callee's call frame.
uint16_t num_regs;
// Test whether to use the interpreter or compiler entrypoint, and save that result to pass to
diff --git a/runtime/interpreter/shadow_frame.cc b/runtime/interpreter/shadow_frame.cc
index fe7e3e0a9b..264ec6a997 100644
--- a/runtime/interpreter/shadow_frame.cc
+++ b/runtime/interpreter/shadow_frame.cc
@@ -28,7 +28,7 @@ mirror::Object* ShadowFrame::GetThisObject() const {
return GetVRegReference(0);
} else {
CHECK(m->GetCodeItem() != nullptr) << ArtMethod::PrettyMethod(m);
- CodeItemDataAccessor accessor(m);
+ CodeItemDataAccessor accessor(m->DexInstructionData());
uint16_t reg = accessor.RegistersSize() - accessor.InsSize();
return GetVRegReference(reg);
}
diff --git a/runtime/jdwp/jdwp_handler.cc b/runtime/jdwp/jdwp_handler.cc
index 89eef88b88..90cac853ff 100644
--- a/runtime/jdwp/jdwp_handler.cc
+++ b/runtime/jdwp/jdwp_handler.cc
@@ -27,6 +27,7 @@
#include "base/logging.h" // For VLOG.
#include "base/macros.h"
#include "debugger.h"
+#include "dex/utf.h"
#include "jdwp/jdwp_constants.h"
#include "jdwp/jdwp_event.h"
#include "jdwp/jdwp_expand_buf.h"
@@ -34,7 +35,6 @@
#include "runtime.h"
#include "scoped_thread_state_change-inl.h"
#include "thread-current-inl.h"
-#include "utils.h"
namespace art {
diff --git a/runtime/jit/jit.cc b/runtime/jit/jit.cc
index 12bf79d7ca..1baa613bb5 100644
--- a/runtime/jit/jit.cc
+++ b/runtime/jit/jit.cc
@@ -467,7 +467,7 @@ bool Jit::MaybeDoOnStackReplacement(Thread* thread,
// Fetch some data before looking up for an OSR method. We don't want thread
// suspension once we hold an OSR method, as the JIT code cache could delete the OSR
// method while we are being suspended.
- CodeItemDataAccessor accessor(method);
+ CodeItemDataAccessor accessor(method->DexInstructionData());
const size_t number_of_vregs = accessor.RegistersSize();
const char* shorty = method->GetShorty();
std::string method_name(VLOG_IS_ON(jit) ? method->PrettyMethod() : "");
diff --git a/runtime/jni_internal.cc b/runtime/jni_internal.cc
index c40360f612..dc0d65dcc1 100644
--- a/runtime/jni_internal.cc
+++ b/runtime/jni_internal.cc
@@ -33,6 +33,7 @@
#include "base/stl_util.h"
#include "class_linker-inl.h"
#include "dex/dex_file-inl.h"
+#include "dex/utf.h"
#include "fault_handler.h"
#include "hidden_api.h"
#include "gc/accounting/card_table-inl.h"
@@ -57,7 +58,6 @@
#include "safe_map.h"
#include "scoped_thread_state_change-inl.h"
#include "thread.h"
-#include "utf.h"
#include "well_known_classes.h"
namespace {
diff --git a/runtime/method_handles.cc b/runtime/method_handles.cc
index 8bb3bec9ac..2701ec66a4 100644
--- a/runtime/method_handles.cc
+++ b/runtime/method_handles.cc
@@ -415,7 +415,7 @@ static inline bool MethodHandleInvokeMethod(ArtMethod* called_method,
const InstructionOperands* const operands,
JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) {
// Compute method information.
- CodeItemDataAccessor accessor(called_method);
+ CodeItemDataAccessor accessor(called_method->DexInstructionData());
// Number of registers for the callee's call frame. Note that for non-exact
// invokes, we always derive this information from the callee method. We
@@ -557,7 +557,7 @@ static inline bool MethodHandleInvokeTransform(ArtMethod* called_method,
// - One for the only method argument (an EmulatedStackFrame).
static constexpr size_t kNumRegsForTransform = 2;
- CodeItemDataAccessor accessor(called_method);
+ CodeItemDataAccessor accessor(called_method->DexInstructionData());
DCHECK_EQ(kNumRegsForTransform, accessor.RegistersSize());
DCHECK_EQ(kNumRegsForTransform, accessor.InsSize());
@@ -1041,7 +1041,7 @@ static inline bool MethodHandleInvokeExactInternal(
}
// Compute method information.
- CodeItemDataAccessor accessor(called_method);
+ CodeItemDataAccessor accessor(called_method->DexInstructionData());
uint16_t num_regs;
size_t num_input_regs;
size_t first_dest_reg;
diff --git a/runtime/mirror/string-inl.h b/runtime/mirror/string-inl.h
index 24c75ec0d8..8c2a49c5f6 100644
--- a/runtime/mirror/string-inl.h
+++ b/runtime/mirror/string-inl.h
@@ -24,11 +24,11 @@
#include "base/bit_utils.h"
#include "class.h"
#include "common_throws.h"
+#include "dex/utf.h"
#include "gc/heap-inl.h"
#include "globals.h"
#include "runtime.h"
#include "thread.h"
-#include "utf.h"
#include "utils.h"
namespace art {
diff --git a/runtime/mirror/string.cc b/runtime/mirror/string.cc
index 82ff6ddead..cad84ceecb 100644
--- a/runtime/mirror/string.cc
+++ b/runtime/mirror/string.cc
@@ -21,6 +21,7 @@
#include "base/array_ref.h"
#include "base/stl_util.h"
#include "class-inl.h"
+#include "dex/utf-inl.h"
#include "gc/accounting/card_table-inl.h"
#include "gc_root-inl.h"
#include "handle_scope-inl.h"
@@ -29,7 +30,6 @@
#include "runtime.h"
#include "string-inl.h"
#include "thread.h"
-#include "utf-inl.h"
namespace art {
namespace mirror {
diff --git a/runtime/monitor.cc b/runtime/monitor.cc
index 325591fb53..0c9c65a401 100644
--- a/runtime/monitor.cc
+++ b/runtime/monitor.cc
@@ -1378,7 +1378,7 @@ void Monitor::VisitLocks(StackVisitor* stack_visitor, void (*callback)(mirror::O
// Is there any reason to believe there's any synchronization in this method?
CHECK(m->GetCodeItem() != nullptr) << m->PrettyMethod();
- CodeItemDataAccessor accessor(m);
+ CodeItemDataAccessor accessor(m->DexInstructionData());
if (accessor.TriesSize() == 0) {
return; // No "tries" implies no synchronization, so no held locks to report.
}
diff --git a/runtime/native/dalvik_system_ZygoteHooks.cc b/runtime/native/dalvik_system_ZygoteHooks.cc
index 26496e8ca1..e58fd9dac9 100644
--- a/runtime/native/dalvik_system_ZygoteHooks.cc
+++ b/runtime/native/dalvik_system_ZygoteHooks.cc
@@ -174,6 +174,7 @@ enum {
DISABLE_VERIFIER = 1 << 9,
ONLY_USE_SYSTEM_OAT_FILES = 1 << 10,
DISABLE_HIDDEN_API_CHECKS = 1 << 11,
+ DEBUG_GENERATE_MINI_DEBUG_INFO = 1 << 12,
};
static uint32_t EnableDebugFeatures(uint32_t runtime_flags) {
@@ -210,12 +211,6 @@ static uint32_t EnableDebugFeatures(uint32_t runtime_flags) {
runtime_flags &= ~DEBUG_ENABLE_SAFEMODE;
}
- const bool generate_debug_info = (runtime_flags & DEBUG_GENERATE_DEBUG_INFO) != 0;
- if (generate_debug_info) {
- runtime->AddCompilerOption("--generate-debug-info");
- runtime_flags &= ~DEBUG_GENERATE_DEBUG_INFO;
- }
-
// This is for backwards compatibility with Dalvik.
runtime_flags &= ~DEBUG_ENABLE_ASSERT;
@@ -229,8 +224,7 @@ static uint32_t EnableDebugFeatures(uint32_t runtime_flags) {
bool needs_non_debuggable_classes = false;
if ((runtime_flags & DEBUG_JAVA_DEBUGGABLE) != 0) {
runtime->AddCompilerOption("--debuggable");
- // Generate native debug information to allow backtracing through JITed code.
- runtime->AddCompilerOption("--generate-mini-debug-info");
+ runtime_flags |= DEBUG_GENERATE_MINI_DEBUG_INFO;
runtime->SetJavaDebuggable(true);
// Deoptimize the boot image as it may be non-debuggable.
runtime->DeoptimizeBootImage();
@@ -243,12 +237,23 @@ static uint32_t EnableDebugFeatures(uint32_t runtime_flags) {
if ((runtime_flags & DEBUG_NATIVE_DEBUGGABLE) != 0) {
runtime->AddCompilerOption("--debuggable");
- // Generate all native debug information we can (e.g. line-numbers).
- runtime->AddCompilerOption("--generate-debug-info");
+ runtime_flags |= DEBUG_GENERATE_DEBUG_INFO;
runtime->SetNativeDebuggable(true);
runtime_flags &= ~DEBUG_NATIVE_DEBUGGABLE;
}
+ if ((runtime_flags & DEBUG_GENERATE_MINI_DEBUG_INFO) != 0) {
+ // Generate native minimal debug information to allow backtracing.
+ runtime->AddCompilerOption("--generate-mini-debug-info");
+ runtime_flags &= ~DEBUG_GENERATE_MINI_DEBUG_INFO;
+ }
+
+ if ((runtime_flags & DEBUG_GENERATE_DEBUG_INFO) != 0) {
+ // Generate all native debug information we can (e.g. line-numbers).
+ runtime->AddCompilerOption("--generate-debug-info");
+ runtime_flags &= ~DEBUG_GENERATE_DEBUG_INFO;
+ }
+
return runtime_flags;
}
diff --git a/runtime/native/java_lang_Class.cc b/runtime/native/java_lang_Class.cc
index 5544275984..a1f23bdfb8 100644
--- a/runtime/native/java_lang_Class.cc
+++ b/runtime/native/java_lang_Class.cc
@@ -25,6 +25,7 @@
#include "common_throws.h"
#include "dex/dex_file-inl.h"
#include "dex/dex_file_annotations.h"
+#include "dex/utf.h"
#include "hidden_api.h"
#include "jni_internal.h"
#include "mirror/class-inl.h"
@@ -43,7 +44,6 @@
#include "reflection.h"
#include "scoped_fast_native_object_access-inl.h"
#include "scoped_thread_state_change-inl.h"
-#include "utf.h"
#include "well_known_classes.h"
namespace art {
diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc
index 307f7b96ed..dc4bae3415 100644
--- a/runtime/oat_file.cc
+++ b/runtime/oat_file.cc
@@ -47,6 +47,7 @@
#include "dex/dex_file_loader.h"
#include "dex/dex_file_types.h"
#include "dex/standard_dex_file.h"
+#include "dex/utf-inl.h"
#include "elf_file.h"
#include "elf_utils.h"
#include "gc_root.h"
@@ -60,7 +61,6 @@
#include "os.h"
#include "runtime.h"
#include "type_lookup_table.h"
-#include "utf-inl.h"
#include "utils.h"
#include "vdex_file.h"
diff --git a/runtime/oat_file.h b/runtime/oat_file.h
index 50a706d1ba..46c692e568 100644
--- a/runtime/oat_file.h
+++ b/runtime/oat_file.h
@@ -28,12 +28,12 @@
#include "compiler_filter.h"
#include "dex/dex_file.h"
#include "dex/dex_file_layout.h"
+#include "dex/utf.h"
#include "index_bss_mapping.h"
#include "mirror/object.h"
#include "oat.h"
#include "os.h"
#include "type_lookup_table.h"
-#include "utf.h"
#include "utils.h"
namespace art {
diff --git a/runtime/quick_exception_handler.cc b/runtime/quick_exception_handler.cc
index 3a7640fa8b..006405f095 100644
--- a/runtime/quick_exception_handler.cc
+++ b/runtime/quick_exception_handler.cc
@@ -222,7 +222,7 @@ void QuickExceptionHandler::SetCatchEnvironmentForOptimizedHandler(StackVisitor*
self_->DumpStack(LOG_STREAM(INFO) << "Setting catch phis: ");
}
- CodeItemDataAccessor accessor(handler_method_);
+ CodeItemDataAccessor accessor(handler_method_->DexInstructionData());
const size_t number_of_vregs = accessor.RegistersSize();
CodeInfo code_info = handler_method_header_->GetOptimizedCodeInfo();
CodeInfoEncoding encoding = code_info.ExtractEncoding();
@@ -360,7 +360,7 @@ class DeoptimizeStackVisitor FINAL : public StackVisitor {
const size_t frame_id = GetFrameId();
ShadowFrame* new_frame = GetThread()->FindDebuggerShadowFrame(frame_id);
const bool* updated_vregs;
- CodeItemDataAccessor accessor(method);
+ CodeItemDataAccessor accessor(method->DexInstructionData());
const size_t num_regs = accessor.RegistersSize();
if (new_frame == nullptr) {
new_frame = ShadowFrame::CreateDeoptimizedFrame(num_regs, nullptr, method, GetDexPc());
@@ -408,7 +408,7 @@ class DeoptimizeStackVisitor FINAL : public StackVisitor {
uintptr_t native_pc_offset = method_header->NativeQuickPcOffset(GetCurrentQuickFramePc());
CodeInfoEncoding encoding = code_info.ExtractEncoding();
StackMap stack_map = code_info.GetStackMapForNativePcOffset(native_pc_offset, encoding);
- CodeItemDataAccessor accessor(m);
+ CodeItemDataAccessor accessor(m->DexInstructionData());
const size_t number_of_vregs = accessor.RegistersSize();
uint32_t register_mask = code_info.GetRegisterMaskOf(encoding, stack_map);
BitMemoryRegion stack_mask = code_info.GetStackMaskOf(encoding, stack_map);
diff --git a/runtime/stack.cc b/runtime/stack.cc
index dfdea28ae8..229238e0f7 100644
--- a/runtime/stack.cc
+++ b/runtime/stack.cc
@@ -154,7 +154,7 @@ mirror::Object* StackVisitor::GetThisObject() const {
return cur_shadow_frame_->GetVRegReference(0);
}
} else {
- CodeItemDataAccessor accessor(m);
+ CodeItemDataAccessor accessor(m->DexInstructionData());
if (!accessor.HasCodeItem()) {
UNIMPLEMENTED(ERROR) << "Failed to determine this object of abstract or proxy method: "
<< ArtMethod::PrettyMethod(m);
@@ -225,7 +225,7 @@ bool StackVisitor::GetVRegFromOptimizedCode(ArtMethod* m, uint16_t vreg, VRegKin
DCHECK_EQ(m, GetMethod());
// Can't be null or how would we compile its instructions?
DCHECK(m->GetCodeItem() != nullptr) << m->PrettyMethod();
- CodeItemDataAccessor accessor(m);
+ CodeItemDataAccessor accessor(m->DexInstructionData());
uint16_t number_of_dex_registers = accessor.RegistersSize();
DCHECK_LT(vreg, number_of_dex_registers);
const OatQuickMethodHeader* method_header = GetCurrentOatQuickMethodHeader();
@@ -395,7 +395,7 @@ bool StackVisitor::SetVReg(ArtMethod* m,
uint16_t vreg,
uint32_t new_value,
VRegKind kind) {
- CodeItemDataAccessor accessor(m);
+ CodeItemDataAccessor accessor(m->DexInstructionData());
if (!accessor.HasCodeItem()) {
return false;
}
@@ -432,7 +432,7 @@ bool StackVisitor::SetVRegPair(ArtMethod* m,
LOG(FATAL) << "Expected long or double: kind_lo=" << kind_lo << ", kind_hi=" << kind_hi;
UNREACHABLE();
}
- CodeItemDataAccessor accessor(m);
+ CodeItemDataAccessor accessor(m->DexInstructionData());
if (!accessor.HasCodeItem()) {
return false;
}
diff --git a/runtime/string_reference.h b/runtime/string_reference.h
index 97661c6019..1ee5d6d53a 100644
--- a/runtime/string_reference.h
+++ b/runtime/string_reference.h
@@ -24,7 +24,7 @@
#include "dex/dex_file-inl.h"
#include "dex/dex_file_reference.h"
#include "dex/dex_file_types.h"
-#include "utf-inl.h"
+#include "dex/utf-inl.h"
namespace art {
diff --git a/runtime/thread.cc b/runtime/thread.cc
index 14375f7bcd..9dc92f3788 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -3628,7 +3628,7 @@ class ReferenceMapVisitor : public StackVisitor {
const CodeInfoEncoding& _encoding,
const StackMap& map,
RootVisitor& _visitor)
- : number_of_dex_registers(CodeItemDataAccessor(method).RegistersSize()),
+ : number_of_dex_registers(method->DexInstructionData().RegistersSize()),
code_info(_code_info),
encoding(_encoding),
dex_register_map(code_info.GetDexRegisterMapOf(map,
diff --git a/runtime/type_lookup_table.cc b/runtime/type_lookup_table.cc
index 649a4f9547..925a9089cb 100644
--- a/runtime/type_lookup_table.cc
+++ b/runtime/type_lookup_table.cc
@@ -21,7 +21,7 @@
#include "base/bit_utils.h"
#include "dex/dex_file-inl.h"
-#include "utf-inl.h"
+#include "dex/utf-inl.h"
#include "utils.h"
namespace art {
diff --git a/runtime/type_lookup_table.h b/runtime/type_lookup_table.h
index 50c93ad9f0..a1f9519f18 100644
--- a/runtime/type_lookup_table.h
+++ b/runtime/type_lookup_table.h
@@ -18,8 +18,8 @@
#define ART_RUNTIME_TYPE_LOOKUP_TABLE_H_
#include "dex/dex_file_types.h"
+#include "dex/utf.h"
#include "leb128.h"
-#include "utf.h"
namespace art {
diff --git a/runtime/type_lookup_table_test.cc b/runtime/type_lookup_table_test.cc
index d04652a8e7..b6ab6da78c 100644
--- a/runtime/type_lookup_table_test.cc
+++ b/runtime/type_lookup_table_test.cc
@@ -20,8 +20,8 @@
#include "common_runtime_test.h"
#include "dex/dex_file-inl.h"
+#include "dex/utf-inl.h"
#include "scoped_thread_state_change-inl.h"
-#include "utf-inl.h"
namespace art {
diff --git a/runtime/utils.cc b/runtime/utils.cc
index b2ec669f32..393b18e1b3 100644
--- a/runtime/utils.cc
+++ b/runtime/utils.cc
@@ -30,8 +30,8 @@
#include "android-base/stringprintf.h"
#include "android-base/strings.h"
+#include "dex/utf-inl.h"
#include "os.h"
-#include "utf-inl.h"
#if defined(__APPLE__)
#include <crt_externs.h>
@@ -151,57 +151,6 @@ std::string PrettySize(int64_t byte_count) {
negative_str, byte_count / kBytesPerUnit[i], kUnitStrings[i]);
}
-static inline constexpr bool NeedsEscaping(uint16_t ch) {
- return (ch < ' ' || ch > '~');
-}
-
-std::string PrintableChar(uint16_t ch) {
- std::string result;
- result += '\'';
- if (NeedsEscaping(ch)) {
- StringAppendF(&result, "\\u%04x", ch);
- } else {
- result += static_cast<std::string::value_type>(ch);
- }
- result += '\'';
- return result;
-}
-
-std::string PrintableString(const char* utf) {
- std::string result;
- result += '"';
- const char* p = utf;
- size_t char_count = CountModifiedUtf8Chars(p);
- for (size_t i = 0; i < char_count; ++i) {
- uint32_t ch = GetUtf16FromUtf8(&p);
- if (ch == '\\') {
- result += "\\\\";
- } else if (ch == '\n') {
- result += "\\n";
- } else if (ch == '\r') {
- result += "\\r";
- } else if (ch == '\t') {
- result += "\\t";
- } else {
- const uint16_t leading = GetLeadingUtf16Char(ch);
-
- if (NeedsEscaping(leading)) {
- StringAppendF(&result, "\\u%04x", leading);
- } else {
- result += static_cast<std::string::value_type>(leading);
- }
-
- const uint32_t trailing = GetTrailingUtf16Char(ch);
- if (trailing != 0) {
- // All high surrogates will need escaping.
- StringAppendF(&result, "\\u%04x", trailing);
- }
- }
- }
- result += '"';
- return result;
-}
-
std::string GetJniShortName(const std::string& class_descriptor, const std::string& method) {
// Remove the leading 'L' and trailing ';'...
std::string class_name(class_descriptor);
diff --git a/runtime/utils.h b/runtime/utils.h
index abdafcc9f7..443b0cc398 100644
--- a/runtime/utils.h
+++ b/runtime/utils.h
@@ -67,12 +67,6 @@ static inline uint32_t PointerToLowMemUInt32(const void* p) {
return intp & 0xFFFFFFFFU;
}
-std::string PrintableChar(uint16_t ch);
-
-// Returns an ASCII string corresponding to the given UTF-8 string.
-// Java escapes are used for non-ASCII characters.
-std::string PrintableString(const char* utf8);
-
// Used to implement PrettyClass, PrettyField, PrettyMethod, and PrettyTypeOf,
// one of which is probably more useful to you.
// Returns a human-readable equivalent of 'descriptor'. So "I" would be "int",
diff --git a/runtime/vdex_file.h b/runtime/vdex_file.h
index b9fd467017..0f347952c9 100644
--- a/runtime/vdex_file.h
+++ b/runtime/vdex_file.h
@@ -87,8 +87,8 @@ class VdexFile {
private:
static constexpr uint8_t kVdexMagic[] = { 'v', 'd', 'e', 'x' };
- // Last update: Separate section for compact dex data.
- static constexpr uint8_t kVdexVersion[] = { '0', '1', '6', '\0' };
+ // Last update: Fix separate section for compact dex data.
+ static constexpr uint8_t kVdexVersion[] = { '0', '1', '7', '\0' };
uint8_t magic_[4];
uint8_t version_[4];
@@ -101,6 +101,9 @@ class VdexFile {
friend class VdexFile;
};
+ // Note: The file is called "primary" to match the naming with profiles.
+ static const constexpr char* kVdexNameInDmFile = "primary.vdex";
+
typedef uint32_t VdexChecksum;
using QuickeningTableOffsetType = uint32_t;
diff --git a/test/004-ThreadStress/src/Main.java b/test/004-ThreadStress/src-art/Main.java
index c03a9120bf..a142934638 100644
--- a/test/004-ThreadStress/src/Main.java
+++ b/test/004-ThreadStress/src-art/Main.java
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+import dalvik.system.VMRuntime;
+
import java.lang.reflect.*;
import java.util.ArrayList;
import java.util.Arrays;
@@ -32,25 +34,26 @@ import java.util.concurrent.Semaphore;
// (It is important to pass Main if you want to give parameters...)
//
// ThreadStress command line parameters:
-// -n X ............ number of threads
-// -d X ............ number of daemon threads
-// -o X ............ number of overall operations
-// -t X ............ number of operations per thread
-// -p X ............ number of permits granted by semaphore
-// --dumpmap ....... print the frequency map
-// --locks-only .... select a pre-set frequency map with lock-related operations only
-// --allocs-only ... select a pre-set frequency map with allocation-related operations only
-// -oom:X .......... frequency of OOM (double)
-// -sigquit:X ...... frequency of SigQuit (double)
-// -alloc:X ........ frequency of Alloc (double)
-// -largealloc:X ... frequency of LargeAlloc (double)
-// -stacktrace:X ... frequency of StackTrace (double)
-// -exit:X ......... frequency of Exit (double)
-// -sleep:X ........ frequency of Sleep (double)
-// -wait:X ......... frequency of Wait (double)
-// -timedwait:X .... frequency of TimedWait (double)
-// -syncandwork:X .. frequency of SyncAndWork (double)
-// -queuedwait:X ... frequency of QueuedWait (double)
+// -n X .............. number of threads
+// -d X .............. number of daemon threads
+// -o X .............. number of overall operations
+// -t X .............. number of operations per thread
+// -p X .............. number of permits granted by semaphore
+// --dumpmap ......... print the frequency map
+// --locks-only ...... select a pre-set frequency map with lock-related operations only
+// --allocs-only ..... select a pre-set frequency map with allocation-related operations only
+// -oom:X ............ frequency of OOM (double)
+// -sigquit:X ........ frequency of SigQuit (double)
+// -alloc:X .......... frequency of Alloc (double)
+// -largealloc:X ..... frequency of LargeAlloc (double)
+// -nonmovingalloc:X.. frequency of NonMovingAlloc (double)
+// -stacktrace:X ..... frequency of StackTrace (double)
+// -exit:X ........... frequency of Exit (double)
+// -sleep:X .......... frequency of Sleep (double)
+// -wait:X ........... frequency of Wait (double)
+// -timedwait:X ...... frequency of TimedWait (double)
+// -syncandwork:X .... frequency of SyncAndWork (double)
+// -queuedwait:X ..... frequency of QueuedWait (double)
public class Main implements Runnable {
@@ -158,6 +161,25 @@ public class Main implements Runnable {
}
}
+ private final static class NonMovingAlloc extends Operation {
+ private final static int ALLOC_SIZE = 1024; // Needs to be small enough to not be in LOS.
+ private final static int ALLOC_COUNT = 1024;
+ private final static VMRuntime runtime = VMRuntime.getRuntime();
+
+ @Override
+ public boolean perform() {
+ try {
+ List<byte[]> l = new ArrayList<byte[]>();
+ for (int i = 0; i < ALLOC_COUNT; i++) {
+ l.add((byte[]) runtime.newNonMovableArray(byte.class, ALLOC_SIZE));
+ }
+ } catch (OutOfMemoryError e) {
+ }
+ return true;
+ }
+ }
+
+
private final static class StackTrace extends Operation {
@Override
public boolean perform() {
@@ -295,6 +317,9 @@ public class Main implements Runnable {
frequencyMap.put(new SigQuit(), 0.095); // 19/200
frequencyMap.put(new Alloc(), 0.225); // 45/200
frequencyMap.put(new LargeAlloc(), 0.05); // 10/200
+ // TODO: NonMovingAlloc operations fail an assertion with the
+ // GSS collector (see b/72738921); disable them for now.
+ frequencyMap.put(new NonMovingAlloc(), 0.0); // 0/200
frequencyMap.put(new StackTrace(), 0.1); // 20/200
frequencyMap.put(new Exit(), 0.225); // 45/200
frequencyMap.put(new Sleep(), 0.125); // 25/200
@@ -308,8 +333,9 @@ public class Main implements Runnable {
private final static Map<Operation, Double> createAllocFrequencyMap() {
Map<Operation, Double> frequencyMap = new HashMap<Operation, Double>();
frequencyMap.put(new Sleep(), 0.2); // 40/200
- frequencyMap.put(new Alloc(), 0.65); // 130/200
+ frequencyMap.put(new Alloc(), 0.575); // 115/200
frequencyMap.put(new LargeAlloc(), 0.15); // 30/200
+ frequencyMap.put(new NonMovingAlloc(), 0.075); // 15/200
return frequencyMap;
}
diff --git a/test/044-proxy/src/Main.java b/test/044-proxy/src/Main.java
index e44c122e3d..7b70e65b8c 100644
--- a/test/044-proxy/src/Main.java
+++ b/test/044-proxy/src/Main.java
@@ -54,4 +54,8 @@ public class Main {
private static final HashMap<String, String> proxyClassNameMap = new HashMap<String, String>();
private static int uniqueTestProxyClassNum = 0;
+
+ static native void startJit();
+ static native void stopJit();
+ static native void waitForCompilation();
}
diff --git a/test/044-proxy/src/OOMEOnDispatch.java b/test/044-proxy/src/OOMEOnDispatch.java
index 94f267980d..2ee57926ae 100644
--- a/test/044-proxy/src/OOMEOnDispatch.java
+++ b/test/044-proxy/src/OOMEOnDispatch.java
@@ -32,6 +32,11 @@ public class OOMEOnDispatch implements InvocationHandler {
OOMEInterface.class.getClassLoader(), new Class[] { OOMEInterface.class },
handler);
+ // Stop the JIT to be sure nothing is running that could be resolving classes or causing
+ // verification.
+ Main.stopJit();
+ Main.waitForCompilation();
+
int l = 1024 * 1024;
while (l > 8) {
try {
@@ -40,17 +45,6 @@ public class OOMEOnDispatch implements InvocationHandler {
l = l/2;
}
}
- // Have an extra run with the exact size of Method objects. The above loop should have
- // filled with enough large objects for simplicity and speed, but ensure exact allocation
- // size.
- final int methodAsByteArrayLength = 40 - 12; // Method size - byte array overhead.
- for (;;) {
- try {
- storage.add(new byte[methodAsByteArrayLength]);
- } catch (OutOfMemoryError e) {
- break;
- }
- }
try {
inf.foo();
@@ -60,6 +54,8 @@ public class OOMEOnDispatch implements InvocationHandler {
storage.clear();
System.out.println("Received OOME");
}
+
+ Main.startJit();
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
diff --git a/test/141-class-unload/jni_unload.cc b/test/141-class-unload/jni_unload.cc
index 355457d68d..894ae8b0d7 100644
--- a/test/141-class-unload/jni_unload.cc
+++ b/test/141-class-unload/jni_unload.cc
@@ -32,19 +32,5 @@ extern "C" JNIEXPORT void JNICALL Java_IntHolder_waitForCompilation(JNIEnv*, jcl
}
}
-extern "C" JNIEXPORT void JNICALL Java_Main_stopJit(JNIEnv*, jclass) {
- jit::Jit* jit = Runtime::Current()->GetJit();
- if (jit != nullptr) {
- jit->Stop();
- }
-}
-
-extern "C" JNIEXPORT void JNICALL Java_Main_startJit(JNIEnv*, jclass) {
- jit::Jit* jit = Runtime::Current()->GetJit();
- if (jit != nullptr) {
- jit->Start();
- }
-}
-
} // namespace
} // namespace art
diff --git a/test/466-get-live-vreg/get_live_vreg_jni.cc b/test/466-get-live-vreg/get_live_vreg_jni.cc
index aeb9e44541..44ea0c9877 100644
--- a/test/466-get-live-vreg/get_live_vreg_jni.cc
+++ b/test/466-get-live-vreg/get_live_vreg_jni.cc
@@ -42,7 +42,8 @@ class TestVisitor : public StackVisitor {
CHECK(GetVReg(m, 0, kIntVReg, &value));
CHECK_EQ(value, 42u);
} else if (m_name.compare("$opt$noinline$testIntervalHole") == 0) {
- uint32_t number_of_dex_registers = CodeItemDataAccessor(m).RegistersSize();
+ uint32_t number_of_dex_registers =
+ CodeItemDataAccessor(m->DexInstructionData()).RegistersSize();
uint32_t dex_register_of_first_parameter = number_of_dex_registers - 2;
found_method_ = true;
uint32_t value = 0;
diff --git a/test/674-HelloWorld-Dm/expected.txt b/test/674-HelloWorld-Dm/expected.txt
new file mode 100644
index 0000000000..af5626b4a1
--- /dev/null
+++ b/test/674-HelloWorld-Dm/expected.txt
@@ -0,0 +1 @@
+Hello, world!
diff --git a/test/674-HelloWorld-Dm/info.txt b/test/674-HelloWorld-Dm/info.txt
new file mode 100644
index 0000000000..3a769c48a6
--- /dev/null
+++ b/test/674-HelloWorld-Dm/info.txt
@@ -0,0 +1 @@
+Hello World test with --dm-file passed to dex2oat.
diff --git a/test/674-HelloWorld-Dm/run b/test/674-HelloWorld-Dm/run
new file mode 100644
index 0000000000..199ffc31e1
--- /dev/null
+++ b/test/674-HelloWorld-Dm/run
@@ -0,0 +1,17 @@
+#!/bin/bash
+#
+# 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.
+
+exec ${RUN} --dm "${@}"
diff --git a/test/674-HelloWorld-Dm/src/Main.java b/test/674-HelloWorld-Dm/src/Main.java
new file mode 100644
index 0000000000..1ef6289559
--- /dev/null
+++ b/test/674-HelloWorld-Dm/src/Main.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+public class Main {
+ public static void main(String[] args) {
+ System.out.println("Hello, world!");
+ }
+}
diff --git a/test/674-hotness-compiled/expected.txt b/test/674-hotness-compiled/expected.txt
new file mode 100644
index 0000000000..6a5618ebc6
--- /dev/null
+++ b/test/674-hotness-compiled/expected.txt
@@ -0,0 +1 @@
+JNI_OnLoad called
diff --git a/test/674-hotness-compiled/info.txt b/test/674-hotness-compiled/info.txt
new file mode 100644
index 0000000000..e2cf59a093
--- /dev/null
+++ b/test/674-hotness-compiled/info.txt
@@ -0,0 +1 @@
+Test for the --count-hotness-in-compiled-code compiler option.
diff --git a/test/674-hotness-compiled/run b/test/674-hotness-compiled/run
new file mode 100755
index 0000000000..85e8e3b13f
--- /dev/null
+++ b/test/674-hotness-compiled/run
@@ -0,0 +1,17 @@
+#!/bin/bash
+#
+# 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.
+
+${RUN} "$@" -Xcompiler-option --count-hotness-in-compiled-code
diff --git a/test/674-hotness-compiled/src/Main.java b/test/674-hotness-compiled/src/Main.java
new file mode 100644
index 0000000000..76ec92777f
--- /dev/null
+++ b/test/674-hotness-compiled/src/Main.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+public class Main {
+ public static void $noinline$hotnessCount() {
+ }
+
+ public static void $noinline$hotnessCountWithLoop() {
+ for (int i = 0; i < 100; i++) {
+ $noinline$hotnessCount();
+ }
+ }
+
+ public static void main(String[] args) {
+ System.loadLibrary(args[0]);
+ if (!isAotCompiled(Main.class, "main")) {
+ return;
+ }
+ $noinline$hotnessCount();
+ int counter = getHotnessCounter(Main.class, "$noinline$hotnessCount");
+ if (counter == 0) {
+ throw new Error("Expected hotness counter to be updated");
+ }
+
+ $noinline$hotnessCountWithLoop();
+ if (getHotnessCounter(Main.class, "$noinline$hotnessCountWithLoop") <= counter) {
+ throw new Error("Expected hotness counter of a loop to be greater than without loop");
+ }
+ }
+
+ public static native int getHotnessCounter(Class<?> cls, String methodName);
+ public static native boolean isAotCompiled(Class<?> cls, String methodName);
+}
diff --git a/test/Android.bp b/test/Android.bp
index 730818c4f2..72e8eee95a 100644
--- a/test/Android.bp
+++ b/test/Android.bp
@@ -62,6 +62,7 @@ art_cc_defaults {
"libvixld-arm",
"libvixld-arm64",
"libart-gtest",
+ "libdexfile",
"libbase",
"libicuuc",
@@ -113,6 +114,7 @@ art_cc_defaults {
shared_libs: [
"libartd",
"libartd-compiler",
+ "libdexfile",
],
static_libs: [
"libgtest",
@@ -149,6 +151,7 @@ art_cc_library {
shared_libs: [
"libartd",
"libartd-compiler",
+ "libdexfile",
"libbase",
"libbacktrace",
],
@@ -166,6 +169,7 @@ cc_defaults {
"art_defaults",
],
shared_libs: [
+ "libdexfile",
"libbacktrace",
"libbase",
"libnativehelper",
@@ -264,6 +268,7 @@ art_cc_defaults {
"1943-suspend-raw-monitor-wait/native_suspend_monitor.cc",
],
shared_libs: [
+ "libdexfile",
"libbase",
],
header_libs: [
@@ -394,6 +399,7 @@ cc_defaults {
"708-jit-cache-churn/jit.cc",
],
shared_libs: [
+ "libdexfile",
"libbacktrace",
"libbase",
"libnativehelper",
diff --git a/test/common/runtime_state.cc b/test/common/runtime_state.cc
index c2408b0d2f..298a2f0033 100644
--- a/test/common/runtime_state.cc
+++ b/test/common/runtime_state.cc
@@ -251,13 +251,6 @@ extern "C" JNIEXPORT int JNICALL Java_Main_getHotnessCounter(JNIEnv* env,
jclass,
jclass cls,
jstring method_name) {
- jit::Jit* jit = Runtime::Current()->GetJit();
- if (jit == nullptr) {
- // The hotness counter is valid only under JIT.
- // If we don't JIT return 0 to match test expectations.
- return 0;
- }
-
ArtMethod* method = nullptr;
{
ScopedObjectAccess soa(Thread::Current());
@@ -297,4 +290,25 @@ extern "C" JNIEXPORT jboolean JNICALL Java_Main_isClassMoveable(JNIEnv*,
return runtime->GetHeap()->IsMovableObject(klass);
}
+extern "C" JNIEXPORT void JNICALL Java_Main_waitForCompilation(JNIEnv*, jclass) {
+ jit::Jit* jit = Runtime::Current()->GetJit();
+ if (jit != nullptr) {
+ jit->WaitForCompilationToFinish(Thread::Current());
+ }
+}
+
+extern "C" JNIEXPORT void JNICALL Java_Main_stopJit(JNIEnv*, jclass) {
+ jit::Jit* jit = Runtime::Current()->GetJit();
+ if (jit != nullptr) {
+ jit->Stop();
+ }
+}
+
+extern "C" JNIEXPORT void JNICALL Java_Main_startJit(JNIEnv*, jclass) {
+ jit::Jit* jit = Runtime::Current()->GetJit();
+ if (jit != nullptr) {
+ jit->Start();
+ }
+}
+
} // namespace art
diff --git a/test/etc/run-test-jar b/test/etc/run-test-jar
index ca24471675..ea2d464d24 100755
--- a/test/etc/run-test-jar
+++ b/test/etc/run-test-jar
@@ -64,6 +64,7 @@ ARGS=""
EXTERNAL_LOG_TAGS="n" # if y respect externally set ANDROID_LOG_TAGS.
DRY_RUN="n" # if y prepare to run the test but don't run it.
TEST_VDEX="n"
+TEST_DM="n"
TEST_IS_NDEBUG="n"
APP_IMAGE="y"
JVMTI_STRESS="n"
@@ -346,6 +347,9 @@ while true; do
elif [ "x$1" = "x--vdex" ]; then
TEST_VDEX="y"
shift
+ elif [ "x$1" = "x--dm" ]; then
+ TEST_DM="y"
+ shift
elif [ "x$1" = "x--vdex-filter" ]; then
shift
option="$1"
@@ -678,6 +682,7 @@ fi
profman_cmdline="true"
dex2oat_cmdline="true"
vdex_cmdline="true"
+dm_cmdline="true"
mkdir_locations="${mkdir_locations} ${DEX_LOCATION}/dalvik-cache/$ISA"
strip_cmdline="true"
sync_cmdline="true"
@@ -741,6 +746,10 @@ if [ "$PREBUILD" = "y" ]; then
vdex_cmdline="${dex2oat_cmdline} ${VDEX_FILTER} --input-vdex=$DEX_LOCATION/oat/$ISA/$TEST_NAME.vdex --output-vdex=$DEX_LOCATION/oat/$ISA/$TEST_NAME.vdex"
elif [ "$TEST_VDEX" = "y" ]; then
vdex_cmdline="${dex2oat_cmdline} ${VDEX_FILTER} --input-vdex=$DEX_LOCATION/oat/$ISA/$TEST_NAME.vdex"
+ elif [ "$TEST_DM" = "y" ]; then
+ dex2oat_cmdline="${dex2oat_cmdline} --output-vdex=$DEX_LOCATION/oat/$ISA/primary.vdex"
+ dm_cmdline="zip -qj $DEX_LOCATION/oat/$ISA/$TEST_NAME.dm $DEX_LOCATION/oat/$ISA/primary.vdex"
+ vdex_cmdline="${dex2oat_cmdline} --dump-timings --dm-file=$DEX_LOCATION/oat/$ISA/$TEST_NAME.dm"
elif [ "$PROFILE" = "y" ] || [ "$RANDOM_PROFILE" = "y" ]; then
vdex_cmdline="${dex2oat_cmdline} --input-vdex=$DEX_LOCATION/oat/$ISA/$TEST_NAME.vdex --output-vdex=$DEX_LOCATION/oat/$ISA/$TEST_NAME.vdex"
fi
@@ -788,6 +797,7 @@ dalvikvm_cmdline="$INVOKE_WITH $GDB $ANDROID_ROOT/bin/$DALVIKVM \
# Remove whitespace.
dex2oat_cmdline=$(echo $dex2oat_cmdline)
dalvikvm_cmdline=$(echo $dalvikvm_cmdline)
+dm_cmdline=$(echo $dm_cmdline)
vdex_cmdline=$(echo $vdex_cmdline)
profman_cmdline=$(echo $profman_cmdline)
@@ -857,6 +867,7 @@ if [ "$HOST" = "n" ]; then
export PATH=$ANDROID_ROOT/bin:$PATH && \
$profman_cmdline && \
$dex2oat_cmdline && \
+ $dm_cmdline && \
$vdex_cmdline && \
$strip_cmdline && \
$sync_cmdline && \
@@ -933,7 +944,7 @@ else
fi
if [ "$DEV_MODE" = "y" ]; then
- echo "mkdir -p ${mkdir_locations} && $profman_cmdline && $dex2oat_cmdline && $vdex_cmdline && $strip_cmdline && $sync_cmdline && $cmdline"
+ echo "mkdir -p ${mkdir_locations} && $profman_cmdline && $dex2oat_cmdline && $dm_cmdline && $vdex_cmdline && $strip_cmdline && $sync_cmdline && $cmdline"
fi
cd $ANDROID_BUILD_TOP
@@ -949,6 +960,7 @@ else
mkdir -p ${mkdir_locations} || exit 1
$profman_cmdline || { echo "Profman failed." >&2 ; exit 2; }
$dex2oat_cmdline || { echo "Dex2oat failed." >&2 ; exit 2; }
+ $dm_cmdline || { echo "Dex2oat failed." >&2 ; exit 2; }
$vdex_cmdline || { echo "Dex2oat failed." >&2 ; exit 2; }
$strip_cmdline || { echo "Strip failed." >&2 ; exit 3; }
$sync_cmdline || { echo "Sync failed." >&2 ; exit 4; }
diff --git a/test/run-test b/test/run-test
index a453f22e29..6bcb9cdabb 100755
--- a/test/run-test
+++ b/test/run-test
@@ -427,6 +427,9 @@ while true; do
elif [ "x$1" = "x--vdex" ]; then
run_args="${run_args} --vdex"
shift
+ elif [ "x$1" = "x--dm" ]; then
+ run_args="${run_args} --dm"
+ shift
elif [ "x$1" = "x--vdex-filter" ]; then
shift
filter=$1
diff --git a/tools/hiddenapi/Android.bp b/tools/hiddenapi/Android.bp
index a78bc43aa4..f9824f1fa3 100644
--- a/tools/hiddenapi/Android.bp
+++ b/tools/hiddenapi/Android.bp
@@ -30,6 +30,7 @@ cc_defaults {
},
shared_libs: [
+ "libdexfile",
"libbase",
],
}
diff --git a/tools/public.libraries.buildbot.txt b/tools/public.libraries.buildbot.txt
index 4b01796a0a..734fd1e50b 100644
--- a/tools/public.libraries.buildbot.txt
+++ b/tools/public.libraries.buildbot.txt
@@ -1,5 +1,6 @@
libart.so
libartd.so
+libdexfile.so
libbacktrace.so
libc.so
libc++.so
diff --git a/tools/run-jdwp-tests.sh b/tools/run-jdwp-tests.sh
index 2cf614d795..b512612175 100755
--- a/tools/run-jdwp-tests.sh
+++ b/tools/run-jdwp-tests.sh
@@ -286,6 +286,10 @@ fi
if [[ $mode != "ri" ]]; then
toolchain_args="--toolchain d8 --language CUR"
+ if [[ "x$with_jdwp_path" == "x" ]]; then
+ # Need to enable the internal jdwp implementation.
+ art_debugee="${art_debugee} -XjdwpProvider:internal"
+ fi
else
toolchain_args="--toolchain javac --language CUR"
fi