summaryrefslogtreecommitdiff
path: root/compiler/optimizing/nodes.h
diff options
context:
space:
mode:
author Calin Juravle <calin@google.com> 2015-01-12 18:45:46 +0000
committer Calin Juravle <calin@google.com> 2015-01-21 14:26:35 +0000
commit77520bca97ec44e3758510cebd0f20e3bb4584ea (patch)
tree2e3be6fdc182e5cf5ae390019457af5e9c1ed242 /compiler/optimizing/nodes.h
parent4d2c611bf17ff309abfa152e56c0b98a21ec8787 (diff)
Record implicit null checks at the actual invoke time.
ImplicitNullChecks are recorded only for instructions directly (see NB below) preceeded by NullChecks in the graph. This way we avoid recording redundant safepoints and minimize the code size increase. NB: ParallalelMoves might be inserted by the register allocator between the NullChecks and their uses. These modify the environment and the correct action would be to reverse their modification. This will be addressed in a follow-up CL. Change-Id: Ie50006e5a4bd22932dcf11348f5a655d253cd898
Diffstat (limited to 'compiler/optimizing/nodes.h')
-rw-r--r--compiler/optimizing/nodes.h55
1 files changed, 49 insertions, 6 deletions
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index fa51f27f0a..0bd571a1fb 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -696,6 +696,9 @@ class HInstruction : public ArenaObject<kArenaAllocMisc> {
HInstruction* GetNext() const { return next_; }
HInstruction* GetPrevious() const { return previous_; }
+ HInstruction* GetNextDisregardingMoves() const;
+ HInstruction* GetPreviousDisregardingMoves() const;
+
HBasicBlock* GetBlock() const { return block_; }
void SetBlock(HBasicBlock* block) { block_ = block; }
bool IsInBlock() const { return block_ != nullptr; }
@@ -716,6 +719,8 @@ class HInstruction : public ArenaObject<kArenaAllocMisc> {
virtual bool CanThrow() const { return false; }
bool HasSideEffects() const { return side_effects_.HasSideEffects(); }
+ virtual bool CanDoImplicitNullCheck() const { return false; }
+
void AddUseAt(HInstruction* user, size_t index) {
uses_ = new (block_->GetGraph()->GetArena()) HUseListNode<HInstruction>(user, index, uses_);
}
@@ -1597,7 +1602,7 @@ class HInvoke : public HInstruction {
// Runtime needs to walk the stack, so Dex -> Dex calls need to
// know their environment.
- virtual bool NeedsEnvironment() const { return true; }
+ bool NeedsEnvironment() const OVERRIDE { return true; }
void SetArgumentAt(size_t index, HInstruction* argument) {
SetRawInputAt(index, argument);
@@ -1659,6 +1664,12 @@ class HInvokeStaticOrDirect : public HInvoke {
: HInvoke(arena, number_of_arguments, return_type, dex_pc, dex_method_index),
invoke_type_(invoke_type) {}
+ bool CanDoImplicitNullCheck() 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.
+ return false;
+ }
+
InvokeType GetInvokeType() const { return invoke_type_; }
DECLARE_INSTRUCTION(InvokeStaticOrDirect);
@@ -1680,6 +1691,11 @@ class HInvokeVirtual : public HInvoke {
: HInvoke(arena, number_of_arguments, return_type, dex_pc, dex_method_index),
vtable_index_(vtable_index) {}
+ bool CanDoImplicitNullCheck() const OVERRIDE {
+ // TODO: Add implicit null checks in intrinsics.
+ return !GetLocations()->Intrinsified();
+ }
+
uint32_t GetVTableIndex() const { return vtable_index_; }
DECLARE_INSTRUCTION(InvokeVirtual);
@@ -1701,6 +1717,11 @@ class HInvokeInterface : public HInvoke {
: HInvoke(arena, number_of_arguments, return_type, dex_pc, dex_method_index),
imt_index_(imt_index) {}
+ bool CanDoImplicitNullCheck() const OVERRIDE {
+ // TODO: Add implicit null checks in intrinsics.
+ return !GetLocations()->Intrinsified();
+ }
+
uint32_t GetImtIndex() const { return imt_index_; }
uint32_t GetDexMethodIndex() const { return dex_method_index_; }
@@ -2180,7 +2201,11 @@ class HInstanceFieldGet : public HExpression<1> {
return GetFieldOffset().SizeValue() == other_get->GetFieldOffset().SizeValue();
}
- virtual size_t ComputeHashCode() const {
+ bool CanDoImplicitNullCheck() const OVERRIDE {
+ return GetFieldOffset().Uint32Value() < kPageSize;
+ }
+
+ size_t ComputeHashCode() const OVERRIDE {
return (HInstruction::ComputeHashCode() << 7) | GetFieldOffset().SizeValue();
}
@@ -2210,11 +2235,14 @@ class HInstanceFieldSet : public HTemplateInstruction<2> {
SetRawInputAt(1, value);
}
+ bool CanDoImplicitNullCheck() const OVERRIDE {
+ return GetFieldOffset().Uint32Value() < kPageSize;
+ }
+
const FieldInfo& GetFieldInfo() const { return field_info_; }
MemberOffset GetFieldOffset() const { return field_info_.GetFieldOffset(); }
Primitive::Type GetFieldType() const { return field_info_.GetFieldType(); }
bool IsVolatile() const { return field_info_.IsVolatile(); }
-
HInstruction* GetValue() const { return InputAt(1); }
DECLARE_INSTRUCTION(InstanceFieldSet);
@@ -2238,6 +2266,15 @@ class HArrayGet : public HExpression<2> {
UNUSED(other);
return true;
}
+ bool CanDoImplicitNullCheck() const OVERRIDE {
+ // TODO: We can be smarter here.
+ // Currently, the array access is always preceded by an ArrayLength or a NullCheck
+ // which generates the implicit null check. There are cases when these can be removed
+ // to produce better code. If we ever add optimizations to do so we should allow an
+ // implicit check here (as long as the address falls in the first page).
+ return false;
+ }
+
void SetType(Primitive::Type type) { type_ = type; }
HInstruction* GetArray() const { return InputAt(0); }
@@ -2265,12 +2302,17 @@ class HArraySet : public HTemplateInstruction<3> {
SetRawInputAt(2, value);
}
- bool NeedsEnvironment() const {
+ bool NeedsEnvironment() const OVERRIDE {
// We currently always call a runtime method to catch array store
// exceptions.
return needs_type_check_;
}
+ bool CanDoImplicitNullCheck() const OVERRIDE {
+ // TODO: Same as for ArrayGet.
+ return false;
+ }
+
void ClearNeedsTypeCheck() {
needs_type_check_ = false;
}
@@ -2313,11 +2355,12 @@ class HArrayLength : public HExpression<1> {
SetRawInputAt(0, array);
}
- virtual bool CanBeMoved() const { return true; }
- virtual bool InstructionDataEquals(HInstruction* other) const {
+ bool CanBeMoved() const OVERRIDE { return true; }
+ bool InstructionDataEquals(HInstruction* other) const OVERRIDE {
UNUSED(other);
return true;
}
+ bool CanDoImplicitNullCheck() const OVERRIDE { return true; }
DECLARE_INSTRUCTION(ArrayLength);