我反编译了 Java(实际上是 Dalvik)字节码。在方法的开头,我直接访问实例成员的字段(即不通过 getter)。
似乎 Java 调用Object.getClass()了访问的实例成员 ( mOther),但没有在任何地方使用结果。这是某种检查吗?为什么需要这个电话?我怀疑这是因为我直接访问了一个字段(在该类中定义),但我没有看到连接。
Java代码和反编译后的字节码如下。
(请注意,最后一条指令lifeTime作为常量加载,0x0001因为 in MyOtherClass,我有lifeTime一个public final字段,并且当前是从代码初始化的。)
MyOtherClass other = mOther;
if (mAge >= other.lifeTime) { // lifeTime is initialized to 0x0001
end();
return;
}
.line 53
move-object/from16 v0, p0
iget-object v0, v0, Lcom/example/engine/MyClass1;->mOther:Lcom/example/engine/MyOtherClass;
move-object/from16 v16, v0
.line 54
.local v16, other:Lcom/example/engine/MyOtherClass;
move-object/from16 v0, p0
iget v0, v0, Lcom/example/engine/MyClass1;->mAge:I
move/from16 v18, v0
// Why is Object->getClass() called?
invoke-virtual/range {v16 .. v16}, …Run Code Online (Sandbox Code Playgroud) 我正在使用 ASM 3.1 生成一个虚拟类。它只有一个简单的构造函数,没有其他方法:
public class TestAsm {
public static void main(String... args) throws Throwable {
ClassWriter sw = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
sw.visit(Opcodes.V1_6, Opcodes.ACC_PUBLIC | Opcodes.ACC_SUPER, "test/SubCls", null, "test/SuperCls", null);
sw.visitField(Opcodes.ACC_PUBLIC, "i", "I", null, null);
MethodVisitor mv = sw.visitMethod(0, "<init>", "()V", null, null);
// mv.visitMaxs(2, 1);
mv.visitCode();
mv.visitVarInsn(Opcodes.ALOAD, 0);
mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "test/SuperCls", "<init>", "()V");
mv.visitVarInsn(Opcodes.ALOAD, 0);
mv.visitInsn(Opcodes.ICONST_2);
mv.visitFieldInsn(Opcodes.PUTFIELD, "test/SubCls", "i", "I");
mv.visitInsn(Opcodes.RETURN);
mv.visitEnd();
sw.visitEnd();
byte[] cls = sw.toByteArray();
FileOutputStream fos = new FileOutputStream("bin/test/SubCls.class");
fos.write(cls);
fos.close();
SuperCls o = (SuperCls) Class.forName("test.SubCls").newInstance(); …Run Code Online (Sandbox Code Playgroud) 我遇到的大多数语言都使用 VM 或虚拟机。Java(JVM)、Python、Ruby、PHP(HHVM)等语言。
然后是 C、C++、Haskell 等直接编译为 native 的语言。
我的问题是,使用 VM(操作系统独立性之外)有什么优势?通过使用 [源代码 -> 字节码 -> 本机] 而不是 [源代码 -> 本机],使用 VM 是否只是创建了一个额外的解释步骤?
可以直接编译为什么要使用VM?
编辑
我的理解是 Python、Ruby 等。使用类似于 VM 的东西,如果不完全符合这样的定义,脚本被编译为中间表示(对于 Python,例如 .pyc 文件)。
编辑 2
是的。查了一下。Python、Ruby 和 PHP 都使用中间表示,但根本不存储在单独的文件中,而是由 VM 直接执行。请参阅问题:Java“虚拟机”与 Python“解释器”用语?
“尽管 Python 在幕后使用了虚拟机,但从用户的角度来看,大多数时候人们可以忽略这一细节。”
language-agnostic jit operating-system bytecode vm-implementation
我想实现一个 Erlang 解释器,最近我正在阅读 Erlang 的标准库源代码。我在 erlang.erl 中找到 erlang:display/1 的源代码是:
%% display/1
-spec erlang:display(Term) -> true when
Term :: term().
display(_Term) ->
erlang:bif_error(undefined).
Run Code Online (Sandbox Code Playgroud)
我不知道它是如何产生显示行为的,而且我认为它无论如何都会抛出一个未定义的错误。顺便说一句,我还破解了 erlang.beam 以确保字节码具有与源代码 (erlang.erl) 相同的语义。谁能告诉我 erlang:display 实际上是如何做的?
我试图了解调用python函数的过程,我创建.pyc了调用的简单文件os.listdir('.'),我看到os并listdir保存在co_names表中,执行CALL_FUNCTION字节码指令时,如何os识别库?是根据它的名字使用co_names表吗?python 是否开始搜索名为 的模块os.pyc?如果是这样,python 如何知道.pyc模块中调用的函数的字节码的偏移量在哪里?
谢谢。
dis 模块字节码片段
5 28 LOAD_NAME 0 (os)
31 LOAD_ATTR 2 (listdir)
34 LOAD_CONST 3 ('.')
37 CALL_FUNCTION 1
Run Code Online (Sandbox Code Playgroud) 我有一个旧库(大约 2005 年),它执行字节码操作,但不涉及堆栈图。因此,我的 jvm (java 8) 抱怨它们是无效的类。规避错误的唯一方法是使用-noverify. 但这对我来说不是一个长期的解决方案。
在类已经生成之后,有什么办法可以重新生成堆栈映射吗?我看到ClassWriter该类有一个选项来重新生成堆栈映射,但我不确定如何读取字节类并重写一个新的。那可行吗?
我正在创建一个 JVM 并试图理解字节码指令。我正在尝试编写 Java 代码,该代码在编译时生成一个具有宽指令的 .class 文件。哪个 java 代码会生成那种扩展指令?我对广泛的行为有点迷失
好吧,我发布这个是担心它可能会在任何人阅读它之前被关闭 - 我已经习惯了 - 但我会尝试一下......甚至指出我正确的方向或一些现有的答案确实包含一个特定的答案肯定会...
所以,在这个简短的介绍之后......我目前正在为我设计的编程语言编写一个字节码解释器,在C 中,(基于堆栈的 VM)。
如果您想查看支持的操作码,请随时在此处查看:https : //github.com/arturo-lang/arturo/blob/master/src/vm/opcodes.h
堆栈机并没有什么特别之处。值被压入和弹出,操作符和函数处理它们,将计算结果推回堆栈。到现在为止还挺好。
现在,我正处于所有核心功能所在的地步,我正在尝试通过进一步优化来进一步提升它。
这是一个例子(希望是一个相当说明性的例子)。
输入:
fibo: $(x){
if x<2 {
return 1
} {
return [fibo x-1] + [fibo x-2]
}
}
i: 0
loop i<34 {
print "fibo(" + i + ") = " + [fibo i]
i: i+1
}
Run Code Online (Sandbox Code Playgroud)
产生的字节码:
|== Data Segment /======================>
0 : [Func ]= function <5,1>
1 : [Int ]= 34
2 : [String]= fibo(
3 …Run Code Online (Sandbox Code Playgroud) c programming-languages bytecode bytecode-manipulation compiler-optimization
JVM 运行时数据区为正在执行的每个方法单独的堆栈。它包含操作数堆栈和局部变量。每次加载变量时,都需要const先到操作数栈,然后store再到局部变量。为什么不直接操作局部变量表,还有一些看似重复的工作呢?
我从这个问题中知道 Scala 为trait诸如
trait A {
def a = { ... }
}
Run Code Online (Sandbox Code Playgroud)
类似于以下 Java 代码的结构
public interface A {
public void a();
}
public class A$class {
public static void a(A self) { ... }
}
Run Code Online (Sandbox Code Playgroud)
但是,在 Scala 中, atrait可以扩展 a class:
class B {
def b = { ??? }
}
trait A extends B {
def a = { ??? }
}
Run Code Online (Sandbox Code Playgroud)
这在 Java 等价物中如何翻译,其中接口不能从类继承?是否为 生成了额外的接口B?这个 Scala 特性对 …
bytecode ×10
java ×6
jvm ×2
jvm-bytecode ×2
android ×1
c ×1
dalvik ×1
erlang ×1
inheritance ×1
interpreter ×1
jit ×1
python ×1
scala ×1
subtyping ×1