diff --git a/benchmarks/Microsoft.AspNetCore.Routing.Performance/Matchers/AzureMatcherBenchmark.cs b/benchmarks/Microsoft.AspNetCore.Routing.Performance/Matchers/AzureMatcherBenchmark.cs
index 5a5d9f0a44..1420ef4b5e 100644
--- a/benchmarks/Microsoft.AspNetCore.Routing.Performance/Matchers/AzureMatcherBenchmark.cs
+++ b/benchmarks/Microsoft.AspNetCore.Routing.Performance/Matchers/AzureMatcherBenchmark.cs
@@ -14,7 +14,6 @@ namespace Microsoft.AspNetCore.Routing.Matchers
private BarebonesMatcher _baseline;
private Matcher _dfa;
- private Matcher _instruction;
private Matcher _route;
private Matcher _tree;
@@ -34,7 +33,6 @@ namespace Microsoft.AspNetCore.Routing.Matchers
_baseline = (BarebonesMatcher)SetupMatcher(new BarebonesMatcherBuilder());
_dfa = SetupMatcher(new DfaMatcherBuilder());
- _instruction = SetupMatcher(new InstructionMatcherBuilder());
_route = SetupMatcher(new RouteMatcherBuilder());
_tree = SetupMatcher(new TreeRouterMatcherBuilder());
@@ -67,19 +65,6 @@ namespace Microsoft.AspNetCore.Routing.Matchers
}
}
- [Benchmark(OperationsPerInvoke = SampleCount)]
- public async Task Instruction()
- {
- var feature = _feature;
- for (var i = 0; i < SampleCount; i++)
- {
- var sample = _samples[i];
- var httpContext = _requests[sample];
- await _instruction.MatchAsync(httpContext, feature);
- Validate(httpContext, _endpoints[sample], feature.Endpoint);
- }
- }
-
[Benchmark(OperationsPerInvoke = SampleCount)]
public async Task LegacyRoute()
{
diff --git a/benchmarks/Microsoft.AspNetCore.Routing.Performance/Matchers/GithubMatcherBenchmark.cs b/benchmarks/Microsoft.AspNetCore.Routing.Performance/Matchers/GithubMatcherBenchmark.cs
index 39f2fb3c45..58b4906006 100644
--- a/benchmarks/Microsoft.AspNetCore.Routing.Performance/Matchers/GithubMatcherBenchmark.cs
+++ b/benchmarks/Microsoft.AspNetCore.Routing.Performance/Matchers/GithubMatcherBenchmark.cs
@@ -13,7 +13,6 @@ namespace Microsoft.AspNetCore.Routing.Matchers
{
private BarebonesMatcher _baseline;
private Matcher _dfa;
- private Matcher _instruction;
private Matcher _route;
private Matcher _tree;
@@ -28,7 +27,6 @@ namespace Microsoft.AspNetCore.Routing.Matchers
_baseline = (BarebonesMatcher)SetupMatcher(new BarebonesMatcherBuilder());
_dfa = SetupMatcher(new DfaMatcherBuilder());
- _instruction = SetupMatcher(new InstructionMatcherBuilder());
_route = SetupMatcher(new RouteMatcherBuilder());
_tree = SetupMatcher(new TreeRouterMatcherBuilder());
@@ -59,18 +57,6 @@ namespace Microsoft.AspNetCore.Routing.Matchers
}
}
- [Benchmark(OperationsPerInvoke = EndpointCount)]
- public async Task Instruction()
- {
- var feature = _feature;
- for (var i = 0; i < EndpointCount; i++)
- {
- var httpContext = _requests[i];
- await _instruction.MatchAsync(httpContext, feature);
- Validate(httpContext, _endpoints[i], feature.Endpoint);
- }
- }
-
[Benchmark(OperationsPerInvoke = EndpointCount)]
public async Task LegacyRoute()
{
diff --git a/benchmarks/Microsoft.AspNetCore.Routing.Performance/Matchers/SingleEntryMatcherBenchmark.cs b/benchmarks/Microsoft.AspNetCore.Routing.Performance/Matchers/SingleEntryMatcherBenchmark.cs
index 586eb45390..278597b30e 100644
--- a/benchmarks/Microsoft.AspNetCore.Routing.Performance/Matchers/SingleEntryMatcherBenchmark.cs
+++ b/benchmarks/Microsoft.AspNetCore.Routing.Performance/Matchers/SingleEntryMatcherBenchmark.cs
@@ -11,7 +11,6 @@ namespace Microsoft.AspNetCore.Routing.Matchers
{
private Matcher _baseline;
private Matcher _dfa;
- private Matcher _instruction;
private Matcher _route;
private Matcher _tree;
@@ -30,7 +29,6 @@ namespace Microsoft.AspNetCore.Routing.Matchers
_baseline = SetupMatcher(new TrivialMatcherBuilder());
_dfa = SetupMatcher(new DfaMatcherBuilder());
- _instruction = SetupMatcher(new InstructionMatcherBuilder());
_route = SetupMatcher(new RouteMatcherBuilder());
_tree = SetupMatcher(new TreeRouterMatcherBuilder());
@@ -59,14 +57,6 @@ namespace Microsoft.AspNetCore.Routing.Matchers
Validate(_requests[0], _endpoints[0], feature.Endpoint);
}
- [Benchmark]
- public async Task Instruction()
- {
- var feature = _feature;
- await _instruction.MatchAsync(_requests[0], feature);
- Validate(_requests[0], _endpoints[0], feature.Endpoint);
- }
-
[Benchmark]
public async Task LegacyRoute()
{
diff --git a/benchmarks/Microsoft.AspNetCore.Routing.Performance/Matchers/SmallEntryCountLiteralMatcherBenchark.cs b/benchmarks/Microsoft.AspNetCore.Routing.Performance/Matchers/SmallEntryCountLiteralMatcherBenchark.cs
index 5804246ca1..ed88e69693 100644
--- a/benchmarks/Microsoft.AspNetCore.Routing.Performance/Matchers/SmallEntryCountLiteralMatcherBenchark.cs
+++ b/benchmarks/Microsoft.AspNetCore.Routing.Performance/Matchers/SmallEntryCountLiteralMatcherBenchark.cs
@@ -11,7 +11,6 @@ namespace Microsoft.AspNetCore.Routing.Matchers
{
private Matcher _baseline;
private Matcher _dfa;
- private Matcher _instruction;
private Matcher _route;
private Matcher _tree;
@@ -26,7 +25,6 @@ namespace Microsoft.AspNetCore.Routing.Matchers
_baseline = SetupMatcher(new TrivialMatcherBuilder());
_dfa = SetupMatcher(new DfaMatcherBuilder());
- _instruction = SetupMatcher(new InstructionMatcherBuilder());
_route = SetupMatcher(new RouteMatcherBuilder());
_tree = SetupMatcher(new TreeRouterMatcherBuilder());
@@ -89,14 +87,6 @@ namespace Microsoft.AspNetCore.Routing.Matchers
Validate(_requests[0], _endpoints[9], feature.Endpoint);
}
- [Benchmark]
- public async Task Instruction()
- {
- var feature = _feature;
- await _instruction.MatchAsync(_requests[0], feature);
- Validate(_requests[0], _endpoints[9], feature.Endpoint);
- }
-
[Benchmark]
public async Task LegacyRoute()
{
diff --git a/benchmarks/Microsoft.AspNetCore.Routing.Performance/Microsoft.AspNetCore.Routing.Performance.csproj b/benchmarks/Microsoft.AspNetCore.Routing.Performance/Microsoft.AspNetCore.Routing.Performance.csproj
index 8c807811b5..145966eafb 100644
--- a/benchmarks/Microsoft.AspNetCore.Routing.Performance/Microsoft.AspNetCore.Routing.Performance.csproj
+++ b/benchmarks/Microsoft.AspNetCore.Routing.Performance/Microsoft.AspNetCore.Routing.Performance.csproj
@@ -33,12 +33,6 @@
Matchers\DfaMatcherBuilder.cs
-
- Matchers\InstructionMatcher.cs
-
-
- Matchers\InstructionMatcherBuilder.cs
-
Matchers\RouteMatcher.cs
diff --git a/test/Microsoft.AspNetCore.Routing.Tests/Matchers/InstructionMatcher.cs b/test/Microsoft.AspNetCore.Routing.Tests/Matchers/InstructionMatcher.cs
deleted file mode 100644
index cc4d9e6f8d..0000000000
--- a/test/Microsoft.AspNetCore.Routing.Tests/Matchers/InstructionMatcher.cs
+++ /dev/null
@@ -1,214 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-using System;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.Runtime.InteropServices;
-using System.Threading.Tasks;
-using Microsoft.AspNetCore.Http;
-
-namespace Microsoft.AspNetCore.Routing.Matchers
-{
- internal class InstructionMatcher : Matcher
- {
- private State _state;
-
- public InstructionMatcher(Instruction[] instructions, Candidate[] candidates, JumpTable[] tables)
- {
- _state = new State()
- {
- Instructions = instructions,
- Candidates = candidates,
- Tables = tables,
- };
- }
-
- public unsafe override Task MatchAsync(HttpContext httpContext, IEndpointFeature feature)
- {
- if (httpContext == null)
- {
- throw new ArgumentNullException(nameof(httpContext));
- }
-
- if (feature == null)
- {
- throw new ArgumentNullException(nameof(feature));
- }
-
- var state = _state;
-
- var path = httpContext.Request.Path.Value;
- var buffer = stackalloc PathSegment[32];
- var count = FastPathTokenizer.Tokenize(path, buffer, 32);
-
- var i = 0;
- var candidates = new List();
- while (i < state.Instructions.Length)
- {
- var instruction = state.Instructions[i];
- switch (instruction.Code)
- {
- case InstructionCode.Accept:
- {
- if (count == instruction.Depth)
- {
- candidates.Add(state.Candidates[instruction.Payload]);
- }
- i++;
- break;
- }
- case InstructionCode.Branch:
- {
- var table = state.Tables[instruction.Payload];
- i = table.GetDestination(buffer, count, path);
- break;
- }
- case InstructionCode.Jump:
- {
- i = instruction.Payload;
- break;
- }
- }
- }
-
- var matches = new List<(Endpoint, RouteValueDictionary)>();
- for (i = 0; i < candidates.Count; i++)
- {
- var values = new RouteValueDictionary();
- var parameters = candidates[i].Parameters;
- if (parameters != null)
- {
- for (var j = 0; j < parameters.Length; j++)
- {
- var parameter = parameters[j];
- if (parameter != null && buffer[j].Length == 0)
- {
- goto notmatch;
- }
- else if (parameter != null)
- {
- var value = path.Substring(buffer[j].Start, buffer[j].Length);
- values.Add(parameter, value);
- }
- }
- }
-
- matches.Add((candidates[i].Endpoint, values));
-
- notmatch:;
- }
-
- feature.Endpoint = matches.Count == 0 ? null : matches[0].Item1;
- feature.Values = matches.Count == 0 ? null : matches[0].Item2;
-
- return Task.CompletedTask;
- }
-
- public struct Candidate
- {
- public Endpoint Endpoint;
- public string[] Parameters;
- }
-
- public class State
- {
- public Candidate[] Candidates;
- public Instruction[] Instructions;
- public JumpTable[] Tables;
- }
-
- [DebuggerDisplay("{ToDebugString(),nq}")]
- [StructLayout(LayoutKind.Explicit)]
- public struct Instruction
- {
- [FieldOffset(0)]
- public byte Depth;
-
- [FieldOffset(3)]
- public InstructionCode Code;
-
- [FieldOffset(4)]
- public int Payload;
-
- private string ToDebugString()
- {
- return $"{Code}: {Payload}";
- }
- }
-
- public enum InstructionCode : byte
- {
- Accept,
- Branch,
- Jump,
- Pop, // Only used during the instruction builder phase
- }
-
- public abstract class JumpTable
- {
- public unsafe abstract int GetDestination(PathSegment* segments, int depth, string path);
- }
-
- public class JumpTableBuilder
- {
- private readonly List<(string text, int destination)> _entries = new List<(string text, int destination)>();
-
- public int Depth { get; set; }
-
- public int Exit { get; set; }
-
- public void AddEntry(string text, int destination)
- {
- _entries.Add((text, destination));
- }
-
- public JumpTable Build()
- {
- return new SimpleJumpTable(Depth, Exit, _entries.ToArray());
- }
- }
-
- public class SimpleJumpTable : JumpTable
- {
- private readonly (string text, int destination)[] _entries;
- private readonly int _depth;
- private readonly int _exit;
-
- public SimpleJumpTable(int depth, int exit, (string text, int destination)[] entries)
- {
- _depth = depth;
- _exit = exit;
- _entries = entries;
- }
-
- public unsafe override int GetDestination(PathSegment* segments, int count, string path)
- {
- if (_depth == count)
- {
- return _exit;
- }
-
- var start = segments[_depth].Start;
- var length = segments[_depth].Length;
-
- for (var i = 0; i < _entries.Length; i++)
- {
- if (length == _entries[i].text.Length &&
- string.Compare(
- path,
- start,
- _entries[i].text,
- 0,
- length,
- StringComparison.OrdinalIgnoreCase) == 0)
- {
- return _entries[i].destination;
- }
- }
-
- return _exit;
- }
- }
- }
-}
diff --git a/test/Microsoft.AspNetCore.Routing.Tests/Matchers/InstructionMatcherBuilder.cs b/test/Microsoft.AspNetCore.Routing.Tests/Matchers/InstructionMatcherBuilder.cs
deleted file mode 100644
index 40476d5008..0000000000
--- a/test/Microsoft.AspNetCore.Routing.Tests/Matchers/InstructionMatcherBuilder.cs
+++ /dev/null
@@ -1,356 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using Microsoft.AspNetCore.Routing.Template;
-using static Microsoft.AspNetCore.Routing.Matchers.InstructionMatcher;
-
-namespace Microsoft.AspNetCore.Routing.Matchers
-{
- internal class InstructionMatcherBuilder : MatcherBuilder
- {
- private List _entries = new List();
-
- public override void AddEndpoint(MatcherEndpoint endpoint)
- {
- var parsed = TemplateParser.Parse(endpoint.Template);
- _entries.Add(new Entry()
- {
- Order = 0,
- Pattern = parsed,
- Precedence = RoutePrecedence.ComputeInbound(parsed),
- Endpoint = endpoint,
- });
- }
-
- public override Matcher Build()
- {
- _entries.Sort((x, y) =>
- {
- var comparison = x.Order.CompareTo(y.Order);
- if (comparison != 0)
- {
- return comparison;
- }
-
- comparison = x.Precedence.CompareTo(y.Precedence);
- if (comparison != 0)
- {
- return comparison;
- }
-
- return x.Pattern.TemplateText.CompareTo(y.Pattern.TemplateText);
- });
-
- var roots = new List();
-
- for (var i = 0; i < _entries.Count; i++)
- {
- var entry = _entries[i];
-
- var parent = (SequenceNode)GetOrCreateRootNode(roots, entry.Order);
-
- var depth = 0;
- for (; depth < entry.Pattern.Segments.Count; depth++)
- {
- var segment = entry.Pattern.Segments[depth];
- if (segment.IsSimple && segment.Parts[0].IsLiteral)
- {
- var branch = parent.GetNode() ?? parent.AddNode(new BranchNode(depth));
-
- var index = -1;
- for (var j = 0; j < branch.Literals.Count; j++)
- {
- if (string.Equals(segment.Parts[0].Text, branch.Literals[j], StringComparison.OrdinalIgnoreCase))
- {
- index = j;
- break;
- }
- }
-
- if (index == -1)
- {
- branch.Literals.Add(segment.Parts[0].Text);
- branch.AddNode(new SequenceNode(depth + 1));
- index = branch.Children.Count - 1;
- }
-
- parent = (SequenceNode)branch.Children[index];
- }
- else if (segment.IsSimple && segment.Parts[0].IsParameter)
- {
- var parameter = parent.GetNode() ?? parent.AddNode(new ParameterNode(depth));
- if (parameter.Children.Count == 0)
- {
- parameter.AddNode(new SequenceNode(depth + 1));
- }
-
- parent = (SequenceNode)parameter.Children[0];
- }
- else
- {
- throw new InvalidOperationException("Not implemented!");
- }
- }
-
- parent.AddNode(new AcceptNode(depth, entry.Endpoint));
- }
-
- var builder = new InstructionBuilder();
- for (var i = 0; i < roots.Count; i++)
- {
- roots[i].Lower(builder);
- }
-
- var (instructions, endpoints, tables) = builder;
- var candidates = new Candidate[endpoints.Length];
- for (var i = 0; i < endpoints.Length; i++)
- {
- candidates[i] = CreateCandidate(endpoints[i]);
- }
-
- return new InstructionMatcher(instructions, candidates, tables);
- }
-
- private OrderNode GetOrCreateRootNode(List roots, int order)
- {
- OrderNode root = null;
- for (var j = 0; j < roots.Count; j++)
- {
- if (roots[j].Order == order)
- {
- root = roots[j];
- break;
- }
- }
-
- if (root == null)
- {
- // Nodes are guaranteed to be in order because the entries are in order.
- root = new OrderNode(order);
- roots.Add(root);
- }
-
- return root;
- }
-
- private static Candidate CreateCandidate(MatcherEndpoint endpoint)
- {
- var parsed = TemplateParser.Parse(endpoint.Template);
- return new Candidate()
- {
- Endpoint = endpoint,
- Parameters = parsed.Segments.Select(s => s.IsSimple && s.Parts[0].IsParameter ? s.Parts[0].Name : null).ToArray(),
- };
- }
-
- private class Entry
- {
- public int Order;
- public decimal Precedence;
- public RouteTemplate Pattern;
- public MatcherEndpoint Endpoint;
- }
-
- private class InstructionBuilder
- {
- private readonly List _instructions = new List();
- private readonly List _endpoints = new List();
- private readonly List _tables = new List();
-
- private readonly List _blocks = new List();
-
- public int Next => _instructions.Count;
-
- public void BeginBlock()
- {
- _blocks.Add(Next);
- }
-
- public void EndBlock()
- {
- var start = _blocks[_blocks.Count - 1];
- var end = Next;
- for (var i = start; i < end; i++)
- {
- if (_instructions[i].Code == InstructionCode.Pop)
- {
- _instructions[i] = new Instruction()
- {
- Code = InstructionCode.Jump,
- Depth = _instructions[i].Depth,
- Payload = end,
- };
- }
- }
-
- _blocks.RemoveAt(_blocks.Count - 1);
- }
-
- public int AddInstruction(Instruction instruction)
- {
- _instructions.Add(instruction);
- return _instructions.Count - 1;
- }
-
- public int AddEndpoint(MatcherEndpoint endpoint)
- {
- _endpoints.Add(endpoint);
- return _endpoints.Count - 1;
- }
-
- public int AddJumpTable(JumpTableBuilder table)
- {
- _tables.Add(table);
- return _tables.Count - 1;
- }
-
- public void Deconstruct(
- out Instruction[] instructions,
- out MatcherEndpoint[] endpoints,
- out JumpTable[] tables)
- {
- instructions = _instructions.ToArray();
- endpoints = _endpoints.ToArray();
-
- tables = new JumpTable[_tables.Count];
- for (var i = 0; i < _tables.Count; i++)
- {
- tables[i] = _tables[i].Build();
- }
- }
- }
-
- private abstract class Node
- {
- public int Depth { get; protected set; }
- public List Children { get; } = new List();
-
- public abstract void Lower(InstructionBuilder builder);
-
- public TNode GetNode() where TNode : Node
- {
- for (var i = 0; i < Children.Count; i++)
- {
- if (Children[i] is TNode match)
- {
- return match;
- }
- }
-
- return null;
- }
-
- public TNode AddNode(TNode node) where TNode : Node
- {
- // We already ordered the routes into precedence order
- Children.Add(node);
- return node;
- }
- }
-
- private class SequenceNode : Node
- {
- public SequenceNode(int depth)
- {
- Depth = depth;
- }
-
- public override void Lower(InstructionBuilder builder)
- {
- for (var i = 0; i < Children.Count; i++)
- {
- Children[i].Lower(builder);
- }
- }
- }
-
- private class OrderNode : SequenceNode
- {
- public OrderNode(int order)
- : base(0)
- {
- Order = order;
- }
-
- public int Order { get; }
- }
-
- private class BranchNode : Node
- {
- public BranchNode(int depth)
- {
- Depth = depth;
- }
-
- public List Literals { get; } = new List();
-
- public override void Lower(InstructionBuilder builder)
- {
- var table = new JumpTableBuilder() { Depth = Depth, };
- var index = builder.AddJumpTable(table);
- builder.AddInstruction(new Instruction()
- {
- Code = InstructionCode.Branch,
- Depth = (byte)Depth,
- Payload = index
- });
-
- builder.BeginBlock();
-
- for (var i = 0; i < Children.Count; i++)
- {
- table.AddEntry(Literals[i], builder.Next);
- Children[i].Lower(builder);
- builder.AddInstruction(new Instruction()
- {
- Code = InstructionCode.Pop,
- Depth = (byte)Depth,
- });
- }
-
- builder.EndBlock();
- table.Exit = builder.Next;
- }
- }
-
- private class ParameterNode : Node
- {
- public ParameterNode(int depth)
- {
- Depth = depth;
- }
-
- public override void Lower(InstructionBuilder builder)
- {
- for (var i = 0; i < Children.Count; i++)
- {
- Children[i].Lower(builder);
- }
- }
- }
-
- private class AcceptNode : Node
- {
- public AcceptNode(int depth, MatcherEndpoint endpoint)
- {
- Depth = depth;
- Endpoint = endpoint;
- }
-
- public MatcherEndpoint Endpoint { get; }
-
- public override void Lower(InstructionBuilder builder)
- {
- builder.AddInstruction(new Instruction()
- {
- Code = InstructionCode.Accept,
- Depth = (byte)Depth,
- Payload = builder.AddEndpoint(Endpoint),
- });
- }
- }
- }
-}
diff --git a/test/Microsoft.AspNetCore.Routing.Tests/Matchers/InstructionMatcherConformanceTest.cs b/test/Microsoft.AspNetCore.Routing.Tests/Matchers/InstructionMatcherConformanceTest.cs
deleted file mode 100644
index 65a902ff58..0000000000
--- a/test/Microsoft.AspNetCore.Routing.Tests/Matchers/InstructionMatcherConformanceTest.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-namespace Microsoft.AspNetCore.Routing.Matchers
-{
- public class InstructionMatcherConformanceTest : MatcherConformanceTest
- {
- internal override Matcher CreateMatcher(params MatcherEndpoint[] endpoints)
- {
- var builder = new InstructionMatcherBuilder();
- for (int i = 0; i < endpoints.Length; i++)
- {
- builder.AddEndpoint(endpoints[i]);
- }
- return builder.Build();
- }
- }
-}