Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
Public Member Functions | List of all members
dart::kernel::SwitchHelper Class Reference

#include <kernel_to_il.h>

Public Member Functions

 SwitchHelper (Zone *zone, TokenPosition position, bool is_exhaustive, const AbstractType &expression_type, SwitchBlock *switch_block, intptr_t case_count)
 
bool is_optimizable () const
 
const TokenPositionposition () const
 
bool is_exhaustive () const
 
SwitchBlockswitch_block ()
 
intptr_t case_count () const
 
intptr_t default_case () const
 
void set_default_case (intptr_t index)
 
const GrowableArray< Fragment > & case_bodies () const
 
const GrowableArray< intptr_t > & case_expression_counts () const
 
const GrowableArray< SwitchExpression > & expressions () const
 
const GrowableArray< SwitchExpression * > & sorted_expressions () const
 
const AbstractTypeexpression_type () const
 
const Integerexpression_min () const
 
const Integerexpression_max () const
 
bool has_default () const
 
bool is_enum_switch () const
 
int64_t ExpressionRange () const
 
bool RequiresLowerBoundCheck () const
 
bool RequiresUpperBoundCheck () const
 
SwitchDispatch SelectDispatchStrategy ()
 
void AddCaseBody (Fragment body)
 
void AddExpression (intptr_t case_index, TokenPosition position, const Instance &value)
 

Detailed Description

Definition at line 1002 of file kernel_to_il.h.

Constructor & Destructor Documentation

◆ SwitchHelper()

dart::kernel::SwitchHelper::SwitchHelper ( Zone zone,
TokenPosition  position,
bool  is_exhaustive,
const AbstractType expression_type,
SwitchBlock switch_block,
intptr_t  case_count 
)

Definition at line 5866 of file kernel_to_il.cc.

5872 : zone_(zone),
5873 position_(position),
5874 is_exhaustive_(is_exhaustive),
5875 expression_type_(expression_type),
5876 switch_block_(switch_block),
5877 case_count_(case_count),
5878 case_bodies_(case_count),
5879 case_expression_counts_(case_count),
5880 expressions_(case_count),
5881 sorted_expressions_(case_count) {
5882 case_expression_counts_.FillWith(0, 0, case_count);
5883
5886 is_optimizable_ = true;
5887 } else if (expression_type.HasTypeClass() &&
5889 .is_enum_class()) {
5890 is_optimizable_ = true;
5891 is_enum_switch_ = true;
5892 }
5893 }
5894}
virtual bool HasTypeClass() const
Definition object.h:9063
bool IsSmiType() const
Definition object.h:9226
Nullability nullability() const
Definition object.h:9037
virtual ClassPtr type_class() const
Definition object.cc:21083
bool IsIntType() const
Definition object.cc:21472
void FillWith(const T &value, intptr_t start, intptr_t length)
static Object & Handle()
Definition object.h:407
const AbstractType & expression_type() const
intptr_t case_count() const
const TokenPosition & position() const

Member Function Documentation

◆ AddCaseBody()

void dart::kernel::SwitchHelper::AddCaseBody ( Fragment  body)
inline

Definition at line 1066 of file kernel_to_il.h.

1066{ case_bodies_.Add(body); }

◆ AddExpression()

void dart::kernel::SwitchHelper::AddExpression ( intptr_t  case_index,
TokenPosition  position,
const Instance value 
)

Definition at line 6076 of file kernel_to_il.cc.

6078 {
6079 case_expression_counts_[case_index]++;
6080
6081 expressions_.Add(SwitchExpression(case_index, position, value));
6082
6083 if (is_optimizable_) {
6084 // Check the type of the case expression for use in an optimized switch.
6085 if (!value.IsInstanceOf(expression_type_, Object::null_type_arguments(),
6086 Object::null_type_arguments())) {
6087 is_optimizable_ = false;
6088 }
6089 }
6090}
uint8_t value

◆ case_bodies()

const GrowableArray< Fragment > & dart::kernel::SwitchHelper::case_bodies ( ) const
inline

Definition at line 1027 of file kernel_to_il.h.

1027{ return case_bodies_; }

◆ case_count()

intptr_t dart::kernel::SwitchHelper::case_count ( ) const
inline

Definition at line 1018 of file kernel_to_il.h.

1018{ return case_count_; }

◆ case_expression_counts()

const GrowableArray< intptr_t > & dart::kernel::SwitchHelper::case_expression_counts ( ) const
inline

Definition at line 1030 of file kernel_to_il.h.

1030 {
1031 return case_expression_counts_;
1032 }

◆ default_case()

intptr_t dart::kernel::SwitchHelper::default_case ( ) const
inline

Definition at line 1021 of file kernel_to_il.h.

1021{ return default_case_; }

◆ expression_max()

const Integer & dart::kernel::SwitchHelper::expression_max ( ) const
inline

Definition at line 1049 of file kernel_to_il.h.

1049 {
1050 ASSERT(expression_max_ != nullptr);
1051 return *expression_max_;
1052 }
#define ASSERT(E)

◆ expression_min()

const Integer & dart::kernel::SwitchHelper::expression_min ( ) const
inline

Definition at line 1045 of file kernel_to_il.h.

1045 {
1046 ASSERT(expression_min_ != nullptr);
1047 return *expression_min_;
1048 }

◆ expression_type()

const AbstractType & dart::kernel::SwitchHelper::expression_type ( ) const
inline

Definition at line 1043 of file kernel_to_il.h.

1043{ return expression_type_; }

◆ ExpressionRange()

int64_t dart::kernel::SwitchHelper::ExpressionRange ( ) const

Definition at line 5896 of file kernel_to_il.cc.

5896 {
5897 const int64_t min = expression_min().AsInt64Value();
5898 const int64_t max = expression_max().AsInt64Value();
5899 ASSERT(min <= max);
5900 const uint64_t diff = static_cast<uint64_t>(max) - static_cast<uint64_t>(min);
5901 // Saturate to avoid overflow.
5902 if (diff > static_cast<uint64_t>(kMaxInt64 - 1)) {
5903 return kMaxInt64;
5904 }
5905 return static_cast<int64_t>(diff + 1);
5906}
virtual int64_t AsInt64Value() const
Definition object.cc:23137
const Integer & expression_max() const
const Integer & expression_min() const
static float max(float r, float g, float b)
Definition hsl.cpp:49
static float min(float r, float g, float b)
Definition hsl.cpp:48
constexpr int64_t kMaxInt64
Definition globals.h:486

◆ expressions()

const GrowableArray< SwitchExpression > & dart::kernel::SwitchHelper::expressions ( ) const
inline

Definition at line 1034 of file kernel_to_il.h.

1034 {
1035 return expressions_;
1036 }

◆ has_default()

bool dart::kernel::SwitchHelper::has_default ( ) const
inline

Definition at line 1054 of file kernel_to_il.h.

1054{ return default_case_ >= 0; }

◆ is_enum_switch()

bool dart::kernel::SwitchHelper::is_enum_switch ( ) const
inline

Definition at line 1056 of file kernel_to_il.h.

1056{ return is_enum_switch_; }

◆ is_exhaustive()

bool dart::kernel::SwitchHelper::is_exhaustive ( ) const
inline

Definition at line 1016 of file kernel_to_il.h.

1016{ return is_exhaustive_; }

◆ is_optimizable()

bool dart::kernel::SwitchHelper::is_optimizable ( ) const
inline

Definition at line 1014 of file kernel_to_il.h.

1014{ return is_optimizable_; }

◆ position()

const TokenPosition & dart::kernel::SwitchHelper::position ( ) const
inline

Definition at line 1015 of file kernel_to_il.h.

1015{ return position_; }

◆ RequiresLowerBoundCheck()

bool dart::kernel::SwitchHelper::RequiresLowerBoundCheck ( ) const

Definition at line 5908 of file kernel_to_il.cc.

5908 {
5909 if (is_enum_switch()) {
5910 if (expression_min().IsZero()) {
5911 // Enum indexes are always positive.
5912 return false;
5913 }
5914 }
5915 return true;
5916}
bool IsZero(char *begin, char *end)

◆ RequiresUpperBoundCheck()

bool dart::kernel::SwitchHelper::RequiresUpperBoundCheck ( ) const

Definition at line 5918 of file kernel_to_il.cc.

5918 {
5919 if (is_enum_switch()) {
5920 return has_default() || !is_exhaustive();
5921 }
5922 return true;
5923}

◆ SelectDispatchStrategy()

SwitchDispatch dart::kernel::SwitchHelper::SelectDispatchStrategy ( )

Definition at line 5925 of file kernel_to_il.cc.

5925 {
5926 // For small to medium-sized switches, binary search is faster than a
5927 // jump table.
5928 // Please update runtime/tests/vm/dart/optimized_switch_test.dart
5929 // when changing this constant.
5930 const intptr_t kJumpTableMinExpressions = 16;
5931 // This limit comes from IndirectGotoInstr.
5932 // Realistically, the current limit should never be hit by any code.
5933 const intptr_t kJumpTableMaxSize = kMaxInt32;
5934 // Sometimes the switch expressions don't cover a contiguous range.
5935 // If the ratio of holes to expressions is too great we fall back to a
5936 // binary search to avoid code size explosion.
5937 const double kJumpTableMaxHolesRatio = 1.0;
5938
5939 if (!is_optimizable() || expressions().is_empty()) {
5940 // The switch is not optimizable, so we can only use linear scan.
5942 }
5943
5944 if (!CompilerState::Current().is_aot()) {
5945 // JIT mode supports hot-reload, which currently prevents us from
5946 // enabling optimized switches.
5948 }
5949
5950 if (FLAG_force_switch_dispatch_type == kSwitchDispatchLinearScan) {
5952 }
5953
5954 PrepareForOptimizedSwitch();
5955
5956 if (!is_optimizable()) {
5957 // While preparing for an optimized switch we might have discovered that
5958 // the switch is not optimizable after all.
5960 }
5961
5962 if (FLAG_force_switch_dispatch_type == kSwitchDispatchBinarySearch) {
5964 }
5965
5966 const int64_t range = ExpressionRange();
5967 if (range > kJumpTableMaxSize) {
5969 }
5970
5971 const intptr_t num_expressions = expressions().length();
5972 ASSERT(num_expressions <= range);
5973
5974 const intptr_t max_holes = num_expressions * kJumpTableMaxHolesRatio;
5975 const int64_t holes = range - num_expressions;
5976
5977 if (FLAG_force_switch_dispatch_type != kSwitchDispatchJumpTable) {
5978 if (num_expressions < kJumpTableMinExpressions) {
5980 }
5981
5982 if (holes > max_holes) {
5984 }
5985 }
5986
5987 // After this point we will use a jump table.
5988
5989 // In the general case, bounds checks are required before a jump table
5990 // to handle all possible integer values.
5991 // For enums, the set of possible index values is known and much smaller
5992 // than the set of all possible integer values. A jump table that covers
5993 // either or both bounds of the range of index values requires only one or
5994 // no bounds checks.
5995 // If the expressions of an enum switch don't cover the full range of
5996 // values we can try to extend the jump table to cover the full range, but
5997 // not beyond kJumpTableMaxHolesRatio.
5998 // The count of enum values is not available when the flow graph is
5999 // constructed. The lower bound is always 0 so eliminating the lower
6000 // bound check is still possible by extending expression_min to 0.
6001 //
6002 // In the case of an integer switch we try to extend expression_min to 0
6003 // for a different reason.
6004 // If the range starts at zero it directly maps to the jump table
6005 // and we don't need to adjust the switch variable before the
6006 // jump table.
6007 if (expression_min().AsInt64Value() > 0) {
6008 const intptr_t holes_budget = Utils::Minimum(
6009 // Holes still available.
6010 max_holes - holes,
6011 // Entries left in the jump table.
6012 kJumpTableMaxSize - range);
6013
6014 const int64_t required_holes = expression_min().AsInt64Value();
6015 if (required_holes <= holes_budget) {
6016 expression_min_ = &Object::smi_zero();
6017 }
6018 }
6019
6021}
static void is_empty(skiatest::Reporter *reporter, const SkPath &p)
static CompilerState & Current()
static T Minimum(T x, T y)
Definition utils.h:21
const GrowableArray< SwitchExpression > & expressions() const
int64_t ExpressionRange() const
@ kSwitchDispatchLinearScan
@ kSwitchDispatchBinarySearch
constexpr int32_t kMaxInt32
Definition globals.h:483

◆ set_default_case()

void dart::kernel::SwitchHelper::set_default_case ( intptr_t  index)
inline

Definition at line 1022 of file kernel_to_il.h.

1022 {
1023 ASSERT(default_case_ == -1);
1024 default_case_ = index;
1025 }

◆ sorted_expressions()

const GrowableArray< SwitchExpression * > & dart::kernel::SwitchHelper::sorted_expressions ( ) const
inline

Definition at line 1038 of file kernel_to_il.h.

1038 {
1039 return sorted_expressions_;
1040 }

◆ switch_block()

SwitchBlock * dart::kernel::SwitchHelper::switch_block ( )
inline

Definition at line 1017 of file kernel_to_il.h.

1017{ return switch_block_; }

The documentation for this class was generated from the following files: