1 /*
2  * Copyright (C) 2024 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.net.apf;
18 
19 import static android.net.apf.BaseApfGenerator.Rbit.Rbit0;
20 import static android.net.apf.BaseApfGenerator.Register.R0;
21 import static android.net.apf.BaseApfGenerator.Register.R1;
22 
23 
24 import android.annotation.NonNull;
25 
26 import com.android.internal.annotations.VisibleForTesting;
27 
28 import java.util.List;
29 import java.util.Set;
30 
31 /**
32  * APF assembler/generator.  A tool for generating an APF program.
33  *
34  * Call add*() functions to add instructions to the program, then call
35  * {@link BaseApfGenerator#generate} to get the APF bytecode for the program.
36  * <p>
37  * Choose between these approaches for your instruction helper methods: If the functionality must
38  * be identical across APF versions, make it a final method within the base class. If it needs
39  * version-specific adjustments, use an abstract method in the base class with final
40  * implementations in generator instances.
41  *
42  * @param <Type> the generator class
43  *
44  * @hide
45  */
46 public abstract class ApfV4GeneratorBase<Type extends ApfV4GeneratorBase<Type>> extends
47         BaseApfGenerator {
48 
49     /**
50      * Creates an ApfV4GeneratorBase instance which is able to emit instructions for the specified
51      * {@code version} of the APF interpreter. Throws {@code IllegalInstructionException} if
52      * the requested version is unsupported.
53      */
54     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
ApfV4GeneratorBase(int version, boolean disableCounterRangeCheck)55     public ApfV4GeneratorBase(int version, boolean disableCounterRangeCheck)
56             throws IllegalInstructionException {
57         super(version, disableCounterRangeCheck);
58         requireApfVersion(APF_VERSION_2);
59     }
60 
self()61     final Type self() {
62         return (Type) this;
63     }
64 
append(Instruction instruction)65     final Type append(Instruction instruction) {
66         if (mGenerated) {
67             throw new IllegalStateException("Program already generated");
68         }
69         mInstructions.add(instruction);
70         return self();
71     }
72 
73     /**
74      * Define a label at the current end of the program. Jumps can jump to this label. Labels are
75      * their own separate instructions, though with size 0. This facilitates having labels with
76      * no corresponding code to execute, for example a label at the end of a program. For example
77      * an {@link ApfV4GeneratorBase} might be passed to a function that adds a filter like so:
78      * <pre>
79      *   load from packet
80      *   compare loaded data, jump if not equal to "next_filter"
81      *   load from packet
82      *   compare loaded data, jump if not equal to "next_filter"
83      *   jump to drop label
84      *   define "next_filter" here
85      * </pre>
86      * In this case "next_filter" may not have any generated code associated with it.
87      */
defineLabel(String name)88     public final Type defineLabel(String name) throws IllegalInstructionException {
89         return append(new Instruction(Opcodes.LABEL).setLabel(name));
90     }
91 
92     /**
93      * Add an unconditional jump instruction to the end of the program.
94      */
addJump(String target)95     public final Type addJump(String target) {
96         return append(new Instruction(Opcodes.JMP).setTargetLabel(target));
97     }
98 
99     /**
100      * Add an unconditional jump instruction to the next instruction - ie. a no-op.
101      */
addNop()102     public final Type addNop() {
103         return append(new Instruction(Opcodes.JMP).addUnsigned(0));
104     }
105 
106     /**
107      * Add an instruction to the end of the program to load the byte at offset {@code offset}
108      * bytes from the beginning of the packet into {@code register}.
109      */
addLoad8(Register r, int ofs)110     public final Type addLoad8(Register r, int ofs) {
111         return append(new Instruction(Opcodes.LDB, r).addPacketOffset(ofs));
112     }
113 
114     /**
115      * Add an instruction to the end of the program to load 16-bits at offset {@code offset}
116      * bytes from the beginning of the packet into {@code register}.
117      */
addLoad16(Register r, int ofs)118     public final Type addLoad16(Register r, int ofs) {
119         return append(new Instruction(Opcodes.LDH, r).addPacketOffset(ofs));
120     }
121 
122     /**
123      * Add an instruction to the end of the program to load 32-bits at offset {@code offset}
124      * bytes from the beginning of the packet into {@code register}.
125      */
addLoad32(Register r, int ofs)126     public final Type addLoad32(Register r, int ofs) {
127         return append(new Instruction(Opcodes.LDW, r).addPacketOffset(ofs));
128     }
129 
130     /**
131      * Add an instruction to the end of the program to load a byte from the packet into
132      * {@code register}. The offset of the loaded byte from the beginning of the packet is
133      * the sum of {@code offset} and the value in register R1.
134      */
addLoad8Indexed(Register r, int ofs)135     public final Type addLoad8Indexed(Register r, int ofs) {
136         return append(new Instruction(Opcodes.LDBX, r).addTwosCompUnsigned(ofs));
137     }
138 
139     /**
140      * Add an instruction to the end of the program to load 16-bits from the packet into
141      * {@code register}. The offset of the loaded 16-bits from the beginning of the packet is
142      * the sum of {@code offset} and the value in register R1.
143      */
addLoad16Indexed(Register r, int ofs)144     public final Type addLoad16Indexed(Register r, int ofs) {
145         return append(new Instruction(Opcodes.LDHX, r).addTwosCompUnsigned(ofs));
146     }
147 
148     /**
149      * Add an instruction to the end of the program to load 32-bits from the packet into
150      * {@code register}. The offset of the loaded 32-bits from the beginning of the packet is
151      * the sum of {@code offset} and the value in register R1.
152      */
addLoad32Indexed(Register r, int ofs)153     public final Type addLoad32Indexed(Register r, int ofs) {
154         return append(new Instruction(Opcodes.LDWX, r).addTwosCompUnsigned(ofs));
155     }
156 
157     /**
158      * Add an instruction to the end of the program to add {@code value} to register R0.
159      */
addAdd(long val)160     public final Type addAdd(long val) {
161         if (val == 0) return self();  // nop, as APFv6 would '+= R1'
162         return append(new Instruction(Opcodes.ADD).addTwosCompUnsigned(val));
163     }
164 
165     /**
166      * Add an instruction to the end of the program to subtract {@code value} from register R0.
167      */
addSub(long val)168     public final Type addSub(long val) {
169         return addAdd(-val);  // note: addSub(4 billion) isn't valid, as addAdd(-4 billion) isn't
170     }
171 
172     /**
173      * Add an instruction to the end of the program to multiply register R0 by {@code value}.
174      */
addMul(long val)175     public final Type addMul(long val) {
176         if (val == 0) return addLoadImmediate(R0, 0);  // equivalent, as APFv6 would '*= R1'
177         return append(new Instruction(Opcodes.MUL).addUnsigned(val));
178     }
179 
180     /**
181      * Add an instruction to the end of the program to divide register R0 by {@code value}.
182      */
addDiv(long val)183     public final Type addDiv(long val) {
184         if (val == 0) return addPass();  // equivalent, as APFv6 would '/= R1'
185         return append(new Instruction(Opcodes.DIV).addUnsigned(val));
186     }
187 
188     /**
189      * Add an instruction to the end of the program to logically and register R0 with {@code value}.
190      */
addAnd(long val)191     public final Type addAnd(long val) {
192         if (val == 0) return addLoadImmediate(R0, 0);  // equivalent, as APFv6 would '+= R1'
193         return append(new Instruction(Opcodes.AND).addTwosCompUnsigned(val));
194     }
195 
196     /**
197      * Add an instruction to the end of the program to logically or register R0 with {@code value}.
198      */
addOr(long val)199     public final Type addOr(long val) {
200         if (val == 0) return self();  // nop, as APFv6 would '|= R1'
201         return append(new Instruction(Opcodes.OR).addTwosCompUnsigned(val));
202     }
203 
204     /**
205      * Add an instruction to the end of the program to shift left register R0 by {@code value} bits.
206      */
207     // TODO: consider whether should change the argument type to byte
addLeftShift(int val)208     public final Type addLeftShift(int val) {
209         if (val == 0) return self();  // nop, as APFv6 would '<<= R1'
210         return append(new Instruction(Opcodes.SH).addSigned(val));
211     }
212 
213     /**
214      * Add an instruction to the end of the program to shift right register R0 by {@code value}
215      * bits.
216      */
217     // TODO: consider whether should change the argument type to byte
addRightShift(int val)218     public final Type addRightShift(int val) {
219         return addLeftShift(-val);
220     }
221 
222     // R0 op= R1, where op should be one of Opcodes.{ADD,MUL,DIV,AND,OR,SH}
addR0ArithR1(Opcodes opcode)223     abstract void addR0ArithR1(Opcodes opcode);
224 
225     /**
226      * Add an instruction to the end of the program to add register R1 to register R0.
227      */
addAddR1ToR0()228     public final Type addAddR1ToR0() {
229         addR0ArithR1(Opcodes.ADD);  // R0 += R1
230         return self();
231     }
232 
233     /**
234      * Add an instruction to the end of the program to multiply register R0 by register R1.
235      */
addMulR0ByR1()236     public final Type addMulR0ByR1() {
237         addR0ArithR1(Opcodes.MUL);  // R0 *= R1
238         return self();
239     }
240 
241     /**
242      * Add an instruction to the end of the program to divide register R0 by register R1.
243      */
addDivR0ByR1()244     public final Type addDivR0ByR1() {
245         addR0ArithR1(Opcodes.DIV);  // R0 /= R1
246         return self();
247     }
248 
249     /**
250      * Add an instruction to the end of the program to logically and register R0 with register R1
251      * and store the result back into register R0.
252      */
addAndR0WithR1()253     public final Type addAndR0WithR1() {
254         addR0ArithR1(Opcodes.AND);  // R0 &= R1
255         return self();
256     }
257 
258     /**
259      * Add an instruction to the end of the program to logically or register R0 with register R1
260      * and store the result back into register R0.
261      */
addOrR0WithR1()262     public final Type addOrR0WithR1() {
263         addR0ArithR1(Opcodes.OR);  // R0 |= R1
264         return self();
265     }
266 
267     /**
268      * Add an instruction to the end of the program to shift register R0 left by the value in
269      * register R1.
270      */
addLeftShiftR0ByR1()271     public final Type addLeftShiftR0ByR1() {
272         addR0ArithR1(Opcodes.SH);  // R0 <<= R1
273         return self();
274     }
275 
276     /**
277      * Add an instruction to the end of the program to move {@code value} into {@code register}.
278      */
addLoadImmediate(Register register, int value)279     public final Type addLoadImmediate(Register register, int value) {
280         return append(new Instruction(Opcodes.LI, register).addSigned(value));
281     }
282 
283     /**
284      * Add an instruction to the end of the program to jump to {@code target} if register R0's
285      * value equals {@code value}.
286      */
addJumpIfR0Equals(long val, String tgt)287     public final Type addJumpIfR0Equals(long val, String tgt) {
288         return append(new Instruction(Opcodes.JEQ).addTwosCompUnsigned(val).setTargetLabel(tgt));
289     }
290 
291     /**
292      * Add instructions to the end of the program to increase counter and drop packet if R0 equals
293      * {@code val}
294      * WARNING: may modify R1
295      */
addCountAndDropIfR0Equals(long val, ApfCounterTracker.Counter cnt)296     public abstract Type addCountAndDropIfR0Equals(long val, ApfCounterTracker.Counter cnt)
297             throws IllegalInstructionException;
298 
299     /**
300      * Add instructions to the end of the program to increase counter and pass packet if R0 equals
301      * {@code val}
302      * WARNING: may modify R1
303      */
addCountAndPassIfR0Equals(long val, ApfCounterTracker.Counter cnt)304     public abstract Type addCountAndPassIfR0Equals(long val, ApfCounterTracker.Counter cnt)
305             throws IllegalInstructionException;
306 
307     /**
308      * Add an instruction to the end of the program to jump to {@code target} if register R0's
309      * value does not equal {@code value}.
310      */
addJumpIfR0NotEquals(long val, String tgt)311     public final Type addJumpIfR0NotEquals(long val, String tgt) {
312         return append(new Instruction(Opcodes.JNE).addTwosCompUnsigned(val).setTargetLabel(tgt));
313     }
314 
315     /**
316      * Add instructions to the end of the program to increase counter and drop packet if R0 not
317      * equals {@code val}
318      * WARNING: may modify R1
319      */
addCountAndDropIfR0NotEquals(long val, ApfCounterTracker.Counter cnt)320     public abstract Type addCountAndDropIfR0NotEquals(long val, ApfCounterTracker.Counter cnt)
321             throws IllegalInstructionException;
322 
323     /**
324      * Add instructions to the end of the program to increase counter and pass packet if R0 not
325      * equals {@code val}
326      * WARNING: may modify R1
327      */
addCountAndPassIfR0NotEquals(long val, ApfCounterTracker.Counter cnt)328     public abstract Type addCountAndPassIfR0NotEquals(long val, ApfCounterTracker.Counter cnt)
329             throws IllegalInstructionException;
330 
331     /**
332      * Add an instruction to the end of the program to jump to {@code target} if register R0's
333      * value is greater than {@code value}.
334      */
addJumpIfR0GreaterThan(long val, String tgt)335     public final Type addJumpIfR0GreaterThan(long val, String tgt) {
336         return append(new Instruction(Opcodes.JGT).addUnsigned(val).setTargetLabel(tgt));
337     }
338 
339     /**
340      * Add instructions to the end of the program to increase counter and drop packet if R0 greater
341      * than {@code val}
342      * WARNING: may modify R1
343      */
addCountAndDropIfR0GreaterThan(long val, ApfCounterTracker.Counter cnt)344     public abstract Type addCountAndDropIfR0GreaterThan(long val, ApfCounterTracker.Counter cnt)
345             throws IllegalInstructionException;
346 
347     /**
348      * Add instructions to the end of the program to increase counter and pass packet if R0 greater
349      * than {@code val}
350      * WARNING: may modify R1
351      */
addCountAndPassIfR0GreaterThan(long val, ApfCounterTracker.Counter cnt)352     public abstract Type addCountAndPassIfR0GreaterThan(long val, ApfCounterTracker.Counter cnt)
353             throws IllegalInstructionException;
354 
355     /**
356      * Add an instruction to the end of the program to jump to {@code target} if register R0's
357      * value is less than {@code value}.
358      */
addJumpIfR0LessThan(long val, String tgt)359     public final Type addJumpIfR0LessThan(long val, String tgt) {
360         return append(new Instruction(Opcodes.JLT).addUnsigned(val).setTargetLabel(tgt));
361     }
362 
363     /**
364      * Add instructions to the end of the program to increase counter and drop packet if R0 less
365      * than {@code val}
366      * WARNING: may modify R1
367      */
addCountAndDropIfR0LessThan(long val, ApfCounterTracker.Counter cnt)368     public abstract Type addCountAndDropIfR0LessThan(long val, ApfCounterTracker.Counter cnt)
369             throws IllegalInstructionException;
370 
371     /**
372      * Add instructions to the end of the program to increase counter and pass packet if R0 less
373      * than {@code val}
374      * WARNING: may modify R1
375      */
addCountAndPassIfR0LessThan(long val, ApfCounterTracker.Counter cnt)376     public abstract Type addCountAndPassIfR0LessThan(long val, ApfCounterTracker.Counter cnt)
377             throws IllegalInstructionException;
378 
379     /**
380      * Add an instruction to the end of the program to jump to {@code target} if register R0's
381      * value has any bits set that are also set in {@code value}.
382      */
addJumpIfR0AnyBitsSet(long val, String tgt)383     public final Type addJumpIfR0AnyBitsSet(long val, String tgt) {
384         return append(new Instruction(Opcodes.JSET).addTwosCompUnsigned(val).setTargetLabel(tgt));
385     }
386 
387     /**
388      * Add an instruction to the end of the program to count and drop packet if register R0's
389      * value has any bits set that are also set in {@code value}.
390      * WARNING: may modify R1
391      */
addCountAndDropIfR0AnyBitsSet(long val, ApfCounterTracker.Counter cnt)392     public abstract Type addCountAndDropIfR0AnyBitsSet(long val, ApfCounterTracker.Counter cnt)
393             throws IllegalInstructionException;
394 
395     /**
396      * Add an instruction to the end of the program to count and pass packet if register R0's
397      * value has any bits set that are also set in {@code value}.
398      * WARNING: may modify R1
399      */
addCountAndPassIfR0AnyBitsSet(long val, ApfCounterTracker.Counter cnt)400     public abstract Type addCountAndPassIfR0AnyBitsSet(long val, ApfCounterTracker.Counter cnt)
401             throws IllegalInstructionException;
402 
403     /**
404      * Add an instruction to the end of the program to count and drop if the bytes of the
405      * packet at an offset specified by register R0 match any of the elements in {@code bytesList}.
406      * WARNING: may modify R1
407      */
addCountAndDropIfBytesAtR0EqualsAnyOf(@onNull List<byte[]> bytesList, ApfCounterTracker.Counter cnt)408     public abstract Type addCountAndDropIfBytesAtR0EqualsAnyOf(@NonNull List<byte[]> bytesList,
409             ApfCounterTracker.Counter cnt) throws IllegalInstructionException;
410 
411     /**
412      * Add an instruction to the end of the program to count and pass if the bytes of the
413      * packet at an offset specified by register R0 match any of the elements in {@code bytesList}.
414      * WARNING: may modify R1
415      */
addCountAndPassIfBytesAtR0EqualsAnyOf(@onNull List<byte[]> bytesList, ApfCounterTracker.Counter cnt)416     public abstract Type addCountAndPassIfBytesAtR0EqualsAnyOf(@NonNull List<byte[]> bytesList,
417             ApfCounterTracker.Counter cnt) throws IllegalInstructionException;
418 
419     /**
420      * Add an instruction to the end of the program to count and drop if the bytes of the
421      * packet at an offset specified by register R0 match none the elements in {@code bytesList}.
422      * WARNING: may modify R1
423      */
addCountAndDropIfBytesAtR0EqualsNoneOf(@onNull List<byte[]> bytesList, ApfCounterTracker.Counter cnt)424     public abstract Type addCountAndDropIfBytesAtR0EqualsNoneOf(@NonNull List<byte[]> bytesList,
425             ApfCounterTracker.Counter cnt) throws IllegalInstructionException;
426 
427     /**
428      * Add an instruction to the end of the program to count and pass if the bytes of the
429      * packet at an offset specified by register R0 match none of the elements in {@code bytesList}.
430      * WARNING: may modify R1
431      */
addCountAndPassIfBytesAtR0EqualsNoneOf(@onNull List<byte[]> bytesList, ApfCounterTracker.Counter cnt)432     public abstract Type addCountAndPassIfBytesAtR0EqualsNoneOf(@NonNull List<byte[]> bytesList,
433             ApfCounterTracker.Counter cnt) throws IllegalInstructionException;
434 
435     /**
436      * Add an instruction to the end of the program to jump to {@code target} if register R0's
437      * value equals register R1's value.
438      */
addJumpIfR0EqualsR1(String tgt)439     public final Type addJumpIfR0EqualsR1(String tgt) {
440         return append(new Instruction(Opcodes.JEQ, R1).setTargetLabel(tgt));
441     }
442 
443     /**
444      * Add an instruction to the end of the program to jump to {@code target} if register R0's
445      * value does not equal register R1's value.
446      */
addJumpIfR0NotEqualsR1(String tgt)447     public final Type addJumpIfR0NotEqualsR1(String tgt) {
448         return append(new Instruction(Opcodes.JNE, R1).setTargetLabel(tgt));
449     }
450 
451     /**
452      * Add an instruction to the end of the program to jump to {@code target} if register R0's
453      * value is greater than register R1's value.
454      */
addJumpIfR0GreaterThanR1(String tgt)455     public final Type addJumpIfR0GreaterThanR1(String tgt) {
456         return append(new Instruction(Opcodes.JGT, R1).setTargetLabel(tgt));
457     }
458 
459     /**
460      * Add an instruction to the end of the program to jump to {@code target} if register R0's
461      * value is less than register R1's value.
462      */
addJumpIfR0LessThanR1(String target)463     public final Type addJumpIfR0LessThanR1(String target) {
464         return append(new Instruction(Opcodes.JLT, R1).setTargetLabel(target));
465     }
466 
467     /**
468      * Add an instruction to the end of the program to jump to {@code target} if register R0's
469      * value has any bits set that are also set in R1's value.
470      */
addJumpIfR0AnyBitsSetR1(String tgt)471     public final Type addJumpIfR0AnyBitsSetR1(String tgt) {
472         return append(new Instruction(Opcodes.JSET, R1).setTargetLabel(tgt));
473     }
474 
475     /**
476      * Add an instruction to the end of the program to jump to {@code tgt} if the bytes of the
477      * packet at an offset specified by register0 don't match {@code bytes}.
478      * R=0 means check for not equal.
479      */
addJumpIfBytesAtR0NotEqual(@onNull byte[] bytes, String tgt)480     public final Type addJumpIfBytesAtR0NotEqual(@NonNull byte[] bytes, String tgt) {
481         validateBytes(bytes);
482         return append(new Instruction(Opcodes.JBSMATCH).addUnsigned(
483                 bytes.length).setTargetLabel(tgt).setBytesImm(bytes));
484     }
485 
486     /**
487      * Add instructions to the end of the program to increase counter and drop packet if the
488      * bytes of the packet at an offset specified by register0 don't match {@code bytes}.
489      * WARNING: may modify R1
490      */
addCountAndDropIfBytesAtR0NotEqual(byte[] bytes, ApfCounterTracker.Counter cnt)491     public abstract Type addCountAndDropIfBytesAtR0NotEqual(byte[] bytes,
492             ApfCounterTracker.Counter cnt) throws IllegalInstructionException;
493 
494     /**
495      * Add instructions to the end of the program to increase counter and pass packet if the
496      * bytes of the packet at an offset specified by register0 don't match {@code bytes}.
497      * WARNING: may modify R1
498      */
addCountAndPassIfBytesAtR0NotEqual(byte[] bytes, ApfCounterTracker.Counter cnt)499     public abstract Type addCountAndPassIfBytesAtR0NotEqual(byte[] bytes,
500             ApfCounterTracker.Counter cnt) throws IllegalInstructionException;
501 
502     /**
503      * Add instructions to the end of the program to increase counter and drop packet if the
504      * bytes of the packet at an offset specified by register0 match {@code bytes}.
505      * WARNING: may modify R1
506      */
addCountAndDropIfBytesAtR0Equal(byte[] bytes, ApfCounterTracker.Counter cnt)507     public abstract Type addCountAndDropIfBytesAtR0Equal(byte[] bytes,
508             ApfCounterTracker.Counter cnt) throws IllegalInstructionException;
509 
510     /**
511      * Add instructions to the end of the program to increase counter and pass packet if the
512      * bytes of the packet at an offset specified by register0 match {@code bytes}.
513      * WARNING: may modify R1
514      */
addCountAndPassIfBytesAtR0Equal(byte[] bytes, ApfCounterTracker.Counter cnt)515     public abstract Type addCountAndPassIfBytesAtR0Equal(byte[] bytes,
516             ApfCounterTracker.Counter cnt) throws IllegalInstructionException;
517 
518     /**
519      * Add instructions to the end of the program to increase counter and pass packet if the
520      * value in register0 is one of {@code values}.
521      * WARNING: may modify R1
522      */
addCountAndPassIfR0IsOneOf(@onNull Set<Long> values, ApfCounterTracker.Counter cnt)523     public abstract Type addCountAndPassIfR0IsOneOf(@NonNull Set<Long> values,
524             ApfCounterTracker.Counter cnt) throws IllegalInstructionException;
525 
526     /**
527      * Add instructions to the end of the program to increase counter and drop packet if the
528      * value in register0 is one of {@code values}.
529      * WARNING: may modify R1
530      */
addCountAndDropIfR0IsOneOf(@onNull Set<Long> values, ApfCounterTracker.Counter cnt)531     public abstract Type addCountAndDropIfR0IsOneOf(@NonNull Set<Long> values,
532             ApfCounterTracker.Counter cnt) throws IllegalInstructionException;
533 
534     /**
535      * Add instructions to the end of the program to increase counter and pass packet if the
536      * value in register0 is none of {@code values}.
537      * WARNING: may modify R1
538      */
addCountAndPassIfR0IsNoneOf(@onNull Set<Long> values, ApfCounterTracker.Counter cnt)539     public abstract Type addCountAndPassIfR0IsNoneOf(@NonNull Set<Long> values,
540             ApfCounterTracker.Counter cnt) throws IllegalInstructionException;
541 
542     /**
543      * Add instructions to the end of the program to increase counter and drop packet if the
544      * value in register0 is none of {@code values}.
545      * WARNING: may modify R1
546      */
addCountAndDropIfR0IsNoneOf(@onNull Set<Long> values, ApfCounterTracker.Counter cnt)547     public abstract Type addCountAndDropIfR0IsNoneOf(@NonNull Set<Long> values,
548             ApfCounterTracker.Counter cnt) throws IllegalInstructionException;
549 
550     /**
551      * Add an instruction to the end of the program to load memory slot {@code slot} into
552      * {@code register}.
553      */
addLoadFromMemory(Register r, MemorySlot slot)554     public final Type addLoadFromMemory(Register r, MemorySlot slot)
555             throws IllegalInstructionException {
556         return append(new BaseApfGenerator.Instruction(ExtendedOpcodes.LDM, slot.value, r));
557     }
558 
559     /**
560      * Add an instruction to the end of the program to store {@code register} into memory slot
561      * {@code slot}.
562      */
addStoreToMemory(MemorySlot slot, Register r)563     public final Type addStoreToMemory(MemorySlot slot, Register r)
564             throws IllegalInstructionException {
565         return append(new Instruction(ExtendedOpcodes.STM, slot.value, r));
566     }
567 
568     /**
569      * Add an instruction to the end of the program to logically not {@code register}.
570      */
addNot(Register r)571     public final Type addNot(Register r) {
572         return append(new Instruction(ExtendedOpcodes.NOT, r));
573     }
574 
575     /**
576      * Add an instruction to the end of the program to negate {@code register}.
577      */
addNeg(Register r)578     public final Type addNeg(Register r) {
579         return append(new Instruction(ExtendedOpcodes.NEG, r));
580     }
581 
582     /**
583      * Add an instruction to swap the values in register R0 and register R1.
584      */
addSwap()585     public final Type addSwap() {
586         return append(new Instruction(ExtendedOpcodes.SWAP));
587     }
588 
589     /**
590      * Add an instruction to the end of the program to move the value into
591      * {@code register} from the other register.
592      */
addMove(Register r)593     public final Type addMove(Register r) {
594         return append(new Instruction(ExtendedOpcodes.MOVE, r));
595     }
596 
597     /**
598      * Add an instruction to the end of the program to let the program immediately return PASS.
599      */
addPass()600     public final Type addPass() {
601         // PASS requires using Rbit0 because it shares opcode with DROP
602         return append(new Instruction(Opcodes.PASSDROP, Rbit0));
603     }
604 
605     /**
606      * Abstract method for adding instructions to increment the counter and return PASS.
607      */
addCountAndPass(ApfCounterTracker.Counter counter)608     public abstract Type addCountAndPass(ApfCounterTracker.Counter counter);
609 
610     /**
611      * Abstract method for adding instructions to increment the counter and return DROP.
612      */
addCountAndDrop(ApfCounterTracker.Counter counter)613     public abstract Type addCountAndDrop(ApfCounterTracker.Counter counter);
614 
615     /**
616      * Add an instruction to the end of the program to load 32 bits from the data memory into
617      * {@code register}.
618      * In APFv2, it is a noop.
619      * WARNING: clobbers the *other* register.
620      */
addLoadCounter(Register register, ApfCounterTracker.Counter counter)621     public abstract Type addLoadCounter(Register register, ApfCounterTracker.Counter counter)
622             throws IllegalInstructionException;
623 
624     /**
625      * Add an instruction to the end of the program to store 32 bits from {@code register} into the
626      * data memory.
627      * In APFv2, it is a noop.
628      * WARNING: clobbers the *other* register.
629      */
addStoreCounter(ApfCounterTracker.Counter counter, Register register)630     public abstract Type addStoreCounter(ApfCounterTracker.Counter counter, Register register)
631             throws IllegalInstructionException;
632 
633     /**
634      * Add an instruction to the end of the program to increment counter value by {@code val).
635      * In APFv2, it is a noop.
636      * WARNING: clobbers both registers.
637      */
addIncrementCounter(ApfCounterTracker.Counter counter, int val)638     public final Type addIncrementCounter(ApfCounterTracker.Counter counter, int val)
639             throws IllegalInstructionException {
640         if (mVersion <= 2) return self();
641         return addLoadCounter(R0, counter).addAdd(val).addStoreCounter(counter, R0);
642     }
643 
644     /**
645      * Add an instruction to the end of the program to increment counter value by one.
646      * In APFv2, it is a noop.
647      * WARNING: clobbers both registers.
648      */
addIncrementCounter(ApfCounterTracker.Counter counter)649     public final Type addIncrementCounter(ApfCounterTracker.Counter counter)
650             throws IllegalInstructionException {
651         return addIncrementCounter(counter, 1);
652     }
653 
654     /**
655      * The abstract method to generate count trampoline instructions.
656      * @return
657      * @throws IllegalInstructionException
658      */
addCountTrampoline()659     public abstract Type addCountTrampoline() throws IllegalInstructionException;
660 }
661 
662