From 36d22d82aa202bb199967e9512281e9a53db42c9 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 21:33:14 +0200 Subject: Adding upstream version 115.7.0esr. Signed-off-by: Daniel Baumann --- js/src/jit/GenerateMIRFiles.py | 404 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 404 insertions(+) create mode 100644 js/src/jit/GenerateMIRFiles.py (limited to 'js/src/jit/GenerateMIRFiles.py') diff --git a/js/src/jit/GenerateMIRFiles.py b/js/src/jit/GenerateMIRFiles.py new file mode 100644 index 0000000000..3ed92087a3 --- /dev/null +++ b/js/src/jit/GenerateMIRFiles.py @@ -0,0 +1,404 @@ +# 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. + +from collections import OrderedDict + +import buildconfig +import six +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.0. If 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 = six.StringIO() + pp.do_filter("substitution") + pp.do_include(yaml_path) + contents = pp.out.getvalue() + + # Load into an OrderedDict to ensure order is preserved. Note: Python 3.7+ + # also preserves ordering for normal dictionaries. + # Code based on https://stackoverflow.com/a/21912744. + class OrderedLoader(yaml.Loader): + pass + + def construct_mapping(loader, node): + loader.flatten_mapping(node) + return OrderedDict(loader.construct_pairs(node)) + + tag = yaml.resolver.BaseResolver.DEFAULT_MAPPING_TAG + OrderedLoader.add_constructor(tag, construct_mapping) + return yaml.load(contents, OrderedLoader) + + +type_policies = { + "Object": "ObjectPolicy", + "Value": "BoxPolicy", + "Int32": "UnboxedInt32Policy", + "BigInt": "BigIntPolicy", + "Boolean": "BooleanPolicy", + "Double": "DoublePolicy", + "String": "StringPolicy", + "Symbol": "SymbolPolicy", +} + + +def decide_type_policy(types, no_type_policy): + if no_type_policy: + return "public NoTypePolicy::Data" + + if len(types) == 1: + return "public {}<0>::Data".format(type_policies[types[0]]) + + type_num = 0 + mixed_type_policies = [] + for mir_type in types: + policy = type_policies[mir_type] + mixed_type_policies.append("{}<{}>".format(policy, type_num)) + type_num += 1 + + return "public MixPolicy<{}>::Data".format(", ".join(mixed_type_policies)) + + +mir_base_class = [ + "MNullaryInstruction", + "MUnaryInstruction", + "MBinaryInstruction", + "MTernaryInstruction", + "MQuaternaryInstruction", +] + + +gc_pointer_types = [ + "JSObject*", + "NativeObject*", + "JSFunction*", + "BaseScript*", + "PropertyName*", + "Shape*", + "GetterSetter*", + "JSAtom*", + "ClassBodyScope*", + "VarScope*", + "NamedLambdaObject*", + "RegExpObject*", + "JSScript*", + "LexicalScope*", +] + + +def gen_mir_class( + name, + operands, + arguments, + no_type_policy, + result, + guard, + movable, + folds_to, + congruent_to, + alias_set, + might_alias, + possibly_calls, + compute_range, + can_recover, + clone, +): + """Generates class definition for a single MIR opcode.""" + + # Generate a MIR opcode class definition. + # For example: + # class MGuardIndexIsValidUpdateOrAdd + # : public MBinaryInstruction, + # public MixPolicy, 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: + current_oper_num = 0 + for oper_name in 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("({}, {})".format(current_oper_num, oper_name)) + current_oper_num += 1 + type_policy = decide_type_policy(mir_types, no_type_policy) + + class_name = "M" + name + + assert len(mir_operands) < 5 + base_class = mir_base_class[len(mir_operands)] + assert base_class + if base_class != "MNullaryInstruction": + assert type_policy + type_policy = ", " + type_policy + code = "class {} : public {}{} {{\\\n".format(class_name, base_class, type_policy) + + # 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 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_name + ")" + code += " {\\\n" + if guard: + code += " setGuard();\\\n" + if movable: + code += " setMovable();\\\n" + if result: + code += " setResultType(MIRType::{});\\\n".format(result) + code += " }\\\n public:\\\n" + if arguments: + for arg_name in arguments: + code += " " + arguments[arg_name] + " " + arg_name + "() const { " + code += "return " + arg_name + "_; }\\\n" + code += " INSTRUCTION_HEADER({})\\\n".format(name) + 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" + else: + assert alias_set == "none" + code += ( + " AliasSet getAliasSet() const override { " + "return AliasSet::None(); }\\\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 == "if_operands_equal" + code += ( + " bool congruentTo(const MDefinition* ins) const override { " + "return congruentIfOperandsEqual(ins); }\\\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" + 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, " + '"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("_({})".format(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, OrderedDict) + + arguments = op.get("arguments", None) + assert arguments is None or isinstance(arguments, OrderedDict) + + no_type_policy = op.get("type_policy", None) + assert no_type_policy is None or no_type_policy == "none" + + result = op.get("result_type", None) + assert result is None or isinstance(result, str) + + guard = op.get("guard", None) + assert guard is None or True + + movable = op.get("movable", None) + assert movable is None or True + + folds_to = op.get("folds_to", None) + assert folds_to is None or folds_to == "custom" + + congruent_to = op.get("congruent_to", None) + assert ( + congruent_to is None + or congruent_to == "if_operands_equal" + or congruent_to == "custom" + ) + + alias_set = op.get("alias_set", None) + assert alias_set is None or True or isinstance(alias_set, str) + + might_alias = op.get("might_alias", None) + assert might_alias is None or might_alias == "custom" + + possibly_calls = op.get("possibly_calls", None) + assert possibly_calls is None or True or possibly_calls == "custom" + + compute_range = op.get("compute_range", None) + assert compute_range is None or compute_range == "custom" + + can_recover = op.get("can_recover", None) + assert can_recover is None or True or can_recover == "custom" + + clone = op.get("clone", None) + assert clone is None or True + + code = gen_mir_class( + name, + operands, + arguments, + no_type_policy, + result, + guard, + movable, + folds_to, + congruent_to, + alias_set, + might_alias, + possibly_calls, + compute_range, + can_recover, + clone, + ) + 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) -- cgit v1.2.3