一个 TODO 引发的血案

Chrome 都用过吧,V8 都知道吧,V8 性能杠杠的没问题吧。但是你知道吗,有这样一段神奇的代码因为 V8 的优化导致了与实际设计预期的行为发生了相悖。

Object.defineProperty

  • Object.defineProperty([], 'length', {value: -1, configurable: true})
  • Object.defineProperty([], 'len' + 'gth', {value: -1, configurable: true})

我们可以来看一下这俩段代码,从 JavaScript 的语义上来说,这俩段代码并没有什么不同,但是当我们将他们运行在 Chrome 或者 Node.js 中,我们便能得到俩个截然不同的错误。

javascript 复制代码
Object.defineProperty([], 'length', {value: -1, configurable: true})
VM8179:1 Uncaught RangeError: Invalid array length
    at Function.defineProperty (<anonymous>)
    at <anonymous>:1:8
(anonymous) @ VM8179:1

Object.defineProperty([], 'len' + 'gth', {value: -1, configurable: true})
VM8183:2 Uncaught TypeError: Cannot redefine property: length
    at Function.defineProperty (<anonymous>)
    at <anonymous>:2:8

为什么呢?

那这和 V8 性能优化极好又有什么关系呢?我们可以在他们的源码中看到如下内容:

github.com/v8/v8/blob/...

cpp 复制代码
  if (*name == ReadOnlyRoots(isolate).length_string()) {
    // 2a. Return ArraySetLength(A, Desc).
    return ArraySetLength(isolate, o, desc, should_throw);
  }

简单理解一下,就是在这里直接使用了引用与系统内的常量字符串 "length" 引用进行了一个 O(1) 的快速匹配,从而优化了性能,但是也导致了我们上面的错误。

那么为什么 'length''len' + 'gth' 有区别呢?这个没有优化吗?我们可以在这《Exploring V8's strings: implementation and optimizations》看到实际上在 V8 中存在着不同的字符串,当我们使用 %DebugPrint 对俩段内容进行输出的时候,我们可以发现:

  • %DebugPrint('leng'+'th'):ONE_BYTE_STRING_TYPE
  • %DebugPrint('length'):ONE_BYTE_INTERNALIZED_STRING_TYPE

这也是为什么后者没办法作为一个常量字符串和全局只读常量字符串 "length" 进行比较的原因。

标题党!

你可能会问,你说的我都看懂了,但是和 TODO 又有什么关系呢?经常写代码都知道,我们不想处理的问题,都是先 TODO NEVER DO ,其实我们刚刚的代码上面看到一段东西:

github.com/v8/v8/blob/...

arduino 复制代码
  // TODO(jkummerow): Check if we need slow string comparison.

是不是很有趣呢 V8,哈哈哈哈,希望看完这些你能对 JS 一些底层的内容产生兴趣。

后续进展

在去年年底的时候,我与 TC39 的成员 Jack Works 讨论了这个问题,最后得到了一个结论,在 ECMAScript 的设计上来看,这确实是 V8 的一个问题(虽然它是为了优化性能),但是 TC39 也没有料到 V8 的优化这么细节,居然导致了上面的问题。所以在那段时间,他们对于该行为进行了约束,并且在 TC39 的标准中加入了该检测。

github.com/tc39/test26...

当时我在 v8 bugs 中也反映了该问题,他们在最近也对这个问题进行了修复。

bugs.chromium.org/p/v8/issues...

总结

挺开心的,有一种建设世界的快乐了。

相关推荐
wordbaby3 分钟前
搞不懂 px、dpi 和 dp?看这一篇就够了:图解 RN 屏幕适配逻辑
前端
程序员爱钓鱼5 分钟前
使用 Node.js 批量导入多语言标签到 Strapi
前端·node.js·trae
鱼樱前端6 分钟前
uni-app开发app之前提须知(IOS/安卓)
前端·uni-app
V***u4537 分钟前
【学术会议论文投稿】Spring Boot实战:零基础打造你的Web应用新纪元
前端·spring boot·后端
TechMasterPlus7 分钟前
VScode如何调试javascript文件
javascript·ide·vscode
i听风逝夜1 小时前
Web 3D地球实时统计访问来源
前端·后端
iMonster1 小时前
React 组件的组合模式之道 (Composition Pattern)
前端
呐呐呐呐呢1 小时前
antd渐变色边框按钮
前端
元直数字电路验证1 小时前
Jakarta EE Web 聊天室技术梳理
前端
wadesir1 小时前
Nginx配置文件CPU优化(从零开始提升Web服务器性能)
服务器·前端·nginx