Schema zu WebAssembly kompilieren – Eli Benderskys Website

Schema zu WebAssembly kompilieren – Eli Benderskys Website


Eines meiner ältesten Open-Source-Projekte – Bob – hat vor ein paar Monaten seinen 15. Geburtstag gefeiert. Bob ist eine Suite von Implementierungen der Programmiersprache Scheme in Python, einschließlich eines Interpreters, eines Compilers und einer VM. Damals habe ich mich mit CPython-Interna befasst und war sehr neugierig, wie CPython-ähnliche Bytecode-VMs funktionieren. Bob führte ein Experiment durch, um dies herauszufinden, indem er eines von Grund auf für das R5RS-Schema implementierte.

Einige Monate später fügte ich Bob eine C++-VM hinzu, als Übung, um zu lernen, wie solche VMs in einer Low-Level-Sprache implementiert werden, ohne die gesamte Laufzeitunterstützung, die Python bietet; vor allem ohne den eingebauten GC. Die C++-VM in Bob implementiert ihren eigenen Mark-and-Sweep-GC.

Nach vielen ruhigen Jahren (mit nur ein paar kosmetischen Änderungen, Portierungen auf GitHub, Updates auf Python 3 usw.) verspürte ich kurz vor den Feiertagen den Drang, wieder an Bob zu arbeiten. Konkret habe ich beschlossen, der Suite einen weiteren Compiler hinzuzufügen – diesen von Scheme direkt zu WebAssembly.

Die Ziele dieser Bemühungen waren zweierlei:

  1. Experimentieren Sie mit der Herabstufung einer echten Hochsprache wie Scheme auf WebAssembly. Experimente wie das jüngste Let’s Build a Compiler kompilieren Spielzeugsprachen auf C-Ebene (keine Laufzeit). Scheme verfügt über integrierte Datenstrukturen, lexikalische Abschlüsse, Speicherbereinigung usw. Es ist viel anspruchsvoller.
  2. Sammeln Sie praktische Erfahrungen mit der WASM GC-Erweiterung. Ich habe mehrere Beispiele für die Verwendung von WASM GC im Wasm-Wat-Samples-Repository, aber ich wollte es unbedingt für etwas „Echtes“ ausprobieren.

Nun, es ist jetzt erledigt; Hier ist ein aktualisierter Schaltplan des Bob-Projekts:

Schema zu WebAssembly kompilieren – Eli Benderskys Website

Der neue Teil ist der vertikale Pfad ganz rechts. Eine WasmCompiler-Klasse reduziert geparste Scheme-Ausdrücke bis hin zum WebAssembly-Text, der dann in eine Binärdatei kompiliert und mit Standard-WASM-Tools ausgeführt werden kann.

Höhepunkte

Der interessanteste Aspekt dieses Projekts war die Arbeit mit WASM GC zur Darstellung von Scheme-Objekten. Solange wir alle Werte richtig einpacken/verpacken
refs, die zugrunde liegende WASM-Ausführungsumgebung kümmert sich um die Speicherverwaltung.

Für Bob werden einige wichtige Scheme-Objekte wie folgt dargestellt:

;; PAIR holds the car and cdr of a cons cell.
(type $PAIR (struct (field (mut (ref null eq))) (field (mut (ref null eq)))))

;; BOOL represents a Scheme boolean. zero -> false, nonzero -> true.
(type $BOOL (struct (field i32)))

;; SYMBOL represents a Scheme symbol. It holds an offset in linear memory
;; and the length of the symbol name.
(type $SYMBOL (struct (field i32) (field i32)))

$PAAR ist von besonderem Interesse, da es beliebige Objekte in seinen Feldern enthalten kann; (ref null eq) bedeutet „ein nullbarer Verweis auf etwas, das Identität hat“. ref.test kann verwendet werden, um für eine bestimmte Referenz den Laufzeittyp des Werts zu überprüfen, auf den sie verweist.

Sie fragen sich vielleicht: Was ist mit numerischen Werten? Hier hat WASM einen Trick – den i31
Der Typ kann verwendet werden, um einen Verweis auf eine Ganzzahl darzustellen, ohne ihn jedoch tatsächlich einzurahmen (ein Bit wird verwendet, um ein solches Objekt von einem echten Verweis zu unterscheiden). Wir benötigen also keinen separaten Typ, um Verweise auf Zahlen zu speichern.

Auch die $SYMBOL Typ sieht ungewöhnlich aus – wie wird er mit zwei Zahlen dargestellt? Der Schlüssel zum Rätsel liegt darin, dass WASM keine integrierte Unterstützung für Strings bietet; Sie sollten manuell mithilfe von Offsets zum linearen Speicher implementiert werden. Der Bob WASM-Compiler gibt die Zeichenfolgenwerte aller gefundenen Symbole in den linearen Speicher aus und verfolgt dabei den Offset und die Länge jedes einzelnen Symbols. Das sind die beiden eingegebenen Zahlen $SYMBOL. Dies ermöglicht auch die relativ einfache Implementierung der String-Interning-Funktion von Scheme; Mehrere Instanzen desselben Symbols werden nur einmal zugewiesen.

Betrachten Sie diesen trivialen Scheme-Ausschnitt:

Der Compiler gibt die Symbole „foo“ und „bar“ wie folgt in den linearen Speicher aus:

(data (i32.const 2048) "foo")
(data (i32.const 2051) "bar")

Und wenn wir im Rest des ausgegebenen Codes nach einer dieser Adressen suchen, finden wir:

(struct.new $SYMBOL (i32.const 2051) (i32.const 3))

Als Teil des Codes zum Erstellen der Konstante Nachteile Liste, die das Argument darstellt schreiben; Adresse 2051 und Länge 3: Das ist das Symbol Bar.

Apropos schreibendie Implementierung dieses Builtins war sehr interessant. Aus Kompatibilitätsgründen mit den anderen Bob-Implementierungen in meinem Repository: schreiben
muss in der Lage sein, rekursive Darstellungen beliebiger Scheme-Werte zu drucken, einschließlich Listen, Symbolen usw.

Anfangs zögerte ich, all diese Funktionen manuell in WASM-Text zu implementieren, aber alle Alternativen stießen auf Herausforderungen:

  1. Dies auf den Host zu verlagern ist schwierig, da die Hostumgebung keinen Zugriff auf WASM GC-Referenzen hat – diese sind völlig undurchsichtig.
  2. Die Implementierung in einer anderen Sprache (vielleicht C?) und die Reduzierung auf WASM ist aus einem ähnlichen Grund ebenfalls eine Herausforderung – die andere Sprache verfügt wahrscheinlich nicht über eine gute Darstellung von WASM-GC-Objekten.

Also habe ich in den sauren Apfel gebissen und – mit etwas KI-Hilfe für die mühsamen Teile – einfach eine Implementierung von geschrieben schreiben direkt im WASM-Text; es war nicht wirklich so schlimm. Ich importiere nur zwei Funktionen vom Host:

(import "env" "write_char" (func $write_char (param i32)))
(import "env" "write_i32" (func $write_i32 (param i32)))

Obwohl es nicht schwierig ist, Ganzzahlen direkt aus WASM auszugeben, dachte ich, dass dieses Projekt bereits über genügend Code verfügt und dass hier etwas Host-Hilfe willkommen wäre. Im Übrigen nur die unterste Stufe write_char verwendet wird. So werden beispielsweise boolesche Werte in der kanonischen Scheme-Notation ausgegeben (#T Und #F):

(func $emit_bool (param $b (ref $BOOL))
    (call $emit (i32.const 35)) ;; '#'
    (if (i32.eqz (struct.get $BOOL 0 (local.get $b)))
        (then (call $emit (i32.const 102))) ;; 'f'
        (else (call $emit (i32.const 116))) ;; 't'
    )
)

Abschluss

Das war ein wirklich unterhaltsames Projekt und ich habe einiges über die realistische Codeausgabe an WASM gelernt. Schauen Sie sich gerne den Quellcode von WasmCompiler an – er ist sehr gut dokumentiert. Obwohl es insgesamt etwas mehr als 1000 LOC sind, handelt es sich bei mehr als der Hälfte davon tatsächlich um WASM-Textschnipsel, die die integrierten Typen und Funktionen implementieren, die für eine grundlegende Scheme-Implementierung erforderlich sind.




Source link

Postagens Similares

  • Dizüstü bilgisayarımdaki Qwen3.6-35B-A3B bana Claude Opus 4.7’den daha iyi bir pelikan çizdi

    Dizüstü bilgisayarımdaki Qwen3.6-35B-A3B bana Claude Opus 4.7’den daha iyi bir pelikan çizdi 16 Nisan 2026 Pelikan sürme testimi modelleri test etmenin sağlam bir yolu olarak (tavsiye edilmeyen bir şekilde) ciddiye alan herkes için, işte bu sabah piyasaya sürülen iki büyük modelden pelikanlar: Alibaba’dan Qwen3.6-35B-A3B ve Anthropic’ten Claude Opus 4.7. Burada, Unsloth tarafından hazırlanan bu 20,9…

  • 📝 2026-06-23 12:58 – Кев Квірк

    📝 2026-06-23 12:58 – Кев Квірк Гордо руйнує мережу з 2013 року. 23 червня 2026 о 12:58 Створіть одну з цих сторінок використання. Робота все ще триває, але зараз є значна частина того, що я використовую. https://kevquirk.com/uses Відповісти електронною поштою Підпишіться, щоб отримати більше! Вам не обов’язково повертатися сюди, щоб прочитати…

  • 你怎麼知道的

    2014年12月 我讀過維爾哈杜安關於第四次十字軍東徵的編年史至少兩遍,也許三次。然而,如果我必須寫下我所記得的一切,我懷疑它會比一頁多得多。乘以幾百,當我看著我的書架時,我有一種不安的感覺。如果我對這些書的記憶如此之少,那麼閱讀所有這些書有什麼用呢? 幾個月前,當我閱讀康斯坦斯·里德(Constance Reid)撰寫的出色的希爾伯特傳記時,我找到了這個問題的答案,即使不是這個問題的答案,至少也讓我感覺更好了。她寫道: 希爾伯特對數學講座沒有耐心,因為數學講座向學生灌輸大量事實,卻沒有教他們如何提出問題並解決問題。他經常告訴他們「問題的完美表述已經是解決方案的一半」。 在我看來,這一點一直很重要,在聽到希爾伯特的證實後,我更加確信這一點。 但我最初是如何相信這個想法的呢?結合了我自己的經驗和我讀過的其他內容。那一刻我什麼都不記得了!最後我忘了希爾伯特也證實了這一點。但我對這個想法重要性的日益增強的信念仍然是我從這本書中學到的東西,即使在我忘記了我學過它之後。 閱讀和經驗可以訓練你的世界觀。即使你忘記了這段經歷或你讀過的內容,它對你的世界模型的影響仍然存在。你的頭腦就像一個已編譯的程序,但你卻失去了它的來源。它有效,但你不知道為什麼。 我從維爾哈杜安的編年史中尋找的地方不是我從中記住的東西,而是我對十字軍東徵、威尼斯、中世紀文化、攻城戰等的心智模型。這並不意味著我不能更用心地閱讀,但至少閱讀的收穫並不像看起來那麼小。 回想起來,這是顯而易見的事情之一。但這對我來說是一個驚喜,想必對任何其他因為(顯然)忘記他們讀過的東西而感到不安的人來說也是如此。 不過,意識到這一點不僅能讓你對遺忘感覺好一點。有具體的影響。 例如,閱讀和經驗通常是在發生時使用您當時的大腦狀態進行「編譯」的。同一本書在你人生的不同階段會有不同的編輯方式。這意味著重要的書籍非常值得多次閱讀。我過去常常對重讀書籍感到有些疑慮。我無意識地將閱讀與木工等工作混為一談,木工等工作必須重新做某件事就表明你第一次做錯了。而現在「已讀」這個短語似乎幾乎是格式錯誤。 有趣的是,這種意義不僅限於書籍。科技將越來越多地使重溫我們的經驗成為可能。今天,當人們這樣做時,通常是為了再次享受它們(例如,當查看旅行的照片時)或在編譯的代碼中找到某些錯誤的根源(例如,當斯蒂芬·弗萊(Stephen Fry)成功地記住了阻止他唱歌的童年創傷時)。但隨著記錄和回放生活的技術不斷進步,人們在沒有任何目標的情況下重溫經歷可能會變得很常見,只是為了再次從中學習,就像重讀一本書時一樣。 最終,我們不僅能夠回放體驗,還能夠索引甚至編輯它們。因此,儘管不知道如何知道事情似乎是人類的一部分,但事實可能並非如此。 謝謝 感謝 Sam Altman、Jessica Livingston 和 Robert Morris 閱讀本文的草稿。 Source link

  • 我最喜欢的播客 2024 – 大重置

    在我最初的播客库存 4.5 年后,随着新冠疫情和我职业生涯的转变,我的 OPML 文件从 2022 年的 566 个 rss feed 增长到 2024 年的 771*(我最喜欢的 NPR 播客中的相当多),我的积压工作增加到 43GB(根据这个脚本,我的出色剧集:11915 集(播放过: 22451)),我现在需要宣布播客破产。 在 Overcast 的功能请求被搁置了一年之后,我现在热衷于转向一个新的应用程序 Snipd(感谢 Kevin Ben Smith 的加入),即使我不太看重剪切功能,它至少也有转录功能。之前我没有搬家,因为移植过程没有制定好,但现在我已经决定宣布播客破产,现在是切换的好时机,并盘点我未来需要什么。 *注:这并不是我订阅的真正的 771 个播客,这个数字是我在 6 年多的时间里听过的所有内容,甚至是其中的一集,包括我偶尔摘掉音频的 YouTube 视频 根据我的 2020 年类别,以下是我保留的内容: AI:在 2023 年枢轴之后,我在 ai-notes 上积极维护此列表 消息 HN 回顾荚 主流:《华尔街日报》。 (rss, url)、《纽约时报》每日报 (rss, url)、《经济学人情报》(rss, url) 和《经济学人》编辑精选 (rss, url)…

  • 职业蛇梯棋 |凯夫·夸克

    📅 2025 年 10 月 18 日 | ⏱️ ~6 分钟阅读 经过多年在网络领域的攀登,我了解到有时最好的举措并不是向上。它正在退后一步,让生活再次可持续。 企业的阶梯与其说是攀登,不如说是一场蛇梯游戏。进步的时刻、挫折的时刻,以及偶尔的幸运时刻,一切似乎都是一致的。有时向上,有时横向移动,有时向下移动。 攀登永无止境 2024 年 8 月,我获得了晋升,从“高级经理”职位晋升为“高管”职位。它带来了人们认为高管级别职位应有的所有酷炫福利;一个漂亮的角落办公室,一个私人助理,作为少数人之一的荣誉 非常 资深人士,当然还有与之相匹配的薪水。 我接受了这个角色,但高级经理与高管的期望是 非常 不同的。我在一家美国公司工作,所以与我一起工作的很多人都在美国各地。这意味着很多个深夜。 但我在新加坡也有一个团队,所以这也意味着清晨。然后是我在英国、爱尔兰和印度的团队,所以我在核心工作时间也很忙。 管理一个全球团队已经够困难的了,但更重要的是,我在一家美国大型银行的网络安全行业工作,这是一家 巨大的 目标。狗屎变得很忙。 然后 除了定期去美国旅行之外,家里还有一个年轻的家庭,有很多宠物需要照顾,还有我和妈妈都照顾的残疾兄弟。 很多。 重构成功 当我接手这个角色时,我有一种感觉,这次晋升可能有点太过分了。我知道自己将面临什么,但我必须尝试一下,看看我是否能做到。我是我所在的网络团队中仅有的两名高管之一,另一名比我年长近 20 岁。这对我来说是一个巨大的成功标志,我对自己所取得的成就感到无比自豪。 但随着时间的推移,我在办公桌前花的时间越来越多,与亲人相处的时间越来越少,很明显,我需要重新衡量成功的标准。另外,我已经筋疲力尽了。 我清楚地记得我把事情搞砸的那一刻。我曾连续几个晚上特别忙于我们已经运行了几个月的项目。那是一个星期四的晚上,我在晚上 9 点左右下班。星期四,我的孩子们要练习游泳,这对他们来说通常是深夜。他们大约在我下班的同时回到家,我最小的孩子走到我身边,给了我一个大大的拥抱,并告诉我他想念我。 我不明白。我问他为什么在我不在的时候想念我。他说: 是的,你有。你又来美国了,是吗? 我没去过美国。我刚刚工作了很长时间,已经四天没有见到孩子们了。 这并不是一个戏剧性的“崩溃”时刻,而是一种平静的清晰。认识到与我所爱的人在一起比重要更重要。 下台,而不是离开 因此,我认为高管职位不适合我,是时候回到高级经理职位了,职责范围更小,压力更小,最重要的是,更加平衡。这不是失败或撤退,而是朝着可持续发展的有意迈出的一步。 我和我的经理约了时间,并向她透露了这个消息。她告诉我她理解我的决定,我显然花了很多心思,她很高兴支持我辞职。 我们同意她将与人力资源部门交谈并做出安排,以便我可以过渡到这个角色,同时支持接替我的人。我们预计这一过程需要六个月的时间。 但后来我姐姐结束了自己的生命,一切都发生了翻天覆地的变化。在休丧假期间,我找到了我的经理,并解释说我需要尽快退后一步,因为我没有能力继续担任执行职务。 她在我前面几步,已经安排好掩护,以便我可以下来。一周后,我做到了。 我从未感受到过任何雇主如此支持我。任何在大型企业工作过的人都会知道,事情进展得极其缓慢,所以对于我的经理来说,在几周内解决这个问题就像她为我移山一样。 就是有这样的事情让我想在我余下的职业生涯中在某个地方工作。工资、福利、角落办公室——这一切都只是废话和噪音。工作固然重要,但人最重要。 重新定义获胜的样子 有时,滑下梯级正是让你留在游戏中的原因。我宁愿参与游戏,尽管已经从蛇上滑下来,也不愿爬上梯子的另一级;过度劳累、痛苦、压力大、精疲力尽。 由于这一切,我意识到成功不仅仅在于向上运动。它关乎耐力、目标和远见。这是关于对我们所做的工作感到满意。受到挑战,但不会过度劳累。最重要的是,能够与亲人共度时光。 因为说实话,人们:没有人在临终时躺在床上思考 “我希望我能参加晚上…

Deixe um comentário

O seu endereço de email não será publicado. Campos obrigatórios marcados com *