@@ -37,6 +37,7 @@ class JSStringJoiner {
3737 JSStringJoiner (ExecState&, StringView separator, unsigned stringCount);
3838
3939 void append (ExecState&, JSValue);
40+ bool appendWithoutSideEffects (ExecState&, JSValue);
4041 void appendEmptyString ();
4142
4243 JSValue join (ExecState&);
@@ -96,42 +97,52 @@ ALWAYS_INLINE void JSStringJoiner::appendEmptyString()
9697 m_strings.uncheckedAppend ({ { }, { } });
9798}
9899
99- ALWAYS_INLINE void JSStringJoiner::append (ExecState& state, JSValue value)
100+ ALWAYS_INLINE bool JSStringJoiner::appendWithoutSideEffects (ExecState& state, JSValue value)
100101{
101102 // The following code differs from using the result of JSValue::toString in the following ways:
102103 // 1) It's inlined more than JSValue::toString is.
103104 // 2) It includes conversion to WTF::String in a way that avoids allocating copies of substrings.
104105 // 3) It doesn't create a JSString for numbers, true, or false.
105106 // 4) It turns undefined and null into the empty string instead of "undefined" and "null".
106107 // 5) It uses optimized code paths for all the cases known to be 8-bit and for the empty string.
108+ // If we might make an effectful calls, return false. Otherwise return true.
107109
108110 if (value.isCell ()) {
109- if (value. asCell ()-> isString ()) {
110- append ( asString ( value)->viewWithUnderlyingString (state));
111- return ;
112- }
111+ JSString* jsString;
112+ if (! value. asCell ( )->isString ())
113+ return false ;
114+ jsString = asString (value);
113115 append (value.toString (&state)->viewWithUnderlyingString (state));
114- return ;
116+ return true ;
115117 }
116118
117119 if (value.isInt32 ()) {
118120 append8Bit (state.vm ().numericStrings .add (value.asInt32 ()));
119- return ;
121+ return true ;
120122 }
121123 if (value.isDouble ()) {
122124 append8Bit (state.vm ().numericStrings .add (value.asDouble ()));
123- return ;
125+ return true ;
124126 }
125127 if (value.isTrue ()) {
126128 append8Bit (state.vm ().propertyNames ->trueKeyword .string ());
127- return ;
129+ return true ;
128130 }
129131 if (value.isFalse ()) {
130132 append8Bit (state.vm ().propertyNames ->falseKeyword .string ());
131- return ;
133+ return true ;
132134 }
133135 ASSERT (value.isUndefinedOrNull ());
134136 appendEmptyString ();
137+ return true ;
138+ }
139+
140+ ALWAYS_INLINE void JSStringJoiner::append (ExecState& state, JSValue value)
141+ {
142+ if (!appendWithoutSideEffects (state, value)) {
143+ JSString* jsString = value.toString (&state);
144+ append (jsString->viewWithUnderlyingString (state));
145+ }
135146}
136147
137148}
0 commit comments