/// <summary> /// Gets the number of items popped from the stack by an instruction of the given opcode /// with the given operands. /// </summary> /// /// <returns>The number of items popped from the stack.</returns> /// /// <param name="opcode">The instruction opcode.</param> /// <param name="multinameKind">The type of the multiname operand for the instruction. /// If <paramref name="opcode"/> uses a multiname operand, this must be a valid multiname /// kind; otherwise, this argument is ignored.</param> /// <param name="argCount">The argument count for a call-like instruction. If /// <paramref name="opcode"/> does not use an argument count, this argument is ignored.</param> /// /// <exception cref="AVM2Exception">ArgumentError #10061: <paramref name="argCount"/> is negative, /// <paramref name="opcode"/> is not the opcode of a valid instruction, or <paramref name="opcode"/> /// represents an instruction with a multiname argument and <paramref name="multinameKind"/> is not /// a valid multiname kind.</exception> public static int getStackPopCount(ABCOp opcode, ABCConstKind multinameKind = 0, int argCount = 0) { if (argCount < 0) { throw ErrorHelper.createError(ErrorCode.MARIANA__ARGUMENT_OUT_OF_RANGE, nameof(argCount)); } ABCOpInfo opInfo = s_opinfo[(byte)opcode]; if (!opInfo.isValid) { throw ErrorHelper.createError(ErrorCode.MARIANA__ARGUMENT_OUT_OF_RANGE, nameof(opcode)); } (int popCount, bool hasMultiname) = opcode switch { ABCOp.newarray => (argCount, false), ABCOp.newobject => (checked (argCount * 2), false), ABCOp.call => (argCount + 2, false), ABCOp.construct or ABCOp.callmethod or ABCOp.callstatic or ABCOp.constructsuper or ABCOp.applytype => (argCount + 1, false), ABCOp.callproperty or ABCOp.callproplex or ABCOp.callpropvoid or ABCOp.callsuper or ABCOp.callsupervoid or ABCOp.constructprop => (argCount + 1, true), ABCOp.finddef or ABCOp.findproperty or ABCOp.findpropstrict => (0, true), ABCOp.deleteproperty or ABCOp.getdescendants or ABCOp.getproperty or ABCOp.getsuper => (1, true), ABCOp.setproperty or ABCOp.setsuper or ABCOp.initproperty => (2, true), _ => (opInfo.stackPopCount, false) }; if (!hasMultiname) { return(popCount); } return(multinameKind switch { ABCConstKind.QName or ABCConstKind.QNameA or ABCConstKind.Multiname or ABCConstKind.MultinameA => popCount, ABCConstKind.RTQName or ABCConstKind.RTQNameA or ABCConstKind.MultinameL or ABCConstKind.MultinameLA => popCount + 1, ABCConstKind.RTQNameL or ABCConstKind.RTQNameLA => popCount + 2, _ => throw ErrorHelper.createError(ErrorCode.MARIANA__ARGUMENT_OUT_OF_RANGE, nameof(multinameKind)), });
/// <summary> /// Gets the name of the given opcode as a string. /// </summary> /// <returns>The name of the opcode. If the opcode is not valid, returns null.</returns> /// <param name="opcode">The opcode.</param> public static string getName(ABCOp opcode) => s_names[(byte)opcode];
/// <summary> /// Gets the <see cref="ABCOpInfo"/> instance for the given opcode. /// </summary> /// <returns>An <see cref="ABCOpInfo"/> instance.</returns> /// <param name="opcode">The opcode.</param> public static ABCOpInfo getInfo(ABCOp opcode) => s_opinfo[(byte)opcode];