语言运行时嵌入式解释器【免费下载链接】duktapeDuktape - embeddable Javascript engine with a focus on portability and compact footprint项目地址https://gitcode.com/gh_mirrors/du/duktape点击查看免费下载导读本文以 doc/symbols.rst 为骨架系统讲解 Duktape 2.x 如何将 ES2015 Symbol 与 Duktape 1.x 时代的内部键internal keys统一为一套基于duk_hstring的隐藏符号机制。你将掌握 Symbol 在 C API 中以字符串形式存在、以 ECMAScript 语义运转的双重视角理解0xFF/0x80/0x81/0x82各类内部字符串前缀的确切含义与演进历史并学会用DUK_HIDDEN_SYMBOL()等公开宏在 C 代码中安全地创建隐藏符号为嵌入场景下的私有属性、沙箱隔离与宿主扩展提供底层支撑。概述Symbol 与内部键的统一Duktape 2.x 引入了 ES2015 Symbol 支持其核心设计决策是Duktape 1.x 的内部键与 Symbol 概念统一内部键被视为一种自定义的隐藏符号hidden symbol类型——正常情况下对 ECMAScript 代码不可见但 C 代码可以通过公开 API 访问。这种统一并非表面工程。从实现层面看Symbol 的底层表示与既有内部键如出一辙Symbol 被表示为duk_hstring堆对象见 src-input/duk_hstring.h其字符串数据携带一个非法的扩展 UTF-8 字节前缀。由于该前缀在合法的扩展 UTF-8 序列中永远不会出现无论是普通 ECMAScript 字符串还是含非 BMP 码点的字符串Duktape 得以从字节层面杜绝普通字符串与 Symbol 的碰撞。此外Object(sym)得到的包装对象拥有特殊的内部类Symbol其底层 Symbol 值存储在_Value隐藏属性中与 Number 对象等包装对象的存储方式一致。表示基础双重视角下的类型体系Symbol 在 Duktape 内部与 C API 中呈现出一致的双类型描述维度取值说明外部类型C APIDUK_TYPE_STRING对 C 代码而言Symbol 就是一个字符串内部类型标签DUK_TAG_STRING值栈内部同样以字符串槽位承载区分标志DUK_HSTRING_FLAG_SYMBOL用于在内部区分普通字符串与 Symbol隐藏标志DUK_HSTRING_FLAG_HIDDEN隐藏符号额外设置此标志这些标志位定义在 src-input/duk_hstring.h#define DUK_HSTRING_FLAG_SYMBOL DUK_HEAPHDR_USER_FLAG(3) /* string is a symbol (invalid utf-8) */ #define DUK_HSTRING_FLAG_HIDDEN \ /* hidden symbol, only visible to C code */ #define DUK_HSTRING_HAS_SYMBOL(x) DUK_HEAPHDR_CHECK_FLAG_BITS((x)-hdr, DUK_HSTRING_FLAG_SYMBOL) #define DUK_HSTRING_HAS_HIDDEN(x) DUK_HEAPHDR_CHECK_FLAG_BITS((x)-hdr, DUK_HSTRING_FLAG_HIDDEN)duk_is_string()对 Symbol 返回真duk_get_string()会返回指向 Symbol 内部字符串表示即带前缀的原始字节的指针。换言之C 代码创建 Symbol 只需按特定格式推送 C 字符串无需额外的构造 API——这是整个设计的实用主义根基。行为基础C API 是字符串语义是 ECMAScript尽管 C 眼中 Symbol 是字符串Duktape 仍严格遵循 ECMAScript 的强制转换coercion语义二者并不冲突对 ECMAScript 代码的可见性Symbol 按 ES2015 及后续规范对 JS 代码可见隐藏符号则不会出现在Object.getOwnPropertySymbols()等枚举接口中只有在某种途径拿到隐藏符号字符串的引用例如通过 C 绑定时才能访问。对 C 代码的可见性Symbol 作为字符串暴露给 C APIC 代码可以用特定格式的 C 字符串直接创建 Symbol详见下文宏。强制转换语义字符串身份不等同于字符串语义。典型例子是duk_to_string()作用于 Symbol 时会抛出TypeError。这一点在 src-input/duk_js_ops.c 中可以看到痕迹当待转换字符串带有DUK_HSTRING_HAS_SYMBOL标志时错误分类会切换到DUK_STRIDX_LC_SYMBOL而同文件中DUK_STR_CANNOT_NUMBER_COERCE_SYMBOL第 211-212 行表明数值强制转换同样拒绝 Symbol。内部键格式字节前缀即语义Duktape 的扩展 UTF-8 变体中初始字节[0x00,0x7F]与[0xC0,0xFE]均被合法字符占用因此字节0xFF与区间[0x80,0xBF]被腾出来作为 Symbol 标记。下表完整列出各类内部字符串格式原样继承自文档内部字符串格式描述ff anyValue隐藏符号Duktape 特有供应用代码使用。Duktape 2.2 之前Duktape 内部隐藏符号也使用0xFF前缀后跟大写字母A-Z自 Duktape 2.2 起所有0xFF前缀字符串全部保留给应用代码80 symbolDescription全局符号描述为 symbolDescription由Symbol.for()创建81 symbolDescription ff uniqueSuffix局部符号描述为 symbolDescription。尾部唯一后缀使符号唯一后缀不透明、由 Duktape 任意挑选且在整个 Duktape 堆跨所有全局环境内唯一81 ff uniqueSuffix描述为空字符串的局部符号。唯一后缀保证每个此类符号互不相同后缀任意但不能包含0xFF字节81 ff uniqueSuffix ff描述为undefined的局部符号。ES2015 在内部区分空字符串描述与undefined 描述的符号81 symbolDescription ff描述为 symbolDescription 的 well-known 符号。well-known 符号如Symbol.iterator是跨代码 Realm共享的局部符号任何永不与运行时生成唯一局部符号冲突的固定后缀均可当前使用空后缀82 anyValue隐藏符号Duktape 特有仅供 Duktape 内部使用。用户代码不应使用此前缀也不应依赖任何 Duktape 内部隐藏符号83 to be保留给未来使用行为未定义Duktape 2.1 将其解释为 SymbolDuktape 2.2 不再如此两种行为都不可依赖bf自 Duktape 2.2 起作为字节码 dump 格式的初始字节标记00 to 7f合法的 ASCII 初始字节c0 to f7合法的标准 UTF-8或 CESU-8初始字节f8 to fe合法的扩展 UTF-8 初始字节C 语言侧的符号构造宏为了免去手工拼接\xFF等前缀公开头文件 src-input/duktape.h.in 提供了一组静态构造宏与上表逐一对齐#define DUK_HIDDEN_SYMBOL(x) (\xFF x) #define DUK_GLOBAL_SYMBOL(x) (\x80 x) #define DUK_LOCAL_SYMBOL(x,uniq) (\x81 x \xff uniq) #define DUK_WELLKNOWN_SYMBOL(x) (\x81 x \xff) #define DUK_INTERNAL_SYMBOL(x) (\x82 x)头文件注释给出了两个关键使用提示DUK_HIDDEN_SYMBOL(myProperty)等价于(\xFF myProperty)是应用隐藏符号的标准写法。局部符号带唯一后缀调用方应避免与 Duktape 内部表示冲突例如用!字符开头DUK_LOCAL_SYMBOL(myLocal, !123)。这些宏只能用于字符串常量不能用于动态创建的字符串。DUK_INTERNAL_SYMBOL()只保留给 Duktape 内部符号使用对其不提供任何版本兼容保证。全局符号无注册表的固定格式ES2015 第 19.4.2.1 节规定 GlobalSymbolRegistry 是全局可用的列表被所有代码 Realm 共享第 8.2 节则定义了 Realm 的概念内在对象集合 ECMAScript 全局环境 作用域内加载的代码及相关状态资源。Duktape 满足这些要求的做法极其简洁全局注册的符号采用固定格式因此不需要维护任何显式注册表。只要两个 Duktape 线程甚至两个独立的 Duktape 堆中以相同描述创建全局符号其内部表示80 symbolDescription就完全一致。Symbol.for(x)在任何堆、任何 Realm 下产生的内部字符串完全相同跨堆一致性由格式本身天然保证而非由运行时登记簿协调。Well-known 符号固定表示、局部本质Well-known 符号如Symbol.iterator、Symbol.toPrimitive与普通局部/全局符号都不同。ES2015 第 6.1.5.1 节指出它们是规范算法显式引用的内置 Symbol 值通常用作扩展点属性的键且除非另有说明在所有代码 Realm 间共享。Duktape 通过上文表格中的固定表示81 symbolDescription ff实现这一共享语义该表示与带唯一后缀的局部符号基本相同只是去掉了使局部符号唯一的后缀。因此 well-known 符号的静态语义是局部符号但跨 Realm、跨堆具有固定一致的表示。测试用例 tests/ecmascript/bi-symbol/test-bi-symbol-wellknown.js 验证了这一点Symbol.toPrimitive的String(s)输出为Symbol(Symbol.toPrimitive)Symbol.keyFor(s)返回undefined证明它并非全局符号与Symbol.for(Symbol.toPrimitive)也不相等。与 Duktape 内部键的统一必要的语义改动将 Symbol 行为叠加到既有内部键体系上需要散布在代码库各处的语义改造。文档列出的改动清单包括标志位初始字节为0x80、0x81、0x82或0xFF的字符串被标记为符号DUK_HSTRING_FLAG_SYMBOL初始字节为0xFF或0x82时额外设置隐藏符号标志DUK_HSTRING_FLAG_HIDDEN。见 src-input/duk_hstring.h。typeoftypeof(sym)应返回symbol而非string对 Duktape 隐藏符号同样生效。ToString 与 StringToString(sym)必须被拒绝而String(sym)必须专门检测符号强制转换需要剥去可能的唯一后缀以得到 Symbol 描述。枚举与序列化安全Symbol 不得出现在意外枚举、JSON 序列化等路径中——由于 Duktape 1.x 已排除内部键这一点本就成立属于既有设计的自然延续。Object.getOwnPropertySymbols()返回对象的符号属性列表但需过滤掉 Duktape 隐藏符号。对应测试见 tests/ecmascript/bi-symbol/test-bi-symbol-enumeration.js其中for-in、Object.keys()与Reflect.ownKeys()、Object.getOwnPropertySymbols()的输出差异被逐一断言前两者只见字符串键后两者才暴露全局/局部符号且隐藏符号0xFF前缀测试中用十六进制解码构造始终被过滤。Object(sym)创建内部类为Symbol的对象普通符号值存储在_Value隐藏符号属性下与 Number 等对象一致。非严格比较需处理符号ToPrimitive()强制转换可能足以保证sym Object(sym)成立。属性代码普通 Symbol 作为属性键时按字符串处理Symbol 对象应查找其内部字符串值而非被强制转换为如Symbol(symbolDescription)现有代码使用ToString()会引发TypeError需要针对符号特化。以及贯穿代码库的数十处类似语义检查。typeof与数值强制转换的符号分支可以在 src-input/duk_js_ops.c 与 src-input/duk_js_ops.c 中看到实现痕迹而Symbol内置对象的构造器共享逻辑位于 src-input/duk_bi_symbol.c。测试资产行为契约的落地仓库中 tests/ecmascript/bi-symbol/ 目录下聚集了 15 个专门的 Symbol 测试用例覆盖面与本文档讨论的每一处语义一一对应test-bi-symbol-creation.js、test-bi-symbol-long-description.js构造与描述长度边界test-bi-symbol-coercion.js、test-bi-symbol-misc-coercion-order.js强制转换顺序与TypeErrortest-bi-symbol-enumeration.jsfor-in/Object.keys/Reflect.ownKeys/getOwnPropertySymbols的符号可见性矩阵test-bi-symbol-json.jsJSON 序列化对符号的排除test-bi-symbol-property.js、test-bi-symbol-operator.js、test-bi-symbol-array-sort.js属性键、运算符与数组排序中的符号行为test-bi-symbol-object-valueof.jsSymbol 包装对象的valueOftest-bi-symbol-wellknown.jswell-known 符号的 Realm 间共享与非全局本质test-bi-symbol-create-many.js大量创建时的唯一性压力验证test-bi-symbol-custom.js、test-bi-symbol-misc-web.js、test-bi-symbol-misc.js混合语义与浏览器兼容性补充设计讨论C 视角与命名取舍文档最后记录了实现期间的两组设计权衡对理解 API 形态很有帮助。C 代码应如何看到 Symbol最省力的方案是Symbol 默认不被duk_enum()枚举除非显式请求——既可以与内部键合并处理也可以另设标志或许重命名既有的内部键标志属性操作对符号与内部键不加区分地工作提供从 C 代码创建符号的 API 调用将内部字符串的构造细节隐藏起来。最终公开头文件中的宏方案正是这一思路的落地构造细节被宏封装属性操作天然统一。Duktape 内部键的最佳命名随着 GH-979 相关改动的引入Duktape 内部属性将从 ECMAScript 代码彻底不可达——即使你手工构造内部字符串例如用 buffer 构造后当作对象键使用也无法触达。这为沙箱隔离提供了比 ES2015 Symbol 更强的保护因为 ES2015 Symbol 可以被枚举。围绕命名文档逐一评估了候选词候选名称评估Internal symbol易与规范中的符号概念混淆优点是更贴近internal property这一术语Hidden symbol较贴切地传达了语义在 GH-797 前提下Private symbol——Native symbol——Invisible symbol——最终 Duktape 采纳了hidden symbol隐藏符号这一命名并延续至公开宏DUK_HIDDEN_SYMBOL()。需要强调的是0xFF前缀在 Duktape 2.2 之前同时承载 Duktape 内部隐藏符号后跟大写字母区分2.2 起该前缀完整让渡给应用代码内部实现改用0x82前缀——因此在新版本中编写宿主代码时应使用DUK_HIDDEN_SYMBOL()而非手写\xFF以免与历史内部格式混淆。实战要点小结创建隐藏符号C 代码使用DUK_HIDDEN_SYMBOL(myProp)\xFF前缀2.2 起完全归属应用层可用于对象私有属性的键且天然不出现在 JS 侧的枚举与 JSON 序列化中。跨堆一致的全局符号DUK_GLOBAL_SYMBOL(desc)\x80前缀与Symbol.for()对应无需注册表即保证跨 Realm、跨堆一致。唯一局部符号DUK_LOCAL_SYMBOL(desc, !123)\x81前缀后缀由调用方保证不冲突且不含0xFF字节。well-known 符号DUK_WELLKNOWN_SYMBOL(iterator)\x81前缀 尾部\xff表示固定、跨 Realm 共享。不要触碰内部前缀0x82DUK_INTERNAL_SYMBOL仅供 Duktape 内部0x83保留且行为未定义均不可依赖。延伸阅读src-input/duktape.h.in全部符号构造宏的定义与使用注释src-input/duk_hstring.h符号标志位与检查/设置/清除宏src-input/duk_bi_symbol.cSymbol内置对象实现src-input/duk_js_ops.cwell-known 符号如Symbol.hasInstance在运算符语义中的使用tests/ecmascript/bi-symbol/15 个行为契约测试用例doc/Duktape 其他内部机制设计文档如 doc/hobject-design.rst、doc/sandboxing.rst可帮助理解隐藏符号在对象属性与沙箱场景中的定位。赞分享语言运行时嵌入式解释器【免费下载链接】duktapeDuktape - embeddable Javascript engine with a focus on portability and compact footprint项目地址https://gitcode.com/gh_mirrors/du/duktape点击查看免费下载相关推荐深入解析 mruby 的 Symbol 机制mrb_sym 内部表示、C API 与预分配优化指南深入解析 mruby 的 Symbol 机制mrb_sym 内部表示、C API 与预分配优化指南 本篇指南以仓库内 vendored mruby 源码树中的可观测性日志分析云原生流处理Karabiner-Elements 内嵌 Duktape 的 V1 兼容层duk-v1-compat迁移指南从 1.x 到 2.x 的 API 桥接实战Karabiner Elements 内嵌 Duktape 的 V1 兼容层duk v1 compat迁移指南从 1.x 到 2.x 的 API 桥接实战开发工具深入理解 MXNet Symbol API符号式编程的计算图、内存优化与实战指南深入理解 MXNet Symbol API符号式编程的计算图、内存优化与实战指南 Apache MXNet 的 mxnet.symbol Symbol AP深度学习机器学习人工智能上一篇Simple Form 5.3.0迁移注意事项官方指南下一篇Puter 文本生成视频全指南深入解析 puter.ai.txt2vid() 的参数体系、Provider 路由与错误处理创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考