EndOfStream performance cost [was EndOfStream unused]

Paolo Bonzini bonzini at gnu.org
Fri Nov 9 09:30:57 UTC 2007


> - Most String processing loops use atEnd loop (upper level ReadStream
> does not use == nil trick, client code might however uses few).

I found only one that doesn't, in InflateStream>>#atEnd, using this code:

(CompiledMethod allInstances
   select: [ :m | | s |
      s := m getSource asString.
      ('*next*' match: s ) and: [
         ('*next == nil*' match: s )  or: [
         ('*next isNil'  match: s ) or: [
         '*next notNil' match: s ]]]])

Here is the source code:

     atEnd
	"Note: It is possible that we have a few bits left,
	representing just the EOB marker. To check for
	this we must force decompression of the next
	block if at end of data."
	super atEnd ifFalse:[^false]. "Primitive test"
	(position >= readLimit and:[state = StateNoMoreData])
	    ifTrue:[^true].
	self next == nil ifTrue:[^true].
	position := position - 1.
	^false

and in this same class, we have:

     pastEndRead
	state = StateNoMoreData ifTrue:[^nil].
	...
	^self next

     next
	<primitive: 65>
	position >= readLimit
		ifTrue: [^self pastEndRead]
		ifFalse: [^collection at: (position := position + 1)]

So, the "self next == nil" could be written "self pastEndRead == nil". 
Or even better, one could simply rewrite "atEnd and next" like this:

     atEnd
	position < readLimit ifFalse: [^false].
	"for speed, we inline pastEndRead with these changes:"
	state = StateNoMoreData ifTrue:[^true].
	...
	^false

     next
	<primitive: 65>
	"position >= readLimit test inlined for speed"
	(position >= readLimit and: [self atEnd]) ifTrue: [ ^nil ].
	^collection at: (position := position + 1)

Actually, this implementation of #next could be moved up to ReadStream, 
so that no override is necessary in InflateStream.  So, it looks like 
the only explicit usage (in my image) of "self next == nil" ought to be 
eliminated anyway.

In some cases, the "self next == nil" test is used implicitly, for example:

Number>>readExponent:base:
	('edq' includes: aStream next) ifFalse: [^ nil].
	...

This code however does not seem to be written with speed in mind.

Paolo



More information about the Squeak-dev mailing list