BytecodeList.rb   [plain text]


# Copyright (C) 2018-2019 Apple Inc. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
#    notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
#    notice, this list of conditions and the following disclaimer in the
#    documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
# OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

types [
    :VirtualRegister,

    :BasicBlockLocation,
    :BoundLabel,
    :DebugHookType,
    :ECMAMode,
    :ErrorTypeWithExtension,
    :GetByIdMode,
    :GetByIdModeMetadata,
    :GetByValHistory,
    :GetPutInfo,
    :IndexingType,
    :IterationModeMetadata,
    :JSCell,
    :JSGlobalLexicalEnvironment,
    :JSGlobalObject,
    :JSModuleEnvironment,
    :JSObject,
    :JSScope,
    :JSType,
    :JSValue,
    :LLIntCallLinkInfo,
    :ResultType,
    :OperandTypes,
    :ProfileTypeBytecodeFlag,
    :PropertyOffset,
    :PutByIdFlags,
    :PutByValFlags,
    :ResolveType,
    :Structure,
    :StructureID,
    :StructureChain,
    :SymbolTable,
    :SymbolTableOrScopeDepth,
    :ToThisStatus,
    :TypeLocation,
    :WasmBoundLabel,
    :WatchpointSet,

    :ValueProfile,
    :ValueProfileAndVirtualRegisterBuffer,
    :UnaryArithProfile,
    :BinaryArithProfile,
    :ArrayProfile,
    :ArrayAllocationProfile,
    :ObjectAllocationProfile,
]

templates [
    :WriteBarrier,
    :WriteBarrierBase,
]


begin_section :Bytecode,
    emit_in_h_file: true,
    emit_in_structs_file: true,
    emit_in_asm_file: true,
    emit_opcode_id_string_values_in_h_file: true,
    macro_name_component: :BYTECODE,
    asm_prefix: "llint_",
    op_prefix: "op_"

op :wide16
op :wide32

op :enter

op :get_scope,
    args: {
        dst: VirtualRegister
    }

op :create_direct_arguments,
    args: {
        dst: VirtualRegister,
    }

op :create_scoped_arguments,
    args: {
        dst: VirtualRegister,
        scope: VirtualRegister,
    }

op :create_cloned_arguments,
    args: {
        dst: VirtualRegister,
    }

op :create_arguments_butterfly,
    args: {
        dst: VirtualRegister,
    }

op :create_this,
    args: {
        dst: VirtualRegister,
        callee: VirtualRegister,
        inlineCapacity: unsigned,
    },
    metadata: {
        cachedCallee: WriteBarrier[JSCell]
    }

op :create_promise,
    args: {
        dst: VirtualRegister,
        callee: VirtualRegister,
        isInternalPromise: bool,
    },
    metadata: {
        cachedCallee: WriteBarrier[JSCell]
    }

op :new_promise,
    args: {
        dst: VirtualRegister,
        isInternalPromise: bool,
    }

op :new_generator,
    args: {
        dst: VirtualRegister,
    }

op_group :CreateInternalFieldObjectOp,
    [
        :create_generator,
        :create_async_generator,
    ],
    args: {
        dst: VirtualRegister,
        callee: VirtualRegister,
    },
    metadata: {
        cachedCallee: WriteBarrier[JSCell]
    }

op :get_argument,
    args: {
        dst: VirtualRegister,
        index: int,
    },
    metadata: {
        profile: ValueProfile,
    }

op :argument_count,
    args: {
        dst: VirtualRegister,
    }

op :to_this,
    args: {
        srcDst: VirtualRegister,
        ecmaMode: ECMAMode,
    },
    metadata: {
        cachedStructureID: StructureID,
        toThisStatus: ToThisStatus,
        profile: ValueProfile,
    }

op :check_tdz,
    args: {
        targetVirtualRegister: VirtualRegister,
    }

op :new_object,
    args: {
        dst: VirtualRegister,
        inlineCapacity: unsigned,
    },
    metadata: {
        objectAllocationProfile: ObjectAllocationProfile,
    }

op :new_array,
    args: {
        dst: VirtualRegister,
        argv: VirtualRegister,
        argc: unsigned,
        recommendedIndexingType: IndexingType,
    },
    metadata: {
        arrayAllocationProfile: ArrayAllocationProfile,
    }

op :new_array_with_size,
    args: {
        dst: VirtualRegister,
        length: VirtualRegister,
    },
    metadata: {
        arrayAllocationProfile: ArrayAllocationProfile,
    }

op :new_array_buffer,
    args: {
        dst: VirtualRegister,
        immutableButterfly: VirtualRegister,
        recommendedIndexingType: IndexingType
    },
    metadata: {
        arrayAllocationProfile: ArrayAllocationProfile,
    }

op :new_array_with_spread,
    args: {
        dst: VirtualRegister,
        argv: VirtualRegister,
        argc: unsigned,
        bitVector: unsigned,
    }

op :spread,
    args: {
        dst: VirtualRegister,
        argument: VirtualRegister,
    }

op :new_regexp,
    args: {
        dst: VirtualRegister,
        regexp: VirtualRegister,
    }

op :mov,
    args: {
        dst: VirtualRegister,
        src: VirtualRegister,
    }

op_group :BinaryOp,
    [
        :eq,
        :neq,
        :stricteq,
        :nstricteq,
        :less,
        :lesseq,
        :greater,
        :greatereq,
        :below,
        :beloweq,
        :mod,
        :pow,
        :urshift,
    ],
    args: {
        dst: VirtualRegister,
        lhs: VirtualRegister,
        rhs: VirtualRegister,
    }

op_group :ProfiledBinaryOp,
    [
        :add,
        :mul,
        :div,
        :sub,
    ],
    args: {
        dst: VirtualRegister,
        lhs: VirtualRegister,
        rhs: VirtualRegister,
        operandTypes: OperandTypes,
    },
    metadata: {
        arithProfile: BinaryArithProfile
    }

op_group :ValueProfiledBinaryOp,
    [
        :bitand,
        :bitor,
        :bitxor,
        :lshift,
        :rshift,
    ],
    args: {
        dst: VirtualRegister,
        lhs: VirtualRegister,
        rhs: VirtualRegister,
    },
    metadata: {
        profile: ValueProfile
    }

op :bitnot,
    args: {
        dst: VirtualRegister,
        operand: VirtualRegister,
    },
    metadata: {
        profile: ValueProfile
    }

op_group :UnaryOp,
    [
        :eq_null,
        :neq_null,
        :to_string,
        :unsigned,
        :is_empty,
        :typeof_is_undefined,
        :typeof_is_object,
        :typeof_is_function,
        :is_undefined_or_null,
        :is_boolean,
        :is_number,
        :is_big_int,
        :is_object,
        :is_callable,
        :is_constructor,
    ],
    args: {
        dst: VirtualRegister,
        operand: VirtualRegister,
    }

op_group :UnaryInPlaceProfiledOp,
    [
        :inc,
        :dec,
    ],
    args: {
        srcDst: VirtualRegister,
    },
    metadata: {
        arithProfile: UnaryArithProfile
    }

op :to_object,
    args: {
        dst: VirtualRegister,
        operand: VirtualRegister,
        message: unsigned,
    },
    metadata: {
        profile: ValueProfile,
    }

op_group :ValueProfiledUnaryOp,
    [
        :to_number,
        :to_numeric,
    ],
    args: {
        dst: VirtualRegister,
        operand: VirtualRegister,
    },
    metadata: {
        profile: ValueProfile,
    }

op :negate,
    args: {
        dst: VirtualRegister,
        operand: VirtualRegister,
        resultType: ResultType,
    },
    metadata: {
        arithProfile: UnaryArithProfile,
    }

op :not,
    args: {
        dst: VirtualRegister,
        operand: VirtualRegister,
    }


op :identity_with_profile,
    args: {
        srcDst: VirtualRegister,
        topProfile: unsigned,
        bottomProfile: unsigned,
    }

op :overrides_has_instance,
    args: {
        dst: VirtualRegister,
        constructor: VirtualRegister,
        hasInstanceValue: VirtualRegister,
    }

op :instanceof,
    args: {
        dst: VirtualRegister,
        value: VirtualRegister,
        prototype: VirtualRegister,
    }

op :instanceof_custom,
    args: {
        dst: VirtualRegister,
        value: VirtualRegister,
        constructor: VirtualRegister,
        hasInstanceValue: VirtualRegister,
    }

op :typeof,
    args: {
        dst: VirtualRegister,
        value: VirtualRegister,
    }

op :is_cell_with_type,
    args: {
        dst: VirtualRegister,
        operand: VirtualRegister,
        type: JSType,
    }

op :in_by_val,
    args: {
        dst: VirtualRegister,
        base: VirtualRegister,
        property: VirtualRegister,
    },
    metadata: {
        arrayProfile: ArrayProfile,
    }

op :in_by_id,
    args: {
        dst: VirtualRegister,
        base: VirtualRegister,
        property: unsigned,
    }

op :get_by_id,
    args: {
        dst: VirtualRegister,
        base: VirtualRegister,
        property: unsigned,
    },
    metadata: {
        modeMetadata: GetByIdModeMetadata,
        profile: ValueProfile,
    }

op :get_by_id_with_this,
    args: {
        dst: VirtualRegister,
        base: VirtualRegister,
        thisValue: VirtualRegister,
        property: unsigned,
    },
    metadata: {
        profile: ValueProfile,
    }

op :get_by_val_with_this,
    args: {
        dst: VirtualRegister,
        base: VirtualRegister,
        thisValue: VirtualRegister,
        property: VirtualRegister,
    },
    metadata: {
        profile: ValueProfile,
    }

op :get_by_id_direct,
    args: {
        dst: VirtualRegister,
        base: VirtualRegister,
        property: unsigned,
    },
    metadata: {
        profile: ValueProfile, # not used in llint
        structureID: StructureID,
        offset: unsigned,
    }

op :get_prototype_of,
    args: {
        dst: VirtualRegister,
        value: VirtualRegister,
    },
    metadata: {
        profile: ValueProfile,
    }

op :try_get_by_id,
    args: {
        dst: VirtualRegister,
        base: VirtualRegister,
        property: unsigned,
    },
    metadata: {
        profile: ValueProfile,
    }

op :put_by_id,
    args: {
        base: VirtualRegister,
        property: unsigned,
        value: VirtualRegister,
        flags: PutByIdFlags,
    },
    metadata: {
        oldStructureID: StructureID,
        offset: unsigned,
        newStructureID: StructureID,
        structureChain: WriteBarrierBase[StructureChain],
    }

op :put_by_id_with_this,
    args: {
        base: VirtualRegister,
        thisValue: VirtualRegister,
        property: unsigned,
        value: VirtualRegister,
        ecmaMode: ECMAMode,
    }

op :del_by_id,
    args: {
        dst: VirtualRegister,
        base: VirtualRegister,
        property: unsigned,
        ecmaMode: ECMAMode,
    }

op :get_by_val,
    args: {
        dst: VirtualRegister,
        base: VirtualRegister,
        property: VirtualRegister,
    },
    metadata: {
        profile: ValueProfile,
        arrayProfile: ArrayProfile,
        seenIdentifiers: GetByValHistory,
    }

op :get_private_name,
    args: {
        dst: VirtualRegister,
        base: VirtualRegister,
        property: VirtualRegister,
    },
    metadata: {
        profile: ValueProfile,
        structureID: StructureID,
        offset: unsigned,
        property: WriteBarrier[JSCell],
    }

op :put_by_val,
    args: {
        base: VirtualRegister,
        property: VirtualRegister,
        value: VirtualRegister,
        ecmaMode: ECMAMode,
    },
    metadata: {
        arrayProfile: ArrayProfile,
    }

op :put_by_val_with_this,
    args: {
        base: VirtualRegister,
        thisValue: VirtualRegister,
        property: VirtualRegister,
        value: VirtualRegister,
        ecmaMode: ECMAMode,
    }

op :put_by_val_direct,
    args: {
        base: VirtualRegister,
        property: VirtualRegister,
        value: VirtualRegister,
        flags: PutByValFlags,
    },
    metadata: {
        arrayProfile: ArrayProfile,
    }

op :del_by_val,
    args: {
        dst: VirtualRegister,
        base: VirtualRegister,
        property: VirtualRegister,
        ecmaMode: ECMAMode,
    }

op :put_getter_by_id,
    args: {
        base: VirtualRegister,
        property: unsigned,
        attributes: unsigned,
        accessor: VirtualRegister,
    }

op :put_setter_by_id,
    args: {
        base: VirtualRegister,
        property: unsigned,
        attributes: unsigned,
        accessor: VirtualRegister,
    }

op :put_getter_setter_by_id,
    args: {
        base: VirtualRegister,
        property: unsigned,
        attributes: unsigned,
        getter: VirtualRegister,
        setter: VirtualRegister,
    }

op :put_getter_by_val,
    args: {
        base: VirtualRegister,
        property: VirtualRegister,
        attributes: unsigned,
        accessor: VirtualRegister,
    }

op :put_setter_by_val,
    args: {
        base: VirtualRegister,
        property: VirtualRegister,
        attributes: unsigned,
        accessor: VirtualRegister,
    }

op :define_data_property,
    args: {
        base: VirtualRegister,
        property: VirtualRegister,
        value: VirtualRegister,
        attributes: VirtualRegister,
    }

op :define_accessor_property,
    args: {
        base: VirtualRegister,
        property: VirtualRegister,
        getter: VirtualRegister,
        setter: VirtualRegister,
        attributes: VirtualRegister,
    }

op :jmp,
    args: {
        targetLabel: BoundLabel,
    }

op :jtrue,
    args: {
        condition: VirtualRegister,
        targetLabel: BoundLabel,
    }

op :jfalse,
    args: {
        condition: VirtualRegister,
        targetLabel: BoundLabel,
    }

op :jeq_null,
    args: {
        value: VirtualRegister,
        targetLabel: BoundLabel,
    }

op :jneq_null,
    args: {
        value: VirtualRegister,
        targetLabel: BoundLabel,
    }

op :jundefined_or_null,
    args: {
        value: VirtualRegister,
        targetLabel: BoundLabel,
    }

op :jnundefined_or_null,
    args: {
        value: VirtualRegister,
        targetLabel: BoundLabel,
    }

op :jneq_ptr,
    args: {
        value: VirtualRegister,
        specialPointer: VirtualRegister,
        targetLabel: BoundLabel,
    },
    metadata: {
        hasJumped: bool,
    }

op_group :BinaryJmp,
    [
        :jeq,
        :jstricteq,
        :jneq,
        :jnstricteq,
        :jless,
        :jlesseq,
        :jgreater,
        :jgreatereq,
        :jnless,
        :jnlesseq,
        :jngreater,
        :jngreatereq,
        :jbelow,
        :jbeloweq,
    ],
    args: {
        lhs: VirtualRegister,
        rhs: VirtualRegister,
        targetLabel: BoundLabel,
    }

op :loop_hint

op_group :SwitchValue,
    [
        :switch_imm,
        :switch_char,
        :switch_string,
    ],
    args: {
        tableIndex: unsigned,
        defaultOffset: BoundLabel,
        scrutinee: VirtualRegister,
    }

op_group :NewFunction,
    [
        :new_func,
        :new_func_exp,
        :new_generator_func,
        :new_generator_func_exp,
        :new_async_func,
        :new_async_func_exp,
        :new_async_generator_func,
        :new_async_generator_func_exp,
    ],
    args: {
        dst: VirtualRegister,
        scope: VirtualRegister,
        functionDecl: unsigned,
    }

op :set_function_name,
    args: {
        function: VirtualRegister,
        name: VirtualRegister,
    }

# op_call variations
op :call,
    args: {
        dst: VirtualRegister,
        callee: VirtualRegister,
        argc: unsigned,
        argv: unsigned,
    },
    metadata: {
        callLinkInfo: LLIntCallLinkInfo,
        profile: ValueProfile,
    }

op :tail_call,
    args: {
        dst: VirtualRegister,
        callee: VirtualRegister,
        argc: unsigned,
        argv: unsigned,
    },
    metadata: {
        callLinkInfo: LLIntCallLinkInfo,
        profile: ValueProfile,
    }

op :call_eval,
    args: {
        dst: VirtualRegister,
        callee: VirtualRegister,
        argc: unsigned,
        argv: unsigned,
        ecmaMode: ECMAMode,
    },
    metadata: {
        callLinkInfo: LLIntCallLinkInfo,
        profile: ValueProfile,
    }

op :call_varargs,
    args: {
        dst: VirtualRegister,
        callee: VirtualRegister,
        thisValue?: VirtualRegister,
        arguments?: VirtualRegister,
        firstFree: VirtualRegister,
        firstVarArg: int,
    },
    metadata: {
        arrayProfile: ArrayProfile,
        profile: ValueProfile,
    },
    tmps: {
        argCountIncludingThis: unsigned,
    },
    checkpoints: {
        determiningArgCount: nil,
        makeCall: nil,
    }

op :tail_call_varargs,
    args: {
        dst: VirtualRegister,
        callee: VirtualRegister,
        thisValue?: VirtualRegister,
        arguments?: VirtualRegister,
        firstFree: VirtualRegister,
        firstVarArg: int,
    },
    metadata: {
        arrayProfile: ArrayProfile,
        profile: ValueProfile,
    },
    tmps: {
        argCountIncludingThis: unsigned
    },
    checkpoints: {
        determiningArgCount: nil,
        makeCall: nil,
    }

op :tail_call_forward_arguments,
    args: {
        dst: VirtualRegister,
        callee: VirtualRegister,
        thisValue?: VirtualRegister,
        arguments?: VirtualRegister,
        firstFree: VirtualRegister,
        firstVarArg: int,
    },
    metadata: {
        arrayProfile: ArrayProfile,
        profile: ValueProfile,
    }

op :construct,
    args: {
        dst: VirtualRegister,
        callee: VirtualRegister,
        argc: unsigned,
        argv: unsigned,
    },
    metadata: {
        callLinkInfo: LLIntCallLinkInfo,
        profile: ValueProfile,
    }

op :construct_varargs,
    args: {
        dst: VirtualRegister,
        callee: VirtualRegister,
        thisValue?: VirtualRegister,
        arguments?: VirtualRegister,
        firstFree: VirtualRegister,
        firstVarArg: int,
    },
    metadata: {
        arrayProfile: ArrayProfile,
        profile: ValueProfile,
    },
    tmps: {
        argCountIncludingThis: unsigned
    },
    checkpoints: {
        determiningArgCount: nil,
        makeCall: nil,
    }

op :ret,
    args: {
        value: VirtualRegister,
    }

op :strcat,
    args: {
        dst: VirtualRegister,
        src: VirtualRegister,
        count: int,
    }

op :to_primitive,
    args: {
        dst: VirtualRegister,
        src: VirtualRegister,
    }

op :to_property_key,
    args: {
        dst: VirtualRegister,
        src: VirtualRegister,
    }

op :resolve_scope,
    args: {
        dst: VirtualRegister, # offset 1
        scope: VirtualRegister, # offset 2
        var: unsigned, # offset 3
        # $begin: :private,
        resolveType: ResolveType,
        localScopeDepth: unsigned,
    },
    metadata: {
        resolveType: ResolveType, # offset 4
        _0: { # offset 5
            localScopeDepth: unsigned,
            globalLexicalBindingEpoch: unsigned,
        },
        _1: { # offset 6
             # written during linking
             lexicalEnvironment: WriteBarrierBase[JSCell], # lexicalEnvironment && type == ModuleVar
             symbolTable: WriteBarrierBase[SymbolTable], # lexicalEnvironment && type != ModuleVar

             constantScope: WriteBarrierBase[JSScope],

             # written from the slow path
             globalLexicalEnvironment: WriteBarrierBase[JSGlobalLexicalEnvironment],
             globalObject: WriteBarrierBase[JSGlobalObject],
        },
    }

op :get_from_scope,
    args: {
        dst: VirtualRegister, # offset  1
        scope: VirtualRegister, # offset 2
        var: unsigned, # offset 3
        # $begin: :private,
        getPutInfo: GetPutInfo,
        localScopeDepth: unsigned,
        offset: unsigned,
    },
    metadata: {
        getPutInfo: GetPutInfo, # offset 4
        _: { #previously offset 5
            watchpointSet: WatchpointSet.*,
            structure: WriteBarrierBase[Structure],
        },
        operand: uintptr_t, #offset 6
        profile: ValueProfile, # offset 7
    },
    metadata_initializers: {
        getPutInfo: :getPutInfo,
        operand: :offset,
    }

op :put_to_scope,
    args: {
        scope: VirtualRegister, # offset 1
        var: unsigned, # offset 2
        value: VirtualRegister, # offset 3
        # $begin: :private,
        getPutInfo: GetPutInfo,
        symbolTableOrScopeDepth: SymbolTableOrScopeDepth,
        offset: unsigned,
    },
    metadata: {
        getPutInfo: GetPutInfo, # offset 4
        _: { # offset 5
            structure: WriteBarrierBase[Structure],
            watchpointSet: WatchpointSet.*,
        },
        operand: uintptr_t, # offset 6
    },
    metadata_initializers: {
        getPutInfo: :getPutInfo,
        operand: :offset,
    }

op :get_from_arguments,
    args: {
        dst: VirtualRegister,
        arguments: VirtualRegister,
        index: unsigned,
    },
    metadata: {
        profile: ValueProfile,
    }

op :put_to_arguments,
    args: {
        arguments: VirtualRegister,
        index: unsigned,
        value: VirtualRegister,
    }

op :push_with_scope,
    args: {
        dst: VirtualRegister,
        currentScope: VirtualRegister,
        newScope: VirtualRegister,
    }

op :create_lexical_environment,
    args: {
        dst: VirtualRegister,
        scope: VirtualRegister,
        symbolTable: VirtualRegister,
        initialValue: VirtualRegister,
    }

op :create_generator_frame_environment,
    args: {
        dst: VirtualRegister,
        scope: VirtualRegister,
        symbolTable: VirtualRegister,
        initialValue: VirtualRegister,
    }

op :get_parent_scope,
    args: {
        dst: VirtualRegister,
        scope: VirtualRegister,
    }

op :catch,
    args: {
        exception: VirtualRegister,
        thrownValue: VirtualRegister,
    },
    metadata: {
        buffer: ValueProfileAndVirtualRegisterBuffer.*,
    }

op :throw,
    args: {
        value: VirtualRegister,
    }

op :throw_static_error,
    args: {
        message: VirtualRegister,
        errorType: ErrorTypeWithExtension,
    }

op :debug,
    args: {
        debugHookType: DebugHookType,
        hasBreakpoint: bool,
    }

op :end,
    args: {
        value: VirtualRegister,
    }

op :profile_type,
    args: {
        targetVirtualRegister: VirtualRegister,
        symbolTableOrScopeDepth: SymbolTableOrScopeDepth,
        flag: ProfileTypeBytecodeFlag,
        identifier?: unsigned,
        resolveType: ResolveType,
    },
    metadata: {
        typeLocation: TypeLocation.*,
    }

op :profile_control_flow,
    args: {
        textOffset: int,
    },
    metadata: {
        basicBlockLocation: BasicBlockLocation.*,
    }

op :get_enumerable_length,
    args: {
        dst: VirtualRegister,
        base: VirtualRegister,
    }

op :has_indexed_property,
    args: {
        dst: VirtualRegister,
        base: VirtualRegister,
        property: VirtualRegister,
    },
    metadata: {
        arrayProfile: ArrayProfile,
    }

op :has_structure_property,
    args: {
        dst: VirtualRegister,
        base: VirtualRegister,
        property: VirtualRegister,
        enumerator: VirtualRegister,
    }

op :has_own_structure_property,
    args: {
        dst: VirtualRegister,
        base: VirtualRegister,
        property: VirtualRegister,
        enumerator: VirtualRegister,
    }

op :in_structure_property,
    args: {
        dst: VirtualRegister,
        base: VirtualRegister,
        property: VirtualRegister,
        enumerator: VirtualRegister,
    }

op :has_generic_property,
    args: {
        dst: VirtualRegister,
        base: VirtualRegister,
        property: VirtualRegister,
    }

op :get_direct_pname,
    args: {
        dst: VirtualRegister,
        base: VirtualRegister,
        property: VirtualRegister,
        index: VirtualRegister,
        enumerator: VirtualRegister,
    },
    metadata: {
        profile: ValueProfile,
    }

op :get_property_enumerator,
    args: {
        dst: VirtualRegister,
        base: VirtualRegister,
    }

op :enumerator_structure_pname,
    args: {
        dst: VirtualRegister,
        enumerator: VirtualRegister,
        index: VirtualRegister,
    }

op :enumerator_generic_pname,
    args: {
        dst: VirtualRegister,
        enumerator: VirtualRegister,
        index: VirtualRegister,
    }

op :to_index_string,
    args: {
        dst: VirtualRegister,
        index: VirtualRegister,
    }

op :unreachable

op :create_rest,
    args: {
        dst: VirtualRegister,
        arraySize: VirtualRegister,
        numParametersToSkip: unsigned,
    }

op :get_rest_length,
    args: {
        dst: VirtualRegister,
        numParametersToSkip: unsigned,
    }

# Semantically, this is iterator = symbolIterator.@call(iterable); next = iterator.next;
# where symbolIterator the result of iterable[Symbol.iterator] (which is done in a different bytecode).
# For builtin iterators, however, this has special behavior where next becomes the empty value, which
# indicates that we are in a known iteration mode to op_iterator_next.
op :iterator_open,
    args: {
        iterator: VirtualRegister,
        next: VirtualRegister,
        symbolIterator: VirtualRegister,
        iterable: VirtualRegister,
        stackOffset: unsigned,
    },
    metadata: {
        iterationMetadata: IterationModeMetadata,
        iterableProfile: ValueProfile,
        callLinkInfo: LLIntCallLinkInfo,
        iteratorProfile: ValueProfile,
        modeMetadata: GetByIdModeMetadata,
        nextProfile: ValueProfile,
    },
    checkpoints: {
        symbolCall: nil,
        getNext: nil,
    }

# Semantically, this is nextResult = next.@call(iterator); done = nextResult.done; value = done ? undefined : nextResult.value;
op :iterator_next,
    args: {
        done: VirtualRegister,
        value: VirtualRegister,
        iterable: VirtualRegister,
        next: VirtualRegister,
        iterator: VirtualRegister,
        stackOffset: unsigned,
    },
    metadata: {
        iterationMetadata: IterationModeMetadata,
        iterableProfile: ArrayProfile,
        callLinkInfo: LLIntCallLinkInfo,
        nextResultProfile: ValueProfile,
        doneModeMetadata: GetByIdModeMetadata,
        doneProfile: ValueProfile,
        valueModeMetadata: GetByIdModeMetadata,
        valueProfile: ValueProfile,
    },
    tmps: {
        nextResult: JSValue,
    },
    checkpoints: {
        computeNext: nil,
        getDone: nil,
        getValue: nil,
    }

op :yield,
    args: {
        generator: VirtualRegister,
        yieldPoint: unsigned,
        argument: VirtualRegister,
    }

op :check_traps

op :log_shadow_chicken_prologue,
    args: {
        scope: VirtualRegister,
    }

op :log_shadow_chicken_tail,
    args: {
        thisValue: VirtualRegister,
        scope: VirtualRegister,
    }

op :resolve_scope_for_hoisting_func_decl_in_eval,
    args: {
        dst: VirtualRegister,
        scope: VirtualRegister,
        property: unsigned,
    }

op :get_internal_field,
    args: {
        dst: VirtualRegister,
        base: VirtualRegister,
        index: unsigned,
    },
    metadata: {
        profile: ValueProfile,
    }

op :put_internal_field,
    args: {
        base: VirtualRegister,
        index: unsigned,
        value: VirtualRegister,
    }

op :nop

op :super_sampler_begin

op :super_sampler_end

end_section :Bytecode

begin_section :CLoopHelpers,
    emit_in_h_file: true,
    macro_name_component: :CLOOP_BYTECODE_HELPER

op :llint_entry
op :getHostCallReturnValue
op :llint_return_to_host
op :llint_vm_entry_to_javascript
op :llint_vm_entry_to_native
op :llint_cloop_did_return_from_js_1
op :llint_cloop_did_return_from_js_2
op :llint_cloop_did_return_from_js_3
op :llint_cloop_did_return_from_js_4
op :llint_cloop_did_return_from_js_5
op :llint_cloop_did_return_from_js_6
op :llint_cloop_did_return_from_js_7
op :llint_cloop_did_return_from_js_8
op :llint_cloop_did_return_from_js_9
op :llint_cloop_did_return_from_js_10
op :llint_cloop_did_return_from_js_11
op :llint_cloop_did_return_from_js_12
op :llint_cloop_did_return_from_js_13
op :llint_cloop_did_return_from_js_14
op :llint_cloop_did_return_from_js_15
op :llint_cloop_did_return_from_js_16
op :llint_cloop_did_return_from_js_17
op :llint_cloop_did_return_from_js_18
op :llint_cloop_did_return_from_js_19
op :llint_cloop_did_return_from_js_20
op :llint_cloop_did_return_from_js_21
op :llint_cloop_did_return_from_js_22
op :llint_cloop_did_return_from_js_23
op :llint_cloop_did_return_from_js_24
op :llint_cloop_did_return_from_js_25
op :llint_cloop_did_return_from_js_26
op :llint_cloop_did_return_from_js_27
op :llint_cloop_did_return_from_js_28
op :llint_cloop_did_return_from_js_29
op :llint_cloop_did_return_from_js_30
op :llint_cloop_did_return_from_js_31
op :llint_cloop_did_return_from_js_32
op :llint_cloop_did_return_from_js_33
op :llint_cloop_did_return_from_js_34
op :llint_cloop_did_return_from_js_35
op :llint_cloop_did_return_from_js_36
op :llint_cloop_did_return_from_js_37
op :llint_cloop_did_return_from_js_38
op :llint_cloop_did_return_from_js_39
op :llint_cloop_did_return_from_js_40
op :llint_cloop_did_return_from_js_41
op :llint_cloop_did_return_from_js_42
op :llint_cloop_did_return_from_js_43
op :llint_cloop_did_return_from_js_44
op :llint_cloop_did_return_from_js_45
op :llint_cloop_did_return_from_js_46

end_section :CLoopHelpers

begin_section :NativeHelpers,
    emit_in_h_file: true,
    emit_in_asm_file: true,
    macro_name_component: :BYTECODE_HELPER

op :llint_program_prologue
op :llint_eval_prologue
op :llint_module_program_prologue
op :llint_function_for_call_prologue
op :llint_function_for_construct_prologue
op :llint_function_for_call_arity_check
op :llint_function_for_construct_arity_check
op :llint_generic_return_point
op :llint_throw_from_slow_path_trampoline
op :llint_throw_during_call_trampoline
op :llint_native_call_trampoline
op :llint_native_construct_trampoline
op :llint_internal_function_call_trampoline
op :llint_internal_function_construct_trampoline
op :checkpoint_osr_exit_from_inlined_call_trampoline
op :checkpoint_osr_exit_trampoline
op :fuzzer_return_early_from_loop_hint
op :handleUncaughtException
op :op_call_return_location
op :op_construct_return_location
op :op_call_varargs_slow_return_location
op :op_construct_varargs_slow_return_location
op :op_get_by_id_return_location
op :op_get_by_val_return_location
op :op_put_by_id_return_location
op :op_put_by_val_return_location
op :op_iterator_open_return_location
op :op_iterator_next_return_location
op :wasm_function_prologue
op :wasm_function_prologue_no_tls

end_section :NativeHelpers

begin_section :Wasm,
    emit_in_h_file: true,
    emit_in_structs_file: true,
    macro_name_component: :WASM,
    op_prefix: "wasm_"

autogenerate_wasm_opcodes

# Helpers

op :throw_from_slow_path_trampoline

# FIXME: Wasm and JS LLInt should share common opcodes
# https://bugs.webkit.org/show_bug.cgi?id=203656

op :wide16
op :wide32

op :enter
op :nop
op :loop_hint

op :mov,
    args: {
        dst: VirtualRegister,
        src: VirtualRegister,
    }

op_group :ConditionalJump,
    [
        :jtrue,
        :jfalse,
    ],
    args: {
        condition: VirtualRegister,
        targetLabel: WasmBoundLabel,
    }

op :jmp,
    args: {
        targetLabel: WasmBoundLabel,
    }

op :ret

op :switch,
    args: {
        scrutinee: VirtualRegister,
        tableIndex: unsigned,
    }

# Wasm specific bytecodes

op :unreachable
op :ret_void

op :drop_keep,
    args: {
        startOffset: unsigned,
        dropCount: unsigned,
        keepCount: unsigned,
    }

op :ref_is_null,
    args: {
        dst: VirtualRegister,
        ref: VirtualRegister,
    }

op :ref_func,
    args: {
        dst: VirtualRegister,
        functionIndex: unsigned,
    }

op :get_global,
    args: {
        dst: VirtualRegister,
        globalIndex: unsigned,
    }

op :set_global,
    args: {
        globalIndex: unsigned,
        value: VirtualRegister,
    }

op :set_global_ref,
    args: {
        globalIndex: unsigned,
        value: VirtualRegister,
    }

op :get_global_portable_binding,
    args: {
        dst: VirtualRegister,
        globalIndex: unsigned,
    }

op :set_global_portable_binding,
    args: {
        globalIndex: unsigned,
        value: VirtualRegister,
    }

op :set_global_ref_portable_binding,
    args: {
        globalIndex: unsigned,
        value: VirtualRegister,
    }

op :table_get,
    args: {
        dst: VirtualRegister,
        index: VirtualRegister,
        tableIndex: unsigned,
    }

op :table_set,
    args: {
        index: VirtualRegister,
        value: VirtualRegister,
        tableIndex: unsigned,
    }

op :table_size,
    args: {
        dst: VirtualRegister,
        tableIndex: unsigned,
    }

op :table_grow,
    args: {
        dst: VirtualRegister,
        fill: VirtualRegister,
        size: VirtualRegister,
        tableIndex: unsigned,
    }

op :table_fill,
    args: {
        offset: VirtualRegister,
        fill: VirtualRegister,
        size: VirtualRegister,
        tableIndex: unsigned,
    }

op :call,
    args: {
        functionIndex: unsigned,
        stackOffset: unsigned,
        numberOfStackArgs: unsigned,
    }

op :call_no_tls,
    args: {
        functionIndex: unsigned,
        stackOffset: unsigned,
        numberOfStackArgs: unsigned,
    }

op :call_indirect,
    args: {
        functionIndex: VirtualRegister,
        signatureIndex: unsigned,
        stackOffset: unsigned,
        numberOfStackArgs: unsigned,
        tableIndex: unsigned,
    }

op :call_indirect_no_tls,
    args: {
        functionIndex: VirtualRegister,
        signatureIndex: unsigned,
        stackOffset: unsigned,
        numberOfStackArgs: unsigned,
        tableIndex: unsigned,
    }

op :current_memory,
    args: {
        dst: VirtualRegister,
    }

op :grow_memory,
    args: {
        dst: VirtualRegister,
        delta: VirtualRegister
    }

op :select,
    args: {
        dst: VirtualRegister,
        condition: VirtualRegister,
        nonZero: VirtualRegister,
        zero: VirtualRegister,
    }

op_group :Load,
    [
        :load8_u,
        :load16_u,
        :load32_u,
        :load64_u,
        :i32_load8_s,
        :i64_load8_s,
        :i32_load16_s,
        :i64_load16_s,
        :i64_load32_s,
    ],
    args: {
        dst: VirtualRegister,
        pointer: VirtualRegister,
        offset: unsigned,
    }

op_group :Store,
    [
        :store8,
        :store16,
        :store32,
        :store64,
    ],
    args: {
        pointer: VirtualRegister,
        value: VirtualRegister,
        offset: unsigned,
    }

end_section :Wasm