diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/bundler/bundle_v2.zig | 145 | ||||
-rw-r--r-- | src/feature_flags.zig | 2 | ||||
-rw-r--r-- | src/js_ast.zig | 199 | ||||
-rw-r--r-- | src/js_printer.zig | 1 |
4 files changed, 272 insertions, 75 deletions
diff --git a/src/bundler/bundle_v2.zig b/src/bundler/bundle_v2.zig index d572d97a9..9b7aa3c57 100644 --- a/src/bundler/bundle_v2.zig +++ b/src/bundler/bundle_v2.zig @@ -105,7 +105,7 @@ const EntryPoints = @import("./entry_points.zig"); const ThisBundler = @import("../bundler.zig").Bundler; const wyhash = std.hash.Wyhash.hash; const Dependency = js_ast.Dependency; -const JSAst = js_ast.Ast; +const JSAst = js_ast.BundledAst; const Loader = options.Loader; const Index = @import("../ast/base.zig").Index; const Batcher = bun.Batcher; @@ -354,7 +354,7 @@ pub const BundleV2 = struct { reachable: std.ArrayList(Index), visited: bun.bit_set.DynamicBitSet = undefined, all_import_records: []ImportRecord.List, - redirects: []?u32, + redirects: []u32, redirect_map: PathToSourceIndexMap, dynamic_import_entry_points: *std.AutoArrayHashMap(Index.Int, void), @@ -382,7 +382,7 @@ pub const BundleV2 = struct { for (import_records) |*import_record| { const other_source = import_record.source_index; if (other_source.isValid()) { - if (v.redirects[other_source.get()]) |redirect_id| { + if (getRedirectId(v.redirects[other_source.get()])) |redirect_id| { var other_import_records = v.all_import_records[other_source.get()].slice(); const other_import_record = &other_import_records[redirect_id]; import_record.source_index = other_import_record.source_index; @@ -394,7 +394,7 @@ pub const BundleV2 = struct { } // Redirects replace the source file with another file - if (v.redirects[source_index.get()]) |redirect_id| { + if (getRedirectId(v.redirects[source_index.get()])) |redirect_id| { const redirect_source_index = v.all_import_records[source_index.get()].slice()[redirect_id].source_index.get(); v.visit(Index.source(redirect_source_index), was_dynamic_import, check_dynamic_imports); return; @@ -576,10 +576,10 @@ pub const BundleV2 = struct { const source_index = Index.init(@intCast(u32, this.graph.ast.len)); entry.value_ptr.* = source_index.get(); out_source_index = source_index; - this.graph.ast.append(this.graph.allocator, js_ast.Ast.empty) catch unreachable; + this.graph.ast.append(bun.default_allocator, JSAst.empty) catch unreachable; const loader = path.loader(&this.bundler.options.loaders) orelse options.Loader.file; - this.graph.input_files.append(this.graph.allocator, .{ + this.graph.input_files.append(bun.default_allocator, .{ .source = .{ .path = path.*, .key_path = path.*, @@ -641,9 +641,9 @@ pub const BundleV2 = struct { } path.* = try path.dupeAlloc(this.graph.allocator); entry.value_ptr.* = source_index.get(); - this.graph.ast.append(this.graph.allocator, js_ast.Ast.empty) catch unreachable; + this.graph.ast.append(bun.default_allocator, JSAst.empty) catch unreachable; - try this.graph.input_files.append(this.graph.allocator, .{ + try this.graph.input_files.append(bun.default_allocator, .{ .source = .{ .path = path.*, .key_path = path.*, @@ -753,14 +753,14 @@ pub const BundleV2 = struct { { // Add the runtime - try this.graph.input_files.append(this.graph.allocator, Graph.InputFile{ + try this.graph.input_files.append(bun.default_allocator, Graph.InputFile{ .source = ParseTask.runtime_source, .loader = .js, .side_effects = _resolver.SideEffects.no_side_effects__pure_data, }); // try this.graph.entry_points.append(allocator, Index.runtime); - this.graph.ast.append(this.graph.allocator, js_ast.Ast.empty) catch unreachable; + this.graph.ast.append(bun.default_allocator, JSAst.empty) catch unreachable; this.graph.path_to_source_index_map.put(this.graph.allocator, bun.hash("bun:wrap"), Index.runtime.get()) catch unreachable; var runtime_parse_task = try this.graph.allocator.create(ParseTask); runtime_parse_task.* = ParseTask.runtime; @@ -933,9 +933,9 @@ pub const BundleV2 = struct { this.graph.shadow_entry_point_range.loc.start = @intCast(i32, source_index.get()); } - this.graph.ast.append(allocator, js_ast.Ast.empty) catch unreachable; + this.graph.ast.append(bun.default_allocator, JSAst.empty) catch unreachable; this.graph.shadow_entry_points.append(allocator, shadow) catch unreachable; - this.graph.input_files.append(allocator, .{ + this.graph.input_files.append(bun.default_allocator, .{ .source = .{ .path = path, .key_path = path, @@ -1399,10 +1399,10 @@ pub const BundleV2 = struct { const source_index = Index.init(@intCast(u32, this.graph.ast.len)); existing.value_ptr.* = source_index.get(); out_source_index = source_index; - this.graph.ast.append(this.graph.allocator, js_ast.Ast.empty) catch unreachable; + this.graph.ast.append(bun.default_allocator, JSAst.empty) catch unreachable; const loader = path.loader(&this.bundler.options.loaders) orelse options.Loader.file; - this.graph.input_files.append(this.graph.allocator, .{ + this.graph.input_files.append(bun.default_allocator, .{ .source = .{ .path = path, .key_path = path, @@ -1607,6 +1607,8 @@ pub const BundleV2 = struct { } pub fn deinit(this: *BundleV2) void { + defer this.graph.ast.deinit(bun.default_allocator); + defer this.graph.input_files.deinit(bun.default_allocator); if (this.graph.pool.workers_assignments.count() > 0) { { this.graph.pool.workers_assignments_lock.lock(); @@ -1851,8 +1853,8 @@ pub const BundleV2 = struct { new_task.source_index = new_input_file.source.index; new_task.ctx = this; - graph.input_files.append(graph.allocator, new_input_file) catch unreachable; - graph.ast.append(graph.allocator, js_ast.Ast.empty) catch unreachable; + graph.input_files.append(bun.default_allocator, new_input_file) catch unreachable; + graph.ast.append(bun.default_allocator, JSAst.empty) catch unreachable; diff += 1; if (loader.shouldCopyForBundling()) { @@ -1894,7 +1896,7 @@ pub const BundleV2 = struct { if (graph.path_to_source_index_map.get(record.path.hashKey())) |source_index| { record.source_index.value = source_index; - if (result.ast.redirect_import_record_index) |compare| { + if (getRedirectId(result.ast.redirect_import_record_index)) |compare| { if (compare == @truncate(u32, i)) { graph.path_to_source_index_map.put( graph.allocator, @@ -2026,7 +2028,7 @@ pub const ParseTask = struct { }; pub const Success = struct { - ast: js_ast.Ast, + ast: JSAst, resolve_queue: ResolveQueue, source: Logger.Source, log: Logger.Log, @@ -2064,9 +2066,9 @@ pub const ParseTask = struct { threadlocal var override_file_path_buf: [bun.MAX_PATH_BYTES]u8 = undefined; - fn getEmptyAST(log: *Logger.Log, bundler: *Bundler, opts: js_parser.Parser.Options, allocator: std.mem.Allocator, source: Logger.Source) !js_ast.Ast { + fn getEmptyAST(log: *Logger.Log, bundler: *Bundler, opts: js_parser.Parser.Options, allocator: std.mem.Allocator, source: Logger.Source) !JSAst { const root = Expr.init(E.Undefined, E.Undefined{}, Logger.Loc.Empty); - return (try js_parser.newLazyExportAST(allocator, bundler.options.define, opts, log, root, &source, "")).?; + return JSAst.init((try js_parser.newLazyExportAST(allocator, bundler.options.define, opts, log, root, &source, "")).?); } fn getAST( @@ -2079,7 +2081,7 @@ pub const ParseTask = struct { loader: Loader, unique_key_prefix: u64, unique_key_for_additional_file: *[]const u8, - ) !js_ast.Ast { + ) !JSAst { switch (loader) { .jsx, .tsx, .js, .ts => { const trace = tracer(@src(), "ParseJS"); @@ -2091,7 +2093,7 @@ pub const ParseTask = struct { log, &source, )) |res| - res.ast + JSAst.init(res.ast) else try getEmptyAST(log, bundler, opts, allocator, source); }, @@ -2099,20 +2101,20 @@ pub const ParseTask = struct { const trace = tracer(@src(), "ParseJSON"); defer trace.end(); const root = (try resolver.caches.json.parseJSON(log, source, allocator)) orelse Expr.init(E.Object, E.Object{}, Logger.Loc.Empty); - return (try js_parser.newLazyExportAST(allocator, bundler.options.define, opts, log, root, &source, "")).?; + return JSAst.init((try js_parser.newLazyExportAST(allocator, bundler.options.define, opts, log, root, &source, "")).?); }, .toml => { const trace = tracer(@src(), "ParseTOML"); defer trace.end(); const root = try TOML.parse(&source, log, allocator); - return (try js_parser.newLazyExportAST(allocator, bundler.options.define, opts, log, root, &source, "")).?; + return JSAst.init((try js_parser.newLazyExportAST(allocator, bundler.options.define, opts, log, root, &source, "")).?); }, .text => { const root = Expr.init(E.String, E.String{ .data = source.contents, .prefer_template = true, }, Logger.Loc{ .start = 0 }); - return (try js_parser.newLazyExportAST(allocator, bundler.options.define, opts, log, root, &source, "")).?; + return JSAst.init((try js_parser.newLazyExportAST(allocator, bundler.options.define, opts, log, root, &source, "")).?); }, // TODO: css .css, .file => { @@ -2121,13 +2123,13 @@ pub const ParseTask = struct { .data = unique_key, }, Logger.Loc{ .start = 0 }); unique_key_for_additional_file.* = unique_key; - return (try js_parser.newLazyExportAST(allocator, bundler.options.define, opts, log, root, &source, "")).?; + return JSAst.init((try js_parser.newLazyExportAST(allocator, bundler.options.define, opts, log, root, &source, "")).?); }, else => { const root = Expr.init(E.String, E.String{ .data = source.path.text, }, Logger.Loc{ .start = 0 }); - return (try js_parser.newLazyExportAST(allocator, bundler.options.define, opts, log, root, &source, "")).?; + return JSAst.init((try js_parser.newLazyExportAST(allocator, bundler.options.define, opts, log, root, &source, "")).?); }, } } @@ -2291,7 +2293,7 @@ pub const ParseTask = struct { var unique_key_for_additional_file: []const u8 = ""; - var ast: js_ast.Ast = if (!is_empty) + var ast: JSAst = if (!is_empty) try getAST(log, bundler, opts, allocator, resolver, source, loader, task.ctx.unique_key, &unique_key_for_additional_file) else try getEmptyAST(log, bundler, opts, allocator, source); @@ -2908,7 +2910,7 @@ const LinkerGraph = struct { // This is an alias from Graph // it is not a clone! - ast: MultiArrayList(js_ast.Ast) = .{}, + ast: MultiArrayList(JSAst) = .{}, meta: MultiArrayList(JSMeta) = .{}, reachable_files: []Index = &[_]Index{}, @@ -3081,11 +3083,11 @@ const LinkerGraph = struct { const exports_ref = g.ast.items(.exports_ref)[source_index]; const module_ref = g.ast.items(.module_ref)[source_index]; if (!exports_ref.isNull() and ref.eql(exports_ref)) { - g.ast.items(.uses_exports_ref)[source_index] = true; + g.ast.items(.flags)[source_index].uses_exports_ref = true; } if (!module_ref.isNull() and ref.eql(module_ref)) { - g.ast.items(.uses_module_ref)[source_index] = true; + g.ast.items(.flags)[source_index].uses_module_ref = true; } // null ref shouldn't be there. @@ -4175,8 +4177,7 @@ const LinkerContext = struct { var export_star_import_records: [][]u32 = this.graph.ast.items(.export_star_import_records); var exports_refs: []Ref = this.graph.ast.items(.exports_ref); var module_refs: []Ref = this.graph.ast.items(.module_ref); - var lazy_exports: []bool = this.graph.ast.items(.has_lazy_export); - var force_cjs_to_esm: []bool = this.graph.ast.items(.force_cjs_to_esm); + var ast_flags_list = this.graph.ast.items(.flags); var symbols = &this.graph.symbols; defer this.graph.symbols = symbols.*; @@ -4196,6 +4197,7 @@ const LinkerContext = struct { } const other_file = record.source_index.get(); + const other_flags = ast_flags_list[other_file]; // other file is empty if (other_file >= exports_kind.len) continue; const other_kind = exports_kind[other_file]; @@ -4223,7 +4225,7 @@ const LinkerContext = struct { // In that case the module *is* considered a CommonJS module because // the namespace object must be created. if ((record.contains_import_star or record.contains_default_alias) and - !lazy_exports[other_file] and !force_cjs_to_esm[other_file] and + !other_flags.has_lazy_export and !other_flags.force_cjs_to_esm and exports_kind[other_file] == .none) { exports_kind[other_file] = .cjs; @@ -4235,7 +4237,7 @@ const LinkerContext = struct { { if (other_kind == .esm) { flags[other_file].wrap = .esm; - } else if (!force_cjs_to_esm[other_file]) { + } else if (!other_flags.force_cjs_to_esm) { flags[other_file].wrap = .cjs; exports_kind[other_file] = .cjs; } @@ -4246,7 +4248,7 @@ const LinkerContext = struct { // returns a promise, so the imported file must be a CommonJS module if (exports_kind[other_file] == .esm) { flags[other_file].wrap = .esm; - } else if (!force_cjs_to_esm[other_file]) { + } else if (!other_flags.force_cjs_to_esm) { flags[other_file].wrap = .cjs; exports_kind[other_file] = .cjs; } @@ -4357,14 +4359,13 @@ const LinkerContext = struct { } var resolved_exports: []ResolvedExports = this.graph.meta.items(.resolved_exports); var resolved_export_stars: []ExportData = this.graph.meta.items(.resolved_export_star); - var has_lazy_export: []bool = this.graph.ast.items(.has_lazy_export); for (reachable) |source_index_| { const source_index = source_index_.get(); const id = source_index; // -- - if (has_lazy_export[id]) { + if (ast_flags_list[id].has_lazy_export) { try this.generateCodeForLazyExport(id); } // -- @@ -4509,7 +4510,7 @@ const LinkerContext = struct { const named_imports = ast_fields.items(.named_imports); const import_records_list = ast_fields.items(.import_records); const export_star_import_records = ast_fields.items(.export_star_import_records); - const force_cjs_to_esm = ast_fields.items(.force_cjs_to_esm); + const ast_flags = ast_fields.items(.flags); for (reachable) |source_index_| { const source_index = source_index_.get(); const id = source_index; @@ -4770,7 +4771,7 @@ const LinkerContext = struct { if (kind == .require or !output_format.keepES6ImportExportSyntax() or (kind == .dynamic)) { - if (record.source_index.isValid() and kind == .dynamic and force_cjs_to_esm[other_id]) { + if (record.source_index.isValid() and kind == .dynamic and ast_flags[other_id].force_cjs_to_esm) { // If the CommonJS module was converted to ESM // and the developer `import("cjs_module")`, then // they may have code that expects the default export to return the CommonJS module.exports object @@ -4955,7 +4956,7 @@ const LinkerContext = struct { 1, Index.source(source_index), ) catch unreachable; - this.graph.ast.items(.uses_exports_ref)[id] = true; + this.graph.ast.items(.flags)[id].uses_exports_ref = true; record.calls_runtime_re_export_fn = true; re_export_uses += 1; } @@ -5175,7 +5176,7 @@ const LinkerContext = struct { } // Make sure the CommonJS closure, if there is one, includes "exports" - c.graph.ast.items(.uses_exports_ref)[id] = true; + c.graph.ast.items(.flags)[id].uses_exports_ref = true; } // No need to generate a part if it'll be empty @@ -5981,25 +5982,27 @@ const LinkerContext = struct { var freq = js_ast.CharFreq{ .freqs = [_]i32{0} ** 64, }; + const ast_flags_list = c.graph.ast.items(.flags); + var capacity = sorted_imports_from_other_chunks.items.len; { const char_freqs = c.graph.ast.items(.char_freq); + for (files_in_order) |source_index| { - if (char_freqs[source_index]) |char_freq| { - freq.include(char_freq); + if (ast_flags_list[source_index].has_char_freq) { + freq.include(char_freqs[source_index]); } } } - const uses_exports_ref_list = c.graph.ast.items(.uses_exports_ref); - const uses_module_ref_list = c.graph.ast.items(.uses_module_ref); const exports_ref_list = c.graph.ast.items(.exports_ref); const module_ref_list = c.graph.ast.items(.module_ref); const parts_list = c.graph.ast.items(.parts); for (files_in_order) |source_index| { - const uses_exports_ref = uses_exports_ref_list[source_index]; - const uses_module_ref = uses_module_ref_list[source_index]; + const ast_flags = ast_flags_list[source_index]; + const uses_exports_ref = ast_flags.uses_exports_ref; + const uses_module_ref = ast_flags.uses_module_ref; const exports_ref = exports_ref_list[source_index]; const module_ref = module_ref_list[source_index]; const parts = parts_list[source_index]; @@ -6286,7 +6289,7 @@ const LinkerContext = struct { cross_chunk_prefix = js_printer.print( allocator, c.resolver.opts.target, - ast, + ast.toAST(), c.source_(chunk.entry_point.source_index), print_options, cross_chunk_import_records.slice(), @@ -6299,7 +6302,7 @@ const LinkerContext = struct { cross_chunk_suffix = js_printer.print( allocator, c.resolver.opts.target, - ast, + ast.toAST(), c.source_(chunk.entry_point.source_index), print_options, &.{}, @@ -6735,7 +6738,7 @@ const LinkerContext = struct { const flags: JSMeta.Flags = c.graph.meta.items(.flags)[source_index]; var stmts = std.ArrayList(Stmt).init(temp_allocator); defer stmts.deinit(); - const ast: js_ast.Ast = c.graph.ast.get(source_index); + const ast: JSAst = c.graph.ast.get(source_index); switch (c.options.output_format) { // TODO: @@ -7141,7 +7144,7 @@ const LinkerContext = struct { .result = js_printer.print( allocator, c.resolver.opts.target, - ast, + ast.toAST(), c.source_(source_index), print_options, ast.import_records.slice(), @@ -7236,7 +7239,7 @@ const LinkerContext = struct { namespace_ref: Ref, import_record_index: u32, allocator: std.mem.Allocator, - ast: *const js_ast.Ast, + ast: *const JSAst, ) !bool { const record = ast.import_records.at(import_record_index); if (record.tag.isReactReference()) @@ -7409,7 +7412,7 @@ const LinkerContext = struct { chunk: *Chunk, allocator: std.mem.Allocator, wrap: WrapKind, - ast: *const js_ast.Ast, + ast: *const JSAst, ) !void { const shouldExtractESMStmtsForWrap = wrap != .none; const shouldStripExports = c.options.mode != .passthrough or c.graph.files.items(.entry_point_kind)[source_index] != .none; @@ -7932,7 +7935,7 @@ const LinkerContext = struct { Index.invalid; // referencing everything by array makes the code a lot more annoying :( - const ast: js_ast.Ast = c.graph.ast.get(part_range.source_index.get()); + const ast: JSAst = c.graph.ast.get(part_range.source_index.get()); var needs_wrapper = false; @@ -7940,7 +7943,7 @@ const LinkerContext = struct { stmts.reset(); - const part_index_for_lazy_default_export: u32 = if (ast.has_lazy_export) brk: { + const part_index_for_lazy_default_export: u32 = if (ast.flags.has_lazy_export) brk: { if (c.graph.meta.items(.resolved_exports)[part_range.source_index.get()].get("default")) |default| { break :brk c.graph.topLevelSymbolToParts(part_range.source_index.get(), default.data.import_ref)[0]; } @@ -8122,15 +8125,15 @@ const LinkerContext = struct { if (needs_wrapper) { switch (flags.wrap) { .cjs => { - var uses_exports_ref = ast.uses_exports_ref; + var uses_exports_ref = ast.uses_exports_ref(); // Only include the arguments that are actually used var args = std.ArrayList(js_ast.G.Arg).initCapacity( temp_allocator, - if (ast.uses_module_ref or uses_exports_ref) 2 else 0, + if (ast.uses_module_ref() or uses_exports_ref) 2 else 0, ) catch unreachable; - if (ast.uses_module_ref or uses_exports_ref) { + if (ast.uses_module_ref() or uses_exports_ref) { args.appendAssumeCapacity( js_ast.G.Arg{ .binding = js_ast.Binding.alloc( @@ -8143,7 +8146,7 @@ const LinkerContext = struct { }, ); - if (ast.uses_module_ref) { + if (ast.uses_module_ref()) { args.appendAssumeCapacity( js_ast.G.Arg{ .binding = js_ast.Binding.alloc( @@ -8419,7 +8422,7 @@ const LinkerContext = struct { *js_printer.BufferPrinter, &printer, ast.target, - ast, + ast.toAST(), c.source_(part_range.source_index.get()), print_options, ast.import_records.slice(), @@ -9781,7 +9784,7 @@ const LinkerContext = struct { var named_imports: *JSAst.NamedImports = &c.graph.ast.items(.named_imports)[id]; var import_records = c.graph.ast.items(.import_records)[id]; const exports_kind: []const js_ast.ExportsKind = c.graph.ast.items(.exports_kind); - const force_cjs_to_esm: []const bool = c.graph.ast.items(.force_cjs_to_esm); + const ast_flags = c.graph.ast.items(.flags); const named_import: js_ast.NamedImport = named_imports.get(tracker.import_ref) orelse // TODO: investigate if this is a bug @@ -9816,14 +9819,16 @@ const LinkerContext = struct { }; } + const flags = ast_flags[other_id]; + // Is this a named import of a file without any exports? if (!named_import.alias_is_star and - !c.parse_graph.ast.items(.has_lazy_export)[other_id] and + flags.has_lazy_export and // CommonJS exports - c.graph.ast.items(.export_keyword)[other_id].len == 0 and !strings.eqlComptime(named_import.alias orelse "", "default") and + !flags.uses_export_keyword and !strings.eqlComptime(named_import.alias orelse "", "default") and // ESM exports - !c.graph.ast.items(.uses_exports_ref)[other_id] and !c.graph.ast.items(.uses_module_ref)[other_id]) + !flags.uses_exports_ref and !flags.uses_module_ref) { // Just warn about it and replace the import with "undefined" return .{ @@ -9878,7 +9883,7 @@ const LinkerContext = struct { } // Is this a file with dynamic exports? - const is_commonjs_to_esm = force_cjs_to_esm[other_id]; + const is_commonjs_to_esm = ast_flags[other_id].force_cjs_to_esm; if (other_kind.isESMWithDynamicFallback() or is_commonjs_to_esm) { return .{ .value = .{ @@ -11084,3 +11089,11 @@ const ShadowEntryPoint = struct { } }; }; + +fn getRedirectId(id: u32) ?u32 { + if (id == std.math.maxInt(u32)) { + return null; + } + + return id; +} diff --git a/src/feature_flags.zig b/src/feature_flags.zig index dbc7914ea..d686a4909 100644 --- a/src/feature_flags.zig +++ b/src/feature_flags.zig @@ -167,4 +167,4 @@ pub const boundary_based_chunking = true; /// https://github.com/source-map/source-map-rfc/pull/20 pub const source_map_debug_id = true; -pub const alignment_tweak = true; +pub const alignment_tweak = false; diff --git a/src/js_ast.zig b/src/js_ast.zig index 939a70b73..bf02ab7fe 100644 --- a/src/js_ast.zig +++ b/src/js_ast.zig @@ -578,7 +578,7 @@ pub const CharFreq = struct { const Vector = @Vector(64, i32); const Buffer = [64]i32; - freqs: Buffer align(@alignOf(Vector)) = undefined, + freqs: Buffer align(1) = undefined, const scan_big_chunk_size = 32; pub fn scan(this: *CharFreq, text: string, delta: i32) void { @@ -592,7 +592,7 @@ pub const CharFreq = struct { } } - fn scanBig(out: *align(@alignOf(Vector)) Buffer, text: string, delta: i32) void { + fn scanBig(out: *align(1) Buffer, text: string, delta: i32) void { // https://zig.godbolt.org/z/P5dPojWGK var freqs = out.*; defer out.* = freqs; @@ -625,7 +625,7 @@ pub const CharFreq = struct { freqs[63] = deltas['$']; } - fn scanSmall(out: *align(@alignOf(Vector)) [64]i32, text: string, delta: i32) void { + fn scanSmall(out: *align(1) Buffer, text: string, delta: i32) void { var freqs: [64]i32 = out.*; defer out.* = freqs; @@ -5835,8 +5835,6 @@ pub const Ast = struct { force_cjs_to_esm: bool = false, exports_kind: ExportsKind = ExportsKind.none, - bundle_export_ref: ?Ref = null, - // This is a list of ES6 features. They are ranges instead of booleans so // that they can be used in log messages. Check to see if "Len > 0". import_keyword: logger.Range = logger.Range.None, // Does not include TypeScript-specific syntax or "import()" @@ -5862,8 +5860,6 @@ pub const Ast = struct { bun_plugin: BunPlugin = .{}, - bundle_namespace_ref: ?Ref = null, - prepend_part: ?Part = null, // These are used when bundling. They are filled in during the parser pass @@ -5922,6 +5918,195 @@ pub const Ast = struct { } }; +/// Like Ast but slimmer and for bundling only. +/// +/// On Linux, the hottest function in the bundler is: +/// src.multi_array_list.MultiArrayList(src.js_ast.Ast).ensureTotalCapacity +/// https://share.firefox.dev/3NNlRKt +/// +/// So we make a slimmer version of Ast for bundling that doesn't allocate as much memory +pub const BundledAst = struct { + approximate_newline_count: u32 = 0, + nested_scope_slot_counts: SlotCounts = SlotCounts{}, + externals: []u32 = &[_]u32{}, + + exports_kind: ExportsKind = ExportsKind.none, + + /// These are stored at the AST level instead of on individual AST nodes so + /// they can be manipulated efficiently without a full AST traversal + import_records: ImportRecord.List = .{}, + + hashbang: string = "", + directive: string = "", + url_for_css: string = "", + parts: Part.List = Part.List{}, + // This list may be mutated later, so we should store the capacity + symbols: Symbol.List = Symbol.List{}, + module_scope: Scope = Scope{}, + char_freq: CharFreq = undefined, + exports_ref: Ref = Ref.None, + module_ref: Ref = Ref.None, + wrapper_ref: Ref = Ref.None, + require_ref: Ref = Ref.None, + + // These are used when bundling. They are filled in during the parser pass + // since we already have to traverse the AST then anyway and the parser pass + // is conveniently fully parallelized. + named_imports: NamedImports = NamedImports.init(bun.failing_allocator), + named_exports: NamedExports = NamedExports.init(bun.failing_allocator), + export_star_import_records: []u32 = &([_]u32{}), + + allocator: std.mem.Allocator, + top_level_symbols_to_parts: TopLevelSymbolToParts = .{}, + + commonjs_named_exports: CommonJSNamedExports = .{}, + + redirect_import_record_index: u32 = std.math.maxInt(u32), + + /// Only populated when bundling + target: bun.options.Target = .browser, + + const_values: ConstValuesMap = .{}, + + flags: BundledAst.Flags = .{}, + + pub const NamedImports = Ast.NamedImports; + pub const NamedExports = Ast.NamedExports; + pub const TopLevelSymbolToParts = Ast.TopLevelSymbolToParts; + pub const CommonJSNamedExports = Ast.CommonJSNamedExports; + pub const ConstValuesMap = Ast.ConstValuesMap; + + pub const Flags = packed struct { + // This is a list of CommonJS features. When a file uses CommonJS features, + // it's not a candidate for "flat bundling" and must be wrapped in its own + // closure. + uses_exports_ref: bool = false, + uses_module_ref: bool = false, + // uses_require_ref: bool = false, + + uses_export_keyword: bool = false, + + has_char_freq: bool = false, + force_cjs_to_esm: bool = false, + has_lazy_export: bool = false, + }; + + pub const empty = BundledAst.init(Ast.empty); + + pub inline fn uses_exports_ref(this: *const BundledAst) bool { + return this.flags.uses_exports_ref; + } + pub inline fn uses_module_ref(this: *const BundledAst) bool { + return this.flags.uses_module_ref; + } + // pub inline fn uses_require_ref(this: *const BundledAst) bool { + // return this.flags.uses_require_ref; + // } + + pub fn toAST(this: *const BundledAst) Ast { + return .{ + .approximate_newline_count = this.approximate_newline_count, + .nested_scope_slot_counts = this.nested_scope_slot_counts, + .externals = this.externals, + + .exports_kind = this.exports_kind, + + .import_records = this.import_records, + + .hashbang = this.hashbang, + .directive = this.directive, + // .url_for_css = this.url_for_css, + .parts = this.parts, + // This list may be mutated later, so we should store the capacity + .symbols = this.symbols, + .module_scope = this.module_scope, + .char_freq = if (this.flags.has_char_freq) this.char_freq else null, + .exports_ref = this.exports_ref, + .module_ref = this.module_ref, + .wrapper_ref = this.wrapper_ref, + .require_ref = this.require_ref, + + // These are used when bundling. They are filled in during the parser pass + // since we already have to traverse the AST then anyway and the parser pass + // is conveniently fully parallelized. + .named_imports = this.named_imports, + .named_exports = this.named_exports, + .export_star_import_records = this.export_star_import_records, + + .allocator = this.allocator, + .top_level_symbols_to_parts = this.top_level_symbols_to_parts, + + .commonjs_named_exports = this.commonjs_named_exports, + + .redirect_import_record_index = this.redirect_import_record_index, + + .target = this.target, + + .const_values = this.const_values, + + .uses_exports_ref = this.flags.uses_exports_ref, + .uses_module_ref = this.flags.uses_module_ref, + // .uses_require_ref = ast.uses_require_ref, + .export_keyword = .{ .len = if (this.flags.uses_export_keyword) 1 else 0, .loc = .{} }, + .force_cjs_to_esm = this.flags.force_cjs_to_esm, + .has_lazy_export = this.flags.has_lazy_export, + }; + } + + pub fn init(ast: Ast) BundledAst { + return .{ + .approximate_newline_count = @truncate(u32, ast.approximate_newline_count), + .nested_scope_slot_counts = ast.nested_scope_slot_counts, + .externals = ast.externals, + + .exports_kind = ast.exports_kind, + + .import_records = ast.import_records, + + .hashbang = ast.hashbang, + .directive = ast.directive orelse "", + // .url_for_css = ast.url_for_css orelse "", + .parts = ast.parts, + // This list may be mutated later, so we should store the capacity + .symbols = ast.symbols, + .module_scope = ast.module_scope, + .char_freq = ast.char_freq orelse undefined, + .exports_ref = ast.exports_ref, + .module_ref = ast.module_ref, + .wrapper_ref = ast.wrapper_ref, + .require_ref = ast.require_ref, + + // These are used when bundling. They are filled in during the parser pass + // since we already have to traverse the AST then anyway and the parser pass + // is conveniently fully parallelized. + .named_imports = ast.named_imports, + .named_exports = ast.named_exports, + .export_star_import_records = ast.export_star_import_records, + + .allocator = ast.allocator, + .top_level_symbols_to_parts = ast.top_level_symbols_to_parts, + + .commonjs_named_exports = ast.commonjs_named_exports, + + .redirect_import_record_index = ast.redirect_import_record_index orelse std.math.maxInt(u32), + + .target = ast.target, + + .const_values = ast.const_values, + + .flags = .{ + .uses_exports_ref = ast.uses_exports_ref, + .uses_module_ref = ast.uses_module_ref, + // .uses_require_ref = ast.uses_require_ref, + .uses_export_keyword = ast.export_keyword.len > 0, + .has_char_freq = ast.char_freq != null, + .force_cjs_to_esm = ast.force_cjs_to_esm, + .has_lazy_export = ast.has_lazy_export, + }, + }; + } +}; + pub const Span = struct { text: string = "", range: logger.Range = .{}, diff --git a/src/js_printer.zig b/src/js_printer.zig index 14d6321d2..ade7c5594 100644 --- a/src/js_printer.zig +++ b/src/js_printer.zig @@ -487,7 +487,6 @@ pub const Options = struct { runtime_imports: runtime.Runtime.Imports = runtime.Runtime.Imports{}, module_hash: u32 = 0, source_path: ?fs.Path = null, - bundle_export_ref: ?Ref = null, rewrite_require_resolve: bool = true, allocator: std.mem.Allocator = default_allocator, source_map_handler: ?SourceMapHandler = null, |