【问题标题】:How to share array memory between JavaScriptCore and Swift?如何在 JavaScriptCore 和 Swift 之间共享数组内存?
【发布时间】:2020-02-15 03:48:28
【问题描述】:

我正在尝试编写一个通过 JavaScriptCore 运行 JS 的 Swift 程序。我希望在我的程序的两个部分之间共享内存,以便 JS 写入在 Swift 中创建的类型化数组缓冲区,然后 Swift 读取和写入它。这将是一种命令缓冲区。

例如,这里有一些伪代码大致代表了我打算做的事情:

// js
let buf;
let i = 0;
setup() {
   buf = new Uint8Array(mem.alloc(N_BYTES));
}

frame() {
   i = 0;
   buf[i++] = some_command_enum;
}

// swift
func alloc(bytes : Int) -> the_memory {
    // allocate bytes uints and save the memory here
    // save a reference to the memory here
    // return the memory to use in JS
}

问题是,每当我尝试将实现实际添加到 alloc 时,JS 都会通过异常报告该函数未定义,这意味着我做事的方式有问题。非返回函数很好,所以我把它记下来了。

这是我的错误实现(请参阅 cmets):

// swift
@objc protocol JSMemoryExports: JSExport {
    static func alloc(_ byte_count: Int) -> JSObjectRef
    static func free(_ memory: JSObjectRef)
}

class JSMemory: NSObject, JSMemoryExports {
                                           // What is the correct return type?
    class func alloc(_ byte_count: Int) -> JSObjectRef {
        // temp
        let jsContext = JS_Controller.js.ctx!

        print("BYTE_COUNT", byte_count)

        // allocating a typed array
        let arr = JSObjectMakeTypedArray(jsContext.jsGlobalContextRef!, kJSTypedArrayTypeUint8Array, byte_count, nil)

        // just testing here to see how I'd write to this buffer (Note: is this the fastest way, or is all this memory binding slow?:
        // getting the raw bytes
        let ptr = JSObjectGetTypedArrayBytesPtr(jsContext.jsGlobalContextRef!, arr, nil)
        //let buf = JSObjectGetTypedArrayBuffer(jsContext.jsGlobalContextRef, arr, nil)
        let u8Ptr = ptr!.bindMemory(to: UInt8.self, capacity: byte_count)
        //u8Ptr[0] = 5
        return arr!
    }
}

...

jsContext["mem"] = JSMemory.self

// js
const buf = new Uint8Array(mem.alloc(8)) // JS Exception: TypeError: mem.alloc is not a function. (In 'mem.alloc(8)', 'mem.alloc' is undefined)

我见过使用某种@convention 属性的函数绑定变体。我是否打算使用它?

正确的做法是什么?

【问题讨论】:

    标签: swift memory javascriptcore


    【解决方案1】:

    除非您将来自不同来源的大量信息拼凑在一起,否则文档并不是很有帮助。看似可行的解决方案涉及使用可在 Swift 中调用的旧 C API 的部分、不安全的指针,并确保绑定函数的返回值为JSValue?s。这是有道理的,因为 JavaScript 函数都返回一个对象,null undefined。可选类型反映了这种行为。

    这是我为任何可能需要线索的人准备的代码:

    只是为了更新,我想出了如何将旧的 C API 与新的更有限的 Swift 特定 API 混合使用。我还没有确定我没有泄漏内存,但看起来我已经找到了我需要的东西,希望如此。

    如果你想知道:

    @objc protocol JSMemoryExports: JSExport {
        // note that I'm returning an optional
        static func Uint8ArrayMake(_ count : JSValue) -> JSValue?
    }
    
    class JSMemory: NSObject, JSMemoryExports { 
        class func UInt8ArrayMake(_ count : JSValue) -> JSValue? {
            guard !count.isUndefined && !count.isNull else {
                return nil
            }
    
            let ref : JSValueRef = JSObjectMakeTypedArray(
                JS_Controller.js.ctx.jsGlobalContextRef!,
                kJSTypedArrayTypeUint8Array,
                Int(count.toInt32()),
                nil
            )!
    
            // if you want to modify the data
            // let ptr = JSObjectGetTypedArrayBytesPtr(
            //    JS_Controller.js.ctx.jsGlobalContextRef!, ref, nil
            // )
    
            return JSValue(jsValueRef: ref, in: JS_Controller.js.ctx)    
        }
    }
    

    这里有几个有用的参考资料:

    pointers in Swift
    manual memory management in Swift

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-12-03
      • 1970-01-01
      • 2020-02-27
      • 1970-01-01
      • 1970-01-01
      • 2018-03-19
      • 2015-06-04
      相关资源
      最近更新 更多