Android 接入 QuickJS(二)- 源码阅读

引言

我们接入 QuickJS 引擎的目的是为了使用引擎能力,那么应该从哪里获取 QuickJS 支持那些能力呢,比较好的一个来源就是 QuickJS 源码。

相关文章

Android 接入 QuickJS(一)

源码阅读

为了对 QuickJS 引擎有稍微深入的了解,我们需要阅读源码以加深对源码的理解,并且通过源码的阅读找寻当下我们使用引擎可能会用到的 API。

目前我个人是通过几个维度来阅读和分析源码,它们分别是头文件阅读与分析 / 源码 Test Code 阅读 / 引擎核心实现源码阅读。经过这三种维度的源码阅读后会对整体的引擎代码有一个初步了解。有了这些基础后就可以粗略选择出来可能要使用的 API 接口。

头文件

由于 QuickJS 是用 C 语言写的,我们在使用的时候可以优先查看代码通过头文件暴露了那些方法。

这里我以比较重要的 quickjs.h 为例,分析 QuickJS 引擎都提供了那些能力。

从上至下阅读,首先可以看到 QuickJS 对各种 reference 的 tag 定义,如 JS_TAG_INT = 0 / JS_TAG_BOOL = 1 等。

继续往下可以看到 QuickJS 对核心结构体的定义,如 JSValue / JSValueUnion 等。

然后在这个头文件里声明了一些常用的方法,如 #define JS_VALUE_GET_TAG(v) 获取 JSValue 的 tag 等。

最后是一些方法的定义,如 JSRuntime *JS_NewRuntime(void); 产生 JSRuntime 的结构等。

有了这个整体头文件的分析,可以大致对 QuickJS 引擎有一个初步的了解。经过这一宏观的了解后就可以根据 QuickJS 源码中提供的测试代码进行阅读来进一步的熟悉 QuickJS 的架构和基本用法。

Example Code

hello.c

通过编译 QuickJS 的源码会生成一个 test 文件 hello.c 通过对这个文件的阅读,我们可以了解最典型的 QuickJS 引擎用法。

c 复制代码
int main(int argc, char **argv)
{
  JSRuntime *rt;
  JSContext *ctx;
  rt = JS_NewRuntime();
  js_std_set_worker_new_context_func(JS_NewCustomContext);
  js_std_init_handlers(rt);
  ctx = JS_NewCustomContext(rt);
  js_std_add_helpers(ctx, argc, argv);
  js_std_eval_binary(ctx, qjsc_hello, qjsc_hello_size, 0);
  js_std_loop(ctx);
  JS_FreeContext(ctx);
  JS_FreeRuntime(rt);
  return 0;
}

通过上述代码可以分析出,在使用 QuickJS 引擎时,首先要创建一个 JSRuntime 环境,然后通过这个 Runtime 去生成对应的 JSContext 后续的执行则依赖这个 JSContext 去使用。

由于 QuickJS 引擎初衷有一部分是为嵌入式设备使用,因此从 js_std_eval_binary(ctx, qjsc_hello, qjsc_hello_size, 0); 这个方法里也可以看出 QuickJS 是支持直接通过二进制字节码运行脚本代码的。

这个 hello.c 文件驱动的方法都是通过调用 quickjs-libc.h 实现的。通过研究这个文件的实现类 quickjs-libc.c 可以看到大部分的典型用法。

如 js_std_eval_binary 方法中最终是调用 JS_EvalFunction 执行输入的字节码二进制文件,在 js_std_add_helpers 方法中完成对应方法的注入等。

point.c

这个 example 主要是讲解如何自定义自己的 JS Class 以及在 JS 脚本中使用,通过自定义实现,可以在 JS 脚本中使用我们使用 C 语言定义的结构体等。

关于本 example 的使用会在接下来的文章(API 详解)中详细解析,同时也会在该文中解析各个 API 的使用场景和注意事项。

Source Code

经过上述两种方式的阅读后,可以再通过阅读真实的 QuickJS 源码加深对引擎的理解。

阅读源码时,有时候会因为源码的体积或者架构比较复杂感到无从下手,根据我个人的经验,最好的阅读方式是带着问题去阅读和学习更加快速。

现在就以 JS_EvalFunction 为例,看下 QuickJS 引擎是如何执行 Fucntion 的实例的。

阅读代码可以发现这个方法内部调用了 JS_EvalFunctionInternal 进行下一步的执行,其中多添加了一个参数是 ctx->global_obj ,在这个方法的内部首先判断这个输入的 fun_obj 是 JS_TAG_FUNCTION_BYTECODE 还是 JS_TAG_MODULE 类型,如果是 JS_TAG_FUNCTION_BYTECODE 则可以正常执行 JS_CallFree 并且拿到结果。如果是 JS_TAG_MODULE 则会首先拿到对应的 PTR 然后对这个 PTR 进行一系列的操作,最终完成这个 module 的加载。

小结

本篇文章主要从三个维度介绍了如何阅读 QuickJS 的源码,希望通过这些方式可以加深大家对 QuickJS 的了解。

接下来将根据实际代码分析如何使用 QuickJS 引擎在自己的工程中实战。

相关推荐
流星白龙22 分钟前
【C++算法】50.分治_归并_翻转对
c++·算法
q5673152323 分钟前
使用libcurl编写爬虫程序指南
开发语言·c++·爬虫
矛取矛求1 小时前
C++ STL 详解 ——list 的深度解析与实践指南
c++·list
yangshuo12811 小时前
WSA(Windows Subsystem for Android)安装LSPosed和应用教程
android·windows·模拟器·lsposed·windows安卓子系统
ab_dg_dp2 小时前
Android InstalldNativeService::getAppSize源码分析
android
杰杰批2 小时前
第十四届蓝桥杯大赛软件赛国赛C/C++研究生组
c语言·c++·蓝桥杯
aaaweiaaaaaa3 小时前
蓝桥杯c ++笔记(含算法 贪心+动态规划+dp+进制转化+便利等)
c语言·数据结构·c++·算法·贪心算法·蓝桥杯·动态规划
鸿蒙布道师3 小时前
鸿蒙NEXT开发资源工具类(ArkTs)
android·ios·华为·harmonyos·arkts·鸿蒙系统·huawei
V少年3 小时前
深入浅出安卓字节码插装
android
V少年3 小时前
深入浅出Hook
android