|
1 | 1 | # IronRust |
2 | 2 |
|
3 | | -IronRust is the RustScript runtime and compiler for Microsoft CLR. The repository includes the CLR runtime, bytecode-to-CLR compiler, runner CLI, tests, examples, and a minimal Edge HTTP runtime. |
| 3 | +IronRust provides a RustScript runtime and compiler for Microsoft CLR. |
4 | 4 |
|
5 | | -## Projects |
6 | | - |
7 | | -- `PdVm.Runtime` |
8 | | - - CLR-side VM value model, builtin implementations, host dispatch, and program execution helpers. |
9 | | -- `PdVm.Compiler` |
10 | | - - Reads `VMBC` bytecode and emits CLR assemblies (`.dll`) that implement `IPdVmProgram`. |
11 | | -- `PdVm.Runner` |
12 | | - - Small CLI for compile/run/compile-run flows. |
13 | | -- `PdEdge.Http` |
14 | | - - Minimal HTTP/1 proxy runtime for PD Edge scripts on CLR. |
15 | | - - Project name is `PdEdge.Http`, but the built executable name is `pd-edge-http-minimal-clr` so the existing Rust perf harness can target it directly. |
16 | | -- `PdVm.Tests` |
17 | | - - Compiler/runtime tests. |
18 | | -- `PdEdge.Http.Tests` |
19 | | - - HTTP proxy parity tests. |
20 | | - |
21 | | -## Requirements |
22 | | - |
23 | | -- .NET 10 SDK |
24 | | -- Rust toolchain only if you want to run the Rust HTTP perf harness |
25 | | - |
26 | | -`PdEdge.Http --program-source ...` compiles RustScript in-process through `PdVm.Compiler`. It does not launch Cargo or require the `pd-edge` Rust workspace at runtime. |
27 | | - |
28 | | -## Build |
29 | | - |
30 | | -From the repo root: |
| 5 | +## Quick start |
31 | 6 |
|
32 | 7 | ```powershell |
33 | 8 | dotnet build IronRust.sln |
34 | 9 | ``` |
35 | 10 |
|
36 | | -Release build for the proxy runtime: |
37 | | - |
38 | | -```powershell |
39 | | -dotnet build PdEdge.Http\PdEdge.Http.csproj -c Release |
40 | | -``` |
41 | | - |
42 | | -## Test |
43 | | - |
44 | | -Build first, then run tests without rebuilding: |
45 | | - |
46 | | -```powershell |
47 | | -dotnet test IronRust.sln --no-build |
48 | | -``` |
49 | | - |
50 | | -Or run just the HTTP runtime tests: |
51 | | - |
52 | | -```powershell |
53 | | -dotnet test PdEdge.Http.Tests\PdEdge.Http.Tests.csproj --no-build |
54 | | -``` |
55 | | - |
56 | | -## Compile Source To VMBC |
57 | | - |
58 | | -`PdVm.Runner` calls the bundled native compiler library in-process. A separate `pd-vm-run` executable is not required: |
59 | | - |
60 | | -```powershell |
61 | | -PdVm.Runner.exe emit-vmbc ` |
62 | | - path\to\program.rss ` |
63 | | - path\to\program.vmbc |
64 | | -``` |
65 | | - |
66 | | -Managed callers can use `PdVmNativeCompiler.CompileFile` or `CompileFileToVmbc` from `PdVm.Compiler.dll`. The packaged native library is named `Pdvm.Compiler.Native.dll` on Windows, `libPdvm.Compiler.Native.dylib` on macOS, and `libPdvm.Compiler.Native.so` on Linux. The native ABI returns VMBC bytes or a UTF-8 diagnostic and releases result buffers through the matching Rust export. |
67 | | - |
68 | | -The same compiler path can produce VMBC for a PD Edge HTTP proxy script: |
69 | | - |
70 | | -```powershell |
71 | | -PdVm.Runner.exe emit-vmbc ` |
72 | | - path\to\program.rss ` |
73 | | - path\to\program.vmbc |
74 | | -``` |
75 | | - |
76 | | -`PdEdge.Http` validates the compiled host imports against its supported Edge ABI before accepting the program. |
77 | | - |
78 | | -Example source files are in `examples/`: |
79 | | - |
80 | | -- `pdedge-http-local-ok.rss` |
81 | | -- `pdedge-http-proxy-http1.rss` |
82 | | -- `pdedge-http-proxy-http1-body-read.rss` |
83 | | - |
84 | | -## Compile VMBC To CLR |
85 | | - |
86 | | -Compile RustScript source with generated typed .NET modules and the unmodified upstream compiler: |
87 | | - |
88 | | -```powershell |
89 | | -dotnet run --project PdVm.Runner -- compile-source ` |
90 | | - examples\dotnet-typed-console.rss ` |
91 | | - artifacts\dotnet-typed-console.dll |
92 | | -dotnet run --project PdVm.Runner -- run artifacts\dotnet-typed-console.dll |
93 | | -``` |
94 | | - |
95 | | -`run` also accepts an `.rss` source file and compiles it to a temporary CLR assembly before execution: |
96 | | - |
97 | | -```powershell |
98 | | -dotnet run --project PdVm.Runner -- run examples\dotnet-typed-console.rss |
99 | | -dotnet run --project PdVm.Runner -- run examples\dotnet-typed-winforms.rss --profile winforms |
100 | | -``` |
101 | | - |
102 | | -`dotnet-typed-winforms.rss` is a Notepad-style Windows application written in RustScript. It creates the form, menus, editor, dialogs, file actions, font and color actions, word-wrap action, and status bar in `.rss`. The typed Windows Forms profile supplies CLR bindings, a dedicated STA dispatcher, and a thin event queue; it does not contain application behavior. |
103 | | - |
104 | | -The `winforms` profile includes the common profile and the initial Windows Forms surface: |
105 | | - |
106 | | -```powershell |
107 | | -dotnet run --project PdVm.Runner -- compile-source ` |
108 | | - examples\dotnet-typed-winforms.rss ` |
109 | | - artifacts\dotnet-typed-winforms.dll ` |
110 | | - --profile winforms |
111 | | -dotnet run --project PdVm.Runner -- run artifacts\dotnet-typed-winforms.dll |
112 | | -``` |
113 | | - |
114 | | -`--pd-vm-library <path>` selects an explicit native compiler library; `--source-root <path>` sets the module-tree root. By default the native library is loaded beside the Runner. Typed imports carry exact CLR assembly, module, type, member, parameter, and return identities. Name-based dynamic reflection remains behind `--enable-dynamic-dotnet`. |
115 | | - |
116 | | -Typed CLR imports use the C#-style `System` root. The source wrapper scans each reachable `use System::...` declaration, finds the concrete CLR type in the .NET runtime or a referenced DLL, and generates an exact typed module for its supported public members: |
117 | | - |
118 | | -```rust |
119 | | -use System::Security::Cryptography::SHA256; |
120 | | - |
121 | | -let algorithm = SHA256::Create(); |
122 | | -SHA256::Release(algorithm); |
123 | | -``` |
124 | | - |
125 | | -For a third-party CLR assembly, place its DLL beside the source, under the source tree, beside the Runner, or in the current working directory. The wrapper finds it from the imported CLR type name, copies the selected DLL beside the generated program, and registers that output directory for runtime resolution: |
126 | | - |
127 | | -```powershell |
128 | | -dotnet run --project PdVm.Runner -- compile-source crypto.rss crypto.dll |
129 | | -``` |
130 | | - |
131 | | -## Release packages |
132 | | - |
133 | | -The Release workflow builds `win-x64`, `osx-arm64`, and `linux-x64` packages. Each archive contains the framework-dependent `PdVm.Runner` executable, managed DLLs and portable PDBs, runtime configuration, and the platform native compiler library. The Windows archive also contains the native PDB. |
134 | | - |
135 | | -Build a package locally with: |
136 | | - |
137 | | -```powershell |
138 | | -.\scripts\package-release.ps1 ` |
139 | | - -RuntimeIdentifier win-x64 ` |
140 | | - -RustTarget x86_64-pc-windows-msvc |
141 | | -``` |
142 | | - |
143 | | -Compile a `VMBC` file to a CLR assembly: |
144 | | - |
145 | | -```powershell |
146 | | -dotnet run --project PdVm.Runner -- compile input.vmbc output.dll |
147 | | -``` |
148 | | - |
149 | | -Compilation writes `PdVm.Runtime.dll` beside the generated program assembly. The generated assembly references the runtime ABI but has no dependency on `PdVm.Compiler` or the original VMBC payload. |
150 | | - |
151 | | -Run a compiled CLR assembly: |
152 | | - |
153 | | -```powershell |
154 | | -dotnet run --project PdVm.Runner -- run output.dll |
155 | | -``` |
156 | | - |
157 | | -Compile and run in one step: |
158 | | - |
159 | | -```powershell |
160 | | -dotnet run --project PdVm.Runner -- compile-run input.vmbc output.dll |
161 | | -``` |
162 | | - |
163 | | -Optional execution cap: |
164 | | - |
165 | | -```powershell |
166 | | -dotnet run --project PdVm.Runner -- run output.dll --max-steps 1000000 |
167 | | -``` |
168 | | - |
169 | | -`--max-steps` is enforced by budget checks in the generated CLR method. Backward branches remain native CLR branches and do not return to the C# execution driver. |
170 | | - |
171 | | -Experimental dynamic .NET reflection is available only when explicitly enabled: |
172 | | - |
173 | | -```powershell |
174 | | -dotnet run --project PdVm.Runner -- run output.dll --enable-dynamic-dotnet |
175 | | -``` |
176 | | - |
177 | | -This mode is intended for interop development and the WinForms smoke example. It is not the typed wrapper described in `docs/dotnet-interop-wrapper-plan.md` and must not be used for untrusted programs. |
178 | | - |
179 | | -## Run The Minimal HTTP Proxy |
180 | | - |
181 | | -Run with a precompiled `VMBC` program: |
182 | | - |
183 | | -```powershell |
184 | | -dotnet run --project PdEdge.Http -- ` |
185 | | - --program-vmbc path\to\program.vmbc ` |
186 | | - --data-addr 127.0.0.1:8080 |
187 | | -``` |
188 | | - |
189 | | -Run with a source program: |
190 | | - |
191 | | -```powershell |
192 | | -dotnet run --project PdEdge.Http -- ` |
193 | | - --program-source path\to\program.rss ` |
194 | | - --data-addr 127.0.0.1:8080 |
195 | | -``` |
196 | | - |
197 | | -Useful flags: |
198 | | - |
199 | | -- `--proxy-addr <ADDR>` |
200 | | - - Alias for `--data-addr`. |
201 | | -- `--vm-execution-mode async|threading` |
202 | | - - Request-time VM execution strategy. |
203 | | -- `--max-steps <N>` |
204 | | - - Per-request instruction cap. Default is `10000000`. |
205 | | -- `--disable-logging` |
206 | | - - Suppresses console log output. |
207 | | - |
208 | | -Compatibility flags accepted for parity with `pd-edge-http-minimal`: |
209 | | - |
210 | | -- `--vm-fuel` |
211 | | -- `--vm-fuel-check-interval` |
212 | | -- `--vm-jit` |
213 | | - |
214 | | -These are currently parsed but treated as no-ops in the CLR runtime. |
215 | | - |
216 | | -## PdEdge.Http Scope |
217 | | - |
218 | | -`PdEdge.Http` is intentionally minimal: |
219 | | - |
220 | | -- HTTP/1.1 only |
221 | | -- No admin API |
222 | | -- No metrics |
223 | | -- No debugger |
224 | | -- No control plane |
225 | | -- No TLS |
226 | | -- No HTTP/2 |
227 | | -- No HTTP/3 |
228 | | - |
229 | | -It supports the minimal host surface needed for the standalone proxy flow: |
230 | | - |
231 | | -- request getters such as `http::request::get_method`, `get_path`, `get_header`, `get_body` |
232 | | -- response setters such as `http::response::set_status`, `set_header`, `set_headers`, `set_body` |
233 | | -- default upstream preparation via `http::exchange::prepare_default_upstream` |
234 | | -- native forwarding via `proxy::stream::*` and `proxy::forward_native` |
235 | | - |
236 | | -## Benchmark With The Existing Rust Harness |
237 | | - |
238 | | -Build the proxy in Release first: |
239 | | - |
240 | | -```powershell |
241 | | -dotnet build PdEdge.Http\PdEdge.Http.csproj -c Release |
242 | | -``` |
243 | | - |
244 | | -Then run the Rust benchmark harness against the built executable: |
245 | | - |
246 | | -```powershell |
247 | | -cargo run -p pd-edge --example http_proxy_perf_framework -- ` |
248 | | - --binary d:\Workspace\project-d\PdEdge.Http\bin\Release\net10.0\pd-edge-http-minimal-clr.exe ` |
249 | | - --skip-build ` |
250 | | - --scenario http_proxy ` |
251 | | - --requests 2000 ` |
252 | | - --warmup-requests 200 ` |
253 | | - --concurrency 32 |
254 | | -``` |
255 | | - |
256 | | -Body-read scenario: |
257 | | - |
258 | | -```powershell |
259 | | -cargo run -p pd-edge --example http_proxy_perf_framework -- ` |
260 | | - --binary d:\Workspace\project-d\PdEdge.Http\bin\Release\net10.0\pd-edge-http-minimal-clr.exe ` |
261 | | - --skip-build ` |
262 | | - --scenario http_proxy_body_read ` |
263 | | - --requests 2000 ` |
264 | | - --warmup-requests 200 ` |
265 | | - --concurrency 32 |
266 | | -``` |
267 | | - |
268 | | -## Current Status |
| 11 | +## Documentation |
269 | 12 |
|
270 | | -- VMBC is decoded only during compilation. Generated assemblies contain CLR control flow, CLR evaluation locals, generated local fields, and direct intrinsic calls; they do not contain a VMBC instruction stream. |
271 | | -- Typed arithmetic and comparison hints lower to native CLR opcodes. Dynamic values use focused operations from `PdVm.Runtime` rather than an instruction interpreter. |
272 | | -- The operand stack is materialized into runtime state only at halt, host-call, async-resume, and instruction-budget boundaries. |
273 | | -- `PdEdge.Http` local-response and native-forward proxy paths are covered by tests. |
274 | | -- The Rust HTTP perf harness can drive the CLR proxy binary directly. |
| 13 | +- [IronRust reference](https://rustscript.org/docs/reference/ironrust/) |
| 14 | +- [Runtime guides](https://rustscript.org/docs/learn/runtimes/#ironrust) |
| 15 | +- [Runtime implementation guide](https://rustscript.org/docs/contribute/runtimes/#ironrust) |
0 commit comments