JavaScript引擎基础知识:常规形式和内联缓存。 第二部分

大家好! “信息系统的安全性 ”课程将在2周内开始,因此今天我们要发布本文的第二部分,该文章的发布时间恰逢其发布。 您可以在这里阅读第一部分。 因此,让我们开始吧。

内联缓存(IC)

表单背后的主要思想是内联缓存或IC的概念。 它们是快速JavaScript的关键组件! JavaScript引擎使用IC来记住有关在何处查找对象属性的信息,以减少昂贵的搜索次数。



我们有一个getX函数,该函数将一个对象作为输入并从中加载x属性:

 function getX(o) { return ox; } 

如果在JSC中运行此函数,则会得到以下字节码:



第一个get_by_id从第一个参数(arg1)加载'x'属性,并将结果存储在loc0 。 以下语句返回我们存储在loc0
JSC还将内联Cache嵌入到get_by_id ,该get_by_id由两个未初始化的插槽组成。



现在假设我们将getX{ x: 'a' }对象一起调用。 我们已经知道该对象具有'x'属性,其形状存储了属性的偏移量和属性。 首次执行该函数时, get_by_id语句get_by_id 'x'属性,发现其值存储在偏移量0处。



内置的get_by_id IC get_by_id记住找到属性的位置的形状和偏移量。



对于后续的IC启动,您只需要比较表格即可,如果与以前相同,则只需从存储的偏移量中加载值即可。 特别是,如果JavaScript引擎看到的对象具有他早先写下的形式,那么他就不再需要询问有关这些属性的信息-而是可以完全跳过对属性信息的昂贵搜索。 这比每次花时间寻找物业要快得多。

阵列的高效存储

对于数组,通常的做法是存储数组索引。 这种属性的值称为数组元素。 将数组的每个元素的属性属性存储在单独的数组中会很浪费。 相反,JavaScript引擎依赖这样的事实:默认情况下,数组中索引的属性是可写,可枚举和可配置的,并且它们还与其他命名属性分开存储数组元素。

考虑以下数组:

 const array = [ '#jsconfeu', ]; 

引擎存储单位长度的数组,并指向包含'length'属性的偏移量和属性的形状。



这类似于我们之前看到的内容...但是数组元素的值存储在哪里?



每个数组都有一个单独的元素后备存储,其中包含该数组索引的所有属性值。 JavaScript引擎不需要为数组的元素存储任何属性属性,因为它们通常是可写,可枚举和可配置的。

但是,如果它们突然变得不可配置怎么办? 如果更改数组元素的属性的属性该怎么办?

 // Please don't ever do this! const array = Object.defineProperty( [], '0', { value: 'Oh noes!!1', writable: false, enumerable: false, configurable: false, } ); 

上面的代码段定义了一个名为'0'的属性(在这种情况下,它实际上是数组的索引),它将属性值更改为非默认值。

在这种极端情况下,JavaScript引擎将元素的整个备份存储呈现为字典,该字典将数组索引映射到属性属性。



即使阵列中只有一个元素具有非默认属性,元素的备份副本的整个存储也会进入缓慢而低效的操作模式。 避免在数组索引中使用Object.defineProperty ! (我什至不知道您为什么原则上应该使用它。这看起来很奇怪而且不合理。)

结论

我们了解了JavaScript引擎如何存储对象和数组,表单和内联缓存如何帮助优化各种操作。 同样在本文中,我们想提供一些实用的JavaScript技巧,以帮助提高代码的性能:

  • 始终以相同的方式初始化对象,以使它们不具有不同的形状。
  • 不要弄乱数组元素的属性的属性,让它们有机会安全地存储和有效地工作。

现在,该文章可以认为是完整的。 根据既定的惯例,我们正在等待您的评论,并邀请您注册“信息系统安全”课程的公开网络研讨会 ,该课程将于今天由著名的病毒分析师和兼职我们的老师Alexander Kolesnikov举行

阅读第一部分。

Source: https://habr.com/ru/post/zh-CN447220/


All Articles