Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  GenerateMIRFiles.py

  Sprache: Python
 

# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.

# This script generates jit/MIROpsGenerated.h (list of MIR instructions)
# from MIROps.yaml, as well as MIR op definitions.

import io

import buildconfig
import yaml
from mozbuild.preprocessor import Preprocessor

HEADER_TEMPLATE = """\
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef %(includeguard)s
#define %(includeguard)s

/* This file is generated by jit/GenerateMIRFiles.py. Do not edit! */

%(contents)s

#endif // %(includeguard)s
"""


def generate_header(c_out, includeguard, contents):
    c_out.write(
        HEADER_TEMPLATE
        % {
            "includeguard": includeguard,
            "contents": contents,
        }
    )


def load_yaml(yaml_path):
    # First invoke preprocessor.py so that we can use #ifdef JS_SIMULATOR in
    # the YAML file.
    pp = Preprocessor()
    pp.context.update(buildconfig.defines["ALLDEFINES"])
    pp.out = io.StringIO()
    pp.do_filter("substitution")
    pp.do_include(yaml_path)
    contents = pp.out.getvalue()
    return yaml.safe_load(contents)


type_policies = {
    "Object""ObjectPolicy",
    "Value""BoxPolicy",
    "ValueOrObject""BoxExceptObjectPolicy",
    "Int32""UnboxedInt32Policy",
    "BigInt""BigIntPolicy",
    "IntPtr""IntPtrPolicy",
    "Boolean""BooleanPolicy",
    "Double""DoublePolicy",
    "String""StringPolicy",
    "Symbol""SymbolPolicy",
    "Slots""NoTypePolicy",
    "any""NoTypePolicy",
}


def decide_type_policy(types, no_type_policy):
    if no_type_policy:
        return "public NoTypePolicy::Data"

    mixed_type_policies = []
    for type_num, mir_type in enumerate(types):
        policy = type_policies[mir_type]
        if policy != "NoTypePolicy":
            mixed_type_policies.append(f"{policy}<{type_num}>")

    if len(mixed_type_policies) == 0:
        return "public NoTypePolicy::Data"

    if len(mixed_type_policies) == 1:
        return f"public {mixed_type_policies[0]}::Data"

    return "public MixPolicy<{}>::Data".format(", ".join(mixed_type_policies))


# Alias set flags defined in MIR.h.
alias_set_flags = {
    "None",
    "ObjectFields",
    "Element",
    "UnboxedElement",
    "DynamicSlot",
    "FixedSlot",
    "DOMProperty",
    "WasmInstanceData",
    "WasmHeap",
    "WasmHeapMeta",
    "ArrayBufferViewLengthOrOffset",
    "WasmGlobalCell",
    "WasmTableElement",
    "WasmTableMeta",
    "WasmStackResult",
    "ExceptionState",
    "DOMProxyExpando",
    "MapOrSetHashTable",
    "RNG",
    "WasmPendingException",
    "FuzzilliHash",
    "WasmStructInlineDataArea",
    "WasmStructOutlineDataPointer",
    "WasmStructOutlineDataArea",
    "WasmArrayNumElements",
    "WasmArrayDataPointer",
    "WasmArrayDataArea",
    "GlobalGenerationCounter",
    "SharedArrayRawBufferLength",
    "Any",
}


def get_alias_set(load_or_store, alias_set):
    assert load_or_store in ("load""store")

    flags = alias_set.get(load_or_store, [])
    if isinstance(flags, str):
        flags = [flags]

    assert isinstance(flags, list)
    assert alias_set_flags.issuperset(flags), "unknown alias set flag: " + str(flags)
    assert len(flags) == len(set(flags)), "unexpected duplicates: " + str(flags)

    # `AliasSet::{Load,Store}(AliasSet::None)` is not valid, so handle it early.
    if len(flags) == 0 or flags[0] == "None":
        return None

    expr = " | ".join(f"AliasSet::{flag}" for flag in flags)
    return f"AliasSet::{load_or_store.title()}({expr})"


mir_base_class = [
    "MNullaryInstruction",
    "MUnaryInstruction",
    "MBinaryInstruction",
    "MTernaryInstruction",
    "MQuaternaryInstruction",
    "MQuinaryInstruction",
]


gc_pointer_types = [
    "JSObject*",
    "NativeObject*",
    "JSFunction*",
    "BaseScript*",
    "PropertyName*",
    "Shape*",
    "GetterSetter*",
    "JSOffThreadAtom*",
    "ClassBodyScope*",
    "VarScope*",
    "NamedLambdaObject*",
    "RegExpObject*",
    "JSScript*",
    "LexicalScope*",
    "ArgumentsObject*",
]

special_storage_types = {
    "JSOffThreadAtom*": (
        "CompilerGCPointer<JSAtom*>",
        "{}->unwrap()",
        "&{}->asOffThreadAtom()",
    )
}


def arg_type_sig_to_init(type_sig, arg_name):
    if type_sig in special_types:
        _, init, _ = special_types[type_sig]
        return init.format(arg_name)
    else:
        return arg_name


def gen_mir_class(
    name,
    operands,
    arguments,
    no_type_policy,
    result,
    guard,
    movable,
    folds_to,
    value_hash,
    congruent_to,
    alias_set,
    might_alias,
    possibly_calls,
    compute_range,
    can_recover,
    clone,
    can_consume_float32,
    wasm_ref_type,
):
    """Generates class definition for a single MIR opcode."""

    # Generate a MIR opcode class definition.
    # For example:
    # class MGuardIndexIsValidUpdateOrAdd
    #     : public MBinaryInstruction,
    #       public MixPolicy<ObjectPolicy<0>, UnboxedInt32Policy<1>>::Data {
    #  explicit MGuardIndexIsValidUpdateOrAdd(MDefinition* object,
    #                                         MDefinition* index)
    #     : MBinaryInstruction(classOpcode, object, index) {
    #   setGuard();
    #   setMovable();
    #   setResultType(MIRType::Int32);
    #  }
    # public:
    #  INSTRUCTION_HEADER(GetFrameArgument)
    #  TRIVIAL_NEW_WRAPPERS
    #  NAMED_OPERANDS((0, object), (1, index))
    #  AliasSet getAliasSet() const override { return AliasSet::None(); }
    #  bool congruentTo(const MDefinition* ins) const override {
    #    return congruentIfOperandsEqual(ins); }
    #  };
    #

    type_policy = ""
    # MIR op constructor operands.
    mir_operands = []
    # MIR op base class constructor operands.
    mir_base_class_operands = []
    # Types of each constructor operand.
    mir_types = []
    # Items for NAMED_OPERANDS.
    named_operands = []
    if operands:
        for current_oper_num, oper_name in enumerate(operands):
            oper = "MDefinition* " + oper_name
            mir_operands.append(oper)
            mir_base_class_operands.append(", " + oper_name)
            # Collect all the MIR argument types to use for determining the
            # ops type policy.
            mir_types.append(operands[oper_name])
            # Collecting named operands for defining accessors.
            named_operands.append(f"({current_oper_num}, {oper_name})")
        type_policy = decide_type_policy(mir_types, no_type_policy)

    class_name = "M" + name

    assert len(mir_operands) < 6
    base_class = mir_base_class[len(mir_operands)]
    assert base_class
    if base_class != "MNullaryInstruction":
        assert type_policy
        type_policy = ", " + type_policy
    code = f"class {class_name} : public {base_class}{type_policy} {{\\\n"

    # Arguments to class constructor that require accessors.
    mir_args = []
    if arguments:
        for arg_name in arguments:
            arg_type_sig = arguments[arg_name]
            mir_args.append(arg_type_sig + " " + arg_name)
            if arg_type_sig in special_storage_types:
                storage, _, _ = special_storage_types[arg_type_sig]
                code += "  " + storage
            elif arg_type_sig in gc_pointer_types:
                code += "  CompilerGCPointer<" + arg_type_sig + ">"
            else:
                code += "  " + arg_type_sig
            code += " " + arg_name + "_;\\\n"

    code += "  explicit {}({}) : {}(classOpcode{})".format(
        class_name,
        ", ".join(mir_operands + mir_args),
        base_class,
        "".join(mir_base_class_operands),
    )
    if arguments:
        for arg_name in arguments:
            code += ", " + arg_name + "_("
            arg_type_sig = arguments[arg_name]
            if arg_type_sig in special_storage_types:
                _, init, _ = special_storage_types[arg_type_sig]
                code += init.format(arg_name)
            else:
                code += arg_name
            code += ")"
    code += " {\\\n"
    if operands:
        for oper_name in operands:
            mir_type = operands[oper_name]

            # Skip over operands which can have any type.
            if mir_type == "any":
                continue

            policy = type_policies.get(mir_type, "NoTypePolicy")
            if no_type_policy or policy == "NoTypePolicy":
                code += (
                    f"    MOZ_ASSERT({oper_name}->type() == MIRType::{mir_type});\\\n"
                )
    if guard:
        code += "    setGuard();\\\n"
    if movable:
        code += "    setMovable();\\\n"
    if wasm_ref_type is not None:
        code += f"    setWasmRefType({wasm_ref_type});\\\n"
    # Note: MIRType::None is the default MIR result type so don't generate a
    # setResultType call for it.
    if result and result != "None":
        code += f"    setResultType(MIRType::{result});\\\n"
    code += "  }\\\n public:\\\n"
    if arguments:
        for arg_name in arguments:
            code += "  " + arguments[arg_name] + " " + arg_name + "() const { "
            arg_type_sig = arguments[arg_name]
            if arg_type_sig in special_storage_types:
                _, _, load = special_storage_types[arg_type_sig]
                code += "return " + load.format(arg_name + "_") + "; }\\\n"
            else:
                code += "return " + arg_name + "_; }\\\n"
    code += f"  INSTRUCTION_HEADER({name})\\\n"
    code += "  TRIVIAL_NEW_WRAPPERS\\\n"
    if named_operands:
        code += "  NAMED_OPERANDS({})\\\n".format(", ".join(named_operands))
    if alias_set:
        if alias_set == "custom":
            code += "  AliasSet getAliasSet() const override;\\\n"
        elif alias_set == "none":
            code += (
                "  AliasSet getAliasSet() const override { "
                "return AliasSet::None(); }\\\n"
            )
        else:
            assert isinstance(alias_set, dict)
            assert {"load""store"}.issuperset(alias_set.keys())

            load = get_alias_set("load", alias_set)
            store = get_alias_set("store", alias_set)

            if load and store:
                expr = f"{load} | {store}"
            elif load or store:
                expr = load if load else store
            else:
                expr = "AliasSet::None()"

            code += f"  AliasSet getAliasSet() const override {{ return {expr}; }}\\\n"
    if might_alias:
        code += "  AliasType mightAlias(const MDefinition* store) const override;\\\n"
    if folds_to:
        code += "  MDefinition* foldsTo(TempAllocator& alloc) override;\\\n"
    if congruent_to:
        if congruent_to == "custom":
            code += "  bool congruentTo(const MDefinition* ins) const override;\\\n"
        else:
            assert congruent_to in (
                "if_operands_equal",
                "if_operands_equal_ignore_arguments",
                "if_operands_and_arguments_equal",
            )
            assert not arguments or congruent_to in (
                "if_operands_equal_ignore_arguments",
                "if_operands_and_arguments_equal",
            ), (
                f"can't request congruent_to = 'if_operands_equal' for {name} because the instruction has arguments"
            )

            operands_and_args = ["congruentIfOperandsEqual(ins)"]
            if arguments and congruent_to == "if_operands_and_arguments_equal":
                for arg_name in arguments:
                    operands_and_args.append(
                        f"ins->to{name}()->{arg_name}_ == {arg_name}_"
                    )
            expr = " && ".join(operands_and_args)

            code += (
                "  bool congruentTo(const MDefinition* ins) const override { "
                f"return {expr}; }}\\\n"
            )
    if value_hash:
        assert value_hash == "custom"
        code += "  HashNumber valueHash() const override;\\\n"
    if possibly_calls:
        if possibly_calls == "custom":
            code += "  bool possiblyCalls() const override;\\\n"
        else:
            code += "  bool possiblyCalls() const override { return true; }\\\n"
    if compute_range:
        code += "  void computeRange(TempAllocator& alloc) override;\\\n"
    if can_recover:
        code += "  [[nodiscard]] bool writeRecoverData(\\\n"
        code += "    CompactBufferWriter& writer) const override;\\\n"
        if can_recover == "custom":
            code += "  bool canRecoverOnBailout() const override;\\\n"
        else:
            code += "  bool canRecoverOnBailout() const override { return true; }\\\n"
    if clone:
        code += "  ALLOW_CLONE(" + class_name + ")\\\n"
    if can_consume_float32:
        code += (
            "  bool canConsumeFloat32(MUse* use) const override { return true; }\\\n"
        )
    code += "};\\\n"
    return code


def gen_non_gc_pointer_type_assertions(seen_types):
    """Generates a list of static assertions used to ensure that all argument
    types seen are not derived from gc::Cell, ensuring that gc pointer arguments
    are added to the gc_pointer_types list.
    """
    assertions = []

    for seen_type in sorted(seen_types):
        assertions.append(
            "static_assert(!std::is_base_of_v<gc::Cell, " + seen_type.strip("*") + ">, "
            '"Ensure that '
            + seen_type.strip("*")
            + ' is added to the gc_pointer_types list in GenerateMIRFiles.py."'
            ");"
        )

    return assertions


def generate_mir_header(c_out, yaml_path):
    """Generate MIROpsGenerated.h from MIROps.yaml. The generated file
    has a list of MIR ops and boilerplate for MIR op definitions.
    """

    data = load_yaml(yaml_path)

    # MIR_OPCODE_LIST items. Stores the name of each MIR op.
    ops_items = []

    # Generated MIR op class definitions.
    mir_op_classes = []

    # Unique and non gc pointer types seen for arguments to the MIR constructor.
    seen_non_gc_pointer_argument_types = set()

    for op in data:
        name = op["name"]

        ops_items.append(f"_({name})")

        gen_boilerplate = op.get("gen_boilerplate"True)
        assert isinstance(gen_boilerplate, bool)

        if gen_boilerplate:
            operands = op.get("operands"None)
            assert operands is None or isinstance(operands, dict)

            arguments = op.get("arguments"None)
            assert arguments is None or isinstance(arguments, dict)

            no_type_policy = op.get("type_policy"None)
            assert no_type_policy in (None"none")

            result = op.get("result_type"None)
            assert result is None or isinstance(result, str)

            guard = op.get("guard"None)
            assert guard in (NoneTrueFalse)

            movable = op.get("movable"None)
            assert movable in (NoneTrueFalse)

            folds_to = op.get("folds_to"None)
            assert folds_to in (None"custom")

            value_hash = op.get("value_hash"None)
            assert value_hash in (None"custom")

            congruent_to = op.get("congruent_to"None)
            assert congruent_to in (
                None,
                "if_operands_equal",
                "if_operands_equal_ignore_arguments",
                "if_operands_and_arguments_equal",
                "custom",
            )

            alias_set = op.get("alias_set"None)
            assert alias_set in (None"none""custom"or isinstance(alias_set, dict)

            might_alias = op.get("might_alias"None)
            assert might_alias in (None"custom")

            possibly_calls = op.get("possibly_calls"None)
            assert possibly_calls in (NoneTrue"custom")

            compute_range = op.get("compute_range"None)
            assert compute_range in (None"custom")

            can_recover = op.get("can_recover"None)
            assert can_recover in (NoneTrueFalse"custom")

            clone = op.get("clone"None)
            assert clone in (NoneTrueFalse)

            can_consume_float32 = op.get("can_consume_float32"None)
            assert can_consume_float32 in (NoneTrueFalse)

            wasm_ref_type = op.get("wasm_ref_type"None)
            assert result is None or isinstance(result, str)

            code = gen_mir_class(
                name,
                operands,
                arguments,
                no_type_policy,
                result,
                guard,
                movable,
                folds_to,
                value_hash,
                congruent_to,
                alias_set,
                might_alias,
                possibly_calls,
                compute_range,
                can_recover,
                clone,
                can_consume_float32,
                wasm_ref_type,
            )
            mir_op_classes.append(code)

            if arguments:
                for argument in arguments:
                    arg_type = arguments[argument]
                    if arg_type not in gc_pointer_types:
                        seen_non_gc_pointer_argument_types.add(arg_type)

    contents = "#define MIR_OPCODE_LIST(_)\\\n"
    contents += "\\\n".join(ops_items)
    contents += "\n\n"

    contents += "#define MIR_OPCODE_CLASS_GENERATED \\\n"
    contents += "\\\n".join(mir_op_classes)
    contents += "\n\n"

    contents += "#define NON_GC_POINTER_TYPE_ASSERTIONS_GENERATED \\\n"
    contents += "\\\n".join(
        gen_non_gc_pointer_type_assertions(seen_non_gc_pointer_argument_types)
    )
    contents += "\n\n"

    generate_header(c_out, "jit_MIROpsGenerated_h", contents)

Messung V0.5 in Prozent
C=91 H=92 G=91

¤ Dauer der Verarbeitung: 0.7 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Open Source Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Statistik
#Sources=277311
#Domains=752002