! ========================================================================
! Copyright (C) by VMware, Inc. 1991-2011.  All Rights Reserved
!
! $Id: gciinterface.gs,v 1.13 2008-01-09 22:50:10 stever Exp $
!
! ========================================================================


expectvalue %String
run

^ Object _newKernelSubclass: #GciInterface
  instVarNames: #(#sessionId #lastResult #resultIsSpecial #lastError #trace
	#log #errorClass)
  classVars: #()
  classInstVars: #()
  poolDictionaries: #[]
  inDictionary: Globals
  constraints: #[
	#[#sessionId, SmallInteger],
	#[#resultIsSpecial, Boolean],
	#[#lastError, ErrorDescription],
	#[#trace, Boolean],
	#[#log, GsFile],
	#[#errorClass, Behavior]
	]
  instancesInvariant: false
  isModifiable: false
  reservedOop: 925

%

removeallmethods GciInterface
removeallclassmethods GciInterface

! ------------------- Class methods for GciInterface
category: 'For Documentation Installation only'
classmethod
installDocumentation
| doc txt |
doc := GsClassDocumentation newForClass: self.

txt := (GsDocText new) details:
'GciInterface is a Smalltalk representation for the functions defined
 in $GEMSTONE/include/gci.hf .  Using GciInteface a session may
 execute GCI functions in another session .' .

doc documentClassWith: txt.

self description: doc.
%

category: 'Instance Creation'
classmethod: GciInterface
new

"Create a new initialized instance."

^ self basicNew initialize.
%
category: 'Instance Creation'
classmethod: GciInterface
newFromId: id

|result|

"Create a new initialized instance."

result := self basicNew initialize.
result _sessionId: id.
^result
%
category: 'Prims'
classmethod: GciInterface
_objectForOop: oop

"Return the object with the given oop.  If no object exists with this oop,
raise an error."

<primitive: 382>
self _primitiveFailed: #_objectForOop: .
%
! fixed 34061
category: 'Prims'
classmethod: GciInterface
_oopForObject: anObject

"Return the oop for the given object."

<primitive: 383>
self _primitiveFailed: #_oopForObject: .
%
category: 'Prims'
classmethod: GciInterface
_zeroArgPrim: opcode

"Primitive dispatch.  Legal values are:
    42: GciInterface (C) | sessions
"

<primitive: 197>

^self _primitiveFailed: #_zeroArgPrim:
%
category: 'Prims'
classmethod: GciInterface
sessions

"Return an Array listing all of the active session ids"

^self _zeroArgPrim: 42
%

! ------------------- Instance methods for GciInterface
category: 'Error Handling'
method: GciInterface
_errorLoginFailed

"Raise an error because an attempt to login failed."

self _error: #rtErrRemoteLoginFailed args: #[lastError message]
%
category: 'Private'
method: GciInterface
_sessionId: id

"Set the session id"

sessionId := id
%
category: 'Private'
method: GciInterface
_zeroArgPrim: opcode

"Primitive dispatch.  Legal values are:
    32: GciInterface | dirtyObjsInit
    33: GciInterface | logout
    34: GciInterface | commit
    35: GciInterface | nbCommit
    36: GciInterface | abort
    37: GciInterface | nbAbort
    38: GciInterface | softBreak
    39: GciInterface | callInProgress 
    41: GciInterface | notifyHandle
    42: reserved
    43: GciInterface | hardBreak
"

<primitive: 197>

^self _primitiveFailed: #_zeroArgPrim:
%
method: GciInterface
_oneArgPrim: opcode with: arg

"Primitive dispatch.  Legal values are:
    16: GciInterface | remoteExecute:
    17: GciInterface | resolveSymbol:
    18: GciInterface | moreTraversal:
    19: GciInterface | getFreeOops:
    20: GciInterface | nbEnd:
    21: GciInterface | clearStack:
    22: GciInterface | nbRemoteExecute:
    23: GciInterface | nbMoreTraversal:
    24: reserved
    25: GciInterface | nbLogin:
"

<primitive: 198>

"Error diagnostics"
opcode == 20
  ifTrue: [ "errors in nbEnd:"
    (arg isKindOf: Integer)
	ifFalse: [ arg _errorExpectedClass: Integer].
    (arg ~~ 1 _and: [arg ~~ 2])
	ifTrue:[arg _error: #rtErrArgOutOfRange args: #()].
    ].
opcode == 25
  ifTrue: [ "errors in login"
    (arg isKindOf: GemStoneParameters)
	ifFalse: [ arg _errorExpectedClass: GemStoneParameters].

    #[
      arg hostUsername,
      arg gemService,
      arg gemStoneName,
      arg username,
      arg password,
      arg hostPassword
	] do: [:each |
      each size > 1024
	ifTrue: [ each _error: #rtErrBadSize args: #[1024, each size]]].

    ].

^self _primitiveFailed: #_oneArgPrim:
%
method: GciInterface
_twoArgPrim: opcode with: arg1 with: arg2

"Primitive dispatch.  Legal values:
    3: GciInterface | storeTrav:flags:
    4: GciInterface | alteredObjects:
    5: GciInterface | step:level:
    6: GciInterface | traverseObjects:buffer:
    7: GciInterface | remoteExecuteTrav:buffer:
    8: GciInterface | login:execute:
"

<primitive: 199>

"Error diagnostics"
opcode == 8
  ifTrue: [ "errors in login"
    (arg1 isKindOf: GemStoneParameters)
	ifFalse: [ arg1 _errorExpectedClass: GemStoneParameters].
    (arg2 class isBytes)
	ifFalse: [ arg2 _error: #objErrNotByteKind].

    #[arg2,
      arg1 hostUsername,
      arg1 gemService,
      arg1 gemStoneName,
      arg1 username,
      arg1 password,
      arg1 hostPassword
	] do: [:each |
      each size > 1024
	ifTrue: [ each _error: #rtErrBadSize args: #[1024, each size]]].

    ].

^self _primitiveFailed: #_twoArgPrim:
%
method: GciInterface
_threeArgPrim: opcode with: arg1 with: arg2 with: arg3

"Primitive dispatch.  Legal values:
    2: GciInterface | remotePerform:selector:args:
    3: GciInterface | nbRemotePerform:selector:args:
"

<primitive: 505>

(opcode == 3 _or: [opcode == 4])
    ifTrue: [ "diagnostics for nbRemotePerform"
  arg3 size > 20 ifTrue: [arg3 _error: #gciErrArgNotPairs args: #()].
  arg3 size \\ 2 ~~ 0 ifTrue: [arg3 _error: #gciErrArgNotPairs args: #()].
  1 to: arg3 size by: 2 do: [:i |
	(arg3 at: i + 1) class == Boolean ifFalse: [
	    (arg3 at: i + 1) _errorExpectedClass: Boolean].
	(arg3 at: i + 1) ifTrue: [
	  ((arg3 at: i) isKindOf: Integer) ifFalse: [
	    (arg3 at: i) _errorExpectedClass: Integer].
	  ].
	].
  ].

^self _primitiveFailed: #_threeArgPrim:
%
method: GciInterface
_fourArgPrim: opcode with: arg1 with: arg2 with: arg3 with: arg4

"Primitive dispatch.  Legal values:
    1: GciInterface | continueWith:replaceTopOfStackWith:isSpecial:flags:
    2: GciInterface | performTraverse:selector:args:buffer:
"

<primitive: 503>

^self _primitiveFailed: #_fourArgPrim:
%
method: GciInterface
_fiveArgPrim: opcode with: arg1 with: arg2 with: arg3 with: arg4 with: arg5

"Primitive dispatch.  Legal values:
    1: GciInterface | storeTravExecute:flags:execute:alteredObjects:
"

<primitive: 504>

^self _primitiveFailed: #_fiveArgPrim:
%
method: GciInterface
_sevenArgPrim: opcode with: arg1 with: arg2 with: arg3 with: arg4 with: arg5
with: arg6 with: arg7

"Primitive dispatch.  Legal values:
    0: GciInterface | storeTravPerform:flags:perform:selector:args:alteredObjects:
"

<primitive: 506>

^self _primitiveFailed: #_sevenArgPrim:
%
category: 'Public'
method: GciInterface
abort

"Abort the transaction in the remote repository."

trace
  ifTrue: [ self record: 'abort' ].

^ self _zeroArgPrim: 36
%
category: 'Primitives'
method: GciInterface
alteredObjects: alteredObjArray

"Invoke the GciAlteredObjs function."

| str result |

trace
  ifTrue: [ str := String new add: 'alteredObjs: '; yourself ].

result :=  self _twoArgPrim: 4 with: alteredObjArray with: nil.

trace
  ifTrue: [
    str add: ' returned '; add: lastResult asString.
    self record: str
  ].

^ result
%
category: 'Primitives'
method: GciInterface
callInProgress

"Return whether there is a call in progress in the execution thread in the
remote repository."

trace
  ifTrue: [ 
    self record:
      (String new add: sessionId asString; add: ' callInProgress'; yourself)
  ].

^ self _zeroArgPrim: 39
%
category: 'Primitives'
method: GciInterface
notifyHandle

"Return an OS handle that can be used in GsSocket to test if this interface
has read activity."

trace
  ifTrue: [ 
    self record:
      (String new add: sessionId asString; add: ' notifyHandle'; yourself)
  ].

^ self _zeroArgPrim: 41
%
category: 'Primitives'
method: GciInterface
clearStack: processOop

"Clear the stack of Smalltalk execution in the remote repository."

trace
  ifTrue: [ 
    self record:
      (String new add: sessionId asString; add: ' clearStack'; yourself)
  ].

^ self _oneArgPrim: 21 with: processOop
%
category: 'Public'
method: GciInterface
commit

"Commit the transaction in the remote repository."

trace
  ifTrue: [ self record: 'commit' ].

^ self _zeroArgPrim: 34
%
category: 'Primitives'
method: GciInterface
continueWith: processOop
replaceTopOfStackWith: replaceOop
isSpecial: isSpecial
flags: flags

"Invoke the GciContinueWith function.
If replaceOop == nil and isSpecial is false, then use OOP_ILLEGAL as the
replaceOop (which means the evaluation stack is not changed)
"

| str result |

trace
  ifTrue: [
    str := String new
	add: 'continueWith ['; add: replaceOop asString; add: '] '; yourself
  ].

result := self _fourArgPrim: 1
    with: processOop
    with: replaceOop
    with: isSpecial
    with: flags.

trace
  ifTrue: [
    str add: ' returned '; add: lastResult asString.
    self record: str
  ].

^ result
%
category: 'Primitives'
method: GciInterface
dirtyObjsInit

"Execute GciDirtyObjsInit."

trace
  ifTrue: [ 
    self record:
      (String new add: sessionId asString; add: ' dirtyObjsInit'; yourself)
  ].

^ self _zeroArgPrim: 32
%
category: 'Tracing'
method: GciInterface
disableTracing

"Enable tracing of commands issued to the subordinate gem to be logged to
a file."

trace
  ifFalse: [ ^ false ].

trace := false.
log close.
^ false
%
category: 'Tracing'
method: GciInterface
enableFileTracing: filename

"Enable tracing of commands issued to the subordinate gem to be logged to
a file."

trace
  ifTrue: [ ^ true ].

trace := true.

log := GsFile open: filename mode: 'a'.

log addAll: 'Tracing enabled at ';
  addAll: DateTime now asString; lf; flush.
^ true
%
category: 'Accessing'
method: GciInterface
getAndClearLastError

"Return the value of lastError and clear it."

| result |
result := lastError.
lastError := nil.
^ result
%
category: 'Primitives'
method: GciInterface
getFreeOops: num

"Return an array of free remote oops from the subordinate gem.
This method will return a maximum of 2000 free oops.  You must
make multiple calls to receive more."

trace
  ifTrue: [ | str |
    str := String new.
    str add: 'getFreeOops: '; add: num asString.
    self record: str
  ].

^ self _oneArgPrim: 19 with: num
%
category: 'Initialization'
method: GciInterface
initialize

"Initialize the instance variables of the receiver."

trace := false.
sessionId := 0. "GCI_INVALID_SESSION_ID"
errorClass := ErrorDescription.
lastResult := _remoteNil.
^ self
%
category: 'Accessing'
method: GciInterface
errorClass

   "Return the value of the instance variable 'errorClass'."
   ^errorClass
%
category: 'Updating'
method: GciInterface
errorClass: newValue

   "Modify the value of the instance variable 'errorClass'."
  (newValue isSubclassOf: ErrorDescription)
    ifFalse: [
      self _error: #objErrConstraintViolation
        args: #[ newValue, ErrorDescription class, newValue class ]
    ].
   errorClass := newValue
%
category: 'Accessing'
method: GciInterface
lastError

   "Return the value of the instance variable 'lastError'."
   ^lastError
%
category: 'Accessing'
method: GciInterface
lastResult

   "Return the value of the instance variable 'lastResult'."
   ^lastResult
%
category: 'Accessing'
method: GciInterface
log

   "Return the value of the instance variable 'log'."
   ^log
%
category: 'Public'
method: GciInterface
login: params andExecute: aString ifFailure: aBlock

"Login to the remote repository using the given parameters.  If login is
successful, return the remote oop of the result of execution of the given 
string.  If the login fails or the executed block generates an error (which
in turn will cause the session to be logged out), execute the zero argument
block (if the block is nil, raise an error)."

| str gsName result |

params remoteRepository == nil
  ifFalse: [ gsName := params remoteRepository gemStoneName]
  ifTrue:  [ gsName := params gemStoneName].

trace
  ifTrue: [
    str := String new add: 'Logging in to '; add: gsName;
      add: ' as '; add: params username; yourself.
    self record: str
  ].

" login and execute some code "
result := self login: params execute: aString.

" when successful, result is a remote oop (an Integer) "
result == _remoteNil
  ifTrue: [
    aBlock == nil
      ifTrue: [ self _errorLoginFailed ]
      ifFalse: [
        ^ aBlock value 
      ]
  ].

(trace _and: [ aString ~~ nil ])
  ifTrue: [ self record: 'Login successful.'; record: aString ].

^ result
%
category: 'Primitives'
method: GciInterface
login: params
execute: aString

"Login to a GemStone server with the given parameters, and execute
the given string.  The execution string may be nil.  If the result of execution
is _remoteNil, this will immediately logout.  If any error occurs during login 
or remote string execution, this will return _remoteNil; otherwise it returns 
the remote oop of the result of execution."


^ self _twoArgPrim: 8
    with: params
    with: aString
%
category: 'Public'
method: GciInterface
logout

"Terminate the communication with a subordinate gem."

trace
  ifTrue: [
    self record: 'Logging out'.
    self disableTracing.
  ].

^ self _zeroArgPrim: 33
%
category: 'Primitives - Trav'
method: GciInterface
moreTraversal: cBuff

"Continue a traversal from a previous operation.  The returned value will 
be a TraversalBuffer.  The argument cBuff should be an instance of
TraversalBuffer"

| result |

trace
  ifTrue: [
    self record:
      (String new add: sessionId asString; add: ' moreTraversal'; yourself)
  ].

result :=  self _oneArgPrim: 18 with: cBuff.
^ result
%
category: 'Primitives - NB'
method: GciInterface
nbAbort

"Non-blocking abort of the transaction in the remote repository."

trace
  ifTrue: [
    self record:
      (String new add: sessionId asString; add: ' nbAbort'; yourself)
  ].

^ self _zeroArgPrim: 37
%
category: 'Primitives - NB'
method: GciInterface
nbCommit

"Non-blocking commit of the transaction in the remote repository."

trace
  ifTrue: [
    self record:
      (String new add: sessionId asString; add: ' nbCommit'; yourself)
  ].

^ self _zeroArgPrim: 35
%
category: 'Primitives - NB'
method: GciInterface
nbEnd: returnType

"Test the status of a non-blocking call in progress.
The return type indicates if the non-blocking call will return
an OopType (1) or a BoolType (2).

Returns
  -1 if GCI_RESULT_NOT_READY
  0 if GCI_RESULT_PROGRESSED
  1 if GCI_RESULT_READY
  nil if an error occurred
"

| result str |

result := self _oneArgPrim: 20 with: returnType.

trace
  ifTrue: [
    str := String new.
    str add: sessionId asString; add: ' NB end - '.

    result == -1
      ifTrue: [ " self record: str + 'GCI_RESULT_NOT_READY' " ]
      ifFalse: [
        result == 0
          ifTrue: [ str add: 'GCI_RESULT_PROGRESSED' ]
          ifFalse: [
            result == 1
              ifTrue: [ str add: 'GCI_RESULT_READY : returned '; add: lastResult asString ]
              ifFalse: [ str add: 'unknown NbEnd result: '; add: result asString ]
          ].
        self record: str
      ]
  ].

^ result
%
category: 'Primitives - NB'
method: GciInterface
nbEndTraversal

"cover for nbEnd:"

^self nbEnd: 2
%
category: 'Primitives - NB'
method: GciInterface
nbEndBoolean

"cover for nbEnd:"

^self nbEnd: 2
%
category: 'Primitives - NB'
method: GciInterface
nbEndOop

"cover for nbEnd:"

^self nbEnd: 1
%
category: 'Primitives - NB'
method: GciInterface
nbMoreTraversal: cBuff

"Non-blocking more traversal.  
 The argument cBuff should be an instance of TraversalBuffer."

trace
  ifTrue: [
    self record: 
      (String new add: sessionId asString; add: ' nbMoreTraversal'; yourself)
  ].

^ self _oneArgPrim: 23 with: cBuff
%
category: 'Primitives - NB'
method: GciInterface
nbRemoteExecute: aString

"Execute the given string and return the result of execution.
The returned value will be a remote oop."

trace
  ifTrue: [
    self record:
      (String new add: sessionId asString; add: ' nbRemoteExecute:';
        add: aString; yourself)
  ].

^ self _oneArgPrim: 22 with: aString
%
category: 'Primitives - NB'
method: GciInterface
nbRemotePerform: remoteOop selector: selector args: args

"Sends the given selector to the object in a remote repository with the given
remote oop.  The arg array is an array of pairs: either a remote oop or special,
and a boolean indicating whether the arg is special or not, TRUE if the arg
is a remote oop, FALSE if it is special.  The result is a remoteOop."

trace
  ifTrue: [
    self record: (String new add: sessionId asString;
      add: ' nbRemotePerform ['; add: remoteOop asString;
      add: '] '; add: selector; yourself)
  ].

^ self _threeArgPrim: 3
    with: remoteOop
    with: selector
    with: args
%
category: 'Accessing'
method: GciInterface
sessionId

   "Return the value of the instance variable 'sessionId'."
   ^sessionId
%
category: 'Primitives - Trav'
method: GciInterface
performTraverse: remoteOop 
selector: selector 
args: argsArr
buffer: cBuff

"Sends the given selector to the object in a remote repository with the given
remote oop.  argsArr  is an Array of pairs: either a remote oop or special,
and a boolean indicating whether the arg is special or not.

The argument cBuff should be an instance of TraversalBuffer."

trace
  ifTrue: [ | str sz |
    str := String new add: 'Sending ['; add: remoteOop asString;
      add: '] '; add: selector; add: ' '; yourself.
    sz := argsArr size.
    1 to: sz by: 2 do: [ :i |
      (argsArr at: i + 1)
        ifTrue: [ str add: $~ ].
      str add: (argsArr at: i) asString.
      (i + 1) == sz
        ifFalse: [ str add: ', ' ]
    ].
    self record: str.
  ].

^ self _fourArgPrim: 2
    with: remoteOop
    with: selector
    with: argsArr
    with: cBuff
%
category: 'Tracing'
method: GciInterface
record: aString

"Record the given string to the trace log."

log addAll: aString; add: Character lf; flush
%
category: 'Tracing'
method: GciInterface
recordNoLf: aString

"Record the given string to the trace log with no linefeed at the end."

log addAll: aString; flush
%
category: 'Primitives'
method: GciInterface
remoteExecute: aString

"Execute the given string and return the result of execution.
The returned value will be a remote oop."

| str result |

trace
  ifTrue: [ str := String new add: 'Execute: '; add: aString; yourself ].

result :=  self _oneArgPrim: 16 with: aString.

trace
  ifTrue: [
    str add: ' returned '; add: lastResult asString.
    self record: str
  ].

^ result
%
category: 'Primitives - Trav'
method: GciInterface
remoteExecuteTrav: aString buffer: cBuff

"Execute the given string and return the result of execution in the given buffer.
 The argument cBuff should be an instance of TraversalBuffer."

trace
  ifTrue: [ self record: aString ].

^ self _twoArgPrim: 7
    with: aString
    with: cBuff
%
category: 'Primitives'
method: GciInterface
remotePerform: remoteOop selector: selector args: args

"Sends the given selector to the object in a remote repository with the given
remote oop.  The arg array is an array of pairs: either a remote oop or special,
and a boolean indicating whether the arg is special or not.  The result is a
remoteOop."

| str result |

trace
  ifTrue: [
    str := String new add: 'Sending ['; add: remoteOop asString;
      add: '] '; add: selector; yourself
  ].

result := self _threeArgPrim: 2
    with: remoteOop
    with: selector
    with: args.

trace
  ifTrue: [
    str add: ' returned '; add: lastResult asString.
    self record: str
  ].

^ result
%
category: 'Primitives'
method: GciInterface
resolveSymbol: aSymbol

"Resolve the given symbol and return the remote oop."

trace
  ifTrue: [ self record: 'Resolve symbol' , aSymbol ].

^ self _oneArgPrim: 17 with: aSymbol
%
category: 'Accessing'
method: GciInterface
resultIsSpecial

   "Return the value of the instance variable 'resultIsSpecial'."
   ^resultIsSpecial
%
category: 'Primitives'
method: GciInterface
softBreak

"Send a soft break to interrupt execution in the remote repository."

trace
  ifTrue: [ 
    self record:
      (String new add: sessionId asString; add: ' softBreak'; yourself)
  ].

^ self _zeroArgPrim: 38
%
category: 'Primitives'
method: GciInterface
hardBreak

"Send a hard break to interrupt execution in the remote repository."

trace
  ifTrue: [ 
    self record:
      (String new add: sessionId asString; add: ' hardBreak'; yourself)
  ].

^ self _zeroArgPrim: 43
%
category: 'Primitives'
method: GciInterface
step: processOop level: level

"Invoke the GciStep function."

| str result |

trace
  ifTrue: [
    str := String new add: 'GciStep ';
      add: processOop asString;
      add: ' : ';
      add: level asString;
      yourself
  ].

result :=  self _twoArgPrim: 5 with: processOop with: level.

trace
  ifTrue: [
    str add: ' returned '; add: lastResult asString.
    self record: str
  ].

^ result
%
category: 'Primitives'
method: GciInterface
nbLogin: params

"Invoke the GciNbLoginEx function."

^ self _oneArgPrim: 25 with: params.
%
category: 'Primitives - Trav'
method: GciInterface
storeTrav: travBuff flags: flags

"Invoke the store traversal function."

trace
  ifTrue: [ self record: 'GciStoreTrav: ' , flags asString ].

^ self _twoArgPrim: 3 with: travBuff with: flags
%
category: 'Primitives - Trav'
method: GciInterface
storeTravCreate: travBuff 

"Invoke the store traversal function."

^ self storeTrav: travBuff flags: 2
%
category: 'Primitives - Trav'
method: GciInterface
storeTravCreateAndFinishUpdates: travBuff 

"Invoke the store traversal function."

^ self storeTrav: travBuff flags: 10
%
category: 'Primitives - Trav'
method: GciInterface
storeTravExecute: travBuff 
flags: flags 
execute: aString
alteredObjects: alteredObjArray

"Invoke the store traversal function."

| str result |

trace
  ifTrue: [
    str := String new add: 'GciStoreTravExecute: '; add: aString; yourself
  ].

result := self _fiveArgPrim: 1
    with: travBuff
    with: flags
    with: aString
    with: alteredObjArray
    with: nil.

trace
  ifTrue: [
    str add: ' returned '; add: lastResult asString.
    self record: str
  ].

^ result
%
category: 'Primitives - Trav'
method: GciInterface
storeTravPerform: travBuff 
flags: flags 
perform: remoteOop 
selector: selector 
args: args
alteredObjects: alteredObjArray

"Invoke the store traversal function."

| str result |

trace
  ifTrue: [
    str := String new add: 'GciStoreTravPerform ['; add: remoteOop asString;
      add: '] '; add: selector; yourself
  ].

result := self _sevenArgPrim: 0
    with: travBuff
    with: flags
    with: remoteOop
    with: selector
    with: args
    with: alteredObjArray
    with: nil.

trace
  ifTrue: [
    str add: ' returned '; add: lastResult asString.
    self record: str
  ].

^ result
%
category: 'Primitives - Trav'
method: GciInterface
traverseObjects: arrayOfOops buffer: cBuff

"Return a buffer resulting from traversing the given array of remote oops.
If there were too many oops, return nil.
The argument cBuff should be an instance of TraversalBuffer."


trace
  ifTrue: [ | str |
    str := String new.
    str add: 'Traversing '; add: arrayOfOops size asString; add: ' oops'.
    self record: str
  ].

^ self _twoArgPrim: 6 with: arrayOfOops with: cBuff
%

