A closer look at CompilerServices.Unsafe as the modern alternative to the fixed statement: doing reference arithmetic on GC-managed memory without pinning, what "unsafe" really means, and what the CLR does and doesn't promise you.
int[,] looks like the natural choice and performs like the wrong one. Digging into IL and JIT output to show what actually happens when you access single-dimensional, multidimensional and jagged arrays — and why the rectangular one loses.
Every array access in .NET pays for a bounds check — unless you convince the compiler it can skip it. I read the JIT'ed x64 assembly and benchmark tricks that make plain array access 18-34% faster.
Interface, base class, virtual, override, dynamic, reflection or expression trees — .NET gives you many ways to call a method, and their costs differ wildly. Full benchmark with numbers for each.
sizeof() compiles to a constant; Marshal.SizeOf() measures the marshaled struct at runtime. What each one really returns, what it costs, and when to use which — with IL to prove it.
What does a method that just calls another method actually cost? Using the == operator vs IEquatable.Equals as the guinea pig, I benchmark wrapper calls across compilers, JITs and runtimes — and read the disassembly to see why.
Mono.Cecil kept producing broken assemblies with branches jumping out of the method — until Jb Evain explained the magic: call Body.Simplify() before modifying and Body.Optimize() after. Not a bug after all.
A deep dive into user space threading for .NET: why OpenSim needs to pause, serialize and resume thousands of running scripts, and the whole arsenal — from Mono.Cecil IL rewriting to fibers — I have thrown at the problem.
The full event pipeline works end to end: pressing a button in the test app sends an event through the ScriptEngine, into the queue, and out to the correct compiled script. Screenshot included.
The plan for the first simple version of script support: a simplified event queue with a custom threadpool, one shared AppDomain, and a basic LSL compiler that others can extend while I keep working on the core.
Builtin commands are easy — incoming events need planning. An EventHandler translates OpenSim happenings into LSL-compatible events, and an Event Queue Manager executes them on a separate thread so the server never blocks.
The architecture for OpenSim script support: a dynamically loaded ScriptEngine assembly that hooks the server's events, a compiler that turns LSL into .NET assemblies, and the loading pipeline between them.
LSL bytecode is full of pointers — static frames, heap, jump targets — all referring to positions inside a 16k LSO file. Here is my plan for mapping them onto dictionaries and two-pass MSIL label generation.
Direct translation from the LSO stack to the .NET stack falls apart: LSO doesn't always tell you the datatype, and .NET wants its stack served in a very particular order. The fix: my own stack in a base class the compiled scripts inherit from.
The converter can now take LSL bytecode all the way to a compiled .NET .dll on disk, with events visible in Visual Studio and llSay mapped to Console.WriteLine. Messy code, but the goal is simply "Version 1: Functional".
Found the "final bug" in the LSL bytecode parser and compiled my first small function to a working .dll. One opcode and one builtin command supported — it's a start, and it works!
The plan for OpenSim script support: read compiled LSL bytecode, convert it to .NET bytecode and let the JIT produce native code, with AppDomains providing the sandbox. Blazing fast execution inside the .NET VM.