Skip to content

Commit ca33dbd

Browse files
dcroussoConstellation
authored andcommitted
[JSC] add support for Uint8Array.fromBase64 and Uint8Array.prototype.setFromBase64
https://bugs.webkit.org/show_bug.cgi?id=276215 Reviewed by Yusuke Suzuki. These methods will make it easier for developers to decode typed character/byte data. Note that there are other methods in the related proposal, but for ease of reviewing they will be implemented separately. Spec: <https://tc39.es/proposal-arraybuffer-base64/spec/> Proposal: <https://github.com/tc39/proposal-arraybuffer-base64> * Source/JavaScriptCore/runtime/JSGenericTypedArrayViewConstructor.h: * Source/JavaScriptCore/runtime/JSGenericTypedArrayViewConstructorInlines.h: (JSC::JSGenericTypedArrayViewConstructor<ViewClass>::finishCreation): * Source/JavaScriptCore/runtime/JSGenericTypedArrayViewConstructor.cpp: (JSC::uint8ArrayConstructorFromBase64): Added. * Source/JavaScriptCore/runtime/JSGenericTypedArrayViewPrototype.h: * Source/JavaScriptCore/runtime/JSGenericTypedArrayViewPrototypeInlines.h: (JSC::JSGenericTypedArrayViewPrototype<ViewClass>::finishCreation): * Source/JavaScriptCore/runtime/JSGenericTypedArrayViewPrototype.cpp: (JSC::uint8ArrayPrototypeSetFromBase64): Added. * Source/JavaScriptCore/runtime/JSGenericTypedArrayView.h: * Source/JavaScriptCore/runtime/JSGenericTypedArrayView.cpp: Added. (JSC::fromBase64): Create shared utility file for special base64 parsing logic. * Source/JavaScriptCore/runtime/CommonIdentifiers.h: Create builtin identifier for `lastChunkHandling`. * Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj: * Source/JavaScriptCore/Sources.txt: * JSTests/stress/uint8array-fromBase64.js: Added. * JSTests/stress/uint8array-setFromBase64.js: Added. * JSTests/stress/uint8array-fromHex.js: * JSTests/stress/uint8array-setFromHex.js: * JSTests/stress/uint8array-toBase64.js: * JSTests/stress/uint8array-toHex.js: Drive-by: fix a few invalid tests and check that things that should throw actually do. Canonical link: https://commits.webkit.org/281014@main
1 parent e14851d commit ca33dbd

17 files changed

+1665
-53
lines changed

JSTests/stress/uint8array-fromBase64.js

Lines changed: 580 additions & 0 deletions
Large diffs are not rendered by default.

JSTests/stress/uint8array-fromHex.js

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,16 @@ function shouldBeArray(actual, expected) {
1111
shouldBe(actual[i], expected[i]);
1212
}
1313

14+
function shouldThrow(callback, errorConstructor) {
15+
try {
16+
callback();
17+
} catch (e) {
18+
shouldBe(e instanceof errorConstructor, true);
19+
return
20+
}
21+
throw new Error('FAIL: should have thrown');
22+
}
23+
1424
shouldBeArray(Uint8Array.fromHex(""), []);
1525
shouldBeArray(Uint8Array.fromHex("00"), [0]);
1626
shouldBeArray(Uint8Array.fromHex("01"), [1]);
@@ -26,17 +36,13 @@ shouldBeArray(Uint8Array.fromHex("000180feff"), [0, 1, 128, 254, 255]);
2636
shouldBeArray(Uint8Array.fromHex("000180FEFF"), [0, 1, 128, 254, 255]);
2737

2838
for (let invalid of [undefined, null, false, true, 42, {}, []]) {
29-
try {
39+
shouldThrow(() => {
3040
Uint8Array.fromHex(invalid);
31-
} catch (e) {
32-
shouldBe(e instanceof TypeError, true);
33-
}
41+
}, TypeError);
3442
}
3543

3644
for (let invalid of ["0", "012", "0g", "0G", "g0", "G0", "0✅", "✅0"]) {
37-
try {
45+
shouldThrow(() => {
3846
Uint8Array.fromHex(invalid);
39-
} catch (e) {
40-
shouldBe(e instanceof SyntaxError, true);
41-
}
47+
}, SyntaxError);
4248
}

JSTests/stress/uint8array-setFromBase64.js

Lines changed: 704 additions & 0 deletions
Large diffs are not rendered by default.

JSTests/stress/uint8array-setFromHex.js

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,16 @@ function shouldBeArray(actual, expected) {
2121
shouldBe(actual[i], expected[i]);
2222
}
2323

24+
function shouldThrow(callback, errorConstructor) {
25+
try {
26+
callback();
27+
} catch (e) {
28+
shouldBe(e instanceof errorConstructor, true);
29+
return
30+
}
31+
throw new Error('FAIL: should have thrown');
32+
}
33+
2434
function test(input, expectedResult, expectedValue) {
2535
let uint8array = new Uint8Array([42, 42, 42, 42, 42]);
2636

@@ -48,26 +58,20 @@ test("000180FEFF33", {read: 10, written: 5}, [0, 1, 128, 254, 255]);
4858
test("000180feff33cc", {read: 10, written: 5}, [0, 1, 128, 254, 255]);
4959
test("000180FEFF33CC", {read: 10, written: 5}, [0, 1, 128, 254, 255]);
5060

51-
try {
61+
shouldThrow(() => {
5262
let uint8array = new Uint8Array;
5363
$.detachArrayBuffer(uint8array.buffer);
5464
uint8array.setFromHex("");
55-
} catch (e) {
56-
shouldBe(e instanceof TypeError, true);
57-
}
65+
}, TypeError);
5866

5967
for (let invalid of [undefined, null, false, true, 42, {}, []]) {
60-
try {
68+
shouldThrow(() => {
6169
(new Uint8Array).setFromHex(invalid);
62-
} catch (e) {
63-
shouldBe(e instanceof TypeError, true);
64-
}
70+
}, TypeError);
6571
}
6672

67-
for (let invalid of ["0", "012", "0g", "g0", "0✅", "✅0"]) {
68-
try {
69-
(new Uint8Array).setFromHex(invalid);
70-
} catch (e) {
71-
shouldBe(e instanceof SyntaxError, true);
72-
}
73+
for (let invalid of ["0", "012", "0g", "0G", "g0", "G0", "0✅", "✅0"]) {
74+
shouldThrow(() => {
75+
(new Uint8Array([42, 42, 42, 42, 42])).setFromHex(invalid);
76+
}, SyntaxError);
7377
}

JSTests/stress/uint8array-toBase64.js

Lines changed: 23 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,16 @@ function shouldBe(actual, expected) {
55
throw new Error(`FAIL: expected '${expected}' actual '${actual}'`);
66
}
77

8+
function shouldThrow(callback, errorConstructor) {
9+
try {
10+
callback();
11+
} catch (e) {
12+
shouldBe(e instanceof errorConstructor, true);
13+
return
14+
}
15+
throw new Error('FAIL: should have thrown');
16+
}
17+
818
shouldBe((new Uint8Array([])).toBase64(), "");
919
shouldBe((new Uint8Array([0])).toBase64(), "AA==");
1020
shouldBe((new Uint8Array([1])).toBase64(), "AQ==");
@@ -199,60 +209,48 @@ for (let omitPadding of [true, 42, "test", [], {}]) {
199209
shouldBe((new Uint8Array([0, 1, 128, 254, 255])).toBase64({get alphabet() { return "base64url"; }, get omitPadding() { return omitPadding; }}), "AAGA_v8");
200210
}
201211

202-
try {
212+
shouldThrow(() => {
203213
let uint8array = new Uint8Array;
204214
$.detachArrayBuffer(uint8array.buffer);
205215
uint8array.toBase64();
206-
} catch (e) {
207-
shouldBe(e instanceof TypeError, true);
208-
}
216+
}, TypeError);
209217

210218
for (let alphabet of [undefined, "base64", "base64url"]) {
211-
try {
219+
shouldThrow(() => {
212220
let uint8array = new Uint8Array;
213221
uint8array.toBase64({
214222
get alphabet() {
215223
$.detachArrayBuffer(uint8array.buffer);
216224
return alphabet;
217225
},
218226
});
219-
} catch (e) {
220-
shouldBe(e instanceof TypeError, true);
221-
}
227+
}, TypeError);
222228

223-
try {
229+
shouldThrow(() => {
224230
(new Uint8Array).toBase64({
225231
alphabet: {
226232
toString() {
227233
return alphabet;
228234
},
229235
},
230236
});
231-
} catch (e) {
232-
shouldBe(e instanceof TypeError, true);
233-
}
237+
}, TypeError);
234238
}
235239

236-
for (let options of [undefined, null, false, true, 42, "test", []]) {
237-
try {
240+
for (let options of [null, false, true, 42, "test"]) {
241+
shouldThrow(() => {
238242
(new Uint8Array).toBase64(options);
239-
} catch (e) {
240-
shouldBe(e instanceof TypeError, true);
241-
}
243+
}, TypeError);
242244
}
243245

244246
for (let alphabet of [null, false, true, 42, "invalid", {}, []]) {
245-
try {
247+
shouldThrow(() => {
246248
(new Uint8Array).toBase64({alphabet});
247-
} catch (e) {
248-
shouldBe(e instanceof TypeError, true);
249-
}
249+
}, TypeError);
250250

251-
try {
251+
shouldThrow(() => {
252252
(new Uint8Array).toBase64({
253253
get alphabet() { return alphabet; },
254254
});
255-
} catch (e) {
256-
shouldBe(e instanceof TypeError, true);
257-
}
255+
}, TypeError);
258256
}

JSTests/stress/uint8array-toHex.js

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,16 @@ function shouldBe(actual, expected) {
55
throw new Error(`FAIL: expected '${expected}' actual '${actual}'`);
66
}
77

8+
function shouldThrow(callback, errorConstructor) {
9+
try {
10+
callback();
11+
} catch (e) {
12+
shouldBe(e instanceof errorConstructor, true);
13+
return
14+
}
15+
throw new Error('FAIL: should have thrown');
16+
}
17+
818
shouldBe((new Uint8Array([])).toHex(), "");
919
shouldBe((new Uint8Array([0])).toHex(), "00");
1020
shouldBe((new Uint8Array([1])).toHex(), "01");
@@ -34,10 +44,8 @@ shouldBe((new Uint8Array([0, 1, 128, 254, 255])).toHex(), "000180feff");
3444
shouldBe(buffer.toHex(), expected);
3545
}
3646

37-
try {
47+
shouldThrow(() => {
3848
let uint8array = new Uint8Array;
3949
$.detachArrayBuffer(uint8array.buffer);
4050
uint8array.toHex();
41-
} catch (e) {
42-
shouldBe(e instanceof TypeError, true);
43-
}
51+
}, TypeError);

Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4725,6 +4725,7 @@
47254725
918E15BD2447B22600447A56 /* AggregateErrorPrototype.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AggregateErrorPrototype.h; sourceTree = "<group>"; };
47264726
918E15BE2447B22700447A56 /* AggregateErrorPrototype.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AggregateErrorPrototype.cpp; sourceTree = "<group>"; };
47274727
918E15BF2447B22700447A56 /* AggregateErrorConstructor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AggregateErrorConstructor.h; sourceTree = "<group>"; };
4728+
91C326592BFFB2B3009C7E2B /* JSGenericTypedArrayView.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSGenericTypedArrayView.cpp; sourceTree = "<group>"; };
47284729
91C3265B2BFFB2B9009C7E2B /* JSGenericTypedArrayViewConstructor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSGenericTypedArrayViewConstructor.cpp; sourceTree = "<group>"; };
47294730
91C3265D2BFFB2BF009C7E2B /* JSGenericTypedArrayViewPrototype.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSGenericTypedArrayViewPrototype.cpp; sourceTree = "<group>"; };
47304731
91D1578C24E0BE35001F4CED /* Breakpoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Breakpoint.cpp; sourceTree = "<group>"; };
@@ -8337,6 +8338,7 @@
83378338
70B7918C1C024462002481E2 /* JSGeneratorFunction.cpp */,
83388339
70B7918D1C024462002481E2 /* JSGeneratorFunction.h */,
83398340
276B39092A71D2B400252F4E /* JSGeneratorFunctionInlines.h */,
8341+
91C326592BFFB2B3009C7E2B /* JSGenericTypedArrayView.cpp */,
83408342
0F2B66C317B6B5AB00A7AE3F /* JSGenericTypedArrayView.h */,
83418343
91C3265B2BFFB2B9009C7E2B /* JSGenericTypedArrayViewConstructor.cpp */,
83428344
0F2B66C417B6B5AB00A7AE3F /* JSGenericTypedArrayViewConstructor.h */,

Source/JavaScriptCore/Sources.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -917,6 +917,7 @@ runtime/JSFinalizationRegistry.cpp
917917
runtime/JSFunction.cpp
918918
runtime/JSGenerator.cpp
919919
runtime/JSGeneratorFunction.cpp
920+
runtime/JSGenericTypedArrayView.cpp
920921
runtime/JSGenericTypedArrayViewConstructor.cpp
921922
runtime/JSGenericTypedArrayViewPrototype.cpp
922923
runtime/JSGlobalLexicalEnvironment.cpp

Source/JavaScriptCore/runtime/CommonIdentifiers.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,7 @@
184184
macro(language) \
185185
macro(languageDisplay) \
186186
macro(largestUnit) \
187+
macro(lastChunkHandling) \
187188
macro(lastIndex) \
188189
macro(length) \
189190
macro(line) \

0 commit comments

Comments
 (0)