Проверка и манипулирование стеклом Java-вызовов

Мой вопрос: возможно ли (в любом случае) анализировать и модифицировать стек вызовов (как содержимое фреймов, так и содержимое стека) во время выполнения?

Я ищу любую возможность - низкоуровневый, небезопасный или внутренний API, возможность писать расширение C и т.д. Единственное ограничение: оно должно использоваться в стандартной среде исполнения без режима отладки или профилирования. Это тот момент, когда я занимаюсь исследованиями "возможно ли это вообще?", А не "это хорошая идея?".

Я хотел бы собрать все локальные данные из фрейма, сохранить его где-нибудь, а затем удалить этот фрейм из стека с возможностью его восстановления позже. Эффективно, что дает нам продолжение в JVM, и они позволят быстро создавать асинхронные рамки (например, gevents from python) и конструкторы генератора (например, из python).

Это может выглядеть как повторяющийся вопрос, но я нашел ответы на вопросы "use Thread.currentThread().getStackTrace()" или "это должно быть сделано с помощью инструментов отладки". Был похожий вопрос на мой, но на него ответили только в контексте того, что хотел сделать парень (работа над асинхронными вычислениями), в то время как мне нужно более общее (java- стек предназначенный) ответ. Этот вопрос тоже похож, но, как и прежде, он ориентирован на параллелизацию, и ответы тоже сосредоточены на этом.

Повторяю: это шаг исследования в процессе разработки нового предложения по языковым функциям. Я не хочу рисковать чем-то в JVM - я ищу возможность, тогда я проанализирую возможные риски и буду искать их. Я знаю, что манипулирование стеком вручную является уродливым, но также создает экземпляры с омминг-контр-устройством - и это основа для объекенизации. Грязные хаки могут быть грязными, но они могут помочь привнести что-то классное.

PS. Я знаю, что Quasar и Lightwolf существуют, но, как и выше, это concurrency -фокусированные рамки.

ИЗМЕНИТЬ

Небольшое пояснение: я ищу что-то, что будет совместимо с будущими версиями JVM и библиотек. Предпочтительно мы говорим о чем-то, что считается стабильным публичным API, но если решение лежит во внутреннем, но почти стандартном или становится стандартным после внутреннего (например, sun.misc.Unsafe) - это тоже будет сделано. Если это возможно с помощью C-расширения, используя только C JVM API - это нормально. Если это возможно при манипулировании байт-кодами - это тоже нормально (я думаю, что МОЖЕТ быть возможным с ASM).

Ответы

Ответ 1

Я думаю, что есть способ достичь того, что вы хотите использовать JVMTI.

Хотя вы не можете напрямую делать то, что хотите (как указано в комментарии выше), вы можете изменить/переопределить методы (или целые классы) во время выполнения. Таким образом, вы можете просто определить каждый метод для вызова другого метода непосредственно для "восстановления контекста выполнения", и как только у вас есть нужный стек, переопределите их с помощью исходного кода.

Например: скажем, вы хотите восстановить стек, где только A, называемое B и B, называется C. Когда A загружен, измените код, чтобы напрямую вызвать B. Как только B загрузится, переопределите его для прямого вызова C; Вызовите самый верхний метод (A); Как только C будет вызван (который должен быть очень быстрым сейчас), переопределите A и B к их исходному коду.

Если задействованы несколько потоков и значения параметров, которые необходимо восстановить, он становится немного сложнее, но все же возможен с JVMTI. Однако тогда это стоило бы другого вопроса;-).

Надеюсь это поможет. Не стесняйтесь обращаться ко мне или прокомментировать, если вам нужно разъяснение.

РЕДАКТИРОВАТЬ: Хотя я думаю, что это выполнимо, я также думаю, что это много (!!!) работы, особенно если вы хотите восстановить параметры, локальные переменные и контексты вызовов (например, эти указатели, удерживаемые блокировки...).

EDIT в соответствии с запросом: предположим, что тот же стек, что и выше (вызов B, вызывающий C). Хотя A, B и C имеют в них произвольный код, просто измените их следующим образом:

void A() {B(); } void B() {C(); } void C() {redefine(); }

Как только вы достигнете метода redefine, переопределите все классы с их исходным кодом. Тогда у вас есть стек, который вы хотите.

Ответ 2

Не уверен в этом инструменте, но вы можете проверить http://en.wikipedia.org/wiki/GNU_Debugger.

GDB предлагает обширные возможности для отслеживания и изменения выполнения компьютерных программ. Пользователь может контролировать и изменять значения внутренних переменных программ и даже вызывать функции независимо от нормального поведения программы.