## Reverse Engineering The PeopleSoft PRM Inclusion Algorithm

07 Mar 2015

One of the many trace settings in PeopleSoft allows you to dump the “PRM Contents” of a component to a trace file. Documentation on this option is nonexistent. A Google search turns up nothing regarding the purpose of the PRM, let alone what the acronym even stands for, although a friend has told me that it stands for Page Reference Manager.

Here’s the section of a trace file emitted as a result of enabling the PRM Contents trace option:

What is this list, how is it generated, and why is it important? All are great questions that I attempted to answer a year ago, but I was forced to put them aside because I could not find any rhyme or reason to the contents. The list looks deceivingly simple: a collection of record fields ordered lexicographically. They all have something to do with the SSS_STUDENT_CENTER component, as evidenced by the header preceding the list. But that’s as much as I could deduce initially.

I was eventually able to endow the OpenPplSoft runtime with the ability to generate the correct PRM list for any component, after a little insight and much trial and error. I believe I am the only one outside of Oracle to know exactly how the PRM is generated, due to the fact that a) PeopleSoft is a proprietary, closed-source product, and b) I am probably the only person spending part of my free time creating a PeopleSoft runtime (but in the 0.1% chance that describes you as well, please contact me). Below, I provide my answers to the what, how, and why behind the PRM, so that you, dear reader, may achieve PRM enlightenment with me.

### What is the PRM?

The PRM for a given component consists of the record fields referenced by any Component, Record, or Page Activate PeopleCode program attached to the component. It may contain, but may also exclude, actual page fields in the component, which can be confusing given the supposed meaning of PRM to be Page Reference Manager. If a record field is listed in a component’s PRM, it may be written to or read from during the execution of one or more PeopleCode programs. Thus, memory must be allocated for this record field to ensure that writes and/or reads occur successfully.

### How is the PRM Generated?

Let $comp$ be the component for you wish to create the PRM.

Let $A$ be the set: { $x$ | $x$ is a Page PeopleCode program; $x$ is defined for the Activate event; $x$ is defined on a page at the root of the defnition of $comp$}

Let $B$ be the set: { $y$ | $y$ is a Component PeopleCode program; $y$ is defined within the context of the definition of $comp$}

Let $C$ be the set: { $z$ | $z$ is a Record PeopleCode program; $z$ is defined on a field within the structure of $comp$; the parent record of $z$ is not a related display record in $comp$}

Then the PRM list for $comp$ is the lexicographic order on the set:

where $fldFn$ is a function that maps a program to its associated set of record fields that belong in the PRM. For a given program $prog$, $fldFn$ yields the empty set if $prog$ is an AppClass PeopleCode program. Otherwise, $fldFn$ yields the following set of record fields:

{ $i$ | $i$ is a record field referenced in the bytecode of $prog$; $i$ is “used” in the program; at least one reference to $i$ occurs at the “root” of $prog$} $\cup \ \bigcup_{refFldFn(refProg) \in G}$

where $refFldFn$ is defined below; and

where $G$ is the set of Record PeopleCode programs imported (via the Declare statement) by $prog$, excluding those programs for the FieldFormula event that are never actually called in $prog$.

To clarify the meaning of “used”, it must be noted that bytecode references in PeopleCode programs are indexed numerically. For Record PeopleCode programs, the first defined reference is always the record field on which the program is defined. This record field may or may not actually be used (i.e., referred to) in the body of the program itself; if it is, it is considered “used”. The requirement that references appear at the “root” excludes references that appear within functions defined in the program from consideration.

The definition of $refFldFn$ is similar to $fldFn$. For a given program $refProg$, $refFldFn$ yields the empty set if $refProg$ is an AppClass PeopleCode program, just as $fldFn$ does. Otherwise, $refFldFn$ yields the following set of record fields:

{ $j$ | $j$ is a record field referenced in the bytecode of $prog$; $j$ is “used” in the program} $\cup \ \bigcup_{refFldFn(internalRefProg) \in H} \cup \ \bigcup_{refFldFn(externalRefProg) \in I}$

Note that unlike $fldFn$, $refFldFn$ does not restrict inclusion of record fields to only those referenced at the root level of the program. Also note that $refFldFn$ is recursive; it is applied to all of the internally and externally defined programs referenced by $refProg$.

I’ve implemented these defintions in OpenPplSoft. The first part of the algorithm, containing the calls to $fldFn$, is implemented here. The implementation of $fldFn$ is located here, and the implementation of $refFldFn$ is located here.

### Why is the PRM Important?

Along with the importance of allocating memory for PRM fields in order to support writes and/or reads to them by PeopleCode programs, the PRM influences which fields are considered to be part of scrolls and whether or not those fields are considered “used”. In OpenPplSoft, the calls to the static function ComponentBuffer.hasPRMEntry in this file are instances where PRM inclusion directly influences control flow. Above and beyond this, other implications likely exist which I have yet to uncover.

Reversing the PRM algorithm has been a necessary and fun exercise for me. Necessary in that, without it, OpenPplSoft would have a hole in its trace file verification capabilities. Fun in that I’ve always wondered what the hell the PRM is, so I’ve gotten a kick out of being able to gradually uncover its inner workings and make that knowledge globally available for the first time. If you came here looking for PRM information but still aren’t clear on something, don’t hesitate to shoot me an email.