forked from newspeaklanguage/newspeak
-
Notifications
You must be signed in to change notification settings - Fork 0
/
IntermediatesForSqueak.ns
359 lines (339 loc) · 11 KB
/
IntermediatesForSqueak.ns
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
Newspeak3
'Mirrors'
class IntermediatesForSqueak usingPlatform: p = (
(* The output of the compiler and the mutable internals of a mirror builder.
Synthetics: slot accessors, nested class slots, nested class accessor, instance initializers, factories
* The LowLevelMirrors module defines a mirror library at the level of abstraction of the virtual machine - in this case, Squeak. Ideally, the high level mirror library will depend on the low level mirror API, and be largely isolated from the details of Squeak.
Copyright 2008 Cadence Design Systems, Inc.
Copyright 2011 Ryan Macnak
Licensed under the Apache License, Version 2.0 (the ''License''); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*)
|
private List = p collections List.
private Map = p collections Map.
private CompiledMethod = p squeak CompiledMethod.
private CompiledMethodTrailer = p squeak CompiledMethodTrailer.
private AdditionalMethodState = p squeak AdditionalMethodState.
private EncoderForNewsqueakV4 = p squeak EncoderForNewsqueakV4.
|) (
public class IntermediateClassDeclaration = (|
simpleNameX
public headerSource
public factoryName
public comment
public category
public instanceSide = IntermediateMixin for: self isMeta: false.
public classSide = IntermediateMixin for: self isMeta: true.
public enclosingClass <IntermediateMixin>
public builder <ClassDeclarationBuilder>
public existingMixin
public accessor <IntermediateMethod>
public factory <IntermediateMethod>
public initializers <List[IntermediateMethod]>
|) (
public accessModifier ^<Symbol> = (
isTopLevel ifTrue: [^#public].
^accessor accessModifier
)
public addSyntheticSlotsTo: slots = (
| slot = IntermediateSlotDeclaration new. |
slot name: (simpleName, '`slot') asSymbol.
slot isMutable: true.
slot accessModifier: #private.
slots add: slot.
)
public isTopLevel = (
nil = enclosingClass ifFalse: [^false].
(* No enclosing class computed yet, but might be just be deferred. *)
nil = existingMixin ifTrue: [^true (* New class declarations are eagerly computed. *)].
^nil = existingMixin enclosingMixin
)
public name = (
^simpleName
)
public printOn: stream = (
stream nextPutAll: 'IntermediateClassDeclaration:'; nextPutAll: qualifiedName.
)
public simpleName= (
^simpleNameX
)
public simpleName: n = (
(n includes: "`") ifTrue: [halt].
simpleNameX: n
)
) : (
)
public class IntermediateMethod = (|
public method <CompiledMethod>
public debugInfo
public maxStack <Integer>
public maxLocals <Integer>
public argCount <Integer>
public literals <List[Object]>
public bytes <List[Byte]> ::= List new.
public selector <Symbol>
public methodMixin <AbstractMixin>
public source <String>
public pragmas
public psPrimitive
public accessModifier <Symbol>
public metadata = Map new.
public category
public isSynthetic ::= false.
|) (
public bci ^<Integer> = (
^bytes size + 1
)
public byte: b <Integer> = (
assert: [0 <= b and: [b <= 255]] message: 'Bytecode out of range'.
bytes add: b
)
public byteAt: index <Integer> ^<Integer> = (
^bytes at: index
)
public byteAt: index <Integer> put: datum <Integer> = (
bytes at: index put: datum
)
cleanup = (
literals:: nil.
bytes:: nil
)
public compiledMethod ^<CompiledMethod> = (
| properties <MethodProperties> offset <Integer> |
method isNil ifFalse: [^method].
assert: [argCount <= maxLocals] message: ''.
method:: instantiateMethodV4.
(1 to: literals size)
with: literals asOrderedCollection
do: [:i :lit | method literalAt: i put: lit].
method selector: selector.
method methodClass: methodMixin.
(pragmas isNil or: [pragmas isEmpty]) ifFalse:
[properties:: AdditionalMethodState forMethod: method selector: selector.
pragmas do: [:p | properties:: properties copyWith: p].
method properties: properties].
offset:: method initialPC - 1.
1 to: bytes size do:
[:i | method basicAt: i + offset put: (bytes at: i)].
setSourceAndCategory.
cleanup.
^method
)
instantiateMethodV4 ^<CompiledMethod> = (
| header cmethod |
header:: EncoderForNewsqueakV4 basicNew
computeMethodHeaderForNumArgs: argCount
numTemps: maxLocals
numLits: literals size + 2
primitive: 0
accessModifier: accessModifier.
cmethod:: CompiledMethodTrailer empty
createMethod: bytes size
class: CompiledMethod
header: header.
cmethod needsFrameSize:
(maxStack min: CompiledMethod fullFrameSize - maxLocals). (*Suppress warning about frame too big, which apparently is not checked in the constructor used by instantiateMethodV3 and is actually exceeded in some Newspeak code.*)
^cmethod
)
public isSubinitializer: b <Boolean> = (
pragmas add: #isSubinitializer -> true
)
public name = (
^selector
)
public printOn: stream = (
stream nextPutAll: 'IntermediateMethod:'; nextPutAll: name.
)
setSourceAndCategory = (
(* This is horrible, but in Squeak access to source is via the compiled method, which stores the information in itself. To make matters worse, the class and category are required. *)
| cat <String> |
assert: [methodMixin isNil not] message: 'Missing methodMixin'.
assert: [category isNil == isSynthetic] message: 'Category should be missing IFF synthetic'.
isSynthetic ifTrue: [^self (* No source to save *)].
assert: [category isNil not] message: 'Missing category'.
method putSource: source fromParseNode: nil class: methodMixin category: category inFile: 2 priorMethod: nil.
)
public simpleName = (
^selector
)
) : (
)
public class IntermediateMixin for: d isMeta: m = (|
public declaration <IntermediateClassDeclaration> = d.
public isMeta <Boolean> = m.
public slots <List[IntermediateSlotDeclaration]> ::= List new.
public methods <List[IntermediateMethod]> = List new.
public nestedClasses <List[IntermediateClassDeclaration]> = List new.
public transientSlots <List[IntermediateTransientSlot]> = List new.
public builder <MixinBuilder>
|) (
public assembleMethods = (
| assembledMethods = List new. |
assembledMethods addAll: methods.
transientSlots do: [:ts | ts addMethodsInto: assembledMethods ].
assembleSlots do: [:slot | slot addSyntheticMethodsTo: assembledMethods].
nestedClasses do: [:nestedClass | assembledMethods add: nestedClass accessor].
isMeta
ifTrue: [assembledMethods add: declaration factory]
ifFalse: [assembledMethods addAll: declaration initializers].
^assembledMethods
)
public assembleSlots = (
| assembledSlots = List new. |
assembledSlots addAll: slots.
transientSlots do: [:ts | ts addSlotsInto: assembledSlots ].
nestedClasses do: [:nestedClass | nestedClass addSyntheticSlotsTo: assembledSlots].
^assembledSlots
)
public checkNameConflictsForFactory: selector <Symbol> = (
assert: [isMeta] message: ''.
methods do:
[:method |
method selector = selector ifTrue:
[^Error signal: 'Class already has method named ', selector]].
)
public checkNameConflictsForMethod: selector <Symbol> = (
nestedClasses do:
[:nestedClass |
nestedClass name = selector ifTrue:
[^Error signal: 'Class already has nested class named ', selector]].
slots do:
[:slot |
slot name = selector ifTrue:
[^Error signal: 'Class already has slot named ', selector].
(slot isMutable and: [(slot name, ':') = selector]) ifTrue:
[^Error signal: 'Class already has mutable slot named ', selector]].
isMeta ifTrue:
[declaration factoryName = selector ifTrue:
[^Error signal: 'Class already has primary factory named ', selector]].
)
public checkNameConflictsForNestedClass: klassName <Symbol> = (
methods do:
[:method |
method isSynthetic ifFalse:
[method selector = klassName ifTrue:
[^Error signal: 'Class already has method named ', klassName]]].
slots do:
[:slot |
slot name = klassName ifTrue:
[^Error signal: 'Class already has slot named ', klassName]].
)
public checkNameConflictsForSlot: slotName <Symbol> mutable: isMutable <Boolean> = (
nestedClasses do:
[:nestedClass |
nestedClass name = slotName ifTrue:
[^Error signal: 'Class already has nested class named ', slotName]].
methods do:
[:method |
method selector = slotName ifTrue:
[^Error signal: 'Class already has method named ', slotName]].
isMutable ifFalse: [^self].
methods do:
[:method |
method selector = (slotName, ':') ifTrue:
[^Error signal: 'Class already has method named ', method selector]].
)
public printOn: stream = (
stream nextPutAll: 'IntermediateMixin:'; nextPutAll: declaration qualifiedName.
isMeta ifTrue: [stream nextPutAll: ' class'].
)
) : (
)
public class IntermediateSlotDeclaration = (|
public name
public isMutable
public accessModifier
|) (
public addSyntheticMethodsTo: methods = (
| index = 1. |
methods add: (generateInitializerForSlot: index).
methods add: (generateGetterForSlot: index).
isMutable ifTrue: [methods add: (generateSetterForSlot: index)].
)
public generateGetterForSlot: n <Integer> ^<IntermediateMethod> = (
| method = IntermediateMethod new. |
method selector: name asSymbol.
method accessModifier: accessModifier.
method method: (CompiledMethod newGetterForSlot: n accessModifier: accessModifier).
method method selector: method selector.
method isSynthetic: true.
^method
)
public generateInitializerForSlot: n <Integer> ^<IntermediateMethod> = (
| method = IntermediateMethod new. |
method selector: initializerName.
method accessModifier: #private.
method method: (CompiledMethod newSetterForSlot: n accessModifier: #private).
method method selector: method selector.
method isSynthetic: true.
^method
)
public generateSetterForSlot: n <Integer> ^<IntermediateMethod> = (
| method = IntermediateMethod new. |
method selector: setterName.
method accessModifier: accessModifier.
method method: (CompiledMethod newSetterForSlot: n accessModifier: accessModifier).
method method selector: method selector.
method isSynthetic: true.
^method
)
initializerName ^<Symbol> = (
^('init`', name, ':') asSymbol
)
public printOn: stream = (
stream nextPutAll: 'IntermediateSlotDeclaration:'; nextPutAll: simpleName.
)
setterName ^<Symbol> = (
(* Yuck! This is a copy of Compiler#setterSelectorFor: *)
^((isMutable ifTrue: [ '' ] ifFalse: [ 'setOnce`' ]), name, ':') asSymbol
)
public simpleName = (
^name
)
) : (
)
public class IntermediateTransientSlot = (
|
public intermediateInitMethod
public intermediateMainMethod
public intermediateSetterMethod
|
) (
public addMethodsInto: aCollection = (
aCollection add: intermediateInitMethod.
aCollection add: intermediateMainMethod.
isMutable ifTrue: [ aCollection add: intermediateSetterMethod ]
)
public addSlotsInto: aCollection = (
aCollection add: intermediateSlotDeclaration.
)
public intermediateSlotDeclaration = (
|slot|
slot:: IntermediateSlotDeclaration new.
slot name: (class slotNameForTransientSlotNamed: name).
slot isMutable: true.
slot accessModifier: #private.
^slot.
)
public isMutable = (
^intermediateSetterMethod isNil not.
)
public name = (
^intermediateMainMethod selector.
)
public simpleName = (
^name
)
public source = (
^intermediateMainMethod source
)
) : (
public initMethodNameForTransientSlotNamed: selector = (
^(selector, '`method') asSymbol
)
public slotNameForTransientSlotNamed: selector = (
^(selector, '`cacheSlot') asSymbol
)
)
) : (
)