summaryrefslogtreecommitdiff
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/common_compiler_test.h2
-rw-r--r--compiler/driver/compiler_driver.cc83
-rw-r--r--compiler/driver/compiler_driver.h35
-rw-r--r--compiler/image_writer.cc6
-rw-r--r--compiler/image_writer.h2
-rw-r--r--compiler/jni/jni_compiler_test.cc213
-rw-r--r--compiler/jni/quick/arm/calling_convention_arm.cc2
-rw-r--r--compiler/jni/quick/arm64/calling_convention_arm64.cc191
-rw-r--r--compiler/jni/quick/arm64/calling_convention_arm64.h8
-rw-r--r--compiler/jni/quick/calling_convention.cc38
-rw-r--r--compiler/jni/quick/calling_convention.h29
-rw-r--r--compiler/jni/quick/jni_compiler.cc121
-rw-r--r--compiler/jni/quick/mips/calling_convention_mips.cc2
-rw-r--r--compiler/jni/quick/x86/calling_convention_x86.cc2
-rw-r--r--compiler/jni/quick/x86_64/calling_convention_x86_64.cc2
-rw-r--r--compiler/oat_writer.cc36
-rw-r--r--compiler/utils/arm64/assembler_arm64.cc138
-rw-r--r--compiler/utils/arm64/assembler_arm64.h23
-rw-r--r--compiler/utils/arm64/constants_arm64.h3
-rw-r--r--compiler/utils/managed_register.h8
20 files changed, 635 insertions, 309 deletions
diff --git a/compiler/common_compiler_test.h b/compiler/common_compiler_test.h
index 9a21da070a..fdf09a50a6 100644
--- a/compiler/common_compiler_test.h
+++ b/compiler/common_compiler_test.h
@@ -299,7 +299,7 @@ class CommonCompilerTest : public CommonRuntimeTest {
// for ARM, do a runtime check to make sure that the features we are passed from
// the build match the features we actually determine at runtime.
- ASSERT_EQ(instruction_set_features, runtime_features);
+ ASSERT_LE(instruction_set_features, runtime_features);
#elif defined(__aarch64__)
instruction_set = kArm64;
// TODO: arm64 compilation support.
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index a241d51468..2b20c6fc75 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -19,10 +19,8 @@
#define ATRACE_TAG ATRACE_TAG_DALVIK
#include <utils/Trace.h>
-#include <fstream>
#include <vector>
#include <unistd.h>
-#include <utility>
#include "base/stl_util.h"
#include "base/timing_logger.h"
@@ -372,7 +370,7 @@ CompilerDriver::CompilerDriver(const CompilerOptions* compiler_options,
// Read the profile file if one is provided.
if (profile_file != "") {
- profile_ok_ = ReadProfile(profile_file);
+ profile_ok_ = ProfileHelper::LoadProfileMap(profile_map_, profile_file);
}
dex_to_dex_compiler_ = reinterpret_cast<DexToDexCompilerFn>(ArtCompileDEX);
@@ -2036,86 +2034,9 @@ void CompilerDriver::InstructionSetToLLVMTarget(InstructionSet instruction_set,
}
}
-bool CompilerDriver::ReadProfile(const std::string& filename) {
- VLOG(compiler) << "reading profile file " << filename;
- struct stat st;
- int err = stat(filename.c_str(), &st);
- if (err == -1) {
- VLOG(compiler) << "not found";
- return false;
- }
- std::ifstream in(filename.c_str());
- if (!in) {
- VLOG(compiler) << "profile file " << filename << " exists but can't be opened";
- VLOG(compiler) << "file owner: " << st.st_uid << ":" << st.st_gid;
- VLOG(compiler) << "me: " << getuid() << ":" << getgid();
- VLOG(compiler) << "file permissions: " << std::oct << st.st_mode;
- VLOG(compiler) << "errno: " << errno;
- return false;
- }
- // The first line contains summary information.
- std::string line;
- std::getline(in, line);
- if (in.eof()) {
- return false;
- }
- std::vector<std::string> summary_info;
- Split(line, '/', summary_info);
- if (summary_info.size() != 3) {
- // Bad summary info. It should be count/total/bootpath.
- return false;
- }
- // This is the number of hits in all methods.
- uint32_t total_count = 0;
- for (int i = 0 ; i < 3; ++i) {
- total_count += atoi(summary_info[i].c_str());
- }
-
- // Now read each line until the end of file. Each line consists of 3 fields separated by '/'.
- // Store the info in descending order given by the most used methods.
- typedef std::set<std::pair<int, std::vector<std::string>>> ProfileSet;
- ProfileSet countSet;
- while (!in.eof()) {
- std::getline(in, line);
- if (in.eof()) {
- break;
- }
- std::vector<std::string> info;
- Split(line, '/', info);
- if (info.size() != 3) {
- // Malformed.
- break;
- }
- int count = atoi(info[1].c_str());
- countSet.insert(std::make_pair(-count, info));
- }
-
- uint32_t curTotalCount = 0;
- ProfileSet::iterator end = countSet.end();
- const ProfileData* prevData = nullptr;
- for (ProfileSet::iterator it = countSet.begin(); it != end ; it++) {
- const std::string& methodname = it->second[0];
- uint32_t count = -it->first;
- uint32_t size = atoi(it->second[2].c_str());
- double usedPercent = (count * 100.0) / total_count;
-
- curTotalCount += count;
- // Methods with the same count should be part of the same top K percentage bucket.
- double topKPercentage = (prevData != nullptr) && (prevData->GetCount() == count)
- ? prevData->GetTopKUsedPercentage()
- : 100 * static_cast<double>(curTotalCount) / static_cast<double>(total_count);
-
- // Add it to the profile map.
- ProfileData curData = ProfileData(methodname, count, size, usedPercent, topKPercentage);
- profile_map_[methodname] = curData;
- prevData = &curData;
- }
- return true;
-}
-
bool CompilerDriver::SkipCompilation(const std::string& method_name) {
if (!profile_ok_) {
- return true;
+ return false;
}
// Methods that comprise topKPercentThreshold % of the total samples will be compiled.
double topKPercentThreshold = 90.0;
diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h
index 802f859da4..d49523a172 100644
--- a/compiler/driver/compiler_driver.h
+++ b/compiler/driver/compiler_driver.h
@@ -32,6 +32,7 @@
#include "invoke_type.h"
#include "method_reference.h"
#include "os.h"
+#include "profiler.h"
#include "runtime.h"
#include "safe_map.h"
#include "thread_pool.h"
@@ -594,43 +595,9 @@ class CompilerDriver {
return cfi_info_.get();
}
- // Profile data. This is generated from previous runs of the program and stored
- // in a file. It is used to determine whether to compile a particular method or not.
- class ProfileData {
- public:
- ProfileData() : count_(0), method_size_(0), usedPercent_(0) {}
- ProfileData(const std::string& method_name, uint32_t count, uint32_t method_size,
- double usedPercent, double topKUsedPercentage) :
- method_name_(method_name), count_(count), method_size_(method_size),
- usedPercent_(usedPercent), topKUsedPercentage_(topKUsedPercentage) {
- // TODO: currently method_size_ and count_ are unused.
- UNUSED(method_size_);
- UNUSED(count_);
- }
-
- bool IsAbove(double v) const { return usedPercent_ >= v; }
- double GetUsedPercent() const { return usedPercent_; }
- uint32_t GetCount() const { return count_; }
- double GetTopKUsedPercentage() const { return topKUsedPercentage_; }
-
- private:
- std::string method_name_; // Method name.
- uint32_t count_; // Number of times it has been called.
- uint32_t method_size_; // Size of the method on dex instructions.
- double usedPercent_; // Percentage of how many times this method was called.
- double topKUsedPercentage_; // The percentage of the group that comprise K% of the total used
- // methods this methods belongs to.
- };
-
- // Profile data is stored in a map, indexed by the full method name.
- typedef std::map<const std::string, ProfileData> ProfileMap;
ProfileMap profile_map_;
bool profile_ok_;
- // Read the profile data from the given file. Calculates the percentage for each method.
- // Returns false if there was no profile file or it was malformed.
- bool ReadProfile(const std::string& filename);
-
// Should the compiler run on this method given profile information?
bool SkipCompilation(const std::string& method_name);
diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc
index 0405198350..f76587a26e 100644
--- a/compiler/image_writer.cc
+++ b/compiler/image_writer.cc
@@ -235,8 +235,8 @@ bool ImageWriter::AllocMemory() {
}
// Create the image bitmap.
- image_bitmap_.reset(gc::accounting::SpaceBitmap::Create("image bitmap", image_->Begin(),
- length));
+ image_bitmap_.reset(gc::accounting::ContinuousSpaceBitmap::Create("image bitmap", image_->Begin(),
+ length));
if (image_bitmap_.get() == nullptr) {
LOG(ERROR) << "Failed to allocate memory for image bitmap";
return false;
@@ -525,7 +525,7 @@ void ImageWriter::CalculateNewObjectOffsets(size_t oat_loaded_size, size_t oat_d
// Return to write header at start of image with future location of image_roots. At this point,
// image_end_ is the size of the image (excluding bitmaps).
- const size_t heap_bytes_per_bitmap_byte = kBitsPerByte * gc::accounting::SpaceBitmap::kAlignment;
+ const size_t heap_bytes_per_bitmap_byte = kBitsPerByte * kObjectAlignment;
const size_t bitmap_bytes = RoundUp(image_end_, heap_bytes_per_bitmap_byte) /
heap_bytes_per_bitmap_byte;
ImageHeader image_header(PointerToLowMemUInt32(image_begin_),
diff --git a/compiler/image_writer.h b/compiler/image_writer.h
index 92b24f6067..ee241cb02f 100644
--- a/compiler/image_writer.h
+++ b/compiler/image_writer.h
@@ -173,7 +173,7 @@ class ImageWriter {
const byte* oat_data_begin_;
// Image bitmap which lets us know where the objects inside of the image reside.
- UniquePtr<gc::accounting::SpaceBitmap> image_bitmap_;
+ UniquePtr<gc::accounting::ContinuousSpaceBitmap> image_bitmap_;
// Offset from oat_data_begin_ to the stubs.
uint32_t interpreter_to_interpreter_bridge_offset_;
diff --git a/compiler/jni/jni_compiler_test.cc b/compiler/jni/jni_compiler_test.cc
index a0797f3147..6b5e55efa8 100644
--- a/compiler/jni/jni_compiler_test.cc
+++ b/compiler/jni/jni_compiler_test.cc
@@ -1278,4 +1278,217 @@ TEST_F(JniCompilerTest, WithoutImplementation) {
EXPECT_TRUE(env_->ExceptionCheck() == JNI_TRUE);
}
+template <typename U, typename V> V convert(U in) {
+ DCHECK_LE(sizeof(U), sizeof(V));
+ union { U u; V v; } tmp;
+ tmp.u = in;
+ return tmp.v;
+}
+
+void Java_MyClassNatives_stackArgsIntsFirst(JNIEnv* env, jclass klass, jint i1, jint i2, jint i3,
+ jint i4, jint i5, jint i6, jint i7, jint i8, jint i9,
+ jint i10, jfloat f1, jfloat f2, jfloat f3, jfloat f4,
+ jfloat f5, jfloat f6, jfloat f7, jfloat f8, jfloat f9,
+ jfloat f10) {
+ EXPECT_EQ(i1, 1);
+ EXPECT_EQ(i2, 2);
+ EXPECT_EQ(i3, 3);
+ EXPECT_EQ(i4, 4);
+ EXPECT_EQ(i5, 5);
+ EXPECT_EQ(i6, 6);
+ EXPECT_EQ(i7, 7);
+ EXPECT_EQ(i8, 8);
+ EXPECT_EQ(i9, 9);
+ EXPECT_EQ(i10, 10);
+
+ jint i11 = convert<jfloat, jint>(f1);
+ EXPECT_EQ(i11, 11);
+ jint i12 = convert<jfloat, jint>(f2);
+ EXPECT_EQ(i12, 12);
+ jint i13 = convert<jfloat, jint>(f3);
+ EXPECT_EQ(i13, 13);
+ jint i14 = convert<jfloat, jint>(f4);
+ EXPECT_EQ(i14, 14);
+ jint i15 = convert<jfloat, jint>(f5);
+ EXPECT_EQ(i15, 15);
+ jint i16 = convert<jfloat, jint>(f6);
+ EXPECT_EQ(i16, 16);
+ jint i17 = convert<jfloat, jint>(f7);
+ EXPECT_EQ(i17, 17);
+ jint i18 = convert<jfloat, jint>(f8);
+ EXPECT_EQ(i18, 18);
+ jint i19 = convert<jfloat, jint>(f9);
+ EXPECT_EQ(i19, 19);
+ jint i20 = convert<jfloat, jint>(f10);
+ EXPECT_EQ(i20, 20);
+}
+
+TEST_F(JniCompilerTest, StackArgsIntsFirst) {
+ TEST_DISABLED_FOR_PORTABLE();
+ SetUpForTest(true, "stackArgsIntsFirst", "(IIIIIIIIIIFFFFFFFFFF)V",
+ reinterpret_cast<void*>(&Java_MyClassNatives_stackArgsIntsFirst));
+
+ jint i1 = 1;
+ jint i2 = 2;
+ jint i3 = 3;
+ jint i4 = 4;
+ jint i5 = 5;
+ jint i6 = 6;
+ jint i7 = 7;
+ jint i8 = 8;
+ jint i9 = 9;
+ jint i10 = 10;
+
+ jfloat f1 = convert<jint, jfloat>(11);
+ jfloat f2 = convert<jint, jfloat>(12);
+ jfloat f3 = convert<jint, jfloat>(13);
+ jfloat f4 = convert<jint, jfloat>(14);
+ jfloat f5 = convert<jint, jfloat>(15);
+ jfloat f6 = convert<jint, jfloat>(16);
+ jfloat f7 = convert<jint, jfloat>(17);
+ jfloat f8 = convert<jint, jfloat>(18);
+ jfloat f9 = convert<jint, jfloat>(19);
+ jfloat f10 = convert<jint, jfloat>(20);
+
+ env_->CallStaticVoidMethod(jklass_, jmethod_, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, f1, f2,
+ f3, f4, f5, f6, f7, f8, f9, f10);
+}
+
+void Java_MyClassNatives_stackArgsFloatsFirst(JNIEnv* env, jclass klass, jfloat f1, jfloat f2,
+ jfloat f3, jfloat f4, jfloat f5, jfloat f6, jfloat f7,
+ jfloat f8, jfloat f9, jfloat f10, jint i1, jint i2,
+ jint i3, jint i4, jint i5, jint i6, jint i7, jint i8,
+ jint i9, jint i10) {
+ EXPECT_EQ(i1, 1);
+ EXPECT_EQ(i2, 2);
+ EXPECT_EQ(i3, 3);
+ EXPECT_EQ(i4, 4);
+ EXPECT_EQ(i5, 5);
+ EXPECT_EQ(i6, 6);
+ EXPECT_EQ(i7, 7);
+ EXPECT_EQ(i8, 8);
+ EXPECT_EQ(i9, 9);
+ EXPECT_EQ(i10, 10);
+
+ jint i11 = convert<jfloat, jint>(f1);
+ EXPECT_EQ(i11, 11);
+ jint i12 = convert<jfloat, jint>(f2);
+ EXPECT_EQ(i12, 12);
+ jint i13 = convert<jfloat, jint>(f3);
+ EXPECT_EQ(i13, 13);
+ jint i14 = convert<jfloat, jint>(f4);
+ EXPECT_EQ(i14, 14);
+ jint i15 = convert<jfloat, jint>(f5);
+ EXPECT_EQ(i15, 15);
+ jint i16 = convert<jfloat, jint>(f6);
+ EXPECT_EQ(i16, 16);
+ jint i17 = convert<jfloat, jint>(f7);
+ EXPECT_EQ(i17, 17);
+ jint i18 = convert<jfloat, jint>(f8);
+ EXPECT_EQ(i18, 18);
+ jint i19 = convert<jfloat, jint>(f9);
+ EXPECT_EQ(i19, 19);
+ jint i20 = convert<jfloat, jint>(f10);
+ EXPECT_EQ(i20, 20);
+}
+
+TEST_F(JniCompilerTest, StackArgsFloatsFirst) {
+ TEST_DISABLED_FOR_PORTABLE();
+ SetUpForTest(true, "stackArgsFloatsFirst", "(FFFFFFFFFFIIIIIIIIII)V",
+ reinterpret_cast<void*>(&Java_MyClassNatives_stackArgsFloatsFirst));
+
+ jint i1 = 1;
+ jint i2 = 2;
+ jint i3 = 3;
+ jint i4 = 4;
+ jint i5 = 5;
+ jint i6 = 6;
+ jint i7 = 7;
+ jint i8 = 8;
+ jint i9 = 9;
+ jint i10 = 10;
+
+ jfloat f1 = convert<jint, jfloat>(11);
+ jfloat f2 = convert<jint, jfloat>(12);
+ jfloat f3 = convert<jint, jfloat>(13);
+ jfloat f4 = convert<jint, jfloat>(14);
+ jfloat f5 = convert<jint, jfloat>(15);
+ jfloat f6 = convert<jint, jfloat>(16);
+ jfloat f7 = convert<jint, jfloat>(17);
+ jfloat f8 = convert<jint, jfloat>(18);
+ jfloat f9 = convert<jint, jfloat>(19);
+ jfloat f10 = convert<jint, jfloat>(20);
+
+ env_->CallStaticVoidMethod(jklass_, jmethod_, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, i1, i2, i3,
+ i4, i5, i6, i7, i8, i9, i10);
+}
+
+void Java_MyClassNatives_stackArgsMixed(JNIEnv* env, jclass klass, jint i1, jfloat f1, jint i2,
+ jfloat f2, jint i3, jfloat f3, jint i4, jfloat f4, jint i5,
+ jfloat f5, jint i6, jfloat f6, jint i7, jfloat f7, jint i8,
+ jfloat f8, jint i9, jfloat f9, jint i10, jfloat f10) {
+ EXPECT_EQ(i1, 1);
+ EXPECT_EQ(i2, 2);
+ EXPECT_EQ(i3, 3);
+ EXPECT_EQ(i4, 4);
+ EXPECT_EQ(i5, 5);
+ EXPECT_EQ(i6, 6);
+ EXPECT_EQ(i7, 7);
+ EXPECT_EQ(i8, 8);
+ EXPECT_EQ(i9, 9);
+ EXPECT_EQ(i10, 10);
+
+ jint i11 = convert<jfloat, jint>(f1);
+ EXPECT_EQ(i11, 11);
+ jint i12 = convert<jfloat, jint>(f2);
+ EXPECT_EQ(i12, 12);
+ jint i13 = convert<jfloat, jint>(f3);
+ EXPECT_EQ(i13, 13);
+ jint i14 = convert<jfloat, jint>(f4);
+ EXPECT_EQ(i14, 14);
+ jint i15 = convert<jfloat, jint>(f5);
+ EXPECT_EQ(i15, 15);
+ jint i16 = convert<jfloat, jint>(f6);
+ EXPECT_EQ(i16, 16);
+ jint i17 = convert<jfloat, jint>(f7);
+ EXPECT_EQ(i17, 17);
+ jint i18 = convert<jfloat, jint>(f8);
+ EXPECT_EQ(i18, 18);
+ jint i19 = convert<jfloat, jint>(f9);
+ EXPECT_EQ(i19, 19);
+ jint i20 = convert<jfloat, jint>(f10);
+ EXPECT_EQ(i20, 20);
+}
+
+TEST_F(JniCompilerTest, StackArgsMixed) {
+ TEST_DISABLED_FOR_PORTABLE();
+ SetUpForTest(true, "stackArgsMixed", "(IFIFIFIFIFIFIFIFIFIF)V",
+ reinterpret_cast<void*>(&Java_MyClassNatives_stackArgsMixed));
+
+ jint i1 = 1;
+ jint i2 = 2;
+ jint i3 = 3;
+ jint i4 = 4;
+ jint i5 = 5;
+ jint i6 = 6;
+ jint i7 = 7;
+ jint i8 = 8;
+ jint i9 = 9;
+ jint i10 = 10;
+
+ jfloat f1 = convert<jint, jfloat>(11);
+ jfloat f2 = convert<jint, jfloat>(12);
+ jfloat f3 = convert<jint, jfloat>(13);
+ jfloat f4 = convert<jint, jfloat>(14);
+ jfloat f5 = convert<jint, jfloat>(15);
+ jfloat f6 = convert<jint, jfloat>(16);
+ jfloat f7 = convert<jint, jfloat>(17);
+ jfloat f8 = convert<jint, jfloat>(18);
+ jfloat f9 = convert<jint, jfloat>(19);
+ jfloat f10 = convert<jint, jfloat>(20);
+
+ env_->CallStaticVoidMethod(jklass_, jmethod_, i1, f1, i2, f2, i3, f3, i4, f4, i5, f5, i6, f6, i7,
+ f7, i8, f8, i9, f9, i10, f10);
+}
+
} // namespace art
diff --git a/compiler/jni/quick/arm/calling_convention_arm.cc b/compiler/jni/quick/arm/calling_convention_arm.cc
index ab39d6baae..ae18d2e944 100644
--- a/compiler/jni/quick/arm/calling_convention_arm.cc
+++ b/compiler/jni/quick/arm/calling_convention_arm.cc
@@ -145,7 +145,7 @@ size_t ArmJniCallingConvention::FrameSize() {
// Method*, LR and callee save area size, local reference segment state
size_t frame_data_size = (3 + CalleeSaveRegisters().size()) * kFramePointerSize;
// References plus 2 words for SIRT header
- size_t sirt_size = (ReferenceCount() + 2) * sirt_pointer_size_;
+ size_t sirt_size = StackIndirectReferenceTable::GetAlignedSirtSizeTarget(kFramePointerSize, ReferenceCount());
// Plus return value spill area size
return RoundUp(frame_data_size + sirt_size + SizeOfReturnValue(), kStackAlignment);
}
diff --git a/compiler/jni/quick/arm64/calling_convention_arm64.cc b/compiler/jni/quick/arm64/calling_convention_arm64.cc
index c408fa97c3..6212a23a74 100644
--- a/compiler/jni/quick/arm64/calling_convention_arm64.cc
+++ b/compiler/jni/quick/arm64/calling_convention_arm64.cc
@@ -21,14 +21,29 @@
namespace art {
namespace arm64 {
-// Calling convention
+static const Register kCoreArgumentRegisters[] = {
+ X0, X1, X2, X3, X4, X5, X6, X7
+};
+
+static const WRegister kWArgumentRegisters[] = {
+ W0, W1, W2, W3, W4, W5, W6, W7
+};
+
+static const DRegister kDArgumentRegisters[] = {
+ D0, D1, D2, D3, D4, D5, D6, D7
+};
+
+static const SRegister kSArgumentRegisters[] = {
+ S0, S1, S2, S3, S4, S5, S6, S7
+};
+// Calling convention
ManagedRegister Arm64ManagedRuntimeCallingConvention::InterproceduralScratchRegister() {
- return Arm64ManagedRegister::FromCoreRegister(IP0); // X16
+ return Arm64ManagedRegister::FromCoreRegister(X20); // saved on entry restored on exit
}
ManagedRegister Arm64JniCallingConvention::InterproceduralScratchRegister() {
- return Arm64ManagedRegister::FromCoreRegister(IP0); // X16
+ return Arm64ManagedRegister::FromCoreRegister(X20); // saved on entry restored on exit
}
static ManagedRegister ReturnRegisterForShorty(const char* shorty) {
@@ -79,64 +94,64 @@ ManagedRegister Arm64ManagedRuntimeCallingConvention::CurrentParamRegister() {
FrameOffset Arm64ManagedRuntimeCallingConvention::CurrentParamStackOffset() {
CHECK(IsCurrentParamOnStack());
FrameOffset result =
- FrameOffset(displacement_.Int32Value() + // displacement
+ FrameOffset(displacement_.Int32Value() + // displacement
kFramePointerSize + // Method*
- (itr_slots_ * kFramePointerSize)); // offset into in args
+ (itr_slots_ * sizeof(uint32_t))); // offset into in args
return result;
}
const ManagedRegisterEntrySpills& Arm64ManagedRuntimeCallingConvention::EntrySpills() {
// We spill the argument registers on ARM64 to free them up for scratch use, we then assume
// all arguments are on the stack.
- if (entry_spills_.size() == 0) {
- // TODO Need fp regs spilled too.
- //
- size_t num_spills = NumArgs();
-
- // TODO Floating point need spilling too.
- if (num_spills > 0) {
- entry_spills_.push_back(Arm64ManagedRegister::FromCoreRegister(X1));
- if (num_spills > 1) {
- entry_spills_.push_back(Arm64ManagedRegister::FromCoreRegister(X2));
- if (num_spills > 2) {
- entry_spills_.push_back(Arm64ManagedRegister::FromCoreRegister(X3));
- if (num_spills > 3) {
- entry_spills_.push_back(Arm64ManagedRegister::FromCoreRegister(X5));
- if (num_spills > 4) {
- entry_spills_.push_back(Arm64ManagedRegister::FromCoreRegister(X6));
- if (num_spills > 5) {
- entry_spills_.push_back(Arm64ManagedRegister::FromCoreRegister(X7));
- }
+ if ((entry_spills_.size() == 0) && (NumArgs() > 0)) {
+ int gp_reg_index = 1; // we start from X1/W1, X0 holds ArtMethod*.
+ int fp_reg_index = 0; // D0/S0.
+
+ // We need to choose the correct register (D/S or X/W) since the managed
+ // stack uses 32bit stack slots.
+ ResetIterator(FrameOffset(0));
+ while (HasNext()) {
+ if (IsCurrentParamAFloatOrDouble()) { // FP regs.
+ if (fp_reg_index < 8) {
+ if (!IsCurrentParamADouble()) {
+ entry_spills_.push_back(Arm64ManagedRegister::FromSRegister(kSArgumentRegisters[fp_reg_index]));
+ } else {
+ entry_spills_.push_back(Arm64ManagedRegister::FromDRegister(kDArgumentRegisters[fp_reg_index]));
+ }
+ fp_reg_index++;
+ } else { // just increase the stack offset.
+ if (!IsCurrentParamADouble()) {
+ entry_spills_.push_back(ManagedRegister::NoRegister(), 4);
+ } else {
+ entry_spills_.push_back(ManagedRegister::NoRegister(), 8);
}
}
+ } else { // GP regs.
+ if (gp_reg_index < 8) {
+ if (IsCurrentParamALong() && (!IsCurrentParamAReference())) {
+ entry_spills_.push_back(Arm64ManagedRegister::FromCoreRegister(kCoreArgumentRegisters[gp_reg_index]));
+ } else {
+ entry_spills_.push_back(Arm64ManagedRegister::FromWRegister(kWArgumentRegisters[gp_reg_index]));
+ }
+ gp_reg_index++;
+ } else { // just increase the stack offset.
+ if (IsCurrentParamALong() && (!IsCurrentParamAReference())) {
+ entry_spills_.push_back(ManagedRegister::NoRegister(), 8);
+ } else {
+ entry_spills_.push_back(ManagedRegister::NoRegister(), 4);
+ }
}
}
+ Next();
}
}
-
return entry_spills_;
}
-// JNI calling convention
+// JNI calling convention
Arm64JniCallingConvention::Arm64JniCallingConvention(bool is_static, bool is_synchronized,
const char* shorty)
: JniCallingConvention(is_static, is_synchronized, shorty, kFramePointerSize) {
- // TODO This needs to be converted to 64bit.
- // Compute padding to ensure longs and doubles are not split in AAPCS. Ignore the 'this' jobject
- // or jclass for static methods and the JNIEnv. We start at the aligned register r2.
-// size_t padding = 0;
-// for (size_t cur_arg = IsStatic() ? 0 : 1, cur_reg = 2; cur_arg < NumArgs(); cur_arg++) {
-// if (IsParamALongOrDouble(cur_arg)) {
-// if ((cur_reg & 1) != 0) {
-// padding += 4;
-// cur_reg++; // additional bump to ensure alignment
-// }
-// cur_reg++; // additional bump to skip extra long word
-// }
-// cur_reg++; // bump the iterator for every argument
-// }
- padding_ =0;
-
callee_save_regs_.push_back(Arm64ManagedRegister::FromCoreRegister(X19));
callee_save_regs_.push_back(Arm64ManagedRegister::FromCoreRegister(X20));
callee_save_regs_.push_back(Arm64ManagedRegister::FromCoreRegister(X21));
@@ -162,83 +177,87 @@ Arm64JniCallingConvention::Arm64JniCallingConvention(bool is_static, bool is_syn
uint32_t Arm64JniCallingConvention::CoreSpillMask() const {
// Compute spill mask to agree with callee saves initialized in the constructor
uint32_t result = 0;
- result = 1 << X19 | 1 << X20 | 1 << X21 | 1 << X22 | 1 << X23 | 1 << X24 | 1 << X25
- | 1 << X26 | 1 << X27 | 1 << X28 | 1<< X29 | 1 << LR;
+ result = 1 << X19 | 1 << X20 | 1 << X21 | 1 << X22 | 1 << X23 | 1 << X24 |
+ 1 << X25 | 1 << X26 | 1 << X27 | 1 << X28 | 1 << X29 | 1 << LR;
+ return result;
+}
+
+uint32_t Arm64JniCallingConvention::FpSpillMask() const {
+ // Compute spill mask to agree with callee saves initialized in the constructor
+ uint32_t result = 0;
+ result = 1 << D8 | 1 << D9 | 1 << D10 | 1 << D11 | 1 << D12 | 1 << D13 |
+ 1 << D14 | 1 << D15;
return result;
}
ManagedRegister Arm64JniCallingConvention::ReturnScratchRegister() const {
- return Arm64ManagedRegister::FromCoreRegister(X9);
+ return ManagedRegister::NoRegister();
}
size_t Arm64JniCallingConvention::FrameSize() {
- // Method*, LR and callee save area size, local reference segment state
- size_t frame_data_size = (3 + CalleeSaveRegisters().size()) * kFramePointerSize;
+ // Method*, callee save area size, local reference segment state
+ size_t frame_data_size = ((1 + CalleeSaveRegisters().size()) * kFramePointerSize) + sizeof(uint32_t);
// References plus 2 words for SIRT header
- size_t sirt_size = (ReferenceCount() + 2) * sirt_pointer_size_;
+ size_t sirt_size = StackIndirectReferenceTable::GetAlignedSirtSizeTarget(kFramePointerSize, ReferenceCount());
// Plus return value spill area size
return RoundUp(frame_data_size + sirt_size + SizeOfReturnValue(), kStackAlignment);
}
size_t Arm64JniCallingConvention::OutArgSize() {
- return RoundUp(NumberOfOutgoingStackArgs() * kFramePointerSize + padding_,
- kStackAlignment);
-}
-
-// JniCallingConvention ABI follows AAPCS where longs and doubles must occur
-// in even register numbers and stack slots
-void Arm64JniCallingConvention::Next() {
- JniCallingConvention::Next();
- size_t arg_pos = itr_args_ - NumberOfExtraArgumentsForJni();
- if ((itr_args_ >= 2) &&
- (arg_pos < NumArgs()) &&
- IsParamALongOrDouble(arg_pos)) {
- // itr_slots_ needs to be an even number, according to AAPCS.
- if ((itr_slots_ & 0x1u) != 0) {
- itr_slots_++;
- }
- }
+ return RoundUp(NumberOfOutgoingStackArgs() * kFramePointerSize, kStackAlignment);
}
bool Arm64JniCallingConvention::IsCurrentParamInRegister() {
- return itr_slots_ < 4;
+ if (IsCurrentParamAFloatOrDouble()) {
+ return (itr_float_and_doubles_ < 8);
+ } else {
+ return ((itr_args_ - itr_float_and_doubles_) < 8);
+ }
}
bool Arm64JniCallingConvention::IsCurrentParamOnStack() {
return !IsCurrentParamInRegister();
}
-// TODO and floating point?
-
-static const Register kJniArgumentRegisters[] = {
- X0, X1, X2, X3, X4, X5, X6, X7
-};
ManagedRegister Arm64JniCallingConvention::CurrentParamRegister() {
- CHECK_LT(itr_slots_, 4u);
- int arg_pos = itr_args_ - NumberOfExtraArgumentsForJni();
- // TODO Floating point & 64bit registers.
- if ((itr_args_ >= 2) && IsParamALongOrDouble(arg_pos)) {
- CHECK_EQ(itr_slots_, 2u);
- return Arm64ManagedRegister::FromCoreRegister(X1);
+ CHECK(IsCurrentParamInRegister());
+ if (IsCurrentParamAFloatOrDouble()) {
+ CHECK_LT(itr_float_and_doubles_, 8u);
+ if (IsCurrentParamADouble()) {
+ return Arm64ManagedRegister::FromDRegister(kDArgumentRegisters[itr_float_and_doubles_]);
+ } else {
+ return Arm64ManagedRegister::FromSRegister(kSArgumentRegisters[itr_float_and_doubles_]);
+ }
} else {
- return
- Arm64ManagedRegister::FromCoreRegister(kJniArgumentRegisters[itr_slots_]);
+ int gp_reg = itr_args_ - itr_float_and_doubles_;
+ CHECK_LT(static_cast<unsigned int>(gp_reg), 8u);
+ if (IsCurrentParamALong() || IsCurrentParamAReference() || IsCurrentParamJniEnv()) {
+ return Arm64ManagedRegister::FromCoreRegister(kCoreArgumentRegisters[gp_reg]);
+ } else {
+ return Arm64ManagedRegister::FromWRegister(kWArgumentRegisters[gp_reg]);
+ }
}
}
FrameOffset Arm64JniCallingConvention::CurrentParamStackOffset() {
- CHECK_GE(itr_slots_, 4u);
- size_t offset = displacement_.Int32Value() - OutArgSize() + ((itr_slots_ - 4) * kFramePointerSize);
+ CHECK(IsCurrentParamOnStack());
+ size_t args_on_stack = itr_args_
+ - std::min(8u, itr_float_and_doubles_)
+ - std::min(8u, (itr_args_ - itr_float_and_doubles_));
+ size_t offset = displacement_.Int32Value() - OutArgSize() + (args_on_stack * kFramePointerSize);
CHECK_LT(offset, OutArgSize());
return FrameOffset(offset);
}
size_t Arm64JniCallingConvention::NumberOfOutgoingStackArgs() {
- size_t static_args = IsStatic() ? 1 : 0; // count jclass
- // regular argument parameters and this
- size_t param_args = NumArgs() + NumLongOrDoubleArgs();
- // count JNIEnv* less arguments in registers
- return static_args + param_args + 1 - 4;
+ // all arguments including JNI args
+ size_t all_args = NumArgs() + NumberOfExtraArgumentsForJni();
+
+ size_t all_stack_args = all_args -
+ std::min(8u, static_cast<unsigned int>(NumFloatOrDoubleArgs())) -
+ std::min(8u, static_cast<unsigned int>((all_args - NumFloatOrDoubleArgs())));
+
+ return all_stack_args;
}
} // namespace arm64
diff --git a/compiler/jni/quick/arm64/calling_convention_arm64.h b/compiler/jni/quick/arm64/calling_convention_arm64.h
index c18cd2b0ce..92f547c533 100644
--- a/compiler/jni/quick/arm64/calling_convention_arm64.h
+++ b/compiler/jni/quick/arm64/calling_convention_arm64.h
@@ -55,7 +55,6 @@ class Arm64JniCallingConvention FINAL : public JniCallingConvention {
ManagedRegister IntReturnRegister() OVERRIDE;
ManagedRegister InterproceduralScratchRegister() OVERRIDE;
// JNI calling convention
- void Next() OVERRIDE; // Override default behavior for AAPCS
size_t FrameSize() OVERRIDE;
size_t OutArgSize() OVERRIDE;
const std::vector<ManagedRegister>& CalleeSaveRegisters() const OVERRIDE {
@@ -63,9 +62,7 @@ class Arm64JniCallingConvention FINAL : public JniCallingConvention {
}
ManagedRegister ReturnScratchRegister() const OVERRIDE;
uint32_t CoreSpillMask() const OVERRIDE;
- uint32_t FpSpillMask() const OVERRIDE {
- return 0; // Floats aren't spilled in JNI down call
- }
+ uint32_t FpSpillMask() const OVERRIDE;
bool IsCurrentParamInRegister() OVERRIDE;
bool IsCurrentParamOnStack() OVERRIDE;
ManagedRegister CurrentParamRegister() OVERRIDE;
@@ -78,9 +75,6 @@ class Arm64JniCallingConvention FINAL : public JniCallingConvention {
// TODO: these values aren't unique and can be shared amongst instances
std::vector<ManagedRegister> callee_save_regs_;
- // Padding to ensure longs and doubles are not split in AAPCS
- size_t padding_;
-
DISALLOW_COPY_AND_ASSIGN(Arm64JniCallingConvention);
};
diff --git a/compiler/jni/quick/calling_convention.cc b/compiler/jni/quick/calling_convention.cc
index 8efdcdaab2..a99a4c2480 100644
--- a/compiler/jni/quick/calling_convention.cc
+++ b/compiler/jni/quick/calling_convention.cc
@@ -90,6 +90,14 @@ bool ManagedRuntimeCallingConvention::IsCurrentParamAFloatOrDouble() {
return IsParamAFloatOrDouble(itr_args_);
}
+bool ManagedRuntimeCallingConvention::IsCurrentParamADouble() {
+ return IsParamADouble(itr_args_);
+}
+
+bool ManagedRuntimeCallingConvention::IsCurrentParamALong() {
+ return IsParamALong(itr_args_);
+}
+
// JNI calling convention
JniCallingConvention* JniCallingConvention::Create(bool is_static, bool is_synchronized,
@@ -168,6 +176,10 @@ bool JniCallingConvention::IsCurrentParamAReference() {
}
}
+bool JniCallingConvention::IsCurrentParamJniEnv() {
+ return (itr_args_ == kJniEnv);
+}
+
bool JniCallingConvention::IsCurrentParamAFloatOrDouble() {
switch (itr_args_) {
case kJniEnv:
@@ -181,6 +193,32 @@ bool JniCallingConvention::IsCurrentParamAFloatOrDouble() {
}
}
+bool JniCallingConvention::IsCurrentParamADouble() {
+ switch (itr_args_) {
+ case kJniEnv:
+ return false; // JNIEnv*
+ case kObjectOrClass:
+ return false; // jobject or jclass
+ default: {
+ int arg_pos = itr_args_ - NumberOfExtraArgumentsForJni();
+ return IsParamADouble(arg_pos);
+ }
+ }
+}
+
+bool JniCallingConvention::IsCurrentParamALong() {
+ switch (itr_args_) {
+ case kJniEnv:
+ return false; // JNIEnv*
+ case kObjectOrClass:
+ return false; // jobject or jclass
+ default: {
+ int arg_pos = itr_args_ - NumberOfExtraArgumentsForJni();
+ return IsParamALong(arg_pos);
+ }
+ }
+}
+
// Return position of SIRT entry holding reference at the current iterator
// position
FrameOffset JniCallingConvention::CurrentParamSirtEntryOffset() {
diff --git a/compiler/jni/quick/calling_convention.h b/compiler/jni/quick/calling_convention.h
index 7e1cf630c6..4d25d1ce96 100644
--- a/compiler/jni/quick/calling_convention.h
+++ b/compiler/jni/quick/calling_convention.h
@@ -126,6 +126,24 @@ class CallingConvention {
char ch = shorty_[param];
return (ch == 'F' || ch == 'D');
}
+ bool IsParamADouble(unsigned int param) const {
+ DCHECK_LT(param, NumArgs());
+ if (IsStatic()) {
+ param++; // 0th argument must skip return value at start of the shorty
+ } else if (param == 0) {
+ return false; // this argument
+ }
+ return shorty_[param] == 'D';
+ }
+ bool IsParamALong(unsigned int param) const {
+ DCHECK_LT(param, NumArgs());
+ if (IsStatic()) {
+ param++; // 0th argument must skip return value at start of the shorty
+ } else if (param == 0) {
+ return true; // this argument
+ }
+ return shorty_[param] == 'J';
+ }
bool IsParamAReference(unsigned int param) const {
DCHECK_LT(param, NumArgs());
if (IsStatic()) {
@@ -214,6 +232,8 @@ class ManagedRuntimeCallingConvention : public CallingConvention {
void Next();
bool IsCurrentParamAReference();
bool IsCurrentParamAFloatOrDouble();
+ bool IsCurrentParamADouble();
+ bool IsCurrentParamALong();
bool IsCurrentArgExplicit(); // ie a non-implict argument such as this
bool IsCurrentArgPossiblyNull();
size_t CurrentParamSize();
@@ -283,6 +303,9 @@ class JniCallingConvention : public CallingConvention {
virtual void Next();
bool IsCurrentParamAReference();
bool IsCurrentParamAFloatOrDouble();
+ bool IsCurrentParamADouble();
+ bool IsCurrentParamALong();
+ bool IsCurrentParamJniEnv();
size_t CurrentParamSize();
virtual bool IsCurrentParamInRegister() = 0;
virtual bool IsCurrentParamOnStack() = 0;
@@ -299,17 +322,17 @@ class JniCallingConvention : public CallingConvention {
FrameOffset SirtLinkOffset() const {
return FrameOffset(SirtOffset().Int32Value() +
- StackIndirectReferenceTable::LinkOffset());
+ StackIndirectReferenceTable::LinkOffset(frame_pointer_size_));
}
FrameOffset SirtNumRefsOffset() const {
return FrameOffset(SirtOffset().Int32Value() +
- StackIndirectReferenceTable::NumberOfReferencesOffset());
+ StackIndirectReferenceTable::NumberOfReferencesOffset(frame_pointer_size_));
}
FrameOffset SirtReferencesOffset() const {
return FrameOffset(SirtOffset().Int32Value() +
- StackIndirectReferenceTable::ReferencesOffset());
+ StackIndirectReferenceTable::ReferencesOffset(frame_pointer_size_));
}
virtual ~JniCallingConvention() {}
diff --git a/compiler/jni/quick/jni_compiler.cc b/compiler/jni/quick/jni_compiler.cc
index dcdcdd19c2..64508d10fc 100644
--- a/compiler/jni/quick/jni_compiler.cc
+++ b/compiler/jni/quick/jni_compiler.cc
@@ -29,6 +29,7 @@
#include "utils/assembler.h"
#include "utils/managed_register.h"
#include "utils/arm/managed_register_arm.h"
+#include "utils/arm64/managed_register_arm64.h"
#include "utils/mips/managed_register_mips.h"
#include "utils/x86/managed_register_x86.h"
#include "thread.h"
@@ -73,11 +74,17 @@ CompiledMethod* ArtJniCompileMethodInternal(CompilerDriver& compiler,
// Calling conventions to call into JNI method "end" possibly passing a returned reference, the
// method and the current thread.
- size_t jni_end_arg_count = 0;
- if (reference_return) { jni_end_arg_count++; }
- if (is_synchronized) { jni_end_arg_count++; }
- const char* jni_end_shorty = jni_end_arg_count == 0 ? "I"
- : (jni_end_arg_count == 1 ? "II" : "III");
+ const char* jni_end_shorty;
+ if (reference_return && is_synchronized) {
+ jni_end_shorty = "ILL";
+ } else if (reference_return) {
+ jni_end_shorty = "IL";
+ } else if (is_synchronized) {
+ jni_end_shorty = "VL";
+ } else {
+ jni_end_shorty = "V";
+ }
+
UniquePtr<JniCallingConvention> end_jni_conv(
JniCallingConvention::Create(is_static, is_synchronized, jni_end_shorty, instruction_set));
@@ -101,12 +108,22 @@ CompiledMethod* ArtJniCompileMethodInternal(CompilerDriver& compiler,
__ StoreImmediateToFrame(main_jni_conv->SirtNumRefsOffset(),
main_jni_conv->ReferenceCount(),
mr_conv->InterproceduralScratchRegister());
- __ CopyRawPtrFromThread32(main_jni_conv->SirtLinkOffset(),
- Thread::TopSirtOffset<4>(),
- mr_conv->InterproceduralScratchRegister());
- __ StoreStackOffsetToThread32(Thread::TopSirtOffset<4>(),
- main_jni_conv->SirtOffset(),
- mr_conv->InterproceduralScratchRegister());
+
+ if (instruction_set == kArm64 || instruction_set == kX86_64) {
+ __ CopyRawPtrFromThread64(main_jni_conv->SirtLinkOffset(),
+ Thread::TopSirtOffset<8>(),
+ mr_conv->InterproceduralScratchRegister());
+ __ StoreStackOffsetToThread64(Thread::TopSirtOffset<8>(),
+ main_jni_conv->SirtOffset(),
+ mr_conv->InterproceduralScratchRegister());
+ } else {
+ __ CopyRawPtrFromThread32(main_jni_conv->SirtLinkOffset(),
+ Thread::TopSirtOffset<4>(),
+ mr_conv->InterproceduralScratchRegister());
+ __ StoreStackOffsetToThread32(Thread::TopSirtOffset<4>(),
+ main_jni_conv->SirtOffset(),
+ mr_conv->InterproceduralScratchRegister());
+ }
// 3. Place incoming reference arguments into SIRT
main_jni_conv->Next(); // Skip JNIEnv*
@@ -154,9 +171,15 @@ CompiledMethod* ArtJniCompileMethodInternal(CompilerDriver& compiler,
}
// 4. Write out the end of the quick frames.
- __ StoreStackPointerToThread32(Thread::TopOfManagedStackOffset<4>());
- __ StoreImmediateToThread32(Thread::TopOfManagedStackPcOffset<4>(), 0,
- mr_conv->InterproceduralScratchRegister());
+ if (instruction_set == kArm64 || instruction_set == kX86_64) {
+ __ StoreStackPointerToThread64(Thread::TopOfManagedStackOffset<8>());
+ __ StoreImmediateToThread64(Thread::TopOfManagedStackPcOffset<8>(), 0,
+ mr_conv->InterproceduralScratchRegister());
+ } else {
+ __ StoreStackPointerToThread32(Thread::TopOfManagedStackOffset<4>());
+ __ StoreImmediateToThread32(Thread::TopOfManagedStackPcOffset<4>(), 0,
+ mr_conv->InterproceduralScratchRegister());
+ }
// 5. Move frame down to allow space for out going args.
const size_t main_out_arg_size = main_jni_conv->OutArgSize();
@@ -164,13 +187,14 @@ CompiledMethod* ArtJniCompileMethodInternal(CompilerDriver& compiler,
const size_t max_out_arg_size = std::max(main_out_arg_size, end_out_arg_size);
__ IncreaseFrameSize(max_out_arg_size);
-
// 6. Call into appropriate JniMethodStart passing Thread* so that transition out of Runnable
// 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.
- ThreadOffset<4> jni_start = is_synchronized ? QUICK_ENTRYPOINT_OFFSET(4, pJniMethodStartSynchronized)
- : QUICK_ENTRYPOINT_OFFSET(4, pJniMethodStart);
+ ThreadOffset<4> jni_start32 = is_synchronized ? QUICK_ENTRYPOINT_OFFSET(4, pJniMethodStartSynchronized)
+ : QUICK_ENTRYPOINT_OFFSET(4, pJniMethodStart);
+ ThreadOffset<8> jni_start64 = is_synchronized ? QUICK_ENTRYPOINT_OFFSET(8, pJniMethodStartSynchronized)
+ : QUICK_ENTRYPOINT_OFFSET(8, pJniMethodStart);
main_jni_conv->ResetIterator(FrameOffset(main_out_arg_size));
FrameOffset locked_object_sirt_offset(0);
if (is_synchronized) {
@@ -192,12 +216,21 @@ CompiledMethod* ArtJniCompileMethodInternal(CompilerDriver& compiler,
}
if (main_jni_conv->IsCurrentParamInRegister()) {
__ GetCurrentThread(main_jni_conv->CurrentParamRegister());
- __ Call(main_jni_conv->CurrentParamRegister(), Offset(jni_start),
- main_jni_conv->InterproceduralScratchRegister());
+ if (instruction_set == kArm64 || instruction_set == kX86_64) {
+ __ 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());
+ }
} else {
__ GetCurrentThread(main_jni_conv->CurrentParamStackOffset(),
main_jni_conv->InterproceduralScratchRegister());
- __ CallFromThread32(jni_start, main_jni_conv->InterproceduralScratchRegister());
+ if (instruction_set == kArm64 || instruction_set == kX86_64) {
+ __ CallFromThread64(jni_start64, main_jni_conv->InterproceduralScratchRegister());
+ } else {
+ __ CallFromThread32(jni_start32, main_jni_conv->InterproceduralScratchRegister());
+ }
}
if (is_synchronized) { // Check for exceptions from monitor enter.
__ ExceptionPoll(main_jni_conv->InterproceduralScratchRegister(), main_out_arg_size);
@@ -259,11 +292,20 @@ CompiledMethod* ArtJniCompileMethodInternal(CompilerDriver& compiler,
if (main_jni_conv->IsCurrentParamInRegister()) {
ManagedRegister jni_env = main_jni_conv->CurrentParamRegister();
DCHECK(!jni_env.Equals(main_jni_conv->InterproceduralScratchRegister()));
- __ LoadRawPtrFromThread32(jni_env, Thread::JniEnvOffset<4>());
+ if (instruction_set == kArm64 || instruction_set == kX86_64) {
+ __ LoadRawPtrFromThread64(jni_env, Thread::JniEnvOffset<8>());
+ } else {
+ __ LoadRawPtrFromThread32(jni_env, Thread::JniEnvOffset<4>());
+ }
} else {
FrameOffset jni_env = main_jni_conv->CurrentParamStackOffset();
- __ CopyRawPtrFromThread32(jni_env, Thread::JniEnvOffset<4>(),
+ if (instruction_set == kArm64 || instruction_set == kX86_64) {
+ __ CopyRawPtrFromThread64(jni_env, Thread::JniEnvOffset<8>(),
+ main_jni_conv->InterproceduralScratchRegister());
+ } else {
+ __ CopyRawPtrFromThread32(jni_env, Thread::JniEnvOffset<4>(),
main_jni_conv->InterproceduralScratchRegister());
+ }
}
// 9. Plant call to native code associated with method.
@@ -295,19 +337,23 @@ CompiledMethod* ArtJniCompileMethodInternal(CompilerDriver& compiler,
__ Store(return_save_location, main_jni_conv->ReturnRegister(), main_jni_conv->SizeOfReturnValue());
}
- // 12. Call into JNI method end possibly passing a returned reference, the method and the current
// thread.
end_jni_conv->ResetIterator(FrameOffset(end_out_arg_size));
- ThreadOffset<4> jni_end(-1);
+ ThreadOffset<4> jni_end32(-1);
+ ThreadOffset<8> jni_end64(-1);
if (reference_return) {
// Pass result.
- jni_end = is_synchronized ? QUICK_ENTRYPOINT_OFFSET(4, pJniMethodEndWithReferenceSynchronized)
- : QUICK_ENTRYPOINT_OFFSET(4, pJniMethodEndWithReference);
+ jni_end32 = is_synchronized ? QUICK_ENTRYPOINT_OFFSET(4, pJniMethodEndWithReferenceSynchronized)
+ : QUICK_ENTRYPOINT_OFFSET(4, pJniMethodEndWithReference);
+ jni_end64 = is_synchronized ? QUICK_ENTRYPOINT_OFFSET(8, pJniMethodEndWithReferenceSynchronized)
+ : QUICK_ENTRYPOINT_OFFSET(8, pJniMethodEndWithReference);
SetNativeParameter(jni_asm.get(), end_jni_conv.get(), end_jni_conv->ReturnRegister());
end_jni_conv->Next();
} else {
- jni_end = is_synchronized ? QUICK_ENTRYPOINT_OFFSET(4, pJniMethodEndSynchronized)
- : QUICK_ENTRYPOINT_OFFSET(4, pJniMethodEnd);
+ jni_end32 = is_synchronized ? QUICK_ENTRYPOINT_OFFSET(4, pJniMethodEndSynchronized)
+ : QUICK_ENTRYPOINT_OFFSET(4, pJniMethodEnd);
+ jni_end64 = is_synchronized ? QUICK_ENTRYPOINT_OFFSET(8, pJniMethodEndSynchronized)
+ : QUICK_ENTRYPOINT_OFFSET(8, pJniMethodEnd);
}
// Pass saved local reference state.
if (end_jni_conv->IsCurrentParamOnStack()) {
@@ -334,12 +380,21 @@ CompiledMethod* ArtJniCompileMethodInternal(CompilerDriver& compiler,
}
if (end_jni_conv->IsCurrentParamInRegister()) {
__ GetCurrentThread(end_jni_conv->CurrentParamRegister());
- __ Call(end_jni_conv->CurrentParamRegister(), Offset(jni_end),
- end_jni_conv->InterproceduralScratchRegister());
+ if (instruction_set == kArm64 || instruction_set == kX86_64) {
+ __ 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());
+ }
} else {
__ GetCurrentThread(end_jni_conv->CurrentParamStackOffset(),
end_jni_conv->InterproceduralScratchRegister());
- __ CallFromThread32(ThreadOffset<4>(jni_end), end_jni_conv->InterproceduralScratchRegister());
+ if (instruction_set == kArm64 || instruction_set == kX86_64) {
+ __ CallFromThread64(ThreadOffset<8>(jni_end64), end_jni_conv->InterproceduralScratchRegister());
+ } else {
+ __ CallFromThread32(ThreadOffset<4>(jni_end32), end_jni_conv->InterproceduralScratchRegister());
+ }
}
// 13. Reload return value
@@ -360,6 +415,10 @@ CompiledMethod* ArtJniCompileMethodInternal(CompilerDriver& compiler,
// 17. Finalize code generation
__ EmitSlowPaths();
size_t cs = __ CodeSize();
+ if (instruction_set == kArm64) {
+ // Test that we do not exceed the buffer size.
+ CHECK(cs < arm64::kBufferSizeArm64);
+ }
std::vector<uint8_t> managed_code(cs);
MemoryRegion code(&managed_code[0], managed_code.size());
__ FinalizeInstructions(code);
diff --git a/compiler/jni/quick/mips/calling_convention_mips.cc b/compiler/jni/quick/mips/calling_convention_mips.cc
index 51a3f54888..8e1c0c7a73 100644
--- a/compiler/jni/quick/mips/calling_convention_mips.cc
+++ b/compiler/jni/quick/mips/calling_convention_mips.cc
@@ -149,7 +149,7 @@ size_t MipsJniCallingConvention::FrameSize() {
// Method*, LR and callee save area size, local reference segment state
size_t frame_data_size = (3 + CalleeSaveRegisters().size()) * kFramePointerSize;
// References plus 2 words for SIRT header
- size_t sirt_size = (ReferenceCount() + 2) * sirt_pointer_size_;
+ size_t sirt_size = StackIndirectReferenceTable::GetAlignedSirtSizeTarget(kFramePointerSize, ReferenceCount());
// Plus return value spill area size
return RoundUp(frame_data_size + sirt_size + SizeOfReturnValue(), kStackAlignment);
}
diff --git a/compiler/jni/quick/x86/calling_convention_x86.cc b/compiler/jni/quick/x86/calling_convention_x86.cc
index 8b440eda48..153f9538dd 100644
--- a/compiler/jni/quick/x86/calling_convention_x86.cc
+++ b/compiler/jni/quick/x86/calling_convention_x86.cc
@@ -126,7 +126,7 @@ size_t X86JniCallingConvention::FrameSize() {
// Method*, return address and callee save area size, local reference segment state
size_t frame_data_size = (3 + CalleeSaveRegisters().size()) * kFramePointerSize;
// References plus 2 words for SIRT header
- size_t sirt_size = (ReferenceCount() + 2) * sirt_pointer_size_;
+ size_t sirt_size = StackIndirectReferenceTable::GetAlignedSirtSizeTarget(kFramePointerSize, ReferenceCount());
// Plus return value spill area size
return RoundUp(frame_data_size + sirt_size + SizeOfReturnValue(), kStackAlignment);
}
diff --git a/compiler/jni/quick/x86_64/calling_convention_x86_64.cc b/compiler/jni/quick/x86_64/calling_convention_x86_64.cc
index 21e0bd7f61..4dfa29a46f 100644
--- a/compiler/jni/quick/x86_64/calling_convention_x86_64.cc
+++ b/compiler/jni/quick/x86_64/calling_convention_x86_64.cc
@@ -141,7 +141,7 @@ size_t X86_64JniCallingConvention::FrameSize() {
// Method*, return address and callee save area size, local reference segment state
size_t frame_data_size = (3 + CalleeSaveRegisters().size()) * kFramePointerSize;
// References plus link_ (pointer) and number_of_references_ (uint32_t) for SIRT header
- size_t sirt_size = kFramePointerSize + sizeof(uint32_t) + (ReferenceCount() * sirt_pointer_size_);
+ size_t sirt_size = StackIndirectReferenceTable::GetAlignedSirtSizeTarget(kFramePointerSize, ReferenceCount());
// Plus return value spill area size
return RoundUp(frame_data_size + sirt_size + SizeOfReturnValue(), kStackAlignment);
}
diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc
index 2d45a2f65f..eff2425bb7 100644
--- a/compiler/oat_writer.cc
+++ b/compiler/oat_writer.cc
@@ -345,6 +345,36 @@ size_t OatWriter::InitOatCodeClassDef(size_t offset,
return offset;
}
+static void DCheckCodeAlignment(size_t offset, InstructionSet isa) {
+ switch (isa) {
+ case kArm:
+ // Fall-through.
+ case kThumb2:
+ DCHECK_ALIGNED(offset, kArmAlignment);
+ break;
+
+ case kArm64:
+ DCHECK_ALIGNED(offset, kArm64Alignment);
+ break;
+
+ case kMips:
+ DCHECK_ALIGNED(offset, kMipsAlignment);
+ break;
+
+ case kX86_64:
+ // Fall-through.
+ case kX86:
+ DCHECK_ALIGNED(offset, kX86Alignment);
+ break;
+
+ case kNone:
+ // Use a DCHECK instead of FATAL so that in the non-debug case the whole switch can
+ // be optimized away.
+ DCHECK(false);
+ break;
+ }
+}
+
size_t OatWriter::InitOatCodeMethod(size_t offset, size_t oat_class_index,
size_t __attribute__((unused)) class_def_index,
size_t class_def_method_index,
@@ -376,7 +406,8 @@ size_t OatWriter::InitOatCodeMethod(size_t offset, size_t oat_class_index,
} else {
CHECK(quick_code != nullptr);
offset = compiled_method->AlignCode(offset);
- DCHECK_ALIGNED(offset, kArmAlignment);
+ DCheckCodeAlignment(offset, compiled_method->GetInstructionSet());
+
uint32_t code_size = quick_code->size() * sizeof(uint8_t);
CHECK_NE(code_size, 0U);
uint32_t thumb_offset = compiled_method->CodeDelta();
@@ -826,7 +857,8 @@ size_t OatWriter::WriteCodeMethod(OutputStream* out, const size_t file_offset,
relative_offset += aligned_code_delta;
DCHECK_OFFSET();
}
- DCHECK_ALIGNED(relative_offset, kArmAlignment);
+ DCheckCodeAlignment(relative_offset, compiled_method->GetInstructionSet());
+
uint32_t code_size = quick_code->size() * sizeof(uint8_t);
CHECK_NE(code_size, 0U);
diff --git a/compiler/utils/arm64/assembler_arm64.cc b/compiler/utils/arm64/assembler_arm64.cc
index a11c2da19e..1d87eaaa60 100644
--- a/compiler/utils/arm64/assembler_arm64.cc
+++ b/compiler/utils/arm64/assembler_arm64.cc
@@ -50,11 +50,11 @@ void Arm64Assembler::FinalizeInstructions(const MemoryRegion& region) {
}
void Arm64Assembler::GetCurrentThread(ManagedRegister tr) {
- ___ Mov(reg_x(tr.AsArm64().AsCoreRegister()), reg_x(TR));
+ ___ Mov(reg_x(tr.AsArm64().AsCoreRegister()), reg_x(TR1));
}
void Arm64Assembler::GetCurrentThread(FrameOffset offset, ManagedRegister /* scratch */) {
- StoreToOffset(TR, SP, offset.Int32Value());
+ StoreToOffset(TR1, SP, offset.Int32Value());
}
// See Arm64 PCS Section 5.2.2.1.
@@ -138,7 +138,8 @@ void Arm64Assembler::Store(FrameOffset offs, ManagedRegister m_src, size_t size)
void Arm64Assembler::StoreRef(FrameOffset offs, ManagedRegister m_src) {
Arm64ManagedRegister src = m_src.AsArm64();
CHECK(src.IsCoreRegister()) << src;
- StoreToOffset(src.AsCoreRegister(), SP, offs.Int32Value());
+ StoreWToOffset(kStoreWord, src.AsOverlappingCoreRegisterLow(), SP,
+ offs.Int32Value());
}
void Arm64Assembler::StoreRawPtr(FrameOffset offs, ManagedRegister m_src) {
@@ -152,30 +153,31 @@ void Arm64Assembler::StoreImmediateToFrame(FrameOffset offs, uint32_t imm,
Arm64ManagedRegister scratch = m_scratch.AsArm64();
CHECK(scratch.IsCoreRegister()) << scratch;
LoadImmediate(scratch.AsCoreRegister(), imm);
- StoreToOffset(scratch.AsCoreRegister(), SP, offs.Int32Value());
+ StoreWToOffset(kStoreWord, scratch.AsOverlappingCoreRegisterLow(), SP,
+ offs.Int32Value());
}
-void Arm64Assembler::StoreImmediateToThread32(ThreadOffset<4> offs, uint32_t imm,
+void Arm64Assembler::StoreImmediateToThread64(ThreadOffset<8> offs, uint32_t imm,
ManagedRegister m_scratch) {
Arm64ManagedRegister scratch = m_scratch.AsArm64();
CHECK(scratch.IsCoreRegister()) << scratch;
LoadImmediate(scratch.AsCoreRegister(), imm);
- StoreToOffset(scratch.AsCoreRegister(), TR, offs.Int32Value());
+ StoreToOffset(scratch.AsCoreRegister(), TR1, offs.Int32Value());
}
-void Arm64Assembler::StoreStackOffsetToThread32(ThreadOffset<4> tr_offs,
+void Arm64Assembler::StoreStackOffsetToThread64(ThreadOffset<8> tr_offs,
FrameOffset fr_offs,
ManagedRegister m_scratch) {
Arm64ManagedRegister scratch = m_scratch.AsArm64();
CHECK(scratch.IsCoreRegister()) << scratch;
AddConstant(scratch.AsCoreRegister(), SP, fr_offs.Int32Value());
- StoreToOffset(scratch.AsCoreRegister(), TR, tr_offs.Int32Value());
+ StoreToOffset(scratch.AsCoreRegister(), TR1, tr_offs.Int32Value());
}
-void Arm64Assembler::StoreStackPointerToThread32(ThreadOffset<4> tr_offs) {
+void Arm64Assembler::StoreStackPointerToThread64(ThreadOffset<8> tr_offs) {
// Arm64 does not support: "str sp, [dest]" therefore we use IP1 as a temp reg.
___ Mov(reg_x(IP1), reg_x(SP));
- StoreToOffset(IP1, TR, tr_offs.Int32Value());
+ StoreToOffset(IP1, TR1, tr_offs.Int32Value());
}
void Arm64Assembler::StoreSpanning(FrameOffset dest_off, ManagedRegister m_source,
@@ -254,9 +256,13 @@ void Arm64Assembler::Load(Arm64ManagedRegister dest, Register base,
CHECK_EQ(4u, size) << dest;
___ Ldr(reg_w(dest.AsWRegister()), MEM_OP(reg_x(base), offset));
} else if (dest.IsCoreRegister()) {
- CHECK_EQ(8u, size) << dest;
CHECK_NE(dest.AsCoreRegister(), SP) << dest;
- ___ Ldr(reg_x(dest.AsCoreRegister()), MEM_OP(reg_x(base), offset));
+ if (size == 4u) {
+ ___ Ldr(reg_w(dest.AsOverlappingCoreRegisterLow()), MEM_OP(reg_x(base), offset));
+ } else {
+ CHECK_EQ(8u, size) << dest;
+ ___ Ldr(reg_x(dest.AsCoreRegister()), MEM_OP(reg_x(base), offset));
+ }
} else if (dest.IsSRegister()) {
___ Ldr(reg_s(dest.AsSRegister()), MEM_OP(reg_x(base), offset));
} else {
@@ -269,14 +275,14 @@ void Arm64Assembler::Load(ManagedRegister m_dst, FrameOffset src, size_t size) {
return Load(m_dst.AsArm64(), SP, src.Int32Value(), size);
}
-void Arm64Assembler::LoadFromThread32(ManagedRegister m_dst, ThreadOffset<4> src, size_t size) {
- return Load(m_dst.AsArm64(), TR, src.Int32Value(), size);
+void Arm64Assembler::LoadFromThread64(ManagedRegister m_dst, ThreadOffset<8> src, size_t size) {
+ return Load(m_dst.AsArm64(), TR1, src.Int32Value(), size);
}
void Arm64Assembler::LoadRef(ManagedRegister m_dst, FrameOffset offs) {
Arm64ManagedRegister dst = m_dst.AsArm64();
CHECK(dst.IsCoreRegister()) << dst;
- LoadFromOffset(dst.AsCoreRegister(), SP, offs.Int32Value());
+ LoadWFromOffset(kLoadWord, dst.AsOverlappingCoreRegisterLow(), SP, offs.Int32Value());
}
void Arm64Assembler::LoadRef(ManagedRegister m_dst, ManagedRegister m_base,
@@ -284,7 +290,8 @@ void Arm64Assembler::LoadRef(ManagedRegister m_dst, ManagedRegister m_base,
Arm64ManagedRegister dst = m_dst.AsArm64();
Arm64ManagedRegister base = m_base.AsArm64();
CHECK(dst.IsCoreRegister() && base.IsCoreRegister());
- LoadFromOffset(dst.AsCoreRegister(), base.AsCoreRegister(), offs.Int32Value());
+ LoadWFromOffset(kLoadWord, dst.AsOverlappingCoreRegisterLow(), base.AsCoreRegister(),
+ offs.Int32Value());
}
void Arm64Assembler::LoadRawPtr(ManagedRegister m_dst, ManagedRegister m_base, Offset offs) {
@@ -294,10 +301,10 @@ void Arm64Assembler::LoadRawPtr(ManagedRegister m_dst, ManagedRegister m_base, O
LoadFromOffset(dst.AsCoreRegister(), base.AsCoreRegister(), offs.Int32Value());
}
-void Arm64Assembler::LoadRawPtrFromThread32(ManagedRegister m_dst, ThreadOffset<4> offs) {
+void Arm64Assembler::LoadRawPtrFromThread64(ManagedRegister m_dst, ThreadOffset<8> offs) {
Arm64ManagedRegister dst = m_dst.AsArm64();
CHECK(dst.IsCoreRegister()) << dst;
- LoadFromOffset(dst.AsCoreRegister(), TR, offs.Int32Value());
+ LoadFromOffset(dst.AsCoreRegister(), TR1, offs.Int32Value());
}
// Copying routines.
@@ -306,8 +313,16 @@ void Arm64Assembler::Move(ManagedRegister m_dst, ManagedRegister m_src, size_t s
Arm64ManagedRegister src = m_src.AsArm64();
if (!dst.Equals(src)) {
if (dst.IsCoreRegister()) {
- CHECK(src.IsCoreRegister()) << src;
- ___ Mov(reg_x(dst.AsCoreRegister()), reg_x(src.AsCoreRegister()));
+ if (size == 4) {
+ CHECK(src.IsWRegister());
+ ___ Mov(reg_x(dst.AsCoreRegister()), reg_w(src.AsWRegister()));
+ } else {
+ if (src.IsCoreRegister()) {
+ ___ Mov(reg_x(dst.AsCoreRegister()), reg_x(src.AsCoreRegister()));
+ } else {
+ ___ Mov(reg_x(dst.AsCoreRegister()), reg_w(src.AsWRegister()));
+ }
+ }
} else if (dst.IsWRegister()) {
CHECK(src.IsWRegister()) << src;
___ Mov(reg_w(dst.AsWRegister()), reg_w(src.AsWRegister()));
@@ -322,40 +337,42 @@ void Arm64Assembler::Move(ManagedRegister m_dst, ManagedRegister m_src, size_t s
}
}
-void Arm64Assembler::CopyRawPtrFromThread32(FrameOffset fr_offs,
- ThreadOffset<4> tr_offs,
+void Arm64Assembler::CopyRawPtrFromThread64(FrameOffset fr_offs,
+ ThreadOffset<8> tr_offs,
ManagedRegister m_scratch) {
Arm64ManagedRegister scratch = m_scratch.AsArm64();
CHECK(scratch.IsCoreRegister()) << scratch;
- LoadFromOffset(scratch.AsCoreRegister(), TR, tr_offs.Int32Value());
+ LoadFromOffset(scratch.AsCoreRegister(), TR1, tr_offs.Int32Value());
StoreToOffset(scratch.AsCoreRegister(), SP, fr_offs.Int32Value());
}
-void Arm64Assembler::CopyRawPtrToThread32(ThreadOffset<4> tr_offs,
+void Arm64Assembler::CopyRawPtrToThread64(ThreadOffset<8> tr_offs,
FrameOffset fr_offs,
ManagedRegister m_scratch) {
Arm64ManagedRegister scratch = m_scratch.AsArm64();
CHECK(scratch.IsCoreRegister()) << scratch;
LoadFromOffset(scratch.AsCoreRegister(), SP, fr_offs.Int32Value());
- StoreToOffset(scratch.AsCoreRegister(), TR, tr_offs.Int32Value());
+ StoreToOffset(scratch.AsCoreRegister(), TR1, tr_offs.Int32Value());
}
void Arm64Assembler::CopyRef(FrameOffset dest, FrameOffset src,
ManagedRegister m_scratch) {
Arm64ManagedRegister scratch = m_scratch.AsArm64();
CHECK(scratch.IsCoreRegister()) << scratch;
- LoadFromOffset(scratch.AsCoreRegister(), SP, src.Int32Value());
- StoreToOffset(scratch.AsCoreRegister(), SP, dest.Int32Value());
+ LoadWFromOffset(kLoadWord, scratch.AsOverlappingCoreRegisterLow(),
+ SP, src.Int32Value());
+ StoreWToOffset(kStoreWord, scratch.AsOverlappingCoreRegisterLow(),
+ SP, dest.Int32Value());
}
void Arm64Assembler::Copy(FrameOffset dest, FrameOffset src,
ManagedRegister m_scratch, size_t size) {
Arm64ManagedRegister scratch = m_scratch.AsArm64();
- CHECK(scratch.IsCoreRegister() || scratch.IsWRegister()) << scratch;
+ CHECK(scratch.IsCoreRegister()) << scratch;
CHECK(size == 4 || size == 8) << size;
if (size == 4) {
- LoadWFromOffset(kLoadWord, scratch.AsWRegister(), SP, src.Int32Value());
- StoreWToOffset(kStoreWord, scratch.AsWRegister(), SP, dest.Int32Value());
+ LoadWFromOffset(kLoadWord, scratch.AsOverlappingCoreRegisterLow(), SP, src.Int32Value());
+ StoreWToOffset(kStoreWord, scratch.AsOverlappingCoreRegisterLow(), SP, dest.Int32Value());
} else if (size == 8) {
LoadFromOffset(scratch.AsCoreRegister(), SP, src.Int32Value());
StoreToOffset(scratch.AsCoreRegister(), SP, dest.Int32Value());
@@ -418,10 +435,17 @@ void Arm64Assembler::Copy(ManagedRegister m_dest, Offset dest_offset,
CHECK(scratch.IsCoreRegister() || scratch.IsWRegister()) << scratch;
CHECK(size == 4 || size == 8) << size;
if (size == 4) {
- LoadWFromOffset(kLoadWord, scratch.AsWRegister(), src.AsCoreRegister(),
+ if (scratch.IsWRegister()) {
+ LoadWFromOffset(kLoadWord, scratch.AsWRegister(), src.AsCoreRegister(),
src_offset.Int32Value());
- StoreWToOffset(kStoreWord, scratch.AsWRegister(), dest.AsCoreRegister(),
+ StoreWToOffset(kStoreWord, scratch.AsWRegister(), dest.AsCoreRegister(),
dest_offset.Int32Value());
+ } else {
+ LoadWFromOffset(kLoadWord, scratch.AsOverlappingCoreRegisterLow(), src.AsCoreRegister(),
+ src_offset.Int32Value());
+ StoreWToOffset(kStoreWord, scratch.AsOverlappingCoreRegisterLow(), dest.AsCoreRegister(),
+ dest_offset.Int32Value());
+ }
} else if (size == 8) {
LoadFromOffset(scratch.AsCoreRegister(), src.AsCoreRegister(), src_offset.Int32Value());
StoreToOffset(scratch.AsCoreRegister(), dest.AsCoreRegister(), dest_offset.Int32Value());
@@ -486,7 +510,7 @@ void Arm64Assembler::Call(FrameOffset base, Offset offs, ManagedRegister m_scrat
___ Blr(reg_x(scratch.AsCoreRegister()));
}
-void Arm64Assembler::CallFromThread32(ThreadOffset<4> /*offset*/, ManagedRegister /*scratch*/) {
+void Arm64Assembler::CallFromThread64(ThreadOffset<8> /*offset*/, ManagedRegister /*scratch*/) {
UNIMPLEMENTED(FATAL) << "Unimplemented Call() variant";
}
@@ -502,10 +526,11 @@ void Arm64Assembler::CreateSirtEntry(ManagedRegister m_out_reg, FrameOffset sirt
// the address in the SIRT holding the reference.
// e.g. out_reg = (handle == 0) ? 0 : (SP+handle_offset)
if (in_reg.IsNoRegister()) {
- LoadFromOffset(out_reg.AsCoreRegister(), SP, sirt_offs.Int32Value());
+ LoadWFromOffset(kLoadWord, out_reg.AsOverlappingCoreRegisterLow(), SP,
+ sirt_offs.Int32Value());
in_reg = out_reg;
}
- ___ Cmp(reg_x(in_reg.AsCoreRegister()), 0);
+ ___ Cmp(reg_w(in_reg.AsOverlappingCoreRegisterLow()), 0);
if (!out_reg.Equals(in_reg)) {
LoadImmediate(out_reg.AsCoreRegister(), 0, EQ);
}
@@ -520,11 +545,12 @@ void Arm64Assembler::CreateSirtEntry(FrameOffset out_off, FrameOffset sirt_offse
Arm64ManagedRegister scratch = m_scratch.AsArm64();
CHECK(scratch.IsCoreRegister()) << scratch;
if (null_allowed) {
- LoadFromOffset(scratch.AsCoreRegister(), SP, sirt_offset.Int32Value());
+ LoadWFromOffset(kLoadWord, scratch.AsOverlappingCoreRegisterLow(), SP,
+ sirt_offset.Int32Value());
// Null values get a SIRT entry value of 0. Otherwise, the sirt entry is
// the address in the SIRT holding the reference.
// e.g. scratch = (scratch == 0) ? 0 : (SP+sirt_offset)
- ___ Cmp(reg_x(scratch.AsCoreRegister()), 0);
+ ___ Cmp(reg_w(scratch.AsOverlappingCoreRegisterLow()), 0);
// Move this logic in add constants with flags.
AddConstant(scratch.AsCoreRegister(), SP, sirt_offset.Int32Value(), NE);
} else {
@@ -555,7 +581,7 @@ void Arm64Assembler::ExceptionPoll(ManagedRegister m_scratch, size_t stack_adjus
Arm64ManagedRegister scratch = m_scratch.AsArm64();
Arm64Exception *current_exception = new Arm64Exception(scratch, stack_adjust);
exception_blocks_.push_back(current_exception);
- LoadFromOffset(scratch.AsCoreRegister(), TR, Thread::ExceptionOffset<4>().Int32Value());
+ LoadFromOffset(scratch.AsCoreRegister(), TR1, Thread::ExceptionOffset<8>().Int32Value());
___ Cmp(reg_x(scratch.AsCoreRegister()), 0);
___ B(current_exception->Entry(), COND_OP(NE));
}
@@ -569,7 +595,11 @@ void Arm64Assembler::EmitExceptionPoll(Arm64Exception *exception) {
// Pass exception object as argument.
// Don't care about preserving X0 as this won't return.
___ Mov(reg_x(X0), reg_x(exception->scratch_.AsCoreRegister()));
- LoadFromOffset(IP1, TR, QUICK_ENTRYPOINT_OFFSET(8, pDeliverException).Int32Value());
+ LoadFromOffset(IP1, TR1, QUICK_ENTRYPOINT_OFFSET(8, pDeliverException).Int32Value());
+
+ // FIXME: Temporary fix for TR (XSELF).
+ ___ Mov(reg_x(TR), reg_x(TR1));
+
___ Blr(reg_x(IP1));
// Call should never return.
___ Brk();
@@ -590,6 +620,9 @@ void Arm64Assembler::BuildFrame(size_t frame_size, ManagedRegister method_reg,
CHECK_EQ(callee_save_regs.size(), kCalleeSavedRegsSize);
___ PushCalleeSavedRegisters();
+ // FIXME: Temporary fix for TR (XSELF).
+ ___ Mov(reg_x(TR1), reg_x(TR));
+
// Increate frame to required size - must be at least space to push Method*.
CHECK_GT(frame_size, kCalleeSavedRegsSize * kFramePointerSize);
size_t adjust = frame_size - (kCalleeSavedRegsSize * kFramePointerSize);
@@ -598,11 +631,27 @@ void Arm64Assembler::BuildFrame(size_t frame_size, ManagedRegister method_reg,
// Write Method*.
StoreToOffset(X0, SP, 0);
- // Write out entry spills, treated as X regs.
- // TODO: we can implement a %2 STRP variant of StoreToOffset.
+ // Write out entry spills
+ int32_t offset = frame_size + kFramePointerSize;
for (size_t i = 0; i < entry_spills.size(); ++i) {
- Register reg = entry_spills.at(i).AsArm64().AsCoreRegister();
- StoreToOffset(reg, SP, frame_size + kFramePointerSize + (i * kFramePointerSize));
+ Arm64ManagedRegister reg = entry_spills.at(i).AsArm64();
+ if (reg.IsNoRegister()) {
+ // only increment stack offset.
+ ManagedRegisterSpill spill = entry_spills.at(i);
+ offset += spill.getSize();
+ } else if (reg.IsCoreRegister()) {
+ StoreToOffset(reg.AsCoreRegister(), SP, offset);
+ offset += 8;
+ } else if (reg.IsWRegister()) {
+ StoreWToOffset(kStoreWord, reg.AsWRegister(), SP, offset);
+ offset += 4;
+ } else if (reg.IsDRegister()) {
+ StoreDToOffset(reg.AsDRegister(), SP, offset);
+ offset += 8;
+ } else if (reg.IsSRegister()) {
+ StoreSToOffset(reg.AsSRegister(), SP, offset);
+ offset += 4;
+ }
}
}
@@ -618,6 +667,9 @@ void Arm64Assembler::RemoveFrame(size_t frame_size, const std::vector<ManagedReg
size_t adjust = frame_size - (kCalleeSavedRegsSize * kFramePointerSize);
DecreaseFrameSize(adjust);
+ // FIXME: Temporary fix for TR (XSELF).
+ ___ Mov(reg_x(TR), reg_x(TR1));
+
// Pop callee saved and return to LR.
___ PopCalleeSavedRegisters();
___ Ret();
diff --git a/compiler/utils/arm64/assembler_arm64.h b/compiler/utils/arm64/assembler_arm64.h
index 8acd1f9950..97fb93af82 100644
--- a/compiler/utils/arm64/assembler_arm64.h
+++ b/compiler/utils/arm64/assembler_arm64.h
@@ -81,8 +81,8 @@ class Arm64Exception;
class Arm64Assembler FINAL : public Assembler {
public:
- Arm64Assembler() : vixl_buf_(new byte[BUF_SIZE]),
- vixl_masm_(new vixl::MacroAssembler(vixl_buf_, BUF_SIZE)) {}
+ Arm64Assembler() : vixl_buf_(new byte[kBufferSizeArm64]),
+ vixl_masm_(new vixl::MacroAssembler(vixl_buf_, kBufferSizeArm64)) {}
virtual ~Arm64Assembler() {
delete[] vixl_buf_;
@@ -114,27 +114,27 @@ class Arm64Assembler FINAL : public Assembler {
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 StoreImmediateToThread32(ThreadOffset<4> dest, uint32_t imm, ManagedRegister scratch)
+ void StoreImmediateToThread64(ThreadOffset<8> dest, uint32_t imm, ManagedRegister scratch)
OVERRIDE;
- void StoreStackOffsetToThread32(ThreadOffset<4> thr_offs, FrameOffset fr_offs,
+ void StoreStackOffsetToThread64(ThreadOffset<8> thr_offs, FrameOffset fr_offs,
ManagedRegister scratch) OVERRIDE;
- void StoreStackPointerToThread32(ThreadOffset<4> thr_offs) OVERRIDE;
+ void StoreStackPointerToThread64(ThreadOffset<8> 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 LoadFromThread32(ManagedRegister dest, ThreadOffset<4> src, size_t size) OVERRIDE;
+ void LoadFromThread64(ManagedRegister dest, ThreadOffset<8> src, size_t size) OVERRIDE;
void LoadRef(ManagedRegister dest, FrameOffset src) OVERRIDE;
void LoadRef(ManagedRegister dest, ManagedRegister base, MemberOffset offs) OVERRIDE;
void LoadRawPtr(ManagedRegister dest, ManagedRegister base, Offset offs) OVERRIDE;
- void LoadRawPtrFromThread32(ManagedRegister dest, ThreadOffset<4> offs) OVERRIDE;
+ void LoadRawPtrFromThread64(ManagedRegister dest, ThreadOffset<8> offs) OVERRIDE;
// Copying routines.
void Move(ManagedRegister dest, ManagedRegister src, size_t size) OVERRIDE;
- void CopyRawPtrFromThread32(FrameOffset fr_offs, ThreadOffset<4> thr_offs,
+ void CopyRawPtrFromThread64(FrameOffset fr_offs, ThreadOffset<8> thr_offs,
ManagedRegister scratch) OVERRIDE;
- void CopyRawPtrToThread32(ThreadOffset<4> thr_offs, FrameOffset fr_offs, ManagedRegister scratch)
+ void CopyRawPtrToThread64(ThreadOffset<8> 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;
@@ -183,7 +183,7 @@ class Arm64Assembler FINAL : public Assembler {
// 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(ThreadOffset<4> offset, ManagedRegister scratch) OVERRIDE;
+ void CallFromThread64(ThreadOffset<8> offset, ManagedRegister scratch) OVERRIDE;
// Jump to address (not setting link register)
void JumpTo(ManagedRegister m_base, Offset offs, ManagedRegister m_scratch);
@@ -234,9 +234,6 @@ class Arm64Assembler FINAL : public Assembler {
void AddConstant(Register rd, int32_t value, Condition cond = AL);
void AddConstant(Register rd, Register rn, int32_t value, Condition cond = AL);
- // Vixl buffer size.
- static constexpr size_t BUF_SIZE = 4096;
-
// Vixl buffer.
byte* vixl_buf_;
diff --git a/compiler/utils/arm64/constants_arm64.h b/compiler/utils/arm64/constants_arm64.h
index ecf9fbe1d9..2a08c95654 100644
--- a/compiler/utils/arm64/constants_arm64.h
+++ b/compiler/utils/arm64/constants_arm64.h
@@ -31,6 +31,9 @@ namespace arm64 {
constexpr unsigned int kCalleeSavedRegsSize = 20;
+// Vixl buffer size.
+constexpr size_t kBufferSizeArm64 = 4096*2;
+
} // arm64
} // art
diff --git a/compiler/utils/managed_register.h b/compiler/utils/managed_register.h
index 0d31322db6..bfb2829a32 100644
--- a/compiler/utils/managed_register.h
+++ b/compiler/utils/managed_register.h
@@ -91,6 +91,9 @@ class ManagedRegisterSpill : public ManagedRegister {
explicit ManagedRegisterSpill(const ManagedRegister& other)
: ManagedRegister(other), size_(-1), spill_offset_(-1) { }
+ explicit ManagedRegisterSpill(const ManagedRegister& other, int32_t size)
+ : ManagedRegister(other), size_(size), spill_offset_(-1) { }
+
int32_t getSpillOffset() {
return spill_offset_;
}
@@ -113,6 +116,11 @@ class ManagedRegisterEntrySpills : public std::vector<ManagedRegisterSpill> {
std::vector<ManagedRegisterSpill>::push_back(spill);
}
+ void push_back(ManagedRegister __x, int32_t __size) {
+ ManagedRegisterSpill spill(__x, __size);
+ std::vector<ManagedRegisterSpill>::push_back(spill);
+ }
+
void push_back(ManagedRegisterSpill __x) {
std::vector<ManagedRegisterSpill>::push_back(__x);
}