1// Copyright 2017 Istio Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package il
16
17// Opcode is the type for the opcodes in the il.
18type Opcode uint32
19
20// OpcodeArg represents the type of the arguments that opcodes have.
21type OpcodeArg int
22
23// opcodeInfo holds metadata about an opcode.
24type opcodeInfo struct {
25	// The human-readable name of the opcode.
26	name string
27
28	// The string keyword matching this opcode.
29	keyword string
30
31	// The set of arguments that is expected by this opcode.
32	args []OpcodeArg
33}
34
35const (
36	// Halt stops the VM with an error.
37	Halt Opcode = 0
38
39	// Nop does nothing.
40	Nop Opcode = 1
41
42	// Err raises an error.
43	Err Opcode = 2
44
45	// Errz pops a boolean value from stack and check its value. if the value is false, then it
46	// raises an error.
47	Errz Opcode = 3
48
49	// Errnz pops a boolean value from stack and check its value. if the value is true, then it
50	// raises an error.
51	Errnz Opcode = 4
52
53	// PopS pops a string from the stack.
54	PopS Opcode = 10
55
56	// PopB pops a bool from the stack.
57	PopB Opcode = 11
58
59	// PopI pops an integer from the stack.
60	PopI Opcode = 12
61
62	// PopD pops a double from the stack.
63	PopD Opcode = 13
64
65	// DupS pops a string value from the stack and pushes it back into the stack twice.
66	DupS Opcode = 14
67
68	// DupB pops a boolean value from the stack and pushes it back into the stack twice.
69	DupB Opcode = 15
70
71	// DupI pops an integer value from the stack and pushes it back into the stack twice.
72	DupI Opcode = 16
73
74	// DupD pops a double value from the stack and pushes it back into the stack twice.
75	DupD Opcode = 17
76
77	// RLoadS pops a string from the stack and stores in the target register.
78	RLoadS Opcode = 20
79
80	// RLoadB pops a bool from the stack and stores in the target register.
81	RLoadB Opcode = 21
82
83	// RLoadI pops an integer from the stack and stores in the target register.
84	RLoadI Opcode = 22
85
86	// RLoadD pops a double from the stack and stores in the target register.
87	RLoadD Opcode = 23
88
89	// ALoadS loads its string argument into the target register.
90	ALoadS Opcode = 30
91
92	// ALoadB loads its boolean argument into the target register.
93	ALoadB Opcode = 31
94
95	// ALoadI loads its integer argument into the target register.
96	ALoadI Opcode = 32
97
98	// ALoadD loads its double argument into the target register.
99	ALoadD Opcode = 33
100
101	// APushS pushes its string argument to the stack.
102	APushS Opcode = 40
103
104	// APushB pushes its boolean argument to the stack.
105	APushB Opcode = 41
106
107	// APushI pushes its integer argument to the stack.
108	APushI Opcode = 42
109
110	// APushD pushes its double argument to the stack.
111	APushD Opcode = 43
112
113	// RPushS reads a string value from the target register and pushes it into stack.
114	RPushS Opcode = 50
115
116	// RPushB reads a boolean value from the target register and pushes it into stack.
117	RPushB Opcode = 51
118
119	// RPushI reads an integer value from the target register and pushes it into stack.
120	RPushI Opcode = 52
121
122	// RPushD reads a double value from the target register and pushes it into stack.
123	RPushD Opcode = 53
124
125	// EqS pops two string values from the stack and compare for equality. If the strings are
126	// equal then it pushes 1 into the stack, otherwise it pushes 0.
127	EqS Opcode = 60
128
129	// EqB pops two bool values from the stack and compare for equality. If equal, then it
130	// pushes 1 into the stack, otherwise it pushes 0.
131	EqB Opcode = 61
132
133	// EqI pops two integer values from the stack and compare for equality. If equal, then it
134	// pushes 1 into the stack, otherwise it pushes 0.
135	EqI Opcode = 62
136
137	// EqD pops two double values from the stack and compare for equality. If equal, then it
138	// pushes 1 into the stack, otherwise it pushes 0.
139	EqD Opcode = 63
140
141	// AEqS pops a string value from the stack and compare it against its argument for equality.
142	// If equal, then it pushes 1 into the stack, otherwise it pushes 0.
143	AEqS Opcode = 70
144
145	// AEqB pops a bool value from the stack and compare it against its argument for equality.
146	// If equal, then it pushes 1 into the stack, otherwise it pushes 0.
147	AEqB Opcode = 71
148
149	// AEqI pops an integer value from the stack and compare it against its argument for equality
150	// If equal, then it pushes 1 into the stack, otherwise it pushes 0.
151	AEqI Opcode = 72
152
153	// AEqD pops a double value from the stack and compare it against its argument for equality
154	// If equal, then it pushes 1 into the stack, otherwise it pushes 0.
155	AEqD Opcode = 73
156
157	// Xor pops two boolean values from the stack, performs logical exclusive-or, then pushes the
158	// result back into stack.
159	Xor Opcode = 80
160
161	// And pops two boolean values from the stack, performs logical and, then pushes the
162	// result back into stack.
163	And Opcode = 81
164
165	// Or pops two boolean values from the stack, performs logical or, then pushes the
166	// result back into stack.
167	Or Opcode = 82
168
169	// AXor pops a boolean value from the stack and performs logical exclusive-or with its
170	// argument, then pushes the result back into stack.
171	AXor Opcode = 83
172
173	// AAnd pops a boolean value from the stack and performs logical and with its
174	// argument, then pushes the result back into stack.
175	AAnd Opcode = 84
176
177	// AOr pops a boolean value from the stack and performs logical or with its
178	// argument, then pushes the result back into stack.
179	AOr Opcode = 85
180
181	// Not pops a boolean value from the stack and performs logical not,
182	// then pushes the result back into stack.
183	Not Opcode = 86
184
185	// ResolveS lookups up a string attribute value in the bag, with the given name.
186	// If successful, pushes the resolved string into stack, otherwise raises error.
187	ResolveS Opcode = 90
188
189	// ResolveB lookups up a bool attribute value in the bag, with the given name.
190	// If successful, pushes the resolved bool into stack, otherwise raises error.
191	ResolveB Opcode = 91
192
193	// ResolveI lookups up an integer attribute value in the bag, with the given name.
194	// If successful, pushes the resolved integer into stack, otherwise raises error.
195	ResolveI Opcode = 92
196
197	// ResolveD lookups up a double attribute value in the bag, with the given name.
198	// If successful, pushes the resolved double into stack, otherwise raises error.
199	ResolveD Opcode = 93
200
201	// ResolveF lookups up a interface{} attribute value in the bag, with the given name.
202	// If successful, pushes the resolved interface{} into stack, otherwise raises error.
203	ResolveF Opcode = 94
204
205	// TResolveS lookups up a string attribute value in the bag, with the given name.
206	// If successful, pushes the resolved string value, then 1 into the stack,
207	// otherwise pushes 0.
208	TResolveS Opcode = 100
209
210	// TResolveB lookups up a  bool attribute value in the bag, with the given name.
211	// If successful, pushes the resolved bool value, then 1 into the stack,
212	// otherwise pushes 0.
213	TResolveB Opcode = 101
214
215	// TResolveI lookups up an integer attribute value in the bag, with the given name.
216	// If successful, pushes the resolved integer value, then 1 into the stack,
217	// otherwise pushes 0.
218	TResolveI Opcode = 102
219
220	// TResolveD lookups up a double attribute value in the bag, with the given name.
221	// If successful, pushes the resolved double value, then 1 into the stack,
222	// otherwise pushes 0.
223	TResolveD Opcode = 103
224
225	// TResolveF lookups up a interface{} attribute value in the bag, with the given name.
226	// If successful, pushes the resolved interface{} value, then 1 into the stack,
227	// otherwise pushes 0.
228	TResolveF Opcode = 104
229
230	// AddI pops two integer values from the stack, adds their value and pushes the result
231	// back into stack. The operation follows Go's integer addition semantics.
232	AddI Opcode = 110
233
234	// AddD pops two double values from the stack, adds their value and pushes the result
235	// back into stack. The operation follows Go's float addition semantics.
236	AddD Opcode = 111
237
238	// SubI pops two integer values from the stack, and subtracts the second popped value
239	// from the first one, then pushes the result back into stack.
240	// The operation follows Go's integer subtraction semantics.
241	SubI Opcode = 112
242
243	// SubD pops two double values from the stack, and subtracts the second popped value
244	// from the first one, then pushes the result back into stack.
245	// The operation follows Go's float subtraction semantics.
246	SubD Opcode = 113
247
248	// AAddI pops an integer value from the stack, adds the popped value and its argument,
249	// and pushes the result back into stack. The operation follows Go's integer addition
250	// semantics.
251	AAddI Opcode = 114
252
253	// AAddD pops a double value from the stack, adds the popped value and its argument,
254	// and pushes the result back into stack. The operation follows Go's double addition
255	// semantics.
256	AAddD Opcode = 115
257
258	// ASubI pops an integer value from the stack, subtracts its argument from the popped value,
259	// then pushes the result back into stack.  The operation follows Go's integer subtraction
260	// semantics.
261	ASubI Opcode = 116
262
263	// ASubD pops a double value from the stack, subtracts its argument from the popped value,
264	// then pushes the result back into stack.  The operation follows Go's double subtraction
265	// semantics.
266	ASubD Opcode = 117
267
268	// Jmp jumps to the given instruction address.
269	Jmp Opcode = 200
270
271	// Jz pops a bool value from the stack. If the value is zero, then jumps to the given
272	// instruction address.
273	Jz Opcode = 201
274
275	// Jnz pops a bool value from the stack. If the value is not 0, then jumps to the given
276	// instruction address.
277	Jnz Opcode = 202
278
279	// Call invokes the target function.
280	Call Opcode = 203
281
282	// Ret returns from the current function.
283	Ret Opcode = 204
284
285	// Lookup pops a string, then a stringmap from the stack and perform a lookup on the stringmap
286	// using the string as the name. If a value is found, then the value is pushed into the
287	// stack.  Otherwise raises an error.
288	Lookup Opcode = 210
289
290	// TLookup pops a string, then a stringmap from the stack and perform a lookup on the stringmap
291	// using the string as the name. If a value is found, then the value is pushed into the
292	// stack, then 1.  Otherwise 0 is pushed to into the stack.
293	TLookup Opcode = 211
294
295	// ALookup pops a stringmap from the stack and perform a lookup on the stringmap using the string
296	// parameter as the name. If a value is found, then the value is pushed into the stack
297	// Otherwise raises an error.
298	ALookup Opcode = 212
299
300	// NLookup pops a string, then a stringmap from the stack and perform a lookup on the stringmap
301	// using the string as the name. If a value is found, then the value is pushed into the
302	// stack.  Otherwise empty string is pushed onto the stack.
303	NLookup Opcode = 213
304
305	// ANLookup pops a stringmap from the stack and perform a lookup on the stringmap using the string
306	// parameter as the name. If a value is found, then the value is pushed into the stack
307	// Otherwise empty string is pushed onto the stack.
308	ANLookup Opcode = 214
309
310	// AddS pops two string values from the stack, adds their value and pushes the result
311	// back into stack. The operation follows Go's string concatenation semantics.
312	AddS Opcode = 215
313
314	// SizeS pops a string value from the stack, and pushes its length back into stack.
315	SizeS Opcode = 216
316
317	// LtS pops two string values from the stack and compare for order.
318	// If less then it pushes 1 into the stack, otherwise it pushes 0.
319	LtS Opcode = 217
320
321	// LtI pops two integer values from the stack and compare for order.
322	// If less then it pushes 1 into the stack, otherwise it pushes 0.
323	LtI Opcode = 218
324
325	// LtD pops two float values from the stack and compare for order.
326	// If less then it pushes 1 into the stack, otherwise it pushes 0.
327	LtD Opcode = 219
328
329	// ALtS pops a string value from the stack and compare it against its argument for order.
330	// If the value on the stack is less, then it pushes 1 into the stack, otherwise it pushes 0.
331	ALtS Opcode = 220
332
333	// ALtI pops an integer value from the stack and compare it against its argument for order.
334	// If the value on the stack is less, then it pushes 1 into the stack, otherwise it pushes 0.
335	ALtI Opcode = 221
336
337	// ALtD pops a float value from the stack and compare it against its argument for order.
338	// If the value on the stack is less, then it pushes 1 into the stack, otherwise it pushes 0.
339	ALtD Opcode = 222
340
341	// LeS pops two string values from the stack and compare for order.
342	// If less or equals then it pushes 1 into the stack, otherwise it pushes 0.
343	LeS Opcode = 223
344
345	// LeI pops two integer values from the stack and compare for order.
346	// If less or equals then it pushes 1 into the stack, otherwise it pushes 0.
347	LeI Opcode = 224
348
349	// LeD pops two float values from the stack and compare for order.
350	// If less or equals then it pushes 1 into the stack, otherwise it pushes 0.
351	LeD Opcode = 225
352
353	// ALeS pops a string value from the stack and compare it against its argument for order.
354	// If the value on the stack is less or equal, then it pushes 1 into the stack, otherwise it pushes 0.
355	ALeS Opcode = 226
356
357	// ALeI pops an integer value from the stack and compare it against its argument for order.
358	// If the value on the stack is less or equal, then it pushes 1 into the stack, otherwise it pushes 0.
359	ALeI Opcode = 227
360
361	// ALeD pops a float value from the stack and compare it against its argument for order.
362	// If the value on the stack is less or equal, then it pushes 1 into the stack, otherwise it pushes 0.
363	ALeD Opcode = 228
364
365	// GtS pops two string values from the stack and compare for order.
366	// If greater then it pushes 1 into the stack, otherwise it pushes 0.
367	GtS Opcode = 229
368
369	// GtI pops two integer values from the stack and compare for order.
370	// If greater then it pushes 1 into the stack, otherwise it pushes 0.
371	GtI Opcode = 230
372
373	// GtD pops two float values from the stack and compare for order.
374	// If greater then it pushes 1 into the stack, otherwise it pushes 0.
375	GtD Opcode = 231
376
377	// AGtS pops a string value from the stack and compare it against its argument for order.
378	// If the value on the stack is greater, then it pushes 1 into the stack, otherwise it pushes 0.
379	AGtS Opcode = 232
380
381	// AGtI pops an integer value from the stack and compare it against its argument for order.
382	// If the value on the stack is greater, then it pushes 1 into the stack, otherwise it pushes 0.
383	AGtI Opcode = 233
384
385	// AGtD pops a float value from the stack and compare it against its argument for order.
386	// If the value on the stack is greater, then it pushes 1 into the stack, otherwise it pushes 0.
387	AGtD Opcode = 234
388
389	// GeS pops two string values from the stack and compare for order.
390	// If greater or equal then it pushes 1 into the stack, otherwise it pushes 0.
391	GeS Opcode = 235
392
393	// GeI pops two integer values from the stack and compare for order.
394	// If greater or equal then it pushes 1 into the stack, otherwise it pushes 0.
395	GeI Opcode = 236
396
397	// GeD pops two float values from the stack and compare for order.
398	// If greater or equal then it pushes 1 into the stack, otherwise it pushes 0.
399	GeD Opcode = 237
400
401	// AGeS pops a string value from the stack and compare it against its argument for order.
402	// If the value on the stack is greater or equal, then it pushes 1 into the stack, otherwise it pushes 0.
403	AGeS Opcode = 238
404
405	// AGeI pops an integer value from the stack and compare it against its argument for equality.
406	// If greater or equal, then it pushes 1 into the stack, otherwise it pushes 0.
407	AGeI Opcode = 239
408
409	// AGeD pops a float value from the stack and compare it against its argument for equality.
410	// If greater or equal, then it pushes 1 into the stack, otherwise it pushes 0.
411	AGeD Opcode = 240
412)
413
414const (
415	// OpcodeArgRegister represents an argument that references a register.
416	OpcodeArgRegister OpcodeArg = 0
417
418	// OpcodeArgString represents an argument that is a string.
419	OpcodeArgString OpcodeArg = 1
420
421	// OpcodeArgInt represents an argument that is an integer.
422	OpcodeArgInt OpcodeArg = 2
423
424	// OpcodeArgDouble represents an argument that is a double.
425	OpcodeArgDouble OpcodeArg = 3
426
427	// OpcodeArgBool represents an argument that is a boolean.
428	OpcodeArgBool OpcodeArg = 4
429
430	// OpcodeArgFunction represents an argument that is a function.
431	OpcodeArgFunction OpcodeArg = 5
432
433	// OpcodeArgAddress represents an argument that is an address.
434	OpcodeArgAddress OpcodeArg = 6
435)
436
437var argSizes = map[OpcodeArg]uint32{
438	OpcodeArgRegister: 1,
439	OpcodeArgString:   1,
440	OpcodeArgBool:     1,
441	OpcodeArgFunction: 1,
442	OpcodeArgAddress:  1,
443	OpcodeArgDouble:   2,
444	OpcodeArgInt:      2,
445}
446
447var opCodeInfos = map[Opcode]opcodeInfo{
448
449	// Halt stops the VM with an error.
450	Halt: {name: "Halt", keyword: "halt"},
451
452	// Nop does nothing.
453	Nop: {name: "Nop", keyword: "nop"},
454
455	// Err raises an error.
456	Err: {name: "Err", keyword: "err", args: []OpcodeArg{
457		// Text of the error.
458		OpcodeArgString,
459	}},
460
461	// Errz pops a boolean value from stack and check its value. if the value is false, then it
462	// raises an error.
463	Errz: {name: "Errz", keyword: "errz", args: []OpcodeArg{
464		// Text of the error message.
465		OpcodeArgString,
466	}},
467
468	// Errnz pops a boolean value from stack and check its value. if the value is true, then it
469	// raises an error.
470	Errnz: {name: "Errnz", keyword: "errnz", args: []OpcodeArg{
471		// Text of the error message.
472		OpcodeArgString,
473	}},
474
475	// PopS pops a string from the stack.
476	PopS: {name: "PopS", keyword: "pop_s"},
477
478	// PopB pops a bool from the stack.
479	PopB: {name: "PopB", keyword: "pop_b"},
480
481	// PopI pops an integer from the stack.
482	PopI: {name: "PopI", keyword: "pop_i"},
483
484	// PopD pops a double from the stack.
485	PopD: {name: "PopD", keyword: "pop_d"},
486
487	// DupS pops a string value from the stack and pushes it back into the stack twice.
488	DupS: {name: "DupS", keyword: "dup_s"},
489
490	// DupB pops a boolean value from the stack and pushes it back into the stack twice.
491	DupB: {name: "DupB", keyword: "dup_b"},
492
493	// DupI pops an integer value from the stack and pushes it back into the stack twice.
494	DupI: {name: "DupI", keyword: "dup_i"},
495
496	// DupD pops a double value from the stack and pushes it back into the stack twice.
497	DupD: {name: "DupD", keyword: "dup_d"},
498
499	// RLoadS pops a string from the stack and stores in the target register.
500	RLoadS: {name: "RLoadS", keyword: "rload_s", args: []OpcodeArg{
501		// The target register.
502		OpcodeArgRegister,
503	}},
504
505	// RLoadB pops a bool from the stack and stores in the target register.
506	RLoadB: {name: "RLoadB", keyword: "rload_b", args: []OpcodeArg{
507		// The target register.
508		OpcodeArgRegister,
509	}},
510
511	// RLoadI pops an integer from the stack and stores in the target register.
512	RLoadI: {name: "RLoadI", keyword: "rload_i", args: []OpcodeArg{
513		// The target register.
514		OpcodeArgRegister,
515	}},
516
517	// RLoadD pops a double from the stack and stores in the target register.
518	RLoadD: {name: "RLoadD", keyword: "rload_d", args: []OpcodeArg{
519		// The target register.
520		OpcodeArgRegister,
521	}},
522
523	// ALoadS loads its string argument into the target register.
524	ALoadS: {name: "ALoadS", keyword: "aload_s", args: []OpcodeArg{
525		// The target register.
526		OpcodeArgRegister,
527		// The string to load.
528		OpcodeArgString,
529	}},
530
531	// ALoadB loads its boolean argument into the target register.
532	ALoadB: {name: "ALoadB", keyword: "aload_b", args: []OpcodeArg{
533		// The target register.
534		OpcodeArgRegister,
535		// The bool to load.
536		OpcodeArgBool,
537	}},
538
539	// ALoadI loads its integer argument into the target register.
540	ALoadI: {name: "ALoadI", keyword: "aload_i", args: []OpcodeArg{
541		// The target register.
542		OpcodeArgRegister,
543		// The integer to load.
544		OpcodeArgInt,
545	}},
546
547	// ALoadD loads its double argument into the target register.
548	ALoadD: {name: "ALoadD", keyword: "aload_d", args: []OpcodeArg{
549		// The target register.
550		OpcodeArgRegister,
551		// The double to load.
552		OpcodeArgDouble,
553	}},
554
555	// APushS pushes its string argument to the stack.
556	APushS: {name: "APushS", keyword: "apush_s", args: []OpcodeArg{
557		// The string to push.
558		OpcodeArgString,
559	}},
560
561	// APushB pushes its boolean argument to the stack.
562	APushB: {name: "APushB", keyword: "apush_b", args: []OpcodeArg{
563		// The boolean to push.
564		OpcodeArgBool,
565	}},
566
567	// APushI pushes its integer argument to the stack.
568	APushI: {name: "APushI", keyword: "apush_i", args: []OpcodeArg{
569		// The integer to push.
570		OpcodeArgInt,
571	}},
572
573	// APushD pushes its double argument to the stack.
574	APushD: {name: "APushD", keyword: "apush_d", args: []OpcodeArg{
575		// The double to push.
576		OpcodeArgDouble,
577	}},
578
579	// RPushS reads a string value from the target register and pushes it into stack.
580	RPushS: {name: "RPushS", keyword: "rpush_s", args: []OpcodeArg{
581		// The target register.
582		OpcodeArgRegister,
583	}},
584
585	// RPushB reads a boolean value from the target register and pushes it into stack.
586	RPushB: {name: "RPushB", keyword: "rpush_b", args: []OpcodeArg{
587		// The target register.
588		OpcodeArgRegister,
589	}},
590
591	// RPushI reads an integer value from the target register and pushes it into stack.
592	RPushI: {name: "RPushI", keyword: "rpush_i", args: []OpcodeArg{
593		// The target register.
594		OpcodeArgRegister,
595	}},
596
597	// RPushD reads a double value from the target register and pushes it into stack.
598	RPushD: {name: "RPushD", keyword: "rpush_d", args: []OpcodeArg{
599		// The target register.
600		OpcodeArgRegister,
601	}},
602
603	// EqS pops two string values from the stack and compare for equality. If the strings are
604	// equal then it pushes 1 into the stack, otherwise it pushes 0.
605	EqS: {name: "EqS", keyword: "eq_s"},
606
607	// EqB pops two bool values from the stack and compare for equality. If the bools are
608	// equal then it pushes 1 into the stack, otherwise it pushes 0.
609	EqB: {name: "EqB", keyword: "eq_b"},
610
611	// EqI pops two integer values from the stack and compare for equality. If the integers are
612	// equal then it pushes 1 into the stack, otherwise it pushes 0.
613	EqI: {name: "EqI", keyword: "eq_i"},
614
615	// EqD pops two double values from the stack and compare for equality. If the doubles are
616	// equal then it pushes 1 into the stack, otherwise it pushes 0.
617	EqD: {name: "EqD", keyword: "eq_d"},
618
619	// AEqS pops a string value from the stack and compare it against its argument for equality.
620	// If equal, then it pushes 1 into the stack, otherwise it pushes 0.
621	AEqS: {name: "AEqS", keyword: "aeq_s", args: []OpcodeArg{
622		// The string value for comparison.
623		OpcodeArgString,
624	}},
625
626	// AEqB pops a bool value from the stack and compare it against its argument for equality.
627	// If equal, then it pushes 1 into the stack, otherwise it pushes 0.
628	AEqB: {name: "AEqB", keyword: "aeq_b", args: []OpcodeArg{
629		// The bool value for comparison.
630		OpcodeArgBool,
631	}},
632
633	// AEqI pops an integer value from the stack and compare it against its argument for equality.
634	// If equal, then it pushes 1 into the stack, otherwise it pushes 0.
635	AEqI: {name: "AEqI", keyword: "aeq_i", args: []OpcodeArg{
636		// The integer value for comparison.
637		OpcodeArgInt,
638	}},
639
640	// AEqD pops a double value from the stack and compare it against its argument for equality.
641	// If equal, then it pushes 1 into the stack, otherwise it pushes 0.
642	AEqD: {name: "AEqD", keyword: "aeq_d", args: []OpcodeArg{
643		// The double value for comparison.
644		OpcodeArgDouble,
645	}},
646
647	// Xor pops two boolean values from the stack, performs logical exclusive-or, then pushes the
648	// result back into stack.
649	Xor: {name: "Xor", keyword: "xor"},
650
651	// And pops two boolean values from the stack, performs logical and, then pushes the
652	// result back into stack.
653	And: {name: "And", keyword: "and"},
654
655	// Or pops two boolean values from the stack, performs logical or, then pushes the
656	// result back into stack.
657	Or: {name: "Or", keyword: "or"},
658
659	// AXor pops a boolean value from the stack and performs logical exclusive-or with its
660	// argument, then pushes the result back into stack.
661	AXor: {name: "AXor", keyword: "axor", args: []OpcodeArg{
662		// The boolean value to xor.
663		OpcodeArgBool,
664	}},
665
666	// AAnd pops a boolean value from the stack and performs logical and with its
667	// argument, then pushes the result back into stack.
668	AAnd: {name: "AAnd", keyword: "aand", args: []OpcodeArg{
669		// The boolean value to and.
670		OpcodeArgBool,
671	}},
672
673	// AOr pops a boolean value from the stack and performs logical or with its
674	// argument, then pushes the result back into stack.
675	AOr: {name: "AOr", keyword: "aor", args: []OpcodeArg{
676		// The boolean value to or.
677		OpcodeArgBool,
678	}},
679
680	// Not pops a boolean value from the stack and performs logical not,
681	// then pushes the result back into stack.
682	Not: {name: "Not", keyword: "not"},
683
684	// ResolveS lookups up a string attribute value in the bag, with the given name.
685	// If successful, pushes the resolved string into stack, otherwise raises error.
686	ResolveS: {name: "ResolveS", keyword: "resolve_s", args: []OpcodeArg{
687		// The name of the attribute.
688		OpcodeArgString,
689	}},
690
691	// ResolveB lookups up a bool attribute value in the bag, with the given name.
692	// If successful, pushes the resolved bool into stack, otherwise raises error.
693	ResolveB: {name: "ResolveB", keyword: "resolve_b", args: []OpcodeArg{
694		// The name of the attribute.
695		OpcodeArgString,
696	}},
697
698	// ResolveI lookups up an integer attribute value in the bag, with the given name.
699	// If successful, pushes the resolved integer into stack, otherwise raises error.
700	ResolveI: {name: "ResolveI", keyword: "resolve_i", args: []OpcodeArg{
701		// The name of the attribute.
702		OpcodeArgString,
703	}},
704
705	// ResolveD lookups up a double attribute value in the bag, with the given name.
706	// If successful, pushes the resolved double into stack, otherwise raises error.
707	ResolveD: {name: "ResolveD", keyword: "resolve_d", args: []OpcodeArg{
708		// The name of the attribute.
709		OpcodeArgString,
710	}},
711
712	// ResolveF lookups up an interface attribute value in the bag, with the given name.
713	// If successful, pushes the resolved interface{} into stack, otherwise raises error.
714	ResolveF: {name: "ResolveF", keyword: "resolve_f", args: []OpcodeArg{
715		// The name of the attribute.
716		OpcodeArgString,
717	}},
718
719	// TResolveS lookups up a string attribute value in the bag, with the given name.
720	// If successful, pushes the resolved string value, then 1 into the stack,
721	// otherwise pushes 0.
722	TResolveS: {name: "TResolveS", keyword: "tresolve_s", args: []OpcodeArg{
723		// The name of the attribute.
724		OpcodeArgString,
725	}},
726
727	// TResolveB lookups up a  ool attribute value in the bag, with the given name.
728	// If successful, pushes the resolved bool value, then 1 into the stack,
729	// otherwise pushes 0.
730	TResolveB: {name: "TResolveB", keyword: "tresolve_b", args: []OpcodeArg{
731		// The name of the attribute.
732		OpcodeArgString,
733	}},
734
735	// TResolveI lookups up an integer attribute value in the bag, with the given name.
736	// If successful, pushes the resolved integer value, then 1 into the stack,
737	// otherwise pushes 0.
738	TResolveI: {name: "TResolveI", keyword: "tresolve_i", args: []OpcodeArg{
739		// The name of the attribute.
740		OpcodeArgString,
741	}},
742
743	// TResolveD lookups up a double attribute value in the bag, with the given name.
744	// If successful, pushes the resolved double value, then 1 into the stack,
745	// otherwise pushes 0.
746	TResolveD: {name: "TResolveD", keyword: "tresolve_d", args: []OpcodeArg{
747		// The name of the attribute.
748		OpcodeArgString,
749	}},
750
751	// TResolveF lookups up a interface{} attribute value in the bag, with the given name.
752	// If successful, pushes the resolved interface{] value, then 1 into the stack,
753	// otherwise pushes 0.
754	TResolveF: {name: "TResolveF", keyword: "tresolve_f", args: []OpcodeArg{
755		// The name of the attribute.
756		OpcodeArgString,
757	}},
758
759	// AddI pops two integer values from the stack, adds their value and pushes the result
760	// back into stack. The operation follows Go's integer addition semantics.
761	AddI: {name: "AddI", keyword: "add_i"},
762
763	// AddD pops two double values from the stack, adds their value and pushes the result
764	// back into stack. The operation follows Go's float addition semantics.
765	AddD: {name: "AddD", keyword: "add_d"},
766
767	// AddS pops two string values from the stack, adds their value and pushes the result
768	// back into stack. The operation follows Go's string concatenation semantics.
769	AddS: {name: "AddS", keyword: "add_s"},
770
771	// SubI pops two integer values from the stack, and subtracts the second popped value
772	// from the first one, then pushes the result back into stack.
773	// The operation follows Go's integer subtraction semantics.
774	SubI: {name: "SubI", keyword: "sub_i"},
775
776	// SubD pops two double values from the stack, and subtracts the second popped value
777	// from the first one, then pushes the result back into stack.
778	// The operation follows Go's float subtraction semantics.
779	SubD: {name: "SubD", keyword: "sub_d"},
780
781	// AAddI pops an integer value from the stack, adds the popped value and its argument,
782	// and pushes the result back into stack. The operation follows Go's integer addition
783	// semantics.
784	AAddI: {name: "AAddI", keyword: "aadd_i", args: []OpcodeArg{
785		// Value to add
786		OpcodeArgInt,
787	}},
788
789	// AAddD pops a double value from the stack, adds the popped value and its argument,
790	// and pushes the result back into stack. The operation follows Go's double addition
791	// semantics.
792	AAddD: {name: "AAddD", keyword: "aadd_d", args: []OpcodeArg{
793		// Value to add
794		OpcodeArgDouble,
795	}},
796
797	// ASubI pops an integer value from the stack, subtracts its argument from the popped value,
798	// then pushes the result back into stack.  The operation follows Go's integer subtraction
799	// semantics.
800	ASubI: {name: "ASubI", keyword: "asub_i", args: []OpcodeArg{
801		// Value to subtract
802		OpcodeArgInt,
803	}},
804
805	// ASubD pops a double value from the stack, subtracts its argument from the popped value,
806	// then pushes the result back into stack.  The operation follows Go's double subtraction
807	// semantics.
808	ASubD: {name: "ASubD", keyword: "asub_d", args: []OpcodeArg{
809		// Value to subtract
810		OpcodeArgDouble,
811	}},
812
813	// Jmp jumps to the given instruction address.
814	Jmp: {name: "Jmp", keyword: "jmp", args: []OpcodeArg{
815		// The address to jump to.
816		OpcodeArgAddress,
817	}},
818
819	// Jz pops a bool value from the stack. If the value is 0, then jumps to the given
820	// instruction address.
821	Jz: {name: "Jz", keyword: "jz", args: []OpcodeArg{
822		// The address to jump to.
823		OpcodeArgAddress,
824	}},
825
826	// Jnz pops a bool value from the stack. If the value is not 0, then jumps to the given
827	// instruction address.
828	Jnz: {name: "Jnz", keyword: "jnz", args: []OpcodeArg{
829		// The address to jump to.
830		OpcodeArgAddress,
831	}},
832
833	// Call invokes the target function.
834	Call: {name: "Call", keyword: "call", args: []OpcodeArg{
835		// The name of the target function.
836		OpcodeArgFunction,
837	}},
838
839	// Ret returns from the current function.
840	Ret: {name: "Ret", keyword: "ret"},
841
842	// Lookup pops a string, then a stringmap from the stack and perform a lookup on the stringmap
843	// using the string as the name. If a value is found, then the value is pushed into the
844	// stack.  Otherwise raises an error.
845	Lookup: {name: "Lookup", keyword: "lookup"},
846
847	// NLookup pops a string, then a stringmap from the stack and perform a lookup on the stringmap
848	// using the string as the name. If a value is found, then the value is pushed into the
849	// stack.  Otherwise empty string is pushed ono the stack.
850	NLookup: {name: "NLookup", keyword: "nlookup"},
851
852	// TLookup pops a string, then a stringmap from the stack and perform a lookup on the stringmap
853	// using the string as the name. If a value is found, then the value is pushed into the
854	// stack, then 1.  Otherwise 0 is pushed to into the stack.
855	TLookup: {name: "TLookup", keyword: "tlookup"},
856
857	// ALookup pops a stringmap from the stack and perform a lookup on the stringmap using the string
858	// parameter as the name. If a value is found, then the value is pushed into the stack
859	// Otherwise raises an error.
860	ALookup: {name: "ALookup", keyword: "alookup", args: []OpcodeArg{
861		// The name of the attribute.
862		OpcodeArgString,
863	}},
864
865	// ANLookup pops a stringmap from the stack and perform a lookup on the stringmap using the string
866	// parameter as the name. If a value is found, then the value is pushed into the stack
867	// Otherwise empty string is pushed onto the stack.
868	ANLookup: {name: "ANLookup", keyword: "anlookup", args: []OpcodeArg{
869		// The name of the attribute.
870		OpcodeArgString,
871	}},
872
873	// SizeS pops a string and pushes it length.
874	SizeS: {name: "SizeS", keyword: "size_s"},
875
876	// LtS pops two string values from the stack and compare for order.
877	// If less then it pushes 1 into the stack, otherwise it pushes 0.
878	LtS: {name: "LtS", keyword: "lt_s"},
879
880	// LtI pops two integer values from the stack and compare for order.
881	// If less then it pushes 1 into the stack, otherwise it pushes 0.
882	LtI: {name: "LtI", keyword: "lt_i"},
883
884	// LtD pops two float values from the stack and compare for order.
885	// If less then it pushes 1 into the stack, otherwise it pushes 0.
886	LtD: {name: "LtD", keyword: "lt_d"},
887
888	// ALtS pops a string value from the stack and compare it against its argument for order.
889	// If the value on the stack is less, then it pushes 1 into the stack, otherwise it pushes 0.
890	ALtS: {name: "ALtS", keyword: "alt_s", args: []OpcodeArg{
891		// The string value for comparison.
892		OpcodeArgString,
893	}},
894
895	// ALtI pops an integer value from the stack and compare it against its argument for order.
896	// If the value on the stack is less, then it pushes 1 into the stack, otherwise it pushes 0.
897	ALtI: {name: "ALtI", keyword: "alt_i", args: []OpcodeArg{
898		// The integer value for comparison.
899		OpcodeArgInt,
900	}},
901
902	// ALtD pops a float value from the stack and compare it against its argument for order.
903	// If the value on the stack is less, then it pushes 1 into the stack, otherwise it pushes 0.
904	ALtD: {name: "ALtD", keyword: "alt_d", args: []OpcodeArg{
905		// The integer value for comparison.
906		OpcodeArgDouble,
907	}},
908
909	// LeS pops two string values from the stack and compare for order.
910	// If less or equals then it pushes 1 into the stack, otherwise it pushes 0.
911	LeS: {name: "LeS", keyword: "le_s"},
912
913	// LeI pops two integer values from the stack and compare for order.
914	// If less or equals then it pushes 1 into the stack, otherwise it pushes 0.
915	LeI: {name: "LeI", keyword: "le_i"},
916
917	// LeD pops two float values from the stack and compare for order.
918	// If less or equals then it pushes 1 into the stack, otherwise it pushes 0.
919	LeD: {name: "LeD", keyword: "le_d"},
920
921	// ALeS pops a string value from the stack and compare it against its argument for order.
922	// If the value on the stack is less or equal, then it pushes 1 into the stack, otherwise it pushes 0.
923	ALeS: {name: "ALeS", keyword: "ale_s", args: []OpcodeArg{
924		// The string value for comparison.
925		OpcodeArgString,
926	}},
927
928	// ALeI pops an integer value from the stack and compare it against its argument for order.
929	// If the value on the stack is less or equal, then it pushes 1 into the stack, otherwise it pushes 0.
930	ALeI: {name: "ALeI", keyword: "ale_i", args: []OpcodeArg{
931		// The integer value for comparison.
932		OpcodeArgInt,
933	}},
934
935	// ALeD pops a float value from the stack and compare it against its argument for order.
936	// If the value on the stack is less or equal, then it pushes 1 into the stack, otherwise it pushes 0.
937	ALeD: {name: "ALeD", keyword: "ale_d", args: []OpcodeArg{
938		// The integer value for comparison.
939		OpcodeArgDouble,
940	}},
941
942	// GtS pops two string values from the stack and compare for order.
943	// If greater then it pushes 1 into the stack, otherwise it pushes 0.
944	GtS: {name: "GtS", keyword: "gt_s"},
945
946	// GtI pops two integer values from the stack and compare for order.
947	// If greater then it pushes 1 into the stack, otherwise it pushes 0.
948	GtI: {name: "GtI", keyword: "gt_i"},
949
950	// GtD pops two float values from the stack and compare for order.
951	// If greater then it pushes 1 into the stack, otherwise it pushes 0.
952	GtD: {name: "GtD", keyword: "gt_d"},
953
954	// AGtS pops a string value from the stack and compare it against its argument for order.
955	// If the value on the stack is greater, then it pushes 1 into the stack, otherwise it pushes 0.
956	AGtS: {name: "AGtS", keyword: "agt_s", args: []OpcodeArg{
957		// The string value for comparison.
958		OpcodeArgString,
959	}},
960
961	// AGtI pops an integer value from the stack and compare it against its argument for order.
962	// If the value on the stack is greater, then it pushes 1 into the stack, otherwise it pushes 0.
963	AGtI: {name: "AGtI", keyword: "agt_i", args: []OpcodeArg{
964		// The integer value for comparison.
965		OpcodeArgInt,
966	}},
967
968	// AGtD pops a float value from the stack and compare it against its argument for order.
969	// If the value on the stack is greater, then it pushes 1 into the stack, otherwise it pushes 0.
970	AGtD: {name: "AGtD", keyword: "agt_d", args: []OpcodeArg{
971		// The integer value for comparison.
972		OpcodeArgDouble,
973	}},
974
975	// GeS pops two string values from the stack and compare for order.
976	// If greater or equal then it pushes 1 into the stack, otherwise it pushes 0.
977	GeS: {name: "GeS", keyword: "ge_s"},
978
979	// GeI pops two integer values from the stack and compare for order.
980	// If greater or equal then it pushes 1 into the stack, otherwise it pushes 0.
981	GeI: {name: "GeI", keyword: "ge_i"},
982
983	// GeD pops two float values from the stack and compare for order.
984	// If greater or equal then it pushes 1 into the stack, otherwise it pushes 0.
985	GeD: {name: "GeD", keyword: "ge_d"},
986
987	// AGeS pops a string value from the stack and compare it against its argument for order.
988	// If the value on the stack is greater or equal, then it pushes 1 into the stack, otherwise it pushes 0.
989	AGeS: {name: "AGeS", keyword: "age_s", args: []OpcodeArg{
990		// The string value for comparison.
991		OpcodeArgString,
992	}},
993
994	// AGeI pops an integer value from the stack and compare it against its argument for equality.
995	// If greater or equal, then it pushes 1 into the stack, otherwise it pushes 0.
996	AGeI: {name: "AGeI", keyword: "age_i", args: []OpcodeArg{
997		// The integer value for comparison.
998		OpcodeArgInt,
999	}},
1000
1001	// AGeD pops a float value from the stack and compare it against its argument for equality.
1002	// If greater or equal, then it pushes 1 into the stack, otherwise it pushes 0.
1003	AGeD: {name: "AGeD", keyword: "age_d", args: []OpcodeArg{
1004		// The integer value for comparison.
1005		OpcodeArgDouble,
1006	}},
1007}
1008
1009var opcodesByKeyword = func() map[string]Opcode {
1010	r := make(map[string]Opcode)
1011	for o, i := range opCodeInfos {
1012		r[i.keyword] = o
1013	}
1014	return r
1015}()
1016
1017// GetOpcode finds and returns the opcode that matches the keyword text that is supplied.
1018func GetOpcode(text string) (Opcode, bool) {
1019	o, f := opcodesByKeyword[text]
1020	return o, f
1021}
1022
1023func (o Opcode) String() string {
1024	return opCodeInfos[o].name
1025}
1026
1027// Size returns the total size the instruction and its arguments occupy, in uint32s.
1028func (o Opcode) Size() uint32 {
1029	var s uint32 = 1
1030	for _, a := range opCodeInfos[o].args {
1031		s += a.Size()
1032	}
1033	return s
1034}
1035
1036// Keyword returns the keyword corresponding to the opcode.
1037func (o Opcode) Keyword() string {
1038	return opCodeInfos[o].keyword
1039}
1040
1041// Args return the metadata about the arguments to the opcode.
1042func (o Opcode) Args() []OpcodeArg {
1043	return opCodeInfos[o].args
1044}
1045
1046// Size returns the number of uint32 byte codes that the argument occupies.
1047func (o OpcodeArg) Size() uint32 {
1048	return argSizes[o]
1049}
1050