是否有用于编辑java类文件的实用程序(或eclipse插件)?我想操纵java类文件的字节码而不重新编译它,也没有完整的构建路径.
例如,重命名方法,添加/删除指令,更改常量等.
我找到的唯一工具是:
我有一段简单的Java代码:
public static void main(String[] args) {
String testStr = "test";
String rst = testStr + 1 + "a" + "pig" + 2;
System.out.println(rst);
}
Run Code Online (Sandbox Code Playgroud)
使用Eclipse Java编译器对其进行编译,然后使用AsmTools检查字节码。表明:
该方法中包含三个局部变量。参数位于插槽0中,并且代码假定使用插槽1和2。但是我认为2个局部变量就足够了-索引0仍然是参数,并且代码仅需要一个变量。
为了查看我的想法是否正确,我编辑了文本字节码,将局部变量的数量减少到2,并调整了一些相关指令:
我用AsmTools重新编译了它,效果很好!
那么,为什么Javac或Eclipse编译器不进行这种优化以使用最小局部变量呢?
我必须goto在Python中使用.我发现了托管,goto但我的Python实现(Mac上的CPython 2.7.1)没有这个模块,所以它似乎不是可移植的.它应该至少适用于支持CPython字节码的所有Python实现(特别是我关心CPython和PyPy).然后有这个相关的问题,和cdjc的goto.以下是答案给出的.
我可以手动构建字节码(即编写我自己的Python编译器)因为有这样的指令(JUMP_ABSOLUTE和朋友).但我想知道是否有更简单的方法.是否可以通过inspect左右来调用单个字节码指令?我还想过通过Python编译然后自动修补生成的Python字节码.
当然,如果我不解释为什么我真的需要这个,人们会问为什么,不会给我任何有用的答案.所以简而言之我的用例:我正在将一个C AST翻译成Python AST并编译它.我可以用某种方式将每个逻辑流(所有循环和其他东西)映射到等效的Python代码.除了之外的一切goto.相关项目:PyCParser(参见参考资料interpreter.py),PyCPython,PyLua.
今天我在想一个我在一年前写的Python项目,我用logging得非常广泛.我记得由于开销(hotshot表明它是我最大的瓶颈之一),必须在类似内循环的场景(90%代码)中注释掉大量的日志调用.
我现在想知道是否有一些规范的方法可以在Python应用程序中以编程方式去除日志记录调用,而无需一直注释和取消注释.我认为您可以使用检查/重新编译或字节码操作来执行此类操作,并仅针对导致瓶颈的代码对象.这样,您可以添加操纵器作为后编译步骤并使用集中配置文件,如下所示:
[Leave ERROR and above]
my_module.SomeClass.method_with_lots_of_warn_calls
[Leave WARN and above]
my_module.SomeOtherClass.method_with_lots_of_info_calls
[Leave INFO and above]
my_module.SomeWeirdClass.method_with_lots_of_debug_calls
Run Code Online (Sandbox Code Playgroud)
当然,您希望谨慎使用它,并且可能只使用每个函数的粒度 - 仅适用于已显示logging为瓶颈的代码对象.有人知道这样的事吗?
注意:由于动态类型和后期绑定,有一些因素使性能更难以执行.例如,对命名方法的任何调用都debug可能必须用if not isinstance(log, Logger).在任何情况下,我都假设所有的细节都可以通过绅士的协议或一些运行时检查来克服.:-)
假设我在php中有一个字符串,它打印到这样的文本文件:
nÖ§9q1Fª£
如何获取此文本文件的字节代码而不是时髦的ascii字符?
Java是按值传递的.你如何修改语言以引入通过引用传递(或一些等效的行为)?
举个例子
public static void main(String[] args) {
String variable = "'previous String reference'";
passByReference(ref variable);
System.out.println(variable); // I want this to print 'new String reference'
}
public static void passByReference(ref String someString) {
someString = "'new String reference'";
}
Run Code Online (Sandbox Code Playgroud)
哪个(没有ref)编译成以下字节码
public static void main(java.lang.String[]);
Code:
0: ldc #2 // String 'previous String reference'
2: astore_1
3: aload_1
4: invokestatic #3 // Method passByReference:(Ljava/lang/String;)V
7: return
public static void passByReference(java.lang.String);
Code:
0: ldc #4 // String …Run Code Online (Sandbox Code Playgroud) java bytecode language-design pass-by-reference bytecode-manipulation
Android文档中的"性能提示"部分有一个非常大胆的主张:
one()是比较快的.它将所有内容都拉到局部变量中,避免了查找.只有阵列长度才能提供性能优势.
它引用此代码段:
int len = localArray.length;
for (int i = 0; i < len; ++i) {
sum += localArray[i].mSplat;
}
Run Code Online (Sandbox Code Playgroud)
这让我感到很惊讶,因为localArray.length只是访问一个整数,如果你使用一个中间变量,你必须再次执行相同的步骤.我们真的在说一个只需要x代替的中间变量y.x更快吗?
我看了一下这个问题是关于同样的想法但是使用了一个arraylist及其后续的.size()方法.这里的共识似乎是没有区别,因为方法调用可能只是内联到整数访问(这正是我们在这里的场景).
所以我接受了字节码,看看是否可以告诉我任何事情.
给出以下源代码:
public void MethodOne() {
int[] arr = new int[5];
for (int i = 0; i < arr.length; i++) { }
}
public void MethodTwo() {
int[] arr = new int[5];
int len = arr.length;
for (int i = 0; i < …Run Code Online (Sandbox Code Playgroud) 看看这个:
>>> def f():
... return (2+3)*4
...
>>> dis(f)
2 0 LOAD_CONST 5 (20)
3 RETURN_VALUE
Run Code Online (Sandbox Code Playgroud)
显然,编译器已预先评估(2+3)*4,这是有道理的.
现在,如果我只是改变操作数的顺序*:
>>> def f():
... return 4*(2+3)
...
>>> dis(f)
2 0 LOAD_CONST 1 (4)
3 LOAD_CONST 4 (5)
6 BINARY_MULTIPLY
7 RETURN_VALUE
Run Code Online (Sandbox Code Playgroud)
表达式不再完全预先评估!这是什么原因?我正在使用CPython 2.7.3.
我正在查看从Java字节码获取的一些反汇编代码.我看到一些声明如下:
.method static synthetic access$0()Lcom/package/Sample;
Run Code Online (Sandbox Code Playgroud)
我无法弄清楚什么synthetic或access$0意味.有人可以帮我理解这部分吗?
bytecode ×10
java ×6
python ×3
.class-file ×1
ascii ×1
benchmarking ×1
compilation ×1
cpython ×1
decompiler ×1
disassembly ×1
for-loop ×1
goto ×1
javac ×1
jvm ×1
logging ×1
optimization ×1
performance ×1
php ×1
python-2.7 ×1
string ×1