Additional Blogs by SAP
cancel
Showing results for 
Search instead for 
Did you mean: 
former_member181879
Active Contributor
0 Kudos

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 apply 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 isgenerated 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:




<!code>  <%@page language="abap"%>
<!code>  <%IF sy-uzeit < '1200'.%>
<!code>  Good morning <%= sy-uname%>,
<!code>  <%ELSE.%>
<!code>  Good afternoon <%= sy-uname%>,
<!code>  <%ENDIF.%>
<!code>  Welcome back to my great BSP application.
<!code>   


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:




<!code>  METHOD _onlayout.
<!code>  * generated by BSP converter version: 200502181048
<!code>  * generated by BSP compiler version:  1.60
<!code>    DATA: %_O2X TYPE STRING. "#EC *
<!code>    m_out->print_string( value = mhtml offset = 0 length = 2 ).      " CRLF
<!code>    IF sy-uzeit < '1200'.
<!code>      m_out->print_string( value = mhtml offset = 2 length = 15 ).   " Good morning...
<!code>      %_O2X = sy-uname.
<!code>      m_out->print_string( value = %_O2X ).
<!code>    ELSE.
<!code>      m_out->print_string( value = mhtml offset = 20 length = 17 ).  " Good afternoon...
<!code>      %_O2X = sy-uname.
<!code>      m_out->print_string( value = %_O2X ).
<!code>    ENDIF.
<!code>    m_out->print_string( value = mhtml offset = 17 length = 58 ).    " ,CRLF Welcome...
<!code>  ENDMETHOD.
<!code>   
</pre>

<p>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.</p>

<p>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.</p>

<p>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.</p>

<p>Let us look at a slightly more complex example, where a few BSP tags are used on a page:</p>

<pre>

<!code>  <%@page language="abap"%>
<!code>  <%@extension name="htmlb" prefix="htmlb"%>
<!code>  <htmlb:content design="design2003">
<!code>    <htmlb:page title = "Test Page">
<!code>      <htmlb:form>
<!code>        <htmlb:button text    = "myButton"
<!code>                      onClick = "HitMe!" />
<!code>      </htmlb:form>
<!code>    </htmlb:page>
<!code



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!):




<!code>  METHOD _onlayout.
<!code>  * generated by BSP converter version: 200502181048
<!code>  * generated by BSP compiler version:  1.60
<!code>   
<!code>    DATA: %_elem_rc TYPE I.
<!code>   
<!code>  * <htmlb:content>
<!code>    DATA: %_bsp_elem_0 TYPE REF TO CL_HTMLB_CONTENT.
<!code>    CREATE OBJECT %_bsp_elem_0.
<!code>    %_bsp_elem_0->design = 'DESIGN2003'.
<!code>    %_elem_rc = %_bsp_elem_0->DO_AT_BEGINNING( ).
<!code>    IF %_elem_rc = IF_BSP_ELEMENT=>CO_ELEMENT_CONTINUE.
<!code>   
<!code>  *   <htmlb:page>
<!code>      DATA: %_bsp_elem_1 TYPE REF TO CL_HTMLB_PAGE.
<!code>      CREATE OBJECT %_bsp_elem_1.
<!code>      %_bsp_elem_1->title = 'Test Page'.
<!code>      %_elem_rc = %_bsp_elem_1->DO_AT_BEGINNING( ).
<!code>      IF %_elem_rc = IF_BSP_ELEMENT=>CO_ELEMENT_CONTINUE.
<!code>   
<!code>  *     <htmlb:form>
<!code>        DATA: %_bsp_elem_2 TYPE REF TO CL_HTMLB_FORM.
<!code>        CREATE OBJECT %_bsp_elem_2.
<!code>        %_elem_rc = %_bsp_elem_2->DO_AT_BEGINNING( ).
<!code>        IF %_elem_rc = IF_BSP_ELEMENT=>CO_ELEMENT_CONTINUE.
<!code>   
<!code>  *       <htmlb:button/>
<!code>          DATA: %_bsp_elem_3 TYPE REF TO CL_HTMLB_BUTTON.
<!code>          CREATE OBJECT %_bsp_elem_3.
<!code>          %_bsp_elem_3->text = 'myButton'.
<!code>          %_bsp_elem_3->onClick = 'HitMe!'.
<!code>          %_bsp_elem_3->DO_AT_BEGINNING( ).
<!code>          %_bsp_elem_3->DO_AT_END( ).
<!code>   
<!code>  *     </htmlb:form>
<!code>        ENDIF.
<!code>        %_bsp_elem_2->DO_AT_END( ).
<!code>   
<!code>  *   </htmlb:page>
<!code>      ENDIF.
<!code>      %_bsp_elem_1->DO_AT_END( ).
<!code>   
<!code>  * </htmlb:content>
<!code>    ENDIF.
<!code>    %_bsp_elem_0->DO_AT_END( ).
<!code>   
<!code>  ENDMETHOD.
<!code>   


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. Therefore 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


<p>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.</p>

<p>Very important:</i> 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 an offset and dump the string for a specific length.</p>

<p>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:</p>

<pre>

<!code>  <%@page language="abap"%>
<!code>  <%IF sy-uzeit < '1200'.%>
<!code>  Good morning <%= sy-uname%>,
<!code>  <%ELSE.%>
<!code>  Good afternoon <%= sy-uname%>,
<!code>  <%ENDIF.%>
<!code>  Welcome back to my great BSP application.
<!code>   
</pre>

<p>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.</p>

<p>One solution would be to place this critical code sequence in a separate method. Then the layout code would reduce to:</p>

<pre>

<!code>  <%@page language="abap"%>
<!code>  <%= cl_my_class=>greetings( name = sy-uname ) %>
<!code>  Welcome back to my great BSP application.
<!code>   


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:




<!code>  METHOD greetings.
<!code>    " name IMPORTING TYPE STRING
<!code>    " html RETURNING TYPE STRING
<!code>    IF sy-uzeit < '1200'.
<!code>      html = `Good morning`.
<!code>    ELSE.
<!code>      html = `Good afternoon`.
<!code>    ENDIF.
<!code>    CONCATENATE html ` ` name `,` INTO html.
<!code>  ENDMETHOD.
</pre>


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

and its content onto a separate view:




<!code>  <%@page language="abap"%>
<!code>  <%@extension name="htmlb" prefix="htmlb"%>
<!code>  <htmlb:content design="design2003">
<!code>    <htmlb:page title = "Test Page">
<!code>      <htmlb:form>
<!code>        <htmlb:button text    = "myButton"
<!code>                      onClick = "HitMe!" />
<!code>      </htmlb:form>
<!code>    </htmlb:page>
<!code>  </htmlb:content>
<!code>   


As a first step we create a new view (called my_view.htm) with the displaced content (cut-and-paste from page to view):




<!code>  <%@page language="abap"%>
<!code>  <%@extension name="htmlb" prefix="htmlb"%>
<!code>      <htmlb:form>
<!code>        <htmlb:button text    = "myButton"
<!code>                      onClick = "HitMe!" />
<!code>      </htmlb:form>
<!code>   


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".




<!code>  <%@page language="abap"%>
<!code>  <%@extension name="htmlb" prefix="htmlb"%>
<!code>  <%@extension name="bsp" prefix="bsp"%>
<!code>  <htmlb:content design="design2003">
<!code>    <htmlb:page title = "Test Page">
<!code>      <bsp:call url="my_controller.do" comp_id = "view">
<!code>        <bsp:parameter name="view" value="my_view.htm"/>
<!code>      </bsp:call>
<!code>    </htmlb:page>
<!code>  </htmlb:content>
<!code>   


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:




<!code>  METHOD do_request.
<!code>    DATA: page TYPE REF TO if_bsp_page.
<!code>    page = create_view( view_name = view ).
<!code>    call_view( page ).
<!code>  ENDMETHOD.
<!code>   


Passing parameters to different views can also easily be done via the controller.



Recommended Reading:




Solution Idea: Use BSP Element Composition to Bundle BSP Elements


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:




<!code>  <%@page language="abap"%>
<!code>  <%@extension name="htmlb" prefix="htmlb"%>
<!code>  <htmlb:content design="design2003">
<!code>    <htmlb:page title = "Test Page">
<!code>      <htmlb:form>
<!code>        <htmlb:gridLayout rowSize="2" columnSize="2">
<!code>          <htmlb:gridLayoutCell rowIndex="1" columnIndex="1">
<!code>            <htmlb:label      text = "Name:"  for = "Name" />
<!code>          </htmlb:gridLayoutCell>
<!code>          <htmlb:gridLayoutCell rowIndex="1" columnIndex="2">
<!code>            <htmlb:inputField id   = "Name" />
<!code>          </htmlb:gridLayoutCell>
<!code>          <htmlb:gridLayoutCell rowIndex="2" columnIndex="1">
<!code>            <htmlb:label      text = "Email:"  for = "Email" />
<!code>          </htmlb:gridLayoutCell>
<!code>          <htmlb:gridLayoutCell rowIndex="2" columnIndex="2">
<!code>            <htmlb:inputField id   = "Email" />
<!code>          </htmlb:gridLayoutCell>
<!code>        </htmlb:gridLayout>
<!code>      </htmlb:form>
<!code>    </htmlb:page>
<!code>  </htmlb:content>
<!code>   


<!code>  <%@page language="abap"%>
<!code>  <%@extension name="htmlb" prefix="htmlb"%>
<!code>  <htmlb:content design="design2003">
<!code>    <htmlb:page title = "Test Page">
<!code>      <htmlb:form>
<!code>       

<!code>         

<!code>            <htmlb:label      text = "Name:"  for  = "Name" />
<!code>         

<!code>            <htmlb:inputField id   = "Name" />
<!code>         

<!code>            <htmlb:label      text = "Email:" for = "Email" />
<!code>         

<!code>            <htmlb:inputField id   = "Email" />
<!code>          </td></tr>
<!code>        </table>
<!code>      </htmlb:form>
<!code>    </htmlb:page>
<!code>  </htmlb:content>
<!code>   


<!code>  <%@page language="abap"%>
<!code>  <%@extension name="htmlb"  prefix="htmlb"%>
<!code>  <%@extension name="phtmlb" prefix="phtmlb"%>
<!code>  <htmlb:content design="design2003">
<!code>    <htmlb:page title = "Test Page">
<!code>      <htmlb:form>
<!code>        <phtmlb:matrix>
<!code>          <phtmlb:matrixCell row="1" col="1"/>
<!code>            <htmlb:label      text = "Name:"   for = "Name" />
<!code>          <phtmlb:matrixCell row="1" col="2"/>
<!code>            <htmlb:inputField id   = "Name" />
<!code>          <phtmlb:matrixCell row="2" col="1"/>
<!code>            <htmlb:label      text = "Email:"  for = "Email" />
<!code>          <phtmlb:matrixCell row="2" col="2"/>
<!code>            <htmlb:inputField id   = "Email" />
<!code>        </phtmlb:matrix>
<!code>      </htmlb:form>
<!code>    </htmlb:page>
<!code>  </htmlb:content>
</pre>
2 Comments