/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

// Define default versions of all macros used.
#ifndef DEFINE_OPERAND_TYPE
#define DEFINE_OPERAND_TYPE(...)
#endif
#ifndef DEFINE_OPCODE_0
#define DEFINE_OPCODE_0(name) DEFINE_OPCODE(name)
#endif
#ifndef DEFINE_OPCODE_1
#define DEFINE_OPCODE_1(name, ...) DEFINE_OPCODE(name)
#endif
#ifndef DEFINE_OPCODE_2
#define DEFINE_OPCODE_2(name, ...) DEFINE_OPCODE(name)
#endif
#ifndef DEFINE_OPCODE_3
#define DEFINE_OPCODE_3(name, ...) DEFINE_OPCODE(name)
#endif
#ifndef DEFINE_OPCODE_4
#define DEFINE_OPCODE_4(name, ...) DEFINE_OPCODE(name)
#endif
#ifndef DEFINE_OPCODE_5
#define DEFINE_OPCODE_5(name, ...) DEFINE_OPCODE(name)
#endif
#ifndef DEFINE_OPCODE_6
#define DEFINE_OPCODE_6(name, ...) DEFINE_OPCODE(name)
#endif
#ifndef DEFINE_OPCODE
#define DEFINE_OPCODE(...)
#endif
#ifndef DEFINE_JUMP_LONG_VARIANT
#define DEFINE_JUMP_LONG_VARIANT(...)
#endif
#ifndef DEFINE_RET_TARGET
#define DEFINE_RET_TARGET(...)
#endif
#ifndef ASSERT_EQUAL_LAYOUT1
#define ASSERT_EQUAL_LAYOUT1(a, b)
#endif
#ifndef ASSERT_EQUAL_LAYOUT2
#define ASSERT_EQUAL_LAYOUT2(a, b)
#endif
#ifndef ASSERT_EQUAL_LAYOUT3
#define ASSERT_EQUAL_LAYOUT3(a, b)
#endif
#ifndef ASSERT_EQUAL_LAYOUT4
#define ASSERT_EQUAL_LAYOUT4(a, b)
#endif
#ifndef ASSERT_MONOTONE_INCREASING
#define ASSERT_MONOTONE_INCREASING(first, ...)
#endif
#ifndef OPERAND_BIGINT_ID
#define OPERAND_BIGINT_ID(name, operandNumber)
#endif
#ifndef OPERAND_FUNCTION_ID
#define OPERAND_FUNCTION_ID(name, operandNumber)
#endif
#ifndef OPERAND_STRING_ID
#define OPERAND_STRING_ID(name, operandNumber)
#endif

DEFINE_OPERAND_TYPE(Reg8, uint8_t)
DEFINE_OPERAND_TYPE(Reg32, uint32_t)
DEFINE_OPERAND_TYPE(UInt8, uint8_t)
DEFINE_OPERAND_TYPE(UInt16, uint16_t)
DEFINE_OPERAND_TYPE(UInt32, uint32_t)
DEFINE_OPERAND_TYPE(Addr8, int8_t)
DEFINE_OPERAND_TYPE(Addr32, int32_t)
DEFINE_OPERAND_TYPE(Imm32, int32_t)
DEFINE_OPERAND_TYPE(Double, double)

/// Unreachable opcode for stubs and similar. This is first so that it has the
/// value zero.
DEFINE_OPCODE_0(Unreachable)

/// Create an object from a static map of values, as for var={'a': 3}.
/// Any non-constant elements can be set afterwards with PutOwnByInd.
/// Arg1 is the destination.
/// Arg2 is a preallocation size hint.
/// Arg3 is the number of static elements.
/// Arg4 is the index in the object key buffer table.
/// Arg5 is the index in the object val buffer table.
DEFINE_OPCODE_5(NewObjectWithBuffer, Reg8, UInt16, UInt16, UInt16, UInt16)
DEFINE_OPCODE_5(NewObjectWithBufferLong, Reg8, UInt16, UInt16, UInt32, UInt32)

/// Create a new, empty Object using the built-in constructor (regardless of
/// whether it was overridden).
/// Arg1 = {}
DEFINE_OPCODE_1(NewObject, Reg8)

/// Create a new empty Object with the specified parent. If the parent is
/// null, no parent is used. If the parent is not an object, the builtin
/// Object.prototype is used. Otherwise the parent itself is used.
/// Arg1 = the created object
/// Arg2 = the parent.
DEFINE_OPCODE_2(NewObjectWithParent, Reg8, Reg8)

/// Create an array from a static list of values, as for var=[1,2,3].
/// Any non-constant elements can be set afterwards with PutOwnByIndex.
/// Arg1 is the destination.
/// Arg2 is a preallocation size hint.
/// Arg3 is the number of static elements.
/// Arg4 is the index in the array buffer table.
DEFINE_OPCODE_4(NewArrayWithBuffer, Reg8, UInt16, UInt16, UInt16)
DEFINE_OPCODE_4(NewArrayWithBufferLong, Reg8, UInt16, UInt16, UInt32)

/// Create a new array of a given size.
/// Arg1 = new Array(Arg2)
DEFINE_OPCODE_2(NewArray, Reg8, UInt16)

/// Arg1 = Arg2 (Register copy)
DEFINE_OPCODE_2(Mov, Reg8, Reg8)

/// Arg1 = Arg2 (Register copy, long index)
DEFINE_OPCODE_2(MovLong, Reg32, Reg32)

/// Arg1 = -Arg2 (Unary minus)
DEFINE_OPCODE_2(Negate, Reg8, Reg8)

/// Arg1 = !Arg2 (Boolean not)
DEFINE_OPCODE_2(Not, Reg8, Reg8)

/// Arg1 = ~Arg2 (Bitwise not)
DEFINE_OPCODE_2(BitNot, Reg8, Reg8)

/// Arg1 = typeof Arg2 (JS typeof)
DEFINE_OPCODE_2(TypeOf, Reg8, Reg8)

/// Arg1 = Arg2 == Arg3 (JS equality)
DEFINE_OPCODE_3(Eq, Reg8, Reg8, Reg8)

/// Arg1 = Arg2 === Arg3 (JS strict equality)
DEFINE_OPCODE_3(StrictEq, Reg8, Reg8, Reg8)

/// Arg1 = Arg2 != Arg3 (JS inequality)
DEFINE_OPCODE_3(Neq, Reg8, Reg8, Reg8)

/// Arg1 = Arg2 !== Arg3 (JS strict inequality)
DEFINE_OPCODE_3(StrictNeq, Reg8, Reg8, Reg8)

/// Arg1 = Arg2 < Arg3 (JS less-than)
DEFINE_OPCODE_3(Less, Reg8, Reg8, Reg8)

/// Arg1 = Arg2 <= Arg3 (JS less-than-or-equals)
DEFINE_OPCODE_3(LessEq, Reg8, Reg8, Reg8)

/// Arg1 = Arg2 > Arg3 (JS greater-than)
DEFINE_OPCODE_3(Greater, Reg8, Reg8, Reg8)

/// Arg1 = Arg2 >= Arg3 (JS greater-than-or-equals)
DEFINE_OPCODE_3(GreaterEq, Reg8, Reg8, Reg8)

/// Arg1 = Arg2 + Arg3 (JS addition/concatenation)
DEFINE_OPCODE_3(Add, Reg8, Reg8, Reg8)

/// Arg1 = Arg2 + Arg3 (Numeric addition, skips number check)
DEFINE_OPCODE_3(AddN, Reg8, Reg8, Reg8)

/// Arg1 = Arg2 * Arg3 (JS multiplication)
DEFINE_OPCODE_3(Mul, Reg8, Reg8, Reg8)

/// Arg1 = Arg2 * Arg3 (Numeric multiplication, skips number check)
DEFINE_OPCODE_3(MulN, Reg8, Reg8, Reg8)

/// Arg1 = Arg2 / Arg3 (JS division)
DEFINE_OPCODE_3(Div, Reg8, Reg8, Reg8)

/// Arg1 = Arg2 / Arg3 (Numeric division, skips number check)
DEFINE_OPCODE_3(DivN, Reg8, Reg8, Reg8)

/// Arg1 = Arg2 % Arg3 (JS remainder)
DEFINE_OPCODE_3(Mod, Reg8, Reg8, Reg8)

/// Arg1 = Arg2 - Arg3 (JS subtraction)
DEFINE_OPCODE_3(Sub, Reg8, Reg8, Reg8)

/// Arg1 = Arg2 - Arg3 (Numeric subtraction, skips number check)
DEFINE_OPCODE_3(SubN, Reg8, Reg8, Reg8)

/// Arg1 = Arg2 << Arg3 (JS bitshift left)
DEFINE_OPCODE_3(LShift, Reg8, Reg8, Reg8)

/// Arg1 = Arg2 >> Arg3 (JS signed bitshift right)
DEFINE_OPCODE_3(RShift, Reg8, Reg8, Reg8)

/// Arg1 = Arg2 >>> Arg3 (JS unsigned bitshift right)
DEFINE_OPCODE_3(URshift, Reg8, Reg8, Reg8)

/// Arg1 = Arg2 & Arg3 (JS bitwise AND)
DEFINE_OPCODE_3(BitAnd, Reg8, Reg8, Reg8)

/// Arg1 = Arg2 ^ Arg3 (JS bitwise XOR)
DEFINE_OPCODE_3(BitXor, Reg8, Reg8, Reg8)

/// Arg1 = Arg2 | Arg3 (JS bitwise OR)
DEFINE_OPCODE_3(BitOr, Reg8, Reg8, Reg8)

/// Arg1 = Arg2 + 1 (JS increment, skips number check)
DEFINE_OPCODE_2(Inc, Reg8, Reg8)

/// Arg1 = Arg2 - 1 (JS decrement, skips number check)
DEFINE_OPCODE_2(Dec, Reg8, Reg8)

/// Check whether Arg2 contains Arg3 in its prototype chain.
/// Note that this is not the same as JS instanceof.
/// Pseudocode: Arg1 = prototypechain(Arg2).contains(Arg3)
DEFINE_OPCODE_3(InstanceOf, Reg8, Reg8, Reg8)

/// Arg1 = Arg2 in Arg3 (JS relational 'in')
DEFINE_OPCODE_3(IsIn, Reg8, Reg8, Reg8)

/// Get an environment (scope) from N levels up the stack.
/// 0 is the current environment, 1 is the caller's environment, etc.
DEFINE_OPCODE_2(GetEnvironment, Reg8, UInt8)

/// Store a value in an environment.
/// StoreNPToEnvironment[L] store a non-pointer value in an environment
/// Arg1 is the environment (as fetched by GetEnvironment).
/// Arg2 is the environment index slot number.
/// Arg3 is the value.
DEFINE_OPCODE_3(StoreToEnvironment, Reg8, UInt8, Reg8)
DEFINE_OPCODE_3(StoreToEnvironmentL, Reg8, UInt16, Reg8)
DEFINE_OPCODE_3(StoreNPToEnvironment, Reg8, UInt8, Reg8)
DEFINE_OPCODE_3(StoreNPToEnvironmentL, Reg8, UInt16, Reg8)

/// Load a value from an environment.
/// Arg1 is the destination.
/// Arg2 is the environment (as fetched by GetEnvironment).
/// Arg3 is the environment index slot number.
DEFINE_OPCODE_3(LoadFromEnvironment, Reg8, Reg8, UInt8)
DEFINE_OPCODE_3(LoadFromEnvironmentL, Reg8, Reg8, UInt16)

/// Get the global object (the object in which global variables are stored).
DEFINE_OPCODE_1(GetGlobalObject, Reg8)

/// Obtain the value of NewTarget from the frame.
/// Arg1 = NewTarget
DEFINE_OPCODE_1(GetNewTarget, Reg8)

/// Create a new environment, to store values captured by closures.
DEFINE_OPCODE_1(CreateEnvironment, Reg8)

/// Create a new inner environment, to store values captured by closures.
/// Arg1 is the destination.
/// Arg2 is the parent environment.
/// Arg3 is the number of slots in the environment.
DEFINE_OPCODE_3(CreateInnerEnvironment, Reg8, Reg8, UInt32)

/// Declare a global variable by string table index.
/// The variable will be set to undefined.
DEFINE_OPCODE_1(DeclareGlobalVar, UInt32)
OPERAND_STRING_ID(DeclareGlobalVar, 1)

/// Checks if globalThis has a restricted global property with the given name.
/// Arg1 is the name to check.
DEFINE_OPCODE_1(ThrowIfHasRestrictedGlobalProperty, UInt32)
OPERAND_STRING_ID(ThrowIfHasRestrictedGlobalProperty, 1)

/// Get an object property by string table index.
/// Arg1 = Arg2[stringtable[Arg4]]
/// Arg3 is a cache index used to speed up the above operation.
DEFINE_OPCODE_4(GetByIdShort, Reg8, Reg8, UInt8, UInt8)
DEFINE_OPCODE_4(GetById, Reg8, Reg8, UInt8, UInt16)
DEFINE_OPCODE_4(GetByIdLong, Reg8, Reg8, UInt8, UInt32)
OPERAND_STRING_ID(GetByIdShort, 4)
OPERAND_STRING_ID(GetById, 4)
OPERAND_STRING_ID(GetByIdLong, 4)

/// Get an object property by string table index, or throw if not found.
/// This is similar to GetById, but intended for use with global variables
/// where Arg2 = GetGlobalObject.
DEFINE_OPCODE_4(TryGetById, Reg8, Reg8, UInt8, UInt16)
DEFINE_OPCODE_4(TryGetByIdLong, Reg8, Reg8, UInt8, UInt32)
OPERAND_STRING_ID(TryGetById, 4)
OPERAND_STRING_ID(TryGetByIdLong, 4)

/// Set an object property by string index.
/// Arg1[stringtable[Arg4]] = Arg2.
DEFINE_OPCODE_4(PutById, Reg8, Reg8, UInt8, UInt16)
DEFINE_OPCODE_4(PutByIdLong, Reg8, Reg8, UInt8, UInt32)
OPERAND_STRING_ID(PutById, 4)
OPERAND_STRING_ID(PutByIdLong, 4)

/// Set an object property by string index, or throw if undeclared.
/// This is similar to PutById, but intended for use with global variables
/// where Arg1 = GetGlobalObject.
DEFINE_OPCODE_4(TryPutById, Reg8, Reg8, UInt8, UInt16)
DEFINE_OPCODE_4(TryPutByIdLong, Reg8, Reg8, UInt8, UInt32)
OPERAND_STRING_ID(TryPutById, 4)
OPERAND_STRING_ID(TryPutByIdLong, 4)

/// Create a new own property on an object. This is similar to PutById, but
/// the destination must be an object, it only deals with own properties,
/// ignoring the prototype chain, and the property must not already be defined.
/// Similarly to PutById, the property name cannot be a valid array index.
/// Arg1 is the destination object, which is known to be an object.
/// Arg2 is the value to write.
/// Arg3 is the string table ID of the property name.
/// Arg1[stringtable[Arg3]] = Arg2
DEFINE_OPCODE_3(PutNewOwnByIdShort, Reg8, Reg8, UInt8)
DEFINE_OPCODE_3(PutNewOwnById, Reg8, Reg8, UInt16)
DEFINE_OPCODE_3(PutNewOwnByIdLong, Reg8, Reg8, UInt32)
OPERAND_STRING_ID(PutNewOwnByIdShort, 3)
OPERAND_STRING_ID(PutNewOwnById, 3)
OPERAND_STRING_ID(PutNewOwnByIdLong, 3)

/// Create a new non-enumerable own property on an object. This is the same as
/// PutNewOwnById, but creates the property with different enumerability.
/// Arg1 is the destination object.
/// Arg2 is the value to write.
/// Arg3 is the string table ID of the property name.
/// Arg1[stringtable[Arg3]] = Arg2
DEFINE_OPCODE_3(PutNewOwnNEById, Reg8, Reg8, UInt16)
DEFINE_OPCODE_3(PutNewOwnNEByIdLong, Reg8, Reg8, UInt32)
OPERAND_STRING_ID(PutNewOwnNEById, 3)
OPERAND_STRING_ID(PutNewOwnNEByIdLong, 3)

// The "NE" versions must be ordered after the "normal" versions.
ASSERT_MONOTONE_INCREASING(
    PutNewOwnByIdShort,
    PutNewOwnById,
    PutNewOwnByIdLong,
    PutNewOwnNEById,
    PutNewOwnNEByIdLong)

/// Assign a value to a constant integer own property which will be created as
/// enumerable. This is used (potentially in conjunction with
/// NewArrayWithBuffer) for arr=[foo,bar] initializations.
/// Arg1[Arg3] = Arg2;
DEFINE_OPCODE_3(PutOwnByIndex, Reg8, Reg8, UInt8)
DEFINE_OPCODE_3(PutOwnByIndexL, Reg8, Reg8, UInt32)

/// Set an own property identified by value.
/// Arg1 is the destination object.
/// Arg2 is the value to write.
/// Arg3 is the property name.
/// Arg4 : bool -> enumerable. If true, the property is created as enumerable,
///        non-enumerable otherwise.
/// Arg1[Arg3] = Arg2;
DEFINE_OPCODE_4(PutOwnByVal, Reg8, Reg8, Reg8, UInt8)

/// Delete a property by string table index.
/// Arg1 = delete Arg2[stringtable[Arg3]]
DEFINE_OPCODE_3(DelById, Reg8, Reg8, UInt16)
DEFINE_OPCODE_3(DelByIdLong, Reg8, Reg8, UInt32)
OPERAND_STRING_ID(DelById, 3)
OPERAND_STRING_ID(DelByIdLong, 3)

/// Get a property by value. Constants string values should instead use GetById.
/// Arg1 = Arg2[Arg3]
DEFINE_OPCODE_3(GetByVal, Reg8, Reg8, Reg8)

/// Set a property by value. Constant string values should instead use GetById
/// (unless they are array indices according to ES5.1 section 15.4, in which
/// case this is still the right opcode).
/// Arg1[Arg2] = Arg3
DEFINE_OPCODE_3(PutByVal, Reg8, Reg8, Reg8)

/// Delete a property by value (when the value is not known at compile time).
/// Arg1 = delete Arg2[Arg3]
DEFINE_OPCODE_3(DelByVal, Reg8, Reg8, Reg8)

/// Add a getter and a setter for a property by value.
/// Object.defineProperty(Arg1, Arg2, { get: Arg3, set: Arg4 }).
/// Arg1 is the target object which will have a property defined.
/// Arg2 is the property name
/// Arg3 is the getter closure or undefined
/// Arg4 is the setter closure or undefined
/// Arg5 : boolean - if true, the property will be enumerable.
DEFINE_OPCODE_5(PutOwnGetterSetterByVal, Reg8, Reg8, Reg8, Reg8, UInt8)

/// Get the list of properties from an object to implement for..in loop.
/// Returns Arg1, which is the register that holds array of properties.
/// Returns Undefined if the object is null/undefined.
/// Arg2 is the register that holds the object.
/// Arg3 is the register that holds the iterating index.
/// Arg4 is the register that holds the size of the property list.
DEFINE_OPCODE_4(GetPNameList, Reg8, Reg8, Reg8, Reg8)

/// Get the next property in the for..in iterator.
/// Returns Arg1, which is the next property. Undefined if unavailable.
/// Arg2 is the register that holds array of properties.
/// Arg3 is the register that holds the object.
/// Arg4 is the register that holds the iterating index.
/// Arg5 is the register that holds the size of the property list.
DEFINE_OPCODE_5(GetNextPName, Reg8, Reg8, Reg8, Reg8, Reg8)

///!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
/// NOTE: the ordering of Call, CallN, Construct, CallLong, ConstructLong is
/// important. The "long" versions are defined after the "short" versions.
/// It is important for efficiency that all Calls have contiguous opcodes, with
/// wider instructions appearing after narrower ones.

/// Call a function.
/// Arg1 is the destination of the return value.
/// Arg2 is the closure to invoke.
/// Arg3 is the number of arguments, assumed to be found in reverse order
///      from the end of the current frame.
DEFINE_OPCODE_3(Call, Reg8, Reg8, UInt8)
DEFINE_RET_TARGET(Call)

/// Call a constructor, with semantics identical to Call.
/// Arg1 is the destination of the return value.
/// Arg2 is the closure to invoke.
/// Arg3 is the number of arguments, assumed to be found in reverse order
///      from the end of the current frame. The first argument 'this'
///      is assumed to be created with CreateThis.
DEFINE_OPCODE_3(Construct, Reg8, Reg8, UInt8)
DEFINE_RET_TARGET(Construct)

/// Call a function with one arg.
/// Arg1 is the destination of the return value.
/// Arg2 is the closure to invoke.
/// Arg3 is the first argument.
DEFINE_OPCODE_3(Call1, Reg8, Reg8, Reg8)
DEFINE_RET_TARGET(Call1)

/// Call a function directly without a closure.
/// Arg1 is the destination of the return value.
/// Arg2 is the number of arguments, assumed to be found in reverse order
///      from the end of the current frame. The first argument 'this'
///      is assumed to be created with CreateThis.
/// Arg3 is index in the function table.
/// Note that we expect the variable-sized argument to be last.
DEFINE_OPCODE_3(CallDirect, Reg8, UInt8, UInt16)
OPERAND_FUNCTION_ID(CallDirect, 3)
DEFINE_RET_TARGET(CallDirect)

/// Call a function with two args.
/// Arg1 is the destination of the return value.
/// Arg2 is the closure to invoke.
/// Arg3 is the first argument.
/// Arg4 is the second argument.
DEFINE_OPCODE_4(Call2, Reg8, Reg8, Reg8, Reg8)
DEFINE_RET_TARGET(Call2)

/// Call a function with three args.
/// Arg1 is the destination of the return value.
/// Arg2 is the closure to invoke.
/// Arg3 is the first argument.
/// Arg4 is the second argument.
/// Arg5 is the third argument.
DEFINE_OPCODE_5(Call3, Reg8, Reg8, Reg8, Reg8, Reg8)
DEFINE_RET_TARGET(Call3)

/// Call a function with four args.
/// Arg1 is the destination of the return value.
/// Arg2 is the closure to invoke.
/// Arg3 is the first argument.
/// Arg4 is the second argument.
/// Arg5 is the third argument.
/// Arg6 is the fourth argument.
DEFINE_OPCODE_6(Call4, Reg8, Reg8, Reg8, Reg8, Reg8, Reg8)
DEFINE_RET_TARGET(Call4)

/// Identical to Call, but allowing more arguments.
DEFINE_OPCODE_3(CallLong, Reg8, Reg8, UInt32)
DEFINE_RET_TARGET(CallLong)

/// Identical to Construct, but allowing more arguments.
DEFINE_OPCODE_3(ConstructLong, Reg8, Reg8, UInt32)
DEFINE_RET_TARGET(ConstructLong)

/// Identical to CallDirect, but the function index is 32-bit.
DEFINE_OPCODE_3(CallDirectLongIndex, Reg8, UInt8, UInt32)
DEFINE_RET_TARGET(CallDirectLongIndex)

// Enforce the order.
ASSERT_MONOTONE_INCREASING(
    Call,
    Construct,
    Call1,
    CallDirect,
    Call2,
    Call3,
    Call4,
    CallLong,
    ConstructLong,
    CallDirectLongIndex)

/// Call a builtin function.
/// Note this is NOT marked as a Ret target, because the callee is native
/// and therefore never JS.
/// Arg1 is the destination of the return value.
/// Arg2 is the builtin number.
/// Arg3 is the number of arguments, assumed to be found in reverse order
///      from the end of the current frame.
/// thisArg is set to "undefined".
DEFINE_OPCODE_3(CallBuiltin, Reg8, UInt8, UInt8)

/// Call a builtin function.
/// Note this is NOT marked as a Ret target, because the callee is native
/// and therefore never JS.
/// Arg1 is the destination of the return value.
/// Arg2 is the builtin number.
/// Arg3 is the number of arguments, assumed to be found in reverse order
///      from the end of the current frame.
/// thisArg is set to "undefined".
DEFINE_OPCODE_3(CallBuiltinLong, Reg8, UInt8, UInt32)

/// Get a closure from a builtin function.
/// Arg1 is the destination of the return value.
/// Arg2 is the builtin number.
DEFINE_OPCODE_2(GetBuiltinClosure, Reg8, UInt8)

///
///!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

/// Return a value from the current function.
/// return Arg1;
DEFINE_OPCODE_1(Ret, Reg8)

/// Catch an exception (the first instruction in an exception handler).
/// } catch(Arg1) {
DEFINE_OPCODE_1(Catch, Reg8)

/// ES6 18.2.1.1 PerformEval(Arg2, evalRealm, strictCaller=true, direct=true)
/// Arg1 is the destination of the return value.
/// Arg2 is the value to eval.
/// Arg3 is a boolean which is true if the eval should be performed in strict mode.
DEFINE_OPCODE_3(DirectEval, Reg8, Reg8, UInt8)

/// Throw an exception.
/// throw Arg1;
DEFINE_OPCODE_1(Throw, Reg8)

/// If Arg2 is Empty, throw ReferenceError, otherwise move it into Arg1.
/// Arg1 is the destination of the return value
/// Arg2 is the value to check
DEFINE_OPCODE_2(ThrowIfEmpty, Reg8, Reg8)

/// Implementation dependent debugger action.
DEFINE_OPCODE_0(Debugger)

/// Fast check for an async interrupt request.
DEFINE_OPCODE_0(AsyncBreakCheck)

/// Define a profile point.
/// Arg1 is the function local profile point index. The first one will have the
/// largest index. If there are more than 2^16 profile points in the function,
/// all the overflowed profile points have index zero.
DEFINE_OPCODE_1(ProfilePoint, UInt16)

/// Create a closure.
/// Arg1 is the register in which to store the closure.
/// Arg2 is the current environment as loaded by GetEnvironment 0.
/// Arg3 is index in the function table.
DEFINE_OPCODE_3(CreateClosure, Reg8, Reg8, UInt16)
DEFINE_OPCODE_3(CreateClosureLongIndex, Reg8, Reg8, UInt32)
OPERAND_FUNCTION_ID(CreateClosure, 3)
OPERAND_FUNCTION_ID(CreateClosureLongIndex, 3)

/// Create a closure for a GeneratorFunction.
/// Arg1 is the register in which to store the closure.
/// Arg2 is the current environment as loaded by GetEnvironment 0.
/// Arg3 is index in the function table.
DEFINE_OPCODE_3(CreateGeneratorClosure, Reg8, Reg8, UInt16)
DEFINE_OPCODE_3(CreateGeneratorClosureLongIndex, Reg8, Reg8, UInt32)
OPERAND_FUNCTION_ID(CreateGeneratorClosure, 3)
OPERAND_FUNCTION_ID(CreateGeneratorClosureLongIndex, 3)

/// Create a closure for an AsyncFunction.
/// Arg1 is the register in which to store the closure.
/// Arg2 is the current environment as loaded by GetEnvironment 0.
/// Arg3 is index in the function table.
DEFINE_OPCODE_3(CreateAsyncClosure, Reg8, Reg8, UInt16)
DEFINE_OPCODE_3(CreateAsyncClosureLongIndex, Reg8, Reg8, UInt32)
OPERAND_FUNCTION_ID(CreateAsyncClosure, 3)
OPERAND_FUNCTION_ID(CreateAsyncClosureLongIndex, 3)

/// Allocate an empty, uninitialized object (immediately before a constructor).
/// Arg1 is the destination register.
/// Arg2 is the prototype to assign it.
/// Arg3 is the constructor closure that will be used*.
/// * To allow internal constructors to have special objects allocated.
DEFINE_OPCODE_3(CreateThis, Reg8, Reg8, Reg8)

/// Choose the result of a constructor: 'this' or a returned object.
/// Arg1 is the result.
/// Arg2 is the 'this' object used for the constructor.
/// Arg3 is the constructor's return value.
/// Arg1 = Arg3 instanceof Object ? Arg3 : Arg2
DEFINE_OPCODE_3(SelectObject, Reg8, Reg8, Reg8)

/// Load a function parameter by index. Starts at 0 with 'this'.
/// Arg1 = Arg2 == 0 ? this : arguments[Arg2 - 1];
DEFINE_OPCODE_2(LoadParam, Reg8, UInt8)

/// Like LoadParam, but allows accessing arguments >= 255.
DEFINE_OPCODE_2(LoadParamLong, Reg8, UInt32)

/// Load a constant integer value.
DEFINE_OPCODE_2(LoadConstUInt8, Reg8, UInt8)
DEFINE_OPCODE_2(LoadConstInt, Reg8, Imm32)

/// Load a constant double value.
DEFINE_OPCODE_2(LoadConstDouble, Reg8, Double)

/// Load a constant BigInt value by bigint table index.
DEFINE_OPCODE_2(LoadConstBigInt, Reg8, UInt16)
DEFINE_OPCODE_2(LoadConstBigIntLongIndex, Reg8, UInt32)
OPERAND_BIGINT_ID(LoadConstBigInt, 2)
OPERAND_BIGINT_ID(LoadConstBigIntLongIndex, 2)

/// Load a constant string value by string table index.
DEFINE_OPCODE_2(LoadConstString, Reg8, UInt16)
DEFINE_OPCODE_2(LoadConstStringLongIndex, Reg8, UInt32)
OPERAND_STRING_ID(LoadConstString, 2)
OPERAND_STRING_ID(LoadConstStringLongIndex, 2)

/// Load common constants.
DEFINE_OPCODE_1(LoadConstEmpty, Reg8)
DEFINE_OPCODE_1(LoadConstUndefined, Reg8)
DEFINE_OPCODE_1(LoadConstNull, Reg8)
DEFINE_OPCODE_1(LoadConstTrue, Reg8)
DEFINE_OPCODE_1(LoadConstFalse, Reg8)
DEFINE_OPCODE_1(LoadConstZero, Reg8)

/// Coerce a value assumed to contain 'this' to an object using non-strict
/// mode rules. Primitives are boxed, \c null or \c undefed produce the global
/// object.
/// Arg1 = coerce_to_object(Arg2)
DEFINE_OPCODE_2(CoerceThisNS, Reg8, Reg8)

/// Obtain the raw \c this value and coerce it to an object. Equivalent to:
/// \code
///     LoadParam    Arg1, #0
///     CoerceThisNS Arg1, Arg1
/// \endcode
DEFINE_OPCODE_1(LoadThisNS, Reg8)

/// Convert a value to a number.
/// Arg1 = Arg2 - 0
DEFINE_OPCODE_2(ToNumber, Reg8, Reg8)
/// Convert a value to a numberic.
/// Arg1 = ToNumeric(Arg2)
DEFINE_OPCODE_2(ToNumeric, Reg8, Reg8)
/// Convert a value to a 32-bit signed integer.
/// Arg1 = Arg2 | 0
DEFINE_OPCODE_2(ToInt32, Reg8, Reg8)

/// Convert a value to a string as if evaluating the expression:
///     Arg1 = "" + Arg2
/// In practice this means
///     Arg1 = ToString(ToPrimitive(Arg2, PreferredType::NONE))
/// with ToPrimitive (ES5.1 9.1) and ToString (ES5.1 9.8).
DEFINE_OPCODE_2(AddEmptyString, Reg8, Reg8)

// `arguments` opcodes all work with a lazy register that contains either
// undefined or a reified array. On the first ReifyArguments, the register
// will be populated and the rest of the instruction will access it directly.
// This is an optimization to allow arguments[i] to just load an argument
// instead of doing a full array allocation and property lookup.

/// Get a property of the 'arguments' array by value.
/// Arg1 is the result.
/// Arg2 is the index.
/// Arg3 is the lazy loaded register.
/// Arg1 = arguments[Arg2]
DEFINE_OPCODE_3(GetArgumentsPropByVal, Reg8, Reg8, Reg8)

/// Get the length of the 'arguments' array.
/// Arg1 is the result.
/// Arg2 is the lazy loaded register.
/// Arg1 = arguments.length
DEFINE_OPCODE_2(GetArgumentsLength, Reg8, Reg8)

/// Create an actual 'arguments' array, if get-by-index and length isn't enough.
/// Arg1 is the lazy loaded register, which afterwards will contain a proper
///      object that can be used by non-*Arguments* opcodes like Return.
DEFINE_OPCODE_1(ReifyArguments, Reg8)

/// Create a regular expression.
/// Arg1 is the result.
/// Arg2 is the string index of the pattern.
/// Arg3 is the string index of the flags.
/// Arg4 is the regexp bytecode index in the regexp table.
DEFINE_OPCODE_4(CreateRegExp, Reg8, UInt32, UInt32, UInt32)
OPERAND_STRING_ID(CreateRegExp, 2)
OPERAND_STRING_ID(CreateRegExp, 3)

/// Jump table switch - using a table of offset, jump to the offset of the given
/// input or to the default block if out of range (or not right type)
/// Arg 1 is the value to be branched upon
/// Arg 2 is the relative offset of the jump table to be used by this
/// instruction. Jump tables are appended to the bytecode. Arg 3 is the relative
/// offset for the "default" jump. Arg 4 is the unsigned min value, if arg 1 is
/// less than this value jmp to
///   default block
/// Arg 5 is the unsigned max value, if arg 1 is greater than this value jmp to
///   default block.
///
/// Given the above, the jump table entry for a given value (that is in range)
/// is located at offset ip + arg2 + arg1 - arg4. We subtract arg4 to avoid
/// wasting space when compiling denses switches that do not start at zero. Note
/// that Arg2 is *unaligned* it is dynamically aligned at runtime.
DEFINE_OPCODE_5(SwitchImm, Reg8, UInt32, Addr32, UInt32, UInt32)

/// Start the generator by jumping to the next instruction to begin.
/// Restore the stack frame if this generator has previously been suspended.
DEFINE_OPCODE_0(StartGenerator)

/// Resume generator by performing one of the following user-requested actions:
/// - next(val): Set Arg1 to val, Arg2 to false, run next instruction
/// - return(val): Set Arg1 to val, Arg2 to true, run next instruction
/// - throw(val): Throw val as an error
/// Arg1 is the result provided by the user.
/// Arg2 is a boolean which is true if the user requested a return().
DEFINE_OPCODE_2(ResumeGenerator, Reg8, Reg8)

/// Set the generator status to complete, but do not return.
DEFINE_OPCODE_0(CompleteGenerator)

/// Create a generator.
/// Arg1 is the register in which to store the generator.
/// Arg2 is the current environment as loaded by GetEnvironment 0.
/// Arg3 is index in the function table.
DEFINE_OPCODE_3(CreateGenerator, Reg8, Reg8, UInt16)
DEFINE_OPCODE_3(CreateGeneratorLongIndex, Reg8, Reg8, UInt32)
OPERAND_FUNCTION_ID(CreateGenerator, 3)
OPERAND_FUNCTION_ID(CreateGeneratorLongIndex, 3)

/// Arg1 [out] is the result iterator or index.
/// Arg2 [in/out] is the source. Output for either the source or next method.
/// If source is an array with an unmodified [Symbol.iterator], the result is
/// 0. Else the result is source[Symbol.iterator] and the output is the .next()
/// method on the iterator.
/// See IR.md for IteratorBeginInst.
DEFINE_OPCODE_2(IteratorBegin, Reg8, Reg8)

/// Arg1 [out] is the result, or undefined if done.
/// Arg2 [in/out] is the iterator or index.
/// Arg2 [in] is the source or the next method.
/// If iterator is undefined, result = undefined.
/// If iterator is a number:
///   If iterator is less than source.length, return source[iterator++]
///   Else iterator = undefined and result = undefined
/// Else:
///   n = iterator.next()
///   If n.done, iterator = undefined and result = undefined.
///   Else result = n.value
/// See IR.md for IteratorNextInst.
DEFINE_OPCODE_3(IteratorNext, Reg8, Reg8, Reg8)

/// Arg1 [in] is the iterator or array index.
/// Arg2 is a bool indicating whether to ignore the inner exception.
/// If the iterator is an object, call iterator.return().
/// If Arg2 is true, ignore exceptions which are thrown by iterator.return().
/// See IR.md for IteratorCloseInst.
DEFINE_OPCODE_2(IteratorClose, Reg8, UInt8)

// Jump instructions must be defined through the following DEFINE_JUMP macros.
// The numeric suffix indicates number of operands the instruction takes.
// The macros will automatically generate two opcodes for each definition,
// one short jump that takes Addr8 as target and one long jump that takes
// Addr32 as target. The address is relative to the offset of the instruction.
#define DEFINE_JUMP_1(name)           \
  DEFINE_OPCODE_1(name, Addr8)        \
  DEFINE_OPCODE_1(name##Long, Addr32) \
  DEFINE_JUMP_LONG_VARIANT(name, name##Long)

#define DEFINE_JUMP_2(name)                 \
  DEFINE_OPCODE_2(name, Addr8, Reg8)        \
  DEFINE_OPCODE_2(name##Long, Addr32, Reg8) \
  DEFINE_JUMP_LONG_VARIANT(name, name##Long)

#define DEFINE_JUMP_3(name)                       \
  DEFINE_OPCODE_3(name, Addr8, Reg8, Reg8)        \
  DEFINE_OPCODE_3(name##Long, Addr32, Reg8, Reg8) \
  DEFINE_JUMP_LONG_VARIANT(name, name##Long)

/// Unconditional branch to Arg1.
DEFINE_JUMP_1(Jmp)
/// Conditional branches to Arg1 based on Arg2.
DEFINE_JUMP_2(JmpTrue)
DEFINE_JUMP_2(JmpFalse)
/// Jump if the value is undefined.
DEFINE_JUMP_2(JmpUndefined)
/// Save the provided value, yield, and signal the VM to restart execution
/// at the provided target.
DEFINE_JUMP_1(SaveGenerator)

/// Conditional branches to Arg1 based on Arg2 and Arg3.
/// The *N branches assume numbers and are illegal for other types.

/// Not conditionals are required for NaN comparisons
/// Since we want to be able to reorder targets to allow for fall-throughs,
/// we need to be able to say "jump when not less than to BB2" instead of
/// "jump when less than to BB1".
/// Since NaN comparisons always return false, "not less" != "greater or equal"
DEFINE_JUMP_3(JLess)
DEFINE_JUMP_3(JNotLess)
DEFINE_JUMP_3(JLessN)
DEFINE_JUMP_3(JNotLessN)
DEFINE_JUMP_3(JLessEqual)
DEFINE_JUMP_3(JNotLessEqual)
DEFINE_JUMP_3(JLessEqualN)
DEFINE_JUMP_3(JNotLessEqualN)
DEFINE_JUMP_3(JGreater)
DEFINE_JUMP_3(JNotGreater)
DEFINE_JUMP_3(JGreaterN)
DEFINE_JUMP_3(JNotGreaterN)
DEFINE_JUMP_3(JGreaterEqual)
DEFINE_JUMP_3(JNotGreaterEqual)
DEFINE_JUMP_3(JGreaterEqualN)
DEFINE_JUMP_3(JNotGreaterEqualN)
DEFINE_JUMP_3(JEqual)
DEFINE_JUMP_3(JNotEqual)
DEFINE_JUMP_3(JStrictEqual)
DEFINE_JUMP_3(JStrictNotEqual)

#ifdef HERMES_RUN_WASM
/// Arg1 = Arg2 + Arg3 (32-bit integer addition)
DEFINE_OPCODE_3(Add32, Reg8, Reg8, Reg8)
/// Arg1 = Arg2 - Arg3 (32-bit integer subtraction)
DEFINE_OPCODE_3(Sub32, Reg8, Reg8, Reg8)
/// Arg1 = Arg2 * Arg3 (32-bit integer multiplication)
DEFINE_OPCODE_3(Mul32, Reg8, Reg8, Reg8)
/// Arg1 = Arg2 / Arg3 (32-bit signed integer division)
DEFINE_OPCODE_3(Divi32, Reg8, Reg8, Reg8)
/// Arg1 = Arg2 / Arg3 (32-bit unsigned integer division)
DEFINE_OPCODE_3(Divu32, Reg8, Reg8, Reg8)

/// Arg1 = HEAP8[Arg3] (load signed 8-bit integer)
DEFINE_OPCODE_3(Loadi8, Reg8, Reg8, Reg8)
/// Arg1 = HEAPU8[Arg3] (load unsigned 8-bit integer)
DEFINE_OPCODE_3(Loadu8, Reg8, Reg8, Reg8)
/// Arg1 = HEAP16[Arg3 >> 1] (load signed 16-bit integer)
DEFINE_OPCODE_3(Loadi16, Reg8, Reg8, Reg8)
/// Arg1 = HEAPU16[Arg3 >> 1] (load unsigned 16-bit integer)
DEFINE_OPCODE_3(Loadu16, Reg8, Reg8, Reg8)
/// Arg1 = HEAP32[Arg3 >> 2] (load signed 32-bit integer)
DEFINE_OPCODE_3(Loadi32, Reg8, Reg8, Reg8)
/// Arg1 = HEAPU32[Arg3 >> 2] (load unsigned 32-bit integer)
DEFINE_OPCODE_3(Loadu32, Reg8, Reg8, Reg8)

/// HEAP8[Arg2] = Arg3 (store signed or unsigned 8-bit integer)
DEFINE_OPCODE_3(Store8, Reg8, Reg8, Reg8)
/// HEAP16[Arg2] = Arg3 (store signed or unsigned 16-bit integer)
DEFINE_OPCODE_3(Store16, Reg8, Reg8, Reg8)
/// HEAP32[Arg2] = Arg3 (store signed or unsigned 32-bit integer)
DEFINE_OPCODE_3(Store32, Reg8, Reg8, Reg8)
#endif

// Implementations can rely on the following pairs of instructions having the
// same number and type of operands.
ASSERT_EQUAL_LAYOUT3(Call, Construct)
ASSERT_EQUAL_LAYOUT4(GetById, TryGetById)
ASSERT_EQUAL_LAYOUT4(PutById, TryPutById)
ASSERT_EQUAL_LAYOUT3(PutNewOwnById, PutNewOwnNEById)
ASSERT_EQUAL_LAYOUT3(PutNewOwnByIdLong, PutNewOwnNEByIdLong)
ASSERT_EQUAL_LAYOUT3(Add, AddN)
ASSERT_EQUAL_LAYOUT3(Sub, SubN)
ASSERT_EQUAL_LAYOUT3(Mul, MulN)

// Call and CallLong must agree on the first 2 parameters.
ASSERT_EQUAL_LAYOUT2(Call, CallLong)
ASSERT_EQUAL_LAYOUT2(Construct, ConstructLong)

#undef DEFINE_JUMP_1
#undef DEFINE_JUMP_2
#undef DEFINE_JUMP_3

// Undefine all macros used to avoid confusing next include.
#undef DEFINE_OPERAND_TYPE
#undef DEFINE_OPCODE_0
#undef DEFINE_OPCODE_1
#undef DEFINE_OPCODE_2
#undef DEFINE_OPCODE_3
#undef DEFINE_OPCODE_4
#undef DEFINE_OPCODE_5
#undef DEFINE_OPCODE_6
#undef DEFINE_OPCODE
#undef DEFINE_JUMP_LONG_VARIANT
#undef DEFINE_RET_TARGET
#undef ASSERT_EQUAL_LAYOUT1
#undef ASSERT_EQUAL_LAYOUT2
#undef ASSERT_EQUAL_LAYOUT3
#undef ASSERT_EQUAL_LAYOUT4
#undef ASSERT_MONOTONE_INCREASING
#undef OPERAND_BIGINT_ID
#undef OPERAND_FUNCTION_ID
#undef OPERAND_STRING_ID