Gradual loss of memory in Opl programs with menus ================================================= This note should be read by any party producing commercial Series3 Opl programs with menus. The problem ----------- There are some circumstances in which Opl programs with menus can gradually lose small amounts of system memory. All memory lost in this way is fully recovered by the Series3 when the Opl application exits, but if the application runs for a long time without exiting, it is possible that the cumulative amount of memory lost will in time adversely affect the performance of the application. This bug is present in all versions of the Series3. The bug does not affect any programs written in C. The solution ------------ By adding a few extra lines of Opl code to a program, it can be ensured that no memory loss of this sort will occur. These lines include machine code accessed by the USR keyword, which have to be typed in exactly correctly, or else random damage might ensue on the Series3. In practice, these lines of machine code would be copied from an existing source, rather than being typed in afresh. The changes required in an Opl program are as follows (or equivalent): 1) Three global arrays have to be declared; their names don't particularly matter but they could be pt1&(7), pt2&(7), pt3&(8). 2) A call has to be made to a procedure, ptinit: say, in application start up code, before any call to MENU is made; this routine ptinit: (source code given below) copies the relevant machine code into the two arrays pt1&() and pt2&(). 3) Instead of calling MENU directly, a procedure menu%: has to be defined, which includes one call to USR before the call to MENU, and another afterwards (see below for an example menu%:). The inconvenience of requiring an extra layer around calls to MENU is slight, for commercial Opl programs, since these programs are likely to have such a layer already, for example to make calls to LOCK on either side of the call to MENU. Further notes: -------------- In the example program below, the program is dominated, size-wise, by the "patch" code. However, in a realistic commerical application, the amount of code in the "patch" will hardly be significant. If desired, the contents of the procedures ptinit: and menu%: could of course be placed in-line in the calling procedures. The machine code called by the USR commands automatically detects the case when no memory has been lost by the MENU command, and does nothing in this case. It is very unlikely that anyone could notice any speed degradation on account of calling menu%: each time instead of just MENU. For a further simplification of the patch code, the contents of ptinit: could be moved inside menu%:, with virtually no detectable speed degradation, but with the advantage that the three global arrays can become local variables inside menu%:. There is no need to alter any Opl programs which are only used for casual purposes, which do not contain MENU calls, or which are only likely to be run for short periods of time before being exited. Example of changed Opl code --------------------------- PROC test: global pt1&(7),pt2&(7),pt3&(8) local m% ptinit: do mInit mCard "Menu 1","Option 1",%a mCard "Menu 2","Exit",%x m%=menu%: if m%=%a giPrint "Option 1 selected" endif until m%=%x ENDP PROC ptinit: pt1&(1)=&8BF88BFC pt1&(2)=&8B00121E pt1&(3)=&778B205F pt1&(4)=&E42AAC0C pt1&(5)=&A5ABC88B pt1&(6)=&75C084AC pt1&(7)=&CBF8E2FB pt2&(1)=&00B4F08B pt2&(2)=&FC808BCD pt2&(3)=&AD0D7330 pt2&(4)=&C932D08B pt2&(5)=&CDD88BAD pt2&(6)=&F8754ACF pt2&(7)=&CB ENDP PROC menu%: local r% usr(addr(pt1&(1)),addr(pt3&(1)),0,0,0) r%=menu usr(addr(pt2&(1)),addr(pt3&(1)),0,0,0) return(r%) ENDP