From time to time the error message GEN_BRANCHOFFSET_LIMIT_REACHED pops up. It is a very complex problem right from the heart of the ABAP VM. Let us look quickly at why it happens and some ideas to work around the problem. No, there is no patch for this problem.
Background Information
Any (most?) computer languages have typical limitations that play a role in code generation. The ABAP VM is not exception in this case. One such an limitation is that one IF-statement can only jump 32KB of byte code. So effectively, the source code between the IF- and ENDIF-statements, when compiled, must not be more than 32KB of byte code.
And this plays a big role when the Layout of a BSP page is compiled. (The same rules applies for BSP views as well.) For each BSP page, an ABAP class is generated (in the temporary package $TMP). The name is very criptic, as it constructed from with a GUID (global unique identifier). For example: CL_O2D7QDB5488MACT6YI2S549GQVB.
In the generated class, for the complete layout, source code is generated into one method. The event handlers (OnCreate, OnInitialization, etc) are also placed into separate methods on the same class. In this way, each BSP page is translated into a self contained ABAP class, that is generated and instantiated in one step.
So what the problem effectively states, is that somewhere within a method, there is an IF-statement that has a body that exceeds the jump limitations of the ABAP VM. To understand the problem better, we have to look a little bit at how source code generation is done in BSP.
BSP Source Code Generation
Let us assume a simple BSP page with the following source code:
<%@page language="abap"%> <%IF sy-uzeit < '1200'.%> Good morning <%= sy-uname%>, <%ELSE.%> Good afternoon <%= sy-uname%>, <%ENDIF.%> Welcome back to my great BSP application.
This program shows one technique how an IF-statement can appear within the generated source code. The complete source code (in slightly abstract format) will be:
METHOD _onlayout. * generated by BSP converter version: 200502181048 * generated by BSP compiler version: 1.60 DATA: %_O2X TYPE STRING. "#EC * m_out->print_string( value = _m_html offset = 0 length = 2 ). " CRLF IF sy-uzeit < '1200'. m_out->print_string( value = _m_html offset = 2 length = 15 ). " Good morning... %_O2X = sy-uname. m_out->print_string( value = %_O2X ). ELSE. m_out->print_string( value = _m_html offset = 20 length = 17 ). " Good afternoon... %_O2X = sy-uname. m_out->print_string( value = %_O2X ). ENDIF. m_out->print_string( value = _m_html offset = 17 length = 58 ). " ,CRLF Welcome... ENDMETHOD.
The very first interesting aspect is that all static HTML in the BSP page is stored separately in the database, and dynamically loaded at runtime into one string (_m_html
). Any static HTML sequence, independent of length, is translated into print statement.
ABAP code within the BSP page is emitted verbatim. BSP print sequences (<%=...%>
) are translated to code that first forces the value to a string (effectively using ABAP assign statement), and then just prints the string.
In this example, the generated source code reflects very much the source code that was written on the BSP page, and there is a relationship between the length of the written layout code and the generated source code.
Let us look at a slightly more complex example, where a few BSP tags are used on a page:
<%@page language="abap"%> <%@extension name="htmlb" prefix="htmlb"%> <htmlb:content design="design2003"> <htmlb:page title = "Test Page"> <htmlb:form> <htmlb:button text = "myButton" onClick = "HitMe!" /> </htmlb:form> </htmlb:page> </htmlb:content>
This simplest of simple examples, already generate rather complex code. The reason for this is in the specification of the BSP elements themselves. To allow a flexible architecture, BSP elements can dynamically decide a number of aspects. First, let us look at the generated source for the example (extremely stripped!):
METHOD _onlayout. * generated by BSP converter version: 200502181048 * generated by BSP compiler version: 1.60 DATA: %_elem_rc TYPE I. * <htmlb:content> DATA: %_bsp_elem_0 TYPE REF TO CL_HTMLB_CONTENT. CREATE OBJECT %_bsp_elem_0. %_bsp_elem_0->design = 'DESIGN2003'. %_elem_rc = %_bsp_elem_0->DO_AT_BEGINNING( ). IF %_elem_rc = IF_BSP_ELEMENT=>CO_ELEMENT_CONTINUE. * <htmlb:page> DATA: %_bsp_elem_1 TYPE REF TO CL_HTMLB_PAGE. CREATE OBJECT %_bsp_elem_1. %_bsp_elem_1->title = 'Test Page'. %_elem_rc = %_bsp_elem_1->DO_AT_BEGINNING( ). IF %_elem_rc = IF_BSP_ELEMENT=>CO_ELEMENT_CONTINUE. * <htmlb:form> DATA: %_bsp_elem_2 TYPE REF TO CL_HTMLB_FORM. CREATE OBJECT %_bsp_elem_2. %_elem_rc = %_bsp_elem_2->DO_AT_BEGINNING( ). IF %_elem_rc = IF_BSP_ELEMENT=>CO_ELEMENT_CONTINUE. * <htmlb:button/> DATA: %_bsp_elem_3 TYPE REF TO CL_HTMLB_BUTTON. CREATE OBJECT %_bsp_elem_3. %_bsp_elem_3->text = 'myButton'. %_bsp_elem_3->onClick = 'HitMe!'. %_bsp_elem_3->DO_AT_BEGINNING( ). %_bsp_elem_3->DO_AT_END( ). * </htmlb:form> ENDIF. %_bsp_elem_2->DO_AT_END( ). * </htmlb:page> ENDIF. %_bsp_elem_1->DO_AT_END( ). * </htmlb:content> ENDIF. %_bsp_elem_0->DO_AT_END( ). ENDMETHOD.
The complexity of this source code comes from the fact that the BSP compiler does not know before hand whether a specific BSP element wishes to process its own body (inner BSP elements), or wish to just over the body. The BSP element can decide this during its DO_AT_BEGINNING( ) method. Therefor the BSP compiler generates the IF-statements to test for this condition.
The use of BSP elements is the second source of IF-statements on a BSP page.
Effectively the problem is that the complete layout of one BSP page is placed into one method in a class. And this method now has in its generated form an IF statement that is too large. Any solution must attempt to remove some code from the generated method (which means directly from the layout) and place it somewhere else. Below are three typical approaches that are recommended.
Solution Idea: Use Class Methods to Reduce Layout Code
Probably the simplest technique would be to strip code from the layout of the BSP page, and to place it into a method of class.
Very important: Long sequences of HTML on a page does not make much of a difference in the generated source of the method. The complete HTML sequence is replaced with out print_string
statement to start at a an offset and dump the string for a specific length.
For such work, one should look at large blocks of program code (<%...%>
sequences), or for large blocks of print code (<%= .. %>
). Each of these interrupts the HTML, which causes the print_string
statement to be splitted into a large number of print_string
statements. See the first code generation example above. Let us examine this example code again:
<%@page language="abap"%> <%IF sy-uzeit < '1200'.%> Good morning <%= sy-uname%>, <%ELSE.%> Good afternoon <%= sy-uname%>, <%ENDIF.%> Welcome back to my great BSP application.
What we see is that the <%IF...%>
sequence, and the <%=sy-uname%>
causes many more print_string
statements to be emitted, which contributes significantly to the generated code in the layout method.
One solution would be to place this critical code sequence in a separate method. Then the layout code would reduce to:
<%@page language="abap"%> <%= cl_my_class=>greetings( name = sy-uname ) %> Welcome back to my great BSP application.
In the above coding, greeting
is a method that has a returning parameter of type string. This string is then printed. The method itself would be:
METHOD greetings. " name IMPORTING TYPE STRING " html RETURNING TYPE STRING IF sy-uzeit < '1200'. html = `Good morning`. ELSE. html = `Good afternoon`. ENDIF. CONCATENATE html ` ` name `,` INTO html. ENDMETHOD.
Solution Idea: Use Smaller Views in MVC to Split Layout Code
The use of methods to contain rendering code works well with HTML code, but comes more complex once BSP extensions are used. Although it is possible process BSP elements inside methods, it is not easy to write and main. Recommended is to split large layouts into separate views. One typical example could be to place the content of each tab in a tabstrip onto a separate view.
Let us start with this example again, with the goal to place the <form>
and its content onto a separate view:
<%@page language="abap"%> <%@extension name="htmlb" prefix="htmlb"%> <htmlb:content design="design2003"> <htmlb:page title = "Test Page"> <htmlb:form> <htmlb:button text = "myButton" onClick = "HitMe!" /> </htmlb:form> </htmlb:page> </htmlb:content>
As a first step we create a new view (called my_view.htm
) with the displaced content (cut-and-paste from page to view):
<%@page language="abap"%> <%@extension name="htmlb" prefix="htmlb"%> <htmlb:form> <htmlb:button text = "myButton" onClick = "HitMe!" /> </htmlb:form>
On the page main page (or view!), place now a call to a controller that will embed the view. Keep in mind it is not possible to directly expand views in place. See also that we have now added the BSP extension "BSP".
<%@page language="abap"%> <%@extension name="htmlb" prefix="htmlb"%> <%@extension name="bsp" prefix="bsp"%> <htmlb:content design="design2003"> <htmlb:page title = "Test Page"> <bsp:call url="my_controller.do" comp_id = "view"> <bsp:parameter name="view" value="my_view.htm"/> </bsp:call> </htmlb:page> </htmlb:content>
As a last step, we create a new controller (my_controller.do
). We add one attribute view TYPE string
and implement the do_request
method:
METHOD do_request. DATA: page TYPE REF TO if_bsp_page. page = create_view( view_name = view ). call_view( page ). ENDMETHOD.
Passing parameters to different views can also easily be done via the controller.
Recommended Reading:
- MVC Documentation
- The BSP example application IT05 uses the above simple controller to embed any number of views.
Solution Idea: Use BSP Element Composition to Bundle BSP Elements
The most complex, but also the most rewarding approach, is to group often used BSP elements (must be more than one) into one BSP element. The generated code is dramatically reduced, as only one BSP element is called inline. This BSP element will then process/expand all the other BSP elements that it contain.
This technique is especially of interest when a sequence of BSP elements are used often, typical example could be the sequence <htmlb:label><htmlb:inputField>
. For more complete information, please refer to the recommended documentation.
Recommended Reading:
- Defining Your Own BSP Extension
- Creating a New BSP Extension with Composite Elements
- See the BSP-element
<htmlb:page>
, implemented in classCL_HTMLB_PAGE
. This BSP element processes the complete<htmlb:document*>
family of BSP elements in one step.
Solution Idea: Replace BSP Element Sequences with Light-Weight Sequences
Often BSP elements are just wrappers around simple HTML sequences. However, we have seen that such BSP elements can cause a large explosion in the generated code. The use of the BSP elements are practical, as the BSP compiler will help to valid that large sequences are correctly nested. However, in cases where the generated source code is to large, ir might help to replace a few of these sequences with native code.
Let us assume this typical form layout example:
<%@page language="abap"%> <%@extension name="htmlb" prefix="htmlb"%> <htmlb:content design="design2003"> <htmlb:page title = "Test Page"> <htmlb:form> <htmlb:gridLayout rowSize="2" columnSize="2"> <htmlb:gridLayoutCell rowIndex="1" columnIndex="1"> <htmlb:label text = "Name:" for = "Name" /> </htmlb:gridLayoutCell> <htmlb:gridLayoutCell rowIndex="1" columnIndex="2"> <htmlb:inputField id = "Name" /> </htmlb:gridLayoutCell> <htmlb:gridLayoutCell rowIndex="2" columnIndex="1"> <htmlb:label text = "Email:" for = "Email" /> </htmlb:gridLayoutCell> <htmlb:gridLayoutCell rowIndex="2" columnIndex="2"> <htmlb:inputField id = "Email" /> </htmlb:gridLayoutCell> </htmlb:gridLayout> </htmlb:form> </htmlb:page> </htmlb:content>
Here the <htmlb:gridLayout>
and <htmlb:gridLayoutCell>
tags dominate the code generation, but in the final emited HTML, only reduces to effectively a <table>
sequence. In cases where the generated source code is to large, consider to replace the BSP elements with native HTML code. The example code would then be:
<%@page language="abap"%> <%@extension name="htmlb" prefix="htmlb"%> <htmlb:content design="design2003"> <htmlb:page title = "Test Page"> <htmlb:form> <table> <tr><td> <htmlb:label text = "Name:" for = "Name" /> </td><td> <htmlb:inputField id = "Name" /> </td></tr><tr><td> <htmlb:label text = "Email:" for = "Email" /> </td><td> <htmlb:inputField id = "Email" /> </td></tr> </table> </htmlb:form> </htmlb:page> </htmlb:content>
From written code in the layout section, this sequence has about the same complexity. However, each sequence of HTML reduces to one line of generated source code, whereas each BSP element used will reduce to a large number of lines of generated source code.
The alternative could be to replace the <htmlb:gridLayout>
with the newer <phtmlb:matrix>
. This new BSP element uses new features from the BSP compiler to dramatically reduce the generated code footprint. The internal "cell" tags are not separate BSP elements for which code must be generated, but are simple inline method calls onto the <phtmlb:matrix>
BSP element. This effectively reduces the number of BSP elements for which code must be generated by a large factor.
The example could then be (notice the use of the PHTMLB library):
<%@page language="abap"%> <%@extension name="htmlb" prefix="htmlb"%> <%@extension name="phtmlb" prefix="phtmlb"%> <htmlb:content design="design2003"> <htmlb:page title = "Test Page"> <htmlb:form> <phtmlb:matrix> <phtmlb:matrixCell row="1" col="1"/> <htmlb:label text = "Name:" for = "Name" /> <phtmlb:matrixCell row="1" col="2"/> <htmlb:inputField id = "Name" /> <phtmlb:matrixCell row="2" col="1"/> <htmlb:label text = "Email:" for = "Email" /> <phtmlb:matrixCell row="2" col="2"/> <htmlb:inputField id = "Email" /> </phtmlb:matrix> </htmlb:form> </htmlb:page> </htmlb:content>
1 Comment
Unknown User (105tmlzm5)
Can your solution of use smaller view in MVC to split Layout Code work in ITS environment. Reading the documentation on <bsp: call url talks about Web Application Server. But we are still on ITS. Does it work for ITS?
your reply is greatly appreciated.
Thanks
Krishna Muppavarapu
kmuppa@gmail.com