jni: Add read barrier fast path to jni compiler
Static method dispatch via JNI requires a read barrier
for the ArtMethod::GetDeclaringClass() load before adding it to the
JNI StackHandleScope.
We used to call ReadBarrierJni unconditionally but add a branch
to skip calling it if the GC is not currently in the marking phase.
Test: ART_USE_READ_BARRIER=true make test-art-host test-art-target
Bug: 30437917
Change-Id: I4f505ebde17c0a67209c7bb51b3f39e37a06373a
diff --git a/compiler/utils/jni_macro_assembler.h b/compiler/utils/jni_macro_assembler.h
index 0119ae9..59a1a48 100644
--- a/compiler/utils/jni_macro_assembler.h
+++ b/compiler/utils/jni_macro_assembler.h
@@ -35,6 +35,12 @@
class DebugFrameOpCodeWriterForAssembler;
class InstructionSetFeatures;
class MemoryRegion;
+class JNIMacroLabel;
+
+enum class JNIMacroUnaryCondition {
+ kZero,
+ kNotZero
+};
template <PointerSize kPointerSize>
class JNIMacroAssembler : public DeletableArenaObject<kArenaAllocAssembler> {
@@ -193,6 +199,15 @@
// and branch to a ExceptionSlowPath if it is.
virtual void ExceptionPoll(ManagedRegister scratch, size_t stack_adjust) = 0;
+ // Create a new label that can be used with Jump/Bind calls.
+ virtual std::unique_ptr<JNIMacroLabel> CreateLabel() = 0;
+ // Emit an unconditional jump to the label.
+ virtual void Jump(JNIMacroLabel* label) = 0;
+ // Emit a conditional jump to the label by applying a unary condition test to the register.
+ virtual void Jump(JNIMacroLabel* label, JNIMacroUnaryCondition cond, ManagedRegister test) = 0;
+ // Code at this offset will serve as the target for the Jump call.
+ virtual void Bind(JNIMacroLabel* label) = 0;
+
virtual ~JNIMacroAssembler() {}
/**
@@ -205,6 +220,28 @@
explicit JNIMacroAssembler() {}
};
+// A "Label" class used with the JNIMacroAssembler
+// allowing one to use branches (jumping from one place to another).
+//
+// This is just an interface, so every platform must provide
+// its own implementation of it.
+//
+// It is only safe to use a label created
+// via JNIMacroAssembler::CreateLabel with that same macro assembler.
+class JNIMacroLabel {
+ public:
+ virtual ~JNIMacroLabel() = 0;
+
+ const InstructionSet isa_;
+ protected:
+ explicit JNIMacroLabel(InstructionSet isa) : isa_(isa) {}
+};
+
+inline JNIMacroLabel::~JNIMacroLabel() {
+ // Compulsory definition for a pure virtual destructor
+ // to avoid linking errors.
+}
+
template <typename T, PointerSize kPointerSize>
class JNIMacroAssemblerFwd : public JNIMacroAssembler<kPointerSize> {
public:
@@ -230,6 +267,30 @@
T asm_;
};
+template <typename Self, typename PlatformLabel, InstructionSet kIsa>
+class JNIMacroLabelCommon : public JNIMacroLabel {
+ public:
+ static Self* Cast(JNIMacroLabel* label) {
+ CHECK(label != nullptr);
+ CHECK_EQ(kIsa, label->isa_);
+
+ return reinterpret_cast<Self*>(label);
+ }
+
+ protected:
+ PlatformLabel* AsPlatformLabel() {
+ return &label_;
+ }
+
+ JNIMacroLabelCommon() : JNIMacroLabel(kIsa) {
+ }
+
+ virtual ~JNIMacroLabelCommon() OVERRIDE {}
+
+ private:
+ PlatformLabel label_;
+};
+
} // namespace art
#endif // ART_COMPILER_UTILS_JNI_MACRO_ASSEMBLER_H_