This chapter provides some information to help you compile and debug OO COBOL applications.
The processes for compiling an OO application are very similar to those described for all COBOL applications elsewhere in your documentation set.
Use the standard Micro Focus Compiler to compile your OO COBOL programs.
Use the OOCTRL Compiler directive to control behavior that is specific to OO COBOL programs. This provides a number of options, which you set on or off by use of the + and - signs respectively, preceding the option character. The options are:
F | Specifies whether or not to fold method names invoked by the program being compiled to lower case. Use -F if your program calls Java methods, since Java method names are case-sensitive. See your Distributed Computing book for information on using Java and COBOL together. |
G | Specifies whether to make class data global for instances. The use of this option is not recommended. It is provided for compatibility with earlier releases. |
P | Specifies whether to make parameter type information available to the run-time system. This is needed for messages sent to COM. The number of parameters in any method called or declared is limited to 31, plus an optional return value. |
Q | Specifies whether to disable the use of:
|
W | Specifies whether to use Working-Storage Section to mean Object-Storage Section in instances and factory objects (class objects). |
The default is OOCTRL(+F-G-P+Q+W)
If you want to use conformance checking, you must set the REPOSITORY directive. This controls whether or not information about the interfaces you create are stored in the external repository file, and whether new classes are checked for conformance. You might also need to set the RDFPATH directve, which specifies where the external repository is stored.
If you use parameterized classes or parameterized interfaces, you need to set the ACTUAL-PARAMS directive.
Do not set the ALIGN directive when compiling classes. This can cause unpredictable errors at run-time. All classes in the supplied class libraries are compiled with the default value of ALIGN(8).
When you compile OO programs to native code (for linking to .exe or .dll files), set the following compiler directives to optimize the result for fast execution:
CASE FASTCALLS FASTLINK NOFIXOPT NOPARAMCOUNTCHECK NOREENTRANT NOSERIAL
There are two exceptions to this advice:
procedure division using p1 p2 ... returning p5 if address of p1 <> null ... end-if if address of p2 <> null ... end-if
For more details of these directives see your Compiler Directives documentation.
If you use the Micro Focus syntax for inheriting data directly from a superclass (WITH DATA clause in Class-ID paragraph), you must compile the superclass first. Data is inherited directly through .cls and .ins files generated by the Compiler from the Object-Storage Sections in a class. These files must be available before you compile any subclass that inherits the data. See the section Data Inheritance in the chapter Micro Focus OO COBOL Alternative Syntax for more information.
Note: If you change the Object-Storage definitions in a class, you must recompile any of its subclasses that inherit its data. Otherwise, run-time behavior is unpredictable.
Net Express:
If you rebuild the whole project, Net
Express automatically compiles classes in the right order.
Many of the same tools and techniques used for debugging COBOL applications are applicable to OO COBOL applications. You can animate the classes in an application in the same way that you can animate any COBOL program.
When you query an object reference, the Animator displays the object handle contained in the object reference. This enables you to see whether object references are pointing to the same or different objects. An object handle with value x"0000" always refers to the NilObject. An object handle with the value of x"20202020" is reserved by the run-time system. Sending messages to it gives the error message "Invalid object reference".
There are some extra facilities to help you with some debugging problems that are unique to OO programs:
These facilities are explained in the following sections.
The run-time system has a debugging option to prevent reallocation of object handles. The default behavior of the run-time system is to reuse the object handle for any object which has been finalized.
An application which sends messages to object handles after the object referenced has been finalized can cause unpredictable behavior. The message may be sent to a new object which has been allocated the old handle.
If the message sent is one the new object does not understand, then the "doesNotUnderstand" exception is raised, alerting you to the fact that something has gone wrong. If the new object does understand the message, then it will execute a method, and your application may fail at some later point, or give unexpected results.
To prevent reallocation of object handles, set environment variable OOSW to+d:
Net Express:
set oosw=+d
Server Express:
OOSW=+d export OOSW
Now when a message is sent to an object handle for an object which no longer exists, the run-time system displays the following error message:
RTS 240 Object reference not valid
Note: The +d setting for OOSW is intended for development work only. Do not set +d in a production environment, as the run-time system could eventually run out of object handles to allocate. The number of object handles the run-time system can allocate before this happens depends on the amount of memory available.
A memory leak is memory allocated to an object which is no longer in use by your application, but which has not been finalized. One way to track down memory leaks is to watch the number of objects in your application. For example, if adding a record created an extra 24 objects, but deleting it only removed 20, a memory leak is a possibility.
You can find out the number of objects in existence at any time by sending the message "getNumberOfObjects" to the Behavior class. For example:
invoke Behavior "getNumberOfObjects" returning totalNumber
where totalNumber
is declared as a pic x(4) comp-5
.
A guard page is a page of memory that has special permissions set on it so that it cannot be read or written to. By placing guard pages before or after pages assigned to object data storage, the run-time system can catch attempts to read or write beyond the ends of object data.
On some systems guard pages can help you track down some types of memory corruption problem. Check your product release notes to see whether they are supported on your system. They can help you find errors on two types of memory:
You can use guard pages to trap either:
These sorts of problems can occur when you are using reference modification to access data, or when you pass object data as a parameter to a method that tries to access it using Linkage Section data items declared as the wrong size. If you are using the Base class methods "malloc" and "dealloc" to allocate and free memory, the following types of error are also trapped:
If any of these types of errors occur when you are running with guard pages active, you will get run-time error 114; if you are animating the program execution stops with the statement that caused the problem highlighted.
You can set the guard pages before or after object data and memory allocations.
To set the guard page before object data and memory allocations:
Net Express:
set oosw=+g1
Server Express:
OOSW=+g1 export OOSW
To set the guard page after object data and memory allocations:
Net Express:
set oosw=+g2
Server Express:
OOSW=+g2 export OOSW
Switches +g1 and +g2 are mutually exclusive - you cannot set them both at the same time.
Note: Running with guard pages on increases the amount of memory used by your application. Only use it for debugging.
If you are having problems with finding the point at which an application fails or raises an exception, you can switch on a message trace. This can be particularly useful if the error occurs while execution is in one of the class libraries.
Server Express:
To turn on message tracing, set the
OOSW environment variable before you run your application:
OOSW=+t export OOSW
The output is an ASCII file, trace.log, which you can look at with any ASCII editor.
Net Express:
To turn on message tracing, either:
set oosw=+t
The output is an ASCII file, trace.log, which you can look at with any ASCII editor.
Every message sent by the application is logged in file trace.log.
Note: Running with trace on slows down application execution as every message sent is written and flushed to the file.
The table below describes the trace information.
Type of Resolve | The target of an INVOKE is categorized by one of the
three values below:
|
||||||
Object reference | The object handle of the receiver of the message. | ||||||
Message | The message sent by the INVOKE. | ||||||
Object type | Shows one of the following codes:
|
||||||
Class of object invoked | The classname of the type of object invoked. | ||||||
Class of implementor | Class name of the implementor of the method. | ||||||
Stack level | Shows the depth of the message stack. The stack level becomes one greater each time a method sends a message, and one lower each time a method exits. |
This section deals with the following common problems:
When passing parameters to and from methods, you need to ensure that the data items used in the INVOKE statement match those expected by the method. In particular, if a method attempts to move data into a RETURNING parameter, and an INVOKE statement calling a method does not supply a RETURNING parameter, the application may cause a protection violation or memory exception.
For example, the "currentTime" method below returns the time in a 6-byte group item:
method-id. "currentTime". linkage section. 01 lnkTime. 03 lnkHours pic xx. 03 lnkMins pic xx. 03 lnkSecs pic xx. procedure division returning lnkTime. move timeNow to lnkTime exit method. end method "currentTime".
The method invocation below has no RETURNING parameter, and would probably cause a protection violation or other memory exception error at run-time:
invoke mainClock "currentTime"
OO programs can cause RTS error 119 (Symbol redefined) for either of the following reasons:
The first of these happens when within a single class you have named two factory methods the same or two instance methods the same. You are allowed to use the same names for a factory and an instance method; you might for example have a class program which defined an "initialize" method for both the factory and the instance object.
The second usually happens when you have a particular class defined in the Repository paragraph of different programs, against different filenames. Filenames are case-sensitive, so you can get this error even if the names only differ in case.
For example, the Repository paragraph in program A might look like this:
repository. class DateClass as "Date" ...
and the Repository paragraph in the DateClass class might look like this:
repository. class DateClass as "date" ...
At run time, when program A tries to invoke DateClass the run-time system raises error 119. The convention used throughout the Class Library and the examples in this book is to enter all filenames as lower case.
If your application tries to use a class which is not available, the run-time system gives you error message 173 (Called program not found). To be available, there must be an executable file for the class either on the current directory or in any of the directories pointed to by one of the following environment variables:
Copyright © 2004 Micro Focus International Limited. All rights reserved.