Java Bytecode to Native Code Translation: the Caffeine Prototype and Preliminary Results
Total Page:16
File Type:pdf, Size:1020Kb
Java Bytecode to Native Code Translation: The Caffeine Prototype and Preliminary Results Cheng-Hsueh A. Hsieh John C. Gyllenhaal Wen-mei W. Hwu Center for Reliable and High-Performance Computing University of Illinois Urbana-Champaign, IL 61801 ada, gyllen, [email protected] Abstract exists behind efforts to create such a software distribution language. The progress, however, has been very slow due to The Java bytecode language is emerging as a software legal and technical difficulties. distribution standard. With major vendors committed to On the legal side, many software vendors have been porting the Java run-time environment to their platforms, skeptical about the ability of the proposed software distribution programs in Java bytecode are expected to run without languages to protect their intellectual property. In practice, modification on multiple platforms. These first generation run- such concern may have to be addressed empirically after a time environments rely on an interpreter to bridge the gap standard emerges. Although the protection of intellectual between the bytecode instructions and the native hardware. property in software distribution languages is an intriguing This interpreter approach is sufficient for specialized issue, it is not the topic addressed by this paper. For the applications such as Internet browsers where application purpose of our work, we expect Java to be accepted by a performance is often limited by network delays rather than sufficient number of software vendors in the near future to processor speed. It is, however, not sufficient for executing make our work relevant. general applications distributed in Java bytecode. This paper On the technical side, the performance of programs presents our initial prototyping experience with Caffeine, an distributed in a universal software distribution language has optimizing translator from Java bytecode to native machine been a major concern. The problem lies in the mismatch code. We discuss the major technical issues involved in stack between the virtual machine assumed by the software distribution language and the native machine architecture. The to register mapping, run-time memory structure mapping, and task of bridging the gap is made more difficult by the lack of exception handlers. Encouraging initial results based on our source code information in the distributed code in order to X86 port are presented. protect intellectual property. As a result, software interpreters have been the main execution vehicles in the proposed standards. The disadvantage of software interpreters is poor 1. Introduction performance. This disadvantage has been partially compensated for by the fast advance of microprocessor speed. The software community has long desired a universal For applications such as Internet browser applets where overall software distribution language. If such a language is widely performance is often more limited by network delays than supported across systems, software vendors can compile and processor speed, sacrificing processor performance in favor of validate their software products once in this distribution reducing software cost has become acceptable. This is, language, rather than repeating the process for multiple however, not true for general applications. platforms. Software complexity is rapidly increasing and This paper presents our initial prototyping experience with validation has become the deciding factor in software cost and Caffeine, an optimizing Java bytecode to native machine code time to market. Therefore, substantial economic motivation translator. Although our techniques are presented in the context of handling Java, they are applicable to other software distribution languages such as Visual Basic P-code. We are by no means arguing that Java is the ultimate software distribution Copyright 1996 IEEE. Published in the Proceedings of the 29th Annual International Symposium on Microarchitecture, December 2-4, 1996, Paris, France. language. Rather, we intend to develop a strong portfolio of Personal use of this material is permitted. However, permission to reprint/republish techniques from our Java implementation efforts that will this material for resale or redistribution purposes or for creating new collective works contribute to the creation and acceptance of whatever language for resale or redistribution of servers or lists, or to reuse any copyrighted component of becomes the final standard. The objective of this work is to run this work in other works, must be obtained from the IEEE. Contact: Manager, the translated code at nearly the full performance of native code Copyrights and Permissions /IEEE Service Center / 445 Hoes Lane / P. O. Box 1331 / Piscataway, NJ 08855-1331, USA. Telephone: + Intl. 908-562-3966 1 directly generated from a source representation such as the C comparison between these approaches and native code programming language. execution are presented in Section 7. Due to space limitations, we will limit our discussion to Interpreters are the most widely understood approach to three critical issues involved in the translation process. The execute Java bytecode programs. A software interpreter first issue is the mapping of the stack computation model of the emulates the Java bytecode Virtual Machine by fetching, bytecode Virtual Machine to the register computation model of decoding, and executing bytecode instructions. In the process, modern processors. A performance enhancing algorithm that it faithfully maintains the contents of the computation stack, takes advantage of the register computation model is presented. local memory state, and structure memory. The Java interpreter This algorithm requires analysis to identify the precise stack from SUN Microsystems is available to the public [2]. pointer contents at every point of the program. In addition, Just-in-time compilers do on-the-fly code generation and most compilation infrastructures require that each virtual cache the native code sequences to speed up the processing of register contains just one type of data, and that virtual registers the original bytecode sequences in the future. The current do not overlap. We present a live-range-based register- generations of just-in-time compilers do not save the native renaming algorithm that can resolve such inconsistencies in code sequences in external files for future invocations of the non-pathological cases. The second issue is mapping the same program. Rather, they keep the native code sequence to bytecode memory organization to the native architecture. A speed up the handling of the corresponding bytecode sequence more efficient memory organization than the one used by the during the same invocation of the program. Thus, they take Java interpreter is introduced. The third issue is how to advantage of iterative execution patterns such as loops and translate the exception handling semantics of Java. We recursion. At the time of this work, Borland [12] and Symantec describe the preliminary method used by Caffeine and some of [13] had both announced just-in-time compiler products, and the issues involved. the Symantec JIT compiler is used in this paper. Due to the A prototype of Caffeine has been developed based on the code generation overhead that occurs during program execution, IMPACT compilation infrastructure [1]. The prototype is just-in-time compilers are still intrinsically slower than sufficiently stable to handle Java bytecode programs of executing native code programs. substantial size. This paper presents some initial experiments Optimizing native code translators use compiler analysis to comparing the real machine execution time of Java bytecode translate bytecode programs into native code programs off-line. programs using the SUN Java interpreter 1.0.2, the Symantec This is the least understood approach among the three Java Just-in-time (JIT) compiler 1.0, and the IMPACT Java to alternatives. Without extensive analysis and transformation X86 native code translator 1.0 running under Windows 95. capabilities, the native code generated may not be much better Also included in the comparison is the execution time of than that cached in the just-in-time compilers. Therefore, equivalent C programs directly compiled by the Microsoft optimizing native code translators must perform extensive Visual C/C++ compiler 4.0 into X86 native code. Preliminary analysis and optimization in order to offer value beyond just-in- results show that the optimizing translator is currently capable time compilers. Such analysis and transformations tend to of achieving, on average, 68% of the speed of the directly make the translation process more expensive in time and space. compiled native code. In general, only those applications that will be repeatedly The remaining sections are organized as follows. Section 2 invoked or those applications whose execution time is much introduces different approaches to execute Java bytecode longer than the translation time should be translated. Thus, programs and an overview of our translation steps. Section 3 optimizing native code translators will not eliminate the need presents the stack computation model used by Java followed by for interpreters and just-in-time compilers. a proposed stack to register mapping. An overview of the stack Figure 1 shows an overview of the steps in our prototype analyses required to perform and validate this mapping is optimizing native code translator. The Java class files [4] introduced in Section 4. Section 5 discusses the run-time required