Skip to content

Commit 7fdec37

Browse files
authored
Micro-optimize base64Decode (#2897)
* Micro-optimize base64Decode * Update test expectations
1 parent 037d7a5 commit 7fdec37

9 files changed

+45
-63
lines changed

src/wasm2js.h

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2258,15 +2258,13 @@ void Wasm2JSGlue::emitMemory(
22582258
base64ReverseLookup[47] = 63; // '/'
22592259
/** @noinline Inlining this function would mean expanding the base64 string 4x times in the source code, which Closure seems to be happy to do. */
22602260
function base64DecodeToExistingUint8Array(uint8Array, offset, b64) {
2261-
var b1, b2, i = 0, j = offset, bLength = b64.length, end = offset + (bLength*3>>2);
2262-
if (b64[bLength-2] == '=') --end;
2263-
if (b64[bLength-1] == '=') --end;
2264-
for (; i < bLength; i += 4, j += 3) {
2261+
var b1, b2, i = 0, j = offset, bLength = b64.length, end = offset + (bLength*3>>2) - (b64[bLength-2] == '=') - (b64[bLength-1] == '=');
2262+
for (; i < bLength; i += 4) {
22652263
b1 = base64ReverseLookup[b64.charCodeAt(i+1)];
22662264
b2 = base64ReverseLookup[b64.charCodeAt(i+2)];
2267-
uint8Array[j] = base64ReverseLookup[b64.charCodeAt(i)] << 2 | b1 >> 4;
2268-
if (j+1 < end) uint8Array[j+1] = b1 << 4 | b2 >> 2;
2269-
if (j+2 < end) uint8Array[j+2] = b2 << 6 | base64ReverseLookup[b64.charCodeAt(i+3)];
2265+
uint8Array[j++] = base64ReverseLookup[b64.charCodeAt(i)] << 2 | b1 >> 4;
2266+
if (j < end) uint8Array[j++] = b1 << 4 | b2 >> 2;
2267+
if (j < end) uint8Array[j++] = b2 << 6 | base64ReverseLookup[b64.charCodeAt(i+3)];
22702268
}
22712269
})";
22722270
out << expr << '\n';

test/wasm2js/dynamicLibrary.2asm.js

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -59,15 +59,13 @@ for (var base64ReverseLookup = new Uint8Array(123/*'z'+1*/), i = 25; i >= 0; --i
5959
base64ReverseLookup[47] = 63; // '/'
6060
/** @noinline Inlining this function would mean expanding the base64 string 4x times in the source code, which Closure seems to be happy to do. */
6161
function base64DecodeToExistingUint8Array(uint8Array, offset, b64) {
62-
var b1, b2, i = 0, j = offset, bLength = b64.length, end = offset + (bLength*3>>2);
63-
if (b64[bLength-2] == '=') --end;
64-
if (b64[bLength-1] == '=') --end;
65-
for (; i < bLength; i += 4, j += 3) {
62+
var b1, b2, i = 0, j = offset, bLength = b64.length, end = offset + (bLength*3>>2) - (b64[bLength-2] == '=') - (b64[bLength-1] == '=');
63+
for (; i < bLength; i += 4) {
6664
b1 = base64ReverseLookup[b64.charCodeAt(i+1)];
6765
b2 = base64ReverseLookup[b64.charCodeAt(i+2)];
68-
uint8Array[j] = base64ReverseLookup[b64.charCodeAt(i)] << 2 | b1 >> 4;
69-
if (j+1 < end) uint8Array[j+1] = b1 << 4 | b2 >> 2;
70-
if (j+2 < end) uint8Array[j+2] = b2 << 6 | base64ReverseLookup[b64.charCodeAt(i+3)];
66+
uint8Array[j++] = base64ReverseLookup[b64.charCodeAt(i)] << 2 | b1 >> 4;
67+
if (j < end) uint8Array[j++] = b1 << 4 | b2 >> 2;
68+
if (j < end) uint8Array[j++] = b2 << 6 | base64ReverseLookup[b64.charCodeAt(i+3)];
7169
}
7270
}
7371
var bufferView = new Uint8Array(memasmFunc);

test/wasm2js/dynamicLibrary.2asm.js.opt

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -51,15 +51,13 @@ for (var base64ReverseLookup = new Uint8Array(123/*'z'+1*/), i = 25; i >= 0; --i
5151
base64ReverseLookup[47] = 63; // '/'
5252
/** @noinline Inlining this function would mean expanding the base64 string 4x times in the source code, which Closure seems to be happy to do. */
5353
function base64DecodeToExistingUint8Array(uint8Array, offset, b64) {
54-
var b1, b2, i = 0, j = offset, bLength = b64.length, end = offset + (bLength*3>>2);
55-
if (b64[bLength-2] == '=') --end;
56-
if (b64[bLength-1] == '=') --end;
57-
for (; i < bLength; i += 4, j += 3) {
54+
var b1, b2, i = 0, j = offset, bLength = b64.length, end = offset + (bLength*3>>2) - (b64[bLength-2] == '=') - (b64[bLength-1] == '=');
55+
for (; i < bLength; i += 4) {
5856
b1 = base64ReverseLookup[b64.charCodeAt(i+1)];
5957
b2 = base64ReverseLookup[b64.charCodeAt(i+2)];
60-
uint8Array[j] = base64ReverseLookup[b64.charCodeAt(i)] << 2 | b1 >> 4;
61-
if (j+1 < end) uint8Array[j+1] = b1 << 4 | b2 >> 2;
62-
if (j+2 < end) uint8Array[j+2] = b2 << 6 | base64ReverseLookup[b64.charCodeAt(i+3)];
58+
uint8Array[j++] = base64ReverseLookup[b64.charCodeAt(i)] << 2 | b1 >> 4;
59+
if (j < end) uint8Array[j++] = b1 << 4 | b2 >> 2;
60+
if (j < end) uint8Array[j++] = b2 << 6 | base64ReverseLookup[b64.charCodeAt(i+3)];
6361
}
6462
}
6563
var bufferView = new Uint8Array(memasmFunc);

test/wasm2js/emscripten-grow-no.2asm.js

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -55,15 +55,13 @@ for (var base64ReverseLookup = new Uint8Array(123/*'z'+1*/), i = 25; i >= 0; --i
5555
base64ReverseLookup[47] = 63; // '/'
5656
/** @noinline Inlining this function would mean expanding the base64 string 4x times in the source code, which Closure seems to be happy to do. */
5757
function base64DecodeToExistingUint8Array(uint8Array, offset, b64) {
58-
var b1, b2, i = 0, j = offset, bLength = b64.length, end = offset + (bLength*3>>2);
59-
if (b64[bLength-2] == '=') --end;
60-
if (b64[bLength-1] == '=') --end;
61-
for (; i < bLength; i += 4, j += 3) {
58+
var b1, b2, i = 0, j = offset, bLength = b64.length, end = offset + (bLength*3>>2) - (b64[bLength-2] == '=') - (b64[bLength-1] == '=');
59+
for (; i < bLength; i += 4) {
6260
b1 = base64ReverseLookup[b64.charCodeAt(i+1)];
6361
b2 = base64ReverseLookup[b64.charCodeAt(i+2)];
64-
uint8Array[j] = base64ReverseLookup[b64.charCodeAt(i)] << 2 | b1 >> 4;
65-
if (j+1 < end) uint8Array[j+1] = b1 << 4 | b2 >> 2;
66-
if (j+2 < end) uint8Array[j+2] = b2 << 6 | base64ReverseLookup[b64.charCodeAt(i+3)];
62+
uint8Array[j++] = base64ReverseLookup[b64.charCodeAt(i)] << 2 | b1 >> 4;
63+
if (j < end) uint8Array[j++] = b1 << 4 | b2 >> 2;
64+
if (j < end) uint8Array[j++] = b2 << 6 | base64ReverseLookup[b64.charCodeAt(i+3)];
6765
}
6866
}
6967
var bufferView = new Uint8Array(wasmMemory.buffer);

test/wasm2js/emscripten-grow-no.2asm.js.opt

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -55,15 +55,13 @@ for (var base64ReverseLookup = new Uint8Array(123/*'z'+1*/), i = 25; i >= 0; --i
5555
base64ReverseLookup[47] = 63; // '/'
5656
/** @noinline Inlining this function would mean expanding the base64 string 4x times in the source code, which Closure seems to be happy to do. */
5757
function base64DecodeToExistingUint8Array(uint8Array, offset, b64) {
58-
var b1, b2, i = 0, j = offset, bLength = b64.length, end = offset + (bLength*3>>2);
59-
if (b64[bLength-2] == '=') --end;
60-
if (b64[bLength-1] == '=') --end;
61-
for (; i < bLength; i += 4, j += 3) {
58+
var b1, b2, i = 0, j = offset, bLength = b64.length, end = offset + (bLength*3>>2) - (b64[bLength-2] == '=') - (b64[bLength-1] == '=');
59+
for (; i < bLength; i += 4) {
6260
b1 = base64ReverseLookup[b64.charCodeAt(i+1)];
6361
b2 = base64ReverseLookup[b64.charCodeAt(i+2)];
64-
uint8Array[j] = base64ReverseLookup[b64.charCodeAt(i)] << 2 | b1 >> 4;
65-
if (j+1 < end) uint8Array[j+1] = b1 << 4 | b2 >> 2;
66-
if (j+2 < end) uint8Array[j+2] = b2 << 6 | base64ReverseLookup[b64.charCodeAt(i+3)];
62+
uint8Array[j++] = base64ReverseLookup[b64.charCodeAt(i)] << 2 | b1 >> 4;
63+
if (j < end) uint8Array[j++] = b1 << 4 | b2 >> 2;
64+
if (j < end) uint8Array[j++] = b2 << 6 | base64ReverseLookup[b64.charCodeAt(i+3)];
6765
}
6866
}
6967
var bufferView = new Uint8Array(wasmMemory.buffer);

test/wasm2js/emscripten-grow-yes.2asm.js

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -78,15 +78,13 @@ for (var base64ReverseLookup = new Uint8Array(123/*'z'+1*/), i = 25; i >= 0; --i
7878
base64ReverseLookup[47] = 63; // '/'
7979
/** @noinline Inlining this function would mean expanding the base64 string 4x times in the source code, which Closure seems to be happy to do. */
8080
function base64DecodeToExistingUint8Array(uint8Array, offset, b64) {
81-
var b1, b2, i = 0, j = offset, bLength = b64.length, end = offset + (bLength*3>>2);
82-
if (b64[bLength-2] == '=') --end;
83-
if (b64[bLength-1] == '=') --end;
84-
for (; i < bLength; i += 4, j += 3) {
81+
var b1, b2, i = 0, j = offset, bLength = b64.length, end = offset + (bLength*3>>2) - (b64[bLength-2] == '=') - (b64[bLength-1] == '=');
82+
for (; i < bLength; i += 4) {
8583
b1 = base64ReverseLookup[b64.charCodeAt(i+1)];
8684
b2 = base64ReverseLookup[b64.charCodeAt(i+2)];
87-
uint8Array[j] = base64ReverseLookup[b64.charCodeAt(i)] << 2 | b1 >> 4;
88-
if (j+1 < end) uint8Array[j+1] = b1 << 4 | b2 >> 2;
89-
if (j+2 < end) uint8Array[j+2] = b2 << 6 | base64ReverseLookup[b64.charCodeAt(i+3)];
85+
uint8Array[j++] = base64ReverseLookup[b64.charCodeAt(i)] << 2 | b1 >> 4;
86+
if (j < end) uint8Array[j++] = b1 << 4 | b2 >> 2;
87+
if (j < end) uint8Array[j++] = b2 << 6 | base64ReverseLookup[b64.charCodeAt(i+3)];
9088
}
9189
}
9290
var bufferView = new Uint8Array(wasmMemory.buffer);

test/wasm2js/emscripten-grow-yes.2asm.js.opt

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -78,15 +78,13 @@ for (var base64ReverseLookup = new Uint8Array(123/*'z'+1*/), i = 25; i >= 0; --i
7878
base64ReverseLookup[47] = 63; // '/'
7979
/** @noinline Inlining this function would mean expanding the base64 string 4x times in the source code, which Closure seems to be happy to do. */
8080
function base64DecodeToExistingUint8Array(uint8Array, offset, b64) {
81-
var b1, b2, i = 0, j = offset, bLength = b64.length, end = offset + (bLength*3>>2);
82-
if (b64[bLength-2] == '=') --end;
83-
if (b64[bLength-1] == '=') --end;
84-
for (; i < bLength; i += 4, j += 3) {
81+
var b1, b2, i = 0, j = offset, bLength = b64.length, end = offset + (bLength*3>>2) - (b64[bLength-2] == '=') - (b64[bLength-1] == '=');
82+
for (; i < bLength; i += 4) {
8583
b1 = base64ReverseLookup[b64.charCodeAt(i+1)];
8684
b2 = base64ReverseLookup[b64.charCodeAt(i+2)];
87-
uint8Array[j] = base64ReverseLookup[b64.charCodeAt(i)] << 2 | b1 >> 4;
88-
if (j+1 < end) uint8Array[j+1] = b1 << 4 | b2 >> 2;
89-
if (j+2 < end) uint8Array[j+2] = b2 << 6 | base64ReverseLookup[b64.charCodeAt(i+3)];
85+
uint8Array[j++] = base64ReverseLookup[b64.charCodeAt(i)] << 2 | b1 >> 4;
86+
if (j < end) uint8Array[j++] = b1 << 4 | b2 >> 2;
87+
if (j < end) uint8Array[j++] = b2 << 6 | base64ReverseLookup[b64.charCodeAt(i+3)];
9088
}
9189
}
9290
var bufferView = new Uint8Array(wasmMemory.buffer);

test/wasm2js/emscripten.2asm.js

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -213,15 +213,13 @@ for (var base64ReverseLookup = new Uint8Array(123/*'z'+1*/), i = 25; i >= 0; --i
213213
base64ReverseLookup[47] = 63; // '/'
214214
/** @noinline Inlining this function would mean expanding the base64 string 4x times in the source code, which Closure seems to be happy to do. */
215215
function base64DecodeToExistingUint8Array(uint8Array, offset, b64) {
216-
var b1, b2, i = 0, j = offset, bLength = b64.length, end = offset + (bLength*3>>2);
217-
if (b64[bLength-2] == '=') --end;
218-
if (b64[bLength-1] == '=') --end;
219-
for (; i < bLength; i += 4, j += 3) {
216+
var b1, b2, i = 0, j = offset, bLength = b64.length, end = offset + (bLength*3>>2) - (b64[bLength-2] == '=') - (b64[bLength-1] == '=');
217+
for (; i < bLength; i += 4) {
220218
b1 = base64ReverseLookup[b64.charCodeAt(i+1)];
221219
b2 = base64ReverseLookup[b64.charCodeAt(i+2)];
222-
uint8Array[j] = base64ReverseLookup[b64.charCodeAt(i)] << 2 | b1 >> 4;
223-
if (j+1 < end) uint8Array[j+1] = b1 << 4 | b2 >> 2;
224-
if (j+2 < end) uint8Array[j+2] = b2 << 6 | base64ReverseLookup[b64.charCodeAt(i+3)];
220+
uint8Array[j++] = base64ReverseLookup[b64.charCodeAt(i)] << 2 | b1 >> 4;
221+
if (j < end) uint8Array[j++] = b1 << 4 | b2 >> 2;
222+
if (j < end) uint8Array[j++] = b2 << 6 | base64ReverseLookup[b64.charCodeAt(i+3)];
225223
}
226224
}
227225
var bufferView = new Uint8Array(wasmMemory.buffer);

test/wasm2js/emscripten.2asm.js.opt

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -194,15 +194,13 @@ for (var base64ReverseLookup = new Uint8Array(123/*'z'+1*/), i = 25; i >= 0; --i
194194
base64ReverseLookup[47] = 63; // '/'
195195
/** @noinline Inlining this function would mean expanding the base64 string 4x times in the source code, which Closure seems to be happy to do. */
196196
function base64DecodeToExistingUint8Array(uint8Array, offset, b64) {
197-
var b1, b2, i = 0, j = offset, bLength = b64.length, end = offset + (bLength*3>>2);
198-
if (b64[bLength-2] == '=') --end;
199-
if (b64[bLength-1] == '=') --end;
200-
for (; i < bLength; i += 4, j += 3) {
197+
var b1, b2, i = 0, j = offset, bLength = b64.length, end = offset + (bLength*3>>2) - (b64[bLength-2] == '=') - (b64[bLength-1] == '=');
198+
for (; i < bLength; i += 4) {
201199
b1 = base64ReverseLookup[b64.charCodeAt(i+1)];
202200
b2 = base64ReverseLookup[b64.charCodeAt(i+2)];
203-
uint8Array[j] = base64ReverseLookup[b64.charCodeAt(i)] << 2 | b1 >> 4;
204-
if (j+1 < end) uint8Array[j+1] = b1 << 4 | b2 >> 2;
205-
if (j+2 < end) uint8Array[j+2] = b2 << 6 | base64ReverseLookup[b64.charCodeAt(i+3)];
201+
uint8Array[j++] = base64ReverseLookup[b64.charCodeAt(i)] << 2 | b1 >> 4;
202+
if (j < end) uint8Array[j++] = b1 << 4 | b2 >> 2;
203+
if (j < end) uint8Array[j++] = b2 << 6 | base64ReverseLookup[b64.charCodeAt(i+3)];
206204
}
207205
}
208206
var bufferView = new Uint8Array(wasmMemory.buffer);

0 commit comments

Comments
 (0)