diff options
Diffstat (limited to 'compiler/optimizing/nodes.h')
| -rw-r--r-- | compiler/optimizing/nodes.h | 287 |
1 files changed, 222 insertions, 65 deletions
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h index 814cebb99d..0df5d6dd2e 100644 --- a/compiler/optimizing/nodes.h +++ b/compiler/optimizing/nodes.h @@ -1215,23 +1215,33 @@ class HUserRecord : public ValueObject { }; /** - * Side-effects representation for write/read dependences on fields/arrays. + * Side-effects representation. * - * The dependence analysis uses type disambiguation (e.g. a float field write - * cannot modify the value of an integer field read) and the access type (e.g. - * a reference array write cannot modify the value of a reference field read - * [although it may modify the reference fetch prior to reading the field, - * which is represented by its own write/read dependence]). The analysis - * makes conservative points-to assumptions on reference types (e.g. two same - * typed arrays are assumed to be the same, and any reference read depends - * on any reference read without further regard of its type). + * For write/read dependences on fields/arrays, the dependence analysis uses + * type disambiguation (e.g. a float field write cannot modify the value of an + * integer field read) and the access type (e.g. a reference array write cannot + * modify the value of a reference field read [although it may modify the + * reference fetch prior to reading the field, which is represented by its own + * write/read dependence]). The analysis makes conservative points-to + * assumptions on reference types (e.g. two same typed arrays are assumed to be + * the same, and any reference read depends on any reference read without + * further regard of its type). * - * The internal representation uses the following 36-bit flags assignments: + * The internal representation uses 38-bit and is described in the table below. + * The first line indicates the side effect, and for field/array accesses the + * second line indicates the type of the access (in the order of the + * Primitive::Type enum). + * The two numbered lines below indicate the bit position in the bitfield (read + * vertically). * - * |ARRAY-R |FIELD-R |ARRAY-W |FIELD-W | - * +---------+---------+---------+---------+ - * |543210987|654321098|765432109|876543210| - * |DFJISCBZL|DFJISCBZL|DFJISCBZL|DFJISCBZL| + * |Depends on GC|ARRAY-R |FIELD-R |Can trigger GC|ARRAY-W |FIELD-W | + * +-------------+---------+---------+--------------+---------+---------+ + * | |DFJISCBZL|DFJISCBZL| |DFJISCBZL|DFJISCBZL| + * | 3 |333333322|222222221| 1 |111111110|000000000| + * | 7 |654321098|765432109| 8 |765432109|876543210| + * + * Note that, to ease the implementation, 'changes' bits are least significant + * bits, while 'dependency' bits are most significant bits. */ class SideEffects : public ValueObject { public: @@ -1242,6 +1252,22 @@ class SideEffects : public ValueObject { } static SideEffects All() { + return SideEffects(kAllChangeBits | kAllDependOnBits); + } + + static SideEffects AllChanges() { + return SideEffects(kAllChangeBits); + } + + static SideEffects AllDependencies() { + return SideEffects(kAllDependOnBits); + } + + static SideEffects AllExceptGCDependency() { + return AllWritesAndReads().Union(SideEffects::CanTriggerGC()); + } + + static SideEffects AllWritesAndReads() { return SideEffects(kAllWrites | kAllReads); } @@ -1255,7 +1281,7 @@ class SideEffects : public ValueObject { static SideEffects FieldWriteOfType(Primitive::Type type, bool is_volatile) { return is_volatile - ? All() + ? AllWritesAndReads() : SideEffects(TypeFlagWithAlias(type, kFieldWriteOffset)); } @@ -1265,7 +1291,7 @@ class SideEffects : public ValueObject { static SideEffects FieldReadOfType(Primitive::Type type, bool is_volatile) { return is_volatile - ? All() + ? AllWritesAndReads() : SideEffects(TypeFlagWithAlias(type, kFieldReadOffset)); } @@ -1273,11 +1299,40 @@ class SideEffects : public ValueObject { return SideEffects(TypeFlagWithAlias(type, kArrayReadOffset)); } + static SideEffects CanTriggerGC() { + return SideEffects(1ULL << kCanTriggerGCBit); + } + + static SideEffects DependsOnGC() { + return SideEffects(1ULL << kDependsOnGCBit); + } + // Combines the side-effects of this and the other. SideEffects Union(SideEffects other) const { return SideEffects(flags_ | other.flags_); } + SideEffects Exclusion(SideEffects other) const { + return SideEffects(flags_ & ~other.flags_); + } + + bool Includes(SideEffects other) const { + return (other.flags_ & flags_) == other.flags_; + } + + bool HasSideEffects() const { + return (flags_ & kAllChangeBits); + } + + bool HasDependencies() const { + return (flags_ & kAllDependOnBits); + } + + // Returns true if there are no side effects or dependencies. + bool DoesNothing() const { + return flags_ == 0; + } + // Returns true if something is written. bool DoesAnyWrite() const { return (flags_ & kAllWrites); @@ -1288,47 +1343,81 @@ class SideEffects : public ValueObject { return (flags_ & kAllReads); } - // Returns true if nothing is written or read. - bool DoesNothing() const { - return flags_ == 0; - } - // Returns true if potentially everything is written and read // (every type and every kind of access). + bool DoesAllReadWrite() const { + return (flags_ & (kAllWrites | kAllReads)) == (kAllWrites | kAllReads); + } + bool DoesAll() const { - return flags_ == (kAllWrites | kAllReads); + return flags_ == (kAllChangeBits | kAllDependOnBits); } // Returns true if this may read something written by other. bool MayDependOn(SideEffects other) const { - const uint64_t reads = (flags_ & kAllReads) >> kFieldReadOffset; - return (other.flags_ & reads); + const uint64_t depends_on_flags = (flags_ & kAllDependOnBits) >> kChangeBits; + return (other.flags_ & depends_on_flags); } // Returns string representation of flags (for debugging only). - // Format: |DFJISCBZL|DFJISCBZL|DFJISCBZL|DFJISCBZL| + // Format: |x|DFJISCBZL|DFJISCBZL|y|DFJISCBZL|DFJISCBZL| std::string ToString() const { - static const char *kDebug = "LZBCSIJFD"; std::string flags = "|"; - for (int s = 35; s >= 0; s--) { - const int t = s % kBits; - if ((flags_ >> s) & 1) - flags += kDebug[t]; - if (t == 0) + for (int s = kLastBit; s >= 0; s--) { + bool current_bit_is_set = ((flags_ >> s) & 1) != 0; + if ((s == kDependsOnGCBit) || (s == kCanTriggerGCBit)) { + // This is a bit for the GC side effect. + if (current_bit_is_set) { + flags += "GC"; + } flags += "|"; + } else { + // This is a bit for the array/field analysis. + // The underscore character stands for the 'can trigger GC' bit. + static const char *kDebug = "LZBCSIJFDLZBCSIJFD_LZBCSIJFDLZBCSIJFD"; + if (current_bit_is_set) { + flags += kDebug[s]; + } + if ((s == kFieldWriteOffset) || (s == kArrayWriteOffset) || + (s == kFieldReadOffset) || (s == kArrayReadOffset)) { + flags += "|"; + } + } } return flags; } + bool Equals(const SideEffects& other) const { return flags_ == other.flags_; } + private: - static constexpr int kBits = 9; - static constexpr int kFieldWriteOffset = 0 * kBits; - static constexpr int kArrayWriteOffset = 1 * kBits; - static constexpr int kFieldReadOffset = 2 * kBits; - static constexpr int kArrayReadOffset = 3 * kBits; + static constexpr int kFieldArrayAnalysisBits = 9; + + static constexpr int kFieldWriteOffset = 0; + static constexpr int kArrayWriteOffset = kFieldWriteOffset + kFieldArrayAnalysisBits; + static constexpr int kLastBitForWrites = kArrayWriteOffset + kFieldArrayAnalysisBits - 1; + static constexpr int kCanTriggerGCBit = kLastBitForWrites + 1; + + static constexpr int kChangeBits = kCanTriggerGCBit + 1; - static constexpr uint64_t kAllWrites = 0x0003ffff; - static constexpr uint64_t kAllReads = kAllWrites << kFieldReadOffset; + static constexpr int kFieldReadOffset = kCanTriggerGCBit + 1; + static constexpr int kArrayReadOffset = kFieldReadOffset + kFieldArrayAnalysisBits; + static constexpr int kLastBitForReads = kArrayReadOffset + kFieldArrayAnalysisBits - 1; + static constexpr int kDependsOnGCBit = kLastBitForReads + 1; + + static constexpr int kLastBit = kDependsOnGCBit; + static constexpr int kDependOnBits = kLastBit + 1 - kChangeBits; + + // Aliases. + + static_assert(kChangeBits == kDependOnBits, + "the 'change' bits should match the 'depend on' bits."); + + static constexpr uint64_t kAllChangeBits = ((1ULL << kChangeBits) - 1); + static constexpr uint64_t kAllDependOnBits = ((1ULL << kDependOnBits) - 1) << kChangeBits; + static constexpr uint64_t kAllWrites = + ((1ULL << (kLastBitForWrites + 1 - kFieldWriteOffset)) - 1) << kFieldWriteOffset; + static constexpr uint64_t kAllReads = + ((1ULL << (kLastBitForReads + 1 - kFieldReadOffset)) - 1) << kFieldReadOffset; // Work around the fact that HIR aliases I/F and J/D. // TODO: remove this interceptor once HIR types are clean @@ -1610,6 +1699,7 @@ class HInstruction : public ArenaObject<kArenaAllocMisc> { virtual bool IsControlFlow() const { return false; } virtual bool CanThrow() const { return false; } + bool HasSideEffects() const { return side_effects_.HasSideEffects(); } bool DoesAnyWrite() const { return side_effects_.DoesAnyWrite(); } // Does not apply for all instructions, but having this at top level greatly @@ -2302,7 +2392,9 @@ class HBinaryOperation : public HExpression<2> { public: HBinaryOperation(Primitive::Type result_type, HInstruction* left, - HInstruction* right) : HExpression(result_type, SideEffects::None()) { + HInstruction* right, + SideEffects side_effects = SideEffects::None()) + : HExpression(result_type, side_effects) { SetRawInputAt(0, left); SetRawInputAt(1, right); } @@ -2626,7 +2718,9 @@ class HCompare : public HBinaryOperation { HInstruction* second, ComparisonBias bias, uint32_t dex_pc) - : HBinaryOperation(Primitive::kPrimInt, first, second), bias_(bias), dex_pc_(dex_pc) { + : HBinaryOperation(Primitive::kPrimInt, first, second, SideEffectsForArchRuntimeCalls(type)), + bias_(bias), + dex_pc_(dex_pc) { DCHECK_EQ(type, first->GetType()); DCHECK_EQ(type, second->GetType()); } @@ -2649,7 +2743,12 @@ class HCompare : public HBinaryOperation { bool IsGtBias() { return bias_ == ComparisonBias::kGtBias; } - uint32_t GetDexPc() const { return dex_pc_; } + uint32_t GetDexPc() const OVERRIDE { return dex_pc_; } + + static SideEffects SideEffectsForArchRuntimeCalls(Primitive::Type type) { + // MIPS64 uses a runtime call for FP comparisons. + return Primitive::IsFloatingPointType(type) ? SideEffects::CanTriggerGC() : SideEffects::None(); + } DECLARE_INSTRUCTION(Compare); @@ -2791,7 +2890,7 @@ class HDoubleConstant : public HConstant { }; enum class Intrinsics { -#define OPTIMIZING_INTRINSICS(Name, IsStatic) k ## Name, +#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironment) k ## Name, #include "intrinsics_list.h" kNone, INTRINSICS_LIST(OPTIMIZING_INTRINSICS) @@ -2800,13 +2899,18 @@ enum class Intrinsics { }; std::ostream& operator<<(std::ostream& os, const Intrinsics& intrinsic); +enum IntrinsicNeedsEnvironment { + kNoEnvironment, // Intrinsic does not require an environment. + kNeedsEnvironment // Intrinsic requires an environment. +}; + class HInvoke : public HInstruction { public: size_t InputCount() const OVERRIDE { return inputs_.Size(); } // Runtime needs to walk the stack, so Dex -> Dex calls need to // know their environment. - bool NeedsEnvironment() const OVERRIDE { return true; } + bool NeedsEnvironment() const OVERRIDE { return needs_environment_ == kNeedsEnvironment; } void SetArgumentAt(size_t index, HInstruction* argument) { SetRawInputAt(index, argument); @@ -2831,8 +2935,9 @@ class HInvoke : public HInstruction { return intrinsic_; } - void SetIntrinsic(Intrinsics intrinsic) { + void SetIntrinsic(Intrinsics intrinsic, IntrinsicNeedsEnvironment needs_environment) { intrinsic_ = intrinsic; + needs_environment_ = needs_environment; } bool IsFromInlinedInvoke() const { @@ -2851,14 +2956,16 @@ class HInvoke : public HInstruction { uint32_t dex_pc, uint32_t dex_method_index, InvokeType original_invoke_type) - : HInstruction(SideEffects::All()), // assume write/read on all fields/arrays + : HInstruction( + SideEffects::AllExceptGCDependency()), // Assume write/read on all fields/arrays. number_of_arguments_(number_of_arguments), inputs_(arena, number_of_arguments), return_type_(return_type), dex_pc_(dex_pc), dex_method_index_(dex_method_index), original_invoke_type_(original_invoke_type), - intrinsic_(Intrinsics::kNone) { + intrinsic_(Intrinsics::kNone), + needs_environment_(kNeedsEnvironment) { uint32_t number_of_inputs = number_of_arguments + number_of_other_inputs; inputs_.SetSize(number_of_inputs); } @@ -2875,6 +2982,7 @@ class HInvoke : public HInstruction { const uint32_t dex_method_index_; const InvokeType original_invoke_type_; Intrinsics intrinsic_; + IntrinsicNeedsEnvironment needs_environment_; private: DISALLOW_COPY_AND_ASSIGN(HInvoke); @@ -2923,6 +3031,10 @@ class HInvokeStaticOrDirect : public HInvoke { return false; } + bool CanBeNull() const OVERRIDE { + return return_type_ == Primitive::kPrimNot && !IsStringInit(); + } + InvokeType GetInvokeType() const { return invoke_type_; } bool IsRecursive() const { return is_recursive_; } bool NeedsDexCache() const OVERRIDE { return !IsRecursive(); } @@ -3068,7 +3180,7 @@ class HNewInstance : public HExpression<1> { uint16_t type_index, const DexFile& dex_file, QuickEntrypointEnum entrypoint) - : HExpression(Primitive::kPrimNot, SideEffects::None()), + : HExpression(Primitive::kPrimNot, SideEffects::CanTriggerGC()), dex_pc_(dex_pc), type_index_(type_index), dex_file_(dex_file), @@ -3105,7 +3217,7 @@ class HNewInstance : public HExpression<1> { class HNeg : public HUnaryOperation { public: - explicit HNeg(Primitive::Type result_type, HInstruction* input) + HNeg(Primitive::Type result_type, HInstruction* input) : HUnaryOperation(result_type, input) {} template <typename T> T Compute(T x) const { return -x; } @@ -3131,7 +3243,7 @@ class HNewArray : public HExpression<2> { uint16_t type_index, const DexFile& dex_file, QuickEntrypointEnum entrypoint) - : HExpression(Primitive::kPrimNot, SideEffects::None()), + : HExpression(Primitive::kPrimNot, SideEffects::CanTriggerGC()), dex_pc_(dex_pc), type_index_(type_index), dex_file_(dex_file), @@ -3232,7 +3344,8 @@ class HMul : public HBinaryOperation { class HDiv : public HBinaryOperation { public: HDiv(Primitive::Type result_type, HInstruction* left, HInstruction* right, uint32_t dex_pc) - : HBinaryOperation(result_type, left, right), dex_pc_(dex_pc) {} + : HBinaryOperation(result_type, left, right, SideEffectsForArchRuntimeCalls()), + dex_pc_(dex_pc) {} template <typename T> T Compute(T x, T y) const { @@ -3252,6 +3365,11 @@ class HDiv : public HBinaryOperation { uint32_t GetDexPc() const OVERRIDE { return dex_pc_; } + static SideEffects SideEffectsForArchRuntimeCalls() { + // The generated code can use a runtime call. + return SideEffects::CanTriggerGC(); + } + DECLARE_INSTRUCTION(Div); private: @@ -3263,7 +3381,8 @@ class HDiv : public HBinaryOperation { class HRem : public HBinaryOperation { public: HRem(Primitive::Type result_type, HInstruction* left, HInstruction* right, uint32_t dex_pc) - : HBinaryOperation(result_type, left, right), dex_pc_(dex_pc) {} + : HBinaryOperation(result_type, left, right, SideEffectsForArchRuntimeCalls()), + dex_pc_(dex_pc) {} template <typename T> T Compute(T x, T y) const { @@ -3283,6 +3402,10 @@ class HRem : public HBinaryOperation { uint32_t GetDexPc() const OVERRIDE { return dex_pc_; } + static SideEffects SideEffectsForArchRuntimeCalls() { + return SideEffects::CanTriggerGC(); + } + DECLARE_INSTRUCTION(Rem); private: @@ -3298,6 +3421,8 @@ class HDivZeroCheck : public HExpression<1> { SetRawInputAt(0, value); } + Primitive::Type GetType() const OVERRIDE { return InputAt(0)->GetType(); } + bool CanBeMoved() const OVERRIDE { return true; } bool InstructionDataEquals(HInstruction* other) const OVERRIDE { @@ -3533,7 +3658,7 @@ class HParameterValue : public HExpression<0> { class HNot : public HUnaryOperation { public: - explicit HNot(Primitive::Type result_type, HInstruction* input) + HNot(Primitive::Type result_type, HInstruction* input) : HUnaryOperation(result_type, input) {} bool CanBeMoved() const OVERRIDE { return true; } @@ -3591,7 +3716,8 @@ class HTypeConversion : public HExpression<1> { public: // Instantiate a type conversion of `input` to `result_type`. HTypeConversion(Primitive::Type result_type, HInstruction* input, uint32_t dex_pc) - : HExpression(result_type, SideEffects::None()), dex_pc_(dex_pc) { + : HExpression(result_type, SideEffectsForArchRuntimeCalls(input->GetType(), result_type)), + dex_pc_(dex_pc) { SetRawInputAt(0, input); DCHECK_NE(input->GetType(), result_type); } @@ -3611,6 +3737,18 @@ class HTypeConversion : public HExpression<1> { // containing the result. If the input cannot be converted, return nullptr. HConstant* TryStaticEvaluation() const; + static SideEffects SideEffectsForArchRuntimeCalls(Primitive::Type input_type, + Primitive::Type result_type) { + // Some architectures may not require the 'GC' side effects, but at this point + // in the compilation process we do not know what architecture we will + // generate code for, so we must be conservative. + if ((Primitive::IsFloatingPointType(input_type) && Primitive::IsIntegralType(result_type)) + || (input_type == Primitive::kPrimLong && Primitive::IsFloatingPointType(result_type))) { + return SideEffects::CanTriggerGC(); + } + return SideEffects::None(); + } + DECLARE_INSTRUCTION(TypeConversion); private: @@ -3877,7 +4015,9 @@ class HArraySet : public HTemplateInstruction<3> { HInstruction* value, Primitive::Type expected_component_type, uint32_t dex_pc) - : HTemplateInstruction(SideEffects::ArrayWriteOfType(expected_component_type)), + : HTemplateInstruction( + SideEffects::ArrayWriteOfType(expected_component_type).Union( + SideEffectsForArchRuntimeCalls(value->GetType()))), dex_pc_(dex_pc), expected_component_type_(expected_component_type), needs_type_check_(value->GetType() == Primitive::kPrimNot), @@ -3930,6 +4070,10 @@ class HArraySet : public HTemplateInstruction<3> { : expected_component_type_; } + static SideEffects SideEffectsForArchRuntimeCalls(Primitive::Type value_type) { + return (value_type == Primitive::kPrimNot) ? SideEffects::CanTriggerGC() : SideEffects::None(); + } + DECLARE_INSTRUCTION(ArraySet); private: @@ -4024,7 +4168,7 @@ class HTemporary : public HTemplateInstruction<0> { class HSuspendCheck : public HTemplateInstruction<0> { public: explicit HSuspendCheck(uint32_t dex_pc) - : HTemplateInstruction(SideEffects::None()), dex_pc_(dex_pc), slow_path_(nullptr) {} + : HTemplateInstruction(SideEffects::CanTriggerGC()), dex_pc_(dex_pc), slow_path_(nullptr) {} bool NeedsEnvironment() const OVERRIDE { return true; @@ -4056,7 +4200,7 @@ class HLoadClass : public HExpression<1> { const DexFile& dex_file, bool is_referrers_class, uint32_t dex_pc) - : HExpression(Primitive::kPrimNot, SideEffects::None()), + : HExpression(Primitive::kPrimNot, SideEffectsForArchRuntimeCalls()), type_index_(type_index), dex_file_(dex_file), is_referrers_class_(is_referrers_class), @@ -4117,6 +4261,10 @@ class HLoadClass : public HExpression<1> { bool NeedsDexCache() const OVERRIDE { return !is_referrers_class_; } + static SideEffects SideEffectsForArchRuntimeCalls() { + return SideEffects::CanTriggerGC(); + } + DECLARE_INSTRUCTION(LoadClass); private: @@ -4136,7 +4284,7 @@ class HLoadClass : public HExpression<1> { class HLoadString : public HExpression<1> { public: HLoadString(HCurrentMethod* current_method, uint32_t string_index, uint32_t dex_pc) - : HExpression(Primitive::kPrimNot, SideEffects::None()), + : HExpression(Primitive::kPrimNot, SideEffectsForArchRuntimeCalls()), string_index_(string_index), dex_pc_(dex_pc) { SetRawInputAt(0, current_method); @@ -4157,6 +4305,10 @@ class HLoadString : public HExpression<1> { bool NeedsEnvironment() const OVERRIDE { return false; } bool NeedsDexCache() const OVERRIDE { return true; } + static SideEffects SideEffectsForArchRuntimeCalls() { + return SideEffects::CanTriggerGC(); + } + DECLARE_INSTRUCTION(LoadString); private: @@ -4171,10 +4323,10 @@ class HLoadString : public HExpression<1> { */ class HClinitCheck : public HExpression<1> { public: - explicit HClinitCheck(HLoadClass* constant, uint32_t dex_pc) + HClinitCheck(HLoadClass* constant, uint32_t dex_pc) : HExpression( - Primitive::kPrimNot, - SideEffects::AllWrites()), // assume write on all fields/arrays + Primitive::kPrimNot, + SideEffects::AllChanges()), // Assume write/read on all fields/arrays. dex_pc_(dex_pc) { SetRawInputAt(0, constant); } @@ -4303,7 +4455,7 @@ class HClearException : public HTemplateInstruction<0> { class HThrow : public HTemplateInstruction<1> { public: HThrow(HInstruction* exception, uint32_t dex_pc) - : HTemplateInstruction(SideEffects::None()), dex_pc_(dex_pc) { + : HTemplateInstruction(SideEffects::CanTriggerGC()), dex_pc_(dex_pc) { SetRawInputAt(0, exception); } @@ -4329,7 +4481,7 @@ class HInstanceOf : public HExpression<2> { HLoadClass* constant, bool class_is_final, uint32_t dex_pc) - : HExpression(Primitive::kPrimBoolean, SideEffects::None()), + : HExpression(Primitive::kPrimBoolean, SideEffectsForArchRuntimeCalls(class_is_final)), class_is_final_(class_is_final), must_do_null_check_(true), dex_pc_(dex_pc) { @@ -4355,6 +4507,10 @@ class HInstanceOf : public HExpression<2> { bool MustDoNullCheck() const { return must_do_null_check_; } void ClearMustDoNullCheck() { must_do_null_check_ = false; } + static SideEffects SideEffectsForArchRuntimeCalls(bool class_is_final) { + return class_is_final ? SideEffects::None() : SideEffects::CanTriggerGC(); + } + DECLARE_INSTRUCTION(InstanceOf); private: @@ -4414,7 +4570,7 @@ class HCheckCast : public HTemplateInstruction<2> { HLoadClass* constant, bool class_is_final, uint32_t dex_pc) - : HTemplateInstruction(SideEffects::None()), + : HTemplateInstruction(SideEffects::CanTriggerGC()), class_is_final_(class_is_final), must_do_null_check_(true), dex_pc_(dex_pc) { @@ -4456,7 +4612,7 @@ class HMemoryBarrier : public HTemplateInstruction<0> { public: explicit HMemoryBarrier(MemBarrierKind barrier_kind) : HTemplateInstruction( - SideEffects::All()), // assume write/read on all fields/arrays + SideEffects::AllWritesAndReads()), // Assume write/read on all fields/arrays. barrier_kind_(barrier_kind) {} MemBarrierKind GetBarrierKind() { return barrier_kind_; } @@ -4477,7 +4633,8 @@ class HMonitorOperation : public HTemplateInstruction<1> { }; HMonitorOperation(HInstruction* object, OperationKind kind, uint32_t dex_pc) - : HTemplateInstruction(SideEffects::All()), // assume write/read on all fields/arrays + : HTemplateInstruction( + SideEffects::AllExceptGCDependency()), // Assume write/read on all fields/arrays. kind_(kind), dex_pc_(dex_pc) { SetRawInputAt(0, object); } |