/* Ċ Ġ* ĠCopyright Ġ 2 0 1 0 - 2 0 1 9 ĠJetBrains Ġs . r . o . Ġand ĠKotlin ĠProgramming ĠLanguage Ġcontributors . Ċ Ġ* ĠUse Ġof Ġthis Ġsource Ġcode Ġis Ġgoverned Ġby Ġthe ĠApache Ġ 2 . 0 Ġlicense Ġthat Ġcan Ġbe Ġfound Ġin Ġthe Ġlicense / LICENSE . txt Ġfile . Ċ Ġ*/ Ċ Ċ package Ġorg . jetbrains . kotlin . backend . jvm . codegen Ċ Ċ import Ġorg . jetbrains . kotlin . codegen .` when `. Switch Code gen . Companion . prefer Lookup Over Switch Ċ import Ġorg . jetbrains . kotlin . ir . expressions .* Ċ import Ġorg . jetbrains . kotlin . ir . types .* Ċ import Ġorg . jetbrains . kotlin . ir . util . dump Ċ import Ġorg . jetbrains . kotlin . ir . util . isTrue Const Ċ import Ġorg . jetbrains . org . object web . asm . Label Ċ import Ġjava . util .* Ċ Ċ // ĠTODO : Ġeliminate Ġthe Ġtemporary Ġvariable Ċ class ĠSwitch Generator ( private Ġval Ġexpression : ĠIr When , Ġprivate Ġval Ġdata : ĠBlock Info , Ġprivate Ġval Ġcodegen : ĠExpression Code gen ) Ġ{ ĊĠĠĠ Ġdata Ġclass ĠExpression To Label ( val Ġexpression : ĠIr Expression , Ġval Ġlabel : ĠLabel ) ĊĠĠĠ Ġdata Ġclass ĠCall To Label ( val Ġcall : ĠIr Call , Ġval Ġlabel : ĠLabel ) ĊĠĠĠ Ġdata Ġclass ĠValue To Label ( val Ġvalue : ĠAny ?, Ġval Ġlabel : ĠLabel ) ĊĊĠĠĠ Ġ// Ġ@ return Ġnull Ġif Ġthe ĠIr When Ġcannot Ġbe Ġemitted Ġas Ġlookup switch Ġor Ġtable switch . ĊĠĠĠ Ġfun Ġgenerate (): ĠPromise d Value ? Ġ{ ĊĠĠĠĠĠĠĠ Ġval Ġexpression To Labels Ġ= ĠArrayList < Expression To Label >() ĊĠĠĠĠĠĠĠ Ġvar Ġelse Expression : ĠIr Expression ? Ġ= Ġnull ĊĠĠĠĠĠĠĠ Ġval Ġcall To Labels Ġ= ĠArrayList < Call To Label >() ĊĊĠĠĠĠĠĠĠ Ġ// ĠParse Ġthe Ġwhen Ġstructure . ĠNote Ġthat Ġthe Ġcondition Ġcan Ġbe Ġnested . ĠSee Ġmatch Conditions () Ġfor Ġdetails . ĊĠĠĠĠĠĠĠ Ġfor Ġ( branch Ġin Ġexpression . branches ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( branch Ġis ĠIr Else Branch ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġelse Expression Ġ= Ġbranch . result ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġelse Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġconditions Ġ= Ġmatch Conditions ( branch . condition ) Ġ?: Ġreturn Ġnull ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġthen Label Ġ= ĠLabel () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġexpression To Labels . add ( Expression To Label ( branch . result , Ġthen Label )) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġcall To Labels Ġ+= Ġconditions . map Ġ{ ĠCall To Label ( it , Ġthen Label ) Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġ// Ġswitch Ġisn 't Ġapplicable Ġif Ġthere 's Ġno Ġcase Ġat Ġall , Ġe . g ., Ġwhen () Ġ{ Ġelse Ġ-> Ġ... Ġ} ĊĠĠĠĠĠĠĠ Ġif Ġ( call To Labels . size Ġ== Ġ 0 ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġreturn Ġnull ĊĊĠĠĠĠĠĠĠ Ġval Ġcalls Ġ= Ġcall To Labels . map Ġ{ Ġit . call Ġ} ĊĊĠĠĠĠĠĠĠ Ġ// ĠChecks Ġif Ġall Ġconditions Ġare ĠCALL ĠE Q EQ ( tmp _ variable , Ġsome _ constant ) ĊĠĠĠĠĠĠĠ Ġif Ġ(! are Const Comp arisons ( calls )) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġreturn Ġnull ĊĊĠĠĠĠĠĠĠ Ġ// ĠSubject Ġshould Ġbe Ġthe Ġsame Ġfor Ġall Ġconditions . ĠLet 's Ġpick Ġthe Ġfirst . ĊĠĠĠĠĠĠĠ Ġval Ġsubject Ġ= Ġcall To Labels [ 0 ]. call . getValue Argument ( 0 ) !! Ġas ĠIr GetValue ĊĊĠĠĠĠĠĠĠ Ġ// ĠDon 't Ġgenerate Ġrepeated Ġcases , Ġwhich Ġare Ġunreachable Ġbut Ġallowed Ġin ĠKotlin . ĊĠĠĠĠĠĠĠ Ġ// ĠOnly Ġkeep Ġthe Ġfirst Ġencountered Ġcase : ĊĠĠĠĠĠĠĠ Ġval Ġcases Ġ= ĊĠĠĠĠĠĠĠĠĠĠĠ Ġcall To Labels . map Ġ{ ĠValue To Label (( it . call . getValue Argument ( 1 ) Ġas ĠIr Const < *> ). value , Ġit . label ) Ġ}. distinct By Ġ{ Ġit . value Ġ} ĊĊĠĠĠĠĠĠĠ Ġ// ĠRemove Ġlabels Ġand Ġ" then Ġexpressions " Ġthat Ġare Ġnot Ġreachable . ĊĠĠĠĠĠĠĠ Ġval Ġreachable Labels Ġ= ĠHashSet ( cases . map Ġ{ Ġit . label Ġ}) ĊĠĠĠĠĠĠĠ Ġexpression To Labels . remove If Ġ{ Ġit . label Ġ! in Ġreachable Labels Ġ} ĊĊĠĠĠĠĠĠĠ Ġreturn Ġwhen Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġare Const Int Comp arisons ( calls ) Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠInt Switch ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġsubject , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġelse Expression , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġexpression To Labels , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġcases ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġare Const String Comp arisons ( calls ) Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠString Switch ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġsubject , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġelse Expression , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġexpression To Labels , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġcases ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġelse Ġ-> Ġnull Ġ// ĠTODO : ĠEnum , Ġetc . ĊĠĠĠĠĠĠĠ Ġ} ?. gen Optim ized If En ough Cases () ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun Ġare Const Comp arisons ( conditions : ĠList < Ir Call >): ĠBoolean Ġ{ ĊĠĠĠĠĠĠĠ Ġ// ĠAll Ġbranches Ġmust Ġbe ĠCALL Ġ' EQ EQ ( Any ?, ĠAny ?) ': ĠBoolean ĊĠĠĠĠĠĠĠ Ġif Ġ( conditions . any Ġ{ Ġit . symbol Ġ!= Ġcodegen . class Code gen . context . ir Built Ins . eq eq Symbol Ġ}) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġreturn Ġfalse ĊĊĠĠĠĠĠĠĠ Ġ// ĠAll ĠL HS Ġrefer Ġto Ġthe Ġsame Ġtmp Ġvariable . ĊĠĠĠĠĠĠĠ Ġval Ġlhs Ġ= Ġconditions . map Ġ{ Ġit . getValue Argument ( 0 ) Ġas ? ĠIr GetValue Ġ} ĊĠĠĠĠĠĠĠ Ġif Ġ( lhs . any Ġ{ Ġit Ġ== Ġnull Ġ|| Ġit . symbol Ġ!= Ġlhs [ 0 ] !!. symbol Ġ}) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġreturn Ġfalse ĊĊĠĠĠĠĠĠĠ Ġ// ĠAll ĠRHS Ġare Ġconstants ĊĠĠĠĠĠĠĠ Ġif Ġ( conditions . any Ġ{ Ġit . getValue Argument ( 1 ) Ġ! is ĠIr Const < *> Ġ}) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġreturn Ġfalse ĊĊĠĠĠĠĠĠĠ Ġreturn Ġtrue ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun Ġare Const Int Comp arisons ( conditions : ĠList < Ir Call >): ĠBoolean Ġ{ ĊĠĠĠĠĠĠĠ Ġreturn Ġcheck Type Specific s ( conditions , Ġ{ Ġit . is Int () Ġ}, Ġ{ Ġit . kind Ġ== ĠIr Const Kind . Int Ġ}) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun Ġare Const String Comp arisons ( conditions : ĠList < Ir Call >): ĠBoolean Ġ{ ĊĠĠĠĠĠĠĠ Ġreturn Ġcheck Type Specific s ( ĊĠĠĠĠĠĠĠĠĠĠĠ Ġconditions , ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ{ Ġit . isString () Ġ|| Ġit . is Nullable String () Ġ}, ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ{ Ġit . kind Ġ== ĠIr Const Kind . String Ġ|| Ġit . kind Ġ== ĠIr Const Kind . Null Ġ}) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun Ġcheck Type Specific s ( ĊĠĠĠĠĠĠĠ Ġconditions : ĠList < Ir Call >, ĊĠĠĠĠĠĠĠ Ġsubject Type Predicate : Ġ( Ir Type ) Ġ-> ĠBoolean , ĊĠĠĠĠĠĠĠ Ġir Const Predicate : Ġ( Ir Const <* >) Ġ-> ĠBoolean ĊĠĠĠ Ġ): ĠBoolean Ġ{ ĊĠĠĠĠĠĠĠ Ġval Ġlhs Ġ= Ġconditions . map Ġ{ Ġit . getValue Argument ( 0 ) Ġas ĠIr GetValue Ġ} ĊĠĠĠĠĠĠĠ Ġif Ġ( lhs . any Ġ{ Ġ! subject Type Predicate ( it . type ) Ġ}) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġreturn Ġfalse ĊĊĠĠĠĠĠĠĠ Ġval Ġrhs Ġ= Ġconditions . map Ġ{ Ġit . getValue Argument ( 1 ) Ġas ĠIr Const < *> Ġ} ĊĠĠĠĠĠĠĠ Ġif Ġ( rhs . any Ġ{ Ġ! ir Const Predicate ( it ) Ġ}) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġreturn Ġfalse ĊĊĠĠĠĠĠĠĠ Ġreturn Ġtrue ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ// Ġpsi 2 ir Ġlow ers Ġmultiple Ġcases Ġto Ġnested Ġconditions . ĠFor Ġexample , ĊĠĠĠ Ġ// ĊĠĠĠ Ġ// Ġwhen Ġ( subject ) Ġ{ ĊĠĠĠ Ġ// ĠĠ Ġa , Ġb , Ġc Ġ-> Ġaction ĊĠĠĠ Ġ// Ġ} ĊĠĠĠ Ġ// ĊĠĠĠ Ġ// Ġis Ġlower ed Ġto ĊĠĠĠ Ġ// ĊĠĠĠ Ġ// Ġif Ġ( if Ġ( subject Ġ== Ġa ) ĊĠĠĠ Ġ// ĠĠĠĠĠĠ Ġtrue ĊĠĠĠ Ġ// ĠĠĠĠ Ġelse ĊĠĠĠ Ġ// ĠĠĠĠĠĠ Ġif Ġ( subject Ġ== Ġb ) ĊĠĠĠ Ġ// ĠĠĠĠĠĠĠĠ Ġtrue ĊĠĠĠ Ġ// ĠĠĠĠĠĠ Ġelse ĊĠĠĠ Ġ// ĠĠĠĠĠĠĠĠ Ġsubject Ġ== Ġc ) Ġ{ ĊĠĠĠ Ġ// ĠĠĠĠ Ġaction ĊĠĠĠ Ġ// Ġ} ĊĠĠĠ Ġ// ĊĠĠĠ Ġ// Ġ@ return Ġtrue Ġif Ġthe Ġconditions Ġare Ġequality Ġchecks Ġof Ġconstants . ĊĠĠĠ Ġprivate Ġfun Ġmatch Conditions ( condition : ĠIr Expression ): ĠArrayList < Ir Call >? Ġ{ ĊĠĠĠĠĠĠĠ Ġif Ġ( condition Ġis ĠIr Call ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġreturn Ġarray ListOf ( condition ) ĊĠĠĠĠĠĠĠ Ġ} Ġelse Ġif Ġ( condition Ġis ĠIr When Ġ&& Ġcondition . origin Ġ== ĠIr Statement Origin . WHEN _ COMMA ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġassert ( condition . type . is Boolean ()) Ġ{ Ġ" WHEN _ COMMA Ġshould Ġalways Ġbe Ġa ĠBoolean : Ġ${ condition . dump () }" Ġ} ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġcandidates Ġ= ĠArrayList < Ir Call >() ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġ// ĠMatch Ġthe Ġfollowing Ġstructure : ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ// ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ// Ġwhen () Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ// ĠĠ Ġcond _ 1 Ġ-> Ġtrue ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ// ĠĠ Ġcond _ 2 Ġ-> Ġtrue ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ// ĠĠ Ġ... ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ// ĠĠ Ġelse Ġ-> Ġcond _ N ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ// Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ// ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ// ĠName ly , Ġthe Ġstructure Ġwhich Ġreturns Ġtrue Ġif Ġany Ġone Ġof Ġthe Ġcondition Ġis Ġtrue . ĊĠĠĠĠĠĠĠĠĠĠĠ Ġfor Ġ( branch Ġin Ġcondition . branches ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( branch Ġis ĠIr Else Branch ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġassert ( branch . condition . isTrue Const ()) Ġ{ Ġ" Ir Else Branch . condition Ġshould Ġbe Ġconst Ġtrue : Ġ${ branch . condition . dump () }" Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġcandidates Ġ+= Ġmatch Conditions ( branch . result ) Ġ?: Ġreturn Ġnull ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġelse Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ(! branch . result . isTrue Const ()) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġreturn Ġnull ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġcandidates Ġ+= Ġmatch Conditions ( branch . condition ) Ġ?: Ġreturn Ġnull ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġreturn Ġif Ġ( candidates . isNotEmpty ()) Ġcandidates Ġelse Ġreturn Ġnull ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġreturn Ġnull ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġabstract Ġinner Ġclass ĠSwitch ( ĊĠĠĠĠĠĠĠ Ġval Ġsubject : ĠIr GetValue , ĊĠĠĠĠĠĠĠ Ġval Ġelse Expression : ĠIr Expression ?, ĊĠĠĠĠĠĠĠ Ġval Ġexpression To Labels : ĠArrayList < Expression To Label > ĊĠĠĠ Ġ) Ġ{ ĊĠĠĠĠĠĠĠ Ġprotected Ġval Ġdefault Label Ġ= ĠLabel () ĊĊĠĠĠĠĠĠĠ Ġopen Ġfun Ġshould Optimize () Ġ= Ġfalse ĊĊĠĠĠĠĠĠĠ Ġopen Ġfun Ġgen Optim ized If En ough Cases (): ĠPromise d Value ? Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ(! should Optimize ()) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġreturn Ġnull ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġgen Switch () ĊĠĠĠĠĠĠĠĠĠĠĠ Ġreturn Ġgen Branch Targets () ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġprotected Ġabstract Ġfun Ġgen Switch () ĊĊĠĠĠĠĠĠĠ Ġprotected Ġfun Ġgen Int Switch ( un sorted Int Cases : ĠList < Value To Label >) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġint Cases Ġ= Ġun sorted Int Cases . sorted By Ġ{ Ġit . value Ġas ĠInt Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġcase Min Ġ= Ġint Cases . first (). value Ġas ĠInt ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġcase Max Ġ= Ġint Cases . last (). value Ġas ĠInt ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġrange Length Ġ= Ġcase Max . to Long () Ġ- Ġcase Min . to Long () Ġ+ Ġ 1 L ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġ// ĠEmit Ġeither Ġtable switch Ġor Ġlookup switch , Ġdepending Ġon Ġthe Ġcode Ġsize . ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ// ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ// Ġlookup switch Ġis Ġ 2 X Ġas Ġlarge Ġas Ġtable switch Ġwith Ġthe Ġsame Ġentries . ĠHowever , Ġlookup switch Ġis Ġsparse Ġwhile Ġtable switch Ġmust ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ// Ġenumerate Ġall Ġthe Ġentries Ġin Ġthe Ġrange . ĊĠĠĠĠĠĠĠĠĠĠĠ Ġwith ( codegen ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( prefer Lookup Over Switch ( int Cases . size , Ġrange Length )) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġmv . lookup switch ( default Label , Ġint Cases . map Ġ{ Ġit . value Ġas ĠInt Ġ}. to IntArray (), Ġint Cases . map Ġ{ Ġit . label Ġ}. to Typed Array ()) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġelse Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġlabels Ġ= ĠArray ( range Length . toInt ()) Ġ{ Ġdefault Label Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġfor Ġ( case Ġin Ġint Cases ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġlabels [ case . value Ġas ĠInt Ġ- Ġcase Min ] Ġ= Ġcase . label ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġmv . table switch ( case Min , Ġcase Max , Ġdefault Label , Ġ* labels ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġprotected Ġfun Ġgen Branch Targets (): ĠPromise d Value Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġwith ( codegen ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġend Label Ġ= ĠLabel () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġfor Ġ(( then Expression , Ġlabel ) Ġin Ġexpression To Labels ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġmv . visit Label ( label ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġthen Expression . accept ( codegen , Ġdata ). coerce ( expression . asm Type ). material ized ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġmv . goTo ( end Label ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġmv . visit Label ( default Label ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġstack Value Ġ= Ġelse Expression ?. accept ( codegen , Ġdata ) Ġ?: Ġvoid Value ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġresult Ġ= Ġstack Value . coerce ( expression . asm Type ). material ized ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġmv . mark ( end Label ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġreturn Ġresult ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġinner Ġclass ĠInt Switch ( ĊĠĠĠĠĠĠĠ Ġsubject : ĠIr GetValue , ĊĠĠĠĠĠĠĠ Ġelse Expression : ĠIr Expression ?, ĊĠĠĠĠĠĠĠ Ġexpression To Labels : ĠArrayList < Expression To Label >, ĊĠĠĠĠĠĠĠ Ġprivate Ġval Ġcases : ĠList < Value To Label > ĊĠĠĠ Ġ) Ġ: ĠSwitch ( subject , Ġelse Expression , Ġexpression To Labels ) Ġ{ ĊĊĠĠĠĠĠĠĠ Ġ// ĠIF Ġis Ġmore Ġcompact Ġwhen Ġthere Ġare Ġonly Ġ 1 Ġor Ġfewer Ġbranches , Ġin Ġaddition Ġto Ġelse . ĊĠĠĠĠĠĠĠ Ġoverride Ġfun Ġshould Optimize () Ġ= Ġcases . size Ġ> Ġ 1 ĊĊĠĠĠĠĠĠĠ Ġoverride Ġfun Ġgen Switch () Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġwith ( codegen ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġsubject . accept ( codegen , Ġdata ). material ize () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġgen Int Switch ( cases ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ// ĠThe Ġfollowing Ġwhen Ġstructure : ĊĠĠĠ Ġ// ĊĠĠĠ Ġ// ĠĠ Ġwhen Ġ( s ) Ġ{ ĊĠĠĠ Ġ// ĠĠĠĠ Ġs 1 , Ġs 2 Ġ-> Ġe 1 , ĊĠĠĠ Ġ// ĠĠĠĠ Ġs 3 Ġ-> Ġe 2 , ĊĠĠĠ Ġ// ĠĠĠĠ Ġs 4 Ġ-> Ġe 3 , ĊĠĠĠ Ġ// ĠĠĠĠ Ġ... ĊĠĠĠ Ġ// ĠĠĠĠ Ġelse Ġ-> Ġe ĊĠĠĠ Ġ// ĠĠ Ġ} ĊĠĠĠ Ġ// ĊĠĠĠ Ġ// Ġis Ġimplemented Ġas : ĊĠĠĠ Ġ// ĊĠĠĠ Ġ// ĠĠ Ġ// Ġif Ġs Ġis ĠString ?, Ġgenerate Ġthe Ġfollowing Ġnull Ġcheck : ĊĠĠĠ Ġ// ĠĠ Ġif Ġ( s Ġ== Ġnull ) ĊĠĠĠ Ġ// ĠĠĠĠ Ġ// Ġjump Ġto Ġthe Ġcase Ġwhere Ġnull Ġis Ġhandled , Ġif Ġdefined . ĊĠĠĠ Ġ// ĠĠĠĠ Ġ// Ġotherwise , Ġjump Ġout Ġof Ġthe Ġwhen (). ĊĠĠĠ Ġ// ĠĠĠĠ Ġ... ĊĠĠĠ Ġ// ĠĠ Ġ... ĊĠĠĠ Ġ// ĠĠ Ġwhen Ġ( s . hashCode ()) Ġ{ ĊĠĠĠ Ġ// ĠĠĠĠ Ġh 1 Ġ-> Ġ{ ĊĠĠĠ Ġ// ĠĠĠĠĠĠ Ġif Ġ( s Ġ== Ġs 1 ) ĊĠĠĠ Ġ// ĠĠĠĠĠĠĠĠ Ġe 1 ĊĠĠĠ Ġ// ĠĠĠĠĠĠ Ġelse Ġif Ġ( s Ġ== Ġs 2 ) ĊĠĠĠ Ġ// ĠĠĠĠĠĠĠĠ Ġe 1 ĊĠĠĠ Ġ// ĠĠĠĠĠĠ Ġelse Ġif Ġ( s Ġ== Ġs 3 ) ĊĠĠĠ Ġ// ĠĠĠĠĠĠĠĠ Ġe 2 ĊĠĠĠ Ġ// ĠĠĠĠĠĠ Ġelse ĊĠĠĠ Ġ// ĠĠĠĠĠĠĠĠ Ġe ĊĠĠĠ Ġ// ĠĠĠĠ Ġ} ĊĠĠĠ Ġ// ĠĠĠĠ Ġh 2 Ġ-> Ġif Ġ( s Ġ== Ġs 3 ) Ġe 2 Ġelse Ġe , ĊĠĠĠ Ġ// ĠĠĠĠ Ġ... ĊĠĠĠ Ġ// ĠĠĠĠ Ġelse Ġ-> Ġe ĊĠĠĠ Ġ// ĠĠ Ġ} ĊĠĠĠ Ġ// ĊĠĠĠ Ġ// Ġwhere Ġs 1 . hashCode () Ġ== Ġs 2 . hashCode () Ġ== Ġs 3 . hashCode () Ġ== Ġh 1 , ĊĠĠĠ Ġ// ĠĠĠĠĠĠ Ġs 4 . hashCode () Ġ== Ġh 2 . ĊĠĠĠ Ġ// ĊĠĠĠ Ġ// ĠA Ġtable switch Ġor Ġlookup switch Ġis Ġthen Ġused Ġfor Ġthe Ġhash Ġcode Ġlookup . ĊĊĠĠĠ Ġinner Ġclass ĠString Switch ( ĊĠĠĠĠĠĠĠ Ġsubject : ĠIr GetValue , ĊĠĠĠĠĠĠĠ Ġelse Expression : ĠIr Expression ?, ĊĠĠĠĠĠĠĠ Ġexpression To Labels : ĠArrayList < Expression To Label >, ĊĠĠĠĠĠĠĠ Ġprivate Ġval Ġcases : ĠList < Value To Label > ĊĠĠĠ Ġ) Ġ: ĠSwitch ( subject , Ġelse Expression , Ġexpression To Labels ) Ġ{ ĊĊĠĠĠĠĠĠĠ Ġprivate Ġval Ġhash ToString And Expr Labels Ġ= ĠHashMap < Int , ĠArrayList < Value To Label >>() ĊĠĠĠĠĠĠĠ Ġprivate Ġval Ġhash And Switch Labels Ġ= ĠArrayList < Value To Label >() ĊĊĠĠĠĠĠĠĠ Ġinit Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġfor Ġ( case Ġin Ġcases ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( case . value Ġ!= Ġnull ) Ġ// Ġnull Ġis Ġhandled Ġspec ially Ġand Ġwill Ġnever Ġbe Ġdis patched Ġfrom Ġthe Ġswitch . ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġhash ToString And Expr Labels . get Or Put ( case . value . hashCode ()) Ġ{ ĠArrayList () Ġ}. add ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠValue To Label ( case . value , Ġcase . label ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ) ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġfor Ġ( key Ġin Ġhash ToString And Expr Labels . keys ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġhash And Switch Labels . add ( Value To Label ( key , ĠLabel ())) ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġ// ĠUsing Ġa Ġswitch , Ġthe Ġsubject Ġstring Ġhas Ġto Ġbe Ġtra versed Ġat Ġleast Ġtwice Ġ( hash Ġ+ Ġcomparison Ġ* ĠN , Ġwhere ĠN Ġis Ġ# strings Ġhashed Ġinto Ġthe ĊĠĠĠĠĠĠĠ Ġ// Ġsame Ġbucket ). ĠThe Ġoptimization Ġisn 't Ġbetter Ġthan Ġan ĠIF Ġcascade Ġwhen Ġ# switch - targets Ġ<= Ġ 2 . ĊĠĠĠĠĠĠĠ Ġoverride Ġfun Ġshould Optimize () Ġ= Ġhash And Switch Labels . size Ġ> Ġ 2 ĊĊĠĠĠĠĠĠĠ Ġoverride Ġfun Ġgen Switch () Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġwith ( codegen ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( subject . type . is Nullable String ()) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġsubject . accept ( codegen , Ġdata ). material ize () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġmv . if null ( cases . find Ġ{ Ġit . value Ġ== Ġnull Ġ} ?. label Ġ?: Ġdefault Label ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ// ĠRe evalu ating Ġthe Ġsubject Ġis Ġfine Ġhere Ġbecause Ġit Ġis Ġa Ġread Ġof Ġa Ġtemporary . ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġsubject . accept ( codegen , Ġdata ). material ize () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġmv . invokevirtual (" java / lang / String ", Ġ" hashCode ", Ġ" () I ", Ġfalse ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġgen Int Switch ( hash And Switch Labels ) ĊĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ// ĠMultiple Ġstrings Ġcan Ġbe Ġhashed Ġinto Ġthe Ġsame Ġbucket . ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ// ĠGenerate Ġan Ġif Ġcascade Ġto Ġresolve Ġthat Ġfor Ġeach Ġbucket . ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġfor Ġ(( hash , Ġswitch Label ) Ġin Ġhash And Switch Labels ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġmv . visit Label ( switch Label ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġfor Ġ(( string , Ġlabel ) Ġin Ġhash ToString And Expr Labels [ hash ] !! ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġsubject . accept ( codegen , Ġdata ). material ize () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġmv . acon st ( string ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġmv . invokevirtual (" java / lang / String ", Ġ" equals ", Ġ"( Ljava / lang / Object ;) Z ", Ġfalse ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġmv . if ne ( label ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġmv . goTo ( default Label ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} Ċ } Ċ