What to say to judges, from the 20-second hook to the hard technical questions. Read it out loud a few times. The bold parts are the ones to memorize word for word.
Every time you open a website, your browser runs code written by strangers. A lot of it runs on WebAssembly, and there is one official rulebook for how it must behave.
My project, Lockstep, reads that rulebook and automatically builds a fast engine that follows it exactly.
WebAssembly is what lets apps like Figma, Photoshop on the web and games run inside your browser. It’s built into every major browser.
It has an official rulebook that says exactly what every instruction does. Every browser has to follow it exactly, because a mistake can become a security hole.
Think of a board game. The official referee reads the rulebook for every single move. It’s always right, but it’s so slow that one big engine team stopped using the official reference for testing.
Browsers use engines that people wrote by hand. They’re fast, but they’re written separately from the rules, so they can get things wrong.
I built a translator that reads the rulebook and writes the fast engine automatically. I called it Lockstep, because the engine moves in step with the rules: it comes straight from them.
It passes all 55,861 official tests, exactly like the rulebook, and it’s about 45 times faster than running the rulebook directly.
So the rules everyone trusts can now also be fast enough to use.
If they look lost at any point, go back to the board game: referee, hand-made copy, and my machine that builds the fast version from the rulebook.
Same program, same rules, two engines. The top one reads the rulebook step by step. The bottom one is my engine, built from the same rulebook.
(When it finishes.) Same answer, about 20 times faster. And the rulebook’s interpreter needed around 30 seconds just to load before it could even start.
These are the official tests, written by the people who make WebAssembly. 259 files. Watch the counter.
(When it reaches 55,861.) 55,861 out of 55,861, in about 8 seconds, on this laptop. The rulebook’s own interpreter gets exactly the same result on every file.
On the left is the rule exactly as the official specification writes it. On the right is the code my compiler generated from it. I didn’t write the right side. That’s why it can’t drift away from the rules.
Fibonacci numbers are a famous sequence where each number is the sum of the two before it: 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55… So fib(10) = 55, and fib(18) = 2,584.
The race computes it the slow, recursive way on purpose. To get fib(18), the program asks for fib(17) and fib(16); each of those asks for two more, and so on, all the way down to fib(1) and fib(0). That adds up to 8,361 function calls for fib(18), and the count grows about 1.6 times with every step up.
That’s why it’s a good test: the answer is easy to check, and the amount of work is big and adjustable, so you can see how fast each engine really is.
(func $fib (export "fib") (param $n i32) (result i32)
(if (result i32) (i32.lt_s (local.get $n) (i32.const 2))
(then (local.get $n))
(else (i32.add (call $fib (i32.sub (local.get $n) (i32.const 1)))
(call $fib (i32.sub (local.get $n) (i32.const 2)))))))
If n is less than 2, the answer is n itself: fib(0) = 0 and fib(1) = 1.
Otherwise, call fib(n − 1) and fib(n − 2), and add the two answers.
fib(n) makes exactly 2 · fib(n + 1) − 1 calls, so the work grows like φⁿ, where φ ≈ 1.618 is the golden ratio.
Each call runs about a dozen instructions (local.get, i32.const, i32.lt_s, if, i32.sub, call, i32.add), so it stresses the core of an engine: function calls, branches, local variables and integer math.
The comparison is fair: both engines run the same .wast file and report the CPU time of the test only, without the 30-second spec load. Small n is dominated by fixed setup, which is why fib(18) to fib(20) shows the gap best (about 20×). My paper goes further and uses the slope method across sizes, which removes setup completely.
Context. Since 2025 the WebAssembly specification is written in SpecTec, a domain-specific language. SpecTec turns the rules into 474 step-by-step algorithms in its algorithmic language, AL, and it has a meta-interpreter that runs them. That’s the ground truth, but it takes about 30 seconds to load and then runs 27 to 336 times slower than the hand-written OCaml reference interpreter.
Question. Can the specification be compiled mechanically into an engine that agrees with it and is much faster?
Feasibility first. I started with a one-week kill test. I hand-translated the 16 algorithms behind about 15 instructions. Zero needed logic outside the AL, and the result was about 1,000 times faster per loop iteration. So I went ahead.
The compiler. I wrote a new SpecTec backend, spectec --rust, about 700 lines of OCaml. It compiles every AL algorithm into a Rust function, statement by statement, keeping the meta-interpreter’s semantics. Decisions the interpreter makes at run time, like which function a call refers to or how a pattern matches, are made once, at compile time. The subtle part is the tail rule: when an Execute isn’t the last statement, everything it starts has to finish before the next statement, so the compiler inserts a run-to-depth there, and leaves tail positions to the main loop so loops don’t grow the Rust stack.
The runtime. About 4,900 hand-written lines: values, unbounded integers, the context machine, the numeric built-ins ported from SpecTec, and the test runner. It contains no instruction rules. Tests come in through SpecTec’s own parser and validator, dumped as AL values.
Correctness. The criterion is identical results to the meta-interpreter on every file of the official core test suite: 55,861 of 55,861 commands. Like SpecTec’s own runner, it skips 12 long-running files.
Measuring speed. CPU time, the slope method so setup costs cancel out, medians over interleaved and shuffled runs, and geometric means. Because the server was shared, I also used exact allocation counts from a counting allocator, which don’t depend on load.
Results. The first generated engine was 28 times faster than the meta-interpreter on 8 benchmark programs, and 6.8 times faster on the whole suite.
Optimizations. Then seven meaning-preserving rewrites, each re-verified on the full suite: slice arguments, direct numeric dispatch, shared instruction sequences, single-allocation constructors, reusing pure call results through a purity analysis, tag-based type tests, and compact byte memory. Together: 1.69 times faster, 47 to 83 percent fewer allocations, and one test’s memory went from 2.84 GB to 35 MB. Now it’s about 45 times faster than the meta-interpreter and 3.5 times slower than the hand-written interpreter.
Limits and next steps. The timings are preliminary, from a busy server, on small benchmarks. Next: native machine integers, a separate control stack, re-measuring on a quiet machine, and measuring how many engine lines change when a new feature is added to the spec. That should be zero.
A universal, safe instruction language that every browser understands, so programs written in C, C++, Rust and others can run in a web page at near-native speed.
A program that translates code from one language into another. Mine translates the WebAssembly rulebook into Rust code.
Browser and server engines are tested by running huge numbers of random programs and comparing them with a trusted reference. That reference needs to be correct and fast. Wasmtime’s developers abandoned the official OCaml reference interpreter for this because it was too slow (PLDI 2023). Lockstep is a step toward a reference that’s both exact and fast.
Also: new features become runnable as soon as they’re written in the spec, and compilers that output WebAssembly can be checked against the real rules.
It’s written by hand, separately from the spec, so it can disagree with it, and every new feature has to be implemented in it by hand. Mine is generated from the spec itself. Also, in September 2025 a single change made it up to 20 times slower on some programs.
The official test suite: 55,861 commands, identical to the spec’s own interpreter, file by file, and re-checked after every single change I made.
Yes. A bug that my engine shares with the meta-interpreter wouldn’t show up, because both follow the same AL. I list that as a limitation. Tests plus a safety argument for each rewrite is strong evidence, not a proof.
It follows the spec’s abstract machine literally: generic values for everything, contexts for every block, labels exited one at a time. Removing that cost without changing the meaning is the research part, and each rewrite closes some of the gap.
It’s as fast as C but memory-safe, its compiler optimizes the generated code well, and its reference-counted values match how the spec shares values.
Two things. The tail rule, deciding when a step must fully finish before the next one. And proving each speed-up safe: for example, sharing instruction lists is only safe because the spec never edits an instruction list in place, so I checked every in-place update in the generated code.
A function is pure if it reads no machine state, changes nothing in place, and only calls other pure functions. Purity depends on the functions it calls, so I repeat the check until nothing changes, which is called a fixpoint. Then, if a pure function is called twice with arguments that can’t have changed, the second call reuses the first result. That’s how the arithmetic instruction stopped doing its math twice.
I run each program at several sizes and fit a straight line through time against amount of work. The slope is the cost per unit of work, and the fixed setup cost, like loading the spec, drops out.
The server was shared with other jobs, so timings were noisy. Allocation counts are exact and identical on every run, so they show the effect of each change clearly.
Already existed: SpecTec, the WebAssembly specification and the official tests. New in my project: the Rust backend for SpecTec, the test dumper, the runtime, the measurement tools, the seven optimizations and all the experiments.
Yes. I used AI coding assistants, Claude Code and Gemini (for porting the numeric functions), and my logbook records how. I set the research question, designed the experiments, made the decisions and verified everything against the official tests, and I can explain every part.
SpecTec’s own test runner skips them because they’re too slow for it. I kept exactly the same rules so the comparison is fair. Running them is one of my next steps, since my engine is now fast enough to try.
Not yet. It’s a research prototype. A next step is to offer the backend to the SpecTec maintainers.
Native machine integers, a separate control stack, faster branches, bigger real-world benchmarks, re-measuring on a quiet machine, and the feature experiment: add a new feature to the spec, regenerate, and count how many engine lines changed.
| 55,861 | official test commands passed, all of them, identical per file to the spec’s interpreter |
| 259 | files in the official core test suite (12 long ones skipped, like SpecTec does) |
| 474 | algorithms in the spec, all compiled |
| 22,000 | lines of Rust generated |
| 700 | lines of OCaml in the compiler (the new SpecTec backend) |
| 4,900 | lines of hand-written runtime, with no instruction rules |
| ~45× | faster than running the spec directly (was 28× before optimizing) |
| 6.8× | faster on the whole test suite |
| 3.5× | still slower than the hand-written reference interpreter (was 5.6×) |
| 1.69× | gained from 7 meaning-preserving rewrites |
| 47–83% | fewer memory allocations |
| 2.84 GB → 35 MB | memory on one test, after compact memory |
| ~1,000× | kill-test speedup of the small hand translation |
| 30 s | time the spec’s interpreter needs just to load |
| 8 s | for the whole test suite on the laptop |
لما بتفتح Figma أو لعبة في المتصفح، اللي بيشغّلها تكنولوجيا اسمها WebAssembly، وليها كتاب قواعد رسمي، وكل متصفح لازم يمشي عليه بالظبط، لأن أي غلطة ممكن تبقى ثغرة أمنية.
الحَكَم الرسمي اللي بيقرا القواعد خطوة بخطوة دايمًا صح، بس بطيء جدًا، لدرجة إن فريق كبير بطّل يستخدمه في الاختبار.
أنا عملت برنامج بيقرا كتاب القواعد ده ويحوّله تلقائيًا لمحرّك سريع، اسمه لوك ستب، لأنه ماشي خطوة بخطوة مع القواعد. نجح في كل الـ55,861 اختبار الرسميين، وأسرع حوالي 45 مرة من تشغيل القواعد مباشرة.
اللي هتقوله للجنة التحكيم، من أول 20 ثانية لحد أصعب الأسئلة التقنية. اقراه بصوت عالي كذا مرة. الأجزاء الغامقة هي اللي تحفظها كلمة بكلمة.
كل مرة تفتح فيها موقع، المتصفح بتاعك بيشغّل كود كتبه ناس غريبة عنك. جزء كبير منه بيشتغل على WebAssembly، وفيه كتاب قوانين رسمي واحد بيحدد هو لازم يشتغل إزاي.
مشروعي، Lockstep، بيقرا كتاب القوانين ده ويبني أوتوماتيك محرّك سريع بيمشي عليه بالحرف.
WebAssembly هو اللي بيخلّي تطبيقات زي Figma وPhotoshop على الويب والألعاب تشتغل جوه المتصفح بتاعك. وهو موجود جوه كل المتصفحات الكبيرة.
وعنده كتاب قوانين رسمي بيقول بالظبط كل تعليمة بتعمل إيه. وكل متصفح لازم يمشي عليه بالحرف، لأن أي غلطة ممكن تتحوّل لـثغرة أمنية.
تخيّل لعبة زي بنك الحظ (Monopoly) ليها كتاب قوانين تخين. الحكم الرسمي بيقرا كتاب القوانين لكل نقلة لوحدها. دايمًا صح، لكنه بطيء جدًا لدرجة إن فريق محرّك كبير بطّل يستخدم المرجع الرسمي في الاختبار.
المتصفحات بتستخدم محرّكات كتبها الناس بإيديهم. سريعة، لكنها مكتوبة بشكل منفصل عن القوانين، فممكن تغلط.
أنا بنيت مترجم بيقرا كتاب القوانين ويكتب المحرّك السريع أوتوماتيك. سميته Lockstep، لأن المحرّك بيمشي خطوة بخطوة مع القوانين: هو أصلًا طالع منها.
بينجح في كل الـ55,861 اختبار رسمي، بالظبط زي كتاب القوانين، وهو أسرع بحوالي 45 مرة من تشغيل كتاب القوانين مباشرة.
يعني القوانين اللي كل الناس بتثق فيها بقت كمان سريعة كفاية إننا نستخدمها.
لو حسيت إنهم تايهين في أي نقطة، ارجع لمثال اللعبة: الحكم، النسخة المكتوبة بالإيد، والماكينة بتاعتي اللي بتبني النسخة السريعة من كتاب القوانين.
نفس البرنامج، نفس القوانين، محرّكين. اللي فوق بيقرا كتاب القوانين خطوة بخطوة. واللي تحت المحرّك بتاعي، مبني من نفس كتاب القوانين.
(لما يخلّص.) نفس الإجابة، وأسرع بحوالي 20 مرة. وكمان المفسّر بتاع كتاب القوانين احتاج حوالي 30 ثانية عشان يحمّل قبل ما يبدأ أصلًا.
دي الاختبارات الرسمية، اللي كتبها الناس اللي بيعملوا WebAssembly. 259 ملف. بصّ على العدّاد.
(لما يوصل لـ55,861.) 55,861 من 55,861، في حوالي 8 ثواني، على اللابتوب ده. والمفسّر بتاع كتاب القوانين نفسه بيطلع نفس النتيجة بالظبط في كل ملف.
على الشمال القاعدة زي ما المواصفة الرسمية كاتباها بالظبط. وعلى اليمين الكود اللي المترجم بتاعي ولّده منها. أنا مكتبتش الناحية اليمين. عشان كده مستحيل يبعد عن القوانين.
أرقام فيبوناتشي هي متتالية مشهورة، كل رقم فيها بيساوي مجموع الرقمين اللي قبله: 0، 1، 1، 2، 3، 5، 8، 13، 21، 34، 55… يعني fib(10) = 55، وfib(18) = 2,584.
السباق بيحسبها بالطريقة البطيئة العودية عن قصد. عشان تجيب fib(18)، البرنامج بيطلب fib(17) وfib(16)؛ وكل واحد فيهم بيطلب اتنين كمان، وهكذا لحد ما نوصل لـfib(1) وfib(0). ده بيطلّع 8,361 نداء دالة لـfib(18)، والعدد بيكبر حوالي 1.6 مرة مع كل خطوة لفوق.
عشان كده هو اختبار كويس: الإجابة سهلة إنك تتأكد منها، وكمية الشغل كبيرة وقابلة للتعديل، فتقدر تشوف كل محرّك أسرع بكام بالظبط.
(func $fib (export "fib") (param $n i32) (result i32)
(if (result i32) (i32.lt_s (local.get $n) (i32.const 2))
(then (local.get $n))
(else (i32.add (call $fib (i32.sub (local.get $n) (i32.const 1)))
(call $fib (i32.sub (local.get $n) (i32.const 2)))))))
لو n أصغر من 2، الإجابة هي n نفسها: fib(0) = 0 وfib(1) = 1.
غير كده، ننادي fib(n − 1) وfib(n − 2)، ونجمع الإجابتين.
fib(n) بتعمل بالظبط 2 · fib(n + 1) − 1 نداء، يعني الشغل بيكبر زي φⁿ، حيث φ ≈ 1.618 وهي النسبة الذهبية.
كل نداء بيشغّل حوالي دستة تعليمات (local.get، i32.const، i32.lt_s، if، i32.sub، call، i32.add)، فبيضغط على قلب أي محرّك: نداءات الدوال، التفرعات، المتغيرات المحلية، والحسابات الصحيحة.
المقارنة عادلة: المحرّكين بيشغّلوا نفس ملف .wast وبيبلّغوا عن وقت CPU للاختبار بس، من غير الـ30 ثانية بتاعة تحميل المواصفة. قيم n الصغيرة بيغلب عليها التجهيز الثابت، وعشان كده fib(18) لـfib(20) بيوضّح الفرق أحسن حاجة (حوالي 20×). بحثي بيكمّل ويستخدم طريقة الميل عبر أحجام مختلفة، وده بيشيل تكلفة التجهيز خالص.
الخلفية. من سنة 2025، مواصفة WebAssembly بتتكتب بـSpecTec، وهي لغة متخصصة. SpecTec بتحوّل القوانين لـ474 خوارزمية خطوة بخطوة بلغتها الخوارزمية AL، وعندها مفسّر فوقي (meta-interpreter) بيشغّلها. ده المرجع المطلق، لكنه بياخد حوالي 30 ثانية عشان يحمّل، وبعدين بيشتغل أبطأ من المفسّر المرجعي المكتوب بالإيد بـOCaml بحوالي 27 لـ336 مرة.
السؤال. هل يمكن ترجمة المواصفة آليًا لمحرّك يوافقها ويكون أسرع بكتير؟
الجدوى الأول. بدأت باختبار حاسم (kill test) لمدة أسبوع، هدفه يوقّف المشروع بدري لو الفكرة مش هتنفع. ترجمت بإيدي الـ16 خوارزمية اللي ورا حوالي 15 تعليمة. ولا واحدة احتاجت منطق بره الـAL، والنتيجة كانت أسرع بحوالي 1,000 مرة لكل تكرار حلقة. فقررت أكمل.
المترجم. كتبت backend جديد لـSpecTec، اسمه spectec --rust، حوالي 700 سطر OCaml. بيترجم كل خوارزمية AL لدالة Rust، جملة بجملة، مع الحفاظ على دلالات المفسّر الفوقي. القرارات اللي المفسّر بياخدها وقت التشغيل، زي الدالة اللي النداء بيروح لها أو طريقة مطابقة النمط، بتتاخد مرة واحدة، وقت الترجمة. والجزء الدقيق هو قاعدة الذيل: لما Execute مايكونش آخر جملة، كل حاجة بيبدأها لازم تخلّص قبل الجملة اللي بعدها، فالمترجم بيحط run-to-depth في المكان ده، ويسيب آخر خطوة (tail position) للحلقة الرئيسية عشان الحلقات ماتكبّرش الـRust stack.
الـruntime. حوالي 4,900 سطر مكتوبين بالإيد: القيم، الأعداد الصحيحة غير المحدودة، آلة الـcontext، الدوال العددية المدمجة اللي نقلتها من SpecTec، ومشغّل الاختبارات. هو مفيهوش أي قواعد تعليمات. الاختبارات بتيجي عن طريق parser وvalidator بتوع SpecTec نفسهم، وبتتحوّل لقيم AL.
الصحة. المعيار هو نتائج مطابقة للمفسّر الفوقي في كل ملف من مجموعة الاختبارات الرسمية الأساسية: 55,861 من 55,861 أمر. وزي مشغّل SpecTec نفسه، بيتخطى 12 ملف بياخدوا وقت طويل.
قياس السرعة. وقت CPU، طريقة الميل عشان تكاليف التجهيز تتلاشى، الوسيط (median) لتشغيلات متكررة بترتيب عشوائي، والمتوسط الهندسي. وبما إن السيرفر كان مشترك، عدّيت كمان كل مرة المحرّك بيحجز فيها ذاكرة (allocations) بالظبط، والعدد ده مش بيتأثر بضغط السيرفر خالص.
النتايج. أول محرّك متولّد كان أسرع 28 مرة من المفسّر الفوقي على 8 برامج اختبار، و6.8 مرة أسرع على المجموعة كلها.
التحسينات. بعدين 7 عمليات إعادة كتابة بتحافظ على المعنى، وكل واحدة اتعملها تحقق تاني على المجموعة كاملة: slice arguments، direct numeric dispatch، تسلسلات تعليمات مشتركة، constructors بتخصيص واحد، إعادة استخدام نتايج النداءات النقية عن طريق تحليل النقاء، اختبارات نوع مبنية على الـtag، وذاكرة بايتات مدمجة. مع بعض: أسرع 1.69 مرة، ومرات حجز ذاكرة أقل بنسبة 47 لـ83 في المية، وذاكرة اختبار واحد نزلت من 2.84 GB لـ35 MB. دلوقتي بقى أسرع بحوالي 45 مرة من المفسّر الفوقي، وأبطأ 3.5 مرة من المفسّر المكتوب بالإيد.
الحدود والخطوات الجاية. الأوقات مبدئية، من سيرفر مشغول، وعلى اختبارات صغيرة. الجاي: أعداد صحيحة أصلية في الماكينة، stack تحكم منفصل، إعادة القياس على ماكينة هادية، وقياس كام سطر في المحرّك بيتغير لما ميزة جديدة تتضاف للمواصفة. المفروض يكون صفر.
لغة تعليمات عالمية وآمنة كل المتصفحات بتفهمها، فبرامج مكتوبة بـC وC++ وRust وغيرهم تقدر تشتغل جوه صفحة ويب بسرعة قريبة من سرعة الماكينة نفسها.
برنامج بيترجم كود من لغة للغة تانية. بتاعي بيترجم كتاب قوانين WebAssembly لكود Rust.
محرّكات المتصفحات والسيرفرات بتتختبر بتشغيل أعداد ضخمة من البرامج العشوائية ومقارنتها بمرجع موثوق. والمرجع ده لازم يكون صحيح وسريع. مطوّرو Wasmtime بطّلوا يستخدموا المفسّر المرجعي الرسمي (المكتوب بـOCaml) في الاختبار ده لأنه كان بطيء أوي (PLDI 2023). وLockstep خطوة ناحية مرجع يكون دقيق وسريع في نفس الوقت.
وكمان: أي ميزة جديدة بقت قابلة للتشغيل أول ما تتكتب في المواصفة، والمترجمات اللي بتطلّع WebAssembly تقدر تتحقق ضد القوانين الحقيقية.
لأنه مكتوب بالإيد، منفصل عن المواصفة، فممكن يخالفها، وأي ميزة جديدة لازم تتنفّذ فيه بإيد حد. بتاعي متولّد من المواصفة نفسها. وكمان في سبتمبر 2025، تغيير واحد خلّاه أبطأ لحد 20 مرة في بعض البرامج.
مجموعة الاختبارات الرسمية: 55,861 أمر، مطابقة لمفسّر المواصفة نفسه، ملف بملف، واتأكدت منها تاني بعد كل تغيير عملته.
أيوه. أي bug بيشاركني فيه المفسّر الفوقي مش هيبان، لأن الاتنين بيمشوا على نفس الـAL. وأنا حاطط ده كحد من الحدود. الاختبارات زائد حجة أمان لكل إعادة كتابة هو دليل قوي، مش برهان.
لأنه بيمشي حرفيًا على الآلة المجرّدة بتاعة المواصفة: قيم عامة لكل حاجة، contexts لكل بلوك، وlabels بتخرج واحدة واحدة. إزالة التكلفة دي من غير ما يتغير المعنى هو الجزء البحثي، وكل إعادة كتابة بتقلّل الفرق شوية.
لأنها سريعة زي C لكن آمنة في الذاكرة، والمترجم بتاعها بيحسّن الكود المتولّد كويس، وقيمها اللي بتتعدّ بالـreference بتشبه طريقة المواصفة في مشاركة القيم.
حاجتين. قاعدة الذيل، إنك تقرر إمتى الخطوة لازم تخلّص بالكامل قبل اللي بعدها. وإنك تثبت إن كل تسريع آمن: مثلًا، مشاركة قوايم التعليمات آمنة بس لأن المواصفة عمرها ما بتعدّل قائمة تعليمات في مكانها، فأنا راجعت كل تعديل في المكان في الكود المتولّد.
الدالة تكون نقية لو مبتقراش أي حالة من الماكينة، ومبتغيّرش حاجة في مكانها، وبس بتنادي دوال نقية تانية. والنقاء بيعتمد على الدوال اللي بتناديها، فأنا بكرر التحقق لحد ما مفيش حاجة تتغير، وده اسمه نقطة ثبات. وبعد كده، لو دالة نقية اتنادت مرتين بوسائط مستحيل تكون اتغيرت، النداء التاني بيعيد استخدام نتيجة الأول. وده اللي خلّى تعليمة الحساب بطّلت تعمل الحساب مرتين.
بشغّل كل برنامج على كذا حجم، وأعمل خط مستقيم بين الوقت وكمية الشغل. الميل هو التكلفة لكل وحدة شغل، وتكلفة التجهيز الثابتة، زي تحميل المواصفة، بتختفي.
السيرفر كان مشترك مع شغل تاني، فالوقت كان مشوّش. أما عدد مرات حجز الذاكرة فمضبوط ومتطابق في كل تشغيل، فبيوضّح تأثير كل تغيير بوضوح.
الموجود أصلًا: SpecTec، ومواصفة WebAssembly، والاختبارات الرسمية. والجديد في مشروعي: الـbackend بتاع Rust لـSpecTec، وأداة تحويل الاختبارات (test dumper)، والـruntime، وأدوات القياس، والـ7 تحسينات، وكل التجارب.
أيوه. استخدمت مساعدين للبرمجة بالذكاء الاصطناعي، Claude Code وGemini (في نقل الدوال العددية)، والـlogbook بتاعي مسجّل ده إزاي. أنا اللي حددت سؤال البحث، وصممت التجارب، واتخذت القرارات، واتأكدت من كل حاجة ضد الاختبارات الرسمية، وأقدر أشرح كل جزء.
مشغّل الاختبارات بتاع SpecTec نفسه بيتخطاهم لأنهم بطيئين أوي عليه. أنا حافظت على نفس القواعد بالظبط عشان المقارنة تفضل عادلة. وتشغيلهم واحد من خطواتي الجاية، بما إن المحرّك بتاعي بقى سريع كفاية إنه يجرّب.
لسه لأ. هو prototype بحثي. وخطوة جاية إني أعرض الـbackend على المسؤولين عن SpecTec.
أعداد صحيحة أصلية في الماكينة، stack تحكم منفصل، تفرعات أسرع، اختبارات أكبر من الواقع، إعادة القياس على ماكينة هادية، وتجربة الميزة: أضيف ميزة جديدة للمواصفة، أعيد التوليد، وأعد كم سطر في المحرّك اتغير.
| 55,861 | أمر اختبار رسمي عدّيتهم كلهم، ومتطابقين ملف بملف مع مفسّر المواصفة |
| 259 | ملف في مجموعة الاختبارات الرسمية الأساسية (12 ملف طويل متخطّين، زي ما SpecTec بتعمل) |
| 474 | خوارزمية في المواصفة، كلهم مترجمين |
| 22,000 | سطر Rust متولّد |
| 700 | سطر OCaml في المترجم (الـbackend الجديد بتاع SpecTec) |
| 4,900 | سطر runtime مكتوب بالإيد، من غير أي قواعد تعليمات |
| ~45× | أسرع من تشغيل المواصفة مباشرة (كان 28× قبل التحسين) |
| 6.8× | أسرع على مجموعة الاختبارات كلها |
| 3.5× | لسه أبطأ من المفسّر المرجعي المكتوب بالإيد (كان 5.6×) |
| 1.69× | مكسب من 7 عمليات إعادة كتابة بتحافظ على المعنى |
| 47–83% | مرات حجز ذاكرة أقل (allocations) |
| 2.84 GB → 35 MB | الذاكرة في اختبار واحد، بعد الذاكرة المدمجة |
| ~1,000× | تسريع الـkill test (الترجمة اليدوية الصغيرة) |
| 30 s | الوقت اللي مفسّر المواصفة محتاجه عشان يحمّل بس |
| 8 s | لمجموعة الاختبارات كلها على اللابتوب |