1d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen/* 2d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Copyright (C) 2016 The Android Open Source Project 3d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * 4d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Licensed under the Apache License, Version 2.0 (the "License"); 5d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * you may not use this file except in compliance with the License. 6d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * You may obtain a copy of the License at 7d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * 8d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * http://www.apache.org/licenses/LICENSE-2.0 9d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * 10d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Unless required by applicable law or agreed to in writing, software 11d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * distributed under the License is distributed on an "AS IS" BASIS, 12d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * See the License for the specific language governing permissions and 14d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * limitations under the License. 15d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 16d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 17d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensenpackage android.net.apf; 18d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 19d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensenimport java.util.ArrayList; 20d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensenimport java.util.HashMap; 21d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 22d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen/** 23d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * APF assembler/generator. A tool for generating an APF program. 24d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * 25d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Call add*() functions to add instructions to the program, then call 26d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * {@link generate} to get the APF bytecode for the program. 27d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * 28d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * @hide 29d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 30d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensenpublic class ApfGenerator { 31d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 32d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * This exception is thrown when an attempt is made to generate an illegal instruction. 33d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 34d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen public static class IllegalInstructionException extends Exception { 35d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen IllegalInstructionException(String msg) { 36d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen super(msg); 37d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 38d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 39d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen private enum Opcodes { 40d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen LABEL(-1), 41d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen LDB(1), // Load 1 byte from immediate offset, e.g. "ldb R0, [5]" 42d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen LDH(2), // Load 2 bytes from immediate offset, e.g. "ldh R0, [5]" 43d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen LDW(3), // Load 4 bytes from immediate offset, e.g. "ldw R0, [5]" 44d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen LDBX(4), // Load 1 byte from immediate offset plus register, e.g. "ldbx R0, [5]R0" 45d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen LDHX(5), // Load 2 byte from immediate offset plus register, e.g. "ldhx R0, [5]R0" 46d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen LDWX(6), // Load 4 byte from immediate offset plus register, e.g. "ldwx R0, [5]R0" 47d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen ADD(7), // Add, e.g. "add R0,5" 48d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen MUL(8), // Multiply, e.g. "mul R0,5" 49d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen DIV(9), // Divide, e.g. "div R0,5" 50d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen AND(10), // And, e.g. "and R0,5" 51d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen OR(11), // Or, e.g. "or R0,5" 52d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen SH(12), // Left shift, e.g, "sh R0, 5" or "sh R0, -5" (shifts right) 53d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen LI(13), // Load immediate, e.g. "li R0,5" (immediate encoded as signed value) 54d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen JMP(14), // Jump, e.g. "jmp label" 55d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen JEQ(15), // Compare equal and branch, e.g. "jeq R0,5,label" 56d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen JNE(16), // Compare not equal and branch, e.g. "jne R0,5,label" 57d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen JGT(17), // Compare greater than and branch, e.g. "jgt R0,5,label" 58d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen JLT(18), // Compare less than and branch, e.g. "jlt R0,5,label" 59d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen JSET(19), // Compare any bits set and branch, e.g. "jset R0,5,label" 60d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen JNEBS(20), // Compare not equal byte sequence, e.g. "jnebs R0,5,label,0x1122334455" 61d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen EXT(21); // Followed by immediate indicating ExtendedOpcodes. 62d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 63d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen final int value; 64d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 65d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen private Opcodes(int value) { 66d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen this.value = value; 67d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 68d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 69d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen // Extended opcodes. Primary opcode is Opcodes.EXT. ExtendedOpcodes are encoded in the immediate 70d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen // field. 71d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen private enum ExtendedOpcodes { 72d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen LDM(0), // Load from memory, e.g. "ldm R0,5" 73d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen STM(16), // Store to memory, e.g. "stm R0,5" 74d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen NOT(32), // Not, e.g. "not R0" 75d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen NEG(33), // Negate, e.g. "neg R0" 76d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen SWAP(34), // Swap, e.g. "swap R0,R1" 77d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen MOVE(35); // Move, e.g. "move R0,R1" 78d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 79d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen final int value; 80d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 81d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen private ExtendedOpcodes(int value) { 82d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen this.value = value; 83d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 84d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 85d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen public enum Register { 86d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen R0(0), 87d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen R1(1); 88d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 89d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen final int value; 90d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 91d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen private Register(int value) { 92d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen this.value = value; 93d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 94d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 95d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen private class Instruction { 96d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen private final byte mOpcode; // A "Opcode" value. 97d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen private final byte mRegister; // A "Register" value. 98d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen private boolean mHasImm; 99d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen private byte mImmSize; 100d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen private boolean mImmSigned; 101d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen private int mImm; 102d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen // When mOpcode is a jump: 103d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen private byte mTargetLabelSize; 104d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen private String mTargetLabel; 105d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen // When mOpcode == Opcodes.LABEL: 106d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen private String mLabel; 107d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen // When mOpcode == Opcodes.JNEBS: 108d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen private byte[] mCompareBytes; 109d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen // Offset in bytes from the begining of this program. Set by {@link ApfGenerator#generate}. 110d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen int offset; 111d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 112d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen Instruction(Opcodes opcode, Register register) { 113d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen mOpcode = (byte)opcode.value; 114d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen mRegister = (byte)register.value; 115d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 116d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 117d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen Instruction(Opcodes opcode) { 118d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen this(opcode, Register.R0); 119d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 120d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 121d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen void setImm(int imm, boolean signed) { 122d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen mHasImm = true; 123d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen mImm = imm; 124d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen mImmSigned = signed; 125d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen mImmSize = calculateImmSize(imm, signed); 126d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 127d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 128d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen void setUnsignedImm(int imm) { 129d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen setImm(imm, false); 130d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 131d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 132d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen void setSignedImm(int imm) { 133d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen setImm(imm, true); 134d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 135d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 136d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen void setLabel(String label) throws IllegalInstructionException { 137d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen if (mLabels.containsKey(label)) { 138d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen throw new IllegalInstructionException("duplicate label " + label); 139d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 140d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen if (mOpcode != Opcodes.LABEL.value) { 141d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen throw new IllegalStateException("adding label to non-label instruction"); 142d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 143d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen mLabel = label; 144d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen mLabels.put(label, this); 145d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 146d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 147d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen void setTargetLabel(String label) { 148d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen mTargetLabel = label; 149d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen mTargetLabelSize = 4; // May shrink later on in generate(). 150d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 151d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 152d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen void setCompareBytes(byte[] bytes) { 153d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen if (mOpcode != Opcodes.JNEBS.value) { 154d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen throw new IllegalStateException("adding compare bytes to non-JNEBS instruction"); 155d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 156d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen mCompareBytes = bytes; 157d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 158d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 159d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 160d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * @return size of instruction in bytes. 161d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 162d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen int size() { 163d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen if (mOpcode == Opcodes.LABEL.value) { 164d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return 0; 165d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 166d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen int size = 1; 167d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen if (mHasImm) { 168d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen size += generatedImmSize(); 169d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 170d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen if (mTargetLabel != null) { 171d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen size += generatedImmSize(); 172d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 173d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen if (mCompareBytes != null) { 174d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen size += mCompareBytes.length; 175d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 176d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return size; 177d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 178d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 179d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 180d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Resize immediate value field so that it's only as big as required to 181d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * contain the offset of the jump destination. 182d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * @return {@code true} if shrunk. 183d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 184d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen boolean shrink() throws IllegalInstructionException { 185d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen if (mTargetLabel == null) { 186d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return false; 187d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 188d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen int oldSize = size(); 189d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen int oldTargetLabelSize = mTargetLabelSize; 190d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen mTargetLabelSize = calculateImmSize(calculateTargetLabelOffset(), false); 191d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen if (mTargetLabelSize > oldTargetLabelSize) { 192d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen throw new IllegalStateException("instruction grew"); 193d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 194d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return size() < oldSize; 195d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 196d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 197d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 198d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Assemble value for instruction size field. 199d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 200d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen private byte generateImmSizeField() { 201d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen byte immSize = generatedImmSize(); 202d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen // Encode size field to fit in 2 bits: 0->0, 1->1, 2->2, 3->4. 203d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return immSize == 4 ? 3 : immSize; 204d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 205d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 206d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 207d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Assemble first byte of generated instruction. 208d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 209d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen private byte generateInstructionByte() { 210d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen byte sizeField = generateImmSizeField(); 211d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return (byte)((mOpcode << 3) | (sizeField << 1) | mRegister); 212d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 213d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 214d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 215d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Write {@code value} at offset {@code writingOffset} into {@code bytecode}. 216d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * {@link generatedImmSize} bytes are written. {@code value} is truncated to 217d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * {@code generatedImmSize} bytes. {@code value} is treated simply as a 218d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * 32-bit value, so unsigned values should be zero extended and the truncation 219d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * should simply throw away their zero-ed upper bits, and signed values should 220d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * be sign extended and the truncation should simply throw away their signed 221d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * upper bits. 222d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 223d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen private int writeValue(int value, byte[] bytecode, int writingOffset) { 224d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen for (int i = generatedImmSize() - 1; i >= 0; i--) { 225d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen bytecode[writingOffset++] = (byte)((value >> (i * 8)) & 255); 226d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 227d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return writingOffset; 228d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 229d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 230d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 231d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Generate bytecode for this instruction at offset {@link offset}. 232d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 233d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen void generate(byte[] bytecode) throws IllegalInstructionException { 234d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen if (mOpcode == Opcodes.LABEL.value) { 235d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return; 236d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 237d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen int writingOffset = offset; 238d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen bytecode[writingOffset++] = generateInstructionByte(); 239d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen if (mTargetLabel != null) { 240d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen writingOffset = writeValue(calculateTargetLabelOffset(), bytecode, writingOffset); 241d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 242d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen if (mHasImm) { 243d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen writingOffset = writeValue(mImm, bytecode, writingOffset); 244d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 245d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen if (mCompareBytes != null) { 246d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen System.arraycopy(mCompareBytes, 0, bytecode, writingOffset, mCompareBytes.length); 247d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen writingOffset += mCompareBytes.length; 248d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 249d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen if ((writingOffset - offset) != size()) { 250d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen throw new IllegalStateException("wrote " + (writingOffset - offset) + 251d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen " but should have written " + size()); 252d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 253d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 254d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 255d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 256d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Calculate the size of either the immediate field or the target label field, if either is 257d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * present. Most instructions have either an immediate or a target label field, but for the 258d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * instructions that have both, the size of the target label field must be the same as the 259d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * size of the immediate field, because there is only one length field in the instruction 260d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * byte, hence why this function simply takes the maximum of the two sizes, so neither is 261d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * truncated. 262d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 263d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen private byte generatedImmSize() { 264d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return mImmSize > mTargetLabelSize ? mImmSize : mTargetLabelSize; 265d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 266d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 267d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen private int calculateTargetLabelOffset() throws IllegalInstructionException { 268d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen Instruction targetLabelInstruction; 269d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen if (mTargetLabel == DROP_LABEL) { 270d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen targetLabelInstruction = mDropLabel; 271d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } else if (mTargetLabel == PASS_LABEL) { 272d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen targetLabelInstruction = mPassLabel; 273d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } else { 274d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen targetLabelInstruction = mLabels.get(mTargetLabel); 275d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 276d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen if (targetLabelInstruction == null) { 277d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen throw new IllegalInstructionException("label not found: " + mTargetLabel); 278d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 279d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen // Calculate distance from end of this instruction to instruction.offset. 280d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen final int targetLabelOffset = targetLabelInstruction.offset - (offset + size()); 281d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen if (targetLabelOffset < 0) { 282d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen throw new IllegalInstructionException("backward branches disallowed; label: " + 283d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen mTargetLabel); 284d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 285d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return targetLabelOffset; 286d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 287d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 288d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen private byte calculateImmSize(int imm, boolean signed) { 289d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen if (imm == 0) { 290d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return 0; 291d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 292d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen if (signed && (imm >= -128 && imm <= 127) || 293d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen !signed && (imm >= 0 && imm <= 255)) { 294d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return 1; 295d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 296d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen if (signed && (imm >= -32768 && imm <= 32767) || 297d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen !signed && (imm >= 0 && imm <= 65535)) { 298d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return 2; 299d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 300d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return 4; 301d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 302d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 303d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 304d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 305d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Jump to this label to terminate the program and indicate the packet 306d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * should be dropped. 307d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 308d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen public static final String DROP_LABEL = "__DROP__"; 309d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 310d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 311d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Jump to this label to terminate the program and indicate the packet 312d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * should be passed to the AP. 313d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 314d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen public static final String PASS_LABEL = "__PASS__"; 315d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 316d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 317d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Number of memory slots available for access via APF stores to memory and loads from memory. 318d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * The memory slots are numbered 0 to {@code MEMORY_SLOTS} - 1. This must be kept in sync with 319d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * the APF interpreter. 320d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 321d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen public static final int MEMORY_SLOTS = 16; 322d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 323d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 324d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Memory slot number that is prefilled with the IPv4 header length. 325d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Note that this memory slot may be overwritten by a program that 326d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * executes stores to this memory slot. This must be kept in sync with 327d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * the APF interpreter. 328d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 329d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen public static final int IPV4_HEADER_SIZE_MEMORY_SLOT = 13; 330d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 331d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 332d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Memory slot number that is prefilled with the size of the packet being filtered in bytes. 333d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Note that this memory slot may be overwritten by a program that 334d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * executes stores to this memory slot. This must be kept in sync with the APF interpreter. 335d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 336d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen public static final int PACKET_SIZE_MEMORY_SLOT = 14; 337d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 338d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 339d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Memory slot number that is prefilled with the age of the filter in seconds. The age of the 340d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * filter is the time since the filter was installed until now. 341d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Note that this memory slot may be overwritten by a program that 342d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * executes stores to this memory slot. This must be kept in sync with the APF interpreter. 343d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 344d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen public static final int FILTER_AGE_MEMORY_SLOT = 15; 345d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 346d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 347d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * First memory slot containing prefilled values. Can be used in range comparisons to determine 348d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * if memory slot index is within prefilled slots. 349d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 350d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen public static final int FIRST_PREFILLED_MEMORY_SLOT = IPV4_HEADER_SIZE_MEMORY_SLOT; 351d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 352d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 353d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Last memory slot containing prefilled values. Can be used in range comparisons to determine 354d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * if memory slot index is within prefilled slots. 355d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 356d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen public static final int LAST_PREFILLED_MEMORY_SLOT = FILTER_AGE_MEMORY_SLOT; 357d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 358d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen private final ArrayList<Instruction> mInstructions = new ArrayList<Instruction>(); 359d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen private final HashMap<String, Instruction> mLabels = new HashMap<String, Instruction>(); 360d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen private final Instruction mDropLabel = new Instruction(Opcodes.LABEL); 361d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen private final Instruction mPassLabel = new Instruction(Opcodes.LABEL); 362d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen private boolean mGenerated; 363d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 364d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 365d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Set version of APF instruction set to generate instructions for. Returns {@code true} 366d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * if generating for this version is supported, {@code false} otherwise. 367d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 368d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen public boolean setApfVersion(int version) { 369d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen // This version number syncs up with APF_VERSION in hardware/google/apf/apf_interpreter.h 370d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return version == 2; 371d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 372d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 373d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen private void addInstruction(Instruction instruction) { 374d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen if (mGenerated) { 375d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen throw new IllegalStateException("Program already generated"); 376d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 377d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen mInstructions.add(instruction); 378d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 379d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 380d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 381d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Define a label at the current end of the program. Jumps can jump to this label. Labels are 382d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * their own separate instructions, though with size 0. This facilitates having labels with 383d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * no corresponding code to execute, for example a label at the end of a program. For example 384d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * an {@link ApfGenerator} might be passed to a function that adds a filter like so: 385d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * <pre> 386d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * load from packet 387d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * compare loaded data, jump if not equal to "next_filter" 388d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * load from packet 389d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * compare loaded data, jump if not equal to "next_filter" 390d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * jump to drop label 391d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * define "next_filter" here 392d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * </pre> 393d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * In this case "next_filter" may not have any generated code associated with it. 394d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 395d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen public ApfGenerator defineLabel(String name) throws IllegalInstructionException { 396d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen Instruction instruction = new Instruction(Opcodes.LABEL); 397d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen instruction.setLabel(name); 398d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen addInstruction(instruction); 399d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return this; 400d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 401d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 402d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 403d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Add an unconditional jump instruction to the end of the program. 404d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 405d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen public ApfGenerator addJump(String target) { 406d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen Instruction instruction = new Instruction(Opcodes.JMP); 407d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen instruction.setTargetLabel(target); 408d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen addInstruction(instruction); 409d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return this; 410d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 411d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 412d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 413d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Add an instruction to the end of the program to load the byte at offset {@code offset} 414d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * bytes from the begining of the packet into {@code register}. 415d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 416d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen public ApfGenerator addLoad8(Register register, int offset) { 417d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen Instruction instruction = new Instruction(Opcodes.LDB, register); 418d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen instruction.setUnsignedImm(offset); 419d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen addInstruction(instruction); 420d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return this; 421d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 422d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 423d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 424d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Add an instruction to the end of the program to load 16-bits at offset {@code offset} 425d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * bytes from the begining of the packet into {@code register}. 426d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 427d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen public ApfGenerator addLoad16(Register register, int offset) { 428d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen Instruction instruction = new Instruction(Opcodes.LDH, register); 429d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen instruction.setUnsignedImm(offset); 430d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen addInstruction(instruction); 431d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return this; 432d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 433d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 434d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 435d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Add an instruction to the end of the program to load 32-bits at offset {@code offset} 436d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * bytes from the begining of the packet into {@code register}. 437d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 438d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen public ApfGenerator addLoad32(Register register, int offset) { 439d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen Instruction instruction = new Instruction(Opcodes.LDW, register); 440d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen instruction.setUnsignedImm(offset); 441d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen addInstruction(instruction); 442d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return this; 443d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 444d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 445d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 446d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Add an instruction to the end of the program to load a byte from the packet into 447d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * {@code register}. The offset of the loaded byte from the begining of the packet is 448d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * the sum of {@code offset} and the value in register R1. 449d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 450d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen public ApfGenerator addLoad8Indexed(Register register, int offset) { 451d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen Instruction instruction = new Instruction(Opcodes.LDBX, register); 452d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen instruction.setUnsignedImm(offset); 453d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen addInstruction(instruction); 454d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return this; 455d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 456d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 457d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 458d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Add an instruction to the end of the program to load 16-bits from the packet into 459d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * {@code register}. The offset of the loaded 16-bits from the begining of the packet is 460d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * the sum of {@code offset} and the value in register R1. 461d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 462d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen public ApfGenerator addLoad16Indexed(Register register, int offset) { 463d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen Instruction instruction = new Instruction(Opcodes.LDHX, register); 464d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen instruction.setUnsignedImm(offset); 465d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen addInstruction(instruction); 466d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return this; 467d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 468d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 469d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 470d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Add an instruction to the end of the program to load 32-bits from the packet into 471d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * {@code register}. The offset of the loaded 32-bits from the begining of the packet is 472d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * the sum of {@code offset} and the value in register R1. 473d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 474d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen public ApfGenerator addLoad32Indexed(Register register, int offset) { 475d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen Instruction instruction = new Instruction(Opcodes.LDWX, register); 476d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen instruction.setUnsignedImm(offset); 477d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen addInstruction(instruction); 478d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return this; 479d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 480d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 481d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 482d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Add an instruction to the end of the program to add {@code value} to register R0. 483d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 484d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen public ApfGenerator addAdd(int value) { 485d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen Instruction instruction = new Instruction(Opcodes.ADD); 486d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen instruction.setSignedImm(value); 487d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen addInstruction(instruction); 488d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return this; 489d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 490d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 491d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 492d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Add an instruction to the end of the program to multiply register R0 by {@code value}. 493d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 494d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen public ApfGenerator addMul(int value) { 495d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen Instruction instruction = new Instruction(Opcodes.MUL); 496d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen instruction.setSignedImm(value); 497d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen addInstruction(instruction); 498d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return this; 499d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 500d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 501d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 502d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Add an instruction to the end of the program to divide register R0 by {@code value}. 503d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 504d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen public ApfGenerator addDiv(int value) { 505d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen Instruction instruction = new Instruction(Opcodes.DIV); 506d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen instruction.setSignedImm(value); 507d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen addInstruction(instruction); 508d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return this; 509d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 510d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 511d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 512d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Add an instruction to the end of the program to logically and register R0 with {@code value}. 513d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 514d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen public ApfGenerator addAnd(int value) { 515d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen Instruction instruction = new Instruction(Opcodes.AND); 516d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen instruction.setUnsignedImm(value); 517d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen addInstruction(instruction); 518d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return this; 519d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 520d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 521d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 522d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Add an instruction to the end of the program to logically or register R0 with {@code value}. 523d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 524d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen public ApfGenerator addOr(int value) { 525d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen Instruction instruction = new Instruction(Opcodes.OR); 526d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen instruction.setUnsignedImm(value); 527d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen addInstruction(instruction); 528d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return this; 529d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 530d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 531d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 532d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Add an instruction to the end of the program to shift left register R0 by {@code value} bits. 533d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 534d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen public ApfGenerator addLeftShift(int value) { 535d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen Instruction instruction = new Instruction(Opcodes.SH); 536d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen instruction.setSignedImm(value); 537d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen addInstruction(instruction); 538d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return this; 539d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 540d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 541d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 542d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Add an instruction to the end of the program to shift right register R0 by {@code value} 543d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * bits. 544d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 545d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen public ApfGenerator addRightShift(int value) { 546d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen Instruction instruction = new Instruction(Opcodes.SH); 547d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen instruction.setSignedImm(-value); 548d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen addInstruction(instruction); 549d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return this; 550d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 551d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 552d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 553d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Add an instruction to the end of the program to add register R1 to register R0. 554d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 555d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen public ApfGenerator addAddR1() { 556d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen Instruction instruction = new Instruction(Opcodes.ADD, Register.R1); 557d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen addInstruction(instruction); 558d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return this; 559d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 560d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 561d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 562d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Add an instruction to the end of the program to multiply register R0 by register R1. 563d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 564d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen public ApfGenerator addMulR1() { 565d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen Instruction instruction = new Instruction(Opcodes.MUL, Register.R1); 566d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen addInstruction(instruction); 567d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return this; 568d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 569d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 570d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 571d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Add an instruction to the end of the program to divide register R0 by register R1. 572d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 573d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen public ApfGenerator addDivR1() { 574d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen Instruction instruction = new Instruction(Opcodes.DIV, Register.R1); 575d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen addInstruction(instruction); 576d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return this; 577d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 578d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 579d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 580d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Add an instruction to the end of the program to logically and register R0 with register R1 581d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * and store the result back into register R0. 582d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 583d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen public ApfGenerator addAndR1() { 584d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen Instruction instruction = new Instruction(Opcodes.AND, Register.R1); 585d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen addInstruction(instruction); 586d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return this; 587d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 588d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 589d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 590d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Add an instruction to the end of the program to logically or register R0 with register R1 591d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * and store the result back into register R0. 592d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 593d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen public ApfGenerator addOrR1() { 594d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen Instruction instruction = new Instruction(Opcodes.OR, Register.R1); 595d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen addInstruction(instruction); 596d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return this; 597d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 598d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 599d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 600d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Add an instruction to the end of the program to shift register R0 left by the value in 601d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * register R1. 602d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 603d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen public ApfGenerator addLeftShiftR1() { 604d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen Instruction instruction = new Instruction(Opcodes.SH, Register.R1); 605d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen addInstruction(instruction); 606d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return this; 607d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 608d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 609d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 610d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Add an instruction to the end of the program to move {@code value} into {@code register}. 611d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 612d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen public ApfGenerator addLoadImmediate(Register register, int value) { 613d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen Instruction instruction = new Instruction(Opcodes.LI, register); 614d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen instruction.setSignedImm(value); 615d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen addInstruction(instruction); 616d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return this; 617d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 618d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 619d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 620d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Add an instruction to the end of the program to jump to {@code target} if register R0's 621d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * value equals {@code value}. 622d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 623d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen public ApfGenerator addJumpIfR0Equals(int value, String target) { 624d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen Instruction instruction = new Instruction(Opcodes.JEQ); 625d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen instruction.setUnsignedImm(value); 626d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen instruction.setTargetLabel(target); 627d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen addInstruction(instruction); 628d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return this; 629d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 630d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 631d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 632d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Add an instruction to the end of the program to jump to {@code target} if register R0's 633d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * value does not equal {@code value}. 634d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 635d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen public ApfGenerator addJumpIfR0NotEquals(int value, String target) { 636d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen Instruction instruction = new Instruction(Opcodes.JNE); 637d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen instruction.setUnsignedImm(value); 638d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen instruction.setTargetLabel(target); 639d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen addInstruction(instruction); 640d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return this; 641d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 642d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 643d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 644d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Add an instruction to the end of the program to jump to {@code target} if register R0's 645d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * value is greater than {@code value}. 646d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 647d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen public ApfGenerator addJumpIfR0GreaterThan(int value, String target) { 648d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen Instruction instruction = new Instruction(Opcodes.JGT); 649d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen instruction.setUnsignedImm(value); 650d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen instruction.setTargetLabel(target); 651d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen addInstruction(instruction); 652d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return this; 653d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 654d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 655d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 656d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Add an instruction to the end of the program to jump to {@code target} if register R0's 657d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * value is less than {@code value}. 658d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 659d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen public ApfGenerator addJumpIfR0LessThan(int value, String target) { 660d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen Instruction instruction = new Instruction(Opcodes.JLT); 661d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen instruction.setUnsignedImm(value); 662d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen instruction.setTargetLabel(target); 663d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen addInstruction(instruction); 664d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return this; 665d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 666d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 667d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 668d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Add an instruction to the end of the program to jump to {@code target} if register R0's 669d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * value has any bits set that are also set in {@code value}. 670d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 671d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen public ApfGenerator addJumpIfR0AnyBitsSet(int value, String target) { 672d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen Instruction instruction = new Instruction(Opcodes.JSET); 673d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen instruction.setUnsignedImm(value); 674d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen instruction.setTargetLabel(target); 675d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen addInstruction(instruction); 676d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return this; 677d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 678d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 679d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Add an instruction to the end of the program to jump to {@code target} if register R0's 680d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * value equals register R1's value. 681d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 682d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen public ApfGenerator addJumpIfR0EqualsR1(String target) { 683d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen Instruction instruction = new Instruction(Opcodes.JEQ, Register.R1); 684d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen instruction.setTargetLabel(target); 685d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen addInstruction(instruction); 686d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return this; 687d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 688d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 689d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 690d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Add an instruction to the end of the program to jump to {@code target} if register R0's 691d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * value does not equal register R1's value. 692d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 693d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen public ApfGenerator addJumpIfR0NotEqualsR1(String target) { 694d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen Instruction instruction = new Instruction(Opcodes.JNE, Register.R1); 695d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen instruction.setTargetLabel(target); 696d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen addInstruction(instruction); 697d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return this; 698d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 699d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 700d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 701d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Add an instruction to the end of the program to jump to {@code target} if register R0's 702d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * value is greater than register R1's value. 703d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 704d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen public ApfGenerator addJumpIfR0GreaterThanR1(String target) { 705d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen Instruction instruction = new Instruction(Opcodes.JGT, Register.R1); 706d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen instruction.setTargetLabel(target); 707d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen addInstruction(instruction); 708d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return this; 709d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 710d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 711d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 712d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Add an instruction to the end of the program to jump to {@code target} if register R0's 713d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * value is less than register R1's value. 714d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 715d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen public ApfGenerator addJumpIfR0LessThanR1(String target) { 716d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen Instruction instruction = new Instruction(Opcodes.JLT, Register.R1); 717d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen instruction.setTargetLabel(target); 718d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen addInstruction(instruction); 719d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return this; 720d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 721d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 722d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 723d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Add an instruction to the end of the program to jump to {@code target} if register R0's 724d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * value has any bits set that are also set in R1's value. 725d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 726d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen public ApfGenerator addJumpIfR0AnyBitsSetR1(String target) { 727d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen Instruction instruction = new Instruction(Opcodes.JSET, Register.R1); 728d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen instruction.setTargetLabel(target); 729d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen addInstruction(instruction); 730d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return this; 731d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 732d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 733d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 734d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Add an instruction to the end of the program to jump to {@code target} if the bytes of the 735d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * packet at, an offset specified by {@code register}, match {@code bytes}. 736d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 73791723d7f7ecc07e9bfa84c445213acf1dec0664fPaul Jensen public ApfGenerator addJumpIfBytesNotEqual(Register register, byte[] bytes, String target) 73891723d7f7ecc07e9bfa84c445213acf1dec0664fPaul Jensen throws IllegalInstructionException { 73991723d7f7ecc07e9bfa84c445213acf1dec0664fPaul Jensen if (register == Register.R1) { 74091723d7f7ecc07e9bfa84c445213acf1dec0664fPaul Jensen throw new IllegalInstructionException("JNEBS fails with R1"); 74191723d7f7ecc07e9bfa84c445213acf1dec0664fPaul Jensen } 742d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen Instruction instruction = new Instruction(Opcodes.JNEBS, register); 743d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen instruction.setUnsignedImm(bytes.length); 744d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen instruction.setTargetLabel(target); 745d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen instruction.setCompareBytes(bytes); 746d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen addInstruction(instruction); 747d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return this; 748d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 749d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 750d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 751d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Add an instruction to the end of the program to load memory slot {@code slot} into 752d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * {@code register}. 753d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 754d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen public ApfGenerator addLoadFromMemory(Register register, int slot) 755d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen throws IllegalInstructionException { 756d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen if (slot < 0 || slot > (MEMORY_SLOTS - 1)) { 757d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen throw new IllegalInstructionException("illegal memory slot number: " + slot); 758d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 759d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen Instruction instruction = new Instruction(Opcodes.EXT, register); 760d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen instruction.setUnsignedImm(ExtendedOpcodes.LDM.value + slot); 761d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen addInstruction(instruction); 762d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return this; 763d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 764d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 765d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 766d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Add an instruction to the end of the program to store {@code register} into memory slot 767d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * {@code slot}. 768d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 769d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen public ApfGenerator addStoreToMemory(Register register, int slot) 770d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen throws IllegalInstructionException { 771d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen if (slot < 0 || slot > (MEMORY_SLOTS - 1)) { 772d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen throw new IllegalInstructionException("illegal memory slot number: " + slot); 773d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 774d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen Instruction instruction = new Instruction(Opcodes.EXT, register); 775d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen instruction.setUnsignedImm(ExtendedOpcodes.STM.value + slot); 776d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen addInstruction(instruction); 777d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return this; 778d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 779d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 780d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 781d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Add an instruction to the end of the program to logically not {@code register}. 782d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 783d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen public ApfGenerator addNot(Register register) { 784d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen Instruction instruction = new Instruction(Opcodes.EXT, register); 785d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen instruction.setUnsignedImm(ExtendedOpcodes.NOT.value); 786d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen addInstruction(instruction); 787d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return this; 788d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 789d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 790d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 791d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Add an instruction to the end of the program to negate {@code register}. 792d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 793d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen public ApfGenerator addNeg(Register register) { 794d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen Instruction instruction = new Instruction(Opcodes.EXT, register); 795d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen instruction.setUnsignedImm(ExtendedOpcodes.NEG.value); 796d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen addInstruction(instruction); 797d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return this; 798d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 799d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 800d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 801d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Add an instruction to swap the values in register R0 and register R1. 802d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 803d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen public ApfGenerator addSwap() { 804d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen Instruction instruction = new Instruction(Opcodes.EXT); 805d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen instruction.setUnsignedImm(ExtendedOpcodes.SWAP.value); 806d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen addInstruction(instruction); 807d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return this; 808d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 809d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 810d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 811d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Add an instruction to the end of the program to move the value into 812d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * {@code register} from the other register. 813d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 814d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen public ApfGenerator addMove(Register register) { 815d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen Instruction instruction = new Instruction(Opcodes.EXT, register); 816d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen instruction.setUnsignedImm(ExtendedOpcodes.MOVE.value); 817d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen addInstruction(instruction); 818d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return this; 819d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 820d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 821d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 822d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Updates instruction offset fields using latest instruction sizes. 823d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * @return current program length in bytes. 824d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 825d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen private int updateInstructionOffsets() { 826d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen int offset = 0; 827d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen for (Instruction instruction : mInstructions) { 828d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen instruction.offset = offset; 829d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen offset += instruction.size(); 830d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 831d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return offset; 832d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 833d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 834d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 835d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Returns an overestimate of the size of the generated program. {@link #generate} may return 836d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * a program that is smaller. 837d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 838d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen public int programLengthOverEstimate() { 839d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return updateInstructionOffsets(); 840d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 841d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 842d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 843d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Generate the bytecode for the APF program. 844d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * @return the bytecode. 845d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * @throws IllegalStateException if a label is referenced but not defined. 846d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 847d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen public byte[] generate() throws IllegalInstructionException { 848d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen // Enforce that we can only generate once because we cannot unshrink instructions and 849d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen // PASS/DROP labels may move further away requiring unshrinking if we add further 850d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen // instructions. 851d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen if (mGenerated) { 852d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen throw new IllegalStateException("Can only generate() once!"); 853d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 854d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen mGenerated = true; 855d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen int total_size; 856d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen boolean shrunk; 857d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen // Shrink the immediate value fields of instructions. 858d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen // As we shrink the instructions some branch offset 859d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen // fields may shrink also, thereby shrinking the 860d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen // instructions further. Loop until we've reached the 861d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen // minimum size. Rarely will this loop more than a few times. 862d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen // Limit iterations to avoid O(n^2) behavior. 863d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen int iterations_remaining = 10; 864d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen do { 865d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen total_size = updateInstructionOffsets(); 866d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen // Update drop and pass label offsets. 867d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen mDropLabel.offset = total_size + 1; 868d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen mPassLabel.offset = total_size; 869d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen // Limit run-time in aberant circumstances. 870d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen if (iterations_remaining-- == 0) break; 871d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen // Attempt to shrink instructions. 872d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen shrunk = false; 873d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen for (Instruction instruction : mInstructions) { 874d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen if (instruction.shrink()) { 875d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen shrunk = true; 876d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 877d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 878d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } while (shrunk); 879d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen // Generate bytecode for instructions. 880d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen byte[] bytecode = new byte[total_size]; 881d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen for (Instruction instruction : mInstructions) { 882d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen instruction.generate(bytecode); 883d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 884d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return bytecode; 885d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 886d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen} 887d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 888