!=========================================================================
! Copyright (C) VMware, Inc. 1986-2011.  All Rights Reserved.
!
! $Id: softreference.gs,v 1.6 2008-01-09 22:50:18 stever Exp $
!
! Superclass Hierarchy:
!   Object, SoftReference
!
!=========================================================================

expectvalue %String
run
| res cls oldCls clsName |
clsName := #SoftReference .
oldCls := Globals at:clsName otherwise: nil .
oldCls == nil ifTrue:[
  res := Object _newKernelSubclass: clsName"SoftReference"
    instVarNames: #( #inUse #useCount #value )
    classVars: #()
    classInstVars: #()
    poolDictionaries: #[]
    inDictionary: Globals
    constraints: #[ #[ 'inUse', Boolean ],
                       #[ 'useCount' , SmallInteger] ] 
    instancesInvariant: false
    isModifiable: true
    reservedOop: 939 .
  cls := Globals at: clsName .
  cls makeInstancesNonPersistent .
  cls disallowSubclasses .
  cls _disallowGciCreateStore .
  cls immediateInvariant .
] ifFalse: [
  res := clsName asString , 'already exists'.
  oldCls instancesNonPersistent ifFalse:[ nil error:'should be NP' ].
  oldCls subclassesDisallowed ifFalse:[ nil error: 'should have subcls disallow'].
].
^ res
%


! Remove existing behavior from Semaphore
removeallmethods SoftReference
removeallclassmethods 

category: 'For Documentation Installation only'
classmethod
installDocumentation

| doc txt |
doc := GsClassDocumentation newForClass: self.

txt := (GsDocText new) details:
'A SoftReference contains a reference to another object which may be
 cleared by the in-memory garbage collector.   Instances of SoftReference
 are non-persistent and may not be committed ot the repository .

 A SoftReference''s value instVar is only cleared if
 there are no strong references to the referenced value , and if
 the inUse instVar is not true .

 If a SoftReference to A is cleared, all other SoftReferences
 to objects B such that B->A is a strong reference, are also cleared .
 All SoftReferences that are legal to clear are cleared before
 generating OutOfMemory error .

 VM scavenge will never clear SoftReferences , and the normal stubbing of
 references from temporary to committed objects is not performed
 in SoftReferences .

 If percentMemUsed > GEM_SOFTREF_CLEANUP_PERCENT_MEM at start of markSweep,
 markSweep will will attempt to clear SoftReferences as follows:

 if percentMemUsed < 60%,
 markSweep will try to clear the least recently used 10% of SoftReferences.

 if percentMemUsed >= 60% and < 90% ,
 markSweep will try to clear the least recently used 20% of SoftReferences.

 if percentMemUsed >= 90%
 markSweep will try to clear all SoftReferences.'. 
doc documentClassWith: txt.

txt := (GsDocText new) details:
'A Boolean , if true prevents the garbage collector from clearing value.'.
doc documentInstVar: #inUse with: txt.

txt := (GsDocText new) details:
'Reference to another object, may be cleared by the garbage collector.' .
doc documentInstVar: #value with: txt.

txt := (GsDocText new) details:
'Private to the garbage collector and primitives, used to implement least
 recently used behavior for clearing of value.' .
doc documentInstVar: #useCount with: txt.

self description: doc.
%

category: 'Instance creation'
classmethod
new

 " creates a new instance with inUse set to false, 
   useCount set to zero, and value set to nil ."

 ^ super new _initialize
%

category: 'Private'
method
_initialize

  inUse := false .
  useCount := 0 .
  self _setNoStubbing .
%

category: 'Accessing'
method
inUse

  ^ inUse 
%

category: 'Updating'
method
clearInUse

  "make this SoftReference eligible to be cleared by the garbage collector."

  inUse := false
%

category: 'Updating'
method
setInUse

"Sets inUse to true. There is no guarantee that value will
 be non-nil after completion of this method.  After this method completes,
 this SoftReference will not be cleared by the garbage collector.
"

inUse := true 
%

category: 'Private'
method
_useCount

 "return the useCount.  This method is provided for use in debugging only.
  The values returned are generated by the virtual machine,
  and the algorithm used to generate them may change without out notice."

  ^ useCount
%

category: 'Accessing'
method
value

 "if value of the receiver is not nil and not a special object,
  increments useCount. returns value of the receiver."

<primitive:550>
self _primitiveFailed: #value
%

category: 'Accessing'
method
_value

 " return value without incrementing useCount"
  ^ value
%

category: 'Updating'
method
setValue: aValue

  "Installs aValue as the value of the receiver. 
   aValue must not be nil , use clearValue to set the value to nil .
   Returns aValue
  "
  aValue == nil ifTrue:[ ^ self error:'argument must not be nil.' ].
  value := aValue .
  self value  "increment useCount" .
  ^ aValue 
%

category: 'Updating'
method
clearValue

  "sets value instVar to nil.  Provided primarily for unit testing."

  value := nil 
%

category: 'Comparing'
method
= anObject

" return true if the argument is a SoftReference that
  references the identical value"

^ anObject _class == self _class _and:[ anObject _value == value ]
%

category: 'Comparing'
method
hash 

"Return a positive Integer based on the identity of the value referenced by 
 the receiver."

^ value identityHash

%
