tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

GenerateCacheIRFiles.py (23347B)


      1 # This Source Code Form is subject to the terms of the Mozilla Public
      2 # License, v. 2.0. If a copy of the MPL was not distributed with this
      3 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
      4 
      5 # This script generates jit/CacheIROpsGenerated.h from CacheIROps.yaml
      6 
      7 import io
      8 import os
      9 import os.path
     10 
     11 import buildconfig
     12 import yaml
     13 from mozbuild.preprocessor import Preprocessor
     14 
     15 HEADER_TEMPLATE = """\
     16 /* This Source Code Form is subject to the terms of the Mozilla Public
     17 * License, v. 2.0. If a copy of the MPL was not distributed with this
     18 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     19 
     20 #ifndef %(includeguard)s
     21 #define %(includeguard)s
     22 
     23 /* This file is generated by jit/GenerateCacheIRFiles.py. Do not edit! */
     24 
     25 %(contents)s
     26 
     27 #endif // %(includeguard)s
     28 """
     29 
     30 
     31 def generate_header(c_out, includeguard, contents):
     32    c_out.write(
     33        HEADER_TEMPLATE
     34        % {
     35            "includeguard": includeguard,
     36            "contents": contents,
     37        }
     38    )
     39 
     40 
     41 def load_yaml(yaml_path):
     42    # First invoke preprocessor.py so that we can use #ifdef JS_SIMULATOR in
     43    # the YAML file.
     44    pp = Preprocessor()
     45    pp.context.update(buildconfig.defines["ALLDEFINES"])
     46    pp.out = io.StringIO()
     47    pp.do_filter("substitution")
     48    pp.do_include(yaml_path)
     49    contents = pp.out.getvalue()
     50    return yaml.safe_load(contents)
     51 
     52 
     53 # Information for generating CacheIRWriter code for a single argument. Tuple
     54 # stores the C++ argument type and the CacheIRWriter method to call.
     55 arg_writer_info = {
     56    "ValId": ("ValOperandId", "writeOperandId"),
     57    "ObjId": ("ObjOperandId", "writeOperandId"),
     58    "StringId": ("StringOperandId", "writeOperandId"),
     59    "SymbolId": ("SymbolOperandId", "writeOperandId"),
     60    "BooleanId": ("BooleanOperandId", "writeOperandId"),
     61    "Int32Id": ("Int32OperandId", "writeOperandId"),
     62    "NumberId": ("NumberOperandId", "writeOperandId"),
     63    "BigIntId": ("BigIntOperandId", "writeOperandId"),
     64    "ValueTagId": ("ValueTagOperandId", "writeOperandId"),
     65    "IntPtrId": ("IntPtrOperandId", "writeOperandId"),
     66    "RawId": ("OperandId", "writeOperandId"),
     67    "ShapeField": ("Shape*", "writeShapeField"),
     68    "WeakShapeField": ("Shape*", "writeWeakShapeField"),
     69    "ObjectField": ("JSObject*", "writeObjectField"),
     70    "WeakObjectField": ("JSObject*", "writeWeakObjectField"),
     71    "StringField": ("JSString*", "writeStringField"),
     72    "AtomField": ("JSAtom*", "writeStringField"),
     73    "SymbolField": ("JS::Symbol*", "writeSymbolField"),
     74    "WeakBaseScriptField": ("BaseScript*", "writeWeakBaseScriptField"),
     75    "JitCodeField": ("JitCode*", "writeJitCodeField"),
     76    "RawInt32Field": ("uint32_t", "writeRawInt32Field"),
     77    "RawPointerField": ("const void*", "writeRawPointerField"),
     78    "IdField": ("jsid", "writeIdField"),
     79    "ValueField": ("const Value&", "writeValueField"),
     80    "WeakValueField": ("const Value&", "writeWeakValueField"),
     81    "RawInt64Field": ("uint64_t", "writeRawInt64Field"),
     82    "DoubleField": ("double", "writeDoubleField"),
     83    "AllocSiteField": ("gc::AllocSite*", "writeAllocSiteField"),
     84    "JSOpImm": ("JSOp", "writeJSOpImm"),
     85    "JSTypeImm": ("JSType", "writeJSTypeImm"),
     86    "TypeofEqOperandImm": ("TypeofEqOperand", "writeTypeofEqOperandImm"),
     87    "BoolImm": ("bool", "writeBoolImm"),
     88    "ByteImm": ("uint32_t", "writeByteImm"),  # uint32_t to enable fits-in-byte asserts.
     89    "GuardClassKindImm": ("GuardClassKind", "writeGuardClassKindImm"),
     90    "ArrayBufferViewKindImm": ("ArrayBufferViewKind", "writeArrayBufferViewKindImm"),
     91    "ValueTypeImm": ("ValueType", "writeValueTypeImm"),
     92    "JSWhyMagicImm": ("JSWhyMagic", "writeJSWhyMagicImm"),
     93    "CallFlagsImm": ("CallFlags", "writeCallFlagsImm"),
     94    "ScalarTypeImm": ("Scalar::Type", "writeScalarTypeImm"),
     95    "UnaryMathFunctionImm": ("UnaryMathFunction", "writeUnaryMathFunctionImm"),
     96    "WasmValTypeImm": ("wasm::ValType::Kind", "writeWasmValTypeImm"),
     97    "Int32Imm": ("int32_t", "writeInt32Imm"),
     98    "UInt32Imm": ("uint32_t", "writeUInt32Imm"),
     99    "JSNativeImm": ("JSNative", "writeJSNativeImm"),
    100    "StaticStringImm": ("const char*", "writeStaticStringImm"),
    101    "AllocKindImm": ("gc::AllocKind", "writeAllocKindImm"),
    102    "CompletionKindImm": ("CompletionKind", "writeCompletionKindImm"),
    103    "RealmFuseIndexImm": ("RealmFuses::FuseIndex", "writeRealmFuseIndexImm"),
    104    "RuntimeFuseIndexImm": ("RuntimeFuses::FuseIndex", "writeRuntimeFuseIndexImm"),
    105 }
    106 
    107 
    108 def gen_writer_method(name, args, custom_writer):
    109    """Generates a CacheIRWRiter method for a single opcode."""
    110 
    111    # Generate a single method that writes the opcode and each argument.
    112    # For example:
    113    #
    114    #   void guardShape(ObjOperandId obj, Shape* shape) {
    115    #     writeOp(CacheOp::GuardShape);
    116    #     writeOperandId(obj);
    117    #     writeShapeField(shape);
    118    #     assertLengthMatches();
    119    #  }
    120    #
    121    # The assertLengthMatches() call is to assert the information in the
    122    # arg_length dictionary below matches what's written.
    123 
    124    # Method names start with a lowercase letter.
    125    method_name = name[0].lower() + name[1:]
    126    if custom_writer:
    127        method_name += "_"
    128 
    129    method_args = []
    130    ret_type = "void"
    131    args_code = ""
    132    if args:
    133        for arg_name, arg_type in args.items():
    134            cpp_type, write_method = arg_writer_info[arg_type]
    135            if arg_name == "result":
    136                ret_type = cpp_type
    137                args_code += f"  {cpp_type} result(newOperandId());\\\n"
    138                args_code += "  writeOperandId(result);\\\n"
    139            else:
    140                method_args.append(f"{cpp_type} {arg_name}")
    141                args_code += f"  {write_method}({arg_name});\\\n"
    142 
    143    code = ""
    144    if custom_writer:
    145        code += "private:\\\n"
    146    code += "{} {}({}) {{\\\n".format(ret_type, method_name, ", ".join(method_args))
    147    code += f"  writeOp(CacheOp::{name});\\\n"
    148    code += args_code
    149    code += "  assertLengthMatches();\\\n"
    150    if ret_type != "void":
    151        code += "  return result;\\\n"
    152    code += "}"
    153    if custom_writer:
    154        code += "\\\npublic:"
    155    return code
    156 
    157 
    158 # Information for generating code using CacheIRReader for a single argument.
    159 # Tuple stores the C++ type, the suffix used for arguments/variables of this
    160 # type, and the expression to read this type from CacheIRReader.
    161 arg_reader_info = {
    162    "ValId": ("ValOperandId", "Id", "reader.valOperandId()"),
    163    "ObjId": ("ObjOperandId", "Id", "reader.objOperandId()"),
    164    "StringId": ("StringOperandId", "Id", "reader.stringOperandId()"),
    165    "SymbolId": ("SymbolOperandId", "Id", "reader.symbolOperandId()"),
    166    "BooleanId": ("BooleanOperandId", "Id", "reader.booleanOperandId()"),
    167    "Int32Id": ("Int32OperandId", "Id", "reader.int32OperandId()"),
    168    "NumberId": ("NumberOperandId", "Id", "reader.numberOperandId()"),
    169    "BigIntId": ("BigIntOperandId", "Id", "reader.bigIntOperandId()"),
    170    "ValueTagId": ("ValueTagOperandId", "Id", "reader.valueTagOperandId()"),
    171    "IntPtrId": ("IntPtrOperandId", "Id", "reader.intPtrOperandId()"),
    172    "RawId": ("uint32_t", "Id", "reader.rawOperandId()"),
    173    "ShapeField": ("uint32_t", "Offset", "reader.stubOffset()"),
    174    "WeakShapeField": ("uint32_t", "Offset", "reader.stubOffset()"),
    175    "ObjectField": ("uint32_t", "Offset", "reader.stubOffset()"),
    176    "WeakObjectField": ("uint32_t", "Offset", "reader.stubOffset()"),
    177    "StringField": ("uint32_t", "Offset", "reader.stubOffset()"),
    178    "AtomField": ("uint32_t", "Offset", "reader.stubOffset()"),
    179    "SymbolField": ("uint32_t", "Offset", "reader.stubOffset()"),
    180    "WeakBaseScriptField": ("uint32_t", "Offset", "reader.stubOffset()"),
    181    "JitCodeField": ("uint32_t", "Offset", "reader.stubOffset()"),
    182    "RawInt32Field": ("uint32_t", "Offset", "reader.stubOffset()"),
    183    "RawPointerField": ("uint32_t", "Offset", "reader.stubOffset()"),
    184    "IdField": ("uint32_t", "Offset", "reader.stubOffset()"),
    185    "ValueField": ("uint32_t", "Offset", "reader.stubOffset()"),
    186    "WeakValueField": ("uint32_t", "Offset", "reader.stubOffset()"),
    187    "RawInt64Field": ("uint32_t", "Offset", "reader.stubOffset()"),
    188    "DoubleField": ("uint32_t", "Offset", "reader.stubOffset()"),
    189    "AllocSiteField": ("uint32_t", "Offset", "reader.stubOffset()"),
    190    "JSOpImm": ("JSOp", "", "reader.jsop()"),
    191    "JSTypeImm": ("JSType", "", "reader.jstype()"),
    192    "TypeofEqOperandImm": ("TypeofEqOperand", "", "reader.typeofEqOperand()"),
    193    "BoolImm": ("bool", "", "reader.readBool()"),
    194    "ByteImm": ("uint8_t", "", "reader.readByte()"),
    195    "GuardClassKindImm": ("GuardClassKind", "", "reader.guardClassKind()"),
    196    "ArrayBufferViewKindImm": (
    197        "ArrayBufferViewKind",
    198        "",
    199        "reader.arrayBufferViewKind()",
    200    ),
    201    "ValueTypeImm": ("ValueType", "", "reader.valueType()"),
    202    "JSWhyMagicImm": ("JSWhyMagic", "", "reader.whyMagic()"),
    203    "CallFlagsImm": ("CallFlags", "", "reader.callFlags()"),
    204    "ScalarTypeImm": ("Scalar::Type", "", "reader.scalarType()"),
    205    "UnaryMathFunctionImm": ("UnaryMathFunction", "", "reader.unaryMathFunction()"),
    206    "WasmValTypeImm": ("wasm::ValType::Kind", "", "reader.wasmValType()"),
    207    "Int32Imm": ("int32_t", "", "reader.int32Immediate()"),
    208    "UInt32Imm": ("uint32_t", "", "reader.uint32Immediate()"),
    209    "JSNativeImm": ("JSNative", "", "reinterpret_cast<JSNative>(reader.pointer())"),
    210    "StaticStringImm": ("const char*", "", "reinterpret_cast<char*>(reader.pointer())"),
    211    "AllocKindImm": ("gc::AllocKind", "", "reader.allocKind()"),
    212    "CompletionKindImm": ("CompletionKind", "", "reader.completionKind()"),
    213    "RealmFuseIndexImm": ("RealmFuses::FuseIndex", "", "reader.realmFuseIndex()"),
    214    "RuntimeFuseIndexImm": ("RuntimeFuses::FuseIndex", "", "reader.runtimeFuseIndex()"),
    215 }
    216 
    217 
    218 def gen_compiler_method(name, args):
    219    """Generates CacheIRCompiler or WarpCacheIRTranspiler header code for a
    220    single opcode."""
    221 
    222    method_name = "emit" + name
    223 
    224    # We generate the signature of the method that needs to be implemented and a
    225    # separate function forwarding to it. For example:
    226    #
    227    #   [[nodiscard]] bool emitGuardShape(ObjOperandId objId, uint32_t shapeOffset);
    228    #   [[nodiscard]] bool emitGuardShape(CacheIRReader& reader) {
    229    #     ObjOperandId objId = reader.objOperandId();
    230    #     uint32_t shapeOffset = reader.stubOffset();
    231    #     return emitGuardShape(objId, shapeOffset);
    232    #   }
    233    cpp_args = []
    234    method_args = []
    235    args_code = ""
    236    if args:
    237        for arg_name, arg_type in args.items():
    238            cpp_type, suffix, readexpr = arg_reader_info[arg_type]
    239            cpp_name = arg_name + suffix
    240            cpp_args.append(cpp_name)
    241            method_args.append(f"{cpp_type} {cpp_name}")
    242            args_code += f"  {cpp_type} {cpp_name} = {readexpr};\\\n"
    243 
    244    # Generate signature.
    245    code = "[[nodiscard]] bool {}({});\\\n".format(method_name, ", ".join(method_args))
    246 
    247    # Generate the method forwarding to it.
    248    code += f"[[nodiscard]] bool {method_name}(CacheIRReader& reader) {{\\\n"
    249    code += args_code
    250    code += "  return {}({});\\\n".format(method_name, ", ".join(cpp_args))
    251    code += "}\\\n"
    252 
    253    return code
    254 
    255 
    256 def gen_reader_method(name, args):
    257    """Generates CacheIRReader code for a single opcode."""
    258 
    259    # Generate a struct that holds the opcode's arguments and a CacheIRReader
    260    # method that returns this struct. For example for GuardShape:
    261    #
    262    #   struct GuardShapeArgs final { ObjOperandId objId; uint32_t shapeOffset; };
    263    #
    264    #   GuardShapeArgs argsForGuardShape() {
    265    #     MOZ_ASSERT(*lastOp_ == CacheOp::GuardShape);
    266    #     ObjOperandId objId_ = this->objOperandId();
    267    #     uint32_t shapeOffset_ = this->stubOffset();
    268    #     return { objId_, shapeOffset_ };
    269    #   }
    270    #
    271    # Note that we use a trailing underscore for the variables to ensure variable
    272    # names don't conflict with class methods.
    273 
    274    struct_name = f"{name}Args"
    275    method_name = f"argsFor{name}"
    276 
    277    read_args_code = ""
    278    method_vars = []
    279    struct_fields = []
    280 
    281    if args:
    282        for arg_name, arg_type in args.items():
    283            cpp_type, suffix, readexpr = arg_reader_info[arg_type]
    284            readexpr = readexpr.replace("reader.", "this->")
    285            cpp_field_name = arg_name + suffix
    286            cpp_var_name = cpp_field_name + "_"
    287            method_vars.append(cpp_var_name)
    288            struct_fields.append(f"{cpp_type} {cpp_field_name};")
    289            read_args_code += f"  {cpp_type} {cpp_var_name} = {readexpr};\\\n"
    290 
    291    # Generate struct.
    292    code = f"struct {struct_name} final {{ {' '.join(struct_fields)} }};\\\n"
    293 
    294    # Generate reader method.
    295    code += f"{struct_name} {method_name}() {{\\\n"
    296    code += f"  MOZ_ASSERT(*lastOp_ == CacheOp::{name});\\\n"
    297    code += read_args_code
    298    vars_list = ", ".join(method_vars)
    299    code += f"  return {{ {vars_list} }};\\\n"
    300    code += "}\\\n"
    301 
    302    return code
    303 
    304 
    305 # For each argument type, the method name for printing it.
    306 arg_spewer_method = {
    307    "ValId": "spewOperandId",
    308    "ObjId": "spewOperandId",
    309    "StringId": "spewOperandId",
    310    "SymbolId": "spewOperandId",
    311    "BooleanId": "spewOperandId",
    312    "Int32Id": "spewOperandId",
    313    "NumberId": "spewOperandId",
    314    "BigIntId": "spewOperandId",
    315    "ValueTagId": "spewOperandId",
    316    "IntPtrId": "spewOperandId",
    317    "RawId": "spewRawOperandId",
    318    "ShapeField": "spewField",
    319    "WeakShapeField": "spewField",
    320    "ObjectField": "spewField",
    321    "WeakObjectField": "spewField",
    322    "StringField": "spewField",
    323    "AtomField": "spewField",
    324    "SymbolField": "spewField",
    325    "WeakBaseScriptField": "spewField",
    326    "JitCodeField": "spewField",
    327    "RawInt32Field": "spewField",
    328    "RawPointerField": "spewField",
    329    "IdField": "spewField",
    330    "ValueField": "spewField",
    331    "WeakValueField": "spewField",
    332    "RawInt64Field": "spewField",
    333    "DoubleField": "spewField",
    334    "AllocSiteField": "spewField",
    335    "JSOpImm": "spewJSOpImm",
    336    "JSTypeImm": "spewJSTypeImm",
    337    "TypeofEqOperandImm": "spewTypeofEqOperandImm",
    338    "BoolImm": "spewBoolImm",
    339    "ByteImm": "spewByteImm",
    340    "GuardClassKindImm": "spewGuardClassKindImm",
    341    "ArrayBufferViewKindImm": "spewArrayBufferViewKindImm",
    342    "ValueTypeImm": "spewValueTypeImm",
    343    "JSWhyMagicImm": "spewJSWhyMagicImm",
    344    "CallFlagsImm": "spewCallFlagsImm",
    345    "ScalarTypeImm": "spewScalarTypeImm",
    346    "UnaryMathFunctionImm": "spewUnaryMathFunctionImm",
    347    "WasmValTypeImm": "spewWasmValTypeImm",
    348    "Int32Imm": "spewInt32Imm",
    349    "UInt32Imm": "spewUInt32Imm",
    350    "JSNativeImm": "spewJSNativeImm",
    351    "StaticStringImm": "spewStaticStringImm",
    352    "AllocKindImm": "spewAllocKindImm",
    353    "CompletionKindImm": "spewCompletionKindImm",
    354    "RealmFuseIndexImm": "spewRealmFuseIndexImm",
    355    "RuntimeFuseIndexImm": "spewRuntimeFuseIndexImm",
    356 }
    357 
    358 
    359 def gen_spewer_method(name, args):
    360    """Generates spewer code for a single opcode."""
    361 
    362    method_name = "spew" + name
    363 
    364    # Generate code like this:
    365    #
    366    #  void spewGuardShape(CacheIRReader& reader) {
    367    #     spewOp(CacheOp::GuardShape);
    368    #     spewOperandId("objId", reader.objOperandId());
    369    #     spewOperandSeparator();
    370    #     spewField("shapeOffset", reader.stubOffset());
    371    #     spewOpEnd();
    372    #  }
    373    args_code = ""
    374    if args:
    375        is_first = True
    376        for arg_name, arg_type in args.items():
    377            _, suffix, readexpr = arg_reader_info[arg_type]
    378            arg_name += suffix
    379            spew_method = arg_spewer_method[arg_type]
    380            if not is_first:
    381                args_code += "  spewArgSeparator();\\\n"
    382            args_code += f'  {spew_method}("{arg_name}", {readexpr});\\\n'
    383            is_first = False
    384 
    385    code = f"void {method_name}(CacheIRReader& reader) {{\\\n"
    386    code += f"  spewOp(CacheOp::{name});\\\n"
    387    code += args_code
    388    code += "  spewOpEnd();\\\n"
    389    code += "}\\\n"
    390 
    391    return code
    392 
    393 
    394 def gen_clone_method(name, args):
    395    """Generates code for cloning a single opcode."""
    396 
    397    method_name = "clone" + name
    398 
    399    # Generate code like this:
    400    #
    401    #  void cloneGuardShape(CacheIRReader& reader, CacheIRWriter& writer) {
    402    #    writer.writeOp(CacheOp::GuardShape);
    403    #    ObjOperandId objId = reader.objOperandId();
    404    #    writer.writeOperandId(objId);
    405    #    uint32_t shapeOffset = reader.stubOffset();
    406    #    Shape* shape = getShapeField(shapeOffset);
    407    #    writer.writeShapeField(shape);
    408    #    writer.assertLengthMatches();
    409    #  }
    410 
    411    args_code = ""
    412    if args:
    413        for arg_name, arg_type in args.items():
    414            if arg_type == "RawId":
    415                arg_type = "ValId"
    416 
    417            read_type, suffix, readexpr = arg_reader_info[arg_type]
    418            read_name = arg_name + suffix
    419            value_name = read_name
    420            args_code += f"  {read_type} {read_name} = {readexpr};\\\n"
    421 
    422            write_type, write_method = arg_writer_info[arg_type]
    423            if arg_name == "result":
    424                args_code += "  writer.newOperandId();\\\n"
    425            if suffix == "Offset":
    426                # If the write function takes T&, the intermediate variable
    427                # should be of type T.
    428                if write_type.endswith("&"):
    429                    write_type = write_type[:-1]
    430                value_name = arg_name
    431                args_code += (
    432                    f"  {write_type} {value_name} = get{arg_type}({read_name});\\\n"
    433                )
    434            args_code += f"  writer.{write_method}({value_name});\\\n"
    435 
    436    code = f"void {method_name}"
    437    code += "(CacheIRReader& reader, CacheIRWriter& writer) {{\\\n"
    438    code += f"  writer.writeOp(CacheOp::{name});\\\n"
    439    code += args_code
    440    code += "  writer.assertLengthMatches();\\\n"
    441    code += "}}\\\n"
    442 
    443    return code
    444 
    445 
    446 # Length in bytes for each argument type, either an integer or a C++ expression.
    447 # This is used to generate the CacheIROpArgLengths array. CacheIRWriter asserts
    448 # the number of bytes written matches the value in that array.
    449 arg_length = {
    450    "ValId": 1,
    451    "ObjId": 1,
    452    "StringId": 1,
    453    "SymbolId": 1,
    454    "BooleanId": 1,
    455    "Int32Id": 1,
    456    "NumberId": 1,
    457    "BigIntId": 1,
    458    "ValueTagId": 1,
    459    "IntPtrId": 1,
    460    "RawId": 1,
    461    "ShapeField": 1,
    462    "WeakShapeField": 1,
    463    "ObjectField": 1,
    464    "WeakObjectField": 1,
    465    "StringField": 1,
    466    "AtomField": 1,
    467    "SymbolField": 1,
    468    "WeakBaseScriptField": 1,
    469    "JitCodeField": 1,
    470    "RawInt32Field": 1,
    471    "RawPointerField": 1,
    472    "RawInt64Field": 1,
    473    "DoubleField": 1,
    474    "IdField": 1,
    475    "ValueField": 1,
    476    "WeakValueField": 1,
    477    "AllocSiteField": 1,
    478    "ByteImm": 1,
    479    "BoolImm": 1,
    480    "CallFlagsImm": 1,
    481    "ScalarTypeImm": 1,
    482    "UnaryMathFunctionImm": 1,
    483    "JSOpImm": 1,
    484    "JSTypeImm": 1,
    485    "TypeofEqOperandImm": 1,
    486    "ValueTypeImm": 1,
    487    "GuardClassKindImm": 1,
    488    "ArrayBufferViewKindImm": 1,
    489    "JSWhyMagicImm": 1,
    490    "WasmValTypeImm": 1,
    491    "Int32Imm": 4,
    492    "UInt32Imm": 4,
    493    "JSNativeImm": "sizeof(uintptr_t)",
    494    "StaticStringImm": "sizeof(uintptr_t)",
    495    "AllocKindImm": 1,
    496    "CompletionKindImm": 1,
    497    "RealmFuseIndexImm": 1,
    498    "RuntimeFuseIndexImm": 1,
    499 }
    500 
    501 
    502 def generate_cacheirops_header(c_out, yaml_path):
    503    """Generate CacheIROpsGenerated.h from CacheIROps.yaml. The generated file
    504    contains a list of all CacheIR ops and generated source code for
    505    CacheIRWriter and CacheIRCompiler."""
    506 
    507    data = load_yaml(yaml_path)
    508 
    509    # CACHE_IR_OPS items. Each item stores an opcode name and arguments length
    510    # expression. For example: _(GuardShape, 1 + 1)
    511    ops_items = []
    512 
    513    # Generated CacheIRWriter methods.
    514    writer_methods = []
    515 
    516    # Generated CacheIRReader methods.
    517    reader_methods = []
    518 
    519    # Generated CacheIRCompiler methods.
    520    compiler_shared_methods = []
    521    compiler_unshared_methods = []
    522 
    523    # Generated WarpCacheIRTranspiler methods.
    524    transpiler_methods = []
    525 
    526    # List of ops supported by WarpCacheIRTranspiler.
    527    transpiler_ops = []
    528 
    529    # Generated methods for spewers.
    530    spewer_methods = []
    531 
    532    # Generated methods for cloning IC stubs
    533    clone_methods = []
    534 
    535    for op in data:
    536        name = op["name"]
    537 
    538        args = op["args"]
    539        assert args is None or isinstance(args, dict)
    540 
    541        shared = op["shared"]
    542        assert isinstance(shared, bool)
    543 
    544        transpile = op["transpile"]
    545        assert isinstance(transpile, bool)
    546 
    547        # Unscored Ops default to UINT32_MAX
    548        cost_estimate = op.get("cost_estimate", 0xFFFFFFFF)
    549        assert isinstance(cost_estimate, int)
    550 
    551        custom_writer = op.get("custom_writer", False)
    552        assert isinstance(custom_writer, bool)
    553 
    554        if args:
    555            args_length = " + ".join([str(arg_length[v]) for v in args.values()])
    556        else:
    557            args_length = "0"
    558 
    559        transpile_str = "true" if transpile else "false"
    560        ops_items.append(f"_({name}, {args_length}, {transpile_str}, {cost_estimate})")
    561 
    562        writer_methods.append(gen_writer_method(name, args, custom_writer))
    563        reader_methods.append(gen_reader_method(name, args))
    564 
    565        if shared:
    566            compiler_shared_methods.append(gen_compiler_method(name, args))
    567        else:
    568            compiler_unshared_methods.append(gen_compiler_method(name, args))
    569 
    570        if transpile:
    571            transpiler_methods.append(gen_compiler_method(name, args))
    572            transpiler_ops.append(f"_({name})")
    573 
    574        spewer_methods.append(gen_spewer_method(name, args))
    575 
    576        clone_methods.append(gen_clone_method(name, args))
    577 
    578    contents = "#define CACHE_IR_OPS(_)\\\n"
    579    contents += "\\\n".join(ops_items)
    580    contents += "\n\n"
    581 
    582    contents += "#define CACHE_IR_WRITER_GENERATED \\\n"
    583    contents += "\\\n".join(writer_methods)
    584    contents += "\n\n"
    585 
    586    contents += "#define CACHE_IR_READER_GENERATED \\\n"
    587    contents += "\\\n".join(reader_methods)
    588    contents += "\n\n"
    589 
    590    contents += "#define CACHE_IR_COMPILER_SHARED_GENERATED \\\n"
    591    contents += "\\\n".join(compiler_shared_methods)
    592    contents += "\n\n"
    593 
    594    contents += "#define CACHE_IR_COMPILER_UNSHARED_GENERATED \\\n"
    595    contents += "\\\n".join(compiler_unshared_methods)
    596    contents += "\n\n"
    597 
    598    contents += "#define CACHE_IR_TRANSPILER_GENERATED \\\n"
    599    contents += "\\\n".join(transpiler_methods)
    600    contents += "\n\n"
    601 
    602    contents += "#define CACHE_IR_TRANSPILER_OPS(_)\\\n"
    603    contents += "\\\n".join(transpiler_ops)
    604    contents += "\n\n"
    605 
    606    contents += "#define CACHE_IR_SPEWER_GENERATED \\\n"
    607    contents += "\\\n".join(spewer_methods)
    608    contents += "\n\n"
    609 
    610    contents += "#define CACHE_IR_CLONE_GENERATED \\\n"
    611    contents += "\\\n".join(clone_methods)
    612    contents += "\n\n"
    613 
    614    generate_header(c_out, "jit_CacheIROpsGenerated_h", contents)
    615 
    616 
    617 def read_aot_ics(ic_path):
    618    ics = ""
    619    idx = 0
    620    for entry in os.scandir(ic_path):
    621        if entry.is_file() and os.path.basename(entry.path).startswith("IC-"):
    622            with open(entry.path) as f:
    623                content = f.read().strip()
    624                ics += "  _(%d, %s) \\\n" % (idx, content)
    625                idx += 1
    626    return ics
    627 
    628 
    629 def generate_aot_ics_header(c_out, ic_path):
    630    """Generate CacheIROpsGenerated.h from AOT IC corpus."""
    631 
    632    # Read in all ICs from js/src/ics/IC-*.
    633    ics = read_aot_ics(ic_path)
    634 
    635    contents = "#define JS_AOT_IC_DATA(_) \\\n"
    636    contents += ics
    637    contents += "\n"
    638 
    639    generate_header(c_out, "jit_CacheIRAOTGenerated_h", contents)