-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbytecode.go
More file actions
349 lines (315 loc) · 8.56 KB
/
bytecode.go
File metadata and controls
349 lines (315 loc) · 8.56 KB
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
package runevm
import "fmt"
// OpCode represents a bytecode instruction
type OpCode byte
const (
// Stack operations
OP_CONSTANT OpCode = iota // Push constant onto stack
OP_POP // Pop value from stack
OP_DUP // Duplicate top stack value
// Variable operations
OP_GET_GLOBAL // Get global variable
OP_SET_GLOBAL // Set global variable
OP_GET_LOCAL // Get local variable
OP_SET_LOCAL // Set local variable
OP_DEF_GLOBAL // Define global variable
// Arithmetic operations
OP_ADD
OP_SUB
OP_MUL
OP_DIV
OP_MOD
OP_NEG // Unary negation
// Typed arithmetic operations (fast path)
OP_ADD_INT // Integer addition
OP_SUB_INT // Integer subtraction
OP_MUL_INT // Integer multiplication
OP_DIV_INT // Integer division
OP_MOD_INT // Integer modulo
OP_ADD_FLOAT // Float addition
OP_SUB_FLOAT // Float subtraction
OP_MUL_FLOAT // Float multiplication
OP_DIV_FLOAT // Float division
OP_ADD_INT_FLOAT // Int + Float
OP_SUB_INT_FLOAT // Int - Float
OP_MUL_INT_FLOAT // Int * Float
OP_DIV_INT_FLOAT // Int / Float
OP_ADD_FLOAT_INT // Float + Int
OP_SUB_FLOAT_INT // Float - Int
OP_MUL_FLOAT_INT // Float * Int
OP_DIV_FLOAT_INT // Float / Int
// Typed comparison operations (fast path)
OP_EQ_INT // Integer equality
OP_LT_INT // Integer less than
OP_LE_INT // Integer less than or equal
OP_GT_INT // Integer greater than
OP_GE_INT // Integer greater than or equal
OP_EQ_FLOAT // Float equality
OP_LT_FLOAT // Float less than
OP_LE_FLOAT // Float less than or equal
OP_GT_FLOAT // Float greater than
OP_GE_FLOAT // Float greater than or equal
// Comparison operations
OP_EQ // Equal
OP_NE // Not equal
OP_LT // Less than
OP_LE // Less than or equal
OP_GT // Greater than
OP_GE // Greater than or equal
// Logical operations
OP_NOT
OP_AND
OP_OR
// Control flow
OP_JUMP // Unconditional jump
OP_JUMP_FALSE // Jump if false
OP_JUMP_TRUE // Jump if true
OP_LOOP // Jump backwards (for loops)
// Function operations
OP_CALL // Call function
OP_RETURN // Return from function
OP_CLOSURE // Create closure
OP_GET_UPVAL // Get upvalue (closure variable)
OP_SET_UPVAL // Set upvalue
// Collection operations
OP_ARRAY // Create array
OP_TABLE // Create table
OP_INDEX // Index access
OP_INDEX_SET // Index assignment
// Optimized compound operations
OP_CONST_0 // Push constant 0 (very common)
OP_CONST_1 // Push constant 1 (very common)
OP_CONST_2 // Push constant 2 (common)
OP_ADD_CONST // Add a small constant directly (no stack push)
OP_SUB_CONST // Subtract a small constant directly
// Compound stack operations for performance
OP_CONST_CONST // Push two constants at once
OP_LOCAL_CONST // Push local var + constant
OP_CONST_LOCAL // Push constant + local var
OP_LOCAL_LOCAL // Push two local vars
OP_DUP2 // Duplicate top two values
OP_SWAP // Swap top two values
// Fast conditional jumps (combine compare + jump)
OP_JUMP_LE_CONST // Jump if top <= constant
OP_JUMP_GT_CONST // Jump if top > constant
// Special operations
OP_PRINT // Built-in print
OP_PRINTLN // Built-in println
OP_IMPORT // Import statement
OP_BREAK // Break statement
OP_CONTINUE // Continue statement
OP_HALT // End of program
)
// Instruction represents a single bytecode instruction
type Instruction struct {
Op OpCode
Operand int // For instructions that need an operand
Operand2 int // For instructions that need two operands
Line int // Line number for debugging
File string // File name for debugging
}
// Chunk represents a sequence of bytecode instructions
type Chunk struct {
Instructions []Instruction
Constants []interface{} // Constant pool
}
// NewChunk creates a new empty chunk
func NewChunk() *Chunk {
return &Chunk{
Instructions: make([]Instruction, 0),
Constants: make([]interface{}, 0),
}
}
// AddInstruction adds an instruction to the chunk
func (c *Chunk) AddInstruction(op OpCode, line int, file string) int {
c.Instructions = append(c.Instructions, Instruction{
Op: op,
Line: line,
File: file,
})
return len(c.Instructions) - 1
}
// AddInstructionWithOperand adds an instruction with one operand
func (c *Chunk) AddInstructionWithOperand(op OpCode, operand, line int, file string) int {
c.Instructions = append(c.Instructions, Instruction{
Op: op,
Operand: operand,
Line: line,
File: file,
})
return len(c.Instructions) - 1
}
// AddInstructionWithTwoOperands adds an instruction with two operands
func (c *Chunk) AddInstructionWithTwoOperands(op OpCode, operand1, operand2, line int, file string) int {
c.Instructions = append(c.Instructions, Instruction{
Op: op,
Operand: operand1,
Operand2: operand2,
Line: line,
File: file,
})
return len(c.Instructions) - 1
}
// AddConstant adds a constant to the constant pool and returns its index
func (c *Chunk) AddConstant(value interface{}) int {
c.Constants = append(c.Constants, value)
return len(c.Constants) - 1
}
// PatchJump patches a jump instruction with the correct target
func (c *Chunk) PatchJump(instructionIndex, target int) {
c.Instructions[instructionIndex].Operand = target
}
// GetInstruction returns the instruction at the given index
func (c *Chunk) GetInstruction(index int) *Instruction {
if index >= 0 && index < len(c.Instructions) {
return &c.Instructions[index]
}
return nil
}
// String methods for debugging
func (op OpCode) String() string {
switch op {
case OP_CONSTANT:
return "OP_CONSTANT"
case OP_POP:
return "OP_POP"
case OP_DUP:
return "OP_DUP"
case OP_GET_GLOBAL:
return "OP_GET_GLOBAL"
case OP_SET_GLOBAL:
return "OP_SET_GLOBAL"
case OP_GET_LOCAL:
return "OP_GET_LOCAL"
case OP_SET_LOCAL:
return "OP_SET_LOCAL"
case OP_DEF_GLOBAL:
return "OP_DEF_GLOBAL"
case OP_ADD:
return "OP_ADD"
case OP_SUB:
return "OP_SUB"
case OP_MUL:
return "OP_MUL"
case OP_DIV:
return "OP_DIV"
case OP_MOD:
return "OP_MOD"
case OP_NEG:
return "OP_NEG"
case OP_EQ:
return "OP_EQ"
case OP_NE:
return "OP_NE"
case OP_LT:
return "OP_LT"
case OP_LE:
return "OP_LE"
case OP_GT:
return "OP_GT"
case OP_GE:
return "OP_GE"
case OP_NOT:
return "OP_NOT"
case OP_AND:
return "OP_AND"
case OP_OR:
return "OP_OR"
case OP_JUMP:
return "OP_JUMP"
case OP_JUMP_FALSE:
return "OP_JUMP_FALSE"
case OP_JUMP_TRUE:
return "OP_JUMP_TRUE"
case OP_LOOP:
return "OP_LOOP"
case OP_CALL:
return "OP_CALL"
case OP_RETURN:
return "OP_RETURN"
case OP_CLOSURE:
return "OP_CLOSURE"
case OP_GET_UPVAL:
return "OP_GET_UPVAL"
case OP_SET_UPVAL:
return "OP_SET_UPVAL"
case OP_ARRAY:
return "OP_ARRAY"
case OP_TABLE:
return "OP_TABLE"
case OP_INDEX:
return "OP_INDEX"
case OP_INDEX_SET:
return "OP_INDEX_SET"
case OP_CONST_0:
return "OP_CONST_0"
case OP_CONST_1:
return "OP_CONST_1"
case OP_CONST_2:
return "OP_CONST_2"
case OP_ADD_CONST:
return "OP_ADD_CONST"
case OP_SUB_CONST:
return "OP_SUB_CONST"
case OP_CONST_CONST:
return "OP_CONST_CONST"
case OP_LOCAL_CONST:
return "OP_LOCAL_CONST"
case OP_CONST_LOCAL:
return "OP_CONST_LOCAL"
case OP_LOCAL_LOCAL:
return "OP_LOCAL_LOCAL"
case OP_DUP2:
return "OP_DUP2"
case OP_SWAP:
return "OP_SWAP"
case OP_JUMP_LE_CONST:
return "OP_JUMP_LE_CONST"
case OP_JUMP_GT_CONST:
return "OP_JUMP_GT_CONST"
case OP_PRINT:
return "OP_PRINT"
case OP_PRINTLN:
return "OP_PRINTLN"
case OP_IMPORT:
return "OP_IMPORT"
case OP_BREAK:
return "OP_BREAK"
case OP_CONTINUE:
return "OP_CONTINUE"
case OP_HALT:
return "OP_HALT"
default:
return fmt.Sprintf("UNKNOWN_OP(%d)", op)
}
}
// DisassembleChunk prints the bytecode in a human-readable format for debugging
func DisassembleChunk(chunk *Chunk, name string) {
fmt.Printf("== %s ==\n", name)
for i, instr := range chunk.Instructions {
fmt.Printf("%04d ", i)
DisassembleInstruction(&instr, i, chunk)
}
}
// DisassembleInstruction prints a single instruction
func DisassembleInstruction(instr *Instruction, offset int, chunk *Chunk) {
fmt.Printf("%-16s", instr.Op.String())
switch instr.Op {
case OP_CONSTANT:
if instr.Operand < len(chunk.Constants) {
fmt.Printf(" %4d '%v'", instr.Operand, chunk.Constants[instr.Operand])
}
case OP_GET_GLOBAL, OP_SET_GLOBAL, OP_DEF_GLOBAL, OP_GET_LOCAL, OP_SET_LOCAL:
fmt.Printf(" %4d", instr.Operand)
case OP_JUMP, OP_JUMP_FALSE, OP_JUMP_TRUE, OP_LOOP:
fmt.Printf(" %4d -> %d", offset, instr.Operand)
case OP_CALL:
fmt.Printf(" (args: %d)", instr.Operand)
case OP_ARRAY, OP_TABLE:
fmt.Printf(" (size: %d)", instr.Operand)
}
if instr.File != "" {
fmt.Printf(" [%s:%d]", instr.File, instr.Line)
}
fmt.Println()
}