Как я могу убедиться, что Jython не сохраняет «чувствительные» комментарии в скомпилированных файлах $ py.class? - PullRequest
1 голос
/ 13 января 2020

Я хотел посмотреть, сохраняются ли комментарии или строки в файлах $ py.class, поэтому я попытался поэкспериментировать с Jython 2.5.3 и Jython 2.7.0. (В моем случае исходные файлы .py не делаются опубликованными c, но файлы $ py.class являются частью публикуемого файла .jar; я не хочу, чтобы некоторые комментарии были видны)

C:\tmp\jython>java -jar c:\app\java\lib\jython-standalone-2.7.0.jar
Jython 2.7.0 (default:9987c746f838, Apr 29 2015, 02:25:11)
[Java HotSpot(TM) 64-Bit Server VM (Oracle Corporation)] on java1.8.0_152
Type "help", "copyright", "credits" or "license" for more information.
>>> import py_compile
>>> py_compile.compile('loose_lips.py')

, где содержитoose_lips.py:

def loose_lips_sink_ships(x):
    """CM1 Doc comment"""

    # CM2 line comment

    """ 
    CM3 Another multiline string that doesn't do anything
    but is not a doc comment
    """

    return x+1

    """
    CM4 Yet another comment that could theoretically
    be optimized out, since we can never get here
    """

Я предсказал, что CM1 будет единственным строковым содержимым, сохраняемым в результирующем выводе, потому что он имеет четко определенную семантику в Python --- это строка документации, поэтому она вставляется в loose_lips.loose_lips_sink_ships.__doc__. Нет никаких оснований для того, чтобы все остальное заканчивалось каким-либо кодом времени выполнения.

Если я запускаю py_compile.compile('loose_lips.py') в Python 2.7.14 (или просто import loose_lips), тогда он генерирует файл .py c содержит байт-код и единственный сохраненный текст - CM1, как и предсказывалось.

Если я запускаю py_compile.compile('loose_lips.py') в Jython 2.5.3 или Jython 2.7.0, то полученный файл $ py.class содержит CM1 и CM3.

Почему CM3 сохраняется во время выполнения? Есть ли какое-либо внешне видимое поведение, которое пытается обеспечить интерпретатор Jython (например, сохранение исходного кода?), Которое требует сохранения многострочных строк? Можно ли это как-то предотвратить?

Я декомпилировал файл $ py.class в http://www.javadecompilers.com и вот результаты:

import org.python.core.PyRunnableBootstrap;
import org.python.core.CodeBootstrap;
import org.python.core.CodeLoader;
import org.python.core.PyFunction;
import org.python.core.PyString;
import org.python.core.Py;
import org.python.core.PyObject;
import org.python.core.ThreadState;
import org.python.core.PyFrame;
import org.python.core.PyCode;
import org.python.compiler.Filename;
import org.python.compiler.MTime;
import org.python.compiler.APIVersion;
import org.python.core.PyRunnable;
import org.python.core.PyFunctionTable;

// 
// Decompiled by Procyon v0.5.36
// 

@APIVersion(36)
@MTime(1578883953709L)
@Filename("loose_lips.py")
public class loose_lips$py extends PyFunctionTable implements PyRunnable
{
    static loose_lips$py self;
    static final PyCode f$0;
    static final PyCode loose_lips_sink_ships$1;

    public PyObject f$0(final PyFrame pyFrame, final ThreadState threadState) {
        pyFrame.setline(1);
        pyFrame.setlocal("loose_lips_sink_ships", (PyObject)new PyFunction(pyFrame.f_globals, Py.EmptyObjects, loose_lips$py.loose_lips_sink_ships$1, (PyObject)PyString.fromInterned("CM1 Doc comment")));
        pyFrame.f_lasti = -1;
        return Py.None;
    }

    public PyObject loose_lips_sink_ships$1(final PyFrame pyFrame, final ThreadState threadState) {
        pyFrame.setline(2);
        PyString.fromInterned("CM1 Doc comment");
        pyFrame.setline(9);
        PyString.fromInterned(" \n    CM3 Another multiline string that doesn't do anything\n    but is not a doc comment\n    ");
        pyFrame.setline(11);
        final PyObject add = pyFrame.getlocal(0)._add((PyObject)Py.newInteger(1));
        pyFrame.f_lasti = -1;
        return add;
    }

    public loose_lips$py(final String s) {
        loose_lips$py.self = this;
        f$0 = Py.newCode(0, new String[0], s, "<module>", 0, false, false, (PyFunctionTable)loose_lips$py.self, 0, (String[])null, (String[])null, 0, 4096);
        loose_lips_sink_ships$1 = Py.newCode(1, new String[] { "x" }, s, "loose_lips_sink_ships", 1, false, false, (PyFunctionTable)loose_lips$py.self, 1, (String[])null, (String[])null, 0, 4097);
    }

    public PyCode getMain() {
        return loose_lips$py.f$0;
    }

    public static void main(final String[] array) {
        Py.runMain(CodeLoader.createSimpleBootstrap(new loose_lips$py("loose_lips$py").getMain()), array);
    }

    public static CodeBootstrap getCodeBootstrap() {
        return PyRunnableBootstrap.getFilenameConstructorReflectionBootstrap((Class)loose_lips$py.class);
    }

    public PyObject call_function(final int n, final PyFrame pyFrame, final ThreadState threadState) {
        switch (n) {
            case 0: {
                return this.f$0(pyFrame, threadState);
            }
            case 1: {
                return this.loose_lips_sink_ships$1(pyFrame, threadState);
            }
            default: {
                return null;
            }
        }
    }
}
...