diff options
Diffstat (limited to 'compiler/optimizing/nodes.h')
| -rw-r--r-- | compiler/optimizing/nodes.h | 698 |
1 files changed, 440 insertions, 258 deletions
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h index b0657d6f1c..d42f4a7e80 100644 --- a/compiler/optimizing/nodes.h +++ b/compiler/optimizing/nodes.h @@ -26,17 +26,18 @@ #include "base/arena_object.h" #include "base/array_ref.h" #include "base/iteration_range.h" +#include "base/quasi_atomic.h" #include "base/stl_util.h" #include "base/transform_array_ref.h" #include "data_type.h" #include "deoptimization_kind.h" #include "dex/dex_file.h" #include "dex/dex_file_types.h" +#include "dex/invoke_type.h" #include "entrypoints/quick/quick_entrypoints_enum.h" #include "handle.h" #include "handle_scope.h" #include "intrinsics_enum.h" -#include "invoke_type.h" #include "locations.h" #include "method_reference.h" #include "mirror/class.h" @@ -1337,6 +1338,7 @@ class HLoopInformationOutwardIterator : public ValueObject { #define FOR_EACH_CONCRETE_INSTRUCTION_COMMON(M) \ M(Above, Condition) \ M(AboveOrEqual, Condition) \ + M(Abs, UnaryOperation) \ M(Add, BinaryOperation) \ M(And, BinaryOperation) \ M(ArrayGet, Instruction) \ @@ -1382,7 +1384,9 @@ class HLoopInformationOutwardIterator : public ValueObject { M(LoadException, Instruction) \ M(LoadString, Instruction) \ M(LongConstant, Constant) \ + M(Max, Instruction) \ M(MemoryBarrier, Instruction) \ + M(Min, BinaryOperation) \ M(MonitorOperation, Instruction) \ M(Mul, BinaryOperation) \ M(NativeDebugInfo, Instruction) \ @@ -1518,7 +1522,6 @@ FOR_EACH_INSTRUCTION(FORWARD_DECLARATION) private: \ H##type& operator=(const H##type&) = delete; \ public: \ - InstructionKind GetKindInternal() const OVERRIDE { return k##type; } \ const char* DebugName() const OVERRIDE { return #type; } \ bool InstructionTypeEquals(const HInstruction* other) const OVERRIDE { \ return other->Is##type(); \ @@ -1952,7 +1955,14 @@ class HEnvironment : public ArenaObject<kArenaAllocEnvironment> { class HInstruction : public ArenaObject<kArenaAllocInstruction> { public: - HInstruction(SideEffects side_effects, uint32_t dex_pc) +#define DECLARE_KIND(type, super) k##type, + enum InstructionKind { + FOR_EACH_INSTRUCTION(DECLARE_KIND) + kLastInstructionKind + }; +#undef DECLARE_KIND + + HInstruction(InstructionKind kind, SideEffects side_effects, uint32_t dex_pc) : previous_(nullptr), next_(nullptr), block_(nullptr), @@ -1966,16 +1976,12 @@ class HInstruction : public ArenaObject<kArenaAllocInstruction> { lifetime_position_(kNoLifetime), side_effects_(side_effects), reference_type_handle_(ReferenceTypeInfo::CreateInvalid().GetTypeHandle()) { + SetPackedField<InstructionKindField>(kind); SetPackedFlag<kFlagReferenceTypeIsExact>(ReferenceTypeInfo::CreateInvalid().IsExact()); } virtual ~HInstruction() {} -#define DECLARE_KIND(type, super) k##type, - enum InstructionKind { - FOR_EACH_INSTRUCTION(DECLARE_KIND) - }; -#undef DECLARE_KIND HInstruction* GetNext() const { return next_; } HInstruction* GetPrevious() const { return previous_; } @@ -2279,8 +2285,7 @@ class HInstruction : public ArenaObject<kArenaAllocInstruction> { // is adopted and implemented by our C++ compiler(s). Fow now, we need to hide // the virtual function because the __attribute__((__pure__)) doesn't really // apply the strong requirement for virtual functions, preventing optimizations. - InstructionKind GetKind() const PURE; - virtual InstructionKind GetKindInternal() const = 0; + InstructionKind GetKind() const { return GetPackedField<InstructionKindField>(); } virtual size_t ComputeHashCode() const { size_t result = GetKind(); @@ -2332,9 +2337,16 @@ class HInstruction : public ArenaObject<kArenaAllocInstruction> { // its users. Used by liveness analysis to compute use positions accordingly. static constexpr size_t kFlagEmittedAtUseSite = 0u; static constexpr size_t kFlagReferenceTypeIsExact = kFlagEmittedAtUseSite + 1; - static constexpr size_t kNumberOfGenericPackedBits = kFlagReferenceTypeIsExact + 1; + static constexpr size_t kFieldInstructionKind = kFlagReferenceTypeIsExact + 1; + static constexpr size_t kFieldInstructionKindSize = + MinimumBitsToStore(static_cast<size_t>(InstructionKind::kLastInstructionKind - 1)); + static constexpr size_t kNumberOfGenericPackedBits = + kFieldInstructionKind + kFieldInstructionKindSize; static constexpr size_t kMaxNumberOfPackedBits = sizeof(uint32_t) * kBitsPerByte; + static_assert(kNumberOfGenericPackedBits <= kMaxNumberOfPackedBits, + "Too many generic packed fields"); + const HUserRecord<HInstruction*> InputRecordAt(size_t i) const { return GetInputRecords()[i]; } @@ -2391,9 +2403,13 @@ class HInstruction : public ArenaObject<kArenaAllocInstruction> { live_interval_(nullptr), lifetime_position_(kNoLifetime), side_effects_(other.side_effects_), - reference_type_handle_(other.reference_type_handle_) {} + reference_type_handle_(other.reference_type_handle_) { + } private: + using InstructionKindField = + BitField<InstructionKind, kFieldInstructionKind, kFieldInstructionKindSize>; + void FixUpUserRecordsAfterUseInsertion(HUseList<HInstruction*>::iterator fixup_end) { auto before_use_node = uses_.before_begin(); for (auto use_node = uses_.begin(); use_node != fixup_end; ++use_node) { @@ -2569,12 +2585,13 @@ class HVariableInputSizeInstruction : public HInstruction { void RemoveAllInputs(); protected: - HVariableInputSizeInstruction(SideEffects side_effects, + HVariableInputSizeInstruction(InstructionKind inst_kind, + SideEffects side_effects, uint32_t dex_pc, ArenaAllocator* allocator, size_t number_of_inputs, ArenaAllocKind kind) - : HInstruction(side_effects, dex_pc), + : HInstruction(inst_kind, side_effects, dex_pc), inputs_(number_of_inputs, allocator->Adapter(kind)) {} DEFAULT_COPY_CONSTRUCTOR(VariableInputSizeInstruction); @@ -2585,8 +2602,8 @@ class HVariableInputSizeInstruction : public HInstruction { template<size_t N> class HTemplateInstruction: public HInstruction { public: - HTemplateInstruction<N>(SideEffects side_effects, uint32_t dex_pc) - : HInstruction(side_effects, dex_pc), inputs_() {} + HTemplateInstruction<N>(InstructionKind kind, SideEffects side_effects, uint32_t dex_pc) + : HInstruction(kind, side_effects, dex_pc), inputs_() {} virtual ~HTemplateInstruction() {} using HInstruction::GetInputRecords; // Keep the const version visible. @@ -2607,8 +2624,8 @@ class HTemplateInstruction: public HInstruction { template<> class HTemplateInstruction<0>: public HInstruction { public: - explicit HTemplateInstruction<0>(SideEffects side_effects, uint32_t dex_pc) - : HInstruction(side_effects, dex_pc) {} + explicit HTemplateInstruction<0>(InstructionKind kind, SideEffects side_effects, uint32_t dex_pc) + : HInstruction(kind, side_effects, dex_pc) {} virtual ~HTemplateInstruction() {} @@ -2627,8 +2644,12 @@ class HTemplateInstruction<0>: public HInstruction { template<intptr_t N> class HExpression : public HTemplateInstruction<N> { public: - HExpression<N>(DataType::Type type, SideEffects side_effects, uint32_t dex_pc) - : HTemplateInstruction<N>(side_effects, dex_pc) { + using HInstruction::InstructionKind; + HExpression<N>(InstructionKind kind, + DataType::Type type, + SideEffects side_effects, + uint32_t dex_pc) + : HTemplateInstruction<N>(kind, side_effects, dex_pc) { this->template SetPackedField<TypeField>(type); } virtual ~HExpression() {} @@ -2653,7 +2674,8 @@ class HExpression : public HTemplateInstruction<N> { class HReturnVoid FINAL : public HTemplateInstruction<0> { public: explicit HReturnVoid(uint32_t dex_pc = kNoDexPc) - : HTemplateInstruction(SideEffects::None(), dex_pc) {} + : HTemplateInstruction(kReturnVoid, SideEffects::None(), dex_pc) { + } bool IsControlFlow() const OVERRIDE { return true; } @@ -2668,7 +2690,7 @@ class HReturnVoid FINAL : public HTemplateInstruction<0> { class HReturn FINAL : public HTemplateInstruction<1> { public: explicit HReturn(HInstruction* value, uint32_t dex_pc = kNoDexPc) - : HTemplateInstruction(SideEffects::None(), dex_pc) { + : HTemplateInstruction(kReturn, SideEffects::None(), dex_pc) { SetRawInputAt(0, value); } @@ -2688,6 +2710,7 @@ class HPhi FINAL : public HVariableInputSizeInstruction { DataType::Type type, uint32_t dex_pc = kNoDexPc) : HVariableInputSizeInstruction( + kPhi, SideEffects::None(), dex_pc, allocator, @@ -2788,7 +2811,9 @@ class HPhi FINAL : public HVariableInputSizeInstruction { // exit block. class HExit FINAL : public HTemplateInstruction<0> { public: - explicit HExit(uint32_t dex_pc = kNoDexPc) : HTemplateInstruction(SideEffects::None(), dex_pc) {} + explicit HExit(uint32_t dex_pc = kNoDexPc) + : HTemplateInstruction(kExit, SideEffects::None(), dex_pc) { + } bool IsControlFlow() const OVERRIDE { return true; } @@ -2801,7 +2826,9 @@ class HExit FINAL : public HTemplateInstruction<0> { // Jumps from one block to another. class HGoto FINAL : public HTemplateInstruction<0> { public: - explicit HGoto(uint32_t dex_pc = kNoDexPc) : HTemplateInstruction(SideEffects::None(), dex_pc) {} + explicit HGoto(uint32_t dex_pc = kNoDexPc) + : HTemplateInstruction(kGoto, SideEffects::None(), dex_pc) { + } bool IsClonable() const OVERRIDE { return true; } bool IsControlFlow() const OVERRIDE { return true; } @@ -2818,8 +2845,9 @@ class HGoto FINAL : public HTemplateInstruction<0> { class HConstant : public HExpression<0> { public: - explicit HConstant(DataType::Type type, uint32_t dex_pc = kNoDexPc) - : HExpression(type, SideEffects::None(), dex_pc) {} + explicit HConstant(InstructionKind kind, DataType::Type type, uint32_t dex_pc = kNoDexPc) + : HExpression(kind, type, SideEffects::None(), dex_pc) { + } bool CanBeMoved() const OVERRIDE { return true; } @@ -2860,7 +2888,8 @@ class HNullConstant FINAL : public HConstant { private: explicit HNullConstant(uint32_t dex_pc = kNoDexPc) - : HConstant(DataType::Type::kReference, dex_pc) {} + : HConstant(kNullConstant, DataType::Type::kReference, dex_pc) { + } friend class HGraph; }; @@ -2899,9 +2928,12 @@ class HIntConstant FINAL : public HConstant { private: explicit HIntConstant(int32_t value, uint32_t dex_pc = kNoDexPc) - : HConstant(DataType::Type::kInt32, dex_pc), value_(value) {} + : HConstant(kIntConstant, DataType::Type::kInt32, dex_pc), value_(value) { + } explicit HIntConstant(bool value, uint32_t dex_pc = kNoDexPc) - : HConstant(DataType::Type::kInt32, dex_pc), value_(value ? 1 : 0) {} + : HConstant(kIntConstant, DataType::Type::kInt32, dex_pc), + value_(value ? 1 : 0) { + } const int32_t value_; @@ -2935,7 +2967,9 @@ class HLongConstant FINAL : public HConstant { private: explicit HLongConstant(int64_t value, uint32_t dex_pc = kNoDexPc) - : HConstant(DataType::Type::kInt64, dex_pc), value_(value) {} + : HConstant(kLongConstant, DataType::Type::kInt64, dex_pc), + value_(value) { + } const int64_t value_; @@ -2986,9 +3020,13 @@ class HFloatConstant FINAL : public HConstant { private: explicit HFloatConstant(float value, uint32_t dex_pc = kNoDexPc) - : HConstant(DataType::Type::kFloat32, dex_pc), value_(value) {} + : HConstant(kFloatConstant, DataType::Type::kFloat32, dex_pc), + value_(value) { + } explicit HFloatConstant(int32_t value, uint32_t dex_pc = kNoDexPc) - : HConstant(DataType::Type::kFloat32, dex_pc), value_(bit_cast<float, int32_t>(value)) {} + : HConstant(kFloatConstant, DataType::Type::kFloat32, dex_pc), + value_(bit_cast<float, int32_t>(value)) { + } const float value_; @@ -3039,9 +3077,13 @@ class HDoubleConstant FINAL : public HConstant { private: explicit HDoubleConstant(double value, uint32_t dex_pc = kNoDexPc) - : HConstant(DataType::Type::kFloat64, dex_pc), value_(value) {} + : HConstant(kDoubleConstant, DataType::Type::kFloat64, dex_pc), + value_(value) { + } explicit HDoubleConstant(int64_t value, uint32_t dex_pc = kNoDexPc) - : HConstant(DataType::Type::kFloat64, dex_pc), value_(bit_cast<double, int64_t>(value)) {} + : HConstant(kDoubleConstant, DataType::Type::kFloat64, dex_pc), + value_(bit_cast<double, int64_t>(value)) { + } const double value_; @@ -3055,7 +3097,7 @@ class HDoubleConstant FINAL : public HConstant { class HIf FINAL : public HTemplateInstruction<1> { public: explicit HIf(HInstruction* input, uint32_t dex_pc = kNoDexPc) - : HTemplateInstruction(SideEffects::None(), dex_pc) { + : HTemplateInstruction(kIf, SideEffects::None(), dex_pc) { SetRawInputAt(0, input); } @@ -3091,7 +3133,7 @@ class HTryBoundary FINAL : public HTemplateInstruction<0> { }; explicit HTryBoundary(BoundaryKind kind, uint32_t dex_pc = kNoDexPc) - : HTemplateInstruction(SideEffects::None(), dex_pc) { + : HTemplateInstruction(kTryBoundary, SideEffects::None(), dex_pc) { SetPackedField<BoundaryKindField>(kind); } @@ -3150,6 +3192,7 @@ class HDeoptimize FINAL : public HVariableInputSizeInstruction { DeoptimizationKind kind, uint32_t dex_pc) : HVariableInputSizeInstruction( + kDeoptimize, SideEffects::All(), dex_pc, allocator, @@ -3173,6 +3216,7 @@ class HDeoptimize FINAL : public HVariableInputSizeInstruction { DeoptimizationKind kind, uint32_t dex_pc) : HVariableInputSizeInstruction( + kDeoptimize, SideEffects::CanTriggerGC(), dex_pc, allocator, @@ -3241,7 +3285,12 @@ class HShouldDeoptimizeFlag FINAL : public HVariableInputSizeInstruction { // CHA guards are only optimized in a separate pass and it has no side effects // with regard to other passes. HShouldDeoptimizeFlag(ArenaAllocator* allocator, uint32_t dex_pc) - : HVariableInputSizeInstruction(SideEffects::None(), dex_pc, allocator, 0, kArenaAllocCHA) { + : HVariableInputSizeInstruction(kShouldDeoptimizeFlag, + SideEffects::None(), + dex_pc, + allocator, + 0, + kArenaAllocCHA) { } DataType::Type GetType() const OVERRIDE { return DataType::Type::kInt32; } @@ -3264,7 +3313,8 @@ class HShouldDeoptimizeFlag FINAL : public HVariableInputSizeInstruction { class HCurrentMethod FINAL : public HExpression<0> { public: explicit HCurrentMethod(DataType::Type type, uint32_t dex_pc = kNoDexPc) - : HExpression(type, SideEffects::None(), dex_pc) {} + : HExpression(kCurrentMethod, type, SideEffects::None(), dex_pc) { + } DECLARE_INSTRUCTION(CurrentMethod); @@ -3286,7 +3336,7 @@ class HClassTableGet FINAL : public HExpression<1> { TableKind kind, size_t index, uint32_t dex_pc) - : HExpression(type, SideEffects::None(), dex_pc), + : HExpression(kClassTableGet, type, SideEffects::None(), dex_pc), index_(index) { SetPackedField<TableKindField>(kind); SetRawInputAt(0, cls); @@ -3329,7 +3379,7 @@ class HPackedSwitch FINAL : public HTemplateInstruction<1> { uint32_t num_entries, HInstruction* input, uint32_t dex_pc = kNoDexPc) - : HTemplateInstruction(SideEffects::None(), dex_pc), + : HTemplateInstruction(kPackedSwitch, SideEffects::None(), dex_pc), start_value_(start_value), num_entries_(num_entries) { SetRawInputAt(0, input); @@ -3359,8 +3409,11 @@ class HPackedSwitch FINAL : public HTemplateInstruction<1> { class HUnaryOperation : public HExpression<1> { public: - HUnaryOperation(DataType::Type result_type, HInstruction* input, uint32_t dex_pc = kNoDexPc) - : HExpression(result_type, SideEffects::None(), dex_pc) { + HUnaryOperation(InstructionKind kind, + DataType::Type result_type, + HInstruction* input, + uint32_t dex_pc = kNoDexPc) + : HExpression(kind, result_type, SideEffects::None(), dex_pc) { SetRawInputAt(0, input); } @@ -3394,12 +3447,13 @@ class HUnaryOperation : public HExpression<1> { class HBinaryOperation : public HExpression<2> { public: - HBinaryOperation(DataType::Type result_type, + HBinaryOperation(InstructionKind kind, + DataType::Type result_type, HInstruction* left, HInstruction* right, SideEffects side_effects = SideEffects::None(), uint32_t dex_pc = kNoDexPc) - : HExpression(result_type, side_effects, dex_pc) { + : HExpression(kind, result_type, side_effects, dex_pc) { SetRawInputAt(0, left); SetRawInputAt(1, right); } @@ -3498,8 +3552,16 @@ std::ostream& operator<<(std::ostream& os, const ComparisonBias& rhs); class HCondition : public HBinaryOperation { public: - HCondition(HInstruction* first, HInstruction* second, uint32_t dex_pc = kNoDexPc) - : HBinaryOperation(DataType::Type::kBool, first, second, SideEffects::None(), dex_pc) { + HCondition(InstructionKind kind, + HInstruction* first, + HInstruction* second, + uint32_t dex_pc = kNoDexPc) + : HBinaryOperation(kind, + DataType::Type::kBool, + first, + second, + SideEffects::None(), + dex_pc) { SetPackedField<ComparisonBiasField>(ComparisonBias::kNoBias); } @@ -3579,7 +3641,8 @@ class HCondition : public HBinaryOperation { class HEqual FINAL : public HCondition { public: HEqual(HInstruction* first, HInstruction* second, uint32_t dex_pc = kNoDexPc) - : HCondition(first, second, dex_pc) {} + : HCondition(kEqual, first, second, dex_pc) { + } bool IsCommutative() const OVERRIDE { return true; } @@ -3623,8 +3686,10 @@ class HEqual FINAL : public HCondition { class HNotEqual FINAL : public HCondition { public: - HNotEqual(HInstruction* first, HInstruction* second, uint32_t dex_pc = kNoDexPc) - : HCondition(first, second, dex_pc) {} + HNotEqual(HInstruction* first, HInstruction* second, + uint32_t dex_pc = kNoDexPc) + : HCondition(kNotEqual, first, second, dex_pc) { + } bool IsCommutative() const OVERRIDE { return true; } @@ -3667,8 +3732,10 @@ class HNotEqual FINAL : public HCondition { class HLessThan FINAL : public HCondition { public: - HLessThan(HInstruction* first, HInstruction* second, uint32_t dex_pc = kNoDexPc) - : HCondition(first, second, dex_pc) {} + HLessThan(HInstruction* first, HInstruction* second, + uint32_t dex_pc = kNoDexPc) + : HCondition(kLessThan, first, second, dex_pc) { + } HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE { return MakeConstantCondition(Compute(x->GetValue(), y->GetValue()), GetDexPc()); @@ -3705,8 +3772,10 @@ class HLessThan FINAL : public HCondition { class HLessThanOrEqual FINAL : public HCondition { public: - HLessThanOrEqual(HInstruction* first, HInstruction* second, uint32_t dex_pc = kNoDexPc) - : HCondition(first, second, dex_pc) {} + HLessThanOrEqual(HInstruction* first, HInstruction* second, + uint32_t dex_pc = kNoDexPc) + : HCondition(kLessThanOrEqual, first, second, dex_pc) { + } HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE { return MakeConstantCondition(Compute(x->GetValue(), y->GetValue()), GetDexPc()); @@ -3744,7 +3813,8 @@ class HLessThanOrEqual FINAL : public HCondition { class HGreaterThan FINAL : public HCondition { public: HGreaterThan(HInstruction* first, HInstruction* second, uint32_t dex_pc = kNoDexPc) - : HCondition(first, second, dex_pc) {} + : HCondition(kGreaterThan, first, second, dex_pc) { + } HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE { return MakeConstantCondition(Compute(x->GetValue(), y->GetValue()), GetDexPc()); @@ -3782,7 +3852,8 @@ class HGreaterThan FINAL : public HCondition { class HGreaterThanOrEqual FINAL : public HCondition { public: HGreaterThanOrEqual(HInstruction* first, HInstruction* second, uint32_t dex_pc = kNoDexPc) - : HCondition(first, second, dex_pc) {} + : HCondition(kGreaterThanOrEqual, first, second, dex_pc) { + } HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE { return MakeConstantCondition(Compute(x->GetValue(), y->GetValue()), GetDexPc()); @@ -3820,7 +3891,8 @@ class HGreaterThanOrEqual FINAL : public HCondition { class HBelow FINAL : public HCondition { public: HBelow(HInstruction* first, HInstruction* second, uint32_t dex_pc = kNoDexPc) - : HCondition(first, second, dex_pc) {} + : HCondition(kBelow, first, second, dex_pc) { + } HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE { return MakeConstantCondition(Compute(x->GetValue(), y->GetValue()), GetDexPc()); @@ -3861,7 +3933,8 @@ class HBelow FINAL : public HCondition { class HBelowOrEqual FINAL : public HCondition { public: HBelowOrEqual(HInstruction* first, HInstruction* second, uint32_t dex_pc = kNoDexPc) - : HCondition(first, second, dex_pc) {} + : HCondition(kBelowOrEqual, first, second, dex_pc) { + } HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE { return MakeConstantCondition(Compute(x->GetValue(), y->GetValue()), GetDexPc()); @@ -3902,7 +3975,8 @@ class HBelowOrEqual FINAL : public HCondition { class HAbove FINAL : public HCondition { public: HAbove(HInstruction* first, HInstruction* second, uint32_t dex_pc = kNoDexPc) - : HCondition(first, second, dex_pc) {} + : HCondition(kAbove, first, second, dex_pc) { + } HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE { return MakeConstantCondition(Compute(x->GetValue(), y->GetValue()), GetDexPc()); @@ -3943,7 +4017,8 @@ class HAbove FINAL : public HCondition { class HAboveOrEqual FINAL : public HCondition { public: HAboveOrEqual(HInstruction* first, HInstruction* second, uint32_t dex_pc = kNoDexPc) - : HCondition(first, second, dex_pc) {} + : HCondition(kAboveOrEqual, first, second, dex_pc) { + } HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE { return MakeConstantCondition(Compute(x->GetValue(), y->GetValue()), GetDexPc()); @@ -3993,7 +4068,8 @@ class HCompare FINAL : public HBinaryOperation { HInstruction* second, ComparisonBias bias, uint32_t dex_pc) - : HBinaryOperation(DataType::Type::kInt32, + : HBinaryOperation(kCompare, + DataType::Type::kInt32, first, second, SideEffectsForArchRuntimeCalls(comparison_type), @@ -4079,7 +4155,10 @@ class HNewInstance FINAL : public HExpression<1> { const DexFile& dex_file, bool finalizable, QuickEntrypointEnum entrypoint) - : HExpression(DataType::Type::kReference, SideEffects::CanTriggerGC(), dex_pc), + : HExpression(kNewInstance, + DataType::Type::kReference, + SideEffects::CanTriggerGC(), + dex_pc), type_index_(type_index), dex_file_(dex_file), entrypoint_(entrypoint) { @@ -4235,7 +4314,8 @@ class HInvoke : public HVariableInputSizeInstruction { using InvokeTypeField = BitField<InvokeType, kFieldInvokeType, kFieldInvokeTypeSize>; using ReturnTypeField = BitField<DataType::Type, kFieldReturnType, kFieldReturnTypeSize>; - HInvoke(ArenaAllocator* allocator, + HInvoke(InstructionKind kind, + ArenaAllocator* allocator, uint32_t number_of_arguments, uint32_t number_of_other_inputs, DataType::Type return_type, @@ -4244,6 +4324,7 @@ class HInvoke : public HVariableInputSizeInstruction { ArtMethod* resolved_method, InvokeType invoke_type) : HVariableInputSizeInstruction( + kind, SideEffects::AllExceptGCDependency(), // Assume write/read on all fields/arrays. dex_pc, allocator, @@ -4278,7 +4359,8 @@ class HInvokeUnresolved FINAL : public HInvoke { uint32_t dex_pc, uint32_t dex_method_index, InvokeType invoke_type) - : HInvoke(allocator, + : HInvoke(kInvokeUnresolved, + allocator, number_of_arguments, 0u /* number_of_other_inputs */, return_type, @@ -4303,14 +4385,16 @@ class HInvokePolymorphic FINAL : public HInvoke { DataType::Type return_type, uint32_t dex_pc, uint32_t dex_method_index) - : HInvoke(allocator, + : HInvoke(kInvokePolymorphic, + allocator, number_of_arguments, 0u /* number_of_other_inputs */, return_type, dex_pc, dex_method_index, nullptr, - kVirtual) {} + kVirtual) { + } bool IsClonable() const OVERRIDE { return true; } @@ -4347,6 +4431,10 @@ class HInvokeStaticOrDirect FINAL : public HInvoke { // Used for app->boot calls with non-relocatable image and for JIT-compiled calls. kDirectAddress, + // Load from an entry in the .data.bimg.rel.ro using a PC-relative load. + // Used for app->boot calls with relocatable image. + kBootImageRelRo, + // Load from an entry in the .bss section using a PC-relative load. // Used for classes outside boot image when .bss is accessible with a PC-relative load. kBssEntry, @@ -4387,7 +4475,8 @@ class HInvokeStaticOrDirect FINAL : public HInvoke { InvokeType invoke_type, MethodReference target_method, ClinitCheckRequirement clinit_check_requirement) - : HInvoke(allocator, + : HInvoke(kInvokeStaticOrDirect, + allocator, number_of_arguments, // There is potentially one extra argument for the HCurrentMethod node, and // potentially one other if the clinit check is explicit, and potentially @@ -4478,6 +4567,7 @@ class HInvokeStaticOrDirect FINAL : public HInvoke { bool HasMethodAddress() const { return GetMethodLoadKind() == MethodLoadKind::kDirectAddress; } bool HasPcRelativeMethodLoadKind() const { return GetMethodLoadKind() == MethodLoadKind::kBootImageLinkTimePcRelative || + GetMethodLoadKind() == MethodLoadKind::kBootImageRelRo || GetMethodLoadKind() == MethodLoadKind::kBssEntry; } bool HasCurrentMethodInput() const { @@ -4567,7 +4657,7 @@ class HInvokeStaticOrDirect FINAL : public HInvoke { kFieldClinitCheckRequirementSize>; // Cached values of the resolved method, to avoid needing the mutator lock. - MethodReference target_method_; + const MethodReference target_method_; DispatchInfo dispatch_info_; }; std::ostream& operator<<(std::ostream& os, HInvokeStaticOrDirect::MethodLoadKind rhs); @@ -4582,7 +4672,8 @@ class HInvokeVirtual FINAL : public HInvoke { uint32_t dex_method_index, ArtMethod* resolved_method, uint32_t vtable_index) - : HInvoke(allocator, + : HInvoke(kInvokeVirtual, + allocator, number_of_arguments, 0u, return_type, @@ -4590,7 +4681,8 @@ class HInvokeVirtual FINAL : public HInvoke { dex_method_index, resolved_method, kVirtual), - vtable_index_(vtable_index) {} + vtable_index_(vtable_index) { + } bool IsClonable() const OVERRIDE { return true; } @@ -4633,7 +4725,8 @@ class HInvokeInterface FINAL : public HInvoke { uint32_t dex_method_index, ArtMethod* resolved_method, uint32_t imt_index) - : HInvoke(allocator, + : HInvoke(kInvokeInterface, + allocator, number_of_arguments, 0u, return_type, @@ -4641,7 +4734,8 @@ class HInvokeInterface FINAL : public HInvoke { dex_method_index, resolved_method, kInterface), - imt_index_(imt_index) {} + imt_index_(imt_index) { + } bool IsClonable() const OVERRIDE { return true; } @@ -4670,7 +4764,7 @@ class HInvokeInterface FINAL : public HInvoke { class HNeg FINAL : public HUnaryOperation { public: HNeg(DataType::Type result_type, HInstruction* input, uint32_t dex_pc = kNoDexPc) - : HUnaryOperation(result_type, input, dex_pc) { + : HUnaryOperation(kNeg, result_type, input, dex_pc) { DCHECK_EQ(result_type, DataType::Kind(input->GetType())); } @@ -4698,7 +4792,7 @@ class HNeg FINAL : public HUnaryOperation { class HNewArray FINAL : public HExpression<2> { public: HNewArray(HInstruction* cls, HInstruction* length, uint32_t dex_pc) - : HExpression(DataType::Type::kReference, SideEffects::CanTriggerGC(), dex_pc) { + : HExpression(kNewArray, DataType::Type::kReference, SideEffects::CanTriggerGC(), dex_pc) { SetRawInputAt(0, cls); SetRawInputAt(1, length); } @@ -4734,7 +4828,8 @@ class HAdd FINAL : public HBinaryOperation { HInstruction* left, HInstruction* right, uint32_t dex_pc = kNoDexPc) - : HBinaryOperation(result_type, left, right, SideEffects::None(), dex_pc) {} + : HBinaryOperation(kAdd, result_type, left, right, SideEffects::None(), dex_pc) { + } bool IsCommutative() const OVERRIDE { return true; } @@ -4769,7 +4864,8 @@ class HSub FINAL : public HBinaryOperation { HInstruction* left, HInstruction* right, uint32_t dex_pc = kNoDexPc) - : HBinaryOperation(result_type, left, right, SideEffects::None(), dex_pc) {} + : HBinaryOperation(kSub, result_type, left, right, SideEffects::None(), dex_pc) { + } template <typename T> static T Compute(T x, T y) { return x - y; } @@ -4802,7 +4898,8 @@ class HMul FINAL : public HBinaryOperation { HInstruction* left, HInstruction* right, uint32_t dex_pc = kNoDexPc) - : HBinaryOperation(result_type, left, right, SideEffects::None(), dex_pc) {} + : HBinaryOperation(kMul, result_type, left, right, SideEffects::None(), dex_pc) { + } bool IsCommutative() const OVERRIDE { return true; } @@ -4837,7 +4934,8 @@ class HDiv FINAL : public HBinaryOperation { HInstruction* left, HInstruction* right, uint32_t dex_pc) - : HBinaryOperation(result_type, left, right, SideEffects::None(), dex_pc) {} + : HBinaryOperation(kDiv, result_type, left, right, SideEffects::None(), dex_pc) { + } template <typename T> T ComputeIntegral(T x, T y) const { @@ -4884,7 +4982,8 @@ class HRem FINAL : public HBinaryOperation { HInstruction* left, HInstruction* right, uint32_t dex_pc) - : HBinaryOperation(result_type, left, right, SideEffects::None(), dex_pc) {} + : HBinaryOperation(kRem, result_type, left, right, SideEffects::None(), dex_pc) { + } template <typename T> T ComputeIntegral(T x, T y) const { @@ -4925,12 +5024,123 @@ class HRem FINAL : public HBinaryOperation { DEFAULT_COPY_CONSTRUCTOR(Rem); }; +class HMin FINAL : public HBinaryOperation { + public: + HMin(DataType::Type result_type, + HInstruction* left, + HInstruction* right, + uint32_t dex_pc) + : HBinaryOperation(kMin, result_type, left, right, SideEffects::None(), dex_pc) {} + + bool IsCommutative() const OVERRIDE { return true; } + + // Evaluation for integral values. + template <typename T> static T ComputeIntegral(T x, T y) { + return (x <= y) ? x : y; + } + + HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE { + return GetBlock()->GetGraph()->GetIntConstant( + ComputeIntegral(x->GetValue(), y->GetValue()), GetDexPc()); + } + HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const OVERRIDE { + return GetBlock()->GetGraph()->GetLongConstant( + ComputeIntegral(x->GetValue(), y->GetValue()), GetDexPc()); + } + // TODO: Evaluation for floating-point values. + HConstant* Evaluate(HFloatConstant* x ATTRIBUTE_UNUSED, + HFloatConstant* y ATTRIBUTE_UNUSED) const OVERRIDE { return nullptr; } + HConstant* Evaluate(HDoubleConstant* x ATTRIBUTE_UNUSED, + HDoubleConstant* y ATTRIBUTE_UNUSED) const OVERRIDE { return nullptr; } + + DECLARE_INSTRUCTION(Min); + + protected: + DEFAULT_COPY_CONSTRUCTOR(Min); +}; + +class HMax FINAL : public HBinaryOperation { + public: + HMax(DataType::Type result_type, + HInstruction* left, + HInstruction* right, + uint32_t dex_pc) + : HBinaryOperation(kMax, result_type, left, right, SideEffects::None(), dex_pc) {} + + bool IsCommutative() const OVERRIDE { return true; } + + // Evaluation for integral values. + template <typename T> static T ComputeIntegral(T x, T y) { + return (x >= y) ? x : y; + } + + HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE { + return GetBlock()->GetGraph()->GetIntConstant( + ComputeIntegral(x->GetValue(), y->GetValue()), GetDexPc()); + } + HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const OVERRIDE { + return GetBlock()->GetGraph()->GetLongConstant( + ComputeIntegral(x->GetValue(), y->GetValue()), GetDexPc()); + } + // TODO: Evaluation for floating-point values. + HConstant* Evaluate(HFloatConstant* x ATTRIBUTE_UNUSED, + HFloatConstant* y ATTRIBUTE_UNUSED) const OVERRIDE { return nullptr; } + HConstant* Evaluate(HDoubleConstant* x ATTRIBUTE_UNUSED, + HDoubleConstant* y ATTRIBUTE_UNUSED) const OVERRIDE { return nullptr; } + + DECLARE_INSTRUCTION(Max); + + protected: + DEFAULT_COPY_CONSTRUCTOR(Max); +}; + +class HAbs FINAL : public HUnaryOperation { + public: + HAbs(DataType::Type result_type, HInstruction* input, uint32_t dex_pc = kNoDexPc) + : HUnaryOperation(kAbs, result_type, input, dex_pc) {} + + // Evaluation for integral values. + template <typename T> static T ComputeIntegral(T x) { + return x < 0 ? -x : x; + } + + // Evaluation for floating-point values. + // Note, as a "quality of implementation", rather than pure "spec compliance", + // we require that Math.abs() clears the sign bit (but changes nothing else) + // for all floating-point numbers, including NaN (signaling NaN may become quiet though). + // http://b/30758343 + template <typename T, typename S> static T ComputeFP(T x) { + S bits = bit_cast<S, T>(x); + return bit_cast<T, S>(bits & std::numeric_limits<S>::max()); + } + + HConstant* Evaluate(HIntConstant* x) const OVERRIDE { + return GetBlock()->GetGraph()->GetIntConstant(ComputeIntegral(x->GetValue()), GetDexPc()); + } + HConstant* Evaluate(HLongConstant* x) const OVERRIDE { + return GetBlock()->GetGraph()->GetLongConstant(ComputeIntegral(x->GetValue()), GetDexPc()); + } + HConstant* Evaluate(HFloatConstant* x) const OVERRIDE { + return GetBlock()->GetGraph()->GetFloatConstant( + ComputeFP<float, int32_t>(x->GetValue()), GetDexPc()); + } + HConstant* Evaluate(HDoubleConstant* x) const OVERRIDE { + return GetBlock()->GetGraph()->GetDoubleConstant( + ComputeFP<double, int64_t>(x->GetValue()), GetDexPc()); + } + + DECLARE_INSTRUCTION(Abs); + + protected: + DEFAULT_COPY_CONSTRUCTOR(Abs); +}; + class HDivZeroCheck FINAL : public HExpression<1> { public: // `HDivZeroCheck` can trigger GC, as it may call the `ArithmeticException` // constructor. HDivZeroCheck(HInstruction* value, uint32_t dex_pc) - : HExpression(value->GetType(), SideEffects::CanTriggerGC(), dex_pc) { + : HExpression(kDivZeroCheck, value->GetType(), SideEffects::CanTriggerGC(), dex_pc) { SetRawInputAt(0, value); } @@ -4957,7 +5167,7 @@ class HShl FINAL : public HBinaryOperation { HInstruction* value, HInstruction* distance, uint32_t dex_pc = kNoDexPc) - : HBinaryOperation(result_type, value, distance, SideEffects::None(), dex_pc) { + : HBinaryOperation(kShl, result_type, value, distance, SideEffects::None(), dex_pc) { DCHECK_EQ(result_type, DataType::Kind(value->GetType())); DCHECK_EQ(DataType::Type::kInt32, DataType::Kind(distance->GetType())); } @@ -5003,7 +5213,7 @@ class HShr FINAL : public HBinaryOperation { HInstruction* value, HInstruction* distance, uint32_t dex_pc = kNoDexPc) - : HBinaryOperation(result_type, value, distance, SideEffects::None(), dex_pc) { + : HBinaryOperation(kShr, result_type, value, distance, SideEffects::None(), dex_pc) { DCHECK_EQ(result_type, DataType::Kind(value->GetType())); DCHECK_EQ(DataType::Type::kInt32, DataType::Kind(distance->GetType())); } @@ -5049,7 +5259,7 @@ class HUShr FINAL : public HBinaryOperation { HInstruction* value, HInstruction* distance, uint32_t dex_pc = kNoDexPc) - : HBinaryOperation(result_type, value, distance, SideEffects::None(), dex_pc) { + : HBinaryOperation(kUShr, result_type, value, distance, SideEffects::None(), dex_pc) { DCHECK_EQ(result_type, DataType::Kind(value->GetType())); DCHECK_EQ(DataType::Type::kInt32, DataType::Kind(distance->GetType())); } @@ -5097,7 +5307,8 @@ class HAnd FINAL : public HBinaryOperation { HInstruction* left, HInstruction* right, uint32_t dex_pc = kNoDexPc) - : HBinaryOperation(result_type, left, right, SideEffects::None(), dex_pc) {} + : HBinaryOperation(kAnd, result_type, left, right, SideEffects::None(), dex_pc) { + } bool IsCommutative() const OVERRIDE { return true; } @@ -5134,7 +5345,8 @@ class HOr FINAL : public HBinaryOperation { HInstruction* left, HInstruction* right, uint32_t dex_pc = kNoDexPc) - : HBinaryOperation(result_type, left, right, SideEffects::None(), dex_pc) {} + : HBinaryOperation(kOr, result_type, left, right, SideEffects::None(), dex_pc) { + } bool IsCommutative() const OVERRIDE { return true; } @@ -5171,7 +5383,8 @@ class HXor FINAL : public HBinaryOperation { HInstruction* left, HInstruction* right, uint32_t dex_pc = kNoDexPc) - : HBinaryOperation(result_type, left, right, SideEffects::None(), dex_pc) {} + : HBinaryOperation(kXor, result_type, left, right, SideEffects::None(), dex_pc) { + } bool IsCommutative() const OVERRIDE { return true; } @@ -5205,7 +5418,7 @@ class HXor FINAL : public HBinaryOperation { class HRor FINAL : public HBinaryOperation { public: HRor(DataType::Type result_type, HInstruction* value, HInstruction* distance) - : HBinaryOperation(result_type, value, distance) { + : HBinaryOperation(kRor, result_type, value, distance) { DCHECK_EQ(result_type, DataType::Kind(value->GetType())); DCHECK_EQ(DataType::Type::kInt32, DataType::Kind(distance->GetType())); } @@ -5262,7 +5475,7 @@ class HParameterValue FINAL : public HExpression<0> { uint8_t index, DataType::Type parameter_type, bool is_this = false) - : HExpression(parameter_type, SideEffects::None(), kNoDexPc), + : HExpression(kParameterValue, parameter_type, SideEffects::None(), kNoDexPc), dex_file_(dex_file), type_index_(type_index), index_(index) { @@ -5301,7 +5514,8 @@ class HParameterValue FINAL : public HExpression<0> { class HNot FINAL : public HUnaryOperation { public: HNot(DataType::Type result_type, HInstruction* input, uint32_t dex_pc = kNoDexPc) - : HUnaryOperation(result_type, input, dex_pc) {} + : HUnaryOperation(kNot, result_type, input, dex_pc) { + } bool CanBeMoved() const OVERRIDE { return true; } bool InstructionDataEquals(const HInstruction* other ATTRIBUTE_UNUSED) const OVERRIDE { @@ -5334,7 +5548,8 @@ class HNot FINAL : public HUnaryOperation { class HBooleanNot FINAL : public HUnaryOperation { public: explicit HBooleanNot(HInstruction* input, uint32_t dex_pc = kNoDexPc) - : HUnaryOperation(DataType::Type::kBool, input, dex_pc) {} + : HUnaryOperation(kBooleanNot, DataType::Type::kBool, input, dex_pc) { + } bool CanBeMoved() const OVERRIDE { return true; } bool InstructionDataEquals(const HInstruction* other ATTRIBUTE_UNUSED) const OVERRIDE { @@ -5372,7 +5587,7 @@ class HTypeConversion FINAL : public HExpression<1> { public: // Instantiate a type conversion of `input` to `result_type`. HTypeConversion(DataType::Type result_type, HInstruction* input, uint32_t dex_pc = kNoDexPc) - : HExpression(result_type, SideEffects::None(), dex_pc) { + : HExpression(kTypeConversion, result_type, SideEffects::None(), dex_pc) { SetRawInputAt(0, input); // Invariant: We should never generate a conversion to a Boolean value. DCHECK_NE(DataType::Type::kBool, result_type); @@ -5404,7 +5619,7 @@ class HNullCheck FINAL : public HExpression<1> { // `HNullCheck` can trigger GC, as it may call the `NullPointerException` // constructor. HNullCheck(HInstruction* value, uint32_t dex_pc) - : HExpression(value->GetType(), SideEffects::CanTriggerGC(), dex_pc) { + : HExpression(kNullCheck, value->GetType(), SideEffects::CanTriggerGC(), dex_pc) { SetRawInputAt(0, value); } @@ -5474,7 +5689,10 @@ class HInstanceFieldGet FINAL : public HExpression<1> { uint16_t declaring_class_def_index, const DexFile& dex_file, uint32_t dex_pc) - : HExpression(field_type, SideEffects::FieldReadOfType(field_type, is_volatile), dex_pc), + : HExpression(kInstanceFieldGet, + field_type, + SideEffects::FieldReadOfType(field_type, is_volatile), + dex_pc), field_info_(field, field_offset, field_type, @@ -5534,7 +5752,9 @@ class HInstanceFieldSet FINAL : public HTemplateInstruction<2> { uint16_t declaring_class_def_index, const DexFile& dex_file, uint32_t dex_pc) - : HTemplateInstruction(SideEffects::FieldWriteOfType(field_type, is_volatile), dex_pc), + : HTemplateInstruction(kInstanceFieldSet, + SideEffects::FieldWriteOfType(field_type, is_volatile), + dex_pc), field_info_(field, field_offset, field_type, @@ -5586,7 +5806,8 @@ class HArrayGet FINAL : public HExpression<2> { type, SideEffects::ArrayReadOfType(type), dex_pc, - /* is_string_char_at */ false) {} + /* is_string_char_at */ false) { + } HArrayGet(HInstruction* array, HInstruction* index, @@ -5594,7 +5815,7 @@ class HArrayGet FINAL : public HExpression<2> { SideEffects side_effects, uint32_t dex_pc, bool is_string_char_at) - : HExpression(type, side_effects, dex_pc) { + : HExpression(kArrayGet, type, side_effects, dex_pc) { SetPackedFlag<kFlagIsStringCharAt>(is_string_char_at); SetRawInputAt(0, array); SetRawInputAt(1, index); @@ -5678,7 +5899,8 @@ class HArraySet FINAL : public HTemplateInstruction<3> { expected_component_type, // Make a best guess for side effects now, may be refined during SSA building. ComputeSideEffects(GetComponentType(value->GetType(), expected_component_type)), - dex_pc) {} + dex_pc) { + } HArraySet(HInstruction* array, HInstruction* index, @@ -5686,7 +5908,7 @@ class HArraySet FINAL : public HTemplateInstruction<3> { DataType::Type expected_component_type, SideEffects side_effects, uint32_t dex_pc) - : HTemplateInstruction(side_effects, dex_pc) { + : HTemplateInstruction(kArraySet, side_effects, dex_pc) { SetPackedField<ExpectedComponentTypeField>(expected_component_type); SetPackedFlag<kFlagNeedsTypeCheck>(value->GetType() == DataType::Type::kReference); SetPackedFlag<kFlagValueCanBeNull>(true); @@ -5786,7 +6008,7 @@ class HArraySet FINAL : public HTemplateInstruction<3> { class HArrayLength FINAL : public HExpression<1> { public: HArrayLength(HInstruction* array, uint32_t dex_pc, bool is_string_length = false) - : HExpression(DataType::Type::kInt32, SideEffects::None(), dex_pc) { + : HExpression(kArrayLength, DataType::Type::kInt32, SideEffects::None(), dex_pc) { SetPackedFlag<kFlagIsStringLength>(is_string_length); // Note that arrays do not change length, so the instruction does not // depend on any write. @@ -5829,7 +6051,7 @@ class HBoundsCheck FINAL : public HExpression<2> { HInstruction* length, uint32_t dex_pc, bool is_string_char_at = false) - : HExpression(index->GetType(), SideEffects::CanTriggerGC(), dex_pc) { + : HExpression(kBoundsCheck, index->GetType(), SideEffects::CanTriggerGC(), dex_pc) { DCHECK_EQ(DataType::Type::kInt32, DataType::Kind(index->GetType())); SetPackedFlag<kFlagIsStringCharAt>(is_string_char_at); SetRawInputAt(0, index); @@ -5862,7 +6084,9 @@ class HBoundsCheck FINAL : public HExpression<2> { class HSuspendCheck FINAL : public HTemplateInstruction<0> { public: explicit HSuspendCheck(uint32_t dex_pc = kNoDexPc) - : HTemplateInstruction(SideEffects::CanTriggerGC(), dex_pc), slow_path_(nullptr) {} + : HTemplateInstruction(kSuspendCheck, SideEffects::CanTriggerGC(), dex_pc), + slow_path_(nullptr) { + } bool IsClonable() const OVERRIDE { return true; } @@ -5889,7 +6113,8 @@ class HSuspendCheck FINAL : public HTemplateInstruction<0> { class HNativeDebugInfo : public HTemplateInstruction<0> { public: explicit HNativeDebugInfo(uint32_t dex_pc) - : HTemplateInstruction<0>(SideEffects::None(), dex_pc) {} + : HTemplateInstruction<0>(kNativeDebugInfo, SideEffects::None(), dex_pc) { + } bool NeedsEnvironment() const OVERRIDE { return true; @@ -5947,11 +6172,12 @@ class HLoadClass FINAL : public HInstruction { bool is_referrers_class, uint32_t dex_pc, bool needs_access_check) - : HInstruction(SideEffectsForArchRuntimeCalls(), dex_pc), + : HInstruction(kLoadClass, SideEffectsForArchRuntimeCalls(), dex_pc), special_input_(HUserRecord<HInstruction*>(current_method)), type_index_(type_index), dex_file_(dex_file), - klass_(klass) { + klass_(klass), + loaded_class_rti_(ReferenceTypeInfo::CreateInvalid()) { // Referrers class should not need access check. We never inline unverified // methods so we can't possibly end up in this situation. DCHECK(!is_referrers_class || !needs_access_check); @@ -5961,7 +6187,6 @@ class HLoadClass FINAL : public HInstruction { SetPackedFlag<kFlagNeedsAccessCheck>(needs_access_check); SetPackedFlag<kFlagIsInBootImage>(false); SetPackedFlag<kFlagGenerateClInitCheck>(false); - SetPackedFlag<kFlagValidLoadedClassRTI>(false); } bool IsClonable() const OVERRIDE { return true; } @@ -6010,18 +6235,13 @@ class HLoadClass FINAL : public HInstruction { } ReferenceTypeInfo GetLoadedClassRTI() { - if (GetPackedFlag<kFlagValidLoadedClassRTI>()) { - // Note: The is_exact flag from the return value should not be used. - return ReferenceTypeInfo::CreateUnchecked(klass_, /* is_exact */ true); - } else { - return ReferenceTypeInfo::CreateInvalid(); - } + return loaded_class_rti_; } - // Loaded class RTI is marked as valid by RTP if the klass_ is admissible. - void SetValidLoadedClassRTI() REQUIRES_SHARED(Locks::mutator_lock_) { - DCHECK(klass_ != nullptr); - SetPackedFlag<kFlagValidLoadedClassRTI>(true); + void SetLoadedClassRTI(ReferenceTypeInfo rti) { + // Make sure we only set exact types (the loaded class should never be merged). + DCHECK(rti.IsExact()); + loaded_class_rti_ = rti; } dex::TypeIndex GetTypeIndex() const { return type_index_; } @@ -6074,8 +6294,7 @@ class HLoadClass FINAL : public HInstruction { static constexpr size_t kFieldLoadKind = kFlagGenerateClInitCheck + 1; static constexpr size_t kFieldLoadKindSize = MinimumBitsToStore(static_cast<size_t>(LoadKind::kLast)); - static constexpr size_t kFlagValidLoadedClassRTI = kFieldLoadKind + kFieldLoadKindSize; - static constexpr size_t kNumberOfLoadClassPackedBits = kFlagValidLoadedClassRTI + 1; + static constexpr size_t kNumberOfLoadClassPackedBits = kFieldLoadKind + kFieldLoadKindSize; static_assert(kNumberOfLoadClassPackedBits < kMaxNumberOfPackedBits, "Too many packed fields."); using LoadKindField = BitField<LoadKind, kFieldLoadKind, kFieldLoadKindSize>; @@ -6103,6 +6322,8 @@ class HLoadClass FINAL : public HInstruction { const DexFile& dex_file_; Handle<mirror::Class> klass_; + + ReferenceTypeInfo loaded_class_rti_; }; std::ostream& operator<<(std::ostream& os, HLoadClass::LoadKind rhs); @@ -6167,7 +6388,7 @@ class HLoadString FINAL : public HInstruction { dex::StringIndex string_index, const DexFile& dex_file, uint32_t dex_pc) - : HInstruction(SideEffectsForArchRuntimeCalls(), dex_pc), + : HInstruction(kLoadString, SideEffectsForArchRuntimeCalls(), dex_pc), special_input_(HUserRecord<HInstruction*>(current_method)), string_index_(string_index), dex_file_(dex_file) { @@ -6304,6 +6525,7 @@ class HClinitCheck FINAL : public HExpression<1> { public: HClinitCheck(HLoadClass* constant, uint32_t dex_pc) : HExpression( + kClinitCheck, DataType::Type::kReference, SideEffects::AllExceptGCDependency(), // Assume write/read on all fields/arrays. dex_pc) { @@ -6346,7 +6568,10 @@ class HStaticFieldGet FINAL : public HExpression<1> { uint16_t declaring_class_def_index, const DexFile& dex_file, uint32_t dex_pc) - : HExpression(field_type, SideEffects::FieldReadOfType(field_type, is_volatile), dex_pc), + : HExpression(kStaticFieldGet, + field_type, + SideEffects::FieldReadOfType(field_type, is_volatile), + dex_pc), field_info_(field, field_offset, field_type, @@ -6403,7 +6628,9 @@ class HStaticFieldSet FINAL : public HTemplateInstruction<2> { uint16_t declaring_class_def_index, const DexFile& dex_file, uint32_t dex_pc) - : HTemplateInstruction(SideEffects::FieldWriteOfType(field_type, is_volatile), dex_pc), + : HTemplateInstruction(kStaticFieldSet, + SideEffects::FieldWriteOfType(field_type, is_volatile), + dex_pc), field_info_(field, field_offset, field_type, @@ -6446,7 +6673,10 @@ class HUnresolvedInstanceFieldGet FINAL : public HExpression<1> { DataType::Type field_type, uint32_t field_index, uint32_t dex_pc) - : HExpression(field_type, SideEffects::AllExceptGCDependency(), dex_pc), + : HExpression(kUnresolvedInstanceFieldGet, + field_type, + SideEffects::AllExceptGCDependency(), + dex_pc), field_index_(field_index) { SetRawInputAt(0, obj); } @@ -6474,7 +6704,9 @@ class HUnresolvedInstanceFieldSet FINAL : public HTemplateInstruction<2> { DataType::Type field_type, uint32_t field_index, uint32_t dex_pc) - : HTemplateInstruction(SideEffects::AllExceptGCDependency(), dex_pc), + : HTemplateInstruction(kUnresolvedInstanceFieldSet, + SideEffects::AllExceptGCDependency(), + dex_pc), field_index_(field_index) { SetPackedField<FieldTypeField>(field_type); DCHECK_EQ(DataType::Kind(field_type), DataType::Kind(value->GetType())); @@ -6512,7 +6744,10 @@ class HUnresolvedStaticFieldGet FINAL : public HExpression<0> { HUnresolvedStaticFieldGet(DataType::Type field_type, uint32_t field_index, uint32_t dex_pc) - : HExpression(field_type, SideEffects::AllExceptGCDependency(), dex_pc), + : HExpression(kUnresolvedStaticFieldGet, + field_type, + SideEffects::AllExceptGCDependency(), + dex_pc), field_index_(field_index) { } @@ -6538,7 +6773,9 @@ class HUnresolvedStaticFieldSet FINAL : public HTemplateInstruction<1> { DataType::Type field_type, uint32_t field_index, uint32_t dex_pc) - : HTemplateInstruction(SideEffects::AllExceptGCDependency(), dex_pc), + : HTemplateInstruction(kUnresolvedStaticFieldSet, + SideEffects::AllExceptGCDependency(), + dex_pc), field_index_(field_index) { SetPackedField<FieldTypeField>(field_type); DCHECK_EQ(DataType::Kind(field_type), DataType::Kind(value->GetType())); @@ -6574,7 +6811,8 @@ class HUnresolvedStaticFieldSet FINAL : public HTemplateInstruction<1> { class HLoadException FINAL : public HExpression<0> { public: explicit HLoadException(uint32_t dex_pc = kNoDexPc) - : HExpression(DataType::Type::kReference, SideEffects::None(), dex_pc) {} + : HExpression(kLoadException, DataType::Type::kReference, SideEffects::None(), dex_pc) { + } bool CanBeNull() const OVERRIDE { return false; } @@ -6589,7 +6827,8 @@ class HLoadException FINAL : public HExpression<0> { class HClearException FINAL : public HTemplateInstruction<0> { public: explicit HClearException(uint32_t dex_pc = kNoDexPc) - : HTemplateInstruction(SideEffects::AllWrites(), dex_pc) {} + : HTemplateInstruction(kClearException, SideEffects::AllWrites(), dex_pc) { + } DECLARE_INSTRUCTION(ClearException); @@ -6600,7 +6839,7 @@ class HClearException FINAL : public HTemplateInstruction<0> { class HThrow FINAL : public HTemplateInstruction<1> { public: HThrow(HInstruction* exception, uint32_t dex_pc) - : HTemplateInstruction(SideEffects::CanTriggerGC(), dex_pc) { + : HTemplateInstruction(kThrow, SideEffects::CanTriggerGC(), dex_pc) { SetRawInputAt(0, exception); } @@ -6630,143 +6869,50 @@ enum class TypeCheckKind { kInterfaceCheck, // No optimization yet when checking against an interface. kArrayObjectCheck, // Can just check if the array is not primitive. kArrayCheck, // No optimization yet when checking against a generic array. - kBitstringCheck, // Compare the type check bitstring. kLast = kArrayCheck }; std::ostream& operator<<(std::ostream& os, TypeCheckKind rhs); -// Note: HTypeCheckInstruction is just a helper class, not an abstract instruction with an -// `IsTypeCheckInstruction()`. (New virtual methods in the HInstruction class have a high cost.) -class HTypeCheckInstruction : public HVariableInputSizeInstruction { +class HInstanceOf FINAL : public HExpression<2> { public: - HTypeCheckInstruction(HInstruction* object, - HInstruction* target_class_or_null, - TypeCheckKind check_kind, - Handle<mirror::Class> klass, - uint32_t dex_pc, - ArenaAllocator* allocator, - HIntConstant* bitstring_path_to_root, - HIntConstant* bitstring_mask, - SideEffects side_effects) - : HVariableInputSizeInstruction( - side_effects, - dex_pc, - allocator, - /* number_of_inputs */ check_kind == TypeCheckKind::kBitstringCheck ? 4u : 2u, - kArenaAllocTypeCheckInputs), - klass_(klass) { + HInstanceOf(HInstruction* object, + HLoadClass* target_class, + TypeCheckKind check_kind, + uint32_t dex_pc) + : HExpression(kInstanceOf, + DataType::Type::kBool, + SideEffectsForArchRuntimeCalls(check_kind), + dex_pc) { SetPackedField<TypeCheckKindField>(check_kind); SetPackedFlag<kFlagMustDoNullCheck>(true); - SetPackedFlag<kFlagValidTargetClassRTI>(false); SetRawInputAt(0, object); - SetRawInputAt(1, target_class_or_null); - DCHECK_EQ(check_kind == TypeCheckKind::kBitstringCheck, bitstring_path_to_root != nullptr); - DCHECK_EQ(check_kind == TypeCheckKind::kBitstringCheck, bitstring_mask != nullptr); - if (check_kind == TypeCheckKind::kBitstringCheck) { - DCHECK(target_class_or_null->IsNullConstant()); - SetRawInputAt(2, bitstring_path_to_root); - SetRawInputAt(3, bitstring_mask); - } else { - DCHECK(target_class_or_null->IsLoadClass()); - } + SetRawInputAt(1, target_class); } HLoadClass* GetTargetClass() const { - DCHECK_NE(GetTypeCheckKind(), TypeCheckKind::kBitstringCheck); HInstruction* load_class = InputAt(1); DCHECK(load_class->IsLoadClass()); return load_class->AsLoadClass(); } - uint32_t GetBitstringPathToRoot() const { - DCHECK_EQ(GetTypeCheckKind(), TypeCheckKind::kBitstringCheck); - HInstruction* path_to_root = InputAt(2); - DCHECK(path_to_root->IsIntConstant()); - return static_cast<uint32_t>(path_to_root->AsIntConstant()->GetValue()); - } - - uint32_t GetBitstringMask() const { - DCHECK_EQ(GetTypeCheckKind(), TypeCheckKind::kBitstringCheck); - HInstruction* mask = InputAt(3); - DCHECK(mask->IsIntConstant()); - return static_cast<uint32_t>(mask->AsIntConstant()->GetValue()); - } - bool IsClonable() const OVERRIDE { return true; } bool CanBeMoved() const OVERRIDE { return true; } - bool InstructionDataEquals(const HInstruction* other) const OVERRIDE { - DCHECK(other->IsInstanceOf() || other->IsCheckCast()) << other->DebugName(); - return GetPackedFields() == down_cast<const HTypeCheckInstruction*>(other)->GetPackedFields(); + bool InstructionDataEquals(const HInstruction* other ATTRIBUTE_UNUSED) const OVERRIDE { + return true; } + bool NeedsEnvironment() const OVERRIDE { + return CanCallRuntime(GetTypeCheckKind()); + } + + // Used only in code generation. bool MustDoNullCheck() const { return GetPackedFlag<kFlagMustDoNullCheck>(); } void ClearMustDoNullCheck() { SetPackedFlag<kFlagMustDoNullCheck>(false); } TypeCheckKind GetTypeCheckKind() const { return GetPackedField<TypeCheckKindField>(); } bool IsExactCheck() const { return GetTypeCheckKind() == TypeCheckKind::kExactCheck; } - ReferenceTypeInfo GetTargetClassRTI() { - if (GetPackedFlag<kFlagValidTargetClassRTI>()) { - // Note: The is_exact flag from the return value should not be used. - return ReferenceTypeInfo::CreateUnchecked(klass_, /* is_exact */ true); - } else { - return ReferenceTypeInfo::CreateInvalid(); - } - } - - // Target class RTI is marked as valid by RTP if the klass_ is admissible. - void SetValidTargetClassRTI() REQUIRES_SHARED(Locks::mutator_lock_) { - DCHECK(klass_ != nullptr); - SetPackedFlag<kFlagValidTargetClassRTI>(true); - } - - Handle<mirror::Class> GetClass() const { - return klass_; - } - - protected: - DEFAULT_COPY_CONSTRUCTOR(TypeCheckInstruction); - - private: - static constexpr size_t kFieldTypeCheckKind = kNumberOfGenericPackedBits; - static constexpr size_t kFieldTypeCheckKindSize = - MinimumBitsToStore(static_cast<size_t>(TypeCheckKind::kLast)); - static constexpr size_t kFlagMustDoNullCheck = kFieldTypeCheckKind + kFieldTypeCheckKindSize; - static constexpr size_t kFlagValidTargetClassRTI = kFlagMustDoNullCheck + 1; - static constexpr size_t kNumberOfInstanceOfPackedBits = kFlagValidTargetClassRTI + 1; - static_assert(kNumberOfInstanceOfPackedBits <= kMaxNumberOfPackedBits, "Too many packed fields."); - using TypeCheckKindField = BitField<TypeCheckKind, kFieldTypeCheckKind, kFieldTypeCheckKindSize>; - - Handle<mirror::Class> klass_; -}; - -class HInstanceOf FINAL : public HTypeCheckInstruction { - public: - HInstanceOf(HInstruction* object, - HInstruction* target_class_or_null, - TypeCheckKind check_kind, - Handle<mirror::Class> klass, - uint32_t dex_pc, - ArenaAllocator* allocator, - HIntConstant* bitstring_path_to_root, - HIntConstant* bitstring_mask) - : HTypeCheckInstruction(object, - target_class_or_null, - check_kind, - klass, - dex_pc, - allocator, - bitstring_path_to_root, - bitstring_mask, - SideEffectsForArchRuntimeCalls(check_kind)) {} - - DataType::Type GetType() const OVERRIDE { return DataType::Type::kBool; } - - bool NeedsEnvironment() const OVERRIDE { - return CanCallRuntime(GetTypeCheckKind()); - } - static bool CanCallRuntime(TypeCheckKind check_kind) { // Mips currently does runtime calls for any other checks. return check_kind != TypeCheckKind::kExactCheck; @@ -6780,12 +6926,21 @@ class HInstanceOf FINAL : public HTypeCheckInstruction { protected: DEFAULT_COPY_CONSTRUCTOR(InstanceOf); + + private: + static constexpr size_t kFieldTypeCheckKind = kNumberOfExpressionPackedBits; + static constexpr size_t kFieldTypeCheckKindSize = + MinimumBitsToStore(static_cast<size_t>(TypeCheckKind::kLast)); + static constexpr size_t kFlagMustDoNullCheck = kFieldTypeCheckKind + kFieldTypeCheckKindSize; + static constexpr size_t kNumberOfInstanceOfPackedBits = kFlagMustDoNullCheck + 1; + static_assert(kNumberOfInstanceOfPackedBits <= kMaxNumberOfPackedBits, "Too many packed fields."); + using TypeCheckKindField = BitField<TypeCheckKind, kFieldTypeCheckKind, kFieldTypeCheckKindSize>; }; class HBoundType FINAL : public HExpression<1> { public: explicit HBoundType(HInstruction* input, uint32_t dex_pc = kNoDexPc) - : HExpression(DataType::Type::kReference, SideEffects::None(), dex_pc), + : HExpression(kBoundType, DataType::Type::kReference, SideEffects::None(), dex_pc), upper_bound_(ReferenceTypeInfo::CreateInvalid()) { SetPackedFlag<kFlagUpperCanBeNull>(true); SetPackedFlag<kFlagCanBeNull>(true); @@ -6829,25 +6984,31 @@ class HBoundType FINAL : public HExpression<1> { ReferenceTypeInfo upper_bound_; }; -class HCheckCast FINAL : public HTypeCheckInstruction { +class HCheckCast FINAL : public HTemplateInstruction<2> { public: HCheckCast(HInstruction* object, - HInstruction* target_class_or_null, + HLoadClass* target_class, TypeCheckKind check_kind, - Handle<mirror::Class> klass, - uint32_t dex_pc, - ArenaAllocator* allocator, - HIntConstant* bitstring_path_to_root, - HIntConstant* bitstring_mask) - : HTypeCheckInstruction(object, - target_class_or_null, - check_kind, - klass, - dex_pc, - allocator, - bitstring_path_to_root, - bitstring_mask, - SideEffects::CanTriggerGC()) {} + uint32_t dex_pc) + : HTemplateInstruction(kCheckCast, SideEffects::CanTriggerGC(), dex_pc) { + SetPackedField<TypeCheckKindField>(check_kind); + SetPackedFlag<kFlagMustDoNullCheck>(true); + SetRawInputAt(0, object); + SetRawInputAt(1, target_class); + } + + HLoadClass* GetTargetClass() const { + HInstruction* load_class = InputAt(1); + DCHECK(load_class->IsLoadClass()); + return load_class->AsLoadClass(); + } + + bool IsClonable() const OVERRIDE { return true; } + bool CanBeMoved() const OVERRIDE { return true; } + + bool InstructionDataEquals(const HInstruction* other ATTRIBUTE_UNUSED) const OVERRIDE { + return true; + } bool NeedsEnvironment() const OVERRIDE { // Instruction may throw a CheckCastError. @@ -6856,10 +7017,24 @@ class HCheckCast FINAL : public HTypeCheckInstruction { bool CanThrow() const OVERRIDE { return true; } + bool MustDoNullCheck() const { return GetPackedFlag<kFlagMustDoNullCheck>(); } + void ClearMustDoNullCheck() { SetPackedFlag<kFlagMustDoNullCheck>(false); } + TypeCheckKind GetTypeCheckKind() const { return GetPackedField<TypeCheckKindField>(); } + bool IsExactCheck() const { return GetTypeCheckKind() == TypeCheckKind::kExactCheck; } + DECLARE_INSTRUCTION(CheckCast); protected: DEFAULT_COPY_CONSTRUCTOR(CheckCast); + + private: + static constexpr size_t kFieldTypeCheckKind = kNumberOfGenericPackedBits; + static constexpr size_t kFieldTypeCheckKindSize = + MinimumBitsToStore(static_cast<size_t>(TypeCheckKind::kLast)); + static constexpr size_t kFlagMustDoNullCheck = kFieldTypeCheckKind + kFieldTypeCheckKindSize; + static constexpr size_t kNumberOfCheckCastPackedBits = kFlagMustDoNullCheck + 1; + static_assert(kNumberOfCheckCastPackedBits <= kMaxNumberOfPackedBits, "Too many packed fields."); + using TypeCheckKindField = BitField<TypeCheckKind, kFieldTypeCheckKind, kFieldTypeCheckKindSize>; }; /** @@ -6892,7 +7067,9 @@ class HMemoryBarrier FINAL : public HTemplateInstruction<0> { public: explicit HMemoryBarrier(MemBarrierKind barrier_kind, uint32_t dex_pc = kNoDexPc) : HTemplateInstruction( - SideEffects::AllWritesAndReads(), dex_pc) { // Assume write/read on all fields/arrays. + kMemoryBarrier, + SideEffects::AllWritesAndReads(), // Assume write/read on all fields/arrays. + dex_pc) { SetPackedField<BarrierKindField>(barrier_kind); } @@ -7011,7 +7188,8 @@ class HConstructorFence FINAL : public HVariableInputSizeInstruction { // // If in a later phase we discover that there are no writes to reference final fields, // we can refine the side effect to a smaller set of type reads (see above constraints). - : HVariableInputSizeInstruction(SideEffects::AllReads(), + : HVariableInputSizeInstruction(kConstructorFence, + SideEffects::AllReads(), dex_pc, allocator, /* number_of_inputs */ 1, @@ -7078,6 +7256,7 @@ class HMonitorOperation FINAL : public HTemplateInstruction<1> { HMonitorOperation(HInstruction* object, OperationKind kind, uint32_t dex_pc) : HTemplateInstruction( + kMonitorOperation, SideEffects::AllExceptGCDependency(), // Assume write/read on all fields/arrays. dex_pc) { SetPackedField<OperationKindField>(kind); @@ -7119,7 +7298,7 @@ class HSelect FINAL : public HExpression<3> { HInstruction* true_value, HInstruction* false_value, uint32_t dex_pc) - : HExpression(HPhi::ToPhiType(true_value->GetType()), SideEffects::None(), dex_pc) { + : HExpression(kSelect, HPhi::ToPhiType(true_value->GetType()), SideEffects::None(), dex_pc) { DCHECK_EQ(HPhi::ToPhiType(true_value->GetType()), HPhi::ToPhiType(false_value->GetType())); // First input must be `true_value` or `false_value` to allow codegens to @@ -7232,7 +7411,7 @@ static constexpr size_t kDefaultNumberOfMoves = 4; class HParallelMove FINAL : public HTemplateInstruction<0> { public: explicit HParallelMove(ArenaAllocator* allocator, uint32_t dex_pc = kNoDexPc) - : HTemplateInstruction(SideEffects::None(), dex_pc), + : HTemplateInstruction(kParallelMove, SideEffects::None(), dex_pc), moves_(allocator->Adapter(kArenaAllocMoveOperands)) { moves_.reserve(kDefaultNumberOfMoves); } @@ -7294,7 +7473,10 @@ class HParallelMove FINAL : public HTemplateInstruction<0> { class HIntermediateAddress FINAL : public HExpression<2> { public: HIntermediateAddress(HInstruction* base_address, HInstruction* offset, uint32_t dex_pc) - : HExpression(DataType::Type::kInt32, SideEffects::DependsOnGC(), dex_pc) { + : HExpression(kIntermediateAddress, + DataType::Type::kInt32, + SideEffects::DependsOnGC(), + dex_pc) { DCHECK_EQ(DataType::Size(DataType::Type::kInt32), DataType::Size(DataType::Type::kReference)) << "kPrimInt and kPrimNot have different sizes."; |