summaryrefslogtreecommitdiff
path: root/compiler/optimizing/nodes.h
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/optimizing/nodes.h')
-rw-r--r--compiler/optimizing/nodes.h713
1 files changed, 348 insertions, 365 deletions
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index 6f3e536d05..da84afbb39 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -36,6 +36,8 @@
#include "offsets.h"
#include "primitive.h"
#include "utils/array_ref.h"
+#include "utils/intrusive_forward_list.h"
+#include "utils/transform_array_ref.h"
namespace art {
@@ -169,7 +171,7 @@ class ReferenceTypeInfo : ValueObject {
return handle.GetReference() != nullptr;
}
- bool IsValid() const SHARED_REQUIRES(Locks::mutator_lock_) {
+ bool IsValid() const {
return IsValidHandle(type_handle_);
}
@@ -649,6 +651,7 @@ class HLoopInformation : public ArenaObject<kArenaAllocLoopInfo> {
: header_(header),
suspend_check_(nullptr),
irreducible_(false),
+ contains_irreducible_loop_(false),
back_edges_(graph->GetArena()->Adapter(kArenaAllocLoopInfoBackEdges)),
// Make bit vector growable, as the number of blocks may change.
blocks_(graph->GetArena(), graph->GetBlocks().size(), true, kArenaAllocLoopInfoBackEdges) {
@@ -656,6 +659,7 @@ class HLoopInformation : public ArenaObject<kArenaAllocLoopInfo> {
}
bool IsIrreducible() const { return irreducible_; }
+ bool ContainsIrreducibleLoop() const { return contains_irreducible_loop_; }
void Dump(std::ostream& os);
@@ -724,6 +728,14 @@ class HLoopInformation : public ArenaObject<kArenaAllocLoopInfo> {
blocks_.ClearAllBits();
}
+ bool HasBackEdgeNotDominatedByHeader() const;
+
+ bool IsPopulated() const {
+ return blocks_.GetHighestBitSet() != -1;
+ }
+
+ bool DominatesAllBackEdges(HBasicBlock* block);
+
private:
// Internal recursive implementation of `Populate`.
void PopulateRecursive(HBasicBlock* block);
@@ -732,6 +744,7 @@ class HLoopInformation : public ArenaObject<kArenaAllocLoopInfo> {
HBasicBlock* header_;
HSuspendCheck* suspend_check_;
bool irreducible_;
+ bool contains_irreducible_loop_;
ArenaVector<HBasicBlock*> back_edges_;
ArenaBitVector blocks_;
@@ -1321,12 +1334,12 @@ class HLoopInformationOutwardIterator : public ValueObject {
FOR_EACH_INSTRUCTION(FORWARD_DECLARATION)
#undef FORWARD_DECLARATION
-#define DECLARE_INSTRUCTION(type) \
- InstructionKind GetKindInternal() const OVERRIDE { return k##type; } \
- const char* DebugName() const OVERRIDE { return #type; } \
- bool InstructionTypeEquals(HInstruction* other) const OVERRIDE { \
- return other->Is##type(); \
- } \
+#define DECLARE_INSTRUCTION(type) \
+ 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(); \
+ } \
void Accept(HGraphVisitor* visitor) OVERRIDE
#define DECLARE_ABSTRACT_INSTRUCTION(type) \
@@ -1334,127 +1347,31 @@ FOR_EACH_INSTRUCTION(FORWARD_DECLARATION)
const H##type* As##type() const { return this; } \
H##type* As##type() { return this; }
-template <typename T> class HUseList;
-
template <typename T>
class HUseListNode : public ArenaObject<kArenaAllocUseListNode> {
public:
- HUseListNode* GetPrevious() const { return prev_; }
- HUseListNode* GetNext() const { return next_; }
T GetUser() const { return user_; }
size_t GetIndex() const { return index_; }
void SetIndex(size_t index) { index_ = index; }
+ // Hook for the IntrusiveForwardList<>.
+ // TODO: Hide this better.
+ IntrusiveForwardListHook hook;
+
private:
HUseListNode(T user, size_t index)
- : user_(user), index_(index), prev_(nullptr), next_(nullptr) {}
+ : user_(user), index_(index) {}
T const user_;
size_t index_;
- HUseListNode<T>* prev_;
- HUseListNode<T>* next_;
- friend class HUseList<T>;
+ friend class HInstruction;
DISALLOW_COPY_AND_ASSIGN(HUseListNode);
};
template <typename T>
-class HUseList : public ValueObject {
- public:
- HUseList() : first_(nullptr) {}
-
- void Clear() {
- first_ = nullptr;
- }
-
- // Adds a new entry at the beginning of the use list and returns
- // the newly created node.
- HUseListNode<T>* AddUse(T user, size_t index, ArenaAllocator* arena) {
- HUseListNode<T>* new_node = new (arena) HUseListNode<T>(user, index);
- if (IsEmpty()) {
- first_ = new_node;
- } else {
- first_->prev_ = new_node;
- new_node->next_ = first_;
- first_ = new_node;
- }
- return new_node;
- }
-
- HUseListNode<T>* GetFirst() const {
- return first_;
- }
-
- void Remove(HUseListNode<T>* node) {
- DCHECK(node != nullptr);
- DCHECK(Contains(node));
-
- if (node->prev_ != nullptr) {
- node->prev_->next_ = node->next_;
- }
- if (node->next_ != nullptr) {
- node->next_->prev_ = node->prev_;
- }
- if (node == first_) {
- first_ = node->next_;
- }
- }
-
- bool Contains(const HUseListNode<T>* node) const {
- if (node == nullptr) {
- return false;
- }
- for (HUseListNode<T>* current = first_; current != nullptr; current = current->GetNext()) {
- if (current == node) {
- return true;
- }
- }
- return false;
- }
-
- bool IsEmpty() const {
- return first_ == nullptr;
- }
-
- bool HasOnlyOneUse() const {
- return first_ != nullptr && first_->next_ == nullptr;
- }
-
- size_t SizeSlow() const {
- size_t count = 0;
- for (HUseListNode<T>* current = first_; current != nullptr; current = current->GetNext()) {
- ++count;
- }
- return count;
- }
-
- private:
- HUseListNode<T>* first_;
-};
-
-template<typename T>
-class HUseIterator : public ValueObject {
- public:
- explicit HUseIterator(const HUseList<T>& uses) : current_(uses.GetFirst()) {}
-
- bool Done() const { return current_ == nullptr; }
-
- void Advance() {
- DCHECK(!Done());
- current_ = current_->GetNext();
- }
-
- HUseListNode<T>* Current() const {
- DCHECK(!Done());
- return current_;
- }
-
- private:
- HUseListNode<T>* current_;
-
- friend class HValue;
-};
+using HUseList = IntrusiveForwardList<HUseListNode<T>>;
// This class is used by HEnvironment and HInstruction classes to record the
// instructions they use and pointers to the corresponding HUseListNodes kept
@@ -1462,25 +1379,26 @@ class HUseIterator : public ValueObject {
template <typename T>
class HUserRecord : public ValueObject {
public:
- HUserRecord() : instruction_(nullptr), use_node_(nullptr) {}
- explicit HUserRecord(HInstruction* instruction) : instruction_(instruction), use_node_(nullptr) {}
+ HUserRecord() : instruction_(nullptr), before_use_node_() {}
+ explicit HUserRecord(HInstruction* instruction) : instruction_(instruction), before_use_node_() {}
- HUserRecord(const HUserRecord<T>& old_record, HUseListNode<T>* use_node)
- : instruction_(old_record.instruction_), use_node_(use_node) {
+ HUserRecord(const HUserRecord<T>& old_record, typename HUseList<T>::iterator before_use_node)
+ : HUserRecord(old_record.instruction_, before_use_node) {}
+ HUserRecord(HInstruction* instruction, typename HUseList<T>::iterator before_use_node)
+ : instruction_(instruction), before_use_node_(before_use_node) {
DCHECK(instruction_ != nullptr);
- DCHECK(use_node_ != nullptr);
- DCHECK(old_record.use_node_ == nullptr);
}
HInstruction* GetInstruction() const { return instruction_; }
- HUseListNode<T>* GetUseNode() const { return use_node_; }
+ typename HUseList<T>::iterator GetBeforeUseNode() const { return before_use_node_; }
+ typename HUseList<T>::iterator GetUseNode() const { return ++GetBeforeUseNode(); }
private:
// Instruction used by the user.
HInstruction* instruction_;
- // Corresponding entry in the use list kept by 'instruction_'.
- HUseListNode<T>* use_node_;
+ // Iterator before the corresponding entry in the use list kept by 'instruction_'.
+ typename HUseList<T>::iterator before_use_node_;
};
/**
@@ -1805,14 +1723,6 @@ class HEnvironment : public ArenaObject<kArenaAllocEnvironment> {
}
private:
- // Record instructions' use entries of this environment for constant-time removal.
- // It should only be called by HInstruction when a new environment use is added.
- void RecordEnvUse(HUseListNode<HEnvironment*>* env_use) {
- DCHECK(env_use->GetUser() == this);
- size_t index = env_use->GetIndex();
- vregs_[index] = HUserRecord<HEnvironment*>(vregs_[index], env_use);
- }
-
ArenaVector<HUserRecord<HEnvironment*>> vregs_;
ArenaVector<Location> locations_;
HEnvironment* parent_;
@@ -1872,16 +1782,41 @@ class HInstruction : public ArenaObject<kArenaAllocInstruction> {
return IsLoopHeaderPhi() && GetBlock()->GetLoopInformation()->IsIrreducible();
}
- virtual size_t InputCount() const = 0;
+ virtual ArrayRef<HUserRecord<HInstruction*>> GetInputRecords() = 0;
+
+ ArrayRef<const HUserRecord<HInstruction*>> GetInputRecords() const {
+ // One virtual method is enough, just const_cast<> and then re-add the const.
+ return ArrayRef<const HUserRecord<HInstruction*>>(
+ const_cast<HInstruction*>(this)->GetInputRecords());
+ }
+
+ auto GetInputs() {
+ return MakeTransformArrayRef(
+ GetInputRecords(),
+ [](HUserRecord<HInstruction*>& record) -> HInstruction* {
+ return record.GetInstruction();
+ });
+ }
+
+ auto GetInputs() const {
+ return MakeTransformArrayRef(
+ GetInputRecords(),
+ [](const HUserRecord<HInstruction*>& record) -> const HInstruction* {
+ return record.GetInstruction();
+ });
+ }
+
+ size_t InputCount() const { return GetInputRecords().size(); }
HInstruction* InputAt(size_t i) const { return InputRecordAt(i).GetInstruction(); }
+ void SetRawInputAt(size_t index, HInstruction* input) {
+ SetRawInputRecordAt(index, HUserRecord<HInstruction*>(input));
+ }
+
virtual void Accept(HGraphVisitor* visitor) = 0;
virtual const char* DebugName() const = 0;
virtual Primitive::Type GetType() const { return Primitive::kPrimVoid; }
- void SetRawInputAt(size_t index, HInstruction* input) {
- SetRawInputRecordAt(index, HUserRecord<HInstruction*>(input));
- }
virtual bool NeedsEnvironment() const { return false; }
@@ -1916,36 +1851,52 @@ class HInstruction : public ArenaObject<kArenaAllocInstruction> {
ReferenceTypeInfo GetReferenceTypeInfo() const {
DCHECK_EQ(GetType(), Primitive::kPrimNot);
return ReferenceTypeInfo::CreateUnchecked(reference_type_handle_,
- GetPackedFlag<kFlagReferenceTypeIsExact>());;
+ GetPackedFlag<kFlagReferenceTypeIsExact>());
}
void AddUseAt(HInstruction* user, size_t index) {
DCHECK(user != nullptr);
- HUseListNode<HInstruction*>* use =
- uses_.AddUse(user, index, GetBlock()->GetGraph()->GetArena());
- user->SetRawInputRecordAt(index, HUserRecord<HInstruction*>(user->InputRecordAt(index), use));
+ // Note: fixup_end remains valid across push_front().
+ auto fixup_end = uses_.empty() ? uses_.begin() : ++uses_.begin();
+ HUseListNode<HInstruction*>* new_node =
+ new (GetBlock()->GetGraph()->GetArena()) HUseListNode<HInstruction*>(user, index);
+ uses_.push_front(*new_node);
+ FixUpUserRecordsAfterUseInsertion(fixup_end);
}
void AddEnvUseAt(HEnvironment* user, size_t index) {
DCHECK(user != nullptr);
- HUseListNode<HEnvironment*>* env_use =
- env_uses_.AddUse(user, index, GetBlock()->GetGraph()->GetArena());
- user->RecordEnvUse(env_use);
+ // Note: env_fixup_end remains valid across push_front().
+ auto env_fixup_end = env_uses_.empty() ? env_uses_.begin() : ++env_uses_.begin();
+ HUseListNode<HEnvironment*>* new_node =
+ new (GetBlock()->GetGraph()->GetArena()) HUseListNode<HEnvironment*>(user, index);
+ env_uses_.push_front(*new_node);
+ FixUpUserRecordsAfterEnvUseInsertion(env_fixup_end);
}
void RemoveAsUserOfInput(size_t input) {
HUserRecord<HInstruction*> input_use = InputRecordAt(input);
- input_use.GetInstruction()->uses_.Remove(input_use.GetUseNode());
+ HUseList<HInstruction*>::iterator before_use_node = input_use.GetBeforeUseNode();
+ input_use.GetInstruction()->uses_.erase_after(before_use_node);
+ input_use.GetInstruction()->FixUpUserRecordsAfterUseRemoval(before_use_node);
+ }
+
+ void RemoveAsUserOfAllInputs() {
+ for (const HUserRecord<HInstruction*>& input_use : GetInputRecords()) {
+ HUseList<HInstruction*>::iterator before_use_node = input_use.GetBeforeUseNode();
+ input_use.GetInstruction()->uses_.erase_after(before_use_node);
+ input_use.GetInstruction()->FixUpUserRecordsAfterUseRemoval(before_use_node);
+ }
}
const HUseList<HInstruction*>& GetUses() const { return uses_; }
const HUseList<HEnvironment*>& GetEnvUses() const { return env_uses_; }
- bool HasUses() const { return !uses_.IsEmpty() || !env_uses_.IsEmpty(); }
- bool HasEnvironmentUses() const { return !env_uses_.IsEmpty(); }
- bool HasNonEnvironmentUses() const { return !uses_.IsEmpty(); }
+ bool HasUses() const { return !uses_.empty() || !env_uses_.empty(); }
+ bool HasEnvironmentUses() const { return !env_uses_.empty(); }
+ bool HasNonEnvironmentUses() const { return !uses_.empty(); }
bool HasOnlyOneNonEnvironmentUse() const {
- return !HasEnvironmentUses() && GetUses().HasOnlyOneUse();
+ return !HasEnvironmentUses() && GetUses().HasExactlyOneElement();
}
// Does this instruction strictly dominate `other_instruction`?
@@ -2042,21 +1993,21 @@ class HInstruction : public ArenaObject<kArenaAllocInstruction> {
virtual bool CanBeMoved() const { return false; }
// Returns whether the two instructions are of the same kind.
- virtual bool InstructionTypeEquals(HInstruction* other ATTRIBUTE_UNUSED) const {
+ virtual bool InstructionTypeEquals(const HInstruction* other ATTRIBUTE_UNUSED) const {
return false;
}
// Returns whether any data encoded in the two instructions is equal.
// This method does not look at the inputs. Both instructions must be
// of the same type, otherwise the method has undefined behavior.
- virtual bool InstructionDataEquals(HInstruction* other ATTRIBUTE_UNUSED) const {
+ virtual bool InstructionDataEquals(const HInstruction* other ATTRIBUTE_UNUSED) const {
return false;
}
// Returns whether two instructions are equal, that is:
// 1) They have the same type and contain the same data (InstructionDataEquals).
// 2) Their inputs are identical.
- bool Equals(HInstruction* other) const;
+ bool Equals(const HInstruction* other) const;
// TODO: Remove this indirection when the [[pure]] attribute proposal (n3744)
// is adopted and implemented by our C++ compiler(s). Fow now, we need to hide
@@ -2067,8 +2018,8 @@ class HInstruction : public ArenaObject<kArenaAllocInstruction> {
virtual size_t ComputeHashCode() const {
size_t result = GetKind();
- for (size_t i = 0, e = InputCount(); i < e; ++i) {
- result = (result * 31) + InputAt(i)->GetId();
+ for (const HInstruction* input : GetInputs()) {
+ result = (result * 31) + input->GetId();
}
return result;
}
@@ -2118,8 +2069,14 @@ class HInstruction : public ArenaObject<kArenaAllocInstruction> {
static constexpr size_t kNumberOfGenericPackedBits = kFlagReferenceTypeIsExact + 1;
static constexpr size_t kMaxNumberOfPackedBits = sizeof(uint32_t) * kBitsPerByte;
- virtual const HUserRecord<HInstruction*> InputRecordAt(size_t i) const = 0;
- virtual void SetRawInputRecordAt(size_t index, const HUserRecord<HInstruction*>& input) = 0;
+ const HUserRecord<HInstruction*> InputRecordAt(size_t i) const {
+ return GetInputRecords()[i];
+ }
+
+ void SetRawInputRecordAt(size_t index, const HUserRecord<HInstruction*>& input) {
+ ArrayRef<HUserRecord<HInstruction*>> input_records = GetInputRecords();
+ input_records[index] = input;
+ }
uint32_t GetPackedFields() const {
return packed_fields_;
@@ -2147,7 +2104,45 @@ class HInstruction : public ArenaObject<kArenaAllocInstruction> {
}
private:
- void RemoveEnvironmentUser(HUseListNode<HEnvironment*>* use_node) { env_uses_.Remove(use_node); }
+ 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) {
+ HInstruction* user = use_node->GetUser();
+ size_t input_index = use_node->GetIndex();
+ user->SetRawInputRecordAt(input_index, HUserRecord<HInstruction*>(this, before_use_node));
+ before_use_node = use_node;
+ }
+ }
+
+ void FixUpUserRecordsAfterUseRemoval(HUseList<HInstruction*>::iterator before_use_node) {
+ auto next = ++HUseList<HInstruction*>::iterator(before_use_node);
+ if (next != uses_.end()) {
+ HInstruction* next_user = next->GetUser();
+ size_t next_index = next->GetIndex();
+ DCHECK(next_user->InputRecordAt(next_index).GetInstruction() == this);
+ next_user->SetRawInputRecordAt(next_index, HUserRecord<HInstruction*>(this, before_use_node));
+ }
+ }
+
+ void FixUpUserRecordsAfterEnvUseInsertion(HUseList<HEnvironment*>::iterator env_fixup_end) {
+ auto before_env_use_node = env_uses_.before_begin();
+ for (auto env_use_node = env_uses_.begin(); env_use_node != env_fixup_end; ++env_use_node) {
+ HEnvironment* user = env_use_node->GetUser();
+ size_t input_index = env_use_node->GetIndex();
+ user->vregs_[input_index] = HUserRecord<HEnvironment*>(this, before_env_use_node);
+ before_env_use_node = env_use_node;
+ }
+ }
+
+ void FixUpUserRecordsAfterEnvUseRemoval(HUseList<HEnvironment*>::iterator before_env_use_node) {
+ auto next = ++HUseList<HEnvironment*>::iterator(before_env_use_node);
+ if (next != env_uses_.end()) {
+ HEnvironment* next_user = next->GetUser();
+ size_t next_index = next->GetIndex();
+ DCHECK(next_user->vregs_[next_index].GetInstruction() == this);
+ next_user->vregs_[next_index] = HUserRecord<HEnvironment*>(this, before_env_use_node);
+ }
+ }
HInstruction* previous_;
HInstruction* next_;
@@ -2202,21 +2197,6 @@ class HInstruction : public ArenaObject<kArenaAllocInstruction> {
};
std::ostream& operator<<(std::ostream& os, const HInstruction::InstructionKind& rhs);
-class HInputIterator : public ValueObject {
- public:
- explicit HInputIterator(HInstruction* instruction) : instruction_(instruction), index_(0) {}
-
- bool Done() const { return index_ == instruction_->InputCount(); }
- HInstruction* Current() const { return instruction_->InputAt(index_); }
- void Advance() { index_++; }
-
- private:
- HInstruction* instruction_;
- size_t index_;
-
- DISALLOW_COPY_AND_ASSIGN(HInputIterator);
-};
-
class HInstructionIterator : public ValueObject {
public:
explicit HInstructionIterator(const HInstructionList& instructions)
@@ -2266,17 +2246,9 @@ class HTemplateInstruction: public HInstruction {
: HInstruction(side_effects, dex_pc), inputs_() {}
virtual ~HTemplateInstruction() {}
- size_t InputCount() const OVERRIDE { return N; }
-
- protected:
- const HUserRecord<HInstruction*> InputRecordAt(size_t i) const OVERRIDE {
- DCHECK_LT(i, N);
- return inputs_[i];
- }
-
- void SetRawInputRecordAt(size_t i, const HUserRecord<HInstruction*>& input) OVERRIDE {
- DCHECK_LT(i, N);
- inputs_[i] = input;
+ using HInstruction::GetInputRecords; // Keep the const version visible.
+ ArrayRef<HUserRecord<HInstruction*>> GetInputRecords() OVERRIDE FINAL {
+ return ArrayRef<HUserRecord<HInstruction*>>(inputs_);
}
private:
@@ -2294,18 +2266,9 @@ class HTemplateInstruction<0>: public HInstruction {
virtual ~HTemplateInstruction() {}
- size_t InputCount() const OVERRIDE { return 0; }
-
- protected:
- const HUserRecord<HInstruction*> InputRecordAt(size_t i ATTRIBUTE_UNUSED) const OVERRIDE {
- LOG(FATAL) << "Unreachable";
- UNREACHABLE();
- }
-
- void SetRawInputRecordAt(size_t i ATTRIBUTE_UNUSED,
- const HUserRecord<HInstruction*>& input ATTRIBUTE_UNUSED) OVERRIDE {
- LOG(FATAL) << "Unreachable";
- UNREACHABLE();
+ using HInstruction::GetInputRecords; // Keep the const version visible.
+ ArrayRef<HUserRecord<HInstruction*>> GetInputRecords() OVERRIDE FINAL {
+ return ArrayRef<HUserRecord<HInstruction*>>();
}
private:
@@ -2337,7 +2300,7 @@ class HExpression : public HTemplateInstruction<N> {
// Represents dex's RETURN_VOID opcode. A HReturnVoid is a control flow
// instruction that branches to the exit block.
-class HReturnVoid : public HTemplateInstruction<0> {
+class HReturnVoid FINAL : public HTemplateInstruction<0> {
public:
explicit HReturnVoid(uint32_t dex_pc = kNoDexPc)
: HTemplateInstruction(SideEffects::None(), dex_pc) {}
@@ -2352,7 +2315,7 @@ class HReturnVoid : public HTemplateInstruction<0> {
// Represents dex's RETURN opcodes. A HReturn is a control flow
// instruction that branches to the exit block.
-class HReturn : public HTemplateInstruction<1> {
+class HReturn FINAL : public HTemplateInstruction<1> {
public:
explicit HReturn(HInstruction* value, uint32_t dex_pc = kNoDexPc)
: HTemplateInstruction(SideEffects::None(), dex_pc) {
@@ -2367,7 +2330,7 @@ class HReturn : public HTemplateInstruction<1> {
DISALLOW_COPY_AND_ASSIGN(HReturn);
};
-class HPhi : public HInstruction {
+class HPhi FINAL : public HInstruction {
public:
HPhi(ArenaAllocator* arena,
uint32_t reg_number,
@@ -2393,7 +2356,10 @@ class HPhi : public HInstruction {
bool IsCatchPhi() const { return GetBlock()->IsCatchBlock(); }
- size_t InputCount() const OVERRIDE { return inputs_.size(); }
+ using HInstruction::GetInputRecords; // Keep the const version visible.
+ ArrayRef<HUserRecord<HInstruction*>> GetInputRecords() OVERRIDE FINAL {
+ return ArrayRef<HUserRecord<HInstruction*>>(inputs_);
+ }
void AddInput(HInstruction* input);
void RemoveInputAt(size_t index);
@@ -2443,15 +2409,6 @@ class HPhi : public HInstruction {
DECLARE_INSTRUCTION(Phi);
- protected:
- const HUserRecord<HInstruction*> InputRecordAt(size_t index) const OVERRIDE {
- return inputs_[index];
- }
-
- void SetRawInputRecordAt(size_t index, const HUserRecord<HInstruction*>& input) OVERRIDE {
- inputs_[index] = input;
- }
-
private:
static constexpr size_t kFieldType = HInstruction::kNumberOfGenericPackedBits;
static constexpr size_t kFieldTypeSize =
@@ -2462,7 +2419,7 @@ class HPhi : public HInstruction {
static_assert(kNumberOfPhiPackedBits <= kMaxNumberOfPackedBits, "Too many packed fields.");
using TypeField = BitField<Primitive::Type, kFieldType, kFieldTypeSize>;
- ArenaVector<HUserRecord<HInstruction*> > inputs_;
+ ArenaVector<HUserRecord<HInstruction*>> inputs_;
const uint32_t reg_number_;
DISALLOW_COPY_AND_ASSIGN(HPhi);
@@ -2471,7 +2428,7 @@ class HPhi : public HInstruction {
// The exit instruction is the only instruction of the exit block.
// Instructions aborting the method (HThrow and HReturn) must branch to the
// exit block.
-class HExit : public HTemplateInstruction<0> {
+class HExit FINAL : public HTemplateInstruction<0> {
public:
explicit HExit(uint32_t dex_pc = kNoDexPc) : HTemplateInstruction(SideEffects::None(), dex_pc) {}
@@ -2484,7 +2441,7 @@ class HExit : public HTemplateInstruction<0> {
};
// Jumps from one block to another.
-class HGoto : public HTemplateInstruction<0> {
+class HGoto FINAL : public HTemplateInstruction<0> {
public:
explicit HGoto(uint32_t dex_pc = kNoDexPc) : HTemplateInstruction(SideEffects::None(), dex_pc) {}
@@ -2524,9 +2481,9 @@ class HConstant : public HExpression<0> {
DISALLOW_COPY_AND_ASSIGN(HConstant);
};
-class HNullConstant : public HConstant {
+class HNullConstant FINAL : public HConstant {
public:
- bool InstructionDataEquals(HInstruction* other ATTRIBUTE_UNUSED) const OVERRIDE {
+ bool InstructionDataEquals(const HInstruction* other ATTRIBUTE_UNUSED) const OVERRIDE {
return true;
}
@@ -2548,7 +2505,7 @@ class HNullConstant : public HConstant {
// Constants of the type int. Those can be from Dex instructions, or
// synthesized (for example with the if-eqz instruction).
-class HIntConstant : public HConstant {
+class HIntConstant FINAL : public HConstant {
public:
int32_t GetValue() const { return value_; }
@@ -2556,7 +2513,7 @@ class HIntConstant : public HConstant {
return static_cast<uint64_t>(static_cast<uint32_t>(value_));
}
- bool InstructionDataEquals(HInstruction* other) const OVERRIDE {
+ bool InstructionDataEquals(const HInstruction* other) const OVERRIDE {
DCHECK(other->IsIntConstant()) << other->DebugName();
return other->AsIntConstant()->value_ == value_;
}
@@ -2589,13 +2546,13 @@ class HIntConstant : public HConstant {
DISALLOW_COPY_AND_ASSIGN(HIntConstant);
};
-class HLongConstant : public HConstant {
+class HLongConstant FINAL : public HConstant {
public:
int64_t GetValue() const { return value_; }
uint64_t GetValueAsUint64() const OVERRIDE { return value_; }
- bool InstructionDataEquals(HInstruction* other) const OVERRIDE {
+ bool InstructionDataEquals(const HInstruction* other) const OVERRIDE {
DCHECK(other->IsLongConstant()) << other->DebugName();
return other->AsLongConstant()->value_ == value_;
}
@@ -2619,7 +2576,7 @@ class HLongConstant : public HConstant {
DISALLOW_COPY_AND_ASSIGN(HLongConstant);
};
-class HFloatConstant : public HConstant {
+class HFloatConstant FINAL : public HConstant {
public:
float GetValue() const { return value_; }
@@ -2627,7 +2584,7 @@ class HFloatConstant : public HConstant {
return static_cast<uint64_t>(bit_cast<uint32_t, float>(value_));
}
- bool InstructionDataEquals(HInstruction* other) const OVERRIDE {
+ bool InstructionDataEquals(const HInstruction* other) const OVERRIDE {
DCHECK(other->IsFloatConstant()) << other->DebugName();
return other->AsFloatConstant()->GetValueAsUint64() == GetValueAsUint64();
}
@@ -2672,13 +2629,13 @@ class HFloatConstant : public HConstant {
DISALLOW_COPY_AND_ASSIGN(HFloatConstant);
};
-class HDoubleConstant : public HConstant {
+class HDoubleConstant FINAL : public HConstant {
public:
double GetValue() const { return value_; }
uint64_t GetValueAsUint64() const OVERRIDE { return bit_cast<uint64_t, double>(value_); }
- bool InstructionDataEquals(HInstruction* other) const OVERRIDE {
+ bool InstructionDataEquals(const HInstruction* other) const OVERRIDE {
DCHECK(other->IsDoubleConstant()) << other->DebugName();
return other->AsDoubleConstant()->GetValueAsUint64() == GetValueAsUint64();
}
@@ -2725,7 +2682,7 @@ class HDoubleConstant : public HConstant {
// Conditional branch. A block ending with an HIf instruction must have
// two successors.
-class HIf : public HTemplateInstruction<1> {
+class HIf FINAL : public HTemplateInstruction<1> {
public:
explicit HIf(HInstruction* input, uint32_t dex_pc = kNoDexPc)
: HTemplateInstruction(SideEffects::None(), dex_pc) {
@@ -2754,7 +2711,7 @@ class HIf : public HTemplateInstruction<1> {
// non-exceptional control flow.
// Normal-flow successor is stored at index zero, exception handlers under
// higher indices in no particular order.
-class HTryBoundary : public HTemplateInstruction<0> {
+class HTryBoundary FINAL : public HTemplateInstruction<0> {
public:
enum class BoundaryKind {
kEntry,
@@ -2812,7 +2769,7 @@ class HTryBoundary : public HTemplateInstruction<0> {
};
// Deoptimize to interpreter, upon checking a condition.
-class HDeoptimize : public HTemplateInstruction<1> {
+class HDeoptimize FINAL : public HTemplateInstruction<1> {
public:
// We set CanTriggerGC to prevent any intermediate address to be live
// at the point of the `HDeoptimize`.
@@ -2822,7 +2779,7 @@ class HDeoptimize : public HTemplateInstruction<1> {
}
bool CanBeMoved() const OVERRIDE { return true; }
- bool InstructionDataEquals(HInstruction* other ATTRIBUTE_UNUSED) const OVERRIDE {
+ bool InstructionDataEquals(const HInstruction* other ATTRIBUTE_UNUSED) const OVERRIDE {
return true;
}
bool NeedsEnvironment() const OVERRIDE { return true; }
@@ -2837,7 +2794,7 @@ class HDeoptimize : public HTemplateInstruction<1> {
// Represents the ArtMethod that was passed as a first argument to
// the method. It is used by instructions that depend on it, like
// instructions that work with the dex cache.
-class HCurrentMethod : public HExpression<0> {
+class HCurrentMethod FINAL : public HExpression<0> {
public:
explicit HCurrentMethod(Primitive::Type type, uint32_t dex_pc = kNoDexPc)
: HExpression(type, SideEffects::None(), dex_pc) {}
@@ -2850,7 +2807,7 @@ class HCurrentMethod : public HExpression<0> {
// Fetches an ArtMethod from the virtual table or the interface method table
// of a class.
-class HClassTableGet : public HExpression<1> {
+class HClassTableGet FINAL : public HExpression<1> {
public:
enum class TableKind {
kVTable,
@@ -2869,7 +2826,7 @@ class HClassTableGet : public HExpression<1> {
}
bool CanBeMoved() const OVERRIDE { return true; }
- bool InstructionDataEquals(HInstruction* other) const OVERRIDE {
+ bool InstructionDataEquals(const HInstruction* other) const OVERRIDE {
return other->AsClassTableGet()->GetIndex() == index_ &&
other->AsClassTableGet()->GetPackedFields() == GetPackedFields();
}
@@ -2897,7 +2854,7 @@ class HClassTableGet : public HExpression<1> {
// PackedSwitch (jump table). A block ending with a PackedSwitch instruction will
// have one successor for each entry in the switch table, and the final successor
// will be the block containing the next Dex opcode.
-class HPackedSwitch : public HTemplateInstruction<1> {
+class HPackedSwitch FINAL : public HTemplateInstruction<1> {
public:
HPackedSwitch(int32_t start_value,
uint32_t num_entries,
@@ -2939,7 +2896,7 @@ class HUnaryOperation : public HExpression<1> {
Primitive::Type GetResultType() const { return GetType(); }
bool CanBeMoved() const OVERRIDE { return true; }
- bool InstructionDataEquals(HInstruction* other ATTRIBUTE_UNUSED) const OVERRIDE {
+ bool InstructionDataEquals(const HInstruction* other ATTRIBUTE_UNUSED) const OVERRIDE {
return true;
}
@@ -3011,7 +2968,7 @@ class HBinaryOperation : public HExpression<2> {
}
bool CanBeMoved() const OVERRIDE { return true; }
- bool InstructionDataEquals(HInstruction* other ATTRIBUTE_UNUSED) const OVERRIDE {
+ bool InstructionDataEquals(const HInstruction* other ATTRIBUTE_UNUSED) const OVERRIDE {
return true;
}
@@ -3084,7 +3041,7 @@ class HCondition : public HBinaryOperation {
ComparisonBias GetBias() const { return GetPackedField<ComparisonBiasField>(); }
void SetBias(ComparisonBias bias) { SetPackedField<ComparisonBiasField>(bias); }
- bool InstructionDataEquals(HInstruction* other) const OVERRIDE {
+ bool InstructionDataEquals(const HInstruction* other) const OVERRIDE {
return GetPackedFields() == other->AsCondition()->GetPackedFields();
}
@@ -3142,7 +3099,7 @@ class HCondition : public HBinaryOperation {
};
// Instruction to check if two inputs are equal to each other.
-class HEqual : public HCondition {
+class HEqual FINAL : public HCondition {
public:
HEqual(HInstruction* first, HInstruction* second, uint32_t dex_pc = kNoDexPc)
: HCondition(first, second, dex_pc) {}
@@ -3186,7 +3143,7 @@ class HEqual : public HCondition {
DISALLOW_COPY_AND_ASSIGN(HEqual);
};
-class HNotEqual : public HCondition {
+class HNotEqual FINAL : public HCondition {
public:
HNotEqual(HInstruction* first, HInstruction* second, uint32_t dex_pc = kNoDexPc)
: HCondition(first, second, dex_pc) {}
@@ -3229,7 +3186,7 @@ class HNotEqual : public HCondition {
DISALLOW_COPY_AND_ASSIGN(HNotEqual);
};
-class HLessThan : public HCondition {
+class HLessThan FINAL : public HCondition {
public:
HLessThan(HInstruction* first, HInstruction* second, uint32_t dex_pc = kNoDexPc)
: HCondition(first, second, dex_pc) {}
@@ -3266,7 +3223,7 @@ class HLessThan : public HCondition {
DISALLOW_COPY_AND_ASSIGN(HLessThan);
};
-class HLessThanOrEqual : public HCondition {
+class HLessThanOrEqual FINAL : public HCondition {
public:
HLessThanOrEqual(HInstruction* first, HInstruction* second, uint32_t dex_pc = kNoDexPc)
: HCondition(first, second, dex_pc) {}
@@ -3303,7 +3260,7 @@ class HLessThanOrEqual : public HCondition {
DISALLOW_COPY_AND_ASSIGN(HLessThanOrEqual);
};
-class HGreaterThan : public HCondition {
+class HGreaterThan FINAL : public HCondition {
public:
HGreaterThan(HInstruction* first, HInstruction* second, uint32_t dex_pc = kNoDexPc)
: HCondition(first, second, dex_pc) {}
@@ -3340,7 +3297,7 @@ class HGreaterThan : public HCondition {
DISALLOW_COPY_AND_ASSIGN(HGreaterThan);
};
-class HGreaterThanOrEqual : public HCondition {
+class HGreaterThanOrEqual FINAL : public HCondition {
public:
HGreaterThanOrEqual(HInstruction* first, HInstruction* second, uint32_t dex_pc = kNoDexPc)
: HCondition(first, second, dex_pc) {}
@@ -3377,7 +3334,7 @@ class HGreaterThanOrEqual : public HCondition {
DISALLOW_COPY_AND_ASSIGN(HGreaterThanOrEqual);
};
-class HBelow : public HCondition {
+class HBelow FINAL : public HCondition {
public:
HBelow(HInstruction* first, HInstruction* second, uint32_t dex_pc = kNoDexPc)
: HCondition(first, second, dex_pc) {}
@@ -3417,7 +3374,7 @@ class HBelow : public HCondition {
DISALLOW_COPY_AND_ASSIGN(HBelow);
};
-class HBelowOrEqual : public HCondition {
+class HBelowOrEqual FINAL : public HCondition {
public:
HBelowOrEqual(HInstruction* first, HInstruction* second, uint32_t dex_pc = kNoDexPc)
: HCondition(first, second, dex_pc) {}
@@ -3457,7 +3414,7 @@ class HBelowOrEqual : public HCondition {
DISALLOW_COPY_AND_ASSIGN(HBelowOrEqual);
};
-class HAbove : public HCondition {
+class HAbove FINAL : public HCondition {
public:
HAbove(HInstruction* first, HInstruction* second, uint32_t dex_pc = kNoDexPc)
: HCondition(first, second, dex_pc) {}
@@ -3497,7 +3454,7 @@ class HAbove : public HCondition {
DISALLOW_COPY_AND_ASSIGN(HAbove);
};
-class HAboveOrEqual : public HCondition {
+class HAboveOrEqual FINAL : public HCondition {
public:
HAboveOrEqual(HInstruction* first, HInstruction* second, uint32_t dex_pc = kNoDexPc)
: HCondition(first, second, dex_pc) {}
@@ -3539,7 +3496,7 @@ class HAboveOrEqual : public HCondition {
// Instruction to check how two inputs compare to each other.
// Result is 0 if input0 == input1, 1 if input0 > input1, or -1 if input0 < input1.
-class HCompare : public HBinaryOperation {
+class HCompare FINAL : public HBinaryOperation {
public:
// Note that `comparison_type` is the type of comparison performed
// between the comparison's inputs, not the type of the instantiated
@@ -3588,7 +3545,7 @@ class HCompare : public HBinaryOperation {
return MakeConstantComparison(ComputeFP(x->GetValue(), y->GetValue()), GetDexPc());
}
- bool InstructionDataEquals(HInstruction* other) const OVERRIDE {
+ bool InstructionDataEquals(const HInstruction* other) const OVERRIDE {
return GetPackedFields() == other->AsCompare()->GetPackedFields();
}
@@ -3628,21 +3585,21 @@ class HCompare : public HBinaryOperation {
DISALLOW_COPY_AND_ASSIGN(HCompare);
};
-class HNewInstance : public HExpression<2> {
+class HNewInstance FINAL : public HExpression<2> {
public:
HNewInstance(HInstruction* cls,
HCurrentMethod* current_method,
uint32_t dex_pc,
uint16_t type_index,
const DexFile& dex_file,
- bool can_throw,
+ bool needs_access_check,
bool finalizable,
QuickEntrypointEnum entrypoint)
: HExpression(Primitive::kPrimNot, SideEffects::CanTriggerGC(), dex_pc),
type_index_(type_index),
dex_file_(dex_file),
entrypoint_(entrypoint) {
- SetPackedFlag<kFlagCanThrow>(can_throw);
+ SetPackedFlag<kFlagNeedsAccessCheck>(needs_access_check);
SetPackedFlag<kFlagFinalizable>(finalizable);
SetRawInputAt(0, cls);
SetRawInputAt(1, current_method);
@@ -3654,10 +3611,11 @@ class HNewInstance : public HExpression<2> {
// Calls runtime so needs an environment.
bool NeedsEnvironment() const OVERRIDE { return true; }
- // It may throw when called on type that's not instantiable/accessible.
- // It can throw OOME.
- // TODO: distinguish between the two cases so we can for example allow allocation elimination.
- bool CanThrow() const OVERRIDE { return GetPackedFlag<kFlagCanThrow>() || true; }
+ // Can throw errors when out-of-memory or if it's not instantiable/accessible.
+ bool CanThrow() const OVERRIDE { return true; }
+
+ // Needs to call into runtime to make sure it's instantiable/accessible.
+ bool NeedsAccessCheck() const { return GetPackedFlag<kFlagNeedsAccessCheck>(); }
bool IsFinalizable() const { return GetPackedFlag<kFlagFinalizable>(); }
@@ -3674,8 +3632,8 @@ class HNewInstance : public HExpression<2> {
DECLARE_INSTRUCTION(NewInstance);
private:
- static constexpr size_t kFlagCanThrow = kNumberOfExpressionPackedBits;
- static constexpr size_t kFlagFinalizable = kFlagCanThrow + 1;
+ static constexpr size_t kFlagNeedsAccessCheck = kNumberOfExpressionPackedBits;
+ static constexpr size_t kFlagFinalizable = kFlagNeedsAccessCheck + 1;
static constexpr size_t kNumberOfNewInstancePackedBits = kFlagFinalizable + 1;
static_assert(kNumberOfNewInstancePackedBits <= kMaxNumberOfPackedBits,
"Too many packed fields.");
@@ -3717,10 +3675,13 @@ enum IntrinsicExceptions {
class HInvoke : public HInstruction {
public:
- size_t InputCount() const OVERRIDE { return inputs_.size(); }
-
bool NeedsEnvironment() const OVERRIDE;
+ using HInstruction::GetInputRecords; // Keep the const version visible.
+ ArrayRef<HUserRecord<HInstruction*>> GetInputRecords() OVERRIDE {
+ return ArrayRef<HUserRecord<HInstruction*>>(inputs_);
+ }
+
void SetArgumentAt(size_t index, HInstruction* argument) {
SetRawInputAt(index, argument);
}
@@ -3757,7 +3718,7 @@ class HInvoke : public HInstruction {
bool CanBeMoved() const OVERRIDE { return IsIntrinsic(); }
- bool InstructionDataEquals(HInstruction* other) const OVERRIDE {
+ bool InstructionDataEquals(const HInstruction* other) const OVERRIDE {
return intrinsic_ != Intrinsics::kNone && intrinsic_ == other->AsInvoke()->intrinsic_;
}
@@ -3808,14 +3769,6 @@ class HInvoke : public HInstruction {
SetPackedFlag<kFlagCanThrow>(true);
}
- const HUserRecord<HInstruction*> InputRecordAt(size_t index) const OVERRIDE {
- return inputs_[index];
- }
-
- void SetRawInputRecordAt(size_t index, const HUserRecord<HInstruction*>& input) OVERRIDE {
- inputs_[index] = input;
- }
-
void SetCanThrow(bool can_throw) { SetPackedFlag<kFlagCanThrow>(can_throw); }
uint32_t number_of_arguments_;
@@ -3830,7 +3783,7 @@ class HInvoke : public HInstruction {
DISALLOW_COPY_AND_ASSIGN(HInvoke);
};
-class HInvokeUnresolved : public HInvoke {
+class HInvokeUnresolved FINAL : public HInvoke {
public:
HInvokeUnresolved(ArenaAllocator* arena,
uint32_t number_of_arguments,
@@ -3853,7 +3806,7 @@ class HInvokeUnresolved : public HInvoke {
DISALLOW_COPY_AND_ASSIGN(HInvokeUnresolved);
};
-class HInvokeStaticOrDirect : public HInvoke {
+class HInvokeStaticOrDirect FINAL : public HInvoke {
public:
// Requirements of this method call regarding the class
// initialization (clinit) check of its declaring class.
@@ -3982,6 +3935,25 @@ class HInvokeStaticOrDirect : public HInvoke {
InsertInputAt(GetSpecialInputIndex(), input);
}
+ using HInstruction::GetInputRecords; // Keep the const version visible.
+ ArrayRef<HUserRecord<HInstruction*>> GetInputRecords() OVERRIDE {
+ ArrayRef<HUserRecord<HInstruction*>> input_records = HInvoke::GetInputRecords();
+ if (kIsDebugBuild && IsStaticWithExplicitClinitCheck()) {
+ DCHECK(!input_records.empty());
+ DCHECK_GT(input_records.size(), GetNumberOfArguments());
+ HInstruction* last_input = input_records.back().GetInstruction();
+ // Note: `last_input` may be null during arguments setup.
+ if (last_input != nullptr) {
+ // `last_input` is the last input of a static invoke marked as having
+ // an explicit clinit check. It must either be:
+ // - an art::HClinitCheck instruction, set by art::HGraphBuilder; or
+ // - an art::HLoadClass instruction, set by art::PrepareForRegisterAllocation.
+ DCHECK(last_input->IsClinitCheck() || last_input->IsLoadClass()) << last_input->DebugName();
+ }
+ }
+ return input_records;
+ }
+
bool CanDoImplicitNullCheckOn(HInstruction* obj ATTRIBUTE_UNUSED) const OVERRIDE {
// We access the method via the dex cache so we can't do an implicit null check.
// TODO: for intrinsics we can generate implicit null checks.
@@ -4066,8 +4038,8 @@ class HInvokeStaticOrDirect : public HInvoke {
// instruction; only relevant for static calls with explicit clinit check.
void RemoveExplicitClinitCheck(ClinitCheckRequirement new_requirement) {
DCHECK(IsStaticWithExplicitClinitCheck());
- size_t last_input_index = InputCount() - 1;
- HInstruction* last_input = InputAt(last_input_index);
+ size_t last_input_index = inputs_.size() - 1u;
+ HInstruction* last_input = inputs_.back().GetInstruction();
DCHECK(last_input != nullptr);
DCHECK(last_input->IsLoadClass() || last_input->IsClinitCheck()) << last_input->DebugName();
RemoveAsUserOfInput(last_input_index);
@@ -4096,20 +4068,6 @@ class HInvokeStaticOrDirect : public HInvoke {
DECLARE_INSTRUCTION(InvokeStaticOrDirect);
protected:
- const HUserRecord<HInstruction*> InputRecordAt(size_t i) const OVERRIDE {
- const HUserRecord<HInstruction*> input_record = HInvoke::InputRecordAt(i);
- if (kIsDebugBuild && IsStaticWithExplicitClinitCheck() && (i == InputCount() - 1)) {
- HInstruction* input = input_record.GetInstruction();
- // `input` is the last input of a static invoke marked as having
- // an explicit clinit check. It must either be:
- // - an art::HClinitCheck instruction, set by art::HGraphBuilder; or
- // - an art::HLoadClass instruction, set by art::PrepareForRegisterAllocation.
- DCHECK(input != nullptr);
- DCHECK(input->IsClinitCheck() || input->IsLoadClass()) << input->DebugName();
- }
- return input_record;
- }
-
void InsertInputAt(size_t index, HInstruction* input);
void RemoveInputAt(size_t index);
@@ -4142,7 +4100,7 @@ class HInvokeStaticOrDirect : public HInvoke {
std::ostream& operator<<(std::ostream& os, HInvokeStaticOrDirect::MethodLoadKind rhs);
std::ostream& operator<<(std::ostream& os, HInvokeStaticOrDirect::ClinitCheckRequirement rhs);
-class HInvokeVirtual : public HInvoke {
+class HInvokeVirtual FINAL : public HInvoke {
public:
HInvokeVirtual(ArenaAllocator* arena,
uint32_t number_of_arguments,
@@ -4168,7 +4126,7 @@ class HInvokeVirtual : public HInvoke {
DISALLOW_COPY_AND_ASSIGN(HInvokeVirtual);
};
-class HInvokeInterface : public HInvoke {
+class HInvokeInterface FINAL : public HInvoke {
public:
HInvokeInterface(ArenaAllocator* arena,
uint32_t number_of_arguments,
@@ -4195,7 +4153,7 @@ class HInvokeInterface : public HInvoke {
DISALLOW_COPY_AND_ASSIGN(HInvokeInterface);
};
-class HNeg : public HUnaryOperation {
+class HNeg FINAL : public HUnaryOperation {
public:
HNeg(Primitive::Type result_type, HInstruction* input, uint32_t dex_pc = kNoDexPc)
: HUnaryOperation(result_type, input, dex_pc) {
@@ -4223,7 +4181,7 @@ class HNeg : public HUnaryOperation {
DISALLOW_COPY_AND_ASSIGN(HNeg);
};
-class HNewArray : public HExpression<2> {
+class HNewArray FINAL : public HExpression<2> {
public:
HNewArray(HInstruction* length,
HCurrentMethod* current_method,
@@ -4262,7 +4220,7 @@ class HNewArray : public HExpression<2> {
DISALLOW_COPY_AND_ASSIGN(HNewArray);
};
-class HAdd : public HBinaryOperation {
+class HAdd FINAL : public HBinaryOperation {
public:
HAdd(Primitive::Type result_type,
HInstruction* left,
@@ -4297,7 +4255,7 @@ class HAdd : public HBinaryOperation {
DISALLOW_COPY_AND_ASSIGN(HAdd);
};
-class HSub : public HBinaryOperation {
+class HSub FINAL : public HBinaryOperation {
public:
HSub(Primitive::Type result_type,
HInstruction* left,
@@ -4330,7 +4288,7 @@ class HSub : public HBinaryOperation {
DISALLOW_COPY_AND_ASSIGN(HSub);
};
-class HMul : public HBinaryOperation {
+class HMul FINAL : public HBinaryOperation {
public:
HMul(Primitive::Type result_type,
HInstruction* left,
@@ -4365,7 +4323,7 @@ class HMul : public HBinaryOperation {
DISALLOW_COPY_AND_ASSIGN(HMul);
};
-class HDiv : public HBinaryOperation {
+class HDiv FINAL : public HBinaryOperation {
public:
HDiv(Primitive::Type result_type,
HInstruction* left,
@@ -4417,7 +4375,7 @@ class HDiv : public HBinaryOperation {
DISALLOW_COPY_AND_ASSIGN(HDiv);
};
-class HRem : public HBinaryOperation {
+class HRem FINAL : public HBinaryOperation {
public:
HRem(Primitive::Type result_type,
HInstruction* left,
@@ -4468,7 +4426,7 @@ class HRem : public HBinaryOperation {
DISALLOW_COPY_AND_ASSIGN(HRem);
};
-class HDivZeroCheck : public HExpression<1> {
+class HDivZeroCheck FINAL : public HExpression<1> {
public:
// `HDivZeroCheck` can trigger GC, as it may call the `ArithmeticException`
// constructor.
@@ -4481,7 +4439,7 @@ class HDivZeroCheck : public HExpression<1> {
bool CanBeMoved() const OVERRIDE { return true; }
- bool InstructionDataEquals(HInstruction* other ATTRIBUTE_UNUSED) const OVERRIDE {
+ bool InstructionDataEquals(const HInstruction* other ATTRIBUTE_UNUSED) const OVERRIDE {
return true;
}
@@ -4494,7 +4452,7 @@ class HDivZeroCheck : public HExpression<1> {
DISALLOW_COPY_AND_ASSIGN(HDivZeroCheck);
};
-class HShl : public HBinaryOperation {
+class HShl FINAL : public HBinaryOperation {
public:
HShl(Primitive::Type result_type,
HInstruction* value,
@@ -4540,7 +4498,7 @@ class HShl : public HBinaryOperation {
DISALLOW_COPY_AND_ASSIGN(HShl);
};
-class HShr : public HBinaryOperation {
+class HShr FINAL : public HBinaryOperation {
public:
HShr(Primitive::Type result_type,
HInstruction* value,
@@ -4586,7 +4544,7 @@ class HShr : public HBinaryOperation {
DISALLOW_COPY_AND_ASSIGN(HShr);
};
-class HUShr : public HBinaryOperation {
+class HUShr FINAL : public HBinaryOperation {
public:
HUShr(Primitive::Type result_type,
HInstruction* value,
@@ -4634,7 +4592,7 @@ class HUShr : public HBinaryOperation {
DISALLOW_COPY_AND_ASSIGN(HUShr);
};
-class HAnd : public HBinaryOperation {
+class HAnd FINAL : public HBinaryOperation {
public:
HAnd(Primitive::Type result_type,
HInstruction* left,
@@ -4671,7 +4629,7 @@ class HAnd : public HBinaryOperation {
DISALLOW_COPY_AND_ASSIGN(HAnd);
};
-class HOr : public HBinaryOperation {
+class HOr FINAL : public HBinaryOperation {
public:
HOr(Primitive::Type result_type,
HInstruction* left,
@@ -4708,7 +4666,7 @@ class HOr : public HBinaryOperation {
DISALLOW_COPY_AND_ASSIGN(HOr);
};
-class HXor : public HBinaryOperation {
+class HXor FINAL : public HBinaryOperation {
public:
HXor(Primitive::Type result_type,
HInstruction* left,
@@ -4745,7 +4703,7 @@ class HXor : public HBinaryOperation {
DISALLOW_COPY_AND_ASSIGN(HXor);
};
-class HRor : public HBinaryOperation {
+class HRor FINAL : public HBinaryOperation {
public:
HRor(Primitive::Type result_type, HInstruction* value, HInstruction* distance)
: HBinaryOperation(result_type, value, distance) {
@@ -4798,7 +4756,7 @@ class HRor : public HBinaryOperation {
// The value of a parameter in this method. Its location depends on
// the calling convention.
-class HParameterValue : public HExpression<0> {
+class HParameterValue FINAL : public HExpression<0> {
public:
HParameterValue(const DexFile& dex_file,
uint16_t type_index,
@@ -4840,13 +4798,13 @@ class HParameterValue : public HExpression<0> {
DISALLOW_COPY_AND_ASSIGN(HParameterValue);
};
-class HNot : public HUnaryOperation {
+class HNot FINAL : public HUnaryOperation {
public:
HNot(Primitive::Type result_type, HInstruction* input, uint32_t dex_pc = kNoDexPc)
: HUnaryOperation(result_type, input, dex_pc) {}
bool CanBeMoved() const OVERRIDE { return true; }
- bool InstructionDataEquals(HInstruction* other ATTRIBUTE_UNUSED) const OVERRIDE {
+ bool InstructionDataEquals(const HInstruction* other ATTRIBUTE_UNUSED) const OVERRIDE {
return true;
}
@@ -4873,13 +4831,13 @@ class HNot : public HUnaryOperation {
DISALLOW_COPY_AND_ASSIGN(HNot);
};
-class HBooleanNot : public HUnaryOperation {
+class HBooleanNot FINAL : public HUnaryOperation {
public:
explicit HBooleanNot(HInstruction* input, uint32_t dex_pc = kNoDexPc)
: HUnaryOperation(Primitive::Type::kPrimBoolean, input, dex_pc) {}
bool CanBeMoved() const OVERRIDE { return true; }
- bool InstructionDataEquals(HInstruction* other ATTRIBUTE_UNUSED) const OVERRIDE {
+ bool InstructionDataEquals(const HInstruction* other ATTRIBUTE_UNUSED) const OVERRIDE {
return true;
}
@@ -4910,7 +4868,7 @@ class HBooleanNot : public HUnaryOperation {
DISALLOW_COPY_AND_ASSIGN(HBooleanNot);
};
-class HTypeConversion : public HExpression<1> {
+class HTypeConversion FINAL : public HExpression<1> {
public:
// Instantiate a type conversion of `input` to `result_type`.
HTypeConversion(Primitive::Type result_type, HInstruction* input, uint32_t dex_pc)
@@ -4927,7 +4885,9 @@ class HTypeConversion : public HExpression<1> {
Primitive::Type GetResultType() const { return GetType(); }
bool CanBeMoved() const OVERRIDE { return true; }
- bool InstructionDataEquals(HInstruction* other ATTRIBUTE_UNUSED) const OVERRIDE { return true; }
+ bool InstructionDataEquals(const HInstruction* other ATTRIBUTE_UNUSED) const OVERRIDE {
+ return true;
+ }
// Try to statically evaluate the conversion and return a HConstant
// containing the result. If the input cannot be converted, return nullptr.
@@ -4953,7 +4913,7 @@ class HTypeConversion : public HExpression<1> {
static constexpr uint32_t kNoRegNumber = -1;
-class HNullCheck : public HExpression<1> {
+class HNullCheck FINAL : public HExpression<1> {
public:
// `HNullCheck` can trigger GC, as it may call the `NullPointerException`
// constructor.
@@ -4963,7 +4923,7 @@ class HNullCheck : public HExpression<1> {
}
bool CanBeMoved() const OVERRIDE { return true; }
- bool InstructionDataEquals(HInstruction* other ATTRIBUTE_UNUSED) const OVERRIDE {
+ bool InstructionDataEquals(const HInstruction* other ATTRIBUTE_UNUSED) const OVERRIDE {
return true;
}
@@ -5015,7 +4975,7 @@ class FieldInfo : public ValueObject {
const Handle<mirror::DexCache> dex_cache_;
};
-class HInstanceFieldGet : public HExpression<1> {
+class HInstanceFieldGet FINAL : public HExpression<1> {
public:
HInstanceFieldGet(HInstruction* value,
Primitive::Type field_type,
@@ -5041,8 +5001,8 @@ class HInstanceFieldGet : public HExpression<1> {
bool CanBeMoved() const OVERRIDE { return !IsVolatile(); }
- bool InstructionDataEquals(HInstruction* other) const OVERRIDE {
- HInstanceFieldGet* other_get = other->AsInstanceFieldGet();
+ bool InstructionDataEquals(const HInstruction* other) const OVERRIDE {
+ const HInstanceFieldGet* other_get = other->AsInstanceFieldGet();
return GetFieldOffset().SizeValue() == other_get->GetFieldOffset().SizeValue();
}
@@ -5067,7 +5027,7 @@ class HInstanceFieldGet : public HExpression<1> {
DISALLOW_COPY_AND_ASSIGN(HInstanceFieldGet);
};
-class HInstanceFieldSet : public HTemplateInstruction<2> {
+class HInstanceFieldSet FINAL : public HTemplateInstruction<2> {
public:
HInstanceFieldSet(HInstruction* object,
HInstruction* value,
@@ -5118,22 +5078,16 @@ class HInstanceFieldSet : public HTemplateInstruction<2> {
DISALLOW_COPY_AND_ASSIGN(HInstanceFieldSet);
};
-class HArrayGet : public HExpression<2> {
+class HArrayGet FINAL : public HExpression<2> {
public:
- HArrayGet(HInstruction* array,
- HInstruction* index,
- Primitive::Type type,
- uint32_t dex_pc,
- SideEffects additional_side_effects = SideEffects::None())
- : HExpression(type,
- SideEffects::ArrayReadOfType(type).Union(additional_side_effects),
- dex_pc) {
+ HArrayGet(HInstruction* array, HInstruction* index, Primitive::Type type, uint32_t dex_pc)
+ : HExpression(type, SideEffects::ArrayReadOfType(type), dex_pc) {
SetRawInputAt(0, array);
SetRawInputAt(1, index);
}
bool CanBeMoved() const OVERRIDE { return true; }
- bool InstructionDataEquals(HInstruction* other ATTRIBUTE_UNUSED) const OVERRIDE {
+ bool InstructionDataEquals(const HInstruction* other ATTRIBUTE_UNUSED) const OVERRIDE {
return true;
}
bool CanDoImplicitNullCheckOn(HInstruction* obj ATTRIBUTE_UNUSED) const OVERRIDE {
@@ -5170,17 +5124,14 @@ class HArrayGet : public HExpression<2> {
DISALLOW_COPY_AND_ASSIGN(HArrayGet);
};
-class HArraySet : public HTemplateInstruction<3> {
+class HArraySet FINAL : public HTemplateInstruction<3> {
public:
HArraySet(HInstruction* array,
HInstruction* index,
HInstruction* value,
Primitive::Type expected_component_type,
- uint32_t dex_pc,
- SideEffects additional_side_effects = SideEffects::None())
- : HTemplateInstruction(
- SideEffectsForArchRuntimeCalls(value->GetType()).Union(additional_side_effects),
- dex_pc) {
+ uint32_t dex_pc)
+ : HTemplateInstruction(SideEffects::None(), dex_pc) {
SetPackedField<ExpectedComponentTypeField>(expected_component_type);
SetPackedFlag<kFlagNeedsTypeCheck>(value->GetType() == Primitive::kPrimNot);
SetPackedFlag<kFlagValueCanBeNull>(true);
@@ -5188,8 +5139,8 @@ class HArraySet : public HTemplateInstruction<3> {
SetRawInputAt(0, array);
SetRawInputAt(1, index);
SetRawInputAt(2, value);
- // We can now call component type logic to set correct type-based side effects.
- AddSideEffects(SideEffects::ArrayWriteOfType(GetComponentType()));
+ // Make a best guess now, may be refined during SSA building.
+ ComputeSideEffects();
}
bool NeedsEnvironment() const OVERRIDE {
@@ -5242,6 +5193,12 @@ class HArraySet : public HTemplateInstruction<3> {
return GetPackedField<ExpectedComponentTypeField>();
}
+ void ComputeSideEffects() {
+ Primitive::Type type = GetComponentType();
+ SetSideEffects(SideEffects::ArrayWriteOfType(type).Union(
+ SideEffectsForArchRuntimeCalls(type)));
+ }
+
static SideEffects SideEffectsForArchRuntimeCalls(Primitive::Type value_type) {
return (value_type == Primitive::kPrimNot) ? SideEffects::CanTriggerGC() : SideEffects::None();
}
@@ -5267,7 +5224,7 @@ class HArraySet : public HTemplateInstruction<3> {
DISALLOW_COPY_AND_ASSIGN(HArraySet);
};
-class HArrayLength : public HExpression<1> {
+class HArrayLength FINAL : public HExpression<1> {
public:
HArrayLength(HInstruction* array, uint32_t dex_pc)
: HExpression(Primitive::kPrimInt, SideEffects::None(), dex_pc) {
@@ -5277,20 +5234,33 @@ class HArrayLength : public HExpression<1> {
}
bool CanBeMoved() const OVERRIDE { return true; }
- bool InstructionDataEquals(HInstruction* other ATTRIBUTE_UNUSED) const OVERRIDE {
+ bool InstructionDataEquals(const HInstruction* other ATTRIBUTE_UNUSED) const OVERRIDE {
return true;
}
bool CanDoImplicitNullCheckOn(HInstruction* obj) const OVERRIDE {
return obj == InputAt(0);
}
+ void MarkAsStringLength() { SetPackedFlag<kFlagIsStringLength>(); }
+ bool IsStringLength() const { return GetPackedFlag<kFlagIsStringLength>(); }
+
DECLARE_INSTRUCTION(ArrayLength);
private:
+ // We treat a String as an array, creating the HArrayLength from String.length()
+ // or String.isEmpty() intrinsic in the instruction simplifier. We can always
+ // determine whether a particular HArrayLength is actually a String.length() by
+ // looking at the type of the input but that requires holding the mutator lock, so
+ // we prefer to use a flag, so that code generators don't need to do the locking.
+ static constexpr size_t kFlagIsStringLength = kNumberOfExpressionPackedBits;
+ static constexpr size_t kNumberOfArrayLengthPackedBits = kFlagIsStringLength + 1;
+ static_assert(kNumberOfArrayLengthPackedBits <= HInstruction::kMaxNumberOfPackedBits,
+ "Too many packed fields.");
+
DISALLOW_COPY_AND_ASSIGN(HArrayLength);
};
-class HBoundsCheck : public HExpression<2> {
+class HBoundsCheck FINAL : public HExpression<2> {
public:
// `HBoundsCheck` can trigger GC, as it may call the `IndexOutOfBoundsException`
// constructor.
@@ -5302,7 +5272,7 @@ class HBoundsCheck : public HExpression<2> {
}
bool CanBeMoved() const OVERRIDE { return true; }
- bool InstructionDataEquals(HInstruction* other ATTRIBUTE_UNUSED) const OVERRIDE {
+ bool InstructionDataEquals(const HInstruction* other ATTRIBUTE_UNUSED) const OVERRIDE {
return true;
}
@@ -5318,7 +5288,7 @@ class HBoundsCheck : public HExpression<2> {
DISALLOW_COPY_AND_ASSIGN(HBoundsCheck);
};
-class HSuspendCheck : public HTemplateInstruction<0> {
+class HSuspendCheck FINAL : public HTemplateInstruction<0> {
public:
explicit HSuspendCheck(uint32_t dex_pc = kNoDexPc)
: HTemplateInstruction(SideEffects::CanTriggerGC(), dex_pc), slow_path_(nullptr) {}
@@ -5360,7 +5330,7 @@ class HNativeDebugInfo : public HTemplateInstruction<0> {
/**
* Instruction to load a Class object.
*/
-class HLoadClass : public HExpression<1> {
+class HLoadClass FINAL : public HExpression<1> {
public:
HLoadClass(HCurrentMethod* current_method,
uint16_t type_index,
@@ -5386,7 +5356,7 @@ class HLoadClass : public HExpression<1> {
bool CanBeMoved() const OVERRIDE { return true; }
- bool InstructionDataEquals(HInstruction* other) const OVERRIDE {
+ bool InstructionDataEquals(const HInstruction* other) const OVERRIDE {
// Note that we don't need to test for generate_clinit_check_.
// Whether or not we need to generate the clinit check is processed in
// prepare_for_register_allocator based on existing HInvokes and HClinitChecks.
@@ -5464,7 +5434,7 @@ class HLoadClass : public HExpression<1> {
DISALLOW_COPY_AND_ASSIGN(HLoadClass);
};
-class HLoadString : public HExpression<1> {
+class HLoadString FINAL : public HInstruction {
public:
// Determines how to load the String.
enum class LoadKind {
@@ -5503,12 +5473,12 @@ class HLoadString : public HExpression<1> {
uint32_t string_index,
const DexFile& dex_file,
uint32_t dex_pc)
- : HExpression(Primitive::kPrimNot, SideEffectsForArchRuntimeCalls(), dex_pc),
+ : HInstruction(SideEffectsForArchRuntimeCalls(), dex_pc),
+ special_input_(HUserRecord<HInstruction*>(current_method)),
string_index_(string_index) {
SetPackedFlag<kFlagIsInDexCache>(false);
SetPackedField<LoadKindField>(LoadKind::kDexCacheViaMethod);
load_data_.ref.dex_file = &dex_file;
- SetRawInputAt(0, current_method);
}
void SetLoadKindWithAddress(LoadKind load_kind, uint64_t address) {
@@ -5555,7 +5525,7 @@ class HLoadString : public HExpression<1> {
bool CanBeMoved() const OVERRIDE { return true; }
- bool InstructionDataEquals(HInstruction* other) const OVERRIDE;
+ bool InstructionDataEquals(const HInstruction* other) const OVERRIDE;
size_t ComputeHashCode() const OVERRIDE { return string_index_; }
@@ -5588,18 +5558,25 @@ class HLoadString : public HExpression<1> {
SetPackedFlag<kFlagIsInDexCache>(true);
DCHECK(!NeedsEnvironment());
RemoveEnvironment();
+ SetSideEffects(SideEffects::None());
}
- size_t InputCount() const OVERRIDE {
- return (InputAt(0) != nullptr) ? 1u : 0u;
+ void AddSpecialInput(HInstruction* special_input);
+
+ using HInstruction::GetInputRecords; // Keep the const version visible.
+ ArrayRef<HUserRecord<HInstruction*>> GetInputRecords() OVERRIDE FINAL {
+ return ArrayRef<HUserRecord<HInstruction*>>(
+ &special_input_, (special_input_.GetInstruction() != nullptr) ? 1u : 0u);
}
- void AddSpecialInput(HInstruction* special_input);
+ Primitive::Type GetType() const OVERRIDE {
+ return Primitive::kPrimNot;
+ }
DECLARE_INSTRUCTION(LoadString);
private:
- static constexpr size_t kFlagIsInDexCache = kNumberOfExpressionPackedBits;
+ static constexpr size_t kFlagIsInDexCache = kNumberOfGenericPackedBits;
static constexpr size_t kFieldLoadKind = kFlagIsInDexCache + 1;
static constexpr size_t kFieldLoadKindSize =
MinimumBitsToStore(static_cast<size_t>(LoadKind::kLast));
@@ -5623,6 +5600,8 @@ class HLoadString : public HExpression<1> {
void SetLoadKindInternal(LoadKind load_kind);
+ HUserRecord<HInstruction*> special_input_;
+
// String index serves also as the hash code and it's also needed for slow-paths,
// so it must not be overwritten with other load data.
uint32_t string_index_;
@@ -5657,15 +5636,17 @@ inline void HLoadString::AddSpecialInput(HInstruction* special_input) {
// The special input is used for PC-relative loads on some architectures.
DCHECK(GetLoadKind() == LoadKind::kBootImageLinkTimePcRelative ||
GetLoadKind() == LoadKind::kDexCachePcRelative) << GetLoadKind();
- DCHECK(InputAt(0) == nullptr);
- SetRawInputAt(0u, special_input);
+ // HLoadString::GetInputRecords() returns an empty array at this point,
+ // so use the GetInputRecords() from the base class to set the input record.
+ DCHECK(special_input_.GetInstruction() == nullptr);
+ special_input_ = HUserRecord<HInstruction*>(special_input);
special_input->AddUseAt(this, 0);
}
/**
* Performs an initialization check on its Class object input.
*/
-class HClinitCheck : public HExpression<1> {
+class HClinitCheck FINAL : public HExpression<1> {
public:
HClinitCheck(HLoadClass* constant, uint32_t dex_pc)
: HExpression(
@@ -5676,7 +5657,7 @@ class HClinitCheck : public HExpression<1> {
}
bool CanBeMoved() const OVERRIDE { return true; }
- bool InstructionDataEquals(HInstruction* other ATTRIBUTE_UNUSED) const OVERRIDE {
+ bool InstructionDataEquals(const HInstruction* other ATTRIBUTE_UNUSED) const OVERRIDE {
return true;
}
@@ -5695,7 +5676,7 @@ class HClinitCheck : public HExpression<1> {
DISALLOW_COPY_AND_ASSIGN(HClinitCheck);
};
-class HStaticFieldGet : public HExpression<1> {
+class HStaticFieldGet FINAL : public HExpression<1> {
public:
HStaticFieldGet(HInstruction* cls,
Primitive::Type field_type,
@@ -5722,8 +5703,8 @@ class HStaticFieldGet : public HExpression<1> {
bool CanBeMoved() const OVERRIDE { return !IsVolatile(); }
- bool InstructionDataEquals(HInstruction* other) const OVERRIDE {
- HStaticFieldGet* other_get = other->AsStaticFieldGet();
+ bool InstructionDataEquals(const HInstruction* other) const OVERRIDE {
+ const HStaticFieldGet* other_get = other->AsStaticFieldGet();
return GetFieldOffset().SizeValue() == other_get->GetFieldOffset().SizeValue();
}
@@ -5744,7 +5725,7 @@ class HStaticFieldGet : public HExpression<1> {
DISALLOW_COPY_AND_ASSIGN(HStaticFieldGet);
};
-class HStaticFieldSet : public HTemplateInstruction<2> {
+class HStaticFieldSet FINAL : public HTemplateInstruction<2> {
public:
HStaticFieldSet(HInstruction* cls,
HInstruction* value,
@@ -5792,7 +5773,7 @@ class HStaticFieldSet : public HTemplateInstruction<2> {
DISALLOW_COPY_AND_ASSIGN(HStaticFieldSet);
};
-class HUnresolvedInstanceFieldGet : public HExpression<1> {
+class HUnresolvedInstanceFieldGet FINAL : public HExpression<1> {
public:
HUnresolvedInstanceFieldGet(HInstruction* obj,
Primitive::Type field_type,
@@ -5817,7 +5798,7 @@ class HUnresolvedInstanceFieldGet : public HExpression<1> {
DISALLOW_COPY_AND_ASSIGN(HUnresolvedInstanceFieldGet);
};
-class HUnresolvedInstanceFieldSet : public HTemplateInstruction<2> {
+class HUnresolvedInstanceFieldSet FINAL : public HTemplateInstruction<2> {
public:
HUnresolvedInstanceFieldSet(HInstruction* obj,
HInstruction* value,
@@ -5855,7 +5836,7 @@ class HUnresolvedInstanceFieldSet : public HTemplateInstruction<2> {
DISALLOW_COPY_AND_ASSIGN(HUnresolvedInstanceFieldSet);
};
-class HUnresolvedStaticFieldGet : public HExpression<0> {
+class HUnresolvedStaticFieldGet FINAL : public HExpression<0> {
public:
HUnresolvedStaticFieldGet(Primitive::Type field_type,
uint32_t field_index,
@@ -5878,7 +5859,7 @@ class HUnresolvedStaticFieldGet : public HExpression<0> {
DISALLOW_COPY_AND_ASSIGN(HUnresolvedStaticFieldGet);
};
-class HUnresolvedStaticFieldSet : public HTemplateInstruction<1> {
+class HUnresolvedStaticFieldSet FINAL : public HTemplateInstruction<1> {
public:
HUnresolvedStaticFieldSet(HInstruction* value,
Primitive::Type field_type,
@@ -5915,7 +5896,7 @@ class HUnresolvedStaticFieldSet : public HTemplateInstruction<1> {
};
// Implement the move-exception DEX instruction.
-class HLoadException : public HExpression<0> {
+class HLoadException FINAL : public HExpression<0> {
public:
explicit HLoadException(uint32_t dex_pc = kNoDexPc)
: HExpression(Primitive::kPrimNot, SideEffects::None(), dex_pc) {}
@@ -5930,7 +5911,7 @@ class HLoadException : public HExpression<0> {
// Implicit part of move-exception which clears thread-local exception storage.
// Must not be removed because the runtime expects the TLS to get cleared.
-class HClearException : public HTemplateInstruction<0> {
+class HClearException FINAL : public HTemplateInstruction<0> {
public:
explicit HClearException(uint32_t dex_pc = kNoDexPc)
: HTemplateInstruction(SideEffects::AllWrites(), dex_pc) {}
@@ -5941,7 +5922,7 @@ class HClearException : public HTemplateInstruction<0> {
DISALLOW_COPY_AND_ASSIGN(HClearException);
};
-class HThrow : public HTemplateInstruction<1> {
+class HThrow FINAL : public HTemplateInstruction<1> {
public:
HThrow(HInstruction* exception, uint32_t dex_pc)
: HTemplateInstruction(SideEffects::CanTriggerGC(), dex_pc) {
@@ -5978,7 +5959,7 @@ enum class TypeCheckKind {
std::ostream& operator<<(std::ostream& os, TypeCheckKind rhs);
-class HInstanceOf : public HExpression<2> {
+class HInstanceOf FINAL : public HExpression<2> {
public:
HInstanceOf(HInstruction* object,
HLoadClass* constant,
@@ -5995,7 +5976,7 @@ class HInstanceOf : public HExpression<2> {
bool CanBeMoved() const OVERRIDE { return true; }
- bool InstructionDataEquals(HInstruction* other ATTRIBUTE_UNUSED) const OVERRIDE {
+ bool InstructionDataEquals(const HInstruction* other ATTRIBUTE_UNUSED) const OVERRIDE {
return true;
}
@@ -6032,7 +6013,7 @@ class HInstanceOf : public HExpression<2> {
DISALLOW_COPY_AND_ASSIGN(HInstanceOf);
};
-class HBoundType : public HExpression<1> {
+class HBoundType FINAL : public HExpression<1> {
public:
HBoundType(HInstruction* input, uint32_t dex_pc = kNoDexPc)
: HExpression(Primitive::kPrimNot, SideEffects::None(), dex_pc),
@@ -6076,7 +6057,7 @@ class HBoundType : public HExpression<1> {
DISALLOW_COPY_AND_ASSIGN(HBoundType);
};
-class HCheckCast : public HTemplateInstruction<2> {
+class HCheckCast FINAL : public HTemplateInstruction<2> {
public:
HCheckCast(HInstruction* object,
HLoadClass* constant,
@@ -6091,7 +6072,7 @@ class HCheckCast : public HTemplateInstruction<2> {
bool CanBeMoved() const OVERRIDE { return true; }
- bool InstructionDataEquals(HInstruction* other ATTRIBUTE_UNUSED) const OVERRIDE {
+ bool InstructionDataEquals(const HInstruction* other ATTRIBUTE_UNUSED) const OVERRIDE {
return true;
}
@@ -6121,7 +6102,7 @@ class HCheckCast : public HTemplateInstruction<2> {
DISALLOW_COPY_AND_ASSIGN(HCheckCast);
};
-class HMemoryBarrier : public HTemplateInstruction<0> {
+class HMemoryBarrier FINAL : public HTemplateInstruction<0> {
public:
explicit HMemoryBarrier(MemBarrierKind barrier_kind, uint32_t dex_pc = kNoDexPc)
: HTemplateInstruction(
@@ -6146,7 +6127,7 @@ class HMemoryBarrier : public HTemplateInstruction<0> {
DISALLOW_COPY_AND_ASSIGN(HMemoryBarrier);
};
-class HMonitorOperation : public HTemplateInstruction<1> {
+class HMonitorOperation FINAL : public HTemplateInstruction<1> {
public:
enum class OperationKind {
kEnter,
@@ -6191,7 +6172,7 @@ class HMonitorOperation : public HTemplateInstruction<1> {
DISALLOW_COPY_AND_ASSIGN(HMonitorOperation);
};
-class HSelect : public HExpression<3> {
+class HSelect FINAL : public HExpression<3> {
public:
HSelect(HInstruction* condition,
HInstruction* true_value,
@@ -6214,7 +6195,9 @@ class HSelect : public HExpression<3> {
HInstruction* GetCondition() const { return InputAt(2); }
bool CanBeMoved() const OVERRIDE { return true; }
- bool InstructionDataEquals(HInstruction* other ATTRIBUTE_UNUSED) const OVERRIDE { return true; }
+ bool InstructionDataEquals(const HInstruction* other ATTRIBUTE_UNUSED) const OVERRIDE {
+ return true;
+ }
bool CanBeNull() const OVERRIDE {
return GetTrueValue()->CanBeNull() || GetFalseValue()->CanBeNull();
@@ -6304,7 +6287,7 @@ std::ostream& operator<<(std::ostream& os, const MoveOperands& rhs);
static constexpr size_t kDefaultNumberOfMoves = 4;
-class HParallelMove : public HTemplateInstruction<0> {
+class HParallelMove FINAL : public HTemplateInstruction<0> {
public:
explicit HParallelMove(ArenaAllocator* arena, uint32_t dex_pc = kNoDexPc)
: HTemplateInstruction(SideEffects::None(), dex_pc),