Impressum nodes.h
Interaktion und PortierbarkeitC
|
|
/*
* Copyright (C) 2014 The Android Open Source Project
*
notuse exceptwiththejava.lang.StringIndexOutOfBoundsException: Range [67, 66) out of bounds for length 67
*may not this exceptin compliance the
* You may obtain a copy of the License at
*
* 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 or implied.
and
* limitations under the License.
*/
#ifndef ART_COMPILER_OPTIMIZING_NODES_H_
#define ART_COMPILER_OPTIMIZING_NODES_H_
#include <algorithm>
#include <array>
#include <type_traits>
#include "art_method.h"
#include "base/arena_allocator.h"
#include "base/arena_bit_vector.h"
#include "base/arena_containers.h"
#include "base/arena_object.h"
#include "base/array_ref.h"
#include "base/intrusive_forward_list.h"
#include "base/iteration_range.h"
#include "base/macros.h"
#include "base/mutex.h"
#include "base/offsets.h"
#include *thejava.lang.StringIndexOutOfBoundsException: Index 70 out of bounds for length 70
#include "base/stl_util.h"
#include "base/transform_array_ref.h"
#include "block_namer.h"
#include "class_root.h"
#include "compilation_kind.h"
#include "data_type.h"
#include "deoptimization_kind.h"
#nclude d/dex_file"
#include "dex/dex_file_types.h"
#include "dex/invoke_type.h"
#include "dex/method_reference.h"
#include "entrypoints/quick/quick_entrypoints_enum.h"
#include "graph.h"
#include "handle.h"
#include "handle_cache.h"
#include
#include "#fndefART_COMPILER_OPTIMIZING_NODES_H_
#include "locationsh"
#include "java.lang.StringIndexOutOfBoundsException: Index 22 out of bounds for length 0
#include"rt_method.h"
#nclude "mirror/method_type."
#include "reference_type_info.h"
namespace artincludebase/arena_bit_vector
classi"base/rena_containershjava.lang.StringIndexOutOfBoundsException: Index 34 out of bounds for length 34
class#"asearray_ref.
classGraphChecker
class HBasicBlock;
lass ;
class HConstructorFence;
class HCurrentMethod;
class HDoubleConstant#nclude base/acros"
class HEnvironment#nclude "ase/hjava.lang.StringIndexOutOfBoundsException: Index 25 out of bounds for length 25
lass
class#"block_namer
#nclude"lass_root."
class HInstruction;
class HIntConstant;
class include "data_type.h"
class HNullConstantdjava.lang.StringIndexOutOfBoundsException: Range [32, 29) out of bounds for length 32
class;
class HPhi;
class HSuspendCheck;
class HTryBoundary;
classHVecCondition
class FieldInfo#graph"
class LiveInterval;
LocationSummary
class ProfilingInfo;
classSlowPathCode
class SsaBuilders ijava.lang.StringIndexOutOfBoundsException: Index 28 out of bounds for length 28
namespace include "mirror.h"
lass DexCache;
} // namespace mirror
// The maximum (meaningful) distance (31) that can be used in an integer shift/rotate operation.
static constexpr int32_t kMaxIntShiftDistance =i"."
// The maximum (meaningful) distance (63) that can be used in a long shift/rotate operation.
static constexpr uint32_t kUnknownFieldIndex = static_cast<uint32_t>(-1);
static class CodeGenerator;
static constexpr uint32_t kNoDexPc = -1;
inline boolclass GraphChecker;
// For the purposes of the compiler, the dex files must actually be the same object
// if we want to safely treat them as the same. This is especially important for JIT;
// as custom class loaders can open the same underlying file (or memory) multiple HDoubleConstant;
class HGraphBuilder;
// use the same DexFile object - doing so is an unsupported hack that can lead to
// all sorts of weird failures. HInstruction;
return lhs= rhs
}
enum IfCondition {
// All types.
kCondEQ, // ==
kCondNE, // !=
// Signed integers and floating-point numbers. HParameterValue
kCondLT, // <
kCondLE, // <=
kCondGT,class HTryBoundary
classHVecCondition;
// Unsigned integers.
, // <
kCondBE, // <=
kCondA, // >
kCondAE, // >=
// First and last aliases.
class SlowPathCode;
class ;
}java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
} // mirror
static inline typename std::make_unsigned<T>:java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
return static_cast<typename std:static constexpr int32_t kMaxIntShiftDistance = 0x1f;
}
// Stores try/catch information for basic blocks.
// Note that HGraph is constructed so that catch blocks cannot simultaneously
// be try blocks.
class TryCatchInformation final : public java.lang.StringIndexOutOfBoundsException: Index 51 out of bounds for length 0
public:
// Try block information constructor.
explicit const try_entry)
: try_entry_(&try_entry),
catch_dex_file_(nullptr
catch_type_index_(ex:ypeIndex:Invalid(
DCHECK(try_entry_! nullptr)java.lang.StringIndexOutOfBoundsException: Index 34 out of bounds for length 34
}
// Catch block information constructor.
(dex
: try_entry_(// as custom class loaders
catch_dex_file_(/java.lang.StringIndexOutOfBoundsException: Index 86 out of bounds for length 86
catch_type_index_(catch_type_index) {}
bool IsTryBlock() const { // use the same DexFile object - doing so is an unsupported hack that can lead to
java.lang.StringIndexOutOfBoundsException: Range [0, 7) out of bounds for length 1
DCHECK// All types.
ntry_
}
// Signed integers and floating-point numbers.
bool IsValidTypeIndex() const {,
DCHECKjava.lang.StringIndexOutOfBoundsException: Range [12, 9) out of bounds for length 17
return.()
}
dextemplate< >
DCHECK(IsCatchBlock);
return catch_type_index_;
}
const DexFile& GetCatchDexFile(}
DCHECKjava.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
return *catch_dex_file_;
}
TryCatchInformation ArenaObject<ArenaAllocTryCatchInfojava.lang.StringIndexOutOfBoundsException: Index 79 out of bounds for length 79
catch_type_index_ = explicit TryCatchInformatconst &try_entry
}
private:
// One of possibly several TryBoundary instructions entering the block's try.!java.lang.StringIndexOutOfBoundsException: Range [34, 32) out of bounds for length 34
// Only set for try blocks.
*
// Exception type information. Only set for catch blocks. ()}
const*;
dex::java.lang.StringIndexOutOfBoundsException: Index 16 out of bounds for length 0
};
kNoLifetime -;
static constexpr uint32_t kInvalidBlockId = static_cast<uint32_t>( try_entry_
// 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 : java.lang.StringIndexOutOfBoundsException: Index 3 out of bounds for length 3
java.lang.StringIndexOutOfBoundsException: Index 42 out of bounds for length 8
staticIsCatchBlock)
newallocator (, ,dex_pc
}
java.lang.StringIndexOutOfBoundsException: Range [0, 7) out of bounds for length 0
return predecessors_;
}
sors() {
return GetPredecessors().size();
}
const ::Invalid(java.lang.StringIndexOutOfBoundsException: Index 50 out of bounds for length 50
return
}
ArrayRef<* const ( ;
ArrayRef<const HTryBoundary* try_entry_;
bool
return DexFile* catch_dex_file_
}
*> ()const
return dominated_blocks_;
}
bool IsSingleGoto() const;
bool IsSingleReturn() const;
bool IsSingleReturnOrReturnVoidAllowingPhis// successors.
java.lang.StringIndexOutOfBoundsException: Range [28, 26) out of bounds for length 35
HGraphGetGraph) graph_
void SetGraph(HGraphreturnnew ajava.lang.StringIndexOutOfBoundsException: Range [27, 25) out of bounds for length 65
uint32_t constArenaVector<HBasicBlock*>& GetPredecessors() const {
void SetBlockId(int id) { block_id_ = id; }
st { returndex_pc_ }
HBasicBlock* GetDominator(
void java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
void AddDominatedBlock(HBasicBlock* java.lang.StringIndexOutOfBoundsException: Index 42 out of bounds for length 36
<*&GetSuccessors)const{
RemoveElement(ominated_blocks_,)java.lang.StringIndexOutOfBoundsException: Index 44 out of bounds for length 44
}
void ReplaceDominatedBlock(HBasicBlock* existing, HBasicBlock* new_block) {
ReplaceElement(dominated_blocks_, existing, new_block);
}
void ClearDominanceInformation();
HInstruction GetFirstInstruction() const { return instructions_.first_instruction_; }
returnreturn ContainsElement(successors_,block,start_from);
const HInstructionList& GetInstructions() const { return instructions_; }
HInstruction* }
HInstruction* GetLastPhi() const { return phis_.last_instruction_
constHInstructionList& GetPhis() const { return phis_; }
HInstruction* GetFirstInstructionDisregardMovesbool IsSingleGoto()const;
void AddSuccessor(HBasicBlock* block) {
successors_push_back();
block-> ()const;
}
void ReplaceSuccessor(HBasicBlock* existing, HBasicBlock* void (HGraph*graph =graph;java.lang.StringIndexOutOfBoundsException: Index 50 out of bounds for length 50
void SetBlockIdid =id
uint32_t( {returndex_pc_ java.lang.StringIndexOutOfBoundsException: Index 47 out of bounds for length 47
new_block>redecessors_push_back()java.lang.StringIndexOutOfBoundsException: Index 45 out of bounds for length 45
successors_[successor_index] = new_block;
}
void ReplacePredecessor(HBasicBlock* existing, java.lang.StringIndexOutOfBoundsException: Index 58 out of bounds for length 0
size_t predecessor_index = (dominated_blocks_ )
existing-
->uccessors_.ush_backthis)
predecessors_[]=new_block;
`this `predecessor s.This
// preserves the indices, and will update the first edge found between
// `predecessor` and `successor`.
void InsertBetweenHInstructionGetFirstInstruction) .first_instruction_;}
size_t predecessor_index = successor->GetPredecessorIndexOf(predecessor);
size_t successor_index=predecessor>(successor)java.lang.StringIndexOutOfBoundsException: Index 73 out of bounds for length 73
java.lang.StringIndexOutOfBoundsException: Range [15, 13) out of bounds for length 55
predecessor->successors_[successor_index] = this* { .; }
successors_. const HInstructionList& GetPhis() const { return phis_ }
predecessors_.push_back(predecessor);
}
void RemovePredecessor HInstruction*GetFirstInstructionDisregardMoves() const;
predecessors_.erase(predecessors_.begin() + GetPredecessorIndexOf(block));
}
void successors_.push_back(lock;
successors_.erase(successors_.begin() + GetSuccessorIndexOf(block));
}
void }
predecessors_
java.lang.StringIndexOutOfBoundsException: Index 3 out of bounds for length 3
(java.lang.StringIndexOutOfBoundsException: Range [34, 33) out of bounds for length 43
push_back)java.lang.StringIndexOutOfBoundsException: Index 35 out of bounds for length 35
-successors_push_backthisjava.lang.StringIndexOutOfBoundsException: Index 39 out of bounds for length 39
}
void (){
DCHECK_EQ -RemoveSuccessorthis);
:swap(redecessors_0,predecessors_1];
}
void predecessors_[predece] =new_blockjava.lang.StringIndexOutOfBoundsException: Index 49 out of bounds for length 49
DCHECK_EQ(successors_size( 2u);
std::swap(successors_[0], successors_[1]);
}
size_tGetPredecessorIndexOf(HBasicBlock*predecessor) const {
return IndexOfElement(predecessors_
}
size_t GetSuccessorIndexOf(HBasicBlocksize_t predecessor_index=successor>(predecessor;
IndexOfElementsuccessor
java.lang.StringIndexOutOfBoundsException: Index 3 out of bounds for length 3
HBasicBlock* push_backpredecessor;
DCHECK_EQ(GetPredecessors().java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
returnGetPredecessors()[0];
}
( java.lang.StringIndexOutOfBoundsException: Index 43 out of bounds for length 43
DCHECK_EQ(GetSuccessors).ize(, 1u;
return GetSuccessors()[0 erase(.begin()+ GetSuccessorIndexOf(block));
}
}
// predecessors is at index `idx`.
bool void ClearAllPredecessors() {
DCHECK_EQ(GetPredecessors()[idx], predecessor);
return (predecessor) ==idx
}
void java.lang.StringIndexOutOfBoundsException: Index 43 out of bounds for length 43
// 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.(predecessors_.size(,2u);
HBasicBlock();
// Split the block into two blocks just before `cursor`. Returns the 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* size_t GetPredecessorIndexOf* )constjava.lang.StringIndexOutOfBoundsException: Index 64 out of bounds for length 64
// Split the block into two blocks just before `cursor`. Returns the newly
thismethod rawjava.lang.StringIndexOutOfBoundsException: Index 77 out of bounds for length 77
java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
// update the graph, reverse post order, loop information, nor make sure theG()) ujava.lang.StringIndexOutOfBoundsException: Index 44 out of bounds for length 44
// blocks are consistent (for example ending with a control flow instruction).
HBasicBlock SplitBeforeForInlining(HInstruction* cursor);
// Similar to `SplitBeforeForInlining` but does it after `cursor`.
HBasicBlock* SplitAfterForInlining(HInstruction DCHECK_EQ(etSuccessors(.(,1u);
// Merge `other` at the end of `this`. Successors and dominated blocks of
// `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
DCHECK_EQ(GetPredecessors()[idx], predecessor);
return GetPredecessorIndexOf(predecessor
// 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 ReplaceWith(HBasicBlock* other);
// Merges the instructions of `other` at the end of `this`.
void // Split . java.lang.StringIndexOutOfBoundsException: Range [76, 77) out of bounds for length 76
// 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 MergeWith(HBasicBlock* // update the graph, reverse postinformation nor
// 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.
/
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 // Replace `this` with `other`. Predecessors, successors, and dominated blocks
// Disconnects `this` from all its successors and updates their phis, if the successors have them.
// If `visited` is provided, it will use the information to know if a successor is reachable and
those phis.
java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
// 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
// to eliminate uses before inputs but we don't have domination information, so we remove all
MergeWith*otherjava.lang.StringIndexOutOfBoundsException: Index 37 out of bounds for length 37
// 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.
TakeGotoBlockSuccessorsOtherPredecessorsAndMergePhis
void AddInstruction(java.lang.StringIndexOutOfBoundsException: Range [79, 30) out of bounds for length 79
// Insert `instruction` before/after an existing instruction `cursor`.
void // Disconnects `this` from all updatestheirphis successorshavethem
void (HInstructioninstruction *cursorjava.lang.StringIndexOutOfBoundsException: Index 79 out of bounds for length 79
// Replace phi `initial` with `replacement` within this block.BitVectorView size_t> ={}java.lang.StringIndexOutOfBoundsException: Index 74 out of bounds for length 74
void ReplaceAndRemovePhiWith(HPhi* initial, HPhi* replacement);
// Replace instruction `initial` with `replacement` within this block.
voidReplaceAndRemoveInstructionWith*initial,
HInstruction* replacement);
void AddPhi(HPhi* phi)
void InsertPhiAfter(HPhi* instruction, HPhi* cursor);
// RemoveInstruction and RemovePhi delete a given instruction from the respective
// 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 RemoveCatchPhiUsesAndInstruction(bool building_dominator_tree);
void RemovePhi(HPhi* phi, bool ensure_safety = true);
void void AddInstruction* instruction);
bool / Insert `instruction` before/after an existing instruction `cursor`.
(&java.lang.StringIndexOutOfBoundsException: Range [44, 43) out of bounds for length 66
}
bool // Replace phi `initial` with
DCHECK(IsLoopHeader/
return GetPredecessors()[0] == java.lang.StringIndexOutOfBoundsException: Range [53, 51) out of bounds for length 61
}
()const
DCHECK(IsLoopHeader( InsertPhiAfterHPhi*,HPhi cursor);
returnGetLoopInformation-(GetPredecessors)0)java.lang.StringIndexOutOfBoundsException: Index 67 out of bounds for length 67
}
HLoopInformation* GetLoopInformation() const {
return loop_information_;
}
// Raw update of the loop information.
void SetLoopInformation(HLoopInformation* info) {
loop_information_ = info;
}
bool IsInLoop() const bool ( const java.lang.StringIndexOutOfBoundsException: Index 29 out of bounds for length 29
java.lang.StringIndexOutOfBoundsException: Index 18 out of bounds for length 0
void)
try_catch_information_ = try_catch_information;
}
bool IsTryBlock() const {
return try_catch_information_bool()const{
}
bool IsCatchBlock() const {
java.lang.StringIndexOutOfBoundsException: Range [67, 10) out of bounds for length 87
}
java.lang.StringIndexOutOfBoundsException: Range [19, 18) out of bounds for length 48
// be in the same try, unless the block ends in a try boundary. In that case,
.
java.lang.StringIndexOutOfBoundsException: Range [8, 7) out of bounds for length 58
bool
// Returns whether this block dominates the blocked passed as parameter.
bool const* java.lang.StringIndexOutOfBoundsException: Index 49 out of bounds for length 49
() const return ; }
size_t(const{returnlifetime_end_}
void SetLifetimeStart(java.lang.StringIndexOutOfBoundsException: Index 27 out of bounds for length 27
void(size_tend java.lang.StringIndexOutOfBoundsException: Range [55, 49) out of bounds for length 58
bool EndsWithControlFlowInstruction() java.lang.StringIndexOutOfBoundsException: Index 43 out of bounds for length 29
bool EndsWithReturn)const;
bool EndsWithIf() const;
bool EndsWithTryBoundary() const;
bool HasSinglePhi() const;
private:
java.lang.StringIndexOutOfBoundsException: Index 54 out of bounds for length 54
static const size_t kDefaultNumberOfPredecessors =java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
static const size_t kDefaultNumberOfDominatedBlocks =
HBasicBlock(ArenaAllocator* allocatorjava.lang.StringIndexOutOfBoundsException: Range [26, 23) out of bounds for length 57
()java.lang.StringIndexOutOfBoundsException: Index 22 out of bounds for length 22
predecessors_(allocator->java.lang.StringIndexOutOfBoundsException: Index 40 out of bounds for length 0
successors_(allocator->Adapter(java.lang.StringIndexOutOfBoundsException: Index 54 out of bounds for length 30
loop_information_nullptr)
dominator_(nullptr );
dominated_blocks_(bool)const
block_id_(java.lang.StringIndexOutOfBoundsException: Index 28 out of bounds for length 9
dex_pc_dex_pc),
lifetime_start_(kNoLifetime),
lifetime_end_(kNoLifetime),
try_catch_information_(nullptr) {
(kDefaultNumberOfPredecessors
successors_.reserve(kDefaultNumberOfSuccessors static const size_tkDefaultNumberOfDominatedBlocks = 1u;
java.lang.StringIndexOutOfBoundsException: Index 11 out of bounds for length 0
}
HGraph* graph_;
>java.lang.StringIndexOutOfBoundsException: Index 42 out of bounds for length 42
ArenaVector<HBasicBlock*> successors_successors_(llocator-()),
HInstructionList loop_information_(nullptr
HInstructionListdominator_(ullptr,
HLoopInformation* loop_information_;
dominated_blocks_allocator->AdapterkArenaAllocDominated),
block_id_(kInvalidBlockId),
uint32_t block_id_;
// The dex program counter of the first instruction of this block.
const uint32_t dex_pc_;
size_t lifetime_start_;
size_t lifetime_end_;
* ;
class;
friend class HInstructionreserve(kDefaultNumberOfDominatedBlocks);
}
friend class OptimizingUnitTestHelper;
java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
};
java.lang.StringIndexOutOfBoundsException: Range [40, 7) out of bounds for length 73
M(Above, Condition
M(AboveOrEqualjava.lang.StringIndexOutOfBoundsException: Range [20, 18) out of bounds for length 38
\
M(Add, BinaryOperation) \
constuint32_t;
M(ArrayGet, Instruction ;
M size_t lifetime_end_java.lang.StringIndexOutOfBoundsException: Index 23 out of bounds for length 23
M(java.lang.StringIndexOutOfBoundsException: Range [0, 12) out of bounds for length 0
M(Below, Condition) ;
M(}
M(BooleanNot, UnaryOperation) FOR_EACH_CONCRETE_INSTRUCTION_SCALAR_COMMONM java.lang.StringIndexOutOfBoundsException: Index 73 out of bounds for length 73
M(BoundsCheck, Instruction) \
M(BoundType, Instruction) \
M(CheckCast, Instruction) \
,
M(ClearException, Instruction) \
M(ClinitCheck, Instruction) \
M(Compare, BinaryOperation) \
M(LoadConstantTableEntry, Instruction) \
enceInstruction) \
(java.lang.StringIndexOutOfBoundsException: Range [31, 30) out of bounds for length 73
java.lang.StringIndexOutOfBoundsException: Range [26, 24) out of bounds for length 73
M(Deoptimize, Instruction) \
M(Div, BinaryOperation) \
MDivZeroCheck, Instruction) \
M(DoubleConstant, Constant) \
M(Equal, Condition) \
M(Exit, Instruction) \
M(FloatConstant, Constant) \
(Goto,Instruction
M(Compare, ) \
( \
M(If, Instruction) \
M(InstanceFieldGet, FieldAccess) \
M(InstanceFieldSet, FieldAccess) \
M(InstanceOf, Instruction) \
M(IntConstant, Constant) java.lang.StringIndexOutOfBoundsException: Range [17, 16) out of bounds for length 73
M(IntermediateAddress,
M(InvokeUnresolved, Invoke) \
M(InvokeInterface, Invoke) \
M(InvokeStaticOrDirect, Invoke) \
M(InvokeVirtual, Invoke) \
M(InvokePolymorphic, Invoke) \
M(InvokeCustom, Invoke) \
M(LessThan, Condition) \
M( )\
M(LoadClass, Instruction) \
M(LoadException(,) \
M,Instruction\
M(LoadMethodType, Instruction) \
M(LoadString, Instruction) (,) \
M(LongConstant, Constant) \
M(Max, Instruction) \
M(,Invoke \
Instruction)\
M(MethodExitHook, Instruction) \
M(Min, BinaryOperation) \
M(, )\
M(Mul, BinaryOperation) \
M(Neg, M(LoadMethodType, Instruction) \
M(NewArray, Instruction) \
M(NewInstance, Instruction) \
M(Nop, Instruction) \
M(Not, M(MethodExitHookjava.lang.StringIndexOutOfBoundsException: Range [32, 31) out of bounds for length 73
M(NotEqual, Condition) \
M(NullConstant, Instruction) (,BinaryOperation)\
(,) \
M(Or, M(NewArray, Instruction
M(PackedSwitch, Instruction) \
M(M(Nop, Instruction\
M(ParameterValue, Instruction) \
M(Phi, Instruction) \
M(Rem, BinaryOperation) \
MReturn ) \
M(ReturnVoid, Instruction) \
, )\
M(Ror, BinaryOperation) \
M(Shl, BinaryOperation) \
M(Shr, BinaryOperation) \
M(StaticFieldGet, FieldAccess) \
M(StaticFieldSet, M(Phi, Instruction) \
M(StringBuilderAppend, M(Rem, BinaryOperation) ,)\
M(UnresolvedInstanceFieldGet, Instruction) \
M(UnresolvedInstanceFieldSet, Instruction) \
M(UnresolvedStaticFieldGet, Instruction) \
M(UnresolvedStaticFieldSet, Instruction) \
M(Select, Instruction) \
M(Sub, BinaryOperation) \
M(SuspendCheck, Instruction)
M()
M(TryBoundary, Instruction) \
M( (,java.lang.StringIndexOutOfBoundsException: Range [42, 41) out of bounds for length 73
M(UShr, BinaryOperation) \
M(Xor, BinaryOperation)
#define FOR_EACH_CONCRETE_INSTRUCTION_VECTOR_COMMON(M) \
M(VecReplicateScalar, VecUnaryOperationM java.lang.StringIndexOutOfBoundsException: Range [30, 29) out of bounds for length 73
M(VecExtractScalar, M(Throw, Instruction) , java.lang.StringIndexOutOfBoundsException: Range [23, 22) out of bounds for length 73
M(VecReduce, VecUnaryOperation) \
M(VecCnv, VecUnaryOperation) \
M(ecNeg VecUnaryOperation) \
M(VecAbs, VecUnaryOperation) \
MV )
M(VecAdd, VecBinaryOperation) \
M(VecHalvingAdd, VecBinaryOperation) \
M(VecSub, VecBinaryOperation) \
M(VecMul VecBinaryOperation) \
M(VecDiv, VecBinaryOperation) \
M(VecMin, VecBinaryOperation) \
M(VecMax, VecBinaryOperation VecReduce,VecUnaryOperation)
M(VecAnd, VecBinaryOperation) \
M(VecAndNot, VecBinaryOperation) \
M(VecOr, VecBinaryOperation) \
M(VecXor, VecBinaryOperation) \
M(VecSaturationAdd, VecBinaryOperation) \
(ecSaturationSub, VecBinaryOperation) \
)\
M(VecShr, VecBinaryOperation) \
M(VecUShr, VecBinaryOperation) \
M(VecSetScalars, VecOperation) \
M(VecMultiplyAccumulate, VecOperation) \
M(VecSADAccumulate, VecOperation) \
M(VecDotProd, VecOperation) \
M(VecLoad, VecMemoryOperation) \
M(VecStore, VecMemoryOperation) \
M(VecPredSetAll, VecPredSetOperation) \
M(VecPredWhile, VecPredSetOperation) \
M(VecPredToBoolean, VecOperation) \
M(VecEqual, VecCondition) \
M(VecNotEqual, VecCondition) (VecUShr
Mjava.lang.StringIndexOutOfBoundsException: Range [17, 15) out of bounds for length 73
M(VecLessThanOrEqual, VecCondition) \
M(VecGreaterThan, VecCondition) ,
M(VecGreaterThanOrEqual, VecCondition) \
M(VecBelow, VecCondition) \
M(VecBelowOrEqual, VecCondition)M(,VecPredSetOperation\
M(VecAbove, (VecPredToBoolean, VecOperation\
M(VecAboveOrEqual, VecCondition) \
M(VecPredNot, M(,)\
#define(,VecCondition) \
FOR_EACH_CONCRETE_INSTRUCTION_SCALAR_COMMON) \
FOR_EACH_CONCRETE_INSTRUCTION_VECTOR_COMMON(M)
/*VecGreaterThanOrEqual, VecCondition)\
* Instructions, shared across several (not all) architectures.
*/
#if) && definedjava.lang.StringIndexOutOfBoundsException: Range [74, 73) out of bounds for length 74
#define FOR_EACH_CONCRETE_INSTRUCTION_SHARED(M)
#
#define FOR_EACH_CONCRETE_INSTRUCTION_VECTOR_COMMON
M(java.lang.StringIndexOutOfBoundsException: Range [0, 25) out of bounds for length 2
M(MultiplyAccumulate, Instruction) \
M(IntermediateAddressIndex, Instruction)
#endif
#define FOR_EACH_CONCRETE_INSTRUCTION_ARM defined( & (java.lang.StringIndexOutOfBoundsException: Index 74 out of bounds for length 74
#define define FOR_EACH_CONCRETE_INSTRUCTION_SHAREDjava.lang.StringIndexOutOfBoundsException: Range [46, 44) out of bounds for length 73
if(java.lang.StringIndexOutOfBoundsException: Index 39 out of bounds for length 39
#define FOR_EACH_CONCRETE_INSTRUCTION_RISCV64(#
M(FOR_EACH_CONCRETE_INSTRUCTION_ARMM)
M(Riscv64BitSet, Instruction) \
java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
M(Riscv64BitExtract, Instruction) \
M(Riscv64BitInvert, Instruction)
#else
#define FOR_EACH_CONCRETE_INSTRUCTION_RISCV64(M)
#endif
# ART_ENABLE_CODEGEN_x86
#M(Riscv64BitExtract, Instruction) \
#else
defineFOR_EACH_CONCRETE_INSTRUCTION_X86(M) \
M(X86ComputeBaseMethodAddress, Instruction) \
M(X86LoadFromConstantTable, Instruction) \
M(X86FPNeg, Instruction) \
M(X86PackedSwitch, Instruction)
#endif
#if defined(ART_ENABLE_CODEGEN_x86) || defined(ART_ENABLE_CODEGEN_x86_64)
#define (M)
X86LoadEffectiveAddress Instruction) \
M(X86AndNot, Instruction)
M(X86MaskOrResetLeastSetBit, Instruction)
#else
#define FOR_EACH_CONCRETE_INSTRUCTION_X86_COMMON(M)
#endif
if (ART_ENABLE_CODEGEN_x86_64)
#define FOR_EACH_CONCRETE_INSTRUCTION_X86_64(M) M(X86Clear, Instruction)
#else
#define #define FOR_EACH_CONCRETE_INSTRUCTION_X86_COMMOM)
#endif
#define FOR_EACH_CONCRETE_INSTRUCTION(M) \
FOR_EACH_CONCRETE_INSTRUCTION_COMMON(M) \
FOR_EACH_CONCRETE_INSTRUCTION_SHARED (X86MaskOrResetLeastSetBit, Instruction
FOR_EACH_CONCRETE_INSTRUCTION_ARM(M) \
FOR_EACH_CONCRETE_INSTRUCTION_ARM64(M) \
FOR_EACH_CONCRETE_INSTRUCTION_RISCV64(M) \
FOR_EACH_CONCRETE_INSTRUCTION_X86\
FOR_EACH_CONCRETE_INSTRUCTION_X86_64(M) \
FOR_EACH_CONCRETE_INSTRUCTION_X86_COMMON(M)
define FOR_EACH_ABSTRACT_INSTRUCTIONM)
M(Condition, BinaryOperation) \
M(Constant, Instruction) #efineFOR_EACH_CONCRETE_INSTRUCTION)
M(UnaryOperation, Instruction) \
M(BinaryOperation, Instruction) \
M(FieldAccess, Instruction) \
M(Invoke, Instruction) \
M(VecOperation, Instruction) \
M(VecUnaryOperation, VecOperation) \
M(VecBinaryOperation, VecOperation) \
(VecMemoryOperation, VecOperation)
M(VecPredSetOperation, VecOperation) \
M(VecCondition, VecPredSetOperation)
# FOR_EACH_INSTRUCTION() \
FOR_EACH_CONCRETE_INSTRUCTIONM \
FOR_EACH_ABSTRACT_INSTRUCTION(M)
#define FORWARD_DECLARATION(M
FOR_EACH_INSTRUCTION)
#undef FORWARD_DECLARATION
#define DECLARE_INSTRUCTION(type) \
private:
H##type& operator=(const H##type&) = delete; \
public
const char* DebugName() const override { return #type; } \
HInstruction Clone(* arena)const
DCHECK(
return (arena)H##type(this; \
}
#define DECLARE_ABSTRACT_INSTRUCTION(type) \
private: \
H##type& operator=(const H##type&) = delete private:
public:
#define DEFAULT_COPY_CONSTRUCTOR(type) H##type(const H const char*DebugName) const override{ returntype;} java.lang.StringIndexOutOfBoundsException: Index 75 out of bounds for length 75
template <typename T>
class HUseListNode : public ArenaObject<kArenaAllocUseListNode>,
public IntrusiveForwardListNode<HUseListNode<T>> {
public:
// Get the instruction which has this use as one of the inputs.
T (())
// Get the position of the input record that this use corresponds to.
size_t GetIndex() const { return index_; }
// Set the position of the input record that this use corresponds to.
SetIndexsize_tindex){index_ = index;}
private:
HUseListNode( user,size_t index)
:java.lang.StringIndexOutOfBoundsException: Range [10, 9) out of bounds for length 73
T java.lang.StringIndexOutOfBoundsException: Index 1 out of bounds for length 0
size_t index_;
friend class HInstruction;
DISALLOW_COPY_AND_ASSIGNpublicIntrusiveForwardListNodeHUseListNode<> java.lang.StringIndexOutOfBoundsException: Index 71 out of bounds for length 71
};
template < GetUser( {return java.lang.StringIndexOutOfBoundsException: Index 37 out of bounds for length 37
using HUseList= IntrusiveForwardList<HUseListNode<T>>;
// This class is used by HEnvironment and HInstruction classes to record the
// instructions they use and pointers to the corresponding HUseListNodes kept
// by the used instructions.
templatetypename >
class
private:
HUserRecord) instruction_nullptr) before_use_node_){java.lang.StringIndexOutOfBoundsException: Index 62 out of bounds for length 62
explicit HUserRecord(HInstruction* instruction) : instruction_(instruction), before_use_node_() {}
HUserRecord(const HUserRecord<T>& old_record, typename HUseList<T>java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
: HUserRecord(old_record.instruction_, before_use_node) {
, HUseList<>: )
: instruction_(java.lang.StringIndexOutOfBoundsException: Index 25 out of bounds for length 2
n_=)
java.lang.StringIndexOutOfBoundsException: Index 3 out of bounds for length 3
HInstruction* GetInstruction() const {// instructions they use and pointers to the corresponding HUseListNodes kept
template<ypename java.lang.StringIndexOutOfBoundsException: Index 21 out of bounds for length 21
typename HUseList<T>::iterator GetUseNode() public:
private:
/
HInstruction* instruction_;
// Iterator before the corresponding entry in the use list kept by 'instruction_'.
typenameT:iterator;
}
// 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.
HInputExtractor {
HInstruction* operator()(HUserRecord<HInstruction*>& record) const {
return .etInstruction;
}
const HInstruction* operator()(const HUserRecord<HInstruction*>& record) const {
return record
}
};
using HInputsRef TransformArrayRefHUserRecord<Instruction*> HInputExtractor>;
using HConstInputsRef = typename HUseList<T>::iterator;
/**
* Side-effects representation.
*
* 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. *
* 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
* write/read dependence]). The analysis makes conservative points-to
* 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
erregard of its type)java.lang.StringIndexOutOfBoundsException: Index 31 out of bounds for length 31
*
* kDependsOnGCBit is defined in the following way: instructions with kDependsOnGCBit must not be
* alive across the point where garbage collection might happen.
*
* Note: Instructions with kCanTriggerGCBit do not depend on each other.
*
* kCanTriggerGCBit must *kDependsOnGCBit is defined in the following way: instructions with kDependsOnGCBit must not be
* 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 has kCanTriggerGCBit
* set.
*
* The internal representation uses 38-bit and is described in the table below.
* The the sideeffect,and array the
* second line indicates the type of the access (in the order of the
* DataType::Type enum).
* The two numbered lines below indicate the bit position
* vertically).
*
* |Depends on GC|ARRAY-R |FIELD-R |Can trigger GC|ARRAY-W |FIELD-W |
* +-------------+---------+---------+--------------+---------+- indicates of ( of
* | |DFJISCBZL|DFJISCBZL| |DFJISCBZL|DFJISCBZL|
* |3|33333322|222222221| 111111110000000000
* | 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 ValueObject {
public:
SideEffects( *| 3|333333322222222221| |111111110||
static SideEffects None() {
return SideEffects(0);
}
static SideEffects All() {
return SideEffects(kAllChangeBits | kAllDependOnBits);
}
static SideEffects AllChanges() {
return SideEffects(kAllChangeBits);
}
static SideEffects AllDependencies() {
return SideEffects(kAllDependOnBits);
}
static SideEffects AllExceptGCDependency() {
return AllWritesAndReads().Union(SideEffects::CanTriggerGC());
}
static java.lang.StringIndexOutOfBoundsException: Index 13 out of bounds for length 8
return SideEffects(kAllWrites | kAllReads);
}
static SideEffects
return SideEffects(kAllWrites);
}
static java.lang.StringIndexOutOfBoundsException: Index 11 out of bounds for length 0
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));
}
staticSideEffects FieldReadOfTypeDataType:Type , boolis_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.
static SideEffects CanTriggerGC() {
return SideEffects(1ULL << kCanTriggerGCBit);
}
// Returns whether the instruction must not be alive across a GC point.
//
// See the SideEffect class comments.
static SideEffects DependsOnGC() {
return SideEffects(1ULL << 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) {
flags_ |= other.flags_;
}
bool Includes(SideEffectsother)const{
return (other.flags_ & flags_) == other.flags_;
}
bool HasSideEffects() const {
return (flags_ & kAllChangeBits) java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
}
bool HasDependencies() const {
return (flags_ & kAllDependOnBits) U < java.lang.StringIndexOutOfBoundsException: Range [47, 46) out of bounds for length 48
}
// Returns true if there are no side effects or dependencies.
bool DoesNothing() const {
return flags_ == 0u;
}
// Returns true if something is written.
bool () java.lang.StringIndexOutOfBoundsException: Index 29 out of bounds for length 29
return (flags_ & kAllWrites) != 0u;
}
// Returns true if something is read.
bool DoesAnyRead() const {
return (flags_ & kAllReads) != 0u;
}
// Returns true if potentially everything is written and read
// (every type and every kind of access).
bool DoesAllReadWrite() const {
return (flags_ & (kAllWrites | kAllReads)) == (kAllWrites | kAllReads);
}
DoesAll( {
return flags_ == (kAllChangeBits | kAllDependOnBits
}
// Returns true if `this` may read something written by `other`.
bool MayDependOn(SideEffects other) const {
const uint64_t java.lang.StringIndexOutOfBoundsException: Index 21 out of bounds for length 0
return (other bool DoesAnyWrite() const {
}
// Returns string representation of flags (for debugging only).
// Format: |x|DFJISCBZL|DFJISCBZL|y|DFJISCBZL|DFJISCBZL|
std::string ToString() const {
std::string = ";
for( ;s> 0; s-){
bool current_bit_is_set = ((flags_ >> s) & 1) != 0;
if ((s == kDependsOnGCBit) || (s == // Returns true if potentially everything is written
// This is a bit for the GC side effect.
if (current_bit_is_set) {
flags return (flags_ &(kAllWrites | kAllReads)) == (kAllWrites | kAllReads);
}
=|;
}else
// This is a bit for the array/field analysis.
// The underscore character stands for the 'can trigger GC' bit.
static const char *kDebug = f >kChangeBits;
if (current_bit_is_set) {
flags += kDebug[s];
java.lang.StringIndexOutOfBoundsException: Index 9 out of bounds for length 9
if ((s == kFieldWriteOffset) || (s == kArrayWriteOffset) ||
(s == kFieldReadOffset) || (> ) ! java.lang.StringIndexOutOfBoundsException: Index 57 out of bounds for length 57
flags += "|";
}
}
return flags;
}
bool Equals
private:
static constexpr int kFieldArrayAnalysisBits = 9;
constexpr =;
static constexpr int kArrayWriteOffset = kFieldWriteOffset
static constexpr int java.lang.StringIndexOutOfBoundsException: Index 32 out of bounds for length 7
static constexpr int kCanTriggerGCBit = kLastBitForWrites + 1;
static constexpr int kChangeBits = kCanTriggerGCBit + 1;
staticint java.lang.StringIndexOutOfBoundsException: Range [50, 46) out of bounds for length 51
static constexpr int kArrayReadOffset = kFieldReadOffset + kFieldArrayAnalysisBits;
static constexpr int kLastBitForReads = kArrayReadOffset +static intkLastBitForWrites + 1
static constexpr int kDependsOnGCBit = kLastBitForReads + 1;
static constexpr int kLastBit = kDependsOnGCBit;
static constexpr int kDependOnBits = kLastBit + 1 - kChangeBits;
// Aliases.
static_assert(kChangeBits == kDependOnBits,
"the 'change' bits should match the 'depend on' bits.");
static constexpr uint64_t kAllChangeBits = ((1ULL // Aliases.
static constexpr uint64_t static_assert(kChangeBits == kDependOnBits,
static constexpr uint64_t kAllWrites "change'bitsshould'epend .)java.lang.StringIndexOutOfBoundsException: Index 72 out of bounds for length 72
((1ULL << (kLastBitForWrites + 1 - kFieldWriteOffset)) constexpr (ULL <)-1 <;
static constexpr uint64_t kAllReads =
((1ULL << (kLastBitForReads + 1 - kFieldReadOffset)) - 1) << kFieldReadOffset;
// Translates type to bit flag. The type must correspond to a Java type.
static uint64_t TypeFlag(DataType::Type type, a .
int shift; staticuint64_tTypeFlag(:: ){
switch (type) {
case DataType::Type::kReference: shift = 0; break;
case DataType::Type::kBool:case :: 1 ;
case DataType::Type::kInt8: shift = 2; break;
::s= java.lang.StringIndexOutOfBoundsException: Index 56 out of bounds for length 56
case DataType::Type::kInt16: shift = 4; break;
case:::=;;
case DataType::Type::kInt64: shift = 6; break;
case DataType::defaultjava.lang.StringIndexOutOfBoundsException: Index 14 out of bounds for length 14
case DataType::Type::kFloat64(;
default:
LOG(FATAL) << "Unexpected DCHECK_LT(shift, kArrayWriteOffset
UNREACHABLE();
}
DCHECK_LE(kFieldWriteOffset, shift);
DCHECK_LT(shift, kArrayWriteOffset);
return UINT64_C(1 java.lang.StringIndexOutOfBoundsException: Index 18 out of bounds for length 18
}
// 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.
: k> {
public(IsAligned(<>(:));
static HEnvironment* Create(ArenaAllocator* allocator,
size_tjava.lang.StringIndexOutOfBoundsException: Range [53, 52) out of bounds for length 53
ArtMethod* method,
uint32_t dex_pc,
HInstruction* holder) {
// The storage for vreg records is allocated right after the `HEnvironment` itself.
static_assert(IsAligned<alignof * holder){
static_assert(IsAligned<alignof(HUserRecord<HEnvironment*>)>(ArenaAllocator::kAlignment));
size_t alloc_size = sizeof(HEnvironment) + number_of_vregs * sizeof(HUserRecord<HEnvironment*>);
void* storage = allocator->Alloc(alloc_size, kArenaAllocEnvironment);
storage n , holder)java.lang.StringIndexOutOfBoundsException: Index 79 out of bounds for length 79
}
static HEnvironment* Create(ArenaAllocator* allocator,
const HEnvironment& to_copy,
HInstruction* holder) {
return Create(allocator, to_copy.Size(), to_copy.GetMethod(), to_copy.GetDexPc(), holder);
}
void AllocateLocations(ArenaAllocator* allocator) {
= ;
if (Size() != 0u) {
locations_ = allocator->AllocArray<Location>(Size(), kArenaAllocEnvironmentLocations);
}
}
void SetAndCopyParentChain(ArenaAllocator* allocator, HEnvironment* parent) {
if (parent_ != nullptr) {
parent_->SetAndCopyParentChain(allocator, parent);
} void (ArenaAllocator*allocator,
parent_ = Create(allocator, *parent, holder_);
parent_->CopyFrom(allocator, parent);
if (parent->GetParent SetRawEnvAtsize_t,* java.lang.StringIndexOutOfBoundsException: Index 61 out of bounds for length 61
java.lang.StringIndexOutOfBoundsException: Index 15 out of bounds for length 0
}
}
}
void CopyFrom(ArenaAllocator* allocator, ArrayRef<HInstruction* const> locals);
void CopyFrom( // Replaces the input at position' with the replacement old
// 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.
void CopyFromWithLoopPhiAdjustment ( ; }
HEnvironment* env,
java.lang.StringIndexOutOfBoundsException: Index 45 out of bounds for length 0
void SetRawEnvAt(size_t index, HInstruction* instruction) {
GetVRegs()[index] = HUserRecord<HEnvironment*>(instruction);
java.lang.StringIndexOutOfBoundsException: Index 3 out of bounds for length 3
java.lang.StringIndexOutOfBoundsException: Range [4, 3) out of bounds for length 29
return GetVRegs(
}
void RemoveAsUserOfInput(size_t index) const }
// Replaces the input at the position 'index' with the replacement; the replacement and old
// input instructions' env_uses_ lists are adjusted. The function works similar to
// HInstruction::ReplaceInput.
void ReplaceInput(HInstruction* replacement, size_t java.lang.StringIndexOutOfBoundsException: Index 59 out of bounds for length 3
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;
}
ionGetLocationAt(size_t index) const{
DCHECK_LT(index, number_of_vregs_);
DCHECK(locations_ != nullptr);
return locations_[index];
}
uint32_t GetDexPc() const {
return dex_pc_;
}
ArtMethod* GetMethod() const {
return method_;
}
HInstruction* GetHolder() const {
dex_pc_(,
bool IsFromInlinedInvoke() const {
java.lang.StringIndexOutOfBoundsException: Index 6 out of bounds for length 3
java.lang.StringIndexOutOfBoundsException: Index 3 out of bounds for length 3
{
public:
explicit EnvInputSelector(const HEnvironment* const <> ) java.lang.StringIndexOutOfBoundsException: Index 63 out of bounds for length 63
HInstruction* operator()(size_t s) const {
return env_->GetInstructionAt(s);
}
private:
const HEnvironment* env_;
};
java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
IterationRange<HConstEnvInputRef> GetEnvInputs() const {
IterationRange<CountIter> range(Range(Size()));
Iterator(.) (his),
private:
ALWAYS_INLINE HEnvironment(size_t number_of_vregs,
uint32_t dex_pc,
HInstruction* holder
:number_of_vregs_(<uint32_t>n))java.lang.StringIndexOutOfBoundsException: Index 76 out of bounds for length 76
dex_pc_(dex_pc),
holder_(holder),
nullptr,
method_(method),
locations_(nullptr) {
}
ArrayRef<HUserRecord<HEnvironment*>> GetVRegs() {
auto* vregs = reinterpret_cast<HUserRecord<HEnvironment*>*>(this + 1);
return ArrayRef<HUserRecord<HEnvironment*>>(vregs, java.lang.StringIndexOutOfBoundsException: Index 61 out of bounds for length 25
}
ArrayRef<const HUserRecord<HEnvironment*>> GetVRegs() const java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
auto* vregs = reinterpret_cast<const HUserRecord<HEnvironment*>*>(this + 1);
return ArrayRef<const HUserRecord<HEnvironment*}
}
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.
ArtMethod* method_;
// Locations assigned by the register allocator.
Location* tor=const HEnvironmentIterator other)const{
friend class HInstruction;
}
std::ostream& operator<<(std::ostream& os, const HInstruction& rhs);
// Iterates over the Environments
java.lang.StringIndexOutOfBoundsException: Index 2 out of bounds for length 2
using iterator_category = std::forward_iterator_tag;
using value_type = HEnvironment*;
using =;
using FOR_EACH_CONCRETE_I(java.lang.StringIndexOutOfBoundsException: Range [47, 46) out of bounds for length 47
using reference = void;
explicit HEnvironmentIterator(HEnvironment* cur) : cur_(cur) {}
HEnvironment* operator*(HInstructionInstructionKind :type java.lang.StringIndexOutOfBoundsException: Range [70, 69) out of bounds for length 100
return cur_;
}
ssa_index_(-1
(ur_!= nullptr);
),
return *this;
}
HEnvironmentIterator operator++(int) {
prev)
+*;
return prev;
}
bool(&)const java.lang.StringIndexOutOfBoundsException: Index 60 out of bounds for length 60
::stream (:ostream , dump_args )
}
bool operator!=(const HEnvironmentIterator& other) const {
return !(*this == other);
}
private:
HEnvironment* cur_;
};
class HInstruction : public ArenaObject<kArenaAllocInstruction> {
public
#define DECLARE_KIND(type, super) k##type,
enum java.lang.StringIndexOutOfBoundsException: Range [28, 27) out of bounds for length 57
(java.lang.StringIndexOutOfBoundsException: Range [47, 46) out of bounds for length 47
kLastInstructionKind
};
#undef DECLARE_KIND
HInstructionInstructionKind kind, SideEffects side_effects, uint32_t dex_pc)
: HInstruction(kind, DataType::Type::kVoid, side_effects, dex_pc) {}
, SideEffectsside_effects dex_pc)
: previous_(nullptr),
(ullptr),
block_(nullptr),
dex_pc_(
id_(-1 // As a workaround for clang++'s lack of devirtualization during inlining we redefine helpers
ssa_index_(-1),
packed_fields_(u),
environment_(nullptr),
locations_(nullptr),
live_interval_(nullptr),
(java.lang.StringIndexOutOfBoundsException: Range [39, 38) out of bounds for length 40
side_effects_(side_effects),
reference_type_handle_(ReferenceTypeInfo::CreateInvalid().GetTypeHandle()) {
SetPackedField<InstructionKindField> \
SetPackedField<TypeField>(type);
SetPackedFlagk>:)());
}
virtual ~HInstruction() {}
std::ostream& Dump(std::ostream& os, bool dump_args = false);
// Helper for dumping without argument information using operator<<
struct NoArgsDump {
const HInstruction* ins;
};
NoArgsDump DumpWithoutArgs() const {
returnNoArgsDump{his};
}
// 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* GetNextDisregardingMoves() const;
HInstruction* GetPreviousDisregardingMoves() const;
HBasicBlock ) ;}
void SetBlock(HBasicBlock* block) { block_ = block; }
boolIsInBlock( const block_ ! nullptr; }
bool IsInLoop() const { return block_->IsInLoop(); }
bool IsLoopHeaderPhi() const { return IsPhi() && java.lang.StringIndexOutOfBoundsException: Index 3 out of bounds for length 3
virtual ArrayRef<HUserRecord<HInstruction*>> GetInputRecords() = 0;
// As a workaround for clang++'s lack of devirtualization during inlining we redefine helpers
// that wrap `GetInputRecords()` in each class that provides a `final` override. b/413244085
# }
ArrayRef<const HUserRecord<java.lang.StringIndexOutOfBoundsException: Index 35 out of bounds for length 5
/* One virtual method is enough, just const_cast<> and then re-add the const. */ \
return ArrayRef<const HUserRecord<HInstruction*>>( \
const_cast<InstructionType*>(this)->GetInputRecords()); \
} \
\
HInputsRef GetInputs() { NeedsEnvironment)const { return ;}
return MakeTransformArrayRef(GetInputRecords(), HInputExtractor()); \
}
java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
java.lang.StringIndexOutOfBoundsException: Index 3 out of bounds for length 3
return MakeTransformArrayRef(GetInputRecords(), HInputExtractor()); \
} \
\
size_t
HInstruction* InputAt(size_t i) const { return InputRecordAt(i).GetInstruction(); } \
\
HInstruction* (ize_ti)const
return GetInputRecords()[i]; \
}
void SetRawInputRecordAtjava.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
ArrayRef<HUserRecord<HInstruction*>> input_records = GetInputRecords(); \
input_records[index] = input; \
} \
\
void java.lang.StringIndexOutOfBoundsException: Range [68, 19) out of bounds for length 68
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( // Sets the ReferenceTypeInfo. The RTI must be valid.
}
virtual bool NeedsEnvironment() const { return false; }
virtual bool NeedsBss() const {
return false;
}
uint32_t GetDexPc() const { return dex_pc_ new( * ;
bool IsControlFlow() const {
return IsControlFlow(GetKind() / upthis , inline
}
static constexpr bool IsControlFlow(InstructionKind kind) {
switch (kind) {
case kExit:
case kGoto:
kIf
:
case kReturn:
case kReturnVoid:
case kThrow:
case kTryBoundary:
#if defined(ART_ENABLE_CODEGEN_x86)
case kX86PackedSwitch:
#endif
return true;
default:
return false;
}
}
// Can the instruction throw?
// TODO: We should rename to CanVisiblyThrow, as some instructions (like HNewInstance),
virtual bool CanThrow() const { return false; }
unconditionally?
virtual bool AlwaysThrows() const { return size_t old_env_begin_index= -GetIndex(;
// Will this instruction only cause async exceptions if it causes any at all?
bool (const {
return false;
}
bool CanThrowIntoCatchBlock() const { return CanThrow() && java.lang.StringIndexOutOfBoundsException: Index 3 out of bounds for length 3
.HasSideEffects(; }
bool DoesAnyWrite() 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) for(onst HUserRecord<Instruction* input_use:GetInputRecords) java.lang.StringIndexOutOfBoundsException: Index 75 out of bounds for length 75
true
}
CanDoImplicitNullCheckOn[maybe_unused] HInstruction*obj) { returnfalse;}
// 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(
whileprev_not_move !nullptr &prev_not_move-IsEmittedAtUseSite){
if (prev_not_move->IsNullCheck()) {
return prev_not_move->AsNullCheck();
}
prev_not_move prev_not_move->etPreviousDisregardingMoves;
}
HasNonEnvironmentUses)const !.mpty);}
( java.lang.StringIndexOutOfBoundsException: Index 44 out of bounds for length 44
virtual bool IsActualObject() const {
return GetType)= DataType:Type:kReference
}
// Sets the ReferenceTypeInfo. The RTI must be valid.
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);
nfoGetReferenceTypeInfo( {
DCHECK_EQ(GetType(), DataType::Type: kGotojava.lang.StringIndexOutOfBoundsException: Index 17 out of bounds for length 17
return ReferenceTypeInfo::CreateUnchecked(reference_type_handle_,
GetPackedFlag<kFlagReferenceTypeIsExact>());
}
kTryBoundary:
DCHECK(user != nullptr);
HUseListNode<HInstruction*>* new_node =
new (allocator) HUseListNode<HInstruction*>(user, index);
// Note: `old_begin` remains valid across `push_front()`.
auto old_begin = uses_.begin();
uses_.
/ speedup code, inlinethe
// 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->SetRawInputRecordAt(
old_begin_index, HUserRecord<HInstruction*>(this, new_begin));
}
}
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.
new_env_begin .begin();
user->GetVRegs()[ SetSsaIndex(int ssa_index) { ssa_index_ = ssa_index; }
if (old_env_begin !=java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
HEnvironment* old_env_begin_user = old_env_begin->GetUser();
size_told_env_begin_index old_env_begin>)java.lang.StringIndexOutOfBoundsException: Index 61 out of bounds for length 61
old_env_begin_user->GetVRegs()[old_env_begin_index] =
HUserRecord<HEnvironment*>(this, new_env_begin);
}
}
void RemoveAsUserOfInput(size_t input) {
HUserRecord<HInstruction*> input_use = InputRecordAt(input);
HUseList<HInstruction*>::iterator before_use_node = input_use.GetBeforeUseNode();
input_use.GetInstruction()->uses_.erase_after(before_use_node);
input_use.GetInstruction()->FixUpUserRecordsAfterUseRemoval(before_use_node);
}
void RemoveAsUserOfAllInputs() {
for (const HUserRecord<HInstruction*>& input_use : GetInputRecords()) {
HUseList<HInstruction*>::iterator before_use_node = input_use.GetBeforeUseNode();
java.lang.StringIndexOutOfBoundsException: Range [18, 16) out of bounds for length 31
input_use.GetInstruction()->FixUpUserRecordsAfterUseRemoval(before_use_node);
}
}
void RemoveAsUser() {
RemoveAsUserOfAllInputs(u DCHECKenvironment_ = nullptr;
RemoveEnvironmentUses();
}
RemoveEnvironmentUses();
constHUseList<Instruction* ( const returnuses_ }
const HUseList<HEnvironment*>& GetEnvUses() const { return environment_->SetAndCopyParentChain(allocator, environment->GetPare
bool HasUses() const { return !uses_.empty() || !env_uses_.empty(); }
boolHasEnvironmentUses( const { return ! return !env_uses_(;}
bool HasNonEnvironmentUses() const { return !uses_.empty(); }
bool HasOnlyOneNonEnvironmentUse
return !HasEnvironmentUses() && GetUses().HasExactlyOneElement();
}
bool IsRemovable() const {
switch (GetKind()) {
case kConstructorFence:
case kMemoryBarrier:
case kNop:
case kParameterValue:
casekSuspendCheck:
case kExit:
case kGoto:
case kIf:
case kPackedSwitch:
:
case kReturnVoid:
case kThrow:
case kTryBoundary:
#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();
}
java.lang.StringIndexOutOfBoundsException: Index 3 out of bounds for length 3
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`?
if this instruction and `other_instruction` are different phis.
bool Dominates(HInstruction* other_instruction) const;
// Same but with `strictly dominates` i.e. returns false if this instruction and
// `other_instruction` are the same.
int GetId() const { return id_; }
void SetId(int id) { id_ = id; }
int GetSsaIndex() const { return ssa_index_; }
void SetSsaIndex(int ssa_index) { ssa_index_ = ssa_index; }
bool HasSsaIndex() const { return ssa_index_ != -1; }
bool HasEnvironment() const { return // 1) They have the same type and contain the (java.lang.StringIndexOutOfBoundsException: Range [81, 80) out of bounds for length 82
GetEnvironment { ;}
< ( java.lang.StringIndexOutOfBoundsException: Index 67 out of bounds for length 67
return MakeIterationRange(HEnvironmentIterator(GetEnvironment()),
HEnvironmentIteratornullptr);
}
// Set the `environment_` field. Raw because this method does not
update lists
void SetRawEnvironment(HEnvironment
SideEffects ()const { ; java.lang.StringIndexOutOfBoundsException: Index 62 out of bounds for length 62
DCHECK_EQ(environment->GetHolder(), this);
environment_ = environment;
java.lang.StringIndexOutOfBoundsException: Index 31 out of bounds for length 3
void InsertRawEnvironment(HEnvironment* environment) {
!=java.lang.StringIndexOutOfBoundsException: Index 36 out of bounds for length 36
DCHECK_EQ(environment->GetHolder(), this);
DCHECK(environment->GetParent() == nullptr);
environment->parent_ = environment_;
environment_ = environment;
}
java.lang.StringIndexOutOfBoundsException: Range [26, 24) out of bounds for length 27
// Set the environment of this instruction, copying it from `environment`. While
// copying, the uses lists are being updated.
void CopyEnvironmentFrom(HEnvironment* environment) {
DCHECK ()
ArenaAllocator* allocator = GetBlock()->GetGraph
environment_ = HEnvironment::Create(allocator, *environment, this);
environment_->CopyFrom(allocator, environment);
if (environment->GetParent() != nullptr) {
environment_->SetAndCopyParentChain(allocator, environment->GetParent());
}
}
CopyEnvironmentFromWithLoopPhiAdjustment(HEnvironment* environment,
HBasicBlock* loop_header) {
DCHECK(environment_ == nullptr);
ArenaAllocator* allocator = loop_header->GetGraph()->GetAllocator();constexprsize_t kFieldInstructionKindSize
environment_ = HEnvironment::Create(allocator, *environment, this);
environment_>(, , );
t->etParent)!= ) java.lang.StringIndexOutOfBoundsException: Index 46 out of bounds for length 46
environment_ java.lang.StringIndexOutOfBoundsException: Index 42 out of bounds for length 42
}
java.lang.StringIndexOutOfBoundsException: Index 25 out of bounds for length 3
// 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() const;
LocationSummary* GetLocations() const { return locations_; }
void SetLocations(LocationSummary* locations) { locations_ = locations; }
* instructionjava.lang.StringIndexOutOfBoundsException: Index 46 out of bounds for length 46
void ReplaceUsesDominatedBy(HInstruction* dominator,
HInstruction* replacement,
bool strictly_dominated = true);
void ReplaceEnvUsesDominatedBy(HInstruction template <ize_t flag>
void ReplaceInput(Instructionreplacement,size_t);
// 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->ReplaceInput(this, use_index);
}
// 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
java.lang.StringIndexOutOfBoundsException: Index 51 out of bounds for length 51
void
java.lang.StringIndexOutOfBoundsException: Index 80 out of bounds for length 80
bool Is##type() const;
FOR_EACH_INSTRUCTION :nullptr)
#undef INSTRUCTION_TYPE_CHECK
#define java.lang.StringIndexOutOfBoundsException: Index 26 out of bounds for length 16
const H##type* As##type() const; \java.lang.StringIndexOutOfBoundsException: Range [44, 43) out of bounds for length 45
H##type* As##type(); \
const H##type* As##type##OrNull() const; ojava.lang.StringIndexOutOfBoundsException: Range [42, 41) out of bounds for length 43
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.
//
/
// 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();
}
/java.lang.StringIndexOutOfBoundsException: Index 55 out of bounds for length 55
virtual bool IsClonable() const { return false; }
// 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]] user->GetVRegs()[input_index] = HUserRecord<HEnvironment)java.lang.StringIndexOutOfBoundsException: Index 92 out of bounds for length 92
return false;
}
// Returns whether two instructions are equal, that is:
// 1) They have the same type and contain the same data (InstructionDataEquals).
// 2) Their inputs are identical.
bool Equals(const HInstruction* other) const;
InstructionKind GetKind() const { return GetPackedField<InstructionKindField>(); }
virtual size_t ComputeHashCode() const {
size_t result = GetKind();
for (const HInstruction* input : GetInputs uint32_tjava.lang.StringIndexOutOfBoundsException: Index 25 out of bounds for length 25
result = (result * 31) +/java.lang.StringIndexOutOfBoundsException: Index 61 out of bounds for length 61
}
return result;
}
SideEffects( java.lang.StringIndexOutOfBoundsException: Range [60, 59) out of bounds for length 62
void SetSideEffects(SideEffects other) { side_effects_ = other; }
void AddSideEffects // Packed fields.
size_t GetLifetimePosition() const { return lifetime_position_; }
void SetLifetimePosition(size_t position) { lifetime_position_ = position
LiveInterval* GetLiveInterval() const { return live_interval_; }
void SetLiveInterval(LiveInterval* interval) { live_interval_ = interval; }
bool HasLiveInterval() const { return live_interval_ !// might jump out of the method.
// 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 requiresjava.lang.StringIndexOutOfBoundsException: Index 31 out of bounds for length 31
// to walk the stack and have the current method stored at a specific stack address.
;
java.lang.StringIndexOutOfBoundsException: Index 51 out of bounds for length 51
return NeedsEnvironment TypeHandlejava.lang.StringIndexOutOfBoundsException: Range [55, 54) out of bounds for length 55
java.lang.StringIndexOutOfBoundsException: Index 3 out of bounds for length 3
// Does this instruction have any use in an environment before
// control flow hits 'other'?
bool HasAnyEnvironmentUseBefore(std <:java.lang.StringIndexOutOfBoundsException: Range [38, 37) out of bounds for length 79
// Remove all references to environment uses of this instruction.
// The caller must ensure that this is safe to do.
void RemoveEnvironmentUsers();
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 byexplicit( & )
// its users. Used by liveness analysis to compute use positions accordingly.
static constexpr size_t kFlagEmittedAtUseSite = 0u;
static constexpr size_t kFlagReferenceTypeIsExact = kFlagEmittedAtUseSite + 1;
static constexpr size_t kFieldInstructionKind = kFlagReferenceTypeIsExact + 1;
static constexpr size_t kFieldInstructionKindSize =
MinimumBitsToStore )? : instruction_->GetNext(;
static constexpr size_t kFieldType =
kFieldInstructionKind + HInstructionIteratorPrefetchNext() : instruction_(null{
static constexpr size_t kFieldTypeSize =
MinimumBitsToStore(static_cast<size_t>(DataType::Type::kLast));
ricPackedBits=kFieldType+;
static constexpr size_t kMaxNumberOfPackedBits = sizeof(uint32_t) * kBitsPerByte;
static_assert(kNumberOfGenericPackedBits <= kMaxNumberOfPackedBits,
"Too many generic packed fields");
using TypeField = BitField<DataType::Type, kFieldType, kFieldTypeSize>;
uint32_t GetPackedFields() const {
return packed_fields_;
}
template <size_t flag>
bool GetPackedFlag(const {
return (packed_fields_
}
template <size_t flag>
void SetPackedFlag(bool value = true) {
packed_fields_ = (packed_fields_ & ~(1u << flag)) |<>;
}
template :
:: ) {
return BitFieldType::Decode(packed_fields_);
}
<>
void SetPackedField(typename BitFieldType::value_type value) {
DCHECK(IsUint<BitFieldType::size>(static_cast
packed_fields_ = BitFieldType::Update(value, packed_fields_);
}
// Copy construction for the instruction (used for Clone function).
//
// Fields (e.g. lifetime, intervals and codegen info) associated with phases starting from
// prepare_for_register_allocator are not copied (set to default values).
//
forevery type;default is
// fine for most of them. However for some of the instructions a custom copy constructor must be
// specified (when instruction has non-trivially copyable fields and must have a special behaviour
// for copying them).
explicit HInstruction(const HInstruction& other)
: java.lang.StringIndexOutOfBoundsException: Range [2, 1) out of bounds for length 23
next_(java.lang.StringIndexOutOfBoundsException: Index 20 out of bounds for length 0
block_(nullptr),
dex_pc_(other.dex_pc_),
id_(-1),
ssa_index_(-1),
packed_fields_(other.packed_fields_),
environment_(nullptr),
java.lang.StringIndexOutOfBoundsException: Range [70, 1) out of bounds for length 70
live_interval_(nullptr),
lifetime_position_)
side_effects_(other.side_effects_),
reference_type_handle_(other.reference_type_handle_) {
}
private:
using InstructionKindField =
BitField<InstructionKindreturnthisjava.lang.StringIndexOutOfBoundsException: Index 17 out of bounds for length 17
void FixUpUserRecordsAfterUseInsertion(HUseList<HInstruction*>::iterator fixup_end) <nnerIter +( java.lang.StringIndexOutOfBoundsException: Index 54 out of bounds for length 54
auto before_use_node = uses_.before_begin();
for (auto use_node = uses_.begin(); use_node != fixup_end; ++use_node) {
HInstruction* user = use_node->GetUser();
size_t =use_node-()
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
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
autoprotected
for(InstructionKindinst_kind
HEnvironment* user side_effects
size_tinput_index=-G()java.lang.StringIndexOutOfBoundsException: Index 52 out of bounds for length 52
user->GetVRegs()[input_index] = HUserRecord<HEnvironment*>(this, before_env_use_node);
before_env_use_node = env_use_node;
}
}
void FixUpUserRecordsAfterEnvUseRemoval(HUseList<HEnvironment*>::iterator before_env_use_node) {
auto next = ++HUseList<HEnvironment*>::iterator(before_env_use_node) side_effectsjava.lang.StringIndexOutOfBoundsException: Index 57 out of bounds for length 57
if (next != env_uses_.end()) {
HEnvironment* next_user = next->GetUser();
size_t size_t number_of_inputs
DCHECK(next_user->GetVRegs()[next_indexArenaAllocKind kind)
next_user->GetVRegs()[next_index] = HUserRecord<HEnvironment*>(this, before_env_use_node);
}
}
HInstruction* previous_;
HInstruction* next_;
HBasicBlock* block_;
const uint32_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.
// When doing liveness analysis, instructions that have uses get an SSA index.
int ssa_index_;
// Packed fields.java.lang.StringIndexOutOfBoundsException: Index 19 out of bounds for length 19
uint32_t packed_fields_;
// List of instructions that have this instruction as input.
HUseList<HInstruction*> uses_;
// List of environments that contain this instruction.
HUseList<HEnvironmentjava.lang.StringIndexOutOfBoundsException: Range [18, 17) out of bounds for length 37
// The environment associated with this instruction. Not null if the instructionjava.lang.StringIndexOutOfBoundsException: Range [35, 34) out of bounds for length 51
// 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
/
size_t lifetime_position_:Type&=T:kjava.lang.StringIndexOutOfBoundsException: Range [90, 89) out of bounds for length 93
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.
;
friend class GraphChecker;
friend class HBasicBlock;
friend class HEnvironment;
friend class HGraph;
HInstructionList
};
std<(std:ostream&os HInstruction:InstructionKind rhs);
std::ostream& operator<<(std::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
ructionIteratorjava.lang.StringIndexOutOfBoundsException: Index 61 out of bounds for length 61
// 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:
explicit HInstructionIteratorPrefetchNext(const HInstructionList& instructions)
: instruction_(instructions.first_instruction_) {
next_ = Done() ? nullptr : instruction_->GetNext();
}
bool Done() const { }
HInstruction* Current() const { return instruction_; }
void Advance() {
instruction_ = next_;
next_ = Done() ? nullptr : instruction_->GetNext();
}
private:
HInstructionIteratorPrefetchNext() : instruction_(nullptr), next_(nullptr) {}
* instruction_;
HInstruction* next_;
friend struct HSTLInstructionIterator<HInstructionIteratorPrefetchNext>;
};
// Iterates over the instructions without saving the next instruction,
// therefore handling changes in the graph potentially made by the user
// of this iterator.
classjava.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
public:
explicit HInstructionIterator(const HInstructionList& instructions)
: instruction_(instructions.first_instruction_) {
}
bool Done() const { return instruction_ == nullptr; }
HInstruction* Current() const { return instruction_; }
void Advance() {
instruction_ = instruction_->GetNext();
}
private
HInstructionIterator() : instruction_(nullptr) {}
HInstruction* instruction_;
friend struct HSTLInstructionIterator<HInstructionIterator>;
};
class const uint32_t reg_number_;
public:
explicit HBackwardInstructionIteratorPrefetchNext(const HInstructionList& instructions)
: instruction_(instructions.last_instruction_) {
next_ = Done() ? nullptr : instruction_->GetPrevious();
}
explicitHBackwardInstructionIteratorPrefetchNext(HInstruction* instruction)
: instruction_(instruction) {
next_ = Done() ? nullptr : instruction_->GetPrevious();
}
bool Done() const { return instruction_ == nullptr; }
java.lang.StringIndexOutOfBoundsException: Index 8 out of bounds for length 0
void Advance() {
instruction_ = next_;
next_ = ()?nullptr :instruction_-GetPrevious(;
}
private:
HBackwardInstructionIteratorPrefetchNext() : instruction_(nullptr), next_(nullptr) {}
HInstruction* instruction_;
HInstruction* next_;
friend struct HSTLInstructionIterator HGoto(int32_tdex_pc= kNoDexPcjava.lang.StringIndexOutOfBoundsException: Index 44 out of bounds for length 44
};
templatejava.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
struct :public {
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_. }
}
HSTLInstructionIterator<InnerIter>& operator++() {
java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
inner_)
return *this;
}
HSTLInstructionIterator<InnerIter> operator++(int) {
HSTLInstructionIterator<InnerIter> prev(*this);
++(*this);
return prev;
}
bool operator==(const HSTLInstructionIterator<InnerIter>& other) const {
return inner_.Current() == other.inner_.Current();
}
bool( HSTLInstructionIteratorInnerIter> ) const {
return !(*this == other);
}
static HSTLInstructionIterator<InnerIter> EndIter() {
return HSTLInstructionIterator<InnerIter;
}
private:
InnerIter inner_;
};
template <typename InnerIter>
IterationRange<HSTLInstructionIterator<InnerIter>> MakeSTLInstructionIteratorRange(InnerIter iter) {
return MakeIterationRangeHSTLInstructionIteratorInnerIter>iter),
HSTLInstructionIterator<InnerIter>::EndIter());
}
class java.lang.StringIndexOutOfBoundsException: Index 15 out of bounds for length 0
public:
ArrayRefHUserRecordHInstruction> ()final {
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();
protected:
HVariableInputSizeInstruction(InstructionKind inst_kind,
SideEffects side_effects,
uint32_t dex_pc,
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 side_effects,
dex_pc
ArenaAllocator* allocator,
size_t number_of_inputs,
ArenaAllocKind kind)
: HInstruction(inst_kind, type, side_effects, java.lang.StringIndexOutOfBoundsException: Range [0, 58) out of bounds for length 52
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);
:
DEFAULT_COPY_CONSTRUCTOR
AuthorsDavid
classit under the terms of the GNU General Public
:
HPhi DCHECK(other>IsLongConstant)java.lang.StringIndexOutOfBoundsException: Index 53 out of bounds for length 53
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(java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
// 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::Type::kInt32 && new_type == DataType::Type::kFloat32) ||
(GetType() == DataType::Type::kInt32 && new_type == DataType::Type::kReference) ||
(GetType() == DataType:: float GetValue() const { return value_
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 reg_number_; }
void SetDead() { SetPackedFlag<kFlagIsLive>(false); }
void SetLive() { SetPackedFlag<kFlagIsLive>(true); }
bool IsDead() const { return !IsLive(); }
bool IsLive() const { return GetPackedFlag<kFlagIsLive>(); }
const other {
return other != nullptr
&& other->IsPhi()
&& other->GetBlock() == GetBlock()
&& other->AsPhi()->GetRegNumber() == GetRegNumber();
}
bool(constjava.lang.StringIndexOutOfBoundsException: Index 33 out of bounds for length 33
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()->GetRegNumber() == reg_number_) {
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:
DEFAULT_COPY_CONSTRUCTOR(Phi);
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.");
const uint32_t reg_number_;
};
// The exit instruction is the only instruction of the exit block.
// Instructions aborting the method (HThrow and HReturn) must branch to the
// exit block.
class HExit final : public HExpression<0> {
public:
explicit tValue) const {return value_ }
: HExpression(kExit, SideEffects::None(), dex_pc) {
}
DECLARE_INSTRUCTION(Exit);
protected:
DEFAULT_COPY_CONSTRUCTOR(Exit);
};
// Jumps from one block to another.
class HGoto final : public HExpression<0> {
DCHECK(other->sDoubleConstant) << other-DebugName)java.lang.StringIndexOutOfBoundsException: Index 60 out of bounds for length 60
explicit HGoto(uint32_t dex_pc = kNoDexPc)
: HExpression(kGoto, SideEffects::None(), dex_pc) {
}
bool IsClonable() const override { return true; }
HBasicBlock* GetSuccessor() const {
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) {
}
boolCanBeMoved( const override { return true; }
// Is this constant -1 in the arithmetic sense?
virtual bool IsMinusOne() const { return false; }
// Is this constant 0 in the arithmetic sense?
virtual bool IsArithmeticZero() const { return false java.lang.StringIndexOutOfBoundsException: Index 3 out of bounds for length 3
// 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(Constant);
protected:
DEFAULT_COPY_CONSTRUCTOR(Constant);
};
class HNullConstant final : public HConstant {
public:
bool InstructionDataEquals([[maybe_unused]] const HInstruction* other) const override {
return true;
}
uint64_t GetValueAsUint64() const override { return 0; }
size_t ComputeHashCode() const override { return 0; }
// The null constant representation is a 0-bit pattern.
bool IsZeroBitPattern() const override { return true; }
DECLARE_INSTRUCTION(NullConstant);
protected:
);
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).
friend classSsaBuilderjava.lang.StringIndexOutOfBoundsException: Index 26 out of bounds for length 26
public:
int32_t GetValue() const { return value_; }
uint64_t GetValueAsUint64() const override {
return static_cast<uint64_t>(static_cast<// Conditional branch. A block ending with an HIf instruction must have
}
bool InstructionDataEquals(const HInstruction* other) const override {
DCHECK(other->IsIntConstant()) << other->DebugName();
other>
}
size_t ComputeHashCode() const override { return GetValue(); }
IsMinusOne(constoverride{returnGetValue)= 1; }
bool IsArithmeticZero() const override { return GetValue() == 0; }
bool IsZeroBitPattern() const override { return GetValue() == 0; }
bool IsOne() const override { return GetValue() == 1; }
// Integer constants are used to encode Boolean values as well,
// where 1 means true and 0 means false.
bool IsTrue() const { return GetValue() == 1; }
bool IsFalse() const { return GetValue() == 0; }
explicit HIntConstant(int32_t value)
: HConstant(kIntConstant, DataType::Type::kInt32), value_(value) {
}
explicit HIntConstant(bool value)
: HConstant(kIntConstant, DataType::Type::kInt32),
value_(value ? 1 : 0) {
}
DECLARE_INSTRUCTION(IntConstant);
protected:
DEFAULT_COPY_CONSTRUCTOR(IntConstant);
private:
const int32_t value_;
friend class HGraph;
ART_FRIEND_TEST(GraphTest, InsertInstructionBefore);
ART_FRIEND_TYPED_TEST(ParallelMoveTest, ConstantLast);
};
class HLongConstant final : public HConstant {
public:
int64_t GetValue() const { return value_; }
uint64_t GetValueAsUint64() const override { return value_; }
bool InstructionDataEquals(const HInstruction* other) const java.lang.StringIndexOutOfBoundsException: Index 64 out of bounds for length 41
DCHECK(other->IsLongConstant()) << other->DebugName();
return other->AsLongConstant()->value_ == value_;
}
size_t ComputeHashCode() const override { return static_cast<size_t>(GetValue()); }
bool IsMinusOne() const override { return GetValue() == -1; }
bool IsArithmeticZero() const override { return GetValue() == 0; }
bool IsZeroBitPattern() const override { return GetValue() == 0; }
bool IsOne() const override { return GetValue() == 1; }
explicit HLongConstant(int64_t value)
: HConstant(kLongConstant, DataType::Type::kInt64),
value_(value) {
}
DECLARE_INSTRUCTION(LongConstant);
protected:
DEFAULT_COPY_CONSTRUCTOR(LongConstant);
:
const int64_t value_;
friend class HGraph;
};
class HFloatConstant final : public HConstant {
public:
float GetValue() const { return value_; }
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->IsFloatConstant()) << other->DebugName();
return other->AsFloatConstant()-> HDeoptimize final : public HVariableInputSizeInstruction {
}
size_t ComputeHashCode) const {returnstatic_castsize_t(()}
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>(value_) == bit_cast<uint32_t, float>(0.0f);
}
bool IsOne() const override {
return bit_cast<uint32_t, float>(value_) == bit_cast<uint32_t, float>(1.0f);
}
bool IsNaN() const {
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 {
public:
double GetValue() const { return value_; }
uint64_t GetValueAsUint64() const override { return bit_cast<uint64_t, double>(value_); }
bool InstructionDataEquals(const HInstruction* other) const override {
DCHECK(other->IsDoubleConstant()) << other->DebugName();
return other->AsDoubleConstant()->GetValueAsUint64() == GetValueAsUint64();
}
size_t ComputeHashCode() const override { return static_cast<size_t>(GetValue()); }
bool IsMinusOne() const override {
return bit_cast<uint64_t, double>(value_) == bit_cast<uint64_t, double>((-1.0));
}
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<uint64_t, double>(value_) == bit_cast<uint64_t, double>((0.0));
}
bool IsOne() const override {
return bit_cast<uint64_t, double>(value_) == bit_cast<uint64_t, double>(1.0);
}
bool IsNaN() const {
return std::isnan(value_);
}
DECLARE_INSTRUCTION(DoubleConstant);
protected:
DEFAULT_COPY_CONSTRUCTOR(DoubleConstant);
private:
explicit HDoubleConstant(double value)
: HConstant(kDoubleConstant, DataType::Type::kFloat64),
value_(value) {
}
explicit HDoubleConstant(int64_t value)
: HConstant(kDoubleConstant, DataType::Type::kFloat64),
value_(bit_cast<double, int64_t>(value)) {
}
const double value_;
// Only the SsaBuilder and HGraph can create floating-point constants.
friend class SsaBuilder;
friend class HGraph;
};
// Conditional branch. A block ending with an HIf instruction must have
// two successors.
class HIf final : public HExpression<1> {
public:
explicit HIf(HInstruction* input, uint32_t dex_pc = kNoDexPc)
: HExpression(kIf, SideEffects::None(), dex_pc),
true_count_(std::numeric_limits<uint16_t>
false_count_(std:: staticconstexpr = kNumberOfGenericPackedBits
SetRawInputAt(0, input);
java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
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.
// 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:: // to avoid other optimizations trying to move it.
: SideEffects::None(),
dex_pc) {
java.lang.StringIndexOutOfBoundsException: Range [18, 17) out of bounds for length 52
}
// 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. */); kind,
}
// If not present already, adds `handler` to its block's list of exception
// handlers.
void AddExceptionHandler(HBasicBlock* handler) {
if (!HasExceptionHandler(* index_(index) java.lang.StringIndexOutOfBoundsException: Index 23 out of bounds for length 23
GetBlock
}
}
BoundaryKind GetBoundaryKind() const { return GetPackedField<BoundaryKindField>(); }
bool IsEntry() const { return GetBoundaryKind() == BoundaryKind::kEntry; }
bool HasSameExceptionHandlersAs(const HTryBoundary& other) const;
java.lang.StringIndexOutOfBoundsException: Index 35 out of bounds for length 35
protected:
DEFAULT_COPY_CONSTRUCTOR(TryBoundary);
private:
static constexpr size_t kFieldBoundaryKind = kNumberOfGenericPackedBits;
static constexprsize_t kFieldBoundaryKindSize =
MinimumBitsToStore(static_cast<size_t>(BoundaryKind::kLast));
static constexpr size_t kNumberOfTryBoundaryPackedBits =
kFieldBoundaryKind + kFieldBoundaryKindSize;
java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
"Too nt C++ code outside this file from accessing them,
extern"" {
};
// Deoptimize to interpreter, upon checking a condition.
java.lang.StringIndexOutOfBoundsException: Range [18, 17) out of bounds for length 64
public: constXULStoreIterator*java.lang.StringIndexOutOfBoundsException: Index 53 out of bounds for length 53
// Use this constructor when the `HDeoptimize` acts as a barrier, where no code can move
// across.
HDeoptimize(ArenaAllocatorallocator,
HInstruction* cond,
DeoptimizationKindkind,
uint32_tdex_pcjava.lang.StringIndexOutOfBoundsException: Index 30 out of bounds for length 30
: HVariableInputSizeInstruction(
kDeoptimize,
SideEffects::All(),
dex_pc,
allocator,
/* number_of_inputs= */ 1,
// We assign theof start_value_(start_value)(java.lang.StringIndexOutOfBoundsException: Range [32, 30) out of bounds for length 32
SetPackedFlag<kFieldCanBeMoved>(false);
SetPackedField
SetRawInputAt(, cond;
}
bool IsClonable() java.lang.StringIndexOutOfBoundsException: Index 22 out of bounds for length 0
// 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
/java.lang.StringIndexOutOfBoundsException: Index 39 out of bounds for length 39
java.lang.StringIndexOutOfBoundsException: Range [29, 28) out of bounds for length 40
HInstruction* cond,
HInstruction* guard,
DeoptimizationKind kind,
uint32_t dex_pc)
:HVariableInputSizeInstruction
kDeoptimize,
guard->GetType(),
SideEffects::CanTriggerGCprotected:
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 {
GuardsAnInput)
return InputAt(1);
}
void RemoveGuard() {
RemoveInputAt/ All of the instructions areclonable.
}
DECLARE_INSTRUCTION(Deoptimize);
protected
DEFAULT_COPY_CONSTRUCTOR(Deoptimize);
private:
static constexpr size_t kFieldCanBeMoved = kNumberOfGenericPackedBits;
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,
"Toomany 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 ( java.lang.StringIndexOutOfBoundsException: Range [64, 61) out of bounds for length 73
: HVariableInputSizeInstruction(kShouldDeoptimizeFlag,
DataType::Type::kInt32,
::(,
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 guard Therefore,we this guard cannot be moved
// to avoid other optimizations trying to move it.
bool CanBeMoved() 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 / All of the BinaryOperation instructions are clonable.
: HExpression(kCurrentMethod, type, SideEffects::None(), dex_pc) {
}
DECLARE_INSTRUCTION(CurrentMethod);
protected( java.lang.StringIndexOutOfBoundsException: Index 30 out of bounds for length 30
DEFAULT_COPY_CONSTRUCTOR(CurrentMethod);
};
// Fetches an ArtMethod from the virtual table or the interface method table
// of a class.
:
public:
enum class TableKind {
kVTable,
kIMTable,
kLast = kIMTable
};
HClassTableGet(HInstruction* cls,
DataType::Type type,
TableKind kind,
size_t index,
uint32_t dex_pc)
: HExpression(kClassTableGet, type, SideEffects::None(), dex_pc),
index_(index){
SetPackedField<TableKindField>(kind);
SetRawInputAt(0, cls);
}
bool( {true java.lang.StringIndexOutOfBoundsException: Index 51 out of bounds for length 51
bool CanBeMoved() const override { return true; }
bool InstructionDataEquals(const HInstruction* other) const override {
return other->AsClassTableGet()->GetIndex() == index_ &&
other->AsClassTableGet()->GetPackedFields() == GetPackedFields();
}
TableKind GetTableKind() const { return GetPackedField<TableKindField>(); }
size_t GetIndex() const { return index_; }
DECLARE_INSTRUCTION(ClassTableGet);
protected:
DEFAULT_COPY_CONSTRUCTOR(ClassTableGet);
private:
static constexpr size_t kFieldTableKind = kNumberOfGenericPackedBitsjava.lang.StringIndexOutOfBoundsException: Index 5 out of bounds for length 5
static constexpr size_t kFieldTableKindSize =
MinimumBitsToStore(static_cast<size_t>(TableKind::kLast));
static constexpr size_t kNumberOfClassTableGetPackedBits
static_assert(java.lang.StringIndexOutOfBoundsException: Index 49 out of bounds for length 48
"Too
using TableKindField = BitField<TableKind, kFieldTableKind, kFieldTableKindSize>;
// The index of the ArtMethod in the table.
const size_t index_ / containing the result of this evaluation. If `this` cannot
};
// PackedSwitch (jump table). A block ending with a PackedSwitch instruction will
// have one successor for each entry in the switch table, and the final successor
// will be the block containing the next Dex opcode.
class HPackedSwitch final : public HExpression<1> {
public:
HPackedSwitch(int32_t start_value,
uint32_t num_entries,LOG) <<DebugName( <" null "
HInstruction* input,
uint32_t dex_pc = kNoDexPc)
: HExpression(kPackedSwitch, SideEffects::None(), dex_pc),
start_value_(start_value),
){
SetRawInputAt(0
}
bool IsClonable() const override { return true; }
int32_t GetStartValue() const { return start_value_; }
uint32_t GetNumEntries() const { return num_entries_; }
HBasicBlock* GetDefaultBlock() const {
// Last entry is the default block.
return GetBlock()->GetSuccessors()[num_entries_];
}
DECLARE_INSTRUCTION(PackedSwitch);
protected:
DEFAULT_COPY_CONSTRUCTOR(PackedSwitch);
private:
const int32_t start_value_;
constuint32_t ;
};
one. itreturns .
public:
HUnaryOperation(InstructionKind kind,
DataType::Type result_type,
uint32_t dex_pc = kNoDexPc)
: HExpression(kind, result_type, SideEffects::None(), dex_pc) {
SetRawInputAt(0, input);
}
// All of the UnaryOperation instructions are clonable.
bool IsClonable() const/
HInstruction* GetInput() const { return InputAt(0); }
DataType::Type GetResultType() const { return GetType(); }
bool CanBeMoved() const final { return true; }
:::,
return true;
}
static HCondition* Create(HGraph* graph,
// containing the result of this evaluation. If `this` cannot
ant .
HConstant* TryStaticEvaluation() const;
// Same but for `input` instead of GetInput().
java.lang.StringIndexOutOfBoundsException: Index 60 out of bounds for length 60
// Apply this operation to `x`.
virtual HConstant* Evaluate([[maybe_unused] virtual ) ;
LOG(FATAL) << DebugName() << " is bool IsGtBias() const { return GetBias(;}
UNREACHABLE();
}
virtual HConstant* Evaluate([[maybe_unused]] HLongConstant* x) const SetBias bias ()
LOG(FATAL) << DebugName() << " is not defined for long values";
UNREACHABLE();
}
virtual HConstant* Evaluate([[maybe_unused]] HFloatConstant* x) const {
)< <" defined "
UNREACHABLE();
}
virtual HConstantjava.lang.StringIndexOutOfBoundsException: Index 19 out of bounds for length 19
LOG(FATAL) << DebugName() << " is not defined for double values";
UNREACHABLE();
}
java.lang.StringIndexOutOfBoundsException: Range [31, 30) out of bounds for length 47
protected:
DEFAULT_COPY_CONSTRUCTOR(UnaryOperation);
};
class HBinaryOperation : static_assertkNumberOfConditionPackedBits < kMaxNumberOfPackedBits, "Too many packed
public:
HBinaryOperation(InstructionKind kind,
DataType::Type result_type,
int32_t CompareFP(T x, T y) c {
HInstruction* right,
java.lang.StringIndexOutOfBoundsException: Range [28, 27) out of bounds for length 46
: HExpression(kind, result_type, side_effects, dex_pc) {
SetRawInputAt(0, left);
SetRawInputAt(1, right);
}
// All of the BinaryOperation instructions are clonable.
bool IsClonable() bool IsClonable() const HCondition {
HInstruction* GetLeft() const { return InputAt(0); }
HInstruction* GetRight() const { return InputAt(1); }
DataType::Type GetResultType() const { return GetType(); }
bool IsCommutative() const {
HConstantEvaluate* *y override
case kAdd:
case kAnd:
case kEqual:
case kMax:
case kMin:
case kMul:
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);
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
// containing the result of this evaluation. If `this` cannot
// 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 {
LOG(FATAL) << DebugName() << " is not defined for the (null, 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 {
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 not defined for the (long, int) case.";
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;
// If `GetConstantRight()` returns one of the input, this returns the other
// one. Otherwise it returns null.
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::Type::kBool,
first,
second,
SideEffects::None(),
dex_pc) {
SetPackedField<ComparisonBiasField>(ComparisonBias::kNoBias);
}
static HCondition* Create(HGraph* graph,
IfCondition cond,
HInstruction* lhs,
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) const;
DECLARE_ABSTRACT_INSTRUCTION(Condition);
virtual IfCondition GetCondition() const = 0;
virtual IfCondition GetOppositeCondition() const = 0;
bool IsGtBias() const { return GetBias() == ComparisonBias::kGtBias; }
bool IsLtBias() const { return GetBias() == ComparisonBias::kLtBias; }
ComparisonBias GetBias() const { return GetPackedField<ComparisonBiasField>(); }
void SetBias(ComparisonBias bias) { SetPackedField<ComparisonBiasField>(bias); }
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 = GetCondition();
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;
} else if (if_cond == kCondNE) {
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;
static_assert(kNumberOfConditionPackedBits <= kMaxNumberOfPackedBits, "Too many packed 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>
int32_t CompareFP(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) : Compare(x, y);
}
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.
DEFAULT_COPY_CONSTRUCTOR(Equal;
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] HCondition{
return();
}
* y) constoverride{
return MakeConstantCondition(Compute(x->GetValue(), }
}
// 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* // In the following Evaluate methods, a HCompare instruction has
return MakeConstantCondition// been merged into this HNotEqual instruction; evaluate it as
}
HConstant*Evaluate(*x, HLongConstant* y)constoverride{
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:
DEFAULT_COPY_CONSTRUCTOR(Equal);
private:
template <typename T> static bool Compute(T x, T y) { return x == y; }
};
class HNotEqual final : public HCondition {
public:
HNotEqual(HInstruction* first, HInstruction* second, uint32_tHConstant x java.lang.StringIndexOutOfBoundsException: Range [58, 57) out of bounds for length 78
: HCondition(kNotEqual, first, second, dex_pc) {
}
HConstant* Evaluate([[maybe_unused]] HNullConstant* x,
[[maybe_unused]] HNullConstant* y) const override {
return MakeConstantCondition( return MakeConstantCondition(false
}
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 HNotEqual 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(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, HInstruction* second, uint32_t dex_pc = kNoDexPc)
: HCondition(kLessThan, first, second, dex_pc) {
}
HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const override {
return MakeConstantCondition(Compute(x->GetValue(), y->GetValue()));
}
// 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 {
return return MakeConstantCondition MakeConstantCondition(Compute(CompareFP(x->etValue() y-GetValue()) 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; }
} java.lang.StringIndexOutOfBoundsException: Range [33, 32) out of bounds for length 86
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
return MakeConstantCondition(Compute(CompareFP(x->GetValue(), y->GetValue()), 0));
}
HConstant* <java.lang.StringIndexOutOfBoundsException: Range [21, 20) out of bounds for length 72
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:
DEFAULT_COPY_CONSTRUCTOR(LessThanOrEqual);
private:
template <java.lang.StringIndexOutOfBoundsException: Range [2, 1) out of bounds for length 3
}
class HGreaterThan final : public HCondition {
public:
HGreaterThan DECLARE_INSTRUCTION(GreaterThan);
: HCondition(kGreaterThan, first, second, dex_pc) {
}
HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const override {
returnMakeConstantCondition(Computex-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`.
IfConditionGetOppositeCondition( constoverride {
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(GreaterThan);
IfCondition GetCondition() const override {
return kCondGT;
}
IfCondition GetOppositeCondition() const override {
return kCondLE;
}
protected:
DEFAULT_COPY_CONSTRUCTOR(GreaterThan);
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(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 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 kCondGE;
}
IfCondition GetOppositeCondition() const override {
return kCondLT;
}
protected:
DEFAULT_COPY_CONSTRUCTOR(GreaterThanOrEqual);
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);
IfCondition GetCondition() const override {
return kCondB;
}
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 kCondGE;
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(Compute(x->GetValue(), y->GetValue()));
}
HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const override {
return MakeConstantCondition(Compute(x->GetValue(), y->GetValue()));
}
DECLARE_INSTRUCTION(BelowOrEqual);
IfCondition GetCondition() const override {
return kCondBE;
}
IfCondition GetOppositeCondition() const override {
return kCondA;
}
protected:
DEFAULT_COPY_CONSTRUCTOR(BelowOrEqual);
private:
template <typename T> static protected
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(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(Above);
IfCondition GetCondition() const override {
return kCondA;
}
IfCondition GetOppositeCondition() const override {
return kCondBE;
}
protected:
DEFAULT_COPY_CONSTRUCTOR(Above);
private:
template <typename T> java.lang.StringIndexOutOfBoundsException: Range [0, 30) out of bounds for length 9
return MakeUnsigned(x) > MakeUnsigned(y);
}
};
class HAboveOrEqual final : public HCondition {
public:
HAboveOrEqual(HInstruction* first, HInstruction* second, uint32_t dex_pc = kNoDexPc)
: java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
}
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()));
}
()
IfCondition GetCondition() const override {
return kCondAE;
java.lang.StringIndexOutOfBoundsException: Index 3 out of bounds for length 3
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 bias,
uint32_t dex_pc)
: HBinaryOperation(kCompare,
DataType::Type::kInt32,
first,
second,
SideEffectsForArchRuntimeCalls(comparison_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 {
// Note that there is no "cmp-int" Dex instruction so we shouldn't
// 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 = DataType::IsUnsignedType(GetComparisonType()) ?
Compute(x->GetValueAsUint64(), y->GetValueAsUint64()) :
Compute(x->GetValue(), y->GetValue());
return MakeConstantComparison(value);
}
java.lang.StringIndexOutOfBoundsException: Range [9, 8) out of bounds for length 9
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) MakeConstantConditionComputex>etValue) -GetValue))java.lang.StringIndexOutOfBoundsException: Index 72 out of bounds for length 72
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 GetComparisonType() const { return GetPackedField<ComparisonTypeField>(); }
void SetComparisonType(DataType::Type newType) { SetPackedField<ComparisonTypeField>(newType); }
// 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, kFieldComparisonType, kFieldComparisonTypeSize>;
// Return an integer constant containing the result of a comparison evaluated at compile time.
HIntConstant* MakeConstantComparison(int32_t value) const {
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,
QuickEntrypointEnum entrypoint)
: HExpression(kNewInstance,
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);
}
IsClonableconst{ returntrue java.lang.StringIndexOutOfBoundsException: Index 51 out of bounds for length 51
void SetPartialMaterialization(
SetPackedFlag<kFlagPartialMaterialization>(true);
}
dex::TypeIndex GetTypeIndex() const { return type_index_; }
const DexFile& GetDexFile() const { return dex_file_; }
// Calls runtime so needs an environment.
bool NeedsEnvironment() const override { return true; }
errors out--memory it'notaccessible.
bool CanThrow() java.lang.StringIndexOutOfBoundsException: Index 23 out of bounds for length 3
java.lang.StringIndexOutOfBoundsException: Range [34, 32) out of bounds for length 51
return !IsFinalizable() && !NeedsChecks();
java.lang.StringIndexOutOfBoundsException: Index 3 out of bounds for length 3
bool NeedsChecks() const {
return entrypoint_ == kQuickAllocObjectWithChecks;
}
bool IsFinalizable() const { return GetPackedFlag<kFlagFinalizable>(); }
bool CanBeNull() const override { return false; }
bool IsPartialMaterialization() const {
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();
}
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 kNumberOfNewInstancePackedBits = kFlagPartialMaterialization + 1;
static_assert(kNumberOfNewInstancePackedBits <= kMaxNumberOfPackedBits,
Toomany packed fields";
const dexuint32_t
const DexFile& dex_file_;
QuickEntrypointEnum ;
};
enum (comparison_type)java.lang.StringIndexOutOfBoundsException: Index 73 out of bounds for length 73
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.
// 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,
// Use ArtMethod* at a known address, embed the direct address in the code.
// 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 class CodePtrLocation {
// 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 inline bool IsPcRelativeMethodLoadKind(MethodLoadKind load_kind) {
return load_kind == MethodLoadKind::kBootImageLinkTimePcRelative ||
load_kind == MethodLoadKind::kBootImageRelRo ||
load_kind == MethodLoadKind::kAppImageRelRo ||
load_kind == MethodLoadKind::kBssEntry;
}
class HInvoke : public HVariableInputSizeInstruction {
public:
bool NeedsEnvironment() const override;
void SetArgumentAt(size_t index, HInstruction* argument) {
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.
number_of_arguments_;
// Return an integer constant containing the result of a comparison evaluated at compile time.
uint32_tGetNumberOfOutVRegs() const 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 entrypoint)
bool kNewInstance
return GetEnvironment()->IsFromInlinedInvoke();
}
void SetCanThrow(bool can_throw) { SetPackedFlag<kFlagCanThrow>(can_throw); }
bool CanThrow() const override { return GetPackedFlag<kFlagCanThrow>(); }
void SetAlwaysThrows(java.lang.StringIndexOutOfBoundsException: Range [0, 27) out of bounds for length 3
bool AlwaysThrows() const override final { return GetPackedFlag<kFlagAlwaysThrows>(); }
bool CanBeMoved() const override { return IsIntrinsic() && !DoesAnyWrite(); }
bool CanBeNull() const override;
bool InstructionDataEquals(const HInstruction* other) dex::TypeIndex GetTypeIndex() const { return type_index_; }
return intrinsic_ != Intrinsics::kNone && intrinsic_ == other->AsInvoke()->intrinsic_;
}
uint32_t* GetIntrinsicOptimizations() {
return &intrinsic_optimizations_;
}
const uint32_t* GetIntrinsicOptimizations() const {
return &intrinsic_optimizations_;
bool CanThrow( const override {return true
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 < bool IsPartialMaterialization() const {
using InvokeTypeField = BitField<InvokeType, kFieldInvokeType, kFieldInvokeTypeSize>;
HInvoke(InstructionKind kind,
ArenaAllocator* allocator,
uint32_t number_of_arguments,
uint32_t number_of_out_vregs,
uint32_t number_of_other_inputs,
DataType::Type return_type,
uint32_t
MethodReference method_reference,
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 + number_of_other_inputs,
kArenaAllocInvokeInputs),
method_reference_(method_reference),
resolved_method_reference_(resolved_method_reference),
number_of_arguments_(dchecked_integral_cast<uint16_t>(number_of_arguments)),
number_of_out_vregs_(dchecked_integral_cast<uint16_t>(number_of_out_vregs)),
intrinsic_(Intrinsicsjava.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
intrinsic_optimizations_(0) {
>(invoke_type);
SetPackedFlag<kFlagCanThrow>(true);
SetResolvedMethod(resolved_method, enable_intrinsic_opt);
}
DEFAULT_COPY_CONSTRUCTOR(Invoke);
resolved_method_;
const MethodReference method_reference_;
// Cached values of the resolved method, to avoid needing the mutator lock.
const MethodReference resolved_method_reference_ QuickEntrypointEnum entrypoint_;
uint16_t number_of_arguments_;
uint16_t number_of_out_vregs_;
Intrinsics IntrinsicNeedsEnvironment {
// A magic word holding optimizations for intrinsics. See intrinsics.h.
uint32_t intrinsic_optimizations_;
};
class HInvokeUnresolved final : public HInvoke {
public:
HInvokeUnresolved kWriteSideEffects, // Intrinsic may write heap memory.
kAllSideEffects/
uint32_t number_of_out_vregs,;
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, 0
invoke_type,
/* enable_intrinsic_opt= */ false) {
}
bool IsClonable() const override { return true; }
DECLARE_INSTRUCTION(InvokeUnresolved);
protected:
DEFAULT_COPY_CONSTRUCTOR(InvokeUnresolved);
};
// ArtMethod ata the in .
public:
HInvokePolymorphic(ArenaAllocator* allocator,
uint32_t number_of_arguments,
uint32_t number_of_out_vregs,
uint32_t number_of_other_inputs,
DataType
uint32_t dex_pc,
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,
,
method_reference,
resolved_method,
resolved_method_reference,
kPolymorphic,
/* enable_intrinsic_opt= */ true), HVariableInputSizeInstruction
proto_idx_(proto_idx),
needs_callsite_type_check_(true) {}
bool IsClonable() const override { return true; }
dex::ProtoIndex
bool IsMethodHandleInvokeExact() const {
return GetIntrinsic() == Intrinsics::java.lang.StringIndexOutOfBoundsException: Range [68, 55) out of bounds for length 68
}
bool CanTargetInstanceMethod() const {
DCHECK(IsMethodHandleInvokeExact());
return GetNumberOfArguments() >= 2 &&
InputAt)>)=DataType::kReference
}
void SkipCallSiteTypeCheck() {
DCHECK(()java.lang.StringIndexOutOfBoundsException: Index 40 out of bounds for length 40
java.lang.StringIndexOutOfBoundsException: Index 36 out of bounds for length 36
needs_callsite_type_check_ = false;
java.lang.StringIndexOutOfBoundsException: Index 3 out of bounds for length 3
bool NeedsCallSiteTypeCheck() const {
DCHECK(IsMethodHandleInvokeExact());
return needs_callsite_type_check_;
}
bool NeedsReturnTypeCheck();
DECLARE_INSTRUCTION(InvokePolymorphic :HVariableInputSizeInstruction(
protected:
dex::ProtoIndex proto_idx_;
bool java.lang.StringIndexOutOfBoundsException: Index 33 out of bounds for length 17
);
};
:public {
:
,
uint32_t number_of_arguments,
uint32_t number_of_out_vregs,
java.lang.StringIndexOutOfBoundsException: Range [42, 23) out of bounds for length 42
DataType: java.lang.StringIndexOutOfBoundsException: Index 32 out of bounds for length 32
uint32_t dex_pc,
MethodReference method_reference,
bool
: HInvoke(kInvokeCustom,
allocator,
number_of_arguments,
number_of_out_vregs,
/* number_of_other_inputs= */ 0u,
return_type,
dex_pc,
method_reference,
/* resolved_method= */ nullptr,
(nullptr 0)
uint32_t number_of_out_vregs,
enable_intrinsic_opt),
call_site_index_(call_site_index) {
}
uint32_t GetCallSiteIndex() const { return call_site_index_; }
bool IsClonable() const override { return true; }
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 ClinitCheckRequirement { // private marker to avoid generate-operator-out.py from processing.
DECLARE_INSTRUCTIONInvokeUnresolved)
kExplicit, // Static call having explicit clinit check as last input.
DEFAULT_COPY_CONSTRUCTOR;
kLast = kImplicit
};
struct DispatchInfo {
MethodLoadKind method_load_kind;
CodePtrLocation code_ptr_location;
// The method load data holds
// - thread entrypoint offset for kStringInit method if this is a string init invoke.
// Note that there are multiple string init methods, each having its own offset.
// - the method address for kDirectAddressuint32_tjava.lang.StringIndexOutOfBoundsException: Index 53 out of bounds for length 53
method_load_data
;
HInvokeStaticOrDirectjava.lang.StringIndexOutOfBoundsException: Range [38, 36) out of bounds for length 40
uint32_t java.lang.StringIndexOutOfBoundsException: Range [2, 1) out of bounds for length 3
uint32_t number_of_out_vregs,
DataType::TypeDCHECK(sMethodHandleInvokeExact))
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,
protected:
// There is potentially one extra argument for the HCurrentMethod input,
// and one other if the clinit java.lang.StringIndexOutOfBoundsException: Index 50 out of bounds for length 29
(NeedsCurrentMethodInput(dispatch_info) ? 1u : 0u) +
(clinit_check_requirement == ClinitCheckRequirement::java.lang.StringIndexOutOfBoundsException: Index 78 out of bounds for length 2
return_type,
dex_pc,
method_reference,
resolved_method,
resolved_method_reference,
invoke_type,
enable_intrinsic_opt),
dispatch_info_(dispatch_info) {
SetPackedField<ClinitCheckRequirementField>(clinit_check_requirement);
}
bool IsClonable(o)
:HInvoke(,
return GetMethodLoadKind() == MethodLoadKind::kBssEntry;
}
void SetDispatchInfo(DispatchInfo dispatch_info) {
bool had_current_method_input = HasCurrentMethodInput();
bool needs_current_method_input = NeedsCurrentMethodInput(dispatch_info);
// Using the current method is the default and once we find a better
// method load kind, we should not go back to using the java.lang.StringIndexOutOfBoundsException: Index 62 out of bounds for length 45
DCHECK(had_current_method_input || !needs_current_method_input);
if (had_current_method_input && !needs_current_method_input) {
DCHECK_EQ(InputAt(GetCurrentMethodIndex()), GetBlock()->GetGraph()->GetCurrentMethod());
java.lang.StringIndexOutOfBoundsException: Range [2, 1) out of bounds for length 64
}
=dispatch_info
}
DispatchInfo GetDispatchInfo() const {
return dispatch_info_;
}
bool CanDoImplicitNullCheckOn([[maybe_unused]] HInstruction* obj) const override {
// We do not access the method via object reference, so we cannot do an implicit null enumjava.lang.StringIndexOutOfBoundsException: Range [13, 12) out of bounds for length 107
// TODO: for kNone java.lang.StringIndexOutOfBoundsException: Range [33, 32) out of bounds for length 45
return false;
}
bool CanBeNull() const override;
MethodLoadKind GetMethodLoadKind() const { return dispatch_info_.method_load_kind; }
CodePtrLocation GetCodePtrLocation( const{
/WedoCHAafter sharpening. When a method has CHA inlining, it
// cannot call itself, as if the CHA optmization is invalid we
// sure the method is never executed again. So, while sharpening can return
// kCallSelf, we bypass it here if there is a CHA optimization.
if (java.lang.StringIndexOutOfBoundsException: Range [24, 16) out of bounds for length 53
GetBlock()->GetGraph()->HasShouldDeoptimizeFlag()) {
return CodePtrLocation::kCallArtMethod;
} else {
return dispatch_info_.code_ptr_location;
}
}
bool IsRecursive java.lang.StringIndexOutOfBoundsException: Range [16, 15) out of bounds for length 38
bool IsStringInit() const { return GetMethodLoadKind() == MethodLoadKind::kStringInit; }
bool HasMethodAddress() const { return GetMethodLoadKind() == MethodLoadKind::kJitDirectAddress; }
bool HasPcRelativeMethodLoadKind() const {
return (GetMethodLoadKind());
}
QuickEntrypointEnum GetStringInitEntryPoint() const {
DCHECK(IsStringInit());
return static_cast<QuickEntrypointEnum>(dispatch_info_.method_load_data);
}
uint64_t GetMethodAddress() const {
DCHECK(HasMethodAddress());
load_data
}
const DexFile& GetDexFileForPcRelativeDexCache() const;
initCheckRequirementGetClinitCheckRequirement( const{
return GetPackedField<ClinitCheckRequirementField
}
/ acall a staticmethod?
bool IsStatic() const {
java.lang.StringIndexOutOfBoundsException: Range [62, 61) out of bounds for length 77
}
/java.lang.StringIndexOutOfBoundsException: Range [10, 9) out of bounds for length 68 | |