Object replacement is a general mechanism that allows an object to be substituted by another during a swapping operation (loading or dumping). In the case of dumping, the object that is being dumped can specify a replacement for itself. Say object A specifies that B replaces it when dumping happens. Then, A itself will never be dumped. B, instead, takes its place. 
 
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      A GlobalDescriptor can be used to replace a global variable, where it stores the name of the global in its instance variable 
nameOfGlobal. After defining this class, all that needs to be done is to define a replacement object (a 
GlobalDescriptor) for global Smalltalk. The example below shows a possible replacement object. 
 
      
      
      Once the new class is implemented, GlobalDescriptor, and the replacement object properly defined, identity-based replacement can be done. The example below shows how dumping can be performed so that all references to Smalltalk will be replaced by references to its replacement object, an instance of 
GlobalDescriptor. 
 
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      Replacing something by nil is, conceptually, the same as unlinking, a feature that was present in previous releases and now is obsolete. This can be accomplished by modifying the code in the example above by replacing the 
replaceObject:with: statement with the following: 
 
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      This code replaces the Point 203@485 by a corresponding 
Association, 203 >485, and 
Point 1@2 by a corresponding 
Association, 1 >2. 
 
      
      
      
      
      
      
      
      
      
      
      
      
      
      Class-based replacement using ObjectDumper instance method 
replaceInstancesOf:using: has to be configured for every instance of 
ObjectDumper. However, there is an alternative form of defining class based replacement, which will be applied to all instances of an 
ObjectDumper used in the image. It makes use of protocols that form the Swapper framework (explained in 
The Swapper framework). For instance, suppose you want instances of 
CompiledMethod to be replaced by an intermediate representation, which just carries the class name and selector of the compiled method. And you want this form of replacement to apply to any 
ObjectDumper used in the image. Simply define 
CompiledMethod instance method 
dumpingReplacementForReplacer: as in the following example: 
 
      
      
      
      
      
      
      
      
      CompiledMethodDescriptor is a class whose instances hold the values for the class name and the selector of the compiled method being represented. For example: 
 
      
      
      
      
      You will also need to define CompiledMethodDescriptor instance methods 
className:, 
className, 
methodSelector:, and 
methodSelector and class method 
forClassNamed:selector:. 
 
      
      
      
      
      
      
      
      The parameter aClassBasedReplacer can be ignored now for the sake of simplicity (it is explained in detail in 
The Swapper framework). The method defined in "Example: Redefining methods to implement class-based replacement" on page 
*** will cause all instances of 
CompiledMethod to be replaced (upon unload) by the intermediate representation, 
CompiledMethodDescriptor. 
 
      
      The reason why just implementing dumpingReplacementForReplacer: is not enough is because there are internal optimizations in 
ObjectDumper which avoid computing dumping replacements for instances of classes which do not define any replacement at all. Therefore, implementing 
definesClassBasedReplacement as a class method allows 
ObjectDumper to know whether the optimization is valid for instances of the class or not. 
 
      
      
      In the case of replaceInstVarIndex:of:using:, the first parameter is the instance variable index, an 
Integer. This is the same value you would use to index instance variables using methods 
instVarAt: and
 instVarAt:put:. The second parameter is the class whose instances will have their instance variable replaced (for example, 
Point, 
Rectangle, and so on). The third parameter is a two parameter block. This block will be evaluated using the original object and the index of the instance variable to be replaced as parameters. The result of the block is the replacement object for that particular instance variable of the object. 
 
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      This code will replace instance variable 1 of Point 203@485 by its 
y value, updating it so that the 
Point is 
485@485 when dumped. 
Point 1@2 will also be updated, and 
2@2 will be dumped. Note that this does not affect the original instance of 
Point in the image. Only the dumped copy of the object is changed. 
 
      
      
      
      For these reasons, a second API is provided. By using ObjectDumper instance method 
replaceInstVarNamed:of:using: your code will work correctly even in the situations listed above. The following example shows how the same behavior of the above example can be achieved, but using instance variable names instead. 
 
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      Note that in the case of replaceInstVarNamed:of:using:, the first parameter is the instance variable name, a 
String. The second parameter is the class whose instances will have the instance variable replaced (for example, 
Point, 
Rectangle, and so on). The third parameter is a two parameter block. This block will be evaluated using the original object and the name of the instance variable to be replaced as parameters. The result of the block is the replacement object for that particular instance variable. 
 
      Replacing an object by nil is, conceptually, the same as unlinking. For example, you can modify the 
replaceInstVarNamed:of:using: in the previous example with the following: 
 
      
      
      
      
      Since the need to replace by nil is a common case, the API also accepts 
nil instead of the block. For example, modify the same statement as follows: 
 
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      Instance-variable-based replacement using ObjectDumper instance methods 
replaceInstVarIndex:of:using: and 
replaceInstVarNamed:of:using: has to be configured for every instance of 
ObjectDumper used. However, there is an alternative form of defining instance variable based replacement, which will be applied to all instances of an 
ObjectDumper used in the image. It makes use of protocols that form the Swapper framework (explained in 
The Swapper framework). 
 
      For example, suppose you want the first instance variable of Point to be replaced by the point's 
y value. And you want this form of replacement to apply to any 
ObjectDumper used in the image. You need to define 
Point instance method 
dumpingReplacementForInstVar:forReplacer: to perform the replacement and 
Point class method 
definesInstVarReplacement as shown in the next example: 
 
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      Unlike the dumping replacements presented in Dumping replacement there is no API in 
ObjectLoader to override a loading replacement for just one instance of loader. For instance, 
ObjectLoader new replaceInstancesOf: Point using: [:point | point printString] is not permitted. That is, the 
replaceInstancesOf:using: method is only defined by 
ObjectDumper and is not defined by 
ObjectLoader. A loading replacement for a class will be effective for all instances of 
ObjectLoader used. 
 
      For example, suppose you want to replace all instances of Point in the dumped output by their corresponding print string when you load. To do this, you define 
Point instance method 
loadingReplacementForReplacer: and 
Point class method 
definesLoadingReplacement as in the example below: 
 
      
      
      
      
      
      
      
      
      
      
      
      
      
      In the above example, parameter aLoadingReplacer was ignored. Advanced users can query the replacer and its corresponding 
ObjectLoader, to decide what the replacement must be (see 
The Swapper framework). An example is the implementation of 
Class instance method 
loadingReplacementForReplacer:. 
 
      
      
      In Dumping replacement we saw how to specify different kinds of dumping replacements for an object. For many cases, only a dumping replacement or only a loading replacement is enough. For other cases, a combination of the two is desired. 
 
      
      In Object-identity-based replacement, we saw how to specify a dumping replacement for an object based on its identity. However, what if we want to specify a loading replacement for the replacement dumped? For instance, if now we want to load the object dumped in "Example: Identity-based replacement" on page 
***, so that the reference to Smalltalk is remapped back in the image where the object is loaded, we must define 
GlobalDescriptor instance method 
loadingReplacementForReplacer: as in the next example. Remember to define 
GlobalDescriptor class method 
definesLoadingReplacement and have it return 
true as in "Example: Loading replacement" on page 
***. 
 
      
      
      
      
      
      
      
      The method above will replace the GlobalDescriptor. The original reference to Smalltalk in the image where the object was dumped will be remapped to the local global Smalltalk in the image where the objects are loaded. 
 
      
      
      
      In "Example: Redefining methods to implement class-based replacement" on page *** all instances of 
CompiledMethod were replaced by instances of 
CompiledMethodDescriptor. To have these intermediate representations of 
CompiledMethods rebound again to their corresponding 
CompiledMethods in the image where they are loaded, you must define the replacement method 
CompiledMethodDescriptor instance method 
loadingReplacementForReplacer:. The next example shows how to do this. Remember to define 
CompiledMethodDescriptor class method 
definesLoadingReplacement and have it return 
true. 
 
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      The combined use of a dumping and loading replacement for CompiledMethod presented here swaps only the minimum information necessary, just enough to rebind the object to an equivalent object in the image where it will be loaded. If you also need to transfer the byte codes of the 
CompiledMethod, you should have no class based dumping replacement and a loading replacement that will fix the bytecodes upon loading, so that the instance is consistent and can be run in the image where loaded. 
 
      
      
      
      
      
      
      
      
      Except immediates like SmallInteger, 
true, 
false, 
nil, and 
Character. There are also some loading optimizations, turned on by default, which will make an 
ObjectLoader compute only replacements for objects that were dumped marked as needing loading replacement. See 
Limitations for details on how to deal with these optimizations. 
 
      
    
    
     Copyright 2005, 2018 Instantiations, Inc. All rights reserved.