这可能是一个愚蠢的问题,但是,考虑到输出,比如..
>>> from dis import dis
>>> def myfunc(x):
... print x ** 2
...
>>> dis(myfunc)
2 0 LOAD_FAST 0 (x)
3 LOAD_CONST 1 (2)
6 BINARY_POWER
7 PRINT_ITEM
8 PRINT_NEWLINE
9 LOAD_CONST 0 (None)
12 RETURN_VALUE
Run Code Online (Sandbox Code Playgroud)
..或.pyc文件 - 是否可以将其重新组合成一个有效的Python源代码?即在哪里reassemble(dis(myfunc)) == "def reassembled_function(x):\n print x ** 2"
不是出于任何特殊的实际原因,我只是好奇这是否可能,或者是否已经尝试过......
我正在写一个Bytecode指导员.现在,我试图找出在物体存在的情况下如何做到这一点.我想对我在JVMS中阅读的两行(第4.9.4节)做一些澄清:
1)"验证者在初始化之前拒绝使用新对象的代码."
我的问题是,"使用"在这里意味着什么?我猜它的意思是:把它当作一个方法属性,调用GETFIELD和PUTFIELD它,或调用它的任何实例方法.他们的其他禁止用途是什么?而且我相信它遵循其他指令,例如DUP,LOAD并且STORE被允许.
2)"在该方法调用myClass的另一个实例初始化方法或其直接超类之前,该方法可以对此执行的唯一操作是分配在myClass中声明的字段."
这意味着在一个<init>方法中,GETFIELD和PUTFIELD在<init>被调用之前是允许的.但是,在Java中,在调用之前对实例字段执行任何操作super()或this()导致编译错误.有人可以澄清一下吗?
3)我还有一个问题.对象引用何时初始化,因此可以自由使用?通过阅读JVMS,我想出了一个对象是否被初始化的答案,取决于每个方法.在某个时间点,可以为方法初始化对象,但不能为另一个方法初始化对象.具体来说,当<init>该方法返回时,对象的方法被初始化.
例如,考虑该main()方法创建了一个对象并调用<init>它然后调用超类<init>.从返回后super(),该对象现在被视为初始化<init>,但尚未初始化main().这是否意味着,在<init>之后super(),我可以将对象作为参数传递给方法,甚至在返回main()之前.
有人可以证实这整个分析是真的吗?感谢您的时间.
ps:我实际上已经向Sun论坛发布了同样的问题但是回复了.我希望我能在这里有更多的运气.谢谢.
更新
首先感谢您的回答和时间.虽然我没有得到一个明确的答案(我有很多问题,其中一些有点模糊),但你的答案和例子,以及随后的实验,对于我更深入地了解JVM如何工作非常有用.
我发现的主要问题是Verifier的行为因不同的实现和版本而不同(这使得字节码操作的工作变得更加复杂).问题在于不符合JVMS,或者验证者的开发人员缺乏文档,或者JVMS在验证者的区域中有一些微妙的模糊性.
最后一件事,SO Rocks !!! 我在官方的Sun JVM规范论坛上发布了同样的问题,直到现在我仍然没有回答.
我正在为LLVM中的特殊用途语言编写编译器.我想为已经用C++编写的库添加绑定.我的想法是将库编译为LLVM字节码(使用clang -emit-llvm -S abc.c)并在编译期间将其链接.这适用于类似的代码
// lib.c
int f() {
return 123;
}
Run Code Online (Sandbox Code Playgroud)
但是库的一部分写得像
// A.cc
class A {
public:
int f() { return 123; }
};
Run Code Online (Sandbox Code Playgroud)
这导致空字节码文件.我知道我可以通过分离实现来解决这个问题:
// A.cc
class A {
public:
int f();
};
int A::f() {
return 123;
}
Run Code Online (Sandbox Code Playgroud)
但这将是一项繁琐的工作.有没有办法从我的库源创建有用的字节码呢?或者在我的编译器中使库可用的任何其他方法?
可能重复:
LLVM和java字节码之间有什么区别?
例如,在LLVM中,它说..
What is commonly known as the LLVM bitcode file format
(also, sometimes anachronistically known as bytecode) is actually two things:
a bitstream container format and an encoding of LLVM IR into the container
format.
Run Code Online (Sandbox Code Playgroud)
我只知道Java Bytecode,它是独立于平台的,可以由JVM运行
但是对于LLVM位代码,还有更具体的例子吗?
我正在尝试用C#.NET和Mono编写优化代码,用于游戏.(是的,我有正当理由使用C#而不是C++).
我注意到C#似乎没有正确优化其运算符.运算符的运行速度是使用Vector4数学手动内联代码的两倍.以下是我在.NET 4.5中运行9999999次的一些简单基准测试:
// Test 1
for (uint i = 0; i != 9999999; ++i)// 230 MS
{
vector += vector2;
vector2 -= vector;
}
// Test 2
for (uint i = 0; i != 9999999; ++i)// 185 MS
{
vector = vector.Add(ref vector2);
vector2 = vector2.Sub(ref vector);
}
// Test 3
for (uint i = 0; i != 9999999; ++i)// 116 MS
{
vector.X += vector2.X;
vector.Y += vector2.Y;
vector.Z += vector2.Z;
vector.W += vector2.W;
vector2.X -= vector1.X;
vector2.Y …Run Code Online (Sandbox Code Playgroud) 在C和C++中,不允许编译器重新排序结构的数据成员,因此如果您不小心订购它们,最终会浪费空间.例如:
struct S {
int i;
void *p;
int i2;
};
Run Code Online (Sandbox Code Playgroud)
在具有32位int和64位指针的平台上,i将首先放置,然后是32位填充,以便p可以进行64位对齐.i2然后占用下一个字的一半,接着是另外32位的填充.生成的结构长度为24个字节,而如果p首先声明,则只有16个字节长.如果在阵列中有很多这些结构,找到并删除填充有时可能是一个重要的优化,以节省内存并减少缓存流失.
我很想知道Java是否具有相同的功能.未装箱的类型(例如int和boolean)是否与引用相同或更小?如果它们更小,是否允许编译器对它们重新排序以避免插入填充以对齐后续字段?最后,如果是,那么任何编译器都这样做吗?
我现在对此没有特别的优化需求,我只是很想知道在选择声明我的字段的顺序时是否应该记住这一点,就像我在C中所做的那样.
假设我正在实现一个字节码编译器,类似于Lua的/ Python ......等等.
我正在遍历AST,生成字节码指令,并且我遇到了循环break内部的if-else内部while:
while (cond1)
if (cond2)
...
else
break
Run Code Online (Sandbox Code Playgroud)
(我尝试写出等效的字节码,但它看起来并没有太大帮助.)
关键是,该示例中至少有4个"跳转"指令,我想找到一个优雅的解决方案来填充跳转地址,因为我编译AST ...我不知道while循环的跳转地址或者break直到我完全"编译"内部陈述之后.
我还没读这本龙书.
如果我递归地编译AST,当我break在一些任意数量的循环和if-else块中找到一个语句时,编译器应该如何知道跳转到哪个空标签?我猜测递归AST行走函数外部的某种类型的标签名称堆栈.
使用64位大小的结构时,请使用以下代码段
[StructLayout(LayoutKind.Explicit, Pack = 1, Size = 8)]
unsafe struct BUF
{
}
((BUF*)dst) = *((BUF*)src);
Run Code Online (Sandbox Code Playgroud)
产生
IL_0046: nop
IL_0047: ldloc.s dst
IL_0049: ldloc.2
IL_004a: ldobj MyClass/BUF
IL_004f: stobj MyClass/BUF
Run Code Online (Sandbox Code Playgroud)
但是,当只使用long时,会生成以下代码
*((long*)dst) = *((long*)src);
Run Code Online (Sandbox Code Playgroud)
生产:
IL_0046: nop
IL_0047: ldloc.s dst
IL_0049: ldloc.2
IL_004a: ldind.i8
IL_004b: stind.i8
Run Code Online (Sandbox Code Playgroud)
有没有人知道ldobj/stobj和ldind.i8/stind.i8对于这个例子有什么区别?
ldobj/stobj似乎提高了20%的性能,但我无法弄清楚为什么会这样.这两条线是不是完全一样?
谢谢!
编辑:[64位释放模式]在发布模式下编译时,字节码看起来相同.性能测量是在发布模式下不久前完成的.
我一直在使用' dis '模块来重新编写一些编译脚本(.pyc).我理解JUMP_FORWARD和JUMP_ABSOLUTE之间的区别.据我所知,IF语句将由JUMP_FORWARD关闭:
>>> def f():
if a:
print ''
>>> from dis import dis
>>> dis(f)
2 0 LOAD_GLOBAL 0 (a)
3 JUMP_IF_FALSE 9 (to 15)
6 POP_TOP
3 7 LOAD_CONST 1 ('')
10 PRINT_ITEM
11 PRINT_NEWLINE
12 JUMP_FORWARD 1 (to 16)
>> 15 POP_TOP
>> 16 LOAD_CONST 0 (None)
19 RETURN_VALUE
Run Code Online (Sandbox Code Playgroud)
如果IF语句位于另一个循环的末尾,则会出现JUMP_ABSOLUTE.例如:
>>> def f1():
if a:
if b:
print ''
>>> dis(f1)
2 0 LOAD_GLOBAL 0 (a)
3 JUMP_IF_FALSE 20 (to 26)
6 POP_TOP
3 7 LOAD_GLOBAL …Run Code Online (Sandbox Code Playgroud)