-
Notifications
You must be signed in to change notification settings - Fork 65
/
CogStackPages.class.st
422 lines (373 loc) · 15 KB
/
CogStackPages.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
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
"
I am a class that helps organize the StackInterpreter's collection of stack pages. I hold the set of stack pages represented by InterpreterStackPage instances/StackPage structs. The pages are held in a doubly-linked list that notionally has two heads:
mostRecentlyUsedPage-->used page<->used page<->used page<->used page<--leastRecentlyUsedPage
^ <-next-prev-> ^
| |
v <-prev-next-> v
free page<->free page<->free page<->free page
In fact we don't need the least-recently-used page, and so it is only present conceptually. The point is that there is a possibly empty but contiguous sequence of free pages starting at mostRecentlyUsedPage nextPage. New pages are allocated preferentially from the free page next to the MRUP.
If there are no free pages then (effectively) the LRUP's frames are flushed to contexts and it is used instead.
I have two concrete classes, one for the StackInterpreter and one for the CoInterpreter.
Instance Variables
bytesPerPage: <Integer>
coInterpreter: <StackInterpreter>
mostRecentlyUsedPage: <CogStackPage>
objectMemory: <ObjectMemory|SpurMemoryManager>
overflowLimit: <Integer>
pages: <Array of: CogStackPage>
statNumMaps: <Integer>
statPageCountWhenMappingSum: <Integer>
bytesPerPage
- the size of a page in bytes
coInterpreter
- the interpreter the receiver is holding pages for
mostRecentlyUsedPage
- the most recently used stack page
objectMemory
- the objectMemory of the interpreter
overflowLimit
- the length in bytes of the portion of teh stack that can be used for frames before the page is judged to have overflowed
pages
- the collection of stack pages the receiver is managing
statNumMaps
- the number of mapStackPages calls
statPageCountWhenMappingSum:
- the sum of the number of in use pages at each mapStackPages, used to estimate the average number of in use pages at scavenge, which heavily influences scavenger performance
"
Class {
#name : #CogStackPages,
#superclass : #CogClass,
#instVars : [
'coInterpreter',
'objectMemory',
'pages',
'mostRecentlyUsedPage',
'overflowLimit',
'bytesPerPage',
'statNumMaps',
'statPageCountWhenMappingSum',
'statMaxPageCountWhenMapping'
],
#pools : [
'VMBasicConstants'
],
#category : #'VMMaker-Interpreter'
}
{ #category : #translation }
CogStackPages class >> declareCVarsIn: aCCodeGenerator [
aCCodeGenerator
var: #mostRecentlyUsedPage type: #'StackPage *';
var: #pages type: #'StackPage *'.
aCCodeGenerator
removeVariable: 'coInterpreter'; "These are simulation/debugging things only"
removeVariable: 'objectMemory' "These are simulation/debugging things only"
]
{ #category : #assertions }
CogStackPages >> allPagesFree [
<doNotGenerate>
^pages allSatisfy: [:page| (self isFree: page)]
]
{ #category : #'memory access' }
CogStackPages >> byteAt: byteAddress [ "<Integer>"
self subclassResponsibility
]
{ #category : #initialization }
CogStackPages >> extraStackBytes [
"See initializeStack:numSlots:pageSize:stackLimitOffset:stackPageHeadroom:
``Because stack pages grow down...''"
^objectMemory wordSize
]
{ #category : #'page access' }
CogStackPages >> freeStackPage: aPage [ "<InterpreterStackPage>"
"MRUP-->used page<->used page<->used page<->used page<--LRUP
^ <-next-prev-> ^
| |
v <-prev-next-> v
free page<->free page<->free page<->free page"
<var: #aPage type: #'StackPage *'>
<inline: false>
self freeStackPageNoAssert: aPage.
self assert: self pageListIsWellFormed
]
{ #category : #'page access' }
CogStackPages >> freeStackPageNoAssert: aPage [ "<InterpreterStackPage>"
"MRUP-->used page<->used page<->used page<->used page<--LRUP
^ <-next-prev-> ^
| |
v <-prev-next-> v
free page<->free page<->free page<->free page"
<var: #aPage type: #'StackPage *'>
<returnTypeC: #void>
| prev |
<var: #prev type: #'StackPage *'>
aPage baseFP: 0.
aPage == mostRecentlyUsedPage ifTrue:
[mostRecentlyUsedPage := mostRecentlyUsedPage prevPage.
^nil].
(prev := aPage prevPage) isFree ifTrue:
[^nil].
prev nextPage: aPage nextPage.
aPage nextPage prevPage: prev.
aPage nextPage: mostRecentlyUsedPage nextPage.
mostRecentlyUsedPage nextPage prevPage: aPage.
aPage prevPage: mostRecentlyUsedPage.
mostRecentlyUsedPage nextPage: aPage
]
{ #category : #initialization }
CogStackPages >> initialize [
"Here we can initialize the variables C initializes to zero. #initialize methods do /not/ get translated."
statNumMaps := statPageCountWhenMappingSum := statMaxPageCountWhenMapping := 0
]
{ #category : #initialization }
CogStackPages >> initializeStack: theStackPages numSlots: stackSlots pageSize: slotsPerPage [
"Initialize the stack pages. In the C VM theStackPages will be alloca'ed memory to hold the
stack pages on the C stack. In the simulator they are housed in the memory between the
cogMethodZone and the heap."
<returnTypeC: #void>
self subclassResponsibility
]
{ #category : #initialization }
CogStackPages >> initializeWithByteSize: byteSize "<Integer>" for: anInterpreter [ "<CoInterpreter>" "^<Array of: <Integer>"
"Initialize the stackPages memory for simulation. Answer the base address of the memory."
self subclassResponsibility
]
{ #category : #'page access' }
CogStackPages >> isFree: thePage [
"This is an anachronism. Previously Slang couldn't generate the method correctly
from e.g. CogStackPageSurrogate>>isFree since Slang didn't do substitution on self.
Now it does, but there are still callers of isFree: so we keep this for simulation."
<doNotGenerate>
^thePage baseFP = 0
]
{ #category : #'page access' }
CogStackPages >> markStackPageLeastMostRecentlyUsed: page [ "<InterpreterStackPage>"
"This method is used to move a page to the end of the used pages.
This is to keep asserts checking pageListIsWellFormed happy."
"MRUP-->used page<->used page<->used page<->used page<--LRUP
^ <-next-prev-> ^
| |
v <-prev-next-> v
free page<->free page<->free page<->free page"
<var: #page type: #'StackPage *'>
<returnTypeC: #void>
| lastUsedPage |
<var: #lastUsedPage type: #'StackPage *'>
self assert: page = mostRecentlyUsedPage nextPage.
lastUsedPage := page nextPage.
[lastUsedPage isFree] whileTrue:
[lastUsedPage := lastUsedPage nextPage].
lastUsedPage nextPage = page ifTrue:
[^nil].
page prevPage nextPage: page nextPage.
page nextPage prevPage: page prevPage.
lastUsedPage prevPage nextPage: page.
page prevPage: lastUsedPage prevPage.
page nextPage: lastUsedPage.
lastUsedPage prevPage: page.
self assert: self pageListIsWellFormed
]
{ #category : #'page access' }
CogStackPages >> markStackPageMostRecentlyUsed: page [ "<InterpreterStackPage>"
"MRUP-->used page<->used page<->used page<->used page<--LRUP
^ <-next-prev-> ^
| |
v <-prev-next-> v
free page<->free page<->free page<->free page"
<var: #page type: #'StackPage *'>
<returnTypeC: #void>
page == mostRecentlyUsedPage ifTrue:
[^nil].
"Common case; making new page most recently used."
page prevPage == mostRecentlyUsedPage ifTrue:
[mostRecentlyUsedPage := page.
self assert: self pageListIsWellFormed.
^nil].
page prevPage nextPage: page nextPage.
page nextPage prevPage: page prevPage.
mostRecentlyUsedPage nextPage prevPage: page.
page prevPage: mostRecentlyUsedPage.
page nextPage: mostRecentlyUsedPage nextPage.
mostRecentlyUsedPage nextPage: page.
mostRecentlyUsedPage := page.
self assert: self pageListIsWellFormed
]
{ #category : #'page access' }
CogStackPages >> markStackPageNextMostRecentlyUsed: page [ "<InterpreterStackPage>"
"This method is used to move a page to a position in the list such that it cannot
be deallocated when a new page is allocated, without changing the most recently
used page. There must be at least 3 pages in the system. So making the page
the MRU's prevPage is sufficient to ensure it won't be deallocated."
"MRUP-->used page<->used page<->used page<->used page<--LRUP
^ <-next-prev-> ^
| |
v <-prev-next-> v
free page<->free page<->free page<->free page"
<var: #page type: #'StackPage *'>
<returnTypeC: #void>
self assert: page ~~ mostRecentlyUsedPage.
page nextPage == mostRecentlyUsedPage ifTrue:
[^nil].
page prevPage nextPage: page nextPage.
page nextPage prevPage: page prevPage.
mostRecentlyUsedPage prevPage nextPage: page.
page prevPage: mostRecentlyUsedPage prevPage.
page nextPage: mostRecentlyUsedPage.
mostRecentlyUsedPage prevPage: page.
self assert: self pageListIsWellFormed
]
{ #category : #'page access' }
CogStackPages >> memIndexFor: byteAddress [
"Map an address into the stack zone into a word index into the slots in the stack zone."
<doNotGenerate>
self subclassResponsibility
]
{ #category : #'page access' }
CogStackPages >> mostRecentlyUsedPage [
<cmacro: '() GIV(mostRecentlyUsedPage)'>
<returnTypeC: #'StackPage *'> "this is to guide Slang's inliner"
^mostRecentlyUsedPage
]
{ #category : #'page access' }
CogStackPages >> newStackPage [
"MRUP-->used page<->used page<->used page<->used page<--LRUP
^ <-next-prev-> ^
| |
v <-prev-next-> v
free page<->free page<->free page<->free page"
<returnTypeC: #'StackPage *'>
| lruOrFree |
<var: #lruOrFree type: #'StackPage *'>
lruOrFree := mostRecentlyUsedPage nextPage.
lruOrFree isFree ifTrue:
[^lruOrFree].
coInterpreter divorceFramesIn: lruOrFree.
^lruOrFree
]
{ #category : #'page access' }
CogStackPages >> overflowLimit [
^overflowLimit
]
{ #category : #'page access' }
CogStackPages >> pageIndexFor: pointer [ "<Integer>"
"Answer the page index for a pointer into stack memory, i.e. the index
for the page the address is in. N.B. This is a zero-relative index."
<var: #pointer type: #'void *'>
<inline: true>
self subclassResponsibility
]
{ #category : #assertions }
CogStackPages >> pageListIsWellFormed [
"Answer if the stack page list is well-formed.
MRUP-->used page<->used page<->used page<->used page<--LRUP
^ <-next-prev-> ^
| |
v <-prev-next-> v
free page<->free page<->free page<->free page"
| ok page count limit |
<inline: false>
<var: #page type: #'StackPage *'>
ok := true.
page := mostRecentlyUsedPage nextPage.
count := 1.
limit := coInterpreter numStkPages * 2.
[page isFree
and: [page ~= mostRecentlyUsedPage
and: [count <= limit]]] whileTrue:
[(self asserta: page nextPage prevPage == page) ifFalse:
[ok := false].
page := page nextPage.
count := count + 1].
[page ~= mostRecentlyUsedPage
and: [count <= limit]] whileTrue:
[(self asserta: page nextPage prevPage == page) ifFalse:
[ok := false].
(self asserta: page isFree not)
ifTrue:
[(self asserta: ((page addressIsInPage: page baseFP)
and: [page addressIsInPage: page headSP])) ifFalse:
[ok := false]]
ifFalse:
[ok := false].
page := page nextPage.
count := count + 1].
(self asserta: count = coInterpreter numStkPages) ifFalse:
[ok := false].
^ok
]
{ #category : #accessing }
CogStackPages >> pages [
<doNotGenerate>
^pages
]
{ #category : #statistics }
CogStackPages >> recordLivePagesOnMapping: numLivePages [
<inline: true>
statNumMaps := statNumMaps + 1.
statPageCountWhenMappingSum := statPageCountWhenMappingSum + numLivePages.
statMaxPageCountWhenMapping := statMaxPageCountWhenMapping max: numLivePages
]
{ #category : #initialization }
CogStackPages >> setInterpreter: anInterpreter [
"Initialize the stackPages memory for simulation. To keep access monitoring
in one place we defer to the coInterpreter for accessing memory."
<doNotGenerate>
coInterpreter := anInterpreter.
objectMemory := coInterpreter objectMemory
]
{ #category : #assertions }
CogStackPages >> somePageHasHeadFrameFP: theFP [
<doNotGenerate>
^pages anySatisfy: [:page| page headFP = theFP]
]
{ #category : #'page access' }
CogStackPages >> stackPageAt: index [
"Answer the page for a page index.
N.B. This is a zero-relative index."
<returnTypeC: #'StackPage *'>
<inline: true>
^self stackPageAt: index pages: pages
]
{ #category : #'page access' }
CogStackPages >> stackPageAt: index pages: thePages [
"Answer the page for a page index.
N.B. This is a zero-relative index."
<cmacro: '(index,pages) ((pages) + (index))'>
<returnTypeC: #'StackPage *'> "for Slang..."
^thePages at: index + 1
]
{ #category : #'page access' }
CogStackPages >> stackPageFor: pointer [ "<Integer>"
<inline: true>
<var: #pointer type: #'void *'>
<returnTypeC: #'StackPage *'>
^self stackPageAt: (self pageIndexFor: pointer)
]
{ #category : #statistics }
CogStackPages >> statAverageLivePagesWhenMapping [
<returnTypeC: #double>
^statNumMaps = 0
ifTrue: [0.0]
ifFalse: [statPageCountWhenMappingSum asFloat / statNumMaps]
]
{ #category : #statistics }
CogStackPages >> statAverageLivePagesWhenMapping: aFloat [
<var: #aFloat type: #double>
aFloat == 0.0
ifTrue: [statPageCountWhenMappingSum := statNumMaps := 0]
ifFalse: [coInterpreter primitiveFailFor: PrimErrBadArgument]
]
{ #category : #statistics }
CogStackPages >> statMaxPageCountWhenMapping [
<cmacro: '() GIV(statMaxPageCountWhenMapping)'>
^statMaxPageCountWhenMapping
]
{ #category : #statistics }
CogStackPages >> statMaxPageCountWhenMapping: num [
statMaxPageCountWhenMapping := num
]
{ #category : #'debug printing' }
CogStackPages >> whereIsMaybeStackThing: anOop [
"If anOop is an address within the stack zone answer a string stating that, otherwise answer nil."
<returnTypeC: 'char *'>
self subclassResponsibility
]