diff options
author | 2014-05-15 16:02:46 +0700 | |
---|---|---|
committer | 2014-06-10 10:01:01 -0700 | |
commit | 41c507a9dae44b8329a857da3d9810fab2e9ddc6 (patch) | |
tree | 78d2a1f81227ca41c4541be5fd87cacabaf06ed2 | |
parent | f71f8da2e83fefcec42ad77385c1df62f521ddad (diff) |
ART: Generalize code to find PC for artInvokeInterfaceTrampoline
This allows to determine target method when the interface method has
no dex index, now also for X86-64 and ARM64.
Add constexpr functions to callee_save_frame.h to have compile-time
sizes of callee-save frames. Add a test that ensures they agree
with computations by the corresponding ArtMethod methods.
Move some instruction-set functions into the header file to allow
inlining them. Move arch-specific pointer sizes and alignment sizes
out of globals.h to instruction_set.h to reduce dependencies.
Change-Id: I2997592c7dd1f4dd2bd497522c64bd235ae615a6
Signed-off-by: Alexei Zavjalov <alexei.zavjalov@intel.com>
-rw-r--r-- | build/Android.gtest.mk | 1 | ||||
-rw-r--r-- | runtime/arch/arm64/quick_entrypoints_arm64.S | 2 | ||||
-rw-r--r-- | runtime/entrypoints/quick/callee_save_frame.h | 37 | ||||
-rw-r--r-- | runtime/entrypoints/quick/quick_field_entrypoints.cc | 7 | ||||
-rw-r--r-- | runtime/entrypoints/quick/quick_instrumentation_entrypoints.cc | 6 | ||||
-rw-r--r-- | runtime/entrypoints/quick/quick_trampoline_entrypoints.cc | 81 | ||||
-rw-r--r-- | runtime/entrypoints/quick/quick_trampoline_entrypoints_test.cc | 107 | ||||
-rw-r--r-- | runtime/globals.h | 21 | ||||
-rw-r--r-- | runtime/instruction_set.cc | 93 | ||||
-rw-r--r-- | runtime/instruction_set.h | 117 | ||||
-rw-r--r-- | runtime/instruction_set_test.cc | 4 |
11 files changed, 278 insertions, 198 deletions
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk index e305dc8c53..407269bca6 100644 --- a/build/Android.gtest.mk +++ b/build/Android.gtest.mk @@ -37,6 +37,7 @@ RUNTIME_GTEST_COMMON_SRC_FILES := \ runtime/dex_instruction_visitor_test.cc \ runtime/dex_method_iterator_test.cc \ runtime/entrypoints/math_entrypoints_test.cc \ + runtime/entrypoints/quick/quick_trampoline_entrypoints_test.cc \ runtime/entrypoints_order_test.cc \ runtime/exception_test.cc \ runtime/gc/accounting/space_bitmap_test.cc \ diff --git a/runtime/arch/arm64/quick_entrypoints_arm64.S b/runtime/arch/arm64/quick_entrypoints_arm64.S index 69f5957918..605728955b 100644 --- a/runtime/arch/arm64/quick_entrypoints_arm64.S +++ b/runtime/arch/arm64/quick_entrypoints_arm64.S @@ -479,7 +479,7 @@ ENTRY \c_name // Helper signature is always // (method_idx, *this_object, *caller_method, *self, sp) - ldr x2, [sp, #FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE] // pass caller Method* + ldr w2, [sp, #FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE] // pass caller Method* mov x3, xSELF // pass Thread::Current mov x4, sp bl \cxx_name // (method_idx, this, caller, Thread*, SP) diff --git a/runtime/entrypoints/quick/callee_save_frame.h b/runtime/entrypoints/quick/callee_save_frame.h index b582abb1a6..e573d6da85 100644 --- a/runtime/entrypoints/quick/callee_save_frame.h +++ b/runtime/entrypoints/quick/callee_save_frame.h @@ -18,8 +18,17 @@ #define ART_RUNTIME_ENTRYPOINTS_QUICK_CALLEE_SAVE_FRAME_H_ #include "base/mutex.h" +#include "instruction_set.h" #include "thread-inl.h" +// Specific frame size code is in architecture-specific files. We include this to compile-time +// specialize the code. +#include "arch/arm/quick_method_frame_info_arm.h" +#include "arch/arm64/quick_method_frame_info_arm64.h" +#include "arch/mips/quick_method_frame_info_mips.h" +#include "arch/x86/quick_method_frame_info_x86.h" +#include "arch/x86_64/quick_method_frame_info_x86_64.h" + namespace art { namespace mirror { class ArtMethod; @@ -36,6 +45,34 @@ static inline void FinishCalleeSaveFrameSetup(Thread* self, StackReference<mirro self->VerifyStack(); } +static constexpr size_t GetCalleeSaveFrameSize(InstructionSet isa, Runtime::CalleeSaveType type) { + // constexpr must be a return statement. + return (isa == kArm || isa == kThumb2) ? arm::ArmCalleeSaveFrameSize(type) : + isa == kArm64 ? arm64::Arm64CalleeSaveFrameSize(type) : + isa == kMips ? mips::MipsCalleeSaveFrameSize(type) : + isa == kX86 ? x86::X86CalleeSaveFrameSize(type) : + isa == kX86_64 ? x86_64::X86_64CalleeSaveFrameSize(type) : + isa == kNone ? (LOG(FATAL) << "kNone has no frame size", 0) : + (LOG(FATAL) << "Unknown instruction set" << isa, 0); +} + +// Note: this specialized statement is sanity-checked in the quick-trampoline gtest. +static constexpr size_t GetConstExprPointerSize(InstructionSet isa) { + // constexpr must be a return statement. + return (isa == kArm || isa == kThumb2) ? kArmPointerSize : + isa == kArm64 ? kArm64PointerSize : + isa == kMips ? kMipsPointerSize : + isa == kX86 ? kX86PointerSize : + isa == kX86_64 ? kX86_64PointerSize : + isa == kNone ? (LOG(FATAL) << "kNone has no pointer size", 0) : + (LOG(FATAL) << "Unknown instruction set" << isa, 0); +} + +// Note: this specialized statement is sanity-checked in the quick-trampoline gtest. +static constexpr size_t GetCalleeSavePCOffset(InstructionSet isa, Runtime::CalleeSaveType type) { + return GetCalleeSaveFrameSize(isa, type) - GetConstExprPointerSize(isa); +} + } // namespace art #endif // ART_RUNTIME_ENTRYPOINTS_QUICK_CALLEE_SAVE_FRAME_H_ diff --git a/runtime/entrypoints/quick/quick_field_entrypoints.cc b/runtime/entrypoints/quick/quick_field_entrypoints.cc index 3178cdea03..5cb0f3662f 100644 --- a/runtime/entrypoints/quick/quick_field_entrypoints.cc +++ b/runtime/entrypoints/quick/quick_field_entrypoints.cc @@ -248,10 +248,7 @@ extern "C" int artSet32InstanceFromCode(uint32_t field_idx, mirror::Object* obj, extern "C" int artSet64InstanceFromCode(uint32_t field_idx, mirror::Object* obj, uint64_t new_value, Thread* self, StackReference<mirror::ArtMethod>* sp) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - Runtime* runtime = Runtime::Current(); - mirror::ArtMethod* callee_save = runtime->GetCalleeSaveMethod(Runtime::kRefsOnly); - uint32_t frame_size = - runtime->GetCalleeSaveMethodFrameInfo(Runtime::kRefsOnly).FrameSizeInBytes(); + constexpr size_t frame_size = GetCalleeSaveFrameSize(kRuntimeISA, Runtime::kRefsOnly); mirror::ArtMethod* referrer = reinterpret_cast<StackReference<mirror::ArtMethod>*>( reinterpret_cast<uint8_t*>(sp) + frame_size)->AsMirrorPtr(); @@ -262,7 +259,7 @@ extern "C" int artSet64InstanceFromCode(uint32_t field_idx, mirror::Object* obj, field->Set64<false>(obj, new_value); return 0; // success } - sp->Assign(callee_save); + sp->Assign(Runtime::Current()->GetCalleeSaveMethod(Runtime::kRefsOnly)); self->SetTopOfStack(sp, 0); field = FindFieldFromCode<InstancePrimitiveWrite, true>(field_idx, referrer, self, sizeof(int64_t)); diff --git a/runtime/entrypoints/quick/quick_instrumentation_entrypoints.cc b/runtime/entrypoints/quick/quick_instrumentation_entrypoints.cc index 6ef075da6b..e0be14e7d6 100644 --- a/runtime/entrypoints/quick/quick_instrumentation_entrypoints.cc +++ b/runtime/entrypoints/quick/quick_instrumentation_entrypoints.cc @@ -50,10 +50,8 @@ extern "C" uint64_t artInstrumentationMethodExitFromCode(Thread* self, // Be aware the store below may well stomp on an incoming argument. Locks::mutator_lock_->AssertSharedHeld(self); Runtime* runtime = Runtime::Current(); - mirror::ArtMethod* callee_save = runtime->GetCalleeSaveMethod(Runtime::kRefsOnly); - sp->Assign(callee_save); - uint32_t return_pc_offset = callee_save->GetReturnPcOffsetInBytes( - runtime->GetCalleeSaveMethodFrameInfo(Runtime::kRefsOnly).FrameSizeInBytes()); + sp->Assign(runtime->GetCalleeSaveMethod(Runtime::kRefsOnly)); + uint32_t return_pc_offset = GetCalleeSavePCOffset(kRuntimeISA, Runtime::kRefsOnly); uintptr_t* return_pc = reinterpret_cast<uintptr_t*>(reinterpret_cast<byte*>(sp) + return_pc_offset); CHECK_EQ(*return_pc, 0U); diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc index a3b1683973..5eea2521fa 100644 --- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc +++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc @@ -36,6 +36,9 @@ namespace art { class QuickArgumentVisitor { // Number of bytes for each out register in the caller method's frame. static constexpr size_t kBytesStackArgLocation = 4; + // Frame size in bytes of a callee-save frame for RefsAndArgs. + static constexpr size_t kQuickCalleeSaveFrame_RefAndArgs_FrameSize = + GetCalleeSaveFrameSize(kRuntimeISA, Runtime::kRefsAndArgs); #if defined(__arm__) // The callee save frame is pointed to by SP. // | argN | | @@ -58,7 +61,6 @@ class QuickArgumentVisitor { static constexpr size_t kQuickCalleeSaveFrame_RefAndArgs_Fpr1Offset = 0; // Offset of first FPR arg. static constexpr size_t kQuickCalleeSaveFrame_RefAndArgs_Gpr1Offset = 8; // Offset of first GPR arg. static constexpr size_t kQuickCalleeSaveFrame_RefAndArgs_LrOffset = 44; // Offset of return address. - static constexpr size_t kQuickCalleeSaveFrame_RefAndArgs_FrameSize = 48; // Frame size. static size_t GprIndexToGprOffset(uint32_t gpr_index) { return gpr_index * GetBytesPerGprSpillLocation(kRuntimeISA); } @@ -86,10 +88,9 @@ class QuickArgumentVisitor { static constexpr bool kQuickSoftFloatAbi = false; // This is a hard float ABI. static constexpr size_t kNumQuickGprArgs = 7; // 7 arguments passed in GPRs. static constexpr size_t kNumQuickFprArgs = 8; // 8 arguments passed in FPRs. - static constexpr size_t kQuickCalleeSaveFrame_RefAndArgs_Fpr1Offset =16; // Offset of first FPR arg. + static constexpr size_t kQuickCalleeSaveFrame_RefAndArgs_Fpr1Offset = 16; // Offset of first FPR arg. static constexpr size_t kQuickCalleeSaveFrame_RefAndArgs_Gpr1Offset = 144; // Offset of first GPR arg. static constexpr size_t kQuickCalleeSaveFrame_RefAndArgs_LrOffset = 296; // Offset of return address. - static constexpr size_t kQuickCalleeSaveFrame_RefAndArgs_FrameSize = 304; // Frame size. static size_t GprIndexToGprOffset(uint32_t gpr_index) { return gpr_index * GetBytesPerGprSpillLocation(kRuntimeISA); } @@ -114,7 +115,6 @@ class QuickArgumentVisitor { static constexpr size_t kQuickCalleeSaveFrame_RefAndArgs_Fpr1Offset = 0; // Offset of first FPR arg. static constexpr size_t kQuickCalleeSaveFrame_RefAndArgs_Gpr1Offset = 4; // Offset of first GPR arg. static constexpr size_t kQuickCalleeSaveFrame_RefAndArgs_LrOffset = 60; // Offset of return address. - static constexpr size_t kQuickCalleeSaveFrame_RefAndArgs_FrameSize = 64; // Frame size. static size_t GprIndexToGprOffset(uint32_t gpr_index) { return gpr_index * GetBytesPerGprSpillLocation(kRuntimeISA); } @@ -139,7 +139,6 @@ class QuickArgumentVisitor { static constexpr size_t kQuickCalleeSaveFrame_RefAndArgs_Fpr1Offset = 0; // Offset of first FPR arg. static constexpr size_t kQuickCalleeSaveFrame_RefAndArgs_Gpr1Offset = 4; // Offset of first GPR arg. static constexpr size_t kQuickCalleeSaveFrame_RefAndArgs_LrOffset = 28; // Offset of return address. - static constexpr size_t kQuickCalleeSaveFrame_RefAndArgs_FrameSize = 32; // Frame size. static size_t GprIndexToGprOffset(uint32_t gpr_index) { return gpr_index * GetBytesPerGprSpillLocation(kRuntimeISA); } @@ -177,7 +176,6 @@ class QuickArgumentVisitor { static constexpr size_t kQuickCalleeSaveFrame_RefAndArgs_Fpr1Offset = 16; // Offset of first FPR arg. static constexpr size_t kQuickCalleeSaveFrame_RefAndArgs_Gpr1Offset = 80; // Offset of first GPR arg. static constexpr size_t kQuickCalleeSaveFrame_RefAndArgs_LrOffset = 168; // Offset of return address. - static constexpr size_t kQuickCalleeSaveFrame_RefAndArgs_FrameSize = 176; // Frame size. static size_t GprIndexToGprOffset(uint32_t gpr_index) { switch (gpr_index) { case 0: return (4 * GetBytesPerGprSpillLocation(kRuntimeISA)); @@ -219,10 +217,7 @@ class QuickArgumentVisitor { stack_args_(reinterpret_cast<byte*>(sp) + kQuickCalleeSaveFrame_RefAndArgs_FrameSize + StackArgumentStartFromShorty(is_static, shorty, shorty_len)), gpr_index_(0), fpr_index_(0), stack_index_(0), cur_type_(Primitive::kPrimVoid), - is_split_long_or_double_(false) { - DCHECK_EQ(kQuickCalleeSaveFrame_RefAndArgs_FrameSize, - Runtime::Current()->GetCalleeSaveMethod(Runtime::kRefsAndArgs)->GetFrameSizeInBytes()); - } + is_split_long_or_double_(false) { } virtual ~QuickArgumentVisitor() {} @@ -1802,66 +1797,12 @@ extern "C" MethodAndCode artInvokeInterfaceTrampoline(mirror::ArtMethod* interfa } else { FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsAndArgs); DCHECK(interface_method == Runtime::Current()->GetResolutionMethod()); - // Determine method index from calling dex instruction. -#if defined(__arm__) - // On entry the stack pointed by sp is: - // | argN | | - // | ... | | - // | arg4 | | - // | arg3 spill | | Caller's frame - // | arg2 spill | | - // | arg1 spill | | - // | Method* | --- - // | LR | - // | ... | callee saves - // | R3 | arg3 - // | R2 | arg2 - // | R1 | arg1 - // | R0 | - // | Method* | <- sp - DCHECK_EQ(48U, Runtime::Current()->GetCalleeSaveMethod(Runtime::kRefsAndArgs)->GetFrameSizeInBytes()); - uintptr_t* regs = reinterpret_cast<uintptr_t*>(reinterpret_cast<byte*>(sp) + kPointerSize); - uintptr_t caller_pc = regs[10]; -#elif defined(__i386__) - // On entry the stack pointed by sp is: - // | argN | | - // | ... | | - // | arg4 | | - // | arg3 spill | | Caller's frame - // | arg2 spill | | - // | arg1 spill | | - // | Method* | --- - // | Return | - // | EBP,ESI,EDI | callee saves - // | EBX | arg3 - // | EDX | arg2 - // | ECX | arg1 - // | EAX/Method* | <- sp - DCHECK_EQ(32U, Runtime::Current()->GetCalleeSaveMethod(Runtime::kRefsAndArgs)->GetFrameSizeInBytes()); - uintptr_t* regs = reinterpret_cast<uintptr_t*>(reinterpret_cast<byte*>(sp)); - uintptr_t caller_pc = regs[7]; -#elif defined(__mips__) - // On entry the stack pointed by sp is: - // | argN | | - // | ... | | - // | arg4 | | - // | arg3 spill | | Caller's frame - // | arg2 spill | | - // | arg1 spill | | - // | Method* | --- - // | RA | - // | ... | callee saves - // | A3 | arg3 - // | A2 | arg2 - // | A1 | arg1 - // | A0/Method* | <- sp - DCHECK_EQ(64U, Runtime::Current()->GetCalleeSaveMethod(Runtime::kRefsAndArgs)->GetFrameSizeInBytes()); - uintptr_t* regs = reinterpret_cast<uintptr_t*>(reinterpret_cast<byte*>(sp)); - uintptr_t caller_pc = regs[15]; -#else - UNIMPLEMENTED(FATAL); - uintptr_t caller_pc = 0; -#endif + + // Find the caller PC. + constexpr size_t pc_offset = GetCalleeSavePCOffset(kRuntimeISA, Runtime::kRefsAndArgs); + uintptr_t caller_pc = *reinterpret_cast<uintptr_t*>(reinterpret_cast<byte*>(sp) + pc_offset); + + // Map the caller PC to a dex PC. uint32_t dex_pc = caller_method->ToDexPc(caller_pc); const DexFile::CodeItem* code = MethodHelper(caller_method).GetCodeItem(); CHECK_LT(dex_pc, code->insns_size_in_code_units_); diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints_test.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints_test.cc new file mode 100644 index 0000000000..66ee218bae --- /dev/null +++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints_test.cc @@ -0,0 +1,107 @@ +/* + * 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. + */ + +#include <stdint.h> + +#include "callee_save_frame.h" +#include "common_runtime_test.h" +#include "mirror/art_method-inl.h" +#include "quick/quick_method_frame_info.h" + +namespace art { + +class QuickTrampolineEntrypointsTest : public CommonRuntimeTest { + protected: + static mirror::ArtMethod* CreateCalleeSaveMethod(InstructionSet isa, + Runtime::CalleeSaveType type) + NO_THREAD_SAFETY_ANALYSIS { + Runtime* r = Runtime::Current(); + + Thread* t = Thread::Current(); + t->TransitionFromSuspendedToRunnable(); // So we can create callee-save methods. + + r->SetInstructionSet(isa); + mirror::ArtMethod* save_method = r->CreateCalleeSaveMethod(type); + r->SetCalleeSaveMethod(save_method, type); + + t->TransitionFromRunnableToSuspended(ThreadState::kNative); // So we can shut down. + + return save_method; + } + + static void CheckFrameSize(InstructionSet isa, Runtime::CalleeSaveType type, uint32_t save_size) + NO_THREAD_SAFETY_ANALYSIS { + mirror::ArtMethod* save_method = CreateCalleeSaveMethod(isa, type); + QuickMethodFrameInfo frame_info = save_method->GetQuickFrameInfo(); + EXPECT_EQ(frame_info.FrameSizeInBytes(), save_size) << "Expected and real size differs for " + << type << " core spills=" << std::hex << frame_info.CoreSpillMask() << " fp spills=" + << frame_info.FpSpillMask() << std::dec << " ISA " << isa; + } + + static void CheckPCOffset(InstructionSet isa, Runtime::CalleeSaveType type, size_t pc_offset) + NO_THREAD_SAFETY_ANALYSIS { + mirror::ArtMethod* save_method = CreateCalleeSaveMethod(isa, type); + QuickMethodFrameInfo frame_info = save_method->GetQuickFrameInfo(); + EXPECT_EQ(save_method->GetReturnPcOffsetInBytes(), pc_offset) << "Expected and real pc offset" + " differs for " << type << " core spills=" << std::hex << frame_info.CoreSpillMask() << + " fp spills=" << frame_info.FpSpillMask() << std::dec << " ISA " << isa; + } +}; + +// Note: these tests are all runtime tests. They let the Runtime create the corresponding ArtMethod +// and check against it. Technically we know and expect certain values, but the Runtime code is +// not constexpr, so we cannot make this compile-time checks (and I want the Runtime code tested). + +// This test ensures that kQuickCalleeSaveFrame_RefAndArgs_FrameSize is correct. +TEST_F(QuickTrampolineEntrypointsTest, FrameSize) { + // We have to use a define here as the callee_save_frame.h functions are constexpr. +#define CHECK_FRAME_SIZE(isa) \ + CheckFrameSize(isa, Runtime::kRefsAndArgs, GetCalleeSaveFrameSize(isa, Runtime::kRefsAndArgs)); \ + CheckFrameSize(isa, Runtime::kRefsOnly, GetCalleeSaveFrameSize(isa, Runtime::kRefsOnly)); \ + CheckFrameSize(isa, Runtime::kSaveAll, GetCalleeSaveFrameSize(isa, Runtime::kSaveAll)) + + CHECK_FRAME_SIZE(kArm); + CHECK_FRAME_SIZE(kArm64); + CHECK_FRAME_SIZE(kMips); + CHECK_FRAME_SIZE(kX86); + CHECK_FRAME_SIZE(kX86_64); +} + +// This test ensures that GetConstExprPointerSize is correct with respect to +// GetInstructionSetPointerSize. +TEST_F(QuickTrampolineEntrypointsTest, PointerSize) { + EXPECT_EQ(GetInstructionSetPointerSize(kArm), GetConstExprPointerSize(kArm)); + EXPECT_EQ(GetInstructionSetPointerSize(kArm64), GetConstExprPointerSize(kArm64)); + EXPECT_EQ(GetInstructionSetPointerSize(kMips), GetConstExprPointerSize(kMips)); + EXPECT_EQ(GetInstructionSetPointerSize(kX86), GetConstExprPointerSize(kX86)); + EXPECT_EQ(GetInstructionSetPointerSize(kX86_64), GetConstExprPointerSize(kX86_64)); +} + +// This test ensures that the constexpr specialization of the return PC offset computation in +// GetCalleeSavePCOffset is correct. +TEST_F(QuickTrampolineEntrypointsTest, ReturnPC) { + // Ensure that the computation in callee_save_frame.h correct. + // Note: we can only check against the kRuntimeISA, because the ArtMethod computation uses + // kPointerSize, which is wrong when the target bitwidth is not the same as the host's. + CheckPCOffset(kRuntimeISA, Runtime::kRefsAndArgs, + GetCalleeSavePCOffset(kRuntimeISA, Runtime::kRefsAndArgs)); + CheckPCOffset(kRuntimeISA, Runtime::kRefsOnly, + GetCalleeSavePCOffset(kRuntimeISA, Runtime::kRefsOnly)); + CheckPCOffset(kRuntimeISA, Runtime::kSaveAll, + GetCalleeSavePCOffset(kRuntimeISA, Runtime::kSaveAll)); +} + +} // namespace art diff --git a/runtime/globals.h b/runtime/globals.h index 07fadb9d45..58c2118e27 100644 --- a/runtime/globals.h +++ b/runtime/globals.h @@ -36,13 +36,6 @@ static constexpr size_t GB = KB * KB * KB; static constexpr size_t kWordSize = sizeof(word); static constexpr size_t kPointerSize = sizeof(void*); -// Architecture-specific pointer sizes -static constexpr size_t kArmPointerSize = 4; -static constexpr size_t kArm64PointerSize = 8; -static constexpr size_t kMipsPointerSize = 4; -static constexpr size_t kX86PointerSize = 4; -static constexpr size_t kX86_64PointerSize = 8; - static constexpr size_t kBitsPerByte = 8; static constexpr size_t kBitsPerByteLog2 = 3; static constexpr int kBitsPerWord = kWordSize * kBitsPerByte; @@ -51,20 +44,6 @@ static constexpr size_t kWordHighBitMask = static_cast<size_t>(1) << (kBitsPerWo // Required stack alignment static constexpr size_t kStackAlignment = 16; -// ARM instruction alignment. ARM processors require code to be 4-byte aligned, -// but ARM ELF requires 8.. -static constexpr size_t kArmAlignment = 8; - -// ARM64 instruction alignment. This is the recommended alignment for maximum performance. -static constexpr size_t kArm64Alignment = 16; - -// MIPS instruction alignment. MIPS processors require code to be 4-byte aligned. -// TODO: Can this be 4? -static constexpr size_t kMipsAlignment = 8; - -// X86 instruction alignment. This is the recommended alignment for maximum performance. -static constexpr size_t kX86Alignment = 16; - // System page size. We check this against sysconf(_SC_PAGE_SIZE) at runtime, but use a simple // compile-time constant so the compiler can generate better code. static constexpr int kPageSize = 4096; diff --git a/runtime/instruction_set.cc b/runtime/instruction_set.cc index c1931a9414..5b6039647c 100644 --- a/runtime/instruction_set.cc +++ b/runtime/instruction_set.cc @@ -16,9 +16,6 @@ #include "instruction_set.h" -#include "globals.h" -#include "base/logging.h" // Logging is required for FATAL in the helper functions. - namespace art { const char* GetInstructionSetString(const InstructionSet isa) { @@ -63,75 +60,6 @@ InstructionSet GetInstructionSetFromString(const char* isa_str) { return kNone; } -size_t GetInstructionSetPointerSize(InstructionSet isa) { - switch (isa) { - case kArm: - // Fall-through. - case kThumb2: - return kArmPointerSize; - case kArm64: - return kArm64PointerSize; - case kX86: - return kX86PointerSize; - case kX86_64: - return kX86_64PointerSize; - case kMips: - return kMipsPointerSize; - case kNone: - LOG(FATAL) << "ISA kNone does not have pointer size."; - return 0; - default: - LOG(FATAL) << "Unknown ISA " << isa; - return 0; - } -} - -size_t GetBytesPerGprSpillLocation(InstructionSet isa) { - switch (isa) { - case kArm: - // Fall-through. - case kThumb2: - return 4; - case kArm64: - return 8; - case kX86: - return 4; - case kX86_64: - return 8; - case kMips: - return 4; - case kNone: - LOG(FATAL) << "ISA kNone does not have spills."; - return 0; - default: - LOG(FATAL) << "Unknown ISA " << isa; - return 0; - } -} - -size_t GetBytesPerFprSpillLocation(InstructionSet isa) { - switch (isa) { - case kArm: - // Fall-through. - case kThumb2: - return 4; - case kArm64: - return 8; - case kX86: - return 8; - case kX86_64: - return 8; - case kMips: - return 4; - case kNone: - LOG(FATAL) << "ISA kNone does not have spills."; - return 0; - default: - LOG(FATAL) << "Unknown ISA " << isa; - return 0; - } -} - size_t GetInstructionSetAlignment(InstructionSet isa) { switch (isa) { case kArm: @@ -155,27 +83,6 @@ size_t GetInstructionSetAlignment(InstructionSet isa) { } } -bool Is64BitInstructionSet(InstructionSet isa) { - switch (isa) { - case kArm: - case kThumb2: - case kX86: - case kMips: - return false; - - case kArm64: - case kX86_64: - return true; - - case kNone: - LOG(FATAL) << "ISA kNone does not have bit width."; - return 0; - default: - LOG(FATAL) << "Unknown ISA " << isa; - return 0; - } -} - std::string InstructionSetFeatures::GetFeatureString() const { std::string result; if ((mask_ & kHwDiv) != 0) { diff --git a/runtime/instruction_set.h b/runtime/instruction_set.h index 679c575a47..7b49b47e54 100644 --- a/runtime/instruction_set.h +++ b/runtime/instruction_set.h @@ -20,6 +20,7 @@ #include <iosfwd> #include <string> +#include "base/logging.h" // Logging is required for FATAL in the helper functions. #include "base/macros.h" namespace art { @@ -35,14 +36,122 @@ enum InstructionSet { }; std::ostream& operator<<(std::ostream& os, const InstructionSet& rhs); +// Architecture-specific pointer sizes +static constexpr size_t kArmPointerSize = 4; +static constexpr size_t kArm64PointerSize = 8; +static constexpr size_t kMipsPointerSize = 4; +static constexpr size_t kX86PointerSize = 4; +static constexpr size_t kX86_64PointerSize = 8; + +// ARM instruction alignment. ARM processors require code to be 4-byte aligned, +// but ARM ELF requires 8.. +static constexpr size_t kArmAlignment = 8; + +// ARM64 instruction alignment. This is the recommended alignment for maximum performance. +static constexpr size_t kArm64Alignment = 16; + +// MIPS instruction alignment. MIPS processors require code to be 4-byte aligned. +// TODO: Can this be 4? +static constexpr size_t kMipsAlignment = 8; + +// X86 instruction alignment. This is the recommended alignment for maximum performance. +static constexpr size_t kX86Alignment = 16; + + const char* GetInstructionSetString(InstructionSet isa); InstructionSet GetInstructionSetFromString(const char* instruction_set); -size_t GetInstructionSetPointerSize(InstructionSet isa); +static inline size_t GetInstructionSetPointerSize(InstructionSet isa) { + switch (isa) { + case kArm: + // Fall-through. + case kThumb2: + return kArmPointerSize; + case kArm64: + return kArm64PointerSize; + case kX86: + return kX86PointerSize; + case kX86_64: + return kX86_64PointerSize; + case kMips: + return kMipsPointerSize; + case kNone: + LOG(FATAL) << "ISA kNone does not have pointer size."; + return 0; + default: + LOG(FATAL) << "Unknown ISA " << isa; + return 0; + } +} + size_t GetInstructionSetAlignment(InstructionSet isa); -bool Is64BitInstructionSet(InstructionSet isa); -size_t GetBytesPerGprSpillLocation(InstructionSet isa); -size_t GetBytesPerFprSpillLocation(InstructionSet isa); + +static inline bool Is64BitInstructionSet(InstructionSet isa) { + switch (isa) { + case kArm: + case kThumb2: + case kX86: + case kMips: + return false; + + case kArm64: + case kX86_64: + return true; + + case kNone: + LOG(FATAL) << "ISA kNone does not have bit width."; + return 0; + default: + LOG(FATAL) << "Unknown ISA " << isa; + return 0; + } +} + +static inline size_t GetBytesPerGprSpillLocation(InstructionSet isa) { + switch (isa) { + case kArm: + // Fall-through. + case kThumb2: + return 4; + case kArm64: + return 8; + case kX86: + return 4; + case kX86_64: + return 8; + case kMips: + return 4; + case kNone: + LOG(FATAL) << "ISA kNone does not have spills."; + return 0; + default: + LOG(FATAL) << "Unknown ISA " << isa; + return 0; + } +} + +static inline size_t GetBytesPerFprSpillLocation(InstructionSet isa) { + switch (isa) { + case kArm: + // Fall-through. + case kThumb2: + return 4; + case kArm64: + return 8; + case kX86: + return 8; + case kX86_64: + return 8; + case kMips: + return 4; + case kNone: + LOG(FATAL) << "ISA kNone does not have spills."; + return 0; + default: + LOG(FATAL) << "Unknown ISA " << isa; + return 0; + } +} #if defined(__arm__) static constexpr InstructionSet kRuntimeISA = kArm; diff --git a/runtime/instruction_set_test.cc b/runtime/instruction_set_test.cc index cd6337cb04..ece32386d5 100644 --- a/runtime/instruction_set_test.cc +++ b/runtime/instruction_set_test.cc @@ -45,4 +45,8 @@ TEST_F(InstructionSetTest, TestRoundTrip) { EXPECT_EQ(kRuntimeISA, GetInstructionSetFromString(GetInstructionSetString(kRuntimeISA))); } +TEST_F(InstructionSetTest, PointerSize) { + EXPECT_EQ(kPointerSize, GetInstructionSetPointerSize(kRuntimeISA)); +} + } // namespace art |