Ensure opcode imm is always written first

Ensure actual opcode imm is always written before target label offset
imm for extended opcodes.

* design doc: go/apf-v6-proposal

Bug: 293811969
Test: TH
Change-Id: If6708a18fc06dc9a1ed55de7cd8b958007ae93f2
diff --git a/src/android/net/apf/ApfGenerator.java b/src/android/net/apf/ApfGenerator.java
index 8c7f3b7..05b6484 100644
--- a/src/android/net/apf/ApfGenerator.java
+++ b/src/android/net/apf/ApfGenerator.java
@@ -503,12 +503,19 @@
             int writingOffset = offset;
             bytecode[writingOffset++] = generateInstructionByte();
             int indeterminateSize = calculateRequiredIndeterminateSize();
+            int startOffset = 0;
+            if (mOpcode == Opcodes.EXT.value) {
+                // For extend opcode, always write the actual opcode first.
+                writingOffset = mIntImms.get(startOffset++).writeValue(bytecode, writingOffset,
+                        indeterminateSize);
+            }
             if (mTargetLabel != null) {
                 writingOffset = writeValue(calculateTargetLabelOffset(), bytecode, writingOffset,
                         indeterminateSize);
             }
-            for (IntImmediate imm : mIntImms) {
-                writingOffset = imm.writeValue(bytecode, writingOffset, indeterminateSize);
+            for (int i = startOffset; i < mIntImms.size(); ++i) {
+                writingOffset = mIntImms.get(i).writeValue(bytecode, writingOffset,
+                        indeterminateSize);
             }
             if (mBytesImm != null) {
                 System.arraycopy(mBytesImm, 0, bytecode, writingOffset, mBytesImm.length);
diff --git a/tests/unit/src/android/net/apf/ApfV5Test.kt b/tests/unit/src/android/net/apf/ApfV5Test.kt
index da9e1d4..c02ede9 100644
--- a/tests/unit/src/android/net/apf/ApfV5Test.kt
+++ b/tests/unit/src/android/net/apf/ApfV5Test.kt
@@ -303,9 +303,9 @@
         gen.addJumpIfPktAtR0ContainDnsQ(qnames, 0x0c, ApfGenerator.DROP_LABEL)
         program = gen.generate()
         assertContentEquals(byteArrayOf(
-                encodeInstruction(21, 1, 0), 11, 43, 0x0c.toByte(),
+                encodeInstruction(21, 1, 0), 43, 11, 0x0c.toByte(),
         ) + qnames + byteArrayOf(
-                encodeInstruction(21, 1, 1), 1, 43, 0x0c.toByte(),
+                encodeInstruction(21, 1, 1), 43, 1, 0x0c.toByte(),
         ) + qnames, program)
     }