diff options
Diffstat (limited to 'compiler/optimizing/nodes.h')
-rw-r--r-- | compiler/optimizing/nodes.h | 73 |
1 files changed, 69 insertions, 4 deletions
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h index cbb55918cf..f33b0d8e96 100644 --- a/compiler/optimizing/nodes.h +++ b/compiler/optimizing/nodes.h @@ -6403,6 +6403,27 @@ class HPredicatedInstanceFieldGet final : public HExpression<2> { const FieldInfo field_info_; }; +enum class WriteBarrierKind { + // Emit the write barrier, with a runtime optimization which checks if the value that it is being + // set is null. + kEmitWithNullCheck, + // Emit the write barrier, without the runtime null check optimization. This could be set because: + // A) It is a write barrier for an ArraySet (which does the optimization with the type check, so + // it never does the optimization at the write barrier stage) + // B) We know that the input can't be null + // C) This write barrier is actually several write barriers coalesced into one. Potentially we + // could ask if every value is null for a runtime optimization at the cost of compile time / code + // size. At the time of writing it was deemed not worth the effort. + kEmitNoNullCheck, + // Skip emitting the write barrier. This could be set because: + // A) The write barrier is not needed (e.g. it is not a reference, or the value is the null + // constant) + // B) This write barrier was coalesced into another one so there's no need to emit it. + kDontEmit, + kLast = kDontEmit +}; +std::ostream& operator<<(std::ostream& os, WriteBarrierKind rhs); + class HInstanceFieldSet final : public HExpression<2> { public: HInstanceFieldSet(HInstruction* object, @@ -6427,6 +6448,7 @@ class HInstanceFieldSet final : public HExpression<2> { dex_file) { SetPackedFlag<kFlagValueCanBeNull>(true); SetPackedFlag<kFlagIsPredicatedSet>(false); + SetPackedField<WriteBarrierKindField>(WriteBarrierKind::kEmitWithNullCheck); SetRawInputAt(0, object); SetRawInputAt(1, value); } @@ -6447,6 +6469,12 @@ class HInstanceFieldSet final : public HExpression<2> { void ClearValueCanBeNull() { SetPackedFlag<kFlagValueCanBeNull>(false); } bool GetIsPredicatedSet() const { return GetPackedFlag<kFlagIsPredicatedSet>(); } void SetIsPredicatedSet(bool value = true) { SetPackedFlag<kFlagIsPredicatedSet>(value); } + WriteBarrierKind GetWriteBarrierKind() { return GetPackedField<WriteBarrierKindField>(); } + void SetWriteBarrierKind(WriteBarrierKind kind) { + DCHECK(kind != WriteBarrierKind::kEmitWithNullCheck) + << "We shouldn't go back to the original value."; + SetPackedField<WriteBarrierKindField>(kind); + } DECLARE_INSTRUCTION(InstanceFieldSet); @@ -6456,11 +6484,17 @@ class HInstanceFieldSet final : public HExpression<2> { private: static constexpr size_t kFlagValueCanBeNull = kNumberOfGenericPackedBits; static constexpr size_t kFlagIsPredicatedSet = kFlagValueCanBeNull + 1; - static constexpr size_t kNumberOfInstanceFieldSetPackedBits = kFlagIsPredicatedSet + 1; + static constexpr size_t kWriteBarrierKind = kFlagIsPredicatedSet + 1; + static constexpr size_t kWriteBarrierKindSize = + MinimumBitsToStore(static_cast<size_t>(WriteBarrierKind::kLast)); + static constexpr size_t kNumberOfInstanceFieldSetPackedBits = + kWriteBarrierKind + kWriteBarrierKindSize; static_assert(kNumberOfInstanceFieldSetPackedBits <= kMaxNumberOfPackedBits, "Too many packed fields."); const FieldInfo field_info_; + using WriteBarrierKindField = + BitField<WriteBarrierKind, kWriteBarrierKind, kWriteBarrierKindSize>; }; class HArrayGet final : public HExpression<2> { @@ -6581,6 +6615,8 @@ class HArraySet final : public HExpression<3> { SetPackedFlag<kFlagNeedsTypeCheck>(value->GetType() == DataType::Type::kReference); SetPackedFlag<kFlagValueCanBeNull>(true); SetPackedFlag<kFlagStaticTypeOfArrayIsObjectArray>(false); + // ArraySets never do the null check optimization at the write barrier stage. + SetPackedField<WriteBarrierKindField>(WriteBarrierKind::kEmitNoNullCheck); SetRawInputAt(0, array); SetRawInputAt(1, index); SetRawInputAt(2, value); @@ -6653,6 +6689,16 @@ class HArraySet final : public HExpression<3> { : SideEffects::None(); } + WriteBarrierKind GetWriteBarrierKind() { return GetPackedField<WriteBarrierKindField>(); } + + void SetWriteBarrierKind(WriteBarrierKind kind) { + DCHECK(kind != WriteBarrierKind::kEmitNoNullCheck) + << "We shouldn't go back to the original value."; + DCHECK(kind != WriteBarrierKind::kEmitWithNullCheck) + << "We never do the null check optimization for ArraySets."; + SetPackedField<WriteBarrierKindField>(kind); + } + DECLARE_INSTRUCTION(ArraySet); protected: @@ -6668,11 +6714,16 @@ class HArraySet final : public HExpression<3> { // Cached information for the reference_type_info_ so that codegen // does not need to inspect the static type. static constexpr size_t kFlagStaticTypeOfArrayIsObjectArray = kFlagValueCanBeNull + 1; - static constexpr size_t kNumberOfArraySetPackedBits = - kFlagStaticTypeOfArrayIsObjectArray + 1; + static constexpr size_t kWriteBarrierKind = kFlagStaticTypeOfArrayIsObjectArray + 1; + static constexpr size_t kWriteBarrierKindSize = + MinimumBitsToStore(static_cast<size_t>(WriteBarrierKind::kLast)); + static constexpr size_t kNumberOfArraySetPackedBits = kWriteBarrierKind + kWriteBarrierKindSize; static_assert(kNumberOfArraySetPackedBits <= kMaxNumberOfPackedBits, "Too many packed fields."); using ExpectedComponentTypeField = BitField<DataType::Type, kFieldExpectedComponentType, kFieldExpectedComponentTypeSize>; + + using WriteBarrierKindField = + BitField<WriteBarrierKind, kWriteBarrierKind, kWriteBarrierKindSize>; }; class HArrayLength final : public HExpression<1> { @@ -7470,6 +7521,7 @@ class HStaticFieldSet final : public HExpression<2> { declaring_class_def_index, dex_file) { SetPackedFlag<kFlagValueCanBeNull>(true); + SetPackedField<WriteBarrierKindField>(WriteBarrierKind::kEmitWithNullCheck); SetRawInputAt(0, cls); SetRawInputAt(1, value); } @@ -7485,6 +7537,13 @@ class HStaticFieldSet final : public HExpression<2> { bool GetValueCanBeNull() const { return GetPackedFlag<kFlagValueCanBeNull>(); } void ClearValueCanBeNull() { SetPackedFlag<kFlagValueCanBeNull>(false); } + WriteBarrierKind GetWriteBarrierKind() { return GetPackedField<WriteBarrierKindField>(); } + void SetWriteBarrierKind(WriteBarrierKind kind) { + DCHECK(kind != WriteBarrierKind::kEmitWithNullCheck) + << "We shouldn't go back to the original value."; + SetPackedField<WriteBarrierKindField>(kind); + } + DECLARE_INSTRUCTION(StaticFieldSet); protected: @@ -7492,11 +7551,17 @@ class HStaticFieldSet final : public HExpression<2> { private: static constexpr size_t kFlagValueCanBeNull = kNumberOfGenericPackedBits; - static constexpr size_t kNumberOfStaticFieldSetPackedBits = kFlagValueCanBeNull + 1; + static constexpr size_t kWriteBarrierKind = kFlagValueCanBeNull + 1; + static constexpr size_t kWriteBarrierKindSize = + MinimumBitsToStore(static_cast<size_t>(WriteBarrierKind::kLast)); + static constexpr size_t kNumberOfStaticFieldSetPackedBits = + kWriteBarrierKind + kWriteBarrierKindSize; static_assert(kNumberOfStaticFieldSetPackedBits <= kMaxNumberOfPackedBits, "Too many packed fields."); const FieldInfo field_info_; + using WriteBarrierKindField = + BitField<WriteBarrierKind, kWriteBarrierKind, kWriteBarrierKindSize>; }; class HStringBuilderAppend final : public HVariableInputSizeInstruction { |