Кто-нибудь может объяснить V8 байт-код LdaTheHole? - PullRequest
3 голосов
/ 25 апреля 2020

Я знаю, что байт-код V8 "LdaUndefined" загружает константу "undefined" в регистр аккумулятора. Тогда что "LdaTheHole" загружает в аккумулятор? Может быть "TheHole"? В чем смысл "TheHole"? Спасибо.

Ответы [ 2 ]

3 голосов
/ 25 апреля 2020

(разработчик V8 здесь.)

что загружает "LdaTheHole" в аккумулятор? Может быть "TheHole"?

Да.

Что означает «TheHole»?

Как правильно догадывается ответ Марка, это внутренний страж, что означает «здесь нет значения». Причина этого не в производительности (или распределении ресурсов); необходимо получить правильное поведение в некоторых ситуациях.

Для примера на основе массива рассмотрите следующий код:

var a = [1, 2, 3];           // (1)
a.__proto__ = [11, 22, 33];  // (2)
delete a[1];                 // (3)
console.log(a[1]);           // (4)

Это выведет 22, потому что a будет концептуально есть «дыра» с индексом [1], и вы можете, так сказать, «увидеть ее прототип через эту дыру». (Вы можете создать ту же ситуацию, если замените строки (1) и (3) на var a = [1, , 3].) Если a имеет прототип по умолчанию, то вместо delete a[1] вы можете написать a[1] = undefined, или вот что delete можно было бы сделать под капотом, и результат был бы таким же. Но с пользовательским прототипом есть разница: если вы напишите a[1] = undefined вместо строки (3), то строка (4) выведет undefined. Нам нужно, чтобы «дырочный» страж различал guish, является ли элемент [1] undefined или отсутствует вообще.

Есть несколько других случаев, когда проводится различие между «нет значения» и «определенный, чтобы быть« неопределенным »» полезен или необходим, например, для «временной мертвой зоны» переменных области блока. Переменные старого типа var неявно поднимают свои объявления, тогда как доступ к переменным нового стиля let до их определения является ошибкой. Правильное поведение:

var a = 1; print(a);  // 1
let b = 1; print(b);  // 1
print(c); var c = 1;  // undefined
print(d); let d = 1;  // ReferenceError: Cannot access 'd' before initialization
print(e);             // ReferenceError: e is not defined

Таким образом, оператор print (который является просто примером; то же самое верно для многих других операций) должен выполнять три разные вещи в зависимости от окружающего кода. V8 выполняет это путем внутреннего преобразования строк в:

let c = undefined; print(c); c = 1;
let d = <TheHole>; print(d); d = 1;

Таким образом, когда переменная, к которой осуществляется доступ, имеет в качестве значения «дыру», система знает, что что-то не так, поэтому в данном случае, а не загружая значение переменной и передавая ее в функцию print, он знает, что это должна быть переменная в области блока, доступ к которой осуществляется до ее определения, поэтому он выдает соответствующее сообщение об ошибке.

Если вы испытываете искушение поиграйте с этим, помните, что «дыра» - это просто внутренний страж. Он никогда не может «просочиться» до JavaScript. Из вашего кода невозможно проверить, что переменная или свойство в настоящее время имеют это значение. Это скрытая деталь реализации - движки могут делать вещи по-другому; Просто так получилось, что наличие внутреннего «дырочного» стража - достаточно элегантный и эффективный способ решения множества проблем, поэтому V8 решает сделать это таким образом.

1 голос
/ 25 апреля 2020

Я выполнил поиск Google по коду v8 / Chromium, и, похоже, TheHole - это значение часового для неназначенных значений. Во многих ситуациях в JavaScript неназначенное значение обрабатывается так, как если бы оно было undefined (например, при доступе к элементу массива, который не был назначен, или к переменной, которая была объявлена, но никогда не назначалась).

Но иногда интерпретатору необходимо проводить различие между тем, когда отсутствует значение , и когда что-то установлено на неопределенное значение. Это разница между:

var a = [1,2];
console.log(a[2]);

и

var a = [1,2,3];
delete a[2];
console.log(a[2]);

В обоих случаях доступ к [2] вернет «неопределенное», но во втором случае есть «дыра» msgstr "в конце резервного хранилища (сырой памяти) для массива, что означает, что если позже вы снова присвоите значение [2], вам не нужно будет сначала копировать значения в больший массив. Итак, TheHole - это значение, используемое для «ничего там». Вы не можете использовать undefined для этого, потому что вы можете явно установить значение элемента массива на undefined.

Где это действительно важно для таких операций, как Array.splice, или для всего, что ищет массив. Если вы существенно измените содержимое массива в строке, вам не нужно, чтобы каждая операция требовала выделения и освобождения памяти, потому что эти операции выполняются медленно.

Итак, LdaTheHole используется для инициализации переменной перед вами поиск в массиве или «очистка» удаленных значений массива.

...