InterSystems Official
· Feb 27, 2023 2m read

Improvements to how IRIS classes are generated and called

I wanted to provide a heads up of an improvement in how we generate and call method code in IRIS 2023.1.

A class in IRIS is composed of two main runtime components:

  1. Class Descriptor - A highly optimized list of methods, properties, class parameters that make up the class along with attributes associated with each of these e.g. public/private setting.
  2. ObjectScript code - A set of routines that contain the ObjectScript code to be executed when a method is called.

When you call a method of a class/object the dispatch code looks in the class descriptor to find the method, then it verifies if you are allowed to call this or not, then it sets up the correct class context (updating $this in the process) and finally it calls the ObjectScript code in the associated class routine.

The way the ObjectScript is generated in IRIS 2023.1 has been improved to ensure that we always dispatch to this code via the class descriptor and so apply all the correct checks and then run the ObjectScript with the correct class context. Prior to this change it was possible to manually call the ObjectScript code directly which could lead to invalid results and the ability to run ObjectScript code that should not be allowed.

A result of this change is that any attempt to call the ObjectScript method code directly (which was never officially allowed) will report a <NOLINE> error starting in IRIS 2023.1, code doing this should be adjusted to call the method via the class/object.

Details

Prior to IRIS 2023.1 when you compiled a class User.Test.cls with a method such as:

method Test() {
  Write "Test",!
}

The generated ObjectScript code would appear in the 'User.Test.1' routine as:

zTest() public {
  Write "Test",!
}

As this is a regular INT routine you invoke this label with 'Do zTest^User.Test.1()', however this bypassed the correct dispatch via the class descriptor so did not check if you were allowed to call this method if it was private, and it did not setup the class/object context so logic in this method that relies on the class/object context would fail or get unpredictable results.

In IRIS 2023.1 we will generate:

Test() methodimpl {
 Write "Test",!
}

This label is only callable via the class descriptor and any attempt to call it directly will now get a runtime <NOLINE> error. In addition previously for any non-% method we prefixed the label name with 'z' to indicate that label should not be called directly, now for procedure block methods we no longer add this 'z' prefix as these labels are explicitly not callable and this improves the readability of the generated code.

Discussion (10)5
Log in or sign up to continue

I hope, this change does not affect the way I use (some of the) mnemonics - am I right?

Class My.Mnemonics Extends %RegisteredObject
{
/// Set-/Reset mnemonic routine
ClassMethod SetMnemonics(rou={$zname}) [ ProcedureBlock = 0 ]
{
    set old=##class(%Device).GetMnemonicRoutine()
    use $i::"^"_rou
    quit old
    
MA(x)	write "This is MA "_x quit
MB()	write "This is MB" quit
}
}


// for example:
set old=##class(My.Mnemonics).SetMnemonics()
write /ma(123)
do ##class(MyMnemonics).SetMnemonics(old)