perf: add branch hints based on real world data

+ move stream ESC state entry outside of `nextNonUtf8`
pull/9645/head
Qwerasd 2025-11-18 11:31:17 -07:00
parent 5744fb042c
commit 212598ed66
2 changed files with 398 additions and 194 deletions

View File

@ -645,6 +645,11 @@ pub fn Stream(comptime Handler: type) type {
try self.handleCodepoint(codepoint); try self.handleCodepoint(codepoint);
} }
if (!consumed) { if (!consumed) {
// We optimize for the scenario where the text being
// printed in the terminal ISN'T full of ill-formed
// UTF-8 sequences.
@branchHint(.unlikely);
const retry = self.utf8decoder.next(c); const retry = self.utf8decoder.next(c);
// It should be impossible for the decoder // It should be impossible for the decoder
// to not consume the byte twice in a row. // to not consume the byte twice in a row.
@ -665,12 +670,16 @@ pub fn Stream(comptime Handler: type) type {
// a chain of inline functions. // a chain of inline functions.
@setEvalBranchQuota(100_000); @setEvalBranchQuota(100_000);
// C0 control
if (c <= 0xF) { if (c <= 0xF) {
@branchHint(.unlikely);
try self.execute(@intCast(c)); try self.execute(@intCast(c));
return; return;
} }
// ESC
if (c == 0x1B) { if (c == 0x1B) {
try self.nextNonUtf8(@intCast(c)); self.parser.state = .escape;
self.parser.clear();
return; return;
} }
try self.print(@intCast(c)); try self.print(@intCast(c));
@ -681,14 +690,8 @@ pub fn Stream(comptime Handler: type) type {
/// This assumes that we're not in the UTF-8 decoding state. If /// This assumes that we're not in the UTF-8 decoding state. If
/// we may be in the UTF-8 decoding state call nextSlice or next. /// we may be in the UTF-8 decoding state call nextSlice or next.
fn nextNonUtf8(self: *Self, c: u8) !void { fn nextNonUtf8(self: *Self, c: u8) !void {
assert(self.parser.state != .ground or c == 0x1B); assert(self.parser.state != .ground);
// Fast path for ESC
if (self.parser.state == .ground and c == 0x1B) {
self.parser.state = .escape;
self.parser.clear();
return;
}
// Fast path for CSI entry. // Fast path for CSI entry.
if (self.parser.state == .escape and c == '[') { if (self.parser.state == .escape and c == '[') {
self.parser.state = .csi_entry; self.parser.state = .csi_entry;
@ -696,6 +699,11 @@ pub fn Stream(comptime Handler: type) type {
} }
// Fast path for CSI params. // Fast path for CSI params.
if (self.parser.state == .csi_param) csi_param: { if (self.parser.state == .csi_param) csi_param: {
// csi_param is the most common parser state
// other than ground by a fairly wide margin.
//
// ref: https://github.com/qwerasd205/asciinema-stats
@branchHint(.likely);
switch (c) { switch (c) {
// A C0 escape (yes, this is valid): // A C0 escape (yes, this is valid):
0x00...0x0F => try self.execute(c), 0x00...0x0F => try self.execute(c),
@ -814,24 +822,52 @@ pub fn Stream(comptime Handler: type) type {
} }
inline fn csiDispatch(self: *Self, input: Parser.Action.CSI) !void { inline fn csiDispatch(self: *Self, input: Parser.Action.CSI) !void {
// The branch hints here are based on real world data
// which indicates that the most common CSI finals are:
//
// 1. m
// 2. H
// 3. K
// 4. A
// 5. C
// 6. X
// 7. l
// 8. h
// 9. r
//
// Together, these 9 finals make up about 96% of all
// CSI sequences encountered in real world scenarios.
//
// Additionally, within the prongs, unlikely branch
// hints have been added to branches that deal with
// invalid sequences/commands, this is in order to
// optimize for the happy path where we're getting
// valid data from the program we're running.
//
// ref: https://github.com/qwerasd205/asciinema-stats
switch (input.final) { switch (input.final) {
// CUU - Cursor Up // CUU - Cursor Up
'A', 'k' => switch (input.intermediates.len) { 'A', 'k' => {
0 => try self.handler.vt(.cursor_up, .{ @branchHint(.likely);
.value = switch (input.params.len) { switch (input.intermediates.len) {
0 => 1, 0 => try self.handler.vt(.cursor_up, .{
1 => input.params[0], .value = switch (input.params.len) {
else => { 0 => 1,
log.warn("invalid cursor up command: {f}", .{input}); 1 => input.params[0],
return; else => {
@branchHint(.unlikely);
log.warn("invalid cursor up command: {f}", .{input});
return;
},
}, },
}, }),
}),
else => log.warn( else => log.warn(
"ignoring unimplemented CSI A with intermediates: {s}", "ignoring unimplemented CSI A with intermediates: {s}",
.{input.intermediates}, .{input.intermediates},
), ),
}
}, },
// CUD - Cursor Down // CUD - Cursor Down
@ -841,6 +877,7 @@ pub fn Stream(comptime Handler: type) type {
0 => 1, 0 => 1,
1 => input.params[0], 1 => input.params[0],
else => { else => {
@branchHint(.unlikely);
log.warn("invalid cursor down command: {f}", .{input}); log.warn("invalid cursor down command: {f}", .{input});
return; return;
}, },
@ -854,22 +891,26 @@ pub fn Stream(comptime Handler: type) type {
}, },
// CUF - Cursor Right // CUF - Cursor Right
'C' => switch (input.intermediates.len) { 'C' => {
0 => try self.handler.vt(.cursor_right, .{ @branchHint(.likely);
.value = switch (input.params.len) { switch (input.intermediates.len) {
0 => 1, 0 => try self.handler.vt(.cursor_right, .{
1 => input.params[0], .value = switch (input.params.len) {
else => { 0 => 1,
log.warn("invalid cursor right command: {f}", .{input}); 1 => input.params[0],
return; else => {
@branchHint(.unlikely);
log.warn("invalid cursor right command: {f}", .{input});
return;
},
}, },
}, }),
}),
else => log.warn( else => log.warn(
"ignoring unimplemented CSI C with intermediates: {s}", "ignoring unimplemented CSI C with intermediates: {s}",
.{input.intermediates}, .{input.intermediates},
), ),
}
}, },
// CUB - Cursor Left // CUB - Cursor Left
@ -879,6 +920,7 @@ pub fn Stream(comptime Handler: type) type {
0 => 1, 0 => 1,
1 => input.params[0], 1 => input.params[0],
else => { else => {
@branchHint(.unlikely);
log.warn("invalid cursor left command: {f}", .{input}); log.warn("invalid cursor left command: {f}", .{input});
return; return;
}, },
@ -899,6 +941,7 @@ pub fn Stream(comptime Handler: type) type {
0 => 1, 0 => 1,
1 => input.params[0], 1 => input.params[0],
else => { else => {
@branchHint(.unlikely);
log.warn("invalid cursor up command: {f}", .{input}); log.warn("invalid cursor up command: {f}", .{input});
return; return;
}, },
@ -921,6 +964,7 @@ pub fn Stream(comptime Handler: type) type {
0 => 1, 0 => 1,
1 => input.params[0], 1 => input.params[0],
else => { else => {
@branchHint(.unlikely);
log.warn("invalid cursor down command: {f}", .{input}); log.warn("invalid cursor down command: {f}", .{input});
return; return;
}, },
@ -943,6 +987,7 @@ pub fn Stream(comptime Handler: type) type {
0 => 1, 0 => 1,
1 => input.params[0], 1 => input.params[0],
else => { else => {
@branchHint(.unlikely);
log.warn("invalid HPA command: {f}", .{input}); log.warn("invalid HPA command: {f}", .{input});
return; return;
}, },
@ -957,24 +1002,28 @@ pub fn Stream(comptime Handler: type) type {
// CUP - Set Cursor Position. // CUP - Set Cursor Position.
// TODO: test // TODO: test
'H', 'f' => switch (input.intermediates.len) { 'H', 'f' => {
0 => { @branchHint(.likely);
const pos: streampkg.Action.CursorPos = switch (input.params.len) { switch (input.intermediates.len) {
0 => .{ .row = 1, .col = 1 }, 0 => {
1 => .{ .row = input.params[0], .col = 1 }, const pos: streampkg.Action.CursorPos = switch (input.params.len) {
2 => .{ .row = input.params[0], .col = input.params[1] }, 0 => .{ .row = 1, .col = 1 },
else => { 1 => .{ .row = input.params[0], .col = 1 },
log.warn("invalid CUP command: {f}", .{input}); 2 => .{ .row = input.params[0], .col = input.params[1] },
return; else => {
}, @branchHint(.unlikely);
}; log.warn("invalid CUP command: {f}", .{input});
try self.handler.vt(.cursor_pos, pos); return;
}, },
};
try self.handler.vt(.cursor_pos, pos);
},
else => log.warn( else => log.warn(
"ignoring unimplemented CSI H with intermediates: {s}", "ignoring unimplemented CSI H with intermediates: {s}",
.{input.intermediates}, .{input.intermediates},
), ),
}
}, },
// CHT - Cursor Horizontal Tabulation // CHT - Cursor Horizontal Tabulation
@ -1029,6 +1078,7 @@ pub fn Stream(comptime Handler: type) type {
// Erase Line // Erase Line
'K' => { 'K' => {
@branchHint(.likely);
const protected_: ?bool = switch (input.intermediates.len) { const protected_: ?bool = switch (input.intermediates.len) {
0 => false, 0 => false,
1 => if (input.intermediates[0] == '?') true else null, 1 => if (input.intermediates[0] == '?') true else null,
@ -1036,6 +1086,7 @@ pub fn Stream(comptime Handler: type) type {
}; };
const protected = protected_ orelse { const protected = protected_ orelse {
@branchHint(.unlikely);
log.warn("invalid erase line command: {f}", .{input}); log.warn("invalid erase line command: {f}", .{input});
return; return;
}; };
@ -1047,6 +1098,7 @@ pub fn Stream(comptime Handler: type) type {
}; };
const mode = mode_ orelse { const mode = mode_ orelse {
@branchHint(.unlikely);
log.warn("invalid erase line command: {f}", .{input}); log.warn("invalid erase line command: {f}", .{input});
return; return;
}; };
@ -1056,7 +1108,10 @@ pub fn Stream(comptime Handler: type) type {
.left => try self.handler.vt(.erase_line_left, protected), .left => try self.handler.vt(.erase_line_left, protected),
.complete => try self.handler.vt(.erase_line_complete, protected), .complete => try self.handler.vt(.erase_line_complete, protected),
.right_unless_pending_wrap => try self.handler.vt(.erase_line_right_unless_pending_wrap, protected), .right_unless_pending_wrap => try self.handler.vt(.erase_line_right_unless_pending_wrap, protected),
_ => log.warn("invalid erase line mode: {}", .{mode}), _ => {
@branchHint(.unlikely);
log.warn("invalid erase line mode: {}", .{mode});
},
} }
}, },
@ -1189,20 +1244,24 @@ pub fn Stream(comptime Handler: type) type {
}, },
// Erase Characters (ECH) // Erase Characters (ECH)
'X' => switch (input.intermediates.len) { 'X' => {
0 => try self.handler.vt(.erase_chars, switch (input.params.len) { @branchHint(.likely);
0 => 1, switch (input.intermediates.len) {
1 => input.params[0], 0 => try self.handler.vt(.erase_chars, switch (input.params.len) {
else => { 0 => 1,
log.warn("invalid erase characters command: {f}", .{input}); 1 => input.params[0],
return; else => {
}, @branchHint(.unlikely);
}), log.warn("invalid erase characters command: {f}", .{input});
return;
},
}),
else => log.warn( else => log.warn(
"ignoring unimplemented CSI X with intermediates: {s}", "ignoring unimplemented CSI X with intermediates: {s}",
.{input.intermediates}, .{input.intermediates},
), ),
}
}, },
// CHT - Cursor Horizontal Tabulation Back // CHT - Cursor Horizontal Tabulation Back
@ -1342,6 +1401,7 @@ pub fn Stream(comptime Handler: type) type {
// SM - Set Mode // SM - Set Mode
'h' => mode: { 'h' => mode: {
@branchHint(.likely);
const ansi_mode = ansi: { const ansi_mode = ansi: {
if (input.intermediates.len == 0) break :ansi true; if (input.intermediates.len == 0) break :ansi true;
if (input.intermediates.len == 1 and if (input.intermediates.len == 1 and
@ -1362,6 +1422,7 @@ pub fn Stream(comptime Handler: type) type {
// RM - Reset Mode // RM - Reset Mode
'l' => mode: { 'l' => mode: {
@branchHint(.likely);
const ansi_mode = ansi: { const ansi_mode = ansi: {
if (input.intermediates.len == 0) break :ansi true; if (input.intermediates.len == 0) break :ansi true;
if (input.intermediates.len == 1 and if (input.intermediates.len == 1 and
@ -1381,81 +1442,86 @@ pub fn Stream(comptime Handler: type) type {
}, },
// SGR - Select Graphic Rendition // SGR - Select Graphic Rendition
'm' => switch (input.intermediates.len) { 'm' => {
0 => { @branchHint(.likely);
// log.info("parse SGR params={any}", .{input.params}); switch (input.intermediates.len) {
var p: sgr.Parser = .{ 0 => {
.params = input.params, // This is the most common case.
.params_sep = input.params_sep, @branchHint(.likely);
}; // log.info("parse SGR params={any}", .{input.params});
while (p.next()) |attr| { var p: sgr.Parser = .{
// log.info("SGR attribute: {}", .{attr}); .params = input.params,
try self.handler.vt(.set_attribute, attr); .params_sep = input.params_sep,
}
},
1 => switch (input.intermediates[0]) {
'>' => blk: {
if (input.params.len == 0) {
// Reset
try self.handler.vt(.modify_key_format, .legacy);
break :blk;
}
var format: ansi.ModifyKeyFormat = switch (input.params[0]) {
0 => .legacy,
1 => .cursor_keys,
2 => .function_keys,
4 => .other_keys_none,
else => {
log.warn("invalid setModifyKeyFormat: {f}", .{input});
break :blk;
},
}; };
while (p.next()) |attr| {
if (input.params.len > 2) { // log.info("SGR attribute: {}", .{attr});
log.warn("invalid setModifyKeyFormat: {f}", .{input}); try self.handler.vt(.set_attribute, attr);
break :blk;
} }
if (input.params.len == 2) {
switch (format) {
// We don't support any of the subparams yet for these.
.legacy => {},
.cursor_keys => {},
.function_keys => {},
// We only support the numeric form.
.other_keys_none => switch (input.params[1]) {
2 => format = .other_keys_numeric,
else => {},
},
.other_keys_numeric_except => {},
.other_keys_numeric => {},
}
}
try self.handler.vt(.modify_key_format, format);
}, },
else => log.warn( 1 => switch (input.intermediates[0]) {
"unknown CSI m with intermediate: {}", '>' => blk: {
.{input.intermediates[0]}, if (input.params.len == 0) {
), // Reset
}, try self.handler.vt(.modify_key_format, .legacy);
break :blk;
}
else => { var format: ansi.ModifyKeyFormat = switch (input.params[0]) {
// Nothing, but I wanted a place to put this comment: 0 => .legacy,
// there are others forms of CSI m that have intermediates. 1 => .cursor_keys,
// `vim --clean` uses `CSI ? 4 m` and I don't know what 2 => .function_keys,
// that means. And there is also `CSI > m` which is used 4 => .other_keys_none,
// to control modifier key reporting formats that we don't else => {
// support yet. @branchHint(.unlikely);
log.warn( log.warn("invalid setModifyKeyFormat: {f}", .{input});
"ignoring unimplemented CSI m with intermediates: {s}", break :blk;
.{input.intermediates}, },
); };
},
if (input.params.len > 2) {
@branchHint(.unlikely);
log.warn("invalid setModifyKeyFormat: {f}", .{input});
break :blk;
}
if (input.params.len == 2) {
switch (format) {
// We don't support any of the subparams yet for these.
.legacy => {},
.cursor_keys => {},
.function_keys => {},
// We only support the numeric form.
.other_keys_none => switch (input.params[1]) {
2 => format = .other_keys_numeric,
else => {},
},
.other_keys_numeric_except => {},
.other_keys_numeric => {},
}
}
try self.handler.vt(.modify_key_format, format);
},
else => log.warn(
"unknown CSI m with intermediate: {}",
.{input.intermediates[0]},
),
},
else => {
// Nothing, but I wanted a place to put this comment:
// there are others forms of CSI m that have intermediates.
// `vim --clean` uses `CSI ? 4 m` and I don't know what
// that means.
log.warn(
"ignoring unimplemented CSI m with intermediates: {s}",
.{input.intermediates},
);
},
}
}, },
// TODO: test // TODO: test
@ -1622,40 +1688,46 @@ pub fn Stream(comptime Handler: type) type {
), ),
}, },
'r' => switch (input.intermediates.len) { 'r' => {
// DECSTBM - Set Top and Bottom Margins @branchHint(.likely);
0 => switch (input.params.len) { switch (input.intermediates.len) {
0 => try self.handler.vt(.top_and_bottom_margin, .{ .top_left = 0, .bottom_right = 0 }), // DECSTBM - Set Top and Bottom Margins
1 => try self.handler.vt(.top_and_bottom_margin, .{ .top_left = input.params[0], .bottom_right = 0 }), 0 => switch (input.params.len) {
2 => try self.handler.vt(.top_and_bottom_margin, .{ .top_left = input.params[0], .bottom_right = input.params[1] }), 0 => try self.handler.vt(.top_and_bottom_margin, .{ .top_left = 0, .bottom_right = 0 }),
else => log.warn("invalid DECSTBM command: {f}", .{input}), 1 => try self.handler.vt(.top_and_bottom_margin, .{ .top_left = input.params[0], .bottom_right = 0 }),
}, 2 => try self.handler.vt(.top_and_bottom_margin, .{ .top_left = input.params[0], .bottom_right = input.params[1] }),
else => {
@branchHint(.unlikely);
log.warn("invalid DECSTBM command: {f}", .{input});
},
},
1 => switch (input.intermediates[0]) { 1 => switch (input.intermediates[0]) {
// Restore Mode // Restore Mode
'?' => { '?' => {
for (input.params) |mode_int| { for (input.params) |mode_int| {
if (modes.modeFromInt(mode_int, false)) |mode| { if (modes.modeFromInt(mode_int, false)) |mode| {
try self.handler.vt(.restore_mode, .{ .mode = mode }); try self.handler.vt(.restore_mode, .{ .mode = mode });
} else { } else {
log.warn( log.warn(
"unimplemented restore mode: {}", "unimplemented restore mode: {}",
.{mode_int}, .{mode_int},
); );
}
} }
} },
else => log.warn(
"unknown CSI s with intermediate: {f}",
.{input},
),
}, },
else => log.warn( else => log.warn(
"unknown CSI s with intermediate: {f}", "ignoring unimplemented CSI s with intermediates: {f}",
.{input}, .{input},
), ),
}, }
else => log.warn(
"ignoring unimplemented CSI s with intermediates: {f}",
.{input},
),
}, },
's' => switch (input.intermediates.len) { 's' => switch (input.intermediates.len) {
@ -1866,6 +1938,7 @@ pub fn Stream(comptime Handler: type) type {
0 => 1, 0 => 1,
1 => input.params[0], 1 => input.params[0],
else => { else => {
@branchHint(.unlikely);
log.warn("invalid ICH command: {f}", .{input}); log.warn("invalid ICH command: {f}", .{input});
return; return;
}, },
@ -1906,9 +1979,34 @@ pub fn Stream(comptime Handler: type) type {
} }
inline fn oscDispatch(self: *Self, cmd: osc.Command) !void { inline fn oscDispatch(self: *Self, cmd: osc.Command) !void {
// The branch hints here are based on real world data
// which indicates that the most common OSC commands are:
//
// 1. hyperlink_end
// 2. change_window_title
// 3. change_window_icon
// 4. hyperlink_start
// 5. report_pwd
// 6. color_operation
// 7. prompt_start
// 8. prompt_end
//
// Together, these 8 commands make up about 96% of all
// OSC commands encountered in real world scenarios.
//
// Additionally, within the prongs, unlikely branch
// hints have been added to branches that deal with
// invalid sequences/commands, this is in order to
// optimize for the happy path where we're getting
// valid data from the program we're running.
//
// ref: https://github.com/qwerasd205/asciinema-stats
switch (cmd) { switch (cmd) {
.change_window_title => |title| { .change_window_title => |title| {
@branchHint(.likely);
if (!std.unicode.utf8ValidateSlice(title)) { if (!std.unicode.utf8ValidateSlice(title)) {
@branchHint(.unlikely);
log.warn("change title request: invalid utf-8, ignoring request", .{}); log.warn("change title request: invalid utf-8, ignoring request", .{});
return; return;
} }
@ -1917,6 +2015,7 @@ pub fn Stream(comptime Handler: type) type {
}, },
.change_window_icon => |icon| { .change_window_icon => |icon| {
@branchHint(.likely);
log.info("OSC 1 (change icon) received and ignored icon={s}", .{icon}); log.info("OSC 1 (change icon) received and ignored icon={s}", .{icon});
}, },
@ -1928,6 +2027,7 @@ pub fn Stream(comptime Handler: type) type {
}, },
.prompt_start => |v| { .prompt_start => |v| {
@branchHint(.likely);
switch (v.kind) { switch (v.kind) {
.primary, .right => try self.handler.vt(.prompt_start, .{ .primary, .right => try self.handler.vt(.prompt_start, .{
.aid = v.aid, .aid = v.aid,
@ -1939,7 +2039,10 @@ pub fn Stream(comptime Handler: type) type {
} }
}, },
.prompt_end => try self.handler.vt(.prompt_end, {}), .prompt_end => {
@branchHint(.likely);
try self.handler.vt(.prompt_end, {});
},
.end_of_input => try self.handler.vt(.end_of_input, {}), .end_of_input => try self.handler.vt(.end_of_input, {}),
@ -1948,11 +2051,13 @@ pub fn Stream(comptime Handler: type) type {
}, },
.report_pwd => |v| { .report_pwd => |v| {
@branchHint(.likely);
try self.handler.vt(.report_pwd, .{ .url = v.value }); try self.handler.vt(.report_pwd, .{ .url = v.value });
}, },
.mouse_shape => |v| { .mouse_shape => |v| {
const shape = MouseShape.fromString(v.value) orelse { const shape = MouseShape.fromString(v.value) orelse {
@branchHint(.unlikely);
log.warn("unknown cursor shape: {s}", .{v.value}); log.warn("unknown cursor shape: {s}", .{v.value});
return; return;
}; };
@ -1961,6 +2066,7 @@ pub fn Stream(comptime Handler: type) type {
}, },
.color_operation => |v| { .color_operation => |v| {
@branchHint(.likely);
try self.handler.vt(.color_operation, .{ try self.handler.vt(.color_operation, .{
.op = v.op, .op = v.op,
.requests = v.requests, .requests = v.requests,
@ -1980,6 +2086,7 @@ pub fn Stream(comptime Handler: type) type {
}, },
.hyperlink_start => |v| { .hyperlink_start => |v| {
@branchHint(.likely);
try self.handler.vt(.start_hyperlink, .{ try self.handler.vt(.start_hyperlink, .{
.uri = v.uri, .uri = v.uri,
.id = v.id, .id = v.id,
@ -1987,6 +2094,7 @@ pub fn Stream(comptime Handler: type) type {
}, },
.hyperlink_end => { .hyperlink_end => {
@branchHint(.likely);
try self.handler.vt(.end_hyperlink, {}); try self.handler.vt(.end_hyperlink, {});
}, },
@ -2004,6 +2112,7 @@ pub fn Stream(comptime Handler: type) type {
}, },
.invalid => { .invalid => {
@branchHint(.cold);
// This is an invalid internal state, not an invalid OSC // This is an invalid internal state, not an invalid OSC
// string being parsed. We shouldn't see this. // string being parsed. We shouldn't see this.
log.warn("invalid OSC, should never happen", .{}); log.warn("invalid OSC, should never happen", .{});
@ -2029,6 +2138,7 @@ pub fn Stream(comptime Handler: type) type {
'*' => .G2, '*' => .G2,
'+' => .G3, '+' => .G3,
else => { else => {
@branchHint(.unlikely);
log.warn("invalid charset intermediate: {any}", .{intermediates}); log.warn("invalid charset intermediate: {any}", .{intermediates});
return; return;
}, },
@ -2044,22 +2154,56 @@ pub fn Stream(comptime Handler: type) type {
self: *Self, self: *Self,
action: Parser.Action.ESC, action: Parser.Action.ESC,
) !void { ) !void {
// The branch hints here are based on real world data
// which indicates that the most common ESC finals are:
//
// 1. B
// 2. \
// 3. 0
// 4. M
// 5. 8
// 6. 7
// 7. >
// 8. =
//
// Together, these 8 finals make up nearly 99% of all
// ESC sequences encountered in real world scenarios.
//
// Additionally, within the prongs, unlikely branch
// hints have been added to branches that deal with
// invalid sequences/commands, this is in order to
// optimize for the happy path where we're getting
// valid data from the program we're running.
//
// ref: https://github.com/qwerasd205/asciinema-stats
switch (action.final) { switch (action.final) {
// Charsets // Charsets
'B' => try self.configureCharset(action.intermediates, .ascii), 'B' => {
@branchHint(.likely);
try self.configureCharset(action.intermediates, .ascii);
},
'A' => try self.configureCharset(action.intermediates, .british), 'A' => try self.configureCharset(action.intermediates, .british),
'0' => try self.configureCharset(action.intermediates, .dec_special), '0' => {
@branchHint(.likely);
try self.configureCharset(action.intermediates, .dec_special);
},
// DECSC - Save Cursor // DECSC - Save Cursor
'7' => switch (action.intermediates.len) { '7' => {
0 => try self.handler.vt(.save_cursor, {}), @branchHint(.likely);
else => { switch (action.intermediates.len) {
log.warn("invalid command: {f}", .{action}); 0 => try self.handler.vt(.save_cursor, {}),
return; else => {
}, @branchHint(.unlikely);
log.warn("invalid command: {f}", .{action});
return;
},
}
}, },
'8' => blk: { '8' => blk: {
@branchHint(.likely);
switch (action.intermediates.len) { switch (action.intermediates.len) {
// DECRC - Restore Cursor // DECRC - Restore Cursor
0 => { 0 => {
@ -2087,6 +2231,7 @@ pub fn Stream(comptime Handler: type) type {
'D' => switch (action.intermediates.len) { 'D' => switch (action.intermediates.len) {
0 => try self.handler.vt(.index, {}), 0 => try self.handler.vt(.index, {}),
else => { else => {
@branchHint(.unlikely);
log.warn("invalid index command: {f}", .{action}); log.warn("invalid index command: {f}", .{action});
return; return;
}, },
@ -2096,6 +2241,7 @@ pub fn Stream(comptime Handler: type) type {
'E' => switch (action.intermediates.len) { 'E' => switch (action.intermediates.len) {
0 => try self.handler.vt(.next_line, {}), 0 => try self.handler.vt(.next_line, {}),
else => { else => {
@branchHint(.unlikely);
log.warn("invalid next line command: {f}", .{action}); log.warn("invalid next line command: {f}", .{action});
return; return;
}, },
@ -2105,18 +2251,23 @@ pub fn Stream(comptime Handler: type) type {
'H' => switch (action.intermediates.len) { 'H' => switch (action.intermediates.len) {
0 => try self.handler.vt(.tab_set, {}), 0 => try self.handler.vt(.tab_set, {}),
else => { else => {
@branchHint(.unlikely);
log.warn("invalid tab set command: {f}", .{action}); log.warn("invalid tab set command: {f}", .{action});
return; return;
}, },
}, },
// RI - Reverse Index // RI - Reverse Index
'M' => switch (action.intermediates.len) { 'M' => {
0 => try self.handler.vt(.reverse_index, {}), @branchHint(.likely);
else => { switch (action.intermediates.len) {
log.warn("invalid reverse index command: {f}", .{action}); 0 => try self.handler.vt(.reverse_index, {}),
return; else => {
}, @branchHint(.unlikely);
log.warn("invalid reverse index command: {f}", .{action});
return;
},
}
}, },
// SS2 - Single Shift 2 // SS2 - Single Shift 2
@ -2127,6 +2278,7 @@ pub fn Stream(comptime Handler: type) type {
.locking = true, .locking = true,
}), }),
else => { else => {
@branchHint(.unlikely);
log.warn("invalid single shift 2 command: {f}", .{action}); log.warn("invalid single shift 2 command: {f}", .{action});
return; return;
}, },
@ -2140,6 +2292,7 @@ pub fn Stream(comptime Handler: type) type {
.locking = true, .locking = true,
}), }),
else => { else => {
@branchHint(.unlikely);
log.warn("invalid single shift 3 command: {f}", .{action}); log.warn("invalid single shift 3 command: {f}", .{action});
return; return;
}, },
@ -2179,6 +2332,7 @@ pub fn Stream(comptime Handler: type) type {
.locking = false, .locking = false,
}), }),
else => { else => {
@branchHint(.unlikely);
log.warn("invalid single shift 2 command: {f}", .{action}); log.warn("invalid single shift 2 command: {f}", .{action});
return; return;
}, },
@ -2192,6 +2346,7 @@ pub fn Stream(comptime Handler: type) type {
.locking = false, .locking = false,
}), }),
else => { else => {
@branchHint(.unlikely);
log.warn("invalid single shift 3 command: {f}", .{action}); log.warn("invalid single shift 3 command: {f}", .{action});
return; return;
}, },
@ -2205,6 +2360,7 @@ pub fn Stream(comptime Handler: type) type {
.locking = false, .locking = false,
}), }),
else => { else => {
@branchHint(.unlikely);
log.warn("invalid locking shift 1 right command: {f}", .{action}); log.warn("invalid locking shift 1 right command: {f}", .{action});
return; return;
}, },
@ -2218,6 +2374,7 @@ pub fn Stream(comptime Handler: type) type {
.locking = false, .locking = false,
}), }),
else => { else => {
@branchHint(.unlikely);
log.warn("invalid locking shift 2 right command: {f}", .{action}); log.warn("invalid locking shift 2 right command: {f}", .{action});
return; return;
}, },
@ -2231,26 +2388,35 @@ pub fn Stream(comptime Handler: type) type {
.locking = false, .locking = false,
}), }),
else => { else => {
@branchHint(.unlikely);
log.warn("invalid locking shift 3 right command: {f}", .{action}); log.warn("invalid locking shift 3 right command: {f}", .{action});
return; return;
}, },
}, },
// Set application keypad mode // Set application keypad mode
'=' => switch (action.intermediates.len) { '=' => {
0 => try self.handler.vt(.set_mode, .{ .mode = .keypad_keys }), @branchHint(.likely);
else => log.warn("unimplemented setMode: {f}", .{action}), switch (action.intermediates.len) {
0 => try self.handler.vt(.set_mode, .{ .mode = .keypad_keys }),
else => log.warn("unimplemented setMode: {f}", .{action}),
}
}, },
// Reset application keypad mode // Reset application keypad mode
'>' => switch (action.intermediates.len) { '>' => {
0 => try self.handler.vt(.reset_mode, .{ .mode = .keypad_keys }), @branchHint(.likely);
else => log.warn("unimplemented setMode: {f}", .{action}), switch (action.intermediates.len) {
0 => try self.handler.vt(.reset_mode, .{ .mode = .keypad_keys }),
else => log.warn("unimplemented setMode: {f}", .{action}),
}
}, },
// Sets ST (string terminator). We don't have to do anything // Sets ST (string terminator). We don't have to do anything
// because our parser always accepts ST. // because our parser always accepts ST.
'\\' => {}, '\\' => {
@branchHint(.likely);
},
else => log.warn("unimplemented ESC action: {f}", .{action}), else => log.warn("unimplemented ESC action: {f}", .{action}),
} }

View File

@ -165,22 +165,47 @@ pub const StreamHandler = struct {
comptime action: Stream.Action.Tag, comptime action: Stream.Action.Tag,
value: Stream.Action.Value(action), value: Stream.Action.Value(action),
) !void { ) !void {
// The branch hints here are based on real world data
// which indicates that the most common actions are:
//
// 1. print
// 2. set_attribute
// 3. carriage_return
// 4. line_feed
// 5. cursor_pos
//
// Together, these 5 actions make up nearly 98% of
// all actions encountered in real world scenarios.
//
// ref: https://github.com/qwerasd205/asciinema-stats
switch (action) { switch (action) {
.print => try self.terminal.print(value.cp), .print => {
@branchHint(.likely);
try self.terminal.print(value.cp);
},
.print_repeat => try self.terminal.printRepeat(value), .print_repeat => try self.terminal.printRepeat(value),
.bell => self.bell(), .bell => self.bell(),
.backspace => self.terminal.backspace(), .backspace => self.terminal.backspace(),
.horizontal_tab => try self.horizontalTab(value), .horizontal_tab => try self.horizontalTab(value),
.horizontal_tab_back => try self.horizontalTabBack(value), .horizontal_tab_back => try self.horizontalTabBack(value),
.linefeed => try self.linefeed(), .linefeed => {
.carriage_return => self.terminal.carriageReturn(), @branchHint(.likely);
try self.linefeed();
},
.carriage_return => {
@branchHint(.likely);
self.terminal.carriageReturn();
},
.enquiry => try self.enquiry(), .enquiry => try self.enquiry(),
.invoke_charset => self.terminal.invokeCharset(value.bank, value.charset, value.locking), .invoke_charset => self.terminal.invokeCharset(value.bank, value.charset, value.locking),
.cursor_up => self.terminal.cursorUp(value.value), .cursor_up => self.terminal.cursorUp(value.value),
.cursor_down => self.terminal.cursorDown(value.value), .cursor_down => self.terminal.cursorDown(value.value),
.cursor_left => self.terminal.cursorLeft(value.value), .cursor_left => self.terminal.cursorLeft(value.value),
.cursor_right => self.terminal.cursorRight(value.value), .cursor_right => self.terminal.cursorRight(value.value),
.cursor_pos => self.terminal.setCursorPos(value.row, value.col), .cursor_pos => {
@branchHint(.likely);
self.terminal.setCursorPos(value.row, value.col);
},
.cursor_col => self.terminal.setCursorPos(self.terminal.screens.active.cursor.y + 1, value.value), .cursor_col => self.terminal.setCursorPos(self.terminal.screens.active.cursor.y + 1, value.value),
.cursor_row => self.terminal.setCursorPos(value.value, self.terminal.screens.active.cursor.x + 1), .cursor_row => self.terminal.setCursorPos(value.value, self.terminal.screens.active.cursor.x + 1),
.cursor_col_relative => self.terminal.setCursorPos( .cursor_col_relative => self.terminal.setCursorPos(
@ -290,10 +315,23 @@ pub const StreamHandler = struct {
.end_of_command => self.endOfCommand(value.exit_code), .end_of_command => self.endOfCommand(value.exit_code),
.mouse_shape => try self.setMouseShape(value), .mouse_shape => try self.setMouseShape(value),
.configure_charset => self.configureCharset(value.slot, value.charset), .configure_charset => self.configureCharset(value.slot, value.charset),
.set_attribute => switch (value) { .set_attribute => {
.unknown => |unk| log.warn("unimplemented or unknown SGR attribute: {any}", .{unk}), @branchHint(.likely);
else => self.terminal.setAttribute(value) catch |err| switch (value) {
log.warn("error setting attribute {}: {}", .{ value, err }), .unknown => |unk| {
// We optimize for the happy path scenario here, since
// unknown/invalid SGRs aren't that common in the wild.
@branchHint(.unlikely);
log.warn("unimplemented or unknown SGR attribute: {any}", .{unk});
},
else => {
@branchHint(.likely);
self.terminal.setAttribute(value) catch |err| {
@branchHint(.cold);
log.warn("error setting attribute {}: {}", .{ value, err });
};
},
}
}, },
.dcs_hook => try self.dcsHook(value), .dcs_hook => try self.dcsHook(value),
.dcs_put => try self.dcsPut(value), .dcs_put => try self.dcsPut(value),