惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

S
Schneier on Security
P
Proofpoint News Feed
Apple Machine Learning Research
Apple Machine Learning Research
WordPress大学
WordPress大学
博客园 - Franky
V
V2EX
爱范儿
爱范儿
J
Java Code Geeks
小众软件
小众软件
Last Week in AI
Last Week in AI
The Cloudflare Blog
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
Hugging Face - Blog
Hugging Face - Blog
T
The Blog of Author Tim Ferriss
酷 壳 – CoolShell
酷 壳 – CoolShell
The Register - Security
The Register - Security
GbyAI
GbyAI
Vercel News
Vercel News
Y
Y Combinator Blog
腾讯CDC
F
Fortinet All Blogs
I
InfoQ
N
Netflix TechBlog - Medium
B
Blog RSS Feed
D
Docker
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
量子位
博客园 - 司徒正美
阮一峰的网络日志
阮一峰的网络日志
The GitHub Blog
The GitHub Blog
Microsoft Security Blog
Microsoft Security Blog
V
Visual Studio Blog
博客园 - 三生石上(FineUI控件)
宝玉的分享
宝玉的分享
Blog — PlanetScale
Blog — PlanetScale
H
Help Net Security
云风的 BLOG
云风的 BLOG
A
About on SuperTechFans
Scott Helme
Scott Helme
T
Tor Project blog
U
Unit 42
Google Online Security Blog
Google Online Security Blog
PCI Perspectives
PCI Perspectives
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
NISL@THU
NISL@THU
D
Darknet – Hacking Tools, Hacker News & Cyber Security
aimingoo的专栏
aimingoo的专栏
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
Stack Overflow Blog
Stack Overflow Blog
Security Archives - TechRepublic
Security Archives - TechRepublic

Kevin Blog

产品随想 2 产品力与人才密度 产品随想 1 做营销还是做产品 Play PyTorch Stable Diffusion and ONNX, Ollama on Intel Core Ultra 5 225H Ubuntu 25.04 Play with ROCm, PyTorch, Ollama on Ubuntu 24.04 and 780m 写在新的旅程开始前 想念自然与青春 懒猫微服体验——自由协作的神器 没有光纤的日子怎么上网?自制 Home WI-FI! Swift on Server Tour 6 关联 User 和 Post Swift on Server Tour 5 创建 Users Swift on Server Tour 4 构建 Post Controller Swift on Server Tour 3 构建 Post 的 API 将不懂的日语一拍扫尽,介绍捧读全新的「OCR 工作台」功能 Swift on Server Tour 2 连通你的数据库与服务器 Swift on Server Tour 1 你的第一个 Server App 以及它背后的故事 Swift on Server Tour 0: 为什么这可能是你的好选择 纪念左耳朵耗子 How to learn Japanese by reading Novels and News with the help of Oyomi. BenQ WiT ScreenBar Halo 体验报告 记录 2021 年考驾照的体验 捧读的 EPUB 日语轻小说阅读器来了 使用 Go Mobile 开发跨平台 Library 使用 Kotlin Native 开发跨平台 Library 小番茄 - 一个只有陪伴的自习室 保友金豪电脑椅异响维修记 青岛度假指南 2020 「捧读」更新,支持针对任意文本进行语法讲解 一次百元耳机与千元耳机的横评 高刷墨水屏的海信 A5 Pro 体验报告 「捧读」更新 Safari 扩展,轻松阅读日语网页 新 App 「捧读:日语语法学习与分析」的开发幕后思考 明基 WiT ScreenBar Plus 体验 Switch游戏推荐:「健身环大冒险」和「太鼓达人」 妥协是否是一种艺术? 「50 音起源」1.2 更新说明 作客 UX Coffee 分享了自己最近的独立开发者生活 青岛度假指南 2019 我有「快乐自由」 关于小电台这款产品 聊一聊 50 音起源的再设计 极端精英主义的崩塌 Xcode Error: CFBundleSupportedPlatforms or Mach-O LC_VERSION_MIN 自由职业一周年我收获了什么 「50音起源」从起源学习 50 音的 App iOS/Android 青岛疗养(度假)指南 关于独处的一些经验 跨省携猫🐱搬家记 关于 FilmMentor 这款小众产品的想法 选择离开北京,以及为什么可以
Write WebAssembly in Swift and use it in Swift App
2022-06-11 · via Kevin Blog

Background

I've been developing a new app for a while, one of the coolest ideas is to let the user write their own script to extend the app's ability.

But what kind of scripting language should I support? Why not support them all? So the decision is to adapt WebAssembly which grants the user's flavor.

What's more, We will also use Swift to write wasm thanks to the great SwiftWasm project.

Communication

WebAssembly was designed to be a 32-bit sandbox VM, it's safe and isolated from our 64-bit Swift host app.

The only way to communicate with each other is to copy memory from the host app into the VM and read the processed memory from VM back later.

This's a big challenge, but we will overcome it step by step.

Reference

If you are not quite familiar with Swift pointer & memory layout, check out these talks.

Exploring Swift Memory Layout Size, Stride, Alignment Unsafe Swift: Using Pointers and Interacting With C

Setup SwiftWasm

1. Install swiftenv

We will use swiftenv to manage the toolchain, So please install it first.

2. Install swiftwasm

Since swiftwasm has not been merged into the repo, we gonna install it on our own.

Here is the Github release page of the toolchain.

3. Set swift env in project

Use swiftenv to check the version of your swiftwasm

Mine is wasm-5.6.0 at the time, so at the root of your project folder, run swiftenv local wasm-5.6.0 to set the project level swift env.

Basic WebAssembly App

Finished project can be found here https://github.com/kevinzhow/write-wasm-in-swift-demo

As we know before, the Host app can only communicate with WebAssembly VM through memory copy, with the help of protobuf, we can transport data between 32-bit wasm VM and 64-bit host app easily.

But we also need to implement a few functions to handle these.

  1. allocate memory with size and return memory pointer
  2. deallocate memory at the pointer
  3. function to do the real work with memory address and size.

Quick look

import Foundation

@_cdecl("allocate")
func allocate(size: Int) -> UnsafeMutableRawPointer {
  return UnsafeMutableRawPointer.allocate(byteCount: size, alignment: MemoryLayout<UInt8>.alignment)
}
@_cdecl("deallocate")
func deallocate(pointer: UnsafeMutableRawPointer) {
  pointer.deallocate()
}

@_cdecl("change_article_proto")
func changeBookProto(protoData: UnsafeMutableRawPointer,  size: Int,  newAuthor: UnsafeRawPointer, authorSize: Int, newSize: UnsafeMutablePointer<Int>) -> UnsafeRawPointer {
    // Decode proto binary data
    let data = Data(bytes: protoData, count: size)
    var book = try! BookInfo(serializedData: data)

    // Change author
    book.author =  String(data: Data(bytes: newAuthor, count: authorSize), encoding: .utf8)!

    let newData = try! book.serializedData()
    newSize.pointee = newData.count

    // get the data pointer of the new book proto data
    let pointer = newData.withUnsafeBytes{ (bufferRawBufferPointer) -> UnsafeRawPointer in

        let bufferPointer: UnsafePointer<UInt8> = bufferRawBufferPointer.baseAddress!.assumingMemoryBound(to: UInt8.self)
        return UnsafeRawPointer(bufferPointer)
    }

    return pointer
}

Now we can build our wasm with command

swift build --triple wasm32-unknown-wasi  -c release -Xlinker --allow-undefined

We pass --allow-undefined to make sure all @_cdecl functions will be exported.

Then copy it out

cp .build/release/swiftwasm.wasm ./swiftwasm.wasm

Swift Host App

Finished Project can be found here https://github.com/kevinzhow/swiftwasm-host-app-demo

First, we implement a Wasm Module to handle the memory exchange and method call.

import Foundation
import WasmInterpreter
import SwiftProtobuf

public struct WasmModule {
    private let _vm: WasmInterpreter

    init() throws {
        _vm = try WasmInterpreter(module: Bundle.module.url(forResource: "swiftwasm", withExtension: "wasm")!)
    }

    /// Allocate memory on heap
    /// It returns byteoffset
    func allocate(size: Int) throws -> Int {
        return Int(try _vm.call("allocate", Int32(size)) as Int32)
    }
    
    func deallocate(byteOffset: Int) throws {
        try _vm.call("deallocate", Int32(byteOffset))
    }
    
    /// Allocate size on heap
    /// It returns byteoffset
    func allocateSize() throws -> Int {
        
        let length = MemoryLayout<Int32>.size
        
        let newSizePointer = try! allocate(size: length)
        
        return newSizePointer
    }
    
    /// Write string to heap
    /// It returns byteoffset
    func writeString(string: String) throws -> (Int, Int) {
        
        let length = Data(string.utf8).count
        
        let pointer = try! allocate(size: length)
        
        try _vm.writeToHeap(string: string, byteOffset: pointer)
        
        return (pointer, length)
    }
    
    /// Write Data to heap
    /// It returns byteoffset
    func writeData(data: Data) throws -> Int {
        
        let length = data.count
        
        let pointer = try! allocate(size: length)
        
        try _vm.writeToHeap(data: data, byteOffset: pointer)

        return pointer
    }

    /// Send Protobuf binary into
    func changeBook(_ book: BookInfo, author: String) throws -> BookInfo {
         let data = try! book.serializedData()
        
        let (newAuthorPtr, newAuthorSize) = try! writeString(string: author)
        
        let newSizePointer = try! allocateSize()
        
        let dataPointer = try writeData(data: data)
        
        let newArticlePointer = Int(try _vm.call("change_article_proto",
                                                 Int32(dataPointer),
                                                 Int32(data.count),
                                                 Int32(newAuthorPtr),
                                                 Int32(newAuthorSize),
                                                 Int32(newSizePointer)) as Int32)
        
        let newSizeValue = Int(try _vm.valueFromHeap(byteOffset: newSizePointer) as Int32)
        
        let newData = try _vm.dataFromHeap(byteOffset: newArticlePointer, length: newSizeValue)
        
        let newBook = try! BookInfo(serializedData: newData)
        
        try! deallocate(byteOffset: newAuthorPtr)
        try! deallocate(byteOffset: newSizePointer)
        try! deallocate(byteOffset: dataPointer)
        try! deallocate(byteOffset: newArticlePointer)
        
        return newBook
    }
}

Finally, we can use it.

main.swift

import WasmInterpreter
print("Hello, world!")

let module = try! WasmModule()
var book = BookInfo()
book.id = 1
book.author = "Apple"
book.title = "Swift Programming"
let newBook = try! module.changeBook(book, author: "Apple Stuff")
print(newBook.author)