Skip to content

Commit 6cfbb5d

Browse files
committed
Add support for initializers in the interpreter
This commit add support for let's and register's initializers. These initializers are executed before the main entry point. This prompted some changes in the interpreter. Since there's no longer a single "entry" function but rather a list of initializers followed by the "entry" function, the interpreter maintains a worklist of functions to execute (in `todo` instvar) and when the bottom-most context returns, it simply executes next function in the worklist. Interpretation finishes once all functions from worklist are executed and return (see `JibInterpreter >> interpretEnd:`). Another little complication comes from the fact that - for some unknown reason - initializers do not have explicit `end` instruction. To deal with this, after each instruction executed the interpreter checks if the PC (of next instruction) is beyond the end of instruction sequence and if it is, executes fabricated `end`. This way, the function return logic is at single place (`JibInterpreter >> interpretEnd:`).
1 parent ebbda5a commit 6cfbb5d

13 files changed

+291
-33
lines changed

Diff for: src/Sail-Jib-Interpreter-Tests/JibDebuggerSessionTests.class.st

+52
Original file line numberDiff line numberDiff line change
@@ -102,4 +102,56 @@ fn zmain(zarg) {
102102

103103

104104

105+
]
106+
107+
{ #category : #tests }
108+
JibDebuggerSessionTests >> test_03 [
109+
| program main interpreter session |
110+
111+
program := JibParser parse:'
112+
113+
let (zxlen_val: %i64) {
114+
zz40 : %i64;
115+
zz40 = 64;
116+
zxlen_val = zz40;
117+
}
118+
119+
register zPC : %bv64 {
120+
zPC = 0xCAFE0000CAFE0000;
121+
}
122+
123+
val zmain : () -> %i64
124+
125+
fn zmain() {
126+
return = zxlen_val;
127+
end;
128+
}
129+
130+
'.
131+
132+
main := program lookupFunction: 'zmain'.
133+
134+
interpreter := JibInterpreter for: main arguments: #().
135+
session := JibDebuggerSession for: interpreter.
136+
137+
"
138+
JibDebugger openOn: session.
139+
"
140+
self assert: interpreter context function isRegister.
141+
session stepInto: interpreter context. "zz40 : %i64;"
142+
session stepInto: interpreter context. "zz40 = 64;"
143+
session stepInto: interpreter context. "zxlen_val = zz40;"
144+
145+
self assert: interpreter context function isLet.
146+
147+
148+
149+
150+
151+
152+
153+
154+
155+
156+
105157
]

Diff for: src/Sail-Jib-Interpreter-Tests/JibInterpreterTests.class.st

+64
Original file line numberDiff line numberDiff line change
@@ -183,4 +183,68 @@ fn zmain(zarg) {
183183

184184

185185

186+
]
187+
188+
{ #category : #tests }
189+
JibInterpreterTests >> test_06l [
190+
| program main interpreter |
191+
program := JibParser parse:'
192+
193+
let (zxlen_val: %i64) {
194+
zz40 : %i64;
195+
zz40 = 64;
196+
zxlen_val = zz40;
197+
}
198+
199+
val zmain : () -> %i64
200+
201+
fn zmain(zarg) {
202+
return = zxlen_val;
203+
end;
204+
}
205+
206+
'.
207+
208+
main := program lookupFunction: 'zmain'.
209+
210+
interpreter := JibInterpreter for: main arguments: { -1 toBitVector: 16 }.
211+
212+
interpreter interpret.
213+
214+
self assert: interpreter retVal = 64.
215+
216+
217+
218+
]
219+
220+
{ #category : #tests }
221+
JibInterpreterTests >> test_06r [
222+
| program main interpreter |
223+
program := JibParser parse:'
224+
225+
register zxlen_val : %i64 {
226+
zz40 : %i64;
227+
zz40 = 64;
228+
zxlen_val = zz40;
229+
}
230+
231+
val zmain : () -> %i64
232+
233+
fn zmain(zarg) {
234+
return = zxlen_val;
235+
end;
236+
}
237+
238+
'.
239+
240+
main := program lookupFunction: 'zmain'.
241+
242+
interpreter := JibInterpreter for: main arguments: { -1 toBitVector: 16 }.
243+
244+
interpreter interpret.
245+
246+
self assert: interpreter retVal = 64.
247+
248+
249+
186250
]

Diff for: src/Sail-Jib-Interpreter/Def_Fn.extension.st

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
Extension { #name : #'Def_Fn' }
2+
3+
{ #category : #'*Sail-Jib-Interpreter' }
4+
Def_Fn >> hasCode [
5+
^ true
6+
]
7+
8+
{ #category : #'*Sail-Jib-Interpreter' }
9+
Def_Fn >> instrAt: pc [
10+
^instrs at: pc
11+
]

Diff for: src/Sail-Jib-Interpreter/Def_Let.extension.st

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
Extension { #name : #'Def_Let' }
2+
3+
{ #category : #'*Sail-Jib-Interpreter' }
4+
Def_Let >> hasCode [
5+
^ self hasInitializer
6+
]
7+
8+
{ #category : #'*Sail-Jib-Interpreter' }
9+
Def_Let >> hasInitializer [
10+
^ instrs notEmpty
11+
]

Diff for: src/Sail-Jib-Interpreter/Def_Register.extension.st

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
Extension { #name : #'Def_Register' }
2+
3+
{ #category : #'*Sail-Jib-Interpreter' }
4+
Def_Register >> hasCode [
5+
^ self hasInitializer
6+
]
7+
8+
{ #category : #'*Sail-Jib-Interpreter' }
9+
Def_Register >> hasInitializer [
10+
^ instrs notEmpty
11+
]

Diff for: src/Sail-Jib-Interpreter/JibDebugger.class.st

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ JibDebugger >> formatInstruction: insn forContext: context [
1616

1717
{ #category : #formatting }
1818
JibDebugger >> formatStackForContext: context [
19-
^context function id
19+
^context function displayString
2020
]
2121

2222
{ #category : #'building presentations' }

Diff for: src/Sail-Jib-Interpreter/JibDef.extension.st

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
Extension { #name : #JibDef }
2+
3+
{ #category : #'*Sail-Jib-Interpreter' }
4+
JibDef >> hasCode [
5+
^ false
6+
]

Diff for: src/Sail-Jib-Interpreter/JibInterpreter.class.st

+67-17
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,11 @@ Class {
44
#instVars : [
55
'program',
66
'context',
7+
'lets',
78
'registers',
8-
'retval'
9+
'entry',
10+
'retval',
11+
'todo'
912
],
1013
#category : #'Sail-Jib-Interpreter-Interpreter'
1114
}
@@ -24,14 +27,23 @@ JibInterpreter >> context [
2427

2528
{ #category : #'accessing - variables' }
2629
JibInterpreter >> get: id [
27-
(registers includesKey: id) ifTrue:[
30+
(lets includesKey: id) ifTrue:[
31+
^ lets at: id
32+
] ifFalse:[(registers includesKey: id) ifTrue:[
2833
^ registers at: id
2934
] ifFalse:[
3035
^ context get: id
31-
]
36+
]]
37+
]
38+
39+
{ #category : #'accessing - globals' }
40+
JibInterpreter >> getGlobal: id [
41+
self assert:(lets includesKey: id).
42+
43+
^ lets at: id
3244
]
3345

34-
{ #category : #'accessing - registers' }
46+
{ #category : #'accessing - globals' }
3547
JibInterpreter >> getRegister: id [
3648
self assert:(registers includesKey: id).
3749

@@ -40,16 +52,33 @@ JibInterpreter >> getRegister: id [
4052

4153
{ #category : #initialization }
4254
JibInterpreter >> initializeWithFunction: fn arguments: args [
55+
entry := fn.
4356
program := fn program.
44-
context := JibInterpreterContext for: fn arguments: args.
4557
registers := OrderedDictionary new.
58+
lets := OrderedDictionary new.
59+
todo := OrderedCollection new.
60+
4661
program registersDo: [ :register |
47-
register instrs notEmpty ifTrue:[
48-
self notYetImplemented
62+
registers at: register id put: register regType newUndefined.
63+
64+
register hasInitializer ifTrue:[
65+
todo add: (JibInterpreterContext for: register arguments: #())
66+
]
67+
].
68+
69+
program letsDo: [ :let |
70+
let variables do: [ :nameAndType |
71+
lets at: nameAndType key put: nameAndType value newUndefined.
4972
].
5073

51-
registers at: register id put: register regType newUndefined
52-
]
74+
let hasInitializer ifTrue:[
75+
todo add: (JibInterpreterContext for: let arguments: #())
76+
]
77+
].
78+
79+
todo add: (JibInterpreterContext for: fn arguments: args).
80+
81+
context := todo removeFirst.
5382

5483

5584
]
@@ -66,8 +95,6 @@ JibInterpreter >> interpret1 [
6695
"Interpret exactly one instruction."
6796
| instr |
6897

69-
self assert: (context pc between: 1 and: context function instrs size).
70-
7198
instr := context function instrs at: context pc.
7299
"Here we advance pc to following instruction. However, the pc
73100
can be changed as part of interpreting that instruction (for
@@ -76,6 +103,17 @@ JibInterpreter >> interpret1 [
76103
instructions. Maybe not a great idea, will see."
77104
context pc: context pc + 1.
78105
instr interpretIn: self.
106+
107+
(context notNil and:[context function isFn not]) ifTrue:[
108+
"For some unknown reason, let and register initializers do not
109+
have an 'end' instruction. So here we check if PC is past the
110+
instruction sequence of current initilalizer and if so, finish
111+
its execution by interpreting fabricated Instr_End (this is
112+
merely a trick to have function return logic at one place)."
113+
(context pc) == (context function instrs size + 1) ifTrue:[
114+
self interpretEnd: Instr_End new.
115+
].
116+
].
79117
]
80118

81119
{ #category : #'interpreting - insns' }
@@ -158,10 +196,13 @@ JibInterpreter >> interpretEnd: insn [
158196
"Drop the current context"
159197
context := caller.
160198

161-
162199
caller isNil ifTrue:[
163-
"We're done, just note the resulting value."
164-
retval := callee getRetVal.
200+
todo isEmpty ifTrue:[
201+
"We're done, just note the resulting value."
202+
retval := callee getRetVal.
203+
] ifFalse:[
204+
context := todo removeFirst.
205+
]
165206
] ifFalse:[
166207
| call |
167208

@@ -226,14 +267,23 @@ JibInterpreter >> retVal [
226267

227268
{ #category : #'accessing - variables' }
228269
JibInterpreter >> set: id to: value [
229-
(registers includesKey: id) ifTrue:[
270+
(lets includesKey: id) ifTrue:[
271+
lets at: id put: value.
272+
] ifFalse:[(registers includesKey: id) ifTrue:[
230273
registers at: id put: value.
231274
] ifFalse:[
232275
context set: id to: value
233-
]
276+
]]
277+
]
278+
279+
{ #category : #'accessing - globals' }
280+
JibInterpreter >> setGlobal: id to: value [
281+
self assert:(lets includesKey: id).
282+
283+
lets at: id put: value
234284
]
235285

236-
{ #category : #'accessing - registers' }
286+
{ #category : #'accessing - globals' }
237287
JibInterpreter >> setRegister: id to: value [
238288
self assert:(registers includesKey: id).
239289

0 commit comments

Comments
 (0)