Web Replay — это проект, позволяющий процессам содержимого Firefox записывать свое поведение, воспроизводить его позже и перематывать в предыдущие состояния. Процессы воспроизведения сохраняют все то же поведение JS, структуры DOM, графические обновления и большинство других действий, которые произошли во время записи. Отладчик JS браузера можно использовать для проверки и контроля воспроизведения. В настоящее время поддерживается только macOS.
Работа продолжается на https://hg.mozilla.org/projects/ash и отслеживается в баг 1207696 и его блокировщиках.
Сборка доступна для тестирования! Вещи все еще пред-альфа, но нам бы хотелось услышать обратную связь в #rr на слабине или сообщить о проблеме с любыми проблемами.
Чтобы загрузить сборку, перейдите на страницу https://treeherder.mozilla.org/#/jobs?repo=ash, выберите зеленый 'B' рядом с ' OS X Cross Compiled opt 'в последнем запуске и скачать артефакт target.dmg.
Содержание статьи
Архитектура
В проект входит несколько основных компонентов:
- Инфраструктура записи / воспроизведения записывает достаточную информацию во время записи, чтобы воспроизведенный процесс мог работать и воспроизводить те же наблюдаемые виды поведения.
- IPC-интеграция позволяет процессу воспроизведения взаимодействовать с процессом chrome с использованием IPDL и разделяемой памяти.
- Инфраструктура перемотки позволяет процессу воспроизведения восстанавливать предыдущее состояние, сохраняя при этом связь с процессом хрома.
- Интеграция отладчика позволяет отладчику JS считывать нужную информацию из процесса воспроизведения и контролировать выполнение процесса (возобновить / перематывать). Отладчику не разрешено изменять наблюдаемое состояние процесса воспроизведения.
Инфраструктура записи / воспроизведения
В целом, надежная запись / воспроизведение достигается путем контроля за недетерминизмом в браузере. Этот детерминизм исходит из двух источников: внутрипоточных и межпоточных. Внутрипоточные недетерминированные поведения не являются детерминированными даже при отсутствии действий другими потоками, а неинтерминированное поведение между потоками — это те, которые влияют на выполнение чередования с другими потоками и которые всегда ведут себя одинаково при одинаковом чередовании.
Внутрипоточный недетерминизм записывается и затем воспроизводится для каждого потока. Эти поведения в основном происходят из системных вызовов (i / o и таких).
Неинтерминированность между потоками обрабатывается, если предположить, что программа — это гонка данных: доступ к общей памяти, который в противном случае был бы расой, либо защищен блокировками, либо использует API, которые выполняют атомарные операции. Если мы записываем и позже воспроизводим порядок, в котором потоки приобретают блокировки (и, в дополнение, блокируют блокировку и используют condvars), тогда обращения в защищенной от блокировки памяти будут выполняться в том же порядке. Атомные переменные могут обрабатываться обработкой чтения и записи, как если бы они были обернуты захватом / выпуском блокировки во время записи.
Однако недостаточно просто записывать все эти недетерминированные источники и воспроизводить эти поведения точно в процессе воспроизведения. Компоненты интеграции IPC и отладчика могут вести себя по-разному между записью и воспроизведением или между различными повторами. Оба они включают в себя связь между потоками и вызовы для не детерминированных API, и в результате процесса репликации должен быть разрешен результирующий недетерминизм.
Допустимый детерминизм
В этом дизайне есть некоторая отслойка: процесс воспроизведения должен быть недостаточно детерминированным, чтобы работать с компонентами IPC и отладчика, но не так детерминированны, что подвержены наблюдаемым поведением. Мы разрешаем эту отставку, сводя к минимуму допустимый не-детерминизм: процесс воспроизведения должен быть просто недостаточно детерминированным, чтобы работали компоненты IPC и отладчика. На практике не детерминированное воспроизведение разрешено в следующих областях:
- Распределение кучи может выполняться компонентами IPC и отладчика и поэтому может отличаться между записью и воспроизведением.
- JS-компиляции и другое внутреннее состояние зависят от присутствия отладчика и какие крючки / точки останова являются активными и поэтому могут отличаться между записью и воспроизведением.
- Отладчик может выделять вещи GC, а распределение других объектов GC может отличаться в присутствии отладчика. Например, компиляция скриптов включает выделение объектов GC, а наблюдение за изменениями в объекте изменит его форму.
. Расслабляющий недетерминизм здесь имеет ряд волновых эффектов в других областях. В основном, значения указателя могут различаться между записью и воспроизведением, а также точки, в которых происходят GC, и набор собранных объектов могут отличаться. Этот недетерминизм не может слишком распространяться со следующими методами:
- Различные значения указателя могут влиять на внутреннюю компоновку хэш-таблиц. Чтобы это не повлияло на порядок итерации (и поведение выполнения) в таблице, основные классы таблицы (на данный момент PLHashTable и PLDHashTable) используются так, чтобы они всегда перебирали элементы в том порядке, в котором они были добавлены при записи или воспроизведении.
- Различие в поведении GC может привести к тому, что финализаторы объектов будут выполняться в разное время. Чтобы это не повлияло на поведение выполнения, GC-финализаторы, которые могут повлиять на запись, настраиваются так, что действие финализатора выполняется одновременно с воспроизведением, как это было во время записи. Даже если связанный объект JS еще не был уничтожен во время повтора, он больше никогда не будет использоваться, потому что на этом этапе записи он был завершен.
- Аналогично, поведение GC может привести к тому, что значения, считанные из слабых указателей, будут отличаться между записью и воспроизведением. Если это отличие может повлиять на запись, слабый указатель должен быть инструментальным, чтобы во время воспроизведения он удерживался на своей цели в течение той же продолжительности, что и во время записи.
Запись
Процесс записи контента отличается от обычного процесса содержимого следующими способами:
- Звонки на определенные функции перехватываются путем их перехвата (переписывание машинного кода в их точках входа для вызова другой функции с той же сигнатурой), включая функцию, используемую для отправки сообщений mach. Когда вызов или сообщение перехватывается, обернутый вызов / сообщение сначала выполняется нормально, а затем он и его выходы записываются в поток данных для потока, выполняющего вызов. Во время выполнения обернутого вызова / сообщения запись любых внутренних вызовов подавляется, так что они выполняются нормально, не затрагивая запись. Перехваченные функции обычно находятся на системном вызове и уровне системной библиотеки. В общем, любая функция, которая не компилируется как часть Gecko, является честной игрой.
- Порядок регистрации блокировок записывается в поток данных для каждой блокировки. Некоторые блокировки, связанные с недетерминированными компонентами, не регистрируются, например, блокировка JS GC и вспомогательных потоков.
- Доступ к атомным переменным / полям записывается в глобальном потоке данных, как если бы они были защищены глобальной блокировкой. Некоторые атомы связаны с недетерминированными компонентами и исключены из этого потока.
- В потоках используются файловые дескрипторы, которые ждут блокировок и уведомляют друг друга, вместо использования встроенной реализации для блокировки и переменных условий. По крайней мере, на Mac, pthreads locks / cvars, похоже, используют сочетание локального состояния и состояния ядра, а иногда не работают корректно после перемотки процесса.
- Некоторые изменения поведения изменяются для упрощения записи, таким образом, чтобы они не влияли на наблюдаемое поведение. Например, инкрементные GC (недетерминированный компонент) работают, проводя события в основной поток (детерминированный компонент), поэтому на данный момент инкрементные GC отключены. Многие из этих поведенческих изменений в конечном итоге должны быть удалены.
- Графический рендеринг полностью локален для процесса содержимого. Вместо того, чтобы передавать через IPC с помощью Compositor в процессе пользовательского интерфейса, есть композитор в самом процессе записи, который выполняет рендеринг.
- Некоторые дополнительные приборы выполняются в разделе «Разрешенный недетерминизм» выше.
- Компоненты IPC, перемотки и отладки все активны во время записи. Они порождают ряд потоков, которые не участвуют в записи: любые события, которые они выполняют, являются живыми. Подробнее о том, как это влияет на поведение процесса, можно найти в следующих разделах.
Чтобы упростить обеспечение того, чтобы недетерминированные компоненты не влияли на записанное поведение, определенные области кода могут быть помечены как запрещающие события — при выполнении им никаких потоков, блокировок или атомных событий должны быть записаны. Это делается в коде, связанном с недетерминированными компонентами, например, во время компиляции GC или Ion, чтобы помочь отслеживать поведение, которое должно остаться незаписанным.
Воспроизведение
Процесс воспроизведения в режиме воспроизведения ведет себя так же, как и процесс записи, за исключением следующего:
- Здесь также перехватываются вызовы и сообщения mach, которые были перехвачены во время записи. Когда вызов / сообщение перехватывается, завершенный вызов / сообщение выполняется а не но результаты вызова / сообщения считываются из потока данных и возвращаются вызывающему абоненту, эмулируя поведение вызова /сообщение. Это требует, чтобы процесс был достаточно детерминированным, чтобы события воспроизводились в одном порядке в каждом потоке между записью и воспроизведением. В потоке данных должно быть достаточно проверки на наличие ошибок, чтобы мы могли сразу обнаружить, что воспроизведение не синхронизировалось с записью.
- Записанные потоки данных, которые определяют порядок сбора для каждой блокировки, считываются и используются для того, чтобы блокировки были получены в том же порядке. Когда нить пытается получить блокировку, она сначала ждет, пока она не окажется в очереди.
- Аналогичным образом, атомарные обращения, которые были включены в запись, будут происходить в том же порядке во время воспроизведения, как если бы все они были защищены одной глобальной блокировкой. Обратите внимание, что, хотя это может потенциально сильно повлиять на производительность во время воспроизведения и записи, многие из самых горячих атомов (refcounts, GC counters и т. Д.) Связаны с недетерминированными компонентами и не записываются.
IPC-интеграция
Связь между процессом хрома и процессом записи или воспроизведения — далее именуемым дочерним процессом — управляется через отдельный процесс содержимого посредника. Детский процесс расширен, чтобы он мог общаться с посредником, используя специальный двунаправленный канал и сообщения, отдельно от состояния IPDL.
Миддман-процесс
Средний посредник — это то же самое, что и обычный процесс содержимого, за исключением того, что он порождает и общается с дочерним процессом и избегает создания каких-либо документов. Использование посредника дает следующие преимущества:
- Связь IPDL значительно упрощена. Процессы chrome и middleman взаимодействуют с использованием стандартных протоколов браузера (PContent, PBrowser и т. Д.) И реализаций для своих участников, в то время как посреднические и дочерние процессы взаимодействуют со своим собственным каналом и сообщениями, которые настроены на требования записи / воспроизведения процесс.
- Средство может выполнять действия, которые чрезвычайно сложно управлять в процессе воспроизведения, не выходя из синхронизации с записью. В основном это включает в себя выполнение скриптов на стороне контента devtools.
- Процесс записи может быть перенесен в процесс воспроизведения, не затрагивая процесс пользовательского интерфейса. Во время записи сообщения IPDL из процесса пользовательского интерфейса перенаправляются посредником в процесс записи (с некоторыми графическими сообщениями, обрабатываемыми непосредственно посредником). После того, как процесс начнет воспроизведение, новые входящие сообщения из процесса пользовательского интерфейса игнорируются.
Расширения процесса записи / воспроизведения
Во время инициализации дочерний процесс порождает поток, который не участвует в записи — любые IPC или другие вызовы системы, которые он выполняет, являются живыми, даже при повторном воспроизведении. Этот поток отправляет и получает сообщения от посредника.
Сообщения описывают действия, которые дочерний процесс способен делать независимо от записи; в настоящее время это включает в себя отправку графических обновлений, получение и восстановление моментальных снимков процесса и ответ на запросы отладчика.
Переоборудование инфраструктуры
Детский процесс может быть перемотан в более раннее состояние в ответ на сообщение от посредника. После того, как процесс записи перемотается, он становится процессом повторного воспроизведения. Перемотка происходит, периодически беря снимки памяти во время выполнения, а затем восстанавливая их. Необходимо проявлять осторожность при принятии / восстановлении снимков и управлении системными ресурсами при восстановлении.
Снимки
В конце инициализации процесса выполняется первый снимок, который является просто копией стеков / регистров для каждого потока. Каждый последующий снимок включает копии стеков / регистров потоков, а также diff, содержащий исходное содержимое всех страниц кучи и статической памяти, которые были изменены с момента предыдущего снимка. Определенные области памяти исключаются из моментальных снимков; эти области памяти выделены специальным API и используются для состояния, которое необходимо сохранить при перемотке. Данные моментальных снимков могут храниться в памяти или на диске. Диффы вычисляются путем первой настройки потока обработчика исключений (только для mac), очень похожего на тот, который используется asm.js. При первом снимке вся адресная память в процессе перечисляется и защищена от записи, а при возникновении сбоев специальный поток обработчика исключений защищает память, копирует ее содержимое и маркирует ее как грязную. Когда выполняется следующий снимок, проверяется только грязная память для любых изменений и сделанных копий.
Этот механизм требует перехвата mmap (или аналогичных функций распределения низкого уровня), так что любая вновь адресуемая память известна — анонимные сопоставления в противном случае не были бы перехвачены или включены в запись, так как распределение кучи не является детерминированным во время повторного воспроизведения. mprotect перехватывается и nop'ed во избежание вмешательства в грязный механизм памяти, и munmap перехватывается без фактического снятия с карты, так что память не нуждается в переназначении при восстановлении моментального снимка (поддерживается набор свободных областей, чтобы повторное использование эта память).
Все снимки берутся из основного потока. Перед выполнением моментального снимка все потоки, участвующие в записи, должны войти в состояние ожидания, ожидая переменную условия конкретного потока. Нити входят в это состояние, когда они ждут, чтобы получить блокировку или выполнить атомное действие, которое является частью записи. Во время записи потоки могут блокировать вызовы в библиотеках (например, kevent). Чтобы разрешить эти потоки, вызов выполняется вместо отдельного потока, который не участвует в записи, так что вызывающий поток может входить в правильное состояние бездействия, даже когда его выполнение блокируется при завершении вызова. После того как весь поток простаивает, основной поток вычисляет разницу в памяти, считывает стеки из каждого потока и их состояния регистра (каждый из которых записывается путем вызова setjmp перед холостым ходом).
Восстановление снимков также выполняется из основного потока. Что касается моментального снимка, все остальные потоки входят в незанятое состояние. Информация о грязной памяти, вычисленная с момента последнего моментального снимка, была использована для восстановления кучи состояния в последнем снимке, а затем разности памяти можно использовать для восстановления более раннего моментального снимка, если это необходимо. Нитки индивидуально отвечают за восстановление своих стеков; когда они просыпаются из состояния ожидания, они видят, что основной поток подготовил новый стек для восстановления, поэтому они longjmp в новое состояние регистра и копируют в содержимое нового стека.
Управление системными ресурсами
Когда дочерний процесс восстанавливает моментальный снимок, состояние всех доступных ему ресурсов системы не изменяется. Необходимо следить за тем, чтобы эти ресурсы были согласованы с процессом после завершения восстановления. Это делается следующим образом:
- Вместо создания или уничтожения потоков по требованию при записи / воспроизведении всех потоков, которые понадобятся, создаются во время инициализации процесса. Если во время записи контент пытается создать больше потоков, чем был создан, то запись не удалась. Эти потоки простаивают до тех пор, пока контент записи / воспроизведения не попытается «создать» их, тогда они запустит свою основную функцию, и после ее завершения простаивает бесконечно. Это гарантирует, что независимо от того, когда мы создадим или восстановим моментальный снимок, будет существовать один и тот же набор потоков и будет иметь согласованные расположения стеков.
- Переменные замков и условий в какой-то мере являются системными ресурсами, и чтобы избежать проблем, мы гарантируем, что каждый поток ожидает согласованной переменной при сохранении или восстановлении моментального снимка (см. Раздел выше).
- IPC-интеграция использует файловый дескриптор для общения с посредником. Это остается в покое при восстановлении моментального снимка, поэтому при сохранении или восстановлении моментального снимка они должны быть в согласованном состоянии для дочернего процесса. Ограничения используются, когда сообщения могут быть отправлены между посредником и дочерним процессом, гарантируя, что процесс посредника не может отправить сообщение в то время, когда дочерний процесс может перематываться.
Интеграция отладчика
При отладке процесса нормального контента отладчик devtools JS запускает довольно много JS-кода в процессе содержимого, обмениваясь с процессом chrome, главным образом, через потоки данных JSON. При отладке процесса дочернего контента этот JS-код запускается в процессе посредника. Когда код создает объект Debugger, этот отладчик предоставляет информацию о дочернем процессе, а не текущий (посредник) процесс. Хотя отладчик может указать, что он предназначен для дочернего процесса, интерфейс должен быть максимально прозрачным для JS-кода devtools; Debugger все еще может создавать скрипт / объект / etc. объекты отладки, которые относятся к конкретным вещам в дочернем процессе.
Как и в коде JS devtools, этот отладчик живет в процессе посредника, и вместо того, чтобы обертывать вещи из другого отсека, объекты отладки содержат структуры кучи с информацией о какой-то вещи в дочернем процессе. Отладчик может исследовать кучу, отправив сообщения дочернему процессу, чтобы заполнить содержимое создаваемых им объектов отладки. Всякий раз, когда отладчик взаимодействует с дочерним процессом, дочерний процесс приостанавливается в какой-то момент выполнения, а содержимое объектов отладки действует только до тех пор, пока посредник не уведомит дочерний процесс о том, что он может возобновить выполнение в прямом порядке или должен перемотать предыдущий снимок , Когда дочерний процесс снова приостанавливается (например, в точке останова), объекты отладки должны быть восстановлены.
Существует исключение для сценариев и исходных объектов скрипта; объекты отладки для них будут продолжать удерживать один и тот же референт после возобновления или перемотки процесса повторного воспроизведения. Это необходимо для работы контрольных точек сценария и выполняется путем обеспечения того, чтобы упорядочение создания сценариев и источников сценариев было детерминированным (в основном, путем отключения анализа потоков, что является одним из изменений поведения во время записи / воспроизведения).
Интерфейс пользователя для devtools для дочернего процесса такой же, как для обычного процесса содержимого, за исключением того, что добавлены новые кнопки пользовательского интерфейса для перемотки (найти последний раз, когда была достигнута точка останова), и для обратного шага / в / шаг-аут. Пока что только JS-состояние может быть проверено отладчиком, хотя его расширение для проверки DOM и других функций devtools не должно быть слишком сложным.
Неудачные казни
Существуют ограничения на казни, которые можно записать. Все это должно быть обнаружено во время записи, поэтому мы не пытаемся воспроизвести выполнение, которое, как мы знаем, не совпадают с записью. Следующие казни выполняются в основные пределы подхода и не могут быть воспроизведены:
- Исполнения, которые исключают излишние исключения JS, не могут быть надежно воспроизведены; overrecursion происходит в разное время в зависимости от того, как скомпилированы скрипты, которые могут различаться между записью и воспроизведением.
- Аналогичным образом, исполнение, которое в какой-то момент не исчерпывается, невозможно надежно воспроизвести.
- Исполнения, которые в какой-то момент остановлены медленным диалогом сценариев, не могут быть надежно воспроизведены. Отслеживание точной точки, в которой произошло прерывание, потребует довольно много накладных расходов на запись, и, похоже, не стоит пытаться это сделать.
Следующие версии вряд ли будут поддерживаться начальным выпуском, но в будущем они могут быть обработаны:
- В x64 код asm.js полагается на mprotect для обработки отказов по кустам; mprotect работает по-разному во время повторного воспроизведения, поэтому потребуется некоторое сотрудничество между обработчиком исключений asm.js и обработчиком исключений грязной памяти.
- Буферы с общим массивом могут использоваться веб-контентом для внедрения расчётов данных в браузер по содержимому этих буферов, что противоречит фундаментальному предположению об инфраструктуре записи / воспроизведения. Для выполнения записи и повторного воспроизведения с использованием этих буферов потребуются новые методы, такие как обработка всех запросов на буферах как атомных (возможно, неприемлемых служебных данных) или выполнение всех запросов в буфере на одном ядре и отслеживание контекстных переключателей.
- Работники DOM еще не поддержаны. Для простоты интеграция отладчика в настоящее время способна обрабатывать JS-код, который работает в основном потоке.
- WebGL еще не поддерживается, так как он использует довольно отличный путь от обычного веб-контента.
- Элементы мультимедиа еще не поддерживаются, так как многие из них запускают сторонний многопоточный код, который не был протестирован с инфраструктурой.
Переносимость
Практически вся работа по внедрению была на macOS. Работа с портами Windows продолжается, но пока не работает. Трудности заключаются в том, чтобы вычислить набор API-интерфейсов системной системы для перехвата, получения информации об управлении памятью и грязной памятью инфраструктуры перемотки, а также обработки различных графических и IP-троек на разных платформах.
Сравнение с другими проектами
В этой области много работы. Ближайшими проектами являются rr, проект воспроизведения WebKit и отладчик Time-Travel от Microsoft. По сравнению с rr:
- Это должно работать на всех платформах и архитектурах, поддерживаемых Gecko, хотя при этом требуется значительная работа с портами
- Это будет частью самого Gecko, а не отдельным инструментом, что означает, что разработчикам не потребуется дополнительное программное обеспечение для его использования, и что это невозможно использовать для отладки другого программного обеспечения.
- Он может использовать несколько ядер во время записи и воспроизведения.
- Это не сохраняет точное поведение. Контекстные коммутаторы могут возникать в разное время, а расписания данных могут приводить к различному поведению между записью и воспроизведением. Однако расы данных являются ошибками сами по себе, поэтому такой тип недетерминированности следует фиксировать независимо.
- Эта конструкция позволяет процессу воспроизведения вести себя иначе, чем процесс записи, что позволяет довольно просто реализовать интеграцию IPC и Debugger.
Проекты воспроизведения Microsoft и WebKit работают на более высоком уровне, чем rr. Входы в браузер и недетерминированное поведение записываются так, чтобы их можно было воспроизвести позже. В проекте Microsoft уровень абстракции, по-видимому, является границей между движком JS и остальной частью браузера, тогда как в проекте WebKit этот слой, по-видимому, находится во внутренних API WebKit, что может привести к запуску JS или изменению кода JS.
В целом, все эти проекты работают по спектру: на каком уровне находится граница между компонентами, поведение которых записано и остальная часть системы? rr записывает все поведение в пользовательском пространстве процесса; граница — это системные вызовы, которые производятся в ядре. Этот проект записывает все поведение за пределами вызовов системных библиотек, которые выполняются процессом, с исключениями, вырезанными для разрешенного недетерминированности и для целей ничьей. Проекты Microsoft и WebKit записывают меньший подмножество поведения браузера.
Этот проект находится в хорошей точке на этом спектре. По сравнению с проектом более высокого уровня, он может работать на стабильных, полностью документированных библиотечных API. Сосредоточив внимание на перехвате этих API-интерфейсов, аппаратные средства браузера, накладные расходы на запись и расходы на техническое обслуживание в будущем будут сведены к минимуму. По сравнению с проектом более низкого уровня, это способно переносить больше недетерминированности. Весь код, чье поведение записано, скомпилируется в Gecko (а не является частью неизменяемых, обычно закрытых исходных библиотек) и может быть слегка изменен для обработки поведения, которое функция перехвата не может обрабатываться, например, изменение схем таблиц хеш-таблиц и упорядочение атомных доступ.
Приложение: Подробности отладчика
Вот еще более подробная информация о том, как процесс записи / воспроизведения влияет на отладчик, и варианты будущих улучшений.
Изменения отладчика
С точки зрения сервера devtools отладка процесса записи / воспроизведения очень похожа на отладку живого процесса. Когда выполнение приостанавливается, объект JS Debugger и его различные дочерние объекты могут использоваться для проверки состояния выполнения таким же образом для любого вида процесса. Вот основные отличия:
- Явные команды должны быть отправлены в отладчик для управления исполнением. Члены replayResumeBackward () и replayResumeForward () могут быть вызваны для возобновления выполнения, и член replayPause () может быть вызван для приостановки выполнения при следующей возможности. Детский процесс может останавливаться только на контрольных точках и в точках моментального снимка (в настоящее время это происходит только при выполнении графических обновлений, после чего в стеке нет JS).
- Существует новый обработчик onPopFrame, который необходим при выполнении операций обратного шага.
- Операции над debuggee, которые требуют взаимодействия с системой, потерпят неудачу. Этими операциями могут быть доступ к ресурсам, evals или вызовы объектов, а пример — это свойство «font» CanvasRenderingContext2D. В случае неудачных операций в настоящее время просто создается результат заполнения «НЕПОЛНЫЙ».
- Следует избегать операций над debuggee, которые имеют побочные эффекты — eval ("x.f = 3") —. Когда процесс возобновится вперед или назад, эти побочные эффекты будут потеряны (процесс вернется в исходное состояние), и при паузе в точке останова эти эффекты могут вызвать какое-то странное поведение — после вышеупомянутого eval получение свойства xf напрямую может привести к другое значение от eval ("xf"). Хотя странное поведение может быть исправлено (это связано с кэшированием), было бы неплохо предотвратить или по крайней мере отбить у пользователей возможность выполнять такие эффективные операции.
- Основной объект объекта Debugger.Object недоступен; object.unsafeDereference равно null.
- Как описано выше в разделе «Интеграция отладчика», дочерние объекты, кроме сценариев и источников сценариев, становятся недействительными, когда отладчик возобновляет выполнение и должен быть реконструирован каждый раз, когда процесс воспроизведения приостанавливается.
Проверка процесса воспроизведения
Доступ к объектам JS в процессе воспроизведения в настоящее время осуществляется только через интерфейс отладчика JS — Debugger.Object, Debugger.Frame.eval и т. Д. Кажется, это хорошо для панели debugger devtools (кроме небезопасной вещи выше), но я не знаю, насколько это полезно для других панелей devtools. Можно было бы получить доступ к объектам в процессе воспроизведения более непосредственно, предоставив прокси-серверы отладчика, чьи обращения перенаправлены на их обернутый объект в процессе воспроизведения. Некоторые из тех же предостережений применимы как к отладчику: доступ к прокси-серверам, для которых требуется взаимодействие с системой, не удастся, а прокси-сервер станет недействительным, когда процесс повторного воспроизведения возобновит выполнение.