aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile4
-rw-r--r--README.md7
-rw-r--r--src/allocators.zig6
-rw-r--r--src/bundler.zig21
-rw-r--r--src/cache.zig8
-rw-r--r--src/fallback.ts4
-rw-r--r--src/fallback.version2
-rw-r--r--src/fs.zig20
-rw-r--r--src/http.zig122
-rw-r--r--src/javascript/jsc/bindings/ZigGlobalObject.cpp120
-rw-r--r--src/javascript/jsc/bindings/ZigSourceProvider.cpp66
-rw-r--r--src/javascript/jsc/bindings/ZigSourceProvider.h20
-rw-r--r--src/javascript/jsc/bindings/exports.zig9
-rw-r--r--src/javascript/jsc/bindings/header-gen.zig24
-rw-r--r--src/javascript/jsc/bindings/headers-cpp.h2
-rw-r--r--src/javascript/jsc/bindings/headers-handwritten.h4
-rw-r--r--src/javascript/jsc/bindings/headers.h2
-rw-r--r--src/javascript/jsc/bindings/headers.zig2
-rw-r--r--src/javascript/jsc/javascript.zig35
-rw-r--r--src/js_ast.zig2
-rw-r--r--src/linker.zig6
-rw-r--r--src/memory_allocator.zig1
-rw-r--r--src/resolver/resolver.zig116
-rw-r--r--src/resolver/tsconfig_json.zig3
-rw-r--r--src/string_immutable.zig40
-rw-r--r--src/test/fixtures/tsconfig.json2
26 files changed, 428 insertions, 220 deletions
diff --git a/Makefile b/Makefile
index 83af9371d..b0bc7a81f 100644
--- a/Makefile
+++ b/Makefile
@@ -60,8 +60,7 @@ INCLUDE_DIRS := -Isrc/JavaScript/jsc/WebKit/WebKitBuild/Release/JavaScriptCore/P
-Isrc/JavaScript/jsc/bindings/ \
-Isrc/javascript/jsc/WebKit/Source/bmalloc
-CLANG_FLAGS =
- $(INCLUDE_DIRS) \
+CLANG_FLAGS := $(INCLUDE_DIRS) \
-std=gnu++1z \
-stdlib=libc++ \
-DSTATICALLY_LINKED_WITH_JavaScriptCore=1 \
@@ -79,6 +78,7 @@ CLANG_FLAGS =
jsc-bindings-mac: $(OBJ_FILES)
+
MACOS_ICU_FILES := /usr/local/opt/icu4c/lib/libicudata.a \
/usr/local/opt/icu4c/lib/libicui18n.a \
/usr/local/opt/icu4c/lib/libicuuc.a
diff --git a/README.md b/README.md
index be526b36e..ae279b2df 100644
--- a/README.md
+++ b/README.md
@@ -23,14 +23,15 @@ npm install -g bun-cli
In your project folder root (where `package.json` is):
```bash
-npm install bun-framework-next path buffer
+npm install bun-framework-next
bun bun --use next
-open http://localhost:3000; bun dev --origin "http://localhost:3000"
+open http://localhost:3000; bun
```
Here are some features of Next.js that **aren't supported** yet:
-- `getStaticPaths`. These functions will not be called.
+- `getStaticPaths`
+- `fetch` inside of `getStaticProps` or `getServerSideProps`
- locales, zones, `assetPrefix` (workaround: change `--origin \"http://localhsot:3000/assetPrefixInhere\"`)
- `next/image` - `<Image />` component
diff --git a/src/allocators.zig b/src/allocators.zig
index 29f660a12..4150a37c8 100644
--- a/src/allocators.zig
+++ b/src/allocators.zig
@@ -685,6 +685,10 @@ pub fn BSSMap(comptime ValueType: type, comptime count: anytype, store_keys: boo
slice = try self.map.allocator.dupe(u8, key);
}
+ if (comptime remove_trailing_slashes) {
+ slice = constStrToU8(std.mem.trimRight(u8, slice, "/"));
+ }
+
if (!result.index.is_overflow) {
key_list_slices[result.index.index] = slice;
} else {
@@ -945,6 +949,6 @@ pub fn TBSSMap(comptime ValueType: type, comptime count: anytype, store_keys: bo
};
}
-pub fn constStrToU8(s: []const u8) []u8 {
+pub inline fn constStrToU8(s: []const u8) []u8 {
return @intToPtr([*]u8, @ptrToInt(s.ptr))[0..s.len];
}
diff --git a/src/bundler.zig b/src/bundler.zig
index 8b86203f5..a43d6884c 100644
--- a/src/bundler.zig
+++ b/src/bundler.zig
@@ -1102,7 +1102,7 @@ pub fn NewBundler(cache_files: bool) type {
if (!strings.eqlComptime(file_path.namespace, "node"))
break :brk try bundler.resolver.caches.fs.readFileShared(
bundler.fs,
- file_path.text,
+ file_path.textZ(),
resolve.dirname_fd,
if (resolve.file_fd != 0) resolve.file_fd else null,
shared_buffer,
@@ -1476,7 +1476,7 @@ pub fn NewBundler(cache_files: bool) type {
=> {
const entry = bundler.resolver.caches.fs.readFileShared(
bundler.fs,
- file_path.text,
+ file_path.textZ(),
resolve.dirname_fd,
if (resolve.file_fd != 0) resolve.file_fd else null,
shared_buffer,
@@ -2046,6 +2046,7 @@ pub fn NewBundler(cache_files: bool) type {
relative_path: string,
_extension: string,
comptime client_entry_point_enabled: bool,
+ comptime serve_as_package_path: bool,
) !ServeResult {
var extension = _extension;
var old_log = bundler.log;
@@ -2061,13 +2062,15 @@ pub fn NewBundler(cache_files: bool) type {
};
}
- // We make some things faster in theory by using absolute paths instead of relative paths
- var absolute_path = resolve_path.joinAbsStringBuf(
- bundler.fs.top_level_dir,
- &tmp_buildfile_buf,
- &([_][]const u8{relative_path}),
- .auto,
- );
+ var absolute_path = if (comptime serve_as_package_path)
+ relative_path
+ else
+ resolve_path.joinAbsStringBuf(
+ bundler.fs.top_level_dir,
+ &tmp_buildfile_buf,
+ &([_][]const u8{relative_path}),
+ .auto,
+ );
defer {
js_ast.Expr.Data.Store.reset();
diff --git a/src/cache.zig b/src/cache.zig
index 840cd7357..73c093d57 100644
--- a/src/cache.zig
+++ b/src/cache.zig
@@ -68,7 +68,7 @@ pub fn NewCache(comptime cache_files: bool) type {
pub fn readFileShared(
c: *Fs,
_fs: *fs.FileSystem,
- path: string,
+ path: [:0]const u8,
dirname_fd: StoredFileDescriptorType,
_file_handle: ?StoredFileDescriptorType,
shared: *MutableString,
@@ -88,11 +88,7 @@ pub fn NewCache(comptime cache_files: bool) type {
var file_handle: std.fs.File = if (_file_handle) |__file| std.fs.File{ .handle = __file } else undefined;
if (_file_handle == null) {
- if (FeatureFlags.store_file_descriptors and dirname_fd > 0) {
- file_handle = try std.fs.Dir.openFile(std.fs.Dir{ .fd = dirname_fd }, std.fs.path.basename(path), .{ .read = true });
- } else {
- file_handle = try std.fs.openFileAbsolute(path, .{ .read = true });
- }
+ file_handle = try std.fs.openFileAbsoluteZ(path, .{ .read = true });
}
defer {
diff --git a/src/fallback.ts b/src/fallback.ts
index ae969062c..103c9db1d 100644
--- a/src/fallback.ts
+++ b/src/fallback.ts
@@ -6,8 +6,8 @@ import {
} from "./api/schema";
function getFallbackInfo(): FallbackMessageContainer {
- var binary_string = globalThis.atob(
- document.getElementById("#__bunfallback").textContent.trim()
+ const binary_string = globalThis.atob(
+ document.getElementById("__bunfallback").textContent.trim()
);
var len = binary_string.length;
diff --git a/src/fallback.version b/src/fallback.version
index e684473e4..fb76dcb20 100644
--- a/src/fallback.version
+++ b/src/fallback.version
@@ -1 +1 @@
-703503c7cc54abc8 \ No newline at end of file
+c098be5f3e938123 \ No newline at end of file
diff --git a/src/fs.zig b/src/fs.zig
index 2bed1ee47..f1e572835 100644
--- a/src/fs.zig
+++ b/src/fs.zig
@@ -368,7 +368,7 @@ pub const FileSystem = struct {
pub fn kind(entry: *Entry, fs: *Implementation) Kind {
if (entry.need_stat) {
entry.need_stat = false;
- entry.cache = fs.kind(entry.dir, entry.base()) catch unreachable;
+ entry.cache = fs.kind(entry.dir, entry.base(), entry.cache.fd) catch unreachable;
}
return entry.cache.kind;
}
@@ -376,7 +376,7 @@ pub const FileSystem = struct {
pub fn symlink(entry: *Entry, fs: *Implementation) string {
if (entry.need_stat) {
entry.need_stat = false;
- entry.cache = fs.kind(entry.dir, entry.base()) catch unreachable;
+ entry.cache = fs.kind(entry.dir, entry.base(), entry.cache.fd) catch unreachable;
}
return entry.cache.symlink;
}
@@ -398,6 +398,10 @@ pub const FileSystem = struct {
return @call(.{ .modifier = .always_inline }, path_handler.normalizeString, .{ str, true, .auto });
}
+ pub fn normalizeBuf(f: *@This(), buf: []u8, str: string) string {
+ return @call(.{ .modifier = .always_inline }, path_handler.normalizeStringBuf, .{ str, buf, false, .auto, false });
+ }
+
pub fn join(f: *@This(), parts: anytype) string {
return @call(.{ .modifier = .always_inline }, path_handler.joinStringBuf, .{
&join_buf,
@@ -883,7 +887,7 @@ pub const FileSystem = struct {
return try fs.readFileWithHandle(path, _size, file);
}
- pub fn kind(fs: *RealFS, _dir: string, base: string) !Entry.Cache {
+ pub fn kind(fs: *RealFS, _dir: string, base: string, existing_fd: StoredFileDescriptorType) !Entry.Cache {
var dir = _dir;
var combo = [2]string{ dir, base };
var outpath: [std.fs.MAX_PATH_BYTES]u8 = undefined;
@@ -900,13 +904,13 @@ pub const FileSystem = struct {
var cache = Entry.Cache{ .kind = Entry.Kind.file, .symlink = "" };
var symlink: []const u8 = "";
if (is_symlink) {
- var file = try std.fs.openFileAbsoluteZ(absolute_path_c, .{ .read = true });
+ var file = if (existing_fd != 0) std.fs.File{ .handle = existing_fd } else try std.fs.openFileAbsoluteZ(absolute_path_c, .{ .read = true });
setMaxFd(file.handle);
defer {
- if (fs.needToCloseFiles()) {
+ if (fs.needToCloseFiles() and existing_fd == 0) {
file.close();
- } else {
+ } else if (comptime FeatureFlags.store_file_descriptors) {
cache.fd = file.handle;
}
}
@@ -1048,6 +1052,10 @@ pub const Path = struct {
is_parent_package: bool = false,
};
+ pub inline fn textZ(this: *const Path) [:0]const u8 {
+ return @as([:0]const u8, this.text.ptr[0..this.text.len :0]);
+ }
+
pub inline fn sourceDir(this: *const Path) string {
return this.name.dirWithTrailingSlash();
}
diff --git a/src/http.zig b/src/http.zig
index e9fd74ee1..e013c7dbf 100644
--- a/src/http.zig
+++ b/src/http.zig
@@ -17,6 +17,7 @@ const NodeModuleBundle = @import("./node_module_bundle.zig").NodeModuleBundle;
const resolve_path = @import("./resolver/resolve_path.zig");
const OutputFile = Options.OutputFile;
const DotEnv = @import("./env_loader.zig");
+const mimalloc = @import("./allocators/mimalloc.zig");
pub fn constStrToU8(s: string) []u8 {
return @intToPtr([*]u8, @ptrToInt(s.ptr))[0..s.len];
}
@@ -109,7 +110,7 @@ pub const RequestContext = struct {
url: URLPath,
conn: *tcp.Connection,
allocator: *std.mem.Allocator,
- arena: std.heap.ArenaAllocator,
+ arena: *std.heap.ArenaAllocator,
log: logger.Log,
bundler: *Bundler,
keep_alive: bool = true,
@@ -508,7 +509,7 @@ pub const RequestContext = struct {
pub fn init(
req: Request,
- arena: std.heap.ArenaAllocator,
+ arena: *std.heap.ArenaAllocator,
conn: *tcp.Connection,
bundler_: *Bundler,
watcher_: *Watcher,
@@ -521,7 +522,7 @@ pub const RequestContext = struct {
.log = undefined,
.url = try URLPath.parse(req.path),
.conn = conn,
- .allocator = undefined,
+ .allocator = &arena.allocator,
.method = Method.which(req.method) orelse return error.InvalidMethod,
.watcher = watcher_,
.timer = timer,
@@ -993,12 +994,12 @@ pub const RequestContext = struct {
// defer stderr.flush() catch {};
Output.Source.set(&output_source);
- js_ast.Stmt.Data.Store.create(default_allocator);
- js_ast.Expr.Data.Store.create(default_allocator);
+ js_ast.Stmt.Data.Store.create(std.heap.c_allocator);
+ js_ast.Expr.Data.Store.create(std.heap.c_allocator);
defer Output.flush();
var vm = JavaScript.VirtualMachine.init(
- default_allocator,
+ std.heap.c_allocator,
handler.args,
handler.existing_bundle,
handler.log,
@@ -1121,11 +1122,14 @@ pub const RequestContext = struct {
);
}
+ var __arena: std.heap.ArenaAllocator = undefined;
pub fn runLoop(vm: *JavaScript.VirtualMachine, thread: *HandlerThread) !void {
var module_map = ZigGlobalObject.getModuleRegistryMap(vm.global);
- JavaScript.VirtualMachine.vm.has_loaded = true;
while (true) {
+ __arena = std.heap.ArenaAllocator.init(vm.allocator);
+ JavaScript.VirtualMachine.vm.arena = &__arena;
+ JavaScript.VirtualMachine.vm.has_loaded = true;
defer {
JavaScript.VirtualMachine.vm.flush();
std.debug.assert(
@@ -1135,9 +1139,13 @@ pub const RequestContext = struct {
js_ast.Expr.Data.Store.reset();
JavaScript.Bun.flushCSSImports();
Output.flush();
+ JavaScript.VirtualMachine.vm.arena.deinit();
+ JavaScript.VirtualMachine.vm.has_loaded = false;
+ mimalloc.mi_collect(false);
}
var handler: *JavaScriptHandler = try channel.readItem();
+
JavaScript.VirtualMachine.vm.preflush();
JavaScript.EventListenerMixin.emitFetchEvent(
@@ -1985,12 +1993,12 @@ pub const RequestContext = struct {
return true;
}
- if (ctx.url.path.len > "blob:".len and strings.eqlComptime(ctx.url.path[0.."blob:".len], "blob:")) {
+ if (ctx.url.path.len > "blob:".len and strings.eqlComptimeIgnoreLen(ctx.url.path[0.."blob:".len], "blob:")) {
try ctx.handleBlobURL(server);
return true;
}
- if (ctx.url.path.len > "bun:".len and strings.eqlComptime(ctx.url.path[0.."bun:".len], "bun:")) {
+ if (ctx.url.path.len > "bun:".len and strings.eqlComptimeIgnoreLen(ctx.url.path[0.."bun:".len], "bun:")) {
try ctx.handleBunURL(server);
return true;
}
@@ -2001,21 +2009,45 @@ pub const RequestContext = struct {
pub fn handleGet(ctx: *RequestContext) !void {
const result = brk: {
if (ctx.bundler.options.isFrontendFrameworkEnabled()) {
- break :brk try ctx.bundler.buildFile(
- &ctx.log,
- ctx.allocator,
- ctx.url.pathWithoutAssetPrefix(ctx.bundler.options.routes.asset_prefix_path),
- ctx.url.extname,
- true,
- );
+ if (serve_as_package_path) {
+ break :brk try ctx.bundler.buildFile(
+ &ctx.log,
+ ctx.allocator,
+ ctx.url.pathWithoutAssetPrefix(ctx.bundler.options.routes.asset_prefix_path),
+ ctx.url.extname,
+ true,
+ true,
+ );
+ } else {
+ break :brk try ctx.bundler.buildFile(
+ &ctx.log,
+ ctx.allocator,
+ ctx.url.pathWithoutAssetPrefix(ctx.bundler.options.routes.asset_prefix_path),
+ ctx.url.extname,
+ true,
+ false,
+ );
+ }
} else {
- break :brk try ctx.bundler.buildFile(
- &ctx.log,
- ctx.allocator,
- ctx.url.pathWithoutAssetPrefix(ctx.bundler.options.routes.asset_prefix_path),
- ctx.url.extname,
- false,
- );
+ if (serve_as_package_path) {
+ break :brk try ctx.bundler.buildFile(
+ &ctx.log,
+ ctx.allocator,
+ ctx.url.pathWithoutAssetPrefix(ctx.bundler.options.routes.asset_prefix_path),
+ ctx.url.extname,
+ false,
+ true,
+ );
+ } else {
+ break :brk try ctx.bundler.buildFile(
+ &ctx.log,
+ ctx.allocator,
+ ctx.url.pathWithoutAssetPrefix(ctx.bundler.options.routes.asset_prefix_path),
+ ctx.url.extname,
+ false,
+ true,
+ );
+ }
}
};
@@ -2033,6 +2065,7 @@ pub const RequestContext = struct {
}
}
};
+var serve_as_package_path = false;
// // u32 == File ID from Watcher
// pub const WatcherBuildChannel = sync.Channel(u32, .Dynamic);
@@ -2072,6 +2105,7 @@ pub const RequestContext = struct {
// - Resolver time
// - Parsing time
// - IO read time
+
pub const Server = struct {
log: logger.Log,
allocator: *std.mem.Allocator,
@@ -2079,7 +2113,6 @@ pub const Server = struct {
watcher: *Watcher,
timer: std.time.Timer = undefined,
transform_options: Api.TransformOptions,
-
javascript_enabled: bool = false,
pub fn adjustUlimit() !void {
@@ -2266,13 +2299,24 @@ pub const Server = struct {
}
Output.flush();
- // var listener_handle = try std.os.kqueue();
- // var change_list = std.mem.zeroes([2]os.Kevent);
- // change_list[0].ident = @intCast(usize, listener.socket.fd);
- // change_list[1].ident = @intCast(usize, listener.socket.fd);
+ var did_init = false;
+ while (!did_init) {
+ defer Output.flush();
+ var conn = listener.accept(.{ .close_on_exec = true }) catch |err| {
+ continue;
+ };
+
+ // We want to bind to the network socket as quickly as possible so that opening the URL works
+ // We use a secondary loop so that we avoid the extra branch in a hot code path
+ server.detectFastRefresh();
+ server.detectTSConfig();
+ try server.initWatcher();
+ did_init = true;
+
+ server.handleConnection(&conn, comptime features);
+ }
- // var eventlist: [128]os.Kevent = undefined;
while (true) {
defer Output.flush();
var conn = listener.accept(.{ .close_on_exec = true }) catch |err| {
@@ -2283,10 +2327,6 @@ pub const Server = struct {
}
}
- pub fn sendError(server: *Server, request: *Request, conn: *tcp.Connection, code: HTTPStatusCode, msg: string) !void {
- try server.writeStatus(code, connection);
- }
-
threadlocal var req_buf: [32_000]u8 = undefined;
pub const ConnectionFeatures = struct {
@@ -2319,7 +2359,8 @@ pub const Server = struct {
return;
};
- var request_arena = std.heap.ArenaAllocator.init(server.allocator);
+ var request_arena = server.allocator.create(std.heap.ArenaAllocator) catch unreachable;
+ request_arena.* = std.heap.ArenaAllocator.init(server.allocator);
var req_ctx: RequestContext = undefined;
req_ctx = RequestContext.init(
@@ -2351,7 +2392,6 @@ pub const Server = struct {
}
}
- req_ctx.allocator = &req_ctx.arena.allocator;
req_ctx.log = logger.Log.init(server.allocator);
var log = &req_ctx.log;
@@ -2524,6 +2564,14 @@ pub const Server = struct {
};
}
+ pub fn detectTSConfig(this: *Server) void {
+ defer this.bundler.resetStore();
+
+ const dir_info = (this.bundler.resolver.readDirInfo(this.bundler.fs.top_level_dir) catch return) orelse return;
+ const tsconfig = dir_info.tsconfig_json orelse return;
+ serve_as_package_path = tsconfig.base_url_for_paths.len > 0 or tsconfig.base_url.len > 0;
+ }
+
pub var global_start_time: std.time.Timer = undefined;
pub fn start(allocator: *std.mem.Allocator, options: Api.TransformOptions) !void {
var log = logger.Log.init(allocator);
@@ -2541,10 +2589,6 @@ pub const Server = struct {
server.bundler.configureLinker();
try server.bundler.configureRouter(true);
- server.detectFastRefresh();
-
- try server.initWatcher();
-
const public_folder_is_top_level = server.bundler.options.routes.static_dir_enabled and strings.eql(
server.bundler.fs.top_level_dir,
server.bundler.options.routes.static_dir,
diff --git a/src/javascript/jsc/bindings/ZigGlobalObject.cpp b/src/javascript/jsc/bindings/ZigGlobalObject.cpp
index a251d49f1..0d9022a30 100644
--- a/src/javascript/jsc/bindings/ZigGlobalObject.cpp
+++ b/src/javascript/jsc/bindings/ZigGlobalObject.cpp
@@ -2,35 +2,61 @@
#include "helpers.h"
#include "ZigConsoleClient.h"
+#include <JavaScriptCore/AggregateError.h>
+#include <JavaScriptCore/BytecodeIndex.h>
#include <JavaScriptCore/CallFrameInlines.h>
#include <JavaScriptCore/CatchScope.h>
#include <JavaScriptCore/ClassInfo.h>
+#include <JavaScriptCore/CodeBlock.h>
+#include <JavaScriptCore/CodeCache.h>
#include <JavaScriptCore/Completion.h>
#include <JavaScriptCore/Error.h>
+#include <JavaScriptCore/ErrorInstance.h>
#include <JavaScriptCore/Exception.h>
+#include <JavaScriptCore/ExceptionScope.h>
+#include <JavaScriptCore/FunctionConstructor.h>
#include <JavaScriptCore/HashMapImpl.h>
#include <JavaScriptCore/HashMapImplInlines.h>
+#include <JavaScriptCore/Heap.h>
#include <JavaScriptCore/Identifier.h>
#include <JavaScriptCore/InitializeThreading.h>
+#include <JavaScriptCore/IteratorOperations.h>
+#include <JavaScriptCore/JSArray.h>
+#include <JavaScriptCore/JSCInlines.h>
+#include <JavaScriptCore/JSCallbackObject.h>
#include <JavaScriptCore/JSCast.h>
+#include <JavaScriptCore/JSClassRef.h>
#include <JavaScriptCore/JSContextInternal.h>
#include <JavaScriptCore/JSInternalPromise.h>
+#include <JavaScriptCore/JSLock.h>
#include <JavaScriptCore/JSMap.h>
#include <JavaScriptCore/JSModuleLoader.h>
+#include <JavaScriptCore/JSModuleRecord.h>
#include <JavaScriptCore/JSNativeStdFunction.h>
+#include <JavaScriptCore/JSObject.h>
#include <JavaScriptCore/JSPromise.h>
+#include <JavaScriptCore/JSSet.h>
#include <JavaScriptCore/JSSourceCode.h>
#include <JavaScriptCore/JSString.h>
#include <JavaScriptCore/JSValueInternal.h>
#include <JavaScriptCore/JSVirtualMachineInternal.h>
#include <JavaScriptCore/ObjectConstructor.h>
+#include <JavaScriptCore/OptionsList.h>
+#include <JavaScriptCore/ParserError.h>
+#include <JavaScriptCore/ScriptExecutable.h>
#include <JavaScriptCore/SourceOrigin.h>
+#include <JavaScriptCore/StackFrame.h>
+#include <JavaScriptCore/StackVisitor.h>
#include <JavaScriptCore/VM.h>
+#include <JavaScriptCore/VMEntryScope.h>
#include <JavaScriptCore/WasmFaultSignalHandler.h>
-#include <wtf/URL.h>
-
-#include <JavaScriptCore/JSLock.h>
#include <wtf/StdLibExtras.h>
+#include <wtf/URL.h>
+#include <wtf/text/ExternalStringImpl.h>
+#include <wtf/text/StringCommon.h>
+#include <wtf/text/StringImpl.h>
+#include <wtf/text/StringView.h>
+#include <wtf/text/WTFString.h>
#include <cstdlib>
#include <exception>
@@ -60,8 +86,13 @@ extern "C" JSC__JSGlobalObject *Zig__GlobalObject__create(JSClassRef *globalObje
WTF::initializeMainThread();
JSC::initialize();
- JSC::VM &vm = JSC::VM::create(JSC::LargeHeap).leakRef();
+ // JSC::Options::useCodeCache() = false;
+ JSC::Options::useSourceProviderCache() = true;
+ JSC::Options::useUnlinkedCodeBlockJettisoning() = false;
+ JSC::Options::useTopLevelAwait() = true;
+ JSC::VM &vm = JSC::VM::create(JSC::LargeHeap).leakRef();
+ vm.heap.acquireAccess();
#if ENABLE(WEBASSEMBLY)
JSC::Wasm::enableFastMemory();
#endif
@@ -244,39 +275,80 @@ extern "C" bool Zig__GlobalObject__resetModuleRegistryMap(JSC__JSGlobalObject *g
void *map_ptr) {
if (map_ptr == nullptr) return false;
JSC::JSMap *map = reinterpret_cast<JSC::JSMap *>(map_ptr);
-
+ JSC::VM &vm = globalObject->vm();
if (JSC::JSObject *obj =
JSC::jsDynamicCast<JSC::JSObject *>(globalObject->vm(), globalObject->moduleLoader())) {
auto identifier = JSC::Identifier::fromString(globalObject->vm(), "registry");
if (JSC::JSMap *oldMap = JSC::jsDynamicCast<JSC::JSMap *>(
globalObject->vm(), obj->getDirect(globalObject->vm(), identifier))) {
- // Help the GC by releasing the old map.
oldMap->clear(globalObject);
- // forEachInIterable(
- // globalObject, oldMap, [&](VM &vm, JSGlobalObject *globalObject, JSValue nextValue) {
- // auto scope = DECLARE_THROW_SCOPE(vm);
- // JSC::JSValue key = nextObject->getIndex(globalObject, static_cast<unsigned>(0));
- // RETURN_IF_EXCEPTION(scope, void());
+ // vm.finalizeSynchronousJSExecution();
- // if (!map->has(globalObject, key)) {
+ obj->putDirect(globalObject->vm(), identifier,
+ map->clone(globalObject, globalObject->vm(), globalObject->mapStructure()));
- // JSC::JSValue value = nextObject->getIndex(globalObject, static_cast<unsigned>(1));
- // RETURN_IF_EXCEPTION(scope, void());
+ vm.codeCache()->write(vm);
+ vm.shrinkFootprintWhenIdle();
+ // vm.deleteAllLinkedCode(JSC::DeleteAllCodeEffort::DeleteAllCodeIfNotCollecting);
+ // JSC::Heap::PreventCollectionScope(vm.heap);
+ // vm.heap.completeAllJITPlans();
+
+ // vm.forEachScriptExecutableSpace([&](auto &spaceAndSet) {
+ // JSC::HeapIterationScope heapIterationScope(vm.heap);
+ // auto &set = spaceAndSet.set;
+ // set.forEachLiveCell([&](JSC::HeapCell *cell, JSC::HeapCell::Kind) {
+ // if (JSC::ModuleProgramExecutable *executable =
+ // JSC::jsDynamicCast<JSC::ModuleProgramExecutable *>(cell)) {
+ // executable->clearCode(set);
// }
- // scope.release();
// });
- };
-
- return obj->putDirect(
- globalObject->vm(), identifier,
- map->clone(globalObject, globalObject->vm(), globalObject->mapStructure()));
+ // });
+ }
+ // globalObject->vm().heap.deleteAllUnlinkedCodeBlocks(
+ // JSC::DeleteAllCodeEffort::PreventCollectionAndDeleteAllCode);
+ // vm.whenIdle([globalObject, oldMap, map]() {
+ // auto recordIdentifier = JSC::Identifier::fromString(globalObject->vm(), "module");
+
+ // JSC::JSModuleRecord *record;
+ // JSC::JSValue key;
+ // JSC::JSValue value;
+ // JSC::JSObject *mod;
+ // JSC::JSObject *nextObject;
+ // JSC::forEachInIterable(
+ // globalObject, oldMap,
+ // [&](JSC::VM &vm, JSC::JSGlobalObject *globalObject, JSC::JSValue nextValue) {
+ // nextObject = JSC::jsDynamicCast<JSC::JSObject *>(vm, nextValue);
+ // key = nextObject->getIndex(globalObject, static_cast<unsigned>(0));
+
+ // if (!map->has(globalObject, key)) {
+ // value = nextObject->getIndex(globalObject, static_cast<unsigned>(1));
+ // mod = JSC::jsDynamicCast<JSC::JSObject *>(vm, value);
+ // if (mod) {
+ // record = JSC::jsDynamicCast<JSC::JSModuleRecord *>(
+ // vm, mod->getDirect(vm, recordIdentifier));
+ // if (record) {
+ // auto code = &record->sourceCode();
+ // if (code) {
+
+ // Zig::SourceProvider *provider =
+ // reinterpret_cast<Zig::SourceProvider *>(code->provider());
+ // // code->~SourceCode();
+ // if (provider) { provider->freeSourceCode(); }
+ // }
+ // }
+ // }
+ // }
+ // });
+
+ // oldMap->clear(globalObject);
+ // }
+ // }
+ // map
}
-
- return false;
+ return true;
}
-
JSC::JSInternalPromise *GlobalObject::moduleLoaderFetch(JSGlobalObject *globalObject,
JSModuleLoader *loader, JSValue key,
JSValue value1, JSValue value2) {
@@ -319,7 +391,7 @@ JSC::JSInternalPromise *GlobalObject::moduleLoaderFetch(JSGlobalObject *globalOb
promise->resolve(globalObject, jsSourceCode);
globalObject->vm().drainMicrotasks();
return promise;
- }
+}
JSC::JSObject *GlobalObject::moduleLoaderCreateImportMetaProperties(JSGlobalObject *globalObject,
JSModuleLoader *loader,
diff --git a/src/javascript/jsc/bindings/ZigSourceProvider.cpp b/src/javascript/jsc/bindings/ZigSourceProvider.cpp
index 63bf1dcfd..a2cb86c39 100644
--- a/src/javascript/jsc/bindings/ZigSourceProvider.cpp
+++ b/src/javascript/jsc/bindings/ZigSourceProvider.cpp
@@ -23,11 +23,34 @@ using String = WTF::String;
using SourceProviderSourceType = JSC::SourceProviderSourceType;
Ref<SourceProvider> SourceProvider::create(ResolvedSource resolvedSource) {
- return adoptRef(*new SourceProvider(
- resolvedSource,
- JSC::SourceOrigin(WTF::URL::fileURLWithFileSystemPath(toString(resolvedSource.source_url))),
- toStringNotConst(resolvedSource.source_url), TextPosition(),
- JSC::SourceProviderSourceType::Module));
+ void *allocator = resolvedSource.allocator;
+
+ WTF::StringImpl *stringImpl = nullptr;
+ if (allocator) {
+ Ref<WTF::ExternalStringImpl> stringImpl_ = WTF::ExternalStringImpl::create(
+ resolvedSource.source_code.ptr, resolvedSource.source_code.len,
+ [allocator](WTF::ExternalStringImpl *str, void *ptr, unsigned int len) {
+ ZigString__free((const unsigned char *)ptr, len, allocator);
+ });
+ return adoptRef(*new SourceProvider(
+ resolvedSource, reinterpret_cast<WTF::StringImpl *>(stringImpl_.ptr()),
+ JSC::SourceOrigin(WTF::URL::fileURLWithFileSystemPath(toString(resolvedSource.source_url))),
+ toStringNotConst(resolvedSource.source_url), TextPosition(),
+ JSC::SourceProviderSourceType::Module));
+
+ } else {
+ Ref<WTF::ExternalStringImpl> stringImpl_ = WTF::ExternalStringImpl::create(
+ resolvedSource.source_code.ptr, resolvedSource.source_code.len,
+ [=](WTF::ExternalStringImpl *str, void *ptr, unsigned int len) {
+ // ZigString__free((const unsigned char *)ptr, len,
+ // allocator);
+ });
+ return adoptRef(*new SourceProvider(
+ resolvedSource, reinterpret_cast<WTF::StringImpl *>(stringImpl_.ptr()),
+ JSC::SourceOrigin(WTF::URL::fileURLWithFileSystemPath(toString(resolvedSource.source_url))),
+ toStringNotConst(resolvedSource.source_url), TextPosition(),
+ JSC::SourceProviderSourceType::Module));
+ }
}
unsigned SourceProvider::getHash() {
@@ -37,6 +60,20 @@ unsigned SourceProvider::getHash() {
return m_hash;
}
+void SourceProvider::freeSourceCode() {
+ if (did_free_source_code) { return; }
+ did_free_source_code = true;
+ if (m_resolvedSource.allocator != 0) { // // WTF::ExternalStringImpl::destroy(m_source.ptr());
+ this->m_source = WTF::StringImpl::empty()->isolatedCopy();
+ this->m_hash = 0;
+ m_resolvedSource.allocator = 0;
+ }
+ // if (m_resolvedSource.allocator != 0) {
+ // ZigString__free(m_resolvedSource.source_code.ptr, m_resolvedSource.source_code.len,
+ // m_resolvedSource.allocator);
+ // }
+}
+
void SourceProvider::updateCache(const UnlinkedFunctionExecutable *executable, const SourceCode &,
CodeSpecializationKind kind,
const UnlinkedFunctionCodeBlock *codeBlock) {
@@ -122,15 +159,14 @@ int SourceProvider::readCache(JSC::VM &vm, const JSC::SourceCode &sourceCode) {
if (fileTotalSize == 0) return 0;
Ref<JSC::CachedBytecode> cachedBytecode = JSC::CachedBytecode::create(WTFMove(mappedFile));
- auto key = JSC::sourceCodeKeyForSerializedModule(vm, sourceCode);
- if (isCachedBytecodeStillValid(vm, cachedBytecode.copyRef(), key,
- JSC::SourceCodeType::ModuleType)) {
- m_cachedBytecode = WTFMove(cachedBytecode);
- return 1;
- } else {
- FileSystem::truncateFile(fd, 0);
- return 0;
- }
+ // auto key = JSC::sourceCodeKeyForSerializedModule(vm, sourceCode);
+ // if (isCachedBytecodeStillValid(vm, cachedBytecode.copyRef(), key,
+ // JSC::SourceCodeType::ModuleType)) {
+ m_cachedBytecode = WTFMove(cachedBytecode);
+ return 1;
+ // } else {
+ // FileSystem::truncateFile(fd, 0);
+ // return 0;
+ // }
}
-
}; // namespace Zig \ No newline at end of file
diff --git a/src/javascript/jsc/bindings/ZigSourceProvider.h b/src/javascript/jsc/bindings/ZigSourceProvider.h
index 11e89310a..41002af97 100644
--- a/src/javascript/jsc/bindings/ZigSourceProvider.h
+++ b/src/javascript/jsc/bindings/ZigSourceProvider.h
@@ -34,7 +34,11 @@ class SourceProvider final : public JSC::SourceProvider {
public:
static Ref<SourceProvider> create(ResolvedSource resolvedSource);
- ~SourceProvider() { commitCachedBytecode(); }
+ ~SourceProvider() {
+ freeSourceCode();
+
+ commitCachedBytecode();
+ }
unsigned hash() const { return m_hash; };
StringView source() const { return StringView(m_source.get()); }
@@ -52,23 +56,25 @@ class SourceProvider final : public JSC::SourceProvider {
void readOrGenerateByteCodeCache(JSC::VM &vm, const JSC::SourceCode &sourceCode);
ResolvedSource m_resolvedSource;
int readCache(JSC::VM &vm, const JSC::SourceCode &sourceCode);
+ void freeSourceCode();
private:
- SourceProvider(ResolvedSource resolvedSource, const SourceOrigin &sourceOrigin,
- WTF::String &&sourceURL, const TextPosition &startPosition,
- JSC::SourceProviderSourceType sourceType)
- : Base(sourceOrigin, WTFMove(sourceURL), startPosition, sourceType),
- m_source(
- *WTF::String(resolvedSource.source_code.ptr, resolvedSource.source_code.len).impl()) {
+ SourceProvider(ResolvedSource resolvedSource, WTF::StringImpl *sourceImpl,
+ const SourceOrigin &sourceOrigin, WTF::String &&sourceURL,
+ const TextPosition &startPosition, JSC::SourceProviderSourceType sourceType)
+ : Base(sourceOrigin, WTFMove(sourceURL), startPosition, sourceType), m_source(*sourceImpl) {
m_resolvedSource = resolvedSource;
+
m_hash = resolvedSource.hash;
getHash();
}
+
unsigned m_hash;
unsigned getHash();
RefPtr<JSC::CachedBytecode> m_cachedBytecode;
Ref<WTF::StringImpl> m_source;
+ bool did_free_source_code = false;
// JSC::SourceCodeKey key;
};
diff --git a/src/javascript/jsc/bindings/exports.zig b/src/javascript/jsc/bindings/exports.zig
index 41e13d98e..07fd9b02c 100644
--- a/src/javascript/jsc/bindings/exports.zig
+++ b/src/javascript/jsc/bindings/exports.zig
@@ -217,10 +217,19 @@ pub const ResolvedSource = extern struct {
source_url: ZigString,
hash: u32,
+ allocator: ?*c_void,
+
// 0 means disabled
bytecodecache_fd: u64,
};
+export fn ZigString__free(ptr: [*]const u8, len: usize, allocator_: ?*c_void) void {
+ var allocator: *std.mem.Allocator = @ptrCast(*std.mem.Allocator, @alignCast(@alignOf(*std.mem.Allocator), allocator_ orelse return));
+
+ var str = ptr[0..len];
+ allocator.free(str);
+}
+
pub const JSErrorCode = enum(u8) {
Error = 0,
EvalError = 1,
diff --git a/src/javascript/jsc/bindings/header-gen.zig b/src/javascript/jsc/bindings/header-gen.zig
index 692f60130..8b9bb504e 100644
--- a/src/javascript/jsc/bindings/header-gen.zig
+++ b/src/javascript/jsc/bindings/header-gen.zig
@@ -67,15 +67,15 @@ pub fn cTypeLabel(comptime Type: type) ?[]const u8 {
};
}
-var buffer = std.ArrayList(u8).init(default_allocator);
+var buffer = std.ArrayList(u8).init(std.heap.c_allocator);
var writer = buffer.writer();
-var impl_buffer = std.ArrayList(u8).init(default_allocator);
+var impl_buffer = std.ArrayList(u8).init(std.heap.c_allocator);
var impl_writer = impl_buffer.writer();
-var bufset = std.BufSet.init(default_allocator);
-var type_names = TypeNameMap.init(default_allocator);
-var opaque_types = std.BufSet.init(default_allocator);
-var size_map = std.StringHashMap(u32).init(default_allocator);
-var align_map = std.StringHashMap(u29).init(default_allocator);
+var bufset = std.BufSet.init(std.heap.c_allocator);
+var type_names = TypeNameMap.init(std.heap.c_allocator);
+var opaque_types = std.BufSet.init(std.heap.c_allocator);
+var size_map = std.StringHashMap(u32).init(std.heap.c_allocator);
+var align_map = std.StringHashMap(u29).init(std.heap.c_allocator);
pub const C_Generator = struct {
filebase: []const u8,
@@ -618,13 +618,13 @@ pub fn HeaderGen(comptime import: type, comptime fname: []const u8) type {
\\
) catch {};
- var impl_second_buffer = std.ArrayList(u8).init(default_allocator);
+ var impl_second_buffer = std.ArrayList(u8).init(std.heap.c_allocator);
var impl_second_writer = impl_second_buffer.writer();
- var impl_third_buffer = std.ArrayList(u8).init(default_allocator);
+ var impl_third_buffer = std.ArrayList(u8).init(std.heap.c_allocator);
var impl_third_writer = impl_third_buffer.writer();
- var impl_fourth_buffer = std.ArrayList(u8).init(default_allocator);
+ var impl_fourth_buffer = std.ArrayList(u8).init(std.heap.c_allocator);
var impl_fourth_writer = impl_fourth_buffer.writer();
// inline for (import.all_static_externs) |static_extern, i| {
@@ -770,7 +770,7 @@ pub fn HeaderGen(comptime import: type, comptime fname: []const u8) type {
var iter = type_names.iterator();
const NamespaceMap = std.StringArrayHashMap(std.BufMap);
- var namespaces = NamespaceMap.init(default_allocator);
+ var namespaces = NamespaceMap.init(std.heap.c_allocator);
var size_iter = size_map.iterator();
while (size_iter.next()) |size| {
@@ -808,7 +808,7 @@ pub fn HeaderGen(comptime import: type, comptime fname: []const u8) type {
}
if (!namespaces.contains(namespace)) {
- namespaces.put(namespace, std.BufMap.init(default_allocator)) catch unreachable;
+ namespaces.put(namespace, std.BufMap.init(std.heap.c_allocator)) catch unreachable;
}
const class = key[namespace_start + 2 ..];
namespaces.getPtr(namespace).?.put(class, value) catch unreachable;
diff --git a/src/javascript/jsc/bindings/headers-cpp.h b/src/javascript/jsc/bindings/headers-cpp.h
index 50fad777b..312476e25 100644
--- a/src/javascript/jsc/bindings/headers-cpp.h
+++ b/src/javascript/jsc/bindings/headers-cpp.h
@@ -1,4 +1,4 @@
-//-- AUTOGENERATED FILE -- 1628467440
+//-- AUTOGENERATED FILE -- 1630718473
// clang-format off
#pragma once
diff --git a/src/javascript/jsc/bindings/headers-handwritten.h b/src/javascript/jsc/bindings/headers-handwritten.h
index 10bf85a52..a8d53f6e3 100644
--- a/src/javascript/jsc/bindings/headers-handwritten.h
+++ b/src/javascript/jsc/bindings/headers-handwritten.h
@@ -1,3 +1,5 @@
+#pragma once
+
typedef uint16_t ZigErrorCode;
typedef struct ZigString {
@@ -21,6 +23,7 @@ typedef struct ResolvedSource {
ZigString source_code;
ZigString source_url;
uint32_t hash;
+ void *allocator;
uint64_t bytecodecache_fd;
} ResolvedSource;
typedef union ErrorableResolvedSourceResult {
@@ -93,4 +96,5 @@ const JSErrorCode JSErrorCodeUserErrorCode = 254;
#ifdef __cplusplus
extern "C" ZigErrorCode Zig_ErrorCodeParserError;
+extern "C" void ZigString__free(const unsigned char *ptr, size_t len, void *allocator);
#endif
diff --git a/src/javascript/jsc/bindings/headers.h b/src/javascript/jsc/bindings/headers.h
index ed9678c65..3671095cc 100644
--- a/src/javascript/jsc/bindings/headers.h
+++ b/src/javascript/jsc/bindings/headers.h
@@ -1,4 +1,4 @@
-//-- AUTOGENERATED FILE -- 1628467440
+//-- AUTOGENERATED FILE -- 1630718473
// clang-format: off
#pragma once
diff --git a/src/javascript/jsc/bindings/headers.zig b/src/javascript/jsc/bindings/headers.zig
index 10a5dd526..98db40c44 100644
--- a/src/javascript/jsc/bindings/headers.zig
+++ b/src/javascript/jsc/bindings/headers.zig
@@ -37,7 +37,7 @@ pub const __mbstate_t = extern union {
pub const __darwin_mbstate_t = __mbstate_t;
pub const __darwin_ptrdiff_t = c_long;
pub const __darwin_size_t = c_ulong;
-
+
pub const JSC__RegExpPrototype = struct_JSC__RegExpPrototype;
pub const JSC__GeneratorPrototype = struct_JSC__GeneratorPrototype;
diff --git a/src/javascript/jsc/javascript.zig b/src/javascript/jsc/javascript.zig
index 8bbfa3e74..14b010b17 100644
--- a/src/javascript/jsc/javascript.zig
+++ b/src/javascript/jsc/javascript.zig
@@ -350,6 +350,7 @@ pub const VirtualMachine = struct {
flush_list: std.ArrayList(string),
entry_point: ServerEntryPoint = undefined,
+ arena: *std.heap.ArenaAllocator = undefined,
has_loaded: bool = false,
transpiled_count: usize = 0,
@@ -415,6 +416,14 @@ pub const VirtualMachine = struct {
);
VirtualMachine.vm_loaded = true;
+ if (!source_code_printer_loaded) {
+ var writer = try js_printer.BufferWriter.init(allocator);
+ source_code_printer = js_printer.BufferPrinter.init(writer);
+ source_code_printer.ctx.append_null_byte = false;
+
+ source_code_printer_loaded = true;
+ }
+
return VirtualMachine.vm;
}
@@ -460,6 +469,7 @@ pub const VirtualMachine = struct {
const code = try vm.node_modules.?.readCodeAsStringSlow(vm.allocator);
return ResolvedSource{
+ .allocator = null,
.source_code = ZigString.init(code),
.specifier = ZigString.init(vm.bundler.linker.nodeModuleBundleImportPath()),
.source_url = ZigString.init(vm.bundler.options.node_modules_bundle_pretty_path),
@@ -471,6 +481,7 @@ pub const VirtualMachine = struct {
};
} else if (strings.eqlComptime(_specifier, Runtime.Runtime.Imports.Name)) {
return ResolvedSource{
+ .allocator = null,
.source_code = ZigString.init(Runtime.Runtime.sourceContent()),
.specifier = ZigString.init(Runtime.Runtime.Imports.Name),
.source_url = ZigString.init(Runtime.Runtime.Imports.Name),
@@ -521,14 +532,6 @@ pub const VirtualMachine = struct {
false,
);
- if (!source_code_printer_loaded) {
- var writer = try js_printer.BufferWriter.init(vm.allocator);
- source_code_printer = js_printer.BufferPrinter.init(writer);
- source_code_printer.ctx.append_null_byte = false;
-
- source_code_printer_loaded = true;
- }
-
source_code_printer.ctx.reset();
var written = try vm.bundler.print(
@@ -543,6 +546,7 @@ pub const VirtualMachine = struct {
}
return ResolvedSource{
+ .allocator = null,
.source_code = ZigString.init(vm.allocator.dupe(u8, source_code_printer.ctx.written) catch unreachable),
.specifier = ZigString.init(std.mem.span(main_file_name)),
.source_url = ZigString.init(std.mem.span(main_file_name)),
@@ -564,6 +568,8 @@ pub const VirtualMachine = struct {
vm.bundler.resetStore();
const hash = http.Watcher.getHash(path.text);
+ var allocator = if (vm.has_loaded) &vm.arena.allocator else vm.allocator;
+
var fd: ?StoredFileDescriptorType = null;
if (vm.watcher) |watcher| {
@@ -583,7 +589,7 @@ pub const VirtualMachine = struct {
}
var parse_result = vm.bundler.parse(
- vm.bundler.allocator,
+ allocator,
path,
loader,
0,
@@ -606,14 +612,6 @@ pub const VirtualMachine = struct {
vm.resolved_count += vm.bundler.linker.import_counter - start_count;
vm.bundler.linker.import_counter = 0;
- if (!source_code_printer_loaded) {
- var writer = try js_printer.BufferWriter.init(vm.allocator);
- source_code_printer = js_printer.BufferPrinter.init(writer);
- source_code_printer.ctx.append_null_byte = false;
-
- source_code_printer_loaded = true;
- }
-
source_code_printer.ctx.reset();
var written = try vm.bundler.print(
@@ -628,6 +626,7 @@ pub const VirtualMachine = struct {
}
return ResolvedSource{
+ .allocator = if (vm.has_loaded) vm.allocator else null,
.source_code = ZigString.init(vm.allocator.dupe(u8, source_code_printer.ctx.written) catch unreachable),
.specifier = ZigString.init(specifier),
.source_url = ZigString.init(path.text),
@@ -637,6 +636,7 @@ pub const VirtualMachine = struct {
},
else => {
return ResolvedSource{
+ .allocator = vm.allocator,
.source_code = ZigString.init(try strings.quotedAlloc(VirtualMachine.vm.allocator, path.pretty)),
.specifier = ZigString.init(path.text),
.source_url = ZigString.init(path.text),
@@ -1334,6 +1334,7 @@ pub const EventListenerMixin = struct {
// Rely on JS finalizer
var fetch_event = try vm.allocator.create(FetchEvent);
+
fetch_event.* = FetchEvent{
.request_context = request_context,
.request = Request{ .request_context = request_context },
diff --git a/src/js_ast.zig b/src/js_ast.zig
index 8899df8c5..750100750 100644
--- a/src/js_ast.zig
+++ b/src/js_ast.zig
@@ -31,7 +31,7 @@ pub fn NewBaseStore(comptime Union: anytype, comptime count: usize) type {
used: usize = 0,
allocator: *std.mem.Allocator,
- pub fn isFull(block: *const Block) bool {
+ pub inline fn isFull(block: *const Block) bool {
return block.used >= block.items.len;
}
diff --git a/src/linker.zig b/src/linker.zig
index f07fa3f07..dea14f675 100644
--- a/src/linker.zig
+++ b/src/linker.zig
@@ -166,7 +166,11 @@ pub fn NewLinker(comptime BundlerType: type) type {
}
pub inline fn nodeModuleBundleImportPath(this: *const ThisLinker) string {
- return if (this.options.node_modules_bundle_url.len > 0) this.options.node_modules_bundle_url else this.options.node_modules_bundle.?.bundle.import_from_name;
+ return if (this.options.platform != .bun and
+ this.options.node_modules_bundle_url.len > 0)
+ this.options.node_modules_bundle_url
+ else
+ this.options.node_modules_bundle.?.bundle.import_from_name;
}
// pub const Scratch = struct {
diff --git a/src/memory_allocator.zig b/src/memory_allocator.zig
index 3f5a7897c..d8476d0f8 100644
--- a/src/memory_allocator.zig
+++ b/src/memory_allocator.zig
@@ -115,6 +115,7 @@ const CAllocator = struct {
return mem.alignAllocLen(full_len, new_len, len_align);
}
}
+
return error.OutOfMemory;
}
};
diff --git a/src/resolver/resolver.zig b/src/resolver/resolver.zig
index 1d438999d..4d8f91881 100644
--- a/src/resolver/resolver.zig
+++ b/src/resolver/resolver.zig
@@ -40,7 +40,8 @@ pub const TemporaryBuffer = struct {
pub threadlocal var ExtensionPathBuf: [512]u8 = undefined;
pub threadlocal var TSConfigMatchStarBuf: [512]u8 = undefined;
pub threadlocal var TSConfigMatchPathBuf: [512]u8 = undefined;
- pub threadlocal var TSConfigMatchFullBuf: [512]u8 = undefined;
+ pub threadlocal var TSConfigMatchFullBuf: [std.fs.MAX_PATH_BYTES]u8 = undefined;
+ pub threadlocal var TSConfigMatchFullBuf2: [std.fs.MAX_PATH_BYTES]u8 = undefined;
};
pub const PathPair = struct {
@@ -195,6 +196,7 @@ threadlocal var _open_dirs: [256]std.fs.Dir = undefined;
threadlocal var resolve_without_remapping_buf: [std.fs.MAX_PATH_BYTES]u8 = undefined;
threadlocal var index_buf: [std.fs.MAX_PATH_BYTES]u8 = undefined;
threadlocal var dir_info_uncached_filename_buf: [std.fs.MAX_PATH_BYTES]u8 = undefined;
+threadlocal var dir_info_uncached_path_buf: [std.fs.MAX_PATH_BYTES]u8 = undefined;
threadlocal var tsconfig_base_url_buf: [std.fs.MAX_PATH_BYTES]u8 = undefined;
threadlocal var relative_abs_path_buf: [std.fs.MAX_PATH_BYTES]u8 = undefined;
threadlocal var load_as_file_or_directory_via_tsconfig_base_path: [std.fs.MAX_PATH_BYTES]u8 = undefined;
@@ -1240,16 +1242,22 @@ pub fn NewResolver(cache_files: bool) type {
return r.dir_cache.get(path);
}
- inline fn dirInfoCachedMaybeLog(r: *ThisResolver, path: string, comptime enable_logging: bool, comptime follow_symlinks: bool) !?*DirInfo {
+ inline fn dirInfoCachedMaybeLog(r: *ThisResolver, __path: string, comptime enable_logging: bool, comptime follow_symlinks: bool) !?*DirInfo {
r.mutex.lock();
defer r.mutex.unlock();
+ var _path = __path;
+ if (strings.eqlComptime(_path, "./") or strings.eqlComptime(_path, "."))
+ _path = r.fs.top_level_dir;
- const top_result = try r.dir_cache.getOrPut(path);
+ const top_result = try r.dir_cache.getOrPut(_path);
if (top_result.status != .unknown) {
return r.dir_cache.atIndex(top_result.index);
}
var i: i32 = 1;
+ std.mem.copy(u8, &dir_info_uncached_path_buf, _path);
+ var path = dir_info_uncached_path_buf[0.._path.len];
+
_dir_entry_paths_to_resolve[0] = (DirEntryResolveQueueItem{ .result = top_result, .unsafe_path = path, .safe_path = "" });
var top = Dirname.dirname(path);
@@ -1258,7 +1266,12 @@ pub fn NewResolver(cache_files: bool) type {
.hash = 0,
.status = .not_found,
};
- const root_path = if (isWindows) std.fs.path.diskDesignator(path) else "/";
+ const root_path = if (comptime isWindows)
+ std.fs.path.diskDesignator(path)
+ else
+ // we cannot just use "/"
+ // we will write to the buffer past the ptr len so it must be a non-const buffer
+ path[0..1];
var rfs: *Fs.FileSystem.RealFS = &r.fs.fs;
rfs.entries_mutex.lock();
@@ -1321,16 +1334,15 @@ pub fn NewResolver(cache_files: bool) type {
// We want to walk in a straight line from the topmost directory to the desired directory
// For each directory we visit, we get the entries, but not traverse into child directories
// (unless those child directores are in the queue)
- // Going top-down rather than bottom-up should have best performance because we can use
- // the file handle from the parent directory to open the child directory
- // It's important that we walk in precisely a straight line
- // For example
+ // We go top-down instead of bottom-up to increase odds of reusing previously open file handles
// "/home/jarred/Code/node_modules/react/cjs/react.development.js"
// ^
// If we start there, we will traverse all of /home/jarred, including e.g. /home/jarred/Downloads
// which is completely irrelevant.
- // After much experimentation, fts_open is not the fastest way. fts actually just uses readdir!!
+ // After much experimentation...
+ // - fts_open is not the fastest way to read directories. fts actually just uses readdir!!
+ // - remember
var _safe_path: ?string = null;
// Start at the top.
@@ -1341,20 +1353,21 @@ pub fn NewResolver(cache_files: bool) type {
var _open_dir: anyerror!std.fs.Dir = undefined;
if (queue_top.fd == 0) {
- if (open_dir_count > 0) {
- _open_dir = _open_dirs[open_dir_count - 1].openDir(
- std.fs.path.basename(queue_top.unsafe_path),
- .{ .iterate = true, .no_follow = !follow_symlinks },
- );
- } else {
- _open_dir = std.fs.openDirAbsolute(
- queue_top.unsafe_path,
- .{
- .iterate = true,
- .no_follow = !follow_symlinks,
- },
- );
- }
+
+ // This saves us N copies of .toPosixPath
+ // which was likely the perf gain from resolving directories relative to the parent directory, anyway.
+ const prev_char = path.ptr[queue_top.unsafe_path.len];
+ path.ptr[queue_top.unsafe_path.len] = 0;
+ defer path.ptr[queue_top.unsafe_path.len] = prev_char;
+ var sentinel = path.ptr[0..queue_top.unsafe_path.len :0];
+ _open_dir = std.fs.openDirAbsoluteZ(
+ sentinel,
+ .{
+ .iterate = true,
+ .no_follow = !follow_symlinks,
+ },
+ );
+ // }
}
const open_dir = if (queue_top.fd != 0) std.fs.Dir{ .fd = queue_top.fd } else (_open_dir catch |err| {
@@ -1495,14 +1508,7 @@ pub fn NewResolver(cache_files: bool) type {
// This closely follows the behavior of "tryLoadModuleUsingPaths()" in the
// official TypeScript compiler
- pub fn matchTSConfigPaths(r: *ThisResolver, tsconfig: *TSConfigJSON, path_: string, kind: ast.ImportKind) ?MatchResult {
- // Rewrite absolute import paths to be project-relative
- // This is so that whe nimporting URLs from the web, we can still match them.
- var path = path_;
- if (strings.startsWith(path_, r.fs.top_level_dir)) {
- path = path[r.fs.top_level_dir.len..];
- }
-
+ pub fn matchTSConfigPaths(r: *ThisResolver, tsconfig: *TSConfigJSON, path: string, kind: ast.ImportKind) ?MatchResult {
if (r.debug_logs) |*debug| {
debug.addNoteFmt("Matching \"{s}\" against \"paths\" in \"{s}\"", .{ path, tsconfig.abs_path }) catch unreachable;
}
@@ -1569,9 +1575,8 @@ pub fn NewResolver(cache_files: bool) type {
// because we want the output to always be deterministic
if (strings.startsWith(path, prefix) and
strings.endsWith(path, suffix) and
- (prefix.len > longest_match_prefix_length or
- (prefix.len == longest_match_prefix_length and
- suffix.len > longest_match_suffix_length)))
+ (prefix.len >= longest_match_prefix_length and
+ suffix.len > longest_match_suffix_length))
{
longest_match_prefix_length = @intCast(i32, prefix.len);
longest_match_suffix_length = @intCast(i32, suffix.len);
@@ -1591,31 +1596,20 @@ pub fn NewResolver(cache_files: bool) type {
// Swap out the "*" in the original path for whatever the "*" matched
const matched_text = path[longest_match.prefix.len .. path.len - longest_match.suffix.len];
- std.mem.copy(
- u8,
- &TemporaryBuffer.TSConfigMatchPathBuf,
- original_path,
- );
- var start: usize = 0;
- var total_length: usize = 0;
- const star = std.mem.indexOfScalar(u8, original_path, '*') orelse unreachable;
- total_length = star;
- const parts = [_]string{ original_path[0..total_length], matched_text, longest_match.suffix };
- const region = r.fs.joinBuf(&parts, &TemporaryBuffer.TSConfigMatchPathBuf);
-
- // Load the original path relative to the "baseUrl" from tsconfig.json
- var absolute_original_path: string = region;
-
- if (!std.fs.path.isAbsolute(region)) {
- var paths = [_]string{ abs_base_url, region };
- absolute_original_path = r.fs.absAlloc(r.allocator, &paths) catch unreachable;
- } else {
- absolute_original_path = std.mem.dupe(r.allocator, u8, region) catch unreachable;
- }
+ const total_length = std.mem.indexOfScalar(u8, original_path, '*') orelse unreachable;
+ var prefix_parts = [_]string{ abs_base_url, original_path[0..total_length] };
- defer {
- r.allocator.free(absolute_original_path);
- }
+ // 1. Normalize the base path
+ // so that "/Users/foo/project/", "../components/*" => "/Users/foo/components/""
+ var prefix = r.fs.absBuf(&prefix_parts, &TemporaryBuffer.TSConfigMatchFullBuf2);
+
+ // 2. Join the new base path with the matched result
+ // so that "/Users/foo/components/", "/foo/bar" => /Users/foo/components/foo/bar
+ var parts = [_]string{ prefix, std.mem.trimLeft(u8, matched_text, "/"), std.mem.trimLeft(u8, longest_match.suffix, "/") };
+ var absolute_original_path = r.fs.absBuf(
+ &parts,
+ &TemporaryBuffer.TSConfigMatchFullBuf,
+ );
if (r.loadAsFileOrDirectory(absolute_original_path, kind)) |res| {
return res;
@@ -1881,7 +1875,10 @@ pub fn NewResolver(cache_files: bool) type {
}
}
- const dir_info = (r.dirInfoCached(path) catch null) orelse return null;
+ const dir_info = (r.dirInfoCached(path) catch |err| {
+ if (comptime isDebug) Output.prettyErrorln("err: {s} reading {s}", .{ @errorName(err), path });
+ return null;
+ }) orelse return null;
var package_json: ?*PackageJSON = null;
// Try using the main field(s) from "package.json"
@@ -2181,6 +2178,7 @@ pub fn NewResolver(cache_files: bool) type {
if (!r.opts.preserve_symlinks) {
if (parent.?.getEntries()) |parent_entries| {
if (parent_entries.get(base)) |lookup| {
+ if (entries.fd != 0 and lookup.entry.cache.fd == 0) lookup.entry.cache.fd = entries.fd;
const entry = lookup.entry;
var symlink = entry.symlink(rfs);
diff --git a/src/resolver/tsconfig_json.zig b/src/resolver/tsconfig_json.zig
index 5ca1f4b26..20ebd3990 100644
--- a/src/resolver/tsconfig_json.zig
+++ b/src/resolver/tsconfig_json.zig
@@ -39,7 +39,7 @@ pub const TSConfigJSON = struct {
preserve_imports_not_used_as_values: bool = false,
- pub fn hasBaseURL(tsconfig: *TSConfigJSON) bool {
+ pub fn hasBaseURL(tsconfig: *const TSConfigJSON) bool {
return tsconfig.base_url.len > 0;
}
@@ -214,7 +214,6 @@ pub const TSConfigJSON = struct {
}
}
if (count > 0) {
-
result.paths.put(
key,
values[0..count],
diff --git a/src/string_immutable.zig b/src/string_immutable.zig
index f48850908..055239c1a 100644
--- a/src/string_immutable.zig
+++ b/src/string_immutable.zig
@@ -275,16 +275,24 @@ pub inline fn eqlInsensitive(self: string, other: anytype) bool {
}
pub fn eqlComptime(self: string, comptime alt: anytype) bool {
+ return eqlComptimeCheckLen(self, alt, true);
+}
+
+pub fn eqlComptimeIgnoreLen(self: string, comptime alt: anytype) bool {
+ return eqlComptimeCheckLen(self, alt, false);
+}
+
+inline fn eqlComptimeCheckLen(self: string, comptime alt: anytype, comptime check_len: bool) bool {
switch (comptime alt.len) {
0 => {
@compileError("Invalid size passed to eqlComptime");
},
2 => {
const check = comptime std.mem.readIntNative(u16, alt[0..alt.len]);
- return self.len == alt.len and std.mem.readIntNative(u16, self[0..2]) == check;
+ return ((comptime !check_len) or self.len == alt.len) and std.mem.readIntNative(u16, self[0..2]) == check;
},
1, 3 => {
- if (alt.len != self.len) {
+ if ((comptime check_len) and alt.len != self.len) {
return false;
}
@@ -295,7 +303,7 @@ pub fn eqlComptime(self: string, comptime alt: anytype) bool {
},
4 => {
const check = comptime std.mem.readIntNative(u32, alt[0..alt.len]);
- return self.len == alt.len and std.mem.readIntNative(u32, self[0..4]) == check;
+ return ((comptime !check_len) or self.len == alt.len) and std.mem.readIntNative(u32, self[0..4]) == check;
},
6 => {
const first = std.mem.readIntNative(u32, alt[0..4]);
@@ -306,7 +314,7 @@ pub fn eqlComptime(self: string, comptime alt: anytype) bool {
},
5, 7 => {
const check = comptime std.mem.readIntNative(u32, alt[0..4]);
- if (self.len != alt.len or std.mem.readIntNative(u32, self[0..4]) != check) {
+ if (((comptime check_len) and self.len != alt.len) or std.mem.readIntNative(u32, self[0..4]) != check) {
return false;
}
const remainder = self[4..];
@@ -317,12 +325,12 @@ pub fn eqlComptime(self: string, comptime alt: anytype) bool {
},
8 => {
const check = comptime std.mem.readIntNative(u64, alt[0..alt.len]);
- return self.len == alt.len and std.mem.readIntNative(u64, self[0..8]) == check;
+ return ((comptime !check_len) or self.len == alt.len) and std.mem.readIntNative(u64, self[0..8]) == check;
},
9...11 => {
const first = std.mem.readIntNative(u64, alt[0..8]);
- if (self.len != alt.len or first != std.mem.readIntNative(u64, self[0..8])) {
+ if (((comptime check_len) and self.len != alt.len) or first != std.mem.readIntNative(u64, self[0..8])) {
return false;
}
@@ -334,13 +342,13 @@ pub fn eqlComptime(self: string, comptime alt: anytype) bool {
12 => {
const first = comptime std.mem.readIntNative(u64, alt[0..8]);
const second = comptime std.mem.readIntNative(u32, alt[8..12]);
- return (self.len == alt.len) and first == std.mem.readIntNative(u64, self[0..8]) and second == std.mem.readIntNative(u32, self[8..12]);
+ return ((comptime !check_len) or self.len == alt.len) and first == std.mem.readIntNative(u64, self[0..8]) and second == std.mem.readIntNative(u32, self[8..12]);
},
13...15 => {
const first = comptime std.mem.readIntNative(u64, alt[0..8]);
const second = comptime std.mem.readIntNative(u32, alt[8..12]);
- if (self.len != alt.len or first != std.mem.readIntNative(u64, self[0..8]) or second != std.mem.readIntNative(u32, self[8..12])) {
+ if (((comptime !check_len) or self.len != alt.len) or first != std.mem.readIntNative(u64, self[0..8]) or second != std.mem.readIntNative(u32, self[8..12])) {
return false;
}
@@ -353,7 +361,7 @@ pub fn eqlComptime(self: string, comptime alt: anytype) bool {
16 => {
const first = comptime std.mem.readIntNative(u64, alt[0..8]);
const second = comptime std.mem.readIntNative(u64, alt[8..15]);
- return (self.len == alt.len) and first == std.mem.readIntNative(u64, self[0..8]) and second == std.mem.readIntNative(u64, self[8..16]);
+ return ((comptime !check_len) or self.len == alt.len) and first == std.mem.readIntNative(u64, self[0..8]) and second == std.mem.readIntNative(u64, self[8..16]);
},
else => {
@compileError(alt ++ " is too long.");
@@ -365,6 +373,20 @@ pub inline fn append(allocator: *std.mem.Allocator, self: string, other: string)
return std.fmt.allocPrint(allocator, "{s}{s}", .{ self, other });
}
+pub inline fn joinBuf(out: []u8, parts: anytype, comptime parts_len: usize) []u8 {
+ var remain = out;
+ var count: usize = 0;
+ comptime var i: usize = 0;
+ inline while (i < parts_len) : (i += 1) {
+ const part = parts[i];
+ std.mem.copy(u8, remain, part);
+ remain = remain[part.len..];
+ count += part.len;
+ }
+
+ return out[0..count];
+}
+
pub fn index(self: string, str: string) i32 {
if (std.mem.indexOf(u8, self, str)) |i| {
return @intCast(i32, i);
diff --git a/src/test/fixtures/tsconfig.json b/src/test/fixtures/tsconfig.json
index 3408c09f1..b3105de67 100644
--- a/src/test/fixtures/tsconfig.json
+++ b/src/test/fixtures/tsconfig.json
@@ -2,7 +2,7 @@
"compilerOptions": {
"baseUrl": "/Users/jarredsumner/Code/bun/src/test/fixtures",
"paths": {
- "components": ["components/*"]
+ "components/*": ["components/*"]
},
"jsx": "preserve"
}