Title:
casting switch case values causes internal exceptions, slowing down execution
| View in TrackerStatus/Resolution/Reason: Closed/Fixed/Fixed
Reporter/Name(from Bugbase): Alexander Kwaschny / Alexander Kwaschny ()
Created: 07/09/2017
Components: Language, Expressions
Versions: 2016,11.0,10.0
Failure Type: Others
Found In Build/Fixed In Build: all / CF2018.0.0.30436
Priority/Frequency: Normal / Some users will encounter
Locale/System: / Core
Vote Count: 0
Consider the following example code:
<cfset x = "foo">
<cfloop from="1" to="100000" index="i">
<cfswitch expression="#x#">
<cfcase value="bar">
</cfcase>
</cfswitch>
</cfloop>
(For the sake of simplicity I omitted further `<cfcase>` entries. It does not change the observation.)
The code example takes a whopping 5,5 seconds on my machine. So why is that? Let's profile:
coldfusion.runtime.CfJspPage.__caseValue
73% coldfusion.runtime.Cast._Date
22% coldfusion.runtime.Cast._double
So CF casts all case values every time a switch runs. But let's go deeper:
coldfusion.runtime.Cast._Date
coldfusion.runtime.CFPage.internal_LSParseDateTime
coldfusion.util.DateUtils.parseDateTime
coldfusion.runtime.locale.CFLocaleBase.ParseDateTime
coldfusion.runtime.locale.CFLocaleBase$InvalidDateTimeException.<init>
coldfusion.runtime.ExpressionException.<init>
coldfusion.runtime.NeoException.<init>
java.lang.RuntimeException.<init>
java.lang.Exception.<init>
java.lang.Throwable.<init>
java.lang.Throwable.fillInStackTrace
Wait, what? It's already bad enough that CF uses the old date stuff from Java (wrapped in `coldfusion.runtime.locale.CFLocaleBase`), which needs to run in a synchronized methods/blocks to be threadsafe, but no, the actual cause of the sluggish cast are exceptions, i.e. the stacktrace!
Since `bar` is not a valid/castable date, internal exceptions are thrown? What if I do:
<cfset x = now()>
<cfloop from="1" to="100000" index="i">
<cfswitch expression="#x#">
<cfcase value="{ts '2017-01-01 00:00:00'}">
</cfcase>
</cfswitch>
</cfloop>
Surprise, it only took a few milliseconds to execute this. And you guessed right: because there are no more internal exceptions when casting the case value.
Casting to Double (`coldfusion.runtime.Cast._double`) behaves exactly the same by the way.
Workaround
When switching strings, you are better of using `if/elseif/else` to prevent internal casting exceptions on runtime.
Note: This affects all versions of ColdFusion!
Attachments:
Comments: