diff options
Diffstat (limited to 'src/js_ast.zig')
-rw-r--r-- | src/js_ast.zig | 199 |
1 files changed, 192 insertions, 7 deletions
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 = .{}, |