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>
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk
index e305dc8..407269b 100644
--- a/build/Android.gtest.mk
+++ b/build/Android.gtest.mk
@@ -37,6 +37,7 @@
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 69f5957..6057289 100644
--- a/runtime/arch/arm64/quick_entrypoints_arm64.S
+++ b/runtime/arch/arm64/quick_entrypoints_arm64.S
@@ -479,7 +479,7 @@
// 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 b582abb..e573d6d 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 @@
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 3178cde..5cb0f36 100644
--- a/runtime/entrypoints/quick/quick_field_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_field_entrypoints.cc
@@ -248,10 +248,7 @@
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 @@
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 6ef075d..e0be14e 100644
--- a/runtime/entrypoints/quick/quick_instrumentation_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_instrumentation_entrypoints.cc
@@ -50,10 +50,8 @@
// 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 a3b1683..5eea252 100644
--- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
@@ -36,6 +36,9 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
} 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 0000000..66ee218
--- /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 07fadb9..58c2118 100644
--- a/runtime/globals.h
+++ b/runtime/globals.h
@@ -36,13 +36,6 @@
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 @@
// 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 c1931a9..5b60396 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 @@
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 @@
}
}
-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 679c575..7b49b47 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 @@
};
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 cd6337c..ece3238 100644
--- a/runtime/instruction_set_test.cc
+++ b/runtime/instruction_set_test.cc
@@ -45,4 +45,8 @@
EXPECT_EQ(kRuntimeISA, GetInstructionSetFromString(GetInstructionSetString(kRuntimeISA)));
}
+TEST_F(InstructionSetTest, PointerSize) {
+ EXPECT_EQ(kPointerSize, GetInstructionSetPointerSize(kRuntimeISA));
+}
+
} // namespace art