热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

口译员如何解释代码?

如何解决《口译员如何解释代码?》经验,为你挑选了1个好方法。

为简单起见,想象一下这种情况,我们有一台2位计算机,它有一对2位寄存器,称为r1和r2,只适用于立即寻址.

让我们说比特序列00意味着添加到我们的CPU.也01的装置将数据移动到R 1和10组的装置将数据移动到R2.

因此,这台计算机和汇编程序有一个汇编语言,其中的示例代码将被编写为

mov r1,1
mov r2,2
add r1,r2

简单地说,当我将此代码汇编为本机语言时,文件将类似于:

0101 1010 0001

上面的12位是本机代码:

Put decimal 1 to R1, Put decimal 2 to R2, Add the data and store in R1. 

所以这基本上是编译代码的工作方式,对吧?

让我们说有人为这个架构实现了一个JVM.在Java中,我将编写如下代码:

int x = 1 + 2;

JVM将如何解释此代码?我的意思是最终必须将相同的位模式传递给cpu,不是吗?所有cpu都有许多可以理解和执行的指令,它们毕竟只是一些位.让我们说编译的Java字节码看起来像这样:

1111 1100 1001

或者其他..是否意味着解释在执行时将此代码更改为0101 1010 0001?如果是,它已经在本机代码中了,那为什么说JIT只是经过多次启动?如果它没有完全转换为0101 1010 0001,那么它会做什么?它如何使cpu做添加?

也许我的假设存在一些错误.

我知道解释很慢,编译代码更快但不可移植,虚拟机"解释"代码,但是如何?我正在寻找"如何完全/技术解释".任何指针(如书籍或网页)都是受欢迎的,而不是答案.



1> 小智..:

遗憾的是,您描述的CPU架构过于局限,无法通过所有中间步骤实现这一点.相反,我将编写伪C和伪x86汇编程序,希望以一种清晰的方式,而不是非常熟悉C或x86.

编译的JVM字节码可能如下所示:

ldc 0 # push first first constant (== 1)
ldc 1 # push the second constant (== 2)
iadd # pop two integers and push their sum
istore_0 # pop result and store in local variable

解释器具有(二进制编码)数组中的这些指令,以及引用当前指令的索引.它还有一个常量数组,一个用作堆栈的内存区域和一个用于局部变量的内存区域.那么解释器循环看起来像这样:

while (true) {
    switch(instructions[pc]) {
    case LDC:
        sp += 1; // make space for constant
        stack[sp] = constants[instructions[pc+1]];
        pc += 2; // two-byte instruction
    case IADD:
        stack[sp-1] += stack[sp]; // add to first operand
        sp -= 1; // pop other operand
        pc += 1; // one-byte instruction
    case ISTORE_0:
        locals[0] = stack[sp];
        sp -= 1; // pop
        pc += 1; // one-byte instruction
    // ... other cases ...
    }
}

C代码被编译为机器代码并运行.正如您所看到的,它是高度动态的:它在每次执行指令时检查每个字节码指令,并且所有值都通过堆栈(即RAM).

虽然实际添加本身可能发生在寄存器中,但添加的代码与Java-to-machine代码编译器发出的代码有很大不同.以下是C编译器可能将上述内容转换为(伪x86)的摘录:

.ldc:
incl %esi # increment the variable pc, first half of pc += 2;
movb %ecx, program(%esi) # load byte after instruction
movl %eax, constants(,%ebx,4) # load constant from pool
incl %edi # increment sp
movl %eax, stack(,%edi,4) # write constant onto stack
incl %esi # other half of pc += 2
jmp .EndOfSwitch

.addi
movl %eax, stack(,%edi,4) # load first operand
decl %edi # sp -= 1;
addl stack(,%edi,4), %eax # add
incl %esi # pc += 1;
jmp .EndOfSwitch

您可以看到添加的操作数来自内存而不是硬编码,即使出于Java程序的目的,它们也是不变的.那是因为对于翻译来说,他们并不是一成不变的.解释器编译一次,然后必须能够执行各种程序,而不生成专门的代码.

JIT编译器的目的就是:生成专门的代码.JIT可以分析堆栈用于传输数据的方式,程序中各种常量的实际值以及执行的计算顺序,以生成更有效地执行相同操作的代码.在我们的示例程序中,它将局部变量0分配给寄存器,用常量移动常量替换对常量表的访问(movl %eax, $1),并将堆栈访问重定向到正确的机器寄存器.忽略通常会做的一些更优化(复制传播,常量折叠和死代码消除),最终可能会得到如下代码:

movl %ebx, $1 # ldc 0
movl %ecx, $2 # ldc 1
movl %eax, %ebx # (1/2) addi
addl %eax, %ecx # (2/2) addi
# no istore_0, local variable 0 == %eax, so we're done


推荐阅读
  • 本文详细介绍了Java反射机制的基本概念、获取Class对象的方法、反射的主要功能及其在实际开发中的应用。通过具体示例,帮助读者更好地理解和使用Java反射。 ... [详细]
  • 零拷贝技术是提高I/O性能的重要手段,常用于Java NIO、Netty、Kafka等框架中。本文将详细解析零拷贝技术的原理及其应用。 ... [详细]
  • 单片微机原理P3:80C51外部拓展系统
      外部拓展其实是个相对来说很好玩的章节,可以真正开始用单片机写程序了,比较重要的是外部存储器拓展,81C55拓展,矩阵键盘,动态显示,DAC和ADC。0.IO接口电路概念与存 ... [详细]
  • Java高并发与多线程(二):线程的实现方式详解
    本文将深入探讨Java中线程的三种主要实现方式,包括继承Thread类、实现Runnable接口和实现Callable接口,并分析它们之间的异同及其应用场景。 ... [详细]
  • poj 3352 Road Construction ... [详细]
  • 本文详细介绍了MySQL数据库的基础语法与核心操作,涵盖从基础概念到具体应用的多个方面。首先,文章从基础知识入手,逐步深入到创建和修改数据表的操作。接着,详细讲解了如何进行数据的插入、更新与删除。在查询部分,不仅介绍了DISTINCT和LIMIT的使用方法,还探讨了排序、过滤和通配符的应用。此外,文章还涵盖了计算字段以及多种函数的使用,包括文本处理、日期和时间处理及数值处理等。通过这些内容,读者可以全面掌握MySQL数据库的核心操作技巧。 ... [详细]
  • 本文提出了一种基于栈结构的高效四则运算表达式求值方法。该方法能够处理包含加、减、乘、除运算符以及十进制整数和小括号的算术表达式。通过定义和实现栈的基本操作,如入栈、出栈和判空等,算法能够准确地解析并计算输入的表达式,最终输出其计算结果。此方法不仅提高了计算效率,还增强了对复杂表达式的处理能力。 ... [详细]
  • 深入解析 SQL 数据库查询技术
    本文深入探讨了SQL数据库查询技术,重点讲解了单表查询的各种方法。首先,介绍了如何从表中选择特定的列,包括查询指定列、查询所有列以及计算值的查询。此外,还详细解释了如何使用列别名来修改查询结果的列标题,并介绍了更名运算的应用场景和实现方式。通过这些内容,读者可以更好地理解和掌握SQL查询的基本技巧和高级用法。 ... [详细]
  • 本文探讨了C语言和C++中大小写的处理方式,并详细介绍了如何在C++中实现不区分大小写的字符串比较。通过自定义`char_traits`类,可以灵活地处理字符的比较、复制和转换。 ... [详细]
  • 最详尽的4K技术科普
    什么是4K?4K是一个分辨率的范畴,即40962160的像素分辨率,一般用于专业设备居多,目前家庭用的设备,如 ... [详细]
  • 如何将Python与Excel高效结合:常用操作技巧解析
    本文深入探讨了如何将Python与Excel高效结合,涵盖了一系列实用的操作技巧。文章内容详尽,步骤清晰,注重细节处理,旨在帮助读者掌握Python与Excel之间的无缝对接方法,提升数据处理效率。 ... [详细]
  • 深入解析 Synchronized 锁的升级机制及其在并发编程中的应用
    深入解析 Synchronized 锁的升级机制及其在并发编程中的应用 ... [详细]
  • 本文详细探讨了二元Probit模型及其在实际应用中的重要性。作为一种广义线性模型,Probit模型主要用于处理二分类问题,与Logistic模型类似,但其假设误差项服从标准正态分布。尽管Probit模型在某些领域应用较少,但在特定情境下仍具有独特优势。文章不仅介绍了模型的基本原理,还通过实例分析展示了其在经济学、社会学等领域的具体应用。 ... [详细]
  • 本文深入解析了JDK 8中HashMap的源代码,重点探讨了put方法的工作机制及其内部参数的设定原理。HashMap允许键和值为null,但键为null的情况只能出现一次,因为null键在内部通过索引0进行存储。文章详细分析了capacity(容量)、size(大小)、loadFactor(加载因子)以及红黑树转换阈值的设定原则,帮助读者更好地理解HashMap的高效实现和性能优化策略。 ... [详细]
  • 本文探讨了如何通过编程手段在Linux系统中禁用硬件预取功能。基于Intel® Core™微架构的应用性能优化需求,文章详细介绍了相关配置方法和代码实现,旨在帮助开发人员有效控制硬件预取行为,提升应用程序的运行效率。 ... [详细]
author-avatar
悉尼新鲜事儿
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有