编译器优化

[编译原理]0.引论

試著忘記壹切 提交于 2020-02-18 00:01:07
一、语言处理器 语言处理器有编译器(compiler)、解释器(interpreter) 编译器先把源程序翻译成目标程序,目标程序处理输入产生输出。 解释器自身直接(根据源程序提示)处理输入产生输出。 编译器的处理速度较快,但排错功能不如解释器。 编译器: 解释器: 将源程序翻译成目标程序的过程: 二、编译器的结构 编译器由分析(analysis)部分,和综合(synthesis)部分组成。分析部分又称为编译器的前端,综合部分又称为编译器的后端。在前端和后端之间可以加入代码优化部分。 分析部分 1.词法分析(lexical analysis): 这一阶段的任务是分析出输入的代码流中的词素(lexeme), 对于每个词素,词法分析器都会产生一个词法单元(token)。词法单元的格式为<token-name, attribute-value>。 2.语法分析(syntax analysis) 3.语义分析(semantic analysis):这个阶段有一项重要的任务是类型检查(type checking)。 4.中间代码生成(intermediate code generation) 可选阶段 5.代码优化(code optimization):优化的目的是使代码跑的跟快或者更节能。 综合部分 6.代码生成(code generation):这一阶段的输出即为目标代码。 来源:

微信团队分享:极致优化,iOS版微信编译速度3倍提升的实践总结

不羁岁月 提交于 2020-02-13 06:21:40
1、引言 岁月真是个养猪场,这几年,人胖了,微信代码也翻了。 记得 14 年转岗来微信时,用自己笔记本编译微信工程才十来分钟。如今用公司配的 17 年款 27-inch iMac 编译要接近半小时;偶然间更新完代码,又莫名其妙需要全新编译。在这么低的编译效率下,开发心情受到严重影响。 于是年初我向上头请示,优化微信编译效率,上头也同意了。 2、现有方案 在动手之前,先搜索目前已有方案,大概情况如下。 2.1 优化工程配置 1)将 Debug Information Format 改为 DWARF: Debug 时是不需要生成符号表,可以检查一下子工程(尤其开源库)有没有设置正确。 2)将 Build Active Architecture Only 改为 Yes: Debug 时是不需要生成全架构,可以检查一下子工程(尤其开源库)有没有设置正确。 3)优化头文件搜索路径: 避免工程 Header Search Paths 设置了路径递归引用: Xcode 编译源文件时,会根据 Header Search Paths 自动添加 -I 参数,如果递归引用的路径下子目录越多,-I 参数也越多,编译器预处理头文件效率就越低,所以不能简单的设置路径递归引用。同样 Framework Search Paths 也类似处理。 2.2 使用 CocoaPods 管理第三方库 这是业界常用的做法

必会,详细剖析11道嵌入式Linux C语言面试题

丶灬走出姿态 提交于 2020-02-13 00:43:15
预处理器(Preprocessor) 1 . 用预处理指令#define 声明一个常数,用以表明1年中有多少秒(忽略闰年问题) 答: #define SECONDS_PER_YEAR (60 * 60 * 24 * 365)UL 我在这想看到几件事情: 1) #define 语法的基本知识(例如:不能以分号结束,括号的使用,等等) 2) 懂得预处理器将为你计算常数表达式的值,因此,直接写出你是如何计算一年中有多少秒而不是计算出实际的值,是更清晰而没有代价的。 3) 意识到这个表达式将使一个16位机的整型数溢出, 因此要用到长整型符号L, 告诉编译器这个常数是长整型数。 4) 如果你在表达式中用到UL(表示无符号长整型),那么可能这就给面试者留下了很好的第一印象。记住第一印象很重要。 2 . 写一个"标准"宏MIN ,这个宏输入两个参数并返回较小的一个。 答: #define MIN(A,B) ((A) <= (B) ? (A) : (B)) 这个测试是为下面的目的而设的: 1) 标识#define在宏中应用的基本知识。这是很重要的。因为在 嵌入(inline)操作符 变为标准C的一部分之前,宏是方便产生嵌入代码的唯一方法,对于嵌入式系统来说,为了能达到要求的性能,嵌入代码经常是必须的方法。 2) 懂得在宏中小心地把参数用括号括起来 3) 我也用这个问题开始讨论宏的副作用,例如

Javac早期(编译期)

耗尽温柔 提交于 2020-02-12 08:45:11
从Sun Javac的代码来看,编译过程大致可以分为3个过程: 解析与填充符号表过程。 插入式注解处理器的注解处理过程。 分析与字节码生成过程。 Javac编译动作的入口是com.sun.tools.javac.main.JavaCompiler类,上述3个过程的代码逻辑集中在这个类的compile()和compile2()方法中,整个编译最关键的处理就由图中标注的8个方法来完成,下面我们具体看一下这8个方法实现了什么功能。 解析与填充符号表 解析步骤由上图中的parseFiles()方法(过程1.1)完成,解析步骤包括了经典程序编译原理中的词法分析和语法分析两个过程。 词法、语法分析 词法分析是 将源代码的字符流转变为标记(Token)集合 ,单个字符是程序编写过程的最小元素,而标记则是编译过程的最小元素,关键字、变量名、字面量、运算符都可以成为标记,如“int a=b+2”这句代码包含了6个标记,分别是int、a、=、b、+、2,虽然关键字int由3个字符构成,但是它只是一个Token,不可再拆分。在Javac的源码中,词法分析过程由com.sun.tools.javac.parser.Scanner类来实现。 语法分析是 根据Token序列构造抽象语法树的过程 ,抽象语法树(Abstract Syntax Tree,AST)是一种用来描述程序代码语法结构的树形表示方式

Java String 在拼接时的编译器优化

大城市里の小女人 提交于 2020-02-11 14:40:46
都在代码里了 public static void main(String[] args) { String str = "str"; final String finalString = "str"; String str1 = "str01"; String str2 = "str"+ "01"; System.err.println(str1 == str2); //JDK1.6后,常量字符串的+操作,在编译阶段会直接优化成一个字符串 //所以str1和str2指向常量池中的同一引用地址 String str3 = str + "01"; //编译器自动调用StringBuilder.apend()方法添加 //虽然内容一样,但地址是不一样的 System.err.println(str1 == str3); String str4 = finalString + "01"; //final变量在编译后会直接替换成对应的值,故所以str4="str" + "01" //再加上编译器的优化,会直接合并成str4="str01",与str01相等 System.err.println(str1 == str4); String str5 = new String("str01").intern(); //intern方法返回字符串池中的对象,所以相等 System.err

10个有趣又能编译为JavaScript的语言,你用过哪些?

房东的猫 提交于 2020-02-09 12:30:20
现代应用相比普通的网页有不同的要求。但是浏览器是一个有着一套(大部分)固定可用的技术的平台,JavaScript依然是web应用的核心语言;任何需要在浏览器上跑的应用都需要使用这种语言。 我们都知道Javascript并不是最好的语言,特别是在复杂的应用中,它可能不太能胜任。为了避免这种情况,一些新的语言或现有语言的编译器被创造出来,你不用写一行Javascript或者考虑这种语言的局限,就能生产在浏览器能运行的代码。 这篇文章包括了十种有趣的语言能够编译为Javascript,在浏览器或者Node.js中被执行。 --ADVERTISEMENT-- Dart Dart是一个典型的面向对象的语言,任何东西都是一个对象并且任何对象都是一个类的实例(对象也可以表现为函数)。它的特殊性用于打造面向浏览器,服务器和移动设备的应用。它由谷歌来维护,是用于驱动下一代的AdWords UI。AdWords UI是谷歌盈利的重要产品,这也证明了它在体量上的强大。 这种语言可以编译为JavaScript用于浏览器,或者直接通过Dart VM解释,这样也可以允许你构建服务端应用。移动应用可以通过Flutter SDK创建。 复杂的应用还需要一系列特别为任务所设计的成熟的库和语言特性,Dart这些都有。举例来说一个流行的库是AngularDart,一个Dart版本的Angular。

《go语言从入门到进阶实战》_徐波

痞子三分冷 提交于 2020-02-08 02:02:57
摘录 Go语言是Google公司开发的一种静态型、编译型并自带垃圾回收和并发的编程语言。 Go语言不使用虚拟机,只有运行时(runtime)提供垃圾回收和goroutine调度等。 Go语言使用自己的链接器,不依赖任何系统提供的编译器、链接器。因此编译出的可执行文件可以直接运行在几乎所有的操作系统和环境中。 从Go 1.5版本之后,Go语言实现自举,实现了使用Go语言编写Go语言编译器及所有工具链的功能。 Go语言可以利用自己的特性实现并发编译,并发编译的最小元素是包。从Go 1.9版本开始,最小并发编译元素缩小到函数,整体编译速度提高了20%。 Go语言的并发是基于goroutine,goroutine类似于线程,但并非线程。可以将goroutine理解为一种虚拟线程。Go语言运行时会参与调度goroutine,并将goroutine合理地分配到每个CPU中,最大限度地使用CPU性能。 在Go语言中,自增操作符不再是一个操作符,而是一个语句。因此,在Go语言中自增只有一种写法: i++ 如果写成前置自增“++i”,或者赋值后自增“a=i++”都将导致编译错误。 在多个短变量声明和赋值中,至少有一个新声明的变量出现在左值中,即便其他变量名可能是重复声明的,编译器也不会报错。 布尔型无法参与数值运算,也无法与其他类型进行转换。 切片发生越界时,运行时会报出宕机,并打出堆栈

C++异常机制的分析

岁酱吖の 提交于 2020-02-07 22:02:39
找了很多资料发现这一篇文章写的最好,转载以下: https://blog.csdn.net/cqu20093154/article/details/44020043 ................................................................................................................................................................................... 进程和线程的概念相信各位看官早已耳熟能详。在这里,我只想带大家回忆几点重要概念: 一个进程中可以同时包含多个线程。 我们通常认为线程是操作系统可识别的最小并发执行和调度单位(不要跟俺说还有 Green Thread 或者 Fiber,OS Kernel 不认识也不参与这些物件的调度)。 同一进程中的多个线程共享代码段(代码和常量)、数据段(静态和全局变量)和扩展段(堆存储),但是每个线程有自己的栈段。栈段又叫运行时栈,用来存放所有局部变量和临时变量(参数、返回值、临时构造的变量等)。这一条对下文中的某些概念来说是非常重要的 。但是请注意,这里提到的各个“段”都是逻辑上的说法,在物理上某些硬件架构或者操作系统可能不使用段式存储。不过没关系

晚期(运行期)优化

对着背影说爱祢 提交于 2020-02-07 17:40:34
一、概述 部分商用虚拟机中,Java程序最初通过解释器进行解释执行,当虚拟机发现 某个方法或代码块的运行特别频繁 时,就会把这些代码认定为" 热点代码 "。 为了提高热点代码的执行效率,在运行时,虚拟机将会 把这些代码编译成与本地平台相关的机器码,并进行各种层次的优化 ,完成这个任务的编译器称为 即时编译器 二、HotSpot虚拟机内的即时编译器 2.1 解释器与编译器   事实上,现在许多主流的商用虚拟机,如HotSpot、J9等,都同时包含有解释器与编译器。解释器与编译器两者各有优势: 当程序需要快速启动和执行的时候,解释器可以首先发挥作用,省去编译的时间,立即执行 在程序运行后,随着时间推移编译器逐渐发挥作用,把越来越多的代码编译成本地代码之后,可以获得更高的执行效率。 当程序运行环境中内存限制较大时,可以使用解释执行节约内存,反之可以使用编译执行提高效率 同时,解释器还可以作为编译器激进优化时的一个“逃生门”,让编译器根据概率选择一些大多数时候都能提升运行速度的优化手段,当激进优化的假设不成立,如加载了新类后类型继承结构出现变化、出现罕见陷阱时可以通过逆优化退回到解释状态继续执行(部分没有解释器的虚拟机中也会采用不进行激进优化的C1编译器担任“逃生门”的角色)。因此,解释器与编译器经常配合工作,如下图所示: 2.1.1 Client Compiler 与 Server

Cracking Digital VLSI Verification Interview 第三章

大憨熊 提交于 2020-02-05 21:49:51
目录 Programming Basics Basic Programming Concepts Object Oriented Programming Concepts UNIX/Linux Programming in C/C++ Programming in PERL Programming Basics Basic Programming Concepts [68] 在任何一种编程语言中,静态(static)变量和自动(automatic)变量,局部(local)变量和全局(global)变量之间有什么区别? 区分这些名词需要两个概念,作用域(scope)和存储持续时间(storage duration),前者定义了在何处可以访问变量,后者定义了在何时可以访问变量。 按照变量的作用域可以区分局部(local)和全局(global)变量。局部变量的作用范围有限,尽在声明它们的代码块中可见。而全局变量在声明后在程序的任何位置都可见。 存储持续时间可以区分自动(automatic)变量和静态(static)变量。静态变量的生命周其一直持续到程序结束,因此可以始终访问。自动变量具有有限的生命周期,只能持续到程序离开定义的块或者作用域为止。 例如:在以下的systemverilog代码中,global_int被声明为类成员,并且在整个类中具有全局作用域,而当取消引用该类的对象时