-
Notifications
You must be signed in to change notification settings - Fork 64
/
StackInterpreter.class.st
16140 lines (14313 loc) · 595 KB
/
StackInterpreter.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
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
"
This class is a complete implementation of the Smalltalk-80 virtual machine, derived originally from the Blue Book specification but quite different in some areas. This VM supports Closures but *not* old-style BlockContexts.
It has been modernized with 32-bit (and indeed 64-bit) pointers, better management of Contexts (see next item), and attention to variable use that allows the CCodeGenerator (qv) to keep, eg, the instruction pointer and stack pointer in registers as well as keeping most simple variables in a global array that seems to improve performance for most platforms.
The VM does not use Contexts directly. Instead Contexts serve as proxies for a more conventional stack format that is invisible to the image. There is considerable explanation at http://www.mirandabanda.org/cogblog/2009/01/14/under-cover-contexts-and-the-big-frame-up. The VM maintains a fixed-size stack zone divided into pages, each page being capable of holding several method/block activations. A send establishes a new frame in the current stack page, a return returns to the previous frame. This eliminates allocation/deallocation of contexts and the moving of receiver and arguments from caller to callee on each send/return. Contexts are created lazily when an activation needs a context (creating a block, explicit use of thisContext, access to sender when sender is a frame, or linking of stack pages together). Contexts are either conventional and heap-resident (""single"") or ""married"" and serve as proxies for their corresponding frame or ""widowed"", meaning that their spouse frame has been returned from (died). A married context is specially marked (more details in the code) and refers to its frame. Likewise a married frame is specially marked and refers to its context.
In addition to SmallInteger arithmetic and Floats, the VM supports logic on 32-bit (and 64-bit) PositiveLargeIntegers, thus allowing it to simulate itself much more efficiently than would otherwise be the case.
StackInterpreter and subclasses support multiple memory managers. Currently there are two. NewMemoryManager is a slightly refined version of ObjectMemory, and is the memory manager and garbage collector for the original Squeak object representation as described in ""Back to the Future The Story of Squeak, A Practical Smalltalk Written in Itself"", see http://ftp.squeak.org/docs/OOPSLA.Squeak.html. Spur is a faster, more regular object representation that is designed for more performance and functionality, and to have a common header format for both 32-bit and 64-bit versions. You can read about it in SpurMemoryManager's class comment. There is also a video of a presentation at ESUG 2014 (https://www.youtube.com/watch?v=k0nBNS1aHZ4), along with slides (http://www.slideshare.net/esug/spur-a-new-object-representation-for-cog?related=1).
StackInterpreter is designed toi be subclassed by CoInterpreter et al. CoInterpreter cooperates with a bytecode to machine-code JIT compiler, for much higher performance
Instance Variables
atCache
- a small array holding tuples of oop => format,fixedFields,size to speed up at:[put:]. Unused in CoInterpreter
breakLookupClassTag
- if non-nil, the class tag to break on sends, breaking (calling warning) if there's a match
breakSelector
- if breakSelectorLength ~= 0, a pointer to a string to compare messageSelector against on send, breaking (calling warning) if there's a match
breakSelectorLength
- if > 0, breakSelector is checked on each send. If < 0, breakSelector is checked on each MNU
bytecodeSetSelector
- if multiple bytecode sets are in use this is the offset (0 or 256) for the current bytecode set
checkAllocFiller
- a variable used to fill eden to allow checking for overwriting the end of an object
checkedPluginName
- the oop of a symbol which, when gcmode is GCCheckPrimCall, can check for heap memory leaks after a specific primitive has been called
classByteArrayCompactIndex
- the compact class index of the class ByteArray, if appropriate
classNameIndex
- the slot index of name in a class object, used or debug printing, derived from class Array at start-up
currentBytecode
- the value of the currentBytecode
debugCallbackInvokes
- a counter used to debug the old (Python) callback support
debugCallbackPath
- a variable used to hold the path through the new callback support
debugCallbackReturns
- a counter used to debug the old (Python) callback support; it should match debugCallbackInvokes
deferDisplayUpdates
- the variable that implements primitive 126, primitiveDeferDisplayUpdates
desiredEdenBytes
- the desired size of eden, used at image load and snapshot time
desiredNumStackPages
- the desired number of stack pages, used at image load and snapshot time
displayBits
- either the first indexable field of the current display object, or the handle of the current display surface
displayDepth
- pixel depth of the current display object or surface
displayHeight
- height in pixels of the current display object or surface
displayWidth
- width in pixels of the current display object or surface
extA
- if a prefix btecode set, such as SstaV1, is in use, the accumulator for extension A
extB
- if a prefix btecode set, such as SstaV1, is in use, the accumulator for extension B
externalPrimitiveTable
- xxxxx
externalPrimitiveTableFirstFreeIndex
- a small array cacheing the target function pointer for external calls (primitiveExternalCall)
extraFramesToMoveOnOverflow
- a variable used to prevent thrashing on sends and returns at the end of a page (see overflowedPage)
extraVMMemory
- in Spur, free heap to be allocated at startup. In V3, C memory to reserve for malloc at startup (i.e. malloc extraVMMemory, alloc heap, free extraVMMemory)
framePointer
- the pointer to the current frame when primitives (or in the CoInterpreter, when machine-code <-> interpreter transitions) are invoked (c.f. localFP)
fullScreenFlag
- true if the system is in full-screen mode
gcSemaphoreIndex
- if non-zero, the index in the semaphore table of a semaphore to signal after any GC
globalSessionID
- a non-zero number (derived from the time) identifying the current session
highestRunnableProcessPriority
- a tide mark in the runnableProcesses array, used to reduce the time spent scanning the array looking for the highest priority runnable process. This variable is set high when the priority of the highest process is unknown, and set to the highest found when the array is scanned. Hence most of the time the nused entries in the array are not scanned.
imageFloatsBigEndian
- true if the order of data in floats is big-endian
imageHeaderFlags
- the flags stored in the image at load time or to be stored in the image at snapshto time. These flags identify various options, sich as whether floats are in platfrm order.
inIOProcessEvents
- true if the system is receiving events in ioProcessEvents, used to avoid recursion when receiuving events via callbacks
instructionPointer
- the pointer to the current bytecode when primitives (or in the CoInterpreter, when machine-code <-> interpreter transitions) are invoked (c.f. localIP)
interpreterProxy
- the table of functions used to export interpreter and memory manager functions to plugin primitives
interruptCheckChain
- if non nil a funciton pointer to be called when a user interrupt event is received, used by plugin primitives to abort long-running calls on interrupt
interruptKeycode
- the keycode of the event signifying a user interrupt
interruptPending
- a variable set by ioProcessEvents if a user interrupt is pending
jmpBuf
- a small array of jmpbufs (for setjmp/longjmp) used to manage returning in the iold (Python) callback support (see suspendedCallbacks et al)
jmpDepth
- the index of the next free entry in jmpBuf
lastMethodCacheProbeWrite
- the index of the last write into the method lookup cache, used by primitiveExternalCall to rewrite the method cache entry to call the target function, avoiding going through primitiveExternalCall on every plugin primitive dispatch
lkupClass
- the implicit class argument to the class hierarchy looup routines such as lookupOrdinarySend
lkupClassTag
- the implicit class tag argument to message send lookup
localAbsentReceiver
- Newspeak, the absent receiver in any Newspeak absent receiver send
localAbsentReceiverOrZero
- Newspeak, if non-zero, the absent receiver in any Newspeak outer absent receiver send
localFP
- the frame pointer in the fully-inlined interpret routine, hopfully allowing a C compiler to assign localFP to a register variable (c.f. framePointer)
localIP
- the instruction pointer in the fully-inlined interpret routine, hopfully allowing a C compiler to assign localFP to a register variable (c.f. instructionPointer)
localReturnValue
- the value being returned in return bytecodes
localSP
- the stack pointer in the fully-inlined interpret routine, hopfully allowing a C compiler to assign localFP to a register variable (c.f. framePointer)
longRunningPrimitiveCheckMethod
- a variable used to monitor long-running primtiives via primitiveLongRunningPrimitive
longRunningPrimitiveCheckSemaphore
- a variable used to monitor long-running primtiives via primitiveLongRunningPrimitive
longRunningPrimitiveCheckSequenceNumber
- a variable used to monitor long-running primtiives via primitiveLongRunningPrimitive
longRunningPrimitiveGCUsecs
- a variable used to monitor long-running primtiives via primitiveLongRunningPrimitive
longRunningPrimitiveSignalUndelivered
- a variable used to monitor long-running primtiives via primitiveLongRunningPrimitive
longRunningPrimitiveStartUsecs
- a variable used to monitor long-running primtiives via primitiveLongRunningPrimitive
longRunningPrimitiveStopUsecs
- a variable used to monitor long-running primtiives via primitiveLongRunningPrimitive
lowcodeCalloutState
- Lowcode, the state used to marshall an outgoing Lowcode call
maxExtSemTabSizeSet
- a flag stating whether the maximum size of the external semaphore table has been set or not
metaAccessorDepth
- Spur, the accessor depth of a primitive being invoked by one of the meta primitive primitives, primitiveDoPrimitiveWithArgs and primitiveDoNamedPrimitiveWithArgs
metaclassNumSlots
- teh size of a Metaclass instanc, set at startup, used for debug printing
method
- the oop of the current method
methodCache
- a small array holding tuples of selector x class => method,functionPointer to speed up message send (avoid class hierarchy search on send)
methodDictLinearSearchLimit
- a variable used to control searching of method dictionaries. Dictionaries of size within the limit are searched linearly instead of hashed. This can be used either to speed up search in small dictionaries or to turn off hashed lookup wen hashing needs to be changed
nativeSP
- Lowcode, the native (C) stack pointer (?; then why nativeStackPointer?)
nativeStackPointer
- Lowcode, the native (C) stack pointer (?; then why nativeSP?)
nextPollUsecs
- if non-zero, the micosecond clock value at which to next poll for events, used to control event polling rate
nextWakeupUsecs
- if non-zero, the micosecond clock value at which the next delay expires
nsMethodCache
- Newspeak, a small array hilding tuples of selector x class tag x calling method x privacy code => target method,primitive function,actual receiver, used to speed up Newspeak absent receiver sends
numExtB
- the number of bytes in extB, used to correctly maintain extB, given that it is unsigned
numStackPages
- the number of stack pages being used
overflowedPage
- the stack page that a send last overflowed, used to avoid thrashing on send and return at the end of a stack page (see extraFramesToMoveOnOverflow)
pendingFinalizationSignals
- a variable used to control signalling the finalizationSemahpore
primitiveAccessorDepthTable
- Spur, the accessor depths for the iundexed primitives, used to determine how much state to scan loking for forwarders on primitive failure
primitiveFunctionPointer
- the function pointer (in simulation, the selector symbol) of the current primitive, nil for newMethod if there is no primitive
primitiveTable
- the table holding the functions (in simulation the selector symbols) for the indexed primitives
savedWindowSize
- the display size to write into a snapshot. Avoids writing a zero window size into a snapshot when an image is loaded headless.
shadowCallStackPointer
- Lowcode, the shadow stack pointer, used when marshalling Lowcode external calls
showSurfaceFn
- if non-zero, the function to call to update the display when the current display is a surface
stackLimit
- the variable marking the end of the current stack page, also used to break out of interpretation to check for events. When marking the end of a page, it enables a send to create an activation on a new page, When set so that any send would fail the stack limit check, causes a check for events on stack page overflow
stackPage
- the current stack page
stackPages
- the set of stack pages
stackPointer
- the pointer to the top of stack in the current frame when primitives (or in the CoInterpreter, when machine-code <-> interpreter transitions) are invoked (c.f. localSP)
statCheckForEvents
- the count of checkForEventsMaybeContextSwitch: calls
statForceInterruptCheck
- the count of forceInterruptCheck calls
statIOProcessEvents
- the count of ioProcessEvents calls
statIdleUsecs
- the count of microseconds at which the system is at idle (a bad idea; this should be replaced by its inverse; asking the OS how long the VM process has been active)
statPendingFinalizationSignals
- the count of pendingFinalizationSignals
statProcessSwitch
- the count of process switches
statStackOverflow
- the count of stack overflows
statStackPageDivorce
- the cound of stack page divorces (a stack page divorce occurs when a stack page must be freed for use)
suppressHeartbeatFlag
- a flag controlling whether the heatbeat is in effect; the heartbeat is used to set stackLimit periodically to cause break out to chedck for events (see stackLimit)
suspendedCallbacks
- a small array holding the processes suspended when the old callback machinery is in use (see jmpBuf et al)
suspendedMethods
- a small array holding the methods of the processes suspended when the old callback machinery is in use
tempOop
- if non-zero, an oop that may move during primitive execution
tempOop2
- if non-zero, an oop that may move during primitive execution
the2ndUnknownShort
- the value of a field in the image header that is unused in the StackInterpreter but used in the CoInterpreter (and hence to be preserved in snapshots)
theUnknownShort
- the value of a field in the image header that is unused in the StackInterpreter but used in the CoInterpreter (and hence to be preserved in snapshots)
thisClassIndex
- the index in a Metaclass of thisClass (the instance of the metaclass) used in debug printing
"
Class {
#name : #StackInterpreter,
#superclass : #InterpreterPrimitives,
#instVars : [
'currentBytecode',
'stackLimit',
'stackPage',
'stackPages',
'method',
'instructionPointer',
'stackPointer',
'framePointer',
'localReturnValue',
'extA',
'extB',
'numExtB',
'primitiveFunctionPointer',
'methodCache',
'atCache',
'lkupClassTag',
'lkupClass',
'methodDictLinearSearchLimit',
'highestRunnableProcessPriority',
'reenterInterpreter',
'nextWakeupUsecs',
'nextPollUsecs',
'interruptPending',
'savedWindowSize',
'imageHeaderFlags',
'fullScreenFlag',
'extraVMMemory',
'interpreterProxy',
'primitiveTable',
'primitiveAccessorDepthTable',
'externalPrimitiveTable',
'externalPrimitiveTableFirstFreeIndex',
'overflowedPage',
'extraFramesToMoveOnOverflow',
'globalSessionID',
'jmpBuf',
'jmpDepth',
'suspendedCallbacks',
'suspendedMethods',
'numStackPages',
'desiredNumStackPages',
'desiredEdenBytes',
'classNameIndex',
'thisClassIndex',
'metaclassNumSlots',
'suppressHeartbeatFlag',
'breakSelector',
'breakSelectorLength',
'breakLookupClassTag',
'longRunningPrimitiveCheckMethod',
'longRunningPrimitiveCheckSemaphore',
'longRunningPrimitiveStartUsecs',
'longRunningPrimitiveStopUsecs',
'longRunningPrimitiveGCUsecs',
'longRunningPrimitiveCheckSequenceNumber',
'longRunningPrimitiveSignalUndelivered',
'checkAllocFiller',
'tempOop',
'tempOop2',
'metaAccessorDepth',
'theUnknownShort',
'imageFloatsBigEndian',
'maxExtSemTabSizeSet',
'lastMethodCacheProbeWrite',
'gcSemaphoreIndex',
'classByteArrayCompactIndex',
'checkedPluginName',
'displayBits',
'displayWidth',
'displayHeight',
'displayDepth',
'statForceInterruptCheck',
'statStackOverflow',
'statStackPageDivorce',
'statCheckForEvents',
'statProcessSwitch',
'statIdleUsecs',
'debugCallbackPath',
'debugCallbackReturns',
'debugCallbackInvokes',
'printedStackFrames',
'maxStacksToPrint',
'maxStackMessagePrinted',
'libFFI',
'codeGeneratorToComputeAccessorDepth',
'showSurfaceFn',
'imageReaderWriter',
'pendingFinalizationSignals',
'imageVersionNumber'
],
#classVars : [
'AlternateHeaderHasPrimFlag',
'AlternateHeaderIsOptimizedFlag',
'AlternateHeaderNumLiteralsMask',
'AtCacheFixedFields',
'AtCacheFmt',
'AtCacheMask',
'AtCacheOop',
'AtCacheSize',
'AtCacheTotalSize',
'AtPutBase',
'BytecodeEncoderClassName',
'BytecodeTable',
'CSCallbackEnter',
'CSCallbackLeave',
'CSCheckEvents',
'CSEnterCriticalSection',
'CSExitCriticalSection',
'CSResume',
'CSSignal',
'CSSuspend',
'CSWait',
'CSYield',
'CacheProbeMax',
'DirBadPath',
'DirEntryFound',
'DirNoMoreEntries',
'DumpStackOnLowSpace',
'EnclosingObjectIndex',
'FailImbalancedPrimitives',
'LongStoreBytecode',
'MaxExternalPrimitiveTableSize',
'MaxJumpBuf',
'MaxPrimitiveIndex',
'MaxQuickPrimitiveIndex',
'MethodHeaderArgCountShift',
'MethodHeaderFlagBitPosition',
'MethodHeaderTempCountShift',
'PrimitiveTable',
'ReturnToInterpreter',
'StackPageReachedButUntraced',
'StackPageTraceInvalid',
'StackPageTraced',
'StackPageUnreached'
],
#pools : [
'VMBasicConstants',
'VMBytecodeConstants',
'VMClassIndices',
'VMMethodCacheConstants',
'VMObjectIndices',
'VMSpurObjectRepresentationConstants',
'VMStackFrameOffsets',
'VMWellKnownPrimitivesConstants'
],
#category : #'VMMaker-Interpreter'
}
{ #category : #translation }
StackInterpreter class >> additionalHeadersDo: aBinaryBlock [
"Evaluate aBinaryBlock with the names and contents of
any additional header files that need to be generated."
aBinaryBlock
value: 'vmCallback.h'
value: self vmCallbackHeader.
VMMemoryMap generateHeader: aBinaryBlock.
VMRememberedSet generateHeader: aBinaryBlock.
]
{ #category : #translation }
StackInterpreter class >> additionalSelectorTables [
^{ self primitiveTable }
]
{ #category : #translation }
StackInterpreter class >> ancilliaryClasses [
"Answer any extra classes to be included in the translation."
^{ self objectMemoryClass.
VMCallbackContext.
VMStackPages.
LibFFI.
VMStackPage.
SpurImageHeaderStruct.
ComposedMetadataStruct.
"I am putting the abstract superclasses... because I cannot make it work else"
VMImageReaderWriter} , VMImageReaderWriter ancilliaryClasses
]
{ #category : #constants }
StackInterpreter class >> bytecodeTable [
^ BytecodeTable
]
{ #category : #'C translation' }
StackInterpreter class >> declareCVarsIn: aCCodeGenerator [
| vmClass |
self class == thisContext methodClass ifFalse: [^self]. "Don't duplicate decls in subclasses"
vmClass := aCCodeGenerator vmClass. "Generate primitiveTable etc based on vmClass, not just StackInterpreter"
aCCodeGenerator
addHeaderFile:'<stddef.h> /* for e.g. alloca */';
addHeaderFile:'<stdint.h> /* for e.g. alloca */';
addHeaderFile:'"sigjmp_support.h"';
addHeaderFile:'<wchar.h> /* for wint_t */';
addHeaderFile:'"vmCallback.h"';
addHeaderFile:'"sqMemoryFence.h"';
addHeaderFile:'"dispdbg.h"';
addHeaderFile:'"vmMemoryMap.h"';
addHeaderFile:'"vmRememberedSet.h"';
"This cannot be properly expressed in slang.
If ffi is put as a separate header, slang will sort the header and put it outside the #ifdef"
addHeaderFile:'#if FEATURE_FFI
#include <ffi.h>
#endif //FEATURE_FFI
#if FEATURE_THREADED_FFI
#include "worker.h"
#endif //FEATURE_THREADED_FFI'.
vmClass declareInterpreterVersionIn: aCCodeGenerator defaultName: 'Stack'.
aCCodeGenerator
var: #interpreterProxy type: #'struct VirtualMachine*'.
aCCodeGenerator
declareVar: #sendTrace type: 'volatile int';
declareVar: #byteCount type: #usqInt.
"These need to be pointers or unsigned."
self declareC: #(method newMethod)
as: #usqInt
in: aCCodeGenerator.
"These are all pointers; char * because Slang has no support for C pointer arithmetic."
self declareC: #(instructionPointer stackPointer framePointer stackLimit breakSelector)
as: #'char *'
in: aCCodeGenerator.
aCCodeGenerator
var: #breakSelectorLength
declareC: 'sqInt breakSelectorLength = MinSmallInteger'.
self declareC: #(stackPage overflowedPage)
as: #'StackPage *'
in: aCCodeGenerator.
aCCodeGenerator removeVariable: 'stackPages'. "this is an implicit receiver in the translated code."
BytecodeSetHasExtensions == false ifTrue:
[aCCodeGenerator
removeVariable: 'extA';
removeVariable: 'extB'].
aCCodeGenerator
var: #methodCache
declareC: 'sqIntptr_t methodCache[MethodCacheSize + 1 /* ', (MethodCacheSize + 1) printString, ' */]'.
AtCacheTotalSize isInteger ifTrue:
[aCCodeGenerator
var: #atCache
declareC: 'sqInt atCache[AtCacheTotalSize + 1 /* ', (AtCacheTotalSize + 1) printString, ' */]'].
aCCodeGenerator
var: #primitiveTable
declareC: 'void (*primitiveTable[MaxPrimitiveIndex + 2 /* ', (MaxPrimitiveIndex + 2) printString, ' */])(void) = ', vmClass primitiveTableString.
vmClass primitiveTable do:
[:symbolOrNot|
(symbolOrNot isSymbol
and: [symbolOrNot ~~ #primitiveFail]) ifTrue:
[(aCCodeGenerator methodNamed: symbolOrNot) ifNotNil:
[:tMethod| tMethod returnType: #void]]].
aCCodeGenerator
var: #primitiveAccessorDepthTable
type: 'signed char'
sizeString: 'MaxPrimitiveIndex + 2 /* ', (MaxPrimitiveIndex + 2) printString, ' */'
array: vmClass primitiveAccessorDepthTable.
aCCodeGenerator
var: #displayBits type: #'void *'.
self declareC: #(displayWidth displayHeight displayDepth) as: #int in: aCCodeGenerator.
aCCodeGenerator
var: #primitiveFunctionPointer
declareC: 'void (*primitiveFunctionPointer)()';
var: #externalPrimitiveTable
declareC: 'void (*externalPrimitiveTable[MaxExternalPrimitiveTableSize + 1 /* ', (MaxExternalPrimitiveTableSize + 1) printString, ' */])(void)';
var: #interruptCheckChain
declareC: 'void (*interruptCheckChain)(void) = 0';
var: #showSurfaceFn
declareC: 'int (*showSurfaceFn)(sqIntptr_t, int, int, int, int)';
var: #jmpBuf
declareC: 'jmp_buf jmpBuf[MaxJumpBuf + 1 /* ', (MaxJumpBuf + 1) printString, ' */]';
var: #suspendedCallbacks
declareC: 'usqInt suspendedCallbacks[MaxJumpBuf + 1 /* ', (MaxJumpBuf + 1) printString, ' */]';
var: #suspendedMethods
declareC: 'usqInt suspendedMethods[MaxJumpBuf + 1 /* ', (MaxJumpBuf + 1) printString, ' */]'.
self declareCAsUSqLong: #(nextPollUsecs nextWakeupUsecs longRunningPrimitiveGCUsecs
longRunningPrimitiveStartUsecs longRunningPrimitiveStopUsecs
"these are high-frequency enough that they're overflowing quite quickly on modern hardware"
statProcessSwitch statForceInterruptCheck
statCheckForEvents statStackOverflow statStackPageDivorce
statIdleUsecs)
in: aCCodeGenerator.
aCCodeGenerator var: #nextProfileTick type: #sqLong.
aCCodeGenerator
var: #reenterInterpreter
declareC: 'jmp_buf reenterInterpreter; /* private export */'.
aCCodeGenerator
var: #messageCount
type: #'usqInt'.
aCCodeGenerator removeVariable: #'libFFI'.
LibFFIConstants classVariables do: [ :e | aCCodeGenerator removeConstant: e name ].
aCCodeGenerator removeVariable: #imageReaderWriter.
]
{ #category : #translation }
StackInterpreter class >> implicitReturnTypeFor: aSelector [
"Answer the return type for methods that don't have an explicit return."
^#void
]
{ #category : #initialization }
StackInterpreter class >> initializeAssociationIndex [
KeyIndex := 0.
ValueIndex := 1
]
{ #category : #initialization }
StackInterpreter class >> initializeBytecodeTable [
"StackInterpreter initializeBytecodeTable"
VMBytecodeConstants falsifyBytecodeSetFlags: InitializationOptions.
BytecodeSetHasDirectedSuperSend := false.
^ self initializeBytecodeTableForSistaV1
]
{ #category : #initialization }
StackInterpreter class >> initializeBytecodeTableForSistaV1 [
"See e.g. the cass comment for EncoderForSistaV1"
"StackInterpreter initializeBytecodeTableForSistaV1"
"Note: This table will be used to generate a C switch statement."
InitializationOptions at: #SistaV1BytecodeSet put: (SistaV1BytecodeSet := true).
BytecodeTable := Array new: 256.
BytecodeEncoderClassName := #EncoderForSistaV1.
BytecodeSetHasDirectedSuperSend := true.
BytecodeSetHasExtensions := true.
LongStoreBytecode := 245.
self table: BytecodeTable from:
#( "1 byte bytecodes"
( 0 15 pushReceiverVariableBytecode)
( 16 31 pushLiteralVariable16CasesBytecode)
( 32 63 pushLiteralConstantBytecode)
( 64 75 pushTemporaryVariableBytecode)
( 76 pushReceiverBytecode)
( 77 pushConstantTrueBytecode)
( 78 pushConstantFalseBytecode)
( 79 pushConstantNilBytecode)
( 80 pushConstantZeroBytecode)
( 81 pushConstantOneBytecode)
( 82 extPushPseudoVariable)
( 83 duplicateTopBytecode)
( 84 87 unknownBytecode)
( 88 returnReceiver)
( 89 returnTrue)
( 90 returnFalse)
( 91 returnNil)
( 92 returnTopFromMethod)
( 93 returnNilFromBlock)
( 94 returnTopFromBlock)
( 95 extNopBytecode)
( 96 bytecodePrimAdd)
( 97 bytecodePrimSubtract)
( 98 bytecodePrimLessThanSistaV1) "for booleanCheatSistaV1:"
( 99 bytecodePrimGreaterThanSistaV1) "for booleanCheatSistaV1:"
(100 bytecodePrimLessOrEqualSistaV1) "for booleanCheatSistaV1:"
(101 bytecodePrimGreaterOrEqualSistaV1) "for booleanCheatSistaV1:"
(102 bytecodePrimEqualSistaV1) "for booleanCheatSistaV1:"
(103 bytecodePrimNotEqualSistaV1) "for booleanCheatSistaV1:"
(104 bytecodePrimMultiply)
(105 bytecodePrimDivide)
(106 bytecodePrimMod)
(107 bytecodePrimMakePoint)
(108 bytecodePrimBitShift)
(109 bytecodePrimDiv)
(110 bytecodePrimBitAnd)
(111 bytecodePrimBitOr)
(112 bytecodePrimAt)
(113 bytecodePrimAtPut)
(114 bytecodePrimSize)
(115 bytecodePrimNext) "i.e. a 0 arg special selector"
(116 bytecodePrimNextPut) "i.e. a 1 arg special selector"
(117 bytecodePrimAtEnd)
(118 bytecodePrimIdenticalSistaV1) "for booleanCheatSistaV1:"
(119 bytecodePrimClass)
(120 bytecodePrimNotIdenticalSistaV1) "was blockCopy:"
(121 bytecodePrimValue)
(122 bytecodePrimValueWithArg)
(123 bytecodePrimDo) "i.e. a 1 arg special selector"
(124 bytecodePrimNew) "i.e. a 0 arg special selector"
(125 bytecodePrimNewWithArg) "i.e. a 1 arg special selector"
(126 bytecodePrimPointX) "i.e. a 0 arg special selector"
(127 bytecodePrimPointY) "i.e. a 0 arg special selector"
(128 143 sendLiteralSelector0ArgsBytecode)
(144 159 sendLiteralSelector1ArgBytecode)
(160 175 sendLiteralSelector2ArgsBytecode)
(176 183 shortUnconditionalJump)
(184 191 shortConditionalJumpTrue)
(192 199 shortConditionalJumpFalse)
(200 207 storeAndPopReceiverVariableBytecode)
(208 215 storeAndPopTemporaryVariableBytecode)
(216 popStackBytecode)
(217 unconditionnalTrapBytecode)
(218 223 unknownBytecode)
"2 byte bytecodes"
(224 extABytecode)
(225 extBBytecode)
(226 extPushReceiverVariableBytecode)
(227 extPushLiteralVariableBytecode)
(228 extPushLiteralBytecode)
(229 longPushTemporaryVariableBytecode)
(230 unknownBytecode)
(231 pushNewArrayBytecode)
(232 extPushIntegerBytecode)
(233 extPushCharacterBytecode)
(234 extSendBytecode)
(235 extSendSuperBytecode)
(236 callMappedInlinedPrimitive)
(237 extUnconditionalJump)
(238 extJumpIfTrue)
(239 extJumpIfFalse)
(240 extStoreAndPopReceiverVariableBytecode)
(241 extStoreAndPopLiteralVariableBytecode)
(242 longStoreAndPopTemporaryVariableBytecode)
(243 extStoreReceiverVariableBytecode)
(244 extStoreLiteralVariableBytecode)
(245 longStoreTemporaryVariableBytecode)
(246 247 unknownBytecode)
"3 byte bytecodes"
(248 callPrimitiveBytecode)
(249 extPushFullClosureBytecode)
(250 unknownBytecode) "was extPushClosureBytecode"
(251 pushRemoteTempLongBytecode)
(252 storeRemoteTempLongBytecode)
(253 storeAndPopRemoteTempLongBytecode)
(254 255 unknownBytecode)
)
]
{ #category : #initialization }
StackInterpreter class >> initializeCaches [
| atCacheEntries atCacheEntrySize |
MethodCacheEntries := 1024.
MethodCacheSelector := 1.
MethodCacheClass := 2.
MethodCacheMethod := 3.
MethodCachePrimFunction := 4.
MethodCacheEntrySize := 4. "Must be power of two for masking scheme."
MethodCacheMask := (MethodCacheEntries - 1) * MethodCacheEntrySize.
MethodCacheSize := MethodCacheEntries * MethodCacheEntrySize.
CacheProbeMax := 3.
AtCacheOop := 1.
AtCacheSize := 2.
AtCacheFmt := 3.
AtCacheFixedFields := 4.
atCacheEntries := 8.
atCacheEntrySize := 4. "Must be power of two for masking scheme."
AtCacheMask := (atCacheEntries-1) * atCacheEntrySize.
AtPutBase := atCacheEntries * atCacheEntrySize.
AtCacheTotalSize := atCacheEntries * atCacheEntrySize * 2.
]
{ #category : #initialization }
StackInterpreter class >> initializeCharacterIndex [
CharacterValueIndex := 0
]
{ #category : #initialization }
StackInterpreter class >> initializeCharacterScannerIndices [
CrossedX := 258.
EndOfRun := 257
]
{ #category : #initialization }
StackInterpreter class >> initializeClassIndices [
"Class Class"
SuperclassIndex := 0.
MethodDictionaryIndex := 1.
InstanceSpecificationIndex := 2.
"Fields of a message dictionary"
MethodArrayIndex := 1.
SelectorStart := 2.
]
{ #category : #initialization }
StackInterpreter class >> initializeContextIndices [
"Class MethodContext"
SenderIndex := 0.
InstructionPointerIndex := 1.
StackPointerIndex := 2.
MethodIndex := 3.
ClosureIndex := 4. "N.B. Called receiverMap in old images, closureOrNil in newer images."
ReceiverIndex := 5.
CtxtTempFrameStart := 6.
SmallContextSlots := CtxtTempFrameStart + 16. "16 indexable fields"
"Large contexts have 56 indexable fields. Max with single header word of ObjectMemory [but not SpurMemoryManager ;-)]."
LargeContextSlots := CtxtTempFrameStart + 56.
"Class BlockClosure"
FullClosureOuterContextIndex := 0.
FullClosureCompiledBlockIndex := 1.
FullClosureNumArgsIndex := 2.
FullClosureReceiverIndex := 3.
FullClosureFirstCopiedValueIndex := 4.
]
{ #category : #initialization }
StackInterpreter class >> initializeDirectoryLookupResultCodes [
DirEntryFound := 0.
DirNoMoreEntries := 1.
DirBadPath := 2.
]
{ #category : #initialization }
StackInterpreter class >> initializeFrameIndices [
"Format of a stack frame. Word-sized indices relative to the frame pointer.
Terminology
Frames are either single (have no context) or married (have a context).
Contexts are either single (exist on the heap), married (have a context) or widowed (had a frame that has exited).
Stacks grow down:
receiver for method activations/closure for block activations
arg0
...
argN
caller's method ip/base frame's sender context
fp-> saved fp
method
frame flags
context (uninitialized)
receiver
first temp
...
sp-> Nth temp
frame flags holds the number of arguments (since argument temporaries are above the frame)
the flag for a block activation
and the flag indicating if the context field is valid (whether the frame is married).
The first frame in a stack page is the baseFrame and is marked as such by a null saved fp,
in which case the saved method ip is actually the context (possibly hybrid) beneath the base frame"
| fxCallerSavedIP fxSavedFP fxMethod fxFrameFlags fxThisContext fxReceiver |
fxCallerSavedIP := 1.
fxSavedFP := 0.
fxMethod := -1.
fxThisContext := -2.
fxFrameFlags := -3. "Can find numArgs, needed for fast temp access. args are above fxCallerSavedIP.
Can find ``is block'' bit
Can find ``has context'' bit"
fxReceiver := -4.
FrameSlots := fxCallerSavedIP - fxReceiver + 1.
FoxCallerSavedIP := fxCallerSavedIP * BytesPerWord.
"In base frames the caller saved ip field holds the caller context."
FoxCallerContext := FoxCallerSavedIP.
FoxSavedFP := fxSavedFP * BytesPerWord.
FoxMethod := fxMethod * BytesPerWord.
FoxFrameFlags := fxFrameFlags * BytesPerWord.
FoxThisContext := fxThisContext * BytesPerWord.
FoxReceiver := fxReceiver * BytesPerWord.
"Mark the CoInterpreter-specific offsets as #undefined to
avoid including them accidentally in StackInterpreter code."
IFrameSlots := #undefined.
MFrameSlots := #undefined.
FoxIFrameFlags := #undefined.
FoxIFSavedIP := #undefined.
FoxIFReceiver := #undefined.
FoxMFReceiver := #undefined
]
{ #category : #initialization }
StackInterpreter class >> initializeMessageIndices [
MessageSelectorIndex := 0.
MessageArgumentsIndex := 1.
MessageLookupClassIndex := 2.
]
{ #category : #initialization }
StackInterpreter class >> initializeMethodIndices [
| tagBits |
"Class CompiledMethod"
HeaderIndex := 0.
LiteralStart := 1.
tagBits := self objectMemoryClass numSmallIntegerTagBits.
LargeContextBit := 16r20000 << tagBits. "This bit set in method headers if large context is needed."
MethodHeaderTempCountShift := 18 + tagBits.
MethodHeaderArgCountShift := 24 + tagBits.
AlternateHeaderHasPrimFlag := 16r10000 << tagBits.
AlternateHeaderIsOptimizedFlag := 16r8000 << tagBits.
AlternateHeaderNumLiteralsMask := 16r7FFF. "N.B. *not* shifted"
"The position of the unused flag bit in the method header, not including tag bit(s).
Bits 28 & 29 are free for use as flag bits."
MethodHeaderFlagBitPosition := 28 + tagBits.
]
{ #category : #initialization }
StackInterpreter class >> initializeMiscConstants [
super initializeMiscConstants.
STACKVM := true.
"These flags function to identify a GC operation, or
to specify what operations the leak checker should be run for."
GCModeFull := 1. "stop-the-world global GC"
GCModeNewSpace := 2. "Spur's scavenge, or V3's incremental"
GCModeIncremental := 4. "incremental global gc (Dijkstra tri-colour marking); as yet unimplemented"
GCModeBecome := 8. "v3 post-become sweeping/Spur forwarding"
GCModeImageSegment := 16. "just a flag for leak checking image segments"
GCModeFreeSpace := 32. "just a flag for leak checking free space; Spur only"
GCCheckPrimCall := 64. "just a flag for leak checking external primitive calls"
StackPageTraceInvalid := -1.
StackPageUnreached := 0.
StackPageReachedButUntraced := 1.
StackPageTraced := 2.
CSCallbackEnter := 3.
CSCallbackLeave := 4.
CSEnterCriticalSection := 5.
CSExitCriticalSection := 6.
CSResume := 7.
CSSignal := 8.
CSSuspend := 9.
CSWait := 10.
CSYield := 11.
CSCheckEvents := 12.
DumpStackOnLowSpace := 0.
MillisecondClockMask := 16r1FFFFFFF.
"Note: The external primitive table should actually be dynamically sized but for the sake of inferior platforms (e.g., Mac :-) who cannot allocate memory in any reasonable way, we keep it static (and cross our fingers...)"
MaxExternalPrimitiveTableSize := 4096. "entries"
MaxJumpBuf := 32. "max. callback depth"
FailImbalancedPrimitives := InitializationOptions at: #FailImbalancedPrimitives ifAbsentPut: [true].
ReturnToInterpreter := 1. "setjmp/longjmp code."
]
{ #category : #initialization }
StackInterpreter class >> initializePointIndices [
XIndex := 0.
YIndex := 1
]
{ #category : #initialization }
StackInterpreter class >> initializePrimitiveTable [
"This table generates a C function address table used in slowPrimitiveResponse along with dispatchFunctionPointerOn:in:"
"self initializePrimitiveTable"
"NOTE: The real limit here is 2047 because of the old method header layout but there is no point in going over the needed size"
MaxPrimitiveIndex := 660.
MaxQuickPrimitiveIndex := 519.
PrimNumberExternalCall := 117.
PrimNumberDoPrimitive := 118.
PrimNumberFFICall := 120.
PrimNumberDoExternalCall := 218.
PrimitiveTable := Array new: MaxPrimitiveIndex + 1.
self primitivesClass table: PrimitiveTable from:
#( "Integer Primitives (0-19)"