Skip to content

Commit e0f049c

Browse files
committed
[1.10>master] [MERGE #5540 @sethbrenith] Avoid copying strings in (de|en)codeURI(Component)? and trim
Merge pull request #5540 from sethbrenith:user/sethb/encode * The last step of Encode and Decode was copying the buffer for no reason; skip that copy * Often the input to Encode or Decode doesn't require any transformation, so return the original string in that case * Likewise, avoid creating new substrings for trimmed strings if nothing needs to be trimmed Related to OS:17754314
2 parents 4cb51d2 + 22ef695 commit e0f049c

File tree

3 files changed

+41
-10
lines changed

3 files changed

+41
-10
lines changed

lib/Runtime/Library/JavascriptString.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2472,6 +2472,13 @@ namespace Js
24722472
Assert(idxEnd >= 0);
24732473
}
24742474
}
2475+
2476+
if (idxStart == 0 && idxEnd == len - 1)
2477+
{
2478+
AssertMsg(scriptContext == arg->GetScriptContext(), "Should have already marshaled the string in cross site thunk");
2479+
return arg;
2480+
}
2481+
24752482
return SubstringCore(arg, idxStart, idxEnd - idxStart + 1, scriptContext);
24762483
}
24772484

lib/Runtime/Library/UriHelper.cpp

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ namespace Js
2929
}
3030
}
3131

32-
return Encode(strURI->GetString(), strURI->GetLength(), flags, scriptContext);
32+
return Encode(strURI, flags, scriptContext);
3333
}
3434

3535
unsigned char UriHelper::s_uriProps[128] =
@@ -126,10 +126,13 @@ namespace Js
126126
}
127127

128128
// The Encode algorithm described in sec. 15.1.3 of the spec. The input string is
129-
// 'input' and the Unescaped set is described by the flags 'unescapedFlags'. The
129+
// 'strURI' and the Unescaped set is described by the flags 'unescapedFlags'. The
130130
// output is a string var.
131-
Var UriHelper::Encode(__in_ecount(len) const char16* input, uint32 len, unsigned char unescapedFlags, ScriptContext* scriptContext )
131+
Var UriHelper::Encode(JavascriptString* strURI, unsigned char unescapedFlags, ScriptContext* scriptContext )
132132
{
133+
charcount_t len = strURI->GetLength();
134+
__in_ecount(len) const char16* input = strURI->GetString();
135+
bool needsChanges = false;
133136
BYTE bUTF8[MaxUTF8Len];
134137

135138
// pass 1 calculate output length and error check
@@ -144,6 +147,8 @@ namespace Js
144147
}
145148
else
146149
{
150+
needsChanges = true;
151+
147152
if( c >= 0xDC00 && c <= 0xDFFF )
148153
{
149154
JavascriptError::ThrowURIError(scriptContext, JSERR_URIEncodeError /* TODO-ERROR: _u("NEED MESSAGE") */);
@@ -173,6 +178,13 @@ namespace Js
173178
}
174179
}
175180

181+
// If nothing needs encoding, then avoid extra work
182+
if (!needsChanges)
183+
{
184+
AssertMsg(scriptContext == strURI->GetScriptContext(), "Should have already marshaled the string in cross site thunk");
185+
return strURI;
186+
}
187+
176188
//pass 2 generate the encoded URI
177189

178190
uint32 allocSize = UInt32Math::Add(outputLen, 1);
@@ -238,7 +250,7 @@ namespace Js
238250
__analysis_assume(outputLen + 1 == allocSize);
239251
outURI[outputLen] = _u('\0');
240252

241-
return JavascriptString::NewCopyBuffer(outURI, outputLen, scriptContext);
253+
return JavascriptString::NewWithBuffer(outURI, outputLen, scriptContext);
242254
}
243255

244256
Var UriHelper::DecodeCoreURI(ScriptContext* scriptContext, Arguments& args, unsigned char reservedFlags )
@@ -265,14 +277,17 @@ namespace Js
265277
}
266278
}
267279

268-
return Decode(strURI->GetString(), strURI->GetLength(), reservedFlags, scriptContext);
280+
return Decode(strURI, reservedFlags, scriptContext);
269281
}
270282

271283
// The Decode algorithm described in sec. 15.1.3 of the spec. The input string is
272-
// 'input' and the Reserved set is described by the flags 'reservedFlags'. The
284+
// 'strURI' and the Reserved set is described by the flags 'reservedFlags'. The
273285
// output is a string var.
274-
Var UriHelper::Decode(__in_ecount(len) const char16* input, uint32 len, unsigned char reservedFlags, ScriptContext* scriptContext)
286+
Var UriHelper::Decode(JavascriptString* strURI, unsigned char reservedFlags, ScriptContext* scriptContext)
275287
{
288+
charcount_t len = strURI->GetLength();
289+
__in_ecount(len) const char16* input = strURI->GetString();
290+
bool needsChanges = false;
276291
char16 c1;
277292
char16 c;
278293
// pass 1 calculate output length and error check
@@ -283,6 +298,8 @@ namespace Js
283298

284299
if( c == '%')
285300
{
301+
needsChanges = true;
302+
286303
uint32 start = k;
287304
if( k + 2 >= len )
288305
{
@@ -383,6 +400,13 @@ namespace Js
383400
}
384401
}
385402

403+
// If nothing needs decoding, then avoid extra work
404+
if (!needsChanges)
405+
{
406+
AssertMsg(scriptContext == strURI->GetScriptContext(), "Should have already marshaled the string in cross site thunk");
407+
return strURI;
408+
}
409+
386410
//pass 2 generate the decoded URI
387411
uint32 allocSize = UInt32Math::Add(outputLen, 1);
388412
char16* outURI = RecyclerNewArrayLeaf(scriptContext->GetRecycler(), char16, allocSize);
@@ -538,7 +562,7 @@ namespace Js
538562
__analysis_assume(outputLen + 1 == allocSize);
539563
outURI[outputLen] = _u('\0');
540564

541-
return JavascriptString::NewCopyBuffer(outURI, outputLen, scriptContext);
565+
return JavascriptString::NewWithBuffer(outURI, outputLen, scriptContext);
542566
}
543567

544568
// Decodes a two-hexadecimal-digit wide character pair into the byte value it represents

lib/Runtime/Library/UriHelper.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ namespace Js
1818
};
1919

2020
static Var EncodeCoreURI(ScriptContext* scriptContext, Arguments& args, unsigned char flags);
21-
static Var Decode(__in_ecount(len) const char16* psz, uint32 len, unsigned char reservedFlags, ScriptContext* scriptContext);
21+
static Var Decode(JavascriptString* strURI, unsigned char reservedFlags, ScriptContext* scriptContext);
2222
static Var DecodeCoreURI(ScriptContext* scriptContext, Arguments& args, unsigned char reservedFlags);
2323

2424
static unsigned char s_uriProps[128];
@@ -82,7 +82,7 @@ namespace Js
8282
static const uint32 MaxUTF8Len = 4;
8383
static uint32 ToUTF8( uint32 uVal, BYTE bUTF8[MaxUTF8Len]);
8484
static uint32 FromUTF8( BYTE bUTF8[MaxUTF8Len], uint32 uLen );
85-
static Var Encode(__in_ecount(len) const char16* psz, uint32 len, unsigned char unescapedFlags, ScriptContext* scriptContext );
85+
static Var Encode(JavascriptString* strURI, unsigned char unescapedFlags, ScriptContext* scriptContext );
8686

8787
private:
8888
static bool DecodeByteFromHex(const char16 digit1, const char16 digit2, unsigned char &value);

0 commit comments

Comments
 (0)