Flutter Engine
The Flutter Engine
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 5833 of file kernel_to_il.cc.

5839 : zone_(zone),
5840 position_(position),
5841 is_exhaustive_(is_exhaustive),
5842 expression_type_(expression_type),
5843 switch_block_(switch_block),
5844 case_count_(case_count),
5845 case_bodies_(case_count),
5846 case_expression_counts_(case_count),
5847 expressions_(case_count),
5848 sorted_expressions_(case_count) {
5849 case_expression_counts_.FillWith(0, 0, case_count);
5850
5853 is_optimizable_ = true;
5854 } else if (expression_type.HasTypeClass() &&
5856 .is_enum_class()) {
5857 is_optimizable_ = true;
5858 is_enum_switch_ = true;
5859 }
5860 }
5861}
virtual bool HasTypeClass() const
Definition: object.h:9083
bool IsSmiType() const
Definition: object.h:9246
Nullability nullability() const
Definition: object.h:9060
virtual ClassPtr type_class() const
Definition: object.cc:21042
bool IsIntType() const
Definition: object.cc:21411
void FillWith(const T &value, intptr_t start, intptr_t length)
static Object & Handle()
Definition: object.h:407
const AbstractType & expression_type() const
SwitchBlock * switch_block()
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 6043 of file kernel_to_il.cc.

6045 {
6046 case_expression_counts_[case_index]++;
6047
6048 expressions_.Add(SwitchExpression(case_index, position, value));
6049
6050 if (is_optimizable_) {
6051 // Check the type of the case expression for use in an optimized switch.
6052 if (!value.IsInstanceOf(expression_type_, Object::null_type_arguments(),
6053 Object::null_type_arguments())) {
6054 is_optimizable_ = false;
6055 }
6056 }
6057}
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 5863 of file kernel_to_il.cc.

5863 {
5864 const int64_t min = expression_min().AsInt64Value();
5865 const int64_t max = expression_max().AsInt64Value();
5866 ASSERT(min <= max);
5867 const uint64_t diff = static_cast<uint64_t>(max) - static_cast<uint64_t>(min);
5868 // Saturate to avoid overflow.
5869 if (diff > static_cast<uint64_t>(kMaxInt64 - 1)) {
5870 return kMaxInt64;
5871 }
5872 return static_cast<int64_t>(diff + 1);
5873}
virtual int64_t AsInt64Value() const
Definition: object.cc:23058
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 5875 of file kernel_to_il.cc.

5875 {
5876 if (is_enum_switch()) {
5877 if (expression_min().IsZero()) {
5878 // Enum indexes are always positive.
5879 return false;
5880 }
5881 }
5882 return true;
5883}
bool IsZero(char *begin, char *end)

◆ RequiresUpperBoundCheck()

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

Definition at line 5885 of file kernel_to_il.cc.

5885 {
5886 if (is_enum_switch()) {
5887 return has_default() || !is_exhaustive();
5888 }
5889 return true;
5890}

◆ SelectDispatchStrategy()

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

Definition at line 5892 of file kernel_to_il.cc.

5892 {
5893 // For small to medium-sized switches, binary search is faster than a
5894 // jump table.
5895 // Please update runtime/tests/vm/dart/optimized_switch_test.dart
5896 // when changing this constant.
5897 const intptr_t kJumpTableMinExpressions = 16;
5898 // This limit comes from IndirectGotoInstr.
5899 // Realistically, the current limit should never be hit by any code.
5900 const intptr_t kJumpTableMaxSize = kMaxInt32;
5901 // Sometimes the switch expressions don't cover a contiguous range.
5902 // If the ratio of holes to expressions is too great we fall back to a
5903 // binary search to avoid code size explosion.
5904 const double kJumpTableMaxHolesRatio = 1.0;
5905
5906 if (!is_optimizable() || expressions().is_empty()) {
5907 // The switch is not optimizable, so we can only use linear scan.
5909 }
5910
5911 if (!CompilerState::Current().is_aot()) {
5912 // JIT mode supports hot-reload, which currently prevents us from
5913 // enabling optimized switches.
5915 }
5916
5917 if (FLAG_force_switch_dispatch_type == kSwitchDispatchLinearScan) {
5919 }
5920
5921 PrepareForOptimizedSwitch();
5922
5923 if (!is_optimizable()) {
5924 // While preparing for an optimized switch we might have discovered that
5925 // the switch is not optimizable after all.
5927 }
5928
5929 if (FLAG_force_switch_dispatch_type == kSwitchDispatchBinarySearch) {
5931 }
5932
5933 const int64_t range = ExpressionRange();
5934 if (range > kJumpTableMaxSize) {
5936 }
5937
5938 const intptr_t num_expressions = expressions().length();
5939 ASSERT(num_expressions <= range);
5940
5941 const intptr_t max_holes = num_expressions * kJumpTableMaxHolesRatio;
5942 const int64_t holes = range - num_expressions;
5943
5944 if (FLAG_force_switch_dispatch_type != kSwitchDispatchJumpTable) {
5945 if (num_expressions < kJumpTableMinExpressions) {
5947 }
5948
5949 if (holes > max_holes) {
5951 }
5952 }
5953
5954 // After this point we will use a jump table.
5955
5956 // In the general case, bounds checks are required before a jump table
5957 // to handle all possible integer values.
5958 // For enums, the set of possible index values is known and much smaller
5959 // than the set of all possible integer values. A jump table that covers
5960 // either or both bounds of the range of index values requires only one or
5961 // no bounds checks.
5962 // If the expressions of an enum switch don't cover the full range of
5963 // values we can try to extend the jump table to cover the full range, but
5964 // not beyond kJumpTableMaxHolesRatio.
5965 // The count of enum values is not available when the flow graph is
5966 // constructed. The lower bound is always 0 so eliminating the lower
5967 // bound check is still possible by extending expression_min to 0.
5968 //
5969 // In the case of an integer switch we try to extend expression_min to 0
5970 // for a different reason.
5971 // If the range starts at zero it directly maps to the jump table
5972 // and we don't need to adjust the switch variable before the
5973 // jump table.
5974 if (expression_min().AsInt64Value() > 0) {
5975 const intptr_t holes_budget = Utils::Minimum(
5976 // Holes still available.
5977 max_holes - holes,
5978 // Entries left in the jump table.
5979 kJumpTableMaxSize - range);
5980
5981 const int64_t required_holes = expression_min().AsInt64Value();
5982 if (required_holes <= holes_budget) {
5983 expression_min_ = &Object::smi_zero();
5984 }
5985 }
5986
5988}
static void is_empty(skiatest::Reporter *reporter, const SkPath &p)
static CompilerState & Current()
static T Minimum(T x, T y)
Definition: utils.h:36
const GrowableArray< SwitchExpression > & expressions() const
int64_t ExpressionRange() const
@ kSwitchDispatchLinearScan
Definition: kernel_to_il.h:921
@ kSwitchDispatchJumpTable
Definition: kernel_to_il.h:923
@ kSwitchDispatchBinarySearch
Definition: kernel_to_il.h:922
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: