Jint is a JavaScript interpreter for .NET. It parses JavaScript using the Acornima library (AST), then interprets it directly — no bytecode generation or DLR usage.
# Build
dotnet build -c Release
# Run all tests
dotnet test -c Release
# Run a specific test project
dotnet test Jint.Tests\Jint.Tests.csproj -c Release
# Run a single test by name
dotnet test Jint.Tests\Jint.Tests.csproj -c Release --filter "FullyQualifiedName~Jint.Tests.Runtime.EngineTests.CanAccessCLR"Tests use xunit. The solution has TreatWarningsAsErrors enabled.
Benchmarks use BenchmarkDotNet and live in Jint.Benchmark/.
# List available benchmarks
dotnet run -c Release --project Jint.Benchmark\Jint.Benchmark.csproj -- --list flat
# Run a specific benchmark class (preferred — fast iteration)
dotnet run -c Release --project Jint.Benchmark\Jint.Benchmark.csproj -- --filter "Jint.Benchmark.EngineConstructionBenchmark"
# Run a specific method
dotnet run -c Release --project Jint.Benchmark\Jint.Benchmark.csproj -- --filter "*EngineConstructionBenchmark.BuildEngine"
# Wildcard match
dotnet run -c Release --project Jint.Benchmark\Jint.Benchmark.csproj -- --filter "*Array*"
# Run all benchmarks (slow — avoid unless needed)
dotnet run -c Release --project Jint.Benchmark\Jint.Benchmark.csproj- Create a new class in
Jint.Benchmark/with[MemoryDiagnoser]. - For JS script file benchmarks, extend
SingleScriptBenchmarkand overrideFileNameto point at a file inScripts/. The base class handles loading, parsing (Engine.PrepareScript), and providesExecute/Execute_ParsedScriptbenchmark methods. - For standalone benchmarks, add
[Benchmark]methods directly. UseEngine.PrepareScript()to pre-parse scripts when benchmarking execution separately from parsing. - Place any required JS script files in
Jint.Benchmark/Scripts/— they are copied to the output directory automatically. - Always run with
-c Release; Debug builds are not representative.
For fast feedback during development, use --job short to reduce warmup and iteration counts:
dotnet run -c Release --project Jint.Benchmark\Jint.Benchmark.csproj -- --filter "*EngineConstructionBenchmark*" --job short- Parsing — Acornima parses JavaScript source into an AST (
Acornima.Astnodes) - Jint Wrapping — AST nodes are wrapped in
Jint*interpreter classes:JintExpressionsubclasses inRuntime/Interpreter/Expressions/(e.g.,JintCallExpression,JintBinaryExpression)JintStatementsubclasses inRuntime/Interpreter/Statements/(e.g.,JintIfStatement,JintForStatement)
- Execution —
Enginedrives execution. Statements returnCompletion(a value + completion type: Normal/Break/Continue/Return/Throw). Expressions returnJsValueorReference.
Engine— Central entry point. Holds global environment, built-in constructors, execution context stack, constraints, and object pools. Configured viaOptions.JsValue— Abstract base for all JavaScript values. Concrete types:JsString,JsNumber,JsBoolean,JsNull,JsUndefined,JsSymbol,ObjectInstance.ObjectInstance— Base for all JS objects. Properties stored inPropertyDictionary, symbols inSymbolDictionary. Subclassed for Array, Function, Date, RegExp, Map, Set, Promise, Proxy, etc.Completion— Readonly struct representing statement execution results per the ECMAScript spec (§8.9).Key— Internal struct with pre-calculated hash code for fast dictionary lookups.
Jint.Native— JS value types and built-in objects. Each built-in has a subdirectory with*Constructor,*Prototype,*Instanceclasses (e.g.,Native/Array/ArrayConstructor.cs,ArrayPrototype.cs,ArrayInstance.cs).Jint.Runtime— Execution runtime: environments, descriptors, references, type conversion, call stack, interop, interpreter.Jint.Runtime.Interpreter— The statement/expression interpreter classes that wrap Acornima AST nodes.Jint.Runtime.Interop— .NET/CLR interop layer:ObjectWrapper,TypeReference,ClrFunctionInstance,DelegateWrapper.Jint.Runtime.Environments— Lexical environments and environment records (Declarative, Function, Global, Object).Jint.Collections— Custom high-performance dictionary implementations (PropertyDictionary,StringDictionarySlim,DictionarySlim).Jint.Pooling— Object pools for frequently allocated types (ReferencePool,ArgumentsInstancePool,JsValueArrayPool).
Jint.Tests— Main unit tests. Test classes mirror runtime types (e.g.,EngineTests,InteropTests,ArrayTests). JS test scripts are embedded resources inRuntime/Scripts/andParser/Scripts/.Jint.Tests.Test262— ECMAScript Test262 conformance suite.Jint.Tests.Ecma— Legacy ECMA test cases.Jint.Tests.CommonScripts— SunSpider benchmark scripts used for testing.
Performance is a first-class concern in this codebase. Every change must consider its performance impact:
- Use
[MethodImpl(MethodImplOptions.AggressiveInlining)]on hot paths. - Prefer
readonly structtypes to avoid heap allocations. - Prefer
readonly record structand primary constructors for small data types — combines immutability, value semantics, and concise syntax. - Use
Span<T>,ReadOnlySpan<T>, and stack-based allocation wherever possible. - Use modern .NET language features (pattern matching, ranges, nullable reference types, etc.).
- Leverage object pooling (
Jint.Pooling) for frequently allocated types instead of creating new instances. - Mark types as
sealedwhenever possible — it enables devirtualization and inlining by the JIT. - Use
internalvisibility where possible — it avoids virtual dispatch and enables inlining. Public API surface is limited toEngine,Options,JsValue, and interop types.
- Lazy initialization —
JintStatementsubclasses set_initialized = falsein constructors and overrideInitialize()for deferred setup on first execution. - Error throwing uses the static
ExceptionHelperclass (avoids allocations in non-error paths via[DoesNotReturn]). UseThrow.*methods instead ofthrow new. - Built-in JS types follow the Constructor/Prototype/Instance pattern matching the ECMAScript spec structure.
- Engine carries all state —
ObjectInstanceand most runtime types receiveEnginein constructors. Interpreter classes receive state viaEvaluationContext. - Pre-parsed scripts — Use
Engine.PrepareScript()/Engine.PrepareModule()to parse once and execute many times viaPrepared<Script>/Prepared<Module>. - PR target branch is
main.