* WIP sync close (shows ref count bug in stream)
* fix closing on PipeWriter and PipeReader
* remove old todos
* join
* Some shell changes
at least it compiles
* fix some compile errors
* fix ref/unref server on windows
* actually use the ref count in this places
* make windows compile again
* more tests passing
* Make shell compile again
* Slowly remove some `@panic("TODO SHELL")`
* Eliminate `@panic("TODO SHELL")` for BufferedWriter
* Holy cleansing of `@panic("TODO SHELL")`
at least it compiles now
* Okay now the shell compiles, but segfaults
* Fix compiler errors
* more stable stream and now Content-Range pass
* make windows compile again
* revert stuff until the fix is actually ready
* revert onDone thing
* Fix buffered writer for shell
* Fix buffered writer + shell/subproc.zig and windows build
* Fix for #8982 got lost in the merge
* Actually buffer subproc output
* Fix some stuff shell
* oops
* fix context deinit
* fix renderMissing
* shell: Fix array buffer
* more stable streams (#9053)
fix stream ref counting
* wip
* Remove `@panic("TODO")` on shell event loop tasks and Redirect open flags got lost in merge
* Support redirects
* fixes
cc @cirospaciari
* Update ReadableStreamInternals.ts
* Fix spurious error
* Update stream.js
* leak
* Fix UAF
cc @cirospaciari
* Fix memory leaks
* HOLY FUCK big refactor
* misc cleanup
* shell: Fix a bunch of tests
* clean up
* gitignore: fix ending newline
* get windows compiling again
* tidy
* hide linker warn with icu
* closeIfPossible
* Better leak test
* Fix forgetting to decrement reference count
* Update stdio.zig
* Fix shell windows build
* Stupid unreachable
* Woops
* basic echo hi works on windows
* Fix flaky test on Windows
* Fix windows regression in Bun.main (#9156)
* Fix windows regression in Bun.main
* Handle invalid handles
* Fix flaky test
* Better launch config
* Fixup
* Make this test less flaky on Windows
* Fixup
* Cygwin
* Support signal codes in subprocess.kill(), resolve file path
* Treat null as ignore
* Ignore carriage returns
* Fixup
* shell: Fix IOWriter bug
* shell: Use custom `open()`/`openat()`
* windows shell subproc works
* zack commit
* I think I understand WindowsStreamingWriter
* fix thing
* why were we doing this in tests
* shell: Fix rm
* shell: Add rm -rf node_modules/ test
* shell: use `.runAsTest()` in some places to make it easier to determine which test failed
* [autofix.ci] apply automated fixes
* woopsie
* Various changes
* Fix
* shell: abstract output task logic
* shell: mkdir builtin
* fixup
* stuff
* shell: Make writing length of 0 in IOWriter immediately resolve
* shell: Implement `touch`
* shell: basic `cat` working
* Make it compile on windows
* shell: Fix IOReader bug
* [autofix.ci] apply automated fixes
* fix windows kill on subprocess/process
* fix dns tests to match behavior on windows (same as nodejs)
* fix windows ci
* again
* move `close_handle` to flags in `PipeWriter` and fix shell hanging
* Fix `ls` not giving non-zero exit code on error
* Handle edgecase in is_atty
* Fix writer.flush() when there's no data
* Fix some tests
* Disable uv_unref on uv_process_t on Windows, for now.
* fix writer.end
* fix stdout.write
* fix child-process on win32
* Make this test less flaky on Windows
* Add assertion
* Make these the same
* Make it pass on windows
* Don't commit
* Log the test name
* Make this test less flaky on windows
* Make this test less flaky on windows
* Print which test is taking awhile in the runner
* fixups
* Fixups
* Add some assertions
* Bring back test concurrency
* shell: bring back redirect stdin
* make it compile again cc @zackradisic
* initialize env map with capacity
* some fixes
* cleanup
* oops
* fix leak, fix done
* fix unconsumedPromises on events
* always run expect
* Update child_process.test.ts
* fix reading special files
* Fix a test
* Deflake this test
* Make these comparisons easier
* Won't really fix it but slightly cleaner
* Update serve.test.ts
* Make the checks for if the body is already used more resilient
* Move this to the harness
* Make this test not hang in development
* Fix this test
* Make the logs better
* zero init some things
* Make this test better
* Fix readSocket
* Parallelize this test
* Handle EPipe and avoid big data
* This was a mistake
* Fix a bunch of things
* Fix memory leak
* Avoid sigpipe + optimize + delete dead code
* Make this take less time
* Make it bigger
* Remove some redundant code
* Update process.zig
* Merge and hopefully don't breka things along teh way
* Silence build warning
* Uncomment on posix
* Skip test on windows
* windows
* Cleanup test
* Update
* Deflake
* always
* less flaky test
* [autofix.ci] apply automated fixes
* logs
* fix uaf on shell IOReader
* stuff to make it work with mini event loop
* fix 2 double free scenarios, support redirections on windows
* shell: Make `1>&2` and `2>&1` work with libuv
* yoops
* Partial fix
* Partial fix
* fix build
* fix build
* ok
* Make a couple shell tests pass
* More logging
* fix
* fix
* Fix build issue
* more tests pass
* Deflake
* Deflake
* Use Output.panic instead of garbled text
* Formatting
* Introduce `bun.sys.File`, use it for `Output.Source.StreamType`, fix nested Output.scoped() calls, use Win32 `ReadFile` API for reading when it's not a libuv file descriptor.
This lets us avoid the subtle usages of `unreachable` in std.os when writing to stdout/stderr.
Previously, we were initializing the libuv loop immediately at launch due to checking for the existence of a bun build --compile'd executable. When the file descriptor is not from libuv, it's just overhead to use libuv
cc @paperdave, please tell me if Iany of that is incorrect or if you think this is a bad idea.
* Fix closing undefined memory file descriptors in spawn
cc @zackradisic
* pause instead of close
* Fix poorly-written test
* We don't need big numbers for this test
* sad workaround
* fixup
* Clearer error handling for this test
* Fix incorrect test
@electroid when ReadableStream isn't closed, hanging is the correct behavior when consuming buffered data. We cannot know if the buffered data is finished if the stream never closes.
* Fix build
* Remove known failing on windows
* Deflake
* Mark no longer failing
* show all the failing tests
* Sort the list of tests
* fix argument handling
* dont show "posix_spawn" as an error code on windows
* make bun-upgrade.test.ts pass on windows
* fix bunx and bun create again sorry
* a
* fix invalidexe because we should not be running javascript files as if they were exes
* Concurrency in test runner + better logging
* Revert "fix invalidexe because we should not be running javascript files as if they were exes"
This reverts commit da47cf8247.
* WIP: Unix fixes (#9322)
* wip
* [autofix.ci] apply automated fixes
* wip 2
* [autofix.ci] apply automated fixes
---------
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
* Update runner.node.mjs
* Update runner.node.mjs
* Document some environment variables
* shell: Make `Response` work with builtins
* Make it compile
* make pwd test pass
* [autofix.ci] apply automated fixes
* Fix printing garbage for source code previews
* Update javascript.zig
* Fix posix test failures
* Fix signal dispatch
cc @paperdave. Signals can be run from any thread. This causes an assertion failure when the receiving thread happens to not be the main thread. Easiest to reproduce on linux when you spawn 100 short-lived processes at once.
* windows
---------
Co-authored-by: cirospaciari <ciro.spaciari@gmail.com>
Co-authored-by: Zack Radisic <56137411+zackradisic@users.noreply.github.com>
Co-authored-by: Zack Radisic <zackradisic@Zacks-MBP-2.attlocal.net>
Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
Co-authored-by: Meghan Denny <meghan@bun.sh>
Co-authored-by: Zack Radisic <zack@theradisic.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: dave caruso <me@paperdave.net>
Co-authored-by: Dylan Conway <dylan.conway567@gmail.com>
JS Modules
TLDR: If anything here changes, re-run make js. If you add/remove files, make regenerate-bindings.
./nodecontains allnode:*modules./buncontains allbun:*modules./thirdpartycontains npm modules we replace likews./internalcontains modules that aren't assigned to the module resolver
Each .ts/.js file above is assigned a numeric id at compile time and inlined into an array of lazily initialized modules. Internal modules referencing each other is extremely optimized, skipping the module resolver entirely.
Builtins Syntax
Within these files, the $ prefix on variables can be used to access private property names as well as JSC intrinsics.
// Many globals have private versions which are impossible for the user to
// tamper with. Though, these global variables are auto-prefixed by the bundler.
const hello = $Array.from(...);
// Similar situation with prototype values. These aren't autoprefixed since it depends on type.
something.$then(...);
map.$set(...);
// Internal variables we define
$requireMap.$has("elysia");
// JSC engine intrinsics. These usually translate directly to bytecode instructions.
const arr = $newArrayWithSize(5);
// A side effect of this is that using an intrinsic incorrectly like
// this will fail to parse and cause a segfault.
console.log($getInternalField)
V8 has a similar feature to this syntax (they use % instead)
On top of this, we have some special functions that are handled by the builtin preprocessor:
-
requireworks, but it must be passed a string literal that resolves to a module withinsrc/js. This call gets replaced with$getInternalField($internalModuleRegistery, <number>), which directly loads the module by its generated numerical ID, skipping the resolver for inter-internal modules. -
$debug()is exactly like console.log, but is stripped in release builds. It is disabled by default, requiring you to pass one of:BUN_DEBUG_MODULE_NAME=1,BUN_DEBUG_JS=1, orBUN_DEBUG_ALL=1. You can also doif($debug) {}to check if debug env var is set. -
$assert()in debug builds will assert the condition, but it is stripped in release builds. If an assertion fails, the program continues to run, but an error is logged in the console containing the original source condition and any extra messages specified. -
IS_BUN_DEVELOPMENTis inlined to betruein all development builds. -
process.platformandprocess.archis properly inlined and DCE'd. Do use this to run different code on different platforms.
Builtin Modules
In module files, instead of using module.exports, use the export default variable. Due to the internal implementation, these must be JSCell types (function / object).
export default {
hello: 2,
world: 3,
};
Keep in mind that these are not ES modules. export default is only syntax sugar to assign to the variable $exports, which is actually how the module exports its contents. export var and export function are banned syntax, and so is import (use require instead)
To actually wire up one of these modules to the resolver, that is done separately in module_resolver.zig. Maybe in the future we can do codegen for it.
Builtin Functions
./functions contains isolated functions. Each function within is bundled separately, meaning you may not use global variables, non-type imports, and even directly referencing the other functions in these files. require is still resolved the same way it does in the modules.
In function files, these are accessible in C++ by using <file><function>CodeGenerator(vm), for example:
object->putDirectBuiltinFunction(
vm,
globalObject,
identifier,
// ReadableStream.ts, `function readableStreamToJSON()`
// This returns a FunctionExecutable* (extends JSCell*, but not JSFunction*).
readableStreamReadableStreamToJSONCodeGenerator(vm),
JSC::PropertyAttribute::DontDelete | 0
);
Building
Run make js to bundle all the builtins. The output is placed in src/js/out/{modules,functions}/, where these files are loaded dynamically by bun-debug (an exact filepath is inlined into the binary pointing at where you cloned bun, so moving the binary to another machine may not work). In a release build, these get minified and inlined into the binary (Please commit those generated headers).
If you change the list of files or functions, you will have to run make regenerate-bindings, but otherwise any change can be done with just make js.
Notes on how the build process works
This isn't really required knowledge to use it, but a rough overview of how ./_codegen/* works
The build process is built on top of Bun's bundler. The first step is scanning all modules and assigning each a numerical ID. The order is determined by an A-Z sort.
The $ for private names is actually a lie, and in JSC it actually uses @; though that is a syntax error in regular JS/TS, so we opted for better IDE support. So first we have to pre-process the files to spot all instances of $ at the start of an identifier and we convert it to __intrinsic__. We also scan for require(string) and replace it with $requireId(n) after resolving it to the integer id, which is defined in ./functions/Module.ts. export default is transformed into return ...;, however this transform is a little more complicated that a string replace because it supports that not being the final statement, and access to the underlying variable $exports, etc.
The preprocessor is smart enough to not replace $ in strings, comments, regex, etc. However, it is not a real JS parser and instead a recursive regex-based nightmare, so may hit some edge cases. Yell at Dave if it breaks.
The module is then printed like:
// @ts-nocheck
$$capture_start$$(function () {
const path = __intrinsic__requireId(23);
// user code is pasted here
return {
cool: path,
};
}).$$capture_end$$;
This capture thing is used to extract the function declaration afterwards, this is more useful in the functions case where functions can have arguments, or be async functions.
After bundling, the inner part is extracted, and then __intrinsic__ is replaced to @.
These can then be inlined into C++ headers and loaded with createBuiltin. This is done in InternalModuleRegistry.cpp.