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