aboutsummaryrefslogtreecommitdiff
path: root/src/js_parser/js_parser.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/js_parser/js_parser.zig')
-rw-r--r--src/js_parser/js_parser.zig37
1 files changed, 24 insertions, 13 deletions
diff --git a/src/js_parser/js_parser.zig b/src/js_parser/js_parser.zig
index 5afdade21..3321d0ed3 100644
--- a/src/js_parser/js_parser.zig
+++ b/src/js_parser/js_parser.zig
@@ -993,8 +993,9 @@ const ExprOut = struct {
const Tup = std.meta.Tuple;
// This function exists to tie all of these checks together in one place
+// This can sometimes show up on benchmarks as a small thing.
fn isEvalOrArguments(name: string) bool {
- return strings.eql(name, "eval") or strings.eql(name, "arguments");
+ return strings.eqlComptime(name, "eval") or strings.eqlComptime(name, "arguments");
}
const PrependTempRefsOpts = struct {
@@ -1649,7 +1650,7 @@ pub const P = struct {
// symbols must be separate from the pass that binds identifiers to declared
// symbols to handle declaring a hoisted "var" symbol in a nested scope and
// binding a name to it in a parent or sibling scope.
- scopes_in_order: List(ScopeOrder),
+ scopes_in_order: std.ArrayListUnmanaged(ScopeOrder),
// These properties are for the visit pass, which runs after the parse pass.
// The visit pass binds identifiers to declared symbols, does constant
@@ -2240,12 +2241,18 @@ pub const P = struct {
}
pub fn pushScopeForVisitPass(p: *P, comptime kind: js_ast.Scope.Kind, loc: logger.Loc) !void {
+ assert(p.scopes_in_order.items.len > 0);
const order = p.scopes_in_order.items[0];
- p.scopes_in_order.items = p.scopes_in_order.items[1..p.scopes_in_order.items.len];
+ if (p.scopes_in_order.items.len > 1) {
+ p.scopes_in_order.items = p.scopes_in_order.items[1..p.scopes_in_order.items.len];
+ } else {
+ p.scopes_in_order.items = &([_]ScopeOrder{});
+ }
// Sanity-check that the scopes generated by the first and second passes match
if (order.loc.start != loc.start or order.scope.kind != kind) {
- p.panic("Expected scope ({s}, {d}) in {s}, found scope ({s}, {d})", .{ kind, loc.start, p.source.path.pretty, order.scope.kind, order.loc.start });
+ std.debug.print("Expected scope ({s}, {d}) in {s}, found scope ({s}, {d})", .{ kind, loc.start, p.source.path.pretty, order.scope.kind, order.loc.start });
+ p.panic("", .{});
}
p.current_scope = order.scope;
@@ -2284,7 +2291,7 @@ pub const P = struct {
// errors if a statement in the function body tries to re-declare any of the
// arguments.
if (kind == js_ast.Scope.Kind.function_body) {
- assert(parent.kind != js_ast.Scope.Kind.function_args);
+ assert(parent.kind == js_ast.Scope.Kind.function_args);
var iter = scope.parent.?.members.iterator();
while (iter.next()) |entry| {
@@ -2299,7 +2306,7 @@ pub const P = struct {
// Remember the length in case we call popAndDiscardScope() later
const scope_index = p.scopes_in_order.items.len;
- try p.scopes_in_order.append(ScopeOrder{ .loc = loc, .scope = scope });
+ try p.scopes_in_order.append(p.allocator, ScopeOrder{ .loc = loc, .scope = scope });
return scope_index;
}
@@ -4057,7 +4064,7 @@ pub const P = struct {
}
// Truncate the scope order where we started to pretend we never saw this scope
- p.scopes_in_order.shrinkAndFree(scope_index);
+ p.scopes_in_order.shrinkRetainingCapacity(scope_index);
}
pub fn skipTypescriptTypeStmt(p: *P, opts: *ParseStatementOptions) void {
@@ -4122,7 +4129,7 @@ pub const P = struct {
if (p.lexer.isContextualKeyword("as")) {
p.lexer.next();
original_name = p.lexer.identifier;
- name = LocRef{ .loc = alias_loc, .ref = try p.storeNameInRef(alias) };
+ name = LocRef{ .loc = alias_loc, .ref = try p.storeNameInRef(original_name) };
p.lexer.expect(.t_identifier);
} else if (!isIdentifier) {
// An import where the name is a keyword must have an alias
@@ -10690,21 +10697,25 @@ pub const P = struct {
p.panic("", .{});
}
+ // This code is tricky.
+ // - Doing it incorrectly will cause segfaults.
+ // - Doing it correctly drastically affects runtime performance while parsing larger files
+ // The key is in how we remove scopes from the list
+ // If we do an orderedRemove, it gets very slow.
+ // swapRemove is fast. But a little more dangerous.
pub fn popAndFlattenScope(p: *P, scope_index: usize) void {
// Move up to the parent scope
var to_flatten = p.current_scope;
var parent = to_flatten.parent.?;
p.current_scope = parent;
- var scopes_in_order_end = p.scopes_in_order.capacity;
- var _scopes_in_order = p.scopes_in_order.allocatedSlice();
- var scopes_in_order = _scopes_in_order[0..scopes_in_order_end];
+
// Erase this scope from the order. This will shift over the indices of all
// the scopes that were created after us. However, we shouldn't have to
// worry about other code with outstanding scope indices for these scopes.
// These scopes were all created in between this scope's push and pop
// operations, so they should all be child scopes and should all be popped
// by the time we get here.
- std.mem.copyBackwards(ScopeOrder, scopes_in_order[scope_index..scopes_in_order.len], scopes_in_order[scope_index + 1 .. scopes_in_order.len]);
+ _ = p.scopes_in_order.swapRemove(scope_index);
// Remove the last child from the parent scope
const last = parent.children.items.len - 1;
@@ -10895,7 +10906,7 @@ pub const P = struct {
.named_exports = @TypeOf(_parser.named_exports).init(allocator),
.top_level_symbol_to_parts = @TypeOf(_parser.top_level_symbol_to_parts).init(allocator),
.import_namespace_cc_map = @TypeOf(_parser.import_namespace_cc_map).init(allocator),
- .scopes_in_order = std.ArrayList(ScopeOrder).init(allocator),
+ .scopes_in_order = try std.ArrayListUnmanaged(ScopeOrder).initCapacity(allocator, 1),
.temp_refs_to_declare = @TypeOf(_parser.temp_refs_to_declare).init(allocator),
.relocated_top_level_vars = @TypeOf(_parser.relocated_top_level_vars).init(allocator),
.log = log,