Merge "Inliner: make sure the returned value is in the outer graph."
diff --git a/build/Android.common_build.mk b/build/Android.common_build.mk
index b3d246c..cd9d18d 100644
--- a/build/Android.common_build.mk
+++ b/build/Android.common_build.mk
@@ -114,7 +114,8 @@
else
ART_TARGET_CLANG := false
endif
-ART_TARGET_CLANG_arm :=
+# b/25130937
+ART_TARGET_CLANG_arm := false
ART_TARGET_CLANG_arm64 :=
ART_TARGET_CLANG_mips :=
ART_TARGET_CLANG_mips64 :=
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk
index 1b54a51..6295e15 100644
--- a/build/Android.gtest.mk
+++ b/build/Android.gtest.mk
@@ -204,7 +204,6 @@
runtime/interpreter/safe_math_test.cc \
runtime/interpreter/unstarted_runtime_test.cc \
runtime/java_vm_ext_test.cc \
- runtime/jit/jit_code_cache_test.cc \
runtime/lambda/closure_test.cc \
runtime/lambda/shorty_field_type_test.cc \
runtime/leb128_test.cc \
diff --git a/compiler/common_compiler_test.cc b/compiler/common_compiler_test.cc
index 1727657..58a2f96 100644
--- a/compiler/common_compiler_test.cc
+++ b/compiler/common_compiler_test.cc
@@ -32,6 +32,7 @@
#include "mirror/class-inl.h"
#include "mirror/dex_cache.h"
#include "mirror/object-inl.h"
+#include "oat_quick_method_header.h"
#include "scoped_thread_state_change.h"
#include "thread-inl.h"
#include "utils.h"
diff --git a/compiler/dex/local_value_numbering_test.cc b/compiler/dex/local_value_numbering_test.cc
index bd00690..f98969e 100644
--- a/compiler/dex/local_value_numbering_test.cc
+++ b/compiler/dex/local_value_numbering_test.cc
@@ -797,6 +797,10 @@
}
}
+static constexpr int64_t shift_minus_1(size_t by) {
+ return static_cast<int64_t>(static_cast<uint64_t>(INT64_C(-1)) << by);
+}
+
TEST_F(LocalValueNumberingTest, ConstWide) {
static const MIRDef mirs[] = {
// Core reg constants.
@@ -804,45 +808,45 @@
DEF_CONST(Instruction::CONST_WIDE_16, 2u, 1),
DEF_CONST(Instruction::CONST_WIDE_16, 4u, -1),
DEF_CONST(Instruction::CONST_WIDE_32, 6u, 1 << 16),
- DEF_CONST(Instruction::CONST_WIDE_32, 8u, -1 << 16),
+ DEF_CONST(Instruction::CONST_WIDE_32, 8u, shift_minus_1(16)),
DEF_CONST(Instruction::CONST_WIDE_32, 10u, (1 << 16) + 1),
DEF_CONST(Instruction::CONST_WIDE_32, 12u, (1 << 16) - 1),
DEF_CONST(Instruction::CONST_WIDE_32, 14u, -(1 << 16) + 1),
DEF_CONST(Instruction::CONST_WIDE_32, 16u, -(1 << 16) - 1),
DEF_CONST(Instruction::CONST_WIDE, 18u, INT64_C(1) << 32),
- DEF_CONST(Instruction::CONST_WIDE, 20u, INT64_C(-1) << 32),
+ DEF_CONST(Instruction::CONST_WIDE, 20u, shift_minus_1(32)),
DEF_CONST(Instruction::CONST_WIDE, 22u, (INT64_C(1) << 32) + 1),
DEF_CONST(Instruction::CONST_WIDE, 24u, (INT64_C(1) << 32) - 1),
- DEF_CONST(Instruction::CONST_WIDE, 26u, (INT64_C(-1) << 32) + 1),
- DEF_CONST(Instruction::CONST_WIDE, 28u, (INT64_C(-1) << 32) - 1),
+ DEF_CONST(Instruction::CONST_WIDE, 26u, shift_minus_1(32) + 1),
+ DEF_CONST(Instruction::CONST_WIDE, 28u, shift_minus_1(32) - 1),
DEF_CONST(Instruction::CONST_WIDE_HIGH16, 30u, 1), // Effectively 1 << 48.
DEF_CONST(Instruction::CONST_WIDE_HIGH16, 32u, 0xffff), // Effectively -1 << 48.
DEF_CONST(Instruction::CONST_WIDE, 34u, (INT64_C(1) << 48) + 1),
DEF_CONST(Instruction::CONST_WIDE, 36u, (INT64_C(1) << 48) - 1),
- DEF_CONST(Instruction::CONST_WIDE, 38u, (INT64_C(-1) << 48) + 1),
- DEF_CONST(Instruction::CONST_WIDE, 40u, (INT64_C(-1) << 48) - 1),
+ DEF_CONST(Instruction::CONST_WIDE, 38u, shift_minus_1(48) + 1),
+ DEF_CONST(Instruction::CONST_WIDE, 40u, shift_minus_1(48) - 1),
// FP reg constants.
DEF_CONST(Instruction::CONST_WIDE_16, 42u, 0),
DEF_CONST(Instruction::CONST_WIDE_16, 44u, 1),
DEF_CONST(Instruction::CONST_WIDE_16, 46u, -1),
DEF_CONST(Instruction::CONST_WIDE_32, 48u, 1 << 16),
- DEF_CONST(Instruction::CONST_WIDE_32, 50u, -1 << 16),
+ DEF_CONST(Instruction::CONST_WIDE_32, 50u, shift_minus_1(16)),
DEF_CONST(Instruction::CONST_WIDE_32, 52u, (1 << 16) + 1),
DEF_CONST(Instruction::CONST_WIDE_32, 54u, (1 << 16) - 1),
DEF_CONST(Instruction::CONST_WIDE_32, 56u, -(1 << 16) + 1),
DEF_CONST(Instruction::CONST_WIDE_32, 58u, -(1 << 16) - 1),
DEF_CONST(Instruction::CONST_WIDE, 60u, INT64_C(1) << 32),
- DEF_CONST(Instruction::CONST_WIDE, 62u, INT64_C(-1) << 32),
+ DEF_CONST(Instruction::CONST_WIDE, 62u, shift_minus_1(32)),
DEF_CONST(Instruction::CONST_WIDE, 64u, (INT64_C(1) << 32) + 1),
DEF_CONST(Instruction::CONST_WIDE, 66u, (INT64_C(1) << 32) - 1),
- DEF_CONST(Instruction::CONST_WIDE, 68u, (INT64_C(-1) << 32) + 1),
- DEF_CONST(Instruction::CONST_WIDE, 70u, (INT64_C(-1) << 32) - 1),
+ DEF_CONST(Instruction::CONST_WIDE, 68u, shift_minus_1(32) + 1),
+ DEF_CONST(Instruction::CONST_WIDE, 70u, shift_minus_1(32) - 1),
DEF_CONST(Instruction::CONST_WIDE_HIGH16, 72u, 1), // Effectively 1 << 48.
DEF_CONST(Instruction::CONST_WIDE_HIGH16, 74u, 0xffff), // Effectively -1 << 48.
DEF_CONST(Instruction::CONST_WIDE, 76u, (INT64_C(1) << 48) + 1),
DEF_CONST(Instruction::CONST_WIDE, 78u, (INT64_C(1) << 48) - 1),
- DEF_CONST(Instruction::CONST_WIDE, 80u, (INT64_C(-1) << 48) + 1),
- DEF_CONST(Instruction::CONST_WIDE, 82u, (INT64_C(-1) << 48) - 1),
+ DEF_CONST(Instruction::CONST_WIDE, 80u, shift_minus_1(48) + 1),
+ DEF_CONST(Instruction::CONST_WIDE, 82u, shift_minus_1(48) - 1),
};
PrepareMIRs(mirs);
@@ -868,7 +872,7 @@
DEF_CONST(Instruction::CONST_4, 1u, 1),
DEF_CONST(Instruction::CONST_4, 2u, -1),
DEF_CONST(Instruction::CONST_16, 3u, 1 << 4),
- DEF_CONST(Instruction::CONST_16, 4u, -1 << 4),
+ DEF_CONST(Instruction::CONST_16, 4u, shift_minus_1(4)),
DEF_CONST(Instruction::CONST_16, 5u, (1 << 4) + 1),
DEF_CONST(Instruction::CONST_16, 6u, (1 << 4) - 1),
DEF_CONST(Instruction::CONST_16, 7u, -(1 << 4) + 1),
@@ -877,14 +881,14 @@
DEF_CONST(Instruction::CONST_HIGH16, 10u, 0xffff), // Effectively -1 << 16.
DEF_CONST(Instruction::CONST, 11u, (1 << 16) + 1),
DEF_CONST(Instruction::CONST, 12u, (1 << 16) - 1),
- DEF_CONST(Instruction::CONST, 13u, (-1 << 16) + 1),
- DEF_CONST(Instruction::CONST, 14u, (-1 << 16) - 1),
+ DEF_CONST(Instruction::CONST, 13u, shift_minus_1(16) + 1),
+ DEF_CONST(Instruction::CONST, 14u, shift_minus_1(16) - 1),
// FP reg constants.
DEF_CONST(Instruction::CONST_4, 15u, 0),
DEF_CONST(Instruction::CONST_4, 16u, 1),
DEF_CONST(Instruction::CONST_4, 17u, -1),
DEF_CONST(Instruction::CONST_16, 18u, 1 << 4),
- DEF_CONST(Instruction::CONST_16, 19u, -1 << 4),
+ DEF_CONST(Instruction::CONST_16, 19u, shift_minus_1(4)),
DEF_CONST(Instruction::CONST_16, 20u, (1 << 4) + 1),
DEF_CONST(Instruction::CONST_16, 21u, (1 << 4) - 1),
DEF_CONST(Instruction::CONST_16, 22u, -(1 << 4) + 1),
@@ -893,8 +897,8 @@
DEF_CONST(Instruction::CONST_HIGH16, 25u, 0xffff), // Effectively -1 << 16.
DEF_CONST(Instruction::CONST, 26u, (1 << 16) + 1),
DEF_CONST(Instruction::CONST, 27u, (1 << 16) - 1),
- DEF_CONST(Instruction::CONST, 28u, (-1 << 16) + 1),
- DEF_CONST(Instruction::CONST, 29u, (-1 << 16) - 1),
+ DEF_CONST(Instruction::CONST, 28u, shift_minus_1(16) + 1),
+ DEF_CONST(Instruction::CONST, 29u, shift_minus_1(16) - 1),
// null reference constant.
DEF_CONST(Instruction::CONST_4, 30u, 0),
};
diff --git a/compiler/dex/quick/x86/assemble_x86.cc b/compiler/dex/quick/x86/assemble_x86.cc
index 64becb9..e5d3841 100644
--- a/compiler/dex/quick/x86/assemble_x86.cc
+++ b/compiler/dex/quick/x86/assemble_x86.cc
@@ -21,6 +21,7 @@
#include "dex/compiler_ir.h"
#include "dex/quick/mir_to_lir.h"
#include "oat.h"
+#include "oat_quick_method_header.h"
#include "utils.h"
#include "x86_lir.h"
diff --git a/compiler/dex/quick/x86/target_x86.cc b/compiler/dex/quick/x86/target_x86.cc
index 25fb886..75f3fef 100755
--- a/compiler/dex/quick/x86/target_x86.cc
+++ b/compiler/dex/quick/x86/target_x86.cc
@@ -31,6 +31,7 @@
#include "mirror/array-inl.h"
#include "mirror/string.h"
#include "oat.h"
+#include "oat_quick_method_header.h"
#include "x86_lir.h"
namespace art {
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index 8324bf3..b956584 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -594,7 +594,7 @@
}
} else if ((access_flags & kAccAbstract) != 0) {
// Abstract methods don't have code.
- } else {
+ } else if (Runtime::Current()->IsAotCompiler()) {
const VerifiedMethod* verified_method =
driver->GetVerificationResults()->GetVerifiedMethod(method_ref);
bool compile = compilation_enabled &&
@@ -633,6 +633,13 @@
? dex_to_dex_compilation_level
: optimizer::DexToDexCompilationLevel::kRequired);
}
+ } else {
+ // This is for the JIT compiler, which has already ensured the class is verified.
+ // We can go straight to compiling.
+ DCHECK(Runtime::Current()->UseJit());
+ compiled_method = driver->GetCompiler()->Compile(code_item, access_flags, invoke_type,
+ class_def_idx, method_idx, class_loader,
+ dex_file, dex_cache);
}
if (kTimeCompileMethod) {
uint64_t duration_ns = NanoTime() - start_ns;
diff --git a/compiler/jit/jit_compiler.cc b/compiler/jit/jit_compiler.cc
index a45df95..3d1b42f 100644
--- a/compiler/jit/jit_compiler.cc
+++ b/compiler/jit/jit_compiler.cc
@@ -30,6 +30,7 @@
#include "jit/jit.h"
#include "jit/jit_code_cache.h"
#include "oat_file-inl.h"
+#include "oat_quick_method_header.h"
#include "object_lock.h"
#include "thread_list.h"
#include "verifier/method_verifier-inl.h"
@@ -157,61 +158,66 @@
StackHandleScope<2> hs(self);
self->AssertNoPendingException();
Runtime* runtime = Runtime::Current();
+
+ // Check if the method is already compiled.
if (runtime->GetJit()->GetCodeCache()->ContainsMethod(method)) {
VLOG(jit) << "Already compiled " << PrettyMethod(method);
- return true; // Already compiled
+ return true;
}
+
+ // Don't compile the method if we are supposed to be deoptimized.
+ if (runtime->GetInstrumentation()->AreAllMethodsDeoptimized()) {
+ return false;
+ }
+
+ // Ensure the class is initialized.
Handle<mirror::Class> h_class(hs.NewHandle(method->GetDeclaringClass()));
- {
- TimingLogger::ScopedTiming t2("Initializing", &logger);
- if (!runtime->GetClassLinker()->EnsureInitialized(self, h_class, true, true)) {
- VLOG(jit) << "JIT failed to initialize " << PrettyMethod(method);
- return false;
- }
+ if (!runtime->GetClassLinker()->EnsureInitialized(self, h_class, true, true)) {
+ VLOG(jit) << "JIT failed to initialize " << PrettyMethod(method);
+ return false;
}
- const DexFile* dex_file = h_class->GetDexCache()->GetDexFile();
- MethodReference method_ref(dex_file, method->GetDexMethodIndex());
- // Only verify if we don't already have verification results.
- if (verification_results_->GetVerifiedMethod(method_ref) == nullptr) {
- TimingLogger::ScopedTiming t2("Verifying", &logger);
- std::string error;
- if (verifier::MethodVerifier::VerifyMethod(method, true, &error) ==
- verifier::MethodVerifier::kHardFailure) {
- VLOG(jit) << "Not compile method " << PrettyMethod(method)
- << " due to verification failure " << error;
- return false;
- }
- }
+
+ // Do the compilation.
CompiledMethod* compiled_method = nullptr;
{
TimingLogger::ScopedTiming t2("Compiling", &logger);
compiled_method = compiler_driver_->CompileArtMethod(self, method);
}
+
+ // Trim maps to reduce memory usage.
+ // TODO: measure how much this increases compile time.
{
TimingLogger::ScopedTiming t2("TrimMaps", &logger);
- // Trim maps to reduce memory usage, TODO: measure how much this increases compile time.
runtime->GetArenaPool()->TrimMaps();
}
+
+ // Check if we failed compiling.
if (compiled_method == nullptr) {
return false;
}
+
total_time_ += NanoTime() - start_time;
- // Don't add the method if we are supposed to be deoptimized.
bool result = false;
- if (!runtime->GetInstrumentation()->AreAllMethodsDeoptimized()) {
- const void* code = runtime->GetClassLinker()->GetOatMethodQuickCodeFor(method);
- if (code != nullptr) {
- // Already have some compiled code, just use this instead of linking.
- // TODO: Fix recompilation.
- method->SetEntryPointFromQuickCompiledCode(code);
+ const void* code = runtime->GetClassLinker()->GetOatMethodQuickCodeFor(method);
+
+ if (code != nullptr) {
+ // Already have some compiled code, just use this instead of linking.
+ // TODO: Fix recompilation.
+ method->SetEntryPointFromQuickCompiledCode(code);
+ result = true;
+ } else {
+ TimingLogger::ScopedTiming t2("LinkCode", &logger);
+ OatFile::OatMethod oat_method(nullptr, 0);
+ if (AddToCodeCache(method, compiled_method, &oat_method)) {
+ oat_method.LinkMethod(method);
+ CHECK(runtime->GetJit()->GetCodeCache()->ContainsMethod(method)) << PrettyMethod(method);
result = true;
- } else {
- TimingLogger::ScopedTiming t2("MakeExecutable", &logger);
- result = MakeExecutable(compiled_method, method);
}
}
+
// Remove the compiled method to save memory.
- compiler_driver_->RemoveCompiledMethod(method_ref);
+ compiler_driver_->RemoveCompiledMethod(
+ MethodReference(h_class->GetDexCache()->GetDexFile(), method->GetDexMethodIndex()));
runtime->GetJit()->AddTimingLogger(logger);
return result;
}
@@ -220,41 +226,8 @@
return callbacks_.get();
}
-uint8_t* JitCompiler::WriteMethodHeaderAndCode(const CompiledMethod* compiled_method,
- uint8_t* reserve_begin, uint8_t* reserve_end,
- const uint8_t* mapping_table,
- const uint8_t* vmap_table,
- const uint8_t* gc_map) {
- reserve_begin += sizeof(OatQuickMethodHeader);
- reserve_begin = reinterpret_cast<uint8_t*>(
- compiled_method->AlignCode(reinterpret_cast<uintptr_t>(reserve_begin)));
- const auto* quick_code = compiled_method->GetQuickCode();
- CHECK_LE(reserve_begin, reserve_end);
- CHECK_LE(quick_code->size(), static_cast<size_t>(reserve_end - reserve_begin));
- auto* code_ptr = reserve_begin;
- OatQuickMethodHeader* method_header = reinterpret_cast<OatQuickMethodHeader*>(code_ptr) - 1;
- // Construct the header last.
- const auto frame_size_in_bytes = compiled_method->GetFrameSizeInBytes();
- const auto core_spill_mask = compiled_method->GetCoreSpillMask();
- const auto fp_spill_mask = compiled_method->GetFpSpillMask();
- const auto code_size = quick_code->size();
- CHECK_NE(code_size, 0U);
- std::copy(quick_code->data(), quick_code->data() + code_size, code_ptr);
- // After we are done writing we need to update the method header.
- // Write out the method header last.
- method_header = new(method_header) OatQuickMethodHeader(
- (mapping_table == nullptr) ? 0 : code_ptr - mapping_table,
- (vmap_table == nullptr) ? 0 : code_ptr - vmap_table,
- (gc_map == nullptr) ? 0 : code_ptr - gc_map,
- frame_size_in_bytes,
- core_spill_mask,
- fp_spill_mask,
- code_size);
- // Return the code ptr.
- return code_ptr;
-}
-
-bool JitCompiler::AddToCodeCache(ArtMethod* method, const CompiledMethod* compiled_method,
+bool JitCompiler::AddToCodeCache(ArtMethod* method,
+ const CompiledMethod* compiled_method,
OatFile::OatMethod* out_method) {
Runtime* runtime = Runtime::Current();
JitCodeCache* const code_cache = runtime->GetJit()->GetCodeCache();
@@ -264,7 +237,6 @@
}
const auto code_size = quick_code->size();
Thread* const self = Thread::Current();
- const uint8_t* base = code_cache->CodeCachePtr();
auto* const mapping_table = compiled_method->GetMappingTable();
auto* const vmap_table = compiled_method->GetVmapTable();
auto* const gc_map = compiled_method->GetGcMap();
@@ -297,45 +269,35 @@
}
}
- // Don't touch this until you protect / unprotect the code.
- const size_t reserve_size = sizeof(OatQuickMethodHeader) + quick_code->size() + 32;
- uint8_t* const code_reserve = code_cache->ReserveCode(self, reserve_size);
- if (code_reserve == nullptr) {
+ uint8_t* const code = code_cache->CommitCode(self,
+ mapping_table_ptr,
+ vmap_table_ptr,
+ gc_map_ptr,
+ compiled_method->GetFrameSizeInBytes(),
+ compiled_method->GetCoreSpillMask(),
+ compiled_method->GetFpSpillMask(),
+ compiled_method->GetQuickCode()->data(),
+ compiled_method->GetQuickCode()->size());
+
+ if (code == nullptr) {
return false;
}
- auto* code_ptr = WriteMethodHeaderAndCode(
- compiled_method, code_reserve, code_reserve + reserve_size, mapping_table_ptr,
- vmap_table_ptr, gc_map_ptr);
-
- __builtin___clear_cache(reinterpret_cast<char*>(code_ptr),
- reinterpret_cast<char*>(code_ptr + quick_code->size()));
const size_t thumb_offset = compiled_method->CodeDelta();
- const uint32_t code_offset = code_ptr - base + thumb_offset;
- *out_method = OatFile::OatMethod(base, code_offset);
+ const uint32_t code_offset = sizeof(OatQuickMethodHeader) + thumb_offset;
+ *out_method = OatFile::OatMethod(code, code_offset);
DCHECK_EQ(out_method->GetGcMap(), gc_map_ptr);
DCHECK_EQ(out_method->GetMappingTable(), mapping_table_ptr);
DCHECK_EQ(out_method->GetVmapTable(), vmap_table_ptr);
DCHECK_EQ(out_method->GetFrameSizeInBytes(), compiled_method->GetFrameSizeInBytes());
DCHECK_EQ(out_method->GetCoreSpillMask(), compiled_method->GetCoreSpillMask());
DCHECK_EQ(out_method->GetFpSpillMask(), compiled_method->GetFpSpillMask());
- VLOG(jit) << "JIT added " << PrettyMethod(method) << "@" << method << " ccache_size="
- << PrettySize(code_cache->CodeCacheSize()) << ": " << reinterpret_cast<void*>(code_ptr)
- << "," << reinterpret_cast<void*>(code_ptr + code_size);
- return true;
-}
-
-bool JitCompiler::MakeExecutable(CompiledMethod* compiled_method, ArtMethod* method) {
- CHECK(method != nullptr);
- CHECK(compiled_method != nullptr);
- OatFile::OatMethod oat_method(nullptr, 0);
- if (!AddToCodeCache(method, compiled_method, &oat_method)) {
- return false;
- }
- // TODO: Flush instruction cache.
- oat_method.LinkMethod(method);
- CHECK(Runtime::Current()->GetJit()->GetCodeCache()->ContainsMethod(method))
- << PrettyMethod(method);
+ VLOG(jit)
+ << "JIT added "
+ << PrettyMethod(method) << "@" << method
+ << " ccache_size=" << PrettySize(code_cache->CodeCacheSize()) << ": "
+ << reinterpret_cast<void*>(code + code_offset)
+ << "," << reinterpret_cast<void*>(code + code_offset + code_size);
return true;
}
diff --git a/compiler/jit/jit_compiler.h b/compiler/jit/jit_compiler.h
index ef68caa..757f3f3 100644
--- a/compiler/jit/jit_compiler.h
+++ b/compiler/jit/jit_compiler.h
@@ -39,10 +39,6 @@
virtual ~JitCompiler();
bool CompileMethod(Thread* self, ArtMethod* method)
SHARED_REQUIRES(Locks::mutator_lock_);
- // This is in the compiler since the runtime doesn't have access to the compiled method
- // structures.
- bool AddToCodeCache(ArtMethod* method, const CompiledMethod* compiled_method,
- OatFile::OatMethod* out_method) SHARED_REQUIRES(Locks::mutator_lock_);
CompilerCallbacks* GetCompilerCallbacks() const;
size_t GetTotalCompileTime() const {
return total_time_;
@@ -58,12 +54,13 @@
std::unique_ptr<CompilerDriver> compiler_driver_;
std::unique_ptr<const InstructionSetFeatures> instruction_set_features_;
- explicit JitCompiler();
- uint8_t* WriteMethodHeaderAndCode(
- const CompiledMethod* compiled_method, uint8_t* reserve_begin, uint8_t* reserve_end,
- const uint8_t* mapping_table, const uint8_t* vmap_table, const uint8_t* gc_map);
- bool MakeExecutable(CompiledMethod* compiled_method, ArtMethod* method)
- SHARED_REQUIRES(Locks::mutator_lock_);
+ JitCompiler();
+
+ // This is in the compiler since the runtime doesn't have access to the compiled method
+ // structures.
+ bool AddToCodeCache(ArtMethod* method,
+ const CompiledMethod* compiled_method,
+ OatFile::OatMethod* out_method) SHARED_REQUIRES(Locks::mutator_lock_);
DISALLOW_COPY_AND_ASSIGN(JitCompiler);
};
diff --git a/compiler/linker/arm/relative_patcher_arm_base.cc b/compiler/linker/arm/relative_patcher_arm_base.cc
index ceace82..cb9ea38 100644
--- a/compiler/linker/arm/relative_patcher_arm_base.cc
+++ b/compiler/linker/arm/relative_patcher_arm_base.cc
@@ -18,6 +18,7 @@
#include "compiled_method.h"
#include "oat.h"
+#include "oat_quick_method_header.h"
#include "output_stream.h"
namespace art {
diff --git a/compiler/linker/arm/relative_patcher_thumb2_test.cc b/compiler/linker/arm/relative_patcher_thumb2_test.cc
index 13f67e6..5515313 100644
--- a/compiler/linker/arm/relative_patcher_thumb2_test.cc
+++ b/compiler/linker/arm/relative_patcher_thumb2_test.cc
@@ -16,6 +16,7 @@
#include "linker/relative_patcher_test.h"
#include "linker/arm/relative_patcher_thumb2.h"
+#include "oat_quick_method_header.h"
namespace art {
namespace linker {
diff --git a/compiler/linker/arm64/relative_patcher_arm64.cc b/compiler/linker/arm64/relative_patcher_arm64.cc
index 6b9c530..6f234a8 100644
--- a/compiler/linker/arm64/relative_patcher_arm64.cc
+++ b/compiler/linker/arm64/relative_patcher_arm64.cc
@@ -22,6 +22,7 @@
#include "driver/compiler_driver.h"
#include "utils/arm64/assembler_arm64.h"
#include "oat.h"
+#include "oat_quick_method_header.h"
#include "output_stream.h"
namespace art {
diff --git a/compiler/linker/arm64/relative_patcher_arm64_test.cc b/compiler/linker/arm64/relative_patcher_arm64_test.cc
index b3af4c6..857d584 100644
--- a/compiler/linker/arm64/relative_patcher_arm64_test.cc
+++ b/compiler/linker/arm64/relative_patcher_arm64_test.cc
@@ -16,6 +16,7 @@
#include "linker/relative_patcher_test.h"
#include "linker/arm64/relative_patcher_arm64.h"
+#include "oat_quick_method_header.h"
namespace art {
namespace linker {
diff --git a/compiler/linker/relative_patcher_test.h b/compiler/linker/relative_patcher_test.h
index 31d1bce..e357662 100644
--- a/compiler/linker/relative_patcher_test.h
+++ b/compiler/linker/relative_patcher_test.h
@@ -30,6 +30,7 @@
#include "linker/relative_patcher.h"
#include "method_reference.h"
#include "oat.h"
+#include "oat_quick_method_header.h"
#include "utils/array_ref.h"
#include "vector_output_stream.h"
diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc
index a78a5b3..640698b 100644
--- a/compiler/oat_writer.cc
+++ b/compiler/oat_writer.cc
@@ -39,6 +39,7 @@
#include "mirror/class_loader.h"
#include "mirror/dex_cache-inl.h"
#include "mirror/object-inl.h"
+#include "oat_quick_method_header.h"
#include "os.h"
#include "output_stream.h"
#include "safe_map.h"
diff --git a/compiler/oat_writer.h b/compiler/oat_writer.h
index a82d09e..d6cb65b 100644
--- a/compiler/oat_writer.h
+++ b/compiler/oat_writer.h
@@ -281,7 +281,7 @@
// Offsets of the dex cache arrays for each app dex file. For the
// boot image, this information is provided by the ImageWriter.
- SafeMap<const DexFile*, size_t> dex_cache_arrays_offsets_;
+ SafeMap<const DexFile*, size_t> dex_cache_arrays_offsets_; // DexFiles not owned.
// Offset of the oat data from the start of the mmapped region of the elf file.
size_t oat_data_offset_;
diff --git a/compiler/optimizing/bounds_check_elimination_test.cc b/compiler/optimizing/bounds_check_elimination_test.cc
index ce6dc75..c9afdf2 100644
--- a/compiler/optimizing/bounds_check_elimination_test.cc
+++ b/compiler/optimizing/bounds_check_elimination_test.cc
@@ -71,9 +71,9 @@
graph_->AddBlock(entry);
graph_->SetEntryBlock(entry);
HInstruction* parameter1 = new (&allocator_)
- HParameterValue(0, Primitive::kPrimNot); // array
+ HParameterValue(graph_->GetDexFile(), 0, 0, Primitive::kPrimNot); // array
HInstruction* parameter2 = new (&allocator_)
- HParameterValue(0, Primitive::kPrimInt); // i
+ HParameterValue(graph_->GetDexFile(), 0, 0, Primitive::kPrimInt); // i
entry->AddInstruction(parameter1);
entry->AddInstruction(parameter2);
@@ -168,9 +168,9 @@
graph_->AddBlock(entry);
graph_->SetEntryBlock(entry);
HInstruction* parameter1 = new (&allocator_)
- HParameterValue(0, Primitive::kPrimNot); // array
+ HParameterValue(graph_->GetDexFile(), 0, 0, Primitive::kPrimNot); // array
HInstruction* parameter2 = new (&allocator_)
- HParameterValue(0, Primitive::kPrimInt); // i
+ HParameterValue(graph_->GetDexFile(), 0, 0, Primitive::kPrimInt); // i
entry->AddInstruction(parameter1);
entry->AddInstruction(parameter2);
@@ -232,9 +232,9 @@
graph_->AddBlock(entry);
graph_->SetEntryBlock(entry);
HInstruction* parameter1 = new (&allocator_)
- HParameterValue(0, Primitive::kPrimNot); // array
+ HParameterValue(graph_->GetDexFile(), 0, 0, Primitive::kPrimNot); // array
HInstruction* parameter2 = new (&allocator_)
- HParameterValue(0, Primitive::kPrimInt); // i
+ HParameterValue(graph_->GetDexFile(), 0, 0, Primitive::kPrimInt); // i
entry->AddInstruction(parameter1);
entry->AddInstruction(parameter2);
@@ -295,7 +295,8 @@
HBasicBlock* entry = new (&allocator_) HBasicBlock(graph_);
graph_->AddBlock(entry);
graph_->SetEntryBlock(entry);
- HInstruction* parameter = new (&allocator_) HParameterValue(0, Primitive::kPrimNot);
+ HInstruction* parameter = new (&allocator_) HParameterValue(
+ graph_->GetDexFile(), 0, 0, Primitive::kPrimNot);
entry->AddInstruction(parameter);
HInstruction* constant_5 = graph_->GetIntConstant(5);
@@ -363,7 +364,8 @@
HBasicBlock* entry = new (allocator) HBasicBlock(graph);
graph->AddBlock(entry);
graph->SetEntryBlock(entry);
- HInstruction* parameter = new (allocator) HParameterValue(0, Primitive::kPrimNot);
+ HInstruction* parameter = new (allocator) HParameterValue(
+ graph->GetDexFile(), 0, 0, Primitive::kPrimNot);
entry->AddInstruction(parameter);
HInstruction* constant_initial = graph->GetIntConstant(initial);
@@ -477,7 +479,8 @@
HBasicBlock* entry = new (allocator) HBasicBlock(graph);
graph->AddBlock(entry);
graph->SetEntryBlock(entry);
- HInstruction* parameter = new (allocator) HParameterValue(0, Primitive::kPrimNot);
+ HInstruction* parameter = new (allocator) HParameterValue(
+ graph->GetDexFile(), 0, 0, Primitive::kPrimNot);
entry->AddInstruction(parameter);
HInstruction* constant_initial = graph->GetIntConstant(initial);
@@ -689,7 +692,8 @@
HBasicBlock* entry = new (allocator) HBasicBlock(graph);
graph->AddBlock(entry);
graph->SetEntryBlock(entry);
- HInstruction* parameter = new (allocator) HParameterValue(0, Primitive::kPrimNot);
+ HInstruction* parameter = new (allocator) HParameterValue(
+ graph->GetDexFile(), 0, 0, Primitive::kPrimNot);
entry->AddInstruction(parameter);
HInstruction* constant_initial = graph->GetIntConstant(initial);
@@ -791,7 +795,8 @@
HBasicBlock* entry = new (&allocator_) HBasicBlock(graph_);
graph_->AddBlock(entry);
graph_->SetEntryBlock(entry);
- HInstruction* parameter = new (&allocator_) HParameterValue(0, Primitive::kPrimNot);
+ HInstruction* parameter = new (&allocator_) HParameterValue(
+ graph_->GetDexFile(), 0, 0, Primitive::kPrimNot);
entry->AddInstruction(parameter);
HInstruction* constant_0 = graph_->GetIntConstant(0);
diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc
index 21540e8..5dd5be3 100644
--- a/compiler/optimizing/builder.cc
+++ b/compiler/optimizing/builder.cc
@@ -159,9 +159,13 @@
int locals_index = locals_.size() - number_of_parameters;
int parameter_index = 0;
+ const DexFile::MethodId& referrer_method_id =
+ dex_file_->GetMethodId(dex_compilation_unit_->GetDexMethodIndex());
if (!dex_compilation_unit_->IsStatic()) {
// Add the implicit 'this' argument, not expressed in the signature.
- HParameterValue* parameter = new (arena_) HParameterValue(parameter_index++,
+ HParameterValue* parameter = new (arena_) HParameterValue(*dex_file_,
+ referrer_method_id.class_idx_,
+ parameter_index++,
Primitive::kPrimNot,
true);
entry_block_->AddInstruction(parameter);
@@ -170,11 +174,16 @@
number_of_parameters--;
}
- uint32_t pos = 1;
- for (int i = 0; i < number_of_parameters; i++) {
- HParameterValue* parameter = new (arena_) HParameterValue(parameter_index++,
- Primitive::GetType(shorty[pos++]),
- false);
+ const DexFile::ProtoId& proto = dex_file_->GetMethodPrototype(referrer_method_id);
+ const DexFile::TypeList* arg_types = dex_file_->GetProtoParameters(proto);
+ for (int i = 0, shorty_pos = 1; i < number_of_parameters; i++) {
+ HParameterValue* parameter = new (arena_) HParameterValue(
+ *dex_file_,
+ arg_types->GetTypeItem(shorty_pos - 1).type_idx_,
+ parameter_index++,
+ Primitive::GetType(shorty[shorty_pos]),
+ false);
+ ++shorty_pos;
entry_block_->AddInstruction(parameter);
HLocal* local = GetLocalAt(locals_index++);
// Store the parameter value in the local that the dex code will use
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc
index 3e6cad8..92a5878 100644
--- a/compiler/optimizing/code_generator_arm.cc
+++ b/compiler/optimizing/code_generator_arm.cc
@@ -1376,8 +1376,7 @@
LocationSummary* locations = new (GetGraph()->GetArena())
LocationSummary(deoptimize, LocationSummary::kCallOnSlowPath);
HInstruction* cond = deoptimize->InputAt(0);
- DCHECK(cond->IsCondition());
- if (cond->AsCondition()->NeedsMaterialization()) {
+ if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) {
locations->SetInAt(0, Location::RequiresRegister());
}
}
diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc
index ffb9b79..f68b11b 100644
--- a/compiler/optimizing/code_generator_arm64.cc
+++ b/compiler/optimizing/code_generator_arm64.cc
@@ -2353,8 +2353,7 @@
LocationSummary* locations = new (GetGraph()->GetArena())
LocationSummary(deoptimize, LocationSummary::kCallOnSlowPath);
HInstruction* cond = deoptimize->InputAt(0);
- DCHECK(cond->IsCondition());
- if (cond->AsCondition()->NeedsMaterialization()) {
+ if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) {
locations->SetInAt(0, Location::RequiresRegister());
}
}
diff --git a/compiler/optimizing/code_generator_mips64.cc b/compiler/optimizing/code_generator_mips64.cc
index eb20291..f561c97 100644
--- a/compiler/optimizing/code_generator_mips64.cc
+++ b/compiler/optimizing/code_generator_mips64.cc
@@ -2223,8 +2223,7 @@
LocationSummary* locations = new (GetGraph()->GetArena())
LocationSummary(deoptimize, LocationSummary::kCallOnSlowPath);
HInstruction* cond = deoptimize->InputAt(0);
- DCHECK(cond->IsCondition());
- if (cond->AsCondition()->NeedsMaterialization()) {
+ if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) {
locations->SetInAt(0, Location::RequiresRegister());
}
}
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index 2aea859..963eec2 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -1306,8 +1306,7 @@
LocationSummary* locations = new (GetGraph()->GetArena())
LocationSummary(deoptimize, LocationSummary::kCallOnSlowPath);
HInstruction* cond = deoptimize->InputAt(0);
- DCHECK(cond->IsCondition());
- if (cond->AsCondition()->NeedsMaterialization()) {
+ if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) {
locations->SetInAt(0, Location::Any());
}
}
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc
index bf570f5..ed2e4ca 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -1252,8 +1252,7 @@
LocationSummary* locations = new (GetGraph()->GetArena())
LocationSummary(deoptimize, LocationSummary::kCallOnSlowPath);
HInstruction* cond = deoptimize->InputAt(0);
- DCHECK(cond->IsCondition());
- if (cond->AsCondition()->NeedsMaterialization()) {
+ if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) {
locations->SetInAt(0, Location::Any());
}
}
diff --git a/compiler/optimizing/constant_folding_test.cc b/compiler/optimizing/constant_folding_test.cc
index b2e222f..2feb75c 100644
--- a/compiler/optimizing/constant_folding_test.cc
+++ b/compiler/optimizing/constant_folding_test.cc
@@ -569,7 +569,7 @@
Instruction::ADD_INT_LIT16 | 1 << 8 | 0 << 12, 5,
Instruction::GOTO | 4 << 8,
Instruction::ADD_INT_LIT16 | 0 << 8 | 2 << 12, 4,
- static_cast<uint16_t>(Instruction::GOTO | -5 << 8),
+ static_cast<uint16_t>(Instruction::GOTO | 0xFFFFFFFB << 8),
Instruction::ADD_INT_LIT16 | 2 << 8 | 1 << 12, 8,
Instruction::RETURN | 2 << 8);
diff --git a/compiler/optimizing/dead_code_elimination_test.cc b/compiler/optimizing/dead_code_elimination_test.cc
index cf0a4ac..2c6a1ef 100644
--- a/compiler/optimizing/dead_code_elimination_test.cc
+++ b/compiler/optimizing/dead_code_elimination_test.cc
@@ -140,7 +140,7 @@
Instruction::ADD_INT_LIT16 | 1 << 8 | 0 << 12, 3,
Instruction::GOTO | 4 << 8,
Instruction::ADD_INT_LIT16 | 0 << 8 | 2 << 12, 2,
- static_cast<uint16_t>(Instruction::GOTO | -5 << 8),
+ static_cast<uint16_t>(Instruction::GOTO | 0xFFFFFFFB << 8),
Instruction::ADD_INT_LIT16 | 2 << 8 | 1 << 12, 4,
Instruction::RETURN_VOID);
diff --git a/compiler/optimizing/gvn_test.cc b/compiler/optimizing/gvn_test.cc
index 56f2718..aa375f6 100644
--- a/compiler/optimizing/gvn_test.cc
+++ b/compiler/optimizing/gvn_test.cc
@@ -34,7 +34,10 @@
HBasicBlock* entry = new (&allocator) HBasicBlock(graph);
graph->AddBlock(entry);
graph->SetEntryBlock(entry);
- HInstruction* parameter = new (&allocator) HParameterValue(0, Primitive::kPrimNot);
+ HInstruction* parameter = new (&allocator) HParameterValue(graph->GetDexFile(),
+ 0,
+ 0,
+ Primitive::kPrimNot);
entry->AddInstruction(parameter);
HBasicBlock* block = new (&allocator) HBasicBlock(graph);
@@ -111,7 +114,10 @@
HBasicBlock* entry = new (&allocator) HBasicBlock(graph);
graph->AddBlock(entry);
graph->SetEntryBlock(entry);
- HInstruction* parameter = new (&allocator) HParameterValue(0, Primitive::kPrimNot);
+ HInstruction* parameter = new (&allocator) HParameterValue(graph->GetDexFile(),
+ 0,
+ 0,
+ Primitive::kPrimNot);
entry->AddInstruction(parameter);
HBasicBlock* block = new (&allocator) HBasicBlock(graph);
@@ -188,7 +194,10 @@
graph->AddBlock(entry);
graph->SetEntryBlock(entry);
- HInstruction* parameter = new (&allocator) HParameterValue(0, Primitive::kPrimNot);
+ HInstruction* parameter = new (&allocator) HParameterValue(graph->GetDexFile(),
+ 0,
+ 0,
+ Primitive::kPrimNot);
entry->AddInstruction(parameter);
HBasicBlock* block = new (&allocator) HBasicBlock(graph);
@@ -328,7 +337,10 @@
inner_loop_body->AddSuccessor(inner_loop_header);
inner_loop_exit->AddSuccessor(outer_loop_header);
- HInstruction* parameter = new (&allocator) HParameterValue(0, Primitive::kPrimBoolean);
+ HInstruction* parameter = new (&allocator) HParameterValue(graph->GetDexFile(),
+ 0,
+ 0,
+ Primitive::kPrimBoolean);
entry->AddInstruction(parameter);
entry->AddInstruction(new (&allocator) HGoto());
outer_loop_header->AddInstruction(new (&allocator) HIf(parameter));
diff --git a/compiler/optimizing/induction_var_analysis_test.cc b/compiler/optimizing/induction_var_analysis_test.cc
index 20492e7..f16da2a 100644
--- a/compiler/optimizing/induction_var_analysis_test.cc
+++ b/compiler/optimizing/induction_var_analysis_test.cc
@@ -20,7 +20,6 @@
#include "builder.h"
#include "gtest/gtest.h"
#include "induction_var_analysis.h"
-#include "induction_var_range.h"
#include "nodes.h"
#include "optimizing_unit_test.h"
@@ -78,7 +77,8 @@
graph_->SetExitBlock(exit_);
// Provide entry and exit instructions.
- parameter_ = new (&allocator_) HParameterValue(0, Primitive::kPrimNot, true);
+ parameter_ = new (&allocator_) HParameterValue(
+ graph_->GetDexFile(), 0, 0, Primitive::kPrimNot, true);
entry_->AddInstruction(parameter_);
constant0_ = graph_->GetIntConstant(0);
constant1_ = graph_->GetIntConstant(1);
@@ -522,36 +522,6 @@
EXPECT_STREQ("periodic(( - (1)), (0))", GetInductionInfo(neg, 0).c_str());
}
-TEST_F(InductionVarAnalysisTest, FindRange) {
- // Setup:
- // for (int i = 0; i < 100; i++) {
- // k = i << 1;
- // k = k + 1;
- // a[k] = 0;
- // }
- BuildLoopNest(1);
- HInstruction *shl = InsertInstruction(
- new (&allocator_) HShl(Primitive::kPrimInt, InsertLocalLoad(basic_[0], 0), constant1_), 0);
- InsertLocalStore(induc_, shl, 0);
- HInstruction *add = InsertInstruction(
- new (&allocator_) HAdd(Primitive::kPrimInt, InsertLocalLoad(induc_, 0), constant1_), 0);
- InsertLocalStore(induc_, add, 0);
- HInstruction* store = InsertArrayStore(induc_, 0);
- PerformInductionVarAnalysis();
-
- EXPECT_STREQ("((2) * i + (1))", GetInductionInfo(store->InputAt(1), 0).c_str());
-
- InductionVarRange range(iva_);
- InductionVarRange::Value v_min = range.GetMinInduction(store, store->InputAt(1));
- InductionVarRange::Value v_max = range.GetMaxInduction(store, store->InputAt(1));
- ASSERT_TRUE(v_min.is_known);
- EXPECT_EQ(0, v_min.a_constant);
- EXPECT_EQ(1, v_min.b_constant);
- ASSERT_TRUE(v_max.is_known);
- EXPECT_EQ(0, v_max.a_constant);
- EXPECT_EQ(199, v_max.b_constant);
-}
-
TEST_F(InductionVarAnalysisTest, FindDeepLoopInduction) {
// Setup:
// k = 0;
diff --git a/compiler/optimizing/induction_var_range.cc b/compiler/optimizing/induction_var_range.cc
index db12819..f4842f9 100644
--- a/compiler/optimizing/induction_var_range.cc
+++ b/compiler/optimizing/induction_var_range.cc
@@ -75,6 +75,13 @@
return v;
}
+static HInstruction* Insert(HBasicBlock* preheader, HInstruction* instruction) {
+ DCHECK(preheader != nullptr);
+ DCHECK(instruction != nullptr);
+ preheader->InsertInstructionBefore(instruction, preheader->GetLastInstruction());
+ return instruction;
+}
+
//
// Public class methods.
//
@@ -94,6 +101,21 @@
return SimplifyMax(GetInduction(context, instruction, /* is_min */ false));
}
+bool InductionVarRange::CanGenerateCode(HInstruction* context,
+ HInstruction* instruction,
+ /*out*/bool* top_test) {
+ return GenerateCode(context, instruction, nullptr, nullptr, nullptr, nullptr, top_test);
+}
+
+bool InductionVarRange::GenerateCode(HInstruction* context,
+ HInstruction* instruction,
+ HGraph* graph,
+ HBasicBlock* block,
+ /*out*/HInstruction** lower,
+ /*out*/HInstruction** upper) {
+ return GenerateCode(context, instruction, graph, block, lower, upper, nullptr);
+}
+
//
// Private class methods.
//
@@ -162,15 +184,15 @@
case HInductionVarAnalysis::kFetch:
return GetFetch(info->fetch, trip, in_body, is_min);
case HInductionVarAnalysis::kTripCountInLoop:
- if (!in_body) {
- return is_min ? Value(0)
- : GetVal(info->op_b, trip, in_body, is_min); // one extra!
+ if (!in_body && !is_min) { // one extra!
+ return GetVal(info->op_b, trip, in_body, is_min);
}
FALLTHROUGH_INTENDED;
case HInductionVarAnalysis::kTripCountInBody:
- if (in_body) {
- return is_min ? Value(0)
- : SubValue(GetVal(info->op_b, trip, in_body, is_min), Value(1));
+ if (is_min) {
+ return Value(0);
+ } else if (in_body) {
+ return SubValue(GetVal(info->op_b, trip, in_body, is_min), Value(1));
}
break;
default:
@@ -256,9 +278,11 @@
bool InductionVarRange::GetConstant(HInductionVarAnalysis::InductionInfo* info, int32_t *value) {
Value v_min = GetVal(info, nullptr, false, /* is_min */ true);
Value v_max = GetVal(info, nullptr, false, /* is_min */ false);
- if (v_min.a_constant == 0 && v_max.a_constant == 0 && v_min.b_constant == v_max.b_constant) {
- *value = v_min.b_constant;
- return true;
+ if (v_min.is_known && v_max.is_known) {
+ if (v_min.a_constant == 0 && v_max.a_constant == 0 && v_min.b_constant == v_max.b_constant) {
+ *value = v_min.b_constant;
+ return true;
+ }
}
return false;
}
@@ -326,4 +350,129 @@
return Value();
}
+bool InductionVarRange::GenerateCode(HInstruction* context,
+ HInstruction* instruction,
+ HGraph* graph,
+ HBasicBlock* block,
+ /*out*/HInstruction** lower,
+ /*out*/HInstruction** upper,
+ /*out*/bool* top_test) {
+ HLoopInformation* loop = context->GetBlock()->GetLoopInformation(); // closest enveloping loop
+ if (loop != nullptr) {
+ HBasicBlock* header = loop->GetHeader();
+ bool in_body = context->GetBlock() != header;
+ HInductionVarAnalysis::InductionInfo* info = induction_analysis_->LookupInfo(loop, instruction);
+ HInductionVarAnalysis::InductionInfo* trip =
+ induction_analysis_->LookupInfo(loop, header->GetLastInstruction());
+ if (info != nullptr && trip != nullptr) {
+ if (top_test != nullptr) {
+ *top_test = trip->operation != HInductionVarAnalysis::kTripCountInLoop;
+ }
+ return
+ // Success on lower if invariant (not set), or code can be generated.
+ ((info->induction_class == HInductionVarAnalysis::kInvariant) ||
+ GenerateCode(info, trip, graph, block, lower, in_body, /* is_min */ true)) &&
+ // And success on upper.
+ GenerateCode(info, trip, graph, block, upper, in_body, /* is_min */ false);
+ }
+ }
+ return false;
+}
+
+bool InductionVarRange::GenerateCode(HInductionVarAnalysis::InductionInfo* info,
+ HInductionVarAnalysis::InductionInfo* trip,
+ HGraph* graph, // when set, code is generated
+ HBasicBlock* block,
+ /*out*/HInstruction** result,
+ bool in_body,
+ bool is_min) {
+ if (info != nullptr) {
+ Primitive::Type type = Primitive::kPrimInt;
+ HInstruction* opa = nullptr;
+ HInstruction* opb = nullptr;
+ int32_t value = 0;
+ switch (info->induction_class) {
+ case HInductionVarAnalysis::kInvariant:
+ // Invariants.
+ switch (info->operation) {
+ case HInductionVarAnalysis::kAdd:
+ if (GenerateCode(info->op_a, trip, graph, block, &opa, in_body, is_min) &&
+ GenerateCode(info->op_b, trip, graph, block, &opb, in_body, is_min)) {
+ if (graph != nullptr) {
+ *result = Insert(block, new (graph->GetArena()) HAdd(type, opa, opb));
+ }
+ return true;
+ }
+ break;
+ case HInductionVarAnalysis::kSub: // second reversed!
+ if (GenerateCode(info->op_a, trip, graph, block, &opa, in_body, is_min) &&
+ GenerateCode(info->op_b, trip, graph, block, &opb, in_body, !is_min)) {
+ if (graph != nullptr) {
+ *result = Insert(block, new (graph->GetArena()) HSub(type, opa, opb));
+ }
+ return true;
+ }
+ break;
+ case HInductionVarAnalysis::kNeg: // reversed!
+ if (GenerateCode(info->op_b, trip, graph, block, &opb, in_body, !is_min)) {
+ if (graph != nullptr) {
+ *result = Insert(block, new (graph->GetArena()) HNeg(type, opb));
+ }
+ return true;
+ }
+ break;
+ case HInductionVarAnalysis::kFetch:
+ if (graph != nullptr) {
+ *result = info->fetch; // already in HIR
+ }
+ return true;
+ case HInductionVarAnalysis::kTripCountInLoop:
+ if (!in_body && !is_min) { // one extra!
+ return GenerateCode(info->op_b, trip, graph, block, result, in_body, is_min);
+ }
+ FALLTHROUGH_INTENDED;
+ case HInductionVarAnalysis::kTripCountInBody:
+ if (is_min) {
+ if (graph != nullptr) {
+ *result = graph->GetIntConstant(0);
+ }
+ return true;
+ } else if (in_body) {
+ if (GenerateCode(info->op_b, trip, graph, block, &opb, in_body, is_min)) {
+ if (graph != nullptr) {
+ *result = Insert(block,
+ new (graph->GetArena())
+ HSub(type, opb, graph->GetIntConstant(1)));
+ }
+ return true;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ break;
+ case HInductionVarAnalysis::kLinear:
+ // Linear induction a * i + b, for normalized 0 <= i < TC. Restrict to unit stride only
+ // to avoid arithmetic wrap-around situations that are hard to guard against.
+ if (GetConstant(info->op_a, &value)) {
+ if (value == 1 || value == -1) {
+ const bool is_min_a = value == 1 ? is_min : !is_min;
+ if (GenerateCode(trip, trip, graph, block, &opa, in_body, is_min_a) &&
+ GenerateCode(info->op_b, trip, graph, block, &opb, in_body, is_min)) {
+ if (graph != nullptr) {
+ *result = Insert(block, new (graph->GetArena()) HAdd(type, opa, opb));
+ }
+ return true;
+ }
+ }
+ }
+ break;
+ default: // TODO(ajcbik): add more cases
+ break;
+ }
+ }
+ return false;
+}
+
} // namespace art
diff --git a/compiler/optimizing/induction_var_range.h b/compiler/optimizing/induction_var_range.h
index dbdd2ee..7fa5a26 100644
--- a/compiler/optimizing/induction_var_range.h
+++ b/compiler/optimizing/induction_var_range.h
@@ -68,6 +68,33 @@
*/
Value GetMaxInduction(HInstruction* context, HInstruction* instruction);
+ /**
+ * Returns true if range analysis is able to generate code for the lower and upper bound
+ * expressions on the instruction in the given context. Output parameter top_test denotes
+ * whether a top test is needed to protect the trip-count expression evaluation.
+ */
+ bool CanGenerateCode(HInstruction* context, HInstruction* instruction, /*out*/bool* top_test);
+
+ /**
+ * Generates the actual code in the HIR for the lower and upper bound expressions on the
+ * instruction in the given context. Code for the lower and upper bound expression are
+ * generated in given block and graph and are returned in lower and upper, respectively.
+ * For a loop invariant, lower is not set.
+ *
+ * For example, given expression x+i with range [0, 5] for i, calling this method
+ * will generate the following sequence:
+ *
+ * block:
+ * lower: add x, 0
+ * upper: add x, 5
+ */
+ bool GenerateCode(HInstruction* context,
+ HInstruction* instruction,
+ HGraph* graph,
+ HBasicBlock* block,
+ /*out*/HInstruction** lower,
+ /*out*/HInstruction** upper);
+
private:
//
// Private helper methods.
@@ -102,6 +129,27 @@
static Value DivValue(Value v1, Value v2);
static Value MergeVal(Value v1, Value v2, bool is_min);
+ /**
+ * Generates code for lower/upper expression in the HIR. Returns true on success.
+ * With graph == nullptr, the method can be used to determine if code generation
+ * would be successful without generating actual code yet.
+ */
+ bool GenerateCode(HInstruction* context,
+ HInstruction* instruction,
+ HGraph* graph,
+ HBasicBlock* block,
+ /*out*/HInstruction** lower,
+ /*out*/HInstruction** upper,
+ bool* top_test);
+
+ static bool GenerateCode(HInductionVarAnalysis::InductionInfo* info,
+ HInductionVarAnalysis::InductionInfo* trip,
+ HGraph* graph,
+ HBasicBlock* block,
+ /*out*/HInstruction** result,
+ bool in_body,
+ bool is_min);
+
/** Results of prior induction variable analysis. */
HInductionVarAnalysis *induction_analysis_;
diff --git a/compiler/optimizing/induction_var_range_test.cc b/compiler/optimizing/induction_var_range_test.cc
index 4497a88..8fbc59f 100644
--- a/compiler/optimizing/induction_var_range_test.cc
+++ b/compiler/optimizing/induction_var_range_test.cc
@@ -49,12 +49,52 @@
/** Constructs bare minimum graph. */
void BuildGraph() {
graph_->SetNumberOfVRegs(1);
- HBasicBlock* entry_block = new (&allocator_) HBasicBlock(graph_);
- HBasicBlock* exit_block = new (&allocator_) HBasicBlock(graph_);
- graph_->AddBlock(entry_block);
- graph_->AddBlock(exit_block);
- graph_->SetEntryBlock(entry_block);
- graph_->SetExitBlock(exit_block);
+ entry_block_ = new (&allocator_) HBasicBlock(graph_);
+ exit_block_ = new (&allocator_) HBasicBlock(graph_);
+ graph_->AddBlock(entry_block_);
+ graph_->AddBlock(exit_block_);
+ graph_->SetEntryBlock(entry_block_);
+ graph_->SetExitBlock(exit_block_);
+ }
+
+ /** Constructs loop with given upper bound. */
+ void BuildLoop(HInstruction* upper) {
+ // Control flow.
+ loop_preheader_ = new (&allocator_) HBasicBlock(graph_);
+ graph_->AddBlock(loop_preheader_);
+ HBasicBlock* loop_header = new (&allocator_) HBasicBlock(graph_);
+ graph_->AddBlock(loop_header);
+ HBasicBlock* loop_body = new (&allocator_) HBasicBlock(graph_);
+ graph_->AddBlock(loop_body);
+ entry_block_->AddSuccessor(loop_preheader_);
+ loop_preheader_->AddSuccessor(loop_header);
+ loop_header->AddSuccessor(loop_body);
+ loop_header->AddSuccessor(exit_block_);
+ loop_body->AddSuccessor(loop_header);
+ // Instructions.
+ HLocal* induc = new (&allocator_) HLocal(0);
+ entry_block_->AddInstruction(induc);
+ loop_preheader_->AddInstruction(
+ new (&allocator_) HStoreLocal(induc, graph_->GetIntConstant(0))); // i = 0
+ loop_preheader_->AddInstruction(new (&allocator_) HGoto());
+ HInstruction* load = new (&allocator_) HLoadLocal(induc, Primitive::kPrimInt);
+ loop_header->AddInstruction(load);
+ condition_ = new (&allocator_) HLessThan(load, upper);
+ loop_header->AddInstruction(condition_);
+ loop_header->AddInstruction(new (&allocator_) HIf(condition_)); // i < u
+ load = new (&allocator_) HLoadLocal(induc, Primitive::kPrimInt);
+ loop_body->AddInstruction(load);
+ increment_ = new (&allocator_) HAdd(Primitive::kPrimInt, load, graph_->GetIntConstant(1));
+ loop_body->AddInstruction(increment_);
+ loop_body->AddInstruction(new (&allocator_) HStoreLocal(induc, increment_)); // i++
+ loop_body->AddInstruction(new (&allocator_) HGoto());
+ exit_block_->AddInstruction(new (&allocator_) HReturnVoid());
+ }
+
+ /** Performs induction variable analysis. */
+ void PerformInductionVarAnalysis() {
+ ASSERT_TRUE(graph_->TryBuildingSsa());
+ iva_->Run();
}
/** Constructs an invariant. */
@@ -146,15 +186,20 @@
ArenaPool pool_;
ArenaAllocator allocator_;
HGraph* graph_;
+ HBasicBlock* entry_block_;
+ HBasicBlock* exit_block_;
+ HBasicBlock* loop_preheader_;
HInductionVarAnalysis* iva_;
- // Two dummy instructions.
+ // Instructions.
+ HInstruction* condition_;
+ HInstruction* increment_;
HReturnVoid x_;
HReturnVoid y_;
};
//
-// The actual InductionVarRange tests.
+// Tests on static methods.
//
TEST_F(InductionVarRangeTest, GetMinMaxNull) {
@@ -349,4 +394,83 @@
ExpectEqual(Value(), MaxValue(Value(55), Value(&y_, 1, -50)));
}
+//
+// Tests on instance methods.
+//
+
+TEST_F(InductionVarRangeTest, FindRangeConstantTripCount) {
+ BuildLoop(graph_->GetIntConstant(1000));
+ PerformInductionVarAnalysis();
+ InductionVarRange range(iva_);
+
+ // In context of header: known.
+ ExpectEqual(Value(0), range.GetMinInduction(condition_, condition_->InputAt(0)));
+ ExpectEqual(Value(1000), range.GetMaxInduction(condition_, condition_->InputAt(0)));
+
+ // In context of loop-body: known.
+ ExpectEqual(Value(0), range.GetMinInduction(increment_, condition_->InputAt(0)));
+ ExpectEqual(Value(999), range.GetMaxInduction(increment_, condition_->InputAt(0)));
+ ExpectEqual(Value(1), range.GetMinInduction(increment_, increment_));
+ ExpectEqual(Value(1000), range.GetMaxInduction(increment_, increment_));
+}
+
+TEST_F(InductionVarRangeTest, FindRangeSymbolicTripCount) {
+ HInstruction* parameter = new (&allocator_) HParameterValue(
+ graph_->GetDexFile(), 0, 0, Primitive::kPrimInt);
+ entry_block_->AddInstruction(parameter);
+ BuildLoop(parameter);
+ PerformInductionVarAnalysis();
+ InductionVarRange range(iva_);
+
+ // In context of header: full range unknown.
+ ExpectEqual(Value(0), range.GetMinInduction(condition_, condition_->InputAt(0)));
+ ExpectEqual(Value(), range.GetMaxInduction(condition_, condition_->InputAt(0)));
+
+ // In context of loop-body: known.
+ ExpectEqual(Value(0), range.GetMinInduction(increment_, condition_->InputAt(0)));
+ ExpectEqual(Value(parameter, 1, -1), range.GetMaxInduction(increment_, condition_->InputAt(0)));
+ ExpectEqual(Value(1), range.GetMinInduction(increment_, increment_));
+ ExpectEqual(Value(parameter, 1, 0), range.GetMaxInduction(increment_, increment_));
+}
+
+TEST_F(InductionVarRangeTest, CodeGeneration) {
+ HInstruction* parameter = new (&allocator_) HParameterValue(
+ graph_->GetDexFile(), 0, 0, Primitive::kPrimInt);
+ entry_block_->AddInstruction(parameter);
+ BuildLoop(parameter);
+ PerformInductionVarAnalysis();
+ InductionVarRange range(iva_);
+
+ HInstruction* lower = nullptr;
+ HInstruction* upper = nullptr;
+ bool top_test = false;
+
+ // Can generate code in context of loop-body only.
+ EXPECT_FALSE(range.CanGenerateCode(condition_, condition_->InputAt(0), &top_test));
+ ASSERT_TRUE(range.CanGenerateCode(increment_, condition_->InputAt(0), &top_test));
+ EXPECT_TRUE(top_test);
+
+ // Generates code.
+ EXPECT_TRUE(range.GenerateCode(
+ increment_, condition_->InputAt(0), graph_, loop_preheader_, &lower, &upper));
+
+ // Verify lower is 0+0.
+ ASSERT_TRUE(lower != nullptr);
+ ASSERT_TRUE(lower->IsAdd());
+ ASSERT_TRUE(lower->InputAt(0)->IsIntConstant());
+ EXPECT_EQ(0, lower->InputAt(0)->AsIntConstant()->GetValue());
+ ASSERT_TRUE(lower->InputAt(1)->IsIntConstant());
+ EXPECT_EQ(0, lower->InputAt(1)->AsIntConstant()->GetValue());
+
+ // Verify upper is (V-1)+0
+ ASSERT_TRUE(upper != nullptr);
+ ASSERT_TRUE(upper->IsAdd());
+ ASSERT_TRUE(upper->InputAt(0)->IsSub());
+ EXPECT_TRUE(upper->InputAt(0)->InputAt(0)->IsParameterValue());
+ ASSERT_TRUE(upper->InputAt(0)->InputAt(1)->IsIntConstant());
+ EXPECT_EQ(1, upper->InputAt(0)->InputAt(1)->AsIntConstant()->GetValue());
+ ASSERT_TRUE(upper->InputAt(1)->IsIntConstant());
+ EXPECT_EQ(0, upper->InputAt(1)->AsIntConstant()->GetValue());
+}
+
} // namespace art
diff --git a/compiler/optimizing/instruction_simplifier.cc b/compiler/optimizing/instruction_simplifier.cc
index d468540..7814eb9 100644
--- a/compiler/optimizing/instruction_simplifier.cc
+++ b/compiler/optimizing/instruction_simplifier.cc
@@ -73,6 +73,7 @@
void VisitInstanceOf(HInstanceOf* instruction) OVERRIDE;
void VisitFakeString(HFakeString* fake_string) OVERRIDE;
void VisitInvoke(HInvoke* invoke) OVERRIDE;
+ void VisitDeoptimize(HDeoptimize* deoptimize) OVERRIDE;
bool CanEnsureNotNullAt(HInstruction* instr, HInstruction* at) const;
@@ -1151,4 +1152,16 @@
}
}
+void InstructionSimplifierVisitor::VisitDeoptimize(HDeoptimize* deoptimize) {
+ HInstruction* cond = deoptimize->InputAt(0);
+ if (cond->IsConstant()) {
+ if (cond->AsIntConstant()->IsZero()) {
+ // Never deopt: instruction can be removed.
+ deoptimize->GetBlock()->RemoveInstruction(deoptimize);
+ } else {
+ // Always deopt.
+ }
+ }
+}
+
} // namespace art
diff --git a/compiler/optimizing/intrinsics_mips64.cc b/compiler/optimizing/intrinsics_mips64.cc
index a3121a9..56c4177 100644
--- a/compiler/optimizing/intrinsics_mips64.cc
+++ b/compiler/optimizing/intrinsics_mips64.cc
@@ -336,6 +336,130 @@
GenNumberOfTrailingZeroes(invoke->GetLocations(), true, GetAssembler());
}
+static void GenRotateRight(HInvoke* invoke,
+ Primitive::Type type,
+ Mips64Assembler* assembler) {
+ DCHECK(type == Primitive::kPrimInt || type == Primitive::kPrimLong);
+
+ LocationSummary* locations = invoke->GetLocations();
+ GpuRegister in = locations->InAt(0).AsRegister<GpuRegister>();
+ GpuRegister out = locations->Out().AsRegister<GpuRegister>();
+
+ if (invoke->InputAt(1)->IsIntConstant()) {
+ uint32_t shift = static_cast<uint32_t>(invoke->InputAt(1)->AsIntConstant()->GetValue());
+ if (type == Primitive::kPrimInt) {
+ shift &= 0x1f;
+ __ Rotr(out, in, shift);
+ } else {
+ shift &= 0x3f;
+ if (shift < 32) {
+ __ Drotr(out, in, shift);
+ } else {
+ shift &= 0x1f;
+ __ Drotr32(out, in, shift);
+ }
+ }
+ } else {
+ GpuRegister shamt = locations->InAt(1).AsRegister<GpuRegister>();
+ if (type == Primitive::kPrimInt) {
+ __ Rotrv(out, in, shamt);
+ } else {
+ __ Drotrv(out, in, shamt);
+ }
+ }
+}
+
+// int java.lang.Integer.rotateRight(int i, int distance)
+void IntrinsicLocationsBuilderMIPS64::VisitIntegerRotateRight(HInvoke* invoke) {
+ LocationSummary* locations = new (arena_) LocationSummary(invoke,
+ LocationSummary::kNoCall,
+ kIntrinsified);
+ locations->SetInAt(0, Location::RequiresRegister());
+ locations->SetInAt(1, Location::RegisterOrConstant(invoke->InputAt(1)));
+ locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
+}
+
+void IntrinsicCodeGeneratorMIPS64::VisitIntegerRotateRight(HInvoke* invoke) {
+ GenRotateRight(invoke, Primitive::kPrimInt, GetAssembler());
+}
+
+// int java.lang.Long.rotateRight(long i, int distance)
+void IntrinsicLocationsBuilderMIPS64::VisitLongRotateRight(HInvoke* invoke) {
+ LocationSummary* locations = new (arena_) LocationSummary(invoke,
+ LocationSummary::kNoCall,
+ kIntrinsified);
+ locations->SetInAt(0, Location::RequiresRegister());
+ locations->SetInAt(1, Location::RegisterOrConstant(invoke->InputAt(1)));
+ locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
+}
+
+void IntrinsicCodeGeneratorMIPS64::VisitLongRotateRight(HInvoke* invoke) {
+ GenRotateRight(invoke, Primitive::kPrimLong, GetAssembler());
+}
+
+static void GenRotateLeft(HInvoke* invoke,
+ Primitive::Type type,
+ Mips64Assembler* assembler) {
+ DCHECK(type == Primitive::kPrimInt || type == Primitive::kPrimLong);
+
+ LocationSummary* locations = invoke->GetLocations();
+ GpuRegister in = locations->InAt(0).AsRegister<GpuRegister>();
+ GpuRegister out = locations->Out().AsRegister<GpuRegister>();
+
+ if (invoke->InputAt(1)->IsIntConstant()) {
+ int32_t shift = -static_cast<int32_t>(invoke->InputAt(1)->AsIntConstant()->GetValue());
+ if (type == Primitive::kPrimInt) {
+ shift &= 0x1f;
+ __ Rotr(out, in, shift);
+ } else {
+ shift &= 0x3f;
+ if (shift < 32) {
+ __ Drotr(out, in, shift);
+ } else {
+ shift &= 0x1f;
+ __ Drotr32(out, in, shift);
+ }
+ }
+ } else {
+ GpuRegister shamt = locations->InAt(1).AsRegister<GpuRegister>();
+ if (type == Primitive::kPrimInt) {
+ __ Subu(TMP, ZERO, shamt);
+ __ Rotrv(out, in, TMP);
+ } else {
+ __ Dsubu(TMP, ZERO, shamt);
+ __ Drotrv(out, in, TMP);
+ }
+ }
+}
+
+// int java.lang.Integer.rotateLeft(int i, int distance)
+void IntrinsicLocationsBuilderMIPS64::VisitIntegerRotateLeft(HInvoke* invoke) {
+ LocationSummary* locations = new (arena_) LocationSummary(invoke,
+ LocationSummary::kNoCall,
+ kIntrinsified);
+ locations->SetInAt(0, Location::RequiresRegister());
+ locations->SetInAt(1, Location::RegisterOrConstant(invoke->InputAt(1)));
+ locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
+}
+
+void IntrinsicCodeGeneratorMIPS64::VisitIntegerRotateLeft(HInvoke* invoke) {
+ GenRotateLeft(invoke, Primitive::kPrimInt, GetAssembler());
+}
+
+// int java.lang.Long.rotateLeft(long i, int distance)
+void IntrinsicLocationsBuilderMIPS64::VisitLongRotateLeft(HInvoke* invoke) {
+ LocationSummary* locations = new (arena_) LocationSummary(invoke,
+ LocationSummary::kNoCall,
+ kIntrinsified);
+ locations->SetInAt(0, Location::RequiresRegister());
+ locations->SetInAt(1, Location::RegisterOrConstant(invoke->InputAt(1)));
+ locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
+}
+
+void IntrinsicCodeGeneratorMIPS64::VisitLongRotateLeft(HInvoke* invoke) {
+ GenRotateLeft(invoke, Primitive::kPrimLong, GetAssembler());
+}
+
static void GenReverse(LocationSummary* locations,
Primitive::Type type,
Mips64Assembler* assembler) {
@@ -1401,10 +1525,6 @@
UNIMPLEMENTED_INTRINSIC(UnsafeCASLong)
UNIMPLEMENTED_INTRINSIC(UnsafeCASObject)
UNIMPLEMENTED_INTRINSIC(StringEquals)
-UNIMPLEMENTED_INTRINSIC(LongRotateLeft)
-UNIMPLEMENTED_INTRINSIC(LongRotateRight)
-UNIMPLEMENTED_INTRINSIC(IntegerRotateLeft)
-UNIMPLEMENTED_INTRINSIC(IntegerRotateRight)
UNIMPLEMENTED_INTRINSIC(ReferenceGetReferent)
UNIMPLEMENTED_INTRINSIC(StringGetCharsNoCheck)
diff --git a/compiler/optimizing/intrinsics_x86.cc b/compiler/optimizing/intrinsics_x86.cc
index e83aebb..8a7aded 100644
--- a/compiler/optimizing/intrinsics_x86.cc
+++ b/compiler/optimizing/intrinsics_x86.cc
@@ -1837,6 +1837,14 @@
}
void IntrinsicLocationsBuilderX86::VisitUnsafeCASObject(HInvoke* invoke) {
+ // The UnsafeCASObject intrinsic does not always work when heap
+ // poisoning is enabled (it breaks several libcore tests); turn it
+ // off temporarily as a quick fix.
+ // TODO(rpl): Fix it and turn it back on.
+ if (kPoisonHeapReferences) {
+ return;
+ }
+
CreateIntIntIntIntIntToInt(arena_, Primitive::kPrimNot, invoke);
}
diff --git a/compiler/optimizing/intrinsics_x86_64.cc b/compiler/optimizing/intrinsics_x86_64.cc
index e0d88a9..7a1d92d 100644
--- a/compiler/optimizing/intrinsics_x86_64.cc
+++ b/compiler/optimizing/intrinsics_x86_64.cc
@@ -1909,6 +1909,14 @@
}
void IntrinsicLocationsBuilderX86_64::VisitUnsafeCASObject(HInvoke* invoke) {
+ // The UnsafeCASObject intrinsic does not always work when heap
+ // poisoning is enabled (it breaks several libcore tests); turn it
+ // off temporarily as a quick fix.
+ // TODO(rpl): Fix it and turn it back on.
+ if (kPoisonHeapReferences) {
+ return;
+ }
+
CreateIntIntIntIntIntToInt(arena_, Primitive::kPrimNot, invoke);
}
diff --git a/compiler/optimizing/licm_test.cc b/compiler/optimizing/licm_test.cc
index 558892d..a036bd5 100644
--- a/compiler/optimizing/licm_test.cc
+++ b/compiler/optimizing/licm_test.cc
@@ -61,7 +61,7 @@
loop_body_->AddSuccessor(loop_header_);
// Provide boiler-plate instructions.
- parameter_ = new (&allocator_) HParameterValue(0, Primitive::kPrimNot);
+ parameter_ = new (&allocator_) HParameterValue(graph_->GetDexFile(), 0, 0, Primitive::kPrimNot);
entry_->AddInstruction(parameter_);
constant_ = graph_->GetIntConstant(42);
loop_preheader_->AddInstruction(new (&allocator_) HGoto());
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index 939e62c..0db1ba2 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -4059,24 +4059,31 @@
// the calling convention.
class HParameterValue : public HExpression<0> {
public:
- HParameterValue(uint8_t index,
+ HParameterValue(const DexFile& dex_file,
+ uint16_t type_index,
+ uint8_t index,
Primitive::Type parameter_type,
bool is_this = false)
: HExpression(parameter_type, SideEffects::None(), kNoDexPc),
+ dex_file_(dex_file),
+ type_index_(type_index),
index_(index),
is_this_(is_this),
can_be_null_(!is_this) {}
+ const DexFile& GetDexFile() const { return dex_file_; }
+ uint16_t GetTypeIndex() const { return type_index_; }
uint8_t GetIndex() const { return index_; }
+ bool IsThis() const { return is_this_; }
bool CanBeNull() const OVERRIDE { return can_be_null_; }
void SetCanBeNull(bool can_be_null) { can_be_null_ = can_be_null; }
- bool IsThis() const { return is_this_; }
-
DECLARE_INSTRUCTION(ParameterValue);
private:
+ const DexFile& dex_file_;
+ const uint16_t type_index_;
// The index of this parameter in the parameters list. Must be less
// than HGraph::number_of_in_vregs_.
const uint8_t index_;
diff --git a/compiler/optimizing/nodes_test.cc b/compiler/optimizing/nodes_test.cc
index 8eeac56..764f5fe 100644
--- a/compiler/optimizing/nodes_test.cc
+++ b/compiler/optimizing/nodes_test.cc
@@ -34,7 +34,8 @@
HBasicBlock* entry = new (&allocator) HBasicBlock(graph);
graph->AddBlock(entry);
graph->SetEntryBlock(entry);
- HInstruction* parameter = new (&allocator) HParameterValue(0, Primitive::kPrimNot);
+ HInstruction* parameter = new (&allocator) HParameterValue(
+ graph->GetDexFile(), 0, 0, Primitive::kPrimNot);
entry->AddInstruction(parameter);
entry->AddInstruction(new (&allocator) HGoto());
@@ -76,8 +77,10 @@
HBasicBlock* entry = new (&allocator) HBasicBlock(graph);
graph->AddBlock(entry);
graph->SetEntryBlock(entry);
- HInstruction* parameter1 = new (&allocator) HParameterValue(0, Primitive::kPrimNot);
- HInstruction* parameter2 = new (&allocator) HParameterValue(0, Primitive::kPrimNot);
+ HInstruction* parameter1 = new (&allocator) HParameterValue(
+ graph->GetDexFile(), 0, 0, Primitive::kPrimNot);
+ HInstruction* parameter2 = new (&allocator) HParameterValue(
+ graph->GetDexFile(), 0, 0, Primitive::kPrimNot);
entry->AddInstruction(parameter1);
entry->AddInstruction(parameter2);
entry->AddInstruction(new (&allocator) HExit());
@@ -102,7 +105,8 @@
HBasicBlock* entry = new (&allocator) HBasicBlock(graph);
graph->AddBlock(entry);
graph->SetEntryBlock(entry);
- HInstruction* parameter = new (&allocator) HParameterValue(0, Primitive::kPrimNot);
+ HInstruction* parameter = new (&allocator) HParameterValue(
+ graph->GetDexFile(), 0, 0, Primitive::kPrimNot);
entry->AddInstruction(parameter);
ASSERT_FALSE(parameter->HasUses());
@@ -122,7 +126,8 @@
HBasicBlock* entry = new (&allocator) HBasicBlock(graph);
graph->AddBlock(entry);
graph->SetEntryBlock(entry);
- HInstruction* parameter1 = new (&allocator) HParameterValue(0, Primitive::kPrimNot);
+ HInstruction* parameter1 = new (&allocator) HParameterValue(
+ graph->GetDexFile(), 0, 0, Primitive::kPrimNot);
HInstruction* with_environment = new (&allocator) HNullCheck(parameter1, 0);
entry->AddInstruction(parameter1);
entry->AddInstruction(with_environment);
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index 17a4743..5404e56 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -838,18 +838,26 @@
Handle<mirror::DexCache> dex_cache) const {
CompilerDriver* compiler_driver = GetCompilerDriver();
CompiledMethod* method = nullptr;
- const VerifiedMethod* verified_method = compiler_driver->GetVerifiedMethod(&dex_file, method_idx);
- DCHECK(!verified_method->HasRuntimeThrow());
- if (compiler_driver->IsMethodVerifiedWithoutFailures(method_idx, class_def_idx, dex_file)
- || CanHandleVerificationFailure(verified_method)) {
- method = TryCompile(code_item, access_flags, invoke_type, class_def_idx,
- method_idx, jclass_loader, dex_file, dex_cache);
- } else {
- if (compiler_driver->GetCompilerOptions().VerifyAtRuntime()) {
- MaybeRecordStat(MethodCompilationStat::kNotCompiledVerifyAtRuntime);
+ if (Runtime::Current()->IsAotCompiler()) {
+ const VerifiedMethod* verified_method = compiler_driver->GetVerifiedMethod(&dex_file, method_idx);
+ DCHECK(!verified_method->HasRuntimeThrow());
+ if (compiler_driver->IsMethodVerifiedWithoutFailures(method_idx, class_def_idx, dex_file)
+ || CanHandleVerificationFailure(verified_method)) {
+ method = TryCompile(code_item, access_flags, invoke_type, class_def_idx,
+ method_idx, jclass_loader, dex_file, dex_cache);
} else {
- MaybeRecordStat(MethodCompilationStat::kNotCompiledClassNotVerified);
+ if (compiler_driver->GetCompilerOptions().VerifyAtRuntime()) {
+ MaybeRecordStat(MethodCompilationStat::kNotCompiledVerifyAtRuntime);
+ } else {
+ MaybeRecordStat(MethodCompilationStat::kNotCompiledClassNotVerified);
+ }
}
+ } else {
+ // This is for the JIT compiler, which has already ensured the class is verified.
+ // We can go straight to compiling.
+ DCHECK(Runtime::Current()->UseJit());
+ method = TryCompile(code_item, access_flags, invoke_type, class_def_idx,
+ method_idx, jclass_loader, dex_file, dex_cache);
}
if (kIsDebugBuild &&
diff --git a/compiler/optimizing/reference_type_propagation.cc b/compiler/optimizing/reference_type_propagation.cc
index a1feaf7..26a05da 100644
--- a/compiler/optimizing/reference_type_propagation.cc
+++ b/compiler/optimizing/reference_type_propagation.cc
@@ -428,12 +428,21 @@
UpdateReferenceTypeInfo(instr, instr->GetTypeIndex(), instr->GetDexFile(), /* is_exact */ true);
}
+static mirror::Class* GetClassFromDexCache(Thread* self, const DexFile& dex_file, uint16_t type_idx)
+ SHARED_REQUIRES(Locks::mutator_lock_) {
+ mirror::DexCache* dex_cache =
+ Runtime::Current()->GetClassLinker()->FindDexCache(self, dex_file, false);
+ // Get type from dex cache assuming it was populated by the verifier.
+ return dex_cache->GetResolvedType(type_idx);
+}
+
void RTPVisitor::VisitParameterValue(HParameterValue* instr) {
ScopedObjectAccess soa(Thread::Current());
// We check if the existing type is valid: the inliner may have set it.
if (instr->GetType() == Primitive::kPrimNot && !instr->GetReferenceTypeInfo().IsValid()) {
- // TODO: parse the signature and add precise types for the parameters.
- SetClassAsTypeInfo(instr, nullptr, /* is_exact */ false);
+ mirror::Class* resolved_class =
+ GetClassFromDexCache(soa.Self(), instr->GetDexFile(), instr->GetTypeIndex());
+ SetClassAsTypeInfo(instr, resolved_class, /* is_exact */ false);
}
}
@@ -479,11 +488,9 @@
void RTPVisitor::VisitLoadClass(HLoadClass* instr) {
ScopedObjectAccess soa(Thread::Current());
- mirror::DexCache* dex_cache =
- Runtime::Current()->GetClassLinker()->FindDexCache(soa.Self(), instr->GetDexFile(), false);
// Get type from dex cache assuming it was populated by the verifier.
- mirror::Class* resolved_class = dex_cache->GetResolvedType(instr->GetTypeIndex());
- // TODO: investigating why we are still getting unresolved classes: b/22821472.
+ mirror::Class* resolved_class =
+ GetClassFromDexCache(soa.Self(), instr->GetDexFile(), instr->GetTypeIndex());
if (resolved_class != nullptr) {
instr->SetLoadedClassRTI(ReferenceTypeInfo::Create(
handles_->NewHandle(resolved_class), /* is_exact */ true));
diff --git a/compiler/optimizing/register_allocator_test.cc b/compiler/optimizing/register_allocator_test.cc
index 1511606..ed5419e 100644
--- a/compiler/optimizing/register_allocator_test.cc
+++ b/compiler/optimizing/register_allocator_test.cc
@@ -475,7 +475,8 @@
NullHandle<mirror::DexCache> dex_cache;
graph->AddBlock(entry);
graph->SetEntryBlock(entry);
- HInstruction* parameter = new (allocator) HParameterValue(0, Primitive::kPrimNot);
+ HInstruction* parameter = new (allocator) HParameterValue(
+ graph->GetDexFile(), 0, 0, Primitive::kPrimNot);
entry->AddInstruction(parameter);
HBasicBlock* block = new (allocator) HBasicBlock(graph);
@@ -624,7 +625,8 @@
HBasicBlock* entry = new (allocator) HBasicBlock(graph);
graph->AddBlock(entry);
graph->SetEntryBlock(entry);
- HInstruction* parameter = new (allocator) HParameterValue(0, Primitive::kPrimNot);
+ HInstruction* parameter = new (allocator) HParameterValue(
+ graph->GetDexFile(), 0, 0, Primitive::kPrimNot);
entry->AddInstruction(parameter);
HBasicBlock* block = new (allocator) HBasicBlock(graph);
@@ -698,7 +700,8 @@
HBasicBlock* entry = new (allocator) HBasicBlock(graph);
graph->AddBlock(entry);
graph->SetEntryBlock(entry);
- HInstruction* parameter = new (allocator) HParameterValue(0, Primitive::kPrimInt);
+ HInstruction* parameter = new (allocator) HParameterValue(
+ graph->GetDexFile(), 0, 0, Primitive::kPrimInt);
entry->AddInstruction(parameter);
HInstruction* constant1 = graph->GetIntConstant(1);
@@ -768,8 +771,10 @@
HBasicBlock* entry = new (allocator) HBasicBlock(graph);
graph->AddBlock(entry);
graph->SetEntryBlock(entry);
- HInstruction* first = new (allocator) HParameterValue(0, Primitive::kPrimInt);
- HInstruction* second = new (allocator) HParameterValue(0, Primitive::kPrimInt);
+ HInstruction* first = new (allocator) HParameterValue(
+ graph->GetDexFile(), 0, 0, Primitive::kPrimInt);
+ HInstruction* second = new (allocator) HParameterValue(
+ graph->GetDexFile(), 0, 0, Primitive::kPrimInt);
entry->AddInstruction(first);
entry->AddInstruction(second);
@@ -820,10 +825,14 @@
HBasicBlock* entry = new (&allocator) HBasicBlock(graph);
graph->AddBlock(entry);
graph->SetEntryBlock(entry);
- HInstruction* one = new (&allocator) HParameterValue(0, Primitive::kPrimInt);
- HInstruction* two = new (&allocator) HParameterValue(0, Primitive::kPrimInt);
- HInstruction* three = new (&allocator) HParameterValue(0, Primitive::kPrimInt);
- HInstruction* four = new (&allocator) HParameterValue(0, Primitive::kPrimInt);
+ HInstruction* one = new (&allocator) HParameterValue(
+ graph->GetDexFile(), 0, 0, Primitive::kPrimInt);
+ HInstruction* two = new (&allocator) HParameterValue(
+ graph->GetDexFile(), 0, 0, Primitive::kPrimInt);
+ HInstruction* three = new (&allocator) HParameterValue(
+ graph->GetDexFile(), 0, 0, Primitive::kPrimInt);
+ HInstruction* four = new (&allocator) HParameterValue(
+ graph->GetDexFile(), 0, 0, Primitive::kPrimInt);
entry->AddInstruction(one);
entry->AddInstruction(two);
entry->AddInstruction(three);
diff --git a/compiler/utils/mips64/assembler_mips64.cc b/compiler/utils/mips64/assembler_mips64.cc
index 7b4e6a3..00e8995 100644
--- a/compiler/utils/mips64/assembler_mips64.cc
+++ b/compiler/utils/mips64/assembler_mips64.cc
@@ -335,6 +335,10 @@
EmitR(0, rs, rt, rd, 0, 0x04);
}
+void Mips64Assembler::Rotrv(GpuRegister rd, GpuRegister rt, GpuRegister rs) {
+ EmitR(0, rs, rt, rd, 1, 0x06);
+}
+
void Mips64Assembler::Srlv(GpuRegister rd, GpuRegister rt, GpuRegister rs) {
EmitR(0, rs, rt, rd, 0, 0x06);
}
@@ -351,6 +355,10 @@
EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x3a);
}
+void Mips64Assembler::Drotr(GpuRegister rd, GpuRegister rt, int shamt) {
+ EmitR(0, static_cast<GpuRegister>(1), rt, rd, shamt, 0x3a);
+}
+
void Mips64Assembler::Dsra(GpuRegister rd, GpuRegister rt, int shamt) {
EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x3b);
}
@@ -363,6 +371,10 @@
EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x3e);
}
+void Mips64Assembler::Drotr32(GpuRegister rd, GpuRegister rt, int shamt) {
+ EmitR(0, static_cast<GpuRegister>(1), rt, rd, shamt, 0x3e);
+}
+
void Mips64Assembler::Dsra32(GpuRegister rd, GpuRegister rt, int shamt) {
EmitR(0, static_cast<GpuRegister>(0), rt, rd, shamt, 0x3f);
}
@@ -375,6 +387,10 @@
EmitR(0, rs, rt, rd, 0, 0x16);
}
+void Mips64Assembler::Drotrv(GpuRegister rd, GpuRegister rt, GpuRegister rs) {
+ EmitR(0, rs, rt, rd, 1, 0x16);
+}
+
void Mips64Assembler::Dsrav(GpuRegister rd, GpuRegister rt, GpuRegister rs) {
EmitR(0, rs, rt, rd, 0, 0x17);
}
diff --git a/compiler/utils/mips64/assembler_mips64.h b/compiler/utils/mips64/assembler_mips64.h
index ac06521..33f22d2 100644
--- a/compiler/utils/mips64/assembler_mips64.h
+++ b/compiler/utils/mips64/assembler_mips64.h
@@ -123,15 +123,19 @@
void Sra(GpuRegister rd, GpuRegister rt, int shamt);
void Sllv(GpuRegister rd, GpuRegister rt, GpuRegister rs);
void Srlv(GpuRegister rd, GpuRegister rt, GpuRegister rs);
+ void Rotrv(GpuRegister rd, GpuRegister rt, GpuRegister rs);
void Srav(GpuRegister rd, GpuRegister rt, GpuRegister rs);
void Dsll(GpuRegister rd, GpuRegister rt, int shamt); // MIPS64
void Dsrl(GpuRegister rd, GpuRegister rt, int shamt); // MIPS64
+ void Drotr(GpuRegister rd, GpuRegister rt, int shamt);
void Dsra(GpuRegister rd, GpuRegister rt, int shamt); // MIPS64
void Dsll32(GpuRegister rd, GpuRegister rt, int shamt); // MIPS64
void Dsrl32(GpuRegister rd, GpuRegister rt, int shamt); // MIPS64
+ void Drotr32(GpuRegister rd, GpuRegister rt, int shamt); // MIPS64
void Dsra32(GpuRegister rd, GpuRegister rt, int shamt); // MIPS64
void Dsllv(GpuRegister rd, GpuRegister rt, GpuRegister rs); // MIPS64
void Dsrlv(GpuRegister rd, GpuRegister rt, GpuRegister rs); // MIPS64
+ void Drotrv(GpuRegister rd, GpuRegister rt, GpuRegister rs); // MIPS64
void Dsrav(GpuRegister rd, GpuRegister rt, GpuRegister rs); // MIPS64
void Lb(GpuRegister rt, GpuRegister rs, uint16_t imm16);
diff --git a/disassembler/disassembler_mips.cc b/disassembler/disassembler_mips.cc
index faa2d2d..c2f23aa 100644
--- a/disassembler/disassembler_mips.cc
+++ b/disassembler/disassembler_mips.cc
@@ -58,9 +58,10 @@
// 0, 1, movci
{ kRTypeMask, 2, "srl", "DTA", },
{ kRTypeMask, 3, "sra", "DTA", },
- { kRTypeMask, 4, "sllv", "DTS", },
- { kRTypeMask, 6, "srlv", "DTS", },
- { kRTypeMask, 7, "srav", "DTS", },
+ { kRTypeMask | (0x1f << 6), 4, "sllv", "DTS", },
+ { kRTypeMask | (0x1f << 6), 6, "srlv", "DTS", },
+ { kRTypeMask | (0x1f << 6), (1 << 6) | 6, "rotrv", "DTS", },
+ { kRTypeMask | (0x1f << 6), 7, "srav", "DTS", },
{ kRTypeMask, 8, "jr", "S", },
{ kRTypeMask | (0x1f << 11), 9 | (31 << 11), "jalr", "S", }, // rd = 31 is implicit.
{ kRTypeMask | (0x1f << 11), 9, "jr", "S", }, // rd = 0 is implicit.
@@ -74,9 +75,10 @@
{ kRTypeMask, 17, "mthi", "S", },
{ kRTypeMask, 18, "mflo", "D", },
{ kRTypeMask, 19, "mtlo", "S", },
- { kRTypeMask, 20, "dsllv", "DTS", },
- { kRTypeMask, 22, "dsrlv", "DTS", },
- { kRTypeMask, 23, "dsrav", "DTS", },
+ { kRTypeMask | (0x1f << 6), 20, "dsllv", "DTS", },
+ { kRTypeMask | (0x1f << 6), 22, "dsrlv", "DTS", },
+ { kRTypeMask | (0x1f << 6), (1 << 6) | 22, "drotrv", "DTS", },
+ { kRTypeMask | (0x1f << 6), 23, "dsrav", "DTS", },
{ kRTypeMask | (0x1f << 6), 24, "mult", "ST", },
{ kRTypeMask | (0x1f << 6), 25, "multu", "ST", },
{ kRTypeMask | (0x1f << 6), 26, "div", "ST", },
@@ -99,13 +101,14 @@
{ kRTypeMask, 46, "dsub", "DST", },
{ kRTypeMask, 47, "dsubu", "DST", },
// TODO: tge[u], tlt[u], teg, tne
- { kRTypeMask, 56, "dsll", "DTA", },
- { kRTypeMask, 58, "dsrl", "DTA", },
- { kRTypeMask, 59, "dsra", "DTA", },
- { kRTypeMask, 60, "dsll32", "DTA", },
- { kRTypeMask | (0x1f << 21), 62 | (1 << 21), "drotr32", "DTA", },
- { kRTypeMask, 62, "dsrl32", "DTA", },
- { kRTypeMask, 63, "dsra32", "DTA", },
+ { kRTypeMask | (0x1f << 21), 56, "dsll", "DTA", },
+ { kRTypeMask | (0x1f << 21), 58, "dsrl", "DTA", },
+ { kRTypeMask | (0x1f << 21), (1 << 21) | 58, "drotr", "DTA", },
+ { kRTypeMask | (0x1f << 21), 59, "dsra", "DTA", },
+ { kRTypeMask | (0x1f << 21), 60, "dsll32", "DTA", },
+ { kRTypeMask | (0x1f << 21), 62, "dsrl32", "DTA", },
+ { kRTypeMask | (0x1f << 21), (1 << 21) | 62, "drotr32", "DTA", },
+ { kRTypeMask | (0x1f << 21), 63, "dsra32", "DTA", },
// SPECIAL0
{ kSpecial0Mask | 0x7ff, (2 << 6) | 24, "mul", "DST" },
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index dbf5365..ea61b43 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -26,7 +26,6 @@
#include <vector>
#include "arch/instruction_set_features.h"
-#include "art_code.h"
#include "art_field-inl.h"
#include "art_method-inl.h"
#include "base/unix_file/fd_file.h"
@@ -1967,10 +1966,13 @@
InstructionSetPointerSize(state->oat_dumper_->GetOatInstructionSet());
const void* quick_oat_code_begin = state->GetQuickOatCodeBegin(method);
const void* quick_oat_code_end = state->GetQuickOatCodeEnd(method);
- ArtCode art_code(method);
+ OatQuickMethodHeader* method_header = reinterpret_cast<OatQuickMethodHeader*>(
+ reinterpret_cast<uintptr_t>(quick_oat_code_begin) - sizeof(OatQuickMethodHeader));
if (method->IsNative()) {
- DCHECK(art_code.GetNativeGcMap(image_pointer_size) == nullptr) << PrettyMethod(method);
- DCHECK(art_code.GetMappingTable(image_pointer_size) == nullptr) << PrettyMethod(method);
+ if (!Runtime::Current()->GetClassLinker()->IsQuickGenericJniStub(quick_oat_code_begin)) {
+ DCHECK(method_header->GetNativeGcMap() == nullptr) << PrettyMethod(method);
+ DCHECK(method_header->GetMappingTable() == nullptr) << PrettyMethod(method);
+ }
bool first_occurrence;
uint32_t quick_oat_code_size = state->GetQuickOatCodeSize(method);
state->ComputeOatSize(quick_oat_code_begin, &first_occurrence);
@@ -1984,8 +1986,6 @@
} else if (method->IsAbstract() || method->IsCalleeSaveMethod() ||
method->IsResolutionMethod() || method->IsImtConflictMethod() ||
method->IsImtUnimplementedMethod() || method->IsClassInitializer()) {
- DCHECK(art_code.GetNativeGcMap(image_pointer_size) == nullptr) << PrettyMethod(method);
- DCHECK(art_code.GetMappingTable(image_pointer_size) == nullptr) << PrettyMethod(method);
} else {
const DexFile::CodeItem* code_item = method->GetCodeItem();
size_t dex_instruction_bytes = code_item->insns_size_in_code_units_ * 2;
@@ -1993,22 +1993,22 @@
bool first_occurrence;
size_t gc_map_bytes = state->ComputeOatSize(
- art_code.GetNativeGcMap(image_pointer_size), &first_occurrence);
+ method_header->GetNativeGcMap(), &first_occurrence);
if (first_occurrence) {
state->stats_.gc_map_bytes += gc_map_bytes;
}
size_t pc_mapping_table_bytes = state->ComputeOatSize(
- art_code.GetMappingTable(image_pointer_size), &first_occurrence);
+ method_header->GetMappingTable(), &first_occurrence);
if (first_occurrence) {
state->stats_.pc_mapping_table_bytes += pc_mapping_table_bytes;
}
size_t vmap_table_bytes = 0u;
- if (!art_code.IsOptimized(image_pointer_size)) {
+ if (!method_header->IsOptimized()) {
// Method compiled with the optimizing compiler have no vmap table.
vmap_table_bytes = state->ComputeOatSize(
- art_code.GetVmapTable(image_pointer_size), &first_occurrence);
+ method_header->GetVmapTable(), &first_occurrence);
if (first_occurrence) {
state->stats_.vmap_table_bytes += vmap_table_bytes;
}
diff --git a/runtime/Android.mk b/runtime/Android.mk
index 8fe3fa2..9236ffb 100644
--- a/runtime/Android.mk
+++ b/runtime/Android.mk
@@ -19,7 +19,6 @@
include art/build/Android.common_build.mk
LIBART_COMMON_SRC_FILES := \
- art_code.cc \
art_field.cc \
art_method.cc \
atomic.cc.arm \
@@ -156,6 +155,7 @@
oat_file.cc \
oat_file_assistant.cc \
oat_file_manager.cc \
+ oat_quick_method_header.cc \
object_lock.cc \
offsets.cc \
os_linux.cc \
diff --git a/runtime/arch/arch_test.cc b/runtime/arch/arch_test.cc
index e676a09..d6ba304 100644
--- a/runtime/arch/arch_test.cc
+++ b/runtime/arch/arch_test.cc
@@ -39,7 +39,7 @@
runtime->SetInstructionSet(isa);
ArtMethod* save_method = runtime->CreateCalleeSaveMethod();
runtime->SetCalleeSaveMethod(save_method, type);
- QuickMethodFrameInfo frame_info = ArtCode(save_method).GetQuickFrameInfo();
+ QuickMethodFrameInfo frame_info = runtime->GetRuntimeMethodFrameInfo(save_method);
EXPECT_EQ(frame_info.FrameSizeInBytes(), save_size) << "Expected and real size differs for "
<< type << " core spills=" << std::hex << frame_info.CoreSpillMask() << " fp spills="
<< frame_info.FpSpillMask() << std::dec;
diff --git a/runtime/arch/arm/context_arm.cc b/runtime/arch/arm/context_arm.cc
index d5c7846..9cbec1e 100644
--- a/runtime/arch/arm/context_arm.cc
+++ b/runtime/arch/arm/context_arm.cc
@@ -16,9 +16,9 @@
#include "context_arm.h"
-#include "art_method-inl.h"
#include "base/bit_utils.h"
#include "quick/quick_method_frame_info.h"
+#include "thread-inl.h"
namespace art {
namespace arm {
@@ -37,23 +37,21 @@
arg0_ = 0;
}
-void ArmContext::FillCalleeSaves(const StackVisitor& fr) {
- ArtCode art_code = fr.GetCurrentCode();
- const QuickMethodFrameInfo frame_info = art_code.GetQuickFrameInfo();
+void ArmContext::FillCalleeSaves(uint8_t* frame, const QuickMethodFrameInfo& frame_info) {
int spill_pos = 0;
// Core registers come first, from the highest down to the lowest.
uint32_t core_regs = frame_info.CoreSpillMask();
DCHECK_EQ(0u, core_regs & (static_cast<uint32_t>(-1) << kNumberOfCoreRegisters));
for (uint32_t core_reg : HighToLowBits(core_regs)) {
- gprs_[core_reg] = fr.CalleeSaveAddress(spill_pos, frame_info.FrameSizeInBytes());
+ gprs_[core_reg] = CalleeSaveAddress(frame, spill_pos, frame_info.FrameSizeInBytes());
++spill_pos;
}
DCHECK_EQ(spill_pos, POPCOUNT(frame_info.CoreSpillMask()));
// FP registers come second, from the highest down to the lowest.
for (uint32_t fp_reg : HighToLowBits(frame_info.FpSpillMask())) {
- fprs_[fp_reg] = fr.CalleeSaveAddress(spill_pos, frame_info.FrameSizeInBytes());
+ fprs_[fp_reg] = CalleeSaveAddress(frame, spill_pos, frame_info.FrameSizeInBytes());
++spill_pos;
}
DCHECK_EQ(spill_pos, POPCOUNT(frame_info.CoreSpillMask()) + POPCOUNT(frame_info.FpSpillMask()));
diff --git a/runtime/arch/arm/context_arm.h b/runtime/arch/arm/context_arm.h
index ea31055..2623ee9 100644
--- a/runtime/arch/arm/context_arm.h
+++ b/runtime/arch/arm/context_arm.h
@@ -35,7 +35,7 @@
void Reset() OVERRIDE;
- void FillCalleeSaves(const StackVisitor& fr) OVERRIDE SHARED_REQUIRES(Locks::mutator_lock_);
+ void FillCalleeSaves(uint8_t* frame, const QuickMethodFrameInfo& fr) OVERRIDE;
void SetSP(uintptr_t new_sp) OVERRIDE {
SetGPR(SP, new_sp);
diff --git a/runtime/arch/arm64/context_arm64.cc b/runtime/arch/arm64/context_arm64.cc
index cdc03fe..d5d1ec7 100644
--- a/runtime/arch/arm64/context_arm64.cc
+++ b/runtime/arch/arm64/context_arm64.cc
@@ -18,9 +18,9 @@
#include "context_arm64.h"
-#include "art_method-inl.h"
#include "base/bit_utils.h"
#include "quick/quick_method_frame_info.h"
+#include "thread-inl.h"
namespace art {
namespace arm64 {
@@ -39,21 +39,19 @@
arg0_ = 0;
}
-void Arm64Context::FillCalleeSaves(const StackVisitor& fr) {
- ArtCode code = fr.GetCurrentCode();
- const QuickMethodFrameInfo frame_info = code.GetQuickFrameInfo();
+void Arm64Context::FillCalleeSaves(uint8_t* frame, const QuickMethodFrameInfo& frame_info) {
int spill_pos = 0;
// Core registers come first, from the highest down to the lowest.
for (uint32_t core_reg : HighToLowBits(frame_info.CoreSpillMask())) {
- gprs_[core_reg] = fr.CalleeSaveAddress(spill_pos, frame_info.FrameSizeInBytes());
+ gprs_[core_reg] = CalleeSaveAddress(frame, spill_pos, frame_info.FrameSizeInBytes());
++spill_pos;
}
DCHECK_EQ(spill_pos, POPCOUNT(frame_info.CoreSpillMask()));
// FP registers come second, from the highest down to the lowest.
for (uint32_t fp_reg : HighToLowBits(frame_info.FpSpillMask())) {
- fprs_[fp_reg] = fr.CalleeSaveAddress(spill_pos, frame_info.FrameSizeInBytes());
+ fprs_[fp_reg] = CalleeSaveAddress(frame, spill_pos, frame_info.FrameSizeInBytes());
++spill_pos;
}
DCHECK_EQ(spill_pos, POPCOUNT(frame_info.CoreSpillMask()) + POPCOUNT(frame_info.FpSpillMask()));
diff --git a/runtime/arch/arm64/context_arm64.h b/runtime/arch/arm64/context_arm64.h
index 11314e0..105e784 100644
--- a/runtime/arch/arm64/context_arm64.h
+++ b/runtime/arch/arm64/context_arm64.h
@@ -35,7 +35,7 @@
void Reset() OVERRIDE;
- void FillCalleeSaves(const StackVisitor& fr) OVERRIDE SHARED_REQUIRES(Locks::mutator_lock_);
+ void FillCalleeSaves(uint8_t* frame, const QuickMethodFrameInfo& fr) OVERRIDE;
void SetSP(uintptr_t new_sp) OVERRIDE {
SetGPR(SP, new_sp);
diff --git a/runtime/arch/context.h b/runtime/arch/context.h
index 9af7c04..a500648 100644
--- a/runtime/arch/context.h
+++ b/runtime/arch/context.h
@@ -25,7 +25,7 @@
namespace art {
-class StackVisitor;
+class QuickMethodFrameInfo;
// Representation of a thread's context on the executing machine, used to implement long jumps in
// the quick stack frame layout.
@@ -39,10 +39,18 @@
// Re-initializes the registers for context re-use.
virtual void Reset() = 0;
+ static uintptr_t* CalleeSaveAddress(uint8_t* frame, int num, size_t frame_size) {
+ // Callee saves are held at the top of the frame
+ uint8_t* save_addr = frame + frame_size - ((num + 1) * sizeof(void*));
+#if defined(__i386__) || defined(__x86_64__)
+ save_addr -= sizeof(void*); // account for return address
+#endif
+ return reinterpret_cast<uintptr_t*>(save_addr);
+ }
+
// Reads values from callee saves in the given frame. The frame also holds
// the method that holds the layout.
- virtual void FillCalleeSaves(const StackVisitor& fr)
- SHARED_REQUIRES(Locks::mutator_lock_) = 0;
+ virtual void FillCalleeSaves(uint8_t* frame, const QuickMethodFrameInfo& fr) = 0;
// Sets the stack pointer value.
virtual void SetSP(uintptr_t new_sp) = 0;
diff --git a/runtime/arch/mips/context_mips.cc b/runtime/arch/mips/context_mips.cc
index dba62d9..4dedb33 100644
--- a/runtime/arch/mips/context_mips.cc
+++ b/runtime/arch/mips/context_mips.cc
@@ -16,7 +16,6 @@
#include "context_mips.h"
-#include "art_method-inl.h"
#include "base/bit_utils.h"
#include "quick/quick_method_frame_info.h"
@@ -37,21 +36,19 @@
arg0_ = 0;
}
-void MipsContext::FillCalleeSaves(const StackVisitor& fr) {
- ArtCode code = fr.GetCurrentCode();
- const QuickMethodFrameInfo frame_info = code.GetQuickFrameInfo();
+void MipsContext::FillCalleeSaves(uint8_t* frame, const QuickMethodFrameInfo& frame_info) {
int spill_pos = 0;
// Core registers come first, from the highest down to the lowest.
for (uint32_t core_reg : HighToLowBits(frame_info.CoreSpillMask())) {
- gprs_[core_reg] = fr.CalleeSaveAddress(spill_pos, frame_info.FrameSizeInBytes());
+ gprs_[core_reg] = CalleeSaveAddress(frame, spill_pos, frame_info.FrameSizeInBytes());
++spill_pos;
}
DCHECK_EQ(spill_pos, POPCOUNT(frame_info.CoreSpillMask()));
// FP registers come second, from the highest down to the lowest.
for (uint32_t fp_reg : HighToLowBits(frame_info.FpSpillMask())) {
- fprs_[fp_reg] = fr.CalleeSaveAddress(spill_pos, frame_info.FrameSizeInBytes());
+ fprs_[fp_reg] = CalleeSaveAddress(frame, spill_pos, frame_info.FrameSizeInBytes());
++spill_pos;
}
DCHECK_EQ(spill_pos, POPCOUNT(frame_info.CoreSpillMask()) + POPCOUNT(frame_info.FpSpillMask()));
diff --git a/runtime/arch/mips/context_mips.h b/runtime/arch/mips/context_mips.h
index 0affe53..f1e2905 100644
--- a/runtime/arch/mips/context_mips.h
+++ b/runtime/arch/mips/context_mips.h
@@ -34,7 +34,7 @@
void Reset() OVERRIDE;
- void FillCalleeSaves(const StackVisitor& fr) OVERRIDE SHARED_REQUIRES(Locks::mutator_lock_);
+ void FillCalleeSaves(uint8_t* frame, const QuickMethodFrameInfo& fr) OVERRIDE;
void SetSP(uintptr_t new_sp) OVERRIDE {
SetGPR(SP, new_sp);
diff --git a/runtime/arch/mips64/context_mips64.cc b/runtime/arch/mips64/context_mips64.cc
index d808c9e..bd1ac3b 100644
--- a/runtime/arch/mips64/context_mips64.cc
+++ b/runtime/arch/mips64/context_mips64.cc
@@ -16,7 +16,6 @@
#include "context_mips64.h"
-#include "art_method-inl.h"
#include "base/bit_utils.h"
#include "quick/quick_method_frame_info.h"
@@ -37,21 +36,19 @@
arg0_ = 0;
}
-void Mips64Context::FillCalleeSaves(const StackVisitor& fr) {
- ArtCode code = fr.GetCurrentCode();
- const QuickMethodFrameInfo frame_info = code.GetQuickFrameInfo();
+void Mips64Context::FillCalleeSaves(uint8_t* frame, const QuickMethodFrameInfo& frame_info) {
int spill_pos = 0;
// Core registers come first, from the highest down to the lowest.
for (uint32_t core_reg : HighToLowBits(frame_info.CoreSpillMask())) {
- gprs_[core_reg] = fr.CalleeSaveAddress(spill_pos, frame_info.FrameSizeInBytes());
+ gprs_[core_reg] = CalleeSaveAddress(frame, spill_pos, frame_info.FrameSizeInBytes());
++spill_pos;
}
DCHECK_EQ(spill_pos, POPCOUNT(frame_info.CoreSpillMask()));
// FP registers come second, from the highest down to the lowest.
for (uint32_t fp_reg : HighToLowBits(frame_info.FpSpillMask())) {
- fprs_[fp_reg] = fr.CalleeSaveAddress(spill_pos, frame_info.FrameSizeInBytes());
+ fprs_[fp_reg] = CalleeSaveAddress(frame, spill_pos, frame_info.FrameSizeInBytes());
++spill_pos;
}
DCHECK_EQ(spill_pos, POPCOUNT(frame_info.CoreSpillMask()) + POPCOUNT(frame_info.FpSpillMask()));
diff --git a/runtime/arch/mips64/context_mips64.h b/runtime/arch/mips64/context_mips64.h
index 84b1c9b..89fbf8f 100644
--- a/runtime/arch/mips64/context_mips64.h
+++ b/runtime/arch/mips64/context_mips64.h
@@ -34,7 +34,7 @@
void Reset() OVERRIDE;
- void FillCalleeSaves(const StackVisitor& fr) OVERRIDE SHARED_REQUIRES(Locks::mutator_lock_);
+ void FillCalleeSaves(uint8_t* frame, const QuickMethodFrameInfo& fr) OVERRIDE;
void SetSP(uintptr_t new_sp) OVERRIDE {
SetGPR(SP, new_sp);
diff --git a/runtime/arch/x86/context_x86.cc b/runtime/arch/x86/context_x86.cc
index 0d88dd0..077d2db 100644
--- a/runtime/arch/x86/context_x86.cc
+++ b/runtime/arch/x86/context_x86.cc
@@ -16,10 +16,8 @@
#include "context_x86.h"
-#include "art_code.h"
#include "base/bit_utils.h"
#include "quick/quick_method_frame_info.h"
-#include "stack.h"
namespace art {
namespace x86 {
@@ -37,9 +35,7 @@
arg0_ = 0;
}
-void X86Context::FillCalleeSaves(const StackVisitor& fr) {
- ArtCode code = fr.GetCurrentCode();
- const QuickMethodFrameInfo frame_info = code.GetQuickFrameInfo();
+void X86Context::FillCalleeSaves(uint8_t* frame, const QuickMethodFrameInfo& frame_info) {
int spill_pos = 0;
// Core registers come first, from the highest down to the lowest.
@@ -47,7 +43,7 @@
frame_info.CoreSpillMask() & ~(static_cast<uint32_t>(-1) << kNumberOfCpuRegisters);
DCHECK_EQ(1, POPCOUNT(frame_info.CoreSpillMask() & ~core_regs)); // Return address spill.
for (uint32_t core_reg : HighToLowBits(core_regs)) {
- gprs_[core_reg] = fr.CalleeSaveAddress(spill_pos, frame_info.FrameSizeInBytes());
+ gprs_[core_reg] = CalleeSaveAddress(frame, spill_pos, frame_info.FrameSizeInBytes());
++spill_pos;
}
DCHECK_EQ(spill_pos, POPCOUNT(frame_info.CoreSpillMask()) - 1);
@@ -58,9 +54,9 @@
for (uint32_t fp_reg : HighToLowBits(fp_regs)) {
// Two void* per XMM register.
fprs_[2 * fp_reg] = reinterpret_cast<uint32_t*>(
- fr.CalleeSaveAddress(spill_pos + 1, frame_info.FrameSizeInBytes()));
+ CalleeSaveAddress(frame, spill_pos + 1, frame_info.FrameSizeInBytes()));
fprs_[2 * fp_reg + 1] = reinterpret_cast<uint32_t*>(
- fr.CalleeSaveAddress(spill_pos, frame_info.FrameSizeInBytes()));
+ CalleeSaveAddress(frame, spill_pos, frame_info.FrameSizeInBytes()));
spill_pos += 2;
}
DCHECK_EQ(spill_pos,
diff --git a/runtime/arch/x86/context_x86.h b/runtime/arch/x86/context_x86.h
index 59beb12..f482d9f 100644
--- a/runtime/arch/x86/context_x86.h
+++ b/runtime/arch/x86/context_x86.h
@@ -34,7 +34,7 @@
void Reset() OVERRIDE;
- void FillCalleeSaves(const StackVisitor& fr) OVERRIDE SHARED_REQUIRES(Locks::mutator_lock_);
+ void FillCalleeSaves(uint8_t* frame, const QuickMethodFrameInfo& fr) OVERRIDE;
void SetSP(uintptr_t new_sp) OVERRIDE {
SetGPR(ESP, new_sp);
diff --git a/runtime/arch/x86_64/context_x86_64.cc b/runtime/arch/x86_64/context_x86_64.cc
index 12c94bc..7c49e9c 100644
--- a/runtime/arch/x86_64/context_x86_64.cc
+++ b/runtime/arch/x86_64/context_x86_64.cc
@@ -16,10 +16,8 @@
#include "context_x86_64.h"
-#include "art_code.h"
#include "base/bit_utils.h"
#include "quick/quick_method_frame_info.h"
-#include "stack.h"
namespace art {
namespace x86_64 {
@@ -37,9 +35,7 @@
arg0_ = 0;
}
-void X86_64Context::FillCalleeSaves(const StackVisitor& fr) {
- ArtCode code = fr.GetCurrentCode();
- const QuickMethodFrameInfo frame_info = code.GetQuickFrameInfo();
+void X86_64Context::FillCalleeSaves(uint8_t* frame, const QuickMethodFrameInfo& frame_info) {
int spill_pos = 0;
// Core registers come first, from the highest down to the lowest.
@@ -47,7 +43,7 @@
frame_info.CoreSpillMask() & ~(static_cast<uint32_t>(-1) << kNumberOfCpuRegisters);
DCHECK_EQ(1, POPCOUNT(frame_info.CoreSpillMask() & ~core_regs)); // Return address spill.
for (uint32_t core_reg : HighToLowBits(core_regs)) {
- gprs_[core_reg] = fr.CalleeSaveAddress(spill_pos, frame_info.FrameSizeInBytes());
+ gprs_[core_reg] = CalleeSaveAddress(frame, spill_pos, frame_info.FrameSizeInBytes());
++spill_pos;
}
DCHECK_EQ(spill_pos, POPCOUNT(frame_info.CoreSpillMask()) - 1);
@@ -57,7 +53,7 @@
DCHECK_EQ(0u, fp_regs & (static_cast<uint32_t>(-1) << kNumberOfFloatRegisters));
for (uint32_t fp_reg : HighToLowBits(fp_regs)) {
fprs_[fp_reg] = reinterpret_cast<uint64_t*>(
- fr.CalleeSaveAddress(spill_pos, frame_info.FrameSizeInBytes()));
+ CalleeSaveAddress(frame, spill_pos, frame_info.FrameSizeInBytes()));
++spill_pos;
}
DCHECK_EQ(spill_pos,
diff --git a/runtime/arch/x86_64/context_x86_64.h b/runtime/arch/x86_64/context_x86_64.h
index f05b7f0..46f2b63 100644
--- a/runtime/arch/x86_64/context_x86_64.h
+++ b/runtime/arch/x86_64/context_x86_64.h
@@ -34,7 +34,7 @@
void Reset() OVERRIDE;
- void FillCalleeSaves(const StackVisitor& fr) OVERRIDE SHARED_REQUIRES(Locks::mutator_lock_);
+ void FillCalleeSaves(uint8_t* frame, const QuickMethodFrameInfo& fr) OVERRIDE;
void SetSP(uintptr_t new_sp) OVERRIDE {
SetGPR(RSP, new_sp);
diff --git a/runtime/art_code.cc b/runtime/art_code.cc
deleted file mode 100644
index ad0b170..0000000
--- a/runtime/art_code.cc
+++ /dev/null
@@ -1,333 +0,0 @@
-/*
- * Copyright (C) 2015 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 "art_code.h"
-
-#include "art_method.h"
-#include "art_method-inl.h"
-#include "class_linker.h"
-#include "entrypoints/runtime_asm_entrypoints.h"
-#include "handle_scope.h"
-#include "jit/jit.h"
-#include "jit/jit_code_cache.h"
-#include "mapping_table.h"
-#include "oat.h"
-#include "runtime.h"
-#include "utils.h"
-
-namespace art {
-
- // Converts a dex PC to a native PC.
-uintptr_t ArtCode::ToNativeQuickPc(const uint32_t dex_pc,
- bool is_for_catch_handler,
- bool abort_on_failure)
- SHARED_REQUIRES(Locks::mutator_lock_) {
- const void* entry_point = GetQuickOatEntryPoint(sizeof(void*));
- if (IsOptimized(sizeof(void*))) {
- // Optimized code does not have a mapping table. Search for the dex-to-pc
- // mapping in stack maps.
- CodeInfo code_info = GetOptimizedCodeInfo();
- StackMapEncoding encoding = code_info.ExtractEncoding();
-
- // All stack maps are stored in the same CodeItem section, safepoint stack
- // maps first, then catch stack maps. We use `is_for_catch_handler` to select
- // the order of iteration.
- StackMap stack_map =
- LIKELY(is_for_catch_handler) ? code_info.GetCatchStackMapForDexPc(dex_pc, encoding)
- : code_info.GetStackMapForDexPc(dex_pc, encoding);
- if (stack_map.IsValid()) {
- return reinterpret_cast<uintptr_t>(entry_point) + stack_map.GetNativePcOffset(encoding);
- }
- } else {
- MappingTable table((entry_point != nullptr) ? GetMappingTable(sizeof(void*)) : nullptr);
- if (table.TotalSize() == 0) {
- DCHECK_EQ(dex_pc, 0U);
- return 0; // Special no mapping/pc == 0 case
- }
- // Assume the caller wants a dex-to-pc mapping so check here first.
- typedef MappingTable::DexToPcIterator It;
- for (It cur = table.DexToPcBegin(), end = table.DexToPcEnd(); cur != end; ++cur) {
- if (cur.DexPc() == dex_pc) {
- return reinterpret_cast<uintptr_t>(entry_point) + cur.NativePcOffset();
- }
- }
- // Now check pc-to-dex mappings.
- typedef MappingTable::PcToDexIterator It2;
- for (It2 cur = table.PcToDexBegin(), end = table.PcToDexEnd(); cur != end; ++cur) {
- if (cur.DexPc() == dex_pc) {
- return reinterpret_cast<uintptr_t>(entry_point) + cur.NativePcOffset();
- }
- }
- }
-
- if (abort_on_failure) {
- LOG(FATAL) << "Failed to find native offset for dex pc 0x" << std::hex << dex_pc
- << " in " << PrettyMethod(method_);
- }
- return UINTPTR_MAX;
-}
-
-bool ArtCode::IsOptimized(size_t pointer_size) SHARED_REQUIRES(Locks::mutator_lock_) {
- // Temporary solution for detecting if a method has been optimized: the compiler
- // does not create a GC map. Instead, the vmap table contains the stack map
- // (as in stack_map.h).
- return !method_->IsNative()
- && method_->GetEntryPointFromQuickCompiledCodePtrSize(pointer_size) != nullptr
- && GetQuickOatEntryPoint(pointer_size) != nullptr
- && GetNativeGcMap(pointer_size) == nullptr;
-}
-
-CodeInfo ArtCode::GetOptimizedCodeInfo() {
- DCHECK(IsOptimized(sizeof(void*)));
- const void* code_pointer = EntryPointToCodePointer(GetQuickOatEntryPoint(sizeof(void*)));
- DCHECK(code_pointer != nullptr);
- uint32_t offset =
- reinterpret_cast<const OatQuickMethodHeader*>(code_pointer)[-1].vmap_table_offset_;
- const void* data =
- reinterpret_cast<const void*>(reinterpret_cast<const uint8_t*>(code_pointer) - offset);
- return CodeInfo(data);
-}
-
-uintptr_t ArtCode::NativeQuickPcOffset(const uintptr_t pc) {
- const void* quick_entry_point = GetQuickOatEntryPoint(sizeof(void*));
- CHECK_NE(quick_entry_point, GetQuickToInterpreterBridge());
- CHECK_EQ(quick_entry_point,
- Runtime::Current()->GetInstrumentation()->GetQuickCodeFor(method_, sizeof(void*)));
- return pc - reinterpret_cast<uintptr_t>(quick_entry_point);
-}
-
-uint32_t ArtCode::ToDexPc(const uintptr_t pc, bool abort_on_failure) {
- const void* entry_point = GetQuickOatEntryPoint(sizeof(void*));
- uint32_t sought_offset = pc - reinterpret_cast<uintptr_t>(entry_point);
- if (IsOptimized(sizeof(void*))) {
- CodeInfo code_info = GetOptimizedCodeInfo();
- StackMapEncoding encoding = code_info.ExtractEncoding();
- StackMap stack_map = code_info.GetStackMapForNativePcOffset(sought_offset, encoding);
- if (stack_map.IsValid()) {
- return stack_map.GetDexPc(encoding);
- }
- } else {
- MappingTable table(entry_point != nullptr ? GetMappingTable(sizeof(void*)) : nullptr);
- if (table.TotalSize() == 0) {
- // NOTE: Special methods (see Mir2Lir::GenSpecialCase()) have an empty mapping
- // but they have no suspend checks and, consequently, we never call ToDexPc() for them.
- DCHECK(method_->IsNative() || method_->IsCalleeSaveMethod() || method_->IsProxyMethod())
- << PrettyMethod(method_);
- return DexFile::kDexNoIndex; // Special no mapping case
- }
- // Assume the caller wants a pc-to-dex mapping so check here first.
- typedef MappingTable::PcToDexIterator It;
- for (It cur = table.PcToDexBegin(), end = table.PcToDexEnd(); cur != end; ++cur) {
- if (cur.NativePcOffset() == sought_offset) {
- return cur.DexPc();
- }
- }
- // Now check dex-to-pc mappings.
- typedef MappingTable::DexToPcIterator It2;
- for (It2 cur = table.DexToPcBegin(), end = table.DexToPcEnd(); cur != end; ++cur) {
- if (cur.NativePcOffset() == sought_offset) {
- return cur.DexPc();
- }
- }
- }
- if (abort_on_failure) {
- LOG(FATAL) << "Failed to find Dex offset for PC offset " << reinterpret_cast<void*>(sought_offset)
- << "(PC " << reinterpret_cast<void*>(pc) << ", entry_point=" << entry_point
- << " current entry_point=" << GetQuickOatEntryPoint(sizeof(void*))
- << ") in " << PrettyMethod(method_);
- }
- return DexFile::kDexNoIndex;
-}
-
-const uint8_t* ArtCode::GetNativeGcMap(size_t pointer_size) {
- const void* code_pointer = EntryPointToCodePointer(GetQuickOatEntryPoint(pointer_size));
- if (code_pointer == nullptr) {
- return nullptr;
- }
- uint32_t offset =
- reinterpret_cast<const OatQuickMethodHeader*>(code_pointer)[-1].gc_map_offset_;
- if (UNLIKELY(offset == 0u)) {
- return nullptr;
- }
- return reinterpret_cast<const uint8_t*>(code_pointer) - offset;
-}
-
-const uint8_t* ArtCode::GetVmapTable(size_t pointer_size) {
- CHECK(!IsOptimized(pointer_size)) << "Unimplemented vmap table for optimized compiler";
- const void* code_pointer = EntryPointToCodePointer(GetQuickOatEntryPoint(pointer_size));
- if (code_pointer == nullptr) {
- return nullptr;
- }
- uint32_t offset =
- reinterpret_cast<const OatQuickMethodHeader*>(code_pointer)[-1].vmap_table_offset_;
- if (UNLIKELY(offset == 0u)) {
- return nullptr;
- }
- return reinterpret_cast<const uint8_t*>(code_pointer) - offset;
-}
-
-const uint8_t* ArtCode::GetMappingTable(size_t pointer_size) {
- const void* code_pointer = EntryPointToCodePointer(GetQuickOatEntryPoint(pointer_size));
- if (code_pointer == nullptr) {
- return nullptr;
- }
- uint32_t offset =
- reinterpret_cast<const OatQuickMethodHeader*>(code_pointer)[-1].mapping_table_offset_;
- if (UNLIKELY(offset == 0u)) {
- return nullptr;
- }
- return reinterpret_cast<const uint8_t*>(code_pointer) - offset;
-}
-
-// Counts the number of references in the parameter list of the corresponding method.
-// Note: Thus does _not_ include "this" for non-static methods.
-static uint32_t GetNumberOfReferenceArgsWithoutReceiver(ArtMethod* method)
- SHARED_REQUIRES(Locks::mutator_lock_) {
- uint32_t shorty_len;
- const char* shorty = method->GetShorty(&shorty_len);
- uint32_t refs = 0;
- for (uint32_t i = 1; i < shorty_len ; ++i) {
- if (shorty[i] == 'L') {
- refs++;
- }
- }
- return refs;
-}
-
-QuickMethodFrameInfo ArtCode::GetQuickFrameInfo() {
- Runtime* runtime = Runtime::Current();
-
- if (UNLIKELY(method_->IsAbstract())) {
- return runtime->GetCalleeSaveMethodFrameInfo(Runtime::kRefsAndArgs);
- }
-
- // This goes before IsProxyMethod since runtime methods have a null declaring class.
- if (UNLIKELY(method_->IsRuntimeMethod())) {
- return runtime->GetRuntimeMethodFrameInfo(method_);
- }
-
- // For Proxy method we add special handling for the direct method case (there is only one
- // direct method - constructor). Direct method is cloned from original
- // java.lang.reflect.Proxy class together with code and as a result it is executed as usual
- // quick compiled method without any stubs. So the frame info should be returned as it is a
- // quick method not a stub. However, if instrumentation stubs are installed, the
- // instrumentation->GetQuickCodeFor() returns the artQuickProxyInvokeHandler instead of an
- // oat code pointer, thus we have to add a special case here.
- if (UNLIKELY(method_->IsProxyMethod())) {
- if (method_->IsDirect()) {
- CHECK(method_->IsConstructor());
- const void* code_pointer =
- EntryPointToCodePointer(method_->GetEntryPointFromQuickCompiledCode());
- return reinterpret_cast<const OatQuickMethodHeader*>(code_pointer)[-1].frame_info_;
- } else {
- return runtime->GetCalleeSaveMethodFrameInfo(Runtime::kRefsAndArgs);
- }
- }
-
- const void* entry_point = runtime->GetInstrumentation()->GetQuickCodeFor(method_, sizeof(void*));
- ClassLinker* class_linker = runtime->GetClassLinker();
- // On failure, instead of null we get the quick-generic-jni-trampoline for native method
- // indicating the generic JNI, or the quick-to-interpreter-bridge (but not the trampoline)
- // for non-native methods. And we really shouldn't see a failure for non-native methods here.
- DCHECK(!class_linker->IsQuickToInterpreterBridge(entry_point));
-
- if (class_linker->IsQuickGenericJniStub(entry_point)) {
- // Generic JNI frame.
- DCHECK(method_->IsNative());
- uint32_t handle_refs = GetNumberOfReferenceArgsWithoutReceiver(method_) + 1;
- size_t scope_size = HandleScope::SizeOf(handle_refs);
- QuickMethodFrameInfo callee_info = runtime->GetCalleeSaveMethodFrameInfo(Runtime::kRefsAndArgs);
-
- // Callee saves + handle scope + method ref + alignment
- // Note: -sizeof(void*) since callee-save frame stores a whole method pointer.
- size_t frame_size = RoundUp(callee_info.FrameSizeInBytes() - sizeof(void*) +
- sizeof(ArtMethod*) + scope_size, kStackAlignment);
- return QuickMethodFrameInfo(frame_size, callee_info.CoreSpillMask(), callee_info.FpSpillMask());
- }
-
- const void* code_pointer = EntryPointToCodePointer(entry_point);
- return reinterpret_cast<const OatQuickMethodHeader*>(code_pointer)[-1].frame_info_;
-}
-
-void ArtCode::AssertPcIsWithinQuickCode(uintptr_t pc) {
- if (method_->IsNative() || method_->IsRuntimeMethod() || method_->IsProxyMethod()) {
- return;
- }
- if (pc == reinterpret_cast<uintptr_t>(GetQuickInstrumentationExitPc())) {
- return;
- }
- const void* code = method_->GetEntryPointFromQuickCompiledCode();
- if (code == GetQuickInstrumentationEntryPoint()) {
- return;
- }
- ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
- if (class_linker->IsQuickToInterpreterBridge(code) ||
- class_linker->IsQuickResolutionStub(code)) {
- return;
- }
- // If we are the JIT then we may have just compiled the method after the
- // IsQuickToInterpreterBridge check.
- jit::Jit* const jit = Runtime::Current()->GetJit();
- if (jit != nullptr &&
- jit->GetCodeCache()->ContainsCodePtr(reinterpret_cast<const void*>(code))) {
- return;
- }
-
- uint32_t code_size = reinterpret_cast<const OatQuickMethodHeader*>(
- EntryPointToCodePointer(code))[-1].code_size_;
- uintptr_t code_start = reinterpret_cast<uintptr_t>(code);
- CHECK(code_start <= pc && pc <= (code_start + code_size))
- << PrettyMethod(method_)
- << " pc=" << std::hex << pc
- << " code=" << code
- << " size=" << code_size;
-}
-
-bool ArtCode::PcIsWithinQuickCode(uintptr_t pc) {
- /*
- * During a stack walk, a return PC may point past-the-end of the code
- * in the case that the last instruction is a call that isn't expected to
- * return. Thus, we check <= code + GetCodeSize().
- *
- * NOTE: For Thumb both pc and code are offset by 1 indicating the Thumb state.
- */
- uintptr_t code = reinterpret_cast<uintptr_t>(EntryPointToCodePointer(
- method_->GetEntryPointFromQuickCompiledCode()));
- if (code == 0) {
- return pc == 0;
- }
- uintptr_t code_size = reinterpret_cast<const OatQuickMethodHeader*>(code)[-1].code_size_;
- return code <= pc && pc <= (code + code_size);
-}
-
-const void* ArtCode::GetQuickOatEntryPoint(size_t pointer_size) {
- if (method_->IsAbstract() || method_->IsRuntimeMethod() || method_->IsProxyMethod()) {
- return nullptr;
- }
- Runtime* runtime = Runtime::Current();
- ClassLinker* class_linker = runtime->GetClassLinker();
- const void* code = runtime->GetInstrumentation()->GetQuickCodeFor(method_, pointer_size);
- // On failure, instead of null we get the quick-generic-jni-trampoline for native method
- // indicating the generic JNI, or the quick-to-interpreter-bridge (but not the trampoline)
- // for non-native methods.
- if (class_linker->IsQuickToInterpreterBridge(code) ||
- class_linker->IsQuickGenericJniStub(code)) {
- return nullptr;
- }
- return code;
-}
-
-} // namespace art
diff --git a/runtime/art_code.h b/runtime/art_code.h
deleted file mode 100644
index 1d2d898..0000000
--- a/runtime/art_code.h
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright (C) 2015 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_ART_CODE_H_
-#define ART_RUNTIME_ART_CODE_H_
-
-#include "base/mutex.h"
-#include "offsets.h"
-#include "quick/quick_method_frame_info.h"
-#include "stack_map.h"
-
-namespace art {
-
-class ArtMethod;
-
-class ArtCode FINAL {
- public:
- explicit ArtCode(ArtMethod** method) : method_(*method) {}
- explicit ArtCode(ArtMethod* method) : method_(method) {}
- ArtCode() : method_(nullptr) {}
-
- // Converts a dex PC to a native PC.
- uintptr_t ToNativeQuickPc(const uint32_t dex_pc,
- bool is_for_catch_handler,
- bool abort_on_failure = true)
- SHARED_REQUIRES(Locks::mutator_lock_);
-
- bool IsOptimized(size_t pointer_size) SHARED_REQUIRES(Locks::mutator_lock_);
-
- CodeInfo GetOptimizedCodeInfo() SHARED_REQUIRES(Locks::mutator_lock_);
-
- uintptr_t NativeQuickPcOffset(const uintptr_t pc) SHARED_REQUIRES(Locks::mutator_lock_);
-
- // Converts a native PC to a dex PC.
- uint32_t ToDexPc(const uintptr_t pc, bool abort_on_failure = true)
- SHARED_REQUIRES(Locks::mutator_lock_);
-
- // Callers should wrap the uint8_t* in a GcMap instance for convenient access.
- const uint8_t* GetNativeGcMap(size_t pointer_size) SHARED_REQUIRES(Locks::mutator_lock_);
-
- const uint8_t* GetVmapTable(size_t pointer_size) SHARED_REQUIRES(Locks::mutator_lock_);
-
- const uint8_t* GetMappingTable(size_t pointer_size) SHARED_REQUIRES(Locks::mutator_lock_);
-
- QuickMethodFrameInfo GetQuickFrameInfo() SHARED_REQUIRES(Locks::mutator_lock_);
-
- FrameOffset GetReturnPcOffset() SHARED_REQUIRES(Locks::mutator_lock_) {
- return FrameOffset(GetFrameSizeInBytes() - sizeof(void*));
- }
-
- template <bool kCheckFrameSize = true>
- uint32_t GetFrameSizeInBytes() SHARED_REQUIRES(Locks::mutator_lock_) {
- uint32_t result = GetQuickFrameInfo().FrameSizeInBytes();
- if (kCheckFrameSize) {
- DCHECK_LE(static_cast<size_t>(kStackAlignment), result);
- }
- return result;
- }
-
- const void* GetQuickOatEntryPoint(size_t pointer_size) SHARED_REQUIRES(Locks::mutator_lock_);
-
- void AssertPcIsWithinQuickCode(uintptr_t pc) SHARED_REQUIRES(Locks::mutator_lock_);
-
- bool PcIsWithinQuickCode(uintptr_t pc) SHARED_REQUIRES(Locks::mutator_lock_);
-
- FrameOffset GetHandleScopeOffset() SHARED_REQUIRES(Locks::mutator_lock_) {
- constexpr size_t handle_scope_offset = sizeof(ArtMethod*);
- DCHECK_LT(handle_scope_offset, GetFrameSizeInBytes());
- return FrameOffset(handle_scope_offset);
- }
-
- ArtMethod* GetMethod() const { return method_; }
-
- private:
- ArtMethod* method_;
-};
-
-} // namespace art
-
-#endif // ART_RUNTIME_ART_CODE_H_
diff --git a/runtime/art_method.cc b/runtime/art_method.cc
index f9d9077..f5befdf 100644
--- a/runtime/art_method.cc
+++ b/runtime/art_method.cc
@@ -384,4 +384,28 @@
return oat_method.GetVmapTable();
}
+const OatQuickMethodHeader* ArtMethod::GetOatQuickMethodHeader(uintptr_t pc) {
+ if (IsRuntimeMethod() || IsProxyMethod()) {
+ return nullptr;
+ }
+
+ Runtime* runtime = Runtime::Current();
+ const void* code = runtime->GetInstrumentation()->GetQuickCodeFor(this, sizeof(void*));
+ DCHECK(code != nullptr);
+
+ if (runtime->GetClassLinker()->IsQuickGenericJniStub(code)) {
+ // The generic JNI does not have any method header.
+ return nullptr;
+ }
+
+ code = EntryPointToCodePointer(code);
+ OatQuickMethodHeader* method_header = reinterpret_cast<OatQuickMethodHeader*>(
+ reinterpret_cast<uintptr_t>(code) - sizeof(OatQuickMethodHeader));
+
+ // TODO(ngeoffray): validate the pc. Note that unit tests can give unrelated pcs (for
+ // example arch_test).
+ UNUSED(pc);
+ return method_header;
+}
+
} // namespace art
diff --git a/runtime/art_method.h b/runtime/art_method.h
index 9743250..9f1495c 100644
--- a/runtime/art_method.h
+++ b/runtime/art_method.h
@@ -32,6 +32,7 @@
namespace art {
union JValue;
+class OatQuickMethodHeader;
class ProfilingInfo;
class ScopedObjectAccessAlreadyRunnable;
class StringPiece;
@@ -434,6 +435,11 @@
const uint8_t* GetQuickenedInfo() SHARED_REQUIRES(Locks::mutator_lock_);
+ // Returns the method header for the compiled code containing 'pc'. Note that runtime
+ // methods will return null for this method, as they are not oat based.
+ const OatQuickMethodHeader* GetOatQuickMethodHeader(uintptr_t pc)
+ SHARED_REQUIRES(Locks::mutator_lock_);
+
protected:
// Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses".
// The class we are a part of.
diff --git a/runtime/check_reference_map_visitor.h b/runtime/check_reference_map_visitor.h
index e897351..b9ea475 100644
--- a/runtime/check_reference_map_visitor.h
+++ b/runtime/check_reference_map_visitor.h
@@ -17,9 +17,9 @@
#ifndef ART_RUNTIME_CHECK_REFERENCE_MAP_VISITOR_H_
#define ART_RUNTIME_CHECK_REFERENCE_MAP_VISITOR_H_
-#include "art_code.h"
#include "art_method-inl.h"
#include "gc_map.h"
+#include "oat_quick_method_header.h"
#include "scoped_thread_state_change.h"
#include "stack_map.h"
@@ -54,7 +54,7 @@
void CheckReferences(int* registers, int number_of_references, uint32_t native_pc_offset)
SHARED_REQUIRES(Locks::mutator_lock_) {
- if (GetCurrentCode().IsOptimized(sizeof(void*))) {
+ if (GetCurrentOatQuickMethodHeader()->IsOptimized()) {
CheckOptimizedMethod(registers, number_of_references, native_pc_offset);
} else {
CheckQuickMethod(registers, number_of_references, native_pc_offset);
@@ -65,7 +65,7 @@
void CheckOptimizedMethod(int* registers, int number_of_references, uint32_t native_pc_offset)
SHARED_REQUIRES(Locks::mutator_lock_) {
ArtMethod* m = GetMethod();
- CodeInfo code_info = GetCurrentCode().GetOptimizedCodeInfo();
+ CodeInfo code_info = GetCurrentOatQuickMethodHeader()->GetOptimizedCodeInfo();
StackMapEncoding encoding = code_info.ExtractEncoding();
StackMap stack_map = code_info.GetStackMapForNativePcOffset(native_pc_offset, encoding);
uint16_t number_of_dex_registers = m->GetCodeItem()->registers_size_;
@@ -109,7 +109,7 @@
void CheckQuickMethod(int* registers, int number_of_references, uint32_t native_pc_offset)
SHARED_REQUIRES(Locks::mutator_lock_) {
ArtMethod* m = GetMethod();
- NativePcOffsetToReferenceMap map(GetCurrentCode().GetNativeGcMap(sizeof(void*)));
+ NativePcOffsetToReferenceMap map(GetCurrentOatQuickMethodHeader()->GetNativeGcMap());
const uint8_t* ref_bitmap = map.FindBitMap(native_pc_offset);
CHECK(ref_bitmap);
for (int i = 0; i < number_of_references; ++i) {
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 395649e..81622e1 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -1208,7 +1208,7 @@
uint8_t* raw_arrays = nullptr;
if (dex_file.GetOatDexFile() != nullptr &&
dex_file.GetOatDexFile()->GetDexCacheArrays() != nullptr) {
- raw_arrays = const_cast<uint8_t*>(dex_file.GetOatDexFile()->GetDexCacheArrays());
+ raw_arrays = dex_file.GetOatDexFile()->GetDexCacheArrays();
} else if (dex_file.NumStringIds() != 0u || dex_file.NumTypeIds() != 0u ||
dex_file.NumMethodIds() != 0u || dex_file.NumFieldIds() != 0u) {
// NOTE: We "leak" the raw_arrays because we never destroy the dex cache.
@@ -6369,6 +6369,21 @@
}
}
+void ClassLinker::InsertDexFileInToClassLoader(mirror::Object* dex_file,
+ mirror::ClassLoader* class_loader) {
+ DCHECK(dex_file != nullptr);
+ DCHECK(class_loader != nullptr);
+ Thread* const self = Thread::Current();
+ WriterMutexLock mu(self, *Locks::classlinker_classes_lock_);
+ ClassTable* const table = class_loader->GetClassTable();
+ DCHECK(table != nullptr);
+ if (table->InsertDexFile(dex_file)) {
+ // It was not already inserted, perform the write barrier to let the GC know the class loader's
+ // class table was modified.
+ Runtime::Current()->GetHeap()->WriteBarrierEveryFieldOf(class_loader);
+ }
+}
+
void ClassLinker::CleanupClassLoaders() {
Thread* const self = Thread::Current();
WriterMutexLock mu(self, *Locks::classlinker_classes_lock_);
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index fd30a46..a2d38ac 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -526,8 +526,8 @@
// Clean up class loaders, this needs to happen after JNI weak globals are cleared.
void CleanupClassLoaders()
- SHARED_REQUIRES(Locks::mutator_lock_)
- REQUIRES(!Locks::classlinker_classes_lock_);
+ REQUIRES(!Locks::classlinker_classes_lock_)
+ SHARED_REQUIRES(Locks::mutator_lock_);
// Unlike GetOrCreateAllocatorForClassLoader, GetAllocatorForClassLoader asserts that the
// allocator for this class loader is already created.
@@ -537,8 +537,12 @@
// Return the linear alloc for a class loader if it is already allocated, otherwise allocate and
// set it. TODO: Consider using a lock other than classlinker_classes_lock_.
static LinearAlloc* GetOrCreateAllocatorForClassLoader(mirror::ClassLoader* class_loader)
- SHARED_REQUIRES(Locks::mutator_lock_)
- REQUIRES(!Locks::classlinker_classes_lock_);
+ REQUIRES(!Locks::classlinker_classes_lock_)
+ SHARED_REQUIRES(Locks::mutator_lock_);
+
+ void InsertDexFileInToClassLoader(mirror::Object* dex_file, mirror::ClassLoader* class_loader)
+ REQUIRES(!Locks::classlinker_classes_lock_)
+ SHARED_REQUIRES(Locks::mutator_lock_);
private:
struct ClassLoaderData {
diff --git a/runtime/class_table-inl.h b/runtime/class_table-inl.h
index dc60a2c..aef02b6 100644
--- a/runtime/class_table-inl.h
+++ b/runtime/class_table-inl.h
@@ -37,6 +37,9 @@
visitor.VisitRoot(root.AddressWithoutBarrier());
}
}
+ for (GcRoot<mirror::Object>& root : dex_files_) {
+ visitor.VisitRoot(root.AddressWithoutBarrier());
+ }
}
} // namespace art
diff --git a/runtime/class_table.cc b/runtime/class_table.cc
index 4b0cbc8..3ed1c95 100644
--- a/runtime/class_table.cc
+++ b/runtime/class_table.cc
@@ -137,4 +137,15 @@
return ComputeModifiedUtf8Hash(descriptor);
}
+bool ClassTable::InsertDexFile(mirror::Object* dex_file) {
+ DCHECK(dex_file != nullptr);
+ for (GcRoot<mirror::Object>& root : dex_files_) {
+ if (root.Read() == dex_file) {
+ return false;
+ }
+ }
+ dex_files_.push_back(GcRoot<mirror::Object>(dex_file));
+ return true;
+}
+
} // namespace art
diff --git a/runtime/class_table.h b/runtime/class_table.h
index 727392e..002bb56 100644
--- a/runtime/class_table.h
+++ b/runtime/class_table.h
@@ -50,12 +50,14 @@
// Used by image writer for checking.
bool Contains(mirror::Class* klass)
- REQUIRES(Locks::classlinker_classes_lock_) SHARED_REQUIRES(Locks::mutator_lock_);
+ REQUIRES(Locks::classlinker_classes_lock_)
+ SHARED_REQUIRES(Locks::mutator_lock_);
// Freeze the current class tables by allocating a new table and never updating or modifying the
// existing table. This helps prevents dirty pages after caused by inserting after zygote fork.
void FreezeSnapshot()
- REQUIRES(Locks::classlinker_classes_lock_) SHARED_REQUIRES(Locks::mutator_lock_);
+ REQUIRES(Locks::classlinker_classes_lock_)
+ SHARED_REQUIRES(Locks::mutator_lock_);
// Returns the number of classes in previous snapshots.
size_t NumZygoteClasses() const SHARED_REQUIRES(Locks::classlinker_classes_lock_);
@@ -65,17 +67,18 @@
// Update a class in the table with the new class. Returns the existing class which was replaced.
mirror::Class* UpdateClass(const char* descriptor, mirror::Class* new_klass, size_t hash)
- REQUIRES(Locks::classlinker_classes_lock_) SHARED_REQUIRES(Locks::mutator_lock_);
+ REQUIRES(Locks::classlinker_classes_lock_)
+ SHARED_REQUIRES(Locks::mutator_lock_);
// NO_THREAD_SAFETY_ANALYSIS for object marking requiring heap bitmap lock.
template<class Visitor>
void VisitRoots(Visitor& visitor)
- SHARED_REQUIRES(Locks::classlinker_classes_lock_, Locks::mutator_lock_)
- NO_THREAD_SAFETY_ANALYSIS;
+ NO_THREAD_SAFETY_ANALYSIS
+ SHARED_REQUIRES(Locks::classlinker_classes_lock_, Locks::mutator_lock_);
template<class Visitor>
void VisitRoots(const Visitor& visitor)
- SHARED_REQUIRES(Locks::classlinker_classes_lock_, Locks::mutator_lock_)
- NO_THREAD_SAFETY_ANALYSIS;
+ NO_THREAD_SAFETY_ANALYSIS
+ SHARED_REQUIRES(Locks::classlinker_classes_lock_, Locks::mutator_lock_);
// Return false if the callback told us to exit.
bool Visit(ClassVisitor* visitor)
@@ -85,13 +88,21 @@
SHARED_REQUIRES(Locks::classlinker_classes_lock_, Locks::mutator_lock_);
void Insert(mirror::Class* klass)
- REQUIRES(Locks::classlinker_classes_lock_) SHARED_REQUIRES(Locks::mutator_lock_);
+ REQUIRES(Locks::classlinker_classes_lock_)
+ SHARED_REQUIRES(Locks::mutator_lock_);
void InsertWithHash(mirror::Class* klass, size_t hash)
- REQUIRES(Locks::classlinker_classes_lock_) SHARED_REQUIRES(Locks::mutator_lock_);
+ REQUIRES(Locks::classlinker_classes_lock_)
+ SHARED_REQUIRES(Locks::mutator_lock_);
// Returns true if the class was found and removed, false otherwise.
bool Remove(const char* descriptor)
- REQUIRES(Locks::classlinker_classes_lock_) SHARED_REQUIRES(Locks::mutator_lock_);
+ REQUIRES(Locks::classlinker_classes_lock_)
+ SHARED_REQUIRES(Locks::mutator_lock_);
+
+ // Return true if we inserted the dex file, false if it already exists.
+ bool InsertDexFile(mirror::Object* dex_file)
+ REQUIRES(Locks::classlinker_classes_lock_)
+ SHARED_REQUIRES(Locks::mutator_lock_);
private:
class ClassDescriptorHashEquals {
@@ -123,6 +134,9 @@
// TODO: shard lock to have one per class loader.
// We have a vector to help prevent dirty pages after the zygote forks by calling FreezeSnapshot.
std::vector<ClassSet> classes_ GUARDED_BY(Locks::classlinker_classes_lock_);
+ // Dex files used by the class loader which may not be owned by the class loader. We keep these
+ // live so that we do not have issues closing any of the dex files.
+ std::vector<GcRoot<mirror::Object>> dex_files_ GUARDED_BY(Locks::classlinker_classes_lock_);
};
} // namespace art
diff --git a/runtime/entrypoints/entrypoint_utils.cc b/runtime/entrypoints/entrypoint_utils.cc
index 17e6aac..e57569e 100644
--- a/runtime/entrypoints/entrypoint_utils.cc
+++ b/runtime/entrypoints/entrypoint_utils.cc
@@ -16,7 +16,6 @@
#include "entrypoints/entrypoint_utils.h"
-#include "art_code.h"
#include "art_field-inl.h"
#include "art_method-inl.h"
#include "base/mutex.h"
@@ -31,6 +30,7 @@
#include "mirror/object-inl.h"
#include "mirror/object_array-inl.h"
#include "nth_caller_visitor.h"
+#include "oat_quick_method_header.h"
#include "reflection.h"
#include "scoped_thread_state_change.h"
#include "ScopedLocalRef.h"
@@ -359,33 +359,31 @@
const size_t callee_frame_size = GetCalleeSaveFrameSize(kRuntimeISA, type);
auto** caller_sp = reinterpret_cast<ArtMethod**>(
reinterpret_cast<uintptr_t>(sp) + callee_frame_size);
- ArtCode current_code = GetCallingCodeFrom(caller_sp);
+ const size_t callee_return_pc_offset = GetCalleeSaveReturnPcOffset(kRuntimeISA, type);
+ uintptr_t caller_pc = *reinterpret_cast<uintptr_t*>(
+ (reinterpret_cast<uint8_t*>(sp) + callee_return_pc_offset));
ArtMethod* outer_method = *caller_sp;
ArtMethod* caller = outer_method;
- if ((outer_method != nullptr) && current_code.IsOptimized(sizeof(void*))) {
- const size_t callee_return_pc_offset = GetCalleeSaveReturnPcOffset(kRuntimeISA, type);
- uintptr_t caller_pc = *reinterpret_cast<uintptr_t*>(
- (reinterpret_cast<uint8_t*>(sp) + callee_return_pc_offset));
- if (LIKELY(caller_pc != reinterpret_cast<uintptr_t>(GetQuickInstrumentationExitPc()))) {
- uintptr_t native_pc_offset = current_code.NativeQuickPcOffset(caller_pc);
- CodeInfo code_info = current_code.GetOptimizedCodeInfo();
- StackMapEncoding encoding = code_info.ExtractEncoding();
- StackMap stack_map = code_info.GetStackMapForNativePcOffset(native_pc_offset, encoding);
- DCHECK(stack_map.IsValid());
- if (stack_map.HasInlineInfo(encoding)) {
- InlineInfo inline_info = code_info.GetInlineInfoOf(stack_map, encoding);
- caller = GetResolvedMethod(outer_method, inline_info, inline_info.GetDepth() - 1);
- }
- } else {
- // We're instrumenting, just use the StackVisitor which knows how to
- // handle instrumented frames.
- NthCallerVisitor visitor(Thread::Current(), 1, true);
- visitor.WalkStack();
- caller = visitor.caller;
- if (kIsDebugBuild) {
- // Avoid doing the check below.
- do_caller_check = false;
+ if (outer_method != nullptr) {
+ const OatQuickMethodHeader* current_code = outer_method->GetOatQuickMethodHeader(caller_pc);
+ if (current_code->IsOptimized()) {
+ if (LIKELY(caller_pc != reinterpret_cast<uintptr_t>(GetQuickInstrumentationExitPc()))) {
+ uintptr_t native_pc_offset = current_code->NativeQuickPcOffset(caller_pc);
+ CodeInfo code_info = current_code->GetOptimizedCodeInfo();
+ StackMapEncoding encoding = code_info.ExtractEncoding();
+ StackMap stack_map = code_info.GetStackMapForNativePcOffset(native_pc_offset, encoding);
+ DCHECK(stack_map.IsValid());
+ if (stack_map.HasInlineInfo(encoding)) {
+ InlineInfo inline_info = code_info.GetInlineInfoOf(stack_map, encoding);
+ caller = GetResolvedMethod(outer_method, inline_info, inline_info.GetDepth() - 1);
+ }
+ } else {
+ // We're instrumenting, just use the StackVisitor which knows how to
+ // handle instrumented frames.
+ NthCallerVisitor visitor(Thread::Current(), 1, true);
+ visitor.WalkStack();
+ caller = visitor.caller;
}
}
}
diff --git a/runtime/entrypoints/entrypoint_utils.h b/runtime/entrypoints/entrypoint_utils.h
index 171ace2..0469ee6 100644
--- a/runtime/entrypoints/entrypoint_utils.h
+++ b/runtime/entrypoints/entrypoint_utils.h
@@ -20,7 +20,6 @@
#include <jni.h>
#include <stdint.h>
-#include "art_code.h"
#include "base/macros.h"
#include "base/mutex.h"
#include "dex_instruction.h"
@@ -40,6 +39,7 @@
class ArtField;
class ArtMethod;
+class OatQuickMethodHeader;
class ScopedObjectAccessAlreadyRunnable;
class Thread;
@@ -185,10 +185,6 @@
Runtime::CalleeSaveType type,
bool do_caller_check = false);
-inline ArtCode GetCallingCodeFrom(ArtMethod** sp) {
- return ArtCode(sp);
-}
-
} // namespace art
#endif // ART_RUNTIME_ENTRYPOINTS_ENTRYPOINT_UTILS_H_
diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
index 6035dfe..5eda6d6 100644
--- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-#include "art_code.h"
#include "art_method-inl.h"
#include "callee_save_frame.h"
#include "common_throws.h"
@@ -30,6 +29,7 @@
#include "mirror/method.h"
#include "mirror/object-inl.h"
#include "mirror/object_array-inl.h"
+#include "oat_quick_method_header.h"
#include "quick_exception_handler.h"
#include "runtime.h"
#include "scoped_thread_state_change.h"
@@ -295,8 +295,6 @@
static mirror::Object* GetProxyThisObject(ArtMethod** sp)
SHARED_REQUIRES(Locks::mutator_lock_) {
CHECK((*sp)->IsProxyMethod());
- CHECK_EQ(kQuickCalleeSaveFrame_RefAndArgs_FrameSize,
- GetCallingCodeFrom(sp).GetFrameSizeInBytes());
CHECK_GT(kNumQuickGprArgs, 0u);
constexpr uint32_t kThisGprIndex = 0u; // 'this' is in the 1st GPR.
size_t this_arg_offset = kQuickCalleeSaveFrame_RefAndArgs_Gpr1Offset +
@@ -323,10 +321,11 @@
ArtMethod** caller_sp = reinterpret_cast<ArtMethod**>(
reinterpret_cast<uintptr_t>(sp) + callee_frame_size);
uintptr_t outer_pc = QuickArgumentVisitor::GetCallingPc(sp);
- uintptr_t outer_pc_offset = GetCallingCodeFrom(caller_sp).NativeQuickPcOffset(outer_pc);
+ const OatQuickMethodHeader* current_code = (*caller_sp)->GetOatQuickMethodHeader(outer_pc);
+ uintptr_t outer_pc_offset = current_code->NativeQuickPcOffset(outer_pc);
- if (GetCallingCodeFrom(caller_sp).IsOptimized(sizeof(void*))) {
- CodeInfo code_info = GetCallingCodeFrom(caller_sp).GetOptimizedCodeInfo();
+ if (current_code->IsOptimized()) {
+ CodeInfo code_info = current_code->GetOptimizedCodeInfo();
StackMapEncoding encoding = code_info.ExtractEncoding();
StackMap stack_map = code_info.GetStackMapForNativePcOffset(outer_pc_offset, encoding);
DCHECK(stack_map.IsValid());
@@ -337,7 +336,7 @@
return stack_map.GetDexPc(encoding);
}
} else {
- return GetCallingCodeFrom(caller_sp).ToDexPc(outer_pc);
+ return current_code->ToDexPc(*caller_sp, outer_pc);
}
}
@@ -842,10 +841,6 @@
self->StartAssertNoThreadSuspension("Adding to IRT proxy object arguments");
// Register the top of the managed stack, making stack crawlable.
DCHECK_EQ((*sp), proxy_method) << PrettyMethod(proxy_method);
- DCHECK_EQ(GetCallingCodeFrom(sp).GetFrameSizeInBytes(),
- ArtCode(Runtime::Current()->GetCalleeSaveMethod(Runtime::kRefsAndArgs))
- .GetFrameSizeInBytes())
- << PrettyMethod(proxy_method);
self->VerifyStack();
// Start new JNI local reference state.
JNIEnvExt* env = self->GetJniEnv();
diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints_test.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints_test.cc
index 5299394..4e85913 100644
--- a/runtime/entrypoints/quick/quick_trampoline_entrypoints_test.cc
+++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints_test.cc
@@ -49,7 +49,7 @@
static void CheckFrameSize(InstructionSet isa, Runtime::CalleeSaveType type, uint32_t save_size)
NO_THREAD_SAFETY_ANALYSIS {
ArtMethod* save_method = CreateCalleeSaveMethod(isa, type);
- QuickMethodFrameInfo frame_info = ArtCode(save_method).GetQuickFrameInfo();
+ QuickMethodFrameInfo frame_info = Runtime::Current()->GetRuntimeMethodFrameInfo(save_method);
EXPECT_EQ(frame_info.FrameSizeInBytes(), save_size) << "Expected and real size differs for "
<< type << " core spills=" << std::hex << frame_info.CoreSpillMask() << " fp spills="
<< frame_info.FpSpillMask() << std::dec << " ISA " << isa;
@@ -58,8 +58,8 @@
static void CheckPCOffset(InstructionSet isa, Runtime::CalleeSaveType type, size_t pc_offset)
NO_THREAD_SAFETY_ANALYSIS {
ArtMethod* save_method = CreateCalleeSaveMethod(isa, type);
- QuickMethodFrameInfo frame_info = ArtCode(save_method).GetQuickFrameInfo();
- EXPECT_EQ(ArtCode(save_method).GetReturnPcOffset().SizeValue(), pc_offset)
+ QuickMethodFrameInfo frame_info = Runtime::Current()->GetRuntimeMethodFrameInfo(save_method);
+ EXPECT_EQ(frame_info.GetReturnPcOffset(), pc_offset)
<< "Expected and real pc offset differs for " << type
<< " core spills=" << std::hex << frame_info.CoreSpillMask()
<< " fp spills=" << frame_info.FpSpillMask() << std::dec << " ISA " << isa;
diff --git a/runtime/exception_test.cc b/runtime/exception_test.cc
index da1d80e..4de8a8e 100644
--- a/runtime/exception_test.cc
+++ b/runtime/exception_test.cc
@@ -26,6 +26,7 @@
#include "mirror/object_array-inl.h"
#include "mirror/object-inl.h"
#include "mirror/stack_trace_element.h"
+#include "oat_quick_method_header.h"
#include "runtime.h"
#include "scoped_thread_state_change.h"
#include "handle_scope-inl.h"
@@ -169,7 +170,7 @@
r->SetInstructionSet(kRuntimeISA);
ArtMethod* save_method = r->CreateCalleeSaveMethod();
r->SetCalleeSaveMethod(save_method, Runtime::kSaveAll);
- QuickMethodFrameInfo frame_info = ArtCode(save_method).GetQuickFrameInfo();
+ QuickMethodFrameInfo frame_info = r->GetRuntimeMethodFrameInfo(save_method);
ASSERT_EQ(kStackAlignment, 16U);
// ASSERT_EQ(sizeof(uintptr_t), sizeof(uint32_t));
@@ -186,15 +187,15 @@
fake_stack.push_back(0);
}
- fake_stack.push_back(
- ArtCode(method_g_).ToNativeQuickPc(dex_pc, /* is_catch_handler */ false)); // return pc
+ fake_stack.push_back(method_g_->GetOatQuickMethodHeader(0)->ToNativeQuickPc(
+ method_g_, dex_pc, /* is_catch_handler */ false)); // return pc
// Create/push fake 16byte stack frame for method g
fake_stack.push_back(reinterpret_cast<uintptr_t>(method_g_));
fake_stack.push_back(0);
fake_stack.push_back(0);
- fake_stack.push_back(
- ArtCode(method_g_).ToNativeQuickPc(dex_pc, /* is_catch_handler */ false)); // return pc
+ fake_stack.push_back(method_g_->GetOatQuickMethodHeader(0)->ToNativeQuickPc(
+ method_g_, dex_pc, /* is_catch_handler */ false)); // return pc
// Create/push fake 16byte stack frame for method f
fake_stack.push_back(reinterpret_cast<uintptr_t>(method_f_));
diff --git a/runtime/fault_handler.cc b/runtime/fault_handler.cc
index 5b31b3a..52ccbee 100644
--- a/runtime/fault_handler.cc
+++ b/runtime/fault_handler.cc
@@ -20,10 +20,10 @@
#include <sys/mman.h>
#include <sys/ucontext.h>
-#include "art_code.h"
#include "art_method-inl.h"
#include "base/stl_util.h"
#include "mirror/class.h"
+#include "oat_quick_method_header.h"
#include "sigchain.h"
#include "thread-inl.h"
#include "verify_object-inl.h"
@@ -360,17 +360,17 @@
return false;
}
- ArtCode art_code(method_obj);
+ const OatQuickMethodHeader* method_header = method_obj->GetOatQuickMethodHeader(return_pc);
// We can be certain that this is a method now. Check if we have a GC map
// at the return PC address.
if (true || kIsDebugBuild) {
VLOG(signals) << "looking for dex pc for return pc " << std::hex << return_pc;
uint32_t sought_offset = return_pc -
- reinterpret_cast<uintptr_t>(art_code.GetQuickOatEntryPoint(sizeof(void*)));
+ reinterpret_cast<uintptr_t>(method_header->GetEntryPoint());
VLOG(signals) << "pc offset: " << std::hex << sought_offset;
}
- uint32_t dexpc = art_code.ToDexPc(return_pc, false);
+ uint32_t dexpc = method_header->ToDexPc(method_obj, return_pc, false);
VLOG(signals) << "dexpc: " << dexpc;
return !check_dex_pc || dexpc != DexFile::kDexNoIndex;
}
diff --git a/runtime/gc/space/malloc_space.cc b/runtime/gc/space/malloc_space.cc
index 3a0d814..b1572cc 100644
--- a/runtime/gc/space/malloc_space.cc
+++ b/runtime/gc/space/malloc_space.cc
@@ -56,7 +56,7 @@
mark_bitmap_.reset(accounting::ContinuousSpaceBitmap::Create(
StringPrintf("allocspace %s mark-bitmap %d", name.c_str(), static_cast<int>(bitmap_index)),
Begin(), NonGrowthLimitCapacity()));
- CHECK(live_bitmap_.get() != nullptr) << "could not create allocspace mark bitmap #"
+ CHECK(mark_bitmap_.get() != nullptr) << "could not create allocspace mark bitmap #"
<< bitmap_index;
}
for (auto& freed : recent_freed_objects_) {
diff --git a/runtime/instrumentation.cc b/runtime/instrumentation.cc
index 2dd2b7d..ed64d7e 100644
--- a/runtime/instrumentation.cc
+++ b/runtime/instrumentation.cc
@@ -19,7 +19,6 @@
#include <sstream>
#include "arch/context.h"
-#include "art_code.h"
#include "art_method-inl.h"
#include "atomic.h"
#include "class_linker.h"
@@ -37,6 +36,7 @@
#include "mirror/object_array-inl.h"
#include "mirror/object-inl.h"
#include "nth_caller_visitor.h"
+#include "oat_quick_method_header.h"
#include "thread.h"
#include "thread_list.h"
@@ -252,7 +252,9 @@
instrumentation_stack_->insert(it, instrumentation_frame);
SetReturnPc(instrumentation_exit_pc_);
}
- dex_pcs_.push_back(GetCurrentCode().ToDexPc(last_return_pc_));
+ dex_pcs_.push_back((GetCurrentOatQuickMethodHeader() == nullptr)
+ ? DexFile::kDexNoIndex
+ : GetCurrentOatQuickMethodHeader()->ToDexPc(m, last_return_pc_));
last_return_pc_ = return_pc;
++instrumentation_stack_depth_;
return true; // Continue.
diff --git a/runtime/jit/jit_code_cache.cc b/runtime/jit/jit_code_cache.cc
index 4c53162..7e95e71 100644
--- a/runtime/jit/jit_code_cache.cc
+++ b/runtime/jit/jit_code_cache.cc
@@ -25,37 +25,77 @@
namespace art {
namespace jit {
+static constexpr int kProtAll = PROT_READ | PROT_WRITE | PROT_EXEC;
+static constexpr int kProtData = PROT_READ | PROT_WRITE;
+static constexpr int kProtCode = PROT_READ | PROT_EXEC;
+
+#define CHECKED_MPROTECT(memory, size, prot) \
+ do { \
+ int rc = mprotect(memory, size, prot); \
+ if (UNLIKELY(rc != 0)) { \
+ errno = rc; \
+ PLOG(FATAL) << "Failed to mprotect jit code cache"; \
+ } \
+ } while (false) \
+
JitCodeCache* JitCodeCache::Create(size_t capacity, std::string* error_msg) {
CHECK_GT(capacity, 0U);
CHECK_LT(capacity, kMaxCapacity);
std::string error_str;
// Map name specific for android_os_Debug.cpp accounting.
- MemMap* map = MemMap::MapAnonymous("jit-code-cache", nullptr, capacity,
- PROT_READ | PROT_WRITE | PROT_EXEC, false, false, &error_str);
- if (map == nullptr) {
+ MemMap* data_map = MemMap::MapAnonymous(
+ "data-code-cache", nullptr, capacity, kProtAll, false, false, &error_str);
+ if (data_map == nullptr) {
std::ostringstream oss;
oss << "Failed to create read write execute cache: " << error_str << " size=" << capacity;
*error_msg = oss.str();
return nullptr;
}
- return new JitCodeCache(map);
+
+ // Data cache is 1 / 4 of the map.
+ // TODO: Make this variable?
+ size_t data_size = RoundUp(data_map->Size() / 4, kPageSize);
+ size_t code_size = data_map->Size() - data_size;
+ uint8_t* divider = data_map->Begin() + data_size;
+
+ // We need to have 32 bit offsets from method headers in code cache which point to things
+ // in the data cache. If the maps are more than 4G apart, having multiple maps wouldn't work.
+ MemMap* code_map = data_map->RemapAtEnd(divider, "jit-code-cache", kProtAll, &error_str);
+ if (code_map == nullptr) {
+ std::ostringstream oss;
+ oss << "Failed to create read write execute cache: " << error_str << " size=" << capacity;
+ *error_msg = oss.str();
+ return nullptr;
+ }
+ DCHECK_EQ(code_map->Size(), code_size);
+ DCHECK_EQ(code_map->Begin(), divider);
+ return new JitCodeCache(code_map, data_map);
}
-JitCodeCache::JitCodeCache(MemMap* mem_map)
- : lock_("Jit code cache", kJitCodeCacheLock), num_methods_(0) {
- VLOG(jit) << "Created jit code cache size=" << PrettySize(mem_map->Size());
- mem_map_.reset(mem_map);
- uint8_t* divider = mem_map->Begin() + RoundUp(mem_map->Size() / 4, kPageSize);
- // Data cache is 1 / 4 of the map. TODO: Make this variable?
- // Put data at the start.
- data_cache_ptr_ = mem_map->Begin();
- data_cache_end_ = divider;
- data_cache_begin_ = data_cache_ptr_;
- mprotect(data_cache_ptr_, data_cache_end_ - data_cache_begin_, PROT_READ | PROT_WRITE);
- // Code cache after.
- code_cache_begin_ = divider;
- code_cache_ptr_ = divider;
- code_cache_end_ = mem_map->End();
+JitCodeCache::JitCodeCache(MemMap* code_map, MemMap* data_map)
+ : lock_("Jit code cache", kJitCodeCacheLock),
+ code_map_(code_map),
+ data_map_(data_map),
+ num_methods_(0) {
+
+ VLOG(jit) << "Created jit code cache: data size="
+ << PrettySize(data_map_->Size())
+ << ", code size="
+ << PrettySize(code_map_->Size());
+
+ code_mspace_ = create_mspace_with_base(code_map_->Begin(), code_map_->Size(), false /*locked*/);
+ data_mspace_ = create_mspace_with_base(data_map_->Begin(), data_map_->Size(), false /*locked*/);
+
+ if (code_mspace_ == nullptr || data_mspace_ == nullptr) {
+ PLOG(FATAL) << "create_mspace_with_base failed";
+ }
+
+ // Prevent morecore requests from the mspace.
+ mspace_set_footprint_limit(code_mspace_, code_map_->Size());
+ mspace_set_footprint_limit(data_mspace_, data_map_->Size());
+
+ CHECKED_MPROTECT(code_map_->Begin(), code_map_->Size(), kProtCode);
+ CHECKED_MPROTECT(data_map_->Begin(), data_map_->Size(), kProtData);
}
bool JitCodeCache::ContainsMethod(ArtMethod* method) const {
@@ -63,44 +103,93 @@
}
bool JitCodeCache::ContainsCodePtr(const void* ptr) const {
- return ptr >= code_cache_begin_ && ptr < code_cache_end_;
+ return code_map_->Begin() <= ptr && ptr < code_map_->End();
}
-void JitCodeCache::FlushInstructionCache() {
- UNIMPLEMENTED(FATAL);
- // TODO: Investigate if we need to do this.
- // __clear_cache(reinterpret_cast<char*>(code_cache_begin_), static_cast<int>(CodeCacheSize()));
-}
-
-uint8_t* JitCodeCache::ReserveCode(Thread* self, size_t size) {
- MutexLock mu(self, lock_);
- if (size > CodeCacheRemain()) {
- return nullptr;
+class ScopedCodeCacheWrite {
+ public:
+ explicit ScopedCodeCacheWrite(MemMap* code_map) : code_map_(code_map) {
+ CHECKED_MPROTECT(code_map_->Begin(), code_map_->Size(), kProtAll);
}
+ ~ScopedCodeCacheWrite() {
+ CHECKED_MPROTECT(code_map_->Begin(), code_map_->Size(), kProtCode);
+ }
+ private:
+ MemMap* const code_map_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedCodeCacheWrite);
+};
+
+uint8_t* JitCodeCache::CommitCode(Thread* self,
+ const uint8_t* mapping_table,
+ const uint8_t* vmap_table,
+ const uint8_t* gc_map,
+ size_t frame_size_in_bytes,
+ size_t core_spill_mask,
+ size_t fp_spill_mask,
+ const uint8_t* code,
+ size_t code_size) {
+ size_t total_size = RoundUp(sizeof(OatQuickMethodHeader) + code_size + 32, sizeof(void*));
+ OatQuickMethodHeader* method_header = nullptr;
+ uint8_t* code_ptr;
+
+ MutexLock mu(self, lock_);
+ {
+ ScopedCodeCacheWrite scc(code_map_.get());
+ uint8_t* result = reinterpret_cast<uint8_t*>(mspace_malloc(code_mspace_, total_size));
+ if (result == nullptr) {
+ return nullptr;
+ }
+ code_ptr = reinterpret_cast<uint8_t*>(
+ RoundUp(reinterpret_cast<size_t>(result + sizeof(OatQuickMethodHeader)),
+ GetInstructionSetAlignment(kRuntimeISA)));
+
+ std::copy(code, code + code_size, code_ptr);
+ method_header = reinterpret_cast<OatQuickMethodHeader*>(code_ptr) - 1;
+ new (method_header) OatQuickMethodHeader(
+ (mapping_table == nullptr) ? 0 : code_ptr - mapping_table,
+ (vmap_table == nullptr) ? 0 : code_ptr - vmap_table,
+ (gc_map == nullptr) ? 0 : code_ptr - gc_map,
+ frame_size_in_bytes,
+ core_spill_mask,
+ fp_spill_mask,
+ code_size);
+ }
+
+ __builtin___clear_cache(reinterpret_cast<char*>(code_ptr),
+ reinterpret_cast<char*>(code_ptr + code_size));
+
++num_methods_; // TODO: This is hacky but works since each method has exactly one code region.
- code_cache_ptr_ += size;
- return code_cache_ptr_ - size;
+ return reinterpret_cast<uint8_t*>(method_header);
+}
+
+size_t JitCodeCache::CodeCacheSize() {
+ MutexLock mu(Thread::Current(), lock_);
+ size_t bytes_allocated = 0;
+ mspace_inspect_all(code_mspace_, DlmallocBytesAllocatedCallback, &bytes_allocated);
+ return bytes_allocated;
+}
+
+size_t JitCodeCache::DataCacheSize() {
+ MutexLock mu(Thread::Current(), lock_);
+ size_t bytes_allocated = 0;
+ mspace_inspect_all(data_mspace_, DlmallocBytesAllocatedCallback, &bytes_allocated);
+ return bytes_allocated;
}
uint8_t* JitCodeCache::ReserveData(Thread* self, size_t size) {
- MutexLock mu(self, lock_);
size = RoundUp(size, sizeof(void*));
- if (size > DataCacheRemain()) {
- return nullptr;
- }
- data_cache_ptr_ += size;
- return data_cache_ptr_ - size;
+ MutexLock mu(self, lock_);
+ return reinterpret_cast<uint8_t*>(mspace_malloc(data_mspace_, size));
}
uint8_t* JitCodeCache::AddDataArray(Thread* self, const uint8_t* begin, const uint8_t* end) {
- MutexLock mu(self, lock_);
- const size_t size = RoundUp(end - begin, sizeof(void*));
- if (size > DataCacheRemain()) {
+ uint8_t* result = ReserveData(self, end - begin);
+ if (result == nullptr) {
return nullptr; // Out of space in the data cache.
}
- std::copy(begin, end, data_cache_ptr_);
- data_cache_ptr_ += size;
- return data_cache_ptr_ - size;
+ std::copy(begin, end, result);
+ return result;
}
const void* JitCodeCache::GetCodeFor(ArtMethod* method) {
diff --git a/runtime/jit/jit_code_cache.h b/runtime/jit/jit_code_cache.h
index f485e4a..fa90c18 100644
--- a/runtime/jit/jit_code_cache.h
+++ b/runtime/jit/jit_code_cache.h
@@ -22,6 +22,7 @@
#include "atomic.h"
#include "base/macros.h"
#include "base/mutex.h"
+#include "gc/allocator/dlmalloc.h"
#include "gc_root.h"
#include "jni.h"
#include "oat_file.h"
@@ -48,34 +49,26 @@
// in the out arg error_msg.
static JitCodeCache* Create(size_t capacity, std::string* error_msg);
- const uint8_t* CodeCachePtr() const {
- return code_cache_ptr_;
- }
-
- size_t CodeCacheSize() const {
- return code_cache_ptr_ - code_cache_begin_;
- }
-
- size_t CodeCacheRemain() const {
- return code_cache_end_ - code_cache_ptr_;
- }
-
- const uint8_t* DataCachePtr() const {
- return data_cache_ptr_;
- }
-
- size_t DataCacheSize() const {
- return data_cache_ptr_ - data_cache_begin_;
- }
-
- size_t DataCacheRemain() const {
- return data_cache_end_ - data_cache_ptr_;
- }
-
size_t NumMethods() const {
return num_methods_;
}
+ size_t CodeCacheSize() REQUIRES(!lock_);
+
+ size_t DataCacheSize() REQUIRES(!lock_);
+
+ // Allocate and write code and its metadata to the code cache.
+ uint8_t* CommitCode(Thread* self,
+ const uint8_t* mapping_table,
+ const uint8_t* vmap_table,
+ const uint8_t* gc_map,
+ size_t frame_size_in_bytes,
+ size_t core_spill_mask,
+ size_t fp_spill_mask,
+ const uint8_t* code,
+ size_t code_size)
+ REQUIRES(!lock_);
+
// Return true if the code cache contains the code pointer which si the entrypoint of the method.
bool ContainsMethod(ArtMethod* method) const
SHARED_REQUIRES(Locks::mutator_lock_);
@@ -83,9 +76,6 @@
// Return true if the code cache contains a code ptr.
bool ContainsCodePtr(const void* ptr) const;
- // Reserve a region of code of size at least "size". Returns null if there is no more room.
- uint8_t* ReserveCode(Thread* self, size_t size) REQUIRES(!lock_);
-
// Reserve a region of data of size at least "size". Returns null if there is no more room.
uint8_t* ReserveData(Thread* self, size_t size) REQUIRES(!lock_);
@@ -105,25 +95,19 @@
private:
// Takes ownership of code_mem_map.
- explicit JitCodeCache(MemMap* code_mem_map);
-
- // Unimplemented, TODO: Determine if it is necessary.
- void FlushInstructionCache();
+ JitCodeCache(MemMap* code_map, MemMap* data_map);
// Lock which guards.
Mutex lock_;
- // Mem map which holds code and data. We do this since we need to have 32 bit offsets from method
- // headers in code cache which point to things in the data cache. If the maps are more than 4GB
- // apart, having multiple maps wouldn't work.
- std::unique_ptr<MemMap> mem_map_;
- // Code cache section.
- uint8_t* code_cache_ptr_;
- const uint8_t* code_cache_begin_;
- const uint8_t* code_cache_end_;
- // Data cache section.
- uint8_t* data_cache_ptr_;
- const uint8_t* data_cache_begin_;
- const uint8_t* data_cache_end_;
+ // Mem map which holds code.
+ std::unique_ptr<MemMap> code_map_;
+ // Mem map which holds data (stack maps and profiling info).
+ std::unique_ptr<MemMap> data_map_;
+ // The opaque mspace for allocating code.
+ void* code_mspace_;
+ // The opaque mspace for allocating data.
+ void* data_mspace_;
+ // Number of compiled methods.
size_t num_methods_;
// This map holds code for methods if they were deoptimized by the instrumentation stubs. This is
// required since we have to implement ClassLinker::GetQuickOatCodeFor for walking stacks.
diff --git a/runtime/jit/jit_code_cache_test.cc b/runtime/jit/jit_code_cache_test.cc
deleted file mode 100644
index c76dc11..0000000
--- a/runtime/jit/jit_code_cache_test.cc
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Copyright (C) 2015 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 "common_runtime_test.h"
-
-#include "art_method-inl.h"
-#include "class_linker.h"
-#include "jit_code_cache.h"
-#include "scoped_thread_state_change.h"
-#include "thread-inl.h"
-
-namespace art {
-namespace jit {
-
-class JitCodeCacheTest : public CommonRuntimeTest {
- public:
-};
-
-TEST_F(JitCodeCacheTest, TestCoverage) {
- std::string error_msg;
- constexpr size_t kSize = 1 * MB;
- std::unique_ptr<JitCodeCache> code_cache(
- JitCodeCache::Create(kSize, &error_msg));
- ASSERT_TRUE(code_cache.get() != nullptr) << error_msg;
- ASSERT_TRUE(code_cache->CodeCachePtr() != nullptr);
- ASSERT_EQ(code_cache->CodeCacheSize(), 0u);
- ASSERT_GT(code_cache->CodeCacheRemain(), 0u);
- ASSERT_TRUE(code_cache->DataCachePtr() != nullptr);
- ASSERT_EQ(code_cache->DataCacheSize(), 0u);
- ASSERT_GT(code_cache->DataCacheRemain(), 0u);
- ASSERT_EQ(code_cache->CodeCacheRemain() + code_cache->DataCacheRemain(), kSize);
- ASSERT_EQ(code_cache->NumMethods(), 0u);
- ScopedObjectAccess soa(Thread::Current());
- StackHandleScope<1> hs(soa.Self());
- uint8_t* const reserved_code = code_cache->ReserveCode(soa.Self(), 4 * KB);
- ASSERT_TRUE(reserved_code != nullptr);
- ASSERT_TRUE(code_cache->ContainsCodePtr(reserved_code));
- ASSERT_EQ(code_cache->NumMethods(), 1u);
- Runtime* const runtime = Runtime::Current();
- ClassLinker* const class_linker = runtime->GetClassLinker();
- ArtMethod* method = &class_linker->AllocArtMethodArray(soa.Self(),
- runtime->GetLinearAlloc(),
- 1)->At(0);
- ASSERT_FALSE(code_cache->ContainsMethod(method));
- method->SetEntryPointFromQuickCompiledCode(reserved_code);
- ASSERT_TRUE(code_cache->ContainsMethod(method));
- ASSERT_EQ(code_cache->GetCodeFor(method), reserved_code);
- // Save the code and then change it.
- code_cache->SaveCompiledCode(method, reserved_code);
- method->SetEntryPointFromQuickCompiledCode(nullptr);
- ASSERT_EQ(code_cache->GetCodeFor(method), reserved_code);
- const uint8_t data_arr[] = {1, 2, 3, 4, 5};
- uint8_t* data_ptr = code_cache->AddDataArray(soa.Self(), data_arr, data_arr + sizeof(data_arr));
- ASSERT_TRUE(data_ptr != nullptr);
- ASSERT_EQ(memcmp(data_ptr, data_arr, sizeof(data_arr)), 0);
-}
-
-TEST_F(JitCodeCacheTest, TestOverflow) {
- std::string error_msg;
- constexpr size_t kSize = 1 * MB;
- std::unique_ptr<JitCodeCache> code_cache(
- JitCodeCache::Create(kSize, &error_msg));
- ASSERT_TRUE(code_cache.get() != nullptr) << error_msg;
- ASSERT_TRUE(code_cache->CodeCachePtr() != nullptr);
- size_t code_bytes = 0;
- size_t data_bytes = 0;
- constexpr size_t kCodeArrSize = 4 * KB;
- constexpr size_t kDataArrSize = 4 * KB;
- uint8_t data_arr[kDataArrSize];
- std::fill_n(data_arr, arraysize(data_arr), 53);
- // Add code and data until we are full.
- uint8_t* code_ptr = nullptr;
- uint8_t* data_ptr = nullptr;
- do {
- code_ptr = code_cache->ReserveCode(Thread::Current(), kCodeArrSize);
- data_ptr = code_cache->AddDataArray(Thread::Current(), data_arr, data_arr + kDataArrSize);
- if (code_ptr != nullptr) {
- code_bytes += kCodeArrSize;
- }
- if (data_ptr != nullptr) {
- data_bytes += kDataArrSize;
- }
- } while (code_ptr != nullptr || data_ptr != nullptr);
- // Make sure we added a reasonable amount
- CHECK_GT(code_bytes, 0u);
- CHECK_LE(code_bytes, kSize);
- CHECK_GT(data_bytes, 0u);
- CHECK_LE(data_bytes, kSize);
- CHECK_GE(code_bytes + data_bytes, kSize * 4 / 5);
-}
-
-} // namespace jit
-} // namespace art
diff --git a/runtime/leb128_test.cc b/runtime/leb128_test.cc
index 09f7ecc..122f55e 100644
--- a/runtime/leb128_test.cc
+++ b/runtime/leb128_test.cc
@@ -88,7 +88,7 @@
{-0x08000000, {0x80, 0x80, 0x80, 0x40, 0}},
{-0x08000001, {0xFF, 0xFF, 0xFF, 0xBF, 0x7F}},
{-0x20000000, {0x80, 0x80, 0x80, 0x80, 0x7E}},
- {(-1) << 31, {0x80, 0x80, 0x80, 0x80, 0x78}},
+ {static_cast<int32_t>(0x80000000), {0x80, 0x80, 0x80, 0x80, 0x78}},
};
TEST(Leb128Test, UnsignedSinglesVector) {
diff --git a/runtime/native/dalvik_system_DexFile.cc b/runtime/native/dalvik_system_DexFile.cc
index 4eea3f3..8b2f4d8 100644
--- a/runtime/native/dalvik_system_DexFile.cc
+++ b/runtime/native/dalvik_system_DexFile.cc
@@ -243,7 +243,8 @@
jclass,
jstring javaName,
jobject javaLoader,
- jobject cookie) {
+ jobject cookie,
+ jobject dexFile) {
std::vector<const DexFile*> dex_files;
const OatFile* oat_file;
if (!ConvertJavaArrayToDexFiles(env, cookie, /*out*/ dex_files, /*out*/ oat_file)) {
@@ -276,6 +277,10 @@
class_loader,
*dex_file,
*dex_class_def);
+ // Add the used dex file. This only required for the DexFile.loadClass API since normal
+ // class loaders already keep their dex files live.
+ class_linker->InsertDexFileInToClassLoader(soa.Decode<mirror::Object*>(dexFile),
+ class_loader.Get());
if (result != nullptr) {
VLOG(class_linker) << "DexFile_defineClassNative returning " << result
<< " for " << class_name.c_str();
@@ -424,8 +429,13 @@
static JNINativeMethod gMethods[] = {
NATIVE_METHOD(DexFile, closeDexFile, "(Ljava/lang/Object;)Z"),
- NATIVE_METHOD(DexFile, defineClassNative,
- "(Ljava/lang/String;Ljava/lang/ClassLoader;Ljava/lang/Object;)Ljava/lang/Class;"),
+ NATIVE_METHOD(DexFile,
+ defineClassNative,
+ "(Ljava/lang/String;"
+ "Ljava/lang/ClassLoader;"
+ "Ljava/lang/Object;"
+ "Ldalvik/system/DexFile;"
+ ")Ljava/lang/Class;"),
NATIVE_METHOD(DexFile, getClassNameList, "(Ljava/lang/Object;)[Ljava/lang/String;"),
NATIVE_METHOD(DexFile, isDexOptNeeded, "(Ljava/lang/String;)Z"),
NATIVE_METHOD(DexFile, getDexOptNeeded,
diff --git a/runtime/oat.cc b/runtime/oat.cc
index 5625499..40aca0d 100644
--- a/runtime/oat.cc
+++ b/runtime/oat.cc
@@ -483,15 +483,4 @@
OatMethodOffsets::~OatMethodOffsets() {}
-OatQuickMethodHeader::OatQuickMethodHeader(
- uint32_t mapping_table_offset, uint32_t vmap_table_offset, uint32_t gc_map_offset,
- uint32_t frame_size_in_bytes, uint32_t core_spill_mask, uint32_t fp_spill_mask,
- uint32_t code_size)
- : mapping_table_offset_(mapping_table_offset), vmap_table_offset_(vmap_table_offset),
- gc_map_offset_(gc_map_offset),
- frame_info_(frame_size_in_bytes, core_spill_mask, fp_spill_mask), code_size_(code_size) {
-}
-
-OatQuickMethodHeader::~OatQuickMethodHeader() {}
-
} // namespace art
diff --git a/runtime/oat.h b/runtime/oat.h
index 2aa5783..276e7f3 100644
--- a/runtime/oat.h
+++ b/runtime/oat.h
@@ -22,7 +22,6 @@
#include "arch/instruction_set.h"
#include "base/macros.h"
#include "dex_file.h"
-#include "quick/quick_method_frame_info.h"
#include "safe_map.h"
namespace art {
@@ -170,30 +169,6 @@
uint32_t code_offset_;
};
-// OatQuickMethodHeader precedes the raw code chunk generated by the Quick compiler.
-class PACKED(4) OatQuickMethodHeader {
- public:
- OatQuickMethodHeader(uint32_t mapping_table_offset = 0U, uint32_t vmap_table_offset = 0U,
- uint32_t gc_map_offset = 0U, uint32_t frame_size_in_bytes = 0U,
- uint32_t core_spill_mask = 0U, uint32_t fp_spill_mask = 0U,
- uint32_t code_size = 0U);
-
- ~OatQuickMethodHeader();
-
- OatQuickMethodHeader& operator=(const OatQuickMethodHeader&) = default;
-
- // The offset in bytes from the start of the mapping table to the end of the header.
- uint32_t mapping_table_offset_;
- // The offset in bytes from the start of the vmap table to the end of the header.
- uint32_t vmap_table_offset_;
- // The offset in bytes from the start of the gc map to the end of the header.
- uint32_t gc_map_offset_;
- // The stack frame information.
- QuickMethodFrameInfo frame_info_;
- // The code size in bytes.
- uint32_t code_size_;
-};
-
} // namespace art
#endif // ART_RUNTIME_OAT_H_
diff --git a/runtime/oat_file-inl.h b/runtime/oat_file-inl.h
index f7913e1..7b92120 100644
--- a/runtime/oat_file-inl.h
+++ b/runtime/oat_file-inl.h
@@ -18,6 +18,7 @@
#define ART_RUNTIME_OAT_FILE_INL_H_
#include "oat_file.h"
+#include "oat_quick_method_header.h"
namespace art {
diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc
index e861921..a162a4e 100644
--- a/runtime/oat_file.cc
+++ b/runtime/oat_file.cc
@@ -18,6 +18,7 @@
#include <dlfcn.h>
#include <string.h>
+#include <type_traits>
#include <unistd.h>
#include <cstdlib>
@@ -388,13 +389,13 @@
// Readjust to be non-inclusive upper bound.
end_ += sizeof(uint32_t);
- bss_begin_ = elf_file_->FindDynamicSymbolAddress("oatbss");
+ bss_begin_ = const_cast<uint8_t*>(elf_file_->FindDynamicSymbolAddress("oatbss"));
if (bss_begin_ == nullptr) {
// No .bss section. Clear dlerror().
bss_end_ = nullptr;
dlerror();
} else {
- bss_end_ = elf_file_->FindDynamicSymbolAddress("oatbsslastword");
+ bss_end_ = const_cast<uint8_t*>(elf_file_->FindDynamicSymbolAddress("oatbsslastword"));
if (bss_end_ == nullptr) {
*error_msg = StringPrintf("Failed to find oatbasslastword symbol in '%s'",
file->GetPath().c_str());
@@ -407,10 +408,31 @@
return Setup(abs_dex_location, error_msg);
}
+// Read an unaligned entry from the OatDexFile data in OatFile and advance the read
+// position by the number of bytes read, i.e. sizeof(T).
+// Return true on success, false if the read would go beyond the end of the OatFile.
+template <typename T>
+inline static bool ReadOatDexFileData(const OatFile& oat_file,
+ /*inout*/const uint8_t** oat,
+ /*out*/T* value) {
+ DCHECK(oat != nullptr);
+ DCHECK(value != nullptr);
+ DCHECK_LE(*oat, oat_file.End());
+ if (UNLIKELY(static_cast<size_t>(oat_file.End() - *oat) < sizeof(T))) {
+ return false;
+ }
+ static_assert(std::is_trivial<T>::value, "T must be a trivial type");
+ typedef __attribute__((__aligned__(1))) T unaligned_type;
+ *value = *reinterpret_cast<const unaligned_type*>(*oat);
+ *oat += sizeof(T);
+ return true;
+}
+
bool OatFile::Setup(const char* abs_dex_location, std::string* error_msg) {
if (!GetOatHeader().IsValid()) {
std::string cause = GetOatHeader().GetValidationErrorMessage();
- *error_msg = StringPrintf("Invalid oat header for '%s': %s", GetLocation().c_str(),
+ *error_msg = StringPrintf("Invalid oat header for '%s': %s",
+ GetLocation().c_str(),
cause.c_str());
return false;
}
@@ -424,35 +446,42 @@
oat += GetOatHeader().GetKeyValueStoreSize();
if (oat > End()) {
*error_msg = StringPrintf("In oat file '%s' found truncated variable-size data: "
- "%p + %zd + %ud <= %p", GetLocation().c_str(),
- Begin(), sizeof(OatHeader), GetOatHeader().GetKeyValueStoreSize(),
+ "%p + %zu + %u <= %p",
+ GetLocation().c_str(),
+ Begin(),
+ sizeof(OatHeader),
+ GetOatHeader().GetKeyValueStoreSize(),
End());
return false;
}
size_t pointer_size = GetInstructionSetPointerSize(GetOatHeader().GetInstructionSet());
- const uint8_t* dex_cache_arrays = bss_begin_;
+ uint8_t* dex_cache_arrays = bss_begin_;
uint32_t dex_file_count = GetOatHeader().GetDexFileCount();
oat_dex_files_storage_.reserve(dex_file_count);
for (size_t i = 0; i < dex_file_count; i++) {
- uint32_t dex_file_location_size = *reinterpret_cast<const uint32_t*>(oat);
- if (UNLIKELY(dex_file_location_size == 0U)) {
- *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zd with empty location name",
- GetLocation().c_str(), i);
+ uint32_t dex_file_location_size;
+ if (UNLIKELY(!ReadOatDexFileData(*this, &oat, &dex_file_location_size))) {
+ *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zu truncated after dex file "
+ "location size",
+ GetLocation().c_str(),
+ i);
return false;
}
- oat += sizeof(dex_file_location_size);
- if (UNLIKELY(oat > End())) {
- *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zd truncated after dex file "
- "location size", GetLocation().c_str(), i);
+ if (UNLIKELY(dex_file_location_size == 0U)) {
+ *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zu with empty location name",
+ GetLocation().c_str(),
+ i);
return false;
}
const char* dex_file_location_data = reinterpret_cast<const char*>(oat);
oat += dex_file_location_size;
if (UNLIKELY(oat > End())) {
- *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zd with truncated dex file "
- "location", GetLocation().c_str(), i);
+ *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zu with truncated dex file "
+ "location",
+ GetLocation().c_str(),
+ i);
return false;
}
@@ -460,46 +489,61 @@
abs_dex_location,
std::string(dex_file_location_data, dex_file_location_size));
- uint32_t dex_file_checksum = *reinterpret_cast<const uint32_t*>(oat);
- oat += sizeof(dex_file_checksum);
- if (UNLIKELY(oat > End())) {
- *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zd for '%s' truncated after "
- "dex file checksum", GetLocation().c_str(), i,
+ uint32_t dex_file_checksum;
+ if (UNLIKELY(!ReadOatDexFileData(*this, &oat, &dex_file_checksum))) {
+ *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zu for '%s' truncated after "
+ "dex file checksum",
+ GetLocation().c_str(),
+ i,
dex_file_location.c_str());
return false;
}
- uint32_t dex_file_offset = *reinterpret_cast<const uint32_t*>(oat);
+ uint32_t dex_file_offset;
+ if (UNLIKELY(!ReadOatDexFileData(*this, &oat, &dex_file_offset))) {
+ *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zu for '%s' truncated "
+ "after dex file offsets",
+ GetLocation().c_str(),
+ i,
+ dex_file_location.c_str());
+ return false;
+ }
if (UNLIKELY(dex_file_offset == 0U)) {
- *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zd for '%s' with zero dex "
- "file offset", GetLocation().c_str(), i, dex_file_location.c_str());
+ *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zu for '%s' with zero dex "
+ "file offset",
+ GetLocation().c_str(),
+ i,
+ dex_file_location.c_str());
return false;
}
if (UNLIKELY(dex_file_offset > Size())) {
- *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zd for '%s' with dex file "
- "offset %ud > %zd", GetLocation().c_str(), i,
- dex_file_location.c_str(), dex_file_offset, Size());
- return false;
- }
- oat += sizeof(dex_file_offset);
- if (UNLIKELY(oat > End())) {
- *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zd for '%s' truncated "
- "after dex file offsets", GetLocation().c_str(), i,
- dex_file_location.c_str());
+ *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zu for '%s' with dex file "
+ "offset %u > %zu",
+ GetLocation().c_str(),
+ i,
+ dex_file_location.c_str(),
+ dex_file_offset,
+ Size());
return false;
}
const uint8_t* dex_file_pointer = Begin() + dex_file_offset;
if (UNLIKELY(!DexFile::IsMagicValid(dex_file_pointer))) {
- *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zd for '%s' with invalid "
- "dex file magic '%s'", GetLocation().c_str(), i,
- dex_file_location.c_str(), dex_file_pointer);
+ *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zu for '%s' with invalid "
+ "dex file magic '%s'",
+ GetLocation().c_str(),
+ i,
+ dex_file_location.c_str(),
+ dex_file_pointer);
return false;
}
if (UNLIKELY(!DexFile::IsVersionValid(dex_file_pointer))) {
- *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zd for '%s' with invalid "
- "dex file version '%s'", GetLocation().c_str(), i,
- dex_file_location.c_str(), dex_file_pointer);
+ *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zu for '%s' with invalid "
+ "dex file version '%s'",
+ GetLocation().c_str(),
+ i,
+ dex_file_location.c_str(),
+ dex_file_pointer);
return false;
}
const DexFile::Header* header = reinterpret_cast<const DexFile::Header*>(dex_file_pointer);
@@ -507,21 +551,26 @@
oat += (sizeof(*methods_offsets_pointer) * header->class_defs_size_);
if (UNLIKELY(oat > End())) {
- *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zd for '%s' with truncated "
- "method offsets", GetLocation().c_str(), i,
+ *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zu for '%s' with truncated "
+ "method offsets",
+ GetLocation().c_str(),
+ i,
dex_file_location.c_str());
return false;
}
- const uint8_t* current_dex_cache_arrays = nullptr;
+ uint8_t* current_dex_cache_arrays = nullptr;
if (dex_cache_arrays != nullptr) {
DexCacheArraysLayout layout(pointer_size, *header);
if (layout.Size() != 0u) {
if (static_cast<size_t>(bss_end_ - dex_cache_arrays) < layout.Size()) {
- *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zd for '%s' with "
- "truncated dex cache arrays, %zd < %zd.",
- GetLocation().c_str(), i, dex_file_location.c_str(),
- static_cast<size_t>(bss_end_ - dex_cache_arrays), layout.Size());
+ *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zu for '%s' with "
+ "truncated dex cache arrays, %zu < %zu.",
+ GetLocation().c_str(),
+ i,
+ dex_file_location.c_str(),
+ static_cast<size_t>(bss_end_ - dex_cache_arrays),
+ layout.Size());
return false;
}
current_dex_cache_arrays = dex_cache_arrays;
@@ -553,7 +602,7 @@
if (dex_cache_arrays != bss_end_) {
// We expect the bss section to be either empty (dex_cache_arrays and bss_end_
// both null) or contain just the dex cache arrays and nothing else.
- *error_msg = StringPrintf("In oat file '%s' found unexpected bss size bigger by %zd bytes.",
+ *error_msg = StringPrintf("In oat file '%s' found unexpected bss size bigger by %zu bytes.",
GetLocation().c_str(),
static_cast<size_t>(bss_end_ - dex_cache_arrays));
return false;
@@ -661,7 +710,7 @@
uint32_t dex_file_location_checksum,
const uint8_t* dex_file_pointer,
const uint32_t* oat_class_offsets_pointer,
- const uint8_t* dex_cache_arrays)
+ uint8_t* dex_cache_arrays)
: oat_file_(oat_file),
dex_file_location_(dex_file_location),
canonical_dex_file_location_(canonical_dex_file_location),
diff --git a/runtime/oat_file.h b/runtime/oat_file.h
index 34f0141..6acdf86 100644
--- a/runtime/oat_file.h
+++ b/runtime/oat_file.h
@@ -301,10 +301,10 @@
const uint8_t* end_;
// Pointer to the .bss section, if present, otherwise null.
- const uint8_t* bss_begin_;
+ uint8_t* bss_begin_;
// Pointer to the end of the .bss section, if present, otherwise null.
- const uint8_t* bss_end_;
+ uint8_t* bss_end_;
// Was this oat_file loaded executable?
const bool is_executable_;
@@ -396,7 +396,7 @@
// Returns the offset to the OatClass information. Most callers should use GetOatClass.
uint32_t GetOatClassOffset(uint16_t class_def_index) const;
- const uint8_t* GetDexCacheArrays() const {
+ uint8_t* GetDexCacheArrays() const {
return dex_cache_arrays_;
}
@@ -409,7 +409,7 @@
uint32_t dex_file_checksum,
const uint8_t* dex_file_pointer,
const uint32_t* oat_class_offsets_pointer,
- const uint8_t* dex_cache_arrays);
+ uint8_t* dex_cache_arrays);
const OatFile* const oat_file_;
const std::string dex_file_location_;
@@ -417,7 +417,7 @@
const uint32_t dex_file_location_checksum_;
const uint8_t* const dex_file_pointer_;
const uint32_t* const oat_class_offsets_pointer_;
- const uint8_t* const dex_cache_arrays_;
+ uint8_t* const dex_cache_arrays_;
friend class OatFile;
DISALLOW_COPY_AND_ASSIGN(OatDexFile);
diff --git a/runtime/oat_file_assistant.cc b/runtime/oat_file_assistant.cc
index 29b879e..8d5418d 100644
--- a/runtime/oat_file_assistant.cc
+++ b/runtime/oat_file_assistant.cc
@@ -65,8 +65,10 @@
const InstructionSet isa,
bool load_executable,
const char* package_name)
- : dex_location_(dex_location), isa_(isa),
- package_name_(package_name), load_executable_(load_executable) {
+ : isa_(isa), package_name_(package_name), load_executable_(load_executable) {
+ CHECK(dex_location != nullptr) << "OatFileAssistant: null dex location";
+ dex_location_.assign(dex_location);
+
if (load_executable_ && isa != kRuntimeISA) {
LOG(WARNING) << "OatFileAssistant: Load executable specified, "
<< "but isa is not kRuntimeISA. Will not attempt to load executable.";
@@ -110,7 +112,7 @@
ClassLinker* class_linker = runtime->GetClassLinker();
const auto& boot_class_path = class_linker->GetBootClassPath();
for (size_t i = 0; i < boot_class_path.size(); i++) {
- if (boot_class_path[i]->GetLocation() == std::string(dex_location_)) {
+ if (boot_class_path[i]->GetLocation() == dex_location_) {
VLOG(oat) << "Dex location " << dex_location_ << " is in boot class path";
return true;
}
@@ -266,7 +268,6 @@
const std::string* OatFileAssistant::OdexFileName() {
if (!cached_odex_file_name_attempted_) {
- CHECK(dex_location_ != nullptr) << "OatFileAssistant: null dex location";
cached_odex_file_name_attempted_ = true;
std::string error_msg;
@@ -330,15 +331,13 @@
cached_oat_file_name_attempted_ = true;
// Compute the oat file name from the dex location.
- CHECK(dex_location_ != nullptr) << "OatFileAssistant: null dex location";
-
// TODO: The oat file assistant should be the definitive place for
// determining the oat file name from the dex location, not
// GetDalvikCacheFilename.
std::string cache_dir = StringPrintf("%s%s",
DalvikCacheDirectory().c_str(), GetInstructionSetString(isa_));
std::string error_msg;
- cached_oat_file_name_found_ = GetDalvikCacheFilename(dex_location_,
+ cached_oat_file_name_found_ = GetDalvikCacheFilename(dex_location_.c_str(),
cache_dir.c_str(), &cached_oat_file_name_, &error_msg);
if (!cached_oat_file_name_found_) {
// If we can't determine the oat file name, we treat the oat file as
@@ -413,7 +412,7 @@
// what we provide, which verifies the primary dex checksum for us.
const uint32_t* dex_checksum_pointer = GetRequiredDexChecksum();
const OatFile::OatDexFile* oat_dex_file = file.GetOatDexFile(
- dex_location_, dex_checksum_pointer, false);
+ dex_location_.c_str(), dex_checksum_pointer, false);
if (oat_dex_file == nullptr) {
return true;
}
@@ -421,7 +420,7 @@
// Verify the dex checksums for any secondary multidex files
for (size_t i = 1; ; i++) {
std::string secondary_dex_location
- = DexFile::GetMultiDexLocation(i, dex_location_);
+ = DexFile::GetMultiDexLocation(i, dex_location_.c_str());
const OatFile::OatDexFile* secondary_oat_dex_file
= file.GetOatDexFile(secondary_dex_location.c_str(), nullptr, false);
if (secondary_oat_dex_file == nullptr) {
@@ -613,16 +612,14 @@
CHECK(error_msg != nullptr);
if (input_file == nullptr) {
- *error_msg = "Patching of oat file for dex location "
- + std::string(dex_location_)
+ *error_msg = "Patching of oat file for dex location " + dex_location_
+ " not attempted because the input file name could not be determined.";
return false;
}
const std::string& input_file_name = *input_file;
if (OatFileName() == nullptr) {
- *error_msg = "Patching of oat file for dex location "
- + std::string(dex_location_)
+ *error_msg = "Patching of oat file for dex location " + dex_location_
+ " not attempted because the oat file name could not be determined.";
return false;
}
@@ -666,8 +663,7 @@
CHECK(error_msg != nullptr);
if (OatFileName() == nullptr) {
- *error_msg = "Generation of oat file for dex location "
- + std::string(dex_location_)
+ *error_msg = "Generation of oat file for dex location " + dex_location_
+ " not attempted because the oat file name could not be determined.";
return false;
}
@@ -681,14 +677,14 @@
}
std::vector<std::string> args;
- args.push_back("--dex-file=" + std::string(dex_location_));
+ args.push_back("--dex-file=" + dex_location_);
args.push_back("--oat-file=" + oat_file_name);
// dex2oat ignores missing dex files and doesn't report an error.
// Check explicitly here so we can detect the error properly.
// TODO: Why does dex2oat behave that way?
- if (!OS::FileExists(dex_location_)) {
- *error_msg = "Dex location " + std::string(dex_location_) + " does not exists.";
+ if (!OS::FileExists(dex_location_.c_str())) {
+ *error_msg = "Dex location " + dex_location_ + " does not exists.";
return false;
}
@@ -839,8 +835,7 @@
required_dex_checksum_attempted_ = true;
required_dex_checksum_found_ = false;
std::string error_msg;
- CHECK(dex_location_ != nullptr) << "OatFileAssistant provided no dex location";
- if (DexFile::GetChecksum(dex_location_, &cached_required_dex_checksum_, &error_msg)) {
+ if (DexFile::GetChecksum(dex_location_.c_str(), &cached_required_dex_checksum_, &error_msg)) {
required_dex_checksum_found_ = true;
has_original_dex_files_ = true;
} else {
@@ -853,7 +848,7 @@
const OatFile* odex_file = GetOdexFile();
if (odex_file != nullptr) {
const OatFile::OatDexFile* odex_dex_file = odex_file->GetOatDexFile(
- dex_location_, nullptr, false);
+ dex_location_.c_str(), nullptr, false);
if (odex_dex_file != nullptr) {
cached_required_dex_checksum_ = odex_dex_file->GetDexFileLocationChecksum();
required_dex_checksum_found_ = true;
@@ -873,7 +868,7 @@
std::string error_msg;
cached_odex_file_.reset(OatFile::Open(odex_file_name.c_str(),
odex_file_name.c_str(), nullptr, nullptr, load_executable_,
- dex_location_, &error_msg));
+ dex_location_.c_str(), &error_msg));
if (cached_odex_file_.get() == nullptr) {
VLOG(oat) << "OatFileAssistant test for existing pre-compiled oat file "
<< odex_file_name << ": " << error_msg;
@@ -904,7 +899,7 @@
std::string error_msg;
cached_oat_file_.reset(OatFile::Open(oat_file_name.c_str(),
oat_file_name.c_str(), nullptr, nullptr, load_executable_,
- dex_location_, &error_msg));
+ dex_location_.c_str(), &error_msg));
if (cached_oat_file_.get() == nullptr) {
VLOG(oat) << "OatFileAssistant test for existing oat file "
<< oat_file_name << ": " << error_msg;
diff --git a/runtime/oat_file_assistant.h b/runtime/oat_file_assistant.h
index 664db98..f781532 100644
--- a/runtime/oat_file_assistant.h
+++ b/runtime/oat_file_assistant.h
@@ -369,9 +369,7 @@
// remaining lifetime of the OatFileAssistant object.
ScopedFlock flock_;
- // In a properly constructed OatFileAssistant object, dex_location_ should
- // never be null.
- const char* dex_location_ = nullptr;
+ std::string dex_location_;
// In a properly constructed OatFileAssistant object, isa_ should be either
// the 32 or 64 bit variant for the current device.
diff --git a/runtime/oat_quick_method_header.cc b/runtime/oat_quick_method_header.cc
new file mode 100644
index 0000000..9786c05
--- /dev/null
+++ b/runtime/oat_quick_method_header.cc
@@ -0,0 +1,139 @@
+/*
+ * 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 "oat_quick_method_header.h"
+
+#include "art_method.h"
+#include "mapping_table.h"
+#include "scoped_thread_state_change.h"
+#include "thread.h"
+
+namespace art {
+
+OatQuickMethodHeader::OatQuickMethodHeader(
+ uint32_t mapping_table_offset,
+ uint32_t vmap_table_offset,
+ uint32_t gc_map_offset,
+ uint32_t frame_size_in_bytes,
+ uint32_t core_spill_mask,
+ uint32_t fp_spill_mask,
+ uint32_t code_size)
+ : mapping_table_offset_(mapping_table_offset),
+ vmap_table_offset_(vmap_table_offset),
+ gc_map_offset_(gc_map_offset),
+ frame_info_(frame_size_in_bytes, core_spill_mask, fp_spill_mask),
+ code_size_(code_size) {}
+
+OatQuickMethodHeader::~OatQuickMethodHeader() {}
+
+uint32_t OatQuickMethodHeader::ToDexPc(ArtMethod* method,
+ const uintptr_t pc,
+ bool abort_on_failure) const {
+ const void* entry_point = GetEntryPoint();
+ uint32_t sought_offset = pc - reinterpret_cast<uintptr_t>(entry_point);
+ if (IsOptimized()) {
+ CodeInfo code_info = GetOptimizedCodeInfo();
+ StackMapEncoding encoding = code_info.ExtractEncoding();
+ StackMap stack_map = code_info.GetStackMapForNativePcOffset(sought_offset, encoding);
+ if (stack_map.IsValid()) {
+ return stack_map.GetDexPc(encoding);
+ }
+ } else {
+ MappingTable table(GetMappingTable());
+ // NOTE: Special methods (see Mir2Lir::GenSpecialCase()) have an empty mapping
+ // but they have no suspend checks and, consequently, we never call ToDexPc() for them.
+ if (table.TotalSize() == 0) {
+ DCHECK(method->IsNative());
+ return DexFile::kDexNoIndex;
+ }
+
+ // Assume the caller wants a pc-to-dex mapping so check here first.
+ typedef MappingTable::PcToDexIterator It;
+ for (It cur = table.PcToDexBegin(), end = table.PcToDexEnd(); cur != end; ++cur) {
+ if (cur.NativePcOffset() == sought_offset) {
+ return cur.DexPc();
+ }
+ }
+ // Now check dex-to-pc mappings.
+ typedef MappingTable::DexToPcIterator It2;
+ for (It2 cur = table.DexToPcBegin(), end = table.DexToPcEnd(); cur != end; ++cur) {
+ if (cur.NativePcOffset() == sought_offset) {
+ return cur.DexPc();
+ }
+ }
+ }
+ if (abort_on_failure) {
+ ScopedObjectAccess soa(Thread::Current());
+ LOG(FATAL) << "Failed to find Dex offset for PC offset "
+ << reinterpret_cast<void*>(sought_offset)
+ << "(PC " << reinterpret_cast<void*>(pc) << ", entry_point=" << entry_point
+ << " current entry_point=" << method->GetEntryPointFromQuickCompiledCode()
+ << ") in " << PrettyMethod(method);
+ }
+ return DexFile::kDexNoIndex;
+}
+
+uintptr_t OatQuickMethodHeader::ToNativeQuickPc(ArtMethod* method,
+ const uint32_t dex_pc,
+ bool is_for_catch_handler,
+ bool abort_on_failure) const {
+ const void* entry_point = GetEntryPoint();
+ if (IsOptimized()) {
+ // Optimized code does not have a mapping table. Search for the dex-to-pc
+ // mapping in stack maps.
+ CodeInfo code_info = GetOptimizedCodeInfo();
+ StackMapEncoding encoding = code_info.ExtractEncoding();
+
+ // All stack maps are stored in the same CodeItem section, safepoint stack
+ // maps first, then catch stack maps. We use `is_for_catch_handler` to select
+ // the order of iteration.
+ StackMap stack_map =
+ LIKELY(is_for_catch_handler) ? code_info.GetCatchStackMapForDexPc(dex_pc, encoding)
+ : code_info.GetStackMapForDexPc(dex_pc, encoding);
+ if (stack_map.IsValid()) {
+ return reinterpret_cast<uintptr_t>(entry_point) + stack_map.GetNativePcOffset(encoding);
+ }
+ } else {
+ MappingTable table(GetMappingTable());
+ if (table.TotalSize() == 0) {
+ DCHECK_EQ(dex_pc, 0U);
+ return 0; // Special no mapping/pc == 0 case
+ }
+ // Assume the caller wants a dex-to-pc mapping so check here first.
+ typedef MappingTable::DexToPcIterator It;
+ for (It cur = table.DexToPcBegin(), end = table.DexToPcEnd(); cur != end; ++cur) {
+ if (cur.DexPc() == dex_pc) {
+ return reinterpret_cast<uintptr_t>(entry_point) + cur.NativePcOffset();
+ }
+ }
+ // Now check pc-to-dex mappings.
+ typedef MappingTable::PcToDexIterator It2;
+ for (It2 cur = table.PcToDexBegin(), end = table.PcToDexEnd(); cur != end; ++cur) {
+ if (cur.DexPc() == dex_pc) {
+ return reinterpret_cast<uintptr_t>(entry_point) + cur.NativePcOffset();
+ }
+ }
+ }
+
+ if (abort_on_failure) {
+ ScopedObjectAccess soa(Thread::Current());
+ LOG(FATAL) << "Failed to find native offset for dex pc 0x" << std::hex << dex_pc
+ << " in " << PrettyMethod(method);
+ }
+ return UINTPTR_MAX;
+}
+
+} // namespace art
diff --git a/runtime/oat_quick_method_header.h b/runtime/oat_quick_method_header.h
new file mode 100644
index 0000000..6eadd87
--- /dev/null
+++ b/runtime/oat_quick_method_header.h
@@ -0,0 +1,127 @@
+/*
+ * 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_OAT_QUICK_METHOD_HEADER_H_
+#define ART_RUNTIME_OAT_QUICK_METHOD_HEADER_H_
+
+#include "arch/instruction_set.h"
+#include "base/macros.h"
+#include "quick/quick_method_frame_info.h"
+#include "stack_map.h"
+
+namespace art {
+
+class ArtMethod;
+
+// OatQuickMethodHeader precedes the raw code chunk generated by the compiler.
+class PACKED(4) OatQuickMethodHeader {
+ public:
+ OatQuickMethodHeader(uint32_t mapping_table_offset = 0U,
+ uint32_t vmap_table_offset = 0U,
+ uint32_t gc_map_offset = 0U,
+ uint32_t frame_size_in_bytes = 0U,
+ uint32_t core_spill_mask = 0U,
+ uint32_t fp_spill_mask = 0U,
+ uint32_t code_size = 0U);
+
+ ~OatQuickMethodHeader();
+
+ OatQuickMethodHeader& operator=(const OatQuickMethodHeader&) = default;
+
+ uintptr_t NativeQuickPcOffset(const uintptr_t pc) const {
+ return pc - reinterpret_cast<uintptr_t>(GetEntryPoint());
+ }
+
+ bool IsOptimized() const {
+ return gc_map_offset_ == 0 && vmap_table_offset_ != 0;
+ }
+
+ CodeInfo GetOptimizedCodeInfo() const {
+ DCHECK(IsOptimized());
+ const void* data = reinterpret_cast<const void*>(code_ - vmap_table_offset_);
+ return CodeInfo(data);
+ }
+
+ const uint8_t* GetCode() const {
+ return code_;
+ }
+
+ const uint8_t* GetNativeGcMap() const {
+ return (gc_map_offset_ == 0) ? nullptr : code_ - gc_map_offset_;
+ }
+
+ const uint8_t* GetMappingTable() const {
+ return (mapping_table_offset_ == 0) ? nullptr : code_ - mapping_table_offset_;
+ }
+
+ const uint8_t* GetVmapTable() const {
+ CHECK(!IsOptimized()) << "Unimplemented vmap table for optimizing compiler";
+ return (vmap_table_offset_ == 0) ? nullptr : code_ - vmap_table_offset_;
+ }
+
+ bool Contains(uintptr_t pc) const {
+ uintptr_t code_start = reinterpret_cast<uintptr_t>(code_);
+ return code_start <= pc && pc <= (code_start + code_size_);
+ }
+
+ const uint8_t* GetEntryPoint() const {
+ // When the runtime architecture is ARM, `kRuntimeISA` is set to `kArm`
+ // (not `kThumb2`), *but* we always generate code for the Thumb-2
+ // instruction set anyway. Thumb-2 requires the entrypoint to be of
+ // offset 1.
+ static_assert(kRuntimeISA != kThumb2, "kThumb2 cannot be a runtime ISA");
+ return (kRuntimeISA == kArm)
+ ? reinterpret_cast<uint8_t*>(reinterpret_cast<uintptr_t>(code_) | 1)
+ : code_;
+ }
+
+ template <bool kCheckFrameSize = true>
+ uint32_t GetFrameSizeInBytes() {
+ uint32_t result = frame_info_.FrameSizeInBytes();
+ if (kCheckFrameSize) {
+ DCHECK_LE(static_cast<size_t>(kStackAlignment), result);
+ }
+ return result;
+ }
+
+ QuickMethodFrameInfo GetFrameInfo() const {
+ return frame_info_;
+ }
+
+ uintptr_t ToNativeQuickPc(ArtMethod* method,
+ const uint32_t dex_pc,
+ bool is_for_catch_handler,
+ bool abort_on_failure = true) const;
+
+ uint32_t ToDexPc(ArtMethod* method, const uintptr_t pc, bool abort_on_failure = true) const;
+
+ // The offset in bytes from the start of the mapping table to the end of the header.
+ uint32_t mapping_table_offset_;
+ // The offset in bytes from the start of the vmap table to the end of the header.
+ uint32_t vmap_table_offset_;
+ // The offset in bytes from the start of the gc map to the end of the header.
+ uint32_t gc_map_offset_;
+ // The stack frame information.
+ QuickMethodFrameInfo frame_info_;
+ // The code size in bytes.
+ uint32_t code_size_;
+ // The actual code.
+ uint8_t code_[0];
+};
+
+} // namespace art
+
+#endif // ART_RUNTIME_OAT_QUICK_METHOD_HEADER_H_
diff --git a/runtime/quick/quick_method_frame_info.h b/runtime/quick/quick_method_frame_info.h
index 684d4da..71f8265 100644
--- a/runtime/quick/quick_method_frame_info.h
+++ b/runtime/quick/quick_method_frame_info.h
@@ -50,6 +50,10 @@
return fp_spill_mask_;
}
+ size_t GetReturnPcOffset() const {
+ return FrameSizeInBytes() - sizeof(void*);
+ }
+
private:
uint32_t frame_size_in_bytes_;
uint32_t core_spill_mask_;
diff --git a/runtime/quick_exception_handler.cc b/runtime/quick_exception_handler.cc
index 7ba19ab..d05f909 100644
--- a/runtime/quick_exception_handler.cc
+++ b/runtime/quick_exception_handler.cc
@@ -17,7 +17,6 @@
#include "quick_exception_handler.h"
#include "arch/context.h"
-#include "art_code.h"
#include "art_method-inl.h"
#include "dex_instruction.h"
#include "entrypoints/entrypoint_utils.h"
@@ -27,6 +26,7 @@
#include "mirror/class-inl.h"
#include "mirror/class_loader.h"
#include "mirror/throwable.h"
+#include "oat_quick_method_header.h"
#include "stack_map.h"
#include "verifier/method_verifier.h"
@@ -36,13 +36,19 @@
static constexpr size_t kInvalidFrameDepth = 0xffffffff;
QuickExceptionHandler::QuickExceptionHandler(Thread* self, bool is_deoptimization)
- : self_(self), context_(self->GetLongJumpContext()), is_deoptimization_(is_deoptimization),
- method_tracing_active_(is_deoptimization ||
- Runtime::Current()->GetInstrumentation()->AreExitStubsInstalled()),
- handler_quick_frame_(nullptr), handler_quick_frame_pc_(0), handler_quick_arg0_(0),
- handler_method_(nullptr), handler_dex_pc_(0), clear_exception_(false),
- handler_frame_depth_(kInvalidFrameDepth) {
-}
+ : self_(self),
+ context_(self->GetLongJumpContext()),
+ is_deoptimization_(is_deoptimization),
+ method_tracing_active_(is_deoptimization ||
+ Runtime::Current()->GetInstrumentation()->AreExitStubsInstalled()),
+ handler_quick_frame_(nullptr),
+ handler_quick_frame_pc_(0),
+ handler_method_header_(nullptr),
+ handler_quick_arg0_(0),
+ handler_method_(nullptr),
+ handler_dex_pc_(0),
+ clear_exception_(false),
+ handler_frame_depth_(kInvalidFrameDepth) {}
// Finds catch handler.
class CatchBlockStackVisitor FINAL : public StackVisitor {
@@ -62,6 +68,7 @@
// This is the upcall, we remember the frame and last pc so that we may long jump to them.
exception_handler_->SetHandlerQuickFramePc(GetCurrentQuickFramePc());
exception_handler_->SetHandlerQuickFrame(GetCurrentQuickFrame());
+ exception_handler_->SetHandlerMethodHeader(GetCurrentOatQuickMethodHeader());
uint32_t next_dex_pc;
ArtMethod* next_art_method;
bool has_next = GetNextMethodAndDexPc(&next_art_method, &next_dex_pc);
@@ -101,8 +108,10 @@
exception_handler_->SetHandlerMethod(method);
exception_handler_->SetHandlerDexPc(found_dex_pc);
exception_handler_->SetHandlerQuickFramePc(
- GetCurrentCode().ToNativeQuickPc(found_dex_pc, /* is_catch_handler */ true));
+ GetCurrentOatQuickMethodHeader()->ToNativeQuickPc(
+ method, found_dex_pc, /* is_catch_handler */ true));
exception_handler_->SetHandlerQuickFrame(GetCurrentQuickFrame());
+ exception_handler_->SetHandlerMethodHeader(GetCurrentOatQuickMethodHeader());
return false; // End stack walk.
} else if (UNLIKELY(GetThread()->HasDebuggerShadowFrames())) {
// We are going to unwind this frame. Did we prepare a shadow frame for debugging?
@@ -160,8 +169,8 @@
}
// If the handler is in optimized code, we need to set the catch environment.
if (*handler_quick_frame_ != nullptr &&
- handler_method_ != nullptr &&
- ArtCode(handler_quick_frame_).IsOptimized(sizeof(void*))) {
+ handler_method_header_ != nullptr &&
+ handler_method_header_->IsOptimized()) {
SetCatchEnvironmentForOptimizedHandler(&visitor);
}
}
@@ -202,14 +211,14 @@
void QuickExceptionHandler::SetCatchEnvironmentForOptimizedHandler(StackVisitor* stack_visitor) {
DCHECK(!is_deoptimization_);
DCHECK(*handler_quick_frame_ != nullptr) << "Method should not be called on upcall exceptions";
- DCHECK(handler_method_ != nullptr && ArtCode(handler_quick_frame_).IsOptimized(sizeof(void*)));
+ DCHECK(handler_method_ != nullptr && handler_method_header_->IsOptimized());
if (kDebugExceptionDelivery) {
self_->DumpStack(LOG(INFO) << "Setting catch phis: ");
}
const size_t number_of_vregs = handler_method_->GetCodeItem()->registers_size_;
- CodeInfo code_info = ArtCode(handler_quick_frame_).GetOptimizedCodeInfo();
+ CodeInfo code_info = handler_method_header_->GetOptimizedCodeInfo();
StackMapEncoding encoding = code_info.ExtractEncoding();
// Find stack map of the throwing instruction.
@@ -285,6 +294,7 @@
// and last pc so that we may long jump to them.
exception_handler_->SetHandlerQuickFramePc(GetCurrentQuickFramePc());
exception_handler_->SetHandlerQuickFrame(GetCurrentQuickFrame());
+ exception_handler_->SetHandlerMethodHeader(GetCurrentOatQuickMethodHeader());
if (!stacked_shadow_frame_pushed_) {
// In case there is no deoptimized shadow frame for this upcall, we still
// need to push a nullptr to the stack since there is always a matching pop after
diff --git a/runtime/quick_exception_handler.h b/runtime/quick_exception_handler.h
index 89d6a25..eedf83f 100644
--- a/runtime/quick_exception_handler.h
+++ b/runtime/quick_exception_handler.h
@@ -71,6 +71,10 @@
handler_quick_frame_pc_ = handler_quick_frame_pc;
}
+ void SetHandlerMethodHeader(const OatQuickMethodHeader* handler_method_header) {
+ handler_method_header_ = handler_method_header;
+ }
+
void SetHandlerQuickArg0(uintptr_t handler_quick_arg0) {
handler_quick_arg0_ = handler_quick_arg0;
}
@@ -115,6 +119,8 @@
ArtMethod** handler_quick_frame_;
// PC to branch to for the handler.
uintptr_t handler_quick_frame_pc_;
+ // Quick code of the handler.
+ const OatQuickMethodHeader* handler_method_header_;
// The value for argument 0.
uintptr_t handler_quick_arg0_;
// The handler method to report to the debugger.
diff --git a/runtime/reflection_test.cc b/runtime/reflection_test.cc
index bd89be5..c7c2709 100644
--- a/runtime/reflection_test.cc
+++ b/runtime/reflection_test.cc
@@ -157,7 +157,8 @@
result = InvokeWithJValues(soa, receiver_ref.get(), soa.EncodeMethod(method), args);
EXPECT_EQ(SCHAR_MAX, result.GetB());
- args[0].b = (SCHAR_MIN << 24) >> 24;
+ static_assert(SCHAR_MIN == -128, "SCHAR_MIN unexpected");
+ args[0].b = SCHAR_MIN;
result = InvokeWithJValues(soa, receiver_ref.get(), soa.EncodeMethod(method), args);
EXPECT_EQ(SCHAR_MIN, result.GetB());
}
diff --git a/runtime/runtime_linux.cc b/runtime/runtime_linux.cc
index 44a13c9..f0b3c4e 100644
--- a/runtime/runtime_linux.cc
+++ b/runtime/runtime_linux.cc
@@ -41,7 +41,7 @@
public:
explicit Backtrace(void* raw_context) : raw_context_(raw_context) {}
void Dump(std::ostream& os) const {
- DumpNativeStack(os, GetTid(), "\t", nullptr, nullptr, raw_context_);
+ DumpNativeStack(os, GetTid(), "\t", nullptr, raw_context_);
}
private:
// Stores the context of the signal that was unexpected and will terminate the runtime. The
diff --git a/runtime/stack.cc b/runtime/stack.cc
index d8d916c..9359d27 100644
--- a/runtime/stack.cc
+++ b/runtime/stack.cc
@@ -17,7 +17,6 @@
#include "stack.h"
#include "arch/context.h"
-#include "art_code.h"
#include "art_method-inl.h"
#include "base/hex_dump.h"
#include "entrypoints/entrypoint_utils-inl.h"
@@ -25,10 +24,13 @@
#include "gc_map.h"
#include "gc/space/image_space.h"
#include "gc/space/space-inl.h"
+#include "jit/jit.h"
+#include "jit/jit_code_cache.h"
#include "linear_alloc.h"
#include "mirror/class-inl.h"
#include "mirror/object-inl.h"
#include "mirror/object_array-inl.h"
+#include "oat_quick_method_header.h"
#include "quick/quick_method_frame_info.h"
#include "runtime.h"
#include "thread.h"
@@ -103,6 +105,7 @@
cur_shadow_frame_(nullptr),
cur_quick_frame_(nullptr),
cur_quick_frame_pc_(0),
+ cur_oat_quick_method_header_(nullptr),
num_frames_(num_frames),
cur_depth_(0),
current_inlining_depth_(0),
@@ -111,9 +114,9 @@
}
InlineInfo StackVisitor::GetCurrentInlineInfo() const {
- ArtCode outer_code = GetCurrentCode();
- uint32_t native_pc_offset = outer_code.NativeQuickPcOffset(cur_quick_frame_pc_);
- CodeInfo code_info = outer_code.GetOptimizedCodeInfo();
+ const OatQuickMethodHeader* method_header = GetCurrentOatQuickMethodHeader();
+ uint32_t native_pc_offset = method_header->NativeQuickPcOffset(cur_quick_frame_pc_);
+ CodeInfo code_info = method_header->GetOptimizedCodeInfo();
StackMapEncoding encoding = code_info.ExtractEncoding();
StackMap stack_map = code_info.GetStackMapForNativePcOffset(native_pc_offset, encoding);
DCHECK(stack_map.IsValid());
@@ -142,8 +145,11 @@
if (IsInInlinedFrame()) {
size_t depth_in_stack_map = current_inlining_depth_ - 1;
return GetCurrentInlineInfo().GetDexPcAtDepth(depth_in_stack_map);
+ } else if (cur_oat_quick_method_header_ == nullptr) {
+ return DexFile::kDexNoIndex;
} else {
- return GetCurrentCode().ToDexPc(cur_quick_frame_pc_, abort_on_failure);
+ return cur_oat_quick_method_header_->ToDexPc(
+ GetMethod(), cur_quick_frame_pc_, abort_on_failure);
}
} else {
return 0;
@@ -161,8 +167,7 @@
} else if (m->IsNative()) {
if (cur_quick_frame_ != nullptr) {
HandleScope* hs = reinterpret_cast<HandleScope*>(
- reinterpret_cast<char*>(cur_quick_frame_) +
- GetCurrentCode().GetHandleScopeOffset().SizeValue());
+ reinterpret_cast<char*>(cur_quick_frame_) + sizeof(ArtMethod*));
return hs->GetReference(0);
} else {
return cur_shadow_frame_->GetVRegReference(0);
@@ -192,7 +197,7 @@
size_t StackVisitor::GetNativePcOffset() const {
DCHECK(!IsShadowFrame());
- return GetCurrentCode().NativeQuickPcOffset(cur_quick_frame_pc_);
+ return GetCurrentOatQuickMethodHeader()->NativeQuickPcOffset(cur_quick_frame_pc_);
}
bool StackVisitor::IsReferenceVReg(ArtMethod* m, uint16_t vreg) {
@@ -201,10 +206,11 @@
if (m->IsNative() || m->IsRuntimeMethod() || m->IsProxyMethod()) {
return false;
}
- if (GetCurrentCode().IsOptimized(sizeof(void*))) {
+ const OatQuickMethodHeader* method_header = GetCurrentOatQuickMethodHeader();
+ if (method_header->IsOptimized()) {
return true; // TODO: Implement.
}
- const uint8_t* native_gc_map = GetCurrentCode().GetNativeGcMap(sizeof(void*));
+ const uint8_t* native_gc_map = method_header->GetNativeGcMap();
CHECK(native_gc_map != nullptr) << PrettyMethod(m);
const DexFile::CodeItem* code_item = m->GetCodeItem();
// Can't be null or how would we compile its instructions?
@@ -213,7 +219,7 @@
size_t num_regs = std::min(map.RegWidth() * 8, static_cast<size_t>(code_item->registers_size_));
const uint8_t* reg_bitmap = nullptr;
if (num_regs > 0) {
- uintptr_t native_pc_offset = GetCurrentCode().NativeQuickPcOffset(GetCurrentQuickFramePc());
+ uintptr_t native_pc_offset = method_header->NativeQuickPcOffset(GetCurrentQuickFramePc());
reg_bitmap = map.FindBitMap(native_pc_offset);
DCHECK(reg_bitmap != nullptr);
}
@@ -252,7 +258,7 @@
if (GetVRegFromDebuggerShadowFrame(vreg, kind, val)) {
return true;
}
- if (GetCurrentCode().IsOptimized(sizeof(void*))) {
+ if (cur_oat_quick_method_header_->IsOptimized()) {
return GetVRegFromOptimizedCode(m, vreg, kind, val);
} else {
return GetVRegFromQuickCode(m, vreg, kind, val);
@@ -267,8 +273,9 @@
bool StackVisitor::GetVRegFromQuickCode(ArtMethod* m, uint16_t vreg, VRegKind kind,
uint32_t* val) const {
DCHECK_EQ(m, GetMethod());
- const VmapTable vmap_table(GetCurrentCode().GetVmapTable(sizeof(void*)));
- QuickMethodFrameInfo frame_info = GetCurrentCode().GetQuickFrameInfo();
+ const OatQuickMethodHeader* method_header = GetCurrentOatQuickMethodHeader();
+ QuickMethodFrameInfo frame_info = method_header->GetFrameInfo();
+ const VmapTable vmap_table(method_header->GetVmapTable());
uint32_t vmap_offset;
// TODO: IsInContext stops before spotting floating point registers.
if (vmap_table.IsInContext(vreg, kind, &vmap_offset)) {
@@ -294,10 +301,11 @@
// its instructions?
uint16_t number_of_dex_registers = code_item->registers_size_;
DCHECK_LT(vreg, code_item->registers_size_);
- CodeInfo code_info = GetCurrentCode().GetOptimizedCodeInfo();
+ const OatQuickMethodHeader* method_header = GetCurrentOatQuickMethodHeader();
+ CodeInfo code_info = method_header->GetOptimizedCodeInfo();
StackMapEncoding encoding = code_info.ExtractEncoding();
- uint32_t native_pc_offset = GetCurrentCode().NativeQuickPcOffset(cur_quick_frame_pc_);
+ uint32_t native_pc_offset = method_header->NativeQuickPcOffset(cur_quick_frame_pc_);
StackMap stack_map = code_info.GetStackMapForNativePcOffset(native_pc_offset, encoding);
DCHECK(stack_map.IsValid());
size_t depth_in_stack_map = current_inlining_depth_ - 1;
@@ -402,7 +410,7 @@
if (cur_quick_frame_ != nullptr) {
DCHECK(context_ != nullptr); // You can't reliably read registers without a context.
DCHECK(m == GetMethod());
- if (GetCurrentCode().IsOptimized(sizeof(void*))) {
+ if (cur_oat_quick_method_header_->IsOptimized()) {
return GetVRegPairFromOptimizedCode(m, vreg, kind_lo, kind_hi, val);
} else {
return GetVRegPairFromQuickCode(m, vreg, kind_lo, kind_hi, val);
@@ -417,8 +425,9 @@
bool StackVisitor::GetVRegPairFromQuickCode(ArtMethod* m, uint16_t vreg, VRegKind kind_lo,
VRegKind kind_hi, uint64_t* val) const {
DCHECK_EQ(m, GetMethod());
- const VmapTable vmap_table(GetCurrentCode().GetVmapTable(sizeof(void*)));
- QuickMethodFrameInfo frame_info = GetCurrentCode().GetQuickFrameInfo();
+ const OatQuickMethodHeader* method_header = GetCurrentOatQuickMethodHeader();
+ QuickMethodFrameInfo frame_info = method_header->GetFrameInfo();
+ const VmapTable vmap_table(method_header->GetVmapTable());
uint32_t vmap_offset_lo, vmap_offset_hi;
// TODO: IsInContext stops before spotting floating point registers.
if (vmap_table.IsInContext(vreg, kind_lo, &vmap_offset_lo) &&
@@ -477,7 +486,7 @@
if (cur_quick_frame_ != nullptr) {
DCHECK(context_ != nullptr); // You can't reliably write registers without a context.
DCHECK(m == GetMethod());
- if (GetCurrentCode().IsOptimized(sizeof(void*))) {
+ if (cur_oat_quick_method_header_->IsOptimized()) {
return false;
} else {
return SetVRegFromQuickCode(m, vreg, new_value, kind);
@@ -492,8 +501,9 @@
VRegKind kind) {
DCHECK(context_ != nullptr); // You can't reliably write registers without a context.
DCHECK(m == GetMethod());
- const VmapTable vmap_table(GetCurrentCode().GetVmapTable(sizeof(void*)));
- QuickMethodFrameInfo frame_info = GetCurrentCode().GetQuickFrameInfo();
+ const OatQuickMethodHeader* method_header = GetCurrentOatQuickMethodHeader();
+ QuickMethodFrameInfo frame_info = method_header->GetFrameInfo();
+ const VmapTable vmap_table(method_header->GetVmapTable());
uint32_t vmap_offset;
// TODO: IsInContext stops before spotting floating point registers.
if (vmap_table.IsInContext(vreg, kind, &vmap_offset)) {
@@ -584,7 +594,7 @@
if (cur_quick_frame_ != nullptr) {
DCHECK(context_ != nullptr); // You can't reliably write registers without a context.
DCHECK(m == GetMethod());
- if (GetCurrentCode().IsOptimized(sizeof(void*))) {
+ if (cur_oat_quick_method_header_->IsOptimized()) {
return false;
} else {
return SetVRegPairFromQuickCode(m, vreg, new_value, kind_lo, kind_hi);
@@ -599,8 +609,9 @@
bool StackVisitor::SetVRegPairFromQuickCode(
ArtMethod* m, uint16_t vreg, uint64_t new_value, VRegKind kind_lo, VRegKind kind_hi) {
DCHECK_EQ(m, GetMethod());
- const VmapTable vmap_table(GetCurrentCode().GetVmapTable(sizeof(void*)));
- QuickMethodFrameInfo frame_info = GetCurrentCode().GetQuickFrameInfo();
+ const OatQuickMethodHeader* method_header = GetCurrentOatQuickMethodHeader();
+ QuickMethodFrameInfo frame_info = method_header->GetFrameInfo();
+ const VmapTable vmap_table(method_header->GetVmapTable());
uint32_t vmap_offset_lo, vmap_offset_hi;
// TODO: IsInContext stops before spotting floating point registers.
if (vmap_table.IsInContext(vreg, kind_lo, &vmap_offset_lo) &&
@@ -717,14 +728,14 @@
uintptr_t StackVisitor::GetReturnPc() const {
uint8_t* sp = reinterpret_cast<uint8_t*>(GetCurrentQuickFrame());
DCHECK(sp != nullptr);
- uint8_t* pc_addr = sp + GetCurrentCode().GetReturnPcOffset().SizeValue();
+ uint8_t* pc_addr = sp + GetCurrentQuickFrameInfo().GetReturnPcOffset();
return *reinterpret_cast<uintptr_t*>(pc_addr);
}
void StackVisitor::SetReturnPc(uintptr_t new_ret_pc) {
uint8_t* sp = reinterpret_cast<uint8_t*>(GetCurrentQuickFrame());
CHECK(sp != nullptr);
- uint8_t* pc_addr = sp + GetCurrentCode().GetReturnPcOffset().SizeValue();
+ uint8_t* pc_addr = sp + GetCurrentQuickFrameInfo().GetReturnPcOffset();
*reinterpret_cast<uintptr_t*>(pc_addr) = new_ret_pc;
}
@@ -821,6 +832,45 @@
return thread->GetInstrumentationStack()->at(depth);
}
+static void AssertPcIsWithinQuickCode(ArtMethod* method, uintptr_t pc)
+ SHARED_REQUIRES(Locks::mutator_lock_) {
+ if (method->IsNative() || method->IsRuntimeMethod() || method->IsProxyMethod()) {
+ return;
+ }
+
+ if (pc == reinterpret_cast<uintptr_t>(GetQuickInstrumentationExitPc())) {
+ return;
+ }
+
+ const void* code = method->GetEntryPointFromQuickCompiledCode();
+ if (code == GetQuickInstrumentationEntryPoint()) {
+ return;
+ }
+
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ if (class_linker->IsQuickToInterpreterBridge(code) ||
+ class_linker->IsQuickResolutionStub(code)) {
+ return;
+ }
+
+ // If we are the JIT then we may have just compiled the method after the
+ // IsQuickToInterpreterBridge check.
+ jit::Jit* const jit = Runtime::Current()->GetJit();
+ if (jit != nullptr &&
+ jit->GetCodeCache()->ContainsCodePtr(reinterpret_cast<const void*>(code))) {
+ return;
+ }
+
+ uint32_t code_size = reinterpret_cast<const OatQuickMethodHeader*>(
+ EntryPointToCodePointer(code))[-1].code_size_;
+ uintptr_t code_start = reinterpret_cast<uintptr_t>(code);
+ CHECK(code_start <= pc && pc <= (code_start + code_size))
+ << PrettyMethod(method)
+ << " pc=" << std::hex << pc
+ << " code=" << code
+ << " size=" << code_size;
+}
+
void StackVisitor::SanityCheckFrame() const {
if (kIsDebugBuild) {
ArtMethod* method = GetMethod();
@@ -859,9 +909,9 @@
}
}
if (cur_quick_frame_ != nullptr) {
- GetCurrentCode().AssertPcIsWithinQuickCode(cur_quick_frame_pc_);
+ AssertPcIsWithinQuickCode(method, cur_quick_frame_pc_);
// Frame sanity.
- size_t frame_size = GetCurrentCode().GetFrameSizeInBytes();
+ size_t frame_size = GetCurrentQuickFrameInfo().FrameSizeInBytes();
CHECK_NE(frame_size, 0u);
// A rough guess at an upper size we expect to see for a frame.
// 256 registers
@@ -871,13 +921,80 @@
// TODO: 083-compiler-regressions ManyFloatArgs shows this estimate is wrong.
// const size_t kMaxExpectedFrameSize = (256 + 2 + 3 + 3) * sizeof(word);
const size_t kMaxExpectedFrameSize = 2 * KB;
- CHECK_LE(frame_size, kMaxExpectedFrameSize);
- size_t return_pc_offset = GetCurrentCode().GetReturnPcOffset().SizeValue();
+ CHECK_LE(frame_size, kMaxExpectedFrameSize) << PrettyMethod(method);
+ size_t return_pc_offset = GetCurrentQuickFrameInfo().GetReturnPcOffset();
CHECK_LT(return_pc_offset, frame_size);
}
}
}
+// Counts the number of references in the parameter list of the corresponding method.
+// Note: Thus does _not_ include "this" for non-static methods.
+static uint32_t GetNumberOfReferenceArgsWithoutReceiver(ArtMethod* method)
+ SHARED_REQUIRES(Locks::mutator_lock_) {
+ uint32_t shorty_len;
+ const char* shorty = method->GetShorty(&shorty_len);
+ uint32_t refs = 0;
+ for (uint32_t i = 1; i < shorty_len ; ++i) {
+ if (shorty[i] == 'L') {
+ refs++;
+ }
+ }
+ return refs;
+}
+
+QuickMethodFrameInfo StackVisitor::GetCurrentQuickFrameInfo() const {
+ if (cur_oat_quick_method_header_ != nullptr) {
+ return cur_oat_quick_method_header_->GetFrameInfo();
+ }
+
+ ArtMethod* method = GetMethod();
+ Runtime* runtime = Runtime::Current();
+
+ if (method->IsAbstract()) {
+ return runtime->GetCalleeSaveMethodFrameInfo(Runtime::kRefsAndArgs);
+ }
+
+ // This goes before IsProxyMethod since runtime methods have a null declaring class.
+ if (method->IsRuntimeMethod()) {
+ return runtime->GetRuntimeMethodFrameInfo(method);
+ }
+
+ // For Proxy method we add special handling for the direct method case (there is only one
+ // direct method - constructor). Direct method is cloned from original
+ // java.lang.reflect.Proxy class together with code and as a result it is executed as usual
+ // quick compiled method without any stubs. So the frame info should be returned as it is a
+ // quick method not a stub. However, if instrumentation stubs are installed, the
+ // instrumentation->GetQuickCodeFor() returns the artQuickProxyInvokeHandler instead of an
+ // oat code pointer, thus we have to add a special case here.
+ if (method->IsProxyMethod()) {
+ if (method->IsDirect()) {
+ CHECK(method->IsConstructor());
+ const void* code_pointer =
+ EntryPointToCodePointer(method->GetEntryPointFromQuickCompiledCode());
+ return reinterpret_cast<const OatQuickMethodHeader*>(code_pointer)[-1].frame_info_;
+ } else {
+ return runtime->GetCalleeSaveMethodFrameInfo(Runtime::kRefsAndArgs);
+ }
+ }
+
+ ClassLinker* class_linker = runtime->GetClassLinker();
+ DCHECK(method->IsNative());
+ const void* entry_point = runtime->GetInstrumentation()->GetQuickCodeFor(method, sizeof(void*));
+ DCHECK(class_linker->IsQuickGenericJniStub(entry_point)) << PrettyMethod(method);
+ // Generic JNI frame.
+ uint32_t handle_refs = GetNumberOfReferenceArgsWithoutReceiver(method) + 1;
+ size_t scope_size = HandleScope::SizeOf(handle_refs);
+ QuickMethodFrameInfo callee_info = runtime->GetCalleeSaveMethodFrameInfo(Runtime::kRefsAndArgs);
+
+ // Callee saves + handle scope + method ref + alignment
+ // Note: -sizeof(void*) since callee-save frame stores a whole method pointer.
+ size_t frame_size = RoundUp(
+ callee_info.FrameSizeInBytes() - sizeof(void*) + sizeof(ArtMethod*) + scope_size,
+ kStackAlignment);
+ return QuickMethodFrameInfo(frame_size, callee_info.CoreSpillMask(), callee_info.FpSpillMask());
+}
+
void StackVisitor::WalkStack(bool include_transitions) {
DCHECK(thread_ == Thread::Current() || thread_->IsSuspended());
CHECK_EQ(cur_depth_, 0U);
@@ -890,19 +1007,23 @@
cur_shadow_frame_ = current_fragment->GetTopShadowFrame();
cur_quick_frame_ = current_fragment->GetTopQuickFrame();
cur_quick_frame_pc_ = 0;
+ cur_oat_quick_method_header_ = nullptr;
if (cur_quick_frame_ != nullptr) { // Handle quick stack frames.
// Can't be both a shadow and a quick fragment.
DCHECK(current_fragment->GetTopShadowFrame() == nullptr);
ArtMethod* method = *cur_quick_frame_;
while (method != nullptr) {
+ cur_oat_quick_method_header_ = method->GetOatQuickMethodHeader(cur_quick_frame_pc_);
SanityCheckFrame();
if ((walk_kind_ == StackWalkKind::kIncludeInlinedFrames)
- && GetCurrentCode().IsOptimized(sizeof(void*))) {
- CodeInfo code_info = GetCurrentCode().GetOptimizedCodeInfo();
+ && (cur_oat_quick_method_header_ != nullptr)
+ && cur_oat_quick_method_header_->IsOptimized()) {
+ CodeInfo code_info = cur_oat_quick_method_header_->GetOptimizedCodeInfo();
StackMapEncoding encoding = code_info.ExtractEncoding();
- uint32_t native_pc_offset = GetCurrentCode().NativeQuickPcOffset(cur_quick_frame_pc_);
+ uint32_t native_pc_offset =
+ cur_oat_quick_method_header_->NativeQuickPcOffset(cur_quick_frame_pc_);
StackMap stack_map = code_info.GetStackMapForNativePcOffset(native_pc_offset, encoding);
if (stack_map.IsValid() && stack_map.HasInlineInfo(encoding)) {
InlineInfo inline_info = code_info.GetInlineInfoOf(stack_map, encoding);
@@ -925,14 +1046,16 @@
return;
}
+ QuickMethodFrameInfo frame_info = GetCurrentQuickFrameInfo();
if (context_ != nullptr) {
- context_->FillCalleeSaves(*this);
+ context_->FillCalleeSaves(reinterpret_cast<uint8_t*>(cur_quick_frame_), frame_info);
}
- size_t frame_size = GetCurrentCode().GetFrameSizeInBytes();
// Compute PC for next stack frame from return PC.
- size_t return_pc_offset = GetCurrentCode().GetReturnPcOffset().SizeValue();
+ size_t frame_size = frame_info.FrameSizeInBytes();
+ size_t return_pc_offset = frame_size - sizeof(void*);
uint8_t* return_pc_addr = reinterpret_cast<uint8_t*>(cur_quick_frame_) + return_pc_offset;
uintptr_t return_pc = *reinterpret_cast<uintptr_t*>(return_pc_addr);
+
if (UNLIKELY(exit_stubs_installed)) {
// While profiling, the return pc is restored from the side stack, except when walking
// the stack for an exception where the side stack will be unwound in VisitFrame.
@@ -963,7 +1086,6 @@
return_pc = instrumentation_frame.return_pc_;
}
}
- ArtCode code = GetCurrentCode();
cur_quick_frame_pc_ = return_pc;
uint8_t* next_frame = reinterpret_cast<uint8_t*>(cur_quick_frame_) + frame_size;
@@ -971,8 +1093,11 @@
if (kDebugStackWalk) {
LOG(INFO) << PrettyMethod(method) << "@" << method << " size=" << frame_size
- << " optimized=" << code.IsOptimized(sizeof(void*))
+ << std::boolalpha
+ << " optimized=" << (cur_oat_quick_method_header_ != nullptr &&
+ cur_oat_quick_method_header_->IsOptimized())
<< " native=" << method->IsNative()
+ << std::noboolalpha
<< " entrypoints=" << method->GetEntryPointFromQuickCompiledCode()
<< "," << method->GetEntryPointFromJni()
<< " next=" << *cur_quick_frame_;
diff --git a/runtime/stack.h b/runtime/stack.h
index 3e0566d..1f477b6 100644
--- a/runtime/stack.h
+++ b/runtime/stack.h
@@ -20,13 +20,13 @@
#include <stdint.h>
#include <string>
-#include "art_code.h"
#include "arch/instruction_set.h"
#include "base/macros.h"
#include "base/mutex.h"
#include "dex_file.h"
#include "gc_root.h"
#include "mirror/object_reference.h"
+#include "quick/quick_method_frame_info.h"
#include "read_barrier.h"
#include "verify_object.h"
@@ -40,6 +40,7 @@
class Context;
class HandleScope;
class InlineInfo;
+class OatQuickMethodHeader;
class ScopedObjectAccess;
class ShadowFrame;
class StackVisitor;
@@ -561,18 +562,6 @@
size_t GetNativePcOffset() const SHARED_REQUIRES(Locks::mutator_lock_);
- uintptr_t* CalleeSaveAddress(int num, size_t frame_size) const
- SHARED_REQUIRES(Locks::mutator_lock_) {
- // Callee saves are held at the top of the frame
- DCHECK(GetMethod() != nullptr);
- uint8_t* save_addr =
- reinterpret_cast<uint8_t*>(cur_quick_frame_) + frame_size - ((num + 1) * sizeof(void*));
-#if defined(__i386__) || defined(__x86_64__)
- save_addr -= sizeof(void*); // account for return address
-#endif
- return reinterpret_cast<uintptr_t*>(save_addr);
- }
-
// Returns the height of the stack in the managed stack frames, including transitions.
size_t GetFrameHeight() SHARED_REQUIRES(Locks::mutator_lock_) {
return GetNumFrames() - cur_depth_ - 1;
@@ -735,7 +724,11 @@
static void DescribeStack(Thread* thread) SHARED_REQUIRES(Locks::mutator_lock_);
- ArtCode GetCurrentCode() const { return ArtCode(cur_quick_frame_); }
+ const OatQuickMethodHeader* GetCurrentOatQuickMethodHeader() const {
+ return cur_oat_quick_method_header_;
+ }
+
+ QuickMethodFrameInfo GetCurrentQuickFrameInfo() const SHARED_REQUIRES(Locks::mutator_lock_);
private:
// Private constructor known in the case that num_frames_ has already been computed.
@@ -813,6 +806,7 @@
ShadowFrame* cur_shadow_frame_;
ArtMethod** cur_quick_frame_;
uintptr_t cur_quick_frame_pc_;
+ const OatQuickMethodHeader* cur_oat_quick_method_header_;
// Lazily computed, number of frames in the stack.
size_t num_frames_;
// Depth of the frame we're currently at.
diff --git a/runtime/thread.cc b/runtime/thread.cc
index 8e0c288..114e0f6 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -32,7 +32,6 @@
#include <sstream>
#include "arch/context.h"
-#include "art_code.h"
#include "art_field-inl.h"
#include "art_method-inl.h"
#include "base/bit_utils.h"
@@ -58,6 +57,7 @@
#include "mirror/object_array-inl.h"
#include "mirror/stack_trace_element.h"
#include "monitor.h"
+#include "oat_quick_method_header.h"
#include "object_lock.h"
#include "quick_exception_handler.h"
#include "quick/quick_method_frame_info.h"
@@ -1496,8 +1496,7 @@
if (dump_for_abort || ShouldShowNativeStack(this)) {
DumpKernelStack(os, GetTid(), " kernel: ", false);
ArtMethod* method = GetCurrentMethod(nullptr, !dump_for_abort);
- ArtCode art_code(method);
- DumpNativeStack(os, GetTid(), " native: ", method, &art_code);
+ DumpNativeStack(os, GetTid(), " native: ", method);
}
DumpJavaStack(os);
} else {
@@ -2640,38 +2639,15 @@
VisitDeclaringClass(m);
DCHECK(m != nullptr);
size_t num_regs = shadow_frame->NumberOfVRegs();
- if (m->IsNative() || shadow_frame->HasReferenceArray()) {
- // handle scope for JNI or References for interpreter.
- for (size_t reg = 0; reg < num_regs; ++reg) {
- mirror::Object* ref = shadow_frame->GetVRegReference(reg);
- if (ref != nullptr) {
- mirror::Object* new_ref = ref;
- visitor_(&new_ref, reg, this);
- if (new_ref != ref) {
- shadow_frame->SetVRegReference(reg, new_ref);
- }
- }
- }
- } else {
- // Java method.
- // Portable path use DexGcMap and store in Method.native_gc_map_.
- const uint8_t* gc_map = GetCurrentCode().GetNativeGcMap(sizeof(void*));
- CHECK(gc_map != nullptr) << PrettyMethod(m);
- verifier::DexPcToReferenceMap dex_gc_map(gc_map);
- uint32_t dex_pc = shadow_frame->GetDexPC();
- const uint8_t* reg_bitmap = dex_gc_map.FindBitMap(dex_pc);
- DCHECK(reg_bitmap != nullptr);
- num_regs = std::min(dex_gc_map.RegWidth() * 8, num_regs);
- for (size_t reg = 0; reg < num_regs; ++reg) {
- if (TestBitmap(reg, reg_bitmap)) {
- mirror::Object* ref = shadow_frame->GetVRegReference(reg);
- if (ref != nullptr) {
- mirror::Object* new_ref = ref;
- visitor_(&new_ref, reg, this);
- if (new_ref != ref) {
- shadow_frame->SetVRegReference(reg, new_ref);
- }
- }
+ DCHECK(m->IsNative() || shadow_frame->HasReferenceArray());
+ // handle scope for JNI or References for interpreter.
+ for (size_t reg = 0; reg < num_regs; ++reg) {
+ mirror::Object* ref = shadow_frame->GetVRegReference(reg);
+ if (ref != nullptr) {
+ mirror::Object* new_ref = ref;
+ visitor_(&new_ref, reg, this);
+ if (new_ref != ref) {
+ shadow_frame->SetVRegReference(reg, new_ref);
}
}
}
@@ -2702,11 +2678,12 @@
// Process register map (which native and runtime methods don't have)
if (!m->IsNative() && !m->IsRuntimeMethod() && !m->IsProxyMethod()) {
- if (GetCurrentCode().IsOptimized(sizeof(void*))) {
+ const OatQuickMethodHeader* method_header = GetCurrentOatQuickMethodHeader();
+ if (method_header->IsOptimized()) {
auto* vreg_base = reinterpret_cast<StackReference<mirror::Object>*>(
reinterpret_cast<uintptr_t>(cur_quick_frame));
- uintptr_t native_pc_offset = GetCurrentCode().NativeQuickPcOffset(GetCurrentQuickFramePc());
- CodeInfo code_info = GetCurrentCode().GetOptimizedCodeInfo();
+ uintptr_t native_pc_offset = method_header->NativeQuickPcOffset(GetCurrentQuickFramePc());
+ CodeInfo code_info = method_header->GetOptimizedCodeInfo();
StackMapEncoding encoding = code_info.ExtractEncoding();
StackMap map = code_info.GetStackMapForNativePcOffset(native_pc_offset, encoding);
DCHECK(map.IsValid());
@@ -2736,7 +2713,7 @@
}
}
} else {
- const uint8_t* native_gc_map = GetCurrentCode().GetNativeGcMap(sizeof(void*));
+ const uint8_t* native_gc_map = method_header->GetNativeGcMap();
CHECK(native_gc_map != nullptr) << PrettyMethod(m);
const DexFile::CodeItem* code_item = m->GetCodeItem();
// Can't be null or how would we compile its instructions?
@@ -2744,12 +2721,11 @@
NativePcOffsetToReferenceMap map(native_gc_map);
size_t num_regs = map.RegWidth() * 8;
if (num_regs > 0) {
- uintptr_t native_pc_offset =
- GetCurrentCode().NativeQuickPcOffset(GetCurrentQuickFramePc());
+ uintptr_t native_pc_offset = method_header->NativeQuickPcOffset(GetCurrentQuickFramePc());
const uint8_t* reg_bitmap = map.FindBitMap(native_pc_offset);
DCHECK(reg_bitmap != nullptr);
- const VmapTable vmap_table(GetCurrentCode().GetVmapTable(sizeof(void*)));
- QuickMethodFrameInfo frame_info = GetCurrentCode().GetQuickFrameInfo();
+ const VmapTable vmap_table(method_header->GetVmapTable());
+ QuickMethodFrameInfo frame_info = method_header->GetFrameInfo();
// For all dex registers in the bitmap
DCHECK(cur_quick_frame != nullptr);
for (size_t reg = 0; reg < num_regs; ++reg) {
diff --git a/runtime/utils.cc b/runtime/utils.cc
index 40cd6d3..62af380 100644
--- a/runtime/utils.cc
+++ b/runtime/utils.cc
@@ -25,7 +25,6 @@
#include <unistd.h>
#include <memory>
-#include "art_code.h"
#include "art_field-inl.h"
#include "art_method-inl.h"
#include "base/stl_util.h"
@@ -37,6 +36,7 @@
#include "mirror/object-inl.h"
#include "mirror/object_array-inl.h"
#include "mirror/string.h"
+#include "oat_quick_method_header.h"
#include "os.h"
#include "scoped_thread_state_change.h"
#include "utf-inl.h"
@@ -1090,10 +1090,20 @@
map_src.c_str(), offset));
RunCommand(cmdline.c_str(), &os, prefix);
}
+
+static bool PcIsWithinQuickCode(ArtMethod* method, uintptr_t pc) NO_THREAD_SAFETY_ANALYSIS {
+ uintptr_t code = reinterpret_cast<uintptr_t>(EntryPointToCodePointer(
+ method->GetEntryPointFromQuickCompiledCode()));
+ if (code == 0) {
+ return pc == 0;
+ }
+ uintptr_t code_size = reinterpret_cast<const OatQuickMethodHeader*>(code)[-1].code_size_;
+ return code <= pc && pc <= (code + code_size);
+}
#endif
void DumpNativeStack(std::ostream& os, pid_t tid, const char* prefix,
- ArtMethod* current_method, ArtCode* current_code, void* ucontext_ptr) {
+ ArtMethod* current_method, void* ucontext_ptr) {
#if __linux__
// b/18119146
if (RUNNING_ON_MEMORY_TOOL != 0) {
@@ -1147,10 +1157,10 @@
os << "+" << it->func_offset;
}
try_addr2line = true;
- } else if (
- current_method != nullptr && Locks::mutator_lock_->IsSharedHeld(Thread::Current()) &&
- current_code->PcIsWithinQuickCode(it->pc)) {
- const void* start_of_code = current_code->GetQuickOatEntryPoint(sizeof(void*));
+ } else if (current_method != nullptr &&
+ Locks::mutator_lock_->IsSharedHeld(Thread::Current()) &&
+ PcIsWithinQuickCode(current_method, it->pc)) {
+ const void* start_of_code = current_method->GetEntryPointFromQuickCompiledCode();
os << JniLongName(current_method) << "+"
<< (it->pc - reinterpret_cast<uintptr_t>(start_of_code));
} else {
@@ -1164,7 +1174,7 @@
}
}
#else
- UNUSED(os, tid, prefix, current_method, current_code, ucontext_ptr);
+ UNUSED(os, tid, prefix, current_method, ucontext_ptr);
#endif
}
diff --git a/runtime/utils.h b/runtime/utils.h
index 457d43f..79502c7 100644
--- a/runtime/utils.h
+++ b/runtime/utils.h
@@ -222,7 +222,7 @@
// Dumps the native stack for thread 'tid' to 'os'.
void DumpNativeStack(std::ostream& os, pid_t tid, const char* prefix = "",
- ArtMethod* current_method = nullptr, ArtCode* current_code = nullptr, void* ucontext = nullptr)
+ ArtMethod* current_method = nullptr, void* ucontext = nullptr)
NO_THREAD_SAFETY_ANALYSIS;
// Dumps the kernel stack for thread 'tid' to 'os'. Note that this is only available on linux-x86.
diff --git a/test/004-ReferenceMap/stack_walk_refmap_jni.cc b/test/004-ReferenceMap/stack_walk_refmap_jni.cc
index f8d321c..34fb3f8 100644
--- a/test/004-ReferenceMap/stack_walk_refmap_jni.cc
+++ b/test/004-ReferenceMap/stack_walk_refmap_jni.cc
@@ -19,15 +19,17 @@
namespace art {
-#define CHECK_REGS_CONTAIN_REFS(dex_pc, abort_if_not_found, ...) do { \
- int t[] = {__VA_ARGS__}; \
- int t_size = sizeof(t) / sizeof(*t); \
- uintptr_t native_quick_pc = GetCurrentCode().ToNativeQuickPc(dex_pc, \
- /* is_catch_handler */ false, \
- abort_if_not_found); \
- if (native_quick_pc != UINTPTR_MAX) { \
- CheckReferences(t, t_size, GetCurrentCode().NativeQuickPcOffset(native_quick_pc)); \
- } \
+#define CHECK_REGS_CONTAIN_REFS(dex_pc, abort_if_not_found, ...) do { \
+ int t[] = {__VA_ARGS__}; \
+ int t_size = sizeof(t) / sizeof(*t); \
+ const OatQuickMethodHeader* method_header = GetCurrentOatQuickMethodHeader(); \
+ uintptr_t native_quick_pc = method_header->ToNativeQuickPc(GetMethod(), \
+ dex_pc, \
+ /* is_catch_handler */ false, \
+ abort_if_not_found); \
+ if (native_quick_pc != UINTPTR_MAX) { \
+ CheckReferences(t, t_size, method_header->NativeQuickPcOffset(native_quick_pc)); \
+ } \
} while (false);
struct ReferenceMap2Visitor : public CheckReferenceMapVisitor {
@@ -49,7 +51,7 @@
CHECK_REGS_CONTAIN_REFS(0x06U, true, 8, 1); // v8: this, v1: x
CHECK_REGS_CONTAIN_REFS(0x08U, true, 8, 3, 1); // v8: this, v3: y, v1: x
CHECK_REGS_CONTAIN_REFS(0x0cU, true, 8, 3, 1); // v8: this, v3: y, v1: x
- if (!GetCurrentCode().IsOptimized(sizeof(void*))) {
+ if (!GetCurrentOatQuickMethodHeader()->IsOptimized()) {
CHECK_REGS_CONTAIN_REFS(0x0eU, true, 8, 3, 1); // v8: this, v3: y, v1: x
}
CHECK_REGS_CONTAIN_REFS(0x10U, true, 8, 3, 1); // v8: this, v3: y, v1: x
@@ -65,7 +67,7 @@
// Note that v0: ex can be eliminated because it's a dead merge of two different exceptions.
CHECK_REGS_CONTAIN_REFS(0x18U, true, 8, 2, 1); // v8: this, v2: y, v1: x (dead v0: ex)
CHECK_REGS_CONTAIN_REFS(0x1aU, true, 8, 5, 2, 1); // v8: this, v5: x[1], v2: y, v1: x (dead v0: ex)
- if (!GetCurrentCode().IsOptimized(sizeof(void*))) {
+ if (!GetCurrentOatQuickMethodHeader()->IsOptimized()) {
// v8: this, v5: x[1], v2: y, v1: x (dead v0: ex)
CHECK_REGS_CONTAIN_REFS(0x1dU, true, 8, 5, 2, 1);
// v5 is removed from the root set because there is a "merge" operation.
@@ -74,7 +76,7 @@
}
CHECK_REGS_CONTAIN_REFS(0x21U, true, 8, 2, 1); // v8: this, v2: y, v1: x (dead v0: ex)
- if (!GetCurrentCode().IsOptimized(sizeof(void*))) {
+ if (!GetCurrentOatQuickMethodHeader()->IsOptimized()) {
CHECK_REGS_CONTAIN_REFS(0x27U, true, 8, 4, 2, 1); // v8: this, v4: ex, v2: y, v1: x
}
CHECK_REGS_CONTAIN_REFS(0x29U, true, 8, 4, 2, 1); // v8: this, v4: ex, v2: y, v1: x
diff --git a/test/087-gc-after-link/src/Main.java b/test/087-gc-after-link/src/Main.java
index 2f6d496..7c47e99 100644
--- a/test/087-gc-after-link/src/Main.java
+++ b/test/087-gc-after-link/src/Main.java
@@ -91,6 +91,7 @@
* is an error we can't recover from.
*/
meth.invoke(dexFile, name, this);
+ System.out.println("Unreachable");
} finally {
if (dexFile != null) {
/* close the DexFile to make CloseGuard happy */
diff --git a/test/450-checker-types/src/Main.java b/test/450-checker-types/src/Main.java
index 134abd1..f1885de 100644
--- a/test/450-checker-types/src/Main.java
+++ b/test/450-checker-types/src/Main.java
@@ -537,6 +537,17 @@
return ((SubclassA)a).toString();
}
+
+ /// CHECK-START: void Main.argumentCheck(Super, double, SubclassA, Final) reference_type_propagation (after)
+ /// CHECK: ParameterValue klass:Main can_be_null:false exact:false
+ /// CHECK: ParameterValue klass:Super can_be_null:true exact:false
+ /// CHECK: ParameterValue
+ /// CHECK: ParameterValue klass:SubclassA can_be_null:true exact:false
+ /// CHECK: ParameterValue klass:Final can_be_null:true exact:true
+ /// CHECK-NOT: ParameterValue
+ private void argumentCheck(Super s, double d, SubclassA a, Final f) {
+ }
+
public static void main(String[] args) {
}
}
diff --git a/test/454-get-vreg/get_vreg_jni.cc b/test/454-get-vreg/get_vreg_jni.cc
index 0ee2ff9..30f9954 100644
--- a/test/454-get-vreg/get_vreg_jni.cc
+++ b/test/454-get-vreg/get_vreg_jni.cc
@@ -15,9 +15,9 @@
*/
#include "arch/context.h"
-#include "art_code.h"
#include "art_method-inl.h"
#include "jni.h"
+#include "oat_quick_method_header.h"
#include "scoped_thread_state_change.h"
#include "stack.h"
#include "thread.h"
@@ -46,12 +46,12 @@
CHECK_EQ(value, 42u);
bool success = GetVReg(m, 1, kIntVReg, &value);
- if (!IsCurrentFrameInInterpreter() && GetCurrentCode().IsOptimized(sizeof(void*))) {
+ if (!IsCurrentFrameInInterpreter() && GetCurrentOatQuickMethodHeader()->IsOptimized()) {
CHECK(!success);
}
success = GetVReg(m, 2, kIntVReg, &value);
- if (!IsCurrentFrameInInterpreter() && GetCurrentCode().IsOptimized(sizeof(void*))) {
+ if (!IsCurrentFrameInInterpreter() && GetCurrentOatQuickMethodHeader()->IsOptimized()) {
CHECK(!success);
}
@@ -83,12 +83,12 @@
CHECK_EQ(value, 42u);
bool success = GetVRegPair(m, 2, kLongLoVReg, kLongHiVReg, &value);
- if (!IsCurrentFrameInInterpreter() && GetCurrentCode().IsOptimized(sizeof(void*))) {
+ if (!IsCurrentFrameInInterpreter() && GetCurrentOatQuickMethodHeader()->IsOptimized()) {
CHECK(!success);
}
success = GetVRegPair(m, 4, kLongLoVReg, kLongHiVReg, &value);
- if (!IsCurrentFrameInInterpreter() && GetCurrentCode().IsOptimized(sizeof(void*))) {
+ if (!IsCurrentFrameInInterpreter() && GetCurrentOatQuickMethodHeader()->IsOptimized()) {
CHECK(!success);
}
diff --git a/test/457-regs/regs_jni.cc b/test/457-regs/regs_jni.cc
index 6fcebdb..64b2336 100644
--- a/test/457-regs/regs_jni.cc
+++ b/test/457-regs/regs_jni.cc
@@ -15,9 +15,9 @@
*/
#include "arch/context.h"
-#include "art_code.h"
#include "art_method-inl.h"
#include "jni.h"
+#include "oat_quick_method_header.h"
#include "scoped_thread_state_change.h"
#include "stack.h"
#include "thread.h"
@@ -64,7 +64,7 @@
CHECK_EQ(value, 1u);
bool success = GetVReg(m, 2, kIntVReg, &value);
- if (!IsCurrentFrameInInterpreter() && GetCurrentCode().IsOptimized(sizeof(void*))) {
+ if (!IsCurrentFrameInInterpreter() && GetCurrentOatQuickMethodHeader()->IsOptimized()) {
CHECK(!success);
}
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 2a56a7f..375a3fc 100644
--- a/test/466-get-live-vreg/get_live_vreg_jni.cc
+++ b/test/466-get-live-vreg/get_live_vreg_jni.cc
@@ -15,9 +15,9 @@
*/
#include "arch/context.h"
-#include "art_code.h"
#include "art_method-inl.h"
#include "jni.h"
+#include "oat_quick_method_header.h"
#include "scoped_thread_state_change.h"
#include "stack.h"
#include "thread.h"
@@ -44,7 +44,7 @@
found_method_ = true;
uint32_t value = 0;
if (GetCurrentQuickFrame() != nullptr &&
- GetCurrentCode().IsOptimized(sizeof(void*)) &&
+ GetCurrentOatQuickMethodHeader()->IsOptimized() &&
!Runtime::Current()->IsDebuggable()) {
CHECK_EQ(GetVReg(m, 0, kIntVReg, &value), false);
} else {
diff --git a/test/Android.run-test.mk b/test/Android.run-test.mk
index e114a2e..b83d4a4 100644
--- a/test/Android.run-test.mk
+++ b/test/Android.run-test.mk
@@ -302,10 +302,14 @@
TEST_ART_BROKEN_INTERPRETER_ACCESS_CHECK_TESTS :=
# Tests that are broken with GC stress.
-# 137-cfi needs to unwind a second forked process. We're using a primitive sleep to wait till we
-# hope the second process got into the expected state. The slowness of gcstress makes this bad.
+# * 137-cfi needs to unwind a second forked process. We're using a primitive sleep to wait till we
+# hope the second process got into the expected state. The slowness of gcstress makes this bad.
+# * 961-default-iface-resolution-generated is a very long test that often will take more than the
+# timeout to run when gcstress is enabled. This is because gcstress slows down allocations
+# significantly which this test does a lot.
TEST_ART_BROKEN_GCSTRESS_RUN_TESTS := \
- 137-cfi
+ 137-cfi \
+ 961-default-iface-resolution-generated
ifneq (,$(filter gcstress,$(GC_TYPES)))
ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,$(TARGET_TYPES),$(RUN_TYPES),$(PREBUILD_TYPES), \
diff --git a/tools/ahat/Android.mk b/tools/ahat/Android.mk
index 71366c1..6869b04 100644
--- a/tools/ahat/Android.mk
+++ b/tools/ahat/Android.mk
@@ -74,7 +74,7 @@
AHAT_TEST_DUMP_DEPENDENCIES := \
$(ART_HOST_EXECUTABLES) \
$(HOST_OUT_EXECUTABLES)/art \
- $(HOST_CORE_IMG_OUT_BASE)$(CORE_IMG_SUFFIX)
+ $(HOST_CORE_IMG_OUT_BASE)-optimizing-pic$(CORE_IMG_SUFFIX)
$(AHAT_TEST_DUMP_HPROF): PRIVATE_AHAT_TEST_ART := $(HOST_OUT_EXECUTABLES)/art
$(AHAT_TEST_DUMP_HPROF): PRIVATE_AHAT_TEST_DUMP_JAR := $(AHAT_TEST_DUMP_JAR)