Skip to content

Commit

Permalink
Merge r184501 - [JSC] Speed up URL encode/decode by using bitmaps ins…
Browse files Browse the repository at this point in the history
…tead of strchr().

<https://webkit.org/b/145115>

Reviewed by Anders Carlsson.

We were calling strchr() for every character when doing URL encoding/decoding and it stood out
like a sore O(n) thumb in Instruments. Optimize this by using a Bitmap<256> instead.

5.5% progression on Kraken/stanford-crypto-sha256-iterative.

* runtime/JSGlobalObjectFunctions.cpp:
(JSC::makeCharacterBitmap):
(JSC::encode):
(JSC::decode):
(JSC::globalFuncDecodeURI):
(JSC::globalFuncDecodeURIComponent):
(JSC::globalFuncEncodeURI):
(JSC::globalFuncEncodeURIComponent):
(JSC::globalFuncEscape):
  • Loading branch information
Andreas Kling authored and carlosgcampos committed Jul 6, 2015
1 parent 731373b commit 63fa48a
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 19 deletions.
22 changes: 22 additions & 0 deletions Source/JavaScriptCore/ChangeLog
@@ -1,3 +1,25 @@
2015-05-18 Andreas Kling <akling@apple.com>

[JSC] Speed up URL encode/decode by using bitmaps instead of strchr().
<https://webkit.org/b/145115>

Reviewed by Anders Carlsson.

We were calling strchr() for every character when doing URL encoding/decoding and it stood out
like a sore O(n) thumb in Instruments. Optimize this by using a Bitmap<256> instead.

5.5% progression on Kraken/stanford-crypto-sha256-iterative.

* runtime/JSGlobalObjectFunctions.cpp:
(JSC::makeCharacterBitmap):
(JSC::encode):
(JSC::decode):
(JSC::globalFuncDecodeURI):
(JSC::globalFuncDecodeURIComponent):
(JSC::globalFuncEncodeURI):
(JSC::globalFuncEncodeURIComponent):
(JSC::globalFuncEscape):

2015-03-03 Anders Carlsson <andersca@apple.com>

Remove unused compression code
Expand Down
52 changes: 33 additions & 19 deletions Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp
Expand Up @@ -53,7 +53,16 @@ using namespace Unicode;

namespace JSC {

static JSValue encode(ExecState* exec, const char* doNotEscape)
template<unsigned charactersCount>
static Bitmap<256> makeCharacterBitmap(const char (&characters)[charactersCount])
{
Bitmap<256> bitmap;
for (unsigned i = 0; i < charactersCount; ++i)
bitmap.set(characters[i]);
return bitmap;
}

static JSValue encode(ExecState* exec, const Bitmap<256>& doNotEscape)
{
CString cstr = exec->argument(0).toString(exec)->value(exec).utf8(StrictConversion);
if (!cstr.data())
Expand All @@ -63,7 +72,7 @@ static JSValue encode(ExecState* exec, const char* doNotEscape)
const char* p = cstr.data();
for (size_t k = 0; k < cstr.length(); k++, p++) {
char c = *p;
if (c && strchr(doNotEscape, c))
if (c && doNotEscape.get(static_cast<LChar>(c)))
builder.append(static_cast<LChar>(c));
else {
builder.append(static_cast<LChar>('%'));
Expand All @@ -75,7 +84,7 @@ static JSValue encode(ExecState* exec, const char* doNotEscape)

template <typename CharType>
ALWAYS_INLINE
static JSValue decode(ExecState* exec, const CharType* characters, int length, const char* doNotUnescape, bool strict)
static JSValue decode(ExecState* exec, const CharType* characters, int length, const Bitmap<256>& doNotUnescape, bool strict)
{
JSStringBuilder builder;
int k = 0;
Expand Down Expand Up @@ -127,7 +136,7 @@ static JSValue decode(ExecState* exec, const CharType* characters, int length, c
u = Lexer<UChar>::convertUnicode(p[2], p[3], p[4], p[5]);
}
}
if (charLen && (u == 0 || u >= 128 || !strchr(doNotUnescape, u))) {
if (charLen && (u == 0 || u >= 128 || !doNotUnescape.get(static_cast<LChar>(u)))) {
builder.append(u);
k += charLen;
continue;
Expand All @@ -139,7 +148,7 @@ static JSValue decode(ExecState* exec, const CharType* characters, int length, c
return builder.build(exec);
}

static JSValue decode(ExecState* exec, const char* doNotUnescape, bool strict)
static JSValue decode(ExecState* exec, const Bitmap<256>& doNotUnescape, bool strict)
{
String str = exec->argument(0).toString(exec)->value(exec);

Expand Down Expand Up @@ -575,54 +584,59 @@ EncodedJSValue JSC_HOST_CALL globalFuncIsFinite(ExecState* exec)

EncodedJSValue JSC_HOST_CALL globalFuncDecodeURI(ExecState* exec)
{
static const char do_not_unescape_when_decoding_URI[] =
"#$&+,/:;=?@";
static Bitmap<256> doNotUnescapeWhenDecodingURI = makeCharacterBitmap(
"#$&+,/:;=?@"
);

return JSValue::encode(decode(exec, do_not_unescape_when_decoding_URI, true));
return JSValue::encode(decode(exec, doNotUnescapeWhenDecodingURI, true));
}

EncodedJSValue JSC_HOST_CALL globalFuncDecodeURIComponent(ExecState* exec)
{
return JSValue::encode(decode(exec, "", true));
static Bitmap<256> emptyBitmap;
return JSValue::encode(decode(exec, emptyBitmap, true));
}

EncodedJSValue JSC_HOST_CALL globalFuncEncodeURI(ExecState* exec)
{
static const char do_not_escape_when_encoding_URI[] =
static Bitmap<256> doNotEscapeWhenEncodingURI = makeCharacterBitmap(
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789"
"!#$&'()*+,-./:;=?@_~";
"!#$&'()*+,-./:;=?@_~"
);

return JSValue::encode(encode(exec, do_not_escape_when_encoding_URI));
return JSValue::encode(encode(exec, doNotEscapeWhenEncodingURI));
}

EncodedJSValue JSC_HOST_CALL globalFuncEncodeURIComponent(ExecState* exec)
{
static const char do_not_escape_when_encoding_URI_component[] =
static Bitmap<256> doNotEscapeWhenEncodingURIComponent = makeCharacterBitmap(
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789"
"!'()*-._~";
"!'()*-._~"
);

return JSValue::encode(encode(exec, do_not_escape_when_encoding_URI_component));
return JSValue::encode(encode(exec, doNotEscapeWhenEncodingURIComponent));
}

EncodedJSValue JSC_HOST_CALL globalFuncEscape(ExecState* exec)
{
static const char do_not_escape[] =
static Bitmap<256> doNotEscape = makeCharacterBitmap(
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789"
"*+-./@_";
"*+-./@_"
);

JSStringBuilder builder;
String str = exec->argument(0).toString(exec)->value(exec);
if (str.is8Bit()) {
const LChar* c = str.characters8();
for (unsigned k = 0; k < str.length(); k++, c++) {
int u = c[0];
if (u && strchr(do_not_escape, static_cast<char>(u)))
if (u && doNotEscape.get(static_cast<LChar>(u)))
builder.append(*c);
else {
builder.append(static_cast<LChar>('%'));
Expand All @@ -641,7 +655,7 @@ EncodedJSValue JSC_HOST_CALL globalFuncEscape(ExecState* exec)
builder.append(static_cast<LChar>('u'));
appendByteAsHex(u >> 8, builder);
appendByteAsHex(u & 0xFF, builder);
} else if (u != 0 && strchr(do_not_escape, static_cast<char>(u)))
} else if (u != 0 && doNotEscape.get(static_cast<LChar>(u)))
builder.append(*c);
else {
builder.append(static_cast<LChar>('%'));
Expand Down

0 comments on commit 63fa48a

Please sign in to comment.