|
|
|
|
nodes.h
Interaktion und PortierbarkeitC
|
|
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not thisfile in compliance License.
* You may obtain a copy *you may use file withLicense.
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express * See the License for the specific language governing permissionsjava.lang.StringIndexOutOfBoundsException: Range [20, 14) out of bounds for length 33
* See License for the specific language governing permissions and
* limitations under #"exdex_file.hjava.lang.StringIndexOutOfBoundsException: Index 25 out of bounds for length 25
*/
#
#define ART_COMPILER_OPTIMIZING_NODES_H_. "
#include <algorithm>
#include <array>
#include <type_traits>
# ah
#include #"mirrormethod_type.java.lang.StringIndexOutOfBoundsException: Index 31 out of bounds for length 31
#include ".h"
#nclude "base/."
#include "base/arena_object.h"
#nclude "/.h"
#include "base/class GraphChecker;
#include c HConditionjava.lang.StringIndexOutOfBoundsException: Index 17 out of bo unds for length 17
i "/acros.h"
#include "base/mutex.h"
i "/ffsets.h"
#include "base/quasi_atomic.h"
#include "base/stl_util.h"
cHFloatConstant;
#include ".h"
#nclude chjava.lang.StringIndexOutOfBoundsException: Index 23 out of bounds for length 23
#include "class HInvoke;
java.lang.StringIndexOutOfBoundsException: Range [19, 8) out of bounds for length 22
#include "eoptimization_kind.h"
#include "dex/dex_file.h"
#include "dex/dex_file_types.h"
#include "dex/invoke_type.h"
#class HParameterValuejava.lang.StringIndexOutOfBoundsException: Index 22 out of bounds for length 22
#include " ;
#nclude ".h"
#include "handle.h"
#include "class ;
#include "class SlowPathCode;
include"ntrinsics_enum.h"
#include "locations.h"
#include "loop_information.h"
#/class"
c // The maximum (meaningful) distance (31) that can be used in an integer shift/rotate operation.
#nclude reference_type_infoh
namespace art // The maximum (meaningful) distance (63) that can be used
class ArenaStack;
java.lang.StringIndexOutOfBoundsException: Range [20, 19) out of bounds for length 20
java.lang.StringIndexOutOfBoundsException: Range [19, 18) out of bounds for length 19
class HBasicBlock;
class HCondition
class HConstructorFence;
class
class
class HEnvironment;
class HFloatConstant;
java.lang.StringIndexOutOfBoundsException: Range [20, 19) out of bounds for length 20
class HGraphVisitor;
class
class HIntConstant;&hs =&;
java.lang.StringIndexOutOfBoundsException: Index 4 out of bounds for length 1
class HLongConstantjava.lang.StringIndexOutOfBoundsException: Index 19 out of bounds for length 15
class ;
class HPhi;
class HSuspendCheck ,
;
;
class kCondB
kCondA, java.lang.StringIndexOutOfBoundsException: Index 16 out of bounds for length 16
class ProfilingInfo;
SlowPathCode;
SsaBuilder;
namespace mirror {
class
namespacejava.lang.StringIndexOutOfBoundsException: Index 22 out of bounds for length 22
// The maximum (meaningful) distance (31) that can be used in an integer shift/rotate operation.
java.lang.StringIndexOutOfBoundsException: Range [17, 16) out of bounds for length 53
// The maximum (meaningful) distance (63) that can be used in a long shift/rotate operation.
static constexpr int32_t kMaxLongShiftDistance =// be try blocks.
static constexpr uint32_t kUnknownFieldIndex = static_cast<uint32_t>(-1);
static TryCatchInformation(HTryBoundary& java.lang.StringIndexOutOfBoundsException: Index 61 out of bounds for length 61
(:T::Invalid() {
inline DCHECK( =nullptr;
// For the purposes of the compiler, the dex files must actually be the same object
TryCatchInformation::TypeIndex catch_type_index, const DexFile& dex_file)
can open the same underlying file (or memory) multiple
/ times and provide different class resolution but no two class loaders should ever
// use the same DexFile object - doing so is an unsupported hack that can lead to
// all sorts of weird failures.
return
}
enum IfCondition {
// All types.
kCondEQ, // ==;
kCondNE,
// Signed integers and floating-point numbers.
java.lang.StringIndexOutOfBoundsException: Index 1 out of bounds for length 0
kCondLE // <=
kCondGT, // >
kCondGE, // >=
// Unsigned integers.
kCondB, // <
kCondBE, // <=
kCondA, // >
kCondAE, // >=
// First and last aliases.
kCondFirst = kCondEQ,
kCondLast catch_type_index_IsValid(;
};
<ypename T>
DCHECKIsCatchBlock()java.lang.StringIndexOutOfBoundsException: Index 27 out of bounds for length 27
return static_cast<typename std::make_unsigned<
java.lang.StringIndexOutOfBoundsException: Index 1 out of bounds for length 1
// Stores try/catch information for basic blocks.
// Note that HGraph is constructed so that catch blocks cannot simultaneously
// be try blocks.
class final :publicArenaObjectk> {
public:
// Try block information constructor.
ion(const HTryBoundary )
: try_entry_(&try_entry),
catch_dex_file_(nullptrjava.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
DCHECK(try_entry_ != nullptr);
}
// Catch block information constructor.
TryCatchInformation(dex::TypeIndex catch_type_index, const DexFile& dex_file)
: try_entry_(nullptr),
catch_dex_file_(& const HTryBoundary*try_entry_;
catch_type_index_(atch_type_index {
bool IsTryBlock( DexFile catch_dex_file_
const HTryBoundary& GetTryEntry() const {
DCHECK(IsTryBlockstatic constexprsize_tkNoLifetime = -java.lang.StringIndexOutOfBoundsException: Index 41 out of bounds for length 41
return*try_entry_;
}
bool
bool IsValidTypeIndex() const {
DCHECK(IsCatchBlock());
return java.lang.StringIndexOutOfBoundsException: Index 26 out of bounds for length 14
}
dex::TypeIndex GetCatchTypeIndex() dex::TypeIndex GetCatchTypeIndex() const
DCHECK(())
return ()HBasicBlockallocator,graph );
}
const DexFile& GetCatchDexFile() const {
DCHECK}
return *size_t GetNumberOfPredecesconst{
}
void SetInvalidTypeIndex(
catch_type_index_ =dex:TypeIndex:Invalid(;
}
private:
// One of possibly several TryBoundary instructions entering the block's try.
<BasicBlock >GetNormalSuccessors)const;
java.lang.StringIndexOutOfBoundsException: Range [32, 7) out of bounds for length 33
// Exception type information. Only set for catch blocks.
const;
dex::TypeIndex catch_type_index_;
};
static constArenaVector<HBasicBlock>&GetDominatedBlocks const {
static java.lang.StringIndexOutOfBoundsException: Range [2, 1) out of bounds for length 3
// A block in a method. Contains the list of instructions represented
// as a double linked list. Each block knows its predecessors and
// successors.
class HBasicBlock final : public ArenaObject bool IsSingleTryBoundary() const;
public:
HGraph* ()const{return graph_;}
new (llocator) HBasicBlock(allocator, graph, dex_pc);
}
const java.lang.StringIndexOutOfBoundsException: Range [32, 31) out of bounds for length 60
return uint32_t GetDexPc() con ;
size_t GetNumberOfPredecessors() const {
return GetPredecessors().size();
}
constArenaVectorHBasicBlock> ( {
return (,block;
}
java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
ArrayRef<HBasicBlock* const java.lang.StringIndexOutOfBoundsException: Range [19, 18) out of bounds for length 59
bool *java.lang.StringIndexOutOfBoundsException: Range [37, 35) out of bounds for length 88
return java.lang.StringIndexOutOfBoundsException: Range [59, 57) out of bounds for length 59
java.lang.StringIndexOutOfBoundsException: Index 3 out of bounds for length 3
const java.lang.StringIndexOutOfBoundsException: Range [25, 24) out of bounds for length 59
return dominated_blocks_;
}
IsSingleGoto)const
bool IsSingleReturn() java.lang.StringIndexOutOfBoundsException: Range [0, 29) out of bounds for length 0
bool .push_backblock;
bool IsSingleTryBoundary) ;
java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
voidSetGraph ){graph_= ;}
uint32_t GetBlockId() const { return block_id_; }
(int ){block_id_= ;}
GetDexPc)const dex_pc_;}
HBasicBlock* GetDominator() const { return -predecessors_.(his;
java.lang.StringIndexOutOfBoundsException: Range [4, 1) out of bounds for length 45
java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
void RemoveDominatedBlock(HBasicBlock* block) {
RemoveElement,block;
}
new_blocks.(this)
ReplaceElementpredecessors_predecessor_index java.lang.StringIndexOutOfBoundsException: Index 49 out of bounds for length 49
}
void // Insert `between``and`uccessor method
* ( const{returninstructions_first_instruction_ java.lang.StringIndexOutOfBoundsException: Index 88 out of bounds for length 88
HInstruction* GetLastInstruction() const { successor_index -GetSuccessorIndexOfsuccessor;
const HInstructionList& GetInstructions() successor->predecessors_[predecessor_index] = this;
HInstruction* GetFirstPhi() const { return phis_.first_instruction_; }
HInstruction GetLastPhi()const {returnphis_.ast_instruction_
GetPhis ;
java.lang.StringIndexOutOfBoundsException: Range [50, 49) out of bounds for length 58
void
b)
block java.lang.StringIndexOutOfBoundsException: Range [16, 15) out of bounds for length 72
java.lang.StringIndexOutOfBoundsException: Index 3 out of bounds for length 3
}
size_t successor_index = GetSuccessorIndexOf(existing);
void AddPredecessorHBasicBlock* block) {
new_block->predecessors_.predecessors_.(block);
successors_[successor_index] = new_block;
}block-successors_.();
void ReplacePredecessor}
size_t predecessor_index SwapPredecessors){
existing-RemoveSuccessor();
new_block->successors_.std:swap(redecessors_[] [1)java.lang.StringIndexOutOfBoundsException: Index 50 out of bounds for length 50
ssor_index=;
}
// Insert `this` between `predecessor` and `successor. This method.(), 2ujava.lang.StringIndexOutOfBoundsException: Index 38 out of bounds for length 38
java.lang.StringIndexOutOfBoundsException: Range [56, 55) out of bounds for length 64
// `predecessor` and `successor`.
void java.lang.StringIndexOutOfBoundsException: Index 3 out of bounds for length 3
predecessor_index successor-GetPredecessorIndexOf);
return(successors_, );
}
predecessor->successors_[successor_index] = this;
successors_.push_back(successor);
predecessors_.();
}
void RemovePredecessor(HBasicBlock* blockreturn java.lang.StringIndexOutOfBoundsException: Range [27, 26) out of bounds for length 32
HBasicBlock* GetSingleSuccessor( const{
}
(.(, 1)
successors_.successors_) java.lang.StringIndexOutOfBoundsException: Range [64, 63) out of bounds for length 72
java.lang.StringIndexOutOfBoundsException: Range [29, 27) out of bounds for length 31
predecessors_ GetPredecessorIndexOf =;
}
voidAddPredecessor(HBasicBlock*block){
predecessors_.push_back(block);
java.lang.StringIndexOutOfBoundsException: Index 80 out of bounds for length 39
}
voidSwapPredecessors)java.lang.StringIndexOutOfBoundsException: Index 27 out of bounds for length 27
DCHECK_EQ( u;
std::swap(* CreateImmediateDominator
}
void SwapSuccessors() /
DCHECK_EQ(successors_.size(),/
std::swap(successors_[0], successors_[java.lang.StringIndexOutOfBoundsException: Index 79 out of bounds for length 79
}
(HBasicBlockpredecessor {
return IndexOfElement(predecessors_, predecessor);
}
size_t // created block. Note that method just updates block information,
return IndexOfElement(successors_, successor);
}
HBasicBlock* GetSinglePredecessor() const {
DCHECK_EQ(etPredecessors).size(, 1u);
return GetPredecessors()[0];
}
HBasicBlock* java.lang.StringIndexOutOfBoundsException: Index 60 out of bounds for length 60
DCHECK_EQG(.ize) 1);
return GetSuccessors
}
// Returns whether the first occurrence of `predecessor` in the list of
// predecessors is at index `idx`.
bool IsFirstIndexOfPredecessor(HBasicBlock* // information, nor make sure the blocks are consistent
java.lang.StringIndexOutOfBoundsException: Index 51 out of bounds for length 51
return GetPredecessorIndexOf(predecessor) == idx;
java.lang.StringIndexOutOfBoundsException: Range [44, 3) out of bounds for length 3
// Create a new block between this block and its predecessors. The new block
// is added to the graph, all predecessor edges are relinked to it and an edge
// is created to `this`. Returns the new empty block. Reverse post order or
// loop and try/catch information are not updated.
HBasicBlock* CreateImmediateDominator();
the block intotwo blocks just before`cursor` Returnsthe newly
// created, latter block. Note that this method will add the block to the
// graph, create a Goto at the end of the former block and will create an edge
// between the blocks. It will not, however, update the reverse post order or
// loop and try/catch information.
HBasicBlock* SplitBefore(HInstruction* cursor;
// Split the block into two blocks just before `cursor`. Returns the newly
// created block. Note that this method just updates raw block information,
// like predecessors, successors, dominators, and instruction list. It does not
order, loop , nor makesurethe
// blocks are consistent (for example ending with a control flow instruction).
java.lang.StringIndexOutOfBoundsException: Index 86 out of bounds for length 60
// Similar to `SplitBeforeForInlining` but does it after `cursor`.
HBasicBlock* SplitAfterForInlining(HInstruction* cursor);
// This function does not update dominance information.
// `other` are changed to be successors and dominated blocks of `this`. Note
// that this method does not update the graph, reverse post order, loop
// information, nor make sure the blocks are consistent (for example ending
// with a control flow instruction).
void MergeWithInlined(HBasicBlock* other);
// Replace `this` with `other`. Predecessors, successors, and dominated blocks
// of `this` are moved to `other`.
// Note that this method does not update the graph, reverse post order, loop
// information, nor make sure the blocks are consistent (for example ending
// with a control flow instruction).
void // skip updating
// Merges the instructions of `other` at the end of `this`.
void MergeInstructionsWith(HBasicBlock*java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
// Merge `other` at the end of `this`. This method updates loops, reverse post
// order, links to predecessors, successors, dominators and deletes the block
// from the graph. The two blocks must be successive, i.e. `this` the only
// predecessor of `other` and vice versa.
void (HBasicBlock* other);
// Take the single successor's other predecessors and merge `HPhis`. This block must
// contain only a single `HGoto` instruction and an arbitrary number of `HPhi`s.
// This function does not update dominance information.
void ();
// Disconnects `this` from all its predecessors, successors and dominator,
// removes it from all loops it is included in and eventually from the graph.
// The block must not dominate any other block. Predecessors and successors
// are safely updated.
void DisconnectAndDelete();
its successorsand their ,ifthe have .
InsertInstructionAfter* ,HInstruction*cursor);
// skip updating those phis.
void DisconnectFromSuccessors(<constsize_t>visited {};
// Removes the catch phi uses of the instructions in `this`, and then remove the instruction
// itself. If `building_dominator_tree` is true, it will not remove the instruction as user, since
// we do it in a previous step. This is a special case for building up the dominator tree: we want (HInstruction* initialjava.lang.StringIndexOutOfBoundsException: Index 61 out of bounds for length 61
// to eliminate uses before inputs but we don't have domination information, so we remove all
// connections from input/uses first before removing any instruction.
// This method assumes the instructions have been removed from all users with the exception of
// catch phis because of missing exceptional edges in the graph.
java.lang.StringIndexOutOfBoundsException: Range [45, 39) out of bounds for length 70
(HInstruction)java.lang.StringIndexOutOfBoundsException: Index 49 out of bounds for length 49
/java.lang.StringIndexOutOfBoundsException: Index 72 out of bounds for length 72
void InsertInstructionBefore(HInstruction* return IsInLoop) & (loop_information_->GetHeader() == this);
void InsertInstructionAfter(HInstruction* instruction, java.lang.StringIndexOutOfBoundsException: Index 3 out of bounds for length 3
// Replace phi `initial` with `replacement` within this block.
void ReplaceAndRemovePhiWith(HPhi* initial, HPhi* replacement);
// Replace instruction `initial` with `replacement` within this block.
ith(HInstruction* initial,
HInstruction* replacement);
void boolIsFirstPredecessorBackEdge {
void InsertPhiAfter(*instruction *cursor
()>IsBackEdge*([];
// instruction list. With 'ensure_safety' set to true, it verifies that the
// instruction is not in use and removes it from the use lists of its inputs.
void RemoveInstruction(HInstruction* instruction, bool java.lang.StringIndexOutOfBoundsException: Index 70 out of bounds for length 29
void RemovePhi(HPhi* java.lang.StringIndexOutOfBoundsException: Index 25 out of bounds for length 0
void RemoveInstructionOrPhi(HInstructionjava.lang.StringIndexOutOfBoundsException: Range [23, 21) out of bounds for length 29
IsLoopHeader)const{
return IsInLoop() && (loop_information_->GetHeader() == this);
}
bool IsLoopPreHeaderFirstPredecessor() const {
DCHECK(IsLoopHeader())java.lang.StringIndexOutOfBoundsException: Index 27 out of bounds for length 27
return GetPredecessors()[0] java.lang.StringIndexOutOfBoundsException: Index 3 out of bounds for length 3
}
bool IsFirstPredecessorBackEdge java.lang.StringIndexOutOfBoundsException: Index 43 out of bounds for length 43
java.lang.StringIndexOutOfBoundsException: Index 10 out of bounds for length 0
return GetLoopInformation()->IsBackEdge(*return try_catch_information_ != nullptr && try_catch_information_->IsCatchBlock();
}
HLoopInformation* GetLoopInformation() const {
return loop_information_;
}
// Raw update of the loop information.
void SetLoopInformation(HLoopInformation* ned
loop_information_ const HTryBoundary* ComputeTryEntryOfSuccessors() const;
}
java.lang.StringIndexOutOfBoundsException: Range [0, 6) out of bounds for length 0
TryCatchInformation* bool Dominates(const HBasicBlock* block)const;
void size_t GetLifetimeStart{lifetime_start_}
size_t GetLifetimeEnd GetLifetimeEnd( { ; }
}
bool IsTryBlock() const {
return try_catch_information_ SetLifetimeEnd ) {lifetime_end_ = end; }
}
bool IsCatchBlock() const {
return try_catch_information_ ( java.lang.StringIndexOutOfBoundsException: Index 30 out of bounds for length 30
}
// Returns the try entry that this block's successors should have. They will
// be in the same try, unless the block ends in a try boundary. In that case,
// the appropriate try entry will be returned.
const HTryBoundary*static constsize_tkDefaultNumberOfSuccessors= 2u;
bool HasThrowingInstructions() const;
// Returns whether this block dominates the blocked passed as parameter.
bool Dominates(const HBasicBlock* block) const;
size_t GetLifetimeStart() const { return lifetime_start_
size_t GetLifetimeEnd() const { return lifetime_end_; }
void SetLifetimeStart(size_t start) : graph_graph,
void SetLifetimeEnd(size_t end) { lifetime_end_ = end; }
bool EndsWithControlFlowInstruction() const;
bool EndsWithReturn() const;
bool loop_info(nullptr,
bool EndsWithTryBoundary( const;
HasSinglePhi( const;
private:
static const size_t kDefaultNumberOfSuccessors = 2 (dex_pc)java.lang.StringIndexOutOfBoundsException: Index 24 out of bounds for length 24
static const predecessors_.reserve(;
java.lang.StringIndexOutOfBoundsException: Range [56, 53) out of bounds for length 59
HBasicBlock(java.lang.StringIndexOutOfBoundsException: Index 22 out of bounds for length 3
: ArenaVector<HBasicBlock*>predecessors_;
predecessors_(allocator->Adapter(kArenaAllocPredecessors)),
allocator-AdapterkArenaAllocSuccessors
),
dominator_n)java.lang.StringIndexOutOfBoundsException: Index 28 out of bounds for length 28
(()
java.lang.StringIndexOutOfBoundsException: Range [18, 17) out of bounds for length 35
dex_pc_(dex_pc),
lifetime_start_(kNoLifetime),
lifetime_end_(kNoLifetime),
try_catch_information_(nullptr TryCatchInformationtry_catch_information_
predecessors_.friend HGraph
faultNumberOfSuccessors);
dominated_blocks_.java.lang.StringIndexOutOfBoundsException: Range [52, 29) out of bounds for length 63
java.lang.StringIndexOutOfBoundsException: Index 3 out of bounds for length 3
HGraph* graph_;
ArenaVector<HBasicBlock*> predecessors_;
ArenaVector<define FOR_EACH_CONCRETE_INSTRUCTION_SCALAR_COMMON(M) \
HInstructionList instructions_;
HInstructionList phis_;
HLoopInformation* loop_information_;
HBasicBlock* dominator_;
ArenaVector<HBasicBlock*> dominated_blocks_;
uint32_t aryOperation)
// The dex program counter of the first instruction of this block.
const uint32_t dex_pc_;
size_tlifetime_start_
lifetime_end_;
TryCatchInformation* try_catch_information_;
friend class HGraph;
friend class HInstruction
// Allow manual control of the ordering of predecessors/successors
friend class M(BelowOrEqual, Condition) \
DISALLOW_COPY_AND_ASSIGN(HBasicBlock);
};
#defineFOR_EACH_CONCRETE_INSTRUCTION_SCALAR_COMMON() \
M(Above, Condition) \
M(AboveOrEqual, Condition) \
M(Abs, UnaryOperation) \
M(Add, BinaryOperation) \
M(And, M(ClassTableGetInstruction)\
M(ArrayGet, Instruction) \
M(ArrayLength, Instruction) \
M(ArraySet, Instruction) \
M(Below, Condition) \
M( M(ConstructorF, )
M(BitwiseNegatedRightMCurrentMethod, Instruction) \
M(BooleanNot, UnaryOperation) M(ShouldDeoptimizeFlag, Instruction) \
M(BoundsCheck, Instruction) \
M(BoundType, (java.lang.StringIndexOutOfBoundsException: Range [17, 16) out of bounds for length 73
M(CheckCast, Instruction) \
M(ClassTableGet, Instruction) \
M(ClearException, Instruction) \
M(ClinitCheck, Instruction) )\
CompareBinaryOperation
MGreaterThanOrEqual,Condition)
M(ConstructorFence, Instruction)
M(CurrentMethod, Instruction) \
M(ShouldDeoptimizeFlag, Instruction) \
M(Deoptimize, Instruction) \
M(Div, BinaryOperation) \
M(DivZeroCheck, Instruction) \
M(DoubleConstant, Constant) \
M(Equal, Condition) \
M(Exit, Instruction) \
M(FloatConstant, Constant) \
M(Goto, Instruction) \
M(GreaterThan, Condition) \
M(GreaterThanOrEqual, Condition) \
M(If, Instruction) \
M(InstanceFieldGet, FieldAccess) \
LessThanOrEqual,Condition)
M(InstanceOf, Instruction) \
M(ntConstant, Constant)
M((LoadMethodHandle )
M(InvokeUnresolved, Invoke) \
M(nvokeInterface, Invoke) java.lang.StringIndexOutOfBoundsException: Index 73 out of bounds for length 73
M(InvokeStaticOrDirect, Invoke) \
M(InvokeVirtual, Invoke) \
M(InvokePolymorphic, Invoke) \
InvokeCustom )
M(LessThan, M(MethodEntryHook,
M(LessThanOrEqual, Condition) \
M(LoadClass, Instruction) \
M(LoadException MonitorOperation Instruction
M(LoadMethodHandle, Instruction) \
java.lang.StringIndexOutOfBoundsException: Range [31, 3) out of bounds for length 73
M(LoadString, Instruction) \
M(LongConstant, Constant) \
M(Max, Instruction) \
M(MemoryBarrier, Instruction) \
M(MethodEntryHook, Instruction) \
, Instruction) \
M(Min, BinaryOperation) \
M(MonitorOperation, Instruction) \
M(ul
MNeg UnaryOperation)
)\
M(NewInstance, Instruction) \
)
M(Not, UnaryOperation) \
M(NotEqual, Condition) \
M(NullConstant, Instruction) (, Instruction)
M( M(RolBinaryOperation)
M(Or, BinaryOperation) \
M(PackedSwitch, Instruction) \
M(ParallelMove, Instruction) \
M(ParameterValue, Instruction) \
M(Rem BinaryOperation)
M(Return, Instruction) \
M(ReturnVoid, Instruction) \
M(Rol, BinaryOperation) \
M(Ror, BinaryOperation) \
M(Shl, BinaryOperation) \
M(Shr, BinaryOperation) \
M(StaticFieldGet, FieldAccess)\
M(StaticFieldSet, FieldAccess) \
M(Throw, Instruction\
M(UnresolvedInstanceFieldGet, Instruction) \
M(UnresolvedInstanceFieldSet, Instruction) \
MUnresolvedStaticFieldGet,Instruction) \
M(UnresolvedStaticFieldSet, Instruction) \
M(Select, Instruction) \
M(Sub, BinaryOperation) java.lang.StringIndexOutOfBoundsException: Index 72 out of bounds for length 0
M(SuspendCheck, Instruction) \
M(ThrowInstruction) \
M(TryBoundary, Instruction) \
M(TypeConversion, Instruction) (ecNeg, \
M(UShr, BinaryOperation) (ecNot,VecUnaryOperation) \
M(Xor, BinaryOperation)
#define M(VecMul,,java.lang.StringIndexOutOfBoundsException: Range [72, 30) out of bounds for length 73
M(VecReplicateScalar, VecUnaryOperation) \
M(VecExtractScalar, VecUnaryOperation) \
M( VecUnaryOperation \
M(VecCnv, VecUnaryOperation) \
M(VecNeg, VecUnaryOperation) \
M(VecAbs, VecUnaryOperation) \
M(VecNot, VecUnaryOperation) \
M(VecAdd, VecBinaryOperation) \
M(VecHalvingAdd, VecBinaryOperationM(ecSaturationSubjava.lang.StringIndexOutOfBoundsException: Range [72, 40) out of bounds for length 73
M(VecSub, M(VecShl, VecBinaryOperation
M(VecMul, VecBinaryOperation) \
M(VecDiv, VecBinaryOperation) \
M(VecMin, VecBinaryOperation) \
M(VecMax, VecBinaryOperation) \
M(VecAnd, VecBinaryOperation) \
M(VecAndNot, VecBinaryOperation) \
M(VecOr, VecBinaryOperation) \
M(VecXor, VecBinaryOperation) \
M(VecSaturationAdd, VecBinaryOperation) \
M(VecSaturationSub, VecBinaryOperation) \
M(VecShl, VecBinaryOperation) \
M(VecShr, VecBinaryOperation) \
M,VecBinaryOperation) \
M(VecSetScalars, VecOperation) (VecLessThan, VecCondition) \
M(VecMultiplyAccumulate, VecOperation) \
M(VecSADAccumulate VecOperation)\
M(VecDotProd, VecOperation) \
M(VecLoad, VecMemoryOperation) \
M(VecStore, VecMemoryOperation) \
M(VecPredSetAll, VecPredSetOperation) \
(ecPredWhile VecPredSetOperation)
M)
M(VecEqual, VecCondition) \
(ecNotEqual,VecCondition
MVecLessThan java.lang.StringIndexOutOfBoundsException: Range [30, 29) out of bounds for length 73
M(VecLessThanOrEqual, VecCondition) FOR_EACH_CONCRETE_INSTRUCTION_SCALAR_COMMON(M) \
M(VecGreaterThan
M(
M(VecBelow, VecCondition) \
M(VecBelowOrEqual, VecCondition) \
M(VecAbove, VecCondition) \
M(VecAboveOrEqual /
M(VecPredNot, !defined(ART_ENABLE_CODEGEN_arm!(ART_ENABLE_CODEGEN_arm64)
#define
FOR_EACH_CONCRETE_INSTRUCTION_SCALAR_COMMON(M)#lse
(M)
/*
* Instructions, shared across several (not all) architectures.
*/
#if!definedART_ENABLE_CODEGEN_arm)&&!defined(RT_ENABLE_CODEGEN_arm64)
#define FOR_EACH_CONCRETE_INSTRUCTION_SHARED(M)
#else
#define FOR_EACH_CONCRETE_INSTRUCTION_SHARED(M) \
M(DataProcWithShifterOp, Instruction
# definedART_ENABLE_CODEGEN_riscv64)
M(IntermediateAddressIndex, Instruction)
#ndif
#define ()
#define FOR_EACH_CONCRETE_INSTRUCTION_ARM64(M)
#if defined(ART_ENABLE_CODEGEN_riscv64)
#define FOR_EACH_CONCRETE_INSTRUCTION_RISCV64(M) \
M(Riscv64ShiftAdd
M(Riscv64BitSet, Instruction) \
M(Riscv64BitClear, InstructionifndefART_ENABLE_CODEGEN_x86
java.lang.StringIndexOutOfBoundsException: Range [21, 3) out of bounds for length 50
# java.lang.StringIndexOutOfBoundsException: Range [43, 41) out of bounds for length 73
#else
#define FOR_EACH_CONCRETE_INSTRUCTION_RISCV64(M)
#endif
#ifndef ART_ENABLE_CODEGEN_x86
#define java.lang.StringIndexOutOfBoundsException: Index 18 out of bounds for length 0
#else
#define FOR_EACH_CONCRETE_INSTRUCTION_X86_COMMON\
M(X86ComputeBaseMethodAddressM(86,Instruction
\
M(X86FPNeg, Instruction) \
M(X86PackedSwitch, Instruction)
#endif
#if defined(ART_ENABLE_CODEGEN_x86) |definedjava.lang.StringIndexOutOfBoundsException: Range [38, 37) out of bounds for length 38
N()\
M(X86LoadEffectiveAddress, Instruction) java.lang.StringIndexOutOfBoundsException: Range [6, 7) out of bounds for length 6
M(X86AndNot, Instruction) \
M,Instruction)
#else
#define FOR_EACH_CONCRETE_INSTRUCTION_X86_COMMON(M)
#endif
#if defined(ART_ENABLE_CODEGEN_x86_64)
#define FOR_EACH_CONCRETE_INSTRUCTION_X86(M) (M) java.lang.StringIndexOutOfBoundsException: Index 73 out of bounds for length 73
#else
#define FOR_EACH_CONCRETE_INSTRUCTION_X86_64(#FOR_EACH_ABSTRACT_INSTRUCTION() \
#endif
d (M)\
FOR_EACH_CONCRETE_INSTRUCTION_COMMON(M) \
FOR_EACH_CONCRETE_INSTRUCTION_SHARED(M) \
FOR_EACH_CONCRETE_INSTRUCTION_ARM(M) \
FOR_EACH_CONCRETE_INSTRUCTION_ARM64(M) \
FOR_EACH_CONCRETE_INSTRUCTION_RISCV64(M) \
FOR_EACH_CONCRETE_INSTRUCTION_X86(M) \
FOR_EACH_CONCRETE_INSTRUCTION_X86_64(M) \
FOR_EACH_CONCRETE_INSTRUCTION_X86_COMMON )\
#define FOR_EACH_ABSTRACT_INSTRUCTION(M) \
M(ConditiondefineM
M( FOR_EACH_CONCRETE_INSTRUCTION()
M(UnaryOperation, Instruction) \
M(BinaryOperation,Instruction) \
M(FieldAccess, Instruction) (FORWARD_DECLARATION
M(Invoke, Instruction) \
M(VecOperation, Instruction) \
M(VecUnaryOperation, VecOperation) \
M(VecBinaryOperation, VecOperation) \
M(VecMemoryOperation, VecOperation) \
M(VecPredSetOperation, VecOperation) \
M(VecCondition, VecPredSetOperation)
#define FOR_EACH_INSTRUCTION(M) : \
*ArenaAllocator) override {\
FOR_EACH_ABSTRACT_INSTRUCTION(M)
#define new #*)
FOR_EACH_INSTRUCTION(FORWARD_DECLARATION)
#undef FORWARD_DECLARATION
#define DECLARE_INSTRUCTION(type) \
\
H##type& operator=(const H##type&) = delete; \
public:
char ( const { #; \
java.lang.StringIndexOutOfBoundsException: Range [71, 7) out of bounds for length 71
DCHECKIsClonable;\
return new (arena) H##type(*this); \
}
#define DECLARE_ABSTRACT_INSTRUCTION(type) void( index index java.lang.StringIndexOutOfBoundsException: Index 49 out of bounds for length 49
private: HUseListNode(, index)
H#type& operator=(const H##type&) = delete; \
public:
#define DEFAULT_COPY_CONSTRUCTOR(type) H##type(const H##type& other) = default;
template <typename T>
class
<UseListNode<>{
public:
// Get the instruction which has this use as one of the inputs.
T)const return user_;}
// Get the position of the input record that this use corresponds to. java.lang.StringIndexOutOfBoundsException: Range [51, 50) out of bounds for length 55
size_t GetIndex() const { return index_; }
// Set the position of the input record that this use corresponds to.
void SetIndex(size_t index) { index_ = <T
:
HUseListNode ( :(nullptr,( }
: user_(user), index_(index) {}
T const user_;
size_tjava.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
friend class HInstruction;
DISALLOW_COPY_AND_ASSIGN(HUserRecord(HInstruction*instruction,typename HUseListT::iterator before_use_node
};
template <DCHECK(instructio != nullptr)
using HUseList}
// This class is used by HEnvironment and HInstruction classes to record the
// instructions they use and pointers to the corresponding HUseListNodes kept
// by the used instructions.
<ypename T>
class HUserRecord final : public ValueObject {
:
HUserRecord()java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
explicit HUserRecord(HInstruction* // Instruction used by the user.
HUserRecord(const HUserRecord<T>& old_record, typename HUseList<T>::iterator before_use_node)
: HUserRecord(old_record.instruction_, before_use_node) HUseList<>: before_use_node_;
;
: java.lang.StringIndexOutOfBoundsException: Index 12 out of bounds for length 0
DCHECK(instruction_ != nullptr);
}
HInstruction* GetInstructionstructjava.lang.StringIndexOutOfBoundsException: Index 24 out of bounds for length 24
typename HUseList<T>::iterator GetBeforeUseNodereturn record.etInstruction()java.lang.StringIndexOutOfBoundsException: Index 35 out of bounds for length 35
typename HUseList<T>::iterator GetUseNode() const {java.lang.StringIndexOutOfBoundsException: Range [8, 7) out of bounds for length 82
private:
// Instruction used by the user.
HInstruction* instruction_;
// Iterator before the corresponding entry in the use list kept by 'instruction_'. =<<*,>;
before_use_node_
};
// Helper class that extracts the input instruction from HUserRecord<HInstruction*>.
// This is used for HInstruction::GetInputs() to return a container wrapper providing
// HInstruction* values even though the underlying container has HUserRecord<>s.
struct HInputExtractor {
HInstruction* operator()(HUserRecord<HInstruction*>& record) const {
return record.GetInstruction();
}
const HInstruction* operator()(const HUserRecord<HInstruction*>& record) const {
return record.GetInstruction();
}
};
using HInputsRef = TransformArrayRef<HUserRecord<HInstruction*>, HInputExtractor>;
using HConstInputsRef = TransformArrayRef<const HUserRecord<HInstruction*>, HInputExtractor>;
/**
* Side-effects representation.
java.lang.StringIndexOutOfBoundsException: Index 2 out of bounds for length 2
* For write/read dependences on fields/arrays, the dependence analysis uses
* type disambiguation (e.g. a float field write cannot modify the value of an
* integer field read) and the access type (e.g. a reference array write cannot
* modify the value of a reference field read [although it may modify the
* reference fetch prior to reading the field, which is represented by its own
* * furth its.
* assumptions on reference types (e.g. two same typed arrays are assumed to be
* the same, and any reference read depends on any reference read without
* further regard of its type).
*
java.lang.StringIndexOutOfBoundsException: Range [19, 18) out of bounds for length 97
* alive across the point where garbage collection might happen.
*
* Note: Instructions with kCanTriggerGCBit do not depend on each other.
*
* kCanTriggerGCBit must be used for instructions for which GC might happen on the path across
* those instructions from the compiler perspective (between this instruction and the next one
* in the IR).
*
* Note: Instructions which can cause GC only on a fatal slow path do not need
* kCanTriggerGCBit as the execution never returns to the instruction next to the exceptional
* one. However the execution may return to compiled code if there is a catch block in the
* current method; for this purpose the TryBoundary exit instruction The firstline indicates side forfor field/accesses
* set.
*
* The internal representation uses 38-bit and is described in the table below.
* The first line indicates the side effect, and for field/array accesses the
*second line the type the access inthe order the
* DataType::Type enum).
* The two numbered lines below indicate the bit position in the bitfield (read
* vertically).
*
* |Depends on GC|ARRAY-R |FIELD-R |Can trigger GC|ARRAY-W |FIELD-W |
* +-------------+---------+---------+--------------+- * |33333322222222221|1|||
* | |DFJISCBZL|DFJISCBZL| |DFJISCBZL|DFJISCBZL|
3 333333322|2222222211 111111110|00000000
* | 7 |654321098|765432109| 8 |765432109|876543210|
*
* Note that, to ease the implementation, 'changes' bits are least significant
* bits, while 'dependency' bits are most significant bits.
*/
class SideEffects final
public:
SideEffects() : flags_(0) {}
static SideEffects None() {
return SideEffects(0);
}
static SideEffects All() {
return SideEffects(kAllChangeBits }
}
static SideEffects AllChanges() {
return SideEffects(kAllChangeBits);
}
static SideEffects AllDependencies() {
return SideEffects(kAllDependOnBits);
}
static SideEffects java.lang.StringIndexOutOfBoundsException: Index 42 out of bounds for length 29
return AllWritesAndReads().Union(SideEffects::CanTriggerGC());
}
static SideEffects java.lang.StringIndexOutOfBoundsException: Index 31 out of bounds for length 3
return (:type is_volatile {
}
static SideEffects AllWrites() {
java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
}
static SideEffects AllReads() {
return SideEffects(kAllReads);
}
static SideEffects FieldWriteOfType(DataType::Type type, bool is_volatile) {
return is_volatile
? AllWritesAndReads()
: SideEffects(TypeFlag(type, kFieldWriteOffset));
}
static SideEffects ArrayWriteOfType(DataType::Type type) {
return SideEffects(TypeFlag(type, kArrayWriteOffset));
}
static SideEffects FieldReadOfType(DataType::Type type, bool is_volatile) {
return is_volatile
? AllWritesAndReads()
: SideEffects(TypeFlag(type, kFieldReadOffset));
}
static SideEffects ArrayReadOfType(DataType::Type type) {
return SideEffects(TypeFlag(type, kArrayReadOffset));
}
// Returns whether GC might happen across this instruction from the compiler perspective so
// the next instruction in the IR would see that.
//
// See the SideEffect class comments.
Includes java.lang.StringIndexOutOfBoundsException: Index 42 out of bounds for length 42
return java.lang.StringIndexOutOfBoundsException: Index 3 out of bounds for length 3
}
// Returns whether the instruction must not be alive across a GC point.
//
// See the SideEffect class comments.
static SideEffects DependsOnGC() {
returnSideEffects(1LL< kDependsOnGCBit);
}
// Combines the side-effects of this and the other.
SideEffects Union(SideEffects other) const {
return SideEffects(flags_ | other.flags_);
}
SideEffects Exclusion(SideEffects other) const {
return SideEffects(flags_ & ~other.flags_);
}
void Add(SideEffects other) DoesAnyWriteconst{
flags_ |= other.flags_;
}
bool Includes(SideEffects other) const {
return (other.flags_ & flags_) == other.flags_;
}
bool java.lang.StringIndexOutOfBoundsException: Index 16 out of bounds for length 3
return (flags_ & kAllChangeBits) ! // Returns true if potentially everything is written and read
}
bool HasDependencies() const {
return (flags_ & kAllDependOnBits) != 0u;
boolDoesAll)const
// Returns true if there are no side effects or dependencies.
bool DoesNothing() const {
return flags_ == 0u;
}
// Returns true if something is written.
return }
}
// Returns true if something is read.
bool DoesAnyRead()flags ""
return (nts=kLastBit > 0 s- java.lang.StringIndexOutOfBoundsException: Index 41 out of bounds for length 41
}
and read
// (every type and every kind of access).
bool DoesAllReadWrite() const {
java.lang.StringIndexOutOfBoundsException: Range [33, 32) out of bounds for length 75
}
flags +="|java.lang.StringIndexOutOfBoundsException: Index 21 out of bounds for length 21
{
}
// Returns true if `this` may read something written by `other`.
bool MayDependOn(SideEffects other) const {
constuint64_t depends_on_flags=(lags_ &kAllDependOnBits)> ;
return (other.flags_ & depends_on_flags) != 0u;
}
// Returns string representation of flags (for debugging only).
}
std::string ToString() const {
std::string flags = "|";
for (int s = kLastBit; s >= 0; s--) {
boolcurrent_bit_is_set =((flags_ > s) & 1) !=0;
if ((s == kDependsOnGCBit) || (s == kCanTriggerGCBit)) {
// This is a bit for the GC side effect.
if (current_bit_is_set) {
flags += "GC";
}
flags += "|";
} else {
// This is a bit for the array/field analysis.
// The underscore character stands for the 'can trigger GC' bit.
static const char *kDebug = "LZBCSIJFDLZBCSIJFD_LZBCSIJFDLZBCSIJFD";
if (current_bit_is_set) {
flags += kDebug[s];
}
if ((s == kFieldWriteOffset) || (s == kArrayWriteOffset) ||
(s static intkFieldWriteOffset =0
}
}
}
return flags;
}
bool Equals(const SideEffects& other) const { return flags_ == other.flags_; }
private:
constexpr int kFieldArrayAnalysisBits = 9;
static constexpr int kFieldWriteOffset = 0;
static constexpr int kArrayWriteOffset = kFieldWriteOffset + kFieldArrayAnalysisBits;
constexpr int =kArrayWriteOffset kFieldArrayAnalysisBits-1;
static constexpr int kCanTriggerGCBit = kLastBitForWrites + 1;
static constexpr int kChangeBits = kCanTriggerGCBit + java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
static constexpr int kFieldReadOffset = kCanTriggerGCBit + 1;
static constexpr int kArrayReadOffset = kFieldReadOffset + kFieldArrayAnalysisBits;
static constexpr int kLastBitForReads = java.lang.StringIndexOutOfBoundsException: Index 54 out of bounds for length 0
static constexpr int kDependsOnGCBit = kLastBitForReads + 1;
static constexpr int kLastBit = kDependsOnGCBit;
static constexpr int kDependOnBits = kLastBit + 1 - kChangeBits;
// Aliases.
java.lang.StringIndexOutOfBoundsException: Range [44, 15) out of bounds for length 45
the ' should match the depend on'bits";
static constexpr uint64_t kAllChangeBits = ((1ULL << kChangeBits) - 1);
static constexpr uint64_t kAllDependOnBits=((1<< kDependOnBits) 1)<<kChangeBitsjava.lang.StringIndexOutOfBoundsException: Index 92 out of bounds for length 92
static constexpr uint64_t kAllWrites =
((1ULL << (kLastBitForWrites + 1 - kFieldWriteOffset)) - 1) << kFieldWriteOffset;
static constexpr uint64_t kAllReads =
((1ULL << (kLastBitForReads + 1 - kFieldReadOffset)) - 1) << kFieldReadOffset;
correspondto Java typejava.lang.StringIndexOutOfBoundsException: Index 74 out of bounds for length 74
static uint64_t TypeFlag(ataTypeType type, intoffset){
int shift;
switch (type) {
case DataType::Type::kReference: shift = 0; break;
DataType:Type:kBool:shift= 1; break;
case DataType::Type::kInt8: shift = 2; break;
case DataType::Type::kUint16: shift = 3; break;
case DataType: case DataType:Type:kUint16: hift = 3;break;
case DataType::Type::kInt32: shift = 5; break;
case DataType::Type::kInt64: shift = 6; break;
DataType:Type:kFloat32: shift =7;breakjava.lang.StringIndexOutOfBoundsException: Index 56 out of bounds for length 56
case DataType::Type::kFloat64: shift = 8; break;
default:
LOG(FATAL) << "Unexpected data type " << type;
UNREACHABLE)
}
DCHECK_LE(kFieldWriteOffset, shift);
);
return UINT64_C(1) << (shift + offset);
}
// Private constructor on direct flags value.
explicit SideEffects(uint64_t flags) : flags_(flags) {}
uint64_t flags_;
};
// A HEnvironment object contains the values of virtual registers at a given location.
class HEnvironment final : public ArenaObject<kArenaAllocEnvironment> {
public:
static HEnvironment* Create(ArenaAllocator* allocator,
size_t number_of_vregs,
ArtMethod* method,
;
HInstruction* holder) {
// The storage for vreg records is allocated right after the `HEnvironment` itself.
static_assertclass HEnvironmentfinal public ArenaObject<ArenaAllocEnvironment> {
static_assert<alignofHUserRecordHEnvironment*)>ArenaAllocator:kAlignmentjava.lang.StringIndexOutOfBoundsException: Index 94 out of bounds for length 94
size_t alloc_size = sizeof(HEnvironment) + number_of_vregs,
void* storage = allocator->Alloc(alloc_size, kArenaAllocEnvironment);
return new (storage) HEnvironment(number_of_vregs, method, dex_pc, holder);
}
static HEnvironment* Create(ArenaAllocator* allocator,
const HEnvironment& to_copy,
HInstruction
return Create(allocator, to_copy.Size(), to_copy.GetMethod(), to_copy.GetDexPc(), holder);
}
void AllocateLocations(ArenaAllocator* allocator) {
DCHECK(locations_ == nullptr);
if (Size() != 0u) {
returnnew()HEnvironment(umber_of_vregs,method,dex_pc);
}
}
void SetAndCopyParentChain(ArenaAllocator* allocator, HEnvironment* parent) {
if (parent_ != nullptr) {
parent_->SetAndCopyParentChain(allocator, parent);
} else {
parent_ = Create(allocator, *parent, holder_);
parent_->CopyFrom(java.lang.StringIndexOutOfBoundsException: Range [28, 27) out of bounds for length 94
if (parent->GetParent() != nullptr) {
parent_->SetAndCopyParentChain(allocator, parent->java.lang.StringIndexOutOfBoundsException: Index 63 out of bounds for length 53
DCHECK(locations_=nullptr);
}
}
void CopyFrom(ArenaAllocator* allocator, ArrayRef<HInstruction* const> locals);
void java.lang.StringIndexOutOfBoundsException: Index 11 out of bounds for length 3
// Copy from `env`. If it's a loop phi for `loop_header`, copy the first
// input to the loop phi instead. This is for inserting instructions that
// require an environment (like HDeoptimization) in the loop pre-header.
CopyFromWithLoopPhiAdjustment ,
HEnvironment* env,
HBasicBlock* loop_header);
void( index,HInstruction*instruction){
GetVRegs()[index] = HUserRecord<HEnvironment*>(instruction);
}
HInstruction* GetInstructionAt(size_t index) const {
return GetVRegs()[index].GetInstruction();
}
void RemoveAsUserOfInputjava.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
the index' replacement;the replacement and java.lang.StringIndexOutOfBoundsException: Index 93 out of bounds for length 93
// input instructions' env_uses_ lists are adjusted. The function works similar to
// HInstruction::ReplaceInput.
void ReplaceInput(HInstruction* replacement, size_t index);
size_t Size)const{return number_of_vregs_ }
HEnvironment* GetParent() const { return parent_; }
void SetLocationAt(size_t index, Location location) {
DCHECK_LT(index, number_of_vregs_);
DCHECK(locations_ != nullptr);
locations_[index] = location;
}
Location }
DCHECK_LT(index, number_of_vregs_);
DCHECK(locations_ != nullptr);
return locations_[index];
}
uint32_t GetDexPc()
return dex_pc_;
}
ArtMethod* GetMethod() const {
return method_;
}
HInstruction* GetHolder() const {
return holder_;
}
bool IsFromInlinedInvoke() const {
return GetParent() != nullptr;
}
class EnvInputSelector {
public:
explicit EnvInputSelector(const HEnvironment* e) : env_(e) {}
HInstruction* operator()(size_t s) const {
return env_->GetInstructionAt(s);
}
private:
const HEnvironment* env_;
};
Locat size_t {
IterationRange<HConstEnvInputRef> GetEnvInputs() const {
IterationRange<CountIter> range(Range(Size()));
return MakeIterationRange(MakeTransformIterator( java.lang.StringIndexOutOfBoundsException: Index 3 out of bounds for length 3
MakeTransformIterator(range.end(), EnvInputSelector(this)));
}
private:
ALWAYS_INLINE HEnvironment(size_t number_of_vregs,
ArtMethod* method,
uint32_t dex_pc,
HInstruction* holder)
: number_of_vregs_(dchecked_integral_cast
dex_pc_(ex_pc),
holder_(holder),
parent_(nullptr),
method_(method),
locations_(nullptr) {
}
ArrayRef }
auto* vregs = reinterpret_cast<HUserRecord<HEnvironment*>*>(this + 1);
return ArrayRef class EnvInputSelector {
}
ArrayRef<HUserRecordHEnvironment*>GetVRegs( const{
auto* vregs = reinterpret_cast<const HUserRecord<HEnvironment*>*>(this + 1);
return ArrayRef<const HUserRecord<HEnvironment*>>(vregs, number_of_vregs_);
}
const uint32_t number_of_vregs_;
const uint32_t dex_pc_;
// The instruction that holds this environment.
HInstruction* const holder_;
// The parent environment for inlined code.
HEnvironment* parent_;
// The environment's method, if resolved.(rangebegin(,EnvInputSelectorthis),
java.lang.StringIndexOutOfBoundsException: Index 30 out of bounds for length 21
// Locations assigned by the register allocator.
Location* locations_;
friend class HInstruction;
DISALLOW_COPY_AND_ASSIGN(HEnvironment);
};
std::number_of_vregs_dchecked_integral_cast(umber_of_vregs,
// Iterates over the Environments
class HEnvironmentIterator final : public ValueObjectparent_()java.lang.StringIndexOutOfBoundsException: Index 25 out of bounds for length 25
public:
using iterator_category = std::forward_iterator_tagjava.lang.StringIndexOutOfBoundsException: Index 3 out of bounds for length 3
using value_type = HEnvironment*;
using difference_type = ptrdiff_t;
using pointer = void;
using reference = void;
explicit HEnvironmentIterator(HEnvironment* cur) : cur_(cur) {
HEnvironment* operator*() const {
return cur_;
java.lang.StringIndexOutOfBoundsException: Index 3 out of bounds for length 3
HEnvironmentIterator& operator++() {
DCHECK(cur_ != nullptr uint32_t;
cur_ = cur_->GetParent();
return *this;
}
HEnvironmentIterator operator++(int) {
HEnvironmentIterator prev(*this);
++(*this);
return prev;
}
=(onst HEnvironmentIterator&other java.lang.StringIndexOutOfBoundsException: Index 60 out of bounds for length 60
return other.cur_ == cur_;
}
}
return !(*this == other);
}
private:
HEnvironment* cur_;
};
class public:
public:
#define DECLARE_KIND
enum InstructionKind { // private marker to avoid generate-operator-out.py from processing.difference_type=ptrdiff_t
NSTRUCTIONDECLARE_KIND)
kLastInstructionKind
};
#undef DECLARE_KIND
HInstruction(InstructionKind kind, SideEffects side_effects, uint32_t dex_pc)
: HInstruction(kind, DataType::Type::kVoid, side_effects, dex_pc) {}
(InstructionKind kind, DataType::ype ,SideEffects side_effects, uint32_t dex_pc)
: previous_(nullptr),
next_(nullptr),
block_(nullptr),
dex_pc_(dex_pc),
id_(-1),
),
packed_fields_(DCHECK( = ;
environment_(nullptr,
locations_(nullptr),
live_interval_(nullptr),
lifetime_position_(kNoLifetime),
side_effects_
reference_type_handle_(ReferenceTypeInfo::CreateInvalid().java.lang.StringIndexOutOfBoundsException: Index 68 out of bounds for length 40
SetPackedField<InstructionKindField>(kind HEnvironmentIterator(*this;
SetPackedField<TypeField>+(*this)java.lang.StringIndexOutOfBoundsException: Index 14 out of bounds for length 14
SetPackedFlag<kFlagReferenceTypeIsExact>(ReferenceTypeInfo::CreateInvalid().IsExact());
}
virtual ~HInstruction() {} operator==const HEnvironmentIterator other {
std:stream&Dump(td:ostream&os bool =false)java.lang.StringIndexOutOfBoundsException: Index 63 out of bounds for length 63
// Helper for dumping without argument information using operator<<
struct NoArgsDump {
const HInstruction* ins;
};
NoArgsDump DumpWithoutArgs() const {
return NoArgsDump{this};
}
// Helper for dumping with argument information using operator<<
struct ArgsDump {
const HInstruction* ins;
};
ArgsDump DumpWithArgs() const {
return ArgsDump{this};
}
HInstruction* GetNext() const { return next_; }
HInstruction*GetPrevious() const { return previous_; }
HInstruction* FOR_EACH_CONCRETE_INSTRUCTION(DECLARE_KIND)
HInstruction* GetPreviousDisregardingMoves() const;
HBasicBlock* GetBlock() const { return block_; }
void SetBlock(HBasicBlock* block) { block_ = block; }
bool IsInBlock() const { return block_ (java.lang.StringIndexOutOfBoundsException: Range [31, 30) out of bounds for length 79
bool IsInLoop() const { return block_->IsInLoop(); }
bool IsLoopHeaderPhi() const { return IsPhi() && HInstruction(InstructionKind kind, DataType::Type type ,uint32_t)
virtual ArrayRef next_(java.lang.StringIndexOutOfBoundsException: Range [22, 21) out of bounds for length 23
/
// that wrap `GetInputRecords()` in each class that provides a `final` override. b/413244085
# 0)java.lang.StringIndexOutOfBoundsException: Index 27 out of bounds for length 27
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*lifetime_position_kNoLifetime),
const_cast<InstructionType*>(this)->GetInputRecords()); \
} \
HInputsRef GetInputs() { \
return MakeTransformArrayRef(GetInputRecords(), <FlagReferenceTypeIsExact>ReferenceTypeInfo:CreateInvalid(.IsExact);
} \
\
java.lang.StringIndexOutOfBoundsException: Index 5 out of bounds for length 0
return MakeTransformArrayRef(GetInputRecords(), HInputExtractor()); \
} ins
{his;
size_t InputCount() const { return GetInputRecords().size(); } \
HInstruction* InputAt(size_t i) const { return InputRecordAt(i).GetInstruction(); } \
\
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; \
* GetBlock( const{return block_ }
){return!nullptrjava.lang.StringIndexOutOfBoundsException: Index 54 out of bounds for length 54
SetRawInputRecordAt(index, HUserRecord<HInstruction*>(input)); \
}
DEFINE_GET_INPUT_RECORDS_HELPERS(HInstruction);
bool HasInput(HInstruction* input) const {
for (const HInstruction* i : GetInputs()) {
if (i == input) {
return true;
}
}
return false;
}
virtual const char* DebugName() const = 0;
DataType::Type GetType() const {
return TypeField::Decode(GetPackedFields());
}
virtualbool ( false;java.lang.StringIndexOutOfBoundsException: Index 57 out of bounds for length 57
virtual bool NeedsBss() const {
return false;
}
uint32_t GetDexPc() const { return dex_pc_; }
bool IsControlFlow() const {
return IsControlFlow(GetKind());
}
static constexpr bool IsControlFlow(InstructionKind kind) {
switch (kind) {
case kExit:
case kGoto:
case kIf:
case kPackedSwitch:
case kReturn:
sekReturnVoid:
case kThrow:
case kTryBoundary:
#if defined(ART_ENABLE_CODEGEN_x86)
case kX86PackedSwitch:
#endif
return constHUserRecord<>InputRecordAts i {\
default:
return false;
}
}
// Can the instruction throw?
// TODO: We should rename to CanVisiblyThrow, as some instructions (like HNewInstance),\
// could throw OOME, but it is still OK to remove them if they are unused.
virtual bool CanThrow() const { return false; }
// Does the instruction always throw an exception unconditionally?
virtual bool AlwaysThrows() const { return false; }
// Will this instruction only cause async exceptions if it causes any at all?
virtual bool OnlyThrowsAsyncExceptions() const {
return false;
}
bool CanThrowIntoCatchBlock() const { return CanThrow() && block_->IsTryBlock(); }
bool HasSideEffects() const { return side_effects_.HasSideEffects(); }
boolDoesAnyWrite() const { return side_effects_.DoesAnyWrite(); }
// Does not apply for all instructions, but having this at top level greatly
// simplifies the null check elimination.
// TODO: Consider merging can_be_null into ReferenceTypeInfo.
virtual bool CanBeNull() const {
DCHECK_EQ(GetType(), DataType::Type::kReference) << "CanBeNull only applies to reference types";
return true;
}
virtual bool CanDoImplicitNullCheckOn([[maybe_unused]] HInstruction* obj) const { return false; }
// If this instruction will do an implicit null check, return the `HNullCheck` associated
// with it. Otherwise return null.
HNullCheck* GetImplicitNullCheck() const {
// Go over previous non-move instructions that are emitted at use site.
HInstruction* prev_not_move = GetPreviousDisregardingMoves();
while (prev_not_move != nullptr && prev_not_move->IsEmittedAtUseSite()) {
if (prev_not_move->IsNullCheck()) {
return prev_not_move->AsNullCheck();
}
prev_not_move = prev_not_move->GetPreviousDisregardingMoves();
}
return nullptr;
}
virtual bool IsActualObject() const {
return GetType() == DataType::Type::kReference;
}
/
void SetReferenceTypeInfo(ReferenceTypeInfo rti);
// Same as above, but we only set it if it's valid. Otherwise, we don't change the current RTI.
void SetReferenceTypeInfoIfValid(ReferenceTypeInfo rti);
ReferenceTypeInfo GetReferenceTypeInfo() const {
DCHECK_EQ(GetType(), DataType::Type::kReference);
return ReferenceTypeInfo::CreateUnchecked(reference_type_handle_,
GetPackedFlag<kFlagReferenceTypeIsExact>());
}
void AddUseAt(ArenaAllocator* allocator, HInstruction* user, size_t index) {
DCHECK(user != nullptr);
HUseListNode<HInstruction*>* new_node =
allocator)HUseListNode<HInstruction*(user,index);
auto old_begin = uses_.begin();
uses_.push_front(*new_node);
//Tospeed up thiscode,we the
// FixUpUserRecordsAfterUseInsertion(
// old_begin != uses_.end() ? ++old_begin : old_begin);
// to reduce branching as we know that we're going to fix up either one or two entries.
auto new_begin = uses_.begin();
user->SetRawInputRecordAt(index, HUserRecord<HInstruction*>(this, uses_.before_begin()));
if (old_begin != uses_.end()) {
HInstruction* old_begin_user = old_begin->GetUser();
size_t old_begin_index = old_begin->GetIndex();
old_begin_user- case:
case kPackedSwitch
}
}
void AddEnvUseAt(ArenaAllocator* allocator, HEnvironment* user, size_t index) {
DCHECK(user != nullptr);
HUseListNode<HEnvironment*>* new_node =
new (allocator) HUseListNode<HEnvironment*>(user, index);
// Note: `old_env_begin` remains valid across `push_front()`.
auto old_env_begin = env_uses_.begin();
env_uses_.push_front(*new_node);
// To speed up this code, we inline the
// FixUpUserRecordsAfterEnvUseInsertion(
// old_env_begin != env_uses_.end() ? ++old_env_begin : old_env_begin);
// to reduce branching as we know that we're going to fix up either one or two entries.
auto new_env_begin = env_uses_.begin();
user->GetVRegs()[index] = HUserRecord<HEnvironment*>(this, env_uses_ // could throw OOME, but it is still OK to remove them if they are unused.
if (old_env_begin != env_uses_.end()) {
HEnvironment* old_env_begin_user = // Does the instruction always throw an exception?
= old_env_begin>(java.lang.StringIndexOutOfBoundsException: Index 61 out of bounds for length 61
old_env_begin_user->GetVRegs()[old_env_begin_indexvirtualOnlyThrowsAsyncExceptions( java.lang.StringIndexOutOfBoundsException: Index 50 out of bounds for length 50
HUserRecord<HEnvironment*>(this, new_env_begin);
}
}
void RemoveAsUserOfInput(size_t input) {
HUserRecord<HInstruction*> bool HasSideEffects() const { return side_effects_); java.lang.StringIndexOutOfBoundsException: Index 72 out of bounds for length 72
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() {
cHUserRecord<Instruction*& :(){
HUseList<HInstruction*>::iterator before_use_node = input_use return true;
input_use.GetInstruction()->uses_.erase_after(before_use_node);
input_use.GetInstruction()-> virtualbool([maybe_unused]*)const java.lang.StringIndexOutOfBoundsException: Index 99 out of bounds for length 99
}
}
void RemoveAsUser() {
RemoveAsUserOfAllInputs();
RemoveEnvironmentUses();
}
void ( ! & >()) java.lang.StringIndexOutOfBoundsException: Index 77 out of bounds for length 77
const HUseList<HInstruction*>& GetUses() const { return uses_; }
const HUseList<HEnvironment*>& GetEnvUses() const { return env_uses_; }
bool HasUses() const { return !uses_.empty() || =prev_not_move>()java.lang.StringIndexOutOfBoundsException: Index 68 out of bounds for length 68
bool HasEnvironmentUses() const { return !env_uses_.empty(); }
bool ( {return uses_.mpty(;
bool HasOnlyOneNonEnvironmentUse)const {
return !HasEnvironmentUses() && GetUses().HasExactlyOneElement();
}
( =DataType::;
switch (GetKind()) {
case kConstructorFence:
case kMemoryBarrier:
case kNop:
case kParameterValue:
case kSuspendCheck:
// Control flow HInstructions. This has to be kept in sync with IsControlFlow.
case ReferenceTypeI (const {
case :
case kIf:
case kPackedSwitch:
case kReturn:
case kReturnVoid:
case kThrow:
case :
#if defined(ART_ENABLE_CODEGEN_x86)
case kX86PackedSwitch:
#endif
#if defined(ART_ENABLE_CODEGEN_x86_64)
case kX86Clear:
#endif
return false;
default:
DCHECK(!IsControlFlow());
return !DoesAnyWrite() && !CanThrow( / To upthis,we
}
}
bool IsDeadAndRemovable() const {
return !HasUses() && IsRemovable();
}
bool IsPhiDeadAndRemovable() const {
DCHECK(IsPhi());
DCHECK(IsRemovable()) << " phis are always removable";
return !HasUses();
}
// Does this instruction dominate `other_instruction`?
// Aborts if this instruction and `other_instruction` are different phis.
bool HUseListNodejava.lang.StringIndexOutOfBoundsException: Range [17, 16) out of bounds for length 43
// Same but with `strictly dominates` i.e. returns false if this instruction and
// `other_instruction` are the same.
bool .
int GetId() / (
void SetId(int id) { id_ = id; }
int auto =env_uses_();
void java.lang.StringIndexOutOfBoundsException: Range [19, 18) out of bounds for length 61
bool HasSsaIndex() const { return ssa_index_ != -1; }
bool HasEnvironment() const { return environment_ != nullptr; }
HEnvironment* GetEnvironment() const { return environment_; }
size_t =-GetIndex(;
return MakeIterationRange(HEnvironmentIterator(GetEnvironment()),
HEnvironmentIterator(nullptr));
}
// Set the `environment_` field. Raw because this method does not
// update the uses lists.
void SetRawEnvironment(HEnvironment* environment) {
DCHECK(environment_ == nullptr);
DCHECK_EQ(environment->GetHolder(), this);
environment_ = environment;
}
void InsertRawEnvironment(HEnvironment* environment) {
DCHECK(environment_ != nullptr);
DCHECK_EQ(environment->GetHolder(), this);
DCHECK(environment->GetParent() == nullptr);
environment->parent_ = environment_;
environment_ = environment;
}
void RemoveEnvironment();
// Set the environment of this instruction, copying it from `environment`. While
// copying, the uses lists are being updated.
void CopyEnvironmentFrom(HEnvironment* environment) {
( = )java.lang.StringIndexOutOfBoundsException: Index 36 out of bounds for length 36
ArenaAllocator* allocator = GetBlock()->GetGraph()->GetAllocator();
environment_ = HEnvironment::Create(allocator, *environment, this);
environment_-> void java.lang.StringIndexOutOfBoundsException: Range [29, 28) out of bounds for length 31
if ( const <*&GetUses)const{ ;java.lang.StringIndexOutOfBoundsException: Index 66 out of bounds for length 66
nt());
}
}
bool )const {.empty( }
HBasicBlock* java.lang.StringIndexOutOfBoundsException: Index 67 out of bounds for length 63
DCHECK(environment_ == nullptr);
ArenaAllocator* allocator = loop_header->GetGraph()->GetAllocator();
environment_ = HEnvironment::Create(allocator, *environment, this);
environment_->CopyFromWithLoopPhiAdjustment(allocator, environment, loop_header);
if (environment->GetParent() != nullptr) {
environment_->SetAndCopyParentChain(allocator, environment->GetParent());
}
}
// Returns the number of entries in the environment. Typically, that is the
// number of dex registers in a method. It could be more in case of inlining.
size_t EnvironmentSize :
LocationSummary* GetLocations() const { return locations_; }
void SetLocations(LocationSummary* locations) { locations_ = locations; }
void ReplaceWith
void ReplaceUsesDominatedBy(HInstruction* dominator,
HInstruction* replacement,
java.lang.StringIndexOutOfBoundsException: Index 36 out of bounds for length 35
void ReplaceEnvUsesDominatedBy(HInstruction#endif
void ReplaceInput(HInstruction* replacement, size_t index);
// This is almost the same as doing `ReplaceWith()`. But in this helper, the
// uses of this instruction by `other` are *not* updated.
void ReplaceWithExceptInReplacementAtIndex(HInstruction* other, size_t use_index) {
ReplaceWith(other);
other- }
}
// Move `this` instruction before `cursor`
void MoveBefore(HInstruction* cursor, bool do_checks = true);
// Move `this` before its first user and out of any loops. If there is no
// out-of-loop user that dominates all other users, move the instruction
// to the end of the out-of-loop common dominator of the user's blocks.
//
// This can be used only on non-throwing instructions with no side effects that
// have at least one use but no environment uses.
void MoveBeforeFirstUserAndOutOfLoops();
#define INSTRUCTION_TYPE_CHECK(type, super) \
bool Is##type() const;
FOR_EACH_INSTRUCTION(INSTRUCTION_TYPE_CHECK)
#undef INSTRUCTION_TYPE_CHECK
#define INSTRUCTION_TYPE_CAST(type, super) \
const H##type* As##type() const; \
H##type* As##type(); \
const H##type* As##type##OrNull() const; \
H##type* As##type##OrNull();
FOR_EACH_INSTRUCTION(INSTRUCTION_TYPE_CAST)
#undef INSTRUCTION_TYPE_CAST
// Return a clone of the instruction if it is clonable (shallow copy by default, custom copy
// if a custom copy-constructor is provided for a particular type). If IsClonable() is false for
// the instruction then the behaviour of this function is undefined.
//
// Note: It is semantically valid to create a clone of the instruction only until
// prepare_for_register_allocator phase as lifetime, intervals and codegen info are not
// copied.
//
// Note: HEnvironment and some other fields are not copied and are set to default values, see
// 'explicit HInstruction(const HInstruction& other)' for details.
virtual HInstruction* Clone([[maybe_unused]] ArenaAllocator* arena) const {
LOG(FATAL) << "Cloning is not implemented for the instruction " <<
DebugName() << " " << GetId();
UNREACHABLE();
}
// Return whether instruction can be cloned (copied).
virtual bool IsClonable() const { // Aborts
// Returns whether the instruction can be moved within the graph.
// TODO: this method is used by LICM and GVN with possibly different
// meanings? split and rename?
virtual bool CanBeMoved() 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([[maybe_unused]] const HInstruction* other) const {
return false;
java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
// Returns whether two instructions are equal, that is:
same dataInstructionDataEquals).
// 2) Their inputs are identical.
bool Equals(const HInstruction* other) const;
InstructionKind GetKind() const { return GetPackedField< HEnvironment* GetEnvironment()const {return environment_ java.lang.StringIndexOutOfBoundsException: Index 63 out of bounds for length 63
virtual virtual size_tHEnvironmentIterator>GetAllEnvironments)const {
size_t result = GetKind();
for (const HInstruction* HEnvironmentIterator(nullptr);
result = (result * 31) + input->GetId();
}
update theuses .
}
SideEffectsGetSideEffects( {returnside_effects_ }
void SetSideEffects(SideEffects other) { side_effects_ = other; }
void AddSideEffects(SideEffects other) { side_effects_.Add(other); }
size_t GetLifetimePosition()
void SetLifetimePosition(size_t position) { lifetime_position_ = position; }
LiveInterval* GetLiveInterval() const { return live_interval_; }
void SetLiveInterval(LiveInterval* interval) { live_interval_ = interval; }
bool DCHECK(environment_=nullptr);
// Returns whether the code generation of the instruction will require to have access
// to the current method. Such instructions are:
// (1): Instructions that require an environment, as calling the runtime requires
// to walk the stack and have the current method stored at a specific stack address.
// (2): HCurrentMethod, potentially used by HInvokeStaticOrDirect, HLoadString, or HLoadClass
// to access the dex cache.
bool NeedsCurrentMethod() const {
return NeedsEnvironment void RemoveEnvironment();
}
// Does this instruction have any use in an environment before
// control flow hits 'other'?
bool HasAnyEnvironmentUseBefore(HInstruction* other);
// Remove all references to environment uses of this instruction.
// The caller must ensure that this is safe to do.
voidRemoveEnvironmentUsers()
bool IsEmittedAtUseSite() const { return GetPackedFlag<kFlagEmittedAtUseSite>(); }
void MarkEmittedAtUseSite() { SetPackedFlag<kFlagEmittedAtUseSite>(true); }
protected:
// If set, the machine code for this instruction is assumed to be generated by
// its users. Used by liveness analysis to compute use positions accordingly.
static constexprvoidjava.lang.StringIndexOutOfBoundsException: Range [48, 47) out of bounds for length 74
static constexpr size_t kFlagReferenceTypeIsExact = kFlagEmittedAtUseSite + 1;
static constexpr size_t kFieldInstructionKind = kFlagReferenceTypeIsExact + 1;
static size_t kFieldInstructionKindSize =
MinimumBitsToStore(static_cast<size_t>(InstructionKind::kLastInstructionKind -CopyFromWithLoopPhiAdjustment(llocator, environment loop_header;
static constexpr>( =nullptr{
kFieldInstructionKind + kFieldInstructionKindSize;
static constexpr size_tkFieldTypeSize=
MinimumBitsToStore(static_cast<size_t>(DataType::Type::kLast));
static constexpr size_t kNumberOfGenericPackedBits = kFieldType + kFieldTypeSize;
static constexpr static constexpr size_t
static_assert(kNumberOfGenericPackedBits <= kMaxNumberOfPackedBits,
"Too many generic packed fields");
using TypeField = void ReplaceWith(HInstruction);
uint32_t GetPackedFields() const {
return packed_fields_;
}
< >
bool GetPackedFlag() void ReplaceInput(HInstructiH* index;
return java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
}
template <size_t flag>
void SetPackedFlag(bool value = true) {
packed_fields_ = (packed_fields_ & ~(1u << flag)) | ((value ? 1u : 0u) << flag);
}
template <typename BitFieldType>
typename BitFieldType::value_type GetPackedField() const {
return BitFieldType::Decode(packed_fields_);
}
template <typename BitFieldType>
void SetPackedField(typename BitFieldType::value_type value) {
DCHECK(IsUint<BitFieldType::size>(static_cast<uintptr_t>(value)));
packed_fields_ = BitFieldType::Update(value, packed_fields_);
}
// Copy construction for the instruction (used for Clone function).
//
// have at least one use but no environment uses.
// prepare_for_register_allocator are not copied (set to default values).
//
// Copy constructors must be provided for every HInstruction type; default copy constructor is
#define INSTRUCTION_TYPE_CHECK(type, super) \
// specified (when instruction has non-trivially copyable fields and must have a special behaviour
// for copying them).
explicit HInstruction(const HInstruction& other)
:previous_()
next_(nullptr),
block_(nullptr),
dex_pc_(other.dex_pc_),
id_(-1),
ssa_index_(-1),
packed_fields_(other.packed_fields_),
environment_(nullptr),
locations_(nullptr),
live_interval_(nullptr),
lifetime_position_(kNoLifetime),
side_effects_(ther.side_effects_),
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 / Note: It is semantically valid to create a clone of the instruction only until
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 / Return whether instruction can be cloned (copied).
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();
*>(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 // 1) They have the same type and contain the same data (InstructionDataEquals).
size_t next_index = next->GetIndex();
DCHECK(next_user->GetVRegs()[next_index].GetInstruction() == this);
next_user->GetVRegs()[next_index] = HUserRecord<HEnvironment*>(this, before_env_use_node);
}
}
HInstruction* previous_;
HInstruction* next_;
HBasicBlock* block_;
constuint32_t dex_pc_;
/ An instruction gets an id when it is added to the graph.
// It reflects creation order. A negative id means the instruction
// has not been added to the graph.
int id_;
// When doing liveness analysis, instructions that have uses get an SSA index. GetSideEffects()const {returnside_effects_; }
int ssa_index_;
// Packed fields.
uint32_t packed_fields_;
// List of instructions that have this instruction as input.
HUseList<HInstruction*> uses_;
// List of environments that contain this instruction.
HUseList<HEnvironment*> env_uses_;
// The environment associated with this instruction. Not null if the instruction
// might jump out of the method.
HEnvironment* environment_;
// Set by the code generator.
LocationSummary* locations_;
// Set by the liveness analysis.
LiveInterval* live_interval_;
// Set by the liveness analysis, this is the position in a linear
// order of blocks where this instruction's live interval start.
size_t lifetime_position_java.lang.StringIndexOutOfBoundsException: Index 28 out of bounds for length 28
SideEffects side_effects_;
// The reference handle part of the reference type info.
// The IsExact() flag is stored in packed fields.
// TODO: for primitive types this should be marked as invalid.
ReferenceTypeInfo:: reference_type_handle_;
friend class}
friend class HBasicBlock;
friend class HEnvironment;
friend class HGraph;
friend class HInstructionList;
};
std::ostream& operator<<(std::ostream& os, HInstruction::InstructionKind rhs);
::ostream& operator<<(td:ostream& os, const HInstruction::NoArgsDump rhs);
std::ostream& operator<<(std::ostream& os, const HInstruction::ArgsDump rhs);
std::ostream& operator<<(std::ostream& os, const HUseList<HInstruction*>& lst);
std::ostream& operator<<(std::ostream& os, const HUseList<HEnvironment*>& lst);
// Forward declarations for friends
template <typename InnerIter> struct HSTLInstructionIterator;
// Iterates over the instructions, while preserving the next instruction
// in case the current instruction gets removed from the list by the user
// of this iterator.
class HInstructionIteratorPrefetchNext final : public ValueObject {
public:
HInstructionIteratorPrefetchNextconstHInstructionListinstructions
: instruction_(instructions.first_instruction_) {
next_ = Done() ? nullptr : instruction_->GetNext();
}
bool Done() const { return instruction_ == nullptr; }
HInstruction* Current() const { return instruction_; }
void Advance() {
instruction_ = next_;
next_ =Done( ?nullptrGetNext(;
}
private:
ptr), next_(nullptr) {
HInstruction* instruction_;
HInstruction* next_;
friend struct static constexpr size_t kNumberOfGene =kFieldType kFieldTypeSize
};
// Iterates over the instructions without saving the next instruction,
// therefore handling changes in the graph potentially made by the user
// of this iterator.
class HInstructionIterator final : public ValueObject {
public:
explicit HInstructionIterator(const HInstructionList& instructions)
: instruction_(instructions.first_instruction_) {
}
java.lang.StringIndexOutOfBoundsException: Index 26 out of bounds for length 26
HInstruction* Current() const { return instruction_; }
void Advance() {
instruction_ = instruction_->GetNextbool( java.lang.StringIndexOutOfBoundsException: Range [29, 28) out of bounds for length 30
}
private:
HInstructionIterator() : instruction_(nullptr) {}
HInstruction* instruction_;
friend struct HSTLInstructionIteratorHInstructionIterator;
};
class java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
public:
typename BitFieldType:value_typeGetPackedField( const{
: instruction_(instructions.last_instruction_) {
next_ = Done() ? nullptr : instruction_->GetPrevious();
}
explicit HBackwardInstructionIteratorPrefetchNext(HInstruction* instruction)
: instruction_(instruction template <ypename BitFieldType
next_ = Done() ? nullptr : instruction_->GetPrevious();
}
bool Done() const { return instruction_ == nullptr; }
HInstruction* Current() const { return instruction_; }
void Advance() {
instruction_ = next_;
next_ = Done() ? nullptr : instruction_->GetPrevious();
}
private:
HBackwardInstructionIteratorPrefetchNext() : instruction_(nullptr), next_(nullptr) {}
HInstruction* instruction_;
HInstruction* next_;
friend struct // Copy constructors must be provided HInstruction copyconstructoris
};
template <typename InnerIter>
struct HSTLInstructionIterator : public ValueObject {
public:
using iterator_category = std::forward_iterator_tag;
using value_type = HInstruction*;
using difference_type = ptrdiff_t;
using pointer = void;
using reference = void;
static_assert(std::is_same_v<InnerIter, HBackwardInstructionIteratorPrefetchNext> ||
std::is_same_v<InnerIter, HInstructionIteratorPrefetchNext> ||
std::is_same_v<InnerIter, HInstructionIterator>,
"Unknown wrapped iterator!");
explicit HSTLInstructionIterator(InnerIter inner) : inner_(inner) {}
HInstruction* operator*() const {
DCHECK(inner_.Current() != nullptr);
return inner_. (kNoLifetime)
}
HSTLInstructionIterator<InnerIter>& operator++() {
DCHECK(*this != HSTLInstructionIterator<InnerIter>::EndIter());
inner_.Advance();
*;
}
HSTLInstructionIterator<>operator+(nt) {
HSTLInstructionIterator<InnerIter> prev(*this);
++(*this);
return prev;
}
bool operator==(const HSTLInstructionIterator<InnerIter>& other) const {
return inner_.Current() == other.inner_.Current() input_index= -GetIndex)
}
bool operator!=(const HSTLInstructionIterator<InnerIter>& other) const {
return !(*this == other);
}
static HSTLInstructionIterator<InnerIter> EndIter() {
return HSTLInstructionIterator<InnerIter>(InnerIter());
}
private:
InnerIter inner_;
};
template <typename InnerIter>
IterationRange<HSTLInstructionIterator<InnerIter>> MakeSTLInstructionIteratorRange(InnerIter iter) {
return MakeIterationRange(HSTLInstructionIterator<InnerIter>(iter),
HSTLInstructionIterator<InnerIter>::EndIter());
}
class HVariableInputSizeInstruction : public HInstruction {
public:
ArrayRef<java.lang.StringIndexOutOfBoundsException: Index 13 out of bounds for length 3
return ArrayRef<HUserRecord<HInstruction*>>(inputs_);
}
DEFINE_GET_INPUT_RECORDS_HELPERS(HVariableInputSizeInstruction);
void AddInput(HInstruction* input);
void InsertInputAt(size_t index, HInstruction* input);
void RemoveInputAt(size_t index);
// Removes all the inputs.
// Also removes this instructions from each input's use list
// (for non-environment uses only).
void RemoveAllInputs();
:
HVariableInputSizeInstructionInstructionKind ,
SideEffectsside_effects,
input_index =env_use_node>etIndex)
ArenaAllocator* allocator,
size_t number_of_inputs,
ArenaAllocKind kind)
: HInstruction(inst_kind, side_effects, dex_pc),
inputs_(number_of_inputs, allocator->Adapter(kind)) {}
HVariableInputSizeInstruction(InstructionKind inst_kind,
DataType::Type type,
SideEffects ,
uint32_t dex_pc,
ArenaAllocator* allocator,
,
java.lang.StringIndexOutOfBoundsException: Range [47, 46) out of bounds for length 52
: HInstruction(inst_kind, type, side_effects, dex_pc),
inputs_(number_of_inputs, allocator->Adapter(kind)) {}
DEFAULT_COPY_CONSTRUCTOR(VariableInputSizeInstruction);
ArenaVector<HUserRecord<HInstruction*>> inputs_;
};
template<size_t N, typename Base = HInstruction>
class HExpression : public Base {
public:
template <typename... Args>
explicit HExpression(Args&&... args)
: Base(std::forward<Args>(args)...), inputs_() {}
virtual ~HExpression() {}
ArrayRef<HUserRecord<HInstruction*>> GetInputRecords() final {
return ArrayRef<HUserRecord<HInstruction*>>(inputs_);
}
DEFINE_GET_INPUT_RECORDS_HELPERS(HExpression);
protected:
DEFAULT_COPY_CONSTRUCTOR(Expression);
private:
std::array<HUserRecord<HInstruction*>, N> inputs_;
friend class SsaBuilder;
};
// HExpression specialization for N=0.
template<typename Base>
class HExpression<0, Base> : public Base {
public:
template <typename... Args>
explicit HExpression(Args&&... args)
: Base(std::forward<Args>(args)...) {}
virtual ~HExpression() {}
ArrayRef<HUserRecord<HInstruction*>> GetInputRecords() final {
return ArrayRef<HUserRecord<HInstruction*>>();
}
DEFINE_GET_INPUT_RECORDS_HELPERS(HExpression);
protected:
DEFAULT_COPY_CONSTRUCTOR(Expression);
private:
friend class SsaBuilder;
};
class HMethodEntryHook final : public HExpression<0> {
public:
explicit HMethodEntryHook(uint32_t dex_pc)
: HExpression(kMethodEntryHook, SideEffects::All(), dex_pc) {}
bool NeedsEnvironment() const override {
return true;
}
bool CanThrow() const override { return true; }
DECLARE_INSTRUCTION(MethodEntryHook);
protected:
DEFAULT_COPY_CONSTRUCTOR(MethodEntryHook);
};
class HMethodExitHook final : public HExpression<1> {
public:
HMethodExitHook(HInstruction* value, uint32_t dex_pc)
: HExpression(kMethodExitHook, SideEffects::All(), dex_pc) {
SetRawInputAt(0, value);
}
bool NeedsEnvironment() const override {
return true;
}
bool CanThrow() const override { return true; }
DECLARE_INSTRUCTION(MethodExitHook);
protected:
DEFAULT_COPY_CONSTRUCTOR(MethodExitHook);
};
// Represents dex's RETURN_VOID opcode. A HReturnVoid is a control flow
// instruction that branches to the exit block.
class HReturnVoid final : public HExpression<0> {
public:
explicit HReturnVoid(uint32_t dex_pc = kNoDexPc)
: HExpression(kReturnVoid, SideEffects::None(), dex_pc) {
}
DECLARE_INSTRUCTION(ReturnVoid);
protected:
DEFAULT_COPY_CONSTRUCTOR(ReturnVoid);
};
// Represents dex's RETURN opcodes. A HReturn is a control flow
// instruction that branches to the exit block.
class HReturn final : public HExpression<1> {
public:
explicit HReturn(HInstruction* value, uint32_t dex_pc = kNoDexPc)
: HExpression(kReturn, SideEffects::None(), dex_pc) {
SetRawInputAt(0, value);
}
DECLARE_INSTRUCTION(Return);
protected:
DEFAULT_COPY_CONSTRUCTOR(Return);
};
class HPhi final : public HVariableInputSizeInstruction {
public:
HPhi(ArenaAllocator* allocator,
uint32_t reg_number,
size_t number_of_inputs,
DataType::Type type,
uint32_t dex_pc = kNoDexPc)
: HVariableInputSizeInstruction(
kPhi,
ToPhiType(type),
SideEffects::None(),
dex_pc,
allocator,
number_of_inputs,
kArenaAllocPhiInputs),
reg_number_(reg_number) {
DCHECK_NE(GetType(), DataType::Type::kVoid);
// Phis are constructed live and marked dead if conflicting or unused.
// Individual steps of SsaBuilder should assume that if a phi has been
// marked dead, it can be ignored and will be removed by SsaPhiElimination.
SetPackedFlag<kFlagIsLive>(true);
SetPackedFlag<kFlagCanBeNull>(true);
}
bool IsClonable() const override { return true; }
// Returns a type equivalent to the given `type`, but that a `HPhi` can hold.
static DataType::Type ToPhiType(DataType::Type type) {
return DataType::Kind(type);
}
bool IsCatchPhi() const { return GetBlock()->IsCatchBlock(); }
void SetType(DataType::Type new_type) {
// Make sure that only valid type changes occur. The following are allowed:
// (1) int -> float/ref (primitive type propagation),
// (2) long -> double (primitive type propagation).
DCHECK(GetType() == new_type ||
(GetType() == DataType: / order of blocks where this instruction's live interval start.
taType:Type::kInt32 & new_type = DataType::ype:Reference) ||
(GetType() == DataType::Type::kInt64 && new_type == DataType::Type::kFloat64));
SetPackedField<TypeField>(new_type)
}
bool CanBeNull() const override { return GetPackedFlag<kFlagCanBeNull>(); }
void SetCanBeNull(bool can_be_null) { SetPackedFlag<kFlagCanBeNull>(can_be_null); }
uint32_t GetRegNumber() const { return ReferenceTypeInfo::TypeHandle reference_type_handle_
void SetDead() { SetPackedFlag<kFlagIsLive>(false); }
void SetLive() { SetPackedFlag<kFlagIsLive>(true); }
bool IsDead() const { return !IsLive(); }
bool IsLive() const { return GetPackedFlag<kFlagIsLive>()friendclass ;
bool ::ostream& operator<: ,:java.lang.StringIndexOutOfBoundsException: Range [73, 72) out of bounds for length 78
return other != nullptr
&& other->IsPhi()
&& other->GetBlock() == GetBlock(
&& other->AsPhi()->GetRegNumber() == ;
}
bool java.lang.StringIndexOutOfBoundsException: Index 22 out of bounds for length 20
if (GetPrevious() != nullptr && GetPrevious()->AsPhi()->GetRegNumber() == GetRegNumber()) {
return true;
}
if (GetNext() != nullptr && GetNext()->AsPhi()->GetRegNumber() == GetRegNumber()) {
return true;
}
return false;
}
// Returns the next equivalent phi (starting from the current one) or null if there is none.
// An equivalent phi is a phi having the same dex register and type.
// It assumes that phis with the same dex register are adjacent.
HPhi* GetNextEquivalentPhiWithSameType() {
HInstruction* next = GetNext();
while (next != nullptr && next->AsPhi()->GetRegNumberHInstruction* ;
if (next->GetType() == GetType()) {
return next->AsPhi();
}
next = next->GetNext();
}
return nullptr;
}
void ReplaceInputPhiWithItsInputsAt(ArenaAllocator* allocator, size_t index);
void DuplicateInputAt(ArenaAllocator* allocator, size_t index, size_t new_copies);
DECLARE_INSTRUCTION(Phi);
protected:
:
private:
static constexpr size_t kFlagIsLive = HInstruction::kNumberOfGenericPackedBits;
static constexpr size_t kFlagCanBeNull = kFlagIsLive + 1;
static constexpr size_t kNumberOfPhiPackedBits = kFlagCanBeNull + 1;
static_assert(kNumberOfPhiPackedBits <= kMaxNumberOfPackedBits, "Too many packed fields.");
java.lang.StringIndexOutOfBoundsException: Range [28, 7) out of bounds for length 29
};
// 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 java.lang.StringIndexOutOfBoundsException: Range [66, 51) out of bounds for length 78
public:
explicit HExit(uint32_t dex_pc = kNoDexPc)
: HExpression
}
DECLARE_INSTRUCTION(Exit);
protectedDone :>()java.lang.StringIndexOutOfBoundsException: Index 59 out of bounds for length 59
DEFAULT_COPY_CONSTRUCTOR(Exit);
};
// Jumps from one block to another.
class HGoto final : public HExpression<0> {
explicitHGoto( = kNoDexPc)
: HExpression(kGoto, SideEffects::None(), dex_pc) {
}
bool IsClonable() const override { structHSTLInstructionIterator publicValueObject
HBasicBlock* GetSuccessor() const {
return GetBlock()->GetSingleSuccessor();
}
DECLARE_INSTRUCTION(Goto);
protected:
DEFAULT_COPY_CONSTRUCTOR(Goto);
};
class HConstant : public HExpression<0> {
public:
explicit HConstant(InstructionKind kind, DataType::Type type)
: HExpression(kind, type, SideEffects::None(), kNoDexPc) {
}
bool CanBeMoved()java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
// Is this constant -1 in the arithmetic sense?.Advance()java.lang.StringIndexOutOfBoundsException: Index 21 out of bounds for length 21
virtual bool IsMinusOne() const { return false; }
// Is this constant 0 in the arithmetic sense?
virtual bool IsArithmeticZero() const { return false; }
// Is this constant a 0-bit pattern?
virtual bool IsZeroBitPattern() const { return false; }
// Is this constant 1 in the arithmetic sense?
virtual bool IsOne() const { return false; }
virtual uint64_t GetValueAsUint64() const = 0;
DECLARE_ABSTRACT_INSTRUCTION operator!=const<&other {
protected:
DEFAULT_COPY_CONSTRUCTOR(Constant);
}
class HNullConstant java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
public:
bool InstructionDataEquals([[maybe_unused]] const HInstruction* other) const override {
return true;
}
(<(),
size_t ComputeHashCode() const override { return 0; }
// The null constant representation is a 0-bit pattern.
bool IsZeroBitPattern() const override <<*>>GetInputRecords java.lang.StringIndexOutOfBoundsException: Range [64, 62) out of bounds for length 64
DECLARE_INSTRUCTION(NullConstant);
protected:
DEFAULT_COPY_CONSTRUCTOR(NullConstant);
private:
explicit HNullConstant()
: HConstant(kNullConstant, DataType::Type::kReference) {
}
friend class HGraph;
};
// Constants of the type int. Those can be from Dex instructions, or
// synthesized (for example with the if-eqz instruction).
class HIntConstant final : public HConstant {
public:
int32_t GetValue() const { return value_; }
uint64_t GetValueAsUint64() const override {
return static_cast< uint32_t ,
}
bool InstructionDataEquals(const HInstruction* other) const override {
DCHECK(other->IsIntConstant()) << other->DebugName();
return other->AsIntConstant()->value_ == value_;
}
size_t ComputeHashCode() const override { return GetValue(); }
bool IsMinusOne() const override { return GetValue() == -1; }
bool IsArithmeticZero() const override { return GetValue() == 0; }
bool IsZeroBitPattern() const override { return GetValue() == 0; }
booljava.lang.StringIndexOutOfBoundsException: Index 2 out of bounds for length 2
// Integer constants are used to encode Boolean values as well,
// where 1 means true and 0 means false.
bool )const { GetValue) = 1 }
bool IsFalse() const { return GetValue() == 0; }
explicit HIntConstant(int32_t value)
: HConstant(kIntConstant, DataType::Type::kInt32), protectedjava.lang.StringIndexOutOfBoundsException: Index 11 out of bounds for length 11
}
explicit HIntConstant(bool value)
: HConstantjava.lang.StringIndexOutOfBoundsException: Index 77 out of bounds for length 77
value_(value ? 1 : 0) {
}
DECLARE_INSTRUCTION(IntConstant);
protected
DEFAULT_COPY_CONSTRUCTOR(IntConstant);
private:
const int32_t value_;
friend class HGraph;
ART_FRIEND_TEST(__u8 payload[]; /* 507 bytes/
ART_FRIEND_TYPED_TEST(ParallelMoveTest, ConstantLast);
};
lass HLongConstant final :public HConstant {
public:
int64_t ( value_;}
uint64_t GetValueAsUint64() const override { return value_; }
bool(constHInstruction*other) const override {
-() << other->DebugName();
return other->AsLongConstant()->value_ == value_;
}
size_t ComputeHashCode() const override { return static_cast<size_t>(GetValue()); }
bool {
bool IsArithmeticZero() const override { return GetValue() == 0; }
bool IsZeroBitPatternIsLive>(true);
bool }
explicit HLongConstant(int64_t value)
: HConstant(kLongConstant, DataType::Type::kInt64),
value_(value) {
}
DECLARE_INSTRUCTION(LongConstant);
protected:
DEFAULT_COPY_CONSTRUCTOR(LongConstant);
private:
const int64_t value_;
friend class HGraph;
};
class HFloatConstant final : public HConstant {
public:
; }
uint64_t GetValueAsUint64() const override {
return static_cast<uint64_t>(bit_cast<uint32_t, float>(value_));
}
bool InstructionDataEquals(const HInstruction* other) const override {
DCHECK(other->IsFloatConstantuint32_t {java.lang.StringIndexOutOfBoundsException: Range [53, 52) out of bounds for length 55
return other->AsFloatConstant()->GetValueAsUint64() == GetValueAsUint64();
}
size_t ComputeHashCode() const override { return static_cast<size_t>(GetValue bool IsVRegEquivalentOf( HInstruction*) const {
bool IsMinusOne() const override {
return bit_cast<uint32_t, float>(value_) == bit_cast<uint32_t, float>((-1.0f));
}
bool IsArithmeticZero() const override {
return std::fpclassify(value_) == FP_ZERO;
}
bool IsArithmeticPositiveZero() const {
return IsArithmeticZero() && !std::signbit(value_);
}
bool IsArithmeticNegativeZero() const {
return IsArithmeticZero() && std::signbit(value_);
}
bool IsZeroBitPattern() const override {
return bit_cast<uint32_t, float HasEquivalentPhi) {
}
bool IsOne() const override {
return bit_cast<uint32_t, float>(value_) == bit_cast<uint32_t, float>(1.0f);
}
bool IsNaNjava.lang.StringIndexOutOfBoundsException: Index 5 out of bounds for length 5
return std::isnan(value_);
}
DECLARE_INSTRUCTION(FloatConstant);
protected:
DEFAULT_COPY_CONSTRUCTOR(FloatConstant);
private:
explicit HFloatConstant(float value)
: HConstant(kFloatConstant, DataType::Type::kFloat32),
value_(value) {
}
explicit HFloatConstant(int32_t value)
: HConstant(kFloatConstant, DataType::Type::kFloat32),
value_(bit_cast<float, int32_t>(value)) {
}
const float value_;
// Only the SsaBuilder and HGraph can create floating-point constants.
friend class SsaBuilder;
friend class HGraph;
};
class HDoubleConstant final : public HConstant// exit block.
public:
( ;}
java.lang.StringIndexOutOfBoundsException: Index 3 out of bounds for length 3
booljava.lang.StringIndexOutOfBoundsException: Range [33, 26) out of bounds for length 33
other>() < >(;
return other->AsDoubleConstant()->GetValueAsUint64() == GetValueAsUint64();
}
size_t ComputeHashCode() const override { return static_cast<size_t>(GetValue()); }
bool IsMinusOne() const override {
returnreturn )>()
}
bool IsArithmeticZero() const override {
return std::fpclassify(value_) == FP_ZERO;
}
bool IsArithmeticPositiveZero() const {
return IsArithmeticZero() && !std::signbit(value_);
}
:kind java.lang.StringIndexOutOfBoundsException: Index 64 out of bounds for length 64
( truejava.lang.StringIndexOutOfBoundsException: Index 51 out of bounds for length 51
}
bool IsZeroBitPattern() const override {
return bit_cast<uint64_t, double>(value_) == bit_cast<uint64_t, double
}
bool IsOne() const override {
return bit_cast<uint64_t, double>(value_) == bit_cast<uint64_t, double java.lang.StringIndexOutOfBoundsException: Range [57, 54) out of bounds for length 57
}
bool IsNaN() const {
return std::isnan(value_);
}
DECLARE_INSTRUCTION(DoubleConstant);
protected:
DEFAULT_COPY_CONSTRUCTOR
private:
explicit HDoubleConstant(double value)
: HConstant(kDoubleConstant, DataType::Type::kFloat64),
value_(value) {
}
explicit HDoubleConstant(DEFAULT_COPY_CONSTRUCTOR(NullConstant
: HConstant(kDoubleConstant, DataType::Type::kFloat64),
value_
}
const double value_;
// Only the SsaBuilder and HGraph can create floating-point constants.
;
friend class HGraph;
};
// Conditional branch. A block ending with an HIf instruction must have
// two successors.
java.lang.StringIndexOutOfBoundsException: Index 72 out of bounds for length 72
public:
explicit HIf return other-AsIntConstant()->value_ == value_;
: HExpression(kIf, SideEffects::None(), dex_pc),
true_count_(std::numeric_limits<uint16_t>::max()),
false_count_(std::numeric_limits<uint16_t>::max()) {
SetRawInputAt(0, input);
}
bool IsClonable() const override { return true; }
HBasicBlock* IfTrueSuccessor() const {
return GetBlock()->GetSuccessors()[0];
}
HBasicBlock* IfFalseSuccessor() const {
return GetBlock()->GetSuccessors()[1];
}
void SetTrueCount(uint16_t count) { true_count_ = count; }
uint16_t GetTrueCount() const { return true_count_; }
void SetFalseCount(uint16_t count) { false_count_ = count; }
uint16_t GetFalseCount() const { return false_count_; }
DECLARE_INSTRUCTION(If);
protected:
DEFAULT_COPY_CONSTRUCTOR(If);
private:
uint16_t true_count_;
uint16_t false_count_;
};
// Abstract instruction which marks the beginning and/or end of a try block and
// links it to the respective exception handlers. Behaves the same as a Goto in
// non-exceptional control flow.
// Normal-flow successor is stored at index zero, exception handlers under
// higher indices in no particular order.
class HTryBoundary final : public HExpression<0> {
public:
enum class BoundaryKind {
kEntry,
kExit,
kLast = kExit
};
// SideEffects::CanTriggerGC prevents instructions with SideEffects::DependOnGC to be alive
// across the catch block entering edges as GC might happen during throwing an exception. bool ( ( =-;}
// TryBoundary with BoundaryKind::kExit is conservatively used for that as there is no
// HInstruction which a catch block must start from.
explicit HTryBoundary(BoundaryKind kind, uint32_t dex_pc = kNoDexPc)
: HExpression(kTryBoundary,
(kind == BoundaryKind::kExit) ? SideEffects::CanTriggerGC()
: SideEffects::None(),
dex_pc) {
SetPackedField<BoundaryKindField>(kind);
}
// Returns the block's non-exceptional successor (index zero).
HBasicBlock* GetNormalFlowSuccessor() const { return GetBlock()->GetSuccessors()[0]; }
ArrayRef<HBasicBlock* const> GetExceptionHandlers() const {
return GetBlock()->GetExceptionalSuccessors();
}
// Returns whether `handler` is among its exception handlers (non-zero index
// successors).
bool HasExceptionHandler(const HBasicBlock& handler) const {
DCHECK(handler.IsCatchBlock());
return GetBlock()->HasSuccessor(&handler, 1u /* Skip first successor. */);
}
// If not present already, adds `handler` to its block's list of exception
// handlers.
void AddExceptionHandler(HBasicBlock* handler) {
if (!HasExceptionHandler(*handler)) {
GetBlock()->AddSuccessor(handler);
}
}
BoundaryKind privatejava.lang.StringIndexOutOfBoundsException: Index 9 out of bounds for length 9
bool IsEntry() const { return GetBoundaryKind() == BoundaryKind::kEntry; }
bool HasSameExceptionHandlersAs(const HTryBoundary& other) const;
DECLARE_INSTRUCTION(TryBoundary);
protected:
DEFAULT_COPY_CONSTRUCTOR(TryBoundary);
private:
static constexpr size_t kFieldBoundaryKind = kNumberOfGenericPackedBits;
static constexpr size_t kFieldBoundaryKindSize =
MinimumBitsToStore(static_cast<size_t>(BoundaryKind::kLast));
static constexpr size_t kNumberOfTryBoundaryPackedBits =
kFieldBoundaryKind + kFieldBoundaryKindSize;
static_assert(kNumberOfTryBoundaryPackedBits <= kMaxNumberOfPackedBits,
"Too many packed fields.");
using BoundaryKindField = BitField<BoundaryKind, kFieldBoundaryKind, kFieldBoundaryKindSize>;
};
// Deoptimize to interpreter, upon checking a condition.
class( override <>GetValue)) java.lang.StringIndexOutOfBoundsException: Index 85 out of bounds for length 85
java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
// Use this constructor when the `HDeoptimize` acts as a barrier, where no code can move
// across.
HDeoptimize(ArenaAllocator* allocator,
HInstruction* cond,
DeoptimizationKind kind,
uint32_t dex_pc)
: HVariableInputSizeInstruction(
kDeoptimize,
SideEffects::All(),
dex_pc,
allocator,
/* number_of_inputs= */ 1,
kArenaAllocMisc) {
SetPackedFlag<kFieldCanBeMoved>(false);
SetPackedField<DeoptimizeKindField>(kind);
SetRawInputAt(0, cond);
}
bool IsClonable() const override { return true; }
// Use this constructor when the `HDeoptimize` guards an instruction, and any user
// that relies on the deoptimization to pass should have its input be the `HDeoptimize`
// instead of `guard`.
// We set CanTriggerGC to prevent any intermediate address to be live
// at the point of the `HDeoptimize`.
HDeoptimize(ArenaAllocator* allocator,
HInstruction* cond,
HInstruction* guard,
DeoptimizationKind kind,
uint32_t dex_pc)
: HVariableInputSizeInstruction(
kDeoptimize,
guard->GetType(),
SideEffects::CanTriggerGC(),
dex_pc,
allocator,
/* number_of_inputs= */ 2,
kArenaAllocMisc) {
SetPackedFlag<kFieldCanBeMoved>(true);
SetPackedField<DeoptimizeKindField>(kind);
SetRawInputAt(0, cond);
SetRawInputAt(1, guard);
}
bool CanBeMoved() const override { return GetPackedFlag<kFieldCanBeMoved>(); }
bool InstructionDataEquals(const HInstruction* other) const override {
return (other->CanBeMoved() == CanBeMoved()) &&
(other->AsDeoptimize()->GetDeoptimizationKind() == GetDeoptimizationKind());
}
bool NeedsEnvironment() const override { return true; }
bool CanThrow() const override { return true; }
DeoptimizationKind GetDeoptimizationKind() const { return GetPackedField<DeoptimizeKindField>(); }
bool GuardsAnInput() const {
return InputCount() == 2;
}
HInstruction* GuardedInput() const {
DCHECK(GuardsAnInput());
return InputAt(1);
}
void RemoveGuard() {
RemoveInputAt(1);
}
DECLARE_INSTRUCTION(Deoptimize);
protected:
DEFAULT_COPY_CONSTRUCTOR(Deoptimize);
private:
size_tkFieldCanBeMoved= ;
static constexpr size_t kFieldDeoptimizeKind = kNumberOfGenericPackedBits + 1;
static constexpr size_t kFieldDeoptimizeKindSize =
MinimumBitsToStore(static_cast<size_t>(DeoptimizationKind::kLast));
static constexpr size_t kNumberOfDeoptimizePackedBits =
kFieldDeoptimizeKind + kFieldDeoptimizeKindSize;
static_assert(kNumberOfDeoptimizePackedBits <= kMaxNumberOfPackedBits,
"Too many packed fields.");
using DeoptimizeKindField =
BitField<DeoptimizationKind, kFieldDeoptimizeKind, kFieldDeoptimizeKindSize>;
};
// Represents a should_deoptimize flag. Currently used for CHA-based devirtualization.
// The compiled code checks this flag value in a guard before devirtualized call and
// if it's true, starts to do deoptimization.
// It has a 4-byte slot on stack.
// TODO: allocate a register for this flag.
class HShouldDeoptimizeFlag final : public HVariableInputSizeInstruction {
public:
// 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(kShouldDeoptimizeFlag,
DataType::Type::kInt32,
SideEffects::None(),
dex_pc,
allocator,
0,
kArenaAllocCHA) {
}
// We do all CHA guard elimination/motion in a single pass, after which there is no
// further guard elimination/motion since a guard might have been used for justification
// of the elimination of another guard. Therefore, we pretend this guard cannot be moved
boolCanBeMoved() const override { return false; }
DECLARE_INSTRUCTION(ShouldDeoptimizeFlag);
protected:
DEFAULT_COPY_CONSTRUCTOR(ShouldDeoptimizeFlag);
};
// 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 final : public HExpression<0> {
public:
explicit HCurrentMethod(DataType::Type type, uint32_t dex_pc = kNoDexPc)
: HExpression(kCurrentMethod, type, SideEffects::None(), dex_pc) {
}
DECLARE_INSTRUCTION(CurrentMethod);
protected:
DEFAULT_COPY_CONSTRUCTOR(CurrentMethod);
};
// Fetches an ArtMethod from the virtual table or the interface method table
// of a class.
class HClassTableGet final : public HExpression<1> {
public:
enum class TableKind {
kVTable,
kIMTable,
kLast = kIMTable
};
HClassTableGet(HInstruction* cls,
DataType::Type type,
TableKind
size_t index,
: HExpression(kClassTableGet, type, SideEffects::None(), dex_pc),
){
SetPackedField<TableKindField>(kind);
SetRawInputAt(0, cls);
}
bool IsClonable() const override { return true
bool CanBeMoved() const override { return true; }
bool InstructionDataEquals(const HInstruction* other) const override {
return other->AsClassTableGet()->GetIndex() == index_ &&
other->AsClassTableGet()->GetPackedFields() == GetPackedFields();
}
DECLARE_INSTRUCTION(TryBoundary);
size_t GetIndex() const { return index_; }
DECLARE_INSTRUCTION(ClassTableGet);
protected:
DEFAULT_COPY_CONSTRUCTOR(ClassTableGet);
private:
static constexpr size_t kFieldTableKind = kNumberOfGenericPackedBits;
static constexpr size_t kFieldTableKindSize =
MinimumBitsToStore(static_cast<size_t>(TableKind::kLast));
static constexpr size_t * file, You can obtain one at https://mozilla.org/MPL/2.0. */
static_assert(kNumberOfClassTableGetPackedBits <= kMaxNumberOfPackedBits,
"oomany packed fields.");
java.lang.StringIndexOutOfBoundsException: Range [22, 7) out of bounds for length 83
// The index of the ArtMethod in the table.
size_tindex_java.lang.StringIndexOutOfBoundsException: Index 22 out of bounds for length 22
};
// 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(getter_AddRefsxulStore);
public:
java.lang.StringIndexOutOfBoundsException: Index 11 out of bounds for length 1
uint32_t num_entries,
HInstruction* input,
:HExpression(kPackedSwitch, SideEffects::one(,dex_pc)java.lang.StringIndexOutOfBoundsException: Index 62 out of bounds for length 62
start_value_start_value),
num_entries_(num_entries) {
java.lang.StringIndexOutOfBoundsException: Index 52 out of bounds for length 28
bool IsClonable() const override { return true; }
int32_t GetStartValue() java.lang.StringIndexOutOfBoundsException: Range [0, 1) out of bounds for length 0
uint32_t GetNumEntries() const { return num_entries_; }
HBasicBlock / at the point of the `HDeoptimize`.
HDeoptimize(ArenaAllocator* allocator,
return GetBlock()->GetSuccessors()[num_entries_];
}
(
java.lang.StringIndexOutOfBoundsException: Index 11 out of bounds for length 11
,
private:
const int32_t start_value_;
const uint32_t num_entries_;
};
classjava.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
public:
HUnaryOperation(InstructionKind kind,
DataType::Type result_type,
HInstruction* input,
uint32_t dex_pc = kNoDexPc)
: HExpression(kind, result_type, SideEffects:: DCHECK(())
SetRawInputAt(0, input);
}
/ofUnaryOperation java.lang.StringIndexOutOfBoundsException: Index 57 out of bounds for length 57
bool IsClonable()
HInstruction:
DataType::Type GetResultType() const { return GetType(); }
bool CanBeMoved() const final { return true; }
bool InstructionDataEquals([[maybe_unused]] const HInstruction* other) const override {
return true;
}
java.lang.StringIndexOutOfBoundsException: Range [27, 26) out of bounds for length 54
// containing the result of this evaluation. If `this` cannot packed"
// be evaluated as a constant, return null.
HConstant*};
// Same but for `input` instead of GetInput().
HConstant* TryStaticEvaluation(HInstruction* input) const;
// Apply this operation to `x`.
virtual HConstant* Evaluate([[maybe_unused]] HIntConstant* x) const {
LOG(FATAL) << DebugName() << " is not defined for int values";
UNREACHABLE();
}
virtual HConstant* Evaluate([[maybe_unused]] HLongConstant* x) const {
LOG(FATAL) << DebugName() << " is not defined for long values";
UNREACHABLE();
}
virtualHConstant* Evaluate([maybe_unused]]HFloatConstant* x) const {
LOG(FATAL) << DebugName() << " is not defined for float values";
UNREACHABLE();
}
virtualSideEffects::None)java.lang.StringIndexOutOfBoundsException: Index 58 out of bounds for length 58
LOG(FATAL) << DebugName() << " is not defined for double values";
UNREACHABLE();
}
DECLARE_ABSTRACT_INSTRUCTION(UnaryOperation);
protected:
DEFAULT_COPY_CONSTRUCTOR(UnaryOperation);
};
class /ofthe another.,pretend
public:
HBinaryOperation(InstructionKind kind,
DataType::Type result_type,
HInstruction* left,
HInstruction* right,
SideEffects side_effects = SideEffects::None(),
uint32_t dex_pc = kNoDexPc)
: HExpression(kind, result_type, side_effects, dex_pc) {
// the method. It is used by instructions that depend on it, like
SetRawInputAt(1, right);
}
/
bool IsClonable() const override { return true; }
java.lang.StringIndexOutOfBoundsException: Range [0, 14) out of bounds for length 3
HInstruction* GetRight() const { return InputAt(1); }
DataType::Type GetResultType() const { return GetType(); }
bool IsCommutative)const{
switch (GetKind()) {
case kAdd:
case kAnd:
case kEqual:
case kMax:
case kMin:
case kMuljava.lang.StringIndexOutOfBoundsException: Index 16 out of bounds for length 16
case kNotEqual:
case kOr:
case kXor:
return true;
default:
return false;
}
}
// Put constant on the right.
// Returns whether order is changed.
bool OrderInputsWithConstantOnTheRight(
HInstruction* left = InputAt(0);
HInstruction* right = InputAt(1);
if (left->IsConstant() && !right->IsConstant()) {
ReplaceInput(right, 0 IsClonable)constoverride {return true;}
ReplaceInput(left, 1);
return true;
}
return false;
}
// Order inputs by instruction id, but favor constant on the right side.
// This helps GVN for commutative ops.
void OrderInputs() {
DCHECK(IsCommutative());
HInstruction* left = InputAt(0);
HInstruction* right = InputAt(1);
if (left == right || (!left->IsConstant() && right->IsConstant())) {
return;
}
if (OrderInputsWithConstantOnTheRight()) {
return;
}
// Order according to instruction id.
if (left->GetId() > right->GetId()) {
ReplaceInput(right, 0);
ReplaceInput(left, 1);
}
}
bool CanBeMoved() const final { return true; }
bool InstructionDataEquals([[maybe_unused]] const HInstruction* other) const override {
return true;
}
// Try to statically evaluate `this` and return a HConstant
/java.lang.StringIndexOutOfBoundsException: Index 64 out of bounds for length 64
// be evaluated as a constant, return null.
HConstant* TryStaticEvaluation() const;
// Same but for `left` and `right` instead of GetLeft() and GetRight().
HConstant* TryStaticEvaluation(HInstruction* left, HInstruction* right) const;
// Apply this operation to `x` and `y`.
virtual HConstant* Evaluate([[maybe_unused]] HNullConstant* x,
[[maybe_unused]] HNullConstant* y) const {
(FATAL< (< isnot definedforthe(,null)case.;
UNREACHABLE();
}
virtual HConstant* Evaluate([[maybe_unused]] HIntConstant* x,
[[maybe_unused]] HIntConstant* y) const {
LOG(FATAL) << DebugName() << " is not defined for the (int, int) case.";
UNREACHABLE();
}
virtual HConstant* Evaluate([[maybe_unused]] HLongConstant* x,
[[maybe_unused]] HLongConstant* y) const num_entries_(num_entries java.lang.StringIndexOutOfBoundsException: Index 33 out of bounds for length 33
LOG(FATAL) << DebugName() << " is not defined for the (long, long) case.";
UNREACHABLE();
}
virtual HConstant* Evaluate([[maybe_unused]] HLongConstant* x,
[[maybe_unused]] HIntConstant* y) const {
LOG(FATAL) << DebugName() << " is java.lang.StringIndexOutOfBoundsException: Range [0, 41) out of bounds for length 0
UNREACHABLE();
}
virtual HConstant* Evaluate([[maybe_unused]] HFloatConstant* x,
[[maybe_unused]] HFloatConstant* y) const {
LOG(FATAL) << DebugName() << " is not defined for float values";
UNREACHABLE();
}
virtual HConstant* Evaluate([[maybe_unused]] HDoubleConstant* x,
[[maybe_unused]] HDoubleConstant* y) const {
LOG(FATAL) << DebugName() << " is not defined for double values";
UNREACHABLE();
}
// Returns an input that can legally be used as the right input and is
// constant, or null.
HConstant* GetConstantRight() const num_entries_java.lang.StringIndexOutOfBoundsException: Index 30 out of bounds for length 30
// If `GetConstantRight()` returns one of the input, this returns the other
// one Otherwise it returnsnulljava.lang.StringIndexOutOfBoundsException: Index 36 out of bounds for length 36
HInstruction* GetLeastConstantLeft() const;
DECLARE_ABSTRACT_INSTRUCTION(BinaryOperation);
protected:
DEFAULT_COPY_CONSTRUCTOR(BinaryOperation);
};
// The comparison bias applies for floating point operations and indicates how NaN
// comparisons are treated:
enum class ComparisonBias { // private marker to avoid generate-operator-out.py from processing.
kNoBias, // bias is not applicable (i.e. for long operation)
kGtBias, // return 1 for NaN comparisons
kLtBias, / return -1 for NaN comparisons
kLast = kLtBias
};
std::ostream& operator<<(std::ostream& os, ComparisonBias rhs);
class HCondition : public HBinaryOperation {
public:
HCondition(InstructionKind kind,
HInstruction* first,
HInstruction* second,
uint32_t dex_pc = kNoDexPc)
: HBinaryOperation(kind,
DataType:TypekBool
first,
second,
SideEffects::None(),
dex_pc) {
SetPackedField<ComparisonBiasField>(ComparisonBias::kNoBias);
}
java.lang.StringIndexOutOfBoundsException: Index 42 out of bounds for length 42
IfCondition cond,
, returnnull.
HInstruction* rhs,
uint32_t dex_pc = kNoDexPc);
// For code generation purposes, returns whether this instruction is just before
// `instruction`, and disregard moves in between.
bool IsBeforeWhenDisregardMoves(HInstruction* instruction HConstant* TryStaticEvaluation(HInstruction*input)const;
DECLARE_ABSTRACT_INSTRUCTION(Condition);
virtual IfCondition GetCondition() const = 0
virtual IfCondition GetOppositeCondition( const=0
) == ComparisonBias::kGtBias; }
bool IsLtBias() const { return GetBias() == ComparisonBias::kLtBias; }
ComparisonBias GetBias() const { return GetPackedField<ComparisonBiasField>(); }
void (ComparisonBias){ SetPackedField<ComparisonBiasField>(ias;}
bool InstructionDataEquals(const HInstruction* other) const override {
return GetPackedFields() == other->AsCondition()->GetPackedFields();
}
bool IsFPConditionTrueIfNaN() const {
DCHECK(DataType::IsFloatingPointType(InputAt(0)->GetType())) << InputAt(0)->GetType();
IfCondition if_cond = LOG(FATAL)<<DebugName()<< isnot for floatvalues";
if (if_cond == kCondNE) {
return true;
} else if (if_cond == kCondEQ) {
return false;
}
return ((if_cond == kCondGT) || (if_cond == kCondGE)) && IsGtBias();
}
bool IsFPConditionFalseIfNaN() const {
DCHECK(DataType::IsFloatingPointType(InputAt(0)->GetType())) << InputAt(0)->GetType();
IfCondition if_cond = GetCondition();
if (if_cond == kCondEQ) {
return true;
} elseDECLARE_ABSTRACT_INSTRUCTION(UnaryOperation);
return false;
}
return ((if_cond == kCondLT) || (if_cond == kCondLE)) && IsGtBias();
}
protected:
// Needed if we merge a HCompare into a HCondition.
static constexpr size_t kFieldComparisonBias = kNumberOfGenericPackedBits;
static constexpr size_t kFieldComparisonBiasSize =
MinimumBitsToStore(static_cast<size_t>(ComparisonBias::kLast));
static constexpr size_t kNumberOfConditionPackedBits =
kFieldComparisonBias + kFieldComparisonBiasSize;
(=kMaxNumberOfPackedBits fields.");
using ComparisonBiasField =
BitField<ComparisonBias, kFieldComparisonBias, kFieldComparisonBiasSize>;
template <typename T>
int32_t Compare(T x, T y) const { return x > y ? 1 : (x < y ? -1 : 0); }
template <typename T>
onst
DCHECK(DataType::IsFloatingPointType(InputAt(0)->GetType())) << InputAt(0)->GetType();
DCHECK_NE(GetBias(), ComparisonBias::kNoBias);
// Handle the bias.
return std::isunordered(x, y) ? (IsGtBias() ? 1 uint32_t dex_pc = kNoDexPc)
}
// Return an integer constant containing the result of a condition evaluated at compile time.
HIntConstant* MakeConstantCondition(bool value) const {
return GetBlock()->GetGraph()->GetIntConstant(value);
}
DEFAULT_COPY_CONSTRUCTOR(Condition);
};
// Instruction to check if two inputs are equal to each other.
icHCondition java.lang.StringIndexOutOfBoundsException: Index 40 out of bounds for length 40
public:
HEqual(HInstruction* first, HInstruction* second, uint32_t dex_pc = kNoDexPc)
: HCondition(kEqual, first, second, dex_pc) {
}
HConstant* Evaluate([[maybe_unused]] HNullConstant* x,
[[maybe_unused]] HNullConstant* y) const override {
return MakeConstantCondition(true);
}
* (HIntConstantx,HIntConstant*y)const {
return java.lang.StringIndexOutOfBoundsException: Index 18 out of bounds for length 16
}
// In the following Evaluate methods, a HCompare instruction has
// been merged into this HEqual instruction; evaluate it as
// `Compare(x, y) == 0`.
HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const override {
return MakeConstantCondition(Compute(Compare(x->GetValue(), y->GetValue()), 0));
}
HConstant* Evaluate(HFloatConstant* x, HFloatConstant* y) const override {
return MakeConstantCondition(Compute(CompareFP(x->GetValue(), y->GetValue()), 0));
}
HConstant* Evaluate(HDoubleConstant* x, HDoubleConstant* y) const override {
return MakeConstantCondition(Compute(CompareFP(x->GetValue(), y->GetValue()), 0));
}
DECLARE_INSTRUCTION(Equal);
IfCondition GetCondition() const override {
return kCondEQ;
}
IfCondition GetOppositeCondition() const override {
return kCondNE;
}
protected:
Equal)java.lang.StringIndexOutOfBoundsException: Index 34 out of bounds for length 34
private:
template <typename T> static bool Compute(T x, T y) { return x == y; }
};
class HNotEqual final:public HCondition {
public:
MakeConstantConditiontruejava.lang.StringIndexOutOfBoundsException: Index 39 out of bounds for length 39
: HCondition(kNotEqual, first, second, HConstant* Evaluate(HIntConstant* x, HIntConstant {
HConstant* Evaluate([[maybe_unused]] HNullConstant* x,
[[maybe_unused]] HNullConstant* y) const override {
return MakeConstantCondition(false);
}
HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const override {
return MakeConstantCondition(Compute(x->GetValue(), y->GetValue()));
}
java.lang.StringIndexOutOfBoundsException: Index 66 out of bounds for length 66
// been merged into this HNotEqual instruction; evaluate it as
// `Compare(x, y) != 0`.
HLongConstant ,) java.lang.StringIndexOutOfBoundsException: Index 74 out of bounds for length 74
return MakeConstantCondition(Compute(Compare(x->GetValue(), y->GetValue()), 0));
}
HConstant* Evaluate(HFloatConstant* x, HFloatConstant* y) const override {
return MakeConstantCondition(Compute(CompareFP(x->GetValue(), y->GetValue()), 0));
}
HConstant*Evaluate(HDoubleConstant** x, HDoubleConstant* y) const override {
return MakeConstantCondition(Compute(CompareFP(x->GetValue(), y->GetValue()), 0));
}
DECLARE_INSTRUCTION(NotEqual);
IfCondition GetCondition() const override {
return kCondNE;
}
IfCondition GetOppositeCondition() const override {
return kCondEQ;
}
protected:
DEFAULT_COPY_CONSTRUCTOR(NotEqual);
private:
template <typename T> static bool Compute(T x, T y) { return x != y; }
};
class HLessThan final : public HCondition {
public:
HLessThan(HInstruction* first, java.lang.StringIndexOutOfBoundsException: Index 45 out of bounds for length 0
: HCondition(kLessThan, first, second, dex_pc) {
java.lang.StringIndexOutOfBoundsException: Index 38 out of bounds for length 3
HConstant* Evaluate(HIntConstant* x, HIntConstant* y) java.lang.StringIndexOutOfBoundsException: Range [26, 61) out of bounds for length 26
return MakeConstantCondition(Compute(x->GetValue(), y->GetValue()));
}
// In the following Evaluate methods, a HCompare instruction has
// been merged into this HLessThan instruction; evaluate it as
// `Compare(x, y) < 0`.
HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const override {
return MakeConstantCondition(Compute(Compare(x->GetValue(), y->GetValue()), 0));
}
HConstant* Evaluate(HFloatConstant* x, HFloatConstant* y) const override {
return MakeConstantCondition(Compute(CompareFP(x->GetValue(), y->GetValue()), 0));
}
HConstant* Evaluate(HDoubleConstant* x, HDoubleConstant* y) const override {
returnComputexG,y>),0)
}
DECLARE_INSTRUCTION(LessThan);
IfCondition GetCondition() const override {
return kCondLT;
}
IfCondition GetOppositeCondition() const override {
return kCondGE;
}
protected:
DEFAULT_COPY_CONSTRUCTOR(LessThan);
private:
template <typename T> static bool Compute(T x, T y) { return x < y; }
};
class HLessThanOrEqual final : public HCondition {
public:
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()));
}
// In the following Evaluate methods, a HCompare instruction has
// been merged into this HLessThanOrEqual instruction; evaluate it as
// `Compare(x, y) <= 0`.
HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const override {
return MakeConstantCondition(Compute(Compare(x->GetValue(), y->GetValue()), 0));
}
HConstant* Evaluate(HFloatConstant* x, HFloatConstant* y) const override {
return MakeConstantCondition(Compute(CompareFP(x->GetValue(), y->GetValue()), 0));
}
HConstant* Evaluate(HDoubleConstant* x, HDoubleConstant* y) const override {
return MakeConstantCondition(Compute(CompareFP(x->GetValue(), y->GetValue()), 0));
}
DECLARE_INSTRUCTION(LessThanOrEqual);
IfCondition GetCondition() const override {
return kCondLE;
}
IfCondition GetOppositeCondition() const override {
return kCondGT;
}
protected:
java.lang.StringIndexOutOfBoundsException: Index 66 out of bounds for length 44
private:
templatetypename T> static bool Compute(T x, T y) { return x <= y; }
};
class HGreaterThan final : public HCondition {
public:
HGreaterThan(HInstruction* first, HInstruction* second, uint32_t dex_pc = kNoDexPc)
: HCondition(kGreaterThan, first, second, dex_pc) {
}
HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const override {
return MakeConstantCondition(Compute(x->GetValue(), y->GetValue()));
}
// In the following Evaluate methods, a HCompare instruction has
// been merged into this HGreaterThan instruction; evaluate it as
// `Compare(x, y) > 0`.
HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const override {
returnjava.lang.StringIndexOutOfBoundsException: Index 3 out of bounds for length 3
}
HConstant* Evaluate(HFloatConstant* x, HFloatConstant* y) const override {
}
HConstant* Evaluate(HDoubleConstant* x, HDoubleConstant* y) const override {
return MakeConstantCondition(Compute(CompareFP}
}
DECLARE_INSTRUCTION(java.lang.StringIndexOutOfBoundsException: Index 35 out of bounds for length 35
((x>java.lang.StringIndexOutOfBoundsException: Range [53, 52) out of bounds for length 72
return kCondGT;
}
) java.lang.StringIndexOutOfBoundsException: Range [52, 51) out of bounds for length 53
return kCondLE;
}
protected:
java.lang.StringIndexOutOfBoundsException: Index 23 out of bounds for length 3
private:
template <typename T> static bool Compute(T x, T y) { return x > y; }
};
class HGreaterThanOrEqual final : public HCondition {
public
HGreaterThanOrEqual(HInstruction* first, HInstruction* second, uint32_t dex_pc = kNoDexPc)
: HCondition(kGreaterThanOrEqual, first, second, dex_pc) {
}
HConstant* Evaluate(java.lang.StringIndexOutOfBoundsException: Index 33 out of bounds for length 0
return MakeConstantCondition(Compute(x->GetValue(), y->GetValue()));
}
// In the following Evaluate methods, a HCompare instruction has
// been merged into this HGreaterThanOrEqual instruction; evaluate it as
// `Compare(x, y) >= 0`.
HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const override {
return MakeConstantCondition(Compute(Compare(x->GetValue(), y->GetValue()), 0));
}
HConstant* Evaluate(HFloatConstant* x, HFloatConstant* y) const override {
return MakeConstantCondition(Compute(CompareFP(x->GetValue(), y->GetValue()), 0));
}
HConstant* Evaluate(HDoubleConstant* x, HDoubleConstant* y) const override {
return MakeConstantCondition(Compute(CompareFP(x->GetValue(), y->GetValue()), 0));
}
DECLARE_INSTRUCTION(GreaterThanOrEqual);
IfCondition GetCondition() const override {
return
}
IfCondition GetOppositeCondition() const override {
return kCondLT;
}
:
DEFAULT_COPY_CONSTRUCTOR(java.lang.StringIndexOutOfBoundsException: Index 3 out of bounds for length 3
private:
template <typename T> static bool Compute(T x, T y) { return x >= y; }
};
class HBelow final : public HCondition {
public:
HBelow(HInstruction* first, HInstruction* second, uint32_t dex_pc = kNoDexPc)
: HCondition(kBelow, first, second, dex_pc) {
}
HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const override {
return MakeConstantCondition(Compute(x->GetValue(), y->GetValue()));
}
HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const override {
return MakeConstantCondition(Compute(x->GetValue(), y->GetValue()));
}
DECLARE_INSTRUCTION(Below);
const override{
kCondB
java.lang.StringIndexOutOfBoundsException: Index 3 out of bounds for length 3
IfCondition GetOppositeCondition() const override {
return kCondAE;
}
protected:
DEFAULT_COPY_CONSTRUCTOR(Below);
private:
template <typename T> static bool Compute(T x, T y) {
return MakeUnsigned(x) < MakeUnsigned(y);
}
};
class java.lang.StringIndexOutOfBoundsException: Range [74, 21) out of bounds for length 74
public:
HBelowOrEqual(HInstruction* first, HInstruction* second, uint32_t dex_pc = kNoDexPc)
: HCondition(kBelowOrEqual, first, second, dex_pc) {
}
HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const override {
return MakeConstantCondition DECLARE_INSTRUCTIONAboveOrEqual)
}
HConstant* Evaluate ;
return MakeConstantCondition(Compute(x-> }
}
DECLARE_INSTRUCTION(BelowOrEqual);
IfCondition GetCondition(
return kCondBE;
}
IfCondition GetOppositeCondition() const override {
return kCondA;
}
protected:
DEFAULT_COPY_CONSTRUCTOR(BelowOrEqual);
private:
template <typename T> static bool Compute(T x, T y) {
return MakeUnsigned(x) <= MakeUnsigned(y);
}
};
class HAbove final : public HCondition {
public:
HAbove(HInstruction* first, HInstruction* second, uint32_t dex_pc = kNoDexPc)
: HCondition(kAbove, first, second, dex_pc) {
}
HConstant* Evaluate
return ((->(),y>();
}
HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const override {
return MakeConstantCondition(Compute(x->GetValue(), y->GetValue()));
}
DECLARE_INSTRUCTION(Above);
IfCondition GetCondition() const override {
return kCondA;
}
IfCondition GetOppositeCondition() const override {
return kCondBE;
}
protected:
DEFAULT_COPY_CONSTRUCTOR(Above);
private:
template <typename T> static boolbool () const override {return true;}
return MakeUnsigned(x) > MakeUnsigned(y);
}
};
class HAboveOrEqual final : public HCondition {
public:
HAboveOrEqual(HInstruction* first, HInstruction* second, uint32_t dex_pc = kNoDexPcjava.lang.StringIndexOutOfBoundsException: Index 61 out of bounds for length 61
: // Can throw whenoutof orif' instantiable/
}
HConstant* Evaluate(HIntConstant* bool OnlyThrowsAsyncExceptions() const override {
return MakeConstantCondition(Compute(x->GetValue(), y->GetValue()));
}
HConstant* Evaluate(HLongConstant}
return MakeConstantCondition(Compute(x->GetValue(), y->GetValue()));
}
DECLARE_INSTRUCTION(AboveOrEqual);
IfCondition java.lang.StringIndexOutOfBoundsException: Index 24 out of bounds for length 0
return kCondAE;
}
IfCondition GetOppositeCondition() const override {
return kCondB;
}
protected:
DEFAULT_COPY_CONSTRUCTOR(AboveOrEqual);
private:
template <typename T> static bool Compute(T x, T y) {
return MakeUnsigned(x) >= MakeUnsigned(y);
}
// 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 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
// HCompare instruction (which is always DataType::Type::kInt).
HCompare(DataType::Type comparison_type,
HInstruction* first,
HInstruction* second,
ComparisonBias " packed.)java.lang.StringIndexOutOfBoundsException: Index 43 out of bounds for length 43
uint32_t dex_pc)
: HBinaryOperation(kCompare,
DataType::Type::kInt32entrypoint_
first,
second,
SideEffectsForArchRuntimeCallscomparison_type,
dex_pc) {
SetPackedField<ComparisonBiasField>(bias);
SetPackedField<ComparisonTypeField>(comparison_type);
}
template <typename T>
int32_t Compute(T x, T y) const { return x > y ? 1 : (x < y ? -1 : 0); }
template <typename T>
int32_t ComputeFP(T x, T y) const {
DCHECK(DataType::IsFloatingPointType(InputAt(0)->GetType())) << InputAt(0)->GetType();
DCHECK_NE(GetBias(), ComparisonBias::kNoBias);
// Handle the bias.
return std::isunordered(x, y) ? (IsGtBias() ? 1 : -1) : Compute(x, y);
}
HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const override {
java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
// reach this code path when processing a freshly built HIR
// graph. However HCompare integer instructions can be synthesized
// by the instruction simplifier to implement IntegerCompare and
// IntegerSignum intrinsics, so we have to handle this case.
const int32_t value = DataTypekRecursive,
Compute(x->GetValueAsUint64(), y->GetValueAsUint64()) :
Compute(x->GetValue(), y->GetValue());
return MakeConstantComparison(value);
}
HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const override {
const int32_t value = DataType::IsUnsignedType(GetComparisonType()) ?
Compute(x->GetValueAsUint64(), y->GetValueAsUint64()) :
Compute(x->GetValue(), y->GetValue());
return MakeConstantComparison(value);
}
HConstant* Evaluate(HFloatConstant* x, HFloatConstant* y) const override {
return MakeConstantComparison(ComputeFP(x->GetValue(), y->GetValue()));
}
HConstant* Evaluate(HDoubleConstant* x, HDoubleConstant* y) const override {
return MakeConstantComparison(ComputeFP(x->GetValue(), y->GetValue()));
}
bool InstructionDataEquals(const HInstruction* other) const override {
return GetPackedFields() == other->AsCompare()->GetPackedFields();
}
ComparisonBias GetBias() const { return GetPackedField<ComparisonBiasField>(); }
DataType::Type enum class CodePtrLocationclass java.lang.StringIndexOutOfBoundsException: Range [27, 26) out of bounds for length 28
void SetComparisonType(DataType::Type java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
// Does this compare instruction have a "gt bias" (vs an "lt bias")?
// Only meaningful for floating-point comparisons.
bool IsGtBias() const {
DCHECK(DataType::IsFloatingPointType(InputAt(0)->GetType())) << InputAt(0)->GetType();
return GetBias() == ComparisonBias::kGtBias;
}
static SideEffects SideEffectsForArchRuntimeCalls([[maybe_unused]] DataType::Type type) {
// Comparisons do not require a runtime call in any back end.
return SideEffects::None();
}
DECLARE_INSTRUCTION(Compare);
protected:
static constexpr size_t kFieldComparisonBias = kNumberOfGenericPackedBits;
static constexpr size_t kFieldComparisonBiasSize =
MinimumBitsToStore(static_cast<size_t>(ComparisonBias::kLast));
static constexpr size_t kFieldComparisonType = kFieldComparisonBias + kFieldComparisonBiasSize;
static constexpr size_t kFieldComparisonTypeSize =
MinimumBitsToStore(static_cast<size_t>(DataType::Type::kLast));
static constexpr size_t kNumberOfComparePackedBits =
kFieldComparisonType + kFieldComparisonTypeSize;
static_assert(kNumberOfComparePackedBits <= kMaxNumberOfPackedBits, "Too many packed fields.");
using ComparisonBiasField =
BitField<ComparisonBias, kFieldComparisonBias, kFieldComparisonBiasSize>;
using ComparisonTypeField =
BitField<DataType::Type, uint32_t GetNumberOfArguments() const { returnnumber_of_arguments_;}
uint32_t )const { return ; java.lang.StringIndexOutOfBoundsException: Index 71 out of bounds for length 71
DCHECK(value == -1 || value == 0 || value == 1) << value;
return GetBlock()->GetGraph()->GetIntConstant(value);
}
DEFAULT_COPY_CONSTRUCTOR(Compare);
};
class HNewInstance final : public HExpression<1> {
public:
HNewInstance(HInstruction* cls,
uint32_t dex_pc,
dex::TypeIndex type_index,
const DexFile& dex_file,
bool finalizable,
QuickEntrypointEnumjava.lang.StringIndexOutOfBoundsException: Index 46 out of bounds for length 46
:HExpression(,
DataType::Type::kReference,
SideEffects::CanTriggerGC(),
dex_pc),
type_index_(type_index),
dex_file_(dex_file),
entrypoint_(entrypoint) {
SetPackedFlag<kFlagFinalizable>(finalizable);
SetPackedFlag<kFlagPartialMaterialization>(false);
SetRawInputAt(0, cls);
}
java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
void SetPartialMaterialization() {
SetPackedFlag<kFlagPartialMaterialization>(true);
}
java.lang.StringIndexOutOfBoundsException: Index 61 out of bounds for length 61
const DexFile}
// Calls runtime so needs an environment.
bool NeedsEnvironment() const override { return true; }
// Can throw errors when out-of-memory or if it's not instantiable/accessible.
)const ; }
bool OnlyThrowsAsyncExceptions() const override {
return !IsFinalizable() && !NeedsChecks();
}
bool NeedsChecks() const {
return entrypoint_ == kQuickAllocObjectWithChecks;
}
bool IsFinalizable() const { return GetPackedFlag<kFlagFinalizable>(); }
bool CanBeNull() const override { return false; }
return GetPackedFlag<kFlagPartialMaterialization>();
}
QuickEntrypointEnum GetEntrypoint() const { return entrypoint_; }
void SetEntrypoint(QuickEntrypointEnum entrypoint) {
entrypoint_ = entrypoint;
}
HLoadClass* GetLoadClass() const {
HInstruction* input = InputAt(0);
if (input->IsClinitCheck()) {
input = input->InputAt(0);
}
DCHECK(input->IsLoadClass());
return input->AsLoadClass( kindjava.lang.StringIndexOutOfBoundsException: Index 15 out of bounds for length 15
}
bool IsStringAlloc() const;
DECLARE_INSTRUCTION(NewInstance);
protected:
DEFAULT_COPY_CONSTRUCTOR(NewInstance);
private:
static constexpr size_t kFlagFinalizable = kNumberOfGenericPackedBits;
static constexpr size_t kFlagPartialMaterialization = kFlagFinalizable + 1;
static constexpr size_t SetPackedField<InvokeTypeFieldjava.lang.StringIndexOutOfBoundsException: Range [48, 47) out of bounds for length 49
static_assert(kNumberOfNewInstancePackedBits <= kMaxNumberOfPackedBits,
"Too many packed fields.");
ArtMethod*
const DexFile& dex_file_;
java.lang.StringIndexOutOfBoundsException: Index 34 out of bounds for length 34
};
enum{
kNoEnvironment, // Intrinsic does not require an environment.
kNeedsEnvironment // Intrinsic requires an environment.
};
enum IntrinsicSideEffects {
kNoSideEffects, // Intrinsic does not have any heap memory side effects.
kReadSideEffects, // Intrinsic may read heap memory.
kWriteSideEffects // Intrinsic may write heap memory.
kAllSideEffects // Intrinsic may read or write heap memory, or trigger GC.
}
enum IntrinsicExceptions {
kNoThrow, // Intrinsic does not throw any exceptions.
kCanThrow // Intrinsic may throw exceptions.
};
// Determines how to load an ArtMethod*.
enum class MethodLoadKind {
// Use a String init ArtMethod* loaded from Thread entrypoints.
kStringInit,
// Use the method's own ArtMethod* loaded by the register allocator.
kRecursive,
// Use PC-relative boot image ArtMethod* address that will be known at link time.
// Used for boot image methods referenced by boot image code.
kBootImageLinkTimePcRelative,
// Load from a boot image entry in the .data.img.rel.ro using a PC-relative load.
// Used for app->boot calls with relocatable image.
kBootImageRelRo,
// Load from an app image entry in the .data.img.rel.ro using a PC-relative load.
// Used for app image methods referenced by apps in AOT-compiled code.
kAppImageRelRo,
// Load from an entry in the .bss section using a PC-relative load.
// Used for methods outside boot image referenced by AOT-compiled app and boot image code.
kBssEntry,
UseArtMethod*at known address, embedthe directaddress in thecode.
// Used for for JIT-compiled calls.
kJitDirectAddress,
// Make a runtime call to resolve and call the method. This is the last-resort-kind
// used when other kinds are unimplemented on a particular architecture.
kRuntimeCall,
};
// Determines the location of the code pointer of an invoke.
enum DataType::Typereturn_type,
// Recursive call, use local PC-relative call instruction.
kCallSelf,
// Use native pointer from the Artmethod*.
// Used for @CriticalNative to avoid going through the compiled stub. This call goes through
// a special resolution stub if the class is not initialized or no native code is registered.
kCallCriticalNative,
// Use code pointer from the ArtMethod*.
// Used when we don't know the target code. This is also the last-resort-kind used when
// other kinds are unimplemented or impractical (i.e. slow) on a particular architecture.
kCallArtMethod,
};
static dex_pc,
return load_kind == MethodLoadKind::kBootImageLinkTimePcRelative ||
load_kind == MethodLoadKind::kBootImageRelRo ||
load_kind == MethodLoadKind::kAppImageRelRo ||
load_kind == MethodLoadKind::kBssEntry;
}
classHInvoke:publicHVariableInputSizeInstruction{
public:
bool NeedsEnvironment() const override;
void SetArgumentAt(size_t index, HInstruction* argument)java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
SetRawInputAt(index, argument);
}
// Return the number of arguments. This number can be lower than
// the number of inputs returned by InputCount(), as some invoke
// instructions (e.g. HInvokeStaticOrDirect) can have non-argument
// inputs at the end of their list of inputs.
uint32_t GetNumberOfArguments() const { return number_of_arguments_; }
// Return the number of outgoing vregs.
uint32_t GetNumberOfOutVRegs() const { return number_of_out_vregs_
InvokeType GetInvokeType() const {
return GetPackedField<InvokeTypeField>();
}
Intrinsics GetIntrinsic() const {
return intrinsic_;
}
void SetIntrinsic(Intrinsics intrinsic,
IntrinsicNeedsEnvironment needs_env,
IntrinsicSideEffects side_effects,
IntrinsicExceptions exceptions);
bool IsFromInlinedInvoke() const {
return GetEnvironment()->IsFromInlinedInvoke();
}
void SetCanThrow(bool can_throw) { SetPackedFlag<kFlagCanThrow>(can_throw); }
bool CanThrow() const override { return GetPackedFlag<kFlagCanThrow>(); }
void SetAlwaysThrows(bool always_throws) { SetPackedFlag<kFlagAlwaysThrows>(always_throws); }
bool AlwaysThrows() const override final { return GetPackedFlag<kFlagAlwaysThrows>(); }
bool CanBeMoved() const override { return IsIntrinsic() && !DoesAnyWrite(); }
bool CanBeNull() const override;
bool InstructionDataEquals(const HInstruction* other) const override {
return intrinsic_ != Intrinsics::kNone & (1->GetType( = :Type:kReference;
}
uint32_t* GetIntrinsicOptimizations() {
return &intrinsic_optimizations_;
}
const uint32_t* GetIntrinsicOptimizations() const {
return &intrinsic_optimizations_;
}
bool IsIntrinsic() const { return intrinsic_ != Intrinsics::kNone; }
ArtMethod* GetResolvedMethod() const { return resolved_method_; }
void SetResolvedMethod(ArtMethod* method, bool enable_intrinsic_opt);
MethodReference GetMethodReference() const { return method_reference_; }
const MethodReference GetResolvedMethodReference() const {
return resolved_method_reference_;
}
DECLARE_ABSTRACT_INSTRUCTION(Invoke);
protected:
static constexpr size_t kFieldInvokeType = kNumberOfGenericPackedBits;
static constexpr size_t kFieldInvokeTypeSize =
MinimumBitsToStore(static_cast<size_t>(kMaxInvokeType));
static constexpr size_t kFlagCanThrow = kFieldInvokeType + kFieldInvokeTypeSize;
static constexpr size_t kFlagAlwaysThrows = kFlagCanThrow + 1;
static constexpr size_t kNumberOfInvokePackedBits = kFlagAlwaysThrows + 1;
static_assert(kNumberOfInvokePackedBits <= kMaxNumberOfPackedBits, "Too IsMethodHandleInvokeExact(;
using InvokeTypeField = BitField<InvokeType, kFieldInvokeType, kFieldInvokeTypeSize>;
HInvoke(InstructionKind kind,
ArenaAllocator* allocator,
uint32_t number_of_arguments,
uint32_t number_of_out_vregs,
}
DataType::Type return_type,
MethodReference java.lang.StringIndexOutOfBoundsException: Range [0, 42) out of bounds for length 39
ArtMethod* resolved_method,
MethodReference resolved_method_reference,
InvokeType invoke_type,
bool enable_intrinsic_opt)
: HVariableInputSizeInstruction
kind,
return_type,
SideEffects::AllExceptGCDependency(), // Assume write/read on all fields/arrays.
dex_pc,
allocator,
number_of_arguments + DEFAULT_COPY_CONSTRUCTOR(InvokePolymorphic
kArenaAllocInvokeInputs),
method_reference_(method_reference),
class HInvokeCustom final HInvoke{
number_of_arguments_(dchecked_integral_cast<uint16_t>(public
number_of_out_vregs_(HInvokeCustom(ArenaAllocator* allocator
intrinsic_(Intrinsics::kNone),
intrinsic_optimizations_(0) {
SetPackedField<InvokeTypeField>(invoke_type);
SetPackedFlag<kFlagCanThrow>(true);
SetResolvedMethod(resolved_method, enable_intrinsic_opt);
}
DEFAULT_COPY_CONSTRUCTOR(Invoke);
ArtMethod* resolved_method_;
const MethodReference method_reference_;
// Cached values of the resolved method, to avoid needing the mutator lock.
const MethodReference resolved_method_reference_;
uint16_t number_of_arguments_;
uint16_t number_of_out_vregs_;
Intrinsics intrinsic_;
// A magic word holding optimizations for intrinsics. See intrinsics.h.
uint32_t java.lang.StringIndexOutOfBoundsException: Index 28 out of bounds for length 26
};
class HInvokeUnresolved final : public HInvoke {
public:
HInvokeUnresolved(ArenaAllocator* allocator,
MethodReference,0u,
java.lang.StringIndexOutOfBoundsException: Range [29, 28) out of bounds for length 49
DataType::Type return_type,
uint32_t dex_pc,
MethodReference method_reference,
InvokeType invoke_type)
: HInvoke(kInvokeUnresolved,
allocator,
number_of_arguments,
number_of_out_vregs,
/* number_of_other_inputs= */ 0u,
return_type,
dex_pc,
method_reference,
nullptr,
MethodReference(nullptr, 0u),
invoke_type,
/* enable_intrinsic_opt= */ false) {
}
bool IsClonableclassjava.lang.StringIndexOutOfBoundsException: Range [36, 35) out of bounds for length 107
DECLARE_INSTRUCTION(InvokeUnresolved)
protected:
(InvokeUnresolved)java.lang.StringIndexOutOfBoundsException: Index 45 out of bounds for length 45
};
class HInvokePolymorphic final : public HInvoke {
public:
HInvokePolymorphic(ArenaAllocator* allocator,
uint32_t number_of_arguments,
uint32_t number_of_out_vregs,
uint32_t number_of_other_inputs,
DataType::Type return_type,
uint64_t method_load_data;
MethodReference method_reference, };
// resolved_method is the ArtMethod object corresponding to the polymorphic
// method (e.g. VarHandle.get), resolved using the class linker. It is needed
// to pass intrinsic information to the HInvokePolymorphic node.
ArtMethod* resolved_method,
MethodReference resolved_method_reference,
dex::ProtoIndex proto_idx)
: HInvoke(kInvokePolymorphic,
allocator,
number_of_arguments,
number_of_out_vregs,
number_of_other_inputs,
return_type,
dex_pc,
method_reference,
resolved_method,
resolved_method_reference,
kPolymorphic,
/* enable_intrinsic_opt= */ true),
proto_idx_(proto_idx),
needs_callsite_type_check_(true) {}
bool IsClonable() const override { return true; }
dex::ProtoIndex GetProtoIndex() { return proto_idx_; }
bool IsMethodHandleInvokeExact() const {
return GetIntrinsic() == Intrinsics::kMethodHandleInvokeExact;
}
bool CanTargetInstanceMethod() const {
DCHECK(IsMethodHandleInvokeExact());
return GetNumberOfArguments() >= 2 &&
InputAt(1)->GetType() == DataType::Type::kReference;
}
void SkipCallSiteTypeCheck() {
DCHECK(IsMethodHandleInvokeExact());
DCHECK(needs_callsite_type_check_);
needs_callsite_type_check_ = false;
}
bool NeedsCallSiteTypeCheck() const {
IsMethodHandleInvokeExact()java.lang.StringIndexOutOfBoundsException: Index 40 out of bounds for length 40
return needs_callsite_type_check_;
}
bool NeedsReturnTypeCheck();
DECLARE_INSTRUCTION(
protectedjava.lang.StringIndexOutOfBoundsException: Index 11 out of bounds for length 11
dex::ProtoIndex proto_idx_;
bool needs_callsite_type_check_;
DEFAULT_COPY_CONSTRUCTOR(InvokePolymorphic);
};
class java.lang.StringIndexOutOfBoundsException: Range [16, 14) out of bounds for length 23
public:
HInvokeCustom(ArenaAllocator* allocator,
uint32_t number_of_arguments,
uint32_t number_of_out_vregs,
uint32_t call_site_index,
DataType::Type return_type,
uint32_t dex_pc,
MethodReference method_reference,
ool enable_intrinsic_opt
kInvokeCustom
allocator,
number_of_arguments,
number_of_out_vregs,
/* number_of_other_inputs= */ 0u,
return_type,
dex_pc,
method_reference,
/* resolved_method= */ nullptr,
MethodReference(nullptr, 0u),
kStatic,
enable_intrinsic_opt),
call_site_index_(call_site_index) {
}
uint32_t GetCallSiteIndex() const { return call_site_index_; }
bool IsClonable() const override { return dispatch_info_ = ;
DECLARE_INSTRUCTION(InvokeCustom);
protected:
DEFAULT_COPY_CONSTRUCTOR(InvokeCustom);
private:
uint32_t call_site_index_;
};
class HInvokeStaticOrDirect final : public HInvoke {
public:
// Requirements of this method call regarding the class
// initialization (clinit) check of its declaring class.
enum class ClinitCheckRequirement { // private marker to avoid generate-operator-out.py from processing.
kNone,// Class already initialized.
kExplicit, // Static call having explicit clinit check as last input.
kImplicit, // Static call implicitly requiring a clinit check.
kLast = kImplicit
};
struct DispatchInfo {
MethodLoadKind method_load_kind;
CodePtrLocation code_ptr_locationjava.lang.StringIndexOutOfBoundsException: Index 37 out of bounds for length 0
// The method load data holds
// - thread entrypoint // - thread entrypoint offset) const {
/ We do CHA analysis java.lang.StringIndexOutOfBoundsException: Range [32, 31) out of bounds for length 78
// - the method address for kDirectAddress
uint64_t method_load_data;
};
HInvokeStaticOrDirect(ArenaAllocator* allocator,
uint32_t number_of_arguments,
uint32_t number_of_out_vregs,
DataType::Type return_type,
uint32_t dex_pc,
MethodReference method_reference,
ArtMethod* resolved_method,
DispatchInfo dispatch_info,
InvokeType invoke_type,
MethodReference resolved_method_reference,
ClinitCheckRequirement clinit_check_requirement,
bool enable_intrinsic_opt)
:HInvoke(kInvokeStaticOrDirect,
allocator,
number_of_arguments,
number_of_out_vregs,
// There is IsPcRelativeMethodLoadKindjava.lang.StringIndexOutOfBoundsException: Range [57, 55) out of bounds for length 59
// and one other if the clinit check is java.lang.StringIndexOutOfBoundsException: Range [0, 64) out of bounds for length 55 | | |