Class Op

java.lang.Object
com.iizix.prop.gunit.internal.Op

public final class Op extends Object
The opcodes of the unit formula stack machine, in ONE FLAT SPACE.

There is no separate "SCALE" instruction with a unit operand: every unit type gets its own opcode, OP_SCALE+ut. The whole space therefore fits in the values 1 to OP_LAST (38 with the current 29 units), comfortably below 63, which is what SendTransaction.appendUnsigned(int) encodes in a single byte. Every instruction on the wire is thus exactly one byte, plus the constant triple that follows an OP_CONST.

The only instruction carrying an operand is OP_CONST. In the in-memory code array it occupies TWO slots: the opcode itself followed by the index of the constant in the parallel constant arrays of the Formula. On the wire the constant value follows the opcode inline instead, since constants are emitted in code order and there is no constant pool.

Stack effects:

Stack effects per opcode
OpcodePopsPushes
OP_CONST01
OP_SCALE+ut11
OP_NEG11
OP_ADD OP_SUB OP_MUL OP_DIV OP_MIN2 OP_MAX221

Author:
Christopher Mindus
  • Field Summary

    Fields
    Modifier and Type
    Field
    Description
    static final int
    Addition.
    static final int
    Push a constant.
    static final int
    Division.
    static final int
    The numerically largest legal opcode.
    static final int
    Binary maximum, used to fold the variadic max() pairwise.
    static final int
    Binary minimum, used to fold the variadic min() pairwise.
    static final int
    Multiplication.
    static final int
    Unary negation.
    static final int
    The base of the per-unit scale opcodes: the opcode that multiplies the top of the stack by scaleTable[ut] is OP_SCALE+ut, so the scale opcodes occupy OP_SCALE+1 to OP_SCALE+UnitType.UNIT_COUNT.
    static final int
    Subtraction.
  • Method Summary

    Modifier and Type
    Method
    Description
    static boolean
    isScale(int op)
    Checks if an opcode is one of the scale opcodes.
    static int
    scaleOp(int ut)
    Returns the scale opcode for a unit type.
    static int
    stackEffect(int op)
    Returns the net stack effect of an opcode, i.e.
    static String
    toString(int op)
    Returns a short mnemonic for an opcode, for debugging and error text.
    static int
    unitOf(int op)
    Returns the unit type of a scale opcode.
  • Field Details

    • OP_ADD

      public static final int OP_ADD
      Addition. Pops two values, pushes a+b.
      See Also:
    • OP_SUB

      public static final int OP_SUB
      Subtraction. Pops two values, pushes a-b.
      See Also:
    • OP_MUL

      public static final int OP_MUL
      Multiplication. Pops two values, pushes a*b.
      See Also:
    • OP_DIV

      public static final int OP_DIV
      Division. Pops two values, pushes a/b. Division by zero produces an infinity, which is clamped to zero once at the end of the evaluation.
      See Also:
    • OP_NEG

      public static final int OP_NEG
      Unary negation. Pops one value, pushes -a.
      See Also:
    • OP_MIN2

      public static final int OP_MIN2
      Binary minimum, used to fold the variadic min() pairwise. Implemented as a plain compare rather than Math.min, both because a compare is faster and because it avoids having to replicate JavaScript's -0 and NaN rules exactly in Java. See Formula for the NaN consequence.
      See Also:
    • OP_MAX2

      public static final int OP_MAX2
      Binary maximum, used to fold the variadic max() pairwise. See OP_MIN2.
      See Also:
    • OP_CONST

      public static final int OP_CONST
      Push a constant. In the in-memory code array this opcode is followed by the index of the constant in the Formula constant arrays; on the wire it is followed by the constant triple itself.
      See Also:
    • OP_SCALE

      public static final int OP_SCALE
      The base of the per-unit scale opcodes: the opcode that multiplies the top of the stack by scaleTable[ut] is OP_SCALE+ut, so the scale opcodes occupy OP_SCALE+1 to OP_SCALE+UnitType.UNIT_COUNT.

      OP_SCALE itself, i.e. ut==0, is never a valid opcode. Neither is OP_SCALE+UnitType.UT_PX: px is the identity scale of 1.0 and the emitter deliberately emits nothing for it.

      See Also:
    • OP_LAST

      public static final int OP_LAST
      The numerically largest legal opcode. Must stay below 64 for the single-byte wire encoding to hold; this is asserted in the static initializer.
      See Also:
  • Method Details

    • scaleOp

      public static int scaleOp(int ut)
      Returns the scale opcode for a unit type.
      Parameters:
      ut - The unit type, 1 to UnitType.UNIT_COUNT.
      Returns:
      The opcode.
      Throws:
      IllegalArgumentException - If the unit type is out of range.
    • unitOf

      public static int unitOf(int op)
      Returns the unit type of a scale opcode.
      Parameters:
      op - The opcode.
      Returns:
      The unit type 1 to UnitType.UNIT_COUNT, or -1 if the opcode is not a scale opcode.
    • isScale

      public static boolean isScale(int op)
      Checks if an opcode is one of the scale opcodes.
      Parameters:
      op - The opcode.
      Returns:
      true for a scale opcode, false otherwise.
    • stackEffect

      public static int stackEffect(int op)
      Returns the net stack effect of an opcode, i.e. pushes minus pops.
      Parameters:
      op - The opcode.
      Returns:
      +1 for OP_CONST, 0 for the unary and scale opcodes, -1 for the binary opcodes.
      Throws:
      FormulaFormatException - If the opcode is unknown, carrying the stable reason token FormulaFormatException.UNKNOWN_OPCODE. It is an IllegalArgumentException, so existing catches are unaffected.
    • toString

      public static String toString(int op)
      Returns a short mnemonic for an opcode, for debugging and error text.
      Parameters:
      op - The opcode.
      Returns:
      The mnemonic, e.g. "ADD" or "SCALE %w".