Merge "ART: Factor out native stack dumping"
diff --git a/compiler/Android.mk b/compiler/Android.mk
index 8261a87..3b7b1e6 100644
--- a/compiler/Android.mk
+++ b/compiler/Android.mk
@@ -67,8 +67,9 @@
optimizing/parallel_move_resolver.cc \
optimizing/prepare_for_register_allocation.cc \
optimizing/reference_type_propagation.cc \
- optimizing/register_allocator.cc \
optimizing/register_allocation_resolver.cc \
+ optimizing/register_allocator.cc \
+ optimizing/register_allocator_graph_color.cc \
optimizing/register_allocator_linear_scan.cc \
optimizing/select_generator.cc \
optimizing/sharpening.cc \
@@ -80,6 +81,7 @@
optimizing/x86_memory_gen.cc \
trampolines/trampoline_compiler.cc \
utils/assembler.cc \
+ utils/jni_macro_assembler.cc \
utils/swap_space.cc \
compiler.cc \
elf_writer.cc \
diff --git a/compiler/driver/compiler_options.cc b/compiler/driver/compiler_options.cc
index f20dba3..a522e0c 100644
--- a/compiler/driver/compiler_options.cc
+++ b/compiler/driver/compiler_options.cc
@@ -44,7 +44,8 @@
init_failure_output_(nullptr),
dump_cfg_file_name_(""),
dump_cfg_append_(false),
- force_determinism_(false) {
+ force_determinism_(false),
+ register_allocation_strategy_(RegisterAllocator::kRegisterAllocatorDefault) {
}
CompilerOptions::~CompilerOptions() {
@@ -74,7 +75,8 @@
bool abort_on_hard_verifier_failure,
const std::string& dump_cfg_file_name,
bool dump_cfg_append,
- bool force_determinism
+ bool force_determinism,
+ RegisterAllocator::Strategy regalloc_strategy
) : // NOLINT(whitespace/parens)
compiler_filter_(compiler_filter),
huge_method_threshold_(huge_method_threshold),
@@ -99,7 +101,8 @@
init_failure_output_(init_failure_output),
dump_cfg_file_name_(dump_cfg_file_name),
dump_cfg_append_(dump_cfg_append),
- force_determinism_(force_determinism) {
+ force_determinism_(force_determinism),
+ register_allocation_strategy_(regalloc_strategy) {
}
void CompilerOptions::ParseHugeMethodMax(const StringPiece& option, UsageFn Usage) {
@@ -144,6 +147,19 @@
}
}
+void CompilerOptions::ParseRegisterAllocationStrategy(const StringPiece& option,
+ UsageFn Usage) {
+ DCHECK(option.starts_with("--register-allocation-strategy="));
+ StringPiece choice = option.substr(strlen("--register-allocation-strategy=")).data();
+ if (choice == "linear-scan") {
+ register_allocation_strategy_ = RegisterAllocator::Strategy::kRegisterAllocatorLinearScan;
+ } else if (choice == "graph-color") {
+ register_allocation_strategy_ = RegisterAllocator::Strategy::kRegisterAllocatorGraphColor;
+ } else {
+ Usage("Unrecognized register allocation strategy. Try linear-scan, or graph-color.");
+ }
+}
+
bool CompilerOptions::ParseCompilerOption(const StringPiece& option, UsageFn Usage) {
if (option.starts_with("--compiler-filter=")) {
const char* compiler_filter_string = option.substr(strlen("--compiler-filter=")).data();
@@ -190,6 +206,8 @@
dump_cfg_file_name_ = option.substr(strlen("--dump-cfg=")).data();
} else if (option.starts_with("--dump-cfg-append")) {
dump_cfg_append_ = true;
+ } else if (option.starts_with("--register-allocation-strategy=")) {
+ ParseRegisterAllocationStrategy(option, Usage);
} else {
// Option not recognized.
return false;
diff --git a/compiler/driver/compiler_options.h b/compiler/driver/compiler_options.h
index 60b700a..cc66d7a 100644
--- a/compiler/driver/compiler_options.h
+++ b/compiler/driver/compiler_options.h
@@ -24,6 +24,7 @@
#include "base/macros.h"
#include "compiler_filter.h"
#include "globals.h"
+#include "optimizing/register_allocator.h"
#include "utils.h"
namespace art {
@@ -74,7 +75,8 @@
bool abort_on_hard_verifier_failure,
const std::string& dump_cfg_file_name,
bool dump_cfg_append,
- bool force_determinism);
+ bool force_determinism,
+ RegisterAllocator::Strategy regalloc_strategy);
CompilerFilter::Filter GetCompilerFilter() const {
return compiler_filter_;
@@ -244,6 +246,10 @@
return force_determinism_;
}
+ RegisterAllocator::Strategy GetRegisterAllocationStrategy() const {
+ return register_allocation_strategy_;
+ }
+
private:
void ParseDumpInitFailures(const StringPiece& option, UsageFn Usage);
void ParseDumpCfgPasses(const StringPiece& option, UsageFn Usage);
@@ -254,6 +260,7 @@
void ParseSmallMethodMax(const StringPiece& option, UsageFn Usage);
void ParseLargeMethodMax(const StringPiece& option, UsageFn Usage);
void ParseHugeMethodMax(const StringPiece& option, UsageFn Usage);
+ void ParseRegisterAllocationStrategy(const StringPiece& option, UsageFn Usage);
CompilerFilter::Filter compiler_filter_;
size_t huge_method_threshold_;
@@ -297,6 +304,8 @@
// outcomes.
bool force_determinism_;
+ RegisterAllocator::Strategy register_allocation_strategy_;
+
friend class Dex2Oat;
DISALLOW_COPY_AND_ASSIGN(CompilerOptions);
diff --git a/compiler/jit/jit_compiler.cc b/compiler/jit/jit_compiler.cc
index 1785338..2dd87a8 100644
--- a/compiler/jit/jit_compiler.cc
+++ b/compiler/jit/jit_compiler.cc
@@ -32,6 +32,7 @@
#include "oat_file-inl.h"
#include "oat_quick_method_header.h"
#include "object_lock.h"
+#include "optimizing/register_allocator.h"
#include "thread_list.h"
namespace art {
@@ -110,7 +111,8 @@
/* abort_on_hard_verifier_failure */ false,
/* dump_cfg_file_name */ "",
/* dump_cfg_append */ false,
- /* force_determinism */ false));
+ /* force_determinism */ false,
+ RegisterAllocator::kRegisterAllocatorDefault));
for (const std::string& argument : Runtime::Current()->GetCompilerOptions()) {
compiler_options_->ParseCompilerOption(argument, Usage);
}
diff --git a/compiler/jni/jni_cfi_test.cc b/compiler/jni/jni_cfi_test.cc
index 3526802..524ce4d 100644
--- a/compiler/jni/jni_cfi_test.cc
+++ b/compiler/jni/jni_cfi_test.cc
@@ -19,10 +19,12 @@
#include "arch/instruction_set.h"
#include "base/arena_allocator.h"
+#include "base/enums.h"
#include "cfi_test.h"
#include "gtest/gtest.h"
#include "jni/quick/calling_convention.h"
#include "utils/assembler.h"
+#include "utils/jni_macro_assembler.h"
#include "jni/jni_cfi_test_expected.inc"
@@ -36,9 +38,23 @@
// Enable this flag to generate the expected outputs.
static constexpr bool kGenerateExpected = false;
- void TestImpl(InstructionSet isa, const char* isa_str,
+ void TestImpl(InstructionSet isa,
+ const char* isa_str,
const std::vector<uint8_t>& expected_asm,
const std::vector<uint8_t>& expected_cfi) {
+ if (Is64BitInstructionSet(isa)) {
+ TestImplSized<PointerSize::k64>(isa, isa_str, expected_asm, expected_cfi);
+ } else {
+ TestImplSized<PointerSize::k32>(isa, isa_str, expected_asm, expected_cfi);
+ }
+ }
+
+ private:
+ template <PointerSize kPointerSize>
+ void TestImplSized(InstructionSet isa,
+ const char* isa_str,
+ const std::vector<uint8_t>& expected_asm,
+ const std::vector<uint8_t>& expected_cfi) {
// Description of simple method.
const bool is_static = true;
const bool is_synchronized = false;
@@ -55,7 +71,8 @@
ArrayRef<const ManagedRegister> callee_save_regs = jni_conv->CalleeSaveRegisters();
// Assemble the method.
- std::unique_ptr<Assembler> jni_asm(Assembler::Create(&arena, isa));
+ std::unique_ptr<JNIMacroAssembler<kPointerSize>> jni_asm(
+ JNIMacroAssembler<kPointerSize>::Create(&arena, isa));
jni_asm->cfi().SetEnabled(true);
jni_asm->BuildFrame(frame_size, mr_conv->MethodRegister(),
callee_save_regs, mr_conv->EntrySpills());
diff --git a/compiler/jni/quick/jni_compiler.cc b/compiler/jni/quick/jni_compiler.cc
index 277b794..f99f6a8 100644
--- a/compiler/jni/quick/jni_compiler.cc
+++ b/compiler/jni/quick/jni_compiler.cc
@@ -26,6 +26,7 @@
#include "base/enums.h"
#include "base/logging.h"
#include "base/macros.h"
+#include "memory_region.h"
#include "calling_convention.h"
#include "class_linker.h"
#include "compiled_method.h"
@@ -34,7 +35,9 @@
#include "driver/compiler_options.h"
#include "entrypoints/quick/quick_entrypoints.h"
#include "jni_env_ext.h"
+#include "debug/dwarf/debug_frame_opcode_writer.h"
#include "utils/assembler.h"
+#include "utils/jni_macro_assembler.h"
#include "utils/managed_register.h"
#include "utils/arm/managed_register_arm.h"
#include "utils/arm64/managed_register_arm64.h"
@@ -47,22 +50,32 @@
namespace art {
-static void CopyParameter(Assembler* jni_asm,
+template <PointerSize kPointerSize>
+static void CopyParameter(JNIMacroAssembler<kPointerSize>* jni_asm,
ManagedRuntimeCallingConvention* mr_conv,
JniCallingConvention* jni_conv,
size_t frame_size, size_t out_arg_size);
-static void SetNativeParameter(Assembler* jni_asm,
+template <PointerSize kPointerSize>
+static void SetNativeParameter(JNIMacroAssembler<kPointerSize>* jni_asm,
JniCallingConvention* jni_conv,
ManagedRegister in_reg);
+template <PointerSize kPointerSize>
+static std::unique_ptr<JNIMacroAssembler<kPointerSize>> GetMacroAssembler(
+ ArenaAllocator* arena, InstructionSet isa, const InstructionSetFeatures* features) {
+ return JNIMacroAssembler<kPointerSize>::Create(arena, isa, features);
+}
+
// Generate the JNI bridge for the given method, general contract:
// - Arguments are in the managed runtime format, either on stack or in
// registers, a reference to the method object is supplied as part of this
// convention.
//
-CompiledMethod* ArtJniCompileMethodInternal(CompilerDriver* driver,
- uint32_t access_flags, uint32_t method_idx,
- const DexFile& dex_file) {
+template <PointerSize kPointerSize>
+static CompiledMethod* ArtJniCompileMethodInternal(CompilerDriver* driver,
+ uint32_t access_flags,
+ uint32_t method_idx,
+ const DexFile& dex_file) {
const bool is_native = (access_flags & kAccNative) != 0;
CHECK(is_native);
const bool is_static = (access_flags & kAccStatic) != 0;
@@ -70,7 +83,6 @@
const char* shorty = dex_file.GetMethodShorty(dex_file.GetMethodId(method_idx));
InstructionSet instruction_set = driver->GetInstructionSet();
const InstructionSetFeatures* instruction_set_features = driver->GetInstructionSetFeatures();
- const bool is_64_bit_target = Is64BitInstructionSet(instruction_set);
ArenaPool pool;
ArenaAllocator arena(&pool);
@@ -101,8 +113,8 @@
&arena, is_static, is_synchronized, jni_end_shorty, instruction_set));
// Assembler that holds generated instructions
- std::unique_ptr<Assembler> jni_asm(
- Assembler::Create(&arena, instruction_set, instruction_set_features));
+ std::unique_ptr<JNIMacroAssembler<kPointerSize>> jni_asm =
+ GetMacroAssembler<kPointerSize>(&arena, instruction_set, instruction_set_features);
jni_asm->cfi().SetEnabled(driver->GetCompilerOptions().GenerateAnyDebugInfo());
// Offsets into data structures
@@ -124,21 +136,12 @@
main_jni_conv->ReferenceCount(),
mr_conv->InterproceduralScratchRegister());
- if (is_64_bit_target) {
- __ CopyRawPtrFromThread64(main_jni_conv->HandleScopeLinkOffset(),
- Thread::TopHandleScopeOffset<PointerSize::k64>(),
+ __ CopyRawPtrFromThread(main_jni_conv->HandleScopeLinkOffset(),
+ Thread::TopHandleScopeOffset<kPointerSize>(),
+ mr_conv->InterproceduralScratchRegister());
+ __ StoreStackOffsetToThread(Thread::TopHandleScopeOffset<kPointerSize>(),
+ main_jni_conv->HandleScopeOffset(),
mr_conv->InterproceduralScratchRegister());
- __ StoreStackOffsetToThread64(Thread::TopHandleScopeOffset<PointerSize::k64>(),
- main_jni_conv->HandleScopeOffset(),
- mr_conv->InterproceduralScratchRegister());
- } else {
- __ CopyRawPtrFromThread32(main_jni_conv->HandleScopeLinkOffset(),
- Thread::TopHandleScopeOffset<PointerSize::k32>(),
- mr_conv->InterproceduralScratchRegister());
- __ StoreStackOffsetToThread32(Thread::TopHandleScopeOffset<PointerSize::k32>(),
- main_jni_conv->HandleScopeOffset(),
- mr_conv->InterproceduralScratchRegister());
- }
// 3. Place incoming reference arguments into handle scope
main_jni_conv->Next(); // Skip JNIEnv*
@@ -188,11 +191,7 @@
}
// 4. Write out the end of the quick frames.
- if (is_64_bit_target) {
- __ StoreStackPointerToThread64(Thread::TopOfManagedStackOffset<PointerSize::k64>());
- } else {
- __ StoreStackPointerToThread32(Thread::TopOfManagedStackOffset<PointerSize::k32>());
- }
+ __ StoreStackPointerToThread(Thread::TopOfManagedStackOffset<kPointerSize>());
// 5. Move frame down to allow space for out going args.
const size_t main_out_arg_size = main_jni_conv->OutArgSize();
@@ -202,10 +201,8 @@
// Call the read barrier for the declaring class loaded from the method for a static call.
// Note that we always have outgoing param space available for at least two params.
if (kUseReadBarrier && is_static) {
- ThreadOffset32 read_barrier32 =
- QUICK_ENTRYPOINT_OFFSET(PointerSize::k32, pReadBarrierJni);
- ThreadOffset64 read_barrier64 =
- QUICK_ENTRYPOINT_OFFSET(PointerSize::k64, pReadBarrierJni);
+ ThreadOffset<kPointerSize> read_barrier = QUICK_ENTRYPOINT_OFFSET(kPointerSize,
+ pReadBarrierJni);
main_jni_conv->ResetIterator(FrameOffset(main_out_arg_size));
main_jni_conv->Next(); // Skip JNIEnv.
FrameOffset class_handle_scope_offset = main_jni_conv->CurrentParamHandleScopeEntryOffset();
@@ -225,21 +222,13 @@
// Pass the current thread as the second argument and call.
if (main_jni_conv->IsCurrentParamInRegister()) {
__ GetCurrentThread(main_jni_conv->CurrentParamRegister());
- if (is_64_bit_target) {
- __ Call(main_jni_conv->CurrentParamRegister(), Offset(read_barrier64),
- main_jni_conv->InterproceduralScratchRegister());
- } else {
- __ Call(main_jni_conv->CurrentParamRegister(), Offset(read_barrier32),
- main_jni_conv->InterproceduralScratchRegister());
- }
+ __ Call(main_jni_conv->CurrentParamRegister(),
+ Offset(read_barrier),
+ main_jni_conv->InterproceduralScratchRegister());
} else {
__ GetCurrentThread(main_jni_conv->CurrentParamStackOffset(),
main_jni_conv->InterproceduralScratchRegister());
- if (is_64_bit_target) {
- __ CallFromThread64(read_barrier64, main_jni_conv->InterproceduralScratchRegister());
- } else {
- __ CallFromThread32(read_barrier32, main_jni_conv->InterproceduralScratchRegister());
- }
+ __ CallFromThread(read_barrier, main_jni_conv->InterproceduralScratchRegister());
}
main_jni_conv->ResetIterator(FrameOffset(main_out_arg_size)); // Reset.
}
@@ -248,14 +237,10 @@
// can occur. The result is the saved JNI local state that is restored by the exit call. We
// abuse the JNI calling convention here, that is guaranteed to support passing 2 pointer
// arguments.
- ThreadOffset32 jni_start32 =
+ ThreadOffset<kPointerSize> jni_start =
is_synchronized
- ? QUICK_ENTRYPOINT_OFFSET(PointerSize::k32, pJniMethodStartSynchronized)
- : QUICK_ENTRYPOINT_OFFSET(PointerSize::k32, pJniMethodStart);
- ThreadOffset64 jni_start64 =
- is_synchronized
- ? QUICK_ENTRYPOINT_OFFSET(PointerSize::k64, pJniMethodStartSynchronized)
- : QUICK_ENTRYPOINT_OFFSET(PointerSize::k64, pJniMethodStart);
+ ? QUICK_ENTRYPOINT_OFFSET(kPointerSize, pJniMethodStartSynchronized)
+ : QUICK_ENTRYPOINT_OFFSET(kPointerSize, pJniMethodStart);
main_jni_conv->ResetIterator(FrameOffset(main_out_arg_size));
FrameOffset locked_object_handle_scope_offset(0);
if (is_synchronized) {
@@ -276,21 +261,13 @@
}
if (main_jni_conv->IsCurrentParamInRegister()) {
__ GetCurrentThread(main_jni_conv->CurrentParamRegister());
- if (is_64_bit_target) {
- __ Call(main_jni_conv->CurrentParamRegister(), Offset(jni_start64),
- main_jni_conv->InterproceduralScratchRegister());
- } else {
- __ Call(main_jni_conv->CurrentParamRegister(), Offset(jni_start32),
- main_jni_conv->InterproceduralScratchRegister());
- }
+ __ Call(main_jni_conv->CurrentParamRegister(),
+ Offset(jni_start),
+ main_jni_conv->InterproceduralScratchRegister());
} else {
__ GetCurrentThread(main_jni_conv->CurrentParamStackOffset(),
main_jni_conv->InterproceduralScratchRegister());
- if (is_64_bit_target) {
- __ CallFromThread64(jni_start64, main_jni_conv->InterproceduralScratchRegister());
- } else {
- __ CallFromThread32(jni_start32, main_jni_conv->InterproceduralScratchRegister());
- }
+ __ CallFromThread(jni_start, main_jni_conv->InterproceduralScratchRegister());
}
if (is_synchronized) { // Check for exceptions from monitor enter.
__ ExceptionPoll(main_jni_conv->InterproceduralScratchRegister(), main_out_arg_size);
@@ -352,20 +329,12 @@
if (main_jni_conv->IsCurrentParamInRegister()) {
ManagedRegister jni_env = main_jni_conv->CurrentParamRegister();
DCHECK(!jni_env.Equals(main_jni_conv->InterproceduralScratchRegister()));
- if (is_64_bit_target) {
- __ LoadRawPtrFromThread64(jni_env, Thread::JniEnvOffset<PointerSize::k64>());
- } else {
- __ LoadRawPtrFromThread32(jni_env, Thread::JniEnvOffset<PointerSize::k32>());
- }
+ __ LoadRawPtrFromThread(jni_env, Thread::JniEnvOffset<kPointerSize>());
} else {
FrameOffset jni_env = main_jni_conv->CurrentParamStackOffset();
- if (is_64_bit_target) {
- __ CopyRawPtrFromThread64(jni_env, Thread::JniEnvOffset<PointerSize::k64>(),
- main_jni_conv->InterproceduralScratchRegister());
- } else {
- __ CopyRawPtrFromThread32(jni_env, Thread::JniEnvOffset<PointerSize::k32>(),
- main_jni_conv->InterproceduralScratchRegister());
- }
+ __ CopyRawPtrFromThread(jni_env,
+ Thread::JniEnvOffset<kPointerSize>(),
+ main_jni_conv->InterproceduralScratchRegister());
}
// 9. Plant call to native code associated with method.
@@ -398,7 +367,9 @@
+ static_cast<size_t>(kMipsPointerSize));
}
CHECK_LT(return_save_location.Uint32Value(), frame_size + main_out_arg_size);
- __ Store(return_save_location, main_jni_conv->ReturnRegister(), main_jni_conv->SizeOfReturnValue());
+ __ Store(return_save_location,
+ main_jni_conv->ReturnRegister(),
+ main_jni_conv->SizeOfReturnValue());
}
// Increase frame size for out args if needed by the end_jni_conv.
@@ -414,27 +385,18 @@
}
// thread.
end_jni_conv->ResetIterator(FrameOffset(end_out_arg_size));
- ThreadOffset32 jni_end32(-1);
- ThreadOffset64 jni_end64(-1);
+ ThreadOffset<kPointerSize> jni_end(-1);
if (reference_return) {
// Pass result.
- jni_end32 = is_synchronized
- ? QUICK_ENTRYPOINT_OFFSET(PointerSize::k32,
- pJniMethodEndWithReferenceSynchronized)
- : QUICK_ENTRYPOINT_OFFSET(PointerSize::k32, pJniMethodEndWithReference);
- jni_end64 = is_synchronized
- ? QUICK_ENTRYPOINT_OFFSET(PointerSize::k64,
- pJniMethodEndWithReferenceSynchronized)
- : QUICK_ENTRYPOINT_OFFSET(PointerSize::k64, pJniMethodEndWithReference);
+ jni_end = is_synchronized
+ ? QUICK_ENTRYPOINT_OFFSET(kPointerSize, pJniMethodEndWithReferenceSynchronized)
+ : QUICK_ENTRYPOINT_OFFSET(kPointerSize, pJniMethodEndWithReference);
SetNativeParameter(jni_asm.get(), end_jni_conv.get(), end_jni_conv->ReturnRegister());
end_jni_conv->Next();
} else {
- jni_end32 = is_synchronized
- ? QUICK_ENTRYPOINT_OFFSET(PointerSize::k32, pJniMethodEndSynchronized)
- : QUICK_ENTRYPOINT_OFFSET(PointerSize::k32, pJniMethodEnd);
- jni_end64 = is_synchronized
- ? QUICK_ENTRYPOINT_OFFSET(PointerSize::k64, pJniMethodEndSynchronized)
- : QUICK_ENTRYPOINT_OFFSET(PointerSize::k64, pJniMethodEnd);
+ jni_end = is_synchronized
+ ? QUICK_ENTRYPOINT_OFFSET(kPointerSize, pJniMethodEndSynchronized)
+ : QUICK_ENTRYPOINT_OFFSET(kPointerSize, pJniMethodEnd);
}
// Pass saved local reference state.
if (end_jni_conv->IsCurrentParamOnStack()) {
@@ -461,23 +423,13 @@
}
if (end_jni_conv->IsCurrentParamInRegister()) {
__ GetCurrentThread(end_jni_conv->CurrentParamRegister());
- if (is_64_bit_target) {
- __ Call(end_jni_conv->CurrentParamRegister(), Offset(jni_end64),
- end_jni_conv->InterproceduralScratchRegister());
- } else {
- __ Call(end_jni_conv->CurrentParamRegister(), Offset(jni_end32),
- end_jni_conv->InterproceduralScratchRegister());
- }
+ __ Call(end_jni_conv->CurrentParamRegister(),
+ Offset(jni_end),
+ end_jni_conv->InterproceduralScratchRegister());
} else {
__ GetCurrentThread(end_jni_conv->CurrentParamStackOffset(),
end_jni_conv->InterproceduralScratchRegister());
- if (is_64_bit_target) {
- __ CallFromThread64(ThreadOffset64(jni_end64),
- end_jni_conv->InterproceduralScratchRegister());
- } else {
- __ CallFromThread32(ThreadOffset32(jni_end32),
- end_jni_conv->InterproceduralScratchRegister());
- }
+ __ CallFromThread(jni_end, end_jni_conv->InterproceduralScratchRegister());
}
// 13. Reload return value
@@ -517,7 +469,8 @@
}
// Copy a single parameter from the managed to the JNI calling convention.
-static void CopyParameter(Assembler* jni_asm,
+template <PointerSize kPointerSize>
+static void CopyParameter(JNIMacroAssembler<kPointerSize>* jni_asm,
ManagedRuntimeCallingConvention* mr_conv,
JniCallingConvention* jni_conv,
size_t frame_size, size_t out_arg_size) {
@@ -606,7 +559,8 @@
}
}
-static void SetNativeParameter(Assembler* jni_asm,
+template <PointerSize kPointerSize>
+static void SetNativeParameter(JNIMacroAssembler<kPointerSize>* jni_asm,
JniCallingConvention* jni_conv,
ManagedRegister in_reg) {
if (jni_conv->IsCurrentParamOnStack()) {
@@ -621,7 +575,13 @@
CompiledMethod* ArtQuickJniCompileMethod(CompilerDriver* compiler, uint32_t access_flags,
uint32_t method_idx, const DexFile& dex_file) {
- return ArtJniCompileMethodInternal(compiler, access_flags, method_idx, dex_file);
+ if (Is64BitInstructionSet(compiler->GetInstructionSet())) {
+ return ArtJniCompileMethodInternal<PointerSize::k64>(
+ compiler, access_flags, method_idx, dex_file);
+ } else {
+ return ArtJniCompileMethodInternal<PointerSize::k32>(
+ compiler, access_flags, method_idx, dex_file);
+ }
}
} // namespace art
diff --git a/compiler/optimizing/code_generator.cc b/compiler/optimizing/code_generator.cc
index a5493ab..5152075 100644
--- a/compiler/optimizing/code_generator.cc
+++ b/compiler/optimizing/code_generator.cc
@@ -1182,7 +1182,7 @@
<< "instruction->DebugName()=" << instruction->DebugName()
<< " instruction->GetSideEffects().ToString()=" << instruction->GetSideEffects().ToString();
} else {
- DCHECK(instruction->GetLocations()->OnlyCallsOnSlowPath() || slow_path->IsFatal())
+ DCHECK(instruction->GetLocations()->CallsOnSlowPath() || slow_path->IsFatal())
<< "instruction->DebugName()=" << instruction->DebugName()
<< " slow_path->GetDescription()=" << slow_path->GetDescription();
DCHECK(instruction->GetSideEffects().Includes(SideEffects::CanTriggerGC()) ||
diff --git a/compiler/optimizing/code_generator.h b/compiler/optimizing/code_generator.h
index ad02ecf..fd396c4 100644
--- a/compiler/optimizing/code_generator.h
+++ b/compiler/optimizing/code_generator.h
@@ -340,6 +340,9 @@
bool* GetBlockedCoreRegisters() const { return blocked_core_registers_; }
bool* GetBlockedFloatingPointRegisters() const { return blocked_fpu_registers_; }
+ bool IsBlockedCoreRegister(size_t i) { return blocked_core_registers_[i]; }
+ bool IsBlockedFloatingPointRegister(size_t i) { return blocked_fpu_registers_[i]; }
+
// Helper that returns the pointer offset of an index in an object array.
// Note: this method assumes we always have the same pointer size, regardless
// of the architecture.
diff --git a/compiler/optimizing/intrinsics_arm.cc b/compiler/optimizing/intrinsics_arm.cc
index be061f5..27d9d48 100644
--- a/compiler/optimizing/intrinsics_arm.cc
+++ b/compiler/optimizing/intrinsics_arm.cc
@@ -1212,7 +1212,7 @@
void IntrinsicLocationsBuilderARM::VisitStringIndexOf(HInvoke* invoke) {
LocationSummary* locations = new (arena_) LocationSummary(invoke,
- LocationSummary::kCallOnMainOnly,
+ LocationSummary::kCallOnMainAndSlowPath,
kIntrinsified);
// We have a hand-crafted assembly stub that follows the runtime calling convention. So it's
// best to align the inputs accordingly.
@@ -1232,7 +1232,7 @@
void IntrinsicLocationsBuilderARM::VisitStringIndexOfAfter(HInvoke* invoke) {
LocationSummary* locations = new (arena_) LocationSummary(invoke,
- LocationSummary::kCallOnMainOnly,
+ LocationSummary::kCallOnMainAndSlowPath,
kIntrinsified);
// We have a hand-crafted assembly stub that follows the runtime calling convention. So it's
// best to align the inputs accordingly.
@@ -1250,7 +1250,7 @@
void IntrinsicLocationsBuilderARM::VisitStringNewStringFromBytes(HInvoke* invoke) {
LocationSummary* locations = new (arena_) LocationSummary(invoke,
- LocationSummary::kCallOnMainOnly,
+ LocationSummary::kCallOnMainAndSlowPath,
kIntrinsified);
InvokeRuntimeCallingConvention calling_convention;
locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
@@ -1311,7 +1311,7 @@
void IntrinsicLocationsBuilderARM::VisitStringNewStringFromString(HInvoke* invoke) {
LocationSummary* locations = new (arena_) LocationSummary(invoke,
- LocationSummary::kCallOnMainOnly,
+ LocationSummary::kCallOnMainAndSlowPath,
kIntrinsified);
InvokeRuntimeCallingConvention calling_convention;
locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
diff --git a/compiler/optimizing/intrinsics_arm64.cc b/compiler/optimizing/intrinsics_arm64.cc
index e3a9d27..e7c40e6 100644
--- a/compiler/optimizing/intrinsics_arm64.cc
+++ b/compiler/optimizing/intrinsics_arm64.cc
@@ -1408,7 +1408,7 @@
void IntrinsicLocationsBuilderARM64::VisitStringIndexOf(HInvoke* invoke) {
LocationSummary* locations = new (arena_) LocationSummary(invoke,
- LocationSummary::kCallOnMainOnly,
+ LocationSummary::kCallOnMainAndSlowPath,
kIntrinsified);
// We have a hand-crafted assembly stub that follows the runtime calling convention. So it's
// best to align the inputs accordingly.
@@ -1428,7 +1428,7 @@
void IntrinsicLocationsBuilderARM64::VisitStringIndexOfAfter(HInvoke* invoke) {
LocationSummary* locations = new (arena_) LocationSummary(invoke,
- LocationSummary::kCallOnMainOnly,
+ LocationSummary::kCallOnMainAndSlowPath,
kIntrinsified);
// We have a hand-crafted assembly stub that follows the runtime calling convention. So it's
// best to align the inputs accordingly.
@@ -1446,7 +1446,7 @@
void IntrinsicLocationsBuilderARM64::VisitStringNewStringFromBytes(HInvoke* invoke) {
LocationSummary* locations = new (arena_) LocationSummary(invoke,
- LocationSummary::kCallOnMainOnly,
+ LocationSummary::kCallOnMainAndSlowPath,
kIntrinsified);
InvokeRuntimeCallingConvention calling_convention;
locations->SetInAt(0, LocationFrom(calling_convention.GetRegisterAt(0)));
@@ -1505,7 +1505,7 @@
void IntrinsicLocationsBuilderARM64::VisitStringNewStringFromString(HInvoke* invoke) {
LocationSummary* locations = new (arena_) LocationSummary(invoke,
- LocationSummary::kCallOnMainOnly,
+ LocationSummary::kCallOnMainAndSlowPath,
kIntrinsified);
InvokeRuntimeCallingConvention calling_convention;
locations->SetInAt(0, LocationFrom(calling_convention.GetRegisterAt(0)));
diff --git a/compiler/optimizing/intrinsics_mips.cc b/compiler/optimizing/intrinsics_mips.cc
index 9449f79..55e1ab2 100644
--- a/compiler/optimizing/intrinsics_mips.cc
+++ b/compiler/optimizing/intrinsics_mips.cc
@@ -2070,7 +2070,7 @@
// int java.lang.String.indexOf(int ch)
void IntrinsicLocationsBuilderMIPS::VisitStringIndexOf(HInvoke* invoke) {
LocationSummary* locations = new (arena_) LocationSummary(invoke,
- LocationSummary::kCallOnMainOnly,
+ LocationSummary::kCallOnMainAndSlowPath,
kIntrinsified);
// We have a hand-crafted assembly stub that follows the runtime
// calling convention. So it's best to align the inputs accordingly.
@@ -2095,7 +2095,7 @@
// int java.lang.String.indexOf(int ch, int fromIndex)
void IntrinsicLocationsBuilderMIPS::VisitStringIndexOfAfter(HInvoke* invoke) {
LocationSummary* locations = new (arena_) LocationSummary(invoke,
- LocationSummary::kCallOnMainOnly,
+ LocationSummary::kCallOnMainAndSlowPath,
kIntrinsified);
// We have a hand-crafted assembly stub that follows the runtime
// calling convention. So it's best to align the inputs accordingly.
@@ -2121,7 +2121,7 @@
// java.lang.StringFactory.newStringFromBytes(byte[] data, int high, int offset, int byteCount)
void IntrinsicLocationsBuilderMIPS::VisitStringNewStringFromBytes(HInvoke* invoke) {
LocationSummary* locations = new (arena_) LocationSummary(invoke,
- LocationSummary::kCallOnMainOnly,
+ LocationSummary::kCallOnMainAndSlowPath,
kIntrinsified);
InvokeRuntimeCallingConvention calling_convention;
locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
@@ -2186,7 +2186,7 @@
// java.lang.StringFactory.newStringFromString(String toCopy)
void IntrinsicLocationsBuilderMIPS::VisitStringNewStringFromString(HInvoke* invoke) {
LocationSummary* locations = new (arena_) LocationSummary(invoke,
- LocationSummary::kCallOnMainOnly,
+ LocationSummary::kCallOnMainAndSlowPath,
kIntrinsified);
InvokeRuntimeCallingConvention calling_convention;
locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
diff --git a/compiler/optimizing/intrinsics_mips64.cc b/compiler/optimizing/intrinsics_mips64.cc
index 8d4d3e5..1e18540 100644
--- a/compiler/optimizing/intrinsics_mips64.cc
+++ b/compiler/optimizing/intrinsics_mips64.cc
@@ -1707,7 +1707,7 @@
// int java.lang.String.indexOf(int ch)
void IntrinsicLocationsBuilderMIPS64::VisitStringIndexOf(HInvoke* invoke) {
LocationSummary* locations = new (arena_) LocationSummary(invoke,
- LocationSummary::kCallOnMainOnly,
+ LocationSummary::kCallOnMainAndSlowPath,
kIntrinsified);
// We have a hand-crafted assembly stub that follows the runtime
// calling convention. So it's best to align the inputs accordingly.
@@ -1728,7 +1728,7 @@
// int java.lang.String.indexOf(int ch, int fromIndex)
void IntrinsicLocationsBuilderMIPS64::VisitStringIndexOfAfter(HInvoke* invoke) {
LocationSummary* locations = new (arena_) LocationSummary(invoke,
- LocationSummary::kCallOnMainOnly,
+ LocationSummary::kCallOnMainAndSlowPath,
kIntrinsified);
// We have a hand-crafted assembly stub that follows the runtime
// calling convention. So it's best to align the inputs accordingly.
@@ -1748,7 +1748,7 @@
// java.lang.StringFactory.newStringFromBytes(byte[] data, int high, int offset, int byteCount)
void IntrinsicLocationsBuilderMIPS64::VisitStringNewStringFromBytes(HInvoke* invoke) {
LocationSummary* locations = new (arena_) LocationSummary(invoke,
- LocationSummary::kCallOnMainOnly,
+ LocationSummary::kCallOnMainAndSlowPath,
kIntrinsified);
InvokeRuntimeCallingConvention calling_convention;
locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
@@ -1816,7 +1816,7 @@
// java.lang.StringFactory.newStringFromString(String toCopy)
void IntrinsicLocationsBuilderMIPS64::VisitStringNewStringFromString(HInvoke* invoke) {
LocationSummary* locations = new (arena_) LocationSummary(invoke,
- LocationSummary::kCallOnMainOnly,
+ LocationSummary::kCallOnMainAndSlowPath,
kIntrinsified);
InvokeRuntimeCallingConvention calling_convention;
locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
diff --git a/compiler/optimizing/intrinsics_x86.cc b/compiler/optimizing/intrinsics_x86.cc
index 83cc278..dc409c9 100644
--- a/compiler/optimizing/intrinsics_x86.cc
+++ b/compiler/optimizing/intrinsics_x86.cc
@@ -753,6 +753,11 @@
}
void IntrinsicLocationsBuilderX86::VisitMathRoundFloat(HInvoke* invoke) {
+ // See intrinsics.h.
+ if (!kRoundIsPlusPointFive) {
+ return;
+ }
+
// Do we have instruction support?
if (codegen_->GetInstructionSetFeatures().HasSSE4_1()) {
HInvokeStaticOrDirect* static_or_direct = invoke->AsInvokeStaticOrDirect();
@@ -1211,7 +1216,7 @@
void IntrinsicLocationsBuilderX86::VisitStringCompareTo(HInvoke* invoke) {
// The inputs plus one temp.
LocationSummary* locations = new (arena_) LocationSummary(invoke,
- LocationSummary::kCallOnMainOnly,
+ LocationSummary::kCallOnMainAndSlowPath,
kIntrinsified);
InvokeRuntimeCallingConvention calling_convention;
locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
@@ -1485,7 +1490,7 @@
void IntrinsicLocationsBuilderX86::VisitStringNewStringFromBytes(HInvoke* invoke) {
LocationSummary* locations = new (arena_) LocationSummary(invoke,
- LocationSummary::kCallOnMainOnly,
+ LocationSummary::kCallOnMainAndSlowPath,
kIntrinsified);
InvokeRuntimeCallingConvention calling_convention;
locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
@@ -1538,7 +1543,7 @@
void IntrinsicLocationsBuilderX86::VisitStringNewStringFromString(HInvoke* invoke) {
LocationSummary* locations = new (arena_) LocationSummary(invoke,
- LocationSummary::kCallOnMainOnly,
+ LocationSummary::kCallOnMainAndSlowPath,
kIntrinsified);
InvokeRuntimeCallingConvention calling_convention;
locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
diff --git a/compiler/optimizing/intrinsics_x86_64.cc b/compiler/optimizing/intrinsics_x86_64.cc
index a439a53..7dfbfb0 100644
--- a/compiler/optimizing/intrinsics_x86_64.cc
+++ b/compiler/optimizing/intrinsics_x86_64.cc
@@ -598,6 +598,10 @@
}
void IntrinsicLocationsBuilderX86_64::VisitMathRoundFloat(HInvoke* invoke) {
+ // See intrinsics.h.
+ if (!kRoundIsPlusPointFive) {
+ return;
+ }
CreateSSE41FPToIntLocations(arena_, invoke, codegen_);
}
@@ -642,6 +646,10 @@
}
void IntrinsicLocationsBuilderX86_64::VisitMathRoundDouble(HInvoke* invoke) {
+ // See intrinsics.h.
+ if (!kRoundIsPlusPointFive) {
+ return;
+ }
CreateSSE41FPToIntLocations(arena_, invoke, codegen_);
}
@@ -1292,7 +1300,7 @@
void IntrinsicLocationsBuilderX86_64::VisitStringCompareTo(HInvoke* invoke) {
LocationSummary* locations = new (arena_) LocationSummary(invoke,
- LocationSummary::kCallOnMainOnly,
+ LocationSummary::kCallOnMainAndSlowPath,
kIntrinsified);
InvokeRuntimeCallingConvention calling_convention;
locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
@@ -1566,7 +1574,7 @@
void IntrinsicLocationsBuilderX86_64::VisitStringNewStringFromBytes(HInvoke* invoke) {
LocationSummary* locations = new (arena_) LocationSummary(invoke,
- LocationSummary::kCallOnMainOnly,
+ LocationSummary::kCallOnMainAndSlowPath,
kIntrinsified);
InvokeRuntimeCallingConvention calling_convention;
locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
@@ -1623,7 +1631,7 @@
void IntrinsicLocationsBuilderX86_64::VisitStringNewStringFromString(HInvoke* invoke) {
LocationSummary* locations = new (arena_) LocationSummary(invoke,
- LocationSummary::kCallOnMainOnly,
+ LocationSummary::kCallOnMainAndSlowPath,
kIntrinsified);
InvokeRuntimeCallingConvention calling_convention;
locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
diff --git a/compiler/optimizing/locations.h b/compiler/optimizing/locations.h
index 7a78bfd..5fdfb9b 100644
--- a/compiler/optimizing/locations.h
+++ b/compiler/optimizing/locations.h
@@ -376,6 +376,10 @@
return PolicyField::Decode(GetPayload());
}
+ bool RequiresRegisterKind() const {
+ return GetPolicy() == kRequiresRegister || GetPolicy() == kRequiresFpuRegister;
+ }
+
uintptr_t GetEncoding() const {
return GetPayload();
}
@@ -480,6 +484,7 @@
public:
enum CallKind {
kNoCall,
+ kCallOnMainAndSlowPath,
kCallOnSlowPath,
kCallOnMainOnly
};
@@ -540,10 +545,29 @@
Location Out() const { return output_; }
- bool CanCall() const { return call_kind_ != kNoCall; }
- bool WillCall() const { return call_kind_ == kCallOnMainOnly; }
- bool OnlyCallsOnSlowPath() const { return call_kind_ == kCallOnSlowPath; }
- bool NeedsSafepoint() const { return CanCall(); }
+ bool CanCall() const {
+ return call_kind_ != kNoCall;
+ }
+
+ bool WillCall() const {
+ return call_kind_ == kCallOnMainOnly || call_kind_ == kCallOnMainAndSlowPath;
+ }
+
+ bool CallsOnSlowPath() const {
+ return call_kind_ == kCallOnSlowPath || call_kind_ == kCallOnMainAndSlowPath;
+ }
+
+ bool OnlyCallsOnSlowPath() const {
+ return call_kind_ == kCallOnSlowPath;
+ }
+
+ bool CallsOnMainAndSlowPath() const {
+ return call_kind_ == kCallOnMainAndSlowPath;
+ }
+
+ bool NeedsSafepoint() const {
+ return CanCall();
+ }
void SetStackBit(uint32_t index) {
stack_mask_->SetBit(index);
@@ -629,8 +653,7 @@
// Whether these are locations for an intrinsified call.
bool intrinsified_;
- ART_FRIEND_TEST(RegisterAllocatorTest, ExpectedInRegisterHint);
- ART_FRIEND_TEST(RegisterAllocatorTest, SameAsFirstInputHint);
+ friend class RegisterAllocatorTest;
DISALLOW_COPY_AND_ASSIGN(LocationSummary);
};
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index d5b0d77..30da69f 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -546,7 +546,8 @@
NO_INLINE // Avoid increasing caller's frame size by large stack-allocated objects.
static void AllocateRegisters(HGraph* graph,
CodeGenerator* codegen,
- PassObserver* pass_observer) {
+ PassObserver* pass_observer,
+ RegisterAllocator::Strategy strategy) {
{
PassScope scope(PrepareForRegisterAllocation::kPrepareForRegisterAllocationPassName,
pass_observer);
@@ -559,7 +560,7 @@
}
{
PassScope scope(RegisterAllocator::kRegisterAllocatorPassName, pass_observer);
- RegisterAllocator::Create(graph->GetArena(), codegen, liveness)->AllocateRegisters();
+ RegisterAllocator::Create(graph->GetArena(), codegen, liveness, strategy)->AllocateRegisters();
}
}
@@ -626,7 +627,9 @@
RunOptimizations(optimizations2, arraysize(optimizations2), pass_observer);
RunArchOptimizations(driver->GetInstructionSet(), graph, codegen, pass_observer);
- AllocateRegisters(graph, codegen, pass_observer);
+ RegisterAllocator::Strategy regalloc_strategy =
+ driver->GetCompilerOptions().GetRegisterAllocationStrategy();
+ AllocateRegisters(graph, codegen, pass_observer, regalloc_strategy);
}
static ArenaVector<LinkerPatch> EmitAndSortLinkerPatches(CodeGenerator* codegen) {
diff --git a/compiler/optimizing/register_allocator.cc b/compiler/optimizing/register_allocator.cc
index 2367ce1..5b768d5 100644
--- a/compiler/optimizing/register_allocator.cc
+++ b/compiler/optimizing/register_allocator.cc
@@ -21,6 +21,7 @@
#include "base/bit_vector-inl.h"
#include "code_generator.h"
+#include "register_allocator_graph_color.h"
#include "register_allocator_linear_scan.h"
#include "ssa_liveness_analysis.h"
@@ -41,6 +42,8 @@
switch (strategy) {
case kRegisterAllocatorLinearScan:
return new (allocator) RegisterAllocatorLinearScan(allocator, codegen, analysis);
+ case kRegisterAllocatorGraphColor:
+ return new (allocator) RegisterAllocatorGraphColor(allocator, codegen, analysis);
default:
LOG(FATAL) << "Invalid register allocation strategy: " << strategy;
UNREACHABLE();
@@ -163,6 +166,19 @@
} else {
codegen.DumpFloatingPointRegister(message, current->GetRegister());
}
+ for (LiveInterval* interval : intervals) {
+ if (interval->HasRegister()
+ && interval->GetRegister() == current->GetRegister()
+ && interval->CoversSlow(j)) {
+ message << std::endl;
+ if (interval->GetDefinedBy() != nullptr) {
+ message << interval->GetDefinedBy()->GetKind() << " ";
+ } else {
+ message << "physical ";
+ }
+ interval->Dump(message);
+ }
+ }
LOG(FATAL) << message.str();
} else {
return false;
diff --git a/compiler/optimizing/register_allocator.h b/compiler/optimizing/register_allocator.h
index 729eede..7e1fff8 100644
--- a/compiler/optimizing/register_allocator.h
+++ b/compiler/optimizing/register_allocator.h
@@ -40,7 +40,8 @@
class RegisterAllocator : public ArenaObject<kArenaAllocRegisterAllocator> {
public:
enum Strategy {
- kRegisterAllocatorLinearScan
+ kRegisterAllocatorLinearScan,
+ kRegisterAllocatorGraphColor
};
static constexpr Strategy kRegisterAllocatorDefault = kRegisterAllocatorLinearScan;
diff --git a/compiler/optimizing/register_allocator_graph_color.cc b/compiler/optimizing/register_allocator_graph_color.cc
new file mode 100644
index 0000000..79ca5a0
--- /dev/null
+++ b/compiler/optimizing/register_allocator_graph_color.cc
@@ -0,0 +1,1012 @@
+/*
+ * Copyright (C) 2016 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 "register_allocator_graph_color.h"
+
+#include "code_generator.h"
+#include "register_allocation_resolver.h"
+#include "ssa_liveness_analysis.h"
+#include "thread-inl.h"
+
+namespace art {
+
+// Highest number of registers that we support for any platform. This can be used for std::bitset,
+// for example, which needs to know its size at compile time.
+static constexpr size_t kMaxNumRegs = 32;
+
+// The maximum number of graph coloring attempts before triggering a DCHECK.
+// This is meant to catch changes to the graph coloring algorithm that undermine its forward
+// progress guarantees. Forward progress for the algorithm means splitting live intervals on
+// every graph coloring attempt so that eventually the interference graph will be sparse enough
+// to color. The main threat to forward progress is trying to split short intervals which cannot be
+// split further; this could cause infinite looping because the interference graph would never
+// change. This is avoided by prioritizing short intervals before long ones, so that long
+// intervals are split when coloring fails.
+static constexpr size_t kMaxGraphColoringAttemptsDebug = 100;
+
+// Interference nodes make up the interference graph, which is the primary data structure in
+// graph coloring register allocation. Each node represents a single live interval, and contains
+// a set of adjacent nodes corresponding to intervals overlapping with its own. To save memory,
+// pre-colored nodes never contain outgoing edges (only incoming ones).
+//
+// As nodes are pruned from the interference graph, incoming edges of the pruned node are removed,
+// but outgoing edges remain in order to later color the node based on the colors of its neighbors.
+//
+// Note that a pair interval is represented by a single node in the interference graph, which
+// essentially requires two colors. One consequence of this is that the degree of a node is not
+// necessarily equal to the number of adjacent nodes--instead, the degree reflects the maximum
+// number of colors with which a node could interfere. We model this by giving edges different
+// weights (1 or 2) to control how much it increases the degree of adjacent nodes.
+// For example, the edge between two single nodes will have weight 1. On the other hand,
+// the edge between a single node and a pair node will have weight 2. This is because the pair
+// node could block up to two colors for the single node, and because the single node could
+// block an entire two-register aligned slot for the pair node.
+// The degree is defined this way because we use it to decide whether a node is guaranteed a color,
+// and thus whether it is safe to prune it from the interference graph early on.
+class InterferenceNode : public ArenaObject<kArenaAllocRegisterAllocator> {
+ public:
+ InterferenceNode(ArenaAllocator* allocator, LiveInterval* interval, size_t id)
+ : interval_(interval),
+ adjacent_nodes_(CmpPtr, allocator->Adapter(kArenaAllocRegisterAllocator)),
+ out_degree_(0),
+ id_(id) {}
+
+ // Used to maintain determinism when storing InterferenceNode pointers in sets.
+ static bool CmpPtr(const InterferenceNode* lhs, const InterferenceNode* rhs) {
+ return lhs->id_ < rhs->id_;
+ }
+
+ void AddInterference(InterferenceNode* other) {
+ if (adjacent_nodes_.insert(other).second) {
+ out_degree_ += EdgeWeightWith(other);
+ }
+ }
+
+ void RemoveInterference(InterferenceNode* other) {
+ if (adjacent_nodes_.erase(other) > 0) {
+ out_degree_ -= EdgeWeightWith(other);
+ }
+ }
+
+ bool ContainsInterference(InterferenceNode* other) const {
+ return adjacent_nodes_.count(other) > 0;
+ }
+
+ LiveInterval* GetInterval() const {
+ return interval_;
+ }
+
+ const ArenaSet<InterferenceNode*, decltype(&CmpPtr)>& GetAdjacentNodes() const {
+ return adjacent_nodes_;
+ }
+
+ size_t GetOutDegree() const {
+ return out_degree_;
+ }
+
+ size_t GetId() const {
+ return id_;
+ }
+
+ private:
+ // We give extra weight to edges adjacent to pair nodes. See the general comment on the
+ // interference graph above.
+ size_t EdgeWeightWith(InterferenceNode* other) const {
+ return (interval_->HasHighInterval() || other->interval_->HasHighInterval()) ? 2 : 1;
+ }
+
+ // The live interval that this node represents.
+ LiveInterval* const interval_;
+
+ // All nodes interfering with this one.
+ // TODO: There is potential to use a cheaper data structure here, especially since
+ // adjacency sets will usually be small.
+ ArenaSet<InterferenceNode*, decltype(&CmpPtr)> adjacent_nodes_;
+
+ // The maximum number of colors with which this node could interfere. This could be more than
+ // the number of adjacent nodes if this is a pair node, or if some adjacent nodes are pair nodes.
+ // We use "out" degree because incoming edges come from nodes already pruned from the graph,
+ // and do not affect the coloring of this node.
+ size_t out_degree_;
+
+ // A unique identifier for this node, used to maintain determinism when storing
+ // interference nodes in sets.
+ const size_t id_;
+
+ // TODO: We could cache the result of interval_->RequiresRegister(), since it
+ // will not change for the lifetime of this node. (Currently, RequiresRegister() requires
+ // iterating through all uses of a live interval.)
+
+ DISALLOW_COPY_AND_ASSIGN(InterferenceNode);
+};
+
+static bool IsCoreInterval(LiveInterval* interval) {
+ return interval->GetType() != Primitive::kPrimFloat
+ && interval->GetType() != Primitive::kPrimDouble;
+}
+
+static size_t ComputeReservedArtMethodSlots(const CodeGenerator& codegen) {
+ return static_cast<size_t>(InstructionSetPointerSize(codegen.GetInstructionSet())) / kVRegSize;
+}
+
+RegisterAllocatorGraphColor::RegisterAllocatorGraphColor(ArenaAllocator* allocator,
+ CodeGenerator* codegen,
+ const SsaLivenessAnalysis& liveness)
+ : RegisterAllocator(allocator, codegen, liveness),
+ core_intervals_(allocator->Adapter(kArenaAllocRegisterAllocator)),
+ fp_intervals_(allocator->Adapter(kArenaAllocRegisterAllocator)),
+ temp_intervals_(allocator->Adapter(kArenaAllocRegisterAllocator)),
+ safepoints_(allocator->Adapter(kArenaAllocRegisterAllocator)),
+ physical_core_intervals_(allocator->Adapter(kArenaAllocRegisterAllocator)),
+ physical_fp_intervals_(allocator->Adapter(kArenaAllocRegisterAllocator)),
+ int_spill_slot_counter_(0),
+ double_spill_slot_counter_(0),
+ float_spill_slot_counter_(0),
+ long_spill_slot_counter_(0),
+ catch_phi_spill_slot_counter_(0),
+ reserved_art_method_slots_(ComputeReservedArtMethodSlots(*codegen)),
+ reserved_out_slots_(codegen->GetGraph()->GetMaximumNumberOfOutVRegs()),
+ number_of_globally_blocked_core_regs_(0),
+ number_of_globally_blocked_fp_regs_(0),
+ max_safepoint_live_core_regs_(0),
+ max_safepoint_live_fp_regs_(0),
+ coloring_attempt_allocator_(nullptr) {
+ // Before we ask for blocked registers, set them up in the code generator.
+ codegen->SetupBlockedRegisters();
+
+ // Initialize physical core register live intervals and blocked registers.
+ // This includes globally blocked registers, such as the stack pointer.
+ physical_core_intervals_.resize(codegen->GetNumberOfCoreRegisters(), nullptr);
+ for (size_t i = 0; i < codegen->GetNumberOfCoreRegisters(); ++i) {
+ LiveInterval* interval = LiveInterval::MakeFixedInterval(allocator_, i, Primitive::kPrimInt);
+ physical_core_intervals_[i] = interval;
+ core_intervals_.push_back(interval);
+ if (codegen_->IsBlockedCoreRegister(i)) {
+ ++number_of_globally_blocked_core_regs_;
+ interval->AddRange(0, liveness.GetMaxLifetimePosition());
+ }
+ }
+ // Initialize physical floating point register live intervals and blocked registers.
+ physical_fp_intervals_.resize(codegen->GetNumberOfFloatingPointRegisters(), nullptr);
+ for (size_t i = 0; i < codegen->GetNumberOfFloatingPointRegisters(); ++i) {
+ LiveInterval* interval = LiveInterval::MakeFixedInterval(allocator_, i, Primitive::kPrimFloat);
+ physical_fp_intervals_[i] = interval;
+ fp_intervals_.push_back(interval);
+ if (codegen_->IsBlockedFloatingPointRegister(i)) {
+ ++number_of_globally_blocked_fp_regs_;
+ interval->AddRange(0, liveness.GetMaxLifetimePosition());
+ }
+ }
+}
+
+void RegisterAllocatorGraphColor::AllocateRegisters() {
+ // (1) Collect and prepare live intervals.
+ ProcessInstructions();
+
+ for (bool processing_core_regs : {true, false}) {
+ ArenaVector<LiveInterval*>& intervals = processing_core_regs
+ ? core_intervals_
+ : fp_intervals_;
+ size_t num_registers = processing_core_regs
+ ? codegen_->GetNumberOfCoreRegisters()
+ : codegen_->GetNumberOfFloatingPointRegisters();
+
+ size_t attempt = 0;
+ while (true) {
+ ++attempt;
+ DCHECK(attempt <= kMaxGraphColoringAttemptsDebug)
+ << "Exceeded debug max graph coloring register allocation attempts. "
+ << "This could indicate that the register allocator is not making forward progress, "
+ << "which could be caused by prioritizing the wrong live intervals. (Short intervals "
+ << "should be prioritized over long ones, because they cannot be split further.)";
+
+ // Reset the allocator for the next coloring attempt.
+ ArenaAllocator coloring_attempt_allocator(allocator_->GetArenaPool());
+ coloring_attempt_allocator_ = &coloring_attempt_allocator;
+
+ // (2) Build the interference graph.
+ ArenaVector<InterferenceNode*> prunable_nodes(
+ coloring_attempt_allocator_->Adapter(kArenaAllocRegisterAllocator));
+ ArenaVector<InterferenceNode*> safepoints(
+ coloring_attempt_allocator_->Adapter(kArenaAllocRegisterAllocator));
+ BuildInterferenceGraph(intervals, &prunable_nodes, &safepoints);
+
+ // (3) Prune all uncolored nodes from interference graph.
+ ArenaStdStack<InterferenceNode*> pruned_nodes(
+ coloring_attempt_allocator_->Adapter(kArenaAllocRegisterAllocator));
+ PruneInterferenceGraph(prunable_nodes, num_registers, &pruned_nodes);
+
+ // (4) Color pruned nodes based on interferences.
+ bool successful = ColorInterferenceGraph(&pruned_nodes, num_registers);
+
+ if (successful) {
+ // Compute the maximum number of live registers across safepoints.
+ // Notice that we do not count globally blocked registers, such as the stack pointer.
+ if (safepoints.size() > 0) {
+ size_t max_safepoint_live_regs = ComputeMaxSafepointLiveRegisters(safepoints);
+ if (processing_core_regs) {
+ max_safepoint_live_core_regs_ =
+ max_safepoint_live_regs - number_of_globally_blocked_core_regs_;
+ } else {
+ max_safepoint_live_fp_regs_=
+ max_safepoint_live_regs - number_of_globally_blocked_fp_regs_;
+ }
+ }
+
+ // Tell the code generator which registers were allocated.
+ // We only look at prunable_nodes because we already told the code generator about
+ // fixed intervals while processing instructions. We also ignore the fixed intervals
+ // placed at the top of catch blocks.
+ for (InterferenceNode* node : prunable_nodes) {
+ LiveInterval* interval = node->GetInterval();
+ if (interval->HasRegister()) {
+ Location low_reg = processing_core_regs
+ ? Location::RegisterLocation(interval->GetRegister())
+ : Location::FpuRegisterLocation(interval->GetRegister());
+ codegen_->AddAllocatedRegister(low_reg);
+ if (interval->HasHighInterval()) {
+ LiveInterval* high = interval->GetHighInterval();
+ DCHECK(high->HasRegister());
+ Location high_reg = processing_core_regs
+ ? Location::RegisterLocation(high->GetRegister())
+ : Location::FpuRegisterLocation(high->GetRegister());
+ codegen_->AddAllocatedRegister(high_reg);
+ }
+ } else {
+ DCHECK(!interval->HasHighInterval() || !interval->GetHighInterval()->HasRegister());
+ }
+ }
+
+ break;
+ }
+ } // while unsuccessful
+ } // for processing_core_instructions
+
+ // (5) Resolve locations and deconstruct SSA form.
+ RegisterAllocationResolver(allocator_, codegen_, liveness_)
+ .Resolve(max_safepoint_live_core_regs_,
+ max_safepoint_live_fp_regs_,
+ reserved_art_method_slots_ + reserved_out_slots_,
+ int_spill_slot_counter_,
+ long_spill_slot_counter_,
+ float_spill_slot_counter_,
+ double_spill_slot_counter_,
+ catch_phi_spill_slot_counter_,
+ temp_intervals_);
+
+ if (kIsDebugBuild) {
+ Validate(/*log_fatal_on_failure*/ true);
+ }
+}
+
+bool RegisterAllocatorGraphColor::Validate(bool log_fatal_on_failure) {
+ for (bool processing_core_regs : {true, false}) {
+ ArenaVector<LiveInterval*> intervals(
+ allocator_->Adapter(kArenaAllocRegisterAllocatorValidate));
+ for (size_t i = 0; i < liveness_.GetNumberOfSsaValues(); ++i) {
+ HInstruction* instruction = liveness_.GetInstructionFromSsaIndex(i);
+ LiveInterval* interval = instruction->GetLiveInterval();
+ if (interval != nullptr && IsCoreInterval(interval) == processing_core_regs) {
+ intervals.push_back(instruction->GetLiveInterval());
+ }
+ }
+
+ ArenaVector<LiveInterval*>& physical_intervals = processing_core_regs
+ ? physical_core_intervals_
+ : physical_fp_intervals_;
+ for (LiveInterval* fixed : physical_intervals) {
+ if (fixed->GetFirstRange() != nullptr) {
+ // Ideally we would check fixed ranges as well, but currently there are times when
+ // two fixed intervals for the same register will overlap. For example, a fixed input
+ // and a fixed output may sometimes share the same register, in which there will be two
+ // fixed intervals for the same place.
+ }
+ }
+
+ for (LiveInterval* temp : temp_intervals_) {
+ if (IsCoreInterval(temp) == processing_core_regs) {
+ intervals.push_back(temp);
+ }
+ }
+
+ size_t spill_slots = int_spill_slot_counter_
+ + long_spill_slot_counter_
+ + float_spill_slot_counter_
+ + double_spill_slot_counter_
+ + catch_phi_spill_slot_counter_;
+ bool ok = ValidateIntervals(intervals,
+ spill_slots,
+ reserved_art_method_slots_ + reserved_out_slots_,
+ *codegen_,
+ allocator_,
+ processing_core_regs,
+ log_fatal_on_failure);
+ if (!ok) {
+ return false;
+ }
+ } // for processing_core_regs
+
+ return true;
+}
+
+void RegisterAllocatorGraphColor::ProcessInstructions() {
+ for (HLinearPostOrderIterator it(*codegen_->GetGraph()); !it.Done(); it.Advance()) {
+ HBasicBlock* block = it.Current();
+
+ // Note that we currently depend on this ordering, since some helper
+ // code is designed for linear scan register allocation.
+ for (HBackwardInstructionIterator instr_it(block->GetInstructions());
+ !instr_it.Done();
+ instr_it.Advance()) {
+ ProcessInstruction(instr_it.Current());
+ }
+
+ for (HInstructionIterator phi_it(block->GetPhis()); !phi_it.Done(); phi_it.Advance()) {
+ ProcessInstruction(phi_it.Current());
+ }
+
+ if (block->IsCatchBlock() || (block->IsLoopHeader() && block->GetLoopInformation()->IsIrreducible())) {
+ // By blocking all registers at the top of each catch block or irreducible loop, we force
+ // intervals belonging to the live-in set of the catch/header block to be spilled.
+ // TODO(ngeoffray): Phis in this block could be allocated in register.
+ size_t position = block->GetLifetimeStart();
+ BlockRegisters(position, position + 1);
+ }
+ }
+}
+
+void RegisterAllocatorGraphColor::ProcessInstruction(HInstruction* instruction) {
+ LocationSummary* locations = instruction->GetLocations();
+ if (locations == nullptr) {
+ return;
+ }
+ if (locations->NeedsSafepoint() && codegen_->IsLeafMethod()) {
+ // We do this here because we do not want the suspend check to artificially
+ // create live registers.
+ DCHECK(instruction->IsSuspendCheckEntry());
+ DCHECK_EQ(locations->GetTempCount(), 0u);
+ instruction->GetBlock()->RemoveInstruction(instruction);
+ return;
+ }
+
+ CheckForTempLiveIntervals(instruction);
+ CheckForSafepoint(instruction);
+ if (instruction->GetLocations()->WillCall()) {
+ // If a call will happen, create fixed intervals for caller-save registers.
+ // TODO: Note that it may be beneficial to later split intervals at this point,
+ // so that we allow last-minute moves from a caller-save register
+ // to a callee-save register.
+ BlockRegisters(instruction->GetLifetimePosition(),
+ instruction->GetLifetimePosition() + 1,
+ /*caller_save_only*/ true);
+ }
+ CheckForFixedInputs(instruction);
+
+ LiveInterval* interval = instruction->GetLiveInterval();
+ if (interval == nullptr) {
+ // Instructions lacking a valid output location do not have a live interval.
+ DCHECK(!locations->Out().IsValid());
+ return;
+ }
+
+ // Low intervals act as representatives for their corresponding high interval.
+ DCHECK(!interval->IsHighInterval());
+ if (codegen_->NeedsTwoRegisters(interval->GetType())) {
+ interval->AddHighInterval();
+ }
+ AddSafepointsFor(instruction);
+ CheckForFixedOutput(instruction);
+ AllocateSpillSlotForCatchPhi(instruction);
+
+ ArenaVector<LiveInterval*>& intervals = IsCoreInterval(interval)
+ ? core_intervals_
+ : fp_intervals_;
+ if (interval->HasSpillSlot() || instruction->IsConstant()) {
+ // Note that if an interval already has a spill slot, then its value currently resides
+ // in the stack (e.g., parameters). Thus we do not have to allocate a register until its first
+ // register use. This is also true for constants, which can be materialized at any point.
+ size_t first_register_use = interval->FirstRegisterUse();
+ if (first_register_use != kNoLifetime) {
+ LiveInterval* split = SplitBetween(interval, interval->GetStart(), first_register_use - 1);
+ intervals.push_back(split);
+ } else {
+ // We won't allocate a register for this value.
+ }
+ } else {
+ intervals.push_back(interval);
+ }
+}
+
+void RegisterAllocatorGraphColor::CheckForFixedInputs(HInstruction* instruction) {
+ // We simply block physical registers where necessary.
+ // TODO: Ideally we would coalesce the physical register with the register
+ // allocated to the input value, but this can be tricky if, e.g., there
+ // could be multiple physical register uses of the same value at the
+ // same instruction. Need to think about it more.
+ LocationSummary* locations = instruction->GetLocations();
+ size_t position = instruction->GetLifetimePosition();
+ for (size_t i = 0; i < locations->GetInputCount(); ++i) {
+ Location input = locations->InAt(i);
+ if (input.IsRegister() || input.IsFpuRegister()) {
+ BlockRegister(input, position, position + 1);
+ codegen_->AddAllocatedRegister(input);
+ } else if (input.IsPair()) {
+ BlockRegister(input.ToLow(), position, position + 1);
+ BlockRegister(input.ToHigh(), position, position + 1);
+ codegen_->AddAllocatedRegister(input.ToLow());
+ codegen_->AddAllocatedRegister(input.ToHigh());
+ }
+ }
+}
+
+void RegisterAllocatorGraphColor::CheckForFixedOutput(HInstruction* instruction) {
+ // If an instruction has a fixed output location, we give the live interval a register and then
+ // proactively split it just after the definition point to avoid creating too many interferences
+ // with a fixed node.
+ LiveInterval* interval = instruction->GetLiveInterval();
+ Location out = interval->GetDefinedBy()->GetLocations()->Out();
+ size_t position = instruction->GetLifetimePosition();
+ DCHECK_GE(interval->GetEnd() - position, 2u);
+
+ if (out.IsUnallocated() && out.GetPolicy() == Location::kSameAsFirstInput) {
+ out = instruction->GetLocations()->InAt(0);
+ }
+
+ if (out.IsRegister() || out.IsFpuRegister()) {
+ interval->SetRegister(out.reg());
+ codegen_->AddAllocatedRegister(out);
+ Split(interval, position + 1);
+ } else if (out.IsPair()) {
+ interval->SetRegister(out.low());
+ interval->GetHighInterval()->SetRegister(out.high());
+ codegen_->AddAllocatedRegister(out.ToLow());
+ codegen_->AddAllocatedRegister(out.ToHigh());
+ Split(interval, position + 1);
+ } else if (out.IsStackSlot() || out.IsDoubleStackSlot()) {
+ interval->SetSpillSlot(out.GetStackIndex());
+ } else {
+ DCHECK(out.IsUnallocated() || out.IsConstant());
+ }
+}
+
+void RegisterAllocatorGraphColor::AddSafepointsFor(HInstruction* instruction) {
+ LiveInterval* interval = instruction->GetLiveInterval();
+ for (size_t safepoint_index = safepoints_.size(); safepoint_index > 0; --safepoint_index) {
+ HInstruction* safepoint = safepoints_[safepoint_index - 1u];
+ size_t safepoint_position = safepoint->GetLifetimePosition();
+
+ // Test that safepoints_ are ordered in the optimal way.
+ DCHECK(safepoint_index == safepoints_.size() ||
+ safepoints_[safepoint_index]->GetLifetimePosition() < safepoint_position);
+
+ if (safepoint_position == interval->GetStart()) {
+ // The safepoint is for this instruction, so the location of the instruction
+ // does not need to be saved.
+ DCHECK_EQ(safepoint_index, safepoints_.size());
+ DCHECK_EQ(safepoint, instruction);
+ continue;
+ } else if (interval->IsDeadAt(safepoint_position)) {
+ break;
+ } else if (!interval->Covers(safepoint_position)) {
+ // Hole in the interval.
+ continue;
+ }
+ interval->AddSafepoint(safepoint);
+ }
+}
+
+void RegisterAllocatorGraphColor::CheckForTempLiveIntervals(HInstruction* instruction) {
+ LocationSummary* locations = instruction->GetLocations();
+ size_t position = instruction->GetLifetimePosition();
+ for (size_t i = 0; i < locations->GetTempCount(); ++i) {
+ Location temp = locations->GetTemp(i);
+ if (temp.IsRegister() || temp.IsFpuRegister()) {
+ BlockRegister(temp, position, position + 1);
+ codegen_->AddAllocatedRegister(temp);
+ } else {
+ DCHECK(temp.IsUnallocated());
+ switch (temp.GetPolicy()) {
+ case Location::kRequiresRegister: {
+ LiveInterval* interval =
+ LiveInterval::MakeTempInterval(allocator_, Primitive::kPrimInt);
+ interval->AddTempUse(instruction, i);
+ core_intervals_.push_back(interval);
+ temp_intervals_.push_back(interval);
+ break;
+ }
+
+ case Location::kRequiresFpuRegister: {
+ LiveInterval* interval =
+ LiveInterval::MakeTempInterval(allocator_, Primitive::kPrimDouble);
+ interval->AddTempUse(instruction, i);
+ fp_intervals_.push_back(interval);
+ temp_intervals_.push_back(interval);
+ if (codegen_->NeedsTwoRegisters(Primitive::kPrimDouble)) {
+ interval->AddHighInterval(/*is_temp*/ true);
+ temp_intervals_.push_back(interval->GetHighInterval());
+ }
+ break;
+ }
+
+ default:
+ LOG(FATAL) << "Unexpected policy for temporary location "
+ << temp.GetPolicy();
+ }
+ }
+ }
+}
+
+void RegisterAllocatorGraphColor::CheckForSafepoint(HInstruction* instruction) {
+ LocationSummary* locations = instruction->GetLocations();
+ size_t position = instruction->GetLifetimePosition();
+
+ if (locations->NeedsSafepoint()) {
+ safepoints_.push_back(instruction);
+ if (locations->OnlyCallsOnSlowPath()) {
+ // We add a synthesized range at this position to record the live registers
+ // at this position. Ideally, we could just update the safepoints when locations
+ // are updated, but we currently need to know the full stack size before updating
+ // locations (because of parameters and the fact that we don't have a frame pointer).
+ // And knowing the full stack size requires to know the maximum number of live
+ // registers at calls in slow paths.
+ // By adding the following interval in the algorithm, we can compute this
+ // maximum before updating locations.
+ LiveInterval* interval = LiveInterval::MakeSlowPathInterval(allocator_, instruction);
+ interval->AddRange(position, position + 1);
+ core_intervals_.push_back(interval);
+ fp_intervals_.push_back(interval);
+ }
+ }
+}
+
+LiveInterval* RegisterAllocatorGraphColor::TrySplit(LiveInterval* interval, size_t position) {
+ if (interval->GetStart() < position && position < interval->GetEnd()) {
+ return Split(interval, position);
+ } else {
+ return interval;
+ }
+}
+
+void RegisterAllocatorGraphColor::SplitAtRegisterUses(LiveInterval* interval) {
+ DCHECK(!interval->IsHighInterval());
+
+ // Split just after a register definition.
+ if (interval->IsParent() && interval->DefinitionRequiresRegister()) {
+ interval = TrySplit(interval, interval->GetStart() + 1);
+ }
+
+ UsePosition* use = interval->GetFirstUse();
+ while (use != nullptr && use->GetPosition() < interval->GetStart()) {
+ use = use->GetNext();
+ }
+
+ // Split around register uses.
+ size_t end = interval->GetEnd();
+ while (use != nullptr && use->GetPosition() <= end) {
+ if (use->RequiresRegister()) {
+ size_t position = use->GetPosition();
+ interval = TrySplit(interval, position - 1);
+ if (liveness_.GetInstructionFromPosition(position / 2)->IsControlFlow()) {
+ // If we are at the very end of a basic block, we cannot split right
+ // at the use. Split just after instead.
+ interval = TrySplit(interval, position + 1);
+ } else {
+ interval = TrySplit(interval, position);
+ }
+ }
+ use = use->GetNext();
+ }
+}
+
+void RegisterAllocatorGraphColor::AllocateSpillSlotForCatchPhi(HInstruction* instruction) {
+ if (instruction->IsPhi() && instruction->AsPhi()->IsCatchPhi()) {
+ HPhi* phi = instruction->AsPhi();
+ LiveInterval* interval = phi->GetLiveInterval();
+
+ HInstruction* previous_phi = phi->GetPrevious();
+ DCHECK(previous_phi == nullptr ||
+ previous_phi->AsPhi()->GetRegNumber() <= phi->GetRegNumber())
+ << "Phis expected to be sorted by vreg number, "
+ << "so that equivalent phis are adjacent.";
+
+ if (phi->IsVRegEquivalentOf(previous_phi)) {
+ // Assign the same spill slot.
+ DCHECK(previous_phi->GetLiveInterval()->HasSpillSlot());
+ interval->SetSpillSlot(previous_phi->GetLiveInterval()->GetSpillSlot());
+ } else {
+ interval->SetSpillSlot(catch_phi_spill_slot_counter_);
+ catch_phi_spill_slot_counter_ += interval->NeedsTwoSpillSlots() ? 2 : 1;
+ }
+ }
+}
+
+void RegisterAllocatorGraphColor::BlockRegister(Location location,
+ size_t start,
+ size_t end) {
+ DCHECK(location.IsRegister() || location.IsFpuRegister());
+ int reg = location.reg();
+ LiveInterval* interval = location.IsRegister()
+ ? physical_core_intervals_[reg]
+ : physical_fp_intervals_[reg];
+ DCHECK(interval->GetRegister() == reg);
+ bool blocked_by_codegen = location.IsRegister()
+ ? codegen_->IsBlockedCoreRegister(reg)
+ : codegen_->IsBlockedFloatingPointRegister(reg);
+ if (blocked_by_codegen) {
+ // We've already blocked this register for the entire method. (And adding a
+ // range inside another range violates the preconditions of AddRange).
+ } else {
+ interval->AddRange(start, end);
+ }
+}
+
+void RegisterAllocatorGraphColor::BlockRegisters(size_t start, size_t end, bool caller_save_only) {
+ for (size_t i = 0; i < codegen_->GetNumberOfCoreRegisters(); ++i) {
+ if (!caller_save_only || !codegen_->IsCoreCalleeSaveRegister(i)) {
+ BlockRegister(Location::RegisterLocation(i), start, end);
+ }
+ }
+ for (size_t i = 0; i < codegen_->GetNumberOfFloatingPointRegisters(); ++i) {
+ if (!caller_save_only || !codegen_->IsFloatingPointCalleeSaveRegister(i)) {
+ BlockRegister(Location::FpuRegisterLocation(i), start, end);
+ }
+ }
+}
+
+// Add an interference edge, but only if necessary.
+static void AddPotentialInterference(InterferenceNode* from, InterferenceNode* to) {
+ if (from->GetInterval()->HasRegister()) {
+ // We save space by ignoring outgoing edges from fixed nodes.
+ } else if (to->GetInterval()->IsSlowPathSafepoint()) {
+ // Safepoint intervals are only there to count max live registers,
+ // so no need to give them incoming interference edges.
+ // This is also necessary for correctness, because we don't want nodes
+ // to remove themselves from safepoint adjacency sets when they're pruned.
+ } else {
+ from->AddInterference(to);
+ }
+}
+
+// TODO: See locations->OutputCanOverlapWithInputs(); we may want to consider
+// this when building the interference graph.
+void RegisterAllocatorGraphColor::BuildInterferenceGraph(
+ const ArenaVector<LiveInterval*>& intervals,
+ ArenaVector<InterferenceNode*>* prunable_nodes,
+ ArenaVector<InterferenceNode*>* safepoints) {
+ size_t interval_id_counter = 0;
+
+ // Build the interference graph efficiently by ordering range endpoints
+ // by position and doing a linear sweep to find interferences. (That is, we
+ // jump from endpoint to endpoint, maintaining a set of intervals live at each
+ // point. If two nodes are ever in the live set at the same time, then they
+ // interfere with each other.)
+ //
+ // We order by both position and (secondarily) by whether the endpoint
+ // begins or ends a range; we want to process range endings before range
+ // beginnings at the same position because they should not conflict.
+ //
+ // For simplicity, we create a tuple for each endpoint, and then sort the tuples.
+ // Tuple contents: (position, is_range_beginning, node).
+ ArenaVector<std::tuple<size_t, bool, InterferenceNode*>> range_endpoints(
+ coloring_attempt_allocator_->Adapter(kArenaAllocRegisterAllocator));
+ for (LiveInterval* parent : intervals) {
+ for (LiveInterval* sibling = parent; sibling != nullptr; sibling = sibling->GetNextSibling()) {
+ LiveRange* range = sibling->GetFirstRange();
+ if (range != nullptr) {
+ InterferenceNode* node = new (coloring_attempt_allocator_) InterferenceNode(
+ coloring_attempt_allocator_, sibling, interval_id_counter++);
+ if (sibling->HasRegister()) {
+ // Fixed nodes will never be pruned, so no need to keep track of them.
+ } else if (sibling->IsSlowPathSafepoint()) {
+ // Safepoint intervals are synthesized to count max live registers.
+ // They will be processed separately after coloring.
+ safepoints->push_back(node);
+ } else {
+ prunable_nodes->push_back(node);
+ }
+
+ while (range != nullptr) {
+ range_endpoints.push_back(std::make_tuple(range->GetStart(), true, node));
+ range_endpoints.push_back(std::make_tuple(range->GetEnd(), false, node));
+ range = range->GetNext();
+ }
+ }
+ }
+ }
+
+ // Sort the endpoints.
+ std::sort(range_endpoints.begin(), range_endpoints.end());
+
+ // Nodes live at the current position in the linear sweep.
+ ArenaSet<InterferenceNode*, decltype(&InterferenceNode::CmpPtr)> live(
+ InterferenceNode::CmpPtr, coloring_attempt_allocator_->Adapter(kArenaAllocRegisterAllocator));
+
+ // Linear sweep. When we encounter the beginning of a range, we add the corresponding node to the
+ // live set. When we encounter the end of a range, we remove the corresponding node
+ // from the live set. Nodes interfere if they are in the live set at the same time.
+ for (auto it = range_endpoints.begin(); it != range_endpoints.end(); ++it) {
+ bool is_range_beginning;
+ InterferenceNode* node;
+ // Extract information from the tuple, including the node this tuple represents.
+ std::tie(std::ignore, is_range_beginning, node) = *it;
+
+ if (is_range_beginning) {
+ for (InterferenceNode* conflicting : live) {
+ DCHECK_NE(node, conflicting);
+ AddPotentialInterference(node, conflicting);
+ AddPotentialInterference(conflicting, node);
+ }
+ DCHECK_EQ(live.count(node), 0u);
+ live.insert(node);
+ } else {
+ // End of range.
+ DCHECK_EQ(live.count(node), 1u);
+ live.erase(node);
+ }
+ }
+ DCHECK(live.empty());
+}
+
+// The order in which we color nodes is vital to both correctness (forward
+// progress) and code quality. Specifically, we must prioritize intervals
+// that require registers, and after that we must prioritize short intervals.
+// That way, if we fail to color a node, it either won't require a register,
+// or it will be a long interval that can be split in order to make the
+// interference graph sparser.
+// TODO: May also want to consider:
+// - Loop depth
+// - Constants (since they can be rematerialized)
+// - Allocated spill slots
+static bool GreaterNodePriority(const InterferenceNode* lhs,
+ const InterferenceNode* rhs) {
+ LiveInterval* lhs_interval = lhs->GetInterval();
+ LiveInterval* rhs_interval = rhs->GetInterval();
+
+ // (1) Choose the interval that requires a register.
+ if (lhs_interval->RequiresRegister() != rhs_interval->RequiresRegister()) {
+ return lhs_interval->RequiresRegister();
+ }
+
+ // (2) Choose the interval that has a shorter life span.
+ if (lhs_interval->GetLength() != rhs_interval->GetLength()) {
+ return lhs_interval->GetLength() < rhs_interval->GetLength();
+ }
+
+ // (3) Just choose the interval based on a deterministic ordering.
+ return InterferenceNode::CmpPtr(lhs, rhs);
+}
+
+void RegisterAllocatorGraphColor::PruneInterferenceGraph(
+ const ArenaVector<InterferenceNode*>& prunable_nodes,
+ size_t num_regs,
+ ArenaStdStack<InterferenceNode*>* pruned_nodes) {
+ // When pruning the graph, we refer to nodes with degree less than num_regs as low degree nodes,
+ // and all others as high degree nodes. The distinction is important: low degree nodes are
+ // guaranteed a color, while high degree nodes are not.
+
+ // Low-degree nodes are guaranteed a color, so worklist order does not matter.
+ ArenaDeque<InterferenceNode*> low_degree_worklist(
+ coloring_attempt_allocator_->Adapter(kArenaAllocRegisterAllocator));
+
+ // If we have to prune from the high-degree worklist, we cannot guarantee
+ // the pruned node a color. So, we order the worklist by priority.
+ ArenaSet<InterferenceNode*, decltype(&GreaterNodePriority)> high_degree_worklist(
+ GreaterNodePriority, coloring_attempt_allocator_->Adapter(kArenaAllocRegisterAllocator));
+
+ // Build worklists.
+ for (InterferenceNode* node : prunable_nodes) {
+ DCHECK(!node->GetInterval()->HasRegister())
+ << "Fixed nodes should never be pruned";
+ DCHECK(!node->GetInterval()->IsSlowPathSafepoint())
+ << "Safepoint nodes should never be pruned";
+ if (node->GetOutDegree() < num_regs) {
+ low_degree_worklist.push_back(node);
+ } else {
+ high_degree_worklist.insert(node);
+ }
+ }
+
+ // Helper function to prune an interval from the interference graph,
+ // which includes updating the worklists.
+ auto prune_node = [this,
+ num_regs,
+ &pruned_nodes,
+ &low_degree_worklist,
+ &high_degree_worklist] (InterferenceNode* node) {
+ DCHECK(!node->GetInterval()->HasRegister());
+ pruned_nodes->push(node);
+ for (InterferenceNode* adjacent : node->GetAdjacentNodes()) {
+ DCHECK(!adjacent->GetInterval()->IsSlowPathSafepoint())
+ << "Nodes should never interfere with synthesized safepoint nodes";
+ if (adjacent->GetInterval()->HasRegister()) {
+ // No effect on pre-colored nodes; they're never pruned.
+ } else {
+ bool was_high_degree = adjacent->GetOutDegree() >= num_regs;
+ DCHECK(adjacent->ContainsInterference(node))
+ << "Missing incoming interference edge from non-fixed node";
+ adjacent->RemoveInterference(node);
+ if (was_high_degree && adjacent->GetOutDegree() < num_regs) {
+ // This is a transition from high degree to low degree.
+ DCHECK_EQ(high_degree_worklist.count(adjacent), 1u);
+ high_degree_worklist.erase(adjacent);
+ low_degree_worklist.push_back(adjacent);
+ }
+ }
+ }
+ };
+
+ // Prune graph.
+ while (!low_degree_worklist.empty() || !high_degree_worklist.empty()) {
+ while (!low_degree_worklist.empty()) {
+ InterferenceNode* node = low_degree_worklist.front();
+ // TODO: pop_back() should work as well, but it doesn't; we get a
+ // failed check while pruning. We should look into this.
+ low_degree_worklist.pop_front();
+ prune_node(node);
+ }
+ if (!high_degree_worklist.empty()) {
+ // We prune the lowest-priority node, because pruning a node earlier
+ // gives it a higher chance of being spilled.
+ InterferenceNode* node = *high_degree_worklist.rbegin();
+ high_degree_worklist.erase(node);
+ prune_node(node);
+ }
+ }
+}
+
+// Build a mask with a bit set for each register assigned to some
+// interval in `intervals`.
+template <typename Container>
+static std::bitset<kMaxNumRegs> BuildConflictMask(Container& intervals) {
+ std::bitset<kMaxNumRegs> conflict_mask;
+ for (InterferenceNode* adjacent : intervals) {
+ LiveInterval* conflicting = adjacent->GetInterval();
+ if (conflicting->HasRegister()) {
+ conflict_mask.set(conflicting->GetRegister());
+ if (conflicting->HasHighInterval()) {
+ DCHECK(conflicting->GetHighInterval()->HasRegister());
+ conflict_mask.set(conflicting->GetHighInterval()->GetRegister());
+ }
+ } else {
+ DCHECK(!conflicting->HasHighInterval()
+ || !conflicting->GetHighInterval()->HasRegister());
+ }
+ }
+ return conflict_mask;
+}
+
+bool RegisterAllocatorGraphColor::ColorInterferenceGraph(
+ ArenaStdStack<InterferenceNode*>* pruned_nodes,
+ size_t num_regs) {
+ DCHECK_LE(num_regs, kMaxNumRegs) << "kMaxNumRegs is too small";
+ ArenaVector<LiveInterval*> colored_intervals(
+ coloring_attempt_allocator_->Adapter(kArenaAllocRegisterAllocator));
+ bool successful = true;
+
+ while (!pruned_nodes->empty()) {
+ InterferenceNode* node = pruned_nodes->top();
+ pruned_nodes->pop();
+ LiveInterval* interval = node->GetInterval();
+
+ // Search for free register(s).
+ // Note that the graph coloring allocator assumes that pair intervals are aligned here,
+ // excluding pre-colored pair intervals (which can currently be unaligned on x86).
+ std::bitset<kMaxNumRegs> conflict_mask = BuildConflictMask(node->GetAdjacentNodes());
+ size_t reg = 0;
+ if (interval->HasHighInterval()) {
+ while (reg < num_regs - 1 && (conflict_mask[reg] || conflict_mask[reg + 1])) {
+ reg += 2;
+ }
+ } else {
+ // We use CTZ (count trailing zeros) to quickly find the lowest available register.
+ // Note that CTZ is undefined for 0, so we special-case it.
+ reg = conflict_mask.all() ? conflict_mask.size() : CTZ(~conflict_mask.to_ulong());
+ }
+
+ if (reg < (interval->HasHighInterval() ? num_regs - 1 : num_regs)) {
+ // Assign register.
+ DCHECK(!interval->HasRegister());
+ interval->SetRegister(reg);
+ colored_intervals.push_back(interval);
+ if (interval->HasHighInterval()) {
+ DCHECK(!interval->GetHighInterval()->HasRegister());
+ interval->GetHighInterval()->SetRegister(reg + 1);
+ colored_intervals.push_back(interval->GetHighInterval());
+ }
+ } else if (interval->RequiresRegister()) {
+ // The interference graph is too dense to color. Make it sparser by
+ // splitting this live interval.
+ successful = false;
+ SplitAtRegisterUses(interval);
+ // We continue coloring, because there may be additional intervals that cannot
+ // be colored, and that we should split.
+ } else {
+ // Spill.
+ AllocateSpillSlotFor(interval);
+ }
+ }
+
+ // If unsuccessful, reset all register assignments.
+ if (!successful) {
+ for (LiveInterval* interval : colored_intervals) {
+ interval->ClearRegister();
+ }
+ }
+
+ return successful;
+}
+
+size_t RegisterAllocatorGraphColor::ComputeMaxSafepointLiveRegisters(
+ const ArenaVector<InterferenceNode*>& safepoints) {
+ size_t max_safepoint_live_regs = 0;
+ for (InterferenceNode* safepoint : safepoints) {
+ DCHECK(safepoint->GetInterval()->IsSlowPathSafepoint());
+ std::bitset<kMaxNumRegs> conflict_mask = BuildConflictMask(safepoint->GetAdjacentNodes());
+ size_t live_regs = conflict_mask.count();
+ max_safepoint_live_regs = std::max(max_safepoint_live_regs, live_regs);
+ }
+ return max_safepoint_live_regs;
+}
+
+void RegisterAllocatorGraphColor::AllocateSpillSlotFor(LiveInterval* interval) {
+ LiveInterval* parent = interval->GetParent();
+ HInstruction* defined_by = parent->GetDefinedBy();
+ if (parent->HasSpillSlot()) {
+ // We already have a spill slot for this value that we can reuse.
+ } else if (defined_by->IsParameterValue()) {
+ // Parameters already have a stack slot.
+ parent->SetSpillSlot(codegen_->GetStackSlotOfParameter(defined_by->AsParameterValue()));
+ } else if (defined_by->IsCurrentMethod()) {
+ // The current method is always at spill slot 0.
+ parent->SetSpillSlot(0);
+ } else if (defined_by->IsConstant()) {
+ // Constants don't need a spill slot.
+ } else {
+ // Allocate a spill slot based on type.
+ size_t* spill_slot_counter;
+ switch (interval->GetType()) {
+ case Primitive::kPrimDouble:
+ spill_slot_counter = &double_spill_slot_counter_;
+ break;
+ case Primitive::kPrimLong:
+ spill_slot_counter = &long_spill_slot_counter_;
+ break;
+ case Primitive::kPrimFloat:
+ spill_slot_counter = &float_spill_slot_counter_;
+ break;
+ case Primitive::kPrimNot:
+ case Primitive::kPrimInt:
+ case Primitive::kPrimChar:
+ case Primitive::kPrimByte:
+ case Primitive::kPrimBoolean:
+ case Primitive::kPrimShort:
+ spill_slot_counter = &int_spill_slot_counter_;
+ break;
+ case Primitive::kPrimVoid:
+ LOG(FATAL) << "Unexpected type for interval " << interval->GetType();
+ UNREACHABLE();
+ }
+
+ parent->SetSpillSlot(*spill_slot_counter);
+ *spill_slot_counter += parent->NeedsTwoSpillSlots() ? 2 : 1;
+ // TODO: Could color stack slots if we wanted to, even if
+ // it's just a trivial coloring. See the linear scan implementation,
+ // which simply reuses spill slots for values whose live intervals
+ // have already ended.
+ }
+}
+
+} // namespace art
diff --git a/compiler/optimizing/register_allocator_graph_color.h b/compiler/optimizing/register_allocator_graph_color.h
new file mode 100644
index 0000000..0b5af96
--- /dev/null
+++ b/compiler/optimizing/register_allocator_graph_color.h
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_COMPILER_OPTIMIZING_REGISTER_ALLOCATOR_GRAPH_COLOR_H_
+#define ART_COMPILER_OPTIMIZING_REGISTER_ALLOCATOR_GRAPH_COLOR_H_
+
+#include "arch/instruction_set.h"
+#include "base/arena_containers.h"
+#include "base/arena_object.h"
+#include "base/macros.h"
+#include "primitive.h"
+#include "register_allocator.h"
+
+namespace art {
+
+class CodeGenerator;
+class HBasicBlock;
+class HGraph;
+class HInstruction;
+class HParallelMove;
+class Location;
+class SsaLivenessAnalysis;
+class InterferenceNode;
+
+/**
+ * A graph coloring register allocator.
+ *
+ * The algorithm proceeds as follows:
+ * (1) Build an interference graph, where nodes represent live intervals, and edges represent
+ * interferences between two intervals. Coloring this graph with k colors is isomorphic to
+ * finding a valid register assignment with k registers.
+ * (2) To color the graph, first prune all nodes with degree less than k, since these nodes are
+ * guaranteed a color. (No matter how we color their adjacent nodes, we can give them a
+ * different color.) As we prune nodes from the graph, more nodes may drop below degree k,
+ * enabling further pruning. The key is to maintain the pruning order in a stack, so that we
+ * can color the nodes in the reverse order.
+ * When there are no more nodes with degree less than k, we start pruning alternate nodes based
+ * on heuristics. Since these nodes are not guaranteed a color, we are careful to
+ * prioritize nodes that require a register. We also prioritize short intervals, because
+ * short intervals cannot be split very much if coloring fails (see below). "Prioritizing"
+ * a node amounts to pruning it later, since it will have fewer interferences if we prune other
+ * nodes first.
+ * (3) We color nodes in the reverse order in which we pruned them. If we cannot assign
+ * a node a color, we do one of two things:
+ * - If the node requires a register, we consider the current coloring attempt a failure.
+ * However, we split the node's live interval in order to make the interference graph
+ * sparser, so that future coloring attempts may succeed.
+ * - If the node does not require a register, we simply assign it a location on the stack.
+ *
+ * A good reference for graph coloring register allocation is
+ * "Modern Compiler Implementation in Java" (Andrew W. Appel, 2nd Edition).
+ */
+class RegisterAllocatorGraphColor : public RegisterAllocator {
+ public:
+ RegisterAllocatorGraphColor(ArenaAllocator* allocator,
+ CodeGenerator* codegen,
+ const SsaLivenessAnalysis& analysis);
+ ~RegisterAllocatorGraphColor() OVERRIDE {}
+
+ void AllocateRegisters() OVERRIDE;
+
+ bool Validate(bool log_fatal_on_failure);
+
+ private:
+ // Collect all intervals and prepare for register allocation.
+ void ProcessInstructions();
+ void ProcessInstruction(HInstruction* instruction);
+
+ // If any inputs require specific registers, block those registers
+ // at the position of this instruction.
+ void CheckForFixedInputs(HInstruction* instruction);
+
+ // If the output of an instruction requires a specific register, split
+ // the interval and assign the register to the first part.
+ void CheckForFixedOutput(HInstruction* instruction);
+
+ // Add all applicable safepoints to a live interval.
+ // Currently depends on instruction processing order.
+ void AddSafepointsFor(HInstruction* instruction);
+
+ // Collect all live intervals associated with the temporary locations
+ // needed by an instruction.
+ void CheckForTempLiveIntervals(HInstruction* instruction);
+
+ // If a safe point is needed, add a synthesized interval to later record
+ // the number of live registers at this point.
+ void CheckForSafepoint(HInstruction* instruction);
+
+ // Split an interval, but only if `position` is inside of `interval`.
+ // Return either the new interval, or the original interval if not split.
+ static LiveInterval* TrySplit(LiveInterval* interval, size_t position);
+
+ // To ensure every graph can be colored, split live intervals
+ // at their register defs and uses. This creates short intervals with low
+ // degree in the interference graph, which are prioritized during graph
+ // coloring.
+ void SplitAtRegisterUses(LiveInterval* interval);
+
+ // If the given instruction is a catch phi, give it a spill slot.
+ void AllocateSpillSlotForCatchPhi(HInstruction* instruction);
+
+ // Ensure that the given register cannot be allocated for a given range.
+ void BlockRegister(Location location, size_t start, size_t end);
+ void BlockRegisters(size_t start, size_t end, bool caller_save_only = false);
+
+ // Use the intervals collected from instructions to construct an
+ // interference graph mapping intervals to adjacency lists.
+ // Also, collect synthesized safepoint nodes, used to keep
+ // track of live intervals across safepoints.
+ void BuildInterferenceGraph(const ArenaVector<LiveInterval*>& intervals,
+ ArenaVector<InterferenceNode*>* prunable_nodes,
+ ArenaVector<InterferenceNode*>* safepoints);
+
+ // Prune nodes from the interference graph to be colored later. Build
+ // a stack (pruned_nodes) containing these intervals in an order determined
+ // by various heuristics.
+ void PruneInterferenceGraph(const ArenaVector<InterferenceNode*>& prunable_nodes,
+ size_t num_registers,
+ ArenaStdStack<InterferenceNode*>* pruned_nodes);
+
+ // Process pruned_intervals to color the interference graph, spilling when
+ // necessary. Return true if successful. Else, split some intervals to make
+ // the interference graph sparser.
+ bool ColorInterferenceGraph(ArenaStdStack<InterferenceNode*>* pruned_nodes,
+ size_t num_registers);
+
+ // Return the maximum number of registers live at safepoints,
+ // based on the outgoing interference edges of safepoint nodes.
+ size_t ComputeMaxSafepointLiveRegisters(const ArenaVector<InterferenceNode*>& safepoints);
+
+ // If necessary, add the given interval to the list of spilled intervals,
+ // and make sure it's ready to be spilled to the stack.
+ void AllocateSpillSlotFor(LiveInterval* interval);
+
+ // Live intervals, split by kind (core and floating point).
+ // These should not contain high intervals, as those are represented by
+ // the corresponding low interval throughout register allocation.
+ ArenaVector<LiveInterval*> core_intervals_;
+ ArenaVector<LiveInterval*> fp_intervals_;
+
+ // Intervals for temporaries, saved for special handling in the resolution phase.
+ ArenaVector<LiveInterval*> temp_intervals_;
+
+ // Safepoints, saved for special handling while processing instructions.
+ ArenaVector<HInstruction*> safepoints_;
+
+ // Live intervals for specific registers. These become pre-colored nodes
+ // in the interference graph.
+ ArenaVector<LiveInterval*> physical_core_intervals_;
+ ArenaVector<LiveInterval*> physical_fp_intervals_;
+
+ // Allocated stack slot counters.
+ size_t int_spill_slot_counter_;
+ size_t double_spill_slot_counter_;
+ size_t float_spill_slot_counter_;
+ size_t long_spill_slot_counter_;
+ size_t catch_phi_spill_slot_counter_;
+
+ // Number of stack slots needed for the pointer to the current method.
+ // This is 1 for 32-bit architectures, and 2 for 64-bit architectures.
+ const size_t reserved_art_method_slots_;
+
+ // Number of stack slots needed for outgoing arguments.
+ const size_t reserved_out_slots_;
+
+ // The number of globally blocked core and floating point registers, such as the stack pointer.
+ size_t number_of_globally_blocked_core_regs_;
+ size_t number_of_globally_blocked_fp_regs_;
+
+ // The maximum number of registers live at safe points. Needed by the code generator.
+ size_t max_safepoint_live_core_regs_;
+ size_t max_safepoint_live_fp_regs_;
+
+ // An arena allocator used for a single graph coloring attempt.
+ // Many data structures are cleared between graph coloring attempts, so we reduce
+ // total memory usage by using a new arena allocator for each attempt.
+ ArenaAllocator* coloring_attempt_allocator_;
+
+ DISALLOW_COPY_AND_ASSIGN(RegisterAllocatorGraphColor);
+};
+
+} // namespace art
+
+#endif // ART_COMPILER_OPTIMIZING_REGISTER_ALLOCATOR_GRAPH_COLOR_H_
diff --git a/compiler/optimizing/register_allocator_linear_scan.h b/compiler/optimizing/register_allocator_linear_scan.h
index b6e4f92..1a643a0 100644
--- a/compiler/optimizing/register_allocator_linear_scan.h
+++ b/compiler/optimizing/register_allocator_linear_scan.h
@@ -43,6 +43,7 @@
RegisterAllocatorLinearScan(ArenaAllocator* allocator,
CodeGenerator* codegen,
const SsaLivenessAnalysis& analysis);
+ ~RegisterAllocatorLinearScan() OVERRIDE {}
void AllocateRegisters() OVERRIDE;
diff --git a/compiler/optimizing/register_allocator_test.cc b/compiler/optimizing/register_allocator_test.cc
index cbb7b2f..55ea99e 100644
--- a/compiler/optimizing/register_allocator_test.cc
+++ b/compiler/optimizing/register_allocator_test.cc
@@ -31,12 +31,29 @@
namespace art {
+using Strategy = RegisterAllocator::Strategy;
+
// Note: the register allocator tests rely on the fact that constants have live
// intervals and registers get allocated to them.
-class RegisterAllocatorTest : public CommonCompilerTest {};
+class RegisterAllocatorTest : public CommonCompilerTest {
+ protected:
+ // These functions need to access private variables of LocationSummary, so we declare it
+ // as a member of RegisterAllocatorTest, which we make a friend class.
+ static void SameAsFirstInputHint(Strategy strategy);
+ static void ExpectedInRegisterHint(Strategy strategy);
+};
-static bool Check(const uint16_t* data) {
+// This macro should include all register allocation strategies that should be tested.
+#define TEST_ALL_STRATEGIES(test_name)\
+TEST_F(RegisterAllocatorTest, test_name##_LinearScan) {\
+ test_name(Strategy::kRegisterAllocatorLinearScan);\
+}\
+TEST_F(RegisterAllocatorTest, test_name##_GraphColor) {\
+ test_name(Strategy::kRegisterAllocatorGraphColor);\
+}
+
+static bool Check(const uint16_t* data, Strategy strategy) {
ArenaPool pool;
ArenaAllocator allocator(&pool);
HGraph* graph = CreateCFG(&allocator, data);
@@ -45,7 +62,8 @@
x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
SsaLivenessAnalysis liveness(graph, &codegen);
liveness.Analyze();
- RegisterAllocator* register_allocator = RegisterAllocator::Create(&allocator, &codegen, liveness);
+ RegisterAllocator* register_allocator =
+ RegisterAllocator::Create(&allocator, &codegen, liveness, strategy);
register_allocator->AllocateRegisters();
return register_allocator->Validate(false);
}
@@ -143,7 +161,7 @@
}
}
-TEST_F(RegisterAllocatorTest, CFG1) {
+static void CFG1(Strategy strategy) {
/*
* Test the following snippet:
* return 0;
@@ -160,10 +178,12 @@
Instruction::CONST_4 | 0 | 0,
Instruction::RETURN);
- ASSERT_TRUE(Check(data));
+ ASSERT_TRUE(Check(data, strategy));
}
-TEST_F(RegisterAllocatorTest, Loop1) {
+TEST_ALL_STRATEGIES(CFG1);
+
+static void Loop1(Strategy strategy) {
/*
* Test the following snippet:
* int a = 0;
@@ -199,10 +219,12 @@
Instruction::CONST_4 | 5 << 12 | 1 << 8,
Instruction::RETURN | 1 << 8);
- ASSERT_TRUE(Check(data));
+ ASSERT_TRUE(Check(data, strategy));
}
-TEST_F(RegisterAllocatorTest, Loop2) {
+TEST_ALL_STRATEGIES(Loop1);
+
+static void Loop2(Strategy strategy) {
/*
* Test the following snippet:
* int a = 0;
@@ -248,10 +270,12 @@
Instruction::ADD_INT, 1 << 8 | 0,
Instruction::RETURN | 1 << 8);
- ASSERT_TRUE(Check(data));
+ ASSERT_TRUE(Check(data, strategy));
}
-TEST_F(RegisterAllocatorTest, Loop3) {
+TEST_ALL_STRATEGIES(Loop2);
+
+static void Loop3(Strategy strategy) {
/*
* Test the following snippet:
* int a = 0
@@ -296,7 +320,8 @@
x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
SsaLivenessAnalysis liveness(graph, &codegen);
liveness.Analyze();
- RegisterAllocator* register_allocator = RegisterAllocator::Create(&allocator, &codegen, liveness);
+ RegisterAllocator* register_allocator =
+ RegisterAllocator::Create(&allocator, &codegen, liveness, strategy);
register_allocator->AllocateRegisters();
ASSERT_TRUE(register_allocator->Validate(false));
@@ -314,6 +339,8 @@
ASSERT_EQ(phi_interval->GetRegister(), ret->InputAt(0)->GetLiveInterval()->GetRegister());
}
+TEST_ALL_STRATEGIES(Loop3);
+
TEST_F(RegisterAllocatorTest, FirstRegisterUse) {
const uint16_t data[] = THREE_REGISTERS_CODE_ITEM(
Instruction::CONST_4 | 0 | 0,
@@ -354,7 +381,7 @@
ASSERT_EQ(new_interval->FirstRegisterUse(), last_xor->GetLifetimePosition());
}
-TEST_F(RegisterAllocatorTest, DeadPhi) {
+static void DeadPhi(Strategy strategy) {
/* Test for a dead loop phi taking as back-edge input a phi that also has
* this loop phi as input. Walking backwards in SsaDeadPhiElimination
* does not solve the problem because the loop phi will be visited last.
@@ -385,15 +412,19 @@
x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
SsaLivenessAnalysis liveness(graph, &codegen);
liveness.Analyze();
- RegisterAllocator* register_allocator = RegisterAllocator::Create(&allocator, &codegen, liveness);
+ RegisterAllocator* register_allocator =
+ RegisterAllocator::Create(&allocator, &codegen, liveness, strategy);
register_allocator->AllocateRegisters();
ASSERT_TRUE(register_allocator->Validate(false));
}
+TEST_ALL_STRATEGIES(DeadPhi);
+
/**
* Test that the TryAllocateFreeReg method works in the presence of inactive intervals
* that share the same register. It should split the interval it is currently
* allocating for at the minimum lifetime position between the two inactive intervals.
+ * This test only applies to the linear scan allocator.
*/
TEST_F(RegisterAllocatorTest, FreeUntil) {
const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
@@ -507,15 +538,15 @@
graph->GetDexFile(),
dex_cache,
0);
-*input2 = new (allocator) HInstanceFieldGet(parameter,
- Primitive::kPrimInt,
- MemberOffset(42),
- false,
- kUnknownFieldIndex,
- kUnknownClassDefIndex,
- graph->GetDexFile(),
- dex_cache,
- 0);
+ *input2 = new (allocator) HInstanceFieldGet(parameter,
+ Primitive::kPrimInt,
+ MemberOffset(42),
+ false,
+ kUnknownFieldIndex,
+ kUnknownClassDefIndex,
+ graph->GetDexFile(),
+ dex_cache,
+ 0);
then->AddInstruction(*input1);
else_->AddInstruction(*input2);
join->AddInstruction(new (allocator) HExit());
@@ -527,7 +558,7 @@
return graph;
}
-TEST_F(RegisterAllocatorTest, PhiHint) {
+static void PhiHint(Strategy strategy) {
ArenaPool pool;
ArenaAllocator allocator(&pool);
HPhi *phi;
@@ -543,7 +574,7 @@
// Check that the register allocator is deterministic.
RegisterAllocator* register_allocator =
- RegisterAllocator::Create(&allocator, &codegen, liveness);
+ RegisterAllocator::Create(&allocator, &codegen, liveness, strategy);
register_allocator->AllocateRegisters();
ASSERT_EQ(input1->GetLiveInterval()->GetRegister(), 0);
@@ -563,7 +594,7 @@
// the same register.
phi->GetLocations()->UpdateOut(Location::RegisterLocation(2));
RegisterAllocator* register_allocator =
- RegisterAllocator::Create(&allocator, &codegen, liveness);
+ RegisterAllocator::Create(&allocator, &codegen, liveness, strategy);
register_allocator->AllocateRegisters();
ASSERT_EQ(input1->GetLiveInterval()->GetRegister(), 2);
@@ -583,7 +614,7 @@
// the same register.
input1->GetLocations()->UpdateOut(Location::RegisterLocation(2));
RegisterAllocator* register_allocator =
- RegisterAllocator::Create(&allocator, &codegen, liveness);
+ RegisterAllocator::Create(&allocator, &codegen, liveness, strategy);
register_allocator->AllocateRegisters();
ASSERT_EQ(input1->GetLiveInterval()->GetRegister(), 2);
@@ -603,7 +634,7 @@
// the same register.
input2->GetLocations()->UpdateOut(Location::RegisterLocation(2));
RegisterAllocator* register_allocator =
- RegisterAllocator::Create(&allocator, &codegen, liveness);
+ RegisterAllocator::Create(&allocator, &codegen, liveness, strategy);
register_allocator->AllocateRegisters();
ASSERT_EQ(input1->GetLiveInterval()->GetRegister(), 2);
@@ -612,6 +643,12 @@
}
}
+// TODO: Enable this test for graph coloring register allocation when iterative move
+// coalescing is merged.
+TEST_F(RegisterAllocatorTest, PhiHint_LinearScan) {
+ PhiHint(Strategy::kRegisterAllocatorLinearScan);
+}
+
static HGraph* BuildFieldReturn(ArenaAllocator* allocator,
HInstruction** field,
HInstruction** ret) {
@@ -650,7 +687,7 @@
return graph;
}
-TEST_F(RegisterAllocatorTest, ExpectedInRegisterHint) {
+void RegisterAllocatorTest::ExpectedInRegisterHint(Strategy strategy) {
ArenaPool pool;
ArenaAllocator allocator(&pool);
HInstruction *field, *ret;
@@ -664,7 +701,7 @@
liveness.Analyze();
RegisterAllocator* register_allocator =
- RegisterAllocator::Create(&allocator, &codegen, liveness);
+ RegisterAllocator::Create(&allocator, &codegen, liveness, strategy);
register_allocator->AllocateRegisters();
// Sanity check that in normal conditions, the register should be hinted to 0 (EAX).
@@ -684,13 +721,19 @@
ret->GetLocations()->inputs_[0] = Location::RegisterLocation(2);
RegisterAllocator* register_allocator =
- RegisterAllocator::Create(&allocator, &codegen, liveness);
+ RegisterAllocator::Create(&allocator, &codegen, liveness, strategy);
register_allocator->AllocateRegisters();
ASSERT_EQ(field->GetLiveInterval()->GetRegister(), 2);
}
}
+// TODO: Enable this test for graph coloring register allocation when iterative move
+// coalescing is merged.
+TEST_F(RegisterAllocatorTest, ExpectedInRegisterHint_LinearScan) {
+ ExpectedInRegisterHint(Strategy::kRegisterAllocatorLinearScan);
+}
+
static HGraph* BuildTwoSubs(ArenaAllocator* allocator,
HInstruction** first_sub,
HInstruction** second_sub) {
@@ -720,7 +763,7 @@
return graph;
}
-TEST_F(RegisterAllocatorTest, SameAsFirstInputHint) {
+void RegisterAllocatorTest::SameAsFirstInputHint(Strategy strategy) {
ArenaPool pool;
ArenaAllocator allocator(&pool);
HInstruction *first_sub, *second_sub;
@@ -734,7 +777,7 @@
liveness.Analyze();
RegisterAllocator* register_allocator =
- RegisterAllocator::Create(&allocator, &codegen, liveness);
+ RegisterAllocator::Create(&allocator, &codegen, liveness, strategy);
register_allocator->AllocateRegisters();
// Sanity check that in normal conditions, the registers are the same.
@@ -757,7 +800,7 @@
ASSERT_EQ(second_sub->GetLocations()->Out().GetPolicy(), Location::kSameAsFirstInput);
RegisterAllocator* register_allocator =
- RegisterAllocator::Create(&allocator, &codegen, liveness);
+ RegisterAllocator::Create(&allocator, &codegen, liveness, strategy);
register_allocator->AllocateRegisters();
ASSERT_EQ(first_sub->GetLiveInterval()->GetRegister(), 2);
@@ -765,6 +808,12 @@
}
}
+// TODO: Enable this test for graph coloring register allocation when iterative move
+// coalescing is merged.
+TEST_F(RegisterAllocatorTest, SameAsFirstInputHint_LinearScan) {
+ SameAsFirstInputHint(Strategy::kRegisterAllocatorLinearScan);
+}
+
static HGraph* BuildDiv(ArenaAllocator* allocator,
HInstruction** div) {
HGraph* graph = CreateGraph(allocator);
@@ -791,7 +840,7 @@
return graph;
}
-TEST_F(RegisterAllocatorTest, ExpectedExactInRegisterAndSameOutputHint) {
+static void ExpectedExactInRegisterAndSameOutputHint(Strategy strategy) {
ArenaPool pool;
ArenaAllocator allocator(&pool);
HInstruction *div;
@@ -805,7 +854,7 @@
liveness.Analyze();
RegisterAllocator* register_allocator =
- RegisterAllocator::Create(&allocator, &codegen, liveness);
+ RegisterAllocator::Create(&allocator, &codegen, liveness, strategy);
register_allocator->AllocateRegisters();
// div on x86 requires its first input in eax and the output be the same as the first input.
@@ -813,9 +862,16 @@
}
}
+// TODO: Enable this test for graph coloring register allocation when iterative move
+// coalescing is merged.
+TEST_F(RegisterAllocatorTest, ExpectedExactInRegisterAndSameOutputHint_LinearScan) {
+ ExpectedExactInRegisterAndSameOutputHint(Strategy::kRegisterAllocatorLinearScan);
+}
+
// Test a bug in the register allocator, where allocating a blocked
// register would lead to spilling an inactive interval at the wrong
// position.
+// This test only applies to the linear scan allocator.
TEST_F(RegisterAllocatorTest, SpillInactive) {
ArenaPool pool;
diff --git a/compiler/optimizing/ssa_liveness_analysis.cc b/compiler/optimizing/ssa_liveness_analysis.cc
index 7af4302..a01e107 100644
--- a/compiler/optimizing/ssa_liveness_analysis.cc
+++ b/compiler/optimizing/ssa_liveness_analysis.cc
@@ -368,6 +368,27 @@
return live_in->UnionIfNotIn(live_out, kill);
}
+void LiveInterval::DumpWithContext(std::ostream& stream,
+ const CodeGenerator& codegen) const {
+ Dump(stream);
+ if (IsFixed()) {
+ stream << ", register:" << GetRegister() << "(";
+ if (IsFloatingPoint()) {
+ codegen.DumpFloatingPointRegister(stream, GetRegister());
+ } else {
+ codegen.DumpCoreRegister(stream, GetRegister());
+ }
+ stream << ")";
+ } else {
+ stream << ", spill slot:" << GetSpillSlot();
+ }
+ stream << ", requires_register:" << (GetDefinedBy() != nullptr && RequiresRegister());
+ if (GetParent()->GetDefinedBy() != nullptr) {
+ stream << ", defined_by:" << GetParent()->GetDefinedBy()->GetKind();
+ stream << "(" << GetParent()->GetDefinedBy()->GetLifetimePosition() << ")";
+ }
+}
+
static int RegisterOrLowRegister(Location location) {
return location.IsPair() ? location.low() : location.reg();
}
diff --git a/compiler/optimizing/ssa_liveness_analysis.h b/compiler/optimizing/ssa_liveness_analysis.h
index dc98864..346753b 100644
--- a/compiler/optimizing/ssa_liveness_analysis.h
+++ b/compiler/optimizing/ssa_liveness_analysis.h
@@ -150,9 +150,7 @@
if (GetIsEnvironment()) return false;
if (IsSynthesized()) return false;
Location location = GetUser()->GetLocations()->InAt(GetInputIndex());
- return location.IsUnallocated()
- && (location.GetPolicy() == Location::kRequiresRegister
- || location.GetPolicy() == Location::kRequiresFpuRegister);
+ return location.IsUnallocated() && location.RequiresRegisterKind();
}
private:
@@ -481,6 +479,10 @@
return last_range_->GetEnd();
}
+ size_t GetLength() const {
+ return GetEnd() - GetStart();
+ }
+
size_t FirstRegisterUseAfter(size_t position) const {
if (is_temp_) {
return position == GetStart() ? position : kNoLifetime;
@@ -504,10 +506,16 @@
return kNoLifetime;
}
+ // Returns the location of the first register use for this live interval,
+ // including a register definition if applicable.
size_t FirstRegisterUse() const {
return FirstRegisterUseAfter(GetStart());
}
+ // Whether the interval requires a register rather than a stack location.
+ // If needed for performance, this could be cached.
+ bool RequiresRegister() const { return FirstRegisterUse() != kNoLifetime; }
+
size_t FirstUseAfter(size_t position) const {
if (is_temp_) {
return position == GetStart() ? position : kNoLifetime;
@@ -693,6 +701,10 @@
stream << " is_high: " << IsHighInterval();
}
+ // Same as Dump, but adds context such as the instruction defining this interval, and
+ // the register currently assigned to this interval.
+ void DumpWithContext(std::ostream& stream, const CodeGenerator& codegen) const;
+
LiveInterval* GetNextSibling() const { return next_sibling_; }
LiveInterval* GetLastSibling() {
LiveInterval* result = this;
@@ -871,6 +883,33 @@
range_search_start_ = first_range_;
}
+ bool DefinitionRequiresRegister() const {
+ DCHECK(IsParent());
+ LocationSummary* locations = defined_by_->GetLocations();
+ Location location = locations->Out();
+ // This interval is the first interval of the instruction. If the output
+ // of the instruction requires a register, we return the position of that instruction
+ // as the first register use.
+ if (location.IsUnallocated()) {
+ if ((location.GetPolicy() == Location::kRequiresRegister)
+ || (location.GetPolicy() == Location::kSameAsFirstInput
+ && (locations->InAt(0).IsRegister()
+ || locations->InAt(0).IsRegisterPair()
+ || locations->InAt(0).GetPolicy() == Location::kRequiresRegister))) {
+ return true;
+ } else if ((location.GetPolicy() == Location::kRequiresFpuRegister)
+ || (location.GetPolicy() == Location::kSameAsFirstInput
+ && (locations->InAt(0).IsFpuRegister()
+ || locations->InAt(0).IsFpuRegisterPair()
+ || locations->InAt(0).GetPolicy() == Location::kRequiresFpuRegister))) {
+ return true;
+ }
+ } else if (location.IsRegister() || location.IsRegisterPair()) {
+ return true;
+ }
+ return false;
+ }
+
private:
LiveInterval(ArenaAllocator* allocator,
Primitive::Type type,
@@ -925,33 +964,6 @@
return range;
}
- bool DefinitionRequiresRegister() const {
- DCHECK(IsParent());
- LocationSummary* locations = defined_by_->GetLocations();
- Location location = locations->Out();
- // This interval is the first interval of the instruction. If the output
- // of the instruction requires a register, we return the position of that instruction
- // as the first register use.
- if (location.IsUnallocated()) {
- if ((location.GetPolicy() == Location::kRequiresRegister)
- || (location.GetPolicy() == Location::kSameAsFirstInput
- && (locations->InAt(0).IsRegister()
- || locations->InAt(0).IsRegisterPair()
- || locations->InAt(0).GetPolicy() == Location::kRequiresRegister))) {
- return true;
- } else if ((location.GetPolicy() == Location::kRequiresFpuRegister)
- || (location.GetPolicy() == Location::kSameAsFirstInput
- && (locations->InAt(0).IsFpuRegister()
- || locations->InAt(0).IsFpuRegisterPair()
- || locations->InAt(0).GetPolicy() == Location::kRequiresFpuRegister))) {
- return true;
- }
- } else if (location.IsRegister() || location.IsRegisterPair()) {
- return true;
- }
- return false;
- }
-
bool IsDefiningPosition(size_t position) const {
return IsParent() && (position == GetStart());
}
diff --git a/compiler/utils/arm/assembler_arm.cc b/compiler/utils/arm/assembler_arm.cc
index 1796b39..aadc43f 100644
--- a/compiler/utils/arm/assembler_arm.cc
+++ b/compiler/utils/arm/assembler_arm.cc
@@ -568,15 +568,6 @@
StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value());
}
-void ArmAssembler::StoreImmediateToThread32(ThreadOffset32 dest,
- uint32_t imm,
- ManagedRegister mscratch) {
- ArmManagedRegister scratch = mscratch.AsArm();
- CHECK(scratch.IsCoreRegister()) << scratch;
- LoadImmediate(scratch.AsCoreRegister(), imm);
- StoreToOffset(kStoreWord, scratch.AsCoreRegister(), TR, dest.Int32Value());
-}
-
static void EmitLoad(ArmAssembler* assembler, ManagedRegister m_dst,
Register src_register, int32_t src_offset, size_t size) {
ArmManagedRegister dst = m_dst.AsArm();
@@ -601,19 +592,19 @@
return EmitLoad(this, m_dst, SP, src.Int32Value(), size);
}
-void ArmAssembler::LoadFromThread32(ManagedRegister m_dst, ThreadOffset32 src, size_t size) {
+void ArmAssembler::LoadFromThread(ManagedRegister m_dst, ThreadOffset32 src, size_t size) {
return EmitLoad(this, m_dst, TR, src.Int32Value(), size);
}
-void ArmAssembler::LoadRawPtrFromThread32(ManagedRegister m_dst, ThreadOffset32 offs) {
+void ArmAssembler::LoadRawPtrFromThread(ManagedRegister m_dst, ThreadOffset32 offs) {
ArmManagedRegister dst = m_dst.AsArm();
CHECK(dst.IsCoreRegister()) << dst;
LoadFromOffset(kLoadWord, dst.AsCoreRegister(), TR, offs.Int32Value());
}
-void ArmAssembler::CopyRawPtrFromThread32(FrameOffset fr_offs,
- ThreadOffset32 thr_offs,
- ManagedRegister mscratch) {
+void ArmAssembler::CopyRawPtrFromThread(FrameOffset fr_offs,
+ ThreadOffset32 thr_offs,
+ ManagedRegister mscratch) {
ArmManagedRegister scratch = mscratch.AsArm();
CHECK(scratch.IsCoreRegister()) << scratch;
LoadFromOffset(kLoadWord, scratch.AsCoreRegister(),
@@ -622,9 +613,9 @@
SP, fr_offs.Int32Value());
}
-void ArmAssembler::CopyRawPtrToThread32(ThreadOffset32 thr_offs,
- FrameOffset fr_offs,
- ManagedRegister mscratch) {
+void ArmAssembler::CopyRawPtrToThread(ThreadOffset32 thr_offs,
+ FrameOffset fr_offs,
+ ManagedRegister mscratch) {
ArmManagedRegister scratch = mscratch.AsArm();
CHECK(scratch.IsCoreRegister()) << scratch;
LoadFromOffset(kLoadWord, scratch.AsCoreRegister(),
@@ -633,9 +624,9 @@
TR, thr_offs.Int32Value());
}
-void ArmAssembler::StoreStackOffsetToThread32(ThreadOffset32 thr_offs,
- FrameOffset fr_offs,
- ManagedRegister mscratch) {
+void ArmAssembler::StoreStackOffsetToThread(ThreadOffset32 thr_offs,
+ FrameOffset fr_offs,
+ ManagedRegister mscratch) {
ArmManagedRegister scratch = mscratch.AsArm();
CHECK(scratch.IsCoreRegister()) << scratch;
AddConstant(scratch.AsCoreRegister(), SP, fr_offs.Int32Value(), AL);
@@ -643,7 +634,7 @@
TR, thr_offs.Int32Value());
}
-void ArmAssembler::StoreStackPointerToThread32(ThreadOffset32 thr_offs) {
+void ArmAssembler::StoreStackPointerToThread(ThreadOffset32 thr_offs) {
StoreToOffset(kStoreWord, SP, TR, thr_offs.Int32Value());
}
@@ -832,8 +823,8 @@
// TODO: place reference map on call
}
-void ArmAssembler::CallFromThread32(ThreadOffset32 offset ATTRIBUTE_UNUSED,
- ManagedRegister scratch ATTRIBUTE_UNUSED) {
+void ArmAssembler::CallFromThread(ThreadOffset32 offset ATTRIBUTE_UNUSED,
+ ManagedRegister scratch ATTRIBUTE_UNUSED) {
UNIMPLEMENTED(FATAL);
}
diff --git a/compiler/utils/arm/assembler_arm.h b/compiler/utils/arm/assembler_arm.h
index 2b7414d..bb88e6f 100644
--- a/compiler/utils/arm/assembler_arm.h
+++ b/compiler/utils/arm/assembler_arm.h
@@ -23,12 +23,14 @@
#include "base/arena_allocator.h"
#include "base/arena_containers.h"
#include "base/bit_utils.h"
+#include "base/enums.h"
#include "base/logging.h"
#include "base/stl_util.h"
#include "base/value_object.h"
#include "constants_arm.h"
#include "utils/arm/managed_register_arm.h"
#include "utils/assembler.h"
+#include "utils/jni_macro_assembler.h"
#include "offsets.h"
namespace art {
@@ -433,10 +435,19 @@
// This is an abstract ARM assembler. Subclasses provide assemblers for the individual
// instruction sets (ARM32, Thumb2, etc.)
//
-class ArmAssembler : public Assembler {
+class ArmAssembler : public Assembler, public JNIMacroAssembler<PointerSize::k32> {
public:
virtual ~ArmAssembler() {}
+ size_t CodeSize() const OVERRIDE { return Assembler::CodeSize(); }
+ DebugFrameOpCodeWriterForAssembler& cfi() { return Assembler::cfi(); }
+ void FinalizeCode() OVERRIDE {
+ Assembler::FinalizeCode();
+ }
+ void FinalizeInstructions(const MemoryRegion& region) {
+ Assembler::FinalizeInstructions(region);
+ }
+
// Is this assembler for the thumb instruction set?
virtual bool IsThumb() const = 0;
@@ -904,13 +915,11 @@
void StoreImmediateToFrame(FrameOffset dest, uint32_t imm, ManagedRegister scratch) OVERRIDE;
- void StoreImmediateToThread32(ThreadOffset32 dest, uint32_t imm, ManagedRegister scratch)
- OVERRIDE;
+ void StoreStackOffsetToThread(ThreadOffset32 thr_offs,
+ FrameOffset fr_offs,
+ ManagedRegister scratch) OVERRIDE;
- void StoreStackOffsetToThread32(ThreadOffset32 thr_offs, FrameOffset fr_offs,
- ManagedRegister scratch) OVERRIDE;
-
- void StoreStackPointerToThread32(ThreadOffset32 thr_offs) OVERRIDE;
+ void StoreStackPointerToThread(ThreadOffset32 thr_offs) OVERRIDE;
void StoreSpanning(FrameOffset dest, ManagedRegister src, FrameOffset in_off,
ManagedRegister scratch) OVERRIDE;
@@ -918,7 +927,7 @@
// Load routines
void Load(ManagedRegister dest, FrameOffset src, size_t size) OVERRIDE;
- void LoadFromThread32(ManagedRegister dest, ThreadOffset32 src, size_t size) OVERRIDE;
+ void LoadFromThread(ManagedRegister dest, ThreadOffset32 src, size_t size) OVERRIDE;
void LoadRef(ManagedRegister dest, FrameOffset src) OVERRIDE;
@@ -927,15 +936,16 @@
void LoadRawPtr(ManagedRegister dest, ManagedRegister base, Offset offs) OVERRIDE;
- void LoadRawPtrFromThread32(ManagedRegister dest, ThreadOffset32 offs) OVERRIDE;
+ void LoadRawPtrFromThread(ManagedRegister dest, ThreadOffset32 offs) OVERRIDE;
// Copying routines
void Move(ManagedRegister dest, ManagedRegister src, size_t size) OVERRIDE;
- void CopyRawPtrFromThread32(FrameOffset fr_offs, ThreadOffset32 thr_offs,
- ManagedRegister scratch) OVERRIDE;
+ void CopyRawPtrFromThread(FrameOffset fr_offs,
+ ThreadOffset32 thr_offs,
+ ManagedRegister scratch) OVERRIDE;
- void CopyRawPtrToThread32(ThreadOffset32 thr_offs, FrameOffset fr_offs, ManagedRegister scratch)
+ void CopyRawPtrToThread(ThreadOffset32 thr_offs, FrameOffset fr_offs, ManagedRegister scratch)
OVERRIDE;
void CopyRef(FrameOffset dest, FrameOffset src, ManagedRegister scratch) OVERRIDE;
@@ -990,7 +1000,7 @@
// Call to address held at [base+offset]
void Call(ManagedRegister base, Offset offset, ManagedRegister scratch) OVERRIDE;
void Call(FrameOffset base, Offset offset, ManagedRegister scratch) OVERRIDE;
- void CallFromThread32(ThreadOffset32 offset, ManagedRegister scratch) OVERRIDE;
+ void CallFromThread(ThreadOffset32 offset, ManagedRegister scratch) OVERRIDE;
// Generate code to check if Thread::Current()->exception_ is non-null
// and branch to a ExceptionSlowPath if it is.
diff --git a/compiler/utils/arm64/assembler_arm64.cc b/compiler/utils/arm64/assembler_arm64.cc
index dc1f24a..53685bf 100644
--- a/compiler/utils/arm64/assembler_arm64.cc
+++ b/compiler/utils/arm64/assembler_arm64.cc
@@ -164,25 +164,16 @@
offs.Int32Value());
}
-void Arm64Assembler::StoreImmediateToThread64(ThreadOffset64 offs,
- uint32_t imm,
+void Arm64Assembler::StoreStackOffsetToThread(ThreadOffset64 tr_offs,
+ FrameOffset fr_offs,
ManagedRegister m_scratch) {
Arm64ManagedRegister scratch = m_scratch.AsArm64();
CHECK(scratch.IsXRegister()) << scratch;
- LoadImmediate(scratch.AsXRegister(), imm);
- StoreToOffset(scratch.AsXRegister(), TR, offs.Int32Value());
-}
-
-void Arm64Assembler::StoreStackOffsetToThread64(ThreadOffset64 tr_offs,
- FrameOffset fr_offs,
- ManagedRegister m_scratch) {
- Arm64ManagedRegister scratch = m_scratch.AsArm64();
- CHECK(scratch.IsXRegister()) << scratch;
AddConstant(scratch.AsXRegister(), SP, fr_offs.Int32Value());
StoreToOffset(scratch.AsXRegister(), TR, tr_offs.Int32Value());
}
-void Arm64Assembler::StoreStackPointerToThread64(ThreadOffset64 tr_offs) {
+void Arm64Assembler::StoreStackPointerToThread(ThreadOffset64 tr_offs) {
UseScratchRegisterScope temps(&vixl_masm_);
Register temp = temps.AcquireX();
___ Mov(temp, reg_x(SP));
@@ -286,7 +277,7 @@
return Load(m_dst.AsArm64(), SP, src.Int32Value(), size);
}
-void Arm64Assembler::LoadFromThread64(ManagedRegister m_dst, ThreadOffset64 src, size_t size) {
+void Arm64Assembler::LoadFromThread(ManagedRegister m_dst, ThreadOffset64 src, size_t size) {
return Load(m_dst.AsArm64(), TR, src.Int32Value(), size);
}
@@ -319,7 +310,7 @@
___ Ldr(reg_x(dst.AsXRegister()), MEM_OP(reg_x(base.AsXRegister()), offs.Int32Value()));
}
-void Arm64Assembler::LoadRawPtrFromThread64(ManagedRegister m_dst, ThreadOffset64 offs) {
+void Arm64Assembler::LoadRawPtrFromThread(ManagedRegister m_dst, ThreadOffset64 offs) {
Arm64ManagedRegister dst = m_dst.AsArm64();
CHECK(dst.IsXRegister()) << dst;
LoadFromOffset(dst.AsXRegister(), TR, offs.Int32Value());
@@ -355,18 +346,18 @@
}
}
-void Arm64Assembler::CopyRawPtrFromThread64(FrameOffset fr_offs,
- ThreadOffset64 tr_offs,
- ManagedRegister m_scratch) {
+void Arm64Assembler::CopyRawPtrFromThread(FrameOffset fr_offs,
+ ThreadOffset64 tr_offs,
+ ManagedRegister m_scratch) {
Arm64ManagedRegister scratch = m_scratch.AsArm64();
CHECK(scratch.IsXRegister()) << scratch;
LoadFromOffset(scratch.AsXRegister(), TR, tr_offs.Int32Value());
StoreToOffset(scratch.AsXRegister(), SP, fr_offs.Int32Value());
}
-void Arm64Assembler::CopyRawPtrToThread64(ThreadOffset64 tr_offs,
- FrameOffset fr_offs,
- ManagedRegister m_scratch) {
+void Arm64Assembler::CopyRawPtrToThread(ThreadOffset64 tr_offs,
+ FrameOffset fr_offs,
+ ManagedRegister m_scratch) {
Arm64ManagedRegister scratch = m_scratch.AsArm64();
CHECK(scratch.IsXRegister()) << scratch;
LoadFromOffset(scratch.AsXRegister(), SP, fr_offs.Int32Value());
@@ -543,8 +534,8 @@
___ Blr(reg_x(scratch.AsXRegister()));
}
-void Arm64Assembler::CallFromThread64(ThreadOffset64 offset ATTRIBUTE_UNUSED,
- ManagedRegister scratch ATTRIBUTE_UNUSED) {
+void Arm64Assembler::CallFromThread(ThreadOffset64 offset ATTRIBUTE_UNUSED,
+ ManagedRegister scratch ATTRIBUTE_UNUSED) {
UNIMPLEMENTED(FATAL) << "Unimplemented Call() variant";
}
diff --git a/compiler/utils/arm64/assembler_arm64.h b/compiler/utils/arm64/assembler_arm64.h
index b8434b9..d7084da 100644
--- a/compiler/utils/arm64/assembler_arm64.h
+++ b/compiler/utils/arm64/assembler_arm64.h
@@ -22,9 +22,11 @@
#include <vector>
#include "base/arena_containers.h"
+#include "base/enums.h"
#include "base/logging.h"
#include "utils/arm64/managed_register_arm64.h"
#include "utils/assembler.h"
+#include "utils/jni_macro_assembler.h"
#include "offsets.h"
// TODO: make vixl clean wrt -Wshadow, -Wunknown-pragmas, -Wmissing-noreturn
@@ -81,7 +83,7 @@
DISALLOW_COPY_AND_ASSIGN(Arm64Exception);
};
-class Arm64Assembler FINAL : public Assembler {
+class Arm64Assembler FINAL : public Assembler, public JNIMacroAssembler<PointerSize::k64> {
public:
explicit Arm64Assembler(ArenaAllocator* arena)
: Assembler(arena),
@@ -91,6 +93,8 @@
vixl::aarch64::MacroAssembler* GetVIXLAssembler() { return &vixl_masm_; }
+ DebugFrameOpCodeWriterForAssembler& cfi() { return Assembler::cfi(); }
+
// Finalize the code.
void FinalizeCode() OVERRIDE;
@@ -122,28 +126,28 @@
void StoreRef(FrameOffset dest, ManagedRegister src) OVERRIDE;
void StoreRawPtr(FrameOffset dest, ManagedRegister src) OVERRIDE;
void StoreImmediateToFrame(FrameOffset dest, uint32_t imm, ManagedRegister scratch) OVERRIDE;
- void StoreImmediateToThread64(ThreadOffset64 dest, uint32_t imm, ManagedRegister scratch)
- OVERRIDE;
- void StoreStackOffsetToThread64(ThreadOffset64 thr_offs, FrameOffset fr_offs,
- ManagedRegister scratch) OVERRIDE;
- void StoreStackPointerToThread64(ThreadOffset64 thr_offs) OVERRIDE;
+ void StoreStackOffsetToThread(ThreadOffset64 thr_offs,
+ FrameOffset fr_offs,
+ ManagedRegister scratch) OVERRIDE;
+ void StoreStackPointerToThread(ThreadOffset64 thr_offs) OVERRIDE;
void StoreSpanning(FrameOffset dest, ManagedRegister src, FrameOffset in_off,
ManagedRegister scratch) OVERRIDE;
// Load routines.
void Load(ManagedRegister dest, FrameOffset src, size_t size) OVERRIDE;
- void LoadFromThread64(ManagedRegister dest, ThreadOffset64 src, size_t size) OVERRIDE;
+ void LoadFromThread(ManagedRegister dest, ThreadOffset64 src, size_t size) OVERRIDE;
void LoadRef(ManagedRegister dest, FrameOffset src) OVERRIDE;
void LoadRef(ManagedRegister dest, ManagedRegister base, MemberOffset offs,
bool unpoison_reference) OVERRIDE;
void LoadRawPtr(ManagedRegister dest, ManagedRegister base, Offset offs) OVERRIDE;
- void LoadRawPtrFromThread64(ManagedRegister dest, ThreadOffset64 offs) OVERRIDE;
+ void LoadRawPtrFromThread(ManagedRegister dest, ThreadOffset64 offs) OVERRIDE;
// Copying routines.
void Move(ManagedRegister dest, ManagedRegister src, size_t size) OVERRIDE;
- void CopyRawPtrFromThread64(FrameOffset fr_offs, ThreadOffset64 thr_offs,
- ManagedRegister scratch) OVERRIDE;
- void CopyRawPtrToThread64(ThreadOffset64 thr_offs, FrameOffset fr_offs, ManagedRegister scratch)
+ void CopyRawPtrFromThread(FrameOffset fr_offs,
+ ThreadOffset64 thr_offs,
+ ManagedRegister scratch) OVERRIDE;
+ void CopyRawPtrToThread(ThreadOffset64 thr_offs, FrameOffset fr_offs, ManagedRegister scratch)
OVERRIDE;
void CopyRef(FrameOffset dest, FrameOffset src, ManagedRegister scratch) OVERRIDE;
void Copy(FrameOffset dest, FrameOffset src, ManagedRegister scratch, size_t size) OVERRIDE;
@@ -196,7 +200,7 @@
// Call to address held at [base+offset].
void Call(ManagedRegister base, Offset offset, ManagedRegister scratch) OVERRIDE;
void Call(FrameOffset base, Offset offset, ManagedRegister scratch) OVERRIDE;
- void CallFromThread64(ThreadOffset64 offset, ManagedRegister scratch) OVERRIDE;
+ void CallFromThread(ThreadOffset64 offset, ManagedRegister scratch) OVERRIDE;
// Jump to address (not setting link register)
void JumpTo(ManagedRegister m_base, Offset offs, ManagedRegister m_scratch);
diff --git a/compiler/utils/assembler.cc b/compiler/utils/assembler.cc
index 0a1b733..81159e6 100644
--- a/compiler/utils/assembler.cc
+++ b/compiler/utils/assembler.cc
@@ -121,137 +121,4 @@
}
}
-std::unique_ptr<Assembler> Assembler::Create(
- ArenaAllocator* arena,
- InstructionSet instruction_set,
- const InstructionSetFeatures* instruction_set_features) {
- switch (instruction_set) {
-#ifdef ART_ENABLE_CODEGEN_arm
- case kArm:
- return std::unique_ptr<Assembler>(new (arena) arm::Arm32Assembler(arena));
- case kThumb2:
- return std::unique_ptr<Assembler>(new (arena) arm::Thumb2Assembler(arena));
-#endif
-#ifdef ART_ENABLE_CODEGEN_arm64
- case kArm64:
- return std::unique_ptr<Assembler>(new (arena) arm64::Arm64Assembler(arena));
-#endif
-#ifdef ART_ENABLE_CODEGEN_mips
- case kMips:
- return std::unique_ptr<Assembler>(new (arena) mips::MipsAssembler(
- arena,
- instruction_set_features != nullptr
- ? instruction_set_features->AsMipsInstructionSetFeatures()
- : nullptr));
-#endif
-#ifdef ART_ENABLE_CODEGEN_mips64
- case kMips64:
- return std::unique_ptr<Assembler>(new (arena) mips64::Mips64Assembler(arena));
-#endif
-#ifdef ART_ENABLE_CODEGEN_x86
- case kX86:
- return std::unique_ptr<Assembler>(new (arena) x86::X86Assembler(arena));
-#endif
-#ifdef ART_ENABLE_CODEGEN_x86_64
- case kX86_64:
- return std::unique_ptr<Assembler>(new (arena) x86_64::X86_64Assembler(arena));
-#endif
- default:
- LOG(FATAL) << "Unknown InstructionSet: " << instruction_set;
- return nullptr;
- }
-}
-
-void Assembler::StoreImmediateToThread32(ThreadOffset32 dest ATTRIBUTE_UNUSED,
- uint32_t imm ATTRIBUTE_UNUSED,
- ManagedRegister scratch ATTRIBUTE_UNUSED) {
- UNIMPLEMENTED(FATAL);
-}
-
-void Assembler::StoreImmediateToThread64(ThreadOffset64 dest ATTRIBUTE_UNUSED,
- uint32_t imm ATTRIBUTE_UNUSED,
- ManagedRegister scratch ATTRIBUTE_UNUSED) {
- UNIMPLEMENTED(FATAL);
-}
-
-void Assembler::StoreStackOffsetToThread32(
- ThreadOffset32 thr_offs ATTRIBUTE_UNUSED,
- FrameOffset fr_offs ATTRIBUTE_UNUSED,
- ManagedRegister scratch ATTRIBUTE_UNUSED) {
- UNIMPLEMENTED(FATAL);
-}
-
-void Assembler::StoreStackOffsetToThread64(
- ThreadOffset64 thr_offs ATTRIBUTE_UNUSED,
- FrameOffset fr_offs ATTRIBUTE_UNUSED,
- ManagedRegister scratch ATTRIBUTE_UNUSED) {
- UNIMPLEMENTED(FATAL);
-}
-
-void Assembler::StoreStackPointerToThread32(
- ThreadOffset32 thr_offs ATTRIBUTE_UNUSED) {
- UNIMPLEMENTED(FATAL);
-}
-
-void Assembler::StoreStackPointerToThread64(
- ThreadOffset64 thr_offs ATTRIBUTE_UNUSED) {
- UNIMPLEMENTED(FATAL);
-}
-
-void Assembler::LoadFromThread32(ManagedRegister dest ATTRIBUTE_UNUSED,
- ThreadOffset32 src ATTRIBUTE_UNUSED,
- size_t size ATTRIBUTE_UNUSED) {
- UNIMPLEMENTED(FATAL);
-}
-
-void Assembler::LoadFromThread64(ManagedRegister dest ATTRIBUTE_UNUSED,
- ThreadOffset64 src ATTRIBUTE_UNUSED,
- size_t size ATTRIBUTE_UNUSED) {
- UNIMPLEMENTED(FATAL);
-}
-
-void Assembler::LoadRawPtrFromThread32(ManagedRegister dest ATTRIBUTE_UNUSED,
- ThreadOffset32 offs ATTRIBUTE_UNUSED) {
- UNIMPLEMENTED(FATAL);
-}
-
-void Assembler::LoadRawPtrFromThread64(ManagedRegister dest ATTRIBUTE_UNUSED,
- ThreadOffset64 offs ATTRIBUTE_UNUSED) {
- UNIMPLEMENTED(FATAL);
-}
-
-void Assembler::CopyRawPtrFromThread32(FrameOffset fr_offs ATTRIBUTE_UNUSED,
- ThreadOffset32 thr_offs ATTRIBUTE_UNUSED,
- ManagedRegister scratch ATTRIBUTE_UNUSED) {
- UNIMPLEMENTED(FATAL);
-}
-
-void Assembler::CopyRawPtrFromThread64(FrameOffset fr_offs ATTRIBUTE_UNUSED,
- ThreadOffset64 thr_offs ATTRIBUTE_UNUSED,
- ManagedRegister scratch ATTRIBUTE_UNUSED) {
- UNIMPLEMENTED(FATAL);
-}
-
-void Assembler::CopyRawPtrToThread32(ThreadOffset32 thr_offs ATTRIBUTE_UNUSED,
- FrameOffset fr_offs ATTRIBUTE_UNUSED,
- ManagedRegister scratch ATTRIBUTE_UNUSED) {
- UNIMPLEMENTED(FATAL);
-}
-
-void Assembler::CopyRawPtrToThread64(ThreadOffset64 thr_offs ATTRIBUTE_UNUSED,
- FrameOffset fr_offs ATTRIBUTE_UNUSED,
- ManagedRegister scratch ATTRIBUTE_UNUSED) {
- UNIMPLEMENTED(FATAL);
-}
-
-void Assembler::CallFromThread32(ThreadOffset32 offset ATTRIBUTE_UNUSED,
- ManagedRegister scratch ATTRIBUTE_UNUSED) {
- UNIMPLEMENTED(FATAL);
-}
-
-void Assembler::CallFromThread64(ThreadOffset64 offset ATTRIBUTE_UNUSED,
- ManagedRegister scratch ATTRIBUTE_UNUSED) {
- UNIMPLEMENTED(FATAL);
-}
-
} // namespace art
diff --git a/compiler/utils/assembler.h b/compiler/utils/assembler.h
index 89f7947..8981776 100644
--- a/compiler/utils/assembler.h
+++ b/compiler/utils/assembler.h
@@ -356,11 +356,6 @@
class Assembler : public DeletableArenaObject<kArenaAllocAssembler> {
public:
- static std::unique_ptr<Assembler> Create(
- ArenaAllocator* arena,
- InstructionSet instruction_set,
- const InstructionSetFeatures* instruction_set_features = nullptr);
-
// Finalize the code; emit slow paths, fixup branches, add literal pool, etc.
virtual void FinalizeCode() { buffer_.EmitSlowPaths(this); }
@@ -376,144 +371,6 @@
// TODO: Implement with disassembler.
virtual void Comment(const char* format ATTRIBUTE_UNUSED, ...) {}
- // Emit code that will create an activation on the stack
- virtual void BuildFrame(size_t frame_size,
- ManagedRegister method_reg,
- ArrayRef<const ManagedRegister> callee_save_regs,
- const ManagedRegisterEntrySpills& entry_spills) = 0;
-
- // Emit code that will remove an activation from the stack
- virtual void RemoveFrame(size_t frame_size, ArrayRef<const ManagedRegister> callee_save_regs) = 0;
-
- virtual void IncreaseFrameSize(size_t adjust) = 0;
- virtual void DecreaseFrameSize(size_t adjust) = 0;
-
- // Store routines
- virtual void Store(FrameOffset offs, ManagedRegister src, size_t size) = 0;
- virtual void StoreRef(FrameOffset dest, ManagedRegister src) = 0;
- virtual void StoreRawPtr(FrameOffset dest, ManagedRegister src) = 0;
-
- virtual void StoreImmediateToFrame(FrameOffset dest, uint32_t imm, ManagedRegister scratch) = 0;
-
- virtual void StoreImmediateToThread32(ThreadOffset32 dest,
- uint32_t imm,
- ManagedRegister scratch);
- virtual void StoreImmediateToThread64(ThreadOffset64 dest,
- uint32_t imm,
- ManagedRegister scratch);
-
- virtual void StoreStackOffsetToThread32(ThreadOffset32 thr_offs,
- FrameOffset fr_offs,
- ManagedRegister scratch);
- virtual void StoreStackOffsetToThread64(ThreadOffset64 thr_offs,
- FrameOffset fr_offs,
- ManagedRegister scratch);
-
- virtual void StoreStackPointerToThread32(ThreadOffset32 thr_offs);
- virtual void StoreStackPointerToThread64(ThreadOffset64 thr_offs);
-
- virtual void StoreSpanning(FrameOffset dest, ManagedRegister src,
- FrameOffset in_off, ManagedRegister scratch) = 0;
-
- // Load routines
- virtual void Load(ManagedRegister dest, FrameOffset src, size_t size) = 0;
-
- virtual void LoadFromThread32(ManagedRegister dest, ThreadOffset32 src, size_t size);
- virtual void LoadFromThread64(ManagedRegister dest, ThreadOffset64 src, size_t size);
-
- virtual void LoadRef(ManagedRegister dest, FrameOffset src) = 0;
- // If unpoison_reference is true and kPoisonReference is true, then we negate the read reference.
- virtual void LoadRef(ManagedRegister dest, ManagedRegister base, MemberOffset offs,
- bool unpoison_reference) = 0;
-
- virtual void LoadRawPtr(ManagedRegister dest, ManagedRegister base, Offset offs) = 0;
-
- virtual void LoadRawPtrFromThread32(ManagedRegister dest, ThreadOffset32 offs);
- virtual void LoadRawPtrFromThread64(ManagedRegister dest, ThreadOffset64 offs);
-
- // Copying routines
- virtual void Move(ManagedRegister dest, ManagedRegister src, size_t size) = 0;
-
- virtual void CopyRawPtrFromThread32(FrameOffset fr_offs,
- ThreadOffset32 thr_offs,
- ManagedRegister scratch);
- virtual void CopyRawPtrFromThread64(FrameOffset fr_offs,
- ThreadOffset64 thr_offs,
- ManagedRegister scratch);
-
- virtual void CopyRawPtrToThread32(ThreadOffset32 thr_offs,
- FrameOffset fr_offs,
- ManagedRegister scratch);
- virtual void CopyRawPtrToThread64(ThreadOffset64 thr_offs,
- FrameOffset fr_offs,
- ManagedRegister scratch);
-
- virtual void CopyRef(FrameOffset dest, FrameOffset src, ManagedRegister scratch) = 0;
-
- virtual void Copy(FrameOffset dest, FrameOffset src, ManagedRegister scratch, size_t size) = 0;
-
- virtual void Copy(FrameOffset dest, ManagedRegister src_base, Offset src_offset,
- ManagedRegister scratch, size_t size) = 0;
-
- virtual void Copy(ManagedRegister dest_base, Offset dest_offset, FrameOffset src,
- ManagedRegister scratch, size_t size) = 0;
-
- virtual void Copy(FrameOffset dest, FrameOffset src_base, Offset src_offset,
- ManagedRegister scratch, size_t size) = 0;
-
- virtual void Copy(ManagedRegister dest, Offset dest_offset,
- ManagedRegister src, Offset src_offset,
- ManagedRegister scratch, size_t size) = 0;
-
- virtual void Copy(FrameOffset dest, Offset dest_offset, FrameOffset src, Offset src_offset,
- ManagedRegister scratch, size_t size) = 0;
-
- virtual void MemoryBarrier(ManagedRegister scratch) = 0;
-
- // Sign extension
- virtual void SignExtend(ManagedRegister mreg, size_t size) = 0;
-
- // Zero extension
- virtual void ZeroExtend(ManagedRegister mreg, size_t size) = 0;
-
- // Exploit fast access in managed code to Thread::Current()
- virtual void GetCurrentThread(ManagedRegister tr) = 0;
- virtual void GetCurrentThread(FrameOffset dest_offset, ManagedRegister scratch) = 0;
-
- // Set up out_reg to hold a Object** into the handle scope, or to be null if the
- // value is null and null_allowed. in_reg holds a possibly stale reference
- // that can be used to avoid loading the handle scope entry to see if the value is
- // null.
- virtual void CreateHandleScopeEntry(ManagedRegister out_reg,
- FrameOffset handlescope_offset,
- ManagedRegister in_reg,
- bool null_allowed) = 0;
-
- // Set up out_off to hold a Object** into the handle scope, or to be null if the
- // value is null and null_allowed.
- virtual void CreateHandleScopeEntry(FrameOffset out_off,
- FrameOffset handlescope_offset,
- ManagedRegister scratch,
- bool null_allowed) = 0;
-
- // src holds a handle scope entry (Object**) load this into dst
- virtual void LoadReferenceFromHandleScope(ManagedRegister dst, ManagedRegister src) = 0;
-
- // Heap::VerifyObject on src. In some cases (such as a reference to this) we
- // know that src may not be null.
- virtual void VerifyObject(ManagedRegister src, bool could_be_null) = 0;
- virtual void VerifyObject(FrameOffset src, bool could_be_null) = 0;
-
- // Call to address held at [base+offset]
- virtual void Call(ManagedRegister base, Offset offset, ManagedRegister scratch) = 0;
- virtual void Call(FrameOffset base, Offset offset, ManagedRegister scratch) = 0;
- virtual void CallFromThread32(ThreadOffset32 offset, ManagedRegister scratch);
- virtual void CallFromThread64(ThreadOffset64 offset, ManagedRegister scratch);
-
- // Generate code to check if Thread::Current()->exception_ is non-null
- // and branch to a ExceptionSlowPath if it is.
- virtual void ExceptionPoll(ManagedRegister scratch, size_t stack_adjust) = 0;
-
virtual void Bind(Label* label) = 0;
virtual void Jump(Label* label) = 0;
@@ -525,13 +382,17 @@
*/
DebugFrameOpCodeWriterForAssembler& cfi() { return cfi_; }
- protected:
- explicit Assembler(ArenaAllocator* arena) : buffer_(arena), cfi_(this) {}
-
ArenaAllocator* GetArena() {
return buffer_.GetArena();
}
+ AssemblerBuffer* GetBuffer() {
+ return &buffer_;
+ }
+
+ protected:
+ explicit Assembler(ArenaAllocator* arena) : buffer_(arena), cfi_(this) {}
+
AssemblerBuffer buffer_;
DebugFrameOpCodeWriterForAssembler cfi_;
diff --git a/compiler/utils/jni_macro_assembler.cc b/compiler/utils/jni_macro_assembler.cc
new file mode 100644
index 0000000..6c14888
--- /dev/null
+++ b/compiler/utils/jni_macro_assembler.cc
@@ -0,0 +1,109 @@
+/*
+ * 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 "jni_macro_assembler.h"
+
+#include <algorithm>
+#include <vector>
+
+#ifdef ART_ENABLE_CODEGEN_arm
+#include "arm/assembler_arm32.h"
+#include "arm/assembler_thumb2.h"
+#endif
+#ifdef ART_ENABLE_CODEGEN_arm64
+#include "arm64/assembler_arm64.h"
+#endif
+#ifdef ART_ENABLE_CODEGEN_mips
+#include "mips/assembler_mips.h"
+#endif
+#ifdef ART_ENABLE_CODEGEN_mips64
+#include "mips64/assembler_mips64.h"
+#endif
+#ifdef ART_ENABLE_CODEGEN_x86
+#include "x86/assembler_x86.h"
+#endif
+#ifdef ART_ENABLE_CODEGEN_x86_64
+#include "x86_64/assembler_x86_64.h"
+#endif
+#include "base/casts.h"
+#include "globals.h"
+#include "memory_region.h"
+
+namespace art {
+
+using MacroAsm32UniquePtr = std::unique_ptr<JNIMacroAssembler<PointerSize::k32>>;
+
+template <>
+MacroAsm32UniquePtr JNIMacroAssembler<PointerSize::k32>::Create(
+ ArenaAllocator* arena,
+ InstructionSet instruction_set,
+ const InstructionSetFeatures* instruction_set_features) {
+#ifndef ART_ENABLE_CODEGEN_mips
+ UNUSED(instruction_set_features);
+#endif
+
+ switch (instruction_set) {
+#ifdef ART_ENABLE_CODEGEN_arm
+ case kArm:
+ return MacroAsm32UniquePtr(new (arena) arm::Arm32Assembler(arena));
+ case kThumb2:
+ return MacroAsm32UniquePtr(new (arena) arm::Thumb2Assembler(arena));
+#endif
+#ifdef ART_ENABLE_CODEGEN_mips
+ case kMips:
+ return MacroAsm32UniquePtr(new (arena) mips::MipsAssembler(
+ arena,
+ instruction_set_features != nullptr
+ ? instruction_set_features->AsMipsInstructionSetFeatures()
+ : nullptr));
+#endif
+#ifdef ART_ENABLE_CODEGEN_x86
+ case kX86:
+ return MacroAsm32UniquePtr(new (arena) x86::X86Assembler(arena));
+#endif
+ default:
+ LOG(FATAL) << "Unknown/unsupported 4B InstructionSet: " << instruction_set;
+ UNREACHABLE();
+ }
+}
+
+using MacroAsm64UniquePtr = std::unique_ptr<JNIMacroAssembler<PointerSize::k64>>;
+
+template <>
+MacroAsm64UniquePtr JNIMacroAssembler<PointerSize::k64>::Create(
+ ArenaAllocator* arena,
+ InstructionSet instruction_set,
+ const InstructionSetFeatures* instruction_set_features ATTRIBUTE_UNUSED) {
+ switch (instruction_set) {
+#ifdef ART_ENABLE_CODEGEN_arm64
+ case kArm64:
+ return MacroAsm64UniquePtr(new (arena) arm64::Arm64Assembler(arena));
+#endif
+#ifdef ART_ENABLE_CODEGEN_mips64
+ case kMips64:
+ return MacroAsm64UniquePtr(new (arena) mips64::Mips64Assembler(arena));
+#endif
+#ifdef ART_ENABLE_CODEGEN_x86_64
+ case kX86_64:
+ return MacroAsm64UniquePtr(new (arena) x86_64::X86_64Assembler(arena));
+#endif
+ default:
+ LOG(FATAL) << "Unknown/unsupported 8B InstructionSet: " << instruction_set;
+ UNREACHABLE();
+ }
+}
+
+} // namespace art
diff --git a/compiler/utils/jni_macro_assembler.h b/compiler/utils/jni_macro_assembler.h
new file mode 100644
index 0000000..6f45bd6
--- /dev/null
+++ b/compiler/utils/jni_macro_assembler.h
@@ -0,0 +1,235 @@
+/*
+ * 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_COMPILER_UTILS_JNI_MACRO_ASSEMBLER_H_
+#define ART_COMPILER_UTILS_JNI_MACRO_ASSEMBLER_H_
+
+#include <vector>
+
+#include "arch/instruction_set.h"
+#include "base/arena_allocator.h"
+#include "base/arena_object.h"
+#include "base/enums.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "managed_register.h"
+#include "offsets.h"
+#include "utils/array_ref.h"
+
+namespace art {
+
+class ArenaAllocator;
+class DebugFrameOpCodeWriterForAssembler;
+class InstructionSetFeatures;
+class MemoryRegion;
+
+template <PointerSize kPointerSize>
+class JNIMacroAssembler : public DeletableArenaObject<kArenaAllocAssembler> {
+ public:
+ static std::unique_ptr<JNIMacroAssembler<kPointerSize>> Create(
+ ArenaAllocator* arena,
+ InstructionSet instruction_set,
+ const InstructionSetFeatures* instruction_set_features = nullptr);
+
+ // Finalize the code; emit slow paths, fixup branches, add literal pool, etc.
+ virtual void FinalizeCode() = 0;
+
+ // Size of generated code
+ virtual size_t CodeSize() const = 0;
+
+ // Copy instructions out of assembly buffer into the given region of memory
+ virtual void FinalizeInstructions(const MemoryRegion& region) = 0;
+
+ // Emit code that will create an activation on the stack
+ virtual void BuildFrame(size_t frame_size,
+ ManagedRegister method_reg,
+ ArrayRef<const ManagedRegister> callee_save_regs,
+ const ManagedRegisterEntrySpills& entry_spills) = 0;
+
+ // Emit code that will remove an activation from the stack
+ virtual void RemoveFrame(size_t frame_size, ArrayRef<const ManagedRegister> callee_save_regs) = 0;
+
+ virtual void IncreaseFrameSize(size_t adjust) = 0;
+ virtual void DecreaseFrameSize(size_t adjust) = 0;
+
+ // Store routines
+ virtual void Store(FrameOffset offs, ManagedRegister src, size_t size) = 0;
+ virtual void StoreRef(FrameOffset dest, ManagedRegister src) = 0;
+ virtual void StoreRawPtr(FrameOffset dest, ManagedRegister src) = 0;
+
+ virtual void StoreImmediateToFrame(FrameOffset dest, uint32_t imm, ManagedRegister scratch) = 0;
+
+ virtual void StoreStackOffsetToThread(ThreadOffset<kPointerSize> thr_offs,
+ FrameOffset fr_offs,
+ ManagedRegister scratch) = 0;
+
+ virtual void StoreStackPointerToThread(ThreadOffset<kPointerSize> thr_offs) = 0;
+
+ virtual void StoreSpanning(FrameOffset dest,
+ ManagedRegister src,
+ FrameOffset in_off,
+ ManagedRegister scratch) = 0;
+
+ // Load routines
+ virtual void Load(ManagedRegister dest, FrameOffset src, size_t size) = 0;
+
+ virtual void LoadFromThread(ManagedRegister dest,
+ ThreadOffset<kPointerSize> src,
+ size_t size) = 0;
+
+ virtual void LoadRef(ManagedRegister dest, FrameOffset src) = 0;
+ // If unpoison_reference is true and kPoisonReference is true, then we negate the read reference.
+ virtual void LoadRef(ManagedRegister dest,
+ ManagedRegister base,
+ MemberOffset offs,
+ bool unpoison_reference) = 0;
+
+ virtual void LoadRawPtr(ManagedRegister dest, ManagedRegister base, Offset offs) = 0;
+
+ virtual void LoadRawPtrFromThread(ManagedRegister dest, ThreadOffset<kPointerSize> offs) = 0;
+
+ // Copying routines
+ virtual void Move(ManagedRegister dest, ManagedRegister src, size_t size) = 0;
+
+ virtual void CopyRawPtrFromThread(FrameOffset fr_offs,
+ ThreadOffset<kPointerSize> thr_offs,
+ ManagedRegister scratch) = 0;
+
+ virtual void CopyRawPtrToThread(ThreadOffset<kPointerSize> thr_offs,
+ FrameOffset fr_offs,
+ ManagedRegister scratch) = 0;
+
+ virtual void CopyRef(FrameOffset dest, FrameOffset src, ManagedRegister scratch) = 0;
+
+ virtual void Copy(FrameOffset dest, FrameOffset src, ManagedRegister scratch, size_t size) = 0;
+
+ virtual void Copy(FrameOffset dest,
+ ManagedRegister src_base,
+ Offset src_offset,
+ ManagedRegister scratch,
+ size_t size) = 0;
+
+ virtual void Copy(ManagedRegister dest_base,
+ Offset dest_offset,
+ FrameOffset src,
+ ManagedRegister scratch,
+ size_t size) = 0;
+
+ virtual void Copy(FrameOffset dest,
+ FrameOffset src_base,
+ Offset src_offset,
+ ManagedRegister scratch,
+ size_t size) = 0;
+
+ virtual void Copy(ManagedRegister dest,
+ Offset dest_offset,
+ ManagedRegister src,
+ Offset src_offset,
+ ManagedRegister scratch,
+ size_t size) = 0;
+
+ virtual void Copy(FrameOffset dest,
+ Offset dest_offset,
+ FrameOffset src,
+ Offset src_offset,
+ ManagedRegister scratch,
+ size_t size) = 0;
+
+ virtual void MemoryBarrier(ManagedRegister scratch) = 0;
+
+ // Sign extension
+ virtual void SignExtend(ManagedRegister mreg, size_t size) = 0;
+
+ // Zero extension
+ virtual void ZeroExtend(ManagedRegister mreg, size_t size) = 0;
+
+ // Exploit fast access in managed code to Thread::Current()
+ virtual void GetCurrentThread(ManagedRegister tr) = 0;
+ virtual void GetCurrentThread(FrameOffset dest_offset, ManagedRegister scratch) = 0;
+
+ // Set up out_reg to hold a Object** into the handle scope, or to be null if the
+ // value is null and null_allowed. in_reg holds a possibly stale reference
+ // that can be used to avoid loading the handle scope entry to see if the value is
+ // null.
+ virtual void CreateHandleScopeEntry(ManagedRegister out_reg,
+ FrameOffset handlescope_offset,
+ ManagedRegister in_reg,
+ bool null_allowed) = 0;
+
+ // Set up out_off to hold a Object** into the handle scope, or to be null if the
+ // value is null and null_allowed.
+ virtual void CreateHandleScopeEntry(FrameOffset out_off,
+ FrameOffset handlescope_offset,
+ ManagedRegister scratch,
+ bool null_allowed) = 0;
+
+ // src holds a handle scope entry (Object**) load this into dst
+ virtual void LoadReferenceFromHandleScope(ManagedRegister dst, ManagedRegister src) = 0;
+
+ // Heap::VerifyObject on src. In some cases (such as a reference to this) we
+ // know that src may not be null.
+ virtual void VerifyObject(ManagedRegister src, bool could_be_null) = 0;
+ virtual void VerifyObject(FrameOffset src, bool could_be_null) = 0;
+
+ // Call to address held at [base+offset]
+ virtual void Call(ManagedRegister base, Offset offset, ManagedRegister scratch) = 0;
+ virtual void Call(FrameOffset base, Offset offset, ManagedRegister scratch) = 0;
+ virtual void CallFromThread(ThreadOffset<kPointerSize> offset, ManagedRegister scratch) = 0;
+
+ // Generate code to check if Thread::Current()->exception_ is non-null
+ // and branch to a ExceptionSlowPath if it is.
+ virtual void ExceptionPoll(ManagedRegister scratch, size_t stack_adjust) = 0;
+
+ virtual ~JNIMacroAssembler() {}
+
+ /**
+ * @brief Buffer of DWARF's Call Frame Information opcodes.
+ * @details It is used by debuggers and other tools to unwind the call stack.
+ */
+ virtual DebugFrameOpCodeWriterForAssembler& cfi() = 0;
+
+ protected:
+ explicit JNIMacroAssembler() {}
+};
+
+template <typename T, PointerSize kPointerSize>
+class JNIMacroAssemblerFwd : public JNIMacroAssembler<kPointerSize> {
+ public:
+ void FinalizeCode() OVERRIDE {
+ asm_.FinalizeCode();
+ }
+
+ size_t CodeSize() const OVERRIDE {
+ return asm_.CodeSize();
+ }
+
+ void FinalizeInstructions(const MemoryRegion& region) OVERRIDE {
+ asm_.FinalizeInstructions(region);
+ }
+
+ DebugFrameOpCodeWriterForAssembler& cfi() OVERRIDE {
+ return asm_.cfi();
+ }
+
+ protected:
+ explicit JNIMacroAssemblerFwd(ArenaAllocator* arena) : asm_(arena) {}
+
+ T asm_;
+};
+
+} // namespace art
+
+#endif // ART_COMPILER_UTILS_JNI_MACRO_ASSEMBLER_H_
diff --git a/compiler/utils/jni_macro_assembler_test.h b/compiler/utils/jni_macro_assembler_test.h
new file mode 100644
index 0000000..829f34b
--- /dev/null
+++ b/compiler/utils/jni_macro_assembler_test.h
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_COMPILER_UTILS_JNI_MACRO_ASSEMBLER_TEST_H_
+#define ART_COMPILER_UTILS_JNI_MACRO_ASSEMBLER_TEST_H_
+
+#include "jni_macro_assembler.h"
+
+#include "assembler_test_base.h"
+#include "common_runtime_test.h" // For ScratchFile
+
+#include <cstdio>
+#include <cstdlib>
+#include <fstream>
+#include <iterator>
+#include <sys/stat.h>
+
+namespace art {
+
+template<typename Ass>
+class JNIMacroAssemblerTest : public testing::Test {
+ public:
+ Ass* GetAssembler() {
+ return assembler_.get();
+ }
+
+ typedef std::string (*TestFn)(JNIMacroAssemblerTest* assembler_test, Ass* assembler);
+
+ void DriverFn(TestFn f, std::string test_name) {
+ DriverWrapper(f(this, assembler_.get()), test_name);
+ }
+
+ // This driver assumes the assembler has already been called.
+ void DriverStr(std::string assembly_string, std::string test_name) {
+ DriverWrapper(assembly_string, test_name);
+ }
+
+ // This is intended to be run as a test.
+ bool CheckTools() {
+ return test_helper_->CheckTools();
+ }
+
+ protected:
+ explicit JNIMacroAssemblerTest() {}
+
+ void SetUp() OVERRIDE {
+ arena_.reset(new ArenaAllocator(&pool_));
+ assembler_.reset(CreateAssembler(arena_.get()));
+ test_helper_.reset(
+ new AssemblerTestInfrastructure(GetArchitectureString(),
+ GetAssemblerCmdName(),
+ GetAssemblerParameters(),
+ GetObjdumpCmdName(),
+ GetObjdumpParameters(),
+ GetDisassembleCmdName(),
+ GetDisassembleParameters(),
+ GetAssemblyHeader()));
+
+ SetUpHelpers();
+ }
+
+ void TearDown() OVERRIDE {
+ test_helper_.reset(); // Clean up the helper.
+ assembler_.reset();
+ arena_.reset();
+ }
+
+ // Override this to set up any architecture-specific things, e.g., CPU revision.
+ virtual Ass* CreateAssembler(ArenaAllocator* arena) {
+ return new (arena) Ass(arena);
+ }
+
+ // Override this to set up any architecture-specific things, e.g., register vectors.
+ virtual void SetUpHelpers() {}
+
+ // Get the typically used name for this architecture, e.g., aarch64, x86_64, ...
+ virtual std::string GetArchitectureString() = 0;
+
+ // Get the name of the assembler, e.g., "as" by default.
+ virtual std::string GetAssemblerCmdName() {
+ return "as";
+ }
+
+ // Switches to the assembler command. Default none.
+ virtual std::string GetAssemblerParameters() {
+ return "";
+ }
+
+ // Get the name of the objdump, e.g., "objdump" by default.
+ virtual std::string GetObjdumpCmdName() {
+ return "objdump";
+ }
+
+ // Switches to the objdump command. Default is " -h".
+ virtual std::string GetObjdumpParameters() {
+ return " -h";
+ }
+
+ // Get the name of the objdump, e.g., "objdump" by default.
+ virtual std::string GetDisassembleCmdName() {
+ return "objdump";
+ }
+
+ // Switches to the objdump command. As it's a binary, one needs to push the architecture and
+ // such to objdump, so it's architecture-specific and there is no default.
+ virtual std::string GetDisassembleParameters() = 0;
+
+ // If the assembly file needs a header, return it in a sub-class.
+ virtual const char* GetAssemblyHeader() {
+ return nullptr;
+ }
+
+ private:
+ // Override this to pad the code with NOPs to a certain size if needed.
+ virtual void Pad(std::vector<uint8_t>& data ATTRIBUTE_UNUSED) {
+ }
+
+ void DriverWrapper(std::string assembly_text, std::string test_name) {
+ assembler_->FinalizeCode();
+ size_t cs = assembler_->CodeSize();
+ std::unique_ptr<std::vector<uint8_t>> data(new std::vector<uint8_t>(cs));
+ MemoryRegion code(&(*data)[0], data->size());
+ assembler_->FinalizeInstructions(code);
+ Pad(*data);
+ test_helper_->Driver(*data, assembly_text, test_name);
+ }
+
+ ArenaPool pool_;
+ std::unique_ptr<ArenaAllocator> arena_;
+ std::unique_ptr<Ass> assembler_;
+ std::unique_ptr<AssemblerTestInfrastructure> test_helper_;
+
+ DISALLOW_COPY_AND_ASSIGN(JNIMacroAssemblerTest);
+};
+
+} // namespace art
+
+#endif // ART_COMPILER_UTILS_JNI_MACRO_ASSEMBLER_TEST_H_
diff --git a/compiler/utils/mips/assembler_mips.cc b/compiler/utils/mips/assembler_mips.cc
index e6b32de..8b7da3f 100644
--- a/compiler/utils/mips/assembler_mips.cc
+++ b/compiler/utils/mips/assembler_mips.cc
@@ -2799,27 +2799,17 @@
StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value());
}
-void MipsAssembler::StoreImmediateToThread32(ThreadOffset32 dest,
- uint32_t imm,
+void MipsAssembler::StoreStackOffsetToThread(ThreadOffset32 thr_offs,
+ FrameOffset fr_offs,
ManagedRegister mscratch) {
MipsManagedRegister scratch = mscratch.AsMips();
CHECK(scratch.IsCoreRegister()) << scratch;
- // Is this function even referenced anywhere else in the code?
- LoadConst32(scratch.AsCoreRegister(), imm);
- StoreToOffset(kStoreWord, scratch.AsCoreRegister(), S1, dest.Int32Value());
-}
-
-void MipsAssembler::StoreStackOffsetToThread32(ThreadOffset32 thr_offs,
- FrameOffset fr_offs,
- ManagedRegister mscratch) {
- MipsManagedRegister scratch = mscratch.AsMips();
- CHECK(scratch.IsCoreRegister()) << scratch;
Addiu32(scratch.AsCoreRegister(), SP, fr_offs.Int32Value());
StoreToOffset(kStoreWord, scratch.AsCoreRegister(),
S1, thr_offs.Int32Value());
}
-void MipsAssembler::StoreStackPointerToThread32(ThreadOffset32 thr_offs) {
+void MipsAssembler::StoreStackPointerToThread(ThreadOffset32 thr_offs) {
StoreToOffset(kStoreWord, SP, S1, thr_offs.Int32Value());
}
@@ -2836,7 +2826,7 @@
return EmitLoad(mdest, SP, src.Int32Value(), size);
}
-void MipsAssembler::LoadFromThread32(ManagedRegister mdest, ThreadOffset32 src, size_t size) {
+void MipsAssembler::LoadFromThread(ManagedRegister mdest, ThreadOffset32 src, size_t size) {
return EmitLoad(mdest, S1, src.Int32Value(), size);
}
@@ -2864,7 +2854,7 @@
base.AsMips().AsCoreRegister(), offs.Int32Value());
}
-void MipsAssembler::LoadRawPtrFromThread32(ManagedRegister mdest, ThreadOffset32 offs) {
+void MipsAssembler::LoadRawPtrFromThread(ManagedRegister mdest, ThreadOffset32 offs) {
MipsManagedRegister dest = mdest.AsMips();
CHECK(dest.IsCoreRegister());
LoadFromOffset(kLoadWord, dest.AsCoreRegister(), S1, offs.Int32Value());
@@ -2918,9 +2908,9 @@
StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value());
}
-void MipsAssembler::CopyRawPtrFromThread32(FrameOffset fr_offs,
- ThreadOffset32 thr_offs,
- ManagedRegister mscratch) {
+void MipsAssembler::CopyRawPtrFromThread(FrameOffset fr_offs,
+ ThreadOffset32 thr_offs,
+ ManagedRegister mscratch) {
MipsManagedRegister scratch = mscratch.AsMips();
CHECK(scratch.IsCoreRegister()) << scratch;
LoadFromOffset(kLoadWord, scratch.AsCoreRegister(),
@@ -2929,9 +2919,9 @@
SP, fr_offs.Int32Value());
}
-void MipsAssembler::CopyRawPtrToThread32(ThreadOffset32 thr_offs,
- FrameOffset fr_offs,
- ManagedRegister mscratch) {
+void MipsAssembler::CopyRawPtrToThread(ThreadOffset32 thr_offs,
+ FrameOffset fr_offs,
+ ManagedRegister mscratch) {
MipsManagedRegister scratch = mscratch.AsMips();
CHECK(scratch.IsCoreRegister()) << scratch;
LoadFromOffset(kLoadWord, scratch.AsCoreRegister(),
@@ -3103,8 +3093,8 @@
// TODO: place reference map on call.
}
-void MipsAssembler::CallFromThread32(ThreadOffset32 offset ATTRIBUTE_UNUSED,
- ManagedRegister mscratch ATTRIBUTE_UNUSED) {
+void MipsAssembler::CallFromThread(ThreadOffset32 offset ATTRIBUTE_UNUSED,
+ ManagedRegister mscratch ATTRIBUTE_UNUSED) {
UNIMPLEMENTED(FATAL) << "no mips implementation";
}
diff --git a/compiler/utils/mips/assembler_mips.h b/compiler/utils/mips/assembler_mips.h
index 852ced6..41b6c6b 100644
--- a/compiler/utils/mips/assembler_mips.h
+++ b/compiler/utils/mips/assembler_mips.h
@@ -23,12 +23,14 @@
#include "arch/mips/instruction_set_features_mips.h"
#include "base/arena_containers.h"
+#include "base/enums.h"
#include "base/macros.h"
#include "constants_mips.h"
#include "globals.h"
#include "managed_register_mips.h"
#include "offsets.h"
#include "utils/assembler.h"
+#include "utils/jni_macro_assembler.h"
#include "utils/label.h"
namespace art {
@@ -145,7 +147,7 @@
DISALLOW_COPY_AND_ASSIGN(MipsExceptionSlowPath);
};
-class MipsAssembler FINAL : public Assembler {
+class MipsAssembler FINAL : public Assembler, public JNIMacroAssembler<PointerSize::k32> {
public:
explicit MipsAssembler(ArenaAllocator* arena,
const MipsInstructionSetFeatures* instruction_set_features = nullptr)
@@ -160,6 +162,9 @@
cfi().DelayEmittingAdvancePCs();
}
+ size_t CodeSize() const OVERRIDE { return Assembler::CodeSize(); }
+ DebugFrameOpCodeWriterForAssembler& cfi() { return Assembler::cfi(); }
+
virtual ~MipsAssembler() {
for (auto& branch : branches_) {
CHECK(branch.IsResolved());
@@ -500,15 +505,11 @@
void StoreImmediateToFrame(FrameOffset dest, uint32_t imm, ManagedRegister mscratch) OVERRIDE;
- void StoreImmediateToThread32(ThreadOffset32 dest,
- uint32_t imm,
+ void StoreStackOffsetToThread(ThreadOffset32 thr_offs,
+ FrameOffset fr_offs,
ManagedRegister mscratch) OVERRIDE;
- void StoreStackOffsetToThread32(ThreadOffset32 thr_offs,
- FrameOffset fr_offs,
- ManagedRegister mscratch) OVERRIDE;
-
- void StoreStackPointerToThread32(ThreadOffset32 thr_offs) OVERRIDE;
+ void StoreStackPointerToThread(ThreadOffset32 thr_offs) OVERRIDE;
void StoreSpanning(FrameOffset dest,
ManagedRegister msrc,
@@ -518,7 +519,7 @@
// Load routines.
void Load(ManagedRegister mdest, FrameOffset src, size_t size) OVERRIDE;
- void LoadFromThread32(ManagedRegister mdest, ThreadOffset32 src, size_t size) OVERRIDE;
+ void LoadFromThread(ManagedRegister mdest, ThreadOffset32 src, size_t size) OVERRIDE;
void LoadRef(ManagedRegister dest, FrameOffset src) OVERRIDE;
@@ -529,19 +530,19 @@
void LoadRawPtr(ManagedRegister mdest, ManagedRegister base, Offset offs) OVERRIDE;
- void LoadRawPtrFromThread32(ManagedRegister mdest, ThreadOffset32 offs) OVERRIDE;
+ void LoadRawPtrFromThread(ManagedRegister mdest, ThreadOffset32 offs) OVERRIDE;
// Copying routines.
void Move(ManagedRegister mdest, ManagedRegister msrc, size_t size) OVERRIDE;
- void CopyRawPtrFromThread32(FrameOffset fr_offs,
- ThreadOffset32 thr_offs,
- ManagedRegister mscratch) OVERRIDE;
-
- void CopyRawPtrToThread32(ThreadOffset32 thr_offs,
- FrameOffset fr_offs,
+ void CopyRawPtrFromThread(FrameOffset fr_offs,
+ ThreadOffset32 thr_offs,
ManagedRegister mscratch) OVERRIDE;
+ void CopyRawPtrToThread(ThreadOffset32 thr_offs,
+ FrameOffset fr_offs,
+ ManagedRegister mscratch) OVERRIDE;
+
void CopyRef(FrameOffset dest, FrameOffset src, ManagedRegister mscratch) OVERRIDE;
void Copy(FrameOffset dest, FrameOffset src, ManagedRegister mscratch, size_t size) OVERRIDE;
@@ -617,7 +618,7 @@
// Call to address held at [base+offset].
void Call(ManagedRegister base, Offset offset, ManagedRegister mscratch) OVERRIDE;
void Call(FrameOffset base, Offset offset, ManagedRegister mscratch) OVERRIDE;
- void CallFromThread32(ThreadOffset32 offset, ManagedRegister mscratch) OVERRIDE;
+ void CallFromThread(ThreadOffset32 offset, ManagedRegister mscratch) OVERRIDE;
// Generate code to check if Thread::Current()->exception_ is non-null
// and branch to a ExceptionSlowPath if it is.
diff --git a/compiler/utils/mips64/assembler_mips64.cc b/compiler/utils/mips64/assembler_mips64.cc
index 3fd77a0..a2621cb 100644
--- a/compiler/utils/mips64/assembler_mips64.cc
+++ b/compiler/utils/mips64/assembler_mips64.cc
@@ -2115,16 +2115,16 @@
StoreToOffset(kStoreWord, scratch.AsGpuRegister(), SP, dest.Int32Value());
}
-void Mips64Assembler::StoreStackOffsetToThread64(ThreadOffset64 thr_offs,
- FrameOffset fr_offs,
- ManagedRegister mscratch) {
+void Mips64Assembler::StoreStackOffsetToThread(ThreadOffset64 thr_offs,
+ FrameOffset fr_offs,
+ ManagedRegister mscratch) {
Mips64ManagedRegister scratch = mscratch.AsMips64();
CHECK(scratch.IsGpuRegister()) << scratch;
Daddiu64(scratch.AsGpuRegister(), SP, fr_offs.Int32Value());
StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), S1, thr_offs.Int32Value());
}
-void Mips64Assembler::StoreStackPointerToThread64(ThreadOffset64 thr_offs) {
+void Mips64Assembler::StoreStackPointerToThread(ThreadOffset64 thr_offs) {
StoreToOffset(kStoreDoubleword, SP, S1, thr_offs.Int32Value());
}
@@ -2141,7 +2141,7 @@
return EmitLoad(mdest, SP, src.Int32Value(), size);
}
-void Mips64Assembler::LoadFromThread64(ManagedRegister mdest, ThreadOffset64 src, size_t size) {
+void Mips64Assembler::LoadFromThread(ManagedRegister mdest, ThreadOffset64 src, size_t size) {
return EmitLoad(mdest, S1, src.Int32Value(), size);
}
@@ -2174,7 +2174,7 @@
base.AsMips64().AsGpuRegister(), offs.Int32Value());
}
-void Mips64Assembler::LoadRawPtrFromThread64(ManagedRegister mdest, ThreadOffset64 offs) {
+void Mips64Assembler::LoadRawPtrFromThread(ManagedRegister mdest, ThreadOffset64 offs) {
Mips64ManagedRegister dest = mdest.AsMips64();
CHECK(dest.IsGpuRegister());
LoadFromOffset(kLoadDoubleword, dest.AsGpuRegister(), S1, offs.Int32Value());
@@ -2218,18 +2218,18 @@
StoreToOffset(kStoreWord, scratch.AsGpuRegister(), SP, dest.Int32Value());
}
-void Mips64Assembler::CopyRawPtrFromThread64(FrameOffset fr_offs,
- ThreadOffset64 thr_offs,
- ManagedRegister mscratch) {
+void Mips64Assembler::CopyRawPtrFromThread(FrameOffset fr_offs,
+ ThreadOffset64 thr_offs,
+ ManagedRegister mscratch) {
Mips64ManagedRegister scratch = mscratch.AsMips64();
CHECK(scratch.IsGpuRegister()) << scratch;
LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(), S1, thr_offs.Int32Value());
StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), SP, fr_offs.Int32Value());
}
-void Mips64Assembler::CopyRawPtrToThread64(ThreadOffset64 thr_offs,
- FrameOffset fr_offs,
- ManagedRegister mscratch) {
+void Mips64Assembler::CopyRawPtrToThread(ThreadOffset64 thr_offs,
+ FrameOffset fr_offs,
+ ManagedRegister mscratch) {
Mips64ManagedRegister scratch = mscratch.AsMips64();
CHECK(scratch.IsGpuRegister()) << scratch;
LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(),
@@ -2431,8 +2431,8 @@
// TODO: place reference map on call
}
-void Mips64Assembler::CallFromThread64(ThreadOffset64 offset ATTRIBUTE_UNUSED,
- ManagedRegister mscratch ATTRIBUTE_UNUSED) {
+void Mips64Assembler::CallFromThread(ThreadOffset64 offset ATTRIBUTE_UNUSED,
+ ManagedRegister mscratch ATTRIBUTE_UNUSED) {
UNIMPLEMENTED(FATAL) << "No MIPS64 implementation";
}
diff --git a/compiler/utils/mips64/assembler_mips64.h b/compiler/utils/mips64/assembler_mips64.h
index 1ad05b0..a7d350c 100644
--- a/compiler/utils/mips64/assembler_mips64.h
+++ b/compiler/utils/mips64/assembler_mips64.h
@@ -20,12 +20,14 @@
#include <utility>
#include <vector>
+#include "base/enums.h"
#include "base/macros.h"
#include "constants_mips64.h"
#include "globals.h"
#include "managed_register_mips64.h"
#include "offsets.h"
#include "utils/assembler.h"
+#include "utils/jni_macro_assembler.h"
#include "utils/label.h"
namespace art {
@@ -100,7 +102,7 @@
DISALLOW_COPY_AND_ASSIGN(Mips64ExceptionSlowPath);
};
-class Mips64Assembler FINAL : public Assembler {
+class Mips64Assembler FINAL : public Assembler, public JNIMacroAssembler<PointerSize::k64> {
public:
explicit Mips64Assembler(ArenaAllocator* arena)
: Assembler(arena),
@@ -118,6 +120,9 @@
}
}
+ size_t CodeSize() const OVERRIDE { return Assembler::CodeSize(); }
+ DebugFrameOpCodeWriterForAssembler& cfi() { return Assembler::cfi(); }
+
// Emit Machine Instructions.
void Addu(GpuRegister rd, GpuRegister rs, GpuRegister rt);
void Addiu(GpuRegister rt, GpuRegister rs, uint16_t imm16);
@@ -383,11 +388,11 @@
void StoreImmediateToFrame(FrameOffset dest, uint32_t imm, ManagedRegister mscratch) OVERRIDE;
- void StoreStackOffsetToThread64(ThreadOffset64 thr_offs,
- FrameOffset fr_offs,
- ManagedRegister mscratch) OVERRIDE;
+ void StoreStackOffsetToThread(ThreadOffset64 thr_offs,
+ FrameOffset fr_offs,
+ ManagedRegister mscratch) OVERRIDE;
- void StoreStackPointerToThread64(ThreadOffset64 thr_offs) OVERRIDE;
+ void StoreStackPointerToThread(ThreadOffset64 thr_offs) OVERRIDE;
void StoreSpanning(FrameOffset dest, ManagedRegister msrc, FrameOffset in_off,
ManagedRegister mscratch) OVERRIDE;
@@ -395,7 +400,7 @@
// Load routines.
void Load(ManagedRegister mdest, FrameOffset src, size_t size) OVERRIDE;
- void LoadFromThread64(ManagedRegister mdest, ThreadOffset64 src, size_t size) OVERRIDE;
+ void LoadFromThread(ManagedRegister mdest, ThreadOffset64 src, size_t size) OVERRIDE;
void LoadRef(ManagedRegister dest, FrameOffset src) OVERRIDE;
@@ -404,19 +409,19 @@
void LoadRawPtr(ManagedRegister mdest, ManagedRegister base, Offset offs) OVERRIDE;
- void LoadRawPtrFromThread64(ManagedRegister mdest, ThreadOffset64 offs) OVERRIDE;
+ void LoadRawPtrFromThread(ManagedRegister mdest, ThreadOffset64 offs) OVERRIDE;
// Copying routines.
void Move(ManagedRegister mdest, ManagedRegister msrc, size_t size) OVERRIDE;
- void CopyRawPtrFromThread64(FrameOffset fr_offs,
- ThreadOffset64 thr_offs,
- ManagedRegister mscratch) OVERRIDE;
-
- void CopyRawPtrToThread64(ThreadOffset64 thr_offs,
- FrameOffset fr_offs,
+ void CopyRawPtrFromThread(FrameOffset fr_offs,
+ ThreadOffset64 thr_offs,
ManagedRegister mscratch) OVERRIDE;
+ void CopyRawPtrToThread(ThreadOffset64 thr_offs,
+ FrameOffset fr_offs,
+ ManagedRegister mscratch) OVERRIDE;
+
void CopyRef(FrameOffset dest, FrameOffset src, ManagedRegister mscratch) OVERRIDE;
void Copy(FrameOffset dest, FrameOffset src, ManagedRegister mscratch, size_t size) OVERRIDE;
@@ -471,7 +476,7 @@
// Call to address held at [base+offset].
void Call(ManagedRegister base, Offset offset, ManagedRegister mscratch) OVERRIDE;
void Call(FrameOffset base, Offset offset, ManagedRegister mscratch) OVERRIDE;
- void CallFromThread64(ThreadOffset64 offset, ManagedRegister mscratch) OVERRIDE;
+ void CallFromThread(ThreadOffset64 offset, ManagedRegister mscratch) OVERRIDE;
// Generate code to check if Thread::Current()->exception_ is non-null
// and branch to a ExceptionSlowPath if it is.
diff --git a/compiler/utils/x86/assembler_x86.cc b/compiler/utils/x86/assembler_x86.cc
index bd5fc40..89b3c3f 100644
--- a/compiler/utils/x86/assembler_x86.cc
+++ b/compiler/utils/x86/assembler_x86.cc
@@ -2068,20 +2068,16 @@
movl(Address(ESP, dest), Immediate(imm));
}
-void X86Assembler::StoreImmediateToThread32(ThreadOffset32 dest, uint32_t imm, ManagedRegister) {
- fs()->movl(Address::Absolute(dest), Immediate(imm));
-}
-
-void X86Assembler::StoreStackOffsetToThread32(ThreadOffset32 thr_offs,
- FrameOffset fr_offs,
- ManagedRegister mscratch) {
+void X86Assembler::StoreStackOffsetToThread(ThreadOffset32 thr_offs,
+ FrameOffset fr_offs,
+ ManagedRegister mscratch) {
X86ManagedRegister scratch = mscratch.AsX86();
CHECK(scratch.IsCpuRegister());
leal(scratch.AsCpuRegister(), Address(ESP, fr_offs));
fs()->movl(Address::Absolute(thr_offs), scratch.AsCpuRegister());
}
-void X86Assembler::StoreStackPointerToThread32(ThreadOffset32 thr_offs) {
+void X86Assembler::StoreStackPointerToThread(ThreadOffset32 thr_offs) {
fs()->movl(Address::Absolute(thr_offs), ESP);
}
@@ -2117,7 +2113,7 @@
}
}
-void X86Assembler::LoadFromThread32(ManagedRegister mdest, ThreadOffset32 src, size_t size) {
+void X86Assembler::LoadFromThread(ManagedRegister mdest, ThreadOffset32 src, size_t size) {
X86ManagedRegister dest = mdest.AsX86();
if (dest.IsNoRegister()) {
CHECK_EQ(0u, size);
@@ -2167,8 +2163,7 @@
movl(dest.AsCpuRegister(), Address(base.AsX86().AsCpuRegister(), offs));
}
-void X86Assembler::LoadRawPtrFromThread32(ManagedRegister mdest,
- ThreadOffset32 offs) {
+void X86Assembler::LoadRawPtrFromThread(ManagedRegister mdest, ThreadOffset32 offs) {
X86ManagedRegister dest = mdest.AsX86();
CHECK(dest.IsCpuRegister());
fs()->movl(dest.AsCpuRegister(), Address::Absolute(offs));
@@ -2230,18 +2225,18 @@
movl(Address(ESP, dest), scratch.AsCpuRegister());
}
-void X86Assembler::CopyRawPtrFromThread32(FrameOffset fr_offs,
- ThreadOffset32 thr_offs,
- ManagedRegister mscratch) {
+void X86Assembler::CopyRawPtrFromThread(FrameOffset fr_offs,
+ ThreadOffset32 thr_offs,
+ ManagedRegister mscratch) {
X86ManagedRegister scratch = mscratch.AsX86();
CHECK(scratch.IsCpuRegister());
fs()->movl(scratch.AsCpuRegister(), Address::Absolute(thr_offs));
Store(fr_offs, scratch, 4);
}
-void X86Assembler::CopyRawPtrToThread32(ThreadOffset32 thr_offs,
- FrameOffset fr_offs,
- ManagedRegister mscratch) {
+void X86Assembler::CopyRawPtrToThread(ThreadOffset32 thr_offs,
+ FrameOffset fr_offs,
+ ManagedRegister mscratch) {
X86ManagedRegister scratch = mscratch.AsX86();
CHECK(scratch.IsCpuRegister());
Load(scratch, fr_offs, 4);
@@ -2387,7 +2382,7 @@
call(Address(scratch, offset));
}
-void X86Assembler::CallFromThread32(ThreadOffset32 offset, ManagedRegister /*mscratch*/) {
+void X86Assembler::CallFromThread(ThreadOffset32 offset, ManagedRegister /*mscratch*/) {
fs()->call(Address::Absolute(offset));
}
diff --git a/compiler/utils/x86/assembler_x86.h b/compiler/utils/x86/assembler_x86.h
index 6d519e4..b6442fe 100644
--- a/compiler/utils/x86/assembler_x86.h
+++ b/compiler/utils/x86/assembler_x86.h
@@ -21,6 +21,7 @@
#include "base/arena_containers.h"
#include "base/bit_utils.h"
+#include "base/enums.h"
#include "base/macros.h"
#include "constants_x86.h"
#include "globals.h"
@@ -28,6 +29,7 @@
#include "offsets.h"
#include "utils/array_ref.h"
#include "utils/assembler.h"
+#include "utils/jni_macro_assembler.h"
namespace art {
namespace x86 {
@@ -302,11 +304,18 @@
ArenaVector<int32_t> buffer_;
};
-class X86Assembler FINAL : public Assembler {
+class X86Assembler FINAL : public Assembler, public JNIMacroAssembler<PointerSize::k32> {
public:
explicit X86Assembler(ArenaAllocator* arena) : Assembler(arena), constant_area_(arena) {}
virtual ~X86Assembler() {}
+ size_t CodeSize() const OVERRIDE { return Assembler::CodeSize(); }
+ DebugFrameOpCodeWriterForAssembler& cfi() { return Assembler::cfi(); }
+ void FinalizeCode() { Assembler::FinalizeCode(); }
+ void FinalizeInstructions(const MemoryRegion& region) {
+ Assembler::FinalizeInstructions(region);
+ }
+
/*
* Emit Machine Instructions.
*/
@@ -654,13 +663,11 @@
void StoreImmediateToFrame(FrameOffset dest, uint32_t imm, ManagedRegister scratch) OVERRIDE;
- void StoreImmediateToThread32(ThreadOffset32 dest, uint32_t imm, ManagedRegister scratch)
- OVERRIDE;
+ void StoreStackOffsetToThread(ThreadOffset32 thr_offs,
+ FrameOffset fr_offs,
+ ManagedRegister scratch) OVERRIDE;
- void StoreStackOffsetToThread32(ThreadOffset32 thr_offs, FrameOffset fr_offs,
- ManagedRegister scratch) OVERRIDE;
-
- void StoreStackPointerToThread32(ThreadOffset32 thr_offs) OVERRIDE;
+ void StoreStackPointerToThread(ThreadOffset32 thr_offs) OVERRIDE;
void StoreSpanning(FrameOffset dest, ManagedRegister src, FrameOffset in_off,
ManagedRegister scratch) OVERRIDE;
@@ -668,7 +675,7 @@
// Load routines
void Load(ManagedRegister dest, FrameOffset src, size_t size) OVERRIDE;
- void LoadFromThread32(ManagedRegister dest, ThreadOffset32 src, size_t size) OVERRIDE;
+ void LoadFromThread(ManagedRegister dest, ThreadOffset32 src, size_t size) OVERRIDE;
void LoadRef(ManagedRegister dest, FrameOffset src) OVERRIDE;
@@ -677,15 +684,16 @@
void LoadRawPtr(ManagedRegister dest, ManagedRegister base, Offset offs) OVERRIDE;
- void LoadRawPtrFromThread32(ManagedRegister dest, ThreadOffset32 offs) OVERRIDE;
+ void LoadRawPtrFromThread(ManagedRegister dest, ThreadOffset32 offs) OVERRIDE;
// Copying routines
void Move(ManagedRegister dest, ManagedRegister src, size_t size) OVERRIDE;
- void CopyRawPtrFromThread32(FrameOffset fr_offs, ThreadOffset32 thr_offs,
- ManagedRegister scratch) OVERRIDE;
+ void CopyRawPtrFromThread(FrameOffset fr_offs,
+ ThreadOffset32 thr_offs,
+ ManagedRegister scratch) OVERRIDE;
- void CopyRawPtrToThread32(ThreadOffset32 thr_offs, FrameOffset fr_offs, ManagedRegister scratch)
+ void CopyRawPtrToThread(ThreadOffset32 thr_offs, FrameOffset fr_offs, ManagedRegister scratch)
OVERRIDE;
void CopyRef(FrameOffset dest, FrameOffset src, ManagedRegister scratch) OVERRIDE;
@@ -742,7 +750,7 @@
// Call to address held at [base+offset]
void Call(ManagedRegister base, Offset offset, ManagedRegister scratch) OVERRIDE;
void Call(FrameOffset base, Offset offset, ManagedRegister scratch) OVERRIDE;
- void CallFromThread32(ThreadOffset32 offset, ManagedRegister scratch) OVERRIDE;
+ void CallFromThread(ThreadOffset32 offset, ManagedRegister scratch) OVERRIDE;
// Generate code to check if Thread::Current()->exception_ is non-null
// and branch to a ExceptionSlowPath if it is.
diff --git a/compiler/utils/x86_64/assembler_x86_64.cc b/compiler/utils/x86_64/assembler_x86_64.cc
index 977ce9d..ce4ea1d 100644
--- a/compiler/utils/x86_64/assembler_x86_64.cc
+++ b/compiler/utils/x86_64/assembler_x86_64.cc
@@ -2804,11 +2804,7 @@
movl(Address(CpuRegister(RSP), dest), Immediate(imm)); // TODO(64) movq?
}
-void X86_64Assembler::StoreImmediateToThread64(ThreadOffset64 dest, uint32_t imm, ManagedRegister) {
- gs()->movl(Address::Absolute(dest, true), Immediate(imm)); // TODO(64) movq?
-}
-
-void X86_64Assembler::StoreStackOffsetToThread64(ThreadOffset64 thr_offs,
+void X86_64Assembler::StoreStackOffsetToThread(ThreadOffset64 thr_offs,
FrameOffset fr_offs,
ManagedRegister mscratch) {
X86_64ManagedRegister scratch = mscratch.AsX86_64();
@@ -2817,7 +2813,7 @@
gs()->movq(Address::Absolute(thr_offs, true), scratch.AsCpuRegister());
}
-void X86_64Assembler::StoreStackPointerToThread64(ThreadOffset64 thr_offs) {
+void X86_64Assembler::StoreStackPointerToThread(ThreadOffset64 thr_offs) {
gs()->movq(Address::Absolute(thr_offs, true), CpuRegister(RSP));
}
@@ -2858,7 +2854,7 @@
}
}
-void X86_64Assembler::LoadFromThread64(ManagedRegister mdest, ThreadOffset64 src, size_t size) {
+void X86_64Assembler::LoadFromThread(ManagedRegister mdest, ThreadOffset64 src, size_t size) {
X86_64ManagedRegister dest = mdest.AsX86_64();
if (dest.IsNoRegister()) {
CHECK_EQ(0u, size);
@@ -2907,7 +2903,7 @@
movq(dest.AsCpuRegister(), Address(base.AsX86_64().AsCpuRegister(), offs));
}
-void X86_64Assembler::LoadRawPtrFromThread64(ManagedRegister mdest, ThreadOffset64 offs) {
+void X86_64Assembler::LoadRawPtrFromThread(ManagedRegister mdest, ThreadOffset64 offs) {
X86_64ManagedRegister dest = mdest.AsX86_64();
CHECK(dest.IsCpuRegister());
gs()->movq(dest.AsCpuRegister(), Address::Absolute(offs, true));
@@ -2968,7 +2964,7 @@
movl(Address(CpuRegister(RSP), dest), scratch.AsCpuRegister());
}
-void X86_64Assembler::CopyRawPtrFromThread64(FrameOffset fr_offs,
+void X86_64Assembler::CopyRawPtrFromThread(FrameOffset fr_offs,
ThreadOffset64 thr_offs,
ManagedRegister mscratch) {
X86_64ManagedRegister scratch = mscratch.AsX86_64();
@@ -2977,7 +2973,7 @@
Store(fr_offs, scratch, 8);
}
-void X86_64Assembler::CopyRawPtrToThread64(ThreadOffset64 thr_offs,
+void X86_64Assembler::CopyRawPtrToThread(ThreadOffset64 thr_offs,
FrameOffset fr_offs,
ManagedRegister mscratch) {
X86_64ManagedRegister scratch = mscratch.AsX86_64();
@@ -3130,7 +3126,7 @@
call(Address(scratch, offset));
}
-void X86_64Assembler::CallFromThread64(ThreadOffset64 offset, ManagedRegister /*mscratch*/) {
+void X86_64Assembler::CallFromThread(ThreadOffset64 offset, ManagedRegister /*mscratch*/) {
gs()->call(Address::Absolute(offset, true));
}
diff --git a/compiler/utils/x86_64/assembler_x86_64.h b/compiler/utils/x86_64/assembler_x86_64.h
index 52e39cf..d298da2 100644
--- a/compiler/utils/x86_64/assembler_x86_64.h
+++ b/compiler/utils/x86_64/assembler_x86_64.h
@@ -28,6 +28,7 @@
#include "offsets.h"
#include "utils/array_ref.h"
#include "utils/assembler.h"
+#include "utils/jni_macro_assembler.h"
namespace art {
namespace x86_64 {
@@ -332,11 +333,20 @@
};
-class X86_64Assembler FINAL : public Assembler {
+class X86_64Assembler FINAL : public Assembler, public JNIMacroAssembler<PointerSize::k64> {
public:
explicit X86_64Assembler(ArenaAllocator* arena) : Assembler(arena), constant_area_(arena) {}
virtual ~X86_64Assembler() {}
+ size_t CodeSize() const OVERRIDE { return Assembler::CodeSize(); }
+ DebugFrameOpCodeWriterForAssembler& cfi() { return Assembler::cfi(); }
+ void FinalizeCode() OVERRIDE {
+ Assembler::FinalizeCode();
+ }
+ void FinalizeInstructions(const MemoryRegion& region) {
+ Assembler::FinalizeInstructions(region);
+ }
+
/*
* Emit Machine Instructions.
*/
@@ -723,13 +733,11 @@
void StoreImmediateToFrame(FrameOffset dest, uint32_t imm, ManagedRegister scratch) OVERRIDE;
- void StoreImmediateToThread64(ThreadOffset64 dest, uint32_t imm, ManagedRegister scratch)
- OVERRIDE;
+ void StoreStackOffsetToThread(ThreadOffset64 thr_offs,
+ FrameOffset fr_offs,
+ ManagedRegister scratch) OVERRIDE;
- void StoreStackOffsetToThread64(ThreadOffset64 thr_offs, FrameOffset fr_offs,
- ManagedRegister scratch) OVERRIDE;
-
- void StoreStackPointerToThread64(ThreadOffset64 thr_offs) OVERRIDE;
+ void StoreStackPointerToThread(ThreadOffset64 thr_offs) OVERRIDE;
void StoreSpanning(FrameOffset dest, ManagedRegister src, FrameOffset in_off,
ManagedRegister scratch) OVERRIDE;
@@ -737,7 +745,7 @@
// Load routines
void Load(ManagedRegister dest, FrameOffset src, size_t size) OVERRIDE;
- void LoadFromThread64(ManagedRegister dest, ThreadOffset64 src, size_t size) OVERRIDE;
+ void LoadFromThread(ManagedRegister dest, ThreadOffset64 src, size_t size) OVERRIDE;
void LoadRef(ManagedRegister dest, FrameOffset src) OVERRIDE;
@@ -746,15 +754,16 @@
void LoadRawPtr(ManagedRegister dest, ManagedRegister base, Offset offs) OVERRIDE;
- void LoadRawPtrFromThread64(ManagedRegister dest, ThreadOffset64 offs) OVERRIDE;
+ void LoadRawPtrFromThread(ManagedRegister dest, ThreadOffset64 offs) OVERRIDE;
// Copying routines
void Move(ManagedRegister dest, ManagedRegister src, size_t size);
- void CopyRawPtrFromThread64(FrameOffset fr_offs, ThreadOffset64 thr_offs,
- ManagedRegister scratch) OVERRIDE;
+ void CopyRawPtrFromThread(FrameOffset fr_offs,
+ ThreadOffset64 thr_offs,
+ ManagedRegister scratch) OVERRIDE;
- void CopyRawPtrToThread64(ThreadOffset64 thr_offs, FrameOffset fr_offs, ManagedRegister scratch)
+ void CopyRawPtrToThread(ThreadOffset64 thr_offs, FrameOffset fr_offs, ManagedRegister scratch)
OVERRIDE;
void CopyRef(FrameOffset dest, FrameOffset src, ManagedRegister scratch) OVERRIDE;
@@ -812,7 +821,7 @@
// Call to address held at [base+offset]
void Call(ManagedRegister base, Offset offset, ManagedRegister scratch) OVERRIDE;
void Call(FrameOffset base, Offset offset, ManagedRegister scratch) OVERRIDE;
- void CallFromThread64(ThreadOffset64 offset, ManagedRegister scratch) OVERRIDE;
+ void CallFromThread(ThreadOffset64 offset, ManagedRegister scratch) OVERRIDE;
// Generate code to check if Thread::Current()->exception_ is non-null
// and branch to a ExceptionSlowPath if it is.
diff --git a/runtime/arch/arm64/quick_entrypoints_arm64.S b/runtime/arch/arm64/quick_entrypoints_arm64.S
index 415bb71..c8181ba 100644
--- a/runtime/arch/arm64/quick_entrypoints_arm64.S
+++ b/runtime/arch/arm64/quick_entrypoints_arm64.S
@@ -1788,7 +1788,20 @@
ONE_ARG_DOWNCALL art_quick_resolve_string, artResolveStringFromCode, RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
// Generate the allocation entrypoints for each allocator.
-GENERATE_ALLOC_ENTRYPOINTS_FOR_EACH_ALLOCATOR
+GENERATE_ALLOC_ENTRYPOINTS_FOR_NON_REGION_ALLOCATORS
+// Comment out allocators that have arm64 specific asm.
+// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT(_region_tlab, RegionTLAB) implemented in asm
+// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_RESOLVED(_region_tlab, RegionTLAB)
+// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_INITIALIZED(_region_tlab, RegionTLAB)
+GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_WITH_ACCESS_CHECK(_region_tlab, RegionTLAB)
+// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY(_region_tlab, RegionTLAB) implemented in asm
+// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED(_region_tlab, RegionTLAB)
+GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_WITH_ACCESS_CHECK(_region_tlab, RegionTLAB)
+GENERATE_ALLOC_ENTRYPOINTS_CHECK_AND_ALLOC_ARRAY(_region_tlab, RegionTLAB)
+GENERATE_ALLOC_ENTRYPOINTS_CHECK_AND_ALLOC_ARRAY_WITH_ACCESS_CHECK(_region_tlab, RegionTLAB)
+GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_BYTES(_region_tlab, RegionTLAB)
+GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_CHARS(_region_tlab, RegionTLAB)
+GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_STRING(_region_tlab, RegionTLAB)
// A hand-written override for GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT(_rosalloc, RosAlloc).
ENTRY art_quick_alloc_object_rosalloc
@@ -1895,6 +1908,63 @@
RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
END art_quick_alloc_object_rosalloc
+
+// The common fast path code for art_quick_alloc_array_region_tlab.
+.macro ALLOC_ARRAY_TLAB_FAST_PATH slowPathLabel, xClass, wClass, xCount, wCount, xTemp0, wTemp0, xTemp1, wTemp1, xTemp2, wTemp2
+ // Check null class
+ cbz \wClass, \slowPathLabel
+ ALLOC_ARRAY_TLAB_FAST_PATH_RESOLVED \slowPathLabel, \xClass, \wClass, \xCount, \wCount, \xTemp0, \wTemp0, \xTemp1, \wTemp1, \xTemp2, \wTemp2
+.endm
+
+// The common fast path code for art_quick_alloc_array_region_tlab.
+.macro ALLOC_ARRAY_TLAB_FAST_PATH_RESOLVED slowPathLabel, xClass, wClass, xCount, wCount, xTemp0, wTemp0, xTemp1, wTemp1, xTemp2, wTemp2
+ // Arrays are never finalizable, no need to check.
+ ldr \wTemp0, [\xClass, #MIRROR_CLASS_COMPONENT_TYPE_OFFSET] // Load component type
+ ldr \wTemp0, [\xTemp0, #MIRROR_CLASS_OBJECT_PRIMITIVE_TYPE_OFFSET]
+ lsr \xTemp0, \xTemp0, #PRIMITIVE_TYPE_SIZE_SHIFT_SHIFT // Component size shift is in high 16
+ // bits.
+ lsl \xTemp1, \xCount, \xTemp0 // Calculate data size
+ // Add array data offset and alignment.
+ add \xTemp1, \xTemp1, #(MIRROR_INT_ARRAY_DATA_OFFSET + OBJECT_ALIGNMENT_MASK)
+ add \xTemp0, \xTemp0, #1 // Add 4 to the length only if the
+ // component size shift is 3
+ // (for 64 bit alignment).
+ and \xTemp0, \xTemp0, #4
+ add \xTemp1, \xTemp1, \xTemp0
+ ldr \xTemp0, [xSELF, #THREAD_LOCAL_POS_OFFSET] // Check tlab for space, note that
+ // we use (end - begin) to handle
+ // negative size arrays.
+ ldr \xTemp2, [xSELF, #THREAD_LOCAL_END_OFFSET]
+ sub \xTemp2, \xTemp2, \xTemp0
+ cmp \xTemp1, \xTemp2
+ bhi \slowPathLabel
+
+ // "Point of no slow path". Won't go to the slow path from here on. OK to clobber x0 and x1.
+ // Round up the object size by the
+ // object alignment. (addr + 7) & ~7.
+ and \xTemp1, \xTemp1, #OBJECT_ALIGNMENT_MASK_TOGGLED
+ // Move old thread_local_pos to x0
+ // for the return value.
+ mov x0, \xTemp0
+ add \xTemp0, \xTemp0, \xTemp1
+ str \xTemp0, [xSELF, #THREAD_LOCAL_POS_OFFSET] // Store new thread_local_pos.
+ ldr \xTemp0, [xSELF, #THREAD_LOCAL_OBJECTS_OFFSET] // Increment thread_local_objects.
+ add \xTemp0, \xTemp0, #1
+ str \xTemp0, [xSELF, #THREAD_LOCAL_OBJECTS_OFFSET]
+ POISON_HEAP_REF \wClass
+ str \wClass, [x0, #MIRROR_OBJECT_CLASS_OFFSET] // Store the class pointer.
+ str \wCount, [x0, #MIRROR_ARRAY_LENGTH_OFFSET] // Store the array length.
+ // Fence. This is "ish" not "ishst" so
+ // that the code after this allocation
+ // site will see the right values in
+ // the fields of the class.
+ // Alternatively we could use "ishst"
+ // if we use load-acquire for the
+ // class status load.)
+ dmb ish
+ ret
+.endm
+
// The common fast path code for art_quick_alloc_object_tlab and art_quick_alloc_object_region_tlab.
//
// x0: type_idx/return value, x1: ArtMethod*, x2: Class*, xSELF(x19): Thread::Current
@@ -1902,8 +1972,11 @@
// Need to preserve x0 and x1 to the slow path.
.macro ALLOC_OBJECT_TLAB_FAST_PATH slowPathLabel
cbz x2, \slowPathLabel // Check null class
- // Check class status.
- ldr w3, [x2, #MIRROR_CLASS_STATUS_OFFSET]
+ ALLOC_OBJECT_TLAB_FAST_PATH_RESOLVED \slowPathLabel
+.endm
+
+.macro ALLOC_OBJECT_TLAB_FAST_PATH_RESOLVED slowPathLabel
+ ldr w3, [x2, #MIRROR_CLASS_STATUS_OFFSET] // Check class status.
cmp x3, #MIRROR_CLASS_STATUS_INITIALIZED
bne \slowPathLabel
// Add a fake dependence from the
@@ -1916,6 +1989,10 @@
// a load-acquire for the status).
eor x3, x3, x3
add x2, x2, x3
+ ALLOC_OBJECT_TLAB_FAST_PATH_INITIALIZED \slowPathLabel
+.endm
+
+.macro ALLOC_OBJECT_TLAB_FAST_PATH_INITIALIZED slowPathLabel
// Check access flags has
// kAccClassIsFinalizable.
ldr w3, [x2, #MIRROR_CLASS_ACCESS_FLAGS_OFFSET]
@@ -1978,7 +2055,8 @@
END art_quick_alloc_object_tlab
// A hand-written override for GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT(_region_tlab, RegionTLAB)
-ENTRY art_quick_alloc_object_region_tlab
+.macro GENERATE_ALLOC_OBJECT_REGION_TLAB name, entrypoint, fast_path, is_resolved
+ENTRY \name
// Fast path region tlab allocation.
// x0: type_idx/return value, x1: ArtMethod*, xSELF(x19): Thread::Current
// x2-x7: free.
@@ -1986,23 +2064,26 @@
mvn x0, xzr // Read barrier must be enabled here.
ret // Return -1.
#endif
+.if \is_resolved
+ mov x2, x0 // class is actually stored in x0 already
+.else
ldr x2, [x1, #ART_METHOD_DEX_CACHE_TYPES_OFFSET_64] // Load dex cache resolved types array
// Load the class (x2)
ldr w2, [x2, x0, lsl #COMPRESSED_REFERENCE_SIZE_SHIFT]
-
+.endif
// Most common case: GC is not marking.
ldr w3, [xSELF, #THREAD_IS_GC_MARKING_OFFSET]
- cbnz x3, .Lart_quick_alloc_object_region_tlab_marking
-.Lart_quick_alloc_object_region_tlab_do_allocation:
- ALLOC_OBJECT_TLAB_FAST_PATH .Lart_quick_alloc_object_region_tlab_slow_path
-.Lart_quick_alloc_object_region_tlab_marking:
+ cbnz x3, .Lmarking\name
+.Ldo_allocation\name:
+ \fast_path .Lslow_path\name
+.Lmarking\name:
// GC is marking, check the lock word of the class for the mark bit.
// If the class is null, go slow path. The check is required to read the lock word.
- cbz w2, .Lart_quick_alloc_object_region_tlab_slow_path
+ cbz w2, .Lslow_path\name
// Class is not null, check mark bit in lock word.
ldr w3, [x2, #MIRROR_OBJECT_LOCK_WORD_OFFSET]
// If the bit is not zero, do the allocation.
- tbnz w3, #LOCK_WORD_MARK_BIT_SHIFT, .Lart_quick_alloc_object_region_tlab_do_allocation
+ tbnz w3, #LOCK_WORD_MARK_BIT_SHIFT, .Ldo_allocation\name
// The read barrier slow path. Mark
// the class.
stp x0, x1, [sp, #-32]! // Save registers (x0, x1, lr).
@@ -2013,14 +2094,82 @@
ldp x0, x1, [sp, #0] // Restore registers.
ldr xLR, [sp, #16]
add sp, sp, #32
- b .Lart_quick_alloc_object_region_tlab_do_allocation
-.Lart_quick_alloc_object_region_tlab_slow_path:
+ b .Ldo_allocation\name
+.Lslow_path\name:
SETUP_REFS_ONLY_CALLEE_SAVE_FRAME // Save callee saves in case of GC.
mov x2, xSELF // Pass Thread::Current.
- bl artAllocObjectFromCodeRegionTLAB // (uint32_t type_idx, Method* method, Thread*)
+ bl \entrypoint // (uint32_t type_idx, Method* method, Thread*)
RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME
RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
-END art_quick_alloc_object_region_tlab
+END \name
+.endm
+
+GENERATE_ALLOC_OBJECT_REGION_TLAB art_quick_alloc_object_region_tlab, artAllocObjectFromCodeRegionTLAB, ALLOC_OBJECT_TLAB_FAST_PATH, 0
+GENERATE_ALLOC_OBJECT_REGION_TLAB art_quick_alloc_object_resolved_region_tlab, artAllocObjectFromCodeResolvedRegionTLAB, ALLOC_OBJECT_TLAB_FAST_PATH_RESOLVED, 1
+GENERATE_ALLOC_OBJECT_REGION_TLAB art_quick_alloc_object_initialized_region_tlab, artAllocObjectFromCodeInitializedRegionTLAB, ALLOC_OBJECT_TLAB_FAST_PATH_INITIALIZED, 1
+
+// A hand-written override for GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY*(_region_tlab, RegionTLAB)
+.macro GENERATE_ALLOC_ARRAY_REGION_TLAB name, entrypoint, fast_path, is_resolved
+ENTRY \name
+ // Fast path array allocation for region tlab allocation.
+ // x0: uint32_t type_idx
+ // x1: int32_t component_count
+ // x2: ArtMethod* method
+ // x3: Thread* self
+ // x2-x7: free.
+#if !defined(USE_READ_BARRIER)
+ mvn x0, xzr // Read barrier must be enabled here.
+ ret // Return -1.
+#endif
+.if \is_resolved
+ mov x3, x0
+ // If already resolved, class is stored in x0
+.else
+ ldr x3, [x2, #ART_METHOD_DEX_CACHE_TYPES_OFFSET_64] // Load dex cache resolved types array
+ // Load the class (x2)
+ ldr w3, [x3, x0, lsl #COMPRESSED_REFERENCE_SIZE_SHIFT]
+.endif
+ // Most common case: GC is not marking.
+ ldr w4, [xSELF, #THREAD_IS_GC_MARKING_OFFSET]
+ cbnz x4, .Lmarking\name
+.Ldo_allocation\name:
+ \fast_path .Lslow_path\name, x3, w3, x1, w1, x4, w4, x5, w5, x6, w6
+.Lmarking\name:
+ // GC is marking, check the lock word of the class for the mark bit.
+ // If the class is null, go slow path. The check is required to read the lock word.
+ cbz w3, .Lslow_path\name
+ // Class is not null, check mark bit in lock word.
+ ldr w4, [x3, #MIRROR_OBJECT_LOCK_WORD_OFFSET]
+ // If the bit is not zero, do the allocation.
+ tbnz w4, #LOCK_WORD_MARK_BIT_SHIFT, .Ldo_allocation\name
+ b .Lslow_path\name
+ // The read barrier slow path. Mark
+ // the class.
+ stp x0, x1, [sp, #-32]! // Save registers (x0, x1, x2, lr).
+ stp x2, xLR, [sp, #16]
+ mov x0, x3 // Pass the class as the first param.
+ bl artReadBarrierMark
+ mov x3, x0 // Get the (marked) class back.
+ ldp x0, x1, [sp, #0] // Restore registers.
+ ldp x2, xLR, [sp, #16]
+ add sp, sp, #32
+ b .Ldo_allocation\name
+.Lslow_path\name:
+ // x0: uint32_t type_idx
+ // x1: int32_t component_count
+ // x2: ArtMethod* method
+ // x3: Thread* self
+ SETUP_REFS_ONLY_CALLEE_SAVE_FRAME // save callee saves in case of GC
+ mov x3, xSELF // pass Thread::Current
+ bl \entrypoint
+ RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME
+ RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
+END \name
+.endm
+
+GENERATE_ALLOC_ARRAY_REGION_TLAB art_quick_alloc_array_region_tlab, artAllocArrayFromCodeRegionTLAB, ALLOC_ARRAY_TLAB_FAST_PATH, 0
+// TODO: art_quick_alloc_array_resolved_region_tlab seems to not get called. Investigate compiler.
+GENERATE_ALLOC_ARRAY_REGION_TLAB art_quick_alloc_array_resolved_region_tlab, artAllocArrayFromCodeResolvedRegionTLAB, ALLOC_ARRAY_TLAB_FAST_PATH_RESOLVED, 1
/*
* Called by managed code when the thread has been asked to suspend.
diff --git a/runtime/arch/quick_alloc_entrypoints.S b/runtime/arch/quick_alloc_entrypoints.S
index 290769b..34e74a1 100644
--- a/runtime/arch/quick_alloc_entrypoints.S
+++ b/runtime/arch/quick_alloc_entrypoints.S
@@ -87,6 +87,27 @@
ONE_ARG_DOWNCALL art_quick_alloc_string_from_string ## c_suffix, artAllocStringFromStringFromCode ## cxx_suffix, RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
.macro GENERATE_ALLOC_ENTRYPOINTS_FOR_EACH_ALLOCATOR
+GENERATE_ALLOC_ENTRYPOINTS_FOR_NON_REGION_ALLOCATORS
+GENERATE_ALLOC_ENTRYPOINTS_FOR_REGION_ALLOCATOR
+.endm
+
+.macro GENERATE_ALLOC_ENTRYPOINTS_FOR_REGION_ALLOCATOR
+// This is to be separately defined for each architecture to allow a hand-written assembly fast path.
+// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT(_region_tlab, RegionTLAB)
+GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_RESOLVED(_region_tlab, RegionTLAB)
+GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_INITIALIZED(_region_tlab, RegionTLAB)
+GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_WITH_ACCESS_CHECK(_region_tlab, RegionTLAB)
+GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY(_region_tlab, RegionTLAB)
+GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED(_region_tlab, RegionTLAB)
+GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_WITH_ACCESS_CHECK(_region_tlab, RegionTLAB)
+GENERATE_ALLOC_ENTRYPOINTS_CHECK_AND_ALLOC_ARRAY(_region_tlab, RegionTLAB)
+GENERATE_ALLOC_ENTRYPOINTS_CHECK_AND_ALLOC_ARRAY_WITH_ACCESS_CHECK(_region_tlab, RegionTLAB)
+GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_BYTES(_region_tlab, RegionTLAB)
+GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_CHARS(_region_tlab, RegionTLAB)
+GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_STRING(_region_tlab, RegionTLAB)
+.endm
+
+.macro GENERATE_ALLOC_ENTRYPOINTS_FOR_NON_REGION_ALLOCATORS
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT(_dlmalloc, DlMalloc)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_RESOLVED(_dlmalloc, DlMalloc)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_INITIALIZED(_dlmalloc, DlMalloc)
@@ -219,20 +240,6 @@
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_CHARS(_region_instrumented, RegionInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_STRING(_region_instrumented, RegionInstrumented)
-// This is to be separately defined for each architecture to allow a hand-written assembly fast path.
-// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT(_region_tlab, RegionTLAB)
-GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_RESOLVED(_region_tlab, RegionTLAB)
-GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_INITIALIZED(_region_tlab, RegionTLAB)
-GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_WITH_ACCESS_CHECK(_region_tlab, RegionTLAB)
-GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY(_region_tlab, RegionTLAB)
-GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED(_region_tlab, RegionTLAB)
-GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_WITH_ACCESS_CHECK(_region_tlab, RegionTLAB)
-GENERATE_ALLOC_ENTRYPOINTS_CHECK_AND_ALLOC_ARRAY(_region_tlab, RegionTLAB)
-GENERATE_ALLOC_ENTRYPOINTS_CHECK_AND_ALLOC_ARRAY_WITH_ACCESS_CHECK(_region_tlab, RegionTLAB)
-GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_BYTES(_region_tlab, RegionTLAB)
-GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_CHARS(_region_tlab, RegionTLAB)
-GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_STRING(_region_tlab, RegionTLAB)
-
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT(_region_tlab_instrumented, RegionTLABInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_RESOLVED(_region_tlab_instrumented, RegionTLABInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_INITIALIZED(_region_tlab_instrumented, RegionTLABInstrumented)
diff --git a/runtime/asm_support.h b/runtime/asm_support.h
index 0619af8..87b0bcb 100644
--- a/runtime/asm_support.h
+++ b/runtime/asm_support.h
@@ -174,10 +174,17 @@
#define MIRROR_CLASS_OBJECT_SIZE_OFFSET (100 + MIRROR_OBJECT_HEADER_SIZE)
ADD_TEST_EQ(MIRROR_CLASS_OBJECT_SIZE_OFFSET,
art::mirror::Class::ObjectSizeOffset().Int32Value())
+#define MIRROR_CLASS_OBJECT_PRIMITIVE_TYPE_OFFSET (104 + MIRROR_OBJECT_HEADER_SIZE)
+ADD_TEST_EQ(MIRROR_CLASS_OBJECT_PRIMITIVE_TYPE_OFFSET,
+ art::mirror::Class::PrimitiveTypeOffset().Int32Value())
#define MIRROR_CLASS_STATUS_OFFSET (112 + MIRROR_OBJECT_HEADER_SIZE)
ADD_TEST_EQ(MIRROR_CLASS_STATUS_OFFSET,
art::mirror::Class::StatusOffset().Int32Value())
+#define PRIMITIVE_TYPE_SIZE_SHIFT_SHIFT 16
+ADD_TEST_EQ(PRIMITIVE_TYPE_SIZE_SHIFT_SHIFT,
+ static_cast<int>(art::mirror::Class::kPrimitiveTypeSizeShiftShift))
+
// Array offsets.
#define MIRROR_ARRAY_LENGTH_OFFSET MIRROR_OBJECT_HEADER_SIZE
ADD_TEST_EQ(MIRROR_ARRAY_LENGTH_OFFSET, art::mirror::Array::LengthOffset().Int32Value())
diff --git a/runtime/mirror/class-inl.h b/runtime/mirror/class-inl.h
index 8f5419c..8ad47eb 100644
--- a/runtime/mirror/class-inl.h
+++ b/runtime/mirror/class-inl.h
@@ -636,8 +636,9 @@
static_assert(sizeof(Primitive::Type) == sizeof(int32_t),
"art::Primitive::Type and int32_t have different sizes.");
int32_t v32 = GetField32<kVerifyFlags>(OFFSET_OF_OBJECT_MEMBER(Class, primitive_type_));
- Primitive::Type type = static_cast<Primitive::Type>(v32 & 0xFFFF);
- DCHECK_EQ(static_cast<size_t>(v32 >> 16), Primitive::ComponentSizeShift(type));
+ Primitive::Type type = static_cast<Primitive::Type>(v32 & kPrimitiveTypeMask);
+ DCHECK_EQ(static_cast<size_t>(v32 >> kPrimitiveTypeSizeShiftShift),
+ Primitive::ComponentSizeShift(type));
return type;
}
@@ -646,8 +647,9 @@
static_assert(sizeof(Primitive::Type) == sizeof(int32_t),
"art::Primitive::Type and int32_t have different sizes.");
int32_t v32 = GetField32<kVerifyFlags>(OFFSET_OF_OBJECT_MEMBER(Class, primitive_type_));
- size_t size_shift = static_cast<Primitive::Type>(v32 >> 16);
- DCHECK_EQ(size_shift, Primitive::ComponentSizeShift(static_cast<Primitive::Type>(v32 & 0xFFFF)));
+ size_t size_shift = static_cast<Primitive::Type>(v32 >> kPrimitiveTypeSizeShiftShift);
+ DCHECK_EQ(size_shift,
+ Primitive::ComponentSizeShift(static_cast<Primitive::Type>(v32 & kPrimitiveTypeMask)));
return size_shift;
}
diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h
index 5c490de..8f6ce44 100644
--- a/runtime/mirror/class.h
+++ b/runtime/mirror/class.h
@@ -64,6 +64,12 @@
// 2 ref instance fields.]
static constexpr uint32_t kClassWalkSuper = 0xC0000000;
+ // Shift primitive type by kPrimitiveTypeSizeShiftShift to get the component type size shift
+ // Used for computing array size as follows:
+ // array_bytes = header_size + (elements << (primitive_type >> kPrimitiveTypeSizeShiftShift))
+ static constexpr uint32_t kPrimitiveTypeSizeShiftShift = 16;
+ static constexpr uint32_t kPrimitiveTypeMask = (1u << kPrimitiveTypeSizeShiftShift) - 1;
+
// Class Status
//
// kStatusRetired: Class that's temporarily used till class linking time
@@ -371,10 +377,10 @@
void SetPrimitiveType(Primitive::Type new_type) SHARED_REQUIRES(Locks::mutator_lock_) {
DCHECK_EQ(sizeof(Primitive::Type), sizeof(int32_t));
- int32_t v32 = static_cast<int32_t>(new_type);
- DCHECK_EQ(v32 & 0xFFFF, v32) << "upper 16 bits aren't zero";
+ uint32_t v32 = static_cast<uint32_t>(new_type);
+ DCHECK_EQ(v32 & kPrimitiveTypeMask, v32) << "upper 16 bits aren't zero";
// Store the component size shift in the upper 16 bits.
- v32 |= Primitive::ComponentSizeShift(new_type) << 16;
+ v32 |= Primitive::ComponentSizeShift(new_type) << kPrimitiveTypeSizeShiftShift;
SetField32<false>(OFFSET_OF_OBJECT_MEMBER(Class, primitive_type_), v32);
}
diff --git a/test/004-JniTest/src/Main.java b/test/004-JniTest/src/Main.java
index e0530d8..0221900 100644
--- a/test/004-JniTest/src/Main.java
+++ b/test/004-JniTest/src/Main.java
@@ -220,7 +220,7 @@
InvocationHandler handler = new DummyInvocationHandler();
SimpleInterface proxy =
(SimpleInterface) Proxy.newProxyInstance(SimpleInterface.class.getClassLoader(),
- new Class[] {SimpleInterface.class}, handler);
+ new Class<?>[] {SimpleInterface.class}, handler);
if (testGetMethodID(SimpleInterface.class) == 0) {
throw new AssertionError();
}
diff --git a/test/004-UnsafeTest/src/Main.java b/test/004-UnsafeTest/src/Main.java
index 9d4618a..d43d374 100644
--- a/test/004-UnsafeTest/src/Main.java
+++ b/test/004-UnsafeTest/src/Main.java
@@ -249,6 +249,6 @@
public volatile Object volatileObjectVar = null;
}
- private static native int vmArrayBaseOffset(Class clazz);
- private static native int vmArrayIndexScale(Class clazz);
+ private static native int vmArrayBaseOffset(Class<?> clazz);
+ private static native int vmArrayIndexScale(Class<?> clazz);
}
diff --git a/test/005-annotations/src/android/test/anno/AnnoFancyMethod.java b/test/005-annotations/src/android/test/anno/AnnoFancyMethod.java
index 3088866..aa7808f 100644
--- a/test/005-annotations/src/android/test/anno/AnnoFancyMethod.java
+++ b/test/005-annotations/src/android/test/anno/AnnoFancyMethod.java
@@ -10,5 +10,5 @@
boolean callMe() default false;
boolean biteMe();
AnnoFancyMethodEnum enumerated() default AnnoFancyMethodEnum.FOO;
- Class someClass() default SomeClass.class;
+ Class<?> someClass() default SomeClass.class;
}
diff --git a/test/005-annotations/src/android/test/anno/AnnoMissingClass.java b/test/005-annotations/src/android/test/anno/AnnoMissingClass.java
index c32e9a2..7933b80 100644
--- a/test/005-annotations/src/android/test/anno/AnnoMissingClass.java
+++ b/test/005-annotations/src/android/test/anno/AnnoMissingClass.java
@@ -20,5 +20,5 @@
@Retention(RetentionPolicy.RUNTIME)
public @interface AnnoMissingClass {
- Class value();
+ Class<?> value();
}
diff --git a/test/005-annotations/src/android/test/anno/TestAnnotations.java b/test/005-annotations/src/android/test/anno/TestAnnotations.java
index 51254b4..8ea8e8e 100644
--- a/test/005-annotations/src/android/test/anno/TestAnnotations.java
+++ b/test/005-annotations/src/android/test/anno/TestAnnotations.java
@@ -42,7 +42,7 @@
}
}
- static void printAnnotations(Class clazz) {
+ static void printAnnotations(Class<?> clazz) {
Annotation[] annos;
Annotation[][] parAnnos;
@@ -52,7 +52,7 @@
printAnnotationArray("", annos);
System.out.println();
- for (Constructor c: clazz.getDeclaredConstructors()) {
+ for (Constructor<?> c: clazz.getDeclaredConstructors()) {
annos = c.getDeclaredAnnotations();
System.out.println(" annotations on CTOR " + c + ":");
printAnnotationArray(" ", annos);
@@ -139,8 +139,7 @@
final IntToString[] mapping;
try {
- meth = TestAnnotations.class.getMethod("getFocusType",
- (Class[])null);
+ meth = TestAnnotations.class.getMethod("getFocusType");
} catch (NoSuchMethodException nsme) {
throw new RuntimeException(nsme);
}
@@ -255,7 +254,7 @@
}
private static class VMRuntime {
- private static Class vmRuntimeClass;
+ private static Class<?> vmRuntimeClass;
private static Method getRuntimeMethod;
private static Method getTargetSdkVersionMethod;
private static Method setTargetSdkVersionMethod;
diff --git a/test/021-string2/src/Main.java b/test/021-string2/src/Main.java
index 0226614..d1ea0b1 100644
--- a/test/021-string2/src/Main.java
+++ b/test/021-string2/src/Main.java
@@ -85,7 +85,7 @@
Assert.assertEquals("this is a path", test.replaceAll("/", " "));
Assert.assertEquals("this is a path", test.replace("/", " "));
- Class Strings = Class.forName("com.android.org.bouncycastle.util.Strings");
+ Class<?> Strings = Class.forName("com.android.org.bouncycastle.util.Strings");
Method fromUTF8ByteArray = Strings.getDeclaredMethod("fromUTF8ByteArray", byte[].class);
String result = (String) fromUTF8ByteArray.invoke(null, new byte[] {'O', 'K'});
System.out.println(result);
diff --git a/test/031-class-attributes/src/ClassAttrs.java b/test/031-class-attributes/src/ClassAttrs.java
index 38bd525..346e13d 100644
--- a/test/031-class-attributes/src/ClassAttrs.java
+++ b/test/031-class-attributes/src/ClassAttrs.java
@@ -118,14 +118,13 @@
printClassAttrs(FancyClass.class);
try {
- Constructor cons;
- cons = MemberClass.class.getConstructor(
- new Class[] { MemberClass.class });
+ Constructor<?> cons;
+ cons = MemberClass.class.getConstructor(MemberClass.class);
System.out.println("constructor signature: "
+ getSignatureAttribute(cons));
Method meth;
- meth = MemberClass.class.getMethod("foo", (Class[]) null);
+ meth = MemberClass.class.getMethod("foo");
System.out.println("method signature: "
+ getSignatureAttribute(meth));
@@ -222,7 +221,7 @@
public static String getSignatureAttribute(Object obj) {
Method method;
try {
- Class c = obj.getClass();
+ Class<?> c = obj.getClass();
if (c == Method.class || c == Constructor.class) {
c = AbstractMethod.class;
}
@@ -263,9 +262,7 @@
/*
* Dump a variety of class attributes.
*/
- public static void printClassAttrs(Class clazz) {
- Class clazz2;
-
+ public static <T> void printClassAttrs(Class<T> clazz) {
System.out.println("***** " + clazz + ":");
System.out.println(" name: "
@@ -321,7 +318,7 @@
System.out.println(" genericInterfaces: "
+ stringifyTypeArray(clazz.getGenericInterfaces()));
- TypeVariable<Class<?>>[] typeParameters = clazz.getTypeParameters();
+ TypeVariable<Class<T>>[] typeParameters = clazz.getTypeParameters();
System.out.println(" typeParameters: "
+ stringifyTypeArray(typeParameters));
}
diff --git a/test/032-concrete-sub/src/ConcreteSub.java b/test/032-concrete-sub/src/ConcreteSub.java
index 083f25d..95adf63 100644
--- a/test/032-concrete-sub/src/ConcreteSub.java
+++ b/test/032-concrete-sub/src/ConcreteSub.java
@@ -37,13 +37,13 @@
/*
* Check reflection stuff.
*/
- Class absClass = AbstractBase.class;
+ Class<?> absClass = AbstractBase.class;
Method meth;
System.out.println("class modifiers=" + absClass.getModifiers());
try {
- meth = absClass.getMethod("redefineMe", (Class[]) null);
+ meth = absClass.getMethod("redefineMe");
} catch (NoSuchMethodException nsme) {
nsme.printStackTrace();
return;
diff --git a/test/042-new-instance/src/Main.java b/test/042-new-instance/src/Main.java
index 8cd6b2e..755d62e 100644
--- a/test/042-new-instance/src/Main.java
+++ b/test/042-new-instance/src/Main.java
@@ -33,7 +33,7 @@
static void testClassNewInstance() {
// should succeed
try {
- Class c = Class.forName("LocalClass");
+ Class<?> c = Class.forName("LocalClass");
Object obj = c.newInstance();
System.out.println("LocalClass succeeded");
} catch (Exception ex) {
@@ -43,7 +43,7 @@
// should fail
try {
- Class c = Class.forName("otherpackage.PackageAccess");
+ Class<?> c = Class.forName("otherpackage.PackageAccess");
Object obj = c.newInstance();
System.err.println("ERROR: PackageAccess succeeded unexpectedly");
} catch (IllegalAccessException iae) {
@@ -71,8 +71,8 @@
static void testConstructorNewInstance() {
// should fail -- getConstructor only returns public constructors
try {
- Class c = Class.forName("LocalClass");
- Constructor cons = c.getConstructor(new Class[0] /*(Class[])null*/);
+ Class<?> c = Class.forName("LocalClass");
+ Constructor<?> cons = c.getConstructor();
System.err.println("Cons LocalClass succeeded unexpectedly");
} catch (NoSuchMethodException nsme) {
System.out.println("Cons LocalClass failed as expected");
@@ -83,8 +83,8 @@
// should succeed
try {
- Class c = Class.forName("LocalClass2");
- Constructor cons = c.getConstructor((Class[]) null);
+ Class<?> c = Class.forName("LocalClass2");
+ Constructor<?> cons = c.getConstructor();
Object obj = cons.newInstance();
System.out.println("Cons LocalClass2 succeeded");
} catch (Exception ex) {
@@ -94,8 +94,8 @@
// should succeed
try {
- Class c = Class.forName("Main$InnerClass");
- Constructor cons = c.getDeclaredConstructor(new Class<?>[]{Main.class});
+ Class<?> c = Class.forName("Main$InnerClass");
+ Constructor<?> cons = c.getDeclaredConstructor(Main.class);
Object obj = cons.newInstance(new Main());
System.out.println("Cons InnerClass succeeded");
} catch (Exception ex) {
@@ -105,8 +105,8 @@
// should succeed
try {
- Class c = Class.forName("Main$StaticInnerClass");
- Constructor cons = c.getDeclaredConstructor((Class[]) null);
+ Class<?> c = Class.forName("Main$StaticInnerClass");
+ Constructor<?> cons = c.getDeclaredConstructor();
Object obj = cons.newInstance();
System.out.println("Cons StaticInnerClass succeeded");
} catch (Exception ex) {
@@ -116,8 +116,8 @@
// should fail
try {
- Class c = Class.forName("otherpackage.PackageAccess");
- Constructor cons = c.getConstructor(new Class[0] /*(Class[])null*/);
+ Class<?> c = Class.forName("otherpackage.PackageAccess");
+ Constructor<?> cons = c.getConstructor();
System.err.println("ERROR: Cons PackageAccess succeeded unexpectedly");
} catch (NoSuchMethodException nsme) {
// constructor isn't public
@@ -129,8 +129,8 @@
// should fail
try {
- Class c = Class.forName("MaybeAbstract");
- Constructor cons = c.getConstructor(new Class[0] /*(Class[])null*/);
+ Class<?> c = Class.forName("MaybeAbstract");
+ Constructor<?> cons = c.getConstructor();
Object obj = cons.newInstance();
System.err.println("ERROR: Cons MaybeAbstract succeeded unexpectedly");
} catch (InstantiationException ie) {
@@ -143,8 +143,8 @@
// should fail
try {
- Class c = Class.forName("otherpackage.PackageAccess2");
- Constructor cons = c.getConstructor((Class[]) null);
+ Class<?> c = Class.forName("otherpackage.PackageAccess2");
+ Constructor<?> cons = c.getConstructor();
if (!FULL_ACCESS_CHECKS) { throw new IllegalAccessException(); }
Object obj = cons.newInstance();
System.err.println("ERROR: Cons PackageAccess2 succeeded unexpectedly");
@@ -197,7 +197,7 @@
static Object newInstance() {
try {
- Class c = CC.class;
+ Class<?> c = CC.class;
return c.newInstance();
} catch (Exception ex) {
ex.printStackTrace();
diff --git a/test/042-new-instance/src/otherpackage/ConstructorAccess.java b/test/042-new-instance/src/otherpackage/ConstructorAccess.java
index a74e9a0..79d572c 100644
--- a/test/042-new-instance/src/otherpackage/ConstructorAccess.java
+++ b/test/042-new-instance/src/otherpackage/ConstructorAccess.java
@@ -29,8 +29,8 @@
// accessibility using the frame below (in Main class), we will see an
// IllegalAccessException from #newInstance
static public void newConstructorInstance() throws Exception {
- Class c = Inner.class;
- Constructor cons = c.getDeclaredConstructor((Class[]) null);
+ Class<?> c = Inner.class;
+ Constructor cons = c.getDeclaredConstructor();
Object obj = cons.newInstance();
}
}
diff --git a/test/044-proxy/src/BasicTest.java b/test/044-proxy/src/BasicTest.java
index 445a6cc..5f04b93 100644
--- a/test/044-proxy/src/BasicTest.java
+++ b/test/044-proxy/src/BasicTest.java
@@ -99,18 +99,16 @@
InvocationHandler handler = new MyInvocationHandler(proxyMe);
/* create the proxy class */
- Class proxyClass = Proxy.getProxyClass(Shapes.class.getClassLoader(),
- new Class[] { Quads.class, Colors.class, Trace.class });
+ Class<?> proxyClass = Proxy.getProxyClass(Shapes.class.getClassLoader(),
+ Quads.class, Colors.class, Trace.class);
Main.registerProxyClassName(proxyClass.getCanonicalName());
/* create a proxy object, passing the handler object in */
Object proxy = null;
try {
- Constructor<Class> cons;
- cons = proxyClass.getConstructor(
- new Class[] { InvocationHandler.class });
+ Constructor<?> cons = proxyClass.getConstructor(InvocationHandler.class);
//System.out.println("Constructor is " + cons);
- proxy = cons.newInstance(new Object[] { handler });
+ proxy = cons.newInstance(handler);
} catch (NoSuchMethodException nsme) {
System.err.println("failed: " + nsme);
} catch (InstantiationException ie) {
diff --git a/test/044-proxy/src/Clash.java b/test/044-proxy/src/Clash.java
index adeffdc..d000112 100644
--- a/test/044-proxy/src/Clash.java
+++ b/test/044-proxy/src/Clash.java
@@ -30,7 +30,7 @@
/* try passing in the same interface twice */
try {
Proxy.newProxyInstance(Clash.class.getClassLoader(),
- new Class[] { Interface1A.class, Interface1A.class },
+ new Class<?>[] { Interface1A.class, Interface1A.class },
handler);
System.err.println("Dupe did not throw expected exception");
} catch (IllegalArgumentException iae) {
@@ -39,7 +39,7 @@
try {
Proxy.newProxyInstance(Clash.class.getClassLoader(),
- new Class[] { Interface1A.class, Interface1B.class },
+ new Class<?>[] { Interface1A.class, Interface1B.class },
handler);
System.err.println("Clash did not throw expected exception");
} catch (IllegalArgumentException iae) {
diff --git a/test/044-proxy/src/Clash2.java b/test/044-proxy/src/Clash2.java
index 2a384f4..e405cfe 100644
--- a/test/044-proxy/src/Clash2.java
+++ b/test/044-proxy/src/Clash2.java
@@ -29,7 +29,7 @@
try {
Proxy.newProxyInstance(Clash.class.getClassLoader(),
- new Class[] { Interface2A.class, Interface2B.class },
+ new Class<?>[] { Interface2A.class, Interface2B.class },
handler);
System.err.println("Clash2 did not throw expected exception");
} catch (IllegalArgumentException iae) {
diff --git a/test/044-proxy/src/Clash3.java b/test/044-proxy/src/Clash3.java
index 6d6f2f2..44806ce 100644
--- a/test/044-proxy/src/Clash3.java
+++ b/test/044-proxy/src/Clash3.java
@@ -29,7 +29,7 @@
try {
Proxy.newProxyInstance(Clash.class.getClassLoader(),
- new Class[] {
+ new Class<?>[] {
Interface3a.class,
Interface3base.class,
Interface3aa.class,
diff --git a/test/044-proxy/src/Clash4.java b/test/044-proxy/src/Clash4.java
index 1bfb37f..ca5c3ab 100644
--- a/test/044-proxy/src/Clash4.java
+++ b/test/044-proxy/src/Clash4.java
@@ -29,7 +29,7 @@
try {
Proxy.newProxyInstance(Clash.class.getClassLoader(),
- new Class[] {
+ new Class<?>[] {
Interface4a.class,
Interface4aa.class,
Interface4base.class,
diff --git a/test/044-proxy/src/FloatSelect.java b/test/044-proxy/src/FloatSelect.java
index febe697..217ccaf 100644
--- a/test/044-proxy/src/FloatSelect.java
+++ b/test/044-proxy/src/FloatSelect.java
@@ -34,7 +34,7 @@
public static void main(String[] args) {
FloatSelectI proxyObject = (FloatSelectI) Proxy.newProxyInstance(
FloatSelectI.class.getClassLoader(),
- new Class[] { FloatSelectI.class },
+ new Class<?>[] { FloatSelectI.class },
new FloatSelectIInvoke1());
float floatResult = proxyObject.method(2.1f, 5.8f);
diff --git a/test/044-proxy/src/NativeProxy.java b/test/044-proxy/src/NativeProxy.java
index b425da8..c609dc2 100644
--- a/test/044-proxy/src/NativeProxy.java
+++ b/test/044-proxy/src/NativeProxy.java
@@ -40,7 +40,7 @@
try {
NativeInterface inf = (NativeInterface)Proxy.newProxyInstance(
NativeProxy.class.getClassLoader(),
- new Class[] { NativeInterface.class },
+ new Class<?>[] { NativeInterface.class },
new NativeInvocationHandler());
nativeCall(inf);
diff --git a/test/044-proxy/src/ReturnsAndArgPassing.java b/test/044-proxy/src/ReturnsAndArgPassing.java
index 225cc5b..3d8ebf0 100644
--- a/test/044-proxy/src/ReturnsAndArgPassing.java
+++ b/test/044-proxy/src/ReturnsAndArgPassing.java
@@ -98,7 +98,7 @@
MyInvocationHandler myHandler = new MyInvocationHandler();
MyInterface proxyMyInterface =
(MyInterface)Proxy.newProxyInstance(ReturnsAndArgPassing.class.getClassLoader(),
- new Class[] { MyInterface.class },
+ new Class<?>[] { MyInterface.class },
myHandler);
check(fooInvocations == 0);
proxyMyInterface.voidFoo();
@@ -441,7 +441,7 @@
MyInvocationHandler myHandler = new MyInvocationHandler();
MyInterface proxyMyInterface =
(MyInterface)Proxy.newProxyInstance(ReturnsAndArgPassing.class.getClassLoader(),
- new Class[] { MyInterface.class },
+ new Class<?>[] { MyInterface.class },
myHandler);
check((Integer)proxyMyInterface.selectArg(0, Integer.MAX_VALUE, Long.MAX_VALUE,
diff --git a/test/044-proxy/src/WrappedThrow.java b/test/044-proxy/src/WrappedThrow.java
index 27ae84e..643ba05 100644
--- a/test/044-proxy/src/WrappedThrow.java
+++ b/test/044-proxy/src/WrappedThrow.java
@@ -32,7 +32,7 @@
try {
proxy = Proxy.newProxyInstance(WrappedThrow.class.getClassLoader(),
- new Class[] { InterfaceW1.class, InterfaceW2.class },
+ new Class<?>[] { InterfaceW1.class, InterfaceW2.class },
handler);
} catch (IllegalArgumentException iae) {
System.out.println("WT init failed");
diff --git a/test/046-reflect/src/Main.java b/test/046-reflect/src/Main.java
index 67a0d11..10dad8d 100644
--- a/test/046-reflect/src/Main.java
+++ b/test/046-reflect/src/Main.java
@@ -32,7 +32,7 @@
public Main(ArrayList<Integer> stuff) {}
void printMethodInfo(Method meth) {
- Class[] params, exceptions;
+ Class<?>[] params, exceptions;
int i;
System.out.println("Method name is " + meth.getName());
@@ -62,7 +62,7 @@
private void showStrings(Target instance)
throws NoSuchFieldException, IllegalAccessException {
- Class target = Target.class;
+ Class<?> target = Target.class;
String one, two, three, four;
Field field = null;
@@ -80,15 +80,15 @@
public static void checkAccess() {
try {
- Class target = otherpackage.Other.class;
+ Class<?> target = otherpackage.Other.class;
Object instance = new otherpackage.Other();
Method meth;
- meth = target.getMethod("publicMethod", (Class[]) null);
+ meth = target.getMethod("publicMethod");
meth.invoke(instance);
try {
- meth = target.getMethod("packageMethod", (Class[]) null);
+ meth = target.getMethod("packageMethod");
System.err.println("succeeded on package-scope method");
} catch (NoSuchMethodException nsme) {
// good
@@ -97,7 +97,7 @@
instance = otherpackage.Other.getInnerClassInstance();
target = instance.getClass();
- meth = target.getMethod("innerMethod", (Class[]) null);
+ meth = target.getMethod("innerMethod");
try {
if (!FULL_ACCESS_CHECKS) { throw new IllegalAccessException(); }
meth.invoke(instance);
@@ -121,26 +121,25 @@
}
public void run() {
- Class target = Target.class;
+ Class<Target> target = Target.class;
Method meth = null;
Field field = null;
boolean excep;
try {
- meth = target.getMethod("myMethod", new Class[] { int.class });
+ meth = target.getMethod("myMethod", int.class);
if (meth.getDeclaringClass() != target)
throw new RuntimeException();
printMethodInfo(meth);
- meth = target.getMethod("myMethod", new Class[] { float.class });
+ meth = target.getMethod("myMethod", float.class);
printMethodInfo(meth);
- meth = target.getMethod("myNoargMethod", (Class[]) null);
+ meth = target.getMethod("myNoargMethod");
printMethodInfo(meth);
- meth = target.getMethod("myMethod",
- new Class[] { String[].class, float.class, char.class });
+ meth = target.getMethod("myMethod", String[].class, float.class, char.class);
printMethodInfo(meth);
Target instance = new Target();
@@ -157,11 +156,11 @@
System.out.println("Result of invoke: " + boxval.intValue());
System.out.println("Calling no-arg void-return method");
- meth = target.getMethod("myNoargMethod", (Class[]) null);
+ meth = target.getMethod("myNoargMethod");
meth.invoke(instance, (Object[]) null);
/* try invoking a method that throws an exception */
- meth = target.getMethod("throwingMethod", (Class[]) null);
+ meth = target.getMethod("throwingMethod");
try {
meth.invoke(instance, (Object[]) null);
System.out.println("GLITCH: didn't throw");
@@ -372,7 +371,7 @@
Target targ;
Object[] args;
- cons = target.getConstructor(new Class[] { int.class,float.class });
+ cons = target.getConstructor(int.class, float.class);
args = new Object[] { new Integer(7), new Float(3.3333) };
System.out.println("cons modifiers=" + cons.getModifiers());
targ = cons.newInstance(args);
@@ -458,7 +457,7 @@
public static void checkClinitForFields() throws Exception {
// Loading a class constant shouldn't run <clinit>.
System.out.println("calling const-class FieldNoisyInitUser.class");
- Class niuClass = FieldNoisyInitUser.class;
+ Class<?> niuClass = FieldNoisyInitUser.class;
System.out.println("called const-class FieldNoisyInitUser.class");
// Getting the declared fields doesn't run <clinit>.
@@ -480,14 +479,14 @@
public static void checkClinitForMethods() throws Exception {
// Loading a class constant shouldn't run <clinit>.
System.out.println("calling const-class MethodNoisyInitUser.class");
- Class niuClass = MethodNoisyInitUser.class;
+ Class<?> niuClass = MethodNoisyInitUser.class;
System.out.println("called const-class MethodNoisyInitUser.class");
// Getting the declared methods doesn't run <clinit>.
Method[] methods = niuClass.getDeclaredMethods();
System.out.println("got methods");
- Method method = niuClass.getMethod("staticMethod", (Class[]) null);
+ Method method = niuClass.getMethod("staticMethod");
System.out.println("got method");
method.invoke(null);
System.out.println("invoked method");
@@ -517,8 +516,7 @@
Method method;
try {
- method = Main.class.getMethod("fancyMethod",
- new Class[] { ArrayList.class });
+ method = Main.class.getMethod("fancyMethod", ArrayList.class);
} catch (NoSuchMethodException nsme) {
throw new RuntimeException(nsme);
}
@@ -527,9 +525,9 @@
System.out.println("generic method " + method.getName() + " params='"
+ stringifyTypeArray(parmTypes) + "' ret='" + ret + "'");
- Constructor ctor;
+ Constructor<?> ctor;
try {
- ctor = Main.class.getConstructor(new Class[] { ArrayList.class });
+ ctor = Main.class.getConstructor( ArrayList.class);
} catch (NoSuchMethodException nsme) {
throw new RuntimeException(nsme);
}
@@ -580,8 +578,8 @@
}
Method method1, method2;
try {
- method1 = Main.class.getMethod("fancyMethod", new Class[] { ArrayList.class });
- method2 = Main.class.getMethod("fancyMethod", new Class[] { ArrayList.class });
+ method1 = Main.class.getMethod("fancyMethod", ArrayList.class);
+ method2 = Main.class.getMethod("fancyMethod", ArrayList.class);
} catch (NoSuchMethodException nsme) {
throw new RuntimeException(nsme);
}
diff --git a/test/064-field-access/src/Main.java b/test/064-field-access/src/Main.java
index 5d90129..50ad5b9 100644
--- a/test/064-field-access/src/Main.java
+++ b/test/064-field-access/src/Main.java
@@ -38,7 +38,7 @@
}
try {
- Class c = Class.forName("SubClassUsingInaccessibleField");
+ Class<?> c = Class.forName("SubClassUsingInaccessibleField");
Object o = c.newInstance();
c.getMethod("test").invoke(o, null);
} catch (InvocationTargetException ite) {
@@ -64,7 +64,7 @@
* On success, the boxed value retrieved is returned.
*/
public Object getValue(Field field, Object obj, char type,
- Class expectedException) {
+ Class<?> expectedException) {
Object result = null;
try {
switch (type) {
@@ -638,7 +638,7 @@
* reflection call is significant]
*/
public Object getValue(Field field, Object obj, char type,
- Class expectedException) {
+ Class<?> expectedException) {
Object result = null;
try {
switch (type) {
@@ -698,7 +698,7 @@
return result;
}
- public Object invoke(Method method, Object obj, Class expectedException) {
+ public Object invoke(Method method, Object obj, Class<?> expectedException) {
Object result = null;
try {
result = method.invoke(obj);
diff --git a/test/068-classloader/src/FancyLoader.java b/test/068-classloader/src/FancyLoader.java
index 6a153cc..e616bfc 100644
--- a/test/068-classloader/src/FancyLoader.java
+++ b/test/068-classloader/src/FancyLoader.java
@@ -41,7 +41,7 @@
static final String DEX_FILE = System.getenv("DEX_LOCATION") + "/068-classloader-ex.jar";
/* on Dalvik, this is a DexFile; otherwise, it's null */
- private Class mDexClass;
+ private Class<?> mDexClass;
private Object mDexFile;
@@ -82,12 +82,12 @@
if (mDexFile == null) {
synchronized (FancyLoader.class) {
- Constructor ctor;
+ Constructor<?> ctor;
/*
* Construct a DexFile object through reflection.
*/
try {
- ctor = mDexClass.getConstructor(new Class[] {String.class});
+ ctor = mDexClass.getConstructor(String.class);
} catch (NoSuchMethodException nsme) {
throw new ClassNotFoundException("getConstructor failed",
nsme);
@@ -111,8 +111,7 @@
Method meth;
try {
- meth = mDexClass.getMethod("loadClass",
- new Class[] { String.class, ClassLoader.class });
+ meth = mDexClass.getMethod("loadClass", String.class, ClassLoader.class);
} catch (NoSuchMethodException nsme) {
throw new ClassNotFoundException("getMethod failed", nsme);
}
@@ -184,7 +183,7 @@
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
- Class res;
+ Class<?> res;
/*
* 1. Invoke findLoadedClass(String) to check if the class has
diff --git a/test/068-classloader/src/Main.java b/test/068-classloader/src/Main.java
index b2d843b..01539b7 100644
--- a/test/068-classloader/src/Main.java
+++ b/test/068-classloader/src/Main.java
@@ -74,11 +74,10 @@
/* this is the "alternate" DEX/Jar file */
String DEX_FILE = System.getenv("DEX_LOCATION") + "/068-classloader-ex.jar";
/* on Dalvik, this is a DexFile; otherwise, it's null */
- Class mDexClass = Class.forName("dalvik.system.DexFile");
- Constructor ctor = mDexClass.getConstructor(new Class[] {String.class});
+ Class<?> mDexClass = Class.forName("dalvik.system.DexFile");
+ Constructor<?> ctor = mDexClass.getConstructor(String.class);
Object mDexFile = ctor.newInstance(DEX_FILE);
- Method meth = mDexClass.getMethod("loadClass",
- new Class[] { String.class, ClassLoader.class });
+ Method meth = mDexClass.getMethod("loadClass", String.class, ClassLoader.class);
Object klass = meth.invoke(mDexFile, "Mutator", null);
if (klass == null) {
throw new AssertionError("loadClass with nullclass loader failed");
@@ -94,15 +93,15 @@
FancyLoader loader2 = new FancyLoader(ClassLoader.getSystemClassLoader());
try {
- Class target1 = loader1.loadClass("MutationTarget");
- Class target2 = loader2.loadClass("MutationTarget");
+ Class<?> target1 = loader1.loadClass("MutationTarget");
+ Class<?> target2 = loader2.loadClass("MutationTarget");
if (target1 == target2) {
throw new RuntimeException("target1 should not be equal to target2");
}
- Class mutator1 = loader1.loadClass("Mutator");
- Class mutator2 = loader2.loadClass("Mutator");
+ Class<?> mutator1 = loader1.loadClass("Mutator");
+ Class<?> mutator2 = loader2.loadClass("Mutator");
if (mutator1 == mutator2) {
throw new RuntimeException("mutator1 should not be equal to mutator2");
@@ -134,12 +133,12 @@
}
}
- private static void runMutator(Class c, int v) throws Exception {
+ private static void runMutator(Class<?> c, int v) throws Exception {
java.lang.reflect.Method m = c.getDeclaredMethod("mutate", int.class);
m.invoke(null, v);
}
- private static int getMutationTargetValue(Class c) throws Exception {
+ private static int getMutationTargetValue(Class<?> c) throws Exception {
java.lang.reflect.Field f = c.getDeclaredField("value");
return f.getInt(null);
}
@@ -149,7 +148,7 @@
* able to load it but not instantiate it.
*/
static void testAccess1(ClassLoader loader) {
- Class altClass;
+ Class<?> altClass;
try {
altClass = loader.loadClass("Inaccessible1");
@@ -179,7 +178,7 @@
* (though the base *is* accessible to us).
*/
static void testAccess2(ClassLoader loader) {
- Class altClass;
+ Class<?> altClass;
try {
altClass = loader.loadClass("Inaccessible2");
@@ -199,7 +198,7 @@
* See if we can load a class with an inaccessible interface.
*/
static void testAccess3(ClassLoader loader) {
- Class altClass;
+ Class<?> altClass;
try {
altClass = loader.loadClass("Inaccessible3");
@@ -219,7 +218,7 @@
* Test a doubled class that extends the base class.
*/
static void testExtend(ClassLoader loader) {
- Class doubledExtendClass;
+ Class<?> doubledExtendClass;
Object obj;
/* get the "alternate" version of DoubledExtend */
@@ -268,7 +267,7 @@
* it doesn't override the base class method.
*/
static void testExtendOkay(ClassLoader loader) {
- Class doubledExtendOkayClass;
+ Class<?> doubledExtendOkayClass;
Object obj;
/* get the "alternate" version of DoubledExtendOkay */
@@ -316,7 +315,7 @@
* an interface declared in a different class.
*/
static void testInterface(ClassLoader loader) {
- Class getDoubledClass;
+ Class<?> getDoubledClass;
Object obj;
/* get GetDoubled from the "alternate" class loader */
@@ -362,7 +361,7 @@
* Throw an abstract class into the middle and see what happens.
*/
static void testAbstract(ClassLoader loader) {
- Class abstractGetClass;
+ Class<?> abstractGetClass;
Object obj;
/* get AbstractGet from the "alternate" loader */
@@ -407,7 +406,7 @@
* Test a doubled class that implements a common interface.
*/
static void testImplement(ClassLoader loader) {
- Class doubledImplementClass;
+ Class<?> doubledImplementClass;
Object obj;
useImplement(new DoubledImplement(), true);
@@ -465,7 +464,7 @@
* that refers to a doubled class.
*/
static void testIfaceImplement(ClassLoader loader) {
- Class ifaceImplClass;
+ Class<?> ifaceImplClass;
Object obj;
/*
diff --git a/test/071-dexfile/src/Main.java b/test/071-dexfile/src/Main.java
index 2f85790..c3a9671 100644
--- a/test/071-dexfile/src/Main.java
+++ b/test/071-dexfile/src/Main.java
@@ -66,7 +66,7 @@
*/
private static void testDexClassLoader() throws Exception {
ClassLoader dexClassLoader = getDexClassLoader();
- Class Another = dexClassLoader.loadClass("Another");
+ Class<?> Another = dexClassLoader.loadClass("Another");
Object another = Another.newInstance();
// not expected to work; just exercises the call
dexClassLoader.getResource("nonexistent");
@@ -79,18 +79,21 @@
*/
private static ClassLoader getDexClassLoader() throws Exception {
ClassLoader classLoader = Main.class.getClassLoader();
- Class DexClassLoader = classLoader.loadClass("dalvik.system.DexClassLoader");
- Constructor DexClassLoader_init = DexClassLoader.getConstructor(String.class,
- String.class,
- String.class,
- ClassLoader.class);
+ Class<?> DexClassLoader = classLoader.loadClass("dalvik.system.DexClassLoader");
+ Constructor<?> DexClassLoader_init = DexClassLoader.getConstructor(String.class,
+ String.class,
+ String.class,
+ ClassLoader.class);
// create an instance, using the path we found
- return (ClassLoader) DexClassLoader_init.newInstance(CLASS_PATH, getOdexDir(), LIB_DIR, classLoader);
+ return (ClassLoader) DexClassLoader_init.newInstance(CLASS_PATH,
+ getOdexDir(),
+ LIB_DIR,
+ classLoader);
}
private static void testDexFile() throws Exception {
ClassLoader classLoader = Main.class.getClassLoader();
- Class DexFile = classLoader.loadClass("dalvik.system.DexFile");
+ Class<?> DexFile = classLoader.loadClass("dalvik.system.DexFile");
Method DexFile_loadDex = DexFile.getMethod("loadDex",
String.class,
String.class,
diff --git a/test/074-gc-thrash/src/Main.java b/test/074-gc-thrash/src/Main.java
index f947d0b..df04793 100644
--- a/test/074-gc-thrash/src/Main.java
+++ b/test/074-gc-thrash/src/Main.java
@@ -69,7 +69,7 @@
*/
private static Method getDumpHprofDataMethod() {
ClassLoader myLoader = Main.class.getClassLoader();
- Class vmdClass;
+ Class<?> vmdClass;
try {
vmdClass = myLoader.loadClass("dalvik.system.VMDebug");
} catch (ClassNotFoundException cnfe) {
@@ -78,8 +78,7 @@
Method meth;
try {
- meth = vmdClass.getMethod("dumpHprofData",
- new Class[] { String.class });
+ meth = vmdClass.getMethod("dumpHprofData", String.class);
} catch (NoSuchMethodException nsme) {
System.err.println("Found VMDebug but not dumpHprofData method");
return null;
diff --git a/test/080-oom-throw/src/Main.java b/test/080-oom-throw/src/Main.java
index f007b25..0ae92a9 100644
--- a/test/080-oom-throw/src/Main.java
+++ b/test/080-oom-throw/src/Main.java
@@ -105,7 +105,7 @@
static boolean triggerReflectionOOM() {
try {
Class<?> c = Main.class;
- Method m = c.getMethod("blowup", (Class[]) null);
+ Method m = c.getMethod("blowup");
holder = new Object[1000000];
m.invoke(null);
holder = null;
diff --git a/test/086-null-super/src/Main.java b/test/086-null-super/src/Main.java
index 060737f..8bd1786 100644
--- a/test/086-null-super/src/Main.java
+++ b/test/086-null-super/src/Main.java
@@ -75,14 +75,12 @@
* Find the DexFile class, and construct a DexFile object
* through reflection, then call loadCLass on it.
*/
- Class mDexClass = ClassLoader.getSystemClassLoader().
+ Class<?> mDexClass = ClassLoader.getSystemClassLoader().
loadClass("dalvik.system.DexFile");
- Constructor ctor = mDexClass.
- getConstructor(new Class[] {String.class});
+ Constructor<?> ctor = mDexClass.getConstructor(String.class);
Object mDexFile = ctor.newInstance(DEX_FILE);
Method meth = mDexClass.
- getMethod("loadClass",
- new Class[] { String.class, ClassLoader.class });
+ getMethod("loadClass", String.class, ClassLoader.class);
/*
* Invoking loadClass on CLASS_NAME is expected to
* throw an InvocationTargetException. Anything else
diff --git a/test/087-gc-after-link/src/Main.java b/test/087-gc-after-link/src/Main.java
index 7c47e99..698af0b 100644
--- a/test/087-gc-after-link/src/Main.java
+++ b/test/087-gc-after-link/src/Main.java
@@ -70,7 +70,7 @@
throws TestFailed, InvocationTargetException
{
Object dexFile = null;
- Class dexClass = null;
+ Class<?> dexClass = null;
try {
try {
@@ -80,11 +80,9 @@
*/
dexClass = ClassLoader.getSystemClassLoader().
loadClass("dalvik.system.DexFile");
- Constructor ctor = dexClass.
- getConstructor(new Class[] {String.class});
+ Constructor<?> ctor = dexClass.getConstructor(String.class);
dexFile = ctor.newInstance(DEX_FILE);
- Method meth = dexClass.getMethod("loadClass",
- new Class[] { String.class, ClassLoader.class });
+ Method meth = dexClass.getMethod("loadClass", String.class, ClassLoader.class);
/*
* Invoking loadClass on CLASS_NAME is expected to
* throw an InvocationTargetException. Anything else
@@ -95,7 +93,7 @@
} finally {
if (dexFile != null) {
/* close the DexFile to make CloseGuard happy */
- Method meth = dexClass.getMethod("close", (Class[]) null);
+ Method meth = dexClass.getMethod("close");
meth.invoke(dexFile);
}
}
diff --git a/test/088-monitor-verification/src/Main.java b/test/088-monitor-verification/src/Main.java
index 212c894..a6f0e64 100644
--- a/test/088-monitor-verification/src/Main.java
+++ b/test/088-monitor-verification/src/Main.java
@@ -100,7 +100,7 @@
*/
void constantLock() {
assertIsManaged();
- Class thing = Thread.class;
+ Class<?> thing = Thread.class;
synchronized (Thread.class) {}
}
diff --git a/test/098-ddmc/src/Main.java b/test/098-ddmc/src/Main.java
index 50bbe51..72c5a28 100644
--- a/test/098-ddmc/src/Main.java
+++ b/test/098-ddmc/src/Main.java
@@ -136,7 +136,7 @@
private static final Method getRecentAllocationsMethod;
static {
try {
- Class c = Class.forName("org.apache.harmony.dalvik.ddmc.DdmVmInternal");
+ Class<?> c = Class.forName("org.apache.harmony.dalvik.ddmc.DdmVmInternal");
enableRecentAllocationsMethod = c.getDeclaredMethod("enableRecentAllocations",
Boolean.TYPE);
getRecentAllocationStatusMethod = c.getDeclaredMethod("getRecentAllocationStatus");
diff --git a/test/099-vmdebug/src/Main.java b/test/099-vmdebug/src/Main.java
index 8068721..90ad315 100644
--- a/test/099-vmdebug/src/Main.java
+++ b/test/099-vmdebug/src/Main.java
@@ -242,7 +242,7 @@
System.out.println("Instances of null " + VMDebug.countInstancesofClass(null, false));
System.out.println("Instances of ClassA assignable " +
VMDebug.countInstancesofClass(ClassA.class, true));
- Class[] classes = new Class[]{ClassA.class, ClassB.class, null};
+ Class<?>[] classes = new Class<?>[] {ClassA.class, ClassB.class, null};
long[] counts = VMDebug.countInstancesofClasses(classes, false);
System.out.println("Array counts " + Arrays.toString(counts));
counts = VMDebug.countInstancesofClasses(classes, true);
@@ -259,7 +259,7 @@
private static final Method countInstancesOfClassesMethod;
static {
try {
- Class c = Class.forName("dalvik.system.VMDebug");
+ Class<?> c = Class.forName("dalvik.system.VMDebug");
startMethodTracingMethod = c.getDeclaredMethod("startMethodTracing", String.class,
Integer.TYPE, Integer.TYPE, Boolean.TYPE, Integer.TYPE);
stopMethodTracingMethod = c.getDeclaredMethod("stopMethodTracing");
@@ -292,10 +292,10 @@
public static Map<String, String> getRuntimeStats() throws Exception {
return (Map<String, String>) getRuntimeStatsMethod.invoke(null);
}
- public static long countInstancesofClass(Class c, boolean assignable) throws Exception {
+ public static long countInstancesofClass(Class<?> c, boolean assignable) throws Exception {
return (long) countInstancesOfClassMethod.invoke(null, new Object[]{c, assignable});
}
- public static long[] countInstancesofClasses(Class[] classes, boolean assignable)
+ public static long[] countInstancesofClasses(Class<?>[] classes, boolean assignable)
throws Exception {
return (long[]) countInstancesOfClassesMethod.invoke(
null, new Object[]{classes, assignable});
diff --git a/test/100-reflect2/src/Main.java b/test/100-reflect2/src/Main.java
index 1245852..91ba307 100644
--- a/test/100-reflect2/src/Main.java
+++ b/test/100-reflect2/src/Main.java
@@ -275,10 +275,8 @@
}
public static void testConstructorReflection() throws Exception {
- Constructor<?> ctor;
-
- ctor = String.class.getConstructor(new Class[0]);
- show(ctor.newInstance((Object[]) null));
+ Constructor<String> ctor = String.class.getConstructor();
+ show(ctor.newInstance());
ctor = String.class.getConstructor(char[].class, int.class, int.class);
show(ctor.newInstance(new char[] { '\u2714', 'y', 'z', '!' }, 1, 2));
@@ -287,7 +285,7 @@
private static void testPackagePrivateConstructor() {
try {
Class<?> c = Class.forName("sub.PPClass");
- Constructor cons = c.getConstructor();
+ Constructor<?> cons = c.getConstructor();
cons.newInstance();
throw new RuntimeException("Expected IllegalAccessException.");
} catch (IllegalAccessException e) {
@@ -301,7 +299,7 @@
private static void testPackagePrivateAccessibleConstructor() {
try {
Class<?> c = Class.forName("sub.PPClass");
- Constructor cons = c.getConstructor();
+ Constructor<?> cons = c.getConstructor();
cons.setAccessible(true); // ensure we prevent IllegalAccessException
cons.newInstance();
} catch (Exception e) {
diff --git a/test/107-int-math2/src/Main.java b/test/107-int-math2/src/Main.java
index 0c91d44..ec5678d 100644
--- a/test/107-int-math2/src/Main.java
+++ b/test/107-int-math2/src/Main.java
@@ -104,7 +104,7 @@
}
static int constClassTest(int x) {
- Class c = String.class;
+ Class<?> c = String.class;
if (c != null) {
return x * 2;
} else {
diff --git a/test/118-noimage-dex2oat/src/Main.java b/test/118-noimage-dex2oat/src/Main.java
index dba9166..cc19107 100644
--- a/test/118-noimage-dex2oat/src/Main.java
+++ b/test/118-noimage-dex2oat/src/Main.java
@@ -51,7 +51,7 @@
private static final Method isBootClassPathOnDiskMethod;
static {
try {
- Class c = Class.forName("dalvik.system.VMRuntime");
+ Class<?> c = Class.forName("dalvik.system.VMRuntime");
getCurrentInstructionSetMethod = c.getDeclaredMethod("getCurrentInstructionSet");
isBootClassPathOnDiskMethod = c.getDeclaredMethod("isBootClassPathOnDisk",
String.class);
diff --git a/test/125-gc-and-classloading/src/Main.java b/test/125-gc-and-classloading/src/Main.java
index 61e123d..e81ef7b 100644
--- a/test/125-gc-and-classloading/src/Main.java
+++ b/test/125-gc-and-classloading/src/Main.java
@@ -57,7 +57,7 @@
public void run() {
try {
cdl.await();
- Class c0 = Class.forName("Main$BigClass");
+ Class<?> c0 = Class.forName("Main$BigClass");
} catch (Exception e) {
throw new RuntimeException(e);
}
diff --git a/test/130-hprof/src/Main.java b/test/130-hprof/src/Main.java
index 9868c61..c145f27 100644
--- a/test/130-hprof/src/Main.java
+++ b/test/130-hprof/src/Main.java
@@ -37,15 +37,15 @@
private static Object allocInDifferentLoader() throws Exception {
final String DEX_FILE = System.getenv("DEX_LOCATION") + "/130-hprof-ex.jar";
- Class pathClassLoader = Class.forName("dalvik.system.PathClassLoader");
+ Class<?> pathClassLoader = Class.forName("dalvik.system.PathClassLoader");
if (pathClassLoader == null) {
throw new AssertionError("Couldn't find path class loader class");
}
- Constructor constructor =
+ Constructor<?> constructor =
pathClassLoader.getDeclaredConstructor(String.class, ClassLoader.class);
ClassLoader loader = (ClassLoader)constructor.newInstance(
DEX_FILE, ClassLoader.getSystemClassLoader());
- Class allocator = loader.loadClass("Allocator");
+ Class<?> allocator = loader.loadClass("Allocator");
return allocator.getDeclaredMethod("allocObject", null).invoke(null);
}
@@ -105,7 +105,7 @@
System.out.println("Generated data.");
createDumpAndConv();
- Class klass = Class.forName("org.apache.harmony.dalvik.ddmc.DdmVmInternal");
+ Class<?> klass = Class.forName("org.apache.harmony.dalvik.ddmc.DdmVmInternal");
if (klass == null) {
throw new AssertionError("Couldn't find path class loader class");
}
@@ -153,7 +153,7 @@
*/
private static Method getDumpHprofDataMethod() {
ClassLoader myLoader = Main.class.getClassLoader();
- Class vmdClass;
+ Class<?> vmdClass;
try {
vmdClass = myLoader.loadClass("dalvik.system.VMDebug");
} catch (ClassNotFoundException cnfe) {
@@ -162,8 +162,7 @@
Method meth;
try {
- meth = vmdClass.getMethod("dumpHprofData",
- new Class[] { String.class });
+ meth = vmdClass.getMethod("dumpHprofData", String.class);
} catch (NoSuchMethodException nsme) {
System.err.println("Found VMDebug but not dumpHprofData method");
return null;
diff --git a/test/134-reg-promotion/src/Main.java b/test/134-reg-promotion/src/Main.java
index 008ac58..f633524 100644
--- a/test/134-reg-promotion/src/Main.java
+++ b/test/134-reg-promotion/src/Main.java
@@ -32,13 +32,13 @@
public static void main(String args[]) throws Exception {
Class<?> c = Class.forName("Test");
- Method m = c.getMethod("run", (Class[]) null);
+ Method m = c.getMethod("run");
for (int i = 0; i < 10; i++) {
holder = new char[128 * 1024][];
m.invoke(null, (Object[]) null);
holder = null;
}
- m = c.getMethod("run2", (Class[]) null);
+ m = c.getMethod("run2");
for (int i = 0; i < 10; i++) {
holder = new char[128 * 1024][];
m.invoke(null, (Object[]) null);
diff --git a/test/138-duplicate-classes-check/src/Main.java b/test/138-duplicate-classes-check/src/Main.java
index a2ef281..5ffceb9 100644
--- a/test/138-duplicate-classes-check/src/Main.java
+++ b/test/138-duplicate-classes-check/src/Main.java
@@ -38,7 +38,7 @@
getClass().getClassLoader());
try {
- Class testEx = loader.loadClass("TestEx");
+ Class<?> testEx = loader.loadClass("TestEx");
Method test = testEx.getDeclaredMethod("test");
test.invoke(null);
} catch (Exception exc) {
diff --git a/test/138-duplicate-classes-check2/src/FancyLoader.java b/test/138-duplicate-classes-check2/src/FancyLoader.java
index 7e2bb08..58b7ec4 100644
--- a/test/138-duplicate-classes-check2/src/FancyLoader.java
+++ b/test/138-duplicate-classes-check2/src/FancyLoader.java
@@ -42,7 +42,7 @@
"/138-duplicate-classes-check2-ex.jar";
/* on Dalvik, this is a DexFile; otherwise, it's null */
- private Class mDexClass;
+ private Class<?> mDexClass;
private Object mDexFile;
@@ -83,12 +83,12 @@
if (mDexFile == null) {
synchronized (FancyLoader.class) {
- Constructor ctor;
+ Constructor<?> ctor;
/*
* Construct a DexFile object through reflection.
*/
try {
- ctor = mDexClass.getConstructor(new Class[] {String.class});
+ ctor = mDexClass.getConstructor(String.class);
} catch (NoSuchMethodException nsme) {
throw new ClassNotFoundException("getConstructor failed",
nsme);
@@ -112,8 +112,7 @@
Method meth;
try {
- meth = mDexClass.getMethod("loadClass",
- new Class[] { String.class, ClassLoader.class });
+ meth = mDexClass.getMethod("loadClass", String.class, ClassLoader.class);
} catch (NoSuchMethodException nsme) {
throw new ClassNotFoundException("getMethod failed", nsme);
}
@@ -185,7 +184,7 @@
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
- Class res;
+ Class<?> res;
/*
* 1. Invoke findLoadedClass(String) to check if the class has
diff --git a/test/138-duplicate-classes-check2/src/Main.java b/test/138-duplicate-classes-check2/src/Main.java
index a9b5bb0..a0d6977 100644
--- a/test/138-duplicate-classes-check2/src/Main.java
+++ b/test/138-duplicate-classes-check2/src/Main.java
@@ -33,7 +33,7 @@
FancyLoader loader = new FancyLoader(getClass().getClassLoader());
try {
- Class testEx = loader.loadClass("TestEx");
+ Class<?> testEx = loader.loadClass("TestEx");
Method test = testEx.getDeclaredMethod("test");
test.invoke(null);
} catch (Exception exc) {
diff --git a/test/139-register-natives/src/Main.java b/test/139-register-natives/src/Main.java
index 8dd2131..11bd53f 100644
--- a/test/139-register-natives/src/Main.java
+++ b/test/139-register-natives/src/Main.java
@@ -47,7 +47,7 @@
}
}
- private native static int registerNatives(Class c);
+ private native static int registerNatives(Class<?> c);
private static void expectThrows(Base b) {
try {
diff --git a/test/141-class-unload/src/Main.java b/test/141-class-unload/src/Main.java
index 9ed8d28..f9b6180 100644
--- a/test/141-class-unload/src/Main.java
+++ b/test/141-class-unload/src/Main.java
@@ -28,11 +28,11 @@
public static void main(String[] args) throws Exception {
nativeLibraryName = args[0];
- Class pathClassLoader = Class.forName("dalvik.system.PathClassLoader");
+ Class<?> pathClassLoader = Class.forName("dalvik.system.PathClassLoader");
if (pathClassLoader == null) {
throw new AssertionError("Couldn't find path class loader class");
}
- Constructor constructor =
+ Constructor<?> constructor =
pathClassLoader.getDeclaredConstructor(String.class, String.class, ClassLoader.class);
try {
testUnloadClass(constructor);
@@ -67,7 +67,7 @@
System.out.println("Number of loaded unload-ex maps " + count);
}
- private static void stressTest(Constructor constructor) throws Exception {
+ private static void stressTest(Constructor<?> constructor) throws Exception {
for (int i = 0; i <= 100; ++i) {
setUpUnloadLoader(constructor, false);
if (i % 10 == 0) {
@@ -76,7 +76,7 @@
}
}
- private static void testUnloadClass(Constructor constructor) throws Exception {
+ private static void testUnloadClass(Constructor<?> constructor) throws Exception {
WeakReference<Class> klass = setUpUnloadClassWeak(constructor);
// No strong references to class loader, should get unloaded.
Runtime.getRuntime().gc();
@@ -87,7 +87,7 @@
System.out.println(klass2.get());
}
- private static void testUnloadLoader(Constructor constructor)
+ private static void testUnloadLoader(Constructor<?> constructor)
throws Exception {
WeakReference<ClassLoader> loader = setUpUnloadLoader(constructor, true);
// No strong references to class loader, should get unloaded.
@@ -96,8 +96,8 @@
System.out.println(loader.get());
}
- private static void testStackTrace(Constructor constructor) throws Exception {
- Class klass = setUpUnloadClass(constructor);
+ private static void testStackTrace(Constructor<?> constructor) throws Exception {
+ Class<?> klass = setUpUnloadClass(constructor);
WeakReference<Class> weak_klass = new WeakReference(klass);
Method stackTraceMethod = klass.getDeclaredMethod("generateStackTrace");
Throwable throwable = (Throwable) stackTraceMethod.invoke(klass);
@@ -108,7 +108,7 @@
System.out.println("class null " + isNull + " " + throwable.getMessage());
}
- private static void testLoadAndUnloadLibrary(Constructor constructor) throws Exception {
+ private static void testLoadAndUnloadLibrary(Constructor<?> constructor) throws Exception {
WeakReference<ClassLoader> loader = setUpLoadLibrary(constructor);
// No strong references to class loader, should get unloaded.
Runtime.getRuntime().gc();
@@ -117,7 +117,7 @@
}
private static Object testNoUnloadHelper(ClassLoader loader) throws Exception {
- Class intHolder = loader.loadClass("IntHolder");
+ Class<?> intHolder = loader.loadClass("IntHolder");
return intHolder.newInstance();
}
@@ -131,14 +131,14 @@
public WeakReference<ClassLoader> classLoader;
}
- private static Pair testNoUnloadInstanceHelper(Constructor constructor) throws Exception {
+ private static Pair testNoUnloadInstanceHelper(Constructor<?> constructor) throws Exception {
ClassLoader loader = (ClassLoader) constructor.newInstance(
DEX_FILE, LIBRARY_SEARCH_PATH, ClassLoader.getSystemClassLoader());
Object o = testNoUnloadHelper(loader);
return new Pair(o, loader);
}
- private static void testNoUnloadInstance(Constructor constructor) throws Exception {
+ private static void testNoUnloadInstance(Constructor<?> constructor) throws Exception {
Pair p = testNoUnloadInstanceHelper(constructor);
Runtime.getRuntime().gc();
// If the class loader was unloded too early due to races, just pass the test.
@@ -146,10 +146,10 @@
System.out.println("loader null " + isNull);
}
- private static Class setUpUnloadClass(Constructor constructor) throws Exception {
+ private static Class<?> setUpUnloadClass(Constructor<?> constructor) throws Exception {
ClassLoader loader = (ClassLoader) constructor.newInstance(
DEX_FILE, LIBRARY_SEARCH_PATH, ClassLoader.getSystemClassLoader());
- Class intHolder = loader.loadClass("IntHolder");
+ Class<?> intHolder = loader.loadClass("IntHolder");
Method getValue = intHolder.getDeclaredMethod("getValue");
Method setValue = intHolder.getDeclaredMethod("setValue", Integer.TYPE);
// Make sure we don't accidentally preserve the value in the int holder, the class
@@ -161,17 +161,17 @@
return intHolder;
}
- private static WeakReference<Class> setUpUnloadClassWeak(Constructor constructor)
+ private static WeakReference<Class> setUpUnloadClassWeak(Constructor<?> constructor)
throws Exception {
return new WeakReference<Class>(setUpUnloadClass(constructor));
}
- private static WeakReference<ClassLoader> setUpUnloadLoader(Constructor constructor,
+ private static WeakReference<ClassLoader> setUpUnloadLoader(Constructor<?> constructor,
boolean waitForCompilation)
throws Exception {
ClassLoader loader = (ClassLoader) constructor.newInstance(
DEX_FILE, LIBRARY_SEARCH_PATH, ClassLoader.getSystemClassLoader());
- Class intHolder = loader.loadClass("IntHolder");
+ Class<?> intHolder = loader.loadClass("IntHolder");
Method setValue = intHolder.getDeclaredMethod("setValue", Integer.TYPE);
setValue.invoke(intHolder, 2);
if (waitForCompilation) {
@@ -180,7 +180,7 @@
return new WeakReference(loader);
}
- private static void waitForCompilation(Class intHolder) throws Exception {
+ private static void waitForCompilation(Class<?> intHolder) throws Exception {
// Load the native library so that we can call waitForCompilation.
Method loadLibrary = intHolder.getDeclaredMethod("loadLibrary", String.class);
loadLibrary.invoke(intHolder, nativeLibraryName);
@@ -189,11 +189,11 @@
waitForCompilation.invoke(intHolder);
}
- private static WeakReference<ClassLoader> setUpLoadLibrary(Constructor constructor)
+ private static WeakReference<ClassLoader> setUpLoadLibrary(Constructor<?> constructor)
throws Exception {
ClassLoader loader = (ClassLoader) constructor.newInstance(
DEX_FILE, LIBRARY_SEARCH_PATH, ClassLoader.getSystemClassLoader());
- Class intHolder = loader.loadClass("IntHolder");
+ Class<?> intHolder = loader.loadClass("IntHolder");
Method loadLibrary = intHolder.getDeclaredMethod("loadLibrary", String.class);
loadLibrary.invoke(intHolder, nativeLibraryName);
waitForCompilation(intHolder);
diff --git a/test/142-classloader2/src/Main.java b/test/142-classloader2/src/Main.java
index 89dadce..80b00e7 100644
--- a/test/142-classloader2/src/Main.java
+++ b/test/142-classloader2/src/Main.java
@@ -25,8 +25,8 @@
private static ClassLoader createClassLoader(String dexPath, ClassLoader parent) {
try {
Class<?> myClassLoaderClass = Class.forName("MyPathClassLoader");
- Constructor constructor = myClassLoaderClass.getConstructor(String.class,
- ClassLoader.class);
+ Constructor<?> constructor = myClassLoaderClass.getConstructor(String.class,
+ ClassLoader.class);
return (ClassLoader)constructor.newInstance(dexPath, parent);
} catch (Exception e) {
// Ups, not available?!?!
diff --git a/test/145-alloc-tracking-stress/src/Main.java b/test/145-alloc-tracking-stress/src/Main.java
index 752fdd9..4a67a80 100644
--- a/test/145-alloc-tracking-stress/src/Main.java
+++ b/test/145-alloc-tracking-stress/src/Main.java
@@ -31,7 +31,7 @@
}
public static void main(String[] args) throws Exception {
- Class klass = Class.forName("org.apache.harmony.dalvik.ddmc.DdmVmInternal");
+ Class<?> klass = Class.forName("org.apache.harmony.dalvik.ddmc.DdmVmInternal");
if (klass == null) {
throw new AssertionError("Couldn't find DdmVmInternal class");
}
diff --git a/test/148-multithread-gc-annotations/src/AnnoClass1.java b/test/148-multithread-gc-annotations/src/AnnoClass1.java
index b82c61f..3eb45ae 100644
--- a/test/148-multithread-gc-annotations/src/AnnoClass1.java
+++ b/test/148-multithread-gc-annotations/src/AnnoClass1.java
@@ -19,5 +19,5 @@
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface AnnoClass1 {
- Class value();
+ Class<?> value();
}
diff --git a/test/148-multithread-gc-annotations/src/AnnoClass2.java b/test/148-multithread-gc-annotations/src/AnnoClass2.java
index c75d950..b17490f 100644
--- a/test/148-multithread-gc-annotations/src/AnnoClass2.java
+++ b/test/148-multithread-gc-annotations/src/AnnoClass2.java
@@ -19,5 +19,5 @@
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface AnnoClass2 {
- Class value();
+ Class<?> value();
}
diff --git a/test/148-multithread-gc-annotations/src/AnnoClass3.java b/test/148-multithread-gc-annotations/src/AnnoClass3.java
index 5b4a378..7d600a8 100644
--- a/test/148-multithread-gc-annotations/src/AnnoClass3.java
+++ b/test/148-multithread-gc-annotations/src/AnnoClass3.java
@@ -19,5 +19,5 @@
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface AnnoClass3 {
- Class value();
+ Class<?> value();
}
diff --git a/test/201-built-in-exception-detail-messages/src/Main.java b/test/201-built-in-exception-detail-messages/src/Main.java
index f0bb6dd..dc58819 100644
--- a/test/201-built-in-exception-detail-messages/src/Main.java
+++ b/test/201-built-in-exception-detail-messages/src/Main.java
@@ -247,7 +247,7 @@
* Helper for testCastOperatorWithArrays. It's important that
* the return type is Object.
*/
- private static Object makeArray(Class c) {
+ private static Object makeArray(Class<?> c) {
return Array.newInstance(c, 1);
}
diff --git a/test/420-const-class/src/Main.java b/test/420-const-class/src/Main.java
index 44a7436..90ccf3a 100644
--- a/test/420-const-class/src/Main.java
+++ b/test/420-const-class/src/Main.java
@@ -53,15 +53,15 @@
$opt$LoadAndClinitCheck();
}
- public static Class $opt$LoadThisClass() {
+ public static Class<?> $opt$LoadThisClass() {
return Main.class;
}
- public static Class $opt$LoadOtherClass() {
+ public static Class<?> $opt$LoadOtherClass() {
return Other.class;
}
- public static Class $opt$LoadSystemClass() {
+ public static Class<?> $opt$LoadSystemClass() {
return System.class;
}
diff --git a/test/450-checker-types/src/Main.java b/test/450-checker-types/src/Main.java
index 36f14d8..99a1557 100644
--- a/test/450-checker-types/src/Main.java
+++ b/test/450-checker-types/src/Main.java
@@ -103,7 +103,7 @@
/// CHECK-NOT: CheckCast
public String testClassRemove() {
Object s = SubclassA.class;
- return ((Class)s).getName();
+ return ((Class<?>)s).getName();
}
/// CHECK-START: java.lang.String Main.testClassKeep() instruction_simplifier (before)
diff --git a/test/458-checker-instruction-simplification/src/Main.java b/test/458-checker-instruction-simplification/src/Main.java
index 040479e..8a426eb 100644
--- a/test/458-checker-instruction-simplification/src/Main.java
+++ b/test/458-checker-instruction-simplification/src/Main.java
@@ -1859,7 +1859,7 @@
if (doThrow) { throw new Error(); }
try {
Class<?> c = Class.forName("SmaliTests");
- Method m = c.getMethod(name, new Class[] { boolean.class });
+ Method m = c.getMethod(name, boolean.class);
return (Integer) m.invoke(null, input);
} catch (Exception ex) {
throw new Error(ex);
diff --git a/test/462-checker-inlining-across-dex-files/src-multidex/OtherDex.java b/test/462-checker-inlining-across-dex-files/src-multidex/OtherDex.java
index 171ade8..2056e2f 100644
--- a/test/462-checker-inlining-across-dex-files/src-multidex/OtherDex.java
+++ b/test/462-checker-inlining-across-dex-files/src-multidex/OtherDex.java
@@ -38,25 +38,25 @@
return "OtherDex";
}
- public static Class returnOtherDexClass() {
+ public static Class<?> returnOtherDexClass() {
return OtherDex.class;
}
- public static Class returnMainClass() {
+ public static Class<?> returnMainClass() {
return Main.class;
}
- private static Class returnOtherDexClass2() {
+ private static Class<?> returnOtherDexClass2() {
return OtherDex.class;
}
- public static Class returnOtherDexClassStaticCall() {
+ public static Class<?> returnOtherDexClassStaticCall() {
// Do not call returnOtherDexClass, as it may have been flagged
// as non-inlineable.
return returnOtherDexClass2();
}
- public static Class returnOtherDexCallingMain() {
+ public static Class<?> returnOtherDexCallingMain() {
return Main.getOtherClass();
}
diff --git a/test/462-checker-inlining-across-dex-files/src/Main.java b/test/462-checker-inlining-across-dex-files/src/Main.java
index 1fe49a8..c2bb479 100644
--- a/test/462-checker-inlining-across-dex-files/src/Main.java
+++ b/test/462-checker-inlining-across-dex-files/src/Main.java
@@ -106,7 +106,7 @@
/// CHECK-DAG: <<Invoke:l\d+>> InvokeStaticOrDirect
/// CHECK-DAG: Return [<<Invoke>>]
- public static Class dontInlineOtherDexClass() {
+ public static Class<?> dontInlineOtherDexClass() {
return OtherDex.returnOtherDexClass();
}
@@ -123,7 +123,7 @@
// Note: There are two LoadClass instructions. We obtain the correct
// instruction id by matching the Return's input list first.
- public static Class inlineMainClass() {
+ public static Class<?> inlineMainClass() {
return OtherDex.returnMainClass();
}
@@ -135,7 +135,7 @@
/// CHECK-DAG: <<Invoke:l\d+>> InvokeStaticOrDirect
/// CHECK-DAG: Return [<<Invoke>>]
- public static Class dontInlineOtherDexClassStaticCall() {
+ public static Class<?> dontInlineOtherDexClassStaticCall() {
return OtherDex.returnOtherDexClassStaticCall();
}
@@ -152,11 +152,11 @@
// Note: There are two LoadClass instructions. We obtain the correct
// instruction id by matching the Return's input list first.
- public static Class inlineOtherDexCallingMain() {
+ public static Class<?> inlineOtherDexCallingMain() {
return OtherDex.returnOtherDexCallingMain();
}
- public static Class getOtherClass() {
+ public static Class<?> getOtherClass() {
return Main.class;
}
diff --git a/test/471-uninitialized-locals/src/Main.java b/test/471-uninitialized-locals/src/Main.java
index a5b1c48..1ac749e 100644
--- a/test/471-uninitialized-locals/src/Main.java
+++ b/test/471-uninitialized-locals/src/Main.java
@@ -24,8 +24,8 @@
public static void main(String args[]) throws Exception {
try {
Class<?> c = Class.forName("Test");
- Method m = c.getMethod("ThrowException", (Class[]) null);
- m.invoke(null, (Object[]) null);
+ Method m = c.getMethod("ThrowException");
+ m.invoke(null);
} catch (VerifyError e) {
// Compilation should go fine but we expect the runtime verification to fail.
return;
diff --git a/test/472-unreachable-if-regression/src/Main.java b/test/472-unreachable-if-regression/src/Main.java
index c9f9511..d426df1 100644
--- a/test/472-unreachable-if-regression/src/Main.java
+++ b/test/472-unreachable-if-regression/src/Main.java
@@ -25,12 +25,12 @@
System.out.println("Test started.");
Class<?> c = Class.forName("Test");
- Method unreachableIf = c.getMethod("UnreachableIf", (Class[]) null);
- unreachableIf.invoke(null, (Object[]) null);
+ Method unreachableIf = c.getMethod("UnreachableIf");
+ unreachableIf.invoke(null);
System.out.println("Successfully called UnreachableIf().");
- Method unreachablePackedSwitch = c.getMethod("UnreachablePackedSwitch", (Class[]) null);
- unreachablePackedSwitch.invoke(null, (Object[]) null);
+ Method unreachablePackedSwitch = c.getMethod("UnreachablePackedSwitch");
+ unreachablePackedSwitch.invoke(null);
System.out.println("Successfully called UnreachablePackedSwitch().");
}
diff --git a/test/489-current-method-regression/src/Main.java b/test/489-current-method-regression/src/Main.java
index 7d102f5..285c41d 100644
--- a/test/489-current-method-regression/src/Main.java
+++ b/test/489-current-method-regression/src/Main.java
@@ -23,7 +23,7 @@
if (a == 42) {
// The class loading will be seen as dead code by
// the optimizer.
- Class c = Main.class;
+ Class<?> c = Main.class;
}
return new Main().bar();
}
diff --git a/test/496-checker-inlining-and-class-loader/src/Main.java b/test/496-checker-inlining-and-class-loader/src/Main.java
index 78e8a40..15d4dc0 100644
--- a/test/496-checker-inlining-and-class-loader/src/Main.java
+++ b/test/496-checker-inlining-and-class-loader/src/Main.java
@@ -69,7 +69,7 @@
"loadClassBinaryName", String.class, ClassLoader.class, List.class);
if (dexFile != null) {
- Class clazz = (Class)method.invoke(dexFile, className, this, null);
+ Class<?> clazz = (Class<?>)method.invoke(dexFile, className, this, null);
if (clazz != null) {
return clazz;
}
@@ -124,7 +124,7 @@
public class Main {
public static void main(String[] args) throws Exception {
MyClassLoader o = new MyClassLoader();
- Class foo = o.loadClass("LoadedByMyClassLoader");
+ Class<?> foo = o.loadClass("LoadedByMyClassLoader");
Method m = foo.getDeclaredMethod("bar");
m.invoke(null);
}
diff --git a/test/497-inlining-and-class-loader/src/Main.java b/test/497-inlining-and-class-loader/src/Main.java
index 832b1f0..1e27e77 100644
--- a/test/497-inlining-and-class-loader/src/Main.java
+++ b/test/497-inlining-and-class-loader/src/Main.java
@@ -66,7 +66,7 @@
"loadClassBinaryName", String.class, ClassLoader.class, List.class);
if (dex != null) {
- Class clazz = (Class)method.invoke(dex, className, this, null);
+ Class<?> clazz = (Class<?>)method.invoke(dex, className, this, null);
if (clazz != null) {
return clazz;
}
@@ -92,7 +92,7 @@
MyClassLoader o = new MyClassLoader();
MyClassLoader.level1ClassLoader = new MyClassLoader();
- Class foo = o.loadClass("LoadedByMyClassLoader");
+ Class<?> foo = o.loadClass("LoadedByMyClassLoader");
Method m = foo.getDeclaredMethod("bar");
try {
m.invoke(null);
diff --git a/test/501-regression-packed-switch/src/Main.java b/test/501-regression-packed-switch/src/Main.java
index 12bc1a8..74c081a 100644
--- a/test/501-regression-packed-switch/src/Main.java
+++ b/test/501-regression-packed-switch/src/Main.java
@@ -24,12 +24,12 @@
public static void main(String args[]) throws Exception {
Class<?> c = Class.forName("Test");
- Method m = c.getMethod("EmptyPackedSwitch", new Class[] { int.class });
+ Method m = c.getMethod("EmptyPackedSwitch", int.class);
Integer result = (Integer) m.invoke(null, new Integer(42));
if (result != 5) {
throw new Error("Expected 5, got " + result);
}
- m = c.getMethod("PackedSwitchAfterData", new Class[] { int.class });
+ m = c.getMethod("PackedSwitchAfterData", int.class);
result = (Integer) m.invoke(null, new Integer(0));
if (result != 1) {
throw new Error("Expected 1, got " + result);
diff --git a/test/504-regression-baseline-entry/src/Main.java b/test/504-regression-baseline-entry/src/Main.java
index 2c9df28..284cbdc 100644
--- a/test/504-regression-baseline-entry/src/Main.java
+++ b/test/504-regression-baseline-entry/src/Main.java
@@ -24,7 +24,7 @@
public static void main(String args[]) throws Exception {
Class<?> c = Class.forName("Test");
- Method m = c.getMethod("SingleGotoStart", (Class[]) null);
+ Method m = c.getMethod("SingleGotoStart");
Integer result = (Integer) m.invoke(null);
if (result != 5) {
throw new Error("Expected 5, got " + result);
diff --git a/test/510-checker-try-catch/src/Main.java b/test/510-checker-try-catch/src/Main.java
index 25cdc0e..d6dcd30 100644
--- a/test/510-checker-try-catch/src/Main.java
+++ b/test/510-checker-try-catch/src/Main.java
@@ -39,7 +39,7 @@
public static void testMethod(String method) throws Exception {
Class<?> c = Class.forName("Runtime");
- Method m = c.getMethod(method, new Class[] { boolean.class, boolean.class });
+ Method m = c.getMethod(method, boolean.class, boolean.class);
for (TestPath path : TestPath.values()) {
Object[] arguments = new Object[] { path.arg1, path.arg2 };
diff --git a/test/517-checker-builder-fallthrough/src/Main.java b/test/517-checker-builder-fallthrough/src/Main.java
index 23d94e6..14170f5 100644
--- a/test/517-checker-builder-fallthrough/src/Main.java
+++ b/test/517-checker-builder-fallthrough/src/Main.java
@@ -20,7 +20,7 @@
public static int runTest(int input) throws Exception {
Class<?> c = Class.forName("TestCase");
- Method m = c.getMethod("testCase", new Class[] { int.class });
+ Method m = c.getMethod("testCase", int.class);
return (Integer) m.invoke(null, input);
}
diff --git a/test/522-checker-regression-monitor-exit/src/Main.java b/test/522-checker-regression-monitor-exit/src/Main.java
index c85ac96..a5e9512 100644
--- a/test/522-checker-regression-monitor-exit/src/Main.java
+++ b/test/522-checker-regression-monitor-exit/src/Main.java
@@ -40,7 +40,7 @@
Integer result;
try {
Class<?> c = Class.forName("Test");
- Method m = c.getMethod("synchronizedHashCode", new Class[] { Object.class });
+ Method m = c.getMethod("synchronizedHashCode", Object.class);
result = (Integer) m.invoke(null, m_obj);
} catch (Exception e) {
System.err.println("Hash code query exception");
diff --git a/test/542-unresolved-access-check/src/Main.java b/test/542-unresolved-access-check/src/Main.java
index 2bdf47f..62bfea1 100644
--- a/test/542-unresolved-access-check/src/Main.java
+++ b/test/542-unresolved-access-check/src/Main.java
@@ -58,7 +58,7 @@
"loadClassBinaryName", String.class, ClassLoader.class, List.class);
if (dex != null) {
- Class clazz = (Class)method.invoke(dex, className, this, null);
+ Class<?> clazz = (Class<?>)method.invoke(dex, className, this, null);
if (clazz != null) {
return clazz;
}
@@ -72,7 +72,7 @@
public class Main {
public static void main(String[] args) throws Exception {
MyClassLoader o = new MyClassLoader();
- Class foo = o.loadClass("LoadedByMyClassLoader");
+ Class<?> foo = o.loadClass("LoadedByMyClassLoader");
Method m = foo.getDeclaredMethod("main");
m.invoke(null);
}
diff --git a/test/545-tracing-and-jit/src/Main.java b/test/545-tracing-and-jit/src/Main.java
index a2d51d5..f365c6e 100644
--- a/test/545-tracing-and-jit/src/Main.java
+++ b/test/545-tracing-and-jit/src/Main.java
@@ -226,7 +226,7 @@
private static final Method getMethodTracingModeMethod;
static {
try {
- Class c = Class.forName("dalvik.system.VMDebug");
+ Class<?> c = Class.forName("dalvik.system.VMDebug");
startMethodTracingMethod = c.getDeclaredMethod("startMethodTracing", String.class,
Integer.TYPE, Integer.TYPE, Boolean.TYPE, Integer.TYPE);
stopMethodTracingMethod = c.getDeclaredMethod("stopMethodTracing");
diff --git a/test/552-checker-primitive-typeprop/src/Main.java b/test/552-checker-primitive-typeprop/src/Main.java
index fe2343e..1296800 100644
--- a/test/552-checker-primitive-typeprop/src/Main.java
+++ b/test/552-checker-primitive-typeprop/src/Main.java
@@ -29,15 +29,15 @@
public static void main(String[] args) throws Exception {
Class<?> c = Class.forName("SsaBuilder");
- Method m = c.getMethod("environmentPhi", new Class[] { boolean.class, int[].class });
+ Method m = c.getMethod("environmentPhi", boolean.class, int[].class);
int[] array = new int[3];
int result;
- result = (Integer) m.invoke(null, new Object[] { true, array } );
+ result = (Integer) m.invoke(null, true, array);
assertEquals(2, result);
- result = (Integer) m.invoke(null, new Object[] { false, array } );
+ result = (Integer) m.invoke(null, false, array);
assertEquals(0, result);
}
}
diff --git a/test/566-polymorphic-inlining/src/Main.java b/test/566-polymorphic-inlining/src/Main.java
index 53852a4..793b85f 100644
--- a/test/566-polymorphic-inlining/src/Main.java
+++ b/test/566-polymorphic-inlining/src/Main.java
@@ -15,9 +15,9 @@
*/
interface Itf {
- public Class sameInvokeInterface();
- public Class sameInvokeInterface2();
- public Class sameInvokeInterface3();
+ public Class<?> sameInvokeInterface();
+ public Class<?> sameInvokeInterface2();
+ public Class<?> sameInvokeInterface3();
}
public class Main implements Itf {
@@ -81,31 +81,31 @@
assertEquals(20001, counter);
}
- public Class sameInvokeVirtual() {
+ public Class<?> sameInvokeVirtual() {
field.getClass(); // null check to ensure we get an inlined frame in the CodeInfo.
return Main.class;
}
- public Class sameInvokeInterface() {
+ public Class<?> sameInvokeInterface() {
field.getClass(); // null check to ensure we get an inlined frame in the CodeInfo.
return Itf.class;
}
- public Class sameInvokeInterface2() {
+ public Class<?> sameInvokeInterface2() {
field.getClass(); // null check to ensure we get an inlined frame in the CodeInfo.
return Itf.class;
}
- public Class sameInvokeInterface3() {
+ public Class<?> sameInvokeInterface3() {
field.getClass(); // null check to ensure we get an inlined frame in the CodeInfo.
return Itf.class;
}
- public static Class testInvokeInterface(Itf i) {
+ public static Class<?> testInvokeInterface(Itf i) {
return i.sameInvokeInterface();
}
- public static Class testInvokeInterface2(Itf i) {
+ public static Class<?> testInvokeInterface2(Itf i) {
// Make three interface calls that will do a ClassTableGet to ensure bogus code
// generation of ClassTableGet will crash.
i.sameInvokeInterface();
@@ -113,7 +113,7 @@
return i.sameInvokeInterface3();
}
- public static Class testInvokeVirtual(Main m) {
+ public static Class<?> testInvokeVirtual(Main m) {
return m.sameInvokeVirtual();
}
@@ -139,18 +139,18 @@
}
class OtherSubclass extends Main {
- public Class sameInvokeVirtual() {
+ public Class<?> sameInvokeVirtual() {
return OtherSubclass.class;
}
- public Class sameInvokeInterface() {
+ public Class<?> sameInvokeInterface() {
return OtherSubclass.class;
}
- public Class sameInvokeInterface2() {
+ public Class<?> sameInvokeInterface2() {
return null;
}
- public Class sameInvokeInterface3() {
+ public Class<?> sameInvokeInterface3() {
return null;
}
}
diff --git a/test/570-checker-osr/src/Main.java b/test/570-checker-osr/src/Main.java
index 15c232d..8af3894 100644
--- a/test/570-checker-osr/src/Main.java
+++ b/test/570-checker-osr/src/Main.java
@@ -129,7 +129,7 @@
DeoptimizationController.startDeoptimization();
}
- public static Class $noinline$inlineCache(Main m, boolean isSecondInvocation) {
+ public static Class<?> $noinline$inlineCache(Main m, boolean isSecondInvocation) {
// If we are running in non-JIT mode, or were unlucky enough to get this method
// already JITted, just return the expected value.
if (!isInInterpreter("$noinline$inlineCache")) {
@@ -159,7 +159,7 @@
return other.returnClass();
}
- public static Class $noinline$inlineCache2(Main m, boolean isSecondInvocation) {
+ public static Class<?> $noinline$inlineCache2(Main m, boolean isSecondInvocation) {
// If we are running in non-JIT mode, or were unlucky enough to get this method
// already JITted, just return the expected value.
if (!isInInterpreter("$noinline$inlineCache2")) {
@@ -188,7 +188,7 @@
return (other == null) ? null : other.returnClass();
}
- public static Class $noinline$inlineCache3(Main m, boolean isSecondInvocation) {
+ public static Class<?> $noinline$inlineCache3(Main m, boolean isSecondInvocation) {
// If we are running in non-JIT mode, or were unlucky enough to get this method
// already JITted, just return the expected value.
if (!isInInterpreter("$noinline$inlineCache3")) {
@@ -229,7 +229,7 @@
return null;
}
- public Class returnClass() {
+ public Class<?> returnClass() {
return Main.class;
}
@@ -305,7 +305,7 @@
}
class SubMain extends Main {
- public Class returnClass() {
+ public Class<?> returnClass() {
return SubMain.class;
}
diff --git a/test/576-polymorphic-inlining/src/Main.java b/test/576-polymorphic-inlining/src/Main.java
index d8d09af..5763d89 100644
--- a/test/576-polymorphic-inlining/src/Main.java
+++ b/test/576-polymorphic-inlining/src/Main.java
@@ -65,11 +65,11 @@
public void willOnlyInlineForMainVoid() {
}
- public Class willInlineWithReturnValue() {
+ public Class<?> willInlineWithReturnValue() {
return Main.class;
}
- public Class willOnlyInlineForMainWithReturnValue() {
+ public Class<?> willOnlyInlineForMainWithReturnValue() {
return Main.class;
}
public static boolean doThrow;
@@ -83,21 +83,21 @@
public void willInlineVoid() {
}
- public Class willInlineWithReturnValue() {
+ public Class<?> willInlineWithReturnValue() {
return SubMain.class;
}
- public Class willOnlyInlineForMainWithReturnValue() {
+ public Class<?> willOnlyInlineForMainWithReturnValue() {
return SubMain.class;
}
}
class SubSubMain extends SubMain {
- public Class willInlineWithReturnValue() {
+ public Class<?> willInlineWithReturnValue() {
return SubSubMain.class;
}
- public Class willOnlyInlineForMainWithReturnValue() {
+ public Class<?> willOnlyInlineForMainWithReturnValue() {
return SubSubMain.class;
}
}
diff --git a/test/577-profile-foreign-dex/src/Main.java b/test/577-profile-foreign-dex/src/Main.java
index 0cd85b5..ed7a625 100644
--- a/test/577-profile-foreign-dex/src/Main.java
+++ b/test/577-profile-foreign-dex/src/Main.java
@@ -111,11 +111,11 @@
}
private static void loadDexFile(String dexFile) throws Exception {
- Class pathClassLoader = Class.forName("dalvik.system.PathClassLoader");
+ Class<?> pathClassLoader = Class.forName("dalvik.system.PathClassLoader");
if (pathClassLoader == null) {
throw new RuntimeException("Couldn't find path class loader class");
}
- Constructor constructor =
+ Constructor<?> constructor =
pathClassLoader.getDeclaredConstructor(String.class, ClassLoader.class);
constructor.newInstance(
dexFile, ClassLoader.getSystemClassLoader());
@@ -125,7 +125,7 @@
private static final Method registerAppInfoMethod;
static {
try {
- Class c = Class.forName("dalvik.system.VMRuntime");
+ Class<?> c = Class.forName("dalvik.system.VMRuntime");
registerAppInfoMethod = c.getDeclaredMethod("registerAppInfo",
String.class, String.class, String[].class, String.class);
} catch (Exception e) {
diff --git a/test/601-method-access/src/Main.java b/test/601-method-access/src/Main.java
index 838080a..9d9e568 100644
--- a/test/601-method-access/src/Main.java
+++ b/test/601-method-access/src/Main.java
@@ -22,7 +22,7 @@
public class Main {
public static void main(String[] args) {
try {
- Class c = Class.forName("SubClassUsingInaccessibleMethod");
+ Class<?> c = Class.forName("SubClassUsingInaccessibleMethod");
Object o = c.newInstance();
c.getMethod("test").invoke(o, null);
} catch (InvocationTargetException ite) {
diff --git a/test/604-hot-static-interface/src/Main.java b/test/604-hot-static-interface/src/Main.java
index 04d7cd6..a26623c 100644
--- a/test/604-hot-static-interface/src/Main.java
+++ b/test/604-hot-static-interface/src/Main.java
@@ -29,7 +29,7 @@
}
}
- private static native void ensureJitCompiled(Class itf, String method_name);
+ private static native void ensureJitCompiled(Class<?> itf, String method_name);
}
interface Itf {
diff --git a/test/605-new-string-from-bytes/src/Main.java b/test/605-new-string-from-bytes/src/Main.java
index 7dc0c15..5bd6c5d 100644
--- a/test/605-new-string-from-bytes/src/Main.java
+++ b/test/605-new-string-from-bytes/src/Main.java
@@ -20,7 +20,7 @@
public class Main {
public static void main(String[] args) throws Exception {
- Class c = Class.forName("java.lang.StringFactory");
+ Class<?> c = Class.forName("java.lang.StringFactory");
Method m = c.getDeclaredMethod("newStringFromBytes", byte[].class, int.class);
// Loop over allocations to get more chances of doing GC while in the
diff --git a/test/612-jit-dex-cache/src-ex/LoadedByAppClassLoader.java b/test/612-jit-dex-cache/src-ex/LoadedByAppClassLoader.java
index 1d6158a..fcb314d 100644
--- a/test/612-jit-dex-cache/src-ex/LoadedByAppClassLoader.java
+++ b/test/612-jit-dex-cache/src-ex/LoadedByAppClassLoader.java
@@ -29,7 +29,7 @@
}
class OtherClass {
- public static Class getB() {
+ public static Class<?> getB() {
// This used to return the B class of another class loader.
return B.class;
}
diff --git a/test/612-jit-dex-cache/src/Main.java b/test/612-jit-dex-cache/src/Main.java
index 0e4bd22..89ebe09 100644
--- a/test/612-jit-dex-cache/src/Main.java
+++ b/test/612-jit-dex-cache/src/Main.java
@@ -41,7 +41,7 @@
public class Main {
- private static Class classFromDifferentLoader() throws Exception {
+ private static Class<?> classFromDifferentLoader() throws Exception {
final String DEX_FILE = System.getenv("DEX_LOCATION") + "/612-jit-dex-cache-ex.jar";
ClassLoader loader = new DelegateLastPathClassLoader(DEX_FILE, Main.class.getClassLoader());
return loader.loadClass("LoadedByAppClassLoader");
@@ -49,7 +49,7 @@
public static void main(String[] args) throws Exception {
System.loadLibrary(args[0]);
- Class cls = classFromDifferentLoader();
+ Class<?> cls = classFromDifferentLoader();
Method m = cls.getDeclaredMethod("letMeInlineYou", A.class);
B b = new B();
// Invoke the method enough times to get an inline cache and get JITted.
@@ -63,5 +63,5 @@
}
}
- public static native void ensureJitCompiled(Class cls, String method_name);
+ public static native void ensureJitCompiled(Class<?> cls, String method_name);
}
diff --git a/test/MyClassNatives/MyClassNatives.java b/test/MyClassNatives/MyClassNatives.java
index 19c13f7..4a8b0e0 100644
--- a/test/MyClassNatives/MyClassNatives.java
+++ b/test/MyClassNatives/MyClassNatives.java
@@ -35,11 +35,11 @@
static native int getText(long val1, Object obj1, long val2, Object obj2);
synchronized native Object []getSinkPropertiesNative(String path);
- native Class instanceMethodThatShouldReturnClass();
- static native Class staticMethodThatShouldReturnClass();
+ native Class<?> instanceMethodThatShouldReturnClass();
+ static native Class<?> staticMethodThatShouldReturnClass();
- native void instanceMethodThatShouldTakeClass(int i, Class c);
- static native void staticMethodThatShouldTakeClass(int i, Class c);
+ native void instanceMethodThatShouldTakeClass(int i, Class<?> c);
+ static native void staticMethodThatShouldTakeClass(int i, Class<?> c);
native float checkFloats(float f1, float f2);
native void forceStackParameters(int i1, int i2, int i3, int i4, int i5, int i6, int i8, int i9,