一个 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...

总结

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

相关推荐
java1234_小锋43 分钟前
【技术专题】HTML5 网页技术 - HTML5 Canvas 基础以及动画入门
前端·html·html5
知了学历孙老师4 小时前
小自考的校考和统考,出题方和难度差在哪
java·大数据·前端
ShineWinsu6 小时前
对于JavaScript:操作元素的解析
开发语言·前端·javascript·面试·web·dom·元素
福兮说6 小时前
JSON 格式正确,数据就可靠吗?我用一份自编配置检查类型与空值
java·前端·json
程序员老赵8 小时前
Docker 部署青龙面板:轻松搭建定时任务管理平台
前端·docker·开源
Swot8 小时前
Asciidoctor 公式数字下标错位问题:原因分析与解决方案
前端
Swot8 小时前
leo-editor 中将 Markdown 内容转成 asciidoc 格式
前端
狒狒AI8 小时前
Remotion / GSAP+Three / HyperFrames / Skia 四栈实测:代码渲染知识视频的选栈方法(附开源技能)
前端·人工智能·aigc
修炼的dance8 小时前
浏览器里导出H.265,8.5秒和55.5秒差在硬件
前端
补码缩写8 小时前
WebCodecs选编码器,探测之后还要验解码和播放
前端