Abstract:
A system and method for efficient string concatenation in a virtual machine (VM), or other runtime environment, and particularly for use in a system that includes a Java Virtual Machine (JVM). An embodiment improves the performance of string concatenation significantly by analysing the string concatenation chains during bytecode compilation and replacing the dynamic string concatenation code with fixed size structures without bounds checks or locks. The resulting code is also more suitable for inlining.

Description:
CLAIM OF PRIORITY 
       [0001]    This application claims the benefit of U.S. Provisional Application No. 60/870,578, entitled “SYSTEM AND METHOD FOR EFFICIENT STRING CONCATENATION IN A VIRTUAL MACHINE ENVIRONMENT”, filed Dec. 18, 2006, and herein incorporated by reference. 
     
    
     COPYRIGHT NOTICE 
       [0002]    A portion of the disclosure of this patent document contains material which is subject to copyright protection. The copyright owner has no objection to the facsimile reproduction by anyone of the patent document or the patent disclosure, as it appears in the Patent and Trademark Office patent file or records, but otherwise reserves all copyright rights whatsoever. 
       FIELD OF THE INVENTION 
       [0003]    The invention is generally related to virtual machine environments and other runtime environments, and in particular to a system and method for improving string concatenation within such environments. 
       BACKGROUND 
       [0004]    Virtual machines are complex software products that can be used to increase portability and stability of application software. Instead of compiling applications for a particular hardware platform, the applications are instead compiled for a virtual platform. A virtual machine tailored for a particular hardware platform then executes the applications compiled for the virtual machine. The virtual operations are, by tradition, referred to as “byte code”. Java is a language that is compiled to byte code, and the resulting applications are then executed within the virtual machine, or in the particular case of Java, a Java Virtual Machine (JVM). Examples of such virtual machines include the Hotspot product from Sun Microsystems, Inc., and the JRockit product from BEA Systems, Inc. The Java byte code supports several built-in types for variables, for example: integers, floating point numbers, characters, bytes, booleans, pointers to objects, arrays of these types, and objects containing these types. The Java language also includes a large library of useful objects and functions referred to as the Java Development Kit (JDK). The JDK is written in Java, and the compiled library needs to be present both at application compile time and at runtime. 
         [0005]    Java is often used for interactive web applications, which generate web pages by concatenating static strings with strings, and other values from database searches. A particular problem with string concatenation is that, using traditional methods, even a simple string concatenation results in a long chain of calls, wherein each call is dependent on the previous call. These calls are handled using an append feature. However, implementations of buffer append classes, wherein the final length is unknown, starts with a small buffer size that is then doubled each time the buffer is exhausted. For each of these doubling steps a memory copy of the full buffer has to take place. This means that a lot of processor (CPU) time is spent just copying the same information over and over again, which impacts the system&#39;s performance, and any applications that are running thereon. As such, any improvement to the JVM that increases its performance would also provide significant performance improvements for web applications. This is the area the invention is designed to address. 
       SUMMARY 
       [0006]    Disclosed herein is a system and method for efficient string concatenation in a virtual machine (VM), or other runtime environment, and particularly for use in a system that includes a Java Virtual Machine (JVM). In particular, current techniques for string concatenation within JVMs are suboptimal. In accordance with an embodiment, a system and a method is provided to efficiently concatenate strings by reducing the number of times memory is copied, and allow for optimizations of the concatenation code. In accordance with an embodiment, the system provides for efficient string concatenation in a virtual machine environment, comprising: a virtual machine for executing a software application; a memory space for the software application bytecode; a bytecode compiler, comprising a string concatenation sequence detector and transformer; a memory space for the compiled application; a memory space for use by the virtual machine in storing software objects and pointers as part of the software application; a memory space for singleton strings; and a structure or logic for string concatenation of a fixed number of strings. 
         [0007]    In accordance with another embodiment, each element of a chain of concatenations, that normally comprises at least two allocations and a function call including bounds checks, are reduced to a single function call with no bounds checks. 
         [0008]    In accordance with another embodiment, a chain of concatenations is reduced to a single concatenation call with multiple arguments. 
         [0009]    In accordance with another embodiment, the single concatenation functions are generated automatically by the compiler to adapt to the usage statistics of string concatenation within the application. 
         [0010]    In accordance with another embodiment, the compiler decides on the basis of the compiled bytecode how large the fixed number of strings, that can be stored in the structure or logic for string concatenation, should be. 
     
    
     
       BRIEF DESCRIPTION OF THE FIGURES 
         [0011]      FIG. 1  shows an illustration of a system in accordance with an embodiment of the present invention that uses a compiler with a string concatenation detector to generate more efficient string concatenation code. 
           [0012]      FIG. 2  shows a schematic of the memory layout in accordance with an embodiment of the present invention, for an improved string concatenation structure or logic. 
           [0013]      FIG. 3  shows a flowchart in accordance with an embodiment of the invention that illustrates the detection of string concatenation chains. 
       
    
    
     DETAILED DESCRIPTION 
       [0014]    Disclosed herein is a system and method for efficient string concatenation in a virtual machine (VM), or other runtime environment, and particularly for use in a system that includes a Java Virtual Machine (JVM). In particular, current techniques for string concatenation within JVMs are suboptimal. Using traditional methods, even a simple string concatenation results in a long chain of calls, wherein each call is dependent on the previous call. These calls are handled using an append feature. However, implementations of buffer append classes, wherein the final length is unknown, starts with a small buffer size that is then doubled each time the buffer is exhausted. For each of these doubling steps a memory copy of the full buffer has to take place, which requires a lot of processor (CPU) time, and which impacts the system&#39;s performance, and any applications that are running thereon. An embodiment addresses this problem by providing a system and a method to efficiently concatenate strings by reducing the number of times memory is copied and allow for optimizations of the concatenation code. 
         [0015]    Within the Java Development Kit (JDK), the “String” object does not have a built-in byte code representation. Instead, the String object is implemented using character arrays that are wrapped inside a Java object named “String”, and the JDK contains the implementation of the String object. The JVM is instead only required to support a function named “intern”. The intern function takes a character array as an argument, and returns a singleton for that unique sequence of characters. The intern function is used to guarantee that multiple instances of strings that have the same sequence of characters share the same character array. 
         [0016]    String objects in Java are immutable. As a String object is created, the intern function is called to guarantee a reduced memory footprint if the unique sequence of characters has already been used. To create new Strings out of old Strings, the Java language contains a “+ operator” (i.e. a “plus” operator) for concatenating Strings. However the + operator is not implemented in bytecode, nor is it a fixed function in the Java libraries. It is instead syntactic sugar that is understood by the Java compiler (for example, the javac compiler). When the + operator is used, the compiler will identify the type of the object to be appended to the String, and insert suitable byte code for concatenation. 
         [0017]    Traditionally the + operator has been implemented using a JDK construct referred to as StringBuffer (up to and including Java 1.4). As of Java 1.5, the javac compiler uses instead another construct referred to as StringBuilder, which is similar in design but provides better performance, since the old StringBuffer design used many unnecessary synchronizations. The following method is used as an example throughout this description: 
         [0000]                                      Listing 1                                    public int hashCode( ){             return (Sfield_a + Sfield_b + Ifield_c).hashCode( );           }                        
Wherein Sfield_a and Sfield_b are instance fields that are Strings, and Ifield_c is an instance field that is an int. The Java compiler translates the + operator shown above into byte code that is equivalent to the byte code generated from the following Java code:
 
         [0000]                                                    Listing 2                                    StringBuilder tmp = new StringBuilder( );                tmp2 = tmp.append(Sfield_a);   // tmp2 == tmp           tmp3 = tmp2.append(Sfield_b);   // tmp3 == tmp2           tmp4 = tmp3.append(Ifield_c);   // tmp4 == tmp3           String str = tmp4.toString( );           return str.hashCode( );                        
The resulting byte code then looks as shown below:
 
         [0000]                                                            Listing 3                                    0:   new   #2; //class java/lang/StringBuilder                3:   dup               4:   invokespecial   #3;                   //Method java/lang/StringBuilder                   .“&lt;init&gt;”:( )V           7:   aload_0           8:   getfield   #4; //Field Sfield_a:Ljava/lang/String;           11:   invokevirtual   #5;                   //Method java/lang/StringBuilder                   .append:(Ljava/lang/String;)                   Ljava/lang/StringBuilder;           14:   aload_0           15:   getfield   #6; //Field Sfield_b:Ljava/lang/String;           18:   invokevirtual   #5;                   //Method java/lang/StringBuilder                   .append:(Ljava/lang/String;)                   Ljava/lang/StringBuilder;           21:   aload_0           22:   getfield   #7; //Field Ifield_c:I           25:   invokevirtual   #8;                   //Method java/lang/StringBuilder                   .append:(I)Ljava/lang/StringBuilder;           28:   invokevirtual   #9;                   //Method java/lang/StringBuilder                   .toString:( )Ljava/lang/String;           31:   invokevirtual   #10;                   //Method java/lang/String.hashCode:( )I           34:   ireturn                        
The earlier Java 1.4 version would look exactly the same, except that it would use StringBuffer instead of StringBuilder. The progress of the byte code can be traced as follows:
 
         [0018]      0 : allocate a new StringBuilder. 
         [0019]      4 : call the StringBuilder constructor. 
         [0020]      11 : call append on the StringBuilder with Sfield_a as the argument. 
         [0021]      15 : append is called again with Sfield_b  22 : append is called again with Ifield_c. 
         [0022]      28 : an immutable String is created from the StringBuilder. 
         [0023]      31 : the has Code for the String is calculated. 
         [0024]    What seemed as first to be a simple string concatenation, actually turns out to be a long chain of calls, wherein each call is dependent on the previous call. In some JVM&#39;s, for example JRockit, the compiler inside the JVM assumes that parameters to calls escape from the function, and that the system can therefore not perform advanced compiler optimizations on these parameters. It is possible for systems such as the JRockit system to inline calls and to enable compiler optimizations on the parameters since they are no longer escaping (unless of course the inlined function itself makes other calls with the same values). However the append functions are not usually considered for inlining because they are not short enough, which means that string concatenation is not as optimized as it could be. Traditionally, implementations of buffer append classes, wherein the final length is unknown, starts with a small buffer size that is then doubled each time the buffer is exhausted. For each of these doubling steps a memory copy of the full buffer has to take place. As mentioned above, this means that a lot of processor (CPU) time is spent just copying the same information over and over again. Since Java is often used for interactive web applications, which generate web pages by concatenating static strings with strings, and other values from database searches, any improvement to the JVM that reduces the amount of copying and optimizes the concatenation code would provide significant performance improvements for web applications. 
         [0025]      FIG. 1  shows an illustration of a system in accordance with an embodiment that uses a compiler with a string concatenation detector to generate more efficient string concatenation code. As shown in  FIG. 1 , the system  101  comprises a computer server  102  that further comprises a computer hardware  103 . The computer hardware runs an operating system  104 . A virtual machine such as a Java Virtual Machine  105  runs within the operating system. The JVM contains the application software as byte code  106 . The bytecode is compiled using the bytecode compiler  107 . The detector  108  detects any string concatenation chains, and the compiler transforms these into more efficient code. The resulting native code is stored in the memory space  109 . When the application software is concatenating it makes use of the Java Heap  110 , which contains String objects  111 . The String objects refer to singleton instances of unique character arrays  112  stored as part of the char array singleton  113  memory space. In accordance with an embodiment, the system uses a StringMaker  114 , which is an improved string concatenation structure or logic, described in further detail below. 
         [0026]      FIG. 2  shows a schematic of the memory layout in accordance with an embodiment of the present invention, for an improved string concatenation structure or logic. As shown in  FIG. 2 , the string concatenation structure or logic is referred to as a StringMaker  201 . In accordance with an embodiment the StringMaker contains a fixed array  202  with pointers to the string objects  203  that are to be concatenated. In accordance with an embodiment, the maximum capacity of the array is set as 16 elements. The traditional StringBuilder append operation needs to verify the capacity of the char array inside the StringBuilder, and if necessary it has to allocate a larger char array and copy the contents of the original array into the new larger array. In contrast, the StringMaker only needs to store a pointer to the appended string in the next available position  204  in the fixed array. No bounds checking is needed, because the compiler guarantees that the StringMaker will only be used in situations where at most 16 strings need to be concatenated. In accordance with an embodiment the value of 16 was selected by profiling common Java applications; in accordance with other embodiments a different value could be used. 
         [0027]    In accordance with an embodiment the StringMaker does not have an internal character array. Its purpose is to remember the string objects, until it is time to create a new string using the tostring method on the StringMaker. When the tostring method is called, it iterates through all strings pointed to from  202 , and sums the length of the strings. This is only possible because Java Strings are immutable; there is no risk that the strings will change between the append and the later concatenation. A single allocation for the new concatenated string is then performed and the contents of the strings are copied into the new string. The StringMaker does not need any locking because the compiler will only insert StringMakers in string concatenation chains that have certain properties, described in further below. The StringMaker therefore reduces the overhead of string concatenation significantly. 
         [0028]      FIG. 3  shows a flowchart in accordance with an embodiment, that illustrates the detection process of string concatenation chains. As shown in  FIG. 3 , the process begins at step  301  by putting the intermediate representation of the bytecode into single static assignment (SSA) form. Next, at step  302 , an allocation site of a StringBuilder within a limited scope is detected. A suitable limited scope is a basic block within a Java function. In step  303 , the compiler collects a chain using the starting point gathered in the previous step, and using the properties of the SSA-form. At step  304 , the compiler has to verify that, after each StringBuilder allocation, there is exactly one call to its constructor. In step  305 , the append chain consists of a number of appends that all return a new StringBuilder which is used only in one append, or (in step  306 ) a toString, which is considered the end of the chain. Aliasing are permitted, such as moving a variable to another as part of the chain, but joins are not allowed. Finally, in accordance with an embodiment that uses a 16 element array, if the chain uses more than 16 appends, it is ignored. 
         [0029]    In another embodiment of the invention, the compiler can replace the fixed size array of 16 elements with a StringMaker constructor that initiates the array to a proper size that will then encompass the chain size. 
         [0030]    The public API of StringBuilder and StringBuffers specifies that their arguments do not escape, so that when a chain has been found that have the properties above, it follows that none of its elements escape, except for the last toString result. In this instance there are no side effects and it will not need synchronization. It is therefore safe to perform the string concatenation in any other way or order, as long as the result is the same. 
         [0031]    Embodiments of the present invention can therefore be used to replace the StringBuilder allocation and method calls with corresponding StringMaker allocation and calls. The resulting code will be identical to listing  2 , except that StringBuilder is replaced with StringMaker. The StringMaker methods are much shorter than their StringBuilder counterparts, and can be so because the compiler has already statically performed the bounds checks and locking verification as described above. As a result the string concatenation uses a minimal amount of copying and allocation, and the append calls are small enough to be inlined for even higher performance. 
       Collapsing the Concatenation Chain and Keeping the Semantics 
       [0032]    In accordance with an embodiment, it is possible to improve the performance even more by collapsing the concatenation chain. In accordance with one embodiment this is performed by replacing a chain of append calls into a single call to a function with multiple arguments. This is beneficial because, even though the append performance is significantly improved, there is still the call overhead for each append. If, for example, we have three appends in a row, taking a string, a string and an int respectively as in listing  2  above, it can be replaced with a single call append(String, String, int). Thus, listing  2  can then be turned into: 
         [0000]    
       
         
               
             
               
               
             
           
               
                   
               
               
                 Listing 4 
               
               
                   
               
             
             
               
                   
               
             
          
           
               
                   
                 StringMaker tmp = new StringMaker( ); 
               
               
                   
                 tmp2 = tmp.appendSSI(Sfield_a, Sfield_b, Ifield_c);// tmp2 == tmp 
               
               
                   
                 String str = tmp2.toString( ); 
               
               
                   
                 return str.hashCode( ); 
               
               
                   
                   
               
             
          
         
       
     
         [0033]    It is not likely that one would want to create append variations for all possible append situations in advance. Profiling of common Java applications indicates that if the 10 most common combinations of length  3  are created in advance, then this will give a measurable performance improvement. In accordance with an embodiment, a detection algorithm first tries to look up customized append functions by synthesizing descriptors from the detected append chain. It starts with the longest possible descriptor, and gradually decreases the number of arguments until an appropriate StringMaker-append can be found. If no pre-created append variation is found, then it reduces to the original append methods in StringBuilder, now reimplemented by StringMaker. 
         [0034]    In accordance with another embodiment, the system uses the virtual machine to perform a runtime analysis of the concatenation chains that are used in the application, and automatically generate the optimal combination of append functions for a particular application. For example, if an application often executes an append chain that takes two strings, one float, and one int in that order, then an embodiment can generate an append(String, String, float, int) function to improve performance. 
         [0035]    The present invention may be conveniently implemented using a conventional general purpose or a specialized digital computer or microprocessor programmed according to the teachings of the present disclosure. Appropriate software coding can readily be prepared by skilled programmers based on the teachings of the present disclosure, as will be apparent to those skilled in the software art. 
         [0036]    In some embodiments, the present invention includes a computer program product which is a storage medium (media) having instructions stored thereon/in which can be used to program a computer to perform any of the processes of the present invention. The storage medium can include, but is not limited to, any type of disk including floppy disks, optical discs, DVD, CD-ROMs, microdrive, and magneto-optical disks, ROMs, RAMs, EPROMs, EEPROMs, DRAMs, VRAMs, flash memory devices, magnetic or optical cards, nanosystems (including molecular memory ICs), or any type of media or device suitable for storing instructions and/or data. 
         [0037]    The foregoing description of the present invention has been provided for the purposes of illustration and description. It is not intended to be exhaustive or to limit the invention to the precise forms disclosed. Many modifications and variations will be apparent to the practitioner skilled in the art. Particularly, it will be evident that while the examples described herein illustrate how the features may be used in a WebLogic or JRockit environment, other application servers, virtual machines, JVMs, computing environments, and software development systems may use and benefit from the invention. The code examples given are presented for purposes of illustration. It will be evident that the techniques described herein may be applied using other code languages, and with different code. 
         [0038]    The embodiments were chosen and described in order to best explain the principles of the invention and its practical application, thereby enabling others skilled in the art to understand the invention for various embodiments and with various modifications that are suited to the particular use contemplated. It is intended that the scope of the invention be defined by the following claims and their equivalence.