forked from pharo-project/pharo
/
ProtoObject.class.st
333 lines (255 loc) · 10.4 KB
/
ProtoObject.class.st
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
"
ProtoObject establishes minimal behavior required of any object in Pharo, even objects that should balk at normal object behavior.
Generally these are proxy objects designed to read themselves in from the disk, or to perform some wrapper behavior, before responding to a message.
ProtoObject has no instance variables, nor should any be added.
"
Class {
#name : #ProtoObject,
#superclass : #nil,
#category : #'Kernel-Objects'
}
{ #category : #comparing }
ProtoObject >> == anObject [
"Primitive. Answer whether the receiver and the argument are the same
object (have the same object pointer). Do not redefine the message == in
any other class! Essential. No Lookup. Do not override in any subclass.
See Object documentation whatIsAPrimitive."
<primitive: 110>
self primitiveFailed
]
{ #category : #'reflective operations' }
ProtoObject >> basicIdentityHash [
"Answer a 22 bits unsigned SmallInteger whose value is related to the receiver's identity.
Primitive. Fails if the receiver is an immediate. Essential.
See Object documentation whatIsAPrimitive.
Do not override, use #identityHash instead"
<primitive: 75>
self primitiveFailed
]
{ #category : #'reflective operations' }
ProtoObject >> become: otherObject [
"Primitive. Swap the object pointers of the receiver and the argument.
All variables in the entire system that used to point to the
receiver now point to the argument, and vice-versa.
Fails if either object is a SmallInteger"
{self} elementsExchangeIdentityWith: {otherObject}
]
{ #category : #'reflective operations' }
ProtoObject >> becomeForward: otherObject [
"Primitive. All variables in the entire system that used to point
to the receiver now point to the argument.
Fails if either argument is a SmallInteger."
{self} elementsForwardIdentityTo: {otherObject}
]
{ #category : #'reflective operations' }
ProtoObject >> becomeForward: otherObject copyHash: copyHash [
"Primitive. All variables in the entire system that used to point to the receiver now point to the argument.
If copyHash is true, the argument's identity hash bits will be set to those of the receiver.
Fails if either argument is a SmallInteger."
{self} elementsForwardIdentityTo: {otherObject} copyHash: copyHash
]
{ #category : #'reflective operations' }
ProtoObject >> cannotInterpret: aMessage [
"Handle the fact that there was an attempt to send the given message to the receiver but a null methodDictionary was encountered while looking up the message selector. Hopefully this is the result of encountering a stub for a swapped out class which induces this exception on purpose."
"If this is the result of encountering a swap-out stub, then simulating the lookup in Smalltalk should suffice to install the class properly, and the message may be resent."
(self class lookupSelector: aMessage selector) ifNotNil:
["Simulated lookup succeeded -- resend the message."
^ aMessage sentTo: self].
"Could not recover by simulated lookup -- it's an error"
Error signal: 'MethodDictionary fault'.
"Try again in case an error handler fixed things"
^ aMessage sentTo: self
]
{ #category : #'class membership' }
ProtoObject >> class [
"Primitive. Answer the object which is the receiver's class. Essential. See
Object documentation whatIsAPrimitive."
<primitive: 111>
self primitiveFailed
]
{ #category : #debugging }
ProtoObject >> doOnlyOnce: aBlock [
"If the 'one-shot' mechanism is armed, evaluate aBlock once and disarm the one-shot mechanism. To rearm the mechanism, evaluate 'self rearmOneShot' manually."
(self class environment at: #OneShotArmed ifAbsent: [ true ])
ifTrue: [
self class environment at: #OneShotArmed put: false.
aBlock value ]
]
{ #category : #'reflective operations' }
ProtoObject >> doesNotUnderstand: aMessage [
<debuggerCompleteToSender>
^ MessageNotUnderstood new
message: aMessage;
receiver: self;
signal
]
{ #category : #executing }
ProtoObject >> executeMethod: compiledMethod [
^ self withArgs: #( ) executeMethod: compiledMethod
]
{ #category : #flagging }
ProtoObject >> flag: aSymbol [
"Send this message, with a relevant symbol as argument, to flag a message for subsequent retrieval. For example, you might put the following line in a number of messages:
self flag: #returnHereUrgently
Then, to retrieve all such messages, browse all senders of #returnHereUrgently."
]
{ #category : #comparing }
ProtoObject >> identityHash [
"Answer a SmallInteger whose value is related to the receiver's identity.
This method must not be overridden, except by SmallInteger. As of
2014, the 32-bit Spur VM has 22 bits of hash and 31-bit SmallIntegers
(30 bits + 1 sign bit). Shifting by 8 will not create large integers.
Do not override."
^self basicIdentityHash bitShift: 8
]
{ #category : #testing }
ProtoObject >> ifNil: nilBlock [
"Return self, or evaluate the block if I'm == nil (q.v.)"
^ self
]
{ #category : #testing }
ProtoObject >> ifNil: nilBlock ifNotNil: ifNotNilBlock [
"If the receiver is not nil, pass it as argument to the ifNotNilBlock block. else execute the nilBlock block "
"(nil ifNil: [42] ifNotNil: [:o | o +3 ] ) >>> 42"
"(3 ifNil: [42] ifNotNil: [:o | o +3 ]) >>> 6"
^ ifNotNilBlock cull: self
]
{ #category : #testing }
ProtoObject >> ifNotNil: ifNotNilBlock [
"Evaluate the block, unless I'm == nil (q.v.). If the receiver is not nil, pass it as argument to the block."
"(2 ifNotNil: [ :o | o + 3]) >>> 5"
"(nil ifNotNil: [:o | o +3 ]) >>> nil"
^ ifNotNilBlock cull: self
]
{ #category : #testing }
ProtoObject >> ifNotNil: ifNotNilBlock ifNil: nilBlock [
"If the receiver is not nil, pass it as argument to the ifNotNilBlock block. else execute the nilBlock block "
"(nil ifNotNil: [:o | o +3 ] ifNil: [42]) >>> 42"
"(3 ifNotNil: [:o | o +3 ] ifNil: [42]) >>> 6"
^ ifNotNilBlock cull: self
]
{ #category : #initialization }
ProtoObject >> initialize [
"Subclasses should redefine this method to perform initializations on instance creation"
]
{ #category : #introspection }
ProtoObject >> instVarsInclude: anObject [
"Answers true if anObject is among my named or indexed instance variables, and false otherwise"
<primitive: 132>
1 to: self class instSize do:
[:i | (self instVarAt: i) == anObject ifTrue: [^ true]].
1 to: self basicSize do:
[:i | (self basicAt: i) == anObject ifTrue: [^ true]].
^ false
]
{ #category : #testing }
ProtoObject >> isNil [
"Coerces nil to true and everything else to false."
^false
]
{ #category : #'write barrier' }
ProtoObject >> modificationForbiddenFor: selector index: index value: value [
^ (ModificationForbidden
for: self
at: index
with: value
retrySelector: selector) signal
]
{ #category : #'write barrier' }
ProtoObject >> modificationForbiddenFor: selector value: value [
^ self modificationForbiddenFor: selector index: nil value: value
]
{ #category : #'memory scanning' }
ProtoObject >> nextInstance [
"Primitive. Answer the next instance after the receiver in the
enumeration of all instances of this class. Fails if all instances have been
enumerated. Essential. See Object documentation whatIsAPrimitive."
<primitive: 78>
^nil
]
{ #category : #'memory scanning' }
ProtoObject >> nextObject [
"Primitive. Answer the next object after the receiver in the
enumeration of all objects. Return 0 when all objects have been
enumerated."
<primitive: 139>
self primitiveFailed.
]
{ #category : #'pointing to' }
ProtoObject >> pointersTo [
^self pointersToExcept: #()
]
{ #category : #'pointing to' }
ProtoObject >> pointersToExcept: objectsToExclude [
"Find all objects in the system that hold a pointer to me, excluding those listed"
| c pointers objectsToAlwaysExclude |
Smalltalk garbageCollect.
pointers := OrderedCollection new.
SystemNavigation default allObjectsDo: [ :e | (e pointsTo: self) ifTrue: [ pointers add: e ] ].
objectsToAlwaysExclude := {
thisContext.
thisContext sender.
thisContext sender sender.
objectsToExclude.
}.
c := thisContext.
^(pointers removeAllSuchThat: [ :ea |
(ea == thisContext sender) or: [ "warning: this expression is dependent on closure structure of this method"
(objectsToAlwaysExclude identityIncludes: ea)
or: [objectsToExclude identityIncludes: ea ]] ]) asArray
]
{ #category : #'pointing to' }
ProtoObject >> pointsTo: anObject [
"Answers true if I hold a reference to anObject, or false otherwise
an object points to a class via the header either directly or indirectly
via the compact classes array"
^ (self instVarsInclude: anObject) or: [ ^self class == anObject]
]
{ #category : #'primitive failure' }
ProtoObject >> primitiveFail [
"primitiveFail may be invoked by certain methods whose code is translated in C. In such a case primitiveFail and not primitiveFailed
should be invoked. The reason is that this code is translated to C by VMMaker. #primitiveFail is
implemented in Interpreter of VMMaker."
^ self primitiveFailed
]
{ #category : #'primitive failure' }
ProtoObject >> primitiveFailed [
"Announce that a primitive has failed and there is no appropriate Smalltalk code to run."
self primitiveFailed: thisContext sender selector
]
{ #category : #'primitive failure' }
ProtoObject >> primitiveFailed: selector [
"Announce that a primitive has failed and there is no appropriate Smalltalk code to run."
PrimitiveFailed signalFor: selector
]
{ #category : #debugging }
ProtoObject >> rearmOneShot [
"Call this manually to arm the one-shot mechanism; use the mechanism in code by calling
self doOnlyOnce: <a block>"
self class environment at: #OneShotArmed put: true
"self rearmOneShot"
]
{ #category : #'apply primitives' }
ProtoObject >> tryPrimitive: primIndex withArgs: argumentArray [
"This method is a template that the Smalltalk simulator uses to
execute primitives. See Object documentation whatIsAPrimitive."
<primitive: 118 error: code >
^ Context primitiveFailTokenFor: code
]
{ #category : #executing }
ProtoObject >> withArgs: argArray executeMethod: compiledMethod [
"Execute compiledMethod against the receiver and args in argArray"
<primitive: 188>
self primitiveFailed
]
{ #category : #comparing }
ProtoObject >> ~~ anObject [
"Primitive. Answer whether the receiver and the argument are different objects
(do not have the same object pointer). Do not redefine the message ~~ in
any other class! Optional (Assuming == is essential). No Lookup. Do not override in any subclass.
See Object documentation whatIsAPrimitive."
<primitive: 169>
self == anObject
ifTrue: [^ false]
ifFalse: [^ true]
]