Merge "Do not allow OSR jump while debugging is active."
diff --git a/compiler/jni/jni_cfi_test.cc b/compiler/jni/jni_cfi_test.cc
index 371019a..3526802 100644
--- a/compiler/jni/jni_cfi_test.cc
+++ b/compiler/jni/jni_cfi_test.cc
@@ -52,7 +52,7 @@
std::unique_ptr<ManagedRuntimeCallingConvention> mr_conv(
ManagedRuntimeCallingConvention::Create(&arena, is_static, is_synchronized, shorty, isa));
const int frame_size(jni_conv->FrameSize());
- const std::vector<ManagedRegister>& callee_save_regs = jni_conv->CalleeSaveRegisters();
+ ArrayRef<const ManagedRegister> callee_save_regs = jni_conv->CalleeSaveRegisters();
// Assemble the method.
std::unique_ptr<Assembler> jni_asm(Assembler::Create(&arena, isa));
diff --git a/compiler/jni/quick/arm/calling_convention_arm.cc b/compiler/jni/quick/arm/calling_convention_arm.cc
index 9d2732a..29411f0 100644
--- a/compiler/jni/quick/arm/calling_convention_arm.cc
+++ b/compiler/jni/quick/arm/calling_convention_arm.cc
@@ -31,10 +31,6 @@
S0, S1, S2, S3, S4, S5, S6, S7, S8, S9, S10, S11, S12, S13, S14, S15
};
-static const SRegister kHFSCalleeSaveRegisters[] = {
- S16, S17, S18, S19, S20, S21, S22, S23, S24, S25, S26, S27, S28, S29, S30, S31
-};
-
static const DRegister kHFDArgumentRegisters[] = {
D0, D1, D2, D3, D4, D5, D6, D7
};
@@ -42,6 +38,57 @@
static_assert(arraysize(kHFDArgumentRegisters) * 2 == arraysize(kHFSArgumentRegisters),
"ks d argument registers mismatch");
+static constexpr ManagedRegister kCalleeSaveRegisters[] = {
+ // Core registers.
+ ArmManagedRegister::FromCoreRegister(R5),
+ ArmManagedRegister::FromCoreRegister(R6),
+ ArmManagedRegister::FromCoreRegister(R7),
+ ArmManagedRegister::FromCoreRegister(R8),
+ ArmManagedRegister::FromCoreRegister(R10),
+ ArmManagedRegister::FromCoreRegister(R11),
+ // Hard float registers.
+ ArmManagedRegister::FromSRegister(S16),
+ ArmManagedRegister::FromSRegister(S17),
+ ArmManagedRegister::FromSRegister(S18),
+ ArmManagedRegister::FromSRegister(S19),
+ ArmManagedRegister::FromSRegister(S20),
+ ArmManagedRegister::FromSRegister(S21),
+ ArmManagedRegister::FromSRegister(S22),
+ ArmManagedRegister::FromSRegister(S23),
+ ArmManagedRegister::FromSRegister(S24),
+ ArmManagedRegister::FromSRegister(S25),
+ ArmManagedRegister::FromSRegister(S26),
+ ArmManagedRegister::FromSRegister(S27),
+ ArmManagedRegister::FromSRegister(S28),
+ ArmManagedRegister::FromSRegister(S29),
+ ArmManagedRegister::FromSRegister(S30),
+ ArmManagedRegister::FromSRegister(S31)
+};
+
+static constexpr uint32_t CalculateCoreCalleeSpillMask() {
+ // LR is a special callee save which is not reported by CalleeSaveRegisters().
+ uint32_t result = 1 << LR;
+ for (auto&& r : kCalleeSaveRegisters) {
+ if (r.AsArm().IsCoreRegister()) {
+ result |= (1 << r.AsArm().AsCoreRegister());
+ }
+ }
+ return result;
+}
+
+static constexpr uint32_t CalculateFpCalleeSpillMask() {
+ uint32_t result = 0;
+ for (auto&& r : kCalleeSaveRegisters) {
+ if (r.AsArm().IsSRegister()) {
+ result |= (1 << r.AsArm().AsSRegister());
+ }
+ }
+ return result;
+}
+
+static constexpr uint32_t kCoreCalleeSpillMask = CalculateCoreCalleeSpillMask();
+static constexpr uint32_t kFpCalleeSpillMask = CalculateFpCalleeSpillMask();
+
// Calling convention
ManagedRegister ArmManagedRuntimeCallingConvention::InterproceduralScratchRegister() {
@@ -223,32 +270,15 @@
cur_reg++; // bump the iterator for every argument
}
padding_ = padding;
-
- callee_save_regs_.push_back(ArmManagedRegister::FromCoreRegister(R5));
- callee_save_regs_.push_back(ArmManagedRegister::FromCoreRegister(R6));
- callee_save_regs_.push_back(ArmManagedRegister::FromCoreRegister(R7));
- callee_save_regs_.push_back(ArmManagedRegister::FromCoreRegister(R8));
- callee_save_regs_.push_back(ArmManagedRegister::FromCoreRegister(R10));
- callee_save_regs_.push_back(ArmManagedRegister::FromCoreRegister(R11));
-
- for (size_t i = 0; i < arraysize(kHFSCalleeSaveRegisters); ++i) {
- callee_save_regs_.push_back(ArmManagedRegister::FromSRegister(kHFSCalleeSaveRegisters[i]));
- }
}
uint32_t ArmJniCallingConvention::CoreSpillMask() const {
// Compute spill mask to agree with callee saves initialized in the constructor
- uint32_t result = 0;
- result = 1 << R5 | 1 << R6 | 1 << R7 | 1 << R8 | 1 << R10 | 1 << R11 | 1 << LR;
- return result;
+ return kCoreCalleeSpillMask;
}
uint32_t ArmJniCallingConvention::FpSpillMask() const {
- uint32_t result = 0;
- for (size_t i = 0; i < arraysize(kHFSCalleeSaveRegisters); ++i) {
- result |= (1 << kHFSCalleeSaveRegisters[i]);
- }
- return result;
+ return kFpCalleeSpillMask;
}
ManagedRegister ArmJniCallingConvention::ReturnScratchRegister() const {
@@ -269,6 +299,10 @@
kStackAlignment);
}
+ArrayRef<const ManagedRegister> ArmJniCallingConvention::CalleeSaveRegisters() const {
+ return ArrayRef<const ManagedRegister>(kCalleeSaveRegisters);
+}
+
// JniCallingConvention ABI follows AAPCS where longs and doubles must occur
// in even register numbers and stack slots
void ArmJniCallingConvention::Next() {
diff --git a/compiler/jni/quick/arm/calling_convention_arm.h b/compiler/jni/quick/arm/calling_convention_arm.h
index 35b5093..157880b 100644
--- a/compiler/jni/quick/arm/calling_convention_arm.h
+++ b/compiler/jni/quick/arm/calling_convention_arm.h
@@ -58,9 +58,7 @@
void Next() OVERRIDE; // Override default behavior for AAPCS
size_t FrameSize() OVERRIDE;
size_t OutArgSize() OVERRIDE;
- const std::vector<ManagedRegister>& CalleeSaveRegisters() const OVERRIDE {
- return callee_save_regs_;
- }
+ ArrayRef<const ManagedRegister> CalleeSaveRegisters() const OVERRIDE;
ManagedRegister ReturnScratchRegister() const OVERRIDE;
uint32_t CoreSpillMask() const OVERRIDE;
uint32_t FpSpillMask() const OVERRIDE;
@@ -78,9 +76,6 @@
size_t NumberOfOutgoingStackArgs() OVERRIDE;
private:
- // 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_;
diff --git a/compiler/jni/quick/arm64/calling_convention_arm64.cc b/compiler/jni/quick/arm64/calling_convention_arm64.cc
index 9aef10e..ab56c1c 100644
--- a/compiler/jni/quick/arm64/calling_convention_arm64.cc
+++ b/compiler/jni/quick/arm64/calling_convention_arm64.cc
@@ -38,10 +38,65 @@
S0, S1, S2, S3, S4, S5, S6, S7
};
-static const DRegister kDCalleeSaveRegisters[] = {
- D8, D9, D10, D11, D12, D13, D14, D15
+static constexpr ManagedRegister kCalleeSaveRegisters[] = {
+ // Core registers.
+ // Note: The native jni function may call to some VM runtime functions which may suspend
+ // or trigger GC. And the jni method frame will become top quick frame in those cases.
+ // So we need to satisfy GC to save LR and callee-save registers which is similar to
+ // CalleeSaveMethod(RefOnly) frame.
+ // Jni function is the native function which the java code wants to call.
+ // Jni method is the method that is compiled by jni compiler.
+ // Call chain: managed code(java) --> jni method --> jni function.
+ // Thread register(X19) is saved on stack.
+ Arm64ManagedRegister::FromXRegister(X19),
+ Arm64ManagedRegister::FromXRegister(X20),
+ Arm64ManagedRegister::FromXRegister(X21),
+ Arm64ManagedRegister::FromXRegister(X22),
+ Arm64ManagedRegister::FromXRegister(X23),
+ Arm64ManagedRegister::FromXRegister(X24),
+ Arm64ManagedRegister::FromXRegister(X25),
+ Arm64ManagedRegister::FromXRegister(X26),
+ Arm64ManagedRegister::FromXRegister(X27),
+ Arm64ManagedRegister::FromXRegister(X28),
+ Arm64ManagedRegister::FromXRegister(X29),
+ Arm64ManagedRegister::FromXRegister(LR),
+ // Hard float registers.
+ // Considering the case, java_method_1 --> jni method --> jni function --> java_method_2,
+ // we may break on java_method_2 and we still need to find out the values of DEX registers
+ // in java_method_1. So all callee-saves(in managed code) need to be saved.
+ Arm64ManagedRegister::FromDRegister(D8),
+ Arm64ManagedRegister::FromDRegister(D9),
+ Arm64ManagedRegister::FromDRegister(D10),
+ Arm64ManagedRegister::FromDRegister(D11),
+ Arm64ManagedRegister::FromDRegister(D12),
+ Arm64ManagedRegister::FromDRegister(D13),
+ Arm64ManagedRegister::FromDRegister(D14),
+ Arm64ManagedRegister::FromDRegister(D15),
};
+static constexpr uint32_t CalculateCoreCalleeSpillMask() {
+ uint32_t result = 0u;
+ for (auto&& r : kCalleeSaveRegisters) {
+ if (r.AsArm64().IsXRegister()) {
+ result |= (1 << r.AsArm64().AsXRegister());
+ }
+ }
+ return result;
+}
+
+static constexpr uint32_t CalculateFpCalleeSpillMask() {
+ uint32_t result = 0;
+ for (auto&& r : kCalleeSaveRegisters) {
+ if (r.AsArm64().IsDRegister()) {
+ result |= (1 << r.AsArm64().AsDRegister());
+ }
+ }
+ return result;
+}
+
+static constexpr uint32_t kCoreCalleeSpillMask = CalculateCoreCalleeSpillMask();
+static constexpr uint32_t kFpCalleeSpillMask = CalculateFpCalleeSpillMask();
+
// Calling convention
ManagedRegister Arm64ManagedRuntimeCallingConvention::InterproceduralScratchRegister() {
return Arm64ManagedRegister::FromXRegister(X20); // saved on entry restored on exit
@@ -157,47 +212,14 @@
Arm64JniCallingConvention::Arm64JniCallingConvention(bool is_static, bool is_synchronized,
const char* shorty)
: JniCallingConvention(is_static, is_synchronized, shorty, kFramePointerSize) {
- uint32_t core_spill_mask = CoreSpillMask();
- DCHECK_EQ(XZR, kNumberOfXRegisters - 1); // Exclude XZR from the loop (avoid 1 << 32).
- for (int x_reg = 0; x_reg < kNumberOfXRegisters - 1; ++x_reg) {
- if (((1 << x_reg) & core_spill_mask) != 0) {
- callee_save_regs_.push_back(
- Arm64ManagedRegister::FromXRegister(static_cast<XRegister>(x_reg)));
- }
- }
-
- uint32_t fp_spill_mask = FpSpillMask();
- for (int d_reg = 0; d_reg < kNumberOfDRegisters; ++d_reg) {
- if (((1 << d_reg) & fp_spill_mask) != 0) {
- callee_save_regs_.push_back(
- Arm64ManagedRegister::FromDRegister(static_cast<DRegister>(d_reg)));
- }
- }
}
uint32_t Arm64JniCallingConvention::CoreSpillMask() const {
- // Compute spill mask to agree with callee saves initialized in the constructor.
- // Note: The native jni function may call to some VM runtime functions which may suspend
- // or trigger GC. And the jni method frame will become top quick frame in those cases.
- // So we need to satisfy GC to save LR and callee-save registers which is similar to
- // CalleeSaveMethod(RefOnly) frame.
- // Jni function is the native function which the java code wants to call.
- // Jni method is the method that compiled by jni compiler.
- // Call chain: managed code(java) --> jni method --> jni function.
- // Thread register(X19) is saved on stack.
- return 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 kCoreCalleeSpillMask;
}
uint32_t Arm64JniCallingConvention::FpSpillMask() const {
- // Considering the case, java_method_1 --> jni method --> jni function --> java_method_2, we may
- // break on java_method_2 and we still need to find out the values of DEX registers in
- // java_method_1. So all callee-saves(in managed code) need to be saved.
- uint32_t result = 0;
- for (size_t i = 0; i < arraysize(kDCalleeSaveRegisters); ++i) {
- result |= (1 << kDCalleeSaveRegisters[i]);
- }
- return result;
+ return kFpCalleeSpillMask;
}
ManagedRegister Arm64JniCallingConvention::ReturnScratchRegister() const {
@@ -218,6 +240,10 @@
return RoundUp(NumberOfOutgoingStackArgs() * kFramePointerSize, kStackAlignment);
}
+ArrayRef<const ManagedRegister> Arm64JniCallingConvention::CalleeSaveRegisters() const {
+ return ArrayRef<const ManagedRegister>(kCalleeSaveRegisters);
+}
+
bool Arm64JniCallingConvention::IsCurrentParamInRegister() {
if (IsCurrentParamAFloatOrDouble()) {
return (itr_float_and_doubles_ < 8);
diff --git a/compiler/jni/quick/arm64/calling_convention_arm64.h b/compiler/jni/quick/arm64/calling_convention_arm64.h
index 37c92b2..337e881 100644
--- a/compiler/jni/quick/arm64/calling_convention_arm64.h
+++ b/compiler/jni/quick/arm64/calling_convention_arm64.h
@@ -57,9 +57,7 @@
// JNI calling convention
size_t FrameSize() OVERRIDE;
size_t OutArgSize() OVERRIDE;
- const std::vector<ManagedRegister>& CalleeSaveRegisters() const OVERRIDE {
- return callee_save_regs_;
- }
+ ArrayRef<const ManagedRegister> CalleeSaveRegisters() const OVERRIDE;
ManagedRegister ReturnScratchRegister() const OVERRIDE;
uint32_t CoreSpillMask() const OVERRIDE;
uint32_t FpSpillMask() const OVERRIDE;
@@ -77,9 +75,6 @@
size_t NumberOfOutgoingStackArgs() OVERRIDE;
private:
- // TODO: these values aren't unique and can be shared amongst instances
- std::vector<ManagedRegister> callee_save_regs_;
-
DISALLOW_COPY_AND_ASSIGN(Arm64JniCallingConvention);
};
diff --git a/compiler/jni/quick/calling_convention.h b/compiler/jni/quick/calling_convention.h
index 2c4b15c..e8f738d 100644
--- a/compiler/jni/quick/calling_convention.h
+++ b/compiler/jni/quick/calling_convention.h
@@ -17,12 +17,11 @@
#ifndef ART_COMPILER_JNI_QUICK_CALLING_CONVENTION_H_
#define ART_COMPILER_JNI_QUICK_CALLING_CONVENTION_H_
-#include <vector>
-
#include "base/arena_object.h"
#include "handle_scope.h"
#include "primitive.h"
#include "thread.h"
+#include "utils/array_ref.h"
#include "utils/managed_register.h"
namespace art {
@@ -301,7 +300,7 @@
virtual bool RequiresSmallResultTypeExtension() const = 0;
// Callee save registers to spill prior to native code (which may clobber)
- virtual const std::vector<ManagedRegister>& CalleeSaveRegisters() const = 0;
+ virtual ArrayRef<const ManagedRegister> CalleeSaveRegisters() const = 0;
// Spill mask values
virtual uint32_t CoreSpillMask() const = 0;
diff --git a/compiler/jni/quick/jni_compiler.cc b/compiler/jni/quick/jni_compiler.cc
index 27714b8..4311a34 100644
--- a/compiler/jni/quick/jni_compiler.cc
+++ b/compiler/jni/quick/jni_compiler.cc
@@ -112,7 +112,7 @@
// 1. Build the frame saving all callee saves
const size_t frame_size(main_jni_conv->FrameSize());
- const std::vector<ManagedRegister>& callee_save_regs = main_jni_conv->CalleeSaveRegisters();
+ ArrayRef<const ManagedRegister> callee_save_regs = main_jni_conv->CalleeSaveRegisters();
__ BuildFrame(frame_size, mr_conv->MethodRegister(), callee_save_regs, mr_conv->EntrySpills());
DCHECK_EQ(jni_asm->cfi().GetCurrentCFAOffset(), static_cast<int>(frame_size));
diff --git a/compiler/jni/quick/mips/calling_convention_mips.cc b/compiler/jni/quick/mips/calling_convention_mips.cc
index 2d31a98..3d4d140 100644
--- a/compiler/jni/quick/mips/calling_convention_mips.cc
+++ b/compiler/jni/quick/mips/calling_convention_mips.cc
@@ -27,6 +27,32 @@
static const FRegister kFArgumentRegisters[] = { F12, F14 };
static const DRegister kDArgumentRegisters[] = { D6, D7 };
+static constexpr ManagedRegister kCalleeSaveRegisters[] = {
+ // Core registers.
+ MipsManagedRegister::FromCoreRegister(S2),
+ MipsManagedRegister::FromCoreRegister(S3),
+ MipsManagedRegister::FromCoreRegister(S4),
+ MipsManagedRegister::FromCoreRegister(S5),
+ MipsManagedRegister::FromCoreRegister(S6),
+ MipsManagedRegister::FromCoreRegister(S7),
+ MipsManagedRegister::FromCoreRegister(FP),
+ // No hard float callee saves.
+};
+
+static constexpr uint32_t CalculateCoreCalleeSpillMask() {
+ // RA is a special callee save which is not reported by CalleeSaveRegisters().
+ uint32_t result = 1 << RA;
+ for (auto&& r : kCalleeSaveRegisters) {
+ if (r.AsMips().IsCoreRegister()) {
+ result |= (1 << r.AsMips().AsCoreRegister());
+ }
+ }
+ return result;
+}
+
+static constexpr uint32_t kCoreCalleeSpillMask = CalculateCoreCalleeSpillMask();
+static constexpr uint32_t kFpCalleeSpillMask = 0u;
+
// Calling convention
ManagedRegister MipsManagedRuntimeCallingConvention::InterproceduralScratchRegister() {
return MipsManagedRegister::FromCoreRegister(T9);
@@ -161,21 +187,14 @@
cur_reg++; // bump the iterator for every argument
}
padding_ = padding;
-
- callee_save_regs_.push_back(MipsManagedRegister::FromCoreRegister(S2));
- callee_save_regs_.push_back(MipsManagedRegister::FromCoreRegister(S3));
- callee_save_regs_.push_back(MipsManagedRegister::FromCoreRegister(S4));
- callee_save_regs_.push_back(MipsManagedRegister::FromCoreRegister(S5));
- callee_save_regs_.push_back(MipsManagedRegister::FromCoreRegister(S6));
- callee_save_regs_.push_back(MipsManagedRegister::FromCoreRegister(S7));
- callee_save_regs_.push_back(MipsManagedRegister::FromCoreRegister(FP));
}
uint32_t MipsJniCallingConvention::CoreSpillMask() const {
- // Compute spill mask to agree with callee saves initialized in the constructor
- uint32_t result = 0;
- result = 1 << S2 | 1 << S3 | 1 << S4 | 1 << S5 | 1 << S6 | 1 << S7 | 1 << FP | 1 << RA;
- return result;
+ return kCoreCalleeSpillMask;
+}
+
+uint32_t MipsJniCallingConvention::FpSpillMask() const {
+ return kFpCalleeSpillMask;
}
ManagedRegister MipsJniCallingConvention::ReturnScratchRegister() const {
@@ -196,6 +215,10 @@
return RoundUp(NumberOfOutgoingStackArgs() * kFramePointerSize + padding_, kStackAlignment);
}
+ArrayRef<const ManagedRegister> MipsJniCallingConvention::CalleeSaveRegisters() const {
+ return ArrayRef<const ManagedRegister>(kCalleeSaveRegisters);
+}
+
// JniCallingConvention ABI follows AAPCS where longs and doubles must occur
// in even register numbers and stack slots
void MipsJniCallingConvention::Next() {
diff --git a/compiler/jni/quick/mips/calling_convention_mips.h b/compiler/jni/quick/mips/calling_convention_mips.h
index dc45432..5c128b0 100644
--- a/compiler/jni/quick/mips/calling_convention_mips.h
+++ b/compiler/jni/quick/mips/calling_convention_mips.h
@@ -58,14 +58,10 @@
void Next() OVERRIDE; // Override default behavior for AAPCS
size_t FrameSize() OVERRIDE;
size_t OutArgSize() OVERRIDE;
- const std::vector<ManagedRegister>& CalleeSaveRegisters() const OVERRIDE {
- return callee_save_regs_;
- }
+ ArrayRef<const ManagedRegister> CalleeSaveRegisters() const OVERRIDE;
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;
@@ -80,9 +76,6 @@
size_t NumberOfOutgoingStackArgs() OVERRIDE;
private:
- // 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_;
diff --git a/compiler/jni/quick/mips64/calling_convention_mips64.cc b/compiler/jni/quick/mips64/calling_convention_mips64.cc
index 807d740..f2e1da8 100644
--- a/compiler/jni/quick/mips64/calling_convention_mips64.cc
+++ b/compiler/jni/quick/mips64/calling_convention_mips64.cc
@@ -31,6 +31,33 @@
F12, F13, F14, F15, F16, F17, F18, F19
};
+static constexpr ManagedRegister kCalleeSaveRegisters[] = {
+ // Core registers.
+ Mips64ManagedRegister::FromGpuRegister(S2),
+ Mips64ManagedRegister::FromGpuRegister(S3),
+ Mips64ManagedRegister::FromGpuRegister(S4),
+ Mips64ManagedRegister::FromGpuRegister(S5),
+ Mips64ManagedRegister::FromGpuRegister(S6),
+ Mips64ManagedRegister::FromGpuRegister(S7),
+ Mips64ManagedRegister::FromGpuRegister(GP),
+ Mips64ManagedRegister::FromGpuRegister(S8),
+ // No hard float callee saves.
+};
+
+static constexpr uint32_t CalculateCoreCalleeSpillMask() {
+ // RA is a special callee save which is not reported by CalleeSaveRegisters().
+ uint32_t result = 1 << RA;
+ for (auto&& r : kCalleeSaveRegisters) {
+ if (r.AsMips64().IsGpuRegister()) {
+ result |= (1 << r.AsMips64().AsGpuRegister());
+ }
+ }
+ return result;
+}
+
+static constexpr uint32_t kCoreCalleeSpillMask = CalculateCoreCalleeSpillMask();
+static constexpr uint32_t kFpCalleeSpillMask = 0u;
+
// Calling convention
ManagedRegister Mips64ManagedRuntimeCallingConvention::InterproceduralScratchRegister() {
return Mips64ManagedRegister::FromGpuRegister(T9);
@@ -126,22 +153,14 @@
Mips64JniCallingConvention::Mips64JniCallingConvention(bool is_static, bool is_synchronized,
const char* shorty)
: JniCallingConvention(is_static, is_synchronized, shorty, kFramePointerSize) {
- callee_save_regs_.push_back(Mips64ManagedRegister::FromGpuRegister(S2));
- callee_save_regs_.push_back(Mips64ManagedRegister::FromGpuRegister(S3));
- callee_save_regs_.push_back(Mips64ManagedRegister::FromGpuRegister(S4));
- callee_save_regs_.push_back(Mips64ManagedRegister::FromGpuRegister(S5));
- callee_save_regs_.push_back(Mips64ManagedRegister::FromGpuRegister(S6));
- callee_save_regs_.push_back(Mips64ManagedRegister::FromGpuRegister(S7));
- callee_save_regs_.push_back(Mips64ManagedRegister::FromGpuRegister(GP));
- callee_save_regs_.push_back(Mips64ManagedRegister::FromGpuRegister(S8));
}
uint32_t Mips64JniCallingConvention::CoreSpillMask() const {
- // Compute spill mask to agree with callee saves initialized in the constructor
- uint32_t result = 0;
- result = 1 << S2 | 1 << S3 | 1 << S4 | 1 << S5 | 1 << S6 | 1 << S7 | 1 << GP | 1 << S8 | 1 << RA;
- DCHECK_EQ(static_cast<size_t>(POPCOUNT(result)), callee_save_regs_.size() + 1);
- return result;
+ return kCoreCalleeSpillMask;
+}
+
+uint32_t Mips64JniCallingConvention::FpSpillMask() const {
+ return kFpCalleeSpillMask;
}
ManagedRegister Mips64JniCallingConvention::ReturnScratchRegister() const {
@@ -162,6 +181,10 @@
return RoundUp(NumberOfOutgoingStackArgs() * kFramePointerSize, kStackAlignment);
}
+ArrayRef<const ManagedRegister> Mips64JniCallingConvention::CalleeSaveRegisters() const {
+ return ArrayRef<const ManagedRegister>(kCalleeSaveRegisters);
+}
+
bool Mips64JniCallingConvention::IsCurrentParamInRegister() {
return itr_args_ < 8;
}
diff --git a/compiler/jni/quick/mips64/calling_convention_mips64.h b/compiler/jni/quick/mips64/calling_convention_mips64.h
index 3d6aab7..99ea3cd 100644
--- a/compiler/jni/quick/mips64/calling_convention_mips64.h
+++ b/compiler/jni/quick/mips64/calling_convention_mips64.h
@@ -57,14 +57,10 @@
// JNI calling convention
size_t FrameSize() OVERRIDE;
size_t OutArgSize() OVERRIDE;
- const std::vector<ManagedRegister>& CalleeSaveRegisters() const OVERRIDE {
- return callee_save_regs_;
- }
+ ArrayRef<const ManagedRegister> CalleeSaveRegisters() const OVERRIDE;
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;
@@ -79,9 +75,6 @@
size_t NumberOfOutgoingStackArgs() OVERRIDE;
private:
- // TODO: these values aren't unique and can be shared amongst instances
- std::vector<ManagedRegister> callee_save_regs_;
-
DISALLOW_COPY_AND_ASSIGN(Mips64JniCallingConvention);
};
diff --git a/compiler/jni/quick/x86/calling_convention_x86.cc b/compiler/jni/quick/x86/calling_convention_x86.cc
index 322caca..22c7cd0 100644
--- a/compiler/jni/quick/x86/calling_convention_x86.cc
+++ b/compiler/jni/quick/x86/calling_convention_x86.cc
@@ -23,6 +23,28 @@
namespace art {
namespace x86 {
+static constexpr ManagedRegister kCalleeSaveRegisters[] = {
+ // Core registers.
+ X86ManagedRegister::FromCpuRegister(EBP),
+ X86ManagedRegister::FromCpuRegister(ESI),
+ X86ManagedRegister::FromCpuRegister(EDI),
+ // No hard float callee saves.
+};
+
+static constexpr uint32_t CalculateCoreCalleeSpillMask() {
+ // The spilled PC gets a special marker.
+ uint32_t result = 1 << kNumberOfCpuRegisters;
+ for (auto&& r : kCalleeSaveRegisters) {
+ if (r.AsX86().IsCpuRegister()) {
+ result |= (1 << r.AsX86().AsCpuRegister());
+ }
+ }
+ return result;
+}
+
+static constexpr uint32_t kCoreCalleeSpillMask = CalculateCoreCalleeSpillMask();
+static constexpr uint32_t kFpCalleeSpillMask = 0u;
+
// Calling convention
ManagedRegister X86ManagedRuntimeCallingConvention::InterproceduralScratchRegister() {
@@ -169,13 +191,14 @@
X86JniCallingConvention::X86JniCallingConvention(bool is_static, bool is_synchronized,
const char* shorty)
: JniCallingConvention(is_static, is_synchronized, shorty, kFramePointerSize) {
- callee_save_regs_.push_back(X86ManagedRegister::FromCpuRegister(EBP));
- callee_save_regs_.push_back(X86ManagedRegister::FromCpuRegister(ESI));
- callee_save_regs_.push_back(X86ManagedRegister::FromCpuRegister(EDI));
}
uint32_t X86JniCallingConvention::CoreSpillMask() const {
- return 1 << EBP | 1 << ESI | 1 << EDI | 1 << kNumberOfCpuRegisters;
+ return kCoreCalleeSpillMask;
+}
+
+uint32_t X86JniCallingConvention::FpSpillMask() const {
+ return kFpCalleeSpillMask;
}
size_t X86JniCallingConvention::FrameSize() {
@@ -192,6 +215,10 @@
return RoundUp(NumberOfOutgoingStackArgs() * kFramePointerSize, kStackAlignment);
}
+ArrayRef<const ManagedRegister> X86JniCallingConvention::CalleeSaveRegisters() const {
+ return ArrayRef<const ManagedRegister>(kCalleeSaveRegisters);
+}
+
bool X86JniCallingConvention::IsCurrentParamInRegister() {
return false; // Everything is passed by stack.
}
diff --git a/compiler/jni/quick/x86/calling_convention_x86.h b/compiler/jni/quick/x86/calling_convention_x86.h
index cdf0956..9d678b7 100644
--- a/compiler/jni/quick/x86/calling_convention_x86.h
+++ b/compiler/jni/quick/x86/calling_convention_x86.h
@@ -59,14 +59,10 @@
// JNI calling convention
size_t FrameSize() OVERRIDE;
size_t OutArgSize() OVERRIDE;
- const std::vector<ManagedRegister>& CalleeSaveRegisters() const OVERRIDE {
- return callee_save_regs_;
- }
+ ArrayRef<const ManagedRegister> CalleeSaveRegisters() const OVERRIDE;
ManagedRegister ReturnScratchRegister() const OVERRIDE;
uint32_t CoreSpillMask() const OVERRIDE;
- uint32_t FpSpillMask() const OVERRIDE {
- return 0;
- }
+ uint32_t FpSpillMask() const OVERRIDE;
bool IsCurrentParamInRegister() OVERRIDE;
bool IsCurrentParamOnStack() OVERRIDE;
ManagedRegister CurrentParamRegister() OVERRIDE;
@@ -81,9 +77,6 @@
size_t NumberOfOutgoingStackArgs() OVERRIDE;
private:
- // TODO: these values aren't unique and can be shared amongst instances
- std::vector<ManagedRegister> callee_save_regs_;
-
DISALLOW_COPY_AND_ASSIGN(X86JniCallingConvention);
};
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 b6b11ca..cc4d232 100644
--- a/compiler/jni/quick/x86_64/calling_convention_x86_64.cc
+++ b/compiler/jni/quick/x86_64/calling_convention_x86_64.cc
@@ -24,6 +24,45 @@
namespace art {
namespace x86_64 {
+static constexpr ManagedRegister kCalleeSaveRegisters[] = {
+ // Core registers.
+ X86_64ManagedRegister::FromCpuRegister(RBX),
+ X86_64ManagedRegister::FromCpuRegister(RBP),
+ X86_64ManagedRegister::FromCpuRegister(R12),
+ X86_64ManagedRegister::FromCpuRegister(R13),
+ X86_64ManagedRegister::FromCpuRegister(R14),
+ X86_64ManagedRegister::FromCpuRegister(R15),
+ // Hard float registers.
+ X86_64ManagedRegister::FromXmmRegister(XMM12),
+ X86_64ManagedRegister::FromXmmRegister(XMM13),
+ X86_64ManagedRegister::FromXmmRegister(XMM14),
+ X86_64ManagedRegister::FromXmmRegister(XMM15),
+};
+
+static constexpr uint32_t CalculateCoreCalleeSpillMask() {
+ // The spilled PC gets a special marker.
+ uint32_t result = 1 << kNumberOfCpuRegisters;
+ for (auto&& r : kCalleeSaveRegisters) {
+ if (r.AsX86_64().IsCpuRegister()) {
+ result |= (1 << r.AsX86_64().AsCpuRegister().AsRegister());
+ }
+ }
+ return result;
+}
+
+static constexpr uint32_t CalculateFpCalleeSpillMask() {
+ uint32_t result = 0;
+ for (auto&& r : kCalleeSaveRegisters) {
+ if (r.AsX86_64().IsXmmRegister()) {
+ result |= (1 << r.AsX86_64().AsXmmRegister().AsFloatRegister());
+ }
+ }
+ return result;
+}
+
+static constexpr uint32_t kCoreCalleeSpillMask = CalculateCoreCalleeSpillMask();
+static constexpr uint32_t kFpCalleeSpillMask = CalculateFpCalleeSpillMask();
+
// Calling convention
ManagedRegister X86_64ManagedRuntimeCallingConvention::InterproceduralScratchRegister() {
@@ -125,25 +164,14 @@
X86_64JniCallingConvention::X86_64JniCallingConvention(bool is_static, bool is_synchronized,
const char* shorty)
: JniCallingConvention(is_static, is_synchronized, shorty, kFramePointerSize) {
- callee_save_regs_.push_back(X86_64ManagedRegister::FromCpuRegister(RBX));
- callee_save_regs_.push_back(X86_64ManagedRegister::FromCpuRegister(RBP));
- callee_save_regs_.push_back(X86_64ManagedRegister::FromCpuRegister(R12));
- callee_save_regs_.push_back(X86_64ManagedRegister::FromCpuRegister(R13));
- callee_save_regs_.push_back(X86_64ManagedRegister::FromCpuRegister(R14));
- callee_save_regs_.push_back(X86_64ManagedRegister::FromCpuRegister(R15));
- callee_save_regs_.push_back(X86_64ManagedRegister::FromXmmRegister(XMM12));
- callee_save_regs_.push_back(X86_64ManagedRegister::FromXmmRegister(XMM13));
- callee_save_regs_.push_back(X86_64ManagedRegister::FromXmmRegister(XMM14));
- callee_save_regs_.push_back(X86_64ManagedRegister::FromXmmRegister(XMM15));
}
uint32_t X86_64JniCallingConvention::CoreSpillMask() const {
- return 1 << RBX | 1 << RBP | 1 << R12 | 1 << R13 | 1 << R14 | 1 << R15 |
- 1 << kNumberOfCpuRegisters;
+ return kCoreCalleeSpillMask;
}
uint32_t X86_64JniCallingConvention::FpSpillMask() const {
- return 1 << XMM12 | 1 << XMM13 | 1 << XMM14 | 1 << XMM15;
+ return kFpCalleeSpillMask;
}
size_t X86_64JniCallingConvention::FrameSize() {
@@ -160,6 +188,10 @@
return RoundUp(NumberOfOutgoingStackArgs() * kFramePointerSize, kStackAlignment);
}
+ArrayRef<const ManagedRegister> X86_64JniCallingConvention::CalleeSaveRegisters() const {
+ return ArrayRef<const ManagedRegister>(kCalleeSaveRegisters);
+}
+
bool X86_64JniCallingConvention::IsCurrentParamInRegister() {
return !IsCurrentParamOnStack();
}
diff --git a/compiler/jni/quick/x86_64/calling_convention_x86_64.h b/compiler/jni/quick/x86_64/calling_convention_x86_64.h
index 6e47c9f..e2d3d48 100644
--- a/compiler/jni/quick/x86_64/calling_convention_x86_64.h
+++ b/compiler/jni/quick/x86_64/calling_convention_x86_64.h
@@ -55,9 +55,7 @@
// JNI calling convention
size_t FrameSize() OVERRIDE;
size_t OutArgSize() OVERRIDE;
- const std::vector<ManagedRegister>& CalleeSaveRegisters() const OVERRIDE {
- return callee_save_regs_;
- }
+ ArrayRef<const ManagedRegister> CalleeSaveRegisters() const OVERRIDE;
ManagedRegister ReturnScratchRegister() const OVERRIDE;
uint32_t CoreSpillMask() const OVERRIDE;
uint32_t FpSpillMask() const OVERRIDE;
@@ -75,9 +73,6 @@
size_t NumberOfOutgoingStackArgs() OVERRIDE;
private:
- // TODO: these values aren't unique and can be shared amongst instances
- std::vector<ManagedRegister> callee_save_regs_;
-
DISALLOW_COPY_AND_ASSIGN(X86_64JniCallingConvention);
};
diff --git a/compiler/optimizing/code_generator.cc b/compiler/optimizing/code_generator.cc
index 51fbaea..08670a0 100644
--- a/compiler/optimizing/code_generator.cc
+++ b/compiler/optimizing/code_generator.cc
@@ -1305,4 +1305,18 @@
locations->AddTemp(Location::RequiresRegister());
}
+uint32_t CodeGenerator::GetReferenceSlowFlagOffset() const {
+ ScopedObjectAccess soa(Thread::Current());
+ mirror::Class* klass = mirror::Reference::GetJavaLangRefReference();
+ DCHECK(klass->IsInitialized());
+ return klass->GetSlowPathFlagOffset().Uint32Value();
+}
+
+uint32_t CodeGenerator::GetReferenceDisableFlagOffset() const {
+ ScopedObjectAccess soa(Thread::Current());
+ mirror::Class* klass = mirror::Reference::GetJavaLangRefReference();
+ DCHECK(klass->IsInitialized());
+ return klass->GetDisableIntrinsicFlagOffset().Uint32Value();
+}
+
} // namespace art
diff --git a/compiler/optimizing/code_generator.h b/compiler/optimizing/code_generator.h
index 6e75e3b..82a54d2 100644
--- a/compiler/optimizing/code_generator.h
+++ b/compiler/optimizing/code_generator.h
@@ -469,6 +469,9 @@
virtual void GenerateNop() = 0;
+ uint32_t GetReferenceSlowFlagOffset() const;
+ uint32_t GetReferenceDisableFlagOffset() const;
+
protected:
// Method patch info used for recording locations of required linker patches and
// target methods. The target method can be used for various purposes, whether for
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index 50892a9..bdbafcd 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -4308,16 +4308,18 @@
// save one load. However, since this is just an intrinsic slow path we prefer this
// simple and more robust approach rather that trying to determine if that's the case.
SlowPathCode* slow_path = GetCurrentSlowPath();
- DCHECK(slow_path != nullptr); // For intrinsified invokes the call is emitted on the slow path.
- if (slow_path->IsCoreRegisterSaved(location.AsRegister<Register>())) {
- int stack_offset = slow_path->GetStackOffsetOfCoreRegister(location.AsRegister<Register>());
- __ movl(temp, Address(ESP, stack_offset));
- return temp;
+ if (slow_path != nullptr) {
+ if (slow_path->IsCoreRegisterSaved(location.AsRegister<Register>())) {
+ int stack_offset = slow_path->GetStackOffsetOfCoreRegister(location.AsRegister<Register>());
+ __ movl(temp, Address(ESP, stack_offset));
+ return temp;
+ }
}
return location.AsRegister<Register>();
}
-void CodeGeneratorX86::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp) {
+Location CodeGeneratorX86::GenerateCalleeMethodStaticOrDirectCall(HInvokeStaticOrDirect* invoke,
+ Location temp) {
Location callee_method = temp; // For all kinds except kRecursive, callee will be in temp.
switch (invoke->GetMethodLoadKind()) {
case HInvokeStaticOrDirect::MethodLoadKind::kStringInit:
@@ -4366,6 +4368,11 @@
break;
}
}
+ return callee_method;
+}
+
+void CodeGeneratorX86::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp) {
+ Location callee_method = GenerateCalleeMethodStaticOrDirectCall(invoke, temp);
switch (invoke->GetCodePtrLocation()) {
case HInvokeStaticOrDirect::CodePtrLocation::kCallSelf:
diff --git a/compiler/optimizing/code_generator_x86.h b/compiler/optimizing/code_generator_x86.h
index fe7d3ed..98dc8ca 100644
--- a/compiler/optimizing/code_generator_x86.h
+++ b/compiler/optimizing/code_generator_x86.h
@@ -398,6 +398,7 @@
MethodReference target_method) OVERRIDE;
// Generate a call to a static or direct method.
+ Location GenerateCalleeMethodStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp);
void GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp) OVERRIDE;
// Generate a call to a virtual method.
void GenerateVirtualCall(HInvokeVirtual* invoke, Location temp) OVERRIDE;
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc
index 56c5b06..30eca2c 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -762,10 +762,9 @@
}
}
-void CodeGeneratorX86_64::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke,
- Location temp) {
+Location CodeGeneratorX86_64::GenerateCalleeMethodStaticOrDirectCall(HInvokeStaticOrDirect* invoke,
+ Location temp) {
// All registers are assumed to be correctly set up.
-
Location callee_method = temp; // For all kinds except kRecursive, callee will be in temp.
switch (invoke->GetMethodLoadKind()) {
case HInvokeStaticOrDirect::MethodLoadKind::kStringInit:
@@ -815,6 +814,13 @@
break;
}
}
+ return callee_method;
+}
+
+void CodeGeneratorX86_64::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke,
+ Location temp) {
+ // All registers are assumed to be correctly set up.
+ Location callee_method = GenerateCalleeMethodStaticOrDirectCall(invoke, temp);
switch (invoke->GetCodePtrLocation()) {
case HInvokeStaticOrDirect::CodePtrLocation::kCallSelf:
diff --git a/compiler/optimizing/code_generator_x86_64.h b/compiler/optimizing/code_generator_x86_64.h
index d9908bb..7cf1245 100644
--- a/compiler/optimizing/code_generator_x86_64.h
+++ b/compiler/optimizing/code_generator_x86_64.h
@@ -394,6 +394,7 @@
const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
MethodReference target_method) OVERRIDE;
+ Location GenerateCalleeMethodStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp);
void GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp) OVERRIDE;
void GenerateVirtualCall(HInvokeVirtual* invoke, Location temp) OVERRIDE;
diff --git a/compiler/optimizing/intrinsics_mips.cc b/compiler/optimizing/intrinsics_mips.cc
index fa250a3..140f56a 100644
--- a/compiler/optimizing/intrinsics_mips.cc
+++ b/compiler/optimizing/intrinsics_mips.cc
@@ -2433,13 +2433,128 @@
GenLowestOneBit(invoke->GetLocations(), Primitive::kPrimLong, IsR6(), GetAssembler());
}
+// int java.lang.Math.round(float)
+void IntrinsicLocationsBuilderMIPS::VisitMathRoundFloat(HInvoke* invoke) {
+ LocationSummary* locations = new (arena_) LocationSummary(invoke,
+ LocationSummary::kNoCall,
+ kIntrinsified);
+ locations->SetInAt(0, Location::RequiresFpuRegister());
+ locations->AddTemp(Location::RequiresFpuRegister());
+ locations->SetOut(Location::RequiresRegister());
+}
+
+void IntrinsicCodeGeneratorMIPS::VisitMathRoundFloat(HInvoke* invoke) {
+ LocationSummary* locations = invoke->GetLocations();
+ MipsAssembler* assembler = GetAssembler();
+ FRegister in = locations->InAt(0).AsFpuRegister<FRegister>();
+ FRegister half = locations->GetTemp(0).AsFpuRegister<FRegister>();
+ Register out = locations->Out().AsRegister<Register>();
+
+ MipsLabel done;
+ MipsLabel finite;
+ MipsLabel add;
+
+ // if (in.isNaN) {
+ // return 0;
+ // }
+ //
+ // out = floor.w.s(in);
+ //
+ // /*
+ // * This "if" statement is only needed for the pre-R6 version of floor.w.s
+ // * which outputs Integer.MAX_VALUE for negative numbers with magnitudes
+ // * too large to fit in a 32-bit integer.
+ // *
+ // * Starting with MIPSR6, which always sets FCSR.NAN2008=1, negative
+ // * numbers which are too large to be represented in a 32-bit signed
+ // * integer will be processed by floor.w.s to output Integer.MIN_VALUE,
+ // * and will no longer be processed by this "if" statement.
+ // */
+ // if (out == Integer.MAX_VALUE) {
+ // TMP = (in < 0.0f) ? 1 : 0;
+ // /*
+ // * If TMP is 1, then adding it to out will wrap its value from
+ // * Integer.MAX_VALUE to Integer.MIN_VALUE.
+ // */
+ // return out += TMP;
+ // }
+ //
+ // /*
+ // * For negative values not handled by the previous "if" statement the
+ // * test here will correctly set the value of TMP.
+ // */
+ // TMP = ((in - out) >= 0.5f) ? 1 : 0;
+ // return out += TMP;
+
+ // Test for NaN.
+ if (IsR6()) {
+ __ CmpUnS(FTMP, in, in);
+ } else {
+ __ CunS(in, in);
+ }
+
+ // Return zero for NaN.
+ __ Move(out, ZERO);
+ if (IsR6()) {
+ __ Bc1nez(FTMP, &done);
+ } else {
+ __ Bc1t(&done);
+ }
+
+ // out = floor(in);
+ __ FloorWS(FTMP, in);
+ __ Mfc1(out, FTMP);
+
+ __ LoadConst32(TMP, 1);
+
+ // TMP = (out = java.lang.Integer.MAX_VALUE) ? 1 : 0;
+ __ LoadConst32(AT, std::numeric_limits<int32_t>::max());
+ __ Bne(AT, out, &finite);
+
+ __ Mtc1(ZERO, FTMP);
+ if (IsR6()) {
+ __ CmpLtS(FTMP, in, FTMP);
+ __ Mfc1(AT, FTMP);
+ } else {
+ __ ColtS(in, FTMP);
+ }
+
+ __ B(&add);
+
+ __ Bind(&finite);
+
+ // TMP = (0.5f <= (in - out)) ? 1 : 0;
+ __ Cvtsw(FTMP, FTMP); // Convert output of floor.w.s back to "float".
+ __ LoadConst32(AT, bit_cast<int32_t, float>(0.5f));
+ __ SubS(FTMP, in, FTMP);
+ __ Mtc1(AT, half);
+ if (IsR6()) {
+ __ CmpLeS(FTMP, half, FTMP);
+ __ Mfc1(AT, FTMP);
+ } else {
+ __ ColeS(half, FTMP);
+ }
+
+ __ Bind(&add);
+
+ if (IsR6()) {
+ __ Selnez(TMP, TMP, AT);
+ } else {
+ __ Movf(TMP, ZERO);
+ }
+
+ // Return out += TMP.
+ __ Addu(out, out, TMP);
+
+ __ Bind(&done);
+}
+
// Unimplemented intrinsics.
UNIMPLEMENTED_INTRINSIC(MIPS, MathCeil)
UNIMPLEMENTED_INTRINSIC(MIPS, MathFloor)
UNIMPLEMENTED_INTRINSIC(MIPS, MathRint)
UNIMPLEMENTED_INTRINSIC(MIPS, MathRoundDouble)
-UNIMPLEMENTED_INTRINSIC(MIPS, MathRoundFloat)
UNIMPLEMENTED_INTRINSIC(MIPS, UnsafeCASLong)
UNIMPLEMENTED_INTRINSIC(MIPS, ReferenceGetReferent)
diff --git a/compiler/optimizing/intrinsics_x86.cc b/compiler/optimizing/intrinsics_x86.cc
index 99bc40e..d66940f 100644
--- a/compiler/optimizing/intrinsics_x86.cc
+++ b/compiler/optimizing/intrinsics_x86.cc
@@ -2631,8 +2631,66 @@
GenTrailingZeros(GetAssembler(), codegen_, invoke, /* is_long */ true);
}
+void IntrinsicLocationsBuilderX86::VisitReferenceGetReferent(HInvoke* invoke) {
+ if (kEmitCompilerReadBarrier) {
+ // Do not intrinsify this call with the read barrier configuration.
+ return;
+ }
+ LocationSummary* locations = new (arena_) LocationSummary(invoke,
+ LocationSummary::kCallOnSlowPath,
+ kIntrinsified);
+ locations->SetInAt(0, Location::RequiresRegister());
+ locations->SetOut(Location::SameAsFirstInput());
+ locations->AddTemp(Location::RequiresRegister());
+}
+
+void IntrinsicCodeGeneratorX86::VisitReferenceGetReferent(HInvoke* invoke) {
+ DCHECK(!kEmitCompilerReadBarrier);
+ LocationSummary* locations = invoke->GetLocations();
+ X86Assembler* assembler = GetAssembler();
+
+ Register obj = locations->InAt(0).AsRegister<Register>();
+ Register out = locations->Out().AsRegister<Register>();
+
+ SlowPathCode* slow_path = new (GetAllocator()) IntrinsicSlowPathX86(invoke);
+ codegen_->AddSlowPath(slow_path);
+
+ // Load ArtMethod first.
+ HInvokeStaticOrDirect* invoke_direct = invoke->AsInvokeStaticOrDirect();
+ DCHECK(invoke_direct != nullptr);
+ Location temp_loc = codegen_->GenerateCalleeMethodStaticOrDirectCall(
+ invoke_direct, locations->GetTemp(0));
+ DCHECK(temp_loc.Equals(locations->GetTemp(0)));
+ Register temp = temp_loc.AsRegister<Register>();
+
+ // Now get declaring class.
+ __ movl(temp, Address(temp, ArtMethod::DeclaringClassOffset().Int32Value()));
+
+ uint32_t slow_path_flag_offset = codegen_->GetReferenceSlowFlagOffset();
+ uint32_t disable_flag_offset = codegen_->GetReferenceDisableFlagOffset();
+ DCHECK_NE(slow_path_flag_offset, 0u);
+ DCHECK_NE(disable_flag_offset, 0u);
+ DCHECK_NE(slow_path_flag_offset, disable_flag_offset);
+
+ // Check static flags preventing us for using intrinsic.
+ if (slow_path_flag_offset == disable_flag_offset + 1) {
+ __ cmpw(Address(temp, disable_flag_offset), Immediate(0));
+ __ j(kNotEqual, slow_path->GetEntryLabel());
+ } else {
+ __ cmpb(Address(temp, disable_flag_offset), Immediate(0));
+ __ j(kNotEqual, slow_path->GetEntryLabel());
+ __ cmpb(Address(temp, slow_path_flag_offset), Immediate(0));
+ __ j(kNotEqual, slow_path->GetEntryLabel());
+ }
+
+ // Fast path.
+ __ movl(out, Address(obj, mirror::Reference::ReferentOffset().Int32Value()));
+ codegen_->MaybeRecordImplicitNullCheck(invoke);
+ __ MaybeUnpoisonHeapReference(out);
+ __ Bind(slow_path->GetExitLabel());
+}
+
UNIMPLEMENTED_INTRINSIC(X86, MathRoundDouble)
-UNIMPLEMENTED_INTRINSIC(X86, ReferenceGetReferent)
UNIMPLEMENTED_INTRINSIC(X86, SystemArrayCopy)
UNIMPLEMENTED_INTRINSIC(X86, FloatIsInfinite)
UNIMPLEMENTED_INTRINSIC(X86, DoubleIsInfinite)
diff --git a/compiler/optimizing/intrinsics_x86_64.cc b/compiler/optimizing/intrinsics_x86_64.cc
index 06e9cc2..2a86769 100644
--- a/compiler/optimizing/intrinsics_x86_64.cc
+++ b/compiler/optimizing/intrinsics_x86_64.cc
@@ -2719,7 +2719,65 @@
GenTrailingZeros(GetAssembler(), codegen_, invoke, /* is_long */ true);
}
-UNIMPLEMENTED_INTRINSIC(X86_64, ReferenceGetReferent)
+void IntrinsicLocationsBuilderX86_64::VisitReferenceGetReferent(HInvoke* invoke) {
+ if (kEmitCompilerReadBarrier) {
+ // Do not intrinsify this call with the read barrier configuration.
+ return;
+ }
+ LocationSummary* locations = new (arena_) LocationSummary(invoke,
+ LocationSummary::kCallOnSlowPath,
+ kIntrinsified);
+ locations->SetInAt(0, Location::RequiresRegister());
+ locations->SetOut(Location::SameAsFirstInput());
+ locations->AddTemp(Location::RequiresRegister());
+}
+
+void IntrinsicCodeGeneratorX86_64::VisitReferenceGetReferent(HInvoke* invoke) {
+ DCHECK(!kEmitCompilerReadBarrier);
+ LocationSummary* locations = invoke->GetLocations();
+ X86_64Assembler* assembler = GetAssembler();
+
+ CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
+ CpuRegister out = locations->Out().AsRegister<CpuRegister>();
+
+ SlowPathCode* slow_path = new (GetAllocator()) IntrinsicSlowPathX86_64(invoke);
+ codegen_->AddSlowPath(slow_path);
+
+ // Load ArtMethod first.
+ HInvokeStaticOrDirect* invoke_direct = invoke->AsInvokeStaticOrDirect();
+ DCHECK(invoke_direct != nullptr);
+ Location temp_loc = codegen_->GenerateCalleeMethodStaticOrDirectCall(
+ invoke_direct, locations->GetTemp(0));
+ DCHECK(temp_loc.Equals(locations->GetTemp(0)));
+ CpuRegister temp = temp_loc.AsRegister<CpuRegister>();
+
+ // Now get declaring class.
+ __ movl(temp, Address(temp, ArtMethod::DeclaringClassOffset().Int32Value()));
+
+ uint32_t slow_path_flag_offset = codegen_->GetReferenceSlowFlagOffset();
+ uint32_t disable_flag_offset = codegen_->GetReferenceDisableFlagOffset();
+ DCHECK_NE(slow_path_flag_offset, 0u);
+ DCHECK_NE(disable_flag_offset, 0u);
+ DCHECK_NE(slow_path_flag_offset, disable_flag_offset);
+
+ // Check static flags preventing us for using intrinsic.
+ if (slow_path_flag_offset == disable_flag_offset + 1) {
+ __ cmpw(Address(temp, disable_flag_offset), Immediate(0));
+ __ j(kNotEqual, slow_path->GetEntryLabel());
+ } else {
+ __ cmpb(Address(temp, disable_flag_offset), Immediate(0));
+ __ j(kNotEqual, slow_path->GetEntryLabel());
+ __ cmpb(Address(temp, slow_path_flag_offset), Immediate(0));
+ __ j(kNotEqual, slow_path->GetEntryLabel());
+ }
+
+ // Fast path.
+ __ movl(out, Address(obj, mirror::Reference::ReferentOffset().Int32Value()));
+ codegen_->MaybeRecordImplicitNullCheck(invoke);
+ __ MaybeUnpoisonHeapReference(out);
+ __ Bind(slow_path->GetExitLabel());
+}
+
UNIMPLEMENTED_INTRINSIC(X86_64, FloatIsInfinite)
UNIMPLEMENTED_INTRINSIC(X86_64, DoubleIsInfinite)
diff --git a/compiler/utils/arm/assembler_arm.cc b/compiler/utils/arm/assembler_arm.cc
index e5f91dc..a7f4547 100644
--- a/compiler/utils/arm/assembler_arm.cc
+++ b/compiler/utils/arm/assembler_arm.cc
@@ -386,8 +386,9 @@
constexpr size_t kFramePointerSize = kArmPointerSize;
-void ArmAssembler::BuildFrame(size_t frame_size, ManagedRegister method_reg,
- const std::vector<ManagedRegister>& callee_save_regs,
+void ArmAssembler::BuildFrame(size_t frame_size,
+ ManagedRegister method_reg,
+ ArrayRef<const ManagedRegister> callee_save_regs,
const ManagedRegisterEntrySpills& entry_spills) {
CHECK_EQ(buffer_.Size(), 0U); // Nothing emitted yet
CHECK_ALIGNED(frame_size, kStackAlignment);
@@ -442,7 +443,7 @@
}
void ArmAssembler::RemoveFrame(size_t frame_size,
- const std::vector<ManagedRegister>& callee_save_regs) {
+ ArrayRef<const ManagedRegister> callee_save_regs) {
CHECK_ALIGNED(frame_size, kStackAlignment);
cfi_.RememberState();
diff --git a/compiler/utils/arm/assembler_arm.h b/compiler/utils/arm/assembler_arm.h
index ffbe786..274d0de 100644
--- a/compiler/utils/arm/assembler_arm.h
+++ b/compiler/utils/arm/assembler_arm.h
@@ -907,12 +907,13 @@
//
// Emit code that will create an activation on the stack
- void BuildFrame(size_t frame_size, ManagedRegister method_reg,
- const std::vector<ManagedRegister>& callee_save_regs,
+ void BuildFrame(size_t frame_size,
+ ManagedRegister method_reg,
+ ArrayRef<const ManagedRegister> callee_save_regs,
const ManagedRegisterEntrySpills& entry_spills) OVERRIDE;
// Emit code that will remove an activation from the stack
- void RemoveFrame(size_t frame_size, const std::vector<ManagedRegister>& callee_save_regs)
+ void RemoveFrame(size_t frame_size, ArrayRef<const ManagedRegister> callee_save_regs)
OVERRIDE;
void IncreaseFrameSize(size_t adjust) OVERRIDE;
diff --git a/compiler/utils/arm/managed_register_arm.h b/compiler/utils/arm/managed_register_arm.h
index 5b84058..276db44 100644
--- a/compiler/utils/arm/managed_register_arm.h
+++ b/compiler/utils/arm/managed_register_arm.h
@@ -85,34 +85,34 @@
// There is a one-to-one mapping between ManagedRegister and register id.
class ArmManagedRegister : public ManagedRegister {
public:
- Register AsCoreRegister() const {
+ constexpr Register AsCoreRegister() const {
CHECK(IsCoreRegister());
return static_cast<Register>(id_);
}
- SRegister AsSRegister() const {
+ constexpr SRegister AsSRegister() const {
CHECK(IsSRegister());
return static_cast<SRegister>(id_ - kNumberOfCoreRegIds);
}
- DRegister AsDRegister() const {
+ constexpr DRegister AsDRegister() const {
CHECK(IsDRegister());
return static_cast<DRegister>(id_ - kNumberOfCoreRegIds - kNumberOfSRegIds);
}
- SRegister AsOverlappingDRegisterLow() const {
+ constexpr SRegister AsOverlappingDRegisterLow() const {
CHECK(IsOverlappingDRegister());
DRegister d_reg = AsDRegister();
return static_cast<SRegister>(d_reg * 2);
}
- SRegister AsOverlappingDRegisterHigh() const {
+ constexpr SRegister AsOverlappingDRegisterHigh() const {
CHECK(IsOverlappingDRegister());
DRegister d_reg = AsDRegister();
return static_cast<SRegister>(d_reg * 2 + 1);
}
- RegisterPair AsRegisterPair() const {
+ constexpr RegisterPair AsRegisterPair() const {
CHECK(IsRegisterPair());
Register reg_low = AsRegisterPairLow();
if (reg_low == R1) {
@@ -122,50 +122,50 @@
}
}
- Register AsRegisterPairLow() const {
+ constexpr Register AsRegisterPairLow() const {
CHECK(IsRegisterPair());
// Appropriate mapping of register ids allows to use AllocIdLow().
return FromRegId(AllocIdLow()).AsCoreRegister();
}
- Register AsRegisterPairHigh() const {
+ constexpr Register AsRegisterPairHigh() const {
CHECK(IsRegisterPair());
// Appropriate mapping of register ids allows to use AllocIdHigh().
return FromRegId(AllocIdHigh()).AsCoreRegister();
}
- bool IsCoreRegister() const {
+ constexpr bool IsCoreRegister() const {
CHECK(IsValidManagedRegister());
return (0 <= id_) && (id_ < kNumberOfCoreRegIds);
}
- bool IsSRegister() const {
+ constexpr bool IsSRegister() const {
CHECK(IsValidManagedRegister());
const int test = id_ - kNumberOfCoreRegIds;
return (0 <= test) && (test < kNumberOfSRegIds);
}
- bool IsDRegister() const {
+ constexpr bool IsDRegister() const {
CHECK(IsValidManagedRegister());
const int test = id_ - (kNumberOfCoreRegIds + kNumberOfSRegIds);
return (0 <= test) && (test < kNumberOfDRegIds);
}
// Returns true if this DRegister overlaps SRegisters.
- bool IsOverlappingDRegister() const {
+ constexpr bool IsOverlappingDRegister() const {
CHECK(IsValidManagedRegister());
const int test = id_ - (kNumberOfCoreRegIds + kNumberOfSRegIds);
return (0 <= test) && (test < kNumberOfOverlappingDRegIds);
}
- bool IsRegisterPair() const {
+ constexpr bool IsRegisterPair() const {
CHECK(IsValidManagedRegister());
const int test =
id_ - (kNumberOfCoreRegIds + kNumberOfSRegIds + kNumberOfDRegIds);
return (0 <= test) && (test < kNumberOfPairRegIds);
}
- bool IsSameType(ArmManagedRegister test) const {
+ constexpr bool IsSameType(ArmManagedRegister test) const {
CHECK(IsValidManagedRegister() && test.IsValidManagedRegister());
return
(IsCoreRegister() && test.IsCoreRegister()) ||
@@ -182,29 +182,29 @@
void Print(std::ostream& os) const;
- static ArmManagedRegister FromCoreRegister(Register r) {
+ static constexpr ArmManagedRegister FromCoreRegister(Register r) {
CHECK_NE(r, kNoRegister);
return FromRegId(r);
}
- static ArmManagedRegister FromSRegister(SRegister r) {
+ static constexpr ArmManagedRegister FromSRegister(SRegister r) {
CHECK_NE(r, kNoSRegister);
return FromRegId(r + kNumberOfCoreRegIds);
}
- static ArmManagedRegister FromDRegister(DRegister r) {
+ static constexpr ArmManagedRegister FromDRegister(DRegister r) {
CHECK_NE(r, kNoDRegister);
return FromRegId(r + (kNumberOfCoreRegIds + kNumberOfSRegIds));
}
- static ArmManagedRegister FromRegisterPair(RegisterPair r) {
+ static constexpr ArmManagedRegister FromRegisterPair(RegisterPair r) {
CHECK_NE(r, kNoRegisterPair);
return FromRegId(r + (kNumberOfCoreRegIds +
kNumberOfSRegIds + kNumberOfDRegIds));
}
// Return a RegisterPair consisting of Register r_low and r_low + 1.
- static ArmManagedRegister FromCoreRegisterPair(Register r_low) {
+ static constexpr ArmManagedRegister FromCoreRegisterPair(Register r_low) {
if (r_low != R1) { // not the dalvik special case
CHECK_NE(r_low, kNoRegister);
CHECK_EQ(0, (r_low % 2));
@@ -217,7 +217,7 @@
}
// Return a DRegister overlapping SRegister r_low and r_low + 1.
- static ArmManagedRegister FromSRegisterPair(SRegister r_low) {
+ static constexpr ArmManagedRegister FromSRegisterPair(SRegister r_low) {
CHECK_NE(r_low, kNoSRegister);
CHECK_EQ(0, (r_low % 2));
const int r = r_low / 2;
@@ -226,7 +226,7 @@
}
private:
- bool IsValidManagedRegister() const {
+ constexpr bool IsValidManagedRegister() const {
return (0 <= id_) && (id_ < kNumberOfRegIds);
}
@@ -251,9 +251,9 @@
friend class ManagedRegister;
- explicit ArmManagedRegister(int reg_id) : ManagedRegister(reg_id) {}
+ explicit constexpr ArmManagedRegister(int reg_id) : ManagedRegister(reg_id) {}
- static ArmManagedRegister FromRegId(int reg_id) {
+ static constexpr ArmManagedRegister FromRegId(int reg_id) {
ArmManagedRegister reg(reg_id);
CHECK(reg.IsValidManagedRegister());
return reg;
@@ -264,7 +264,7 @@
} // namespace arm
-inline arm::ArmManagedRegister ManagedRegister::AsArm() const {
+constexpr inline arm::ArmManagedRegister ManagedRegister::AsArm() const {
arm::ArmManagedRegister reg(id_);
CHECK(reg.IsNoRegister() || reg.IsValidManagedRegister());
return reg;
diff --git a/compiler/utils/arm64/assembler_arm64.cc b/compiler/utils/arm64/assembler_arm64.cc
index eb5112b..1842f00 100644
--- a/compiler/utils/arm64/assembler_arm64.cc
+++ b/compiler/utils/arm64/assembler_arm64.cc
@@ -683,8 +683,9 @@
DCHECK(registers.IsEmpty());
}
-void Arm64Assembler::BuildFrame(size_t frame_size, ManagedRegister method_reg,
- const std::vector<ManagedRegister>& callee_save_regs,
+void Arm64Assembler::BuildFrame(size_t frame_size,
+ ManagedRegister method_reg,
+ ArrayRef<const ManagedRegister> callee_save_regs,
const ManagedRegisterEntrySpills& entry_spills) {
// Setup VIXL CPURegList for callee-saves.
CPURegList core_reg_list(CPURegister::kRegister, kXRegSize, 0);
@@ -741,7 +742,7 @@
}
void Arm64Assembler::RemoveFrame(size_t frame_size,
- const std::vector<ManagedRegister>& callee_save_regs) {
+ ArrayRef<const ManagedRegister> callee_save_regs) {
// Setup VIXL CPURegList for callee-saves.
CPURegList core_reg_list(CPURegister::kRegister, kXRegSize, 0);
CPURegList fp_reg_list(CPURegister::kFPRegister, kDRegSize, 0);
diff --git a/compiler/utils/arm64/assembler_arm64.h b/compiler/utils/arm64/assembler_arm64.h
index c4e5de7..91171a8 100644
--- a/compiler/utils/arm64/assembler_arm64.h
+++ b/compiler/utils/arm64/assembler_arm64.h
@@ -109,12 +109,13 @@
void UnspillRegisters(vixl::CPURegList registers, int offset);
// Emit code that will create an activation on the stack.
- void BuildFrame(size_t frame_size, ManagedRegister method_reg,
- const std::vector<ManagedRegister>& callee_save_regs,
+ void BuildFrame(size_t frame_size,
+ ManagedRegister method_reg,
+ ArrayRef<const ManagedRegister> callee_save_regs,
const ManagedRegisterEntrySpills& entry_spills) OVERRIDE;
// Emit code that will remove an activation from the stack.
- void RemoveFrame(size_t frame_size, const std::vector<ManagedRegister>& callee_save_regs)
+ void RemoveFrame(size_t frame_size, ArrayRef<const ManagedRegister> callee_save_regs)
OVERRIDE;
void IncreaseFrameSize(size_t adjust) OVERRIDE;
diff --git a/compiler/utils/arm64/managed_register_arm64.h b/compiler/utils/arm64/managed_register_arm64.h
index 46be1c5..f7d74d2 100644
--- a/compiler/utils/arm64/managed_register_arm64.h
+++ b/compiler/utils/arm64/managed_register_arm64.h
@@ -56,80 +56,80 @@
class Arm64ManagedRegister : public ManagedRegister {
public:
- XRegister AsXRegister() const {
+ constexpr XRegister AsXRegister() const {
CHECK(IsXRegister());
return static_cast<XRegister>(id_);
}
- WRegister AsWRegister() const {
+ constexpr WRegister AsWRegister() const {
CHECK(IsWRegister());
return static_cast<WRegister>(id_ - kNumberOfXRegIds);
}
- DRegister AsDRegister() const {
+ constexpr DRegister AsDRegister() const {
CHECK(IsDRegister());
return static_cast<DRegister>(id_ - kNumberOfXRegIds - kNumberOfWRegIds);
}
- SRegister AsSRegister() const {
+ constexpr SRegister AsSRegister() const {
CHECK(IsSRegister());
return static_cast<SRegister>(id_ - kNumberOfXRegIds - kNumberOfWRegIds -
kNumberOfDRegIds);
}
- WRegister AsOverlappingWRegister() const {
+ constexpr WRegister AsOverlappingWRegister() const {
CHECK(IsValidManagedRegister());
if (IsZeroRegister()) return WZR;
return static_cast<WRegister>(AsXRegister());
}
- XRegister AsOverlappingXRegister() const {
+ constexpr XRegister AsOverlappingXRegister() const {
CHECK(IsValidManagedRegister());
return static_cast<XRegister>(AsWRegister());
}
- SRegister AsOverlappingSRegister() const {
+ constexpr SRegister AsOverlappingSRegister() const {
CHECK(IsValidManagedRegister());
return static_cast<SRegister>(AsDRegister());
}
- DRegister AsOverlappingDRegister() const {
+ constexpr DRegister AsOverlappingDRegister() const {
CHECK(IsValidManagedRegister());
return static_cast<DRegister>(AsSRegister());
}
- bool IsXRegister() const {
+ constexpr bool IsXRegister() const {
CHECK(IsValidManagedRegister());
return (0 <= id_) && (id_ < kNumberOfXRegIds);
}
- bool IsWRegister() const {
+ constexpr bool IsWRegister() const {
CHECK(IsValidManagedRegister());
const int test = id_ - kNumberOfXRegIds;
return (0 <= test) && (test < kNumberOfWRegIds);
}
- bool IsDRegister() const {
+ constexpr bool IsDRegister() const {
CHECK(IsValidManagedRegister());
const int test = id_ - (kNumberOfXRegIds + kNumberOfWRegIds);
return (0 <= test) && (test < kNumberOfDRegIds);
}
- bool IsSRegister() const {
+ constexpr bool IsSRegister() const {
CHECK(IsValidManagedRegister());
const int test = id_ - (kNumberOfXRegIds + kNumberOfWRegIds + kNumberOfDRegIds);
return (0 <= test) && (test < kNumberOfSRegIds);
}
- bool IsGPRegister() const {
+ constexpr bool IsGPRegister() const {
return IsXRegister() || IsWRegister();
}
- bool IsFPRegister() const {
+ constexpr bool IsFPRegister() const {
return IsDRegister() || IsSRegister();
}
- bool IsSameType(Arm64ManagedRegister test) const {
+ constexpr bool IsSameType(Arm64ManagedRegister test) const {
CHECK(IsValidManagedRegister() && test.IsValidManagedRegister());
return
(IsXRegister() && test.IsXRegister()) ||
@@ -145,53 +145,53 @@
void Print(std::ostream& os) const;
- static Arm64ManagedRegister FromXRegister(XRegister r) {
+ static constexpr Arm64ManagedRegister FromXRegister(XRegister r) {
CHECK_NE(r, kNoRegister);
return FromRegId(r);
}
- static Arm64ManagedRegister FromWRegister(WRegister r) {
+ static constexpr Arm64ManagedRegister FromWRegister(WRegister r) {
CHECK_NE(r, kNoWRegister);
return FromRegId(r + kNumberOfXRegIds);
}
- static Arm64ManagedRegister FromDRegister(DRegister r) {
+ static constexpr Arm64ManagedRegister FromDRegister(DRegister r) {
CHECK_NE(r, kNoDRegister);
return FromRegId(r + (kNumberOfXRegIds + kNumberOfWRegIds));
}
- static Arm64ManagedRegister FromSRegister(SRegister r) {
+ static constexpr Arm64ManagedRegister FromSRegister(SRegister r) {
CHECK_NE(r, kNoSRegister);
return FromRegId(r + (kNumberOfXRegIds + kNumberOfWRegIds +
kNumberOfDRegIds));
}
// Returns the X register overlapping W register r.
- static Arm64ManagedRegister FromWRegisterX(WRegister r) {
+ static constexpr Arm64ManagedRegister FromWRegisterX(WRegister r) {
CHECK_NE(r, kNoWRegister);
return FromRegId(r);
}
// Return the D register overlapping S register r.
- static Arm64ManagedRegister FromSRegisterD(SRegister r) {
+ static constexpr Arm64ManagedRegister FromSRegisterD(SRegister r) {
CHECK_NE(r, kNoSRegister);
return FromRegId(r + (kNumberOfXRegIds + kNumberOfWRegIds));
}
private:
- bool IsValidManagedRegister() const {
+ constexpr bool IsValidManagedRegister() const {
return (0 <= id_) && (id_ < kNumberOfRegIds);
}
- bool IsStackPointer() const {
+ constexpr bool IsStackPointer() const {
return IsXRegister() && (id_ == SP);
}
- bool IsZeroRegister() const {
+ constexpr bool IsZeroRegister() const {
return IsXRegister() && (id_ == XZR);
}
- int RegId() const {
+ constexpr int RegId() const {
CHECK(!IsNoRegister());
return id_;
}
@@ -202,9 +202,9 @@
friend class ManagedRegister;
- explicit Arm64ManagedRegister(int reg_id) : ManagedRegister(reg_id) {}
+ explicit constexpr Arm64ManagedRegister(int reg_id) : ManagedRegister(reg_id) {}
- static Arm64ManagedRegister FromRegId(int reg_id) {
+ static constexpr Arm64ManagedRegister FromRegId(int reg_id) {
Arm64ManagedRegister reg(reg_id);
CHECK(reg.IsValidManagedRegister());
return reg;
@@ -215,7 +215,7 @@
} // namespace arm64
-inline arm64::Arm64ManagedRegister ManagedRegister::AsArm64() const {
+constexpr inline arm64::Arm64ManagedRegister ManagedRegister::AsArm64() const {
arm64::Arm64ManagedRegister reg(id_);
CHECK(reg.IsNoRegister() || reg.IsValidManagedRegister());
return reg;
diff --git a/compiler/utils/assembler.h b/compiler/utils/assembler.h
index 5267dc3..80aa630 100644
--- a/compiler/utils/assembler.h
+++ b/compiler/utils/assembler.h
@@ -32,6 +32,7 @@
#include "memory_region.h"
#include "mips/constants_mips.h"
#include "offsets.h"
+#include "utils/array_ref.h"
#include "x86/constants_x86.h"
#include "x86_64/constants_x86_64.h"
@@ -375,13 +376,14 @@
virtual void Comment(const char* format ATTRIBUTE_UNUSED, ...) {}
// Emit code that will create an activation on the stack
- virtual void BuildFrame(size_t frame_size, ManagedRegister method_reg,
- const std::vector<ManagedRegister>& callee_save_regs,
+ virtual void BuildFrame(size_t frame_size,
+ ManagedRegister method_reg,
+ ArrayRef<const ManagedRegister> callee_save_regs,
const ManagedRegisterEntrySpills& entry_spills) = 0;
// Emit code that will remove an activation from the stack
virtual void RemoveFrame(size_t frame_size,
- const std::vector<ManagedRegister>& callee_save_regs) = 0;
+ ArrayRef<const ManagedRegister> callee_save_regs) = 0;
virtual void IncreaseFrameSize(size_t adjust) = 0;
virtual void DecreaseFrameSize(size_t adjust) = 0;
diff --git a/compiler/utils/managed_register.h b/compiler/utils/managed_register.h
index 893daff..46adb3f 100644
--- a/compiler/utils/managed_register.h
+++ b/compiler/utils/managed_register.h
@@ -47,40 +47,40 @@
// ManagedRegister is a value class. There exists no method to change the
// internal state. We therefore allow a copy constructor and an
// assignment-operator.
- ManagedRegister(const ManagedRegister& other) : id_(other.id_) { }
+ constexpr ManagedRegister(const ManagedRegister& other) : id_(other.id_) { }
ManagedRegister& operator=(const ManagedRegister& other) {
id_ = other.id_;
return *this;
}
- arm::ArmManagedRegister AsArm() const;
- arm64::Arm64ManagedRegister AsArm64() const;
- mips::MipsManagedRegister AsMips() const;
- mips64::Mips64ManagedRegister AsMips64() const;
- x86::X86ManagedRegister AsX86() const;
- x86_64::X86_64ManagedRegister AsX86_64() const;
+ constexpr arm::ArmManagedRegister AsArm() const;
+ constexpr arm64::Arm64ManagedRegister AsArm64() const;
+ constexpr mips::MipsManagedRegister AsMips() const;
+ constexpr mips64::Mips64ManagedRegister AsMips64() const;
+ constexpr x86::X86ManagedRegister AsX86() const;
+ constexpr x86_64::X86_64ManagedRegister AsX86_64() const;
// It is valid to invoke Equals on and with a NoRegister.
- bool Equals(const ManagedRegister& other) const {
+ constexpr bool Equals(const ManagedRegister& other) const {
return id_ == other.id_;
}
- bool IsNoRegister() const {
+ constexpr bool IsNoRegister() const {
return id_ == kNoRegister;
}
- static ManagedRegister NoRegister() {
+ static constexpr ManagedRegister NoRegister() {
return ManagedRegister();
}
- int RegId() const { return id_; }
- explicit ManagedRegister(int reg_id) : id_(reg_id) { }
+ constexpr int RegId() const { return id_; }
+ explicit constexpr ManagedRegister(int reg_id) : id_(reg_id) { }
protected:
static const int kNoRegister = -1;
- ManagedRegister() : id_(kNoRegister) { }
+ constexpr ManagedRegister() : id_(kNoRegister) { }
int id_;
};
diff --git a/compiler/utils/mips/assembler_mips.cc b/compiler/utils/mips/assembler_mips.cc
index a1798c0..9368301 100644
--- a/compiler/utils/mips/assembler_mips.cc
+++ b/compiler/utils/mips/assembler_mips.cc
@@ -2438,8 +2438,9 @@
constexpr size_t kFramePointerSize = 4;
-void MipsAssembler::BuildFrame(size_t frame_size, ManagedRegister method_reg,
- const std::vector<ManagedRegister>& callee_save_regs,
+void MipsAssembler::BuildFrame(size_t frame_size,
+ ManagedRegister method_reg,
+ ArrayRef<const ManagedRegister> callee_save_regs,
const ManagedRegisterEntrySpills& entry_spills) {
CHECK_ALIGNED(frame_size, kStackAlignment);
DCHECK(!overwriting_);
@@ -2453,7 +2454,7 @@
cfi_.RelOffset(DWARFReg(RA), stack_offset);
for (int i = callee_save_regs.size() - 1; i >= 0; --i) {
stack_offset -= kFramePointerSize;
- Register reg = callee_save_regs.at(i).AsMips().AsCoreRegister();
+ Register reg = callee_save_regs[i].AsMips().AsCoreRegister();
StoreToOffset(kStoreWord, reg, SP, stack_offset);
cfi_.RelOffset(DWARFReg(reg), stack_offset);
}
@@ -2482,7 +2483,7 @@
}
void MipsAssembler::RemoveFrame(size_t frame_size,
- const std::vector<ManagedRegister>& callee_save_regs) {
+ ArrayRef<const ManagedRegister> callee_save_regs) {
CHECK_ALIGNED(frame_size, kStackAlignment);
DCHECK(!overwriting_);
cfi_.RememberState();
@@ -2490,7 +2491,7 @@
// Pop callee saves and return address.
int stack_offset = frame_size - (callee_save_regs.size() * kFramePointerSize) - kFramePointerSize;
for (size_t i = 0; i < callee_save_regs.size(); ++i) {
- Register reg = callee_save_regs.at(i).AsMips().AsCoreRegister();
+ Register reg = callee_save_regs[i].AsMips().AsCoreRegister();
LoadFromOffset(kLoadWord, reg, SP, stack_offset);
cfi_.Restore(DWARFReg(reg));
stack_offset += kFramePointerSize;
diff --git a/compiler/utils/mips/assembler_mips.h b/compiler/utils/mips/assembler_mips.h
index ecb67bd..d5e6285 100644
--- a/compiler/utils/mips/assembler_mips.h
+++ b/compiler/utils/mips/assembler_mips.h
@@ -414,11 +414,11 @@
// Emit code that will create an activation on the stack.
void BuildFrame(size_t frame_size,
ManagedRegister method_reg,
- const std::vector<ManagedRegister>& callee_save_regs,
+ ArrayRef<const ManagedRegister> callee_save_regs,
const ManagedRegisterEntrySpills& entry_spills) OVERRIDE;
// Emit code that will remove an activation from the stack.
- void RemoveFrame(size_t frame_size, const std::vector<ManagedRegister>& callee_save_regs)
+ void RemoveFrame(size_t frame_size, ArrayRef<const ManagedRegister> callee_save_regs)
OVERRIDE;
void IncreaseFrameSize(size_t adjust) OVERRIDE;
diff --git a/compiler/utils/mips/assembler_mips_test.cc b/compiler/utils/mips/assembler_mips_test.cc
index cec43ba..56e5884 100644
--- a/compiler/utils/mips/assembler_mips_test.cc
+++ b/compiler/utils/mips/assembler_mips_test.cc
@@ -561,6 +561,14 @@
DriverStr(RepeatFF(&mips::MipsAssembler::NegD, "neg.d ${reg1}, ${reg2}"), "NegD");
}
+TEST_F(AssemblerMIPSTest, FloorWS) {
+ DriverStr(RepeatFF(&mips::MipsAssembler::FloorWS, "floor.w.s ${reg1}, ${reg2}"), "floor.w.s");
+}
+
+TEST_F(AssemblerMIPSTest, FloorWD) {
+ DriverStr(RepeatFF(&mips::MipsAssembler::FloorWD, "floor.w.d ${reg1}, ${reg2}"), "floor.w.d");
+}
+
TEST_F(AssemblerMIPSTest, CunS) {
DriverStr(RepeatIbFF(&mips::MipsAssembler::CunS, 3, "c.un.s $fcc{imm}, ${reg1}, ${reg2}"),
"CunS");
diff --git a/compiler/utils/mips/managed_register_mips.h b/compiler/utils/mips/managed_register_mips.h
index 5e7ed11..66204e7 100644
--- a/compiler/utils/mips/managed_register_mips.h
+++ b/compiler/utils/mips/managed_register_mips.h
@@ -87,70 +87,70 @@
// There is a one-to-one mapping between ManagedRegister and register id.
class MipsManagedRegister : public ManagedRegister {
public:
- Register AsCoreRegister() const {
+ constexpr Register AsCoreRegister() const {
CHECK(IsCoreRegister());
return static_cast<Register>(id_);
}
- FRegister AsFRegister() const {
+ constexpr FRegister AsFRegister() const {
CHECK(IsFRegister());
return static_cast<FRegister>(id_ - kNumberOfCoreRegIds);
}
- DRegister AsDRegister() const {
+ constexpr DRegister AsDRegister() const {
CHECK(IsDRegister());
return static_cast<DRegister>(id_ - kNumberOfCoreRegIds - kNumberOfFRegIds);
}
- FRegister AsOverlappingDRegisterLow() const {
+ constexpr FRegister AsOverlappingDRegisterLow() const {
CHECK(IsOverlappingDRegister());
DRegister d_reg = AsDRegister();
return static_cast<FRegister>(d_reg * 2);
}
- FRegister AsOverlappingDRegisterHigh() const {
+ constexpr FRegister AsOverlappingDRegisterHigh() const {
CHECK(IsOverlappingDRegister());
DRegister d_reg = AsDRegister();
return static_cast<FRegister>(d_reg * 2 + 1);
}
- Register AsRegisterPairLow() const {
+ constexpr Register AsRegisterPairLow() const {
CHECK(IsRegisterPair());
// Appropriate mapping of register ids allows to use AllocIdLow().
return FromRegId(AllocIdLow()).AsCoreRegister();
}
- Register AsRegisterPairHigh() const {
+ constexpr Register AsRegisterPairHigh() const {
CHECK(IsRegisterPair());
// Appropriate mapping of register ids allows to use AllocIdHigh().
return FromRegId(AllocIdHigh()).AsCoreRegister();
}
- bool IsCoreRegister() const {
+ constexpr bool IsCoreRegister() const {
CHECK(IsValidManagedRegister());
return (0 <= id_) && (id_ < kNumberOfCoreRegIds);
}
- bool IsFRegister() const {
+ constexpr bool IsFRegister() const {
CHECK(IsValidManagedRegister());
const int test = id_ - kNumberOfCoreRegIds;
return (0 <= test) && (test < kNumberOfFRegIds);
}
- bool IsDRegister() const {
+ constexpr bool IsDRegister() const {
CHECK(IsValidManagedRegister());
const int test = id_ - (kNumberOfCoreRegIds + kNumberOfFRegIds);
return (0 <= test) && (test < kNumberOfDRegIds);
}
// Returns true if this DRegister overlaps FRegisters.
- bool IsOverlappingDRegister() const {
+ constexpr bool IsOverlappingDRegister() const {
CHECK(IsValidManagedRegister());
const int test = id_ - (kNumberOfCoreRegIds + kNumberOfFRegIds);
return (0 <= test) && (test < kNumberOfOverlappingDRegIds);
}
- bool IsRegisterPair() const {
+ constexpr bool IsRegisterPair() const {
CHECK(IsValidManagedRegister());
const int test =
id_ - (kNumberOfCoreRegIds + kNumberOfFRegIds + kNumberOfDRegIds);
@@ -164,32 +164,32 @@
// then false is returned.
bool Overlaps(const MipsManagedRegister& other) const;
- static MipsManagedRegister FromCoreRegister(Register r) {
+ static constexpr MipsManagedRegister FromCoreRegister(Register r) {
CHECK_NE(r, kNoRegister);
return FromRegId(r);
}
- static MipsManagedRegister FromFRegister(FRegister r) {
+ static constexpr MipsManagedRegister FromFRegister(FRegister r) {
CHECK_NE(r, kNoFRegister);
return FromRegId(r + kNumberOfCoreRegIds);
}
- static MipsManagedRegister FromDRegister(DRegister r) {
+ static constexpr MipsManagedRegister FromDRegister(DRegister r) {
CHECK_NE(r, kNoDRegister);
return FromRegId(r + kNumberOfCoreRegIds + kNumberOfFRegIds);
}
- static MipsManagedRegister FromRegisterPair(RegisterPair r) {
+ static constexpr MipsManagedRegister FromRegisterPair(RegisterPair r) {
CHECK_NE(r, kNoRegisterPair);
return FromRegId(r + (kNumberOfCoreRegIds + kNumberOfFRegIds + kNumberOfDRegIds));
}
private:
- bool IsValidManagedRegister() const {
+ constexpr bool IsValidManagedRegister() const {
return (0 <= id_) && (id_ < kNumberOfRegIds);
}
- int RegId() const {
+ constexpr int RegId() const {
CHECK(!IsNoRegister());
return id_;
}
@@ -205,9 +205,9 @@
friend class ManagedRegister;
- explicit MipsManagedRegister(int reg_id) : ManagedRegister(reg_id) {}
+ explicit constexpr MipsManagedRegister(int reg_id) : ManagedRegister(reg_id) {}
- static MipsManagedRegister FromRegId(int reg_id) {
+ static constexpr MipsManagedRegister FromRegId(int reg_id) {
MipsManagedRegister reg(reg_id);
CHECK(reg.IsValidManagedRegister());
return reg;
@@ -218,7 +218,7 @@
} // namespace mips
-inline mips::MipsManagedRegister ManagedRegister::AsMips() const {
+constexpr inline mips::MipsManagedRegister ManagedRegister::AsMips() const {
mips::MipsManagedRegister reg(id_);
CHECK(reg.IsNoRegister() || reg.IsValidManagedRegister());
return reg;
diff --git a/compiler/utils/mips64/assembler_mips64.cc b/compiler/utils/mips64/assembler_mips64.cc
index ab480caf..447ede5 100644
--- a/compiler/utils/mips64/assembler_mips64.cc
+++ b/compiler/utils/mips64/assembler_mips64.cc
@@ -1977,8 +1977,9 @@
constexpr size_t kFramePointerSize = 8;
-void Mips64Assembler::BuildFrame(size_t frame_size, ManagedRegister method_reg,
- const std::vector<ManagedRegister>& callee_save_regs,
+void Mips64Assembler::BuildFrame(size_t frame_size,
+ ManagedRegister method_reg,
+ ArrayRef<const ManagedRegister> callee_save_regs,
const ManagedRegisterEntrySpills& entry_spills) {
CHECK_ALIGNED(frame_size, kStackAlignment);
DCHECK(!overwriting_);
@@ -1992,7 +1993,7 @@
cfi_.RelOffset(DWARFReg(RA), stack_offset);
for (int i = callee_save_regs.size() - 1; i >= 0; --i) {
stack_offset -= kFramePointerSize;
- GpuRegister reg = callee_save_regs.at(i).AsMips64().AsGpuRegister();
+ GpuRegister reg = callee_save_regs[i].AsMips64().AsGpuRegister();
StoreToOffset(kStoreDoubleword, reg, SP, stack_offset);
cfi_.RelOffset(DWARFReg(reg), stack_offset);
}
@@ -2003,7 +2004,7 @@
// Write out entry spills.
int32_t offset = frame_size + kFramePointerSize;
for (size_t i = 0; i < entry_spills.size(); ++i) {
- Mips64ManagedRegister reg = entry_spills.at(i).AsMips64();
+ Mips64ManagedRegister reg = entry_spills[i].AsMips64();
ManagedRegisterSpill spill = entry_spills.at(i);
int32_t size = spill.getSize();
if (reg.IsNoRegister()) {
@@ -2022,7 +2023,7 @@
}
void Mips64Assembler::RemoveFrame(size_t frame_size,
- const std::vector<ManagedRegister>& callee_save_regs) {
+ ArrayRef<const ManagedRegister> callee_save_regs) {
CHECK_ALIGNED(frame_size, kStackAlignment);
DCHECK(!overwriting_);
cfi_.RememberState();
@@ -2030,7 +2031,7 @@
// Pop callee saves and return address
int stack_offset = frame_size - (callee_save_regs.size() * kFramePointerSize) - kFramePointerSize;
for (size_t i = 0; i < callee_save_regs.size(); ++i) {
- GpuRegister reg = callee_save_regs.at(i).AsMips64().AsGpuRegister();
+ GpuRegister reg = callee_save_regs[i].AsMips64().AsGpuRegister();
LoadFromOffset(kLoadDoubleword, reg, SP, stack_offset);
cfi_.Restore(DWARFReg(reg));
stack_offset += kFramePointerSize;
diff --git a/compiler/utils/mips64/assembler_mips64.h b/compiler/utils/mips64/assembler_mips64.h
index 8acc38a..0cd0708 100644
--- a/compiler/utils/mips64/assembler_mips64.h
+++ b/compiler/utils/mips64/assembler_mips64.h
@@ -365,13 +365,13 @@
//
// Emit code that will create an activation on the stack.
- void BuildFrame(size_t frame_size, ManagedRegister method_reg,
- const std::vector<ManagedRegister>& callee_save_regs,
+ void BuildFrame(size_t frame_size,
+ ManagedRegister method_reg,
+ ArrayRef<const ManagedRegister> callee_save_regs,
const ManagedRegisterEntrySpills& entry_spills) OVERRIDE;
// Emit code that will remove an activation from the stack.
- void RemoveFrame(size_t frame_size,
- const std::vector<ManagedRegister>& callee_save_regs) OVERRIDE;
+ void RemoveFrame(size_t frame_size, ArrayRef<const ManagedRegister> callee_save_regs) OVERRIDE;
void IncreaseFrameSize(size_t adjust) OVERRIDE;
void DecreaseFrameSize(size_t adjust) OVERRIDE;
diff --git a/compiler/utils/mips64/managed_register_mips64.h b/compiler/utils/mips64/managed_register_mips64.h
index 1d36128..c9f9556 100644
--- a/compiler/utils/mips64/managed_register_mips64.h
+++ b/compiler/utils/mips64/managed_register_mips64.h
@@ -39,22 +39,22 @@
// There is a one-to-one mapping between ManagedRegister and register id.
class Mips64ManagedRegister : public ManagedRegister {
public:
- GpuRegister AsGpuRegister() const {
+ constexpr GpuRegister AsGpuRegister() const {
CHECK(IsGpuRegister());
return static_cast<GpuRegister>(id_);
}
- FpuRegister AsFpuRegister() const {
+ constexpr FpuRegister AsFpuRegister() const {
CHECK(IsFpuRegister());
return static_cast<FpuRegister>(id_ - kNumberOfGpuRegIds);
}
- bool IsGpuRegister() const {
+ constexpr bool IsGpuRegister() const {
CHECK(IsValidManagedRegister());
return (0 <= id_) && (id_ < kNumberOfGpuRegIds);
}
- bool IsFpuRegister() const {
+ constexpr bool IsFpuRegister() const {
CHECK(IsValidManagedRegister());
const int test = id_ - kNumberOfGpuRegIds;
return (0 <= test) && (test < kNumberOfFpuRegIds);
@@ -67,22 +67,22 @@
// then false is returned.
bool Overlaps(const Mips64ManagedRegister& other) const;
- static Mips64ManagedRegister FromGpuRegister(GpuRegister r) {
+ static constexpr Mips64ManagedRegister FromGpuRegister(GpuRegister r) {
CHECK_NE(r, kNoGpuRegister);
return FromRegId(r);
}
- static Mips64ManagedRegister FromFpuRegister(FpuRegister r) {
+ static constexpr Mips64ManagedRegister FromFpuRegister(FpuRegister r) {
CHECK_NE(r, kNoFpuRegister);
return FromRegId(r + kNumberOfGpuRegIds);
}
private:
- bool IsValidManagedRegister() const {
+ constexpr bool IsValidManagedRegister() const {
return (0 <= id_) && (id_ < kNumberOfRegIds);
}
- int RegId() const {
+ constexpr int RegId() const {
CHECK(!IsNoRegister());
return id_;
}
@@ -98,9 +98,9 @@
friend class ManagedRegister;
- explicit Mips64ManagedRegister(int reg_id) : ManagedRegister(reg_id) {}
+ explicit constexpr Mips64ManagedRegister(int reg_id) : ManagedRegister(reg_id) {}
- static Mips64ManagedRegister FromRegId(int reg_id) {
+ static constexpr Mips64ManagedRegister FromRegId(int reg_id) {
Mips64ManagedRegister reg(reg_id);
CHECK(reg.IsValidManagedRegister());
return reg;
@@ -111,7 +111,7 @@
} // namespace mips64
-inline mips64::Mips64ManagedRegister ManagedRegister::AsMips64() const {
+constexpr inline mips64::Mips64ManagedRegister ManagedRegister::AsMips64() const {
mips64::Mips64ManagedRegister reg(id_);
CHECK(reg.IsNoRegister() || reg.IsValidManagedRegister());
return reg;
diff --git a/compiler/utils/x86/assembler_x86.cc b/compiler/utils/x86/assembler_x86.cc
index 84cdb7d..f931d75 100644
--- a/compiler/utils/x86/assembler_x86.cc
+++ b/compiler/utils/x86/assembler_x86.cc
@@ -1932,15 +1932,16 @@
constexpr size_t kFramePointerSize = 4;
-void X86Assembler::BuildFrame(size_t frame_size, ManagedRegister method_reg,
- const std::vector<ManagedRegister>& spill_regs,
+void X86Assembler::BuildFrame(size_t frame_size,
+ ManagedRegister method_reg,
+ ArrayRef<const ManagedRegister> spill_regs,
const ManagedRegisterEntrySpills& entry_spills) {
DCHECK_EQ(buffer_.Size(), 0U); // Nothing emitted yet.
cfi_.SetCurrentCFAOffset(4); // Return address on stack.
CHECK_ALIGNED(frame_size, kStackAlignment);
int gpr_count = 0;
for (int i = spill_regs.size() - 1; i >= 0; --i) {
- Register spill = spill_regs.at(i).AsX86().AsCpuRegister();
+ Register spill = spill_regs[i].AsX86().AsCpuRegister();
pushl(spill);
gpr_count++;
cfi_.AdjustCFAOffset(kFramePointerSize);
@@ -1974,7 +1975,7 @@
}
}
-void X86Assembler::RemoveFrame(size_t frame_size, const std::vector<ManagedRegister>& spill_regs) {
+void X86Assembler::RemoveFrame(size_t frame_size, ArrayRef<const ManagedRegister> spill_regs) {
CHECK_ALIGNED(frame_size, kStackAlignment);
cfi_.RememberState();
// -kFramePointerSize for ArtMethod*.
@@ -1982,7 +1983,7 @@
addl(ESP, Immediate(adjust));
cfi_.AdjustCFAOffset(-adjust);
for (size_t i = 0; i < spill_regs.size(); ++i) {
- Register spill = spill_regs.at(i).AsX86().AsCpuRegister();
+ Register spill = spill_regs[i].AsX86().AsCpuRegister();
popl(spill);
cfi_.AdjustCFAOffset(-static_cast<int>(kFramePointerSize));
cfi_.Restore(DWARFReg(spill));
diff --git a/compiler/utils/x86/assembler_x86.h b/compiler/utils/x86/assembler_x86.h
index bc46e9f..fa61662 100644
--- a/compiler/utils/x86/assembler_x86.h
+++ b/compiler/utils/x86/assembler_x86.h
@@ -633,12 +633,13 @@
//
// Emit code that will create an activation on the stack
- void BuildFrame(size_t frame_size, ManagedRegister method_reg,
- const std::vector<ManagedRegister>& callee_save_regs,
+ void BuildFrame(size_t frame_size,
+ ManagedRegister method_reg,
+ ArrayRef<const ManagedRegister> callee_save_regs,
const ManagedRegisterEntrySpills& entry_spills) OVERRIDE;
// Emit code that will remove an activation from the stack
- void RemoveFrame(size_t frame_size, const std::vector<ManagedRegister>& callee_save_regs)
+ void RemoveFrame(size_t frame_size, ArrayRef<const ManagedRegister> callee_save_regs)
OVERRIDE;
void IncreaseFrameSize(size_t adjust) OVERRIDE;
diff --git a/compiler/utils/x86/managed_register_x86.h b/compiler/utils/x86/managed_register_x86.h
index fc20d7e..c0c2b65 100644
--- a/compiler/utils/x86/managed_register_x86.h
+++ b/compiler/utils/x86/managed_register_x86.h
@@ -89,64 +89,64 @@
// There is a one-to-one mapping between ManagedRegister and register id.
class X86ManagedRegister : public ManagedRegister {
public:
- ByteRegister AsByteRegister() const {
+ constexpr ByteRegister AsByteRegister() const {
CHECK(IsCpuRegister());
CHECK_LT(AsCpuRegister(), ESP); // ESP, EBP, ESI and EDI cannot be encoded as byte registers.
return static_cast<ByteRegister>(id_);
}
- Register AsCpuRegister() const {
+ constexpr Register AsCpuRegister() const {
CHECK(IsCpuRegister());
return static_cast<Register>(id_);
}
- XmmRegister AsXmmRegister() const {
+ constexpr XmmRegister AsXmmRegister() const {
CHECK(IsXmmRegister());
return static_cast<XmmRegister>(id_ - kNumberOfCpuRegIds);
}
- X87Register AsX87Register() const {
+ constexpr X87Register AsX87Register() const {
CHECK(IsX87Register());
return static_cast<X87Register>(id_ -
(kNumberOfCpuRegIds + kNumberOfXmmRegIds));
}
- Register AsRegisterPairLow() const {
+ constexpr Register AsRegisterPairLow() const {
CHECK(IsRegisterPair());
// Appropriate mapping of register ids allows to use AllocIdLow().
return FromRegId(AllocIdLow()).AsCpuRegister();
}
- Register AsRegisterPairHigh() const {
+ constexpr Register AsRegisterPairHigh() const {
CHECK(IsRegisterPair());
// Appropriate mapping of register ids allows to use AllocIdHigh().
return FromRegId(AllocIdHigh()).AsCpuRegister();
}
- RegisterPair AsRegisterPair() const {
+ constexpr RegisterPair AsRegisterPair() const {
CHECK(IsRegisterPair());
return static_cast<RegisterPair>(id_ -
(kNumberOfCpuRegIds + kNumberOfXmmRegIds + kNumberOfX87RegIds));
}
- bool IsCpuRegister() const {
+ constexpr bool IsCpuRegister() const {
CHECK(IsValidManagedRegister());
return (0 <= id_) && (id_ < kNumberOfCpuRegIds);
}
- bool IsXmmRegister() const {
+ constexpr bool IsXmmRegister() const {
CHECK(IsValidManagedRegister());
const int test = id_ - kNumberOfCpuRegIds;
return (0 <= test) && (test < kNumberOfXmmRegIds);
}
- bool IsX87Register() const {
+ constexpr bool IsX87Register() const {
CHECK(IsValidManagedRegister());
const int test = id_ - (kNumberOfCpuRegIds + kNumberOfXmmRegIds);
return (0 <= test) && (test < kNumberOfX87RegIds);
}
- bool IsRegisterPair() const {
+ constexpr bool IsRegisterPair() const {
CHECK(IsValidManagedRegister());
const int test = id_ -
(kNumberOfCpuRegIds + kNumberOfXmmRegIds + kNumberOfX87RegIds);
@@ -160,33 +160,33 @@
// then false is returned.
bool Overlaps(const X86ManagedRegister& other) const;
- static X86ManagedRegister FromCpuRegister(Register r) {
+ static constexpr X86ManagedRegister FromCpuRegister(Register r) {
CHECK_NE(r, kNoRegister);
return FromRegId(r);
}
- static X86ManagedRegister FromXmmRegister(XmmRegister r) {
+ static constexpr X86ManagedRegister FromXmmRegister(XmmRegister r) {
CHECK_NE(r, kNoXmmRegister);
return FromRegId(r + kNumberOfCpuRegIds);
}
- static X86ManagedRegister FromX87Register(X87Register r) {
+ static constexpr X86ManagedRegister FromX87Register(X87Register r) {
CHECK_NE(r, kNoX87Register);
return FromRegId(r + kNumberOfCpuRegIds + kNumberOfXmmRegIds);
}
- static X86ManagedRegister FromRegisterPair(RegisterPair r) {
+ static constexpr X86ManagedRegister FromRegisterPair(RegisterPair r) {
CHECK_NE(r, kNoRegisterPair);
return FromRegId(r + (kNumberOfCpuRegIds + kNumberOfXmmRegIds +
kNumberOfX87RegIds));
}
private:
- bool IsValidManagedRegister() const {
+ constexpr bool IsValidManagedRegister() const {
return (0 <= id_) && (id_ < kNumberOfRegIds);
}
- int RegId() const {
+ constexpr int RegId() const {
CHECK(!IsNoRegister());
return id_;
}
@@ -202,9 +202,9 @@
friend class ManagedRegister;
- explicit X86ManagedRegister(int reg_id) : ManagedRegister(reg_id) {}
+ explicit constexpr X86ManagedRegister(int reg_id) : ManagedRegister(reg_id) {}
- static X86ManagedRegister FromRegId(int reg_id) {
+ static constexpr X86ManagedRegister FromRegId(int reg_id) {
X86ManagedRegister reg(reg_id);
CHECK(reg.IsValidManagedRegister());
return reg;
@@ -215,7 +215,7 @@
} // namespace x86
-inline x86::X86ManagedRegister ManagedRegister::AsX86() const {
+constexpr inline x86::X86ManagedRegister ManagedRegister::AsX86() const {
x86::X86ManagedRegister reg(id_);
CHECK(reg.IsNoRegister() || reg.IsValidManagedRegister());
return reg;
diff --git a/compiler/utils/x86_64/assembler_x86_64.cc b/compiler/utils/x86_64/assembler_x86_64.cc
index 5e7b587..3046710 100644
--- a/compiler/utils/x86_64/assembler_x86_64.cc
+++ b/compiler/utils/x86_64/assembler_x86_64.cc
@@ -2648,15 +2648,16 @@
constexpr size_t kFramePointerSize = 8;
-void X86_64Assembler::BuildFrame(size_t frame_size, ManagedRegister method_reg,
- const std::vector<ManagedRegister>& spill_regs,
+void X86_64Assembler::BuildFrame(size_t frame_size,
+ ManagedRegister method_reg,
+ ArrayRef<const ManagedRegister> spill_regs,
const ManagedRegisterEntrySpills& entry_spills) {
DCHECK_EQ(buffer_.Size(), 0U); // Nothing emitted yet.
cfi_.SetCurrentCFAOffset(8); // Return address on stack.
CHECK_ALIGNED(frame_size, kStackAlignment);
int gpr_count = 0;
for (int i = spill_regs.size() - 1; i >= 0; --i) {
- x86_64::X86_64ManagedRegister spill = spill_regs.at(i).AsX86_64();
+ x86_64::X86_64ManagedRegister spill = spill_regs[i].AsX86_64();
if (spill.IsCpuRegister()) {
pushq(spill.AsCpuRegister());
gpr_count++;
@@ -2674,7 +2675,7 @@
// spill xmms
int64_t offset = rest_of_frame;
for (int i = spill_regs.size() - 1; i >= 0; --i) {
- x86_64::X86_64ManagedRegister spill = spill_regs.at(i).AsX86_64();
+ x86_64::X86_64ManagedRegister spill = spill_regs[i].AsX86_64();
if (spill.IsXmmRegister()) {
offset -= sizeof(double);
movsd(Address(CpuRegister(RSP), offset), spill.AsXmmRegister());
@@ -2707,15 +2708,14 @@
}
}
-void X86_64Assembler::RemoveFrame(size_t frame_size,
- const std::vector<ManagedRegister>& spill_regs) {
+void X86_64Assembler::RemoveFrame(size_t frame_size, ArrayRef<const ManagedRegister> spill_regs) {
CHECK_ALIGNED(frame_size, kStackAlignment);
cfi_.RememberState();
int gpr_count = 0;
// unspill xmms
int64_t offset = static_cast<int64_t>(frame_size) - (spill_regs.size() * kFramePointerSize) - 2 * kFramePointerSize;
for (size_t i = 0; i < spill_regs.size(); ++i) {
- x86_64::X86_64ManagedRegister spill = spill_regs.at(i).AsX86_64();
+ x86_64::X86_64ManagedRegister spill = spill_regs[i].AsX86_64();
if (spill.IsXmmRegister()) {
offset += sizeof(double);
movsd(spill.AsXmmRegister(), Address(CpuRegister(RSP), offset));
@@ -2728,7 +2728,7 @@
addq(CpuRegister(RSP), Immediate(adjust));
cfi_.AdjustCFAOffset(-adjust);
for (size_t i = 0; i < spill_regs.size(); ++i) {
- x86_64::X86_64ManagedRegister spill = spill_regs.at(i).AsX86_64();
+ x86_64::X86_64ManagedRegister spill = spill_regs[i].AsX86_64();
if (spill.IsCpuRegister()) {
popq(spill.AsCpuRegister());
cfi_.AdjustCFAOffset(-static_cast<int>(kFramePointerSize));
diff --git a/compiler/utils/x86_64/assembler_x86_64.h b/compiler/utils/x86_64/assembler_x86_64.h
index 720a402..361f73c 100644
--- a/compiler/utils/x86_64/assembler_x86_64.h
+++ b/compiler/utils/x86_64/assembler_x86_64.h
@@ -704,12 +704,13 @@
//
// Emit code that will create an activation on the stack
- void BuildFrame(size_t frame_size, ManagedRegister method_reg,
- const std::vector<ManagedRegister>& callee_save_regs,
+ void BuildFrame(size_t frame_size,
+ ManagedRegister method_reg,
+ ArrayRef<const ManagedRegister> callee_save_regs,
const ManagedRegisterEntrySpills& entry_spills) OVERRIDE;
// Emit code that will remove an activation from the stack
- void RemoveFrame(size_t frame_size, const std::vector<ManagedRegister>& callee_save_regs)
+ void RemoveFrame(size_t frame_size, ArrayRef<const ManagedRegister> callee_save_regs)
OVERRIDE;
void IncreaseFrameSize(size_t adjust) OVERRIDE;
diff --git a/compiler/utils/x86_64/assembler_x86_64_test.cc b/compiler/utils/x86_64/assembler_x86_64_test.cc
index 9dccc9f..788c725 100644
--- a/compiler/utils/x86_64/assembler_x86_64_test.cc
+++ b/compiler/utils/x86_64/assembler_x86_64_test.cc
@@ -1498,9 +1498,11 @@
// TODO: more interesting spill registers / entry spills.
// Two random spill regs.
- std::vector<ManagedRegister> spill_regs;
- spill_regs.push_back(ManagedFromCpu(x86_64::R10));
- spill_regs.push_back(ManagedFromCpu(x86_64::RSI));
+ const ManagedRegister raw_spill_regs[] = {
+ ManagedFromCpu(x86_64::R10),
+ ManagedFromCpu(x86_64::RSI)
+ };
+ ArrayRef<const ManagedRegister> spill_regs(raw_spill_regs);
// Three random entry spills.
ManagedRegisterEntrySpills entry_spills;
@@ -1543,9 +1545,11 @@
// TODO: more interesting spill registers / entry spills.
// Two random spill regs.
- std::vector<ManagedRegister> spill_regs;
- spill_regs.push_back(ManagedFromCpu(x86_64::R10));
- spill_regs.push_back(ManagedFromCpu(x86_64::RSI));
+ const ManagedRegister raw_spill_regs[] = {
+ ManagedFromCpu(x86_64::R10),
+ ManagedFromCpu(x86_64::RSI)
+ };
+ ArrayRef<const ManagedRegister> spill_regs(raw_spill_regs);
size_t frame_size = 10 * kStackAlignment;
assembler->RemoveFrame(10 * kStackAlignment, spill_regs);
diff --git a/compiler/utils/x86_64/constants_x86_64.h b/compiler/utils/x86_64/constants_x86_64.h
index 0c782d4..37db6b1 100644
--- a/compiler/utils/x86_64/constants_x86_64.h
+++ b/compiler/utils/x86_64/constants_x86_64.h
@@ -29,15 +29,15 @@
class CpuRegister {
public:
- explicit CpuRegister(Register r) : reg_(r) {}
- explicit CpuRegister(int r) : reg_(Register(r)) {}
- Register AsRegister() const {
+ explicit constexpr CpuRegister(Register r) : reg_(r) {}
+ explicit constexpr CpuRegister(int r) : reg_(Register(r)) {}
+ constexpr Register AsRegister() const {
return reg_;
}
- uint8_t LowBits() const {
+ constexpr uint8_t LowBits() const {
return reg_ & 7;
}
- bool NeedsRex() const {
+ constexpr bool NeedsRex() const {
return reg_ > 7;
}
private:
@@ -47,15 +47,15 @@
class XmmRegister {
public:
- explicit XmmRegister(FloatRegister r) : reg_(r) {}
- explicit XmmRegister(int r) : reg_(FloatRegister(r)) {}
- FloatRegister AsFloatRegister() const {
+ explicit constexpr XmmRegister(FloatRegister r) : reg_(r) {}
+ explicit constexpr XmmRegister(int r) : reg_(FloatRegister(r)) {}
+ constexpr FloatRegister AsFloatRegister() const {
return reg_;
}
- uint8_t LowBits() const {
+ constexpr uint8_t LowBits() const {
return reg_ & 7;
}
- bool NeedsRex() const {
+ constexpr bool NeedsRex() const {
return reg_ > 7;
}
private:
diff --git a/compiler/utils/x86_64/managed_register_x86_64.h b/compiler/utils/x86_64/managed_register_x86_64.h
index c4228c1..32af672 100644
--- a/compiler/utils/x86_64/managed_register_x86_64.h
+++ b/compiler/utils/x86_64/managed_register_x86_64.h
@@ -88,52 +88,52 @@
// There is a one-to-one mapping between ManagedRegister and register id.
class X86_64ManagedRegister : public ManagedRegister {
public:
- CpuRegister AsCpuRegister() const {
+ constexpr CpuRegister AsCpuRegister() const {
CHECK(IsCpuRegister());
return CpuRegister(static_cast<Register>(id_));
}
- XmmRegister AsXmmRegister() const {
+ constexpr XmmRegister AsXmmRegister() const {
CHECK(IsXmmRegister());
return XmmRegister(static_cast<FloatRegister>(id_ - kNumberOfCpuRegIds));
}
- X87Register AsX87Register() const {
+ constexpr X87Register AsX87Register() const {
CHECK(IsX87Register());
return static_cast<X87Register>(id_ -
(kNumberOfCpuRegIds + kNumberOfXmmRegIds));
}
- CpuRegister AsRegisterPairLow() const {
+ constexpr CpuRegister AsRegisterPairLow() const {
CHECK(IsRegisterPair());
// Appropriate mapping of register ids allows to use AllocIdLow().
return FromRegId(AllocIdLow()).AsCpuRegister();
}
- CpuRegister AsRegisterPairHigh() const {
+ constexpr CpuRegister AsRegisterPairHigh() const {
CHECK(IsRegisterPair());
// Appropriate mapping of register ids allows to use AllocIdHigh().
return FromRegId(AllocIdHigh()).AsCpuRegister();
}
- bool IsCpuRegister() const {
+ constexpr bool IsCpuRegister() const {
CHECK(IsValidManagedRegister());
return (0 <= id_) && (id_ < kNumberOfCpuRegIds);
}
- bool IsXmmRegister() const {
+ constexpr bool IsXmmRegister() const {
CHECK(IsValidManagedRegister());
const int test = id_ - kNumberOfCpuRegIds;
return (0 <= test) && (test < kNumberOfXmmRegIds);
}
- bool IsX87Register() const {
+ constexpr bool IsX87Register() const {
CHECK(IsValidManagedRegister());
const int test = id_ - (kNumberOfCpuRegIds + kNumberOfXmmRegIds);
return (0 <= test) && (test < kNumberOfX87RegIds);
}
- bool IsRegisterPair() const {
+ constexpr bool IsRegisterPair() const {
CHECK(IsValidManagedRegister());
const int test = id_ -
(kNumberOfCpuRegIds + kNumberOfXmmRegIds + kNumberOfX87RegIds);
@@ -147,32 +147,32 @@
// then false is returned.
bool Overlaps(const X86_64ManagedRegister& other) const;
- static X86_64ManagedRegister FromCpuRegister(Register r) {
+ static constexpr X86_64ManagedRegister FromCpuRegister(Register r) {
CHECK_NE(r, kNoRegister);
return FromRegId(r);
}
- static X86_64ManagedRegister FromXmmRegister(FloatRegister r) {
+ static constexpr X86_64ManagedRegister FromXmmRegister(FloatRegister r) {
return FromRegId(r + kNumberOfCpuRegIds);
}
- static X86_64ManagedRegister FromX87Register(X87Register r) {
+ static constexpr X86_64ManagedRegister FromX87Register(X87Register r) {
CHECK_NE(r, kNoX87Register);
return FromRegId(r + kNumberOfCpuRegIds + kNumberOfXmmRegIds);
}
- static X86_64ManagedRegister FromRegisterPair(RegisterPair r) {
+ static constexpr X86_64ManagedRegister FromRegisterPair(RegisterPair r) {
CHECK_NE(r, kNoRegisterPair);
return FromRegId(r + (kNumberOfCpuRegIds + kNumberOfXmmRegIds +
kNumberOfX87RegIds));
}
private:
- bool IsValidManagedRegister() const {
+ constexpr bool IsValidManagedRegister() const {
return (0 <= id_) && (id_ < kNumberOfRegIds);
}
- int RegId() const {
+ constexpr int RegId() const {
CHECK(!IsNoRegister());
return id_;
}
@@ -188,9 +188,9 @@
friend class ManagedRegister;
- explicit X86_64ManagedRegister(int reg_id) : ManagedRegister(reg_id) {}
+ explicit constexpr X86_64ManagedRegister(int reg_id) : ManagedRegister(reg_id) {}
- static X86_64ManagedRegister FromRegId(int reg_id) {
+ static constexpr X86_64ManagedRegister FromRegId(int reg_id) {
X86_64ManagedRegister reg(reg_id);
CHECK(reg.IsValidManagedRegister());
return reg;
@@ -201,7 +201,7 @@
} // namespace x86_64
-inline x86_64::X86_64ManagedRegister ManagedRegister::AsX86_64() const {
+constexpr inline x86_64::X86_64ManagedRegister ManagedRegister::AsX86_64() const {
x86_64::X86_64ManagedRegister reg(id_);
CHECK(reg.IsNoRegister() || reg.IsValidManagedRegister());
return reg;
diff --git a/runtime/base/logging.h b/runtime/base/logging.h
index 3b5b8b5..e9e97b8 100644
--- a/runtime/base/logging.h
+++ b/runtime/base/logging.h
@@ -198,14 +198,14 @@
// types of LHS and RHS.
template <typename LHS, typename RHS>
struct EagerEvaluator {
- EagerEvaluator(LHS l, RHS r) : lhs(l), rhs(r) { }
+ constexpr EagerEvaluator(LHS l, RHS r) : lhs(l), rhs(r) { }
LHS lhs;
RHS rhs;
};
// Helper function for CHECK_xx.
template <typename LHS, typename RHS>
-static inline EagerEvaluator<LHS, RHS> MakeEagerEvaluator(LHS lhs, RHS rhs) {
+static inline constexpr EagerEvaluator<LHS, RHS> MakeEagerEvaluator(LHS lhs, RHS rhs) {
return EagerEvaluator<LHS, RHS>(lhs, rhs);
}
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 1835c72..8fcb6b2 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -5316,6 +5316,19 @@
const DexFile::ClassDef& class_def = dex_file.GetClassDef(klass->GetDexClassDefIndex());
uint16_t super_class_idx = class_def.superclass_idx_;
if (super_class_idx != DexFile::kDexNoIndex16) {
+ // Check that a class does not inherit from itself directly.
+ //
+ // TODO: This is a cheap check to detect the straightforward case
+ // of a class extending itself (b/28685551), but we should do a
+ // proper cycle detection on loaded classes, to detect all cases
+ // of class circularity errors (b/28830038).
+ if (super_class_idx == class_def.class_idx_) {
+ ThrowClassCircularityError(klass.Get(),
+ "Class %s extends itself",
+ PrettyDescriptor(klass.Get()).c_str());
+ return false;
+ }
+
mirror::Class* super_class = ResolveType(dex_file, super_class_idx, klass.Get());
if (super_class == nullptr) {
DCHECK(Thread::Current()->IsExceptionPending());
diff --git a/runtime/common_throws.cc b/runtime/common_throws.cc
index f8e32c4..75cce42 100644
--- a/runtime/common_throws.cc
+++ b/runtime/common_throws.cc
@@ -137,6 +137,13 @@
ThrowException("Ljava/lang/ClassCircularityError;", c, msg.str().c_str());
}
+void ThrowClassCircularityError(mirror::Class* c, const char* fmt, ...) {
+ va_list args;
+ va_start(args, fmt);
+ ThrowException("Ljava/lang/ClassCircularityError;", c, fmt, &args);
+ va_end(args);
+}
+
// ClassFormatError
void ThrowClassFormatError(mirror::Class* referrer, const char* fmt, ...) {
diff --git a/runtime/common_throws.h b/runtime/common_throws.h
index 39c4e52..c3a1f09 100644
--- a/runtime/common_throws.h
+++ b/runtime/common_throws.h
@@ -58,6 +58,9 @@
void ThrowClassCircularityError(mirror::Class* c)
SHARED_REQUIRES(Locks::mutator_lock_) COLD_ATTR;
+void ThrowClassCircularityError(mirror::Class* c, const char* fmt, ...)
+ SHARED_REQUIRES(Locks::mutator_lock_) COLD_ATTR;
+
// ClassCastException
void ThrowClassCastException(mirror::Class* dest_type, mirror::Class* src_type)
diff --git a/runtime/interpreter/interpreter.cc b/runtime/interpreter/interpreter.cc
index 74a0ab6..1d0e600 100644
--- a/runtime/interpreter/interpreter.cc
+++ b/runtime/interpreter/interpreter.cc
@@ -484,43 +484,6 @@
self->PopShadowFrame();
}
-static bool IsStringInit(Thread* self,
- const Instruction* instr,
- ArtMethod* caller,
- ArtMethod* callee)
- SHARED_REQUIRES(Locks::mutator_lock_) {
- if (instr->Opcode() == Instruction::INVOKE_DIRECT ||
- instr->Opcode() == Instruction::INVOKE_DIRECT_RANGE) {
- if (callee == nullptr) {
- // Don't know the callee. Resolve and find out.
- uint16_t callee_method_idx = (instr->Opcode() == Instruction::INVOKE_DIRECT_RANGE) ?
- instr->VRegB_3rc() : instr->VRegB_35c();
- ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
- // We just returned from callee, the method should resolve.
- // If it's a String constructor, the resolved method should not be null.
- callee = class_linker->ResolveMethod<ClassLinker::kNoICCECheckForCache>(
- self, callee_method_idx, caller, kDirect);
- }
- if (callee == nullptr) {
- // In case null is returned from method resolution, just return false
- // since a string init (just called) must not resolve to null.
- return false;
- }
- if (callee->GetDeclaringClass()->IsStringClass() &&
- callee->IsConstructor()) {
- return true;
- }
- }
- return false;
-}
-
-static int16_t GetReceiverRegisterForStringInit(const Instruction* instr) {
- DCHECK(instr->Opcode() == Instruction::INVOKE_DIRECT_RANGE ||
- instr->Opcode() == Instruction::INVOKE_DIRECT);
- return (instr->Opcode() == Instruction::INVOKE_DIRECT_RANGE) ?
- instr->VRegC_3rc() : instr->VRegC_35c();
-}
-
void EnterInterpreterFromDeoptimize(Thread* self,
ShadowFrame* shadow_frame,
bool from_code,
@@ -531,7 +494,6 @@
value.SetJ(ret_val->GetJ());
// Are we executing the first shadow frame?
bool first = true;
- ArtMethod* callee_method = nullptr;
while (shadow_frame != nullptr) {
// We do not want to recover lock state for lock counting when deoptimizing. Currently,
// the compiler should not have compiled a method that failed structured-locking checks.
@@ -557,13 +519,6 @@
// TODO: should be tested more once b/17586779 is fixed.
const Instruction* instr = Instruction::At(&code_item->insns_[dex_pc]);
if (instr->IsInvoke()) {
- if (IsStringInit(self, instr, shadow_frame->GetMethod(), callee_method)) {
- uint16_t this_obj_vreg = GetReceiverRegisterForStringInit(instr);
- // Move the StringFactory.newStringFromChars() result into the register representing
- // "this object" when invoking the string constructor in the original dex instruction.
- // Also move the result into all aliases.
- SetStringInitValueToAllAliases(shadow_frame, this_obj_vreg, value);
- }
new_dex_pc = dex_pc + instr->SizeInCodeUnits();
} else if (instr->Opcode() == Instruction::NEW_INSTANCE) {
// It's possible to deoptimize at a NEW_INSTANCE dex instruciton that's for a
@@ -574,14 +529,12 @@
instr->VRegB_21c(), shadow_frame->GetMethod());
DCHECK(klass->IsStringClass());
}
- // Move the StringFactory.newEmptyString() result into the destination register.
- shadow_frame->SetVRegReference(instr->VRegA_21c(), value.GetL());
// Skip the dex instruction since we essentially come back from an invocation.
new_dex_pc = dex_pc + instr->SizeInCodeUnits();
} else {
- CHECK(false) << "Unexpected instruction opcode " << instr->Opcode()
- << " at dex_pc " << dex_pc
- << " of method: " << PrettyMethod(shadow_frame->GetMethod(), false);
+ DCHECK(false) << "Unexpected instruction opcode " << instr->Opcode()
+ << " at dex_pc " << dex_pc
+ << " of method: " << PrettyMethod(shadow_frame->GetMethod(), false);
}
} else {
// Nothing to do, the dex_pc is the one at which the code requested
@@ -591,7 +544,6 @@
shadow_frame->SetDexPC(new_dex_pc);
value = Execute(self, code_item, *shadow_frame, value);
}
- callee_method = shadow_frame->GetMethod();
ShadowFrame* old_frame = shadow_frame;
shadow_frame = shadow_frame->GetLink();
ShadowFrame::DeleteDeoptimizedFrame(old_frame);
diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc
index 53d5e43..12d70c5 100644
--- a/runtime/interpreter/interpreter_common.cc
+++ b/runtime/interpreter/interpreter_common.cc
@@ -540,30 +540,6 @@
result, method->GetInterfaceMethodIfProxy(sizeof(void*))->GetShorty());
}
-void SetStringInitValueToAllAliases(ShadowFrame* shadow_frame,
- uint16_t this_obj_vreg,
- JValue result)
- SHARED_REQUIRES(Locks::mutator_lock_) {
- Object* existing = shadow_frame->GetVRegReference(this_obj_vreg);
- if (existing == nullptr) {
- // If it's null, we come from compiled code that was deoptimized. Nothing to do,
- // as the compiler verified there was no alias.
- // Set the new string result of the StringFactory.
- shadow_frame->SetVRegReference(this_obj_vreg, result.GetL());
- return;
- }
- // Set the string init result into all aliases.
- for (uint32_t i = 0, e = shadow_frame->NumberOfVRegs(); i < e; ++i) {
- if (shadow_frame->GetVRegReference(i) == existing) {
- DCHECK_EQ(shadow_frame->GetVRegReference(i),
- reinterpret_cast<mirror::Object*>(shadow_frame->GetVReg(i)));
- shadow_frame->SetVRegReference(i, result.GetL());
- DCHECK_EQ(shadow_frame->GetVRegReference(i),
- reinterpret_cast<mirror::Object*>(shadow_frame->GetVReg(i)));
- }
- }
-}
-
template <bool is_range,
bool do_assignability_check,
size_t kVarArgMax>
@@ -763,7 +739,24 @@
}
if (string_init && !self->IsExceptionPending()) {
- SetStringInitValueToAllAliases(&shadow_frame, string_init_vreg_this, *result);
+ mirror::Object* existing = shadow_frame.GetVRegReference(string_init_vreg_this);
+ if (existing == nullptr) {
+ // If it's null, we come from compiled code that was deoptimized. Nothing to do,
+ // as the compiler verified there was no alias.
+ // Set the new string result of the StringFactory.
+ shadow_frame.SetVRegReference(string_init_vreg_this, result->GetL());
+ } else {
+ // Replace the fake string that was allocated with the StringFactory result.
+ for (uint32_t i = 0; i < shadow_frame.NumberOfVRegs(); ++i) {
+ if (shadow_frame.GetVRegReference(i) == existing) {
+ DCHECK_EQ(shadow_frame.GetVRegReference(i),
+ reinterpret_cast<mirror::Object*>(shadow_frame.GetVReg(i)));
+ shadow_frame.SetVRegReference(i, result->GetL());
+ DCHECK_EQ(shadow_frame.GetVRegReference(i),
+ reinterpret_cast<mirror::Object*>(shadow_frame.GetVReg(i)));
+ }
+ }
+ }
}
return !self->IsExceptionPending();
diff --git a/runtime/interpreter/interpreter_common.h b/runtime/interpreter/interpreter_common.h
index cc470f3..69376fd 100644
--- a/runtime/interpreter/interpreter_common.h
+++ b/runtime/interpreter/interpreter_common.h
@@ -1021,12 +1021,6 @@
ShadowFrame* shadow_frame,
JValue* result);
-// Set string value created from StringFactory.newStringFromXXX() into all aliases of
-// StringFactory.newEmptyString().
-void SetStringInitValueToAllAliases(ShadowFrame* shadow_frame,
- uint16_t this_obj_vreg,
- JValue result);
-
// Explicitly instantiate all DoInvoke functions.
#define EXPLICIT_DO_INVOKE_TEMPLATE_DECL(_type, _is_range, _do_check) \
template SHARED_REQUIRES(Locks::mutator_lock_) \
diff --git a/runtime/jit/profile_saver.cc b/runtime/jit/profile_saver.cc
index 8358ce3..6085783 100644
--- a/runtime/jit/profile_saver.cc
+++ b/runtime/jit/profile_saver.cc
@@ -97,7 +97,15 @@
// classes save (unless they started before the initial saving was done).
{
MutexLock mu(self, wait_lock_);
- period_condition_.TimedWait(self, kSaveResolvedClassesDelayMs, 0);
+ constexpr uint64_t kSleepTime = kSaveResolvedClassesDelayMs;
+ const uint64_t end_time = NanoTime() + MsToNs(kSleepTime);
+ while (true) {
+ const uint64_t current_time = NanoTime();
+ if (current_time >= end_time) {
+ break;
+ }
+ period_condition_.TimedWait(self, NsToMs(end_time - current_time), 0);
+ }
total_ms_of_sleep_ += kSaveResolvedClassesDelayMs;
}
FetchAndCacheResolvedClasses();
diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc
index ae84019..c33a9cd 100644
--- a/runtime/oat_file.cc
+++ b/runtime/oat_file.cc
@@ -98,6 +98,8 @@
virtual const uint8_t* FindDynamicSymbolAddress(const std::string& symbol_name,
std::string* error_msg) const = 0;
+ virtual void PreLoad() = 0;
+
virtual bool Load(const std::string& elf_filename,
uint8_t* oat_file_begin,
bool writable,
@@ -138,6 +140,9 @@
const char* abs_dex_location,
std::string* error_msg) {
std::unique_ptr<OatFileBase> ret(new kOatFileBaseSubType(location, executable));
+
+ ret->PreLoad();
+
if (!ret->Load(elf_filename,
oat_file_begin,
writable,
@@ -150,6 +155,7 @@
if (!ret->ComputeFields(requested_base, elf_filename, error_msg)) {
return nullptr;
}
+
ret->PreSetup(elf_filename);
if (!ret->Setup(abs_dex_location, error_msg)) {
@@ -509,6 +515,7 @@
DlOpenOatFile(const std::string& filename, bool executable)
: OatFileBase(filename, executable),
dlopen_handle_(nullptr),
+ shared_objects_before_(0),
first_oat_(RegisterOatFileLocation(filename)) {
}
@@ -530,6 +537,8 @@
return ptr;
}
+ void PreLoad() OVERRIDE;
+
bool Load(const std::string& elf_filename,
uint8_t* oat_file_begin,
bool writable,
@@ -551,12 +560,38 @@
// Dummy memory map objects corresponding to the regions mapped by dlopen.
std::vector<std::unique_ptr<MemMap>> dlopen_mmaps_;
+ // The number of shared objects the linker told us about before loading. Used to
+ // (optimistically) optimize the PreSetup stage (see comment there).
+ size_t shared_objects_before_;
+
// Track the registration status (= was this the first oat file) for the location.
const bool first_oat_;
DISALLOW_COPY_AND_ASSIGN(DlOpenOatFile);
};
+void DlOpenOatFile::PreLoad() {
+#ifdef __APPLE__
+ UNUSED(shared_objects_before_);
+ LOG(FATAL) << "Should not reach here.";
+ UNREACHABLE();
+#else
+ // Count the entries in dl_iterate_phdr we get at this point in time.
+ struct dl_iterate_context {
+ static int callback(struct dl_phdr_info *info ATTRIBUTE_UNUSED,
+ size_t size ATTRIBUTE_UNUSED,
+ void *data) {
+ reinterpret_cast<dl_iterate_context*>(data)->count++;
+ return 0; // Continue iteration.
+ }
+ size_t count = 0;
+ } context;
+
+ dl_iterate_phdr(dl_iterate_context::callback, &context);
+ shared_objects_before_ = context.count;
+#endif
+}
+
bool DlOpenOatFile::Load(const std::string& elf_filename,
uint8_t* oat_file_begin,
bool writable,
@@ -657,6 +692,14 @@
struct dl_iterate_context {
static int callback(struct dl_phdr_info *info, size_t /* size */, void *data) {
auto* context = reinterpret_cast<dl_iterate_context*>(data);
+ context->shared_objects_seen++;
+ if (context->shared_objects_seen < context->shared_objects_before) {
+ // We haven't been called yet for anything we haven't seen before. Just continue.
+ // Note: this is aggressively optimistic. If another thread was unloading a library,
+ // we may miss out here. However, this does not happen often in practice.
+ return 0;
+ }
+
// See whether this callback corresponds to the file which we have just loaded.
bool contains_begin = false;
for (int i = 0; i < info->dlpi_phnum; i++) {
@@ -687,11 +730,22 @@
}
const uint8_t* const begin_;
std::vector<std::unique_ptr<MemMap>>* const dlopen_mmaps_;
- } context = { Begin(), &dlopen_mmaps_ };
+ const size_t shared_objects_before;
+ size_t shared_objects_seen;
+ };
+ dl_iterate_context context = { Begin(), &dlopen_mmaps_, shared_objects_before_, 0};
if (dl_iterate_phdr(dl_iterate_context::callback, &context) == 0) {
- PrintFileToLog("/proc/self/maps", LogSeverity::WARNING);
- LOG(ERROR) << "File " << elf_filename << " loaded with dlopen but cannot find its mmaps.";
+ // Hm. Maybe our optimization went wrong. Try another time with shared_objects_before == 0
+ // before giving up. This should be unusual.
+ VLOG(oat) << "Need a second run in PreSetup, didn't find with shared_objects_before="
+ << shared_objects_before_;
+ dl_iterate_context context0 = { Begin(), &dlopen_mmaps_, 0, 0};
+ if (dl_iterate_phdr(dl_iterate_context::callback, &context0) == 0) {
+ // OK, give up and print an error.
+ PrintFileToLog("/proc/self/maps", LogSeverity::WARNING);
+ LOG(ERROR) << "File " << elf_filename << " loaded with dlopen but cannot find its mmaps.";
+ }
}
#endif
}
@@ -728,6 +782,9 @@
return ptr;
}
+ void PreLoad() OVERRIDE {
+ }
+
bool Load(const std::string& elf_filename,
uint8_t* oat_file_begin, // Override where the file is loaded to if not null
bool writable,
diff --git a/test/082-inline-execute/src/Main.java b/test/082-inline-execute/src/Main.java
index 9aaed9d..bf561e9 100644
--- a/test/082-inline-execute/src/Main.java
+++ b/test/082-inline-execute/src/Main.java
@@ -809,6 +809,7 @@
Assert.assertEquals(Math.round(-3.0d), -3l);
Assert.assertEquals(Math.round(0.49999999999999994d), 0l);
Assert.assertEquals(Math.round(9007199254740991.0d), 9007199254740991l); // 2^53 - 1
+ Assert.assertEquals(Math.round(-9007199254740991.0d), -9007199254740991l); // -(2^53 - 1)
Assert.assertEquals(Math.round(Double.NaN), (long)+0.0d);
Assert.assertEquals(Math.round(Long.MAX_VALUE + 1.0d), Long.MAX_VALUE);
Assert.assertEquals(Math.round(Long.MIN_VALUE - 1.0d), Long.MIN_VALUE);
@@ -832,7 +833,16 @@
Assert.assertEquals(Math.round(-3.0f), -3);
// 0.4999999701976776123046875
Assert.assertEquals(Math.round(Float.intBitsToFloat(0x3EFFFFFF)), (int)+0.0f);
+ Assert.assertEquals(Math.round(8388607.0f), 8388607); // 2^23 - 1
+ Assert.assertEquals(Math.round(8388607.5f), 8388608); // 2^23 - 0.5
+ Assert.assertEquals(Math.round(8388608.0f), 8388608); // 2^23
+ Assert.assertEquals(Math.round(-8388607.0f), -8388607); // -(2^23 - 1)
+ Assert.assertEquals(Math.round(-8388607.5f), -8388607); // -(2^23 - 0.5)
+ Assert.assertEquals(Math.round(-8388608.0f), -8388608); // -2^23
Assert.assertEquals(Math.round(16777215.0f), 16777215); // 2^24 - 1
+ Assert.assertEquals(Math.round(16777216.0f), 16777216); // 2^24
+ Assert.assertEquals(Math.round(-16777215.0f), -16777215); // -(2^24 - 1)
+ Assert.assertEquals(Math.round(-16777216.0f), -16777216); // -2^24
Assert.assertEquals(Math.round(Float.NaN), (int)+0.0f);
Assert.assertEquals(Math.round(Integer.MAX_VALUE + 1.0f), Integer.MAX_VALUE);
Assert.assertEquals(Math.round(Integer.MIN_VALUE - 1.0f), Integer.MIN_VALUE);
@@ -1144,6 +1154,7 @@
Assert.assertEquals(StrictMath.round(-3.0d), -3l);
Assert.assertEquals(StrictMath.round(0.49999999999999994d), 0l);
Assert.assertEquals(StrictMath.round(9007199254740991.0d), 9007199254740991l); // 2^53 - 1
+ Assert.assertEquals(StrictMath.round(-9007199254740991.0d), -9007199254740991l); // -(2^53 - 1)
Assert.assertEquals(StrictMath.round(Double.NaN), (long)+0.0d);
Assert.assertEquals(StrictMath.round(Long.MAX_VALUE + 1.0d), Long.MAX_VALUE);
Assert.assertEquals(StrictMath.round(Long.MIN_VALUE - 1.0d), Long.MIN_VALUE);
@@ -1167,7 +1178,16 @@
Assert.assertEquals(StrictMath.round(-3.0f), -3);
// 0.4999999701976776123046875
Assert.assertEquals(StrictMath.round(Float.intBitsToFloat(0x3EFFFFFF)), (int)+0.0f);
+ Assert.assertEquals(StrictMath.round(8388607.0f), 8388607); // 2^23 - 1
+ Assert.assertEquals(StrictMath.round(8388607.5f), 8388608); // 2^23 - 0.5
+ Assert.assertEquals(StrictMath.round(8388608.0f), 8388608); // 2^23
+ Assert.assertEquals(StrictMath.round(-8388607.0f), -8388607); // -(2^23 - 1)
+ Assert.assertEquals(StrictMath.round(-8388607.5f), -8388607); // -(2^23 - 0.5)
+ Assert.assertEquals(StrictMath.round(-8388608.0f), -8388608); // -2^23
Assert.assertEquals(StrictMath.round(16777215.0f), 16777215); // 2^24 - 1
+ Assert.assertEquals(StrictMath.round(16777216.0f), 16777216); // 2^24
+ Assert.assertEquals(StrictMath.round(-16777215.0f), -16777215); // -(2^24 - 1)
+ Assert.assertEquals(StrictMath.round(-16777216.0f), -16777216); // -2^24
Assert.assertEquals(StrictMath.round(Float.NaN), (int)+0.0f);
Assert.assertEquals(StrictMath.round(Integer.MAX_VALUE + 1.0f), Integer.MAX_VALUE);
Assert.assertEquals(StrictMath.round(Integer.MIN_VALUE - 1.0f), Integer.MIN_VALUE);
diff --git a/test/597-deopt-new-string/src/Main.java b/test/597-deopt-new-string/src/Main.java
index 556ada1..1224e40 100644
--- a/test/597-deopt-new-string/src/Main.java
+++ b/test/597-deopt-new-string/src/Main.java
@@ -48,12 +48,7 @@
throw new Error();
}
char[] arr = {'a', 'b', 'c'};
- String str = new String(arr, 0, arr.length);
- if (!str.equals("abc")) {
- System.out.println("Failure! " + str);
- System.exit(0);
- }
- return str;
+ return new String(arr, 0, arr.length);
}
public void run() {
@@ -73,11 +68,7 @@
} else {
// This thread keeps doing new String() from a char array.
while (!done) {
- String str = $noinline$run0();
- if (!str.equals("abc")) {
- System.out.println("Failure! " + str);
- System.exit(0);
- }
+ $noinline$run0();
}
}
}
diff --git a/test/804-class-extends-itself/expected.txt b/test/804-class-extends-itself/expected.txt
new file mode 100644
index 0000000..b98f963
--- /dev/null
+++ b/test/804-class-extends-itself/expected.txt
@@ -0,0 +1,2 @@
+Caught ClassCircularityError
+Done!
diff --git a/test/804-class-extends-itself/info.txt b/test/804-class-extends-itself/info.txt
new file mode 100644
index 0000000..c48934c
--- /dev/null
+++ b/test/804-class-extends-itself/info.txt
@@ -0,0 +1 @@
+Exercise class linker check for classes extending themselves (b/28685551).
diff --git a/test/804-class-extends-itself/smali/Main.smali b/test/804-class-extends-itself/smali/Main.smali
new file mode 100644
index 0000000..5c349ed
--- /dev/null
+++ b/test/804-class-extends-itself/smali/Main.smali
@@ -0,0 +1,57 @@
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# We cannot implement Main in Java, as this would require to run
+# dexmerger (to merge the Dex file produced from Smali code and the
+# Dex file produced from Java code), which loops indefinitely when
+# processing class B28685551, as this class inherits from itself. As
+# a workaround, implement Main using Smali (we could also have used
+# multidex, but this requires a custom build script).
+
+.class public LMain;
+.super Ljava/lang/Object;
+
+.method public static main([Ljava/lang/String;)V
+ .registers 3
+ .param p0, "args"
+
+ invoke-static {}, LMain;->test()V
+ sget-object v0, Ljava/lang/System;->out:Ljava/io/PrintStream;
+ const-string v1, "Done!"
+ invoke-virtual {v0, v1}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V
+ return-void
+.end method
+
+.method static test()V
+ .registers 4
+
+ :try_start
+ const-string v2, "B28685551"
+ invoke-static {v2}, Ljava/lang/Class;->forName(Ljava/lang/String;)Ljava/lang/Class;
+ :try_end
+ .catch Ljava/lang/ClassCircularityError; {:try_start .. :try_end} :catch
+
+ move-result-object v0
+
+ :goto_7
+ return-void
+
+ :catch
+ move-exception v1
+ .local v1, "e":Ljava/lang/ClassCircularityError;
+ sget-object v2, Ljava/lang/System;->out:Ljava/io/PrintStream;
+ const-string v3, "Caught ClassCircularityError"
+ invoke-virtual {v2, v3}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V
+ goto :goto_7
+.end method
diff --git a/test/804-class-extends-itself/smali/b_28685551.smali b/test/804-class-extends-itself/smali/b_28685551.smali
new file mode 100644
index 0000000..d98c6e3
--- /dev/null
+++ b/test/804-class-extends-itself/smali/b_28685551.smali
@@ -0,0 +1,18 @@
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Regression test for a class inheriting from itself.
+
+.class public LB28685551;
+.super LB28685551;
diff --git a/tools/run-jdwp-tests.sh b/tools/run-jdwp-tests.sh
index b6a19b7..3e5a1c0 100755
--- a/tools/run-jdwp-tests.sh
+++ b/tools/run-jdwp-tests.sh
@@ -44,6 +44,8 @@
# By default, we run the whole JDWP test suite.
test="org.apache.harmony.jpda.tests.share.AllTests"
host="no"
+# Use JIT compiling by default.
+use_jit=true
while true; do
if [[ "$1" == "--mode=host" ]]; then
@@ -62,6 +64,11 @@
elif [[ $1 == -Ximage:* ]]; then
image="$1"
shift
+ elif [[ "$1" == "--no-jit" ]]; then
+ use_jit=false
+ # Remove the --no-jit from the arguments.
+ args=${args/$1}
+ shift
elif [[ $1 == "--debug" ]]; then
debug="yes"
# Remove the --debug from the arguments.
@@ -90,8 +97,12 @@
if [[ "$image" != "" ]]; then
vm_args="--vm-arg $image"
fi
-vm_args="$vm_args --vm-arg -Xusejit:true"
-debuggee_args="$debuggee_args -Xusejit:true"
+if $use_jit; then
+ vm_args="$vm_args --vm-arg -Xcompiler-option --vm-arg --compiler-filter=interpret-only"
+ debuggee_args="$debuggee_args -Xcompiler-option --compiler-filter=interpret-only"
+fi
+vm_args="$vm_args --vm-arg -Xusejit:$use_jit"
+debuggee_args="$debuggee_args -Xusejit:$use_jit"
if [[ $debug == "yes" ]]; then
art="$art -d"
art_debugee="$art_debugee -d"
diff --git a/tools/run-libcore-tests.sh b/tools/run-libcore-tests.sh
index 00bb3c5..d9905f3 100755
--- a/tools/run-libcore-tests.sh
+++ b/tools/run-libcore-tests.sh
@@ -43,6 +43,9 @@
emulator="yes"
fi
+# Use JIT compiling by default.
+use_jit=true
+
# Packages that currently work correctly with the expectation files.
working_packages=("dalvik.system"
"libcore.icu"
@@ -91,6 +94,11 @@
# classpath/resources differences when compiling the boot image.
vogar_args="$vogar_args --vm-arg -Ximage:/non/existent/vogar.art"
shift
+ elif [[ "$1" == "--no-jit" ]]; then
+ # Remove the --no-jit from the arguments.
+ vogar_args=${vogar_args/$1}
+ use_jit=false
+ shift
elif [[ "$1" == "--debug" ]]; then
# Remove the --debug from the arguments.
vogar_args=${vogar_args/$1}
@@ -111,7 +119,13 @@
# Use Jack with "1.8" configuration.
vogar_args="$vogar_args --toolchain jack --language JN"
+# JIT settings.
+if $use_jit; then
+ vogar_args="$vogar_args --vm-arg -Xcompiler-option --vm-arg --compiler-filter=interpret-only"
+fi
+vogar_args="$vogar_args --vm-arg -Xusejit:$use_jit"
+
# Run the tests using vogar.
echo "Running tests for the following test packages:"
echo ${working_packages[@]} | tr " " "\n"
-vogar $vogar_args --vm-arg -Xusejit:true $expectations --classpath $jsr166_test_jack --classpath $test_jack ${working_packages[@]}
+vogar $vogar_args $expectations --classpath $jsr166_test_jack --classpath $test_jack ${working_packages[@]}