Skip to content

Commit c6cea6e

Browse files
committed
[streams] speed up Readable in some cases
If `encoding` is set, no `Buffer`s would be exposed thus `Uint8Array` can be used directly. - fix segfaults in `BufferList.join()`
1 parent 0b395ca commit c6cea6e

File tree

3 files changed

+115
-2
lines changed

3 files changed

+115
-2
lines changed

src/bun.js/bindings/JSBufferList.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ JSC::JSValue JSBufferList::join(JSC::VM& vm, JSC::JSGlobalObject* lexicalGlobalO
7171
bool needSeq = false;
7272
JSRopeString::RopeBuilder<RecordOverflow> ropeBuilder(vm);
7373
for (auto iter = m_deque.begin(); iter != m_deque.end(); ++iter) {
74-
auto str = JSC::jsCast<JSC::JSString*>(iter->get());
74+
auto str = iter->get().toString(lexicalGlobalObject);
7575
if (needSeq)
7676
if (!ropeBuilder.append(seq))
7777
return throwOutOfMemoryError(lexicalGlobalObject, throwScope);

src/bun.js/streams.exports.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2949,7 +2949,9 @@ var require_readable = __commonJS({
29492949
} else if (chunk instanceof Buffer) {
29502950
encoding = "";
29512951
} else if (Stream._isUint8Array(chunk)) {
2952-
chunk = Stream._uint8ArrayToBuffer(chunk);
2952+
if (addToFront || !state.decoder) {
2953+
chunk = Stream._uint8ArrayToBuffer(chunk);
2954+
}
29532955
encoding = "";
29542956
} else if (chunk != null) {
29552957
err = new ERR_INVALID_ARG_TYPE(
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
import { beforeEach, describe, expect, it } from "bun:test";
2+
import { Readable, Writable } from "stream";
3+
4+
const ABC = new Uint8Array([0x41, 0x42, 0x43]);
5+
const DEF = new Uint8Array([0x44, 0x45, 0x46]);
6+
const GHI = new Uint8Array([0x47, 0x48, 0x49]);
7+
8+
describe("Writable", () => {
9+
let called;
10+
11+
function logCall(fn, id) {
12+
return function() {
13+
called[id] = (called[id] || 0) + 1;
14+
return fn.apply(this, arguments);
15+
};
16+
}
17+
18+
beforeEach(() => {
19+
called = [];
20+
});
21+
22+
it("should perform simple operations", () => {
23+
let n = 0;
24+
const writable = new Writable({
25+
write: logCall((chunk, encoding, cb) => {
26+
expect(chunk instanceof Buffer).toBe(true);
27+
if (n++ === 0) {
28+
expect(String(chunk)).toBe("ABC");
29+
} else {
30+
expect(String(chunk)).toBe("DEF");
31+
}
32+
33+
cb();
34+
}, 0),
35+
});
36+
37+
writable.write(ABC);
38+
writable.end(DEF);
39+
expect(called).toEqual([ 2 ]);
40+
});
41+
42+
it("should pass in Uint8Array in object mode", () => {
43+
const writable = new Writable({
44+
objectMode: true,
45+
write: logCall((chunk, encoding, cb) => {
46+
expect(chunk instanceof Buffer).toBe(false);
47+
expect(chunk instanceof Uint8Array).toBe(true);
48+
expect(chunk).toStrictEqual(ABC);
49+
expect(encoding).toBe("utf8");
50+
cb();
51+
}, 0),
52+
});
53+
54+
writable.end(ABC);
55+
expect(called).toEqual([ 1 ]);
56+
});
57+
58+
it("should handle multiple writes carried out via writev()", () => {
59+
let callback;
60+
61+
const writable = new Writable({
62+
write: logCall((chunk, encoding, cb) => {
63+
expect(chunk instanceof Buffer).toBe(true);
64+
expect(encoding).toBe("buffer");
65+
expect(String(chunk)).toBe("ABC");
66+
callback = cb;
67+
}, 0),
68+
writev: logCall((chunks, cb) => {
69+
expect(chunks.length).toBe(2);
70+
expect(chunks[0].encoding).toBe("buffer");
71+
expect(chunks[1].encoding).toBe("buffer");
72+
expect(chunks[0].chunk + chunks[1].chunk).toBe("DEFGHI");
73+
}, 1),
74+
});
75+
76+
writable.write(ABC);
77+
writable.write(DEF);
78+
writable.end(GHI);
79+
callback();
80+
expect(called).toEqual([ 1, 1 ]);
81+
});
82+
});
83+
84+
describe("Readable", () => {
85+
it("should perform simple operations", () => {
86+
const readable = new Readable({
87+
read() {}
88+
});
89+
90+
readable.push(DEF);
91+
readable.unshift(ABC);
92+
93+
const buf = readable.read();
94+
expect(buf instanceof Buffer).toBe(true);
95+
expect([ ...buf ]).toEqual([ ...ABC, ...DEF ]);
96+
});
97+
98+
it("should work with setEncoding()", () => {
99+
const readable = new Readable({
100+
read() {}
101+
});
102+
103+
readable.setEncoding("utf8");
104+
105+
readable.push(DEF);
106+
readable.unshift(ABC);
107+
108+
const out = readable.read();
109+
expect(out).toBe("ABCDEF");
110+
});
111+
});

0 commit comments

Comments
 (0)