如何用C语言互操作桥接JSVM虚拟机:完整拆解仓颉js_interop系统架构(napi_cffi源码剖析)

发布时间:2026/9/24 16:31:33

如何用C语言互操作桥接JSVM虚拟机:完整拆解仓颉js_interop系统架构(napi_cffi源码剖析) 如何用C语言互操作桥接JSVM虚拟机完整拆解仓颉js_interop系统架构napi_cffi源码剖析【免费下载链接】cangjie_js_interop项目地址: https://gitcode.com/Cangjie/cangjie_js_interop仓颉/cangjie_js_interop 是一个面向鸿蒙场景的仓颉与 JavaScript 跨语言互操作库它通过C 语言互操作CFFI桥接JSVM JavaScript 虚拟机让仓颉应用可以直接创建 JS 运行时、执行 JS 代码、调用 JS 函数并支持 JS 回调仓颉函数。本文基于源码完整拆解它的napi_cffi 接口层与系统架构帮助新手快速理解跨语言互操作是如何落地的。 先搞懂js_interop 解决什么问题在 OpenHarmony 应用开发中仓颉和 JavaScript 经常需要混合开发仓颉调用 JavaScript复用 JS 丰富的库生态把现成的 JS 模块当作依赖来用JavaScript 回调仓颉在 JS 侧触发高性能的仓颉代码模块发挥仓颉高并发优势。互操作库的核心价值就是在两者之间架起一座桥跨语言传参、跨语言函数调用、跨语言类型转换、跨语言异常处理、引用管理与线程协同全部封装成简洁的 API开发者无需关心底层 C 接口细节。️ 系统架构接口层 框架层 JSVM-API 三层结构图示在 DevEco 中选择 [Cangjie] Empty Ability 模板创建仓颉工程这是使用 js_interop 互操作库的第一步。整体架构分为三层层次组件职责接口层js_interopJSRuntime/JSContext/JSCallInfo/JSCodeCache/JSValue面向开发者的跨语言 API创建运行时、获取上下文、封装 JS 数据对象框架层cangjie_js_interop运行时管理、跨语言函数调用、类型转换、异常处理、引用管理、线程协同接口层能力的真正实现内部全部走 C 互操作调用 JSVMJSVM-APIOH_JSVM_*C 函数JavaScript 虚拟机提供的 C 接口是整条链路的地基几个关键概念对应关系JSRuntime一个 JS 虚拟机实例对应 C 层的JSVM_VM指针JSContext与运行时关联的执行上下文对应JSVM_Env指针保存全局对象模块加载、值访问都发生在它的 Scope 里JSCallInfoJS 回调仓颉方法时的调用信息用来取参数个数与参数列表JSValue跨语言通用货币任何 JS 数据在仓颉侧都用它承载再按需转成JSNumber、JSString、JSBoolean等具体类型。 napi_cffi 源码剖析C 互操作桥如何对接JSVM整个库最底层的桥梁就是 src/napi_cffi.cj 中约 100 个 C 函数的foreign声明块。它的作用可以概括为三件事1️⃣ 把 C 的不透明指针变成仓颉类型在 src/napi_cffi.cj 中JSVM_VM、JSVM_Env、JSVM_Value等类型全部被声明为指向空 C 结构的指针如type JSVM_VM CPointerJSVM_VM__。这种不透明句柄模式意味着仓颉侧完全不解析 JSVM 内部结构只传递指针、按 C ABI 约定调用函数从而天然与 JSVM 二进制兼容。2️⃣ 用C结构体精确复刻 C 的内存布局JSVM_Statussrc/napi_cffi.cj、JSVM_CreateVMOptions、JSVM_Callback等结构体加上C标注后与 C 头文件中的定义逐字段对齐。所有OH_JSVM_*函数统一返回JSVM_Status库内通过check()判断状态码非 OK 就抛出仓颉异常——这就是跨语言异常处理的入口。3️⃣ 覆盖 JSVM 的完整能力面foreign块src/napi_cffi.cj按功能分组声明了虚拟机与上下文生命周期OH_JSVM_Init→OH_JSVM_CreateVM→OH_JSVM_CreateEnv→ 打开/关闭 ScopeJS 值创建与读取OH_JSVM_CreateStringUtf8、OH_JSVM_GetValueInt64等是类型转换的基础脚本编译执行OH_JSVM_CompileScript、OH_JSVM_RunScript、OH_JSVM_CreateCodeCache代码缓存加速二次编译函数调用与回调OH_JSVM_CallFunction、OH_JSVM_CreateFunction、OH_JSVM_GetCbInfo。 跨语言函数调用的双向链路仓颉 → JavaScript调用方向源码在 src/runtime.cj 中可以看到完整流程JSRuntime.create()先执行全局OH_JSVM_Init用Once保证只初始化一次再在 libuv 线程上OH_JSVM_CreateVM创建虚拟机并打开 VM Scope随后 src/runtime.cj 的mainContext属性通过OH_JSVM_CreateEnv创建环境包装成JSContext。之后在上下文 Scope 中evaluateJS 代码、从全局对象取出 JS 函数、CallFunction调用返回值以JSValue回到仓颉侧。JavaScript → 仓颉回调方向关键在 src/function.cj 的jsFunctionCallbackStub这是一个 C 函数指针通过OH_JSVM_CreateFunction注册给 JSVM。当 JS 侧调用该函数时JSVM 反向调用这个 stub它再做四步由env反查对应的JSContext通过JSCallInfo.parseCallInfosrc/function.cj把 C 侧的JSVM_CallbackInfo解析成参数数组按lambdaId找到预先注册的仓颉闭包JSLambda并执行若仓颉侧抛异常throwExceptionToJSsrc/function.cj把它转成 JS 异常向 JS 侧传播——双向异常处理由此闭环。线程协同仓颉线程默认不绑定系统线程而 JSVM 要求操作必须发生在绑定线程上。库内部用 src/uv.cj 的UvLoop封装 libuv 事件循环JSContext在访问env前会检查当前线程src/context.cj异步任务则通过postTask投递回 JS 线程执行保证句柄安全。 快速上手3 步跑通第一次互操作创建仓颉工程在 DevEco 中选择[Cangjie] Empty Ability模板仓库可通过git clone https://gitcode.com/Cangjie/cangjie_js_interop获取源码并放入工程顶层目录添加依赖把互操作库加入cjpm.toml的依赖项如下图编写调用代码新建仓颉文件后按 doc/js_interop_user_manual.md 的示例JSRuntime.create()建运行时 →runtime.mainContext取上下文 →context.evaluate(...)加载 JS →context.global[addNumber].asFunction()取函数 →globalCall([1, 2])调用并取回结果。完整 API 细节可查阅 doc/js_interop_api_docs.md。运行效果示意按钮点击触发仓颉函数内部完成仓颉→JS 互操作调用 源码导读各模块文件分工模块文件行数职责src/napi_cffi.cj634C 互操作接口定义JSVM 类型、结构体、foreign 函数声明src/runtime.cj177JSRuntimeVM 创建、销毁、堆统计、状态码检查src/context.cj392JSContextScope 管理、异步任务、引用回收、全局对象访问src/value.cj405JSValue及 JS 基础类型Boolean/Number/String封装src/function.cj194JS 函数调用与仓颉回调 stub、跨语言异常转换src/script.cj152JSScript/JSScriptBuilder脚本编译、代码缓存src/uv.cj242libuv 事件循环封装跨语言线程协同的核心src/slab.cj185小对象内存池承载仓颉闭包与异步回调辅助模块还包括 src/string.cj、src/array.cj、src/map.cj、src/object.cj对应 JSString/JSArray/JSMap/JSObject 类型以及 src/heap.cj、src/log.cj。❓ 常见问题FAQQ1napi_cffi.cj 和 Node.js 的 N-API 是一回事吗命名上借鉴了 N-API 的设计思想C 语言函数指针 不透明句柄但对接的是 JSVM 的OH_JSVM_*C 接口不是 Node 的 N-API。Q2为什么仓颉侧拿不到 JSVM 的内部结构这是刻意为之。C空结构 指针的不透明设计让仓颉侧与 JSVM 实现完全解耦JSVM 升级时只要 C ABI 不变互操作库就无需修改。Q3目前支持哪些平台和方向当前仅支持 Linux 平台编译cjpm build --release运行时面向鸿蒙场景调用方向支持仓颉调用 JS 后 JS 回调仓颉编译配置见根目录 cjpm.toml。Q4JS 侧异常会导致仓颉崩溃吗不会。状态码检查checkAndHandleError会把挂起的 JS 异常取出并转换为仓颉Exception反方向则由throwExceptionToJS把仓颉异常包装为 JS Error两侧都有兜底。✅ 总结仓颉/cangjie_js_interop 用三层架构把跨语言调用的复杂性层层收敛napi_cffi.cj 的 C 互操作声明对接 JSVM框架层实现函数调用、类型转换、异常与引用管理接口层则只暴露JSRuntime/JSContext/JSValue等寥寥几个类。理解了这条C 指针 → CFFI → 仓颉对象的链路你就掌握了整个互操作库的骨架后续阅读任意模块源码都会事半功倍。【免费下载链接】cangjie_js_interop项目地址: https://gitcode.com/Cangjie/cangjie_js_interop创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
延伸阅读

更多相关文章

2026/9/24 17:26:40

RocketMQ怎么保证消息不丢

^^ 《榴芒客服系统》是我们工作室开发的在线客服系统,欢迎下载试用: 《榴芒客服系统》https://blog.csdn.net/look4liming/article/details/164755808 一、Producer端 1、消息发送确认机制: 同步发送会等待Broker确认消息发送成功&#xff…

2026/9/24 17:26:40

第4章 节点 Node 详解

节点是图的基本计算单元。本章讲清节点的完整输入输出契约:它能接收哪些参数(state / config / runtime)、返回值必须遵循什么规则(增量更新);再介绍两个生产级能力——节点缓存(CachePolicy&am…

2026/9/24 17:26:40

RabbitMQ和RocketMQ

^^ 《榴芒客服系统》是我们工作室开发的在线客服系统,欢迎下载试用: 《榴芒客服系统》https://blog.csdn.net/look4liming/article/details/164755808 1、开发语言: RabbitMQ是Erlang语言开发的; RocketMQ是Java语言开发的。 2、…

2026/9/24 17:26:40

RocketMQ知识点

^^ 《榴芒客服系统》是我们工作室开发的在线客服系统,欢迎下载试用: 《榴芒客服系统》https://blog.csdn.net/look4liming/article/details/164755808 RocketMQ是队列式的消息中间件。由Producer、Consumer、Broker、NameServer组成。Productor创建消息…

2026/9/23 12:07:00

GAMP 5 基于风险的计算机化系统验证:软件分类与审计追踪实践

简介:《A Risk-Based Approach to Compliant GxP Computerized Systems》即业内熟知的GAMP 5指南,面向制药企业质量与IT合规人员、验证工程师及计算机化系统管理者,用于解决GxP法规环境下系统合规性难以科学落地的问题。文档以风险管理为主线…

2026/9/23 12:06:55

安全托管MSSP实战:从静态防御到人机协同的攻防运营与应急响应

简介:这份PPT围绕互联网业务安全托管服务展开,面向企业安全负责人、IT运维人员及关注MSSP/MSS选型的读者,重点回应传统安全过度依赖人工、碎片化静态防御难以对抗产业化攻击等痛点。资源共1个pptx文件,包体约30.63MB,以…

2026/9/24 0:00:21

基于YOLOv8的渔船作业监控系统:从环境搭建到边缘部署全流程

简介:这是一套面向计算机、人工智能、自动化等专业学生与教师的毕业设计级项目资源,围绕YOLOv8实现渔船作业监控系统,可用于毕设、课程设计、大作业或项目立项演示。压缩包共97个文件,约24.21MB,以70个Python源码文件为…

2026/9/24 0:00:21

单细胞注释实战:基于Scanpy的标记基因与参考映射流程解析

简介:一份基于单细胞RNA测序数据的细胞类型注释算法研究Python毕业设计源码,针对计算机相关专业正在做毕设或需要项目实战的学习者,可用于课程设计与期末大作业。项目代码完整、经导师指导评审通过,可直接运行,覆盖数据…

2026/9/24 0:00:21

C#源生成器实战:用增量生成器替代反射,告别AOT崩溃

第一次在项目里被反射卡住,是在一个老旧的WinForms模块里:几十个类依赖PropertyChanged通知,运行时反射读属性、发通知,每次启动慢半拍不说,一上.NET Native/AOT裁剪模式几乎全面崩盘。后来我把这段逻辑全部改成C#源生…

2026/9/22 16:34:32

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/22 20:01:30

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/22 13:25:41

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
咨询二维码