Compare commits

...

32 Commits

Author SHA1 Message Date
Ben Grant
e763dc64bb Fix some missing exception checks in Zig::GlobalObject 2024-10-16 18:49:08 -07:00
Ciro Spaciari
2d0b557ff7 add grpc-js bench (#14601) 2024-10-16 11:11:53 -07:00
Meghan Denny
15f5ba3e26 jest: print received value when expect().toThrow() doesnt throw (#14608) 2024-10-16 11:11:26 -07:00
refi64
1385f9f686 cmake: force the c-ares libdir to always be 'lib' (#14602) 2024-10-16 10:13:20 -07:00
Ciro Spaciari
07ccec0fd8 H2 fixes (#14606) 2024-10-16 09:06:56 -07:00
Dylan Conway
7283453eed use memset_patternN in Buffer.fill (#14599) 2024-10-15 21:16:57 -07:00
Ciro Spaciari
1a08cfcd6b fix h2 tests failures (#14598) 2024-10-15 18:36:23 -07:00
Meghan Denny
06e733cc64 ci: run clang-format on .h files too (#14597)
Co-authored-by: nektro <nektro@users.noreply.github.com>
2024-10-15 16:54:49 -07:00
Ciro Spaciari
409e674526 feat(node:http2) Implement HTTP2 server support (#14286)
Co-authored-by: cirospaciari <cirospaciari@users.noreply.github.com>
Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
2024-10-15 16:28:21 -07:00
Meghan Denny
d15eadaa2c tsconfig.json: update excludes (#14578) 2024-10-15 15:39:09 -07:00
dave caruso
5532e1af10 feat(bake): hot-reloading error modal (#14573) 2024-10-15 00:02:58 -07:00
Meghan Denny
68e6304c73 node:child_process: 'ineherit' stdio should make getters be null (#14576) 2024-10-14 23:41:34 -07:00
Meghan Denny
709cd95c30 test: use isWindows from harness (#14577) 2024-10-14 21:19:09 -07:00
Meghan Denny
3830b0c499 more passing node buffer tests (#14371) 2024-10-14 20:22:14 -07:00
Meghan Denny
291b59eb19 bun-types: small fixes (#12794) 2024-10-14 20:15:03 -07:00
190n
035f97ba13 WIP: nuke EventSource as it doesn't work anyway (#14421) 2024-10-14 19:55:06 -07:00
huseeiin
fef9555f82 fix typo. constributors -> contributors (#14531) 2024-10-14 19:50:17 -07:00
Meghan Denny
ae0106b651 delete legacy node test runner (#14572) 2024-10-14 17:31:34 -07:00
Meghan Denny
355dc56db0 scripts/runner.node.mjs: print list of failing tests when run locally (#14571) 2024-10-14 17:22:06 -07:00
Jarred Sumner
5fc53353fb Allow disabling keep-alive (#14569)
Co-authored-by: Ciro Spaciari <ciro.spaciari@gmail.com>
2024-10-14 16:58:42 -07:00
dave caruso
d2fe1ce1c8 feat(bake): handle bundle errors, re-assemble full client payloads, initial error modal (#14504) 2024-10-14 16:49:38 -07:00
Jarred Sumner
29d287261b Fix several bugs when printing exceptions from Error.captureStackTrace (#14548) 2024-10-14 13:43:06 -07:00
Sebastian
6dbd679c06 docs: fix typo (#14565) 2024-10-14 13:29:28 -07:00
Meghan Denny
a5006a13a8 fetch-tcp-stress.test.ts: todo failing on macos ci (#14514) 2024-10-14 12:48:42 -07:00
Meghan Denny
bebf762bcf streams.test.js: todo failing macos test (#14513) 2024-10-14 12:48:04 -07:00
Minsoo Choo
e6ea389e4e Next.js dev server now runs on Bun (#14566) 2024-10-14 12:11:30 -07:00
Timo Sand
47ff4748bd Remove duplicate in import-json.md (#14521) 2024-10-13 15:34:38 +11:00
Don Isaac
09b031d044 fix(parser): uncaught mismatch between JSX opening/closing tags (#14528) 2024-10-12 19:49:45 -07:00
Zack Radisic
6b8fd718c2 Various CSS stuff (#14499)
Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
2024-10-12 07:00:20 -07:00
Jarred Sumner
9ed3858e40 Some types and docs 2024-10-12 06:19:46 -07:00
Dylan Conway
6cf9c41d1f fix(install): ensure read permissions when extracting files (#14511) 2024-10-12 02:37:51 -07:00
Dylan Conway
183a8f61d8 fix bun-build-api.test.ts (#14503) 2024-10-12 00:48:22 -07:00
402 changed files with 44033 additions and 9984 deletions

2
.vscode/launch.json generated vendored
View File

@@ -174,6 +174,8 @@
"BUN_GARBAGE_COLLECTOR_LEVEL": "0",
"BUN_DEBUG_IncrementalGraph": "1",
"BUN_DEBUG_Bake": "1",
"BUN_DEBUG_reload_file_list": "1",
"GOMAXPROCS": "1",
},
"console": "internalConsole",
},

View File

@@ -0,0 +1,33 @@
-----BEGIN CERTIFICATE-----
MIIFxjCCA66gAwIBAgIUUaQCzOcxcFBP0KwoQfNqD/FoI44wDQYJKoZIhvcNAQEL
BQAwYjELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMRYwFAYDVQQHDA1TYW4gRnJh
bmNpc2NvMQwwCgYDVQQKDANCdW4xDDAKBgNVBAsMA0J1bjESMBAGA1UEAwwJbG9j
YWxob3N0MB4XDTI0MTAxNjAwMDExNloXDTM0MTAxNDAwMDExNlowYjELMAkGA1UE
BhMCVVMxCzAJBgNVBAgMAkNBMRYwFAYDVQQHDA1TYW4gRnJhbmNpc2NvMQwwCgYD
VQQKDANCdW4xDDAKBgNVBAsMA0J1bjESMBAGA1UEAwwJbG9jYWxob3N0MIICIjAN
BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAp2s1CWRRV3bkjUxyBefcRCiZj8v6
LIIWOb/kFJOo1PQsmQtOOWfY/kNEATPhLtEVolMzsQtaKV+u/Jnp6vU6cCU0qfQ/
cha/s0XaSn9zkJSXjmNOPDOXoeJ5wmSUvWETRvDgeYXCg84zTwRnD1pXIsKxHtia
SYkTC29skSn0+63GW2Ebzkbn3jcYbk3gfkRO/qw8EDh/4/TcS2SjoHl96E1QcfBX
InXrPGoHQhuqJV60rmmkVws0lTIZIq0g2p7iFDCg5TG1asakX7+CrEM/q+oyo3e8
RwMfc+9pqFEqyvXGIQSulS+CVKKbpAFMg07UGYe1t0s5iCwfLQ9apaKL31t/3Vkr
uVKgy5FrPLnRXkFXDZ1v+43AZBmdLrKODzsqHEbt2JmV0V6JVUkE4kbeJr/nlkhQ
x6yXloYY3VKbnCb1L3HmMInrK1QSpxlOb8RllTd33oBwd1FKEvH2gza0j9hqq8uQ
hWVN7tlamkgtBteZ8Y9fd3MdxD9iZOx4dVtCX1+sgJFdaL2ZgE0asojn46yT8Uqw
5d0M9vqmWc5AqG7c4UWWRrfB1MfOq/X8GtImmKyhEgizIPdWFeF1cNjhPffJv4yR
Y4Rj33OBTCM+9h8ZSw/fKo55yRXyz3bjrW2Mg8Dtq+6TcRd5gSLCaTN6jX8E9y7G
TobnA9MnKHhSIhsCAwEAAaN0MHIwHQYDVR0OBBYEFEJU6/9ELCp1CAxYJ5FJJxpV
FSRmMB8GA1UdIwQYMBaAFEJU6/9ELCp1CAxYJ5FJJxpVFSRmMA8GA1UdEwEB/wQF
MAMBAf8wHwYDVR0RBBgwFoIJbG9jYWxob3N0ggkxMjcuMC4wLjEwDQYJKoZIhvcN
AQELBQADggIBACyOPdVwfJg1aUNANy78+cm6eoInM9NDdXGWHMqCJwYF6qJTQV11
jYwYrl+OWOi3CEC+ogXl+uJX4tSS5d+rBTXEb73cLpogxP+xuxr4cBHhtgpGRpY0
GqWCFUTexHxXMrYhHQxf3uv79PNauw/dd1Baby1OjF3zSKRzFsv4KId97cAgT/9H
HfUo2ym5jmhNFj5rhUavO3Pw1++1eeDeDAkS6T59buzx0h9760WD20oBdgjt42cb
P6xg9OwV7ALQSwJ8YPEXpkl7u+6jy0j5ceYmXh76tAyA+hDYOJrY0opBjSPmXH99
p3W63gvk/AdfeAdbFHp6en0b04x4EIogOGZxBP35rzBvsQpqavBE3PBpUIyrQs5p
OBUncRrcjEDL6WKh6RJIjZnvpHPrEqOqyxaeWRc4+85ZrVArJHGMc8I+zs9uCFjo
Cjfde3d317kCszUTxo0l3azyBpr007PMIUoBF2VJEAyQp2Tz/yu0CbEscNJO/wCn
Sb1A6ojaQcgQe2hsaJz/mS+OOjHHaDbCp9iltP2CS63PYleEx4q1Bn8KVRy2zYTB
n74y4YaD8Q+hSA6zU741pzqK2SFCpBQnSz757ocr6WspQ47iOonX2giGZS/3KVeK
qNzU14+h0b8HaBqZmOvjF+S4G0HDpRwxPzDWgc7dEIWlzHH+ZCqjBFwL
-----END CERTIFICATE-----

View File

@@ -0,0 +1,31 @@
const grpc = require("@grpc/grpc-js");
const protoLoader = require("@grpc/proto-loader");
const packageDefinition = protoLoader.loadSync("benchmark.proto", {});
const proto = grpc.loadPackageDefinition(packageDefinition).benchmark;
const fs = require("fs");
function ping(call, callback) {
callback(null, { message: "Hello, World" });
}
function main() {
const server = new grpc.Server();
server.addService(proto.BenchmarkService.service, { ping: ping });
const tls = !!process.env.TLS && (process.env.TLS === "1" || process.env.TLS === "true");
const port = process.env.PORT || 50051;
const host = process.env.HOST || "localhost";
let credentials;
if (tls) {
const ca = fs.readFileSync("./cert.pem");
const key = fs.readFileSync("./key.pem");
const cert = fs.readFileSync("./cert.pem");
credentials = grpc.ServerCredentials.createSsl(ca, [{ private_key: key, cert_chain: cert }]);
} else {
credentials = grpc.ServerCredentials.createInsecure();
}
server.bindAsync(`${host}:${port}`, credentials, () => {
console.log(`Server running at ${tls ? "https" : "http"}://${host}:${port}`);
});
}
main();

52
bench/grpc-server/key.pem Normal file
View File

@@ -0,0 +1,52 @@
-----BEGIN PRIVATE KEY-----
MIIJQgIBADANBgkqhkiG9w0BAQEFAASCCSwwggkoAgEAAoICAQCnazUJZFFXduSN
THIF59xEKJmPy/osghY5v+QUk6jU9CyZC045Z9j+Q0QBM+Eu0RWiUzOxC1opX678
menq9TpwJTSp9D9yFr+zRdpKf3OQlJeOY048M5eh4nnCZJS9YRNG8OB5hcKDzjNP
BGcPWlciwrEe2JpJiRMLb2yRKfT7rcZbYRvORufeNxhuTeB+RE7+rDwQOH/j9NxL
ZKOgeX3oTVBx8Fcides8agdCG6olXrSuaaRXCzSVMhkirSDanuIUMKDlMbVqxqRf
v4KsQz+r6jKjd7xHAx9z72moUSrK9cYhBK6VL4JUopukAUyDTtQZh7W3SzmILB8t
D1qloovfW3/dWSu5UqDLkWs8udFeQVcNnW/7jcBkGZ0uso4POyocRu3YmZXRXolV
SQTiRt4mv+eWSFDHrJeWhhjdUpucJvUvceYwiesrVBKnGU5vxGWVN3fegHB3UUoS
8faDNrSP2Gqry5CFZU3u2VqaSC0G15nxj193cx3EP2Jk7Hh1W0JfX6yAkV1ovZmA
TRqyiOfjrJPxSrDl3Qz2+qZZzkCobtzhRZZGt8HUx86r9fwa0iaYrKESCLMg91YV
4XVw2OE998m/jJFjhGPfc4FMIz72HxlLD98qjnnJFfLPduOtbYyDwO2r7pNxF3mB
IsJpM3qNfwT3LsZOhucD0ycoeFIiGwIDAQABAoICAE+YYrDCZwHEXsjmzVcNcuVc
wBVjjt9WQabXGmLGCQClzgY9H8WfH8VSyaQgvDB762MvV2YW1ZjSCunBazrvuAbV
SYJ7wyZEtoNO9IdyrMjSPHPPtsRcavzmJalMFIMtAfM6Vh6wf1gW0sIAf9cGxmKa
WYcmx8OqTcmkAePKJNT7O1D6jDO39kjpvM3EbLTbWQsva6bylasVIR8fC8QhvsCQ
8WwaLfMOSPaCGk1Nxcjai+BYDW/sveUo2lZoJTSLUUT0EaqlxXCsXD3BWSj5F+5t
/AFHzdWdIHkIHB2P6V5xFu9fwHjhC3+dh42jqHLNKX2xza0FMKcTAwdzQ094RjL3
cOGIsa0Vdt7Mks5eLCRxz0xI3kyrbF0/CopxT0pVWZwUzPk1G+Z3HesWkVtQpg7u
RYzsoNKKc5mhc/V+vG290WAcNB4E3m85DgKQr4ib+J/rCy5/SnJYgg4QXsEyNlQ5
ESBtRmuPfnrPIxqrDKZ7ZsJv8XFWydXTOfJxeKR1T1S02iYna+z1FnNu+t0ELTr9
uhmkuqmV8RJVTub1P2EJPdiku/61UwNLyyZMgFjATDxB0hHIj1FP1HbfhEYbkYNc
Dl7a7egJ4KFYWpQ+7MzOmc0OKq1HuJ9H4FhoYpbVq1OQosZ6G3d9afKSZa6dFdK0
8ujvdQBR0NlAhc/LAr6BAoIBAQDfD3h9P4i5L8NCdocovCi3Eo0kcNQ3QuvnWrrs
B/9CLoWhJrcLV85d0dEX6lSYl9BWW02ilVB+Qvom2wS2td1CBUgDxovX4tCZCuXt
otYL/yWWOA7IG0Fjt6YEERQD/tRfKnn8hVBlk5cDTXXxHRGVMku4CHsN3ILtITQS
VnVsTrGoWd6mFFA9X9Qu4zR9wKtjGEuL7BT8ixxtXLa2tMjdc4UL140yAgmMemJS
TzC6EURe2OnhIzVe9yyLKcqw0prkGHg/Lau5lA1CAh67ZMY4EjO3cuda8R+O7vyO
z2afeaTORzzdEbSZPG+8oqIN1/RjRCbl3RXYN8ibSwOzp6X7AoIBAQDAJEVta98J
P2/36rXrkl6WrRfYqUPy6vgo/lPuRpp+BQ7ldgmH4+ZrJW5Mxa5hktVujk/C2kAO
auzhzNlsxR+c/KwtsL1JXwBn8CT1bR0qvi+URmvGQn9GOKrLLy+6cfphuZWuc4/r
hAgXzEjzPcJJJfxA1i2soKPbiFiCGHxot68P4uJSM2sU6QjNIxEjPbTJjEg894pD
GJoiRRVHgnzzxL3cqrK90Zn6MAl9f2tYihfddsENeZb5t84LBppxBSGouE3ZH8uD
Sufs4DSj1ptocbDbX+0kRNqfjTI5ivDxlS+ZKBe05PVTUmGBAWLamfCe89IW3/z+
Rfkh4ZBPtlphAoIBADwjSqPR7kWnN+iCVjxIRl3dNYpelQh1FW7hikW6fjpUmphw
/KalPLEUsV/WQIqHW5b8tLihsvrnidPR9rpf29BB5kGGVQuWThEE3CquXTEM0BBo
+qs+lemRiMPN6uyM1qr1o7/OHXfVS8CLMMIZyTTFQ57RQoPhMLdH3WcYQj46FTHD
UQDLtzpkzKr7fJpuyIZF9ZA6zQmtY7OkbGpj4Ue7LmKb8ahK3lIuaLWyPfvcTeeY
aa3WNTxuPWcjlE8J6NKYOksmQAcfgFeMhMaXC83wMltCMlfVbGG30wWZqxxRynoG
wMUFUgCCR8m+uxwqXewpYqdUbOBHYeFkXxIfn+MCggEAR5p8wQ1NHd4lNOekCfkP
BOnWlChoKRPFjUlSL97h3gq2hW6amKimitF1LGkS1kvo+/1O3heFfZn9UxyK/kzr
vg4vgAt4Tup3dUR6EXgrQW2Ev6YKreTEF4Awre2UxM+K9nY5wLxSKvuWJIA9w2AF
kkr0mZj3hniK99n02e6UFlY1iB8OJoIA6tb5L7FcxpxNTjrYBNhfDygQ8Kp8Bp0r
QZDVDHIUkEaXMjRKpRkiAOndgOurgAEK8V69C0DXtzypUX31jO+bYP8+NPlMxK3K
Vn7f4LD75+M88e6lg+oyZmUpStM1GnWksvtlWLUSiNKLaEEGzv2EA6JB+I1dwUb8
oQKCAQEAlmisUyn1/lpNnEzKsfUnRs53WxS2e1br5vJ5+pet3cjXT2btfp6J5/mf
Tfqv5mZfTjYxydG0Kl3afI/SnhTcRS2/s4svrktZYLOLM2PAGYdCV6j1stXl4ObO
eIfjzB3y1Zc2dEcWTylJ/lABoNGMPWFJQ67q8WS37pUHQPseJ++LmZFvlRyBgZBl
VLqiHHiZ2ax+yC1ZxY4RECtEiYFplspNldNe+bP/lzTJftsUDe1FqRT/SvEam+1f
kb//sbHkJ+l4BEv0Us3SIGwJ0BblhxLYO34IFVpheY4UQBy/nRaeUUdVR9r8JtYD
z/cCLOrUJfealezimyd8SKPWPeHhrA==
-----END PRIVATE KEY-----

View File

@@ -0,0 +1,15 @@
{
"name": "bench",
"scripts": {
"deps": "exit 0",
"build": "exit 0",
"bun:server": "TLS=1 PORT=50051 $BUN bun.js",
"node:server": "TLS=1 PORT=50051 $NODE node.js",
"bench": "ghz --cacert ./cert.pem --proto ./benchmark.proto --call benchmark.BenchmarkService.Ping -d '{\"message\": \"Hello\"}' --total=100000 localhost:50051",
"bench:insecure": "ghz --insecure --proto ./benchmark.proto --call benchmark.BenchmarkService.Ping -d '{\"message\": \"Hello\"}' --total=100000 localhost:50051"
},
"dependencies": {
"@grpc/grpc-js": "1.12.0",
"@grpc/proto-loader": "0.7.10"
}
}

View File

@@ -0,0 +1,15 @@
import { bench, run } from "./runner.mjs";
for (let size of [32, 2048, 1024 * 16, 1024 * 1024 * 2, 1024 * 1024 * 16]) {
for (let fillSize of [4, 8, 16, 11]) {
const buffer = Buffer.allocUnsafe(size);
const pattern = "x".repeat(fillSize);
bench(`Buffer.fill ${size} bytes with ${fillSize} byte value`, () => {
buffer.fill(pattern);
});
}
}
await run();

View File

@@ -478,6 +478,7 @@ fn addInternalPackages(b: *Build, obj: *Compile, opts: *BunBuildOptions) void {
.{ .file = "ErrorCode.zig", .import = "ErrorCode" },
.{ .file = "runtime.out.js" },
.{ .file = "bake.client.js", .import = "bake-codegen/bake.client.js", .enable = opts.shouldEmbedCode() },
.{ .file = "bake.error.js", .import = "bake-codegen/bake.error.js", .enable = opts.shouldEmbedCode() },
.{ .file = "bake.server.js", .import = "bake-codegen/bake.server.js", .enable = opts.shouldEmbedCode() },
.{ .file = "bun-error/index.js", .enable = opts.shouldEmbedCode() },
.{ .file = "bun-error/bun-error.css", .enable = opts.shouldEmbedCode() },

View File

@@ -1,6 +1,11 @@
# https://clang.llvm.org/docs/ClangFormat.html
set(CLANG_FORMAT_SOURCES ${BUN_C_SOURCES} ${BUN_CXX_SOURCES})
file(GLOB BUN_H_SOURCES LIST_DIRECTORIES false ${CONFIGURE_DEPENDS}
${CWD}/src/bun.js/bindings/*.h
${CWD}/src/bun.js/modules/*.h
)
set(CLANG_FORMAT_SOURCES ${BUN_C_SOURCES} ${BUN_CXX_SOURCES} ${BUN_H_SOURCES})
register_command(
TARGET

View File

@@ -18,6 +18,7 @@ register_cmake_command(
-DCMAKE_POSITION_INDEPENDENT_CODE=ON
-DCARES_SHARED=OFF
-DCARES_BUILD_TOOLS=OFF # this was set to ON?
-DCMAKE_INSTALL_LIBDIR=lib
LIB_PATH
lib
LIBRARIES

View File

@@ -2,7 +2,7 @@ option(WEBKIT_VERSION "The version of WebKit to use")
option(WEBKIT_LOCAL "If a local version of WebKit should be used instead of downloading")
if(NOT WEBKIT_VERSION)
set(WEBKIT_VERSION 01ac6a63449713c5b7cf38fb03628283041f63be)
set(WEBKIT_VERSION 12e2f46fb01f7c5cf5a992b9414ddfaab32b7110)
endif()
if(WEBKIT_LOCAL)

View File

@@ -14,7 +14,7 @@ In Bun v1.1.9, we added support for DNS caching. This cache makes repeated conne
At the time of writing, we cache up to 255 entries for a maximum of 30 seconds (each). If any connections to a host fail, we remove the entry from the cache. When multiple connections are made to the same host simultaneously, DNS lookups are deduplicated to avoid making multiple requests for the same host.
This cache is automatically used by;
This cache is automatically used by:
- `bun install`
- `fetch()`
@@ -99,7 +99,7 @@ console.log(stats);
### Configuring DNS cache TTL
Bun defaults to 30 seconds for the TTL of DNS cache entries. To change this, you can set the envionrment variable `$BUN_CONFIG_DNS_TIME_TO_LIVE_SECONDS`. For example, to set the TTL to 5 seconds:
Bun defaults to 30 seconds for the TTL of DNS cache entries. To change this, you can set the environment variable `$BUN_CONFIG_DNS_TIME_TO_LIVE_SECONDS`. For example, to set the TTL to 5 seconds:
```sh
BUN_CONFIG_DNS_TIME_TO_LIVE_SECONDS=5 bun run my-script.ts

View File

@@ -325,6 +325,28 @@ As a performance optimization, the class constructor is not called, default init
The database columns are set as properties on the class instance.
### `.iterate()` (`@@iterator`)
Use `.iterate()` to run a query and incrementally return results. This is useful for large result sets that you want to process one row at a time without loading all the results into memory.
```ts
const query = db.query("SELECT * FROM foo");
for (const row of query.iterate()) {
console.log(row);
}
```
You can also use the `@@iterator` protocol:
```ts
const query = db.query("SELECT * FROM foo");
for (const row of query) {
console.log(row);
}
```
This feature was added in Bun v1.1.31.
### `.values()`
Use `values()` to run a query and get back all results as an array of arrays.

View File

@@ -2,12 +2,6 @@
name: Build an app with Next.js and Bun
---
{% callout %}
The Next.js [App Router](https://nextjs.org/docs/app) currently relies on Node.js APIs that Bun does not yet implement. The guide below uses Bun to initialize a project and install dependencies, but it uses Node.js to run the dev server.
{% /callout %}
---
Initialize a Next.js app with `create-next-app`. This automatically installs dependencies using `npm`.
```sh

View File

@@ -27,16 +27,6 @@ data.version; // => "1.0.0"
data.author.name; // => "John Dough"
```
Bun also supports [Import Attributes](https://github.com/tc39/proposal-import-attributes/) and [JSON modules](https://github.com/tc39/proposal-json-modules) syntax.
```ts
import data from "./package.json" with { type: "json" };
data.name; // => "bun"
data.version; // => "1.0.0"
data.author.name; // => "John Dough"
```
---
Bun also supports [Import Attributes](https://github.com/tc39/proposal-import-attributes/) and [JSON modules](https://github.com/tc39/proposal-json-modules) syntax.

View File

@@ -1650,7 +1650,7 @@ declare module "bun" {
* automatically run in a worker thread.
*
* The underlying implementation of these functions are provided by the Zig
* Standard Library. Thanks to @jedisct1 and other Zig constributors for their
* Standard Library. Thanks to @jedisct1 and other Zig contributors for their
* work on this.
*
* ### Example with argon2
@@ -1753,7 +1753,7 @@ declare module "bun" {
* instead which runs in a worker thread.
*
* The underlying implementation of these functions are provided by the Zig
* Standard Library. Thanks to @jedisct1 and other Zig constributors for their
* Standard Library. Thanks to @jedisct1 and other Zig contributors for their
* work on this.
*
* ### Example with argon2
@@ -1792,7 +1792,7 @@ declare module "bun" {
* instead which runs in a worker thread.
*
* The underlying implementation of these functions are provided by the Zig
* Standard Library. Thanks to @jedisct1 and other Zig constributors for their
* Standard Library. Thanks to @jedisct1 and other Zig contributors for their
* work on this.
*
* ### Example with argon2
@@ -4448,15 +4448,18 @@ declare module "bun" {
hostname: string;
port: number;
tls?: TLSOptions;
exclusive?: boolean;
}
interface TCPSocketConnectOptions<Data = undefined> extends SocketOptions<Data> {
hostname: string;
port: number;
tls?: boolean;
exclusive?: boolean;
}
interface UnixSocketOptions<Data = undefined> extends SocketOptions<Data> {
tls?: TLSOptions;
unix: string;
}

View File

@@ -1838,14 +1838,6 @@ declare global {
withCredentials?: boolean;
}
interface EventSource extends Bun.EventSource {}
var EventSource: typeof globalThis extends {
onerror: any;
EventSource: infer T;
}
? T
: EventSource;
interface PromiseConstructor {
/**
* Create a deferred promise, with exposed `resolve` and `reject` methods which can be called

View File

@@ -579,6 +579,15 @@ declare module "bun:sqlite" {
*/
get(...params: ParamsType): ReturnType | null;
/**
* Execute the prepared statement and return an
*
* @param params optional values to bind to the statement. If omitted, the statement is run with the last bound values or no parameters if there are none.
*
*/
iterate(...params: ParamsType): IterableIterator<ReturnType>;
[Symbol.iterator](): IterableIterator<ReturnType>;
/**
* Execute the prepared statement. This returns `undefined`.
*

View File

@@ -208,10 +208,6 @@ const writableStream = new WritableStream();
const a = new ResolveError();
a.level;
}
{
const a = new EventSource("asdf");
a.CLOSED;
}
{
const a = new AbortController();
a;

View File

@@ -233,8 +233,13 @@ async function runTests() {
reportOutputToGitHubAction("failing_tests", markdown);
}
if (!isCI) console.log("-------");
if (!isCI) console.log("passing", results.length - failedTests.length, "/", results.length);
if (!isCI) {
console.log("-------");
console.log("passing", results.length - failedTests.length, "/", results.length);
for (const { testPath } of failedTests) {
console.log("-", testPath);
}
}
return results;
}

View File

@@ -14,6 +14,29 @@ pub fn BabyList(comptime Type: type) type {
pub const Elem = Type;
pub fn parse(input: *bun.css.Parser) bun.css.Result(ListType) {
return switch (input.parseCommaSeparated(Type, bun.css.generic.parseFor(Type))) {
.result => |v| return .{ .result = ListType{
.ptr = v.items.ptr,
.len = @intCast(v.items.len),
.cap = @intCast(v.capacity),
} },
.err => |e| return .{ .err = e },
};
}
pub fn toCss(this: *const ListType, comptime W: type, dest: *bun.css.Printer(W)) bun.css.PrintErr!void {
return bun.css.to_css.fromBabyList(Type, this, W, dest);
}
pub fn eql(lhs: *const ListType, rhs: *const ListType) bool {
if (lhs.len != rhs.len) return false;
for (lhs.sliceConst(), rhs.sliceConst()) |*a, *b| {
if (!bun.css.generic.eql(Type, a, b)) return false;
}
return true;
}
pub fn set(this: *@This(), slice_: []Type) void {
this.ptr = slice_.ptr;
this.len = @as(u32, @truncate(slice_.len));
@@ -29,6 +52,12 @@ pub fn BabyList(comptime Type: type) type {
this.* = .{};
}
pub fn shrinkAndFree(this: *@This(), allocator: std.mem.Allocator, size: usize) void {
var list_ = this.listManaged(allocator);
list_.shrinkAndFree(size);
this.update(list_);
}
pub fn orderedRemove(this: *@This(), index: usize) Type {
var l = this.list();
defer this.update(l);
@@ -290,6 +319,11 @@ pub fn BabyList(comptime Type: type) type {
return this.ptr[0..this.len];
}
pub fn sliceConst(this: *const ListType) callconv(bun.callconv_inline) []const Type {
@setRuntimeSafety(false);
return this.ptr[0..this.len];
}
pub fn write(this: *@This(), allocator: std.mem.Allocator, str: []const u8) !u32 {
if (comptime Type != u8)
@compileError("Unsupported for type " ++ @typeName(Type));

File diff suppressed because it is too large Load Diff

View File

@@ -40,7 +40,11 @@ declare const side: "client" | "server";
*/
declare var server_exports: {
handleRequest: (req: Request, meta: HandleRequestMeta, id: Id) => any;
registerUpdate: (modules: any) => void;
registerUpdate: (
modules: any,
componentManifestAdd: null | string[],
componentManifestDelete: null | string[],
) => void;
};
interface HandleRequestMeta {

View File

@@ -42,8 +42,8 @@ extern fn BakeInitProcessIdentifier() void;
///
/// Full documentation on these fields is located in the TypeScript definitions.
pub const Framework = struct {
entry_client: ?[]const u8 = null,
entry_server: ?[]const u8 = null,
entry_client: []const u8,
entry_server: []const u8,
server_components: ?ServerComponents = null,
react_fast_refresh: ?ReactFastRefresh = null,
@@ -59,7 +59,7 @@ pub const Framework = struct {
.server_components = .{
.separate_ssr_graph = true,
.server_runtime_import = "react-server-dom-webpack/server",
.client_runtime_import = "react-server-dom-webpack/client",
// .client_runtime_import = "react-server-dom-webpack/client",
},
.react_fast_refresh = .{},
.entry_client = "bun-framework-rsc/client.tsx",
@@ -88,7 +88,7 @@ pub const Framework = struct {
const ServerComponents = struct {
separate_ssr_graph: bool = false,
server_runtime_import: []const u8,
client_runtime_import: []const u8,
// client_runtime_import: []const u8,
server_register_client_reference: []const u8 = "registerClientReference",
server_register_server_reference: []const u8 = "registerServerReference",
client_register_server_reference: []const u8 = "registerServerReference",
@@ -106,16 +106,16 @@ pub const Framework = struct {
var clone = f;
var had_errors: bool = false;
if (clone.entry_client) |*path| f.resolveHelper(client, path, &had_errors);
if (clone.entry_server) |*path| f.resolveHelper(server, path, &had_errors);
f.resolveHelper(client, &clone.entry_client, &had_errors, "client entrypoint");
f.resolveHelper(server, &clone.entry_server, &had_errors, "server entrypoint");
if (clone.react_fast_refresh) |*react_fast_refresh| {
f.resolveHelper(client, &react_fast_refresh.import_source, &had_errors);
f.resolveHelper(client, &react_fast_refresh.import_source, &had_errors, "react refresh runtime");
}
if (clone.server_components) |*sc| {
f.resolveHelper(server, &sc.server_runtime_import, &had_errors);
f.resolveHelper(client, &sc.client_runtime_import, &had_errors);
f.resolveHelper(server, &sc.server_runtime_import, &had_errors, "server components runtime");
// f.resolveHelper(client, &sc.client_runtime_import, &had_errors);
}
if (had_errors) return error.ModuleNotFound;
@@ -123,7 +123,7 @@ pub const Framework = struct {
return clone;
}
inline fn resolveHelper(f: *const Framework, r: *bun.resolver.Resolver, path: *[]const u8, had_errors: *bool) void {
inline fn resolveHelper(f: *const Framework, r: *bun.resolver.Resolver, path: *[]const u8, had_errors: *bool, desc: []const u8) void {
if (f.built_in_modules.get(path.*)) |mod| {
switch (mod) {
.import => |p| path.* = p,
@@ -133,9 +133,8 @@ pub const Framework = struct {
}
var result = r.resolve(r.fs.top_level_dir, path.*, .stmt) catch |err| {
bun.Output.err(err, "Failed to resolve '{s}' for framework", .{path.*});
bun.Output.err(err, "Failed to resolve '{s}' for framework ({s})", .{ path.*, desc });
had_errors.* = true;
return;
};
path.* = result.path().?.text; // TODO: what is the lifetime of this string
@@ -203,17 +202,17 @@ pub const Framework = struct {
bun.todoPanic(@src(), "custom react-fast-refresh import source", .{});
},
.server_components = sc: {
const rfr: JSValue = opts.get(global, "serverComponents") orelse {
const sc: JSValue = opts.get(global, "serverComponents") orelse {
if (global.hasException())
return error.JSError;
break :sc null;
};
if (rfr == .null or rfr == .undefined) break :sc null;
if (sc == .null or sc == .undefined) break :sc null;
break :sc .{
.client_runtime_import = "",
// .client_runtime_import = "",
.separate_ssr_graph = brk: {
const prop: JSValue = opts.get(global, "separateSSRGraph") orelse {
const prop: JSValue = sc.get(global, "separateSSRGraph") orelse {
if (!global.hasException())
global.throwInvalidArguments("Missing 'framework.serverComponents.separateSSRGraph'", .{});
return error.JSError;
@@ -224,7 +223,7 @@ pub const Framework = struct {
return error.JSError;
},
.server_runtime_import = brk: {
const prop: JSValue = opts.get(global, "serverRuntimeImportSource") orelse {
const prop: JSValue = sc.get(global, "serverRuntimeImportSource") orelse {
if (!global.hasException())
global.throwInvalidArguments("Missing 'framework.serverComponents.serverRuntimeImportSource'", .{});
return error.JSError;
@@ -239,7 +238,7 @@ pub const Framework = struct {
break :brk str.toUTF8(bun.default_allocator).slice();
},
.server_register_client_reference = brk: {
const prop: JSValue = opts.get(global, "serverRegisterClientReferenceExport") orelse {
const prop: JSValue = sc.get(global, "serverRegisterClientReferenceExport") orelse {
if (!global.hasException())
global.throwInvalidArguments("Missing 'framework.serverComponents.serverRegisterClientReferenceExport'", .{});
return error.JSError;
@@ -326,14 +325,13 @@ pub fn getHmrRuntime(mode: Side) []const u8 {
.server => @embedFile("bake-codegen/bake.server.js"),
}
else switch (mode) {
inline else => |m| bun.runtimeEmbedFile(.codegen, "bake." ++ @tagName(m) ++ ".js"),
inline else => |m| bun.runtimeEmbedFile(.codegen_eager, "bake." ++ @tagName(m) ++ ".js"),
};
}
pub const Mode = enum { production, development };
pub const Side = enum { client, server };
/// TODO: Rename this to Graph
pub const Renderer = enum(u2) {
pub const Graph = enum(u2) {
client,
server,
/// Only used when Framework has .server_components.separate_ssr_graph set

View File

@@ -0,0 +1,82 @@
// This implements error deserialization from the WebSocket protocol
import { BundlerMessageLevel } from "../enums";
import { DataViewReader } from "./reader";
export interface DeserializedFailure {
// If not specified, it is a client-side error.
file: string | null;
messages: BundlerMessage[];
};
export interface BundlerMessage {
kind: "bundler";
level: BundlerMessageLevel;
message: string;
location: BundlerMessageLocation | null;
notes: BundlerNote[];
}
export interface BundlerMessageLocation {
/** One-based */
line: number;
/** One-based */
column: number;
/** Byte length */
length: number;
lineText: string;
}
export interface BundlerNote {
message: string;
location: BundlerMessageLocation | null;
}
export function decodeSerializedError(reader: DataViewReader) {
const kind = reader.u8();
if (kind >= 0 && kind <= 4) {
return readLogMsg(reader, kind);
} else {
throw new Error("TODO: JS Errors");
}
}
/** First byte is already read in. */
function readLogMsg(r: DataViewReader, level: BundlerMessageLevel) {
const message = r.string32();
const location = readBundlerMessageLocationOrNull(r);
const noteCount = r.u32();
const notes = new Array(noteCount);
for (let i = 0; i < noteCount; i++) {
notes[i] = readLogData(r);
}
return {
kind: 'bundler',
level,
message,
location,
notes,
};
}
function readLogData(r: DataViewReader): BundlerNote | null {
return {
message: r.string32(),
location: readBundlerMessageLocationOrNull(r),
};
}
function readBundlerMessageLocationOrNull(r: DataViewReader): BundlerMessageLocation | null {
const line = r.u32();
if (line == 0) return null;
const column = r.u32();
const length = r.u32();
const lineText = r.string32();
return {
line,
column,
length,
lineText,
};
}

View File

View File

@@ -3,12 +3,26 @@
* the user's application causes no issue. This sheet is used to
* style error popups and other elements provided by DevServer.
*/
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
main {
.root {
color-scheme: light dark;
--modal-bg: light-dark(#efefef, #202020);
--modal-text: light-dark(#0a0a0a, #fafafa);
--modal-text-faded: light-dark(#0a0a0a88, #fafafa88);
--item-bg: light-dark(#d4d4d4, #0f0f0f);
--item-bg-hover: light-dark(#cccccc, #171717);
--red: #ff5858;
--log-error: light-dark(#dc0000, #ff5858);
--log-warn: light-dark(#eab308, #fbbf24);
--log-note: light-dark(#008ae6, #22d3ee);
--log-colon: light-dark(#888, #888);
font-family:
system-ui,
-apple-system,
@@ -21,9 +35,142 @@ main {
"Open Sans",
"Helvetica Neue",
sans-serif;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
}
.error {
padding: 1rem;
background-color: rgba(255, 169, 169, 0.9);
code,
.file-name,
.message {
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
}
.modal {
color: var(--modal-text);
background-color: var(--modal-bg);
border-top: 8px solid var(--red);
border-radius: 8px;
margin: 4rem 2rem 2rem 2rem;
max-width: 940px;
width: 100%;
box-shadow:
0 2px 6px #0004,
0 2px 32px #0003;
}
header {
margin: 1rem 1rem;
color: var(--red);
font-size: 2rem;
font-weight: bold;
}
footer {
color: var(--modal-text-faded);
margin: 1rem;
}
pre {
font: unset;
}
.message-group {
display: flex;
flex-direction: column;
background-color: var(--item-bg);
}
/* this is a <button> */
.file-name {
appearance: none;
background-color: transparent;
border: none;
font-size: unset;
font-weight: bold;
padding: 0.5rem 1rem;
text-align: left;
cursor: pointer;
}
/* .file-name:hover,
.file-name:focus-visible {
background-color: var(--item-bg-hover);
}
.file-name::after {
color: var(--modal-text-faded);
font-size: 70%;
}
.file-name:hover::after {
content: " (click to open in editor)";
} */
.message {
margin: 1rem;
margin-bottom: 0;
}
button+.message {
margin-top: 0.5rem;
}
.message-text>span {
color: var(--color);
}
.log-error {
--color: var(--log-error);
font-weight: bold;
}
.log-warn {
--color: var(--log-warn);
}
.log-note {
--color: var(--log-note);
}
.log-colon {
--color: var(--log-colon);
}
.code-line {
display: flex;
margin: 0.5rem 0;
}
.line-num {
color: var(--modal-text-faded);
margin-right: 10px;
}
.highlight-wrap {
color: transparent;
user-select: none;
pointer-events: none;
transform: translateY(-20px);
margin-bottom: -5px;
}
.highlight-wrap .line {
margin-left: 10px;
text-decoration: underline;
text-decoration-style: wavy;
text-decoration-color: var(--color);
}
@media (prefers-color-scheme: light) {
.log-warn,
.log-note {
font-weight: bold;
}
}

View File

@@ -1,33 +1,252 @@
// This file implements the UI for error modals. Since using a framework like
// React could collide with the user's code (consider React DevTools), this
// entire modal is written from scratch using the standard DOM APIs. All CSS is
// scoped in `overlay.css`, and all elements exist under a shadow root. These
// constraints make the overlay simple to understand and work on.
//
// This file has two consumers:
// - The bundler error page which embeds a list of bundler errors to render.
// - The client runtime, for when reloading errors happen.
// Both use a WebSocket to coordinate followup updates, when new errors are
// added or previous ones are solved.
import { BundlerMessageLevel } from "../enums";
import { css } from "../macros" with { type: "macro" };
import { BundlerMessage, BundlerMessageLocation, BundlerNote, decodeSerializedError, type DeserializedFailure } from "./error-serialization";
import { DataViewReader } from "./reader";
// Create a root element to contain all our our DOM nodes.
var root!: HTMLElement;
var mount;
if (side !== "client") throw new Error("Not client side!");
if (side === "client") {
mount = function mount() {
const wrap = document.createElement("bun-hmr");
wrap.setAttribute(
"style",
"position:absolute;display:block;top:0;left:0;width:100%;height:100%;background:transparent",
);
const shadow = wrap.attachShadow({ mode: "open" });
const sheet = new CSSStyleSheet();
sheet.replace(css("client/overlay.css", IS_BUN_DEVELOPMENT));
shadow.adoptedStyleSheets = [sheet];
root = document.createElement("main");
shadow.appendChild(root);
document.body.appendChild(wrap);
};
// I would have used JSX, but TypeScript types interfere in odd ways.
function elem(tagName: string, props?: null | Record<string, string>, children?: (HTMLElement | Text)[]) {
const node = document.createElement(tagName);
if (props)
for (let key in props) {
node.setAttribute(key, props[key]);
}
if (children)
for (const child of children) {
node.appendChild(child);
}
return node;
}
export function showErrorOverlay(e) {
mount();
console.error(e);
root.innerHTML = `<div class='error'><h1>Client-side Runtime Error</h1><pre><code>${e?.message ? `${e?.name ?? e?.constructor?.name ?? "Error"}: ${e.message}\n` : JSON.stringify(e)}${e?.message ? e?.stack : ""}</code></pre><button class='dismiss'>x</button></div>`;
root.querySelector(".dismiss")!.addEventListener("click", () => {
root.innerHTML = "";
function elemText(tagName: string, props: null | Record<string, string>, innerHTML: string) {
const node = document.createElement(tagName);
if (props)
for (let key in props) {
node.setAttribute(key, props[key]);
}
node.textContent = innerHTML;
return node;
}
const textNode = (str = "") => document.createTextNode(str);
/**
* 32-bit integer corresponding to `SerializedFailure.Owner.Packed`
* It is never decoded client-side; treat this as an opaque identifier.
*/
type ErrorId = number;
const errors = new Map<ErrorId, DeserializedFailure>();
const errorDoms = new Map<ErrorId, ErrorDomNodes>();
const updatedErrorOwners = new Set<ErrorId>();
let domShadowRoot: HTMLElement;
let domModalTitle: Text;
let domErrorList: HTMLElement;
interface ErrorDomNodes {
root: HTMLElement;
title: Text;
messages: HTMLElement[];
}
/**
* Initial mount is done lazily. The modal starts invisible, controlled
* by `setModalVisible`.
*/
function mountModal() {
if (domModalTitle) return;
domShadowRoot = elem("bun-hmr", {
style:
"position:absolute!important;" +
"display:none!important;" +
"top:0!important;" +
"left:0!important;" +
"width:100%!important;" +
"height:100%!important;" +
"background:#8883!important",
});
const shadow = domShadowRoot.attachShadow({ mode: "open" });
const sheet = new CSSStyleSheet();
sheet.replace(css("client/overlay.css", IS_BUN_DEVELOPMENT));
shadow.adoptedStyleSheets = [sheet];
const root = elem("div", { class: "root" }, [
elem("div", { class: "modal" }, [
elem("header", null, [(domModalTitle = textNode())]),
(domErrorList = elem("div", { class: "error-list" })),
elem("footer", null, [
// TODO: for HMR turn this into a clickable thing + say it can be dismissed
textNode("Errors during a build can only be dismissed fixing them."),
]),
]),
]);
shadow.appendChild(root);
document.body.appendChild(domShadowRoot);
}
let isModalVisible = false;
function setModalVisible(visible: boolean) {
if (isModalVisible === visible || !domShadowRoot) return;
isModalVisible = visible;
domShadowRoot.style.display = visible ? "block" : "none";
}
/** Handler for `MessageId.errors` websocket packet */
export function onErrorMessage(view: DataView) {
const reader = new DataViewReader(view, 1);
const removedCount = reader.u32();
for (let i = 0; i < removedCount; i++) {
const removed = reader.u32();
updatedErrorOwners.add(removed);
errors.delete(removed);
}
while (reader.hasMoreData()) {
decodeAndAppendError(reader);
}
updateErrorOverlay();
}
export function onErrorClearedMessage() {
errors.keys().forEach(key => updatedErrorOwners.add(key));
errors.clear();
updateErrorOverlay();
}
/**
* Call this for each error, then call `updateErrorOverlay` to commit the
* changes to the UI in one smooth motion.
*/
export function decodeAndAppendError(r: DataViewReader) {
const owner = r.u32();
const file = r.string32() || null;
const messageCount = r.u32();
const messages = new Array(messageCount);
for (let i = 0; i < messageCount; i++) {
messages[i] = decodeSerializedError(r);
}
errors.set(owner, { file, messages });
updatedErrorOwners.add(owner);
}
export function updateErrorOverlay() {
console.log(errors, updatedErrorOwners);
if (errors.size === 0) {
setModalVisible(false);
return;
}
mountModal();
let totalCount = 0;
for (const owner of updatedErrorOwners) {
const data = errors.get(owner);
let dom = errorDoms.get(owner);
// If this failure was removed, delete it.
if (!data) {
dom?.root.remove();
errorDoms.delete(owner);
continue;
}
totalCount += data.messages.length;
// Create the element for the root if it does not yet exist.
if (!dom) {
let title;
const root = elem("div", { class: "message-group" }, [
elem("button", { class: "file-name" }, [
title = textNode()
]),
]);
dom = { root, title, messages: [] };
// TODO: sorted insert?
domErrorList.appendChild(root);
errorDoms.set(owner, dom);
} else {
// For simplicity, messages are not reused, even if left unchanged.
dom.messages.forEach(msg => msg.remove());
}
// Update the DOM with the new data.
dom.title.textContent = data.file;
for (const msg of data.messages) {
const domMessage = renderBundlerMessage(msg);
dom.root.appendChild(domMessage);
dom.messages.push(domMessage);
}
}
domModalTitle.textContent = `${errors.size} Build Error${errors.size !== 1 ? "s" : ""}`;
updatedErrorOwners.clear();
setModalVisible(true);
}
const bundleLogLevelToName = [
"error",
"warn",
"note",
"debug",
"verbose",
];
function renderBundlerMessage(msg: BundlerMessage) {
return elem('div', { class: 'message' }, [
renderErrorMessageLine(msg.level, msg.message),
...msg.location ? renderCodeLine(msg.location, msg.level) : [],
...msg.notes.map(renderNote),
].flat(1));
}
function renderErrorMessageLine(level: BundlerMessageLevel, text: string) {
const levelName = bundleLogLevelToName[level];
if(IS_BUN_DEVELOPMENT && !levelName) {
throw new Error("Unknown log level: " + level);
}
return elem('div', { class: 'message-text' } , [
elemText('span', { class: 'log-' + levelName }, levelName),
elemText('span', { class: 'log-colon' }, ': '),
elemText('span', { class: 'log-text' }, text),
]);
}
function renderCodeLine(location: BundlerMessageLocation, level: BundlerMessageLevel) {
return [
elem('div', { class: 'code-line' }, [
elemText('code', { class: 'line-num' }, `${location.line}`),
elemText('pre', { class: 'code-view' }, location.lineText),
]),
elem('div', { class: 'highlight-wrap log-' + bundleLogLevelToName[level] }, [
elemText('span', { class: 'space' }, '_'.repeat(`${location.line}`.length + location.column - 1)),
elemText('span', { class: 'line' }, '_'.repeat(location.length)),
])
];
}
function renderNote(note: BundlerNote) {
return [
renderErrorMessageLine(BundlerMessageLevel.note, note.message),
...note.location ? renderCodeLine(note.location, BundlerMessageLevel.note) : [],
];
}

View File

@@ -1,4 +1,4 @@
import { td } from "../text-decoder";
import { td } from "../shared";
export class DataViewReader {
view: DataView;
@@ -27,9 +27,17 @@ export class DataViewReader {
return value;
}
string(byteLength: number) {
stringWithLength(byteLength: number) {
const str = td.decode(this.view.buffer.slice(this.cursor, this.cursor + byteLength));
this.cursor += byteLength;
return str;
}
string32() {
return this.stringWithLength(this.u32());
}
hasMoreData() {
return this.cursor < this.view.byteLength;
}
}

View File

@@ -0,0 +1,85 @@
const isLocal = location.host === "localhost" || location.host === "127.0.0.1";
function wait() {
return new Promise<void>(done => {
let timer;
const onTimeout = () => {
if (timer !== null) clearTimeout(timer);
document.removeEventListener("focus", onTimeout);
done();
};
document.addEventListener("focus", onTimeout);
timer = setTimeout(
() => {
timer = null;
onTimeout();
},
isLocal ? 2_500 : 30_000,
);
});
}
export function initWebSocket(handlers: Record<number, (dv: DataView) => void>) {
let firstConnection = true;
function onOpen() {
if (firstConnection) {
firstConnection = false;
console.info("[Bun] Hot-module-reloading socket connected, waiting for changes...");
}
}
function onMessage(ev: MessageEvent<string | ArrayBuffer>) {
const { data } = ev;
if (typeof data === "object") {
const view = new DataView(data);
if (IS_BUN_DEVELOPMENT) {
console.info("[WS] " + String.fromCharCode(view.getUint8(0)));
}
handlers[view.getUint8(0)]?.(view);
}
}
function onError(ev: Event) {
console.error(ev);
}
async function onClose() {
console.warn("[Bun] Hot-module-reloading socket disconnected, reconnecting...");
while (true) {
await wait();
// Note: Cannot use Promise.withResolvers due to lacking support on iOS
let done;
const promise = new Promise<boolean>(cb => (done = cb));
ws = new WebSocket("/_bun/hmr");
ws.binaryType = "arraybuffer";
ws.onopen = () => {
console.info("[Bun] Reconnected");
done(true);
onOpen();
ws.onerror = onError;
};
ws.onmessage = onMessage;
ws.onerror = ev => {
onError(ev);
done(false);
};
if (await promise) {
break;
}
}
}
let ws = new WebSocket("/_bun/hmr");
ws.binaryType = "arraybuffer";
ws.onopen = onOpen;
ws.onmessage = onMessage;
ws.onclose = onClose;
ws.onerror = onError;
}

26
src/bake/enums.ts Normal file
View File

@@ -0,0 +1,26 @@
// TODO: generate this using information in DevServer.zig
export const enum MessageId {
/// Version packet
version = 86,
/// When visualization mode is enabled, this packet contains
/// the entire serialized IncrementalGraph state.
visualizer = 118,
/// Sent on a successful bundle, containing client code.
hot_update = 40,
/// Sent on a successful bundle, containing a list of
/// routes that are updated.
route_update = 82,
/// Sent when the list of errors changes.
errors = 69,
/// Sent when all errors are cleared. Semi-redundant
errors_cleared = 99,
}
export const enum BundlerMessageLevel {
err = 0,
warn = 1,
note = 2,
debug = 3,
verbose = 4,
}

View File

@@ -1,15 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>{[page_title]s}</title>
</head>
<body>
<script id="bun_error_payload" type="text/bun-error-payload">
{[error_payload]s}
</script>
<script src="/_bun/error.js"></script>
</body>
</html>

View File

@@ -19,9 +19,9 @@ export const enum LoadModuleType {
/**
* This object is passed as the CommonJS "module", but has a bunch of
* non-standard properties that are used for implementing hot-module
* reloading. It is unacceptable to depend on these properties, and
* it will not be considered a breaking change.
* non-standard properties that are used for implementing hot-module reloading.
* It is unacceptable for users to depend on these properties, and it will not
* be considered a breaking change when these internals are altered.
*/
export class HotModule<E = any> {
id: Id;
@@ -115,6 +115,8 @@ export function loadModule<T = any>(key: Id, type: LoadModuleType): HotModule<T>
return module;
}
export const getModule = registry.get.bind(registry);
export function replaceModule(key: Id, load: ModuleLoadFunction) {
const module = registry.get(key);
if (module) {
@@ -151,6 +153,16 @@ export function replaceModules(modules: any) {
registry.set("bun:wrap", runtime);
}
export const serverManifest = {};
export const clientManifest = {};
if (side === "server") {
const server_module = new HotModule("bun:bake/server");
server_module.__esModule = true;
server_module.exports = { serverManifest, clientManifest };
registry.set(server_module.id, server_module);
}
if (side === "client") {
const { refresh } = config;
if (refresh) {

View File

@@ -33,15 +33,24 @@ V1.1.30-canary.37+117e1b388
Hot-module-reloading patch. The entire payload is UTF-8 Encoded JavaScript Payload.
### `R`
### `R` - Route reload request
Server-side code has reloaded. Client should either refetch the route or perform a hard reload.
- `u32` Number of updated routes
- `u32`: Number of updated routes
- For each route:
- `u32` Route ID
- `u16` Length of route name.
- `[n]u8` Route name in UTF-8 encoded text.
- `u32`: Route ID
- `u16`: Length of route name.
- `[n]u8`: Route name in UTF-8 encoded text.
### `e` - Error status update
- `u32`: Number of errors removed
- For each removed error:
- `u32` Error owner
- Remainder of payload is repeating each error object:
- `u32` Error owner
- Error Payload
### `v`

View File

@@ -1,12 +1,13 @@
// This file is the entrypoint to the hot-module-reloading runtime
// In the browser, this uses a WebSocket to communicate with the bundler.
import { loadModule, LoadModuleType, replaceModules } from "./hmr-module";
import { showErrorOverlay } from "./client/overlay";
import { onErrorClearedMessage, onErrorMessage } from "./client/overlay";
import { Bake } from "bun";
import { int } from "./macros" with { type: "macro" };
import { td } from "./text-decoder";
import { td } from "./shared";
import { DataViewReader } from "./client/reader";
import { routeMatch } from "./client/route";
import { initWebSocket } from "./client/websocket";
import { MessageId } from "./enums";
if (typeof IS_BUN_DEVELOPMENT !== "boolean") {
throw new Error("DCE is configured incorrectly");
@@ -23,7 +24,7 @@ async function performRouteReload() {
console.error(err);
console.error("The page will hard-reload now.");
if (IS_BUN_DEVELOPMENT) {
return showErrorOverlay(err);
// return showErrorOverlay(err);
}
}
}
@@ -33,84 +34,45 @@ async function performRouteReload() {
location.reload();
}
try {
const main = loadModule<Bake.ClientEntryPoint>(config.main, LoadModuleType.AssertPresent);
let main;
try {
main = loadModule<Bake.ClientEntryPoint>(config.main, LoadModuleType.AssertPresent);
var { onServerSideReload, ...rest } = main.exports;
if (Object.keys(rest).length > 0) {
console.warn(
`Framework client entry point (${config.main}) exported unknown properties, found: ${Object.keys(rest).join(", ")}`,
);
}
const enum SocketState {
Connecting,
Connected,
}
let state = SocketState.Connecting;
function initHmrWebSocket() {
const ws = new WebSocket("/_bun/hmr");
ws.binaryType = "arraybuffer";
ws.onopen = ev => {
console.log("HMR socket open!");
state = SocketState.Connected;
};
ws.onmessage = (ev: MessageEvent<string | ArrayBuffer>) => {
const { data } = ev;
if (typeof data === "string") return data;
const view = new DataView(data);
// See hmr-protocol.md
switch (view.getUint8(0)) {
case int("V"): {
console.log("VERSION", data);
break;
}
case int("("): {
const code = td.decode(data);
const modules = (0, eval)(code);
replaceModules(modules);
break;
}
case int("R"): {
const reader = new DataViewReader(view, 1);
let routeCount = reader.u32();
while (routeCount > 0) {
routeCount -= 1;
const routeId = reader.u32();
const routePattern = reader.string(reader.u16());
if (routeMatch(routeId, routePattern)) {
performRouteReload();
break;
}
}
break;
}
default: {
if (IS_BUN_DEVELOPMENT) {
return showErrorOverlay(
new Error("Unknown WebSocket Payload ID: " + String.fromCharCode(view.getUint8(0))),
);
}
location.reload();
break;
}
}
};
ws.onclose = ev => {
// TODO: visual feedback in overlay.ts
// TODO: reconnection
};
ws.onerror = ev => {
console.error(ev);
};
}
initHmrWebSocket();
} catch (e) {
if (side !== "client") throw e;
showErrorOverlay(e);
// showErrorOverlay(e);
console.error(e);
}
initWebSocket({
[MessageId.version](view) {
// TODO: config.version and verify everything is sane
console.log("VERSION: ", td.decode(view.buffer.slice(1)));
},
[MessageId.hot_update](view) {
const code = td.decode(view.buffer);
const modules = (0, eval)(code);
replaceModules(modules);
},
[MessageId.errors]: onErrorMessage,
[MessageId.errors_cleared]: onErrorClearedMessage,
[MessageId.route_update](view) {
const reader = new DataViewReader(view, 1);
let routeCount = reader.u32();
while (routeCount > 0) {
routeCount -= 1;
const routeId = reader.u32();
const routePattern = reader.stringWithLength(reader.u16());
if (routeMatch(routeId, routePattern)) {
performRouteReload();
break;
}
}
},
});

View File

@@ -0,0 +1,60 @@
// When a bundling error happens, we cannot load any of the users code, since
// that code expects the SSR step to succeed. This version of client just opens
// a websocket and listens only for error resolution events, and reloads the
// page.
//
// This is embedded in `DevServer.sendSerializedFailures`. SSR is
// left unused for simplicity; a flash of unstyled content is
// stopped by the fact this script runs synchronously.
import { decodeAndAppendError, onErrorMessage, updateErrorOverlay } from "./client/overlay";
import { DataViewReader } from "./client/reader";
import { routeMatch } from "./client/route";
import { initWebSocket } from "./client/websocket";
import { MessageId } from "./enums";
/** Injected by DevServer */
declare const error: Uint8Array;
{
const reader = new DataViewReader(new DataView(error.buffer), 0);
while (reader.hasMoreData()) {
decodeAndAppendError(reader);
}
updateErrorOverlay();
}
let firstVersionPacket = true;
initWebSocket({
[MessageId.version](dv) {
if (firstVersionPacket) {
firstVersionPacket = false;
} else {
// On re-connection, the server may have restarted. The route that was
// requested could be in unqueued state. A reload is the only way to
// ensure this bundle is enqueued.
location.reload();
}
},
[MessageId.errors]: onErrorMessage,
[MessageId.route_update](view) {
const reader = new DataViewReader(view, 1);
let routeCount = reader.u32();
while (routeCount > 0) {
routeCount -= 1;
const routeId = reader.u32();
const routePattern = reader.stringWithLength(reader.u16());
if (routeMatch(routeId, routePattern)) {
location.reload();
break;
}
}
},
[MessageId.errors_cleared]() {
location.reload();
},
});

View File

@@ -2,7 +2,7 @@
// On the server, communication is facilitated using the default
// export, which is assigned via `server_exports`.
import type { Bake } from "bun";
import { loadModule, LoadModuleType, replaceModules } from "./hmr-module";
import { loadModule, LoadModuleType, replaceModules, clientManifest, serverManifest, getModule } from "./hmr-module";
if (typeof IS_BUN_DEVELOPMENT !== "boolean") {
throw new Error("DCE is configured incorrectly");
@@ -32,5 +32,37 @@ server_exports = {
// TODO: support streaming
return await response.text();
},
registerUpdate: replaceModules,
registerUpdate(modules, componentManifestAdd, componentManifestDelete) {
replaceModules(modules);
if (componentManifestAdd) {
for (const uid of componentManifestAdd) {
try {
const mod = loadModule(uid, LoadModuleType.AssertPresent);
const { exports, __esModule } = mod;
const exp = __esModule ? exports : (mod._ext_exports ??= { ...exports, default: exports });
for (const exportName of Object.keys(exp)) {
serverManifest[uid] = {
id: uid,
name: exportName,
chunks: [],
};
}
} catch (err) {
console.log(err);
}
}
}
if (componentManifestDelete) {
for (const fileName of componentManifestDelete) {
const client = clientManifest[fileName];
for (const exportName in client) {
delete serverManifest[`${fileName}#${exportName}`];
}
delete clientManifest[fileName];
}
}
},
};

View File

@@ -1,326 +1,345 @@
<!DOCTYPE html>
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>IncrementalGraph Visualization</title>
<script type="text/javascript" src="https://unpkg.com/vis-network/standalone/umd/vis-network.min.js"></script>
<style>
html,
body {
background-color: #1e1e2e;
color: #cdd6f4;
font-family: sans-serif;
}
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>IncrementalGraph Visualization</title>
<script type="text/javascript" src="https://unpkg.com/vis-network/standalone/umd/vis-network.min.js"></script>
<style>
html,
body {
background-color: #1e1e2e;
color: #cdd6f4;
font-family: sans-serif;
}
#network {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
}
#network {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
}
h1 {
position: fixed;
top: 1rem;
left: 1rem;
pointer-events: none;
font-size: 1rem;
margin: 0;
z-index: 100;
}
h1 {
position: fixed;
top: 1rem;
left: 1rem;
pointer-events: none;
font-size: 1rem;
margin: 0;
}
#stat {
font-weight: normal;
}
</style>
</head>
#stat {
font-weight: normal;
}
</style>
</head>
<body>
<h1>IncrementalGraph Visualization <span id="stat"></span></h1>
<div id="network"></div>
<body>
<h1>IncrementalGraph Visualization <span id="stat"></span></h1>
<div id="network"></div>
<script>
// Connect to HMR WebSocket and enable visualization packets. This
// serializes the both `IncrementalGraph`s in full and sends them
// over the wire. A visualization is provided by `vis.js`. Support
//
// Script written partially by ChatGPT
<script>
const c = {
// derived from mocha theme on https://catppuccin.com/palette
red: '#f38ba8',
green: '#a6e3a1',
mauve: '#cba6f7',
gray: '#7f849c',
orange: '#fab387',
sky: '#89dceb',
blue: '#89b4fa',
yellow: '#f9e2af',
};
const ws = new WebSocket(location.origin + "/_bun/hmr");
const c = {
// Derived from mocha theme on https://catppuccin.com/palette
red: "#f38ba8",
green: "#a6e3a1",
mauve: "#cba6f7",
gray: "#7f849c",
orange: "#fab387",
sky: "#89dceb",
blue: "#89b4fa",
yellow: "#f9e2af",
};
const ws = new WebSocket(location.origin + "/_bun/hmr");
ws.binaryType = "arraybuffer"; // We are expecting binary data
ws.binaryType = "arraybuffer"; // We are expecting binary data
ws.onopen = function () {
ws.send(new Uint8Array([118])); // Send 'v' byte to initiate connection
};
ws.onopen = function () {
ws.send(new Uint8Array([118])); // Send 'v' byte to initiate connection
};
// Store nodes and edges
let clientFiles = [];
let serverFiles = [];
let clientEdges = [];
let serverEdges = [];
let currentEdgeIds = new Set();
let isFirst = true;
// Store nodes and edges
let clientFiles = [];
let serverFiles = [];
let clientEdges = [];
let serverEdges = [];
let currentEdgeIds = new Set();
let currentNodeIds = new Set();
let isFirst = true;
// When a message is received
ws.onmessage = function (event) {
const buffer = new Uint8Array(event.data);
// When a message is received
ws.onmessage = function (event) {
const buffer = new Uint8Array(event.data);
// Only process messages starting with 'v' (ASCII code 118)
if (buffer[0] !== 118) return;
console.log('Got Event');
// Only process messages starting with 'v' (ASCII code 118)
if (buffer[0] !== 118) return;
console.log("Got Event");
let offset = 1; // Skip the 'v' byte
let offset = 1; // Skip the 'v' byte
// Parse client files
const clientFileCount = readUint32(buffer, offset);
offset += 4;
clientFiles = parseFiles(buffer, clientFileCount, offset);
offset = clientFiles.offset;
clientFiles = clientFiles.files;
// Parse server files
const serverFileCount = readUint32(buffer, offset);
offset += 4;
serverFiles = parseFiles(buffer, serverFileCount, offset);
offset = serverFiles.offset;
serverFiles = serverFiles.files;
// Parse client edges
const clientEdgeCount = readUint32(buffer, offset);
offset += 4;
clientEdges = parseEdges(buffer, clientEdgeCount, offset);
offset = clientEdges.offset;
clientEdges = clientEdges.edges;
// Parse server edges
const serverEdgeCount = readUint32(buffer, offset);
offset += 4;
serverEdges = parseEdges(buffer, serverEdgeCount, offset);
offset = serverEdges.offset;
serverEdges = serverEdges.edges;
// Update the graph visualization
updateGraph();
};
// Helper to read 4-byte unsigned int
function readUint32(buffer, offset) {
return buffer[offset] |
(buffer[offset + 1] << 8) |
(buffer[offset + 2] << 16) |
(buffer[offset + 3] << 24);
}
function basename(path) {
return path.slice(path.lastIndexOf('/') + 1)
}
// Parse the files from the buffer
function parseFiles(buffer, count, offset) {
const files = [];
for (let i = 0; i < count; i++) {
const nameLength = readUint32(buffer, offset);
// Parse client files
const clientFileCount = readUint32(buffer, offset);
offset += 4;
// If the name length is 0, it's a deleted file
if (nameLength === 0) {
files.push({ id: i, deleted: true });
continue;
clientFiles = parseFiles(buffer, clientFileCount, offset);
offset = clientFiles.offset;
clientFiles = clientFiles.files;
// Parse server files
const serverFileCount = readUint32(buffer, offset);
offset += 4;
serverFiles = parseFiles(buffer, serverFileCount, offset);
offset = serverFiles.offset;
serverFiles = serverFiles.files;
// Parse client edges
const clientEdgeCount = readUint32(buffer, offset);
offset += 4;
clientEdges = parseEdges(buffer, clientEdgeCount, offset);
offset = clientEdges.offset;
clientEdges = clientEdges.edges;
// Parse server edges
const serverEdgeCount = readUint32(buffer, offset);
offset += 4;
serverEdges = parseEdges(buffer, serverEdgeCount, offset);
offset = serverEdges.offset;
serverEdges = serverEdges.edges;
// Update the graph visualization
updateGraph();
};
// Helper to read 4-byte unsigned int
function readUint32(buffer, offset) {
return buffer[offset] | (buffer[offset + 1] << 8) | (buffer[offset + 2] << 16) | (buffer[offset + 3] << 24);
}
function basename(path) {
return path.slice(path.lastIndexOf("/") + 1);
}
// Parse the files from the buffer
function parseFiles(buffer, count, offset) {
const files = [];
for (let i = 0; i < count; i++) {
const nameLength = readUint32(buffer, offset);
offset += 4;
// If the name length is 0, it's a deleted file
if (nameLength === 0) {
files.push({ id: i, deleted: true });
continue;
}
const nameBytes = buffer.slice(offset, offset + nameLength);
const name = new TextDecoder().decode(nameBytes);
offset += nameLength;
const isStale = buffer[offset++] === 1;
const isServer = buffer[offset++] === 1;
const isSSR = buffer[offset++] === 1;
const isRoute = buffer[offset++] === 1;
const isFramework = buffer[offset++] === 1;
const isBoundary = buffer[offset++] === 1;
files.push({
id: i,
name,
isStale,
isServer,
isSSR,
isRoute,
isFramework,
isBoundary,
});
}
const nameBytes = buffer.slice(offset, offset + nameLength);
const name = new TextDecoder().decode(nameBytes);
offset += nameLength;
const isStale = buffer[offset++] === 1;
const isServer = buffer[offset++] === 1;
const isSSR = buffer[offset++] === 1;
const isRoute = buffer[offset++] === 1;
const isFramework = buffer[offset++] === 1;
const isBoundary = buffer[offset++] === 1;
files.push({
id: i,
name,
isStale,
isServer,
isSSR,
isRoute,
isFramework,
isBoundary
});
return { files, offset };
}
return { files, offset };
}
// Parse the edges from the buffer
function parseEdges(buffer, count, offset) {
const edges = [];
for (let i = 0; i < count; i++) {
const from = readUint32(buffer, offset);
offset += 4;
const to = readUint32(buffer, offset);
offset += 4;
edges.push({ from, to });
// Parse the edges from the buffer
function parseEdges(buffer, count, offset) {
const edges = [];
for (let i = 0; i < count; i++) {
const from = readUint32(buffer, offset);
offset += 4;
const to = readUint32(buffer, offset);
offset += 4;
edges.push({ from, to });
}
return { edges, offset };
}
return { edges, offset };
}
// Initialize Vis.js network
const nodes = new vis.DataSet();
const edges = new vis.DataSet();
// Initialize Vis.js network
const nodes = new vis.DataSet();
const edges = new vis.DataSet();
const container = document.getElementById("network");
const data = { nodes, edges };
const options = {};
const network = new vis.Network(container, data, options);
const container = document.getElementById("network");
const data = { nodes, edges };
const options = {};
const network = new vis.Network(container, data, options);
// Helper function to add or update nodes in the graph
function updateNode(id, file, group) {
const label = basename(file.name);
const color = file.name.includes('/node_modules/')
? c.gray
: file.isStale
? c.red
: file.isBoundary
? c.orange
: group === 'client'
? c.mauve
: file.isRoute
? c.blue
: file.isSSR ? file.isServer ? c.yellow : c.green : c.sky;
const props = {
id,
label,
shape: 'dot',
color: color,
borderWidth: file.isRoute ? 3 : 1,
group,
font: file.name.includes('/node_modules/')
? '10px sans-serif #cdd6f488' : '20px sans-serif #cdd6f4',
}
if (nodes.get(id)) {
nodes.update(props);
} else {
nodes.add(props);
}
}
// Helper function to remove a node by ID
function removeNode(id) {
nodes.remove({ id });
}
// Helper function to add or update edges in the graph
const edgeProps = { arrows: 'to' };
function updateEdge(id, from, to, variant) {
const prop = variant === 'normal'
? { id, from, to, arrows: 'to' }
: variant === 'client'
? { id, from, to, arrows: 'to,from', color: '#ffffff99', width: 2, label: '[use client]' }
: { id, from, to };
if (edges.get(id)) {
edges.update(prop);
} else {
edges.add(prop);
}
}
// Helper to remove all edges of a node
function removeEdges(nodeId) {
const edgesToRemove = edges.get({
filter: (edge) => edge.from === nodeId || edge.to === nodeId,
});
edges.remove(edgesToRemove.map(e => e.id));
}
// Function to update the entire graph when new data is received
function updateGraph() {
const newEdgeIds = new Set(); // Track new edges
const boundaries = new Map();
// Update server files
serverFiles.forEach((file, index) => {
const id = `S_${index}`;
if (file.deleted) {
removeNode(id);
removeEdges(id);
// Helper function to add or update nodes in the graph
function updateNode(id, file, group) {
const label = basename(file.name);
const color = file.name.includes("/node_modules/")
? c.gray
: file.isStale
? c.red
: file.isBoundary
? c.orange
: group === "client"
? c.mauve
: file.isRoute
? c.blue
: file.isSSR
? file.isServer
? c.yellow
: c.green
: c.sky;
const props = {
id,
label,
shape: "dot",
color: color,
borderWidth: file.isRoute ? 3 : 1,
group,
font: file.name.includes("/node_modules/") ? "10px sans-serif #cdd6f488" : "20px sans-serif #cdd6f4",
};
if (nodes.get(id)) {
nodes.update(props);
} else {
updateNode(id, file, 'server');
nodes.add(props);
}
if (file.isBoundary) {
boundaries.set(file.name, { server: index, client: -1 });
}
});
// Update client files
clientFiles.forEach((file, index) => {
const id = `C_${index}`;
if (file.deleted) {
removeNode(id);
removeEdges(id);
return;
}
updateNode(id, file, 'client');
const b = boundaries.get(file.name);
if (b) {
b.client = index;
}
});
// Update client edges
clientEdges.forEach((edge, index) => {
const id = `C_edge_${index}`;
updateEdge(id, `C_${edge.from}`, `C_${edge.to}`, 'normal');
newEdgeIds.add(id); // Track this edge
});
// Update server edges
serverEdges.forEach((edge, index) => {
const id = `S_edge_${index}`;
updateEdge(id, `S_${edge.from}`, `S_${edge.to}`, 'normal');
newEdgeIds.add(id); // Track this edge
});
boundaries.forEach(({ server, client }) => {
if (client === -1) return;
const id = `S_edge_bound_${server}_${client}`;
updateEdge(id, `S_${server}`, `C_${client}`, 'client');
newEdgeIds.add(id); // Track this edge
});
// Remove edges that are no longer present
currentEdgeIds.forEach((id) => {
if (!newEdgeIds.has(id)) {
edges.remove(id);
}
});
// Update the currentEdgeIds set to the new one
currentEdgeIds = newEdgeIds;
if (isFirst) {
network.stabilize();
isFirst = false;
}
document.getElementById('stat').innerText = `(server: ${serverFiles.length} files, ${serverEdges.length} edges; client: ${clientFiles.length} files, ${clientEdges.length} edges; ${boundaries.size} boundaries)`;
}
</script>
</body>
// Helper function to remove a node by ID
function removeNode(id) {
nodes.remove({ id });
}
</html>
// Helper function to add or update edges in the graph
const edgeProps = { arrows: "to" };
function updateEdge(id, from, to, variant) {
const prop =
variant === "normal"
? { id, from, to, arrows: "to" }
: variant === "client"
? { id, from, to, arrows: "to,from", color: "#ffffff99", width: 2, label: "[use client]" }
: { id, from, to };
if (edges.get(id)) {
edges.update(prop);
} else {
edges.add(prop);
}
}
// Helper to remove all edges of a node
function removeEdges(nodeId) {
const edgesToRemove = edges.get({
filter: edge => edge.from === nodeId || edge.to === nodeId,
});
edges.remove(edgesToRemove.map(e => e.id));
}
// Function to update the entire graph when new data is received
function updateGraph() {
const newEdgeIds = new Set(); // Track new edges
const newNodeIds = new Set(); // Track new nodes
const boundaries = new Map();
// Update server files
serverFiles.forEach((file, index) => {
const id = `S_${file.name}`;
if (file.deleted) {
removeNode(id);
removeEdges(id);
} else {
updateNode(id, file, "server");
}
if (file.isBoundary) {
boundaries.set(file.name, { server: index, client: -1 });
}
newNodeIds.add(id); // Track this node
});
// Update client files
clientFiles.forEach((file, index) => {
const id = `C_${file.name}`;
if (file.deleted) {
removeNode(id);
removeEdges(id);
return;
}
updateNode(id, file, "client");
const b = boundaries.get(file.name);
if (b) {
b.client = index;
}
newNodeIds.add(id); // Track this node
});
// Update client edges
clientEdges.forEach((edge, index) => {
const id = `C_edge_${index}`;
updateEdge(id, `C_${clientFiles[edge.from].name}`, `C_${clientFiles[edge.to].name}`, "normal");
newEdgeIds.add(id); // Track this edge
});
// Update server edges
serverEdges.forEach((edge, index) => {
const id = `S_edge_${index}`;
updateEdge(id, `S_${serverFiles[edge.from].name}`, `S_${serverFiles[edge.to].name}`, "normal");
newEdgeIds.add(id); // Track this edge
});
boundaries.forEach(({ server, client }) => {
if (client === -1) return;
const id = `S_edge_bound_${server}_${client}`;
updateEdge(id, `S_${serverFiles[server].name}`, `C_${clientFiles[client].name}`, "client");
newEdgeIds.add(id); // Track this edge
});
// Remove edges that are no longer present
currentEdgeIds.forEach(id => {
if (!newEdgeIds.has(id)) {
edges.remove(id);
}
});
// Remove nodes that are no longer present
currentNodeIds.forEach(id => {
if (!newNodeIds.has(id)) {
nodes.remove(id);
}
});
// Update the currentEdgeIds set to the new one
currentEdgeIds = newEdgeIds;
currentNodeIds = newNodeIds;
if (isFirst) {
network.stabilize();
isFirst = false;
}
document.getElementById("stat").innerText =
`(server: ${serverFiles.length} files, ${serverEdges.length} edges; client: ${clientFiles.length} files, ${clientEdges.length} edges; ${boundaries.size} boundaries)`;
}
</script>
</body>
</html>

View File

@@ -1,16 +1,16 @@
import { readFileSync } from "node:fs";
import { resolve } from "node:path";
export function css(file: string, is_development: boolean): string {
const contents = readFileSync(resolve(import.meta.dir, file), "utf-8");
if (!is_development) {
// TODO: minify
return contents;
}
return contents;
}
// @ts-ignore
export async function css(file: string, is_development: boolean): string {
// TODO: CI does not have `experimentalCss`
// const { success, stdout, stderr } = await Bun.spawnSync({
// cmd: [process.execPath, "build", file, "--experimental-css", ...(is_development ? [] : ["--minify"])],
// cwd: import.meta.dir,
// stdio: ["ignore", "pipe", "pipe"],
// });
// if (!success) throw new Error(stderr.toString("utf-8"));
// return stdout.toString("utf-8");
export function int(char: string): number {
if (char.length !== 1) throw new Error("Must be one char long");
return char.charCodeAt(0);
return readFileSync(resolve(import.meta.dir, file)).toString('utf-8');
}

1
src/bake/shared.ts Normal file
View File

@@ -0,0 +1 @@
export const td = /* #__PURE__ */ new TextDecoder();

View File

@@ -1 +0,0 @@
export const td = new TextDecoder();

View File

@@ -12,7 +12,7 @@
"downlevelIteration": true,
"esModuleInterop": true,
"skipLibCheck": true,
"jsx": "react-jsx",
"jsx": "react",
"paths": {
"bun-framework-rsc/*": ["./bun-framework-rsc/*"]
}

View File

@@ -39,6 +39,14 @@ pub fn Bitflags(comptime T: type) type {
this.* = bitwiseOr(this.*, other);
}
pub inline fn remove(this: *T, other: T) void {
this.* = bitwiseAnd(this.*, ~other);
}
pub inline fn maskOut(this: T, other: T) T {
return @bitCast(asBits(this) & ~asBits(other));
}
pub fn contains(lhs: T, rhs: T) bool {
return @as(IntType, @bitCast(lhs)) & @as(IntType, @bitCast(rhs)) != 0;
}
@@ -55,8 +63,16 @@ pub fn Bitflags(comptime T: type) type {
return asBits(lhs) == asBits(rhs);
}
pub fn eql(lhs: T, rhs: T) bool {
return eq(lhs, rhs);
}
pub fn neq(lhs: T, rhs: T) bool {
return asBits(lhs) != asBits(rhs);
}
pub fn hash(this: *const T, hasher: *std.hash.Wyhash) void {
hasher.update(std.mem.asBytes(this));
}
};
}

File diff suppressed because it is too large Load Diff

View File

@@ -5,6 +5,8 @@ const lshpack_header = extern struct {
name_len: usize = 0,
value: [*]const u8 = undefined,
value_len: usize = 0,
never_index: bool = false,
hpack_index: u16 = 255,
};
/// wrapper implemented at src/bun.js/bindings/c-bindings.cpp
@@ -16,6 +18,8 @@ pub const HPACK = extern struct {
pub const DecodeResult = struct {
name: []const u8,
value: []const u8,
never_index: bool,
well_know: u16,
// offset of the next header position in src
next: usize,
};
@@ -37,6 +41,8 @@ pub const HPACK = extern struct {
.name = header.name[0..header.name_len],
.value = header.value[0..header.value_len],
.next = offset,
.never_index = header.never_index,
.well_know = header.hpack_index,
};
}

View File

@@ -19,6 +19,7 @@ const BoringSSL = bun.BoringSSL;
const X509 = @import("./x509.zig");
const Async = bun.Async;
const uv = bun.windows.libuv;
const H2FrameParser = @import("./h2_frame_parser.zig").H2FrameParser;
noinline fn getSSLException(globalThis: *JSC.JSGlobalObject, defaultMessage: []const u8) JSValue {
var zig_str: ZigString = ZigString.init("");
var output_buf: [4096]u8 = undefined;
@@ -1309,7 +1310,6 @@ fn selectALPNCallback(
return BoringSSL.SSL_TLSEXT_ERR_NOACK;
}
}
fn NewSocket(comptime ssl: bool) type {
return struct {
pub const Socket = uws.NewSocketHandler(ssl);
@@ -1328,13 +1328,42 @@ fn NewSocket(comptime ssl: bool) type {
connection: ?Listener.UnixOrHost = null,
protos: ?[]const u8,
server_name: ?[]const u8 = null,
bytesWritten: u64 = 0,
// TODO: switch to something that uses `visitAggregate` and have the
// `Listener` keep a list of all the sockets JSValue in there
// This is wasteful because it means we are keeping a JSC::Weak for every single open socket
has_pending_activity: std.atomic.Value(bool) = std.atomic.Value(bool).init(true),
native_callback: NativeCallbacks = .none,
pub usingnamespace bun.NewRefCounted(@This(), @This().deinit);
pub const DEBUG_REFCOUNT_NAME = "Socket";
// We use this direct callbacks on HTTP2 when available
pub const NativeCallbacks = union(enum) {
h2: *H2FrameParser,
none,
pub fn onData(this: NativeCallbacks, data: []const u8) bool {
switch (this) {
.h2 => |h2| {
h2.onNativeRead(data);
return true;
},
.none => return false,
}
}
pub fn onWritable(this: NativeCallbacks) bool {
switch (this) {
.h2 => |h2| {
h2.onNativeWritable();
return true;
},
.none => return false,
}
}
};
const This = @This();
const log = Output.scoped(.Socket, false);
const WriteResult = union(enum) {
@@ -1362,6 +1391,29 @@ fn NewSocket(comptime ssl: bool) type {
return this.has_pending_activity.load(.acquire);
}
pub fn attachNativeCallback(this: *This, callback: NativeCallbacks) bool {
if (this.native_callback != .none) return false;
this.native_callback = callback;
switch (callback) {
.h2 => |h2| h2.ref(),
.none => {},
}
return true;
}
pub fn detachNativeCallback(this: *This) void {
const native_callback = this.native_callback;
this.native_callback = .none;
switch (native_callback) {
.h2 => |h2| {
h2.onNativeClose();
h2.deref();
},
.none => {},
}
}
pub fn doConnect(this: *This, connection: Listener.UnixOrHost) !void {
bun.assert(this.socket_context != null);
this.ref();
@@ -1418,6 +1470,7 @@ fn NewSocket(comptime ssl: bool) type {
JSC.markBinding(@src());
log("onWritable", .{});
if (this.socket.isDetached()) return;
if (this.native_callback.onWritable()) return;
const handlers = this.handlers;
const callback = handlers.onWritable;
if (callback == .zero) return;
@@ -1549,6 +1602,8 @@ fn NewSocket(comptime ssl: bool) type {
pub fn closeAndDetach(this: *This, code: uws.CloseCode) void {
const socket = this.socket;
this.socket.detach();
this.detachNativeCallback();
socket.close(code);
}
@@ -1780,6 +1835,7 @@ fn NewSocket(comptime ssl: bool) type {
pub fn onClose(this: *This, _: Socket, err: c_int, _: ?*anyopaque) void {
JSC.markBinding(@src());
log("onClose", .{});
this.detachNativeCallback();
this.socket.detach();
defer this.deref();
defer this.markInactive();
@@ -1821,6 +1877,8 @@ fn NewSocket(comptime ssl: bool) type {
log("onData({d})", .{data.len});
if (this.socket.isDetached()) return;
if (this.native_callback.onData(data)) return;
const handlers = this.handlers;
const callback = handlers.onData;
if (callback == .zero or this.flags.finalizing) return;
@@ -2015,7 +2073,7 @@ fn NewSocket(comptime ssl: bool) type {
return ZigString.init(text).toJS(globalThis);
}
fn writeMaybeCorked(this: *This, buffer: []const u8, is_end: bool) i32 {
pub fn writeMaybeCorked(this: *This, buffer: []const u8, is_end: bool) i32 {
if (this.socket.isShutdown() or this.socket.isClosed()) {
return -1;
}
@@ -2025,12 +2083,18 @@ fn NewSocket(comptime ssl: bool) type {
// TLS wrapped but in TCP mode
if (this.wrapped == .tcp) {
const res = this.socket.rawWrite(buffer, is_end);
if (res > 0) {
this.bytesWritten += @intCast(res);
}
log("write({d}, {any}) = {d}", .{ buffer.len, is_end, res });
return res;
}
}
const res = this.socket.write(buffer, is_end);
if (res > 0) {
this.bytesWritten += @intCast(res);
}
log("write({d}, {any}) = {d}", .{ buffer.len, is_end, res });
return res;
}
@@ -2261,6 +2325,7 @@ fn NewSocket(comptime ssl: bool) type {
pub fn deinit(this: *This) void {
this.markInactive();
this.detachNativeCallback();
this.poll_ref.unref(JSC.VirtualMachine.get());
// need to deinit event without being attached
@@ -2499,7 +2564,12 @@ fn NewSocket(comptime ssl: bool) type {
bun.assert(result_size == size);
return buffer;
}
pub fn getBytesWritten(
this: *This,
_: *JSC.JSGlobalObject,
) JSValue {
return JSC.JSValue.jsNumber(this.bytesWritten);
}
pub fn getALPNProtocol(
this: *This,
globalObject: *JSC.JSGlobalObject,
@@ -3322,6 +3392,7 @@ fn NewSocket(comptime ssl: bool) type {
defer this.deref();
// detach and invalidate the old instance
this.detachNativeCallback();
this.socket.detach();
// start TLS handshake after we set extension on the socket

View File

@@ -9,6 +9,10 @@ export default [
fn: "request",
length: 2,
},
setNativeSocket: {
fn: "setNativeSocketFromJS",
length: 1,
},
ping: {
fn: "ping",
length: 0,
@@ -29,6 +33,14 @@ export default [
fn: "read",
length: 1,
},
flush: {
fn: "flushFromJS",
length: 0,
},
detach: {
fn: "detachFromJS",
length: 0,
},
rstStream: {
fn: "rstStream",
length: 1,
@@ -41,12 +53,20 @@ export default [
fn: "sendTrailers",
length: 2,
},
noTrailers: {
fn: "noTrailers",
length: 1,
},
setStreamPriority: {
fn: "setStreamPriority",
length: 2,
},
setEndAfterHeaders: {
fn: "setEndAfterHeaders",
getStreamContext: {
fn: "getStreamContext",
length: 1,
},
setStreamContext: {
fn: "setStreamContext",
length: 2,
},
getEndAfterHeaders: {
@@ -61,6 +81,30 @@ export default [
fn: "getStreamState",
length: 1,
},
bufferSize: {
fn: "getBufferSize",
length: 0,
},
hasNativeRead: {
fn: "hasNativeRead",
length: 1,
},
getAllStreams: {
fn: "getAllStreams",
length: 0,
},
emitErrorToAllStreams: {
fn: "emitErrorToAllStreams",
length: 1,
},
emitAbortToAllStreams: {
fn: "emitAbortToAllStreams",
length: 0,
},
getNextStream: {
fn: "getNextStream",
length: 0,
},
},
finalize: true,
construct: true,

View File

@@ -83,6 +83,9 @@ function generate(ssl) {
alpnProtocol: {
getter: "getALPNProtocol",
},
bytesWritten: {
getter: "getBytesWritten",
},
write: {
fn: "write",
length: 3,

View File

@@ -17,4 +17,4 @@ enum class BufferEncodingType {
};
}
}

View File

@@ -199,4 +199,4 @@ namespace WebCore {
using JSVMClientData = WebCore::JSVMClientData;
using JSHeapData = WebCore::JSHeapData;
}
}

View File

@@ -0,0 +1,37 @@
#include "root.h"
#include "BunHttp2CommonStrings.h"
#include <JavaScriptCore/JSString.h>
#include <JavaScriptCore/JSGlobalObject.h>
#include <JavaScriptCore/LazyProperty.h>
#include <JavaScriptCore/LazyPropertyInlines.h>
#include "ZigGlobalObject.h"
#include <JavaScriptCore/SlotVisitorInlines.h>
#include <JavaScriptCore/VMTrapsInlines.h>
namespace Bun {
using namespace JSC;
#define HTTP2_COMMON_STRINGS_LAZY_PROPERTY_DEFINITION(jsName, key, value, idx) \
this->m_names[idx].initLater( \
[](const JSC::LazyProperty<JSGlobalObject, JSString>::Initializer& init) { \
init.set(jsOwnedString(init.vm, key)); \
});
#define HTTP2_COMMON_STRINGS_LAZY_PROPERTY_VISITOR(name, key, value, idx) \
this->m_names[idx].visit(visitor);
void Http2CommonStrings::initialize()
{
HTTP2_COMMON_STRINGS_EACH_NAME(HTTP2_COMMON_STRINGS_LAZY_PROPERTY_DEFINITION)
}
template<typename Visitor>
void Http2CommonStrings::visit(Visitor& visitor)
{
HTTP2_COMMON_STRINGS_EACH_NAME(HTTP2_COMMON_STRINGS_LAZY_PROPERTY_VISITOR)
}
template void Http2CommonStrings::visit(JSC::AbstractSlotVisitor&);
template void Http2CommonStrings::visit(JSC::SlotVisitor&);
} // namespace Bun

View File

@@ -0,0 +1,107 @@
#pragma once
// clang-format off
#define HTTP2_COMMON_STRINGS_EACH_NAME(macro) \
macro(authority, ":authority"_s, ""_s, 0) \
macro(methodGet, ":method"_s, "GET"_s, 1) \
macro(methodPost, ":method"_s, "POST"_s, 2) \
macro(pathRoot, ":path"_s, "/"_s, 3) \
macro(pathIndex, ":path"_s, "/index.html"_s, 4) \
macro(schemeHttp, ":scheme"_s, "http"_s, 5) \
macro(schemeHttps, ":scheme"_s, "https"_s, 6) \
macro(status200, ":status"_s, "200"_s, 7) \
macro(status204, ":status"_s, "204"_s, 8) \
macro(status206, ":status"_s, "206"_s, 9) \
macro(status304, ":status"_s, "304"_s, 10) \
macro(status400, ":status"_s, "400"_s, 11) \
macro(status404, ":status"_s, "404"_s, 12) \
macro(status500, ":status"_s, "500"_s, 13) \
macro(acceptCharset, "accept-charset"_s, ""_s, 14) \
macro(acceptEncoding, "accept-encoding"_s, "gzip, deflate"_s, 15) \
macro(acceptLanguage, "accept-language"_s, ""_s, 16) \
macro(acceptRanges, "accept-ranges"_s, ""_s, 17) \
macro(accept, "accept"_s, ""_s, 18) \
macro(accessControlAllowOrigin, "access-control-allow-origin"_s, ""_s, 19) \
macro(age, "age"_s, ""_s, 20) \
macro(allow, "allow"_s, ""_s, 21) \
macro(authorization, "authorization"_s, ""_s, 22) \
macro(cacheControl, "cache-control"_s, ""_s, 23) \
macro(contentDisposition, "content-disposition"_s, ""_s, 24) \
macro(contentEncoding, "content-encoding"_s, ""_s, 25) \
macro(contentLanguage, "content-language"_s, ""_s, 26) \
macro(contentLength, "content-length"_s, ""_s, 27) \
macro(contentLocation, "content-location"_s, ""_s, 28) \
macro(contentRange, "content-range"_s, ""_s, 29) \
macro(contentType, "content-type"_s, ""_s, 30) \
macro(cookie, "cookie"_s, ""_s, 31) \
macro(date, "date"_s, ""_s, 32) \
macro(etag, "etag"_s, ""_s, 33) \
macro(expect, "expect"_s, ""_s, 34) \
macro(expires, "expires"_s, ""_s, 35) \
macro(from, "from"_s, ""_s, 36) \
macro(host, "host"_s, ""_s, 37) \
macro(ifMatch, "if-match"_s, ""_s, 38) \
macro(ifModifiedSince, "if-modified-since"_s, ""_s, 39) \
macro(ifNoneMatch, "if-none-match"_s, ""_s, 40) \
macro(ifRange, "if-range"_s, ""_s, 41) \
macro(ifUnmodifiedSince, "if-unmodified-since"_s, ""_s, 42) \
macro(lastModified, "last-modified"_s, ""_s, 43) \
macro(link, "link"_s, ""_s, 44) \
macro(location, "location"_s, ""_s, 45) \
macro(maxForwards, "max-forwards"_s, ""_s, 46) \
macro(proxyAuthenticate, "proxy-authenticate"_s, ""_s, 47) \
macro(proxyAuthorization, "proxy-authorization"_s, ""_s, 48) \
macro(range, "range"_s, ""_s, 49) \
macro(referer, "referer"_s, ""_s, 50) \
macro(refresh, "refresh"_s, ""_s, 51) \
macro(retryAfter, "retry-after"_s, ""_s, 52) \
macro(server, "server"_s, ""_s, 53) \
macro(setCookie, "set-cookie"_s, ""_s, 54) \
macro(strictTransportSecurity, "strict-transport-security"_s, ""_s, 55) \
macro(transferEncoding, "transfer-encoding"_s, ""_s, 56) \
macro(userAgent, "user-agent"_s, ""_s, 57) \
macro(vary, "vary"_s, ""_s, 58) \
macro(via, "via"_s, ""_s, 59) \
macro(wwwAuthenticate, "www-authenticate"_s, ""_s, 60)
// clang-format on
#define HTTP2_COMMON_STRINGS_ACCESSOR_DEFINITION(name, key, value, idx) \
JSC::JSString* name##String(JSC::JSGlobalObject* globalObject) \
{ \
return m_names[idx].getInitializedOnMainThread(globalObject); \
}
namespace Bun {
using namespace JSC;
class Http2CommonStrings {
public:
typedef JSC::JSString* (*commonStringInitializer)(Http2CommonStrings*, JSC::JSGlobalObject* globalObject);
HTTP2_COMMON_STRINGS_EACH_NAME(HTTP2_COMMON_STRINGS_ACCESSOR_DEFINITION)
void initialize();
template<typename Visitor>
void visit(Visitor& visitor);
JSC::JSString* getStringFromHPackIndex(uint16_t index, JSC::JSGlobalObject* globalObject)
{
if (index > 60) {
return nullptr;
}
return m_names[index].getInitializedOnMainThread(globalObject);
}
private:
JSC::LazyProperty<JSC::JSGlobalObject, JSC::JSString> m_names[61];
};
} // namespace Bun
#undef BUN_COMMON_STRINGS_ACCESSOR_DEFINITION
#undef BUN_COMMON_STRINGS_LAZY_PROPERTY_DECLARATION

View File

@@ -12,4 +12,4 @@ public:
bool isHTMLAllCollection(JSC::VM&, JSC::JSValue) override { return false; }
};
}
}

View File

@@ -31,6 +31,7 @@
#include "PathInlines.h"
#include "wtf/text/ASCIILiteral.h"
#include "BunObject+exports.h"
#include "ErrorCode.h"
BUN_DECLARE_HOST_FUNCTION(Bun__DNSResolver__lookup);
BUN_DECLARE_HOST_FUNCTION(Bun__DNSResolver__resolve);
@@ -120,8 +121,7 @@ static inline JSC::EncodedJSValue flattenArrayOfBuffersIntoArrayBufferOrUint8Arr
if (auto* typedArray = JSC::jsDynamicCast<JSC::JSArrayBufferView*>(element)) {
if (UNLIKELY(typedArray->isDetached())) {
throwTypeError(lexicalGlobalObject, throwScope, "ArrayBufferView is detached"_s);
return {};
return Bun::ERR::INVALID_STATE(throwScope, lexicalGlobalObject, "Cannot validate on a detached buffer"_s);
}
size_t current = typedArray->byteLength();
any_typed = true;
@@ -133,8 +133,7 @@ static inline JSC::EncodedJSValue flattenArrayOfBuffersIntoArrayBufferOrUint8Arr
} else if (auto* arrayBuffer = JSC::jsDynamicCast<JSC::JSArrayBuffer*>(element)) {
auto* impl = arrayBuffer->impl();
if (UNLIKELY(!impl)) {
throwTypeError(lexicalGlobalObject, throwScope, "ArrayBuffer is detached"_s);
return {};
return Bun::ERR::INVALID_STATE(throwScope, lexicalGlobalObject, "Cannot validate on a detached buffer"_s);
}
size_t current = impl->byteLength();

View File

@@ -106,4 +106,4 @@ class GlobalObject;
namespace Bun {
JSC::JSValue runVirtualModule(Zig::GlobalObject*, BunString* specifier, bool& wasModuleMock);
JSC::Structure* createModuleMockStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype);
}
}

View File

@@ -53,4 +53,4 @@ public:
private:
MessagePortChannelProviderImpl* m_messagePortChannelProvider;
};
}
}

View File

@@ -6,4 +6,4 @@ namespace WebCore {
class CachedScript {
};
}
}

View File

@@ -13,42 +13,39 @@
#include <JavaScriptCore/CodeBlock.h>
#include <JavaScriptCore/Operations.h>
#include <JavaScriptCore/JSCInlines.h>
#include <JavaScriptCore/ObjectConstructor.h>
#include <JavaScriptCore/JSBoundFunction.h>
using namespace JSC;
namespace Zig {
static JSC_DECLARE_HOST_FUNCTION(callSiteProtoFuncGetThis);
static JSC_DECLARE_HOST_FUNCTION(callSiteProtoFuncGetTypeName);
static JSC_DECLARE_HOST_FUNCTION(callSiteProtoFuncGetFunction);
static JSC_DECLARE_HOST_FUNCTION(callSiteProtoFuncGetFunctionName);
static JSC_DECLARE_HOST_FUNCTION(callSiteProtoFuncGetMethodName);
static JSC_DECLARE_HOST_FUNCTION(callSiteProtoFuncGetFileName);
static JSC_DECLARE_HOST_FUNCTION(callSiteProtoFuncGetLineNumber);
static JSC_DECLARE_HOST_FUNCTION(callSiteProtoFuncGetColumnNumber);
static JSC_DECLARE_HOST_FUNCTION(callSiteProtoFuncGetEvalOrigin);
static JSC_DECLARE_HOST_FUNCTION(callSiteProtoFuncGetScriptNameOrSourceURL);
static JSC_DECLARE_HOST_FUNCTION(callSiteProtoFuncIsToplevel);
static JSC_DECLARE_HOST_FUNCTION(callSiteProtoFuncIsEval);
static JSC_DECLARE_HOST_FUNCTION(callSiteProtoFuncIsNative);
static JSC_DECLARE_HOST_FUNCTION(callSiteProtoFuncIsConstructor);
static JSC_DECLARE_HOST_FUNCTION(callSiteProtoFuncIsAsync);
static JSC_DECLARE_HOST_FUNCTION(callSiteProtoFuncIsPromiseAll);
static JSC_DECLARE_HOST_FUNCTION(callSiteProtoFuncGetPromiseIndex);
static JSC_DECLARE_HOST_FUNCTION(callSiteProtoFuncToString);
JSC_DECLARE_HOST_FUNCTION(callSiteProtoFuncGetThis);
JSC_DECLARE_HOST_FUNCTION(callSiteProtoFuncGetTypeName);
JSC_DECLARE_HOST_FUNCTION(callSiteProtoFuncGetFunction);
JSC_DECLARE_HOST_FUNCTION(callSiteProtoFuncGetFunctionName);
JSC_DECLARE_HOST_FUNCTION(callSiteProtoFuncGetMethodName);
JSC_DECLARE_HOST_FUNCTION(callSiteProtoFuncGetFileName);
JSC_DECLARE_HOST_FUNCTION(callSiteProtoFuncGetLineNumber);
JSC_DECLARE_HOST_FUNCTION(callSiteProtoFuncGetColumnNumber);
JSC_DECLARE_HOST_FUNCTION(callSiteProtoFuncGetEvalOrigin);
JSC_DECLARE_HOST_FUNCTION(callSiteProtoFuncGetScriptNameOrSourceURL);
JSC_DECLARE_HOST_FUNCTION(callSiteProtoFuncIsToplevel);
JSC_DECLARE_HOST_FUNCTION(callSiteProtoFuncIsEval);
JSC_DECLARE_HOST_FUNCTION(callSiteProtoFuncIsNative);
JSC_DECLARE_HOST_FUNCTION(callSiteProtoFuncIsConstructor);
JSC_DECLARE_HOST_FUNCTION(callSiteProtoFuncIsAsync);
JSC_DECLARE_HOST_FUNCTION(callSiteProtoFuncIsPromiseAll);
JSC_DECLARE_HOST_FUNCTION(callSiteProtoFuncGetPromiseIndex);
JSC_DECLARE_HOST_FUNCTION(callSiteProtoFuncToString);
JSC_DECLARE_HOST_FUNCTION(callSiteProtoFuncToJSON);
ALWAYS_INLINE static CallSite* getCallSite(JSGlobalObject* globalObject, JSC::JSValue thisValue)
{
JSC::VM& vm = globalObject->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
if (UNLIKELY(!thisValue.isCell())) {
JSC::throwVMError(globalObject, scope, createNotAnObjectError(globalObject, thisValue));
return nullptr;
}
if (LIKELY(thisValue.asCell()->inherits(CallSite::info()))) {
return JSC::jsCast<CallSite*>(thisValue);
if (auto* callSite = JSC::jsDynamicCast<CallSite*>(thisValue)) {
return callSite;
}
throwTypeError(globalObject, scope, "CallSite operation called on non-CallSite object"_s);
@@ -84,6 +81,7 @@ static const HashTableValue CallSitePrototypeTableValues[]
{ "isPromiseAll"_s, JSC::PropertyAttribute::DontEnum | JSC::PropertyAttribute::Function, NoIntrinsic, { HashTableValue::NativeFunctionType, callSiteProtoFuncIsPromiseAll, 0 } },
{ "getPromiseIndex"_s, JSC::PropertyAttribute::DontEnum | JSC::PropertyAttribute::Function, NoIntrinsic, { HashTableValue::NativeFunctionType, callSiteProtoFuncGetPromiseIndex, 0 } },
{ "toString"_s, JSC::PropertyAttribute::DontEnum | JSC::PropertyAttribute::Function, NoIntrinsic, { HashTableValue::NativeFunctionType, callSiteProtoFuncToString, 0 } },
{ "toJSON"_s, JSC::PropertyAttribute::Function | 0, NoIntrinsic, { HashTableValue::NativeFunctionType, callSiteProtoFuncToJSON, 0 } },
};
const JSC::ClassInfo CallSitePrototype::s_info = { "CallSite"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(CallSitePrototype) };
@@ -165,10 +163,29 @@ JSC_DEFINE_HOST_FUNCTION(callSiteProtoFuncIsToplevel, (JSGlobalObject * globalOb
{
ENTER_PROTO_FUNC();
if (JSValue functionValue = callSite->function()) {
if (JSObject* fn = functionValue.getObject()) {
if (JSFunction* function = jsDynamicCast<JSFunction*>(fn)) {
if (function->inherits<JSC::JSBoundFunction>()) {
return JSC::JSValue::encode(JSC::jsBoolean(false));
}
if (function->isHostFunction()) {
return JSC::JSValue::encode(JSC::jsBoolean(true));
}
if (auto* executable = function->jsExecutable()) {
return JSValue::encode(jsBoolean(executable->isProgramExecutable() || executable->isModuleProgramExecutable()));
}
} else if (auto* function = jsDynamicCast<InternalFunction*>(functionValue)) {
return JSC::JSValue::encode(JSC::jsBoolean(true));
}
}
}
JSC::JSValue thisValue = callSite->thisValue();
// This is what v8 does (JSStackFrame::IsToplevel in messages.cc):
if (thisValue.isUndefinedOrNull()) {
return JSC::JSValue::encode(JSC::jsBoolean(true));
}
@@ -237,4 +254,15 @@ JSC_DEFINE_HOST_FUNCTION(callSiteProtoFuncToString, (JSGlobalObject * globalObje
return JSC::JSValue::encode(JSC::JSValue(jsString(vm, sb.toString())));
}
JSC_DEFINE_HOST_FUNCTION(callSiteProtoFuncToJSON, (JSGlobalObject * globalObject, JSC::CallFrame* callFrame))
{
ENTER_PROTO_FUNC();
JSObject* obj = JSC::constructEmptyObject(globalObject, globalObject->objectPrototype(), 4);
obj->putDirect(vm, JSC::Identifier::fromString(vm, "sourceURL"_s), callSite->sourceURL());
obj->putDirect(vm, JSC::Identifier::fromString(vm, "lineNumber"_s), jsNumber(callSite->lineNumber().oneBasedInt()));
obj->putDirect(vm, JSC::Identifier::fromString(vm, "columnNumber"_s), jsNumber(callSite->columnNumber().zeroBasedInt()));
obj->putDirect(vm, JSC::Identifier::fromString(vm, "functionName"_s), callSite->functionName());
return JSC::JSValue::encode(obj);
}
}

View File

@@ -44,4 +44,4 @@ private:
void finishCreation(JSC::VM& vm, JSC::JSGlobalObject* globalObject);
};
}
}

View File

@@ -13,4 +13,4 @@ public:
}
};
}
}

View File

@@ -60,12 +60,6 @@ static JSC::JSObject* createErrorPrototype(JSC::VM& vm, JSC::JSGlobalObject* glo
return prototype;
}
extern "C" JSC::EncodedJSValue Bun__ERR_INVALID_ARG_TYPE(JSC::JSGlobalObject* globalObject, JSC::EncodedJSValue val_arg_name, JSC::EncodedJSValue val_expected_type, JSC::EncodedJSValue val_actual_value);
extern "C" JSC::EncodedJSValue Bun__ERR_INVALID_ARG_TYPE_static(JSC::JSGlobalObject* globalObject, const ZigString* val_arg_name, const ZigString* val_expected_type, JSC::EncodedJSValue val_actual_value);
extern "C" JSC::EncodedJSValue Bun__ERR_MISSING_ARGS(JSC::JSGlobalObject* globalObject, JSC::EncodedJSValue arg1, JSC::EncodedJSValue arg2, JSC::EncodedJSValue arg3);
extern "C" JSC::EncodedJSValue Bun__ERR_MISSING_ARGS_static(JSC::JSGlobalObject* globalObject, const ZigString* arg1, const ZigString* arg2, const ZigString* arg3);
extern "C" JSC::EncodedJSValue Bun__ERR_IPC_CHANNEL_CLOSED(JSC::JSGlobalObject* globalObject);
// clang-format on
#define EXPECT_ARG_COUNT(count__) \
@@ -227,7 +221,6 @@ namespace Message {
WTF::String ERR_INVALID_ARG_TYPE(JSC::ThrowScope& scope, JSC::JSGlobalObject* globalObject, const StringView& arg_name, const StringView& expected_type, JSValue actual_value)
{
auto actual_value_string = JSValueToStringSafe(globalObject, actual_value);
RETURN_IF_EXCEPTION(scope, {});
@@ -279,7 +272,6 @@ WTF::String ERR_INVALID_ARG_TYPE(JSC::ThrowScope& scope, JSC::JSGlobalObject* gl
WTF::String ERR_INVALID_ARG_TYPE(JSC::ThrowScope& scope, JSC::JSGlobalObject* globalObject, JSValue val_arg_name, JSValue val_expected_type, JSValue val_actual_value)
{
auto arg_name = val_arg_name.toWTFString(globalObject);
RETURN_IF_EXCEPTION(scope, {});
@@ -307,7 +299,7 @@ WTF::String ERR_OUT_OF_RANGE(JSC::ThrowScope& scope, JSC::JSGlobalObject* global
namespace ERR {
JSC::EncodedJSValue INVALID_ARG_TYPE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, ASCIILiteral val_arg_name, ASCIILiteral val_expected_type, JSC::JSValue val_actual_value)
JSC::EncodedJSValue INVALID_ARG_TYPE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, const WTF::String& val_arg_name, const WTF::String& val_expected_type, JSC::JSValue val_actual_value)
{
auto arg_name = val_arg_name.span8();
ASSERT(WTF::charactersAreAllASCII(arg_name));
@@ -327,7 +319,7 @@ JSC::EncodedJSValue INVALID_ARG_TYPE(JSC::ThrowScope& throwScope, JSC::JSGlobalO
throwScope.throwException(globalObject, createError(globalObject, ErrorCode::ERR_INVALID_ARG_TYPE, message));
return {};
}
JSC::EncodedJSValue INVALID_ARG_TYPE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, JSC::JSValue val_arg_name, ASCIILiteral val_expected_type, JSC::JSValue val_actual_value)
JSC::EncodedJSValue INVALID_ARG_TYPE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, JSC::JSValue val_arg_name, const WTF::String& val_expected_type, JSC::JSValue val_actual_value)
{
auto arg_name = val_arg_name.toWTFString(globalObject);
RETURN_IF_EXCEPTION(throwScope, {});
@@ -348,7 +340,7 @@ JSC::EncodedJSValue INVALID_ARG_TYPE(JSC::ThrowScope& throwScope, JSC::JSGlobalO
return {};
}
JSC::EncodedJSValue OUT_OF_RANGE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, ASCIILiteral arg_name, size_t lower, size_t upper, JSC::JSValue actual)
JSC::EncodedJSValue OUT_OF_RANGE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, const WTF::String& arg_name, size_t lower, size_t upper, JSC::JSValue actual)
{
auto lowerStr = jsNumber(lower).toWTFString(globalObject);
auto upperStr = jsNumber(upper).toWTFString(globalObject);
@@ -392,7 +384,7 @@ JSC::EncodedJSValue OUT_OF_RANGE(JSC::ThrowScope& throwScope, JSC::JSGlobalObjec
}
}
}
JSC::EncodedJSValue OUT_OF_RANGE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, JSC::JSValue arg_name_val, ASCIILiteral msg, JSC::JSValue actual)
JSC::EncodedJSValue OUT_OF_RANGE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, JSC::JSValue arg_name_val, const WTF::String& msg, JSC::JSValue actual)
{
auto arg_name = arg_name_val.toWTFString(globalObject);
RETURN_IF_EXCEPTION(throwScope, {});
@@ -403,7 +395,7 @@ JSC::EncodedJSValue OUT_OF_RANGE(JSC::ThrowScope& throwScope, JSC::JSGlobalObjec
throwScope.throwException(globalObject, createError(globalObject, ErrorCode::ERR_OUT_OF_RANGE, message));
return {};
}
JSC::EncodedJSValue OUT_OF_RANGE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, ASCIILiteral arg_name, ASCIILiteral msg, JSC::JSValue actual)
JSC::EncodedJSValue OUT_OF_RANGE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, const WTF::String& arg_name, const WTF::String& msg, JSC::JSValue actual)
{
auto actual_value = JSValueToStringSafe(globalObject, actual);
RETURN_IF_EXCEPTION(throwScope, {});
@@ -413,7 +405,7 @@ JSC::EncodedJSValue OUT_OF_RANGE(JSC::ThrowScope& throwScope, JSC::JSGlobalObjec
return {};
}
JSC::EncodedJSValue INVALID_ARG_VALUE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, ASCIILiteral name, JSC::JSValue value, WTF::String reason)
JSC::EncodedJSValue INVALID_ARG_VALUE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, const WTF::String& name, JSC::JSValue value, const WTF::String& reason)
{
ASCIILiteral type;
{
@@ -430,7 +422,7 @@ JSC::EncodedJSValue INVALID_ARG_VALUE(JSC::ThrowScope& throwScope, JSC::JSGlobal
throwScope.throwException(globalObject, createError(globalObject, ErrorCode::ERR_INVALID_ARG_VALUE, message));
return {};
}
JSC::EncodedJSValue INVALID_ARG_VALUE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, JSC::JSValue name, JSC::JSValue value, WTF::String reason)
JSC::EncodedJSValue INVALID_ARG_VALUE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, JSC::JSValue name, JSC::JSValue value, const WTF::String& reason)
{
auto name_string = JSValueToStringSafe(globalObject, name);
RETURN_IF_EXCEPTION(throwScope, {});
@@ -443,17 +435,14 @@ JSC::EncodedJSValue INVALID_ARG_VALUE(JSC::ThrowScope& throwScope, JSC::JSGlobal
return {};
}
JSC::EncodedJSValue UNKNOWN_ENCODING(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, JSC::JSValue encoding)
JSC::EncodedJSValue UNKNOWN_ENCODING(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, const WTF::String& encoding)
{
auto encoding_string = JSValueToStringSafe(globalObject, encoding);
RETURN_IF_EXCEPTION(throwScope, {});
auto message = makeString("Unknown encoding: "_s, encoding_string);
auto message = makeString("Unknown encoding: "_s, encoding);
throwScope.throwException(globalObject, createError(globalObject, ErrorCode::ERR_UNKNOWN_ENCODING, message));
return {};
}
JSC::EncodedJSValue INVALID_STATE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, ASCIILiteral statemsg)
JSC::EncodedJSValue INVALID_STATE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, const WTF::String& statemsg)
{
auto message = makeString("Invalid state: "_s, statemsg);
throwScope.throwException(globalObject, createError(globalObject, ErrorCode::ERR_INVALID_STATE, message));
@@ -462,7 +451,7 @@ JSC::EncodedJSValue INVALID_STATE(JSC::ThrowScope& throwScope, JSC::JSGlobalObje
JSC::EncodedJSValue STRING_TOO_LONG(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject)
{
auto message = makeString("Cannot create a string longer than "_s, WTF::String::MaxLength, " characters"_s);
auto message = makeString("Cannot create a string longer than "_s, WTF::String ::MaxLength, " characters"_s);
throwScope.throwException(globalObject, createError(globalObject, ErrorCode::ERR_STRING_TOO_LONG, message));
return {};
}
@@ -520,25 +509,6 @@ static JSC::JSValue ERR_INVALID_ARG_TYPE(JSC::ThrowScope& scope, JSC::JSGlobalOb
return createError(globalObject, ErrorCode::ERR_INVALID_ARG_TYPE, msg);
}
extern "C" JSC::EncodedJSValue Bun__ERR_INVALID_ARG_TYPE(JSC::JSGlobalObject* globalObject, JSC::EncodedJSValue val_arg_name, JSC::EncodedJSValue val_expected_type, JSC::EncodedJSValue val_actual_value)
{
JSC::VM& vm = globalObject->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
auto message = Message::ERR_INVALID_ARG_TYPE(scope, globalObject, JSValue::decode(val_arg_name), JSValue::decode(val_expected_type), JSValue::decode(val_actual_value));
RETURN_IF_EXCEPTION(scope, {});
return JSC::JSValue::encode(createError(globalObject, ErrorCode::ERR_INVALID_ARG_TYPE, message));
}
extern "C" JSC::EncodedJSValue Bun__ERR_INVALID_ARG_TYPE_static(JSC::JSGlobalObject* globalObject, const ZigString* val_arg_name, const ZigString* val_expected_type, JSC::EncodedJSValue val_actual_value)
{
JSC::VM& vm = globalObject->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
WTF::String message = Message::ERR_INVALID_ARG_TYPE(scope, globalObject, val_arg_name, val_expected_type, JSValue::decode(val_actual_value));
RETURN_IF_EXCEPTION(scope, {});
return JSC::JSValue::encode(createError(globalObject, ErrorCode::ERR_INVALID_ARG_TYPE, message));
}
JSC_DEFINE_HOST_FUNCTION(jsFunction_ERR_OUT_OF_RANGE, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame))
{
JSC::VM& vm = globalObject->vm();
@@ -566,82 +536,7 @@ extern "C" JSC::EncodedJSValue Bun__createErrorWithCode(JSC::JSGlobalObject* glo
return JSValue::encode(createError(globalObject, code, message->toWTFString(BunString::ZeroCopy)));
}
extern "C" JSC::EncodedJSValue Bun__ERR_MISSING_ARGS(JSC::JSGlobalObject* globalObject, JSC::EncodedJSValue arg1, JSC::EncodedJSValue arg2, JSC::EncodedJSValue arg3)
{
JSC::VM& vm = globalObject->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
if (arg1 == 0) {
JSC::throwTypeError(globalObject, scope, "requires at least 1 argument"_s);
return {};
}
auto name1 = JSValue::decode(arg1).toWTFString(globalObject);
RETURN_IF_EXCEPTION(scope, {});
if (arg2 == 0) {
// 1 arg name passed
auto message = makeString("The \""_s, name1, "\" argument must be specified"_s);
return JSC::JSValue::encode(createError(globalObject, ErrorCode::ERR_MISSING_ARGS, message));
}
auto name2 = JSValue::decode(arg2).toWTFString(globalObject);
RETURN_IF_EXCEPTION(scope, {});
if (arg3 == 0) {
// 2 arg names passed
auto message = makeString("The \""_s, name1, "\" and \""_s, name2, "\" arguments must be specified"_s);
return JSC::JSValue::encode(createError(globalObject, ErrorCode::ERR_MISSING_ARGS, message));
}
auto name3 = JSValue::decode(arg3).toWTFString(globalObject);
RETURN_IF_EXCEPTION(scope, {});
// 3 arg names passed
auto message = makeString("The \""_s, name1, "\", \""_s, name2, "\", and \""_s, name3, "\" arguments must be specified"_s);
return JSC::JSValue::encode(createError(globalObject, ErrorCode::ERR_MISSING_ARGS, message));
}
extern "C" JSC::EncodedJSValue Bun__ERR_MISSING_ARGS_static(JSC::JSGlobalObject* globalObject, const ZigString* arg1, const ZigString* arg2, const ZigString* arg3)
{
JSC::VM& vm = globalObject->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
if (arg1 == nullptr) {
JSC::throwTypeError(globalObject, scope, "requires at least 1 argument"_s);
return {};
}
auto name1 = std::span<const unsigned char>(arg1->ptr, arg1->len);
ASSERT(WTF::charactersAreAllASCII(name1));
if (arg2 == nullptr) {
// 1 arg name passed
auto message = makeString("The \""_s, name1, "\" argument must be specified"_s);
return JSC::JSValue::encode(createError(globalObject, ErrorCode::ERR_MISSING_ARGS, message));
}
auto name2 = std::span<const unsigned char>(arg2->ptr, arg2->len);
ASSERT(WTF::charactersAreAllASCII(name2));
if (arg3 == nullptr) {
// 2 arg names passed
auto message = makeString("The \""_s, name1, "\" and \""_s, name2, "\" arguments must be specified"_s);
return JSC::JSValue::encode(createError(globalObject, ErrorCode::ERR_MISSING_ARGS, message));
}
auto name3 = std::span<const unsigned char>(arg3->ptr, arg3->len);
ASSERT(WTF::charactersAreAllASCII(name3));
// 3 arg names passed
auto message = makeString("The \""_s, name1, "\", \""_s, name2, "\", and \""_s, name3, "\" arguments must be specified"_s);
return JSC::JSValue::encode(createError(globalObject, ErrorCode::ERR_MISSING_ARGS, message));
}
JSC_DEFINE_HOST_FUNCTION(jsFunction_ERR_IPC_CHANNEL_CLOSED, (JSC::JSGlobalObject * globalObject, JSC::CallFrame*))
{
return Bun__ERR_IPC_CHANNEL_CLOSED(globalObject);
}
extern "C" JSC::EncodedJSValue Bun__ERR_IPC_CHANNEL_CLOSED(JSC::JSGlobalObject* globalObject)
{
return JSC::JSValue::encode(createError(globalObject, ErrorCode::ERR_IPC_CHANNEL_CLOSED, "Channel closed."_s));
}

View File

@@ -75,17 +75,17 @@ enum Bound {
namespace ERR {
JSC::EncodedJSValue INVALID_ARG_TYPE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, ASCIILiteral val_arg_name, ASCIILiteral val_expected_type, JSC::JSValue val_actual_value);
JSC::EncodedJSValue INVALID_ARG_TYPE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, JSC::JSValue val_arg_name, ASCIILiteral val_expected_type, JSC::JSValue val_actual_value);
JSC::EncodedJSValue OUT_OF_RANGE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, ASCIILiteral arg_name, size_t lower, size_t upper, JSC::JSValue actual);
JSC::EncodedJSValue INVALID_ARG_TYPE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, const WTF::String& val_arg_name, const WTF::String& val_expected_type, JSC::JSValue val_actual_value);
JSC::EncodedJSValue INVALID_ARG_TYPE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, JSC::JSValue val_arg_name, const WTF::String& val_expected_type, JSC::JSValue val_actual_value);
JSC::EncodedJSValue OUT_OF_RANGE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, const WTF::String& arg_name, size_t lower, size_t upper, JSC::JSValue actual);
JSC::EncodedJSValue OUT_OF_RANGE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, JSC::JSValue arg_name, size_t lower, size_t upper, JSC::JSValue actual);
JSC::EncodedJSValue OUT_OF_RANGE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, JSC::JSValue arg_name_val, size_t bound_num, Bound bound, JSC::JSValue actual);
JSC::EncodedJSValue OUT_OF_RANGE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, JSC::JSValue arg_name_val, ASCIILiteral msg, JSC::JSValue actual);
JSC::EncodedJSValue OUT_OF_RANGE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, ASCIILiteral arg_name_val, ASCIILiteral msg, JSC::JSValue actual);
JSC::EncodedJSValue INVALID_ARG_VALUE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, ASCIILiteral name, JSC::JSValue value, WTF::String reason = "is invalid"_s);
JSC::EncodedJSValue INVALID_ARG_VALUE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, JSC::JSValue name, JSC::JSValue value, WTF::String reason = "is invalid"_s);
JSC::EncodedJSValue UNKNOWN_ENCODING(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, JSC::JSValue encoding);
JSC::EncodedJSValue INVALID_STATE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, ASCIILiteral statemsg);
JSC::EncodedJSValue OUT_OF_RANGE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, JSC::JSValue arg_name_val, const WTF::String& msg, JSC::JSValue actual);
JSC::EncodedJSValue OUT_OF_RANGE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, const WTF::String& arg_name_val, const WTF::String& msg, JSC::JSValue actual);
JSC::EncodedJSValue INVALID_ARG_VALUE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, const WTF::String& name, JSC::JSValue value, const WTF::String& reason = "is invalid"_s);
JSC::EncodedJSValue INVALID_ARG_VALUE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, JSC::JSValue name, JSC::JSValue value, const WTF::String& reason = "is invalid"_s);
JSC::EncodedJSValue UNKNOWN_ENCODING(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, const WTF::String& encoding);
JSC::EncodedJSValue INVALID_STATE(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, const WTF::String& statemsg);
JSC::EncodedJSValue STRING_TOO_LONG(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject);
JSC::EncodedJSValue BUFFER_OUT_OF_BOUNDS(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject);
JSC::EncodedJSValue UNKNOWN_SIGNAL(JSC::ThrowScope& throwScope, JSC::JSGlobalObject* globalObject, JSC::JSValue signal, bool triedUppercase = false);

View File

@@ -13,9 +13,6 @@ export default [
["ABORT_ERR", Error, "AbortError"],
["ERR_CRYPTO_INVALID_DIGEST", TypeError, "TypeError"],
["ERR_ENCODING_INVALID_ENCODED_DATA", TypeError, "TypeError"],
["ERR_HTTP2_INVALID_HEADER_VALUE", TypeError, "TypeError"],
["ERR_HTTP2_INVALID_PSEUDOHEADER", TypeError, "TypeError"],
["ERR_HTTP2_INVALID_SINGLE_VALUE_HEADER", TypeError, "TypeError"],
["ERR_INVALID_ARG_TYPE", TypeError, "TypeError"],
["ERR_INVALID_ARG_VALUE", TypeError, "TypeError"],
["ERR_INVALID_PROTOCOL", TypeError, "TypeError"],
@@ -54,4 +51,30 @@ export default [
["ERR_BODY_ALREADY_USED", Error, "Error"],
["ERR_STREAM_WRAP", Error, "Error"],
["ERR_BORINGSSL", Error, "Error"],
//HTTP2
["ERR_INVALID_HTTP_TOKEN", TypeError, "TypeError"],
["ERR_HTTP2_PSEUDOHEADER_NOT_ALLOWED", TypeError, "TypeError"],
["ERR_HTTP2_SEND_FILE", Error, "Error"],
["ERR_HTTP2_SEND_FILE_NOSEEK", Error, "Error"],
["ERR_HTTP2_HEADERS_SENT", Error, "ERR_HTTP2_HEADERS_SENT"],
["ERR_HTTP2_INFO_STATUS_NOT_ALLOWED", RangeError, "RangeError"],
["ERR_HTTP2_STATUS_INVALID", RangeError, "RangeError"],
["ERR_HTTP2_INVALID_PSEUDOHEADER", TypeError, "TypeError"],
["ERR_HTTP2_INVALID_HEADER_VALUE", TypeError, "TypeError"],
["ERR_HTTP2_PING_CANCEL", Error, "Error"],
["ERR_HTTP2_STREAM_ERROR", Error, "Error"],
["ERR_HTTP2_INVALID_SINGLE_VALUE_HEADER", TypeError, "TypeError"],
["ERR_HTTP2_SESSION_ERROR", Error, "Error"],
["ERR_HTTP2_INVALID_SESSION", Error, "Error"],
["ERR_HTTP2_INVALID_HEADERS", Error, "Error"],
["ERR_HTTP2_PING_LENGTH", RangeError, "RangeError"],
["ERR_HTTP2_INVALID_STREAM", Error, "Error"],
["ERR_HTTP2_TRAILERS_ALREADY_SENT", Error, "Error"],
["ERR_HTTP2_TRAILERS_NOT_READY", Error, "Error"],
["ERR_HTTP2_PAYLOAD_FORBIDDEN", Error, "Error"],
["ERR_HTTP2_NO_SOCKET_MANIPULATION", Error, "Error"],
["ERR_HTTP2_SOCKET_UNBOUND", Error, "Error"],
["ERR_HTTP2_ERROR", Error, "Error"],
["ERR_HTTP2_OUT_OF_STREAMS", Error, "Error"],
] as ErrorCodeMapping;

View File

@@ -22,7 +22,15 @@ void adjustPositionBackwards(ZigStackFramePosition& pos, int amount, CodeBlock*
pos.column_zero_based = pos.column_zero_based - amount;
if (pos.column_zero_based < 0) {
auto source = code->source().provider()->source();
auto* provider = code->source().provider();
if (!provider) {
pos.line_zero_based = 0;
pos.column_zero_based = 0;
pos.byte_position = 0;
return;
}
auto source = provider->source();
if (!source.is8Bit()) {
// Debug-only assertion
// Bun does not yet use 16-bit sources anywhere. The transpiler ensures everything
@@ -75,6 +83,8 @@ ZigStackFramePosition getAdjustedPositionForBytecode(JSC::CodeBlock* code, JSC::
switch (inst->opcodeID()) {
case op_construct:
case op_construct_varargs:
case op_super_construct:
case op_super_construct_varargs:
// The divot by default is pointing at the `(` or the end of the class name.
// We want to point at the `new` keyword, which is conveniently at the
// expression start.

View File

@@ -16,6 +16,8 @@
#include <JavaScriptCore/StackVisitor.h>
#include <JavaScriptCore/NativeCallee.h>
#include <wtf/IterationStatus.h>
#include <JavaScriptCore/CodeBlock.h>
#include <JavaScriptCore/FunctionCodeBlock.h>
#include "ErrorStackFrame.h"
@@ -24,6 +26,69 @@ using namespace WebCore;
namespace Zig {
static ImplementationVisibility getImplementationVisibility(JSC::CodeBlock* codeBlock)
{
if (auto* executable = codeBlock->ownerExecutable()) {
return executable->implementationVisibility();
}
return ImplementationVisibility::Public;
}
static bool isImplementationVisibilityPrivate(JSC::StackVisitor& visitor)
{
ImplementationVisibility implementationVisibility = [&]() -> ImplementationVisibility {
if (visitor->callee().isCell()) {
if (auto* callee = visitor->callee().asCell()) {
if (auto* jsFunction = jsDynamicCast<JSFunction*>(callee)) {
if (auto* executable = jsFunction->executable())
return executable->implementationVisibility();
}
}
}
if (auto* codeBlock = visitor->codeBlock()) {
return getImplementationVisibility(codeBlock);
}
#if ENABLE(WEBASSEMBLY)
if (visitor->isNativeCalleeFrame())
return visitor->callee().asNativeCallee()->implementationVisibility();
#endif
return ImplementationVisibility::Public;
}();
return implementationVisibility != ImplementationVisibility::Public;
}
static bool isImplementationVisibilityPrivate(const JSC::StackFrame& frame)
{
ImplementationVisibility implementationVisibility = [&]() -> ImplementationVisibility {
#if ENABLE(WEBASSEMBLY)
if (frame.isWasmFrame())
return ImplementationVisibility::Public;
#endif
if (auto* callee = frame.callee()) {
if (auto* jsFunction = jsDynamicCast<JSFunction*>(callee)) {
if (auto* executable = jsFunction->executable())
return executable->implementationVisibility();
}
}
if (auto* codeBlock = frame.codeBlock()) {
return getImplementationVisibility(codeBlock);
}
return ImplementationVisibility::Public;
}();
return implementationVisibility != ImplementationVisibility::Public;
}
JSCStackTrace JSCStackTrace::fromExisting(JSC::VM& vm, const WTF::Vector<JSC::StackFrame>& existingFrames)
{
WTF::Vector<JSCStackFrame> newFrames;
@@ -35,41 +100,155 @@ JSCStackTrace JSCStackTrace::fromExisting(JSC::VM& vm, const WTF::Vector<JSC::St
newFrames.reserveInitialCapacity(frameCount);
for (size_t i = 0; i < frameCount; i++) {
newFrames.constructAndAppend(vm, existingFrames.at(i));
if (!isImplementationVisibilityPrivate(existingFrames.at(i))) {
newFrames.constructAndAppend(vm, existingFrames.at(i));
}
}
return JSCStackTrace(newFrames);
}
static bool isImplementationVisibilityPrivate(JSC::StackVisitor& visitor)
void JSCStackTrace::getFramesForCaller(JSC::VM& vm, JSC::CallFrame* callFrame, JSC::JSCell* owner, JSC::JSValue caller, WTF::Vector<JSC::StackFrame>& stackTrace, size_t stackTraceLimit)
{
ImplementationVisibility implementationVisibility = [&]() -> ImplementationVisibility {
if (auto* codeBlock = visitor->codeBlock()) {
if (auto* executable = codeBlock->ownerExecutable()) {
return executable->implementationVisibility();
}
return ImplementationVisibility::Public;
size_t framesCount = 0;
bool belowCaller = false;
int32_t skipFrames = 0;
WTF::String callerName {};
if (JSC::JSFunction* callerFunction = JSC::jsDynamicCast<JSC::JSFunction*>(caller)) {
callerName = callerFunction->name(vm);
if (callerName.isEmpty() && callerFunction->jsExecutable()) {
callerName = callerFunction->jsExecutable()->name().string();
}
}
if (JSC::InternalFunction* callerFunctionInternal = JSC::jsDynamicCast<JSC::InternalFunction*>(caller)) {
callerName = callerFunctionInternal->name();
}
#if ENABLE(WEBASSEMBLY)
if (visitor->isNativeCalleeFrame())
return visitor->callee().asNativeCallee()->implementationVisibility();
#endif
size_t totalFrames = 0;
if (visitor->callee().isCell()) {
if (auto* callee = visitor->callee().asCell()) {
if (auto* jsFunction = jsDynamicCast<JSFunction*>(callee)) {
if (auto* executable = jsFunction->executable())
return executable->implementationVisibility();
return ImplementationVisibility::Public;
if (!callerName.isEmpty()) {
JSC::StackVisitor::visit(callFrame, vm, [&](JSC::StackVisitor& visitor) -> WTF::IterationStatus {
if (isImplementationVisibilityPrivate(visitor)) {
return WTF::IterationStatus::Continue;
}
framesCount += 1;
// skip caller frame and all frames above it
if (!belowCaller) {
skipFrames += 1;
if (visitor->functionName() == callerName) {
belowCaller = true;
return WTF::IterationStatus::Continue;
}
}
totalFrames += 1;
if (totalFrames > stackTraceLimit) {
return WTF::IterationStatus::Done;
}
return WTF::IterationStatus::Continue;
});
} else if (caller && caller.isCell()) {
JSC::StackVisitor::visit(callFrame, vm, [&](JSC::StackVisitor& visitor) -> WTF::IterationStatus {
if (isImplementationVisibilityPrivate(visitor)) {
return WTF::IterationStatus::Continue;
}
framesCount += 1;
// skip caller frame and all frames above it
if (!belowCaller) {
auto callee = visitor->callee();
skipFrames += 1;
if (callee.isCell() && callee.asCell() == caller) {
belowCaller = true;
return WTF::IterationStatus::Continue;
}
}
totalFrames += 1;
if (totalFrames > stackTraceLimit) {
return WTF::IterationStatus::Done;
}
return WTF::IterationStatus::Continue;
});
} else if (caller.isEmpty() || caller.isUndefined()) {
// Skip the first frame.
JSC::StackVisitor::visit(callFrame, vm, [&](JSC::StackVisitor& visitor) -> WTF::IterationStatus {
if (isImplementationVisibilityPrivate(visitor)) {
return WTF::IterationStatus::Continue;
}
framesCount += 1;
if (!belowCaller) {
skipFrames += 1;
belowCaller = true;
}
totalFrames += 1;
if (totalFrames > stackTraceLimit) {
return WTF::IterationStatus::Done;
}
return WTF::IterationStatus::Continue;
});
}
size_t i = 0;
totalFrames = 0;
stackTrace.reserveInitialCapacity(framesCount);
JSC::StackVisitor::visit(callFrame, vm, [&](JSC::StackVisitor& visitor) -> WTF::IterationStatus {
// Skip native frames
if (isImplementationVisibilityPrivate(visitor)) {
return WTF::IterationStatus::Continue;
}
return ImplementationVisibility::Public;
}();
// Skip frames if needed
if (skipFrames > 0) {
skipFrames--;
return WTF::IterationStatus::Continue;
}
return implementationVisibility != ImplementationVisibility::Public;
totalFrames += 1;
if (totalFrames > stackTraceLimit) {
return WTF::IterationStatus::Done;
}
if (visitor->isNativeCalleeFrame()) {
auto* nativeCallee = visitor->callee().asNativeCallee();
switch (nativeCallee->category()) {
case NativeCallee::Category::Wasm: {
stackTrace.append(StackFrame(visitor->wasmFunctionIndexOrName()));
break;
}
case NativeCallee::Category::InlineCache: {
break;
}
}
#if USE(ALLOW_LINE_AND_COLUMN_NUMBER_IN_BUILTINS)
} else if (!!visitor->codeBlock())
#else
} else if (!!visitor->codeBlock() && !visitor->codeBlock()->unlinkedCodeBlock()->isBuiltinFunction())
#endif
stackTrace.append(StackFrame(vm, owner, visitor->callee().asCell(), visitor->codeBlock(), visitor->bytecodeIndex()));
else
stackTrace.append(StackFrame(vm, owner, visitor->callee().asCell()));
i++;
return (i == framesCount) ? WTF::IterationStatus::Done : WTF::IterationStatus::Continue;
});
}
JSCStackTrace JSCStackTrace::captureCurrentJSStackTrace(Zig::GlobalObject* globalObject, JSC::CallFrame* callFrame, size_t frameLimit, JSC::JSValue caller)
@@ -203,6 +382,22 @@ JSCStackTrace JSCStackTrace::getStackTraceForThrownValue(JSC::VM& vm, JSC::JSVal
return fromExisting(vm, *jscStackTrace);
}
static bool isVisibleBuiltinFunction(JSC::CodeBlock* codeBlock)
{
if (!codeBlock->ownerExecutable()) {
return false;
}
const JSC::SourceCode& source = codeBlock->source();
if (auto* provider = source.provider()) {
const auto& url = provider->sourceURL();
if (!url.isEmpty()) {
return true;
}
}
return false;
}
JSCStackFrame::JSCStackFrame(JSC::VM& vm, JSC::StackVisitor& visitor)
: m_vm(vm)
, m_codeBlock(nullptr)
@@ -228,9 +423,18 @@ JSCStackFrame::JSCStackFrame(JSC::VM& vm, JSC::StackVisitor& visitor)
break;
}
}
} else if (!!visitor->codeBlock() && !visitor->codeBlock()->unlinkedCodeBlock()->isBuiltinFunction()) {
m_codeBlock = visitor->codeBlock();
m_bytecodeIndex = visitor->bytecodeIndex();
} else if (auto* codeBlock = visitor->codeBlock()) {
auto* unlinkedCodeBlock = codeBlock->unlinkedCodeBlock();
if (!unlinkedCodeBlock->isBuiltinFunction() || isVisibleBuiltinFunction(codeBlock)) {
m_codeBlock = codeBlock;
m_bytecodeIndex = visitor->bytecodeIndex();
}
}
if (!m_bytecodeIndex && visitor->hasLineAndColumnInfo()) {
auto lineColumn = visitor->computeLineAndColumn();
m_sourcePositions = { OrdinalNumber::fromOneBasedInt(lineColumn.line), OrdinalNumber::fromOneBasedInt(lineColumn.column) };
m_sourcePositionsState = SourcePositionsState::Calculated;
}
}
@@ -250,12 +454,19 @@ JSCStackFrame::JSCStackFrame(JSC::VM& vm, const JSC::StackFrame& frame)
if (frame.isWasmFrame()) {
m_wasmFunctionIndexOrName = frame.wasmFunctionIndexOrName();
m_isWasmFrame = true;
} else {
m_codeBlock = frame.codeBlock();
if (frame.hasBytecodeIndex()) {
} else if (auto* codeBlock = frame.codeBlock()) {
auto* unlinkedCodeBlock = codeBlock->unlinkedCodeBlock();
if (!unlinkedCodeBlock->isBuiltinFunction() || isVisibleBuiltinFunction(codeBlock)) {
m_codeBlock = codeBlock;
m_bytecodeIndex = frame.bytecodeIndex();
}
}
if (!m_codeBlock && frame.hasLineAndColumnInfo()) {
auto lineColumn = frame.computeLineAndColumn();
m_sourcePositions = { OrdinalNumber::fromOneBasedInt(lineColumn.line), OrdinalNumber::fromOneBasedInt(lineColumn.column) };
m_sourcePositionsState = SourcePositionsState::Calculated;
}
}
intptr_t JSCStackFrame::sourceID() const
@@ -308,16 +519,36 @@ ALWAYS_INLINE String JSCStackFrame::retrieveSourceURL()
return String(sourceURLWasmString);
}
if (m_callee && m_callee->isObject()) {
if (auto* jsFunction = jsDynamicCast<JSFunction*>(m_callee)) {
if (auto* executable = jsFunction->executable()) {
if (!executable->isHostFunction()) {
auto* jsExectuable = jsFunction->jsExecutable();
if (jsExectuable) {
const auto* sourceProvider = jsExectuable->source().provider();
if (sourceProvider) {
return sourceProvider->sourceURL();
}
}
}
}
}
}
if (!m_codeBlock) {
return String(sourceURLNativeString);
}
return m_codeBlock->ownerExecutable()->sourceURL();
auto* provider = m_codeBlock->source().provider();
if (provider) {
return provider->sourceURL();
}
return String();
}
ALWAYS_INLINE String JSCStackFrame::retrieveFunctionName()
{
static auto functionNameEvalCodeString = MAKE_STATIC_STRING_IMPL("eval code");
static auto functionNameModuleCodeString = MAKE_STATIC_STRING_IMPL("module code");
static auto functionNameGlobalCodeString = MAKE_STATIC_STRING_IMPL("global code");
@@ -328,7 +559,8 @@ ALWAYS_INLINE String JSCStackFrame::retrieveFunctionName()
if (m_codeBlock) {
switch (m_codeBlock->codeType()) {
case JSC::EvalCode:
return String(functionNameEvalCodeString);
// Node returns null here.
return String();
case JSC::ModuleCode:
return String(functionNameModuleCodeString);
case JSC::FunctionCode:
@@ -340,13 +572,26 @@ ALWAYS_INLINE String JSCStackFrame::retrieveFunctionName()
}
}
String name;
if (m_callee) {
if (m_callee->isObject())
name = getCalculatedDisplayName(m_vm, jsCast<JSObject*>(m_callee)).impl();
if (auto* callee = m_callee->getObject()) {
// Does the code block have a user-defined name property?
JSC::JSValue name = callee->getDirect(m_vm, m_vm.propertyNames->name);
if (name && name.isString()) {
auto scope = DECLARE_CATCH_SCOPE(m_vm);
auto nameString = name.toWTFString(callee->globalObject());
if (scope.exception()) {
scope.clearException();
}
if (!nameString.isEmpty()) {
return nameString;
}
}
return JSC::getCalculatedDisplayName(m_vm, callee);
}
}
return name.isNull() ? emptyString() : name;
return emptyString();
}
ALWAYS_INLINE String JSCStackFrame::retrieveTypeName()

View File

@@ -46,13 +46,13 @@ public:
private:
JSC::VM& m_vm;
JSC::JSCell* m_callee;
JSC::JSCell* m_callee { nullptr };
// May be null
JSC::CallFrame* m_callFrame;
// May be null
JSC::CodeBlock* m_codeBlock;
JSC::CodeBlock* m_codeBlock { nullptr };
JSC::BytecodeIndex m_bytecodeIndex;
// Lazy-initialized
@@ -96,8 +96,40 @@ public:
SourcePositions* getSourcePositions();
bool isWasmFrame() const { return m_isWasmFrame; }
bool isEval() const { return m_codeBlock && (JSC::EvalCode == m_codeBlock->codeType()); }
bool isConstructor() const { return m_codeBlock && (JSC::CodeForConstruct == m_codeBlock->specializationKind()); }
bool isEval()
{
if (m_codeBlock) {
if (m_codeBlock->codeType() == JSC::EvalCode) {
return true;
}
auto* executable = m_codeBlock->ownerExecutable();
if (!executable) {
return false;
}
switch (executable->evalContextType()) {
case JSC::EvalContextType::None: {
return false;
}
case JSC::EvalContextType::FunctionEvalContext:
case JSC::EvalContextType::InstanceFieldEvalContext:
return true;
}
}
if (m_callee && m_callee->inherits<JSC::JSFunction>()) {
auto* function = jsCast<JSC::JSFunction*>(m_callee);
if (function->isHostFunction()) {
return false;
}
}
return false;
}
bool isConstructor() const
{
return m_codeBlock && (JSC::CodeForConstruct == m_codeBlock->specializationKind());
}
private:
ALWAYS_INLINE String retrieveSourceURL();
@@ -130,10 +162,17 @@ public:
{
}
JSCStackTrace(WTF::Vector<JSCStackFrame>&& frames)
: m_frames(WTFMove(frames))
{
}
size_t size() const { return m_frames.size(); }
bool isEmpty() const { return m_frames.isEmpty(); }
JSCStackFrame& at(size_t i) { return m_frames.at(i); }
WTF::Vector<JSCStackFrame>&& frames() { return WTFMove(m_frames); }
static JSCStackTrace fromExisting(JSC::VM& vm, const WTF::Vector<JSC::StackFrame>& existingFrames);
/* This is based on JSC::Interpreter::getStackTrace, but skips native (non js and not wasm)
@@ -145,6 +184,7 @@ public:
*
* Return value must remain stack allocated. */
static JSCStackTrace captureCurrentJSStackTrace(Zig::GlobalObject* globalObject, JSC::CallFrame* callFrame, size_t frameLimit, JSC::JSValue caller);
static void getFramesForCaller(JSC::VM& vm, JSC::CallFrame* callFrame, JSC::JSCell* owner, JSC::JSValue caller, WTF::Vector<JSC::StackFrame>& stackTrace, size_t stackTraceLimit);
/* In JSC, JSC::Exception points to the actual value that was thrown, usually
* a JSC::ErrorInstance (but could be any JSValue). In v8, on the other hand,

View File

@@ -41,4 +41,4 @@ protected:
bool m_isCleanupTask;
};
}
}

View File

@@ -18,4 +18,4 @@ ALWAYS_INLINE GCDeferralContext::~GCDeferralContext()
m_vm.heap.collectIfNecessaryOrDefer();
}
} // namespace JSC
} // namespace JSC

View File

@@ -414,4 +414,4 @@ template<typename T>
struct IsIDLArrayBufferViewAllowShared : public std::integral_constant<bool, std::is_base_of<IDLAllowSharedAdaptor<IDLArrayBufferView>, T>::value> {
};
} // namespace WebCore
} // namespace WebCore

View File

@@ -10,4 +10,4 @@ JSC_DECLARE_HOST_FUNCTION(jsDollarCpp);
JSC_DECLARE_HOST_FUNCTION(jsDollarZig);
} // namespace JS2Native
} // namespace Bun
} // namespace Bun

View File

@@ -53,6 +53,7 @@
#include "JSBufferEncodingType.h"
#include "ErrorCode.h"
#include "NodeValidator.h"
#include "wtf/Assertions.h"
#include "wtf/Forward.h"
#include <JavaScriptCore/JSBase.h>
@@ -90,6 +91,7 @@ static JSC_DECLARE_HOST_FUNCTION(jsBufferConstructorFunction_allocUnsafeSlow);
static JSC_DECLARE_HOST_FUNCTION(jsBufferConstructorFunction_byteLength);
static JSC_DECLARE_HOST_FUNCTION(jsBufferConstructorFunction_compare);
static JSC_DECLARE_HOST_FUNCTION(jsBufferConstructorFunction_concat);
static JSC_DECLARE_HOST_FUNCTION(jsBufferConstructorFunction_copyBytesFrom);
static JSC_DECLARE_HOST_FUNCTION(jsBufferConstructorFunction_from);
static JSC_DECLARE_HOST_FUNCTION(jsBufferConstructorFunction_isBuffer);
static JSC_DECLARE_HOST_FUNCTION(jsBufferConstructorFunction_isEncoding);
@@ -246,29 +248,15 @@ static int normalizeCompareVal(int val, size_t a_length, size_t b_length)
return val;
}
const unsigned U32_MAX = std::numeric_limits<unsigned>().max();
static inline uint32_t parseIndex(JSC::JSGlobalObject* lexicalGlobalObject, JSC::ThrowScope& scope, ASCIILiteral name, JSValue arg, size_t upperBound)
{
if (!arg.isNumber()) return Bun::ERR::INVALID_ARG_TYPE(scope, lexicalGlobalObject, name, "number"_s, arg);
auto num = arg.asNumber();
if (num < 0 || std::isinf(num)) return Bun::ERR::OUT_OF_RANGE(scope, lexicalGlobalObject, name, 0, upperBound, arg);
double intpart;
if (std::modf(num, &intpart) != 0) return Bun::ERR::INVALID_ARG_TYPE(scope, lexicalGlobalObject, name, "integer"_s, arg);
if (intpart >= 0 && intpart <= U32_MAX) return intpart;
return Bun::ERR::OUT_OF_RANGE(scope, lexicalGlobalObject, name, 0, upperBound, arg);
}
static inline WebCore::BufferEncodingType parseEncoding(JSC::JSGlobalObject* lexicalGlobalObject, JSC::ThrowScope& scope, JSValue arg)
{
if (UNLIKELY(!arg.isString())) {
Bun::ERR::INVALID_ARG_TYPE(scope, lexicalGlobalObject, "encoding"_s, "string"_s, arg);
return WebCore::BufferEncodingType::utf8;
}
auto arg_ = arg.toStringOrNull(lexicalGlobalObject);
RETURN_IF_EXCEPTION(scope, {});
auto arg_s = arg_->getString(lexicalGlobalObject);
std::optional<BufferEncodingType> encoded = parseEnumeration<BufferEncodingType>(*lexicalGlobalObject, arg);
std::optional<BufferEncodingType> encoded = parseEnumeration2(*lexicalGlobalObject, arg_s);
if (UNLIKELY(!encoded)) {
Bun::ERR::UNKNOWN_ENCODING(scope, lexicalGlobalObject, arg);
Bun::ERR::UNKNOWN_ENCODING(scope, lexicalGlobalObject, arg_s);
return WebCore::BufferEncodingType::utf8;
}
@@ -415,6 +403,10 @@ static inline JSC::JSUint8Array* JSBuffer__bufferFromLengthAsArray(JSC::JSGlobal
throwNodeRangeError(lexicalGlobalObject, throwScope, "Invalid array length"_s);
return nullptr;
}
if (length > MAX_ARRAY_BUFFER_SIZE) {
Bun::ERR::OUT_OF_RANGE(throwScope, lexicalGlobalObject, "size"_s, 0, MAX_ARRAY_BUFFER_SIZE, jsNumber(length));
return nullptr;
}
auto* globalObject = reinterpret_cast<Zig::GlobalObject*>(lexicalGlobalObject);
auto* subclassStructure = globalObject->JSBufferSubclassStructure();
@@ -428,27 +420,18 @@ extern "C" JSC::EncodedJSValue JSBuffer__bufferFromLength(JSC::JSGlobalObject* l
return JSC::JSValue::encode(JSBuffer__bufferFromLengthAsArray(lexicalGlobalObject, length));
}
// https://github.com/nodejs/node/blob/v22.9.0/lib/buffer.js#L404
static inline JSC::EncodedJSValue jsBufferConstructorFunction_allocUnsafeBody(JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame)
{
VM& vm = lexicalGlobalObject->vm();
auto throwScope = DECLARE_THROW_SCOPE(vm);
JSValue lengthValue = callFrame->argument(0);
if (UNLIKELY(!lengthValue.isNumber())) {
return Bun::ERR::INVALID_ARG_TYPE(throwScope, lexicalGlobalObject, "size"_s, "number"_s, lengthValue);
}
double lengthDouble = lengthValue.toIntegerWithTruncation(lexicalGlobalObject);
if (UNLIKELY(lengthDouble < 0 || lengthDouble > MAX_ARRAY_BUFFER_SIZE || lengthDouble != lengthDouble)) {
return Bun::ERR::OUT_OF_RANGE(throwScope, lexicalGlobalObject, "size"_s, 0, MAX_ARRAY_BUFFER_SIZE, lengthValue);
}
size_t length = static_cast<size_t>(lengthDouble);
RELEASE_AND_RETURN(throwScope, JSValue::encode(allocBufferUnsafe(lexicalGlobalObject, length)));
Bun::V::validateNumber(throwScope, lexicalGlobalObject, lengthValue, jsString(vm, String("size"_s)), jsNumber(0), jsNumber(Bun::Buffer::kMaxLength));
RETURN_IF_EXCEPTION(throwScope, {});
size_t length = lengthValue.toLength(lexicalGlobalObject);
auto result = allocBufferUnsafe(lexicalGlobalObject, length);
RETURN_IF_EXCEPTION(throwScope, {});
RELEASE_AND_RETURN(throwScope, JSValue::encode(result));
}
// new Buffer()
@@ -542,7 +525,7 @@ static inline JSC::EncodedJSValue constructBufferFromStringAndEncoding(JSC::JSGl
if (arg1 && arg1.isString()) {
std::optional<BufferEncodingType> encoded = parseEnumeration<BufferEncodingType>(*lexicalGlobalObject, arg1);
if (!encoded) {
return Bun::ERR::UNKNOWN_ENCODING(scope, lexicalGlobalObject, arg1);
return Bun::ERR::UNKNOWN_ENCODING(scope, lexicalGlobalObject, arg1.getString(lexicalGlobalObject));
}
encoding = encoded.value();
@@ -556,23 +539,16 @@ static inline JSC::EncodedJSValue constructBufferFromStringAndEncoding(JSC::JSGl
RELEASE_AND_RETURN(scope, result);
}
// https://github.com/nodejs/node/blob/v22.9.0/lib/buffer.js#L391
static inline JSC::EncodedJSValue jsBufferConstructorFunction_allocBody(JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame)
{
VM& vm = lexicalGlobalObject->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
JSValue lengthValue = callFrame->uncheckedArgument(0);
if (UNLIKELY(!lengthValue.isNumber())) {
return Bun::ERR::INVALID_ARG_TYPE(scope, lexicalGlobalObject, "size"_s, "number"_s, lengthValue);
return {};
}
double lengthDouble = lengthValue.toIntegerWithTruncation(lexicalGlobalObject);
if (UNLIKELY(lengthDouble < 0 || lengthDouble > MAX_ARRAY_BUFFER_SIZE || lengthDouble != lengthDouble)) {
return Bun::ERR::OUT_OF_RANGE(scope, lexicalGlobalObject, "size"_s, 0, MAX_ARRAY_BUFFER_SIZE, lengthValue);
}
size_t length = static_cast<size_t>(lengthDouble);
JSValue lengthValue = callFrame->argument(0);
Bun::V::validateNumber(scope, lexicalGlobalObject, lengthValue, jsString(vm, String("size"_s)), jsNumber(0), jsNumber(Bun::Buffer::kMaxLength));
RETURN_IF_EXCEPTION(scope, {});
size_t length = lengthValue.toLength(lexicalGlobalObject);
// fill argument
if (UNLIKELY(callFrame->argumentCount() > 1)) {
@@ -769,6 +745,7 @@ static inline JSC::EncodedJSValue jsBufferConstructorFunction_compareBody(JSC::J
RELEASE_AND_RETURN(throwScope, JSC::JSValue::encode(JSC::jsNumber(normalizeCompareVal(result, sourceLength, targetLength))));
}
static inline JSC::EncodedJSValue jsBufferConstructorFunction_concatBody(JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame)
{
auto& vm = JSC::getVM(lexicalGlobalObject);
@@ -876,13 +853,76 @@ static inline JSC::EncodedJSValue jsBufferConstructorFunction_concatBody(JSC::JS
RELEASE_AND_RETURN(throwScope, JSC::JSValue::encode(JSC::JSValue(outBuffer)));
}
// https://github.com/nodejs/node/blob/v22.9.0/lib/buffer.js#L337
static inline JSC::EncodedJSValue jsBufferConstructorFunction_copyBytesFromBody(JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame)
{
auto& vm = JSC::getVM(lexicalGlobalObject);
auto throwScope = DECLARE_THROW_SCOPE(vm);
auto viewValue = callFrame->argument(0);
auto offsetValue = callFrame->argument(1);
auto lengthValue = callFrame->argument(2);
auto view = jsDynamicCast<JSArrayBufferView*>(viewValue);
if (!view) {
return Bun::ERR::INVALID_ARG_TYPE(throwScope, lexicalGlobalObject, "view"_s, "TypedArray"_s, viewValue);
}
auto ty = JSC::typedArrayType(view->type());
auto viewLength = view->length();
if (viewLength == 0) {
return JSValue::encode(createEmptyBuffer(lexicalGlobalObject));
}
double offset;
double length;
if (!offsetValue.isUndefined() || !lengthValue.isUndefined()) {
if (!offsetValue.isUndefined()) {
Bun::V::validateInteger(throwScope, lexicalGlobalObject, offsetValue, jsString(vm, String("offset"_s)), jsNumber(0), jsUndefined());
RETURN_IF_EXCEPTION(throwScope, {});
offset = offsetValue.asNumber();
if (offset >= viewLength) return JSValue::encode(createEmptyBuffer(lexicalGlobalObject));
} else {
offset = 0;
}
double end = 0;
if (!lengthValue.isUndefined()) {
Bun::V::validateInteger(throwScope, lexicalGlobalObject, lengthValue, jsString(vm, String("length"_s)), jsNumber(0), jsUndefined());
RETURN_IF_EXCEPTION(throwScope, {});
length = lengthValue.asNumber();
end = offset + length;
} else {
end = viewLength;
}
end = std::min(end, (double)viewLength);
auto elemSize = JSC::elementSize(ty);
auto offset_r = offset * elemSize;
auto end_r = end * elemSize;
auto span = view->span().subspan(offset_r, end_r - offset_r);
return JSValue::encode(createBuffer(lexicalGlobalObject, span.data(), span.size()));
}
auto boffset = view->byteOffset();
auto blength = view->byteLength();
auto span = view->span().subspan(boffset, blength - boffset);
return JSValue::encode(createBuffer(lexicalGlobalObject, span.data(), span.size()));
}
static inline JSC::EncodedJSValue jsBufferConstructorFunction_isEncodingBody(JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame)
{
auto* encoding_ = callFrame->argument(0).toStringOrNull(lexicalGlobalObject);
if (!encoding_)
auto& vm = lexicalGlobalObject->vm();
auto throwScope = DECLARE_THROW_SCOPE(vm);
auto encodingValue = callFrame->argument(0);
if (!encodingValue.isString()) {
return JSValue::encode(jsBoolean(false));
std::optional<BufferEncodingType> encoded = parseEnumeration<BufferEncodingType>(*lexicalGlobalObject, encoding_);
}
auto* encoding = encodingValue.toString(lexicalGlobalObject);
RETURN_IF_EXCEPTION(throwScope, {});
std::optional<BufferEncodingType> encoded = parseEnumeration<BufferEncodingType>(*lexicalGlobalObject, encoding);
return JSValue::encode(jsBoolean(!!encoded));
}
@@ -951,26 +991,38 @@ static inline JSC::EncodedJSValue jsBufferPrototypeFunction_compareBody(JSC::JSG
switch (callFrame->argumentCount()) {
default:
sourceEndValue = callFrame->uncheckedArgument(4);
if (sourceEndValue != jsUndefined())
sourceEnd = parseIndex(lexicalGlobalObject, throwScope, "sourceEnd"_s, sourceEndValue, sourceEndInit);
if (sourceEndValue != jsUndefined()) {
Bun::V::validateInteger(throwScope, lexicalGlobalObject, sourceEndValue, jsString(vm, String("sourceEnd"_s)), jsNumber(0), jsNumber(Bun::Buffer::kMaxLength));
RETURN_IF_EXCEPTION(throwScope, {});
sourceEnd = sourceEndValue.asNumber();
}
RETURN_IF_EXCEPTION(throwScope, {});
FALLTHROUGH;
case 4:
sourceStartValue = callFrame->uncheckedArgument(3);
if (sourceStartValue != jsUndefined())
sourceStart = parseIndex(lexicalGlobalObject, throwScope, "sourceStart"_s, sourceStartValue, sourceEndInit);
if (sourceStartValue != jsUndefined()) {
Bun::V::validateInteger(throwScope, lexicalGlobalObject, sourceStartValue, jsString(vm, String("sourceStart"_s)), jsNumber(0), jsNumber(Bun::Buffer::kMaxLength));
RETURN_IF_EXCEPTION(throwScope, {});
sourceStart = sourceStartValue.asNumber();
}
RETURN_IF_EXCEPTION(throwScope, {});
FALLTHROUGH;
case 3:
targetEndValue = callFrame->uncheckedArgument(2);
if (targetEndValue != jsUndefined())
targetEnd = parseIndex(lexicalGlobalObject, throwScope, "targetEnd"_s, targetEndValue, targetEndInit);
if (targetEndValue != jsUndefined()) {
Bun::V::validateInteger(throwScope, lexicalGlobalObject, targetEndValue, jsString(vm, String("targetEnd"_s)), jsNumber(0), jsNumber(Bun::Buffer::kMaxLength));
RETURN_IF_EXCEPTION(throwScope, {});
targetEnd = targetEndValue.asNumber();
}
RETURN_IF_EXCEPTION(throwScope, {});
FALLTHROUGH;
case 2:
targetStartValue = callFrame->uncheckedArgument(1);
if (targetStartValue != jsUndefined())
targetStart = parseIndex(lexicalGlobalObject, throwScope, "targetStart"_s, targetStartValue, targetEndInit);
if (targetStartValue != jsUndefined()) {
Bun::V::validateInteger(throwScope, lexicalGlobalObject, targetStartValue, jsString(vm, String("targetStart"_s)), jsNumber(0), jsNumber(Bun::Buffer::kMaxLength));
RETURN_IF_EXCEPTION(throwScope, {});
targetStart = targetStartValue.asNumber();
}
RETURN_IF_EXCEPTION(throwScope, {});
break;
case 1:
@@ -1005,76 +1057,83 @@ static inline JSC::EncodedJSValue jsBufferPrototypeFunction_compareBody(JSC::JSG
RELEASE_AND_RETURN(throwScope, JSC::JSValue::encode(JSC::jsNumber(normalizeCompareVal(result, sourceLength, targetLength))));
}
static double toInteger(JSC::ThrowScope& scope, JSC::JSGlobalObject* globalObject, JSValue value, double defaultVal)
{
auto n = value.toNumber(globalObject);
RETURN_IF_EXCEPTION(scope, {});
if (std::isnan(n)) return defaultVal;
if (n < JSC::minSafeInteger()) return defaultVal;
if (n > JSC::maxSafeInteger()) return defaultVal;
return std::trunc(n);
}
// https://github.com/nodejs/node/blob/v22.9.0/lib/buffer.js#L825
// https://github.com/nodejs/node/blob/v22.9.0/lib/buffer.js#L205
static inline JSC::EncodedJSValue jsBufferPrototypeFunction_copyBody(JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame, typename IDLOperation<JSArrayBufferView>::ClassParameter castedThis)
{
auto& vm = JSC::getVM(lexicalGlobalObject);
auto throwScope = DECLARE_THROW_SCOPE(vm);
if (callFrame->argumentCount() < 1) {
throwVMError(lexicalGlobalObject, throwScope, createNotEnoughArgumentsError(lexicalGlobalObject));
return {};
auto targetValue = callFrame->argument(0);
auto targetStartValue = callFrame->argument(1);
auto sourceStartValue = callFrame->argument(2);
auto sourceEndValue = callFrame->argument(3);
auto source = castedThis;
auto target = jsDynamicCast<JSArrayBufferView*>(targetValue);
if (!target) {
return Bun::ERR::INVALID_ARG_TYPE(throwScope, lexicalGlobalObject, "target"_s, "Buffer or Uint8Array"_s, targetValue);
}
auto buffer = callFrame->uncheckedArgument(0);
if (!buffer.isCell() || !JSC::isTypedView(buffer.asCell()->type())) {
throwVMTypeError(lexicalGlobalObject, throwScope, "Expected Uint8Array"_s);
return {};
}
JSC::JSArrayBufferView* view = JSC::jsDynamicCast<JSC::JSArrayBufferView*>(buffer);
if (UNLIKELY(!view || view->isDetached())) {
throwVMTypeError(lexicalGlobalObject, throwScope, "Uint8Array is detached"_s);
return {};
}
auto sourceLength = source->byteLength();
auto targetLength = target->byteLength();
size_t targetStart = 0;
size_t targetEnd = view->byteLength();
size_t sourceStart = 0;
size_t sourceEndInit = castedThis->byteLength();
size_t sourceEnd = sourceEndInit;
JSValue targetStartValue = jsUndefined();
JSValue sourceStartValue = jsUndefined();
JSValue sourceEndValue = jsUndefined();
switch (callFrame->argumentCount()) {
default:
sourceEndValue = callFrame->uncheckedArgument(3);
sourceEnd = parseIndex(lexicalGlobalObject, throwScope, "sourceEnd"_s, callFrame->uncheckedArgument(3), sourceEndInit);
if (targetStartValue.isUndefined()) {
} else {
double targetStartD = targetStartValue.isAnyInt() ? targetStartValue.asNumber() : toInteger(throwScope, lexicalGlobalObject, targetStartValue, 0);
RETURN_IF_EXCEPTION(throwScope, {});
FALLTHROUGH;
case 3:
sourceStartValue = callFrame->uncheckedArgument(2);
sourceStart = parseIndex(lexicalGlobalObject, throwScope, "sourceStart"_s, callFrame->uncheckedArgument(2), sourceEndInit);
RETURN_IF_EXCEPTION(throwScope, {});
FALLTHROUGH;
case 2:
targetStartValue = callFrame->uncheckedArgument(1);
targetStart = parseIndex(lexicalGlobalObject, throwScope, "targetStart"_s, callFrame->uncheckedArgument(1), targetEnd);
RETURN_IF_EXCEPTION(throwScope, {});
break;
case 1:
case 0:
break;
if (targetStartD < 0) return Bun::ERR::OUT_OF_RANGE(throwScope, lexicalGlobalObject, "targetStart"_s, 0, targetLength, targetStartValue);
targetStart = static_cast<size_t>(targetStartD);
}
targetStart = std::min(targetStart, targetEnd);
sourceEnd = std::min(sourceEnd, sourceEndInit);
sourceStart = std::min(sourceStart, sourceEnd);
size_t sourceStart = 0;
if (sourceStartValue.isUndefined()) {
} else {
double sourceStartD = sourceStartValue.isAnyInt() ? sourceStartValue.asNumber() : toInteger(throwScope, lexicalGlobalObject, sourceStartValue, 0);
RETURN_IF_EXCEPTION(throwScope, {});
if (sourceStartD < 0 || sourceStartD > sourceLength) return Bun::ERR::OUT_OF_RANGE(throwScope, lexicalGlobalObject, "sourceStart"_s, 0, sourceLength, sourceStartValue);
sourceStart = static_cast<size_t>(sourceStartD);
}
auto sourceLength = sourceEnd - sourceStart;
auto targetLength = targetEnd - targetStart;
auto actualLength = std::min(sourceLength, targetLength);
size_t sourceEnd = sourceLength;
if (sourceEndValue.isUndefined()) {
} else {
double sourceEndD = sourceEndValue.isAnyInt() ? sourceEndValue.asNumber() : toInteger(throwScope, lexicalGlobalObject, sourceEndValue, 0);
RETURN_IF_EXCEPTION(throwScope, {});
if (sourceEndD < 0) return Bun::ERR::OUT_OF_RANGE(throwScope, lexicalGlobalObject, "sourceEnd"_s, 0, sourceLength, sourceEndValue);
sourceEnd = static_cast<size_t>(sourceEndD);
}
auto sourceStartPtr = castedThis->typedVector() + sourceStart;
auto targetStartPtr = reinterpret_cast<unsigned char*>(view->vector()) + targetStart;
if (targetStart >= targetLength || sourceStart >= sourceEnd) {
return JSValue::encode(jsNumber(0));
}
if (actualLength > 0)
memmove(targetStartPtr, sourceStartPtr, actualLength);
if (sourceEnd - sourceStart > targetLength - targetStart)
sourceEnd = sourceStart + targetLength - targetStart;
return JSValue::encode(jsNumber(actualLength));
ssize_t nb = sourceEnd - sourceStart;
auto sourceLen = sourceLength - sourceStart;
if (nb > sourceLen) nb = sourceLen;
if (nb <= 0) return JSValue::encode(jsNumber(0));
auto sourceStartPtr = reinterpret_cast<unsigned char*>(source->vector()) + sourceStart;
auto targetStartPtr = reinterpret_cast<unsigned char*>(target->vector()) + targetStart;
memmove(targetStartPtr, sourceStartPtr, nb);
return JSValue::encode(jsNumber(nb));
}
static inline JSC::EncodedJSValue jsBufferPrototypeFunction_equalsBody(JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame, typename IDLOperation<JSArrayBufferView>::ClassParameter castedThis)
@@ -1089,8 +1148,7 @@ static inline JSC::EncodedJSValue jsBufferPrototypeFunction_equalsBody(JSC::JSGl
auto buffer = callFrame->uncheckedArgument(0);
JSC::JSArrayBufferView* view = JSC::jsDynamicCast<JSC::JSArrayBufferView*>(buffer);
if (UNLIKELY(!view)) {
throwVMTypeError(lexicalGlobalObject, throwScope, "Expected Buffer"_s);
return {};
return Bun::ERR::INVALID_ARG_TYPE(throwScope, lexicalGlobalObject, "otherBuffer"_s, "Buffer or Uint8Array"_s, buffer);
}
if (UNLIKELY(view->isDetached())) {
@@ -1123,19 +1181,19 @@ static inline JSC::EncodedJSValue jsBufferPrototypeFunction_fillBody(JSC::JSGlob
auto value = callFrame->uncheckedArgument(0);
const size_t limit = castedThis->byteLength();
size_t start = 0;
size_t offset = 0;
size_t end = limit;
WebCore::BufferEncodingType encoding = WebCore::BufferEncodingType::utf8;
JSValue encodingValue = jsUndefined();
JSValue offsetValue = jsUndefined();
JSValue lengthValue = jsUndefined();
JSValue endValue = jsUndefined();
switch (callFrame->argumentCount()) {
case 4:
encodingValue = callFrame->uncheckedArgument(3);
FALLTHROUGH;
case 3:
lengthValue = callFrame->uncheckedArgument(2);
endValue = callFrame->uncheckedArgument(2);
FALLTHROUGH;
case 2:
offsetValue = callFrame->uncheckedArgument(1);
@@ -1147,49 +1205,48 @@ static inline JSC::EncodedJSValue jsBufferPrototypeFunction_fillBody(JSC::JSGlob
if (offsetValue.isUndefined() || offsetValue.isString()) {
encodingValue = offsetValue;
offsetValue = jsUndefined();
} else if (lengthValue.isString()) {
encodingValue = lengthValue;
lengthValue = jsUndefined();
} else if (endValue.isString()) {
encodingValue = endValue;
endValue = jsUndefined();
}
if (!encodingValue.isUndefined()) {
if (!encodingValue.isUndefined() && value.isString()) {
if (!encodingValue.isString()) return Bun::ERR::INVALID_ARG_TYPE(scope, lexicalGlobalObject, "encoding"_s, "string"_s, encodingValue);
encoding = parseEncoding(lexicalGlobalObject, scope, encodingValue);
RETURN_IF_EXCEPTION(scope, {});
}
// https://github.com/nodejs/node/blob/v22.9.0/lib/buffer.js#L1066-L1079
// https://github.com/nodejs/node/blob/v22.9.0/lib/buffer.js#L122
if (!offsetValue.isUndefined()) {
start = parseIndex(lexicalGlobalObject, scope, "start"_s, offsetValue, limit);
Bun::V::validateNumber(scope, lexicalGlobalObject, offsetValue, jsString(vm, String("offset"_s)), jsNumber(0), jsNumber(Bun::Buffer::kMaxLength));
RETURN_IF_EXCEPTION(scope, {});
offset = offsetValue.toLength(lexicalGlobalObject);
}
if (!lengthValue.isUndefined()) {
end = parseIndex(lexicalGlobalObject, scope, "end"_s, lengthValue, limit - start);
if (!endValue.isUndefined()) {
Bun::V::validateNumber(scope, lexicalGlobalObject, endValue, jsString(vm, String("end"_s)), jsNumber(0), jsNumber(limit));
RETURN_IF_EXCEPTION(scope, {});
end = endValue.toLength(lexicalGlobalObject);
}
if (start >= end) {
if (offset >= end) {
RELEASE_AND_RETURN(scope, JSValue::encode(castedThis));
}
if (UNLIKELY(end > limit)) {
throwNodeRangeError(lexicalGlobalObject, scope, "end out of range"_s);
return {};
}
if (value.isString()) {
auto startPtr = castedThis->typedVector() + start;
auto startPtr = castedThis->typedVector() + offset;
auto str_ = value.toWTFString(lexicalGlobalObject);
RETURN_IF_EXCEPTION(scope, {});
ZigString str = Zig::toZigString(str_);
if (str.len == 0) {
memset(startPtr, 0, end - start);
} else if (UNLIKELY(!Bun__Buffer_fill(&str, startPtr, end - start, encoding))) {
memset(startPtr, 0, end - offset);
} else if (UNLIKELY(!Bun__Buffer_fill(&str, startPtr, end - offset, encoding))) {
return Bun::ERR::INVALID_ARG_VALUE(scope, lexicalGlobalObject, "value"_s, value);
}
} else if (auto* view = JSC::jsDynamicCast<JSC::JSArrayBufferView*>(value)) {
auto* startPtr = castedThis->typedVector() + start;
auto* startPtr = castedThis->typedVector() + offset;
auto* head = startPtr;
size_t remain = end - start;
size_t remain = end - offset;
if (UNLIKELY(view->isDetached())) {
throwVMTypeError(lexicalGlobalObject, scope, "Uint8Array is detached"_s);
@@ -1218,11 +1275,12 @@ static inline JSC::EncodedJSValue jsBufferPrototypeFunction_fillBody(JSC::JSGlob
}
} else {
auto value_ = value.toInt32(lexicalGlobalObject) & 0xFF;
RETURN_IF_EXCEPTION(scope, {});
auto value_uint8 = static_cast<uint8_t>(value_);
RETURN_IF_EXCEPTION(scope, {});
auto startPtr = castedThis->typedVector() + start;
auto startPtr = castedThis->typedVector() + offset;
auto endPtr = castedThis->typedVector() + end;
memset(startPtr, value_uint8, endPtr - startPtr);
}
@@ -1481,6 +1539,9 @@ static inline JSC::EncodedJSValue jsBufferToString(JSC::VM& vm, JSC::JSGlobalObj
if (length > WTF::String::MaxLength) {
return Bun::ERR::STRING_TOO_LONG(scope, lexicalGlobalObject);
}
if (length > castedThis->byteLength()) {
length = castedThis->byteLength();
}
JSC::EncodedJSValue ret = 0;
@@ -1558,6 +1619,8 @@ bool inline parseArrayIndex(JSC::ThrowScope& scope, JSC::JSGlobalObject* globalO
return true;
}
// https://github.com/nodejs/node/blob/v22.9.0/lib/buffer.js#L834
// using byteLength and byte offsets here is intentional
static inline JSC::EncodedJSValue jsBufferPrototypeFunction_toStringBody(JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame, typename IDLOperation<JSArrayBufferView>::ClassParameter castedThis)
{
auto& vm = JSC::getVM(lexicalGlobalObject);
@@ -1584,25 +1647,30 @@ static inline JSC::EncodedJSValue jsBufferPrototypeFunction_toStringBody(JSC::JS
RETURN_IF_EXCEPTION(scope, {});
}
if (!arg2.isUndefined()) {
int32_t istart = arg2.toInt32(lexicalGlobalObject);
RETURN_IF_EXCEPTION(scope, {});
if (istart < 0) {
throwTypeError(lexicalGlobalObject, scope, "Start must be a positive integer"_s);
return {};
}
start = static_cast<uint32_t>(istart);
auto fstart = arg2.toNumber(lexicalGlobalObject);
RETURN_IF_EXCEPTION(scope, {});
if (fstart < 0) {
fstart = 0;
goto lstart;
}
if (fstart > byteLength) {
return JSC::JSValue::encode(JSC::jsEmptyString(vm));
}
start = static_cast<uint32_t>(fstart);
lstart:
if (!arg3.isUndefined()) {
// length is end
end = std::min(byteLength, static_cast<uint32_t>(arg3.toInt32(lexicalGlobalObject)));
auto lend = arg3.toLength(lexicalGlobalObject);
RETURN_IF_EXCEPTION(scope, {});
if (lend < byteLength) end = lend;
}
return jsBufferToString(vm, lexicalGlobalObject, castedThis, start, end > start ? end - start : 0, encoding);
if (end <= start)
return JSC::JSValue::encode(JSC::jsEmptyString(vm));
auto offset = start;
auto length = end > start ? end - start : 0;
return jsBufferToString(vm, lexicalGlobalObject, castedThis, offset, length, encoding);
}
// https://github.com/nodejs/node/blob/2eff28fb7a93d3f672f80b582f664a7c701569fb/src/node_buffer.cc#L544
@@ -1912,6 +1980,11 @@ JSC_DEFINE_HOST_FUNCTION(jsBufferConstructorFunction_concat, (JSGlobalObject * l
return jsBufferConstructorFunction_concatBody(lexicalGlobalObject, callFrame);
}
JSC_DEFINE_HOST_FUNCTION(jsBufferConstructorFunction_copyBytesFrom, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame))
{
return jsBufferConstructorFunction_copyBytesFromBody(lexicalGlobalObject, callFrame);
}
extern "C" JSC_DECLARE_JIT_OPERATION_WITHOUT_WTF_INTERNAL(jsBufferConstructorAllocWithoutTypeChecks, JSUint8Array*, (JSC::JSGlobalObject * lexicalGlobalObject, void* thisValue, int size));
extern "C" JSC_DECLARE_JIT_OPERATION_WITHOUT_WTF_INTERNAL(jsBufferConstructorAllocUnsafeWithoutTypeChecks, JSUint8Array*, (JSC::JSGlobalObject * lexicalGlobalObject, void* thisValue, int size));
extern "C" JSC_DECLARE_JIT_OPERATION_WITHOUT_WTF_INTERNAL(jsBufferConstructorAllocUnsafeSlowWithoutTypeChecks, JSUint8Array*, (JSC::JSGlobalObject * lexicalGlobalObject, void* thisValue, int size));
@@ -2228,6 +2301,7 @@ const ClassInfo JSBufferPrototype::s_info = {
byteLength jsBufferConstructorFunction_byteLength Function 2
compare jsBufferConstructorFunction_compare Function 2
concat jsBufferConstructorFunction_concat Function 2
copyBytesFrom jsBufferConstructorFunction_copyBytesFrom Function 1
from JSBuiltin Builtin|Function 1
isBuffer JSBuiltin Builtin|Function 1
isEncoding jsBufferConstructorFunction_isEncoding Function 1
@@ -2242,6 +2316,7 @@ void JSBufferConstructor::finishCreation(VM& vm, JSGlobalObject* globalObject, J
Base::finishCreation(vm, 3, "Buffer"_s, PropertyAdditionMode::WithoutStructureTransition);
putDirectWithoutTransition(vm, vm.propertyNames->prototype, prototype, PropertyAttribute::DontEnum | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly);
prototype->putDirect(vm, vm.propertyNames->speciesSymbol, this, PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly);
putDirectWithoutTransition(vm, Identifier::fromString(vm, "poolSize"_s), jsNumber(8192));
}
JSC::Structure* createBufferStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype)
@@ -2278,13 +2353,16 @@ static inline JSC::EncodedJSValue createJSBufferFromJS(JSC::JSGlobalObject* lexi
if (distinguishingArg.isAnyInt()) {
throwScope.release();
if (args.at(1).isString()) {
return Bun::ERR::INVALID_ARG_TYPE(throwScope, lexicalGlobalObject, "string"_s, "string"_s, distinguishingArg);
}
return JSBuffer__bufferFromLength(lexicalGlobalObject, distinguishingArg.asAnyInt());
} else if (distinguishingArg.isNumber()) {
double lengthDouble = distinguishingArg.toIntegerWithTruncation(lexicalGlobalObject);
if (UNLIKELY(lengthDouble < 0 || lengthDouble > MAX_ARRAY_BUFFER_SIZE || lengthDouble != lengthDouble)) {
return Bun::ERR::OUT_OF_RANGE(throwScope, lexicalGlobalObject, "size"_s, 0, MAX_ARRAY_BUFFER_SIZE, distinguishingArg);
}
return JSBuffer__bufferFromLength(lexicalGlobalObject, lengthDouble);
JSValue lengthValue = distinguishingArg;
Bun::V::validateNumber(throwScope, lexicalGlobalObject, lengthValue, jsString(vm, String("size"_s)), jsNumber(0), jsNumber(Bun::Buffer::kMaxLength));
RETURN_IF_EXCEPTION(throwScope, {});
size_t length = lengthValue.toLength(lexicalGlobalObject);
return JSBuffer__bufferFromLength(lexicalGlobalObject, length);
} else if (distinguishingArg.isUndefinedOrNull() || distinguishingArg.isBoolean()) {
auto arg_string = distinguishingArg.toWTFString(globalObject);
auto message = makeString("The first argument must be of type string or an instance of Buffer, ArrayBuffer, Array or an Array-like object. Received "_s, arg_string);

View File

@@ -39,6 +39,15 @@ namespace Bun {
std::optional<double> byteLength(JSC::JSString* str, WebCore::BufferEncodingType encoding);
namespace Buffer {
const size_t kMaxLength = MAX_ARRAY_BUFFER_SIZE;
const size_t kStringMaxLength = WTF::String::MaxLength;
const size_t MAX_LENGTH = MAX_ARRAY_BUFFER_SIZE;
const size_t MAX_STRING_LENGTH = WTF::String::MaxLength;
}
}
namespace WebCore {
@@ -55,4 +64,4 @@ JSC::JSObject* createBufferPrototype(JSC::VM&, JSC::JSGlobalObject*);
JSC::Structure* createBufferStructure(JSC::VM&, JSC::JSGlobalObject*, JSC::JSValue prototype);
JSC::JSObject* createBufferConstructor(JSC::VM&, JSC::JSGlobalObject*, JSC::JSObject* bufferPrototype);
}
}

View File

@@ -53,14 +53,17 @@ template<> JSString* convertEnumerationToJS(JSGlobalObject& lexicalGlobalObject,
}
// this function is mostly copied from node
template<> std::optional<BufferEncodingType> parseEnumeration<BufferEncodingType>(JSGlobalObject& lexicalGlobalObject, JSValue value)
template<> std::optional<BufferEncodingType> parseEnumeration<BufferEncodingType>(JSGlobalObject& lexicalGlobalObject, JSValue arg)
{
if (UNLIKELY(!arg.isString())) {
return std::nullopt;
}
return parseEnumeration2(lexicalGlobalObject, asString(arg)->getString(&lexicalGlobalObject));
}
std::optional<BufferEncodingType> parseEnumeration2(JSGlobalObject& lexicalGlobalObject, WTF::String encoding)
{
// caller must check if value is a string
JSC::JSString* str = asString(value);
if (UNLIKELY(!str))
return std::nullopt;
String encoding = str->value(&lexicalGlobalObject);
switch (encoding.length()) {
case 0: {
return BufferEncodingType::utf8;

View File

@@ -7,7 +7,8 @@ namespace WebCore {
String convertEnumerationToString(BufferEncodingType);
template<> JSC::JSString* convertEnumerationToJS(JSC::JSGlobalObject&, BufferEncodingType);
template<> std::optional<BufferEncodingType> parseEnumeration<BufferEncodingType>(JSC::JSGlobalObject&, JSC::JSValue);
template<> std::optional<BufferEncodingType> parseEnumeration<BufferEncodingType>(JSC::JSGlobalObject&, JSValue);
std::optional<BufferEncodingType> parseEnumeration2(JSC::JSGlobalObject&, WTF::String);
template<> WTF::ASCIILiteral expectedEnumerationValues<BufferEncodingType>();
} // namespace WebCore
} // namespace WebCore

View File

@@ -69,4 +69,4 @@ public:
bool tombstoned { false };
};
} // namespace Zig
} // namespace Zig

View File

@@ -26,4 +26,4 @@ public:
HashSet<Ref<JSC::DeferredWorkTimer::TicketData>> m_pendingTicketsOther;
};
}
}

View File

@@ -2,4 +2,4 @@ namespace Bun {
JSC::JSValue createJSCTestingHelpers(Zig::GlobalObject* global);
}
}

View File

@@ -8,4 +8,4 @@
namespace WebCore {
}
}

View File

@@ -35,4 +35,4 @@ JSClass* toJSDOMGlobalObject(JSC::VM& vm, JSC::JSValue value)
return nullptr;
}
}
}

View File

@@ -12,4 +12,4 @@ namespace Bun {
JSC::JSValue createEnvironmentVariablesMap(Zig::GlobalObject* globalObject);
}
}

View File

@@ -37,4 +37,4 @@ public:
bool isEmpty();
void drain(JSC::VM& vm, JSC::JSGlobalObject* globalObject);
};
}
}

View File

@@ -71,4 +71,4 @@ private:
JSC::WriteBarrier<JSC::JSFunction> m_wrappedFn;
};
}
}

View File

@@ -2,7 +2,7 @@
#include "ZigGlobalObject.h"
namespace Bun {
JSC::JSValue createAsyncHooksBinding(Zig::GlobalObject*);
}
}

View File

@@ -4,4 +4,4 @@ namespace Bun {
JSC::JSValue createNodeFetchInternalBinding(Zig::GlobalObject*);
}
}

View File

@@ -1,11 +1,11 @@
#include "config.h"
namespace Bun {
JSC_DECLARE_HOST_FUNCTION(jsHTTPAssignHeaders);
JSC_DECLARE_HOST_FUNCTION(jsHTTPGetHeader);
JSC_DECLARE_HOST_FUNCTION(jsHTTPSetHeader);
JSC::JSValue createNodeHTTPInternalBinding(Zig::GlobalObject*);
}
}

View File

@@ -2,7 +2,7 @@
#include "ZigGlobalObject.h"
namespace Bun {
JSC::JSValue createNodeTLSBinding(Zig::GlobalObject*);
}
}

View File

@@ -5,4 +5,4 @@ namespace Bun {
JSC::JSValue createNodeURLBinding(Zig::GlobalObject*);
} // namespace Bun
} // namespace Bun

View File

@@ -30,10 +30,13 @@ JSC_DEFINE_HOST_FUNCTION(jsFunction_validateInteger, (JSC::JSGlobalObject * glob
auto name = callFrame->argument(1);
auto min = callFrame->argument(2);
auto max = callFrame->argument(3);
return Bun::V::validateInteger(scope, globalObject, value, name, min, max);
}
JSC::EncodedJSValue V::validateInteger(JSC::ThrowScope& scope, JSC::JSGlobalObject* globalObject, JSC::JSValue value, JSC::JSValue name, JSC::JSValue min, JSC::JSValue max)
{
if (!value.isNumber()) return Bun::ERR::INVALID_ARG_TYPE(scope, globalObject, name, "number"_s, value);
if (min.isUndefined()) min = jsNumber(-9007199254740991); // Number.MIN_SAFE_INTEGER
if (max.isUndefined()) max = jsNumber(9007199254740991); // Number.MAX_SAFE_INTEGER
if (min.isUndefined()) min = jsDoubleNumber(JSC::minSafeInteger());
if (max.isUndefined()) max = jsDoubleNumber(JSC::maxSafeInteger());
auto value_num = value.asNumber();
auto min_num = min.toNumber(globalObject);

View File

@@ -26,6 +26,7 @@ JSC_DEFINE_HOST_FUNCTION(jsFunction_validateBuffer, (JSC::JSGlobalObject * globa
namespace V {
JSC::EncodedJSValue validateInteger(JSC::ThrowScope& scope, JSC::JSGlobalObject* globalObject, JSC::JSValue value, JSC::JSValue name, JSC::JSValue min, JSC::JSValue max);
JSC::EncodedJSValue validateNumber(JSC::ThrowScope& scope, JSC::JSGlobalObject* globalObject, JSC::JSValue value, JSC::JSValue name, JSC::JSValue min, JSC::JSValue max);
JSC::EncodedJSValue validateFiniteNumber(JSC::ThrowScope& scope, JSC::JSGlobalObject* globalObject, JSC::JSValue number, JSC::JSValue name);
JSC::EncodedJSValue validateString(JSC::ThrowScope& scope, JSC::JSGlobalObject* globalObject, JSValue value, JSValue name);

View File

@@ -2,7 +2,7 @@
#include "ZigGlobalObject.h"
namespace Bun {
JSC::JSValue createNodePathBinding(Zig::GlobalObject* globalObject);
} // namespace Bun

View File

@@ -43,11 +43,11 @@ using namespace JSC;
static JSValue processBindingConstantsGetOs(VM& vm, JSObject* bindingObject)
{
auto globalObject = bindingObject->globalObject();
auto osObj = JSC::constructEmptyObject(globalObject, globalObject->objectPrototype(), 1);
auto dlopenObj = JSC::constructEmptyObject(globalObject, globalObject->objectPrototype(), 1);
auto errnoObj = JSC::constructEmptyObject(globalObject, globalObject->objectPrototype(), 1);
auto signalsObj = JSC::constructEmptyObject(globalObject, globalObject->objectPrototype(), 1);
auto priorityObj = JSC::constructEmptyObject(globalObject, globalObject->objectPrototype(), 1);
auto osObj = JSC::constructEmptyObject(vm, globalObject->nullPrototypeObjectStructure());
auto dlopenObj = JSC::constructEmptyObject(vm, globalObject->nullPrototypeObjectStructure());
auto errnoObj = JSC::constructEmptyObject(vm, globalObject->nullPrototypeObjectStructure());
auto signalsObj = JSC::constructEmptyObject(vm, globalObject->nullPrototypeObjectStructure());
auto priorityObj = JSC::constructEmptyObject(vm, globalObject->nullPrototypeObjectStructure());
osObj->putDirect(vm, Identifier::fromString(vm, "UV_UDP_REUSEADDR"_s), jsNumber(4));
osObj->putDirect(vm, Identifier::fromString(vm, "dlopen"_s), dlopenObj);
osObj->putDirect(vm, Identifier::fromString(vm, "errno"_s), errnoObj);
@@ -602,7 +602,7 @@ static JSValue processBindingConstantsGetOs(VM& vm, JSObject* bindingObject)
static JSValue processBindingConstantsGetTrace(VM& vm, JSObject* bindingObject)
{
auto globalObject = bindingObject->globalObject();
auto object = JSC::constructEmptyObject(globalObject, globalObject->objectPrototype(), 26);
auto object = JSC::constructEmptyObject(vm, globalObject->nullPrototypeObjectStructure());
object->putDirect(vm, PropertyName(Identifier::fromString(vm, "TRACE_EVENT_PHASE_BEGIN"_s)), jsNumber(66));
object->putDirect(vm, PropertyName(Identifier::fromString(vm, "TRACE_EVENT_PHASE_END"_s)), jsNumber(69));
object->putDirect(vm, PropertyName(Identifier::fromString(vm, "TRACE_EVENT_PHASE_COMPLETE"_s)), jsNumber(88));
@@ -635,7 +635,7 @@ static JSValue processBindingConstantsGetTrace(VM& vm, JSObject* bindingObject)
static JSValue processBindingConstantsGetFs(VM& vm, JSObject* bindingObject)
{
auto globalObject = bindingObject->globalObject();
auto object = JSC::constructEmptyObject(globalObject, globalObject->objectPrototype(), 26);
auto object = JSC::constructEmptyObject(vm, globalObject->nullPrototypeObjectStructure());
object->putDirect(vm, PropertyName(Identifier::fromString(vm, "UV_FS_SYMLINK_DIR"_s)), jsNumber(1));
object->putDirect(vm, PropertyName(Identifier::fromString(vm, "UV_FS_SYMLINK_JUNCTION"_s)), jsNumber(2));
object->putDirect(vm, PropertyName(Identifier::fromString(vm, "O_RDONLY"_s)), jsNumber(O_RDONLY));
@@ -775,7 +775,7 @@ static JSValue processBindingConstantsGetFs(VM& vm, JSObject* bindingObject)
static JSValue processBindingConstantsGetCrypto(VM& vm, JSObject* bindingObject)
{
auto globalObject = bindingObject->globalObject();
auto object = JSC::constructEmptyObject(globalObject, globalObject->objectPrototype());
auto object = JSC::constructEmptyObject(vm, globalObject->nullPrototypeObjectStructure());
#ifdef OPENSSL_VERSION_NUMBER
object->putDirect(vm, PropertyName(Identifier::fromString(vm, "OPENSSL_VERSION_NUMBER"_s)), jsNumber(OPENSSL_VERSION_NUMBER));
#endif
@@ -978,7 +978,7 @@ static JSValue processBindingConstantsGetCrypto(VM& vm, JSObject* bindingObject)
static JSValue processBindingConstantsGetZlib(VM& vm, JSObject* bindingObject)
{
auto globalObject = bindingObject->globalObject();
auto object = JSC::constructEmptyObject(globalObject, globalObject->objectPrototype());
auto object = JSC::constructEmptyObject(vm, globalObject->nullPrototypeObjectStructure());
object->putDirect(vm, PropertyName(Identifier::fromString(vm, "Z_NO_FLUSH"_s)), jsNumber(Z_NO_FLUSH));
object->putDirect(vm, PropertyName(Identifier::fromString(vm, "Z_PARTIAL_FLUSH"_s)), jsNumber(Z_PARTIAL_FLUSH));
object->putDirect(vm, PropertyName(Identifier::fromString(vm, "Z_SYNC_FLUSH"_s)), jsNumber(Z_SYNC_FLUSH));

View File

@@ -15,4 +15,4 @@ JSC::JSValue createNodeTTYWrapObject(JSC::JSGlobalObject* globalObject);
JSC_DECLARE_HOST_FUNCTION(Process_functionInternalGetWindowSize);
}
}

View File

@@ -10,4 +10,4 @@ JSC_DECLARE_HOST_FUNCTION(jsGetErrorMap);
JSC::JSObject* create(JSC::VM& vm, JSC::JSGlobalObject* globalObject);
} // namespace ProcessBindingUV
} // namespace Bun
} // namespace Bun

View File

@@ -206,4 +206,4 @@ public:
ScriptExecutionContext* executionContext(JSC::JSGlobalObject*);
}
}

View File

@@ -14,4 +14,4 @@ enum SinkID : uint8_t {
static constexpr unsigned numberOfSinkIDs
= 7;
}
}

View File

@@ -31,4 +31,4 @@ public:
JSC::Strong<JSC::Unknown> m_cell;
};
}
}

View File

@@ -3,4 +3,4 @@ namespace Bun {
JSC::JSValue createUndiciInternalBinding(Zig::GlobalObject* globalObject);
}
}

View File

@@ -4,4 +4,4 @@ namespace Bun {
JSC::Structure* createUtilInspectOptionsStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject);
}
}

View File

@@ -172,6 +172,7 @@ using namespace Bun;
BUN_DECLARE_HOST_FUNCTION(Bun__NodeUtil__jsParseArgs);
BUN_DECLARE_HOST_FUNCTION(BUN__HTTP2__getUnpackedSettings);
BUN_DECLARE_HOST_FUNCTION(BUN__HTTP2_getPackedSettings);
BUN_DECLARE_HOST_FUNCTION(BUN__HTTP2_assertSettings);
using JSGlobalObject = JSC::JSGlobalObject;
using Exception = JSC::Exception;
@@ -276,27 +277,10 @@ extern "C" void* Bun__getVM();
extern "C" void Bun__setDefaultGlobalObject(Zig::GlobalObject* globalObject);
// Error.captureStackTrace may cause computeErrorInfo to be called twice
// Rather than figure out the plumbing in JSC, we just skip the next call
// TODO: thread_local for workers
static bool skipNextComputeErrorInfo = false;
static JSValue formatStackTraceToJSValue(JSC::VM& vm, Zig::GlobalObject* globalObject, JSC::JSGlobalObject* lexicalGlobalObject, JSC::JSObject* errorObject, JSC::JSArray* callSites, JSValue prepareStackTrace)
static JSValue formatStackTraceToJSValue(JSC::VM& vm, Zig::GlobalObject* globalObject, JSC::JSGlobalObject* lexicalGlobalObject, JSC::JSObject* errorObject, JSC::JSArray* callSites)
{
auto scope = DECLARE_THROW_SCOPE(vm);
auto* errorConstructor = lexicalGlobalObject->m_errorStructure.constructor(globalObject);
if (!prepareStackTrace) {
if (lexicalGlobalObject->inherits<Zig::GlobalObject>()) {
if (auto prepare = globalObject->m_errorConstructorPrepareStackTraceValue.get()) {
prepareStackTrace = prepare;
}
} else {
prepareStackTrace = errorConstructor->getIfPropertyExists(lexicalGlobalObject, JSC::Identifier::fromString(vm, "prepareStackTrace"_s));
}
}
// default formatting
size_t framesCount = callSites->length();
@@ -322,21 +306,20 @@ static JSValue formatStackTraceToJSValue(JSC::VM& vm, Zig::GlobalObject* globalO
CallSite* callSite = JSC::jsDynamicCast<CallSite*>(callSiteValue);
sb.append(" at "_s);
callSite->formatAsString(vm, lexicalGlobalObject, sb);
RETURN_IF_EXCEPTION(scope, {});
if (i != framesCount - 1) {
sb.append("\n"_s);
}
}
bool originalSkipNextComputeErrorInfo = skipNextComputeErrorInfo;
skipNextComputeErrorInfo = true;
if (errorObject->hasProperty(lexicalGlobalObject, vm.propertyNames->stack)) {
skipNextComputeErrorInfo = true;
errorObject->deleteProperty(lexicalGlobalObject, vm.propertyNames->stack);
}
return jsString(vm, sb.toString());
}
skipNextComputeErrorInfo = originalSkipNextComputeErrorInfo;
JSValue stackStringValue = jsString(vm, sb.toString());
static JSValue formatStackTraceToJSValue(JSC::VM& vm, Zig::GlobalObject* globalObject, JSC::JSGlobalObject* lexicalGlobalObject, JSC::JSObject* errorObject, JSC::JSArray* callSites, JSValue prepareStackTrace)
{
auto scope = DECLARE_THROW_SCOPE(vm);
auto stackStringValue = formatStackTraceToJSValue(vm, globalObject, lexicalGlobalObject, errorObject, callSites);
RETURN_IF_EXCEPTION(scope, {});
if (prepareStackTrace && prepareStackTrace.isObject()) {
JSC::CallData prepareStackTraceCallData = JSC::getCallData(prepareStackTrace);
@@ -355,10 +338,10 @@ static JSValue formatStackTraceToJSValue(JSC::VM& vm, Zig::GlobalObject* globalO
JSC::ProfilingReason::Other,
prepareStackTrace,
prepareStackTraceCallData,
errorConstructor,
lexicalGlobalObject->m_errorStructure.constructor(globalObject),
arguments);
RETURN_IF_EXCEPTION(scope, {});
RETURN_IF_EXCEPTION(scope, stackStringValue);
if (result.isUndefinedOrNull()) {
result = jsUndefined();
@@ -371,6 +354,26 @@ static JSValue formatStackTraceToJSValue(JSC::VM& vm, Zig::GlobalObject* globalO
return stackStringValue;
}
static JSValue formatStackTraceToJSValueWithoutPrepareStackTrace(JSC::VM& vm, Zig::GlobalObject* globalObject, JSC::JSGlobalObject* lexicalGlobalObject, JSC::JSObject* errorObject, JSC::JSArray* callSites)
{
JSValue prepareStackTrace = {};
if (lexicalGlobalObject->inherits<Zig::GlobalObject>()) {
if (auto prepare = globalObject->m_errorConstructorPrepareStackTraceValue.get()) {
prepareStackTrace = prepare;
}
} else {
auto scope = DECLARE_CATCH_SCOPE(vm);
auto* errorConstructor = lexicalGlobalObject->m_errorStructure.constructor(globalObject);
prepareStackTrace = errorConstructor->getIfPropertyExists(lexicalGlobalObject, JSC::Identifier::fromString(vm, "prepareStackTrace"_s));
if (scope.exception()) {
scope.clearException();
}
}
return formatStackTraceToJSValue(vm, globalObject, lexicalGlobalObject, errorObject, callSites, prepareStackTrace);
}
WTF::String Bun::formatStackTrace(
JSC::VM& vm,
Zig::GlobalObject* globalObject,
@@ -467,12 +470,13 @@ WTF::String Bun::formatStackTrace(
for (size_t i = 0; i < framesCount; i++) {
StackFrame& frame = stackTrace.at(i);
WTF::String functionName;
bool isBuiltinFunction = false;
sb.append(" at "_s);
WTF::String functionName;
if (auto codeblock = frame.codeBlock()) {
if (codeblock->isConstructor()) {
sb.append("new "_s);
}
@@ -484,11 +488,25 @@ WTF::String Bun::formatStackTrace(
case JSC::CodeType::FunctionCode:
case JSC::CodeType::EvalCode: {
if (auto* callee = frame.callee()) {
if (callee->isObject()) {
JSValue functionNameValue = callee->getObject()->getDirect(vm, vm.propertyNames->name);
if (auto* object = callee->getObject()) {
JSValue functionNameValue = object->getDirect(vm, vm.propertyNames->name);
if (functionNameValue && functionNameValue.isString()) {
functionName = functionNameValue.toWTFString(lexicalGlobalObject);
}
if (functionName.isEmpty()) {
auto catchScope = DECLARE_CATCH_SCOPE(vm);
functionName = JSC::getCalculatedDisplayName(vm, object);
if (catchScope.exception()) {
catchScope.clearException();
}
}
if (auto* unlinkedCodeBlock = codeblock->unlinkedCodeBlock()) {
if (unlinkedCodeBlock->isBuiltinFunction()) {
isBuiltinFunction = true;
}
}
}
}
break;
@@ -544,8 +562,10 @@ WTF::String Bun::formatStackTrace(
}
}
// If it's not a Zig::GlobalObject, don't bother source-mapping it.
if (globalObject == lexicalGlobalObject && globalObject) {
bool isDefinitelyNotRunninginNodeVMGlobalObject = (globalObject == lexicalGlobalObject && globalObject);
bool isDefaultGlobalObjectInAFinalizer = (globalObject && !lexicalGlobalObject && !errorInstance);
if (isDefinitelyNotRunninginNodeVMGlobalObject || isDefaultGlobalObjectInAFinalizer) {
// https://github.com/oven-sh/bun/issues/3595
if (!sourceURLForFrame.isEmpty()) {
remappedFrame.source_url = Bun::toStringRef(sourceURLForFrame);
@@ -572,7 +592,15 @@ WTF::String Bun::formatStackTrace(
}
sb.append(" ("_s);
sb.append(sourceURLForFrame);
if (sourceURLForFrame.isEmpty()) {
if (isBuiltinFunction) {
sb.append("native"_s);
} else {
sb.append("unknown"_s);
}
} else {
sb.append(sourceURLForFrame);
}
sb.append(":"_s);
sb.append(remappedFrame.position.line().oneBasedInt());
sb.append(":"_s);
@@ -623,16 +651,14 @@ static String computeErrorInfoWithoutPrepareStackTrace(
return Bun::formatStackTrace(vm, globalObject, lexicalGlobalObject, name, message, line, column, sourceURL, stackTrace, errorInstance);
}
static String computeErrorInfoWithPrepareStackTrace(JSC::VM& vm, Zig::GlobalObject* globalObject, JSC::JSGlobalObject* lexicalGlobalObject, Vector<StackFrame>& stackFrames, OrdinalNumber& line, OrdinalNumber& column, String& sourceURL, JSObject* errorObject, JSObject* prepareStackTrace)
static JSValue computeErrorInfoWithPrepareStackTrace(JSC::VM& vm, Zig::GlobalObject* globalObject, JSC::JSGlobalObject* lexicalGlobalObject, Vector<StackFrame>& stackFrames, OrdinalNumber& line, OrdinalNumber& column, String& sourceURL, JSObject* errorObject, JSObject* prepareStackTrace)
{
auto scope = DECLARE_THROW_SCOPE(vm);
JSCStackTrace stackTrace = JSCStackTrace::fromExisting(vm, stackFrames);
// Note: we cannot use tryCreateUninitializedRestricted here because we cannot allocate memory inside initializeIndex()
JSC::JSArray* callSites = JSC::JSArray::create(vm,
globalObject->arrayStructureForIndexingTypeDuringAllocation(JSC::ArrayWithContiguous),
stackTrace.size());
MarkedArgumentBuffer callSites;
// Create the call sites (one per frame)
GlobalObject::createCallSitesFromFrames(globalObject, lexicalGlobalObject, stackTrace, callSites);
@@ -657,7 +683,7 @@ static String computeErrorInfoWithPrepareStackTrace(JSC::VM& vm, Zig::GlobalObje
Bun__remapStackFramePositions(globalObject, remappedFrames, framesCount);
for (size_t i = 0; i < framesCount; i++) {
JSC::JSValue callSiteValue = callSites->getIndex(lexicalGlobalObject, i);
JSC::JSValue callSiteValue = callSites.at(i);
CallSite* callSite = JSC::jsDynamicCast<CallSite*>(callSiteValue);
if (remappedFrames[i].remapped) {
callSite->setColumnNumber(remappedFrames[i].position.column());
@@ -666,64 +692,85 @@ static String computeErrorInfoWithPrepareStackTrace(JSC::VM& vm, Zig::GlobalObje
}
}
JSValue value = formatStackTraceToJSValue(vm, jsDynamicCast<Zig::GlobalObject*>(lexicalGlobalObject), lexicalGlobalObject, errorObject, callSites, prepareStackTrace);
JSArray* callSitesArray = JSC::constructArray(globalObject, globalObject->arrayStructureForIndexingTypeDuringAllocation(JSC::ArrayWithContiguous), callSites);
RETURN_IF_EXCEPTION(scope, String());
if (errorObject && !value.isEmpty()) {
errorObject->putDirect(vm, vm.propertyNames->stack, value, 0);
}
if (value.isString()) {
return value.toWTFString(lexicalGlobalObject);
}
return String();
return formatStackTraceToJSValue(vm, globalObject, lexicalGlobalObject, errorObject, callSitesArray, prepareStackTrace);
}
static String computeErrorInfo(JSC::VM& vm, Vector<StackFrame>& stackTrace, OrdinalNumber& line, OrdinalNumber& column, String& sourceURL, JSObject* errorInstance)
static String computeErrorInfoToString(JSC::VM& vm, Vector<StackFrame>& stackTrace, OrdinalNumber& line, OrdinalNumber& column, String& sourceURL)
{
if (skipNextComputeErrorInfo) {
return String();
}
Zig::GlobalObject* globalObject = nullptr;
JSC::JSGlobalObject* lexicalGlobalObject = nullptr;
if (errorInstance) {
lexicalGlobalObject = errorInstance->globalObject();
globalObject = jsDynamicCast<Zig::GlobalObject*>(lexicalGlobalObject);
return computeErrorInfoWithoutPrepareStackTrace(vm, globalObject, lexicalGlobalObject, stackTrace, line, column, sourceURL, nullptr);
}
// Error.prepareStackTrace - https://v8.dev/docs/stack-trace-api#customizing-stack-traces
if (!globalObject) {
// node:vm will use a different JSGlobalObject
globalObject = defaultGlobalObject();
static JSValue computeErrorInfoToJSValueWithoutSkipping(JSC::VM& vm, Vector<StackFrame>& stackTrace, OrdinalNumber& line, OrdinalNumber& column, String& sourceURL, JSObject* errorInstance)
{
Zig::GlobalObject* globalObject = nullptr;
JSC::JSGlobalObject* lexicalGlobalObject = nullptr;
lexicalGlobalObject = errorInstance->globalObject();
globalObject = jsDynamicCast<Zig::GlobalObject*>(lexicalGlobalObject);
// Error.prepareStackTrace - https://v8.dev/docs/stack-trace-api#customizing-stack-traces
if (!globalObject) {
// node:vm will use a different JSGlobalObject
globalObject = defaultGlobalObject();
if (!globalObject->isInsideErrorPrepareStackTraceCallback) {
auto* errorConstructor = lexicalGlobalObject->m_errorStructure.constructor(lexicalGlobalObject);
if (JSValue prepareStackTrace = errorConstructor->getIfPropertyExists(lexicalGlobalObject, Identifier::fromString(vm, "prepareStackTrace"_s))) {
if (prepareStackTrace.isCell() && prepareStackTrace.isObject() && prepareStackTrace.isCallable()) {
return computeErrorInfoWithPrepareStackTrace(vm, globalObject, lexicalGlobalObject, stackTrace, line, column, sourceURL, errorInstance, prepareStackTrace.getObject());
globalObject->isInsideErrorPrepareStackTraceCallback = true;
auto result = computeErrorInfoWithPrepareStackTrace(vm, globalObject, lexicalGlobalObject, stackTrace, line, column, sourceURL, errorInstance, prepareStackTrace.getObject());
globalObject->isInsideErrorPrepareStackTraceCallback = false;
return result;
}
}
} else {
if (JSValue prepareStackTrace = globalObject->m_errorConstructorPrepareStackTraceValue.get()) {
if (prepareStackTrace.isCell() && prepareStackTrace.isObject() && prepareStackTrace.isCallable()) {
return computeErrorInfoWithPrepareStackTrace(vm, globalObject, lexicalGlobalObject, stackTrace, line, column, sourceURL, errorInstance, prepareStackTrace.getObject());
}
} else if (!globalObject->isInsideErrorPrepareStackTraceCallback) {
if (JSValue prepareStackTrace = globalObject->m_errorConstructorPrepareStackTraceValue.get()) {
if (prepareStackTrace) {
if (prepareStackTrace.isCallable()) {
globalObject->isInsideErrorPrepareStackTraceCallback = true;
auto result = computeErrorInfoWithPrepareStackTrace(vm, globalObject, lexicalGlobalObject, stackTrace, line, column, sourceURL, errorInstance, prepareStackTrace.getObject());
globalObject->isInsideErrorPrepareStackTraceCallback = false;
return result;
}
}
}
}
return computeErrorInfoWithoutPrepareStackTrace(vm, globalObject, lexicalGlobalObject, stackTrace, line, column, sourceURL, errorInstance);
String result = computeErrorInfoWithoutPrepareStackTrace(vm, globalObject, lexicalGlobalObject, stackTrace, line, column, sourceURL, errorInstance);
return jsString(vm, result);
}
static JSValue computeErrorInfoToJSValue(JSC::VM& vm, Vector<StackFrame>& stackTrace, OrdinalNumber& line, OrdinalNumber& column, String& sourceURL, JSObject* errorInstance)
{
return computeErrorInfoToJSValueWithoutSkipping(vm, stackTrace, line, column, sourceURL, errorInstance);
}
// TODO: @paperdave: remove this wrapper and make the WTF::Function from JavaScriptCore expect OrdinalNumber instead of unsigned.
static String computeErrorInfoWrapper(JSC::VM& vm, Vector<StackFrame>& stackTrace, unsigned int& line_in, unsigned int& column_in, String& sourceURL, JSObject* errorInstance)
static String computeErrorInfoWrapperToString(JSC::VM& vm, Vector<StackFrame>& stackTrace, unsigned int& line_in, unsigned int& column_in, String& sourceURL)
{
OrdinalNumber line = OrdinalNumber::fromOneBasedInt(line_in);
OrdinalNumber column = OrdinalNumber::fromOneBasedInt(column_in);
WTF::String result = computeErrorInfo(vm, stackTrace, line, column, sourceURL, errorInstance);
WTF::String result = computeErrorInfoToString(vm, stackTrace, line, column, sourceURL);
line_in = line.oneBasedInt();
column_in = column.oneBasedInt();
return result;
}
static JSValue computeErrorInfoWrapperToJSValue(JSC::VM& vm, Vector<StackFrame>& stackTrace, unsigned int& line_in, unsigned int& column_in, String& sourceURL, JSObject* errorInstance)
{
OrdinalNumber line = OrdinalNumber::fromOneBasedInt(line_in);
OrdinalNumber column = OrdinalNumber::fromOneBasedInt(column_in);
JSValue result = computeErrorInfoToJSValue(vm, stackTrace, line, column, sourceURL, errorInstance);
line_in = line.oneBasedInt();
column_in = column.oneBasedInt();
@@ -820,7 +867,8 @@ extern "C" JSC__JSGlobalObject* Zig__GlobalObject__create(void* console_client,
Bun__setDefaultGlobalObject(globalObject);
JSC::gcProtect(globalObject);
vm.setOnComputeErrorInfo(computeErrorInfoWrapper);
vm.setOnComputeErrorInfo(computeErrorInfoWrapperToString);
vm.setOnComputeErrorInfoJSValue(computeErrorInfoWrapperToJSValue);
vm.setOnEachMicrotaskTick([](JSC::VM& vm) -> void {
auto* globalObject = defaultGlobalObject();
if (auto nextTickQueue = globalObject->m_nextTickQueue.get()) {
@@ -2528,7 +2576,7 @@ JSC_DEFINE_HOST_FUNCTION(jsFunctionPerformMicrotaskVariadic, (JSGlobalObject * g
return JSValue::encode(jsUndefined());
}
void GlobalObject::createCallSitesFromFrames(Zig::GlobalObject* globalObject, JSC::JSGlobalObject* lexicalGlobalObject, JSCStackTrace& stackTrace, JSC::JSArray* callSites)
void GlobalObject::createCallSitesFromFrames(Zig::GlobalObject* globalObject, JSC::JSGlobalObject* lexicalGlobalObject, JSCStackTrace& stackTrace, MarkedArgumentBuffer& callSites)
{
/* From v8's "Stack Trace API" (https://github.com/v8/v8/wiki/Stack-Trace-API):
* "To maintain restrictions imposed on strict mode functions, frames that have a
@@ -2543,20 +2591,12 @@ void GlobalObject::createCallSitesFromFrames(Zig::GlobalObject* globalObject, JS
for (size_t i = 0; i < framesCount; i++) {
CallSite* callSite = CallSite::create(lexicalGlobalObject, callSiteStructure, stackTrace.at(i), encounteredStrictFrame);
callSites->putDirectIndex(lexicalGlobalObject, i, callSite);
if (!encounteredStrictFrame) {
encounteredStrictFrame = callSite->isStrict();
}
}
}
void GlobalObject::formatStackTrace(JSC::VM& vm, JSC::JSGlobalObject* lexicalGlobalObject, JSC::JSObject* errorObject, JSC::JSArray* callSites, JSValue prepareStackTrace)
{
JSValue stackTraceValue = formatStackTraceToJSValue(vm, this, lexicalGlobalObject, errorObject, callSites, prepareStackTrace);
if (!stackTraceValue.isEmpty()) {
errorObject->putDirect(vm, vm.propertyNames->stack, stackTraceValue, 0);
callSites.append(callSite);
}
}
@@ -2606,6 +2646,44 @@ JSC_DEFINE_HOST_FUNCTION(jsFunctionDefaultErrorPrepareStackTrace, (JSGlobalObjec
return JSC::JSValue::encode(result);
}
JSC_DEFINE_CUSTOM_GETTER(errorInstanceLazyStackCustomGetter, (JSGlobalObject * globalObject, JSC::EncodedJSValue thisValue, PropertyName))
{
auto& vm = globalObject->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
auto* errorObject = jsDynamicCast<ErrorInstance*>(JSValue::decode(thisValue));
// This shouldn't be possible.
if (!errorObject) {
return JSValue::encode(jsUndefined());
}
OrdinalNumber line;
OrdinalNumber column;
String sourceURL;
auto stackTrace = errorObject->stackTrace();
if (stackTrace == nullptr) {
return JSValue::encode(jsUndefined());
}
JSValue result = computeErrorInfoToJSValue(vm, *stackTrace, line, column, sourceURL, errorObject);
stackTrace->clear();
errorObject->setStackFrames(vm, {});
RETURN_IF_EXCEPTION(scope, {});
errorObject->putDirect(vm, vm.propertyNames->stack, result, 0);
return JSValue::encode(result);
}
JSC_DEFINE_CUSTOM_SETTER(errorInstanceLazyStackCustomSetter, (JSGlobalObject * globalObject, JSC::EncodedJSValue thisValue, JSC::EncodedJSValue value, PropertyName))
{
auto& vm = globalObject->vm();
JSValue decodedValue = JSValue::decode(thisValue);
if (auto* object = decodedValue.getObject()) {
object->putDirect(vm, vm.propertyNames->stack, JSValue::decode(value), 0);
}
return true;
}
JSC_DEFINE_HOST_FUNCTION(errorConstructorFuncCaptureStackTrace, (JSC::JSGlobalObject * lexicalGlobalObject, JSC::CallFrame* callFrame))
{
GlobalObject* globalObject = reinterpret_cast<GlobalObject*>(lexicalGlobalObject);
@@ -2625,56 +2703,30 @@ JSC_DEFINE_HOST_FUNCTION(errorConstructorFuncCaptureStackTrace, (JSC::JSGlobalOb
stackTraceLimit = DEFAULT_ERROR_STACK_TRACE_LIMIT;
}
JSCStackTrace stackTrace = JSCStackTrace::captureCurrentJSStackTrace(globalObject, callFrame, stackTraceLimit, caller);
WTF::Vector<JSC::StackFrame> stackTrace;
JSCStackTrace::getFramesForCaller(vm, callFrame, errorObject, caller, stackTrace, stackTraceLimit);
// Note: we cannot use tryCreateUninitializedRestricted here because we cannot allocate memory inside initializeIndex()
JSC::JSArray* callSites = JSC::JSArray::create(vm,
globalObject->arrayStructureForIndexingTypeDuringAllocation(JSC::ArrayWithContiguous),
stackTrace.size());
// Create the call sites (one per frame)
GlobalObject::createCallSitesFromFrames(globalObject, lexicalGlobalObject, stackTrace, callSites);
/* Format the stack trace.
* Note that v8 won't actually format the stack trace here, but will create a "stack" accessor
* on the error object, which will format the stack trace on the first access. For now, since
* we're not being used internally by JSC, we can assume callers of Error.captureStackTrace in
* node are interested in the (formatted) stack. */
size_t framesCount = stackTrace.size();
ZigStackFrame remappedFrames[64];
framesCount = framesCount > 64 ? 64 : framesCount;
for (int i = 0; i < framesCount; i++) {
memset(remappedFrames + i, 0, sizeof(ZigStackFrame));
remappedFrames[i].source_url = Bun::toStringRef(lexicalGlobalObject, stackTrace.at(i).sourceURL());
if (JSCStackFrame::SourcePositions* sourcePositions = stackTrace.at(i).getSourcePositions()) {
remappedFrames[i].position.line_zero_based = sourcePositions->line.zeroBasedInt();
remappedFrames[i].position.column_zero_based = sourcePositions->column.zeroBasedInt();
} else {
remappedFrames[i].position.line_zero_based = -1;
remappedFrames[i].position.column_zero_based = -1;
if (auto* instance = jsDynamicCast<JSC::ErrorInstance*>(errorObject)) {
instance->setStackFrames(vm, WTFMove(stackTrace));
if (instance->hasMaterializedErrorInfo()) {
const auto& propertyName = vm.propertyNames->stack;
VM::DeletePropertyModeScope scope(vm, VM::DeletePropertyMode::IgnoreConfigurable);
DeletePropertySlot slot;
JSObject::deleteProperty(instance, globalObject, propertyName, slot);
if (auto* zigGlobalObject = jsDynamicCast<Zig::GlobalObject*>(globalObject)) {
instance->putDirectCustomAccessor(vm, vm.propertyNames->stack, zigGlobalObject->m_lazyStackCustomGetterSetter.get(zigGlobalObject), JSC::PropertyAttribute::CustomAccessor | 0);
} else {
instance->putDirectCustomAccessor(vm, vm.propertyNames->stack, CustomGetterSetter::create(vm, errorInstanceLazyStackCustomGetter, errorInstanceLazyStackCustomSetter), JSC::PropertyAttribute::CustomAccessor | 0);
}
}
} else {
OrdinalNumber line;
OrdinalNumber column;
String sourceURL;
JSValue result = computeErrorInfoToJSValue(vm, stackTrace, line, column, sourceURL, errorObject);
errorObject->putDirect(vm, vm.propertyNames->stack, result, 0);
}
// remap line and column start to original source
// XXX: this function does not fully populate the fields of ZigStackFrame,
// be careful reading the fields below.
Bun__remapStackFramePositions(lexicalGlobalObject, remappedFrames, framesCount);
// write the remapped lines back to the CallSites
for (size_t i = 0; i < framesCount; i++) {
JSC::JSValue callSiteValue = callSites->getIndex(lexicalGlobalObject, i);
CallSite* callSite = JSC::jsDynamicCast<CallSite*>(callSiteValue);
if (remappedFrames[i].remapped) {
callSite->setColumnNumber(remappedFrames[i].position.column());
callSite->setLineNumber(remappedFrames[i].position.line());
}
}
globalObject->formatStackTrace(vm, lexicalGlobalObject, errorObject, callSites, JSC::JSValue());
RETURN_IF_EXCEPTION(scope, {});
return JSC::JSValue::encode(JSC::jsUndefined());
}
@@ -2686,9 +2738,15 @@ void GlobalObject::finishCreation(VM& vm)
ASSERT(inherits(info()));
m_commonStrings.initialize();
m_http2_commongStrings.initialize();
Bun::addNodeModuleConstructorProperties(vm, this);
m_lazyStackCustomGetterSetter.initLater(
[](const Initializer<CustomGetterSetter>& init) {
init.set(CustomGetterSetter::create(init.vm, errorInstanceLazyStackCustomGetter, errorInstanceLazyStackCustomSetter));
});
m_JSDOMFileConstructor.initLater(
[](const Initializer<JSObject>& init) {
JSObject* fileConstructor = Bun::createJSDOMFileConstructor(init.vm, init.owner);
@@ -3275,30 +3333,6 @@ JSC_DEFINE_HOST_FUNCTION(functionSetImmediate,
return Bun__Timer__setImmediate(globalObject, JSC::JSValue::encode(job), JSValue::encode(arguments));
}
JSValue getEventSourceConstructor(VM& vm, JSObject* thisObject)
{
auto globalObject = jsCast<Zig::GlobalObject*>(thisObject);
auto scope = DECLARE_THROW_SCOPE(vm);
JSC::JSFunction* getSourceEvent = JSC::JSFunction::create(vm, globalObject, eventSourceGetEventSourceCodeGenerator(vm), globalObject);
RETURN_IF_EXCEPTION(scope, {});
JSC::MarkedArgumentBuffer args;
JSC::CallData callData = JSC::getCallData(getSourceEvent);
NakedPtr<JSC::Exception> returnedException = nullptr;
auto result = JSC::call(globalObject, getSourceEvent, callData, globalObject->globalThis(), args, returnedException);
RETURN_IF_EXCEPTION(scope, {});
if (returnedException) {
throwException(globalObject, scope, returnedException.get());
return jsUndefined();
}
RELEASE_AND_RETURN(scope, result);
}
// `console.Console` or `import { Console } from 'console';`
JSC_DEFINE_CUSTOM_GETTER(getConsoleConstructor, (JSGlobalObject * globalObject, EncodedJSValue thisValue, PropertyName property))
{
@@ -3429,6 +3463,7 @@ JSValue GlobalObject_getGlobalThis(VM& vm, JSObject* globalObject)
void GlobalObject::addBuiltinGlobals(JSC::VM& vm)
{
auto scope = DECLARE_CATCH_SCOPE(vm);
m_builtinInternalFunctions.initialize(*this);
auto clientData = WebCore::clientData(vm);
@@ -3545,6 +3580,8 @@ void GlobalObject::addBuiltinGlobals(JSC::VM& vm)
consoleObject->putDirectCustomAccessor(vm, Identifier::fromString(vm, "Console"_s), CustomGetterSetter::create(vm, getConsoleConstructor, nullptr), PropertyAttribute::CustomValue | 0);
consoleObject->putDirectCustomAccessor(vm, Identifier::fromString(vm, "_stdout"_s), CustomGetterSetter::create(vm, getConsoleStdout, nullptr), PropertyAttribute::DontEnum | PropertyAttribute::CustomValue | 0);
consoleObject->putDirectCustomAccessor(vm, Identifier::fromString(vm, "_stderr"_s), CustomGetterSetter::create(vm, getConsoleStderr, nullptr), PropertyAttribute::DontEnum | PropertyAttribute::CustomValue | 0);
scope.assertNoException();
}
extern "C" bool JSC__JSGlobalObject__startRemoteInspector(JSC__JSGlobalObject* globalObject, unsigned char* host, uint16_t arg1)
@@ -3575,6 +3612,15 @@ extern "C" void JSC__JSGlobalObject__drainMicrotasks(Zig::GlobalObject* globalOb
globalObject->drainMicrotasks();
}
extern "C" EncodedJSValue JSC__JSGlobalObject__getHTTP2CommonString(Zig::GlobalObject* globalObject, uint32_t hpack_index)
{
auto value = globalObject->http2CommonStrings().getStringFromHPackIndex(hpack_index, globalObject);
if (value != nullptr) {
return JSValue::encode(value);
}
return JSValue::encode(JSValue::JSUndefined);
}
template<typename Visitor>
void GlobalObject::visitChildrenImpl(JSCell* cell, Visitor& visitor)
{
@@ -3598,6 +3644,7 @@ void GlobalObject::visitChildrenImpl(JSCell* cell, Visitor& visitor)
thisObject->m_builtinInternalFunctions.visit(visitor);
thisObject->m_commonStrings.visit<Visitor>(visitor);
thisObject->m_http2_commongStrings.visit<Visitor>(visitor);
visitor.append(thisObject->m_assignToStream);
visitor.append(thisObject->m_readableStreamToArrayBuffer);
visitor.append(thisObject->m_readableStreamToArrayBufferResolve);
@@ -3634,6 +3681,7 @@ void GlobalObject::visitChildrenImpl(JSCell* cell, Visitor& visitor)
thisObject->m_JSBufferListClassStructure.visit(visitor);
thisObject->m_JSBufferSubclassStructure.visit(visitor);
thisObject->m_JSCryptoKey.visit(visitor);
thisObject->m_lazyStackCustomGetterSetter.visit(visitor);
thisObject->m_JSDOMFileConstructor.visit(visitor);
thisObject->m_JSFFIFunctionStructure.visit(visitor);
thisObject->m_JSFileSinkClassStructure.visit(visitor);
@@ -4026,8 +4074,7 @@ JSC::JSInternalPromise* GlobalObject::moduleLoaderFetch(JSGlobalObject* globalOb
auto scope = DECLARE_THROW_SCOPE(vm);
auto moduleKey = key.toWTFString(globalObject);
if (UNLIKELY(scope.exception()))
return rejectedInternalPromise(globalObject, scope.exception()->value());
RETURN_IF_EXCEPTION(scope, rejectedInternalPromise(globalObject, scope.exception()->value()));
if (moduleKey.endsWith(".node"_s)) {
return rejectedInternalPromise(globalObject, createTypeError(globalObject, "To load Node-API modules, use require() or process.dlopen instead of import."_s));
@@ -4063,6 +4110,7 @@ JSC::JSInternalPromise* GlobalObject::moduleLoaderFetch(JSGlobalObject* globalOb
&moduleKeyBun,
&source,
typeAttributeString.isEmpty() ? nullptr : &typeAttribute);
RETURN_IF_EXCEPTION(scope, rejectedInternalPromise(globalObject, scope.exception()->value()));
if (auto* internalPromise = JSC::jsDynamicCast<JSC::JSInternalPromise*>(result)) {
return internalPromise;

View File

@@ -51,6 +51,7 @@ class GlobalInternals;
#include "WebCoreJSBuiltins.h"
#include "headers-handwritten.h"
#include "BunCommonStrings.h"
#include "BunHttp2CommonStrings.h"
#include "BunGlobalScope.h"
namespace WebCore {
@@ -191,8 +192,7 @@ public:
void clearDOMGuardedObjects();
static void createCallSitesFromFrames(Zig::GlobalObject* globalObject, JSC::JSGlobalObject* lexicalGlobalObject, JSCStackTrace& stackTrace, JSC::JSArray* callSites);
void formatStackTrace(JSC::VM& vm, JSC::JSGlobalObject* lexicalGlobalObject, JSC::JSObject* errorObject, JSC::JSArray* callSites, JSValue prepareStack = JSC::jsUndefined());
static void createCallSitesFromFrames(Zig::GlobalObject* globalObject, JSC::JSGlobalObject* lexicalGlobalObject, JSCStackTrace& stackTrace, MarkedArgumentBuffer& callSites);
static void reportUncaughtExceptionAtEventLoop(JSGlobalObject*, JSC::Exception*);
static JSGlobalObject* deriveShadowRealmGlobalObject(JSGlobalObject* globalObject);
@@ -374,6 +374,8 @@ public:
}
bool asyncHooksNeedsCleanup = false;
double INSPECT_MAX_BYTES = 50;
bool isInsideErrorPrepareStackTraceCallback = false;
/**
* WARNING: You must update visitChildrenImpl() if you add a new field.
@@ -483,7 +485,7 @@ public:
JSObject* cryptoObject() const { return m_cryptoObject.getInitializedOnMainThread(this); }
JSObject* JSDOMFileConstructor() const { return m_JSDOMFileConstructor.getInitializedOnMainThread(this); }
Bun::CommonStrings& commonStrings() { return m_commonStrings; }
Bun::Http2CommonStrings& http2CommonStrings() { return m_http2_commongStrings; }
#include "ZigGeneratedClasses+lazyStructureHeader.h"
void finishCreation(JSC::VM&);
@@ -499,6 +501,7 @@ private:
Lock m_gcLock;
Ref<WebCore::DOMWrapperWorld> m_world;
Bun::CommonStrings m_commonStrings;
Bun::Http2CommonStrings m_http2_commongStrings;
RefPtr<WebCore::Performance> m_performance { nullptr };
// JSC's hashtable code-generator tries to access these properties, so we make them public.
@@ -584,6 +587,7 @@ public:
LazyProperty<JSGlobalObject, JSObject> m_navigatorObject;
LazyProperty<JSGlobalObject, JSObject> m_performanceObject;
LazyProperty<JSGlobalObject, JSObject> m_processObject;
LazyProperty<JSGlobalObject, CustomGetterSetter> m_lazyStackCustomGetterSetter;
bool hasOverridenModuleResolveFilenameFunction = false;

View File

@@ -23,7 +23,6 @@
structuredClone functionStructuredClone Function 2
global GlobalObject_getGlobalThis PropertyCallback
EventSource getEventSourceConstructor PropertyCallback
Bun GlobalObject::m_bunObject CellProperty|DontDelete|ReadOnly
File GlobalObject::m_JSDOMFileConstructor CellProperty

Some files were not shown because too many files have changed in this diff Show More