tor-browser

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

GenerateABIFunctionType.py (20944B)


      1 import io
      2 
      3 import buildconfig
      4 import yaml
      5 from mozbuild.preprocessor import Preprocessor
      6 
      7 HEADER_TEMPLATE = """\
      8 /* This Source Code Form is subject to the terms of the Mozilla Public
      9 * License, v. 2.0. If a copy of the MPL was not distributed with this
     10 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     11 
     12 #ifndef %(includeguard)s
     13 #define %(includeguard)s
     14 
     15 /* This file is generated by jit/GenerateABIFunctionType.py. Do not edit! */
     16 
     17 %(contents)s
     18 
     19 #endif // %(includeguard)s
     20 """
     21 
     22 
     23 def generate_header(c_out, includeguard, contents):
     24    c_out.write(
     25        HEADER_TEMPLATE
     26        % {
     27            "includeguard": includeguard,
     28            "contents": contents,
     29        }
     30    )
     31 
     32 
     33 def load_yaml(yaml_path):
     34    # First invoke preprocessor.py so that we can use #ifdef JS_SIMULATOR in
     35    # the YAML file.
     36    pp = Preprocessor()
     37    pp.context.update(buildconfig.defines["ALLDEFINES"])
     38    pp.out = io.StringIO()
     39    pp.do_filter("substitution")
     40    pp.do_include(yaml_path)
     41    contents = pp.out.getvalue()
     42    return yaml.safe_load(contents)
     43 
     44 
     45 def cpp_arg_type(arg_type):
     46    if arg_type == "General":
     47        return "intptr_t"
     48    elif arg_type == "Int32":
     49        return "int32_t"
     50    elif arg_type == "Int64":
     51        return "int64_t"
     52    elif arg_type == "Float32":
     53        return "float"
     54    elif arg_type == "Float64":
     55        return "double"
     56    elif arg_type == "Void":
     57        return "void"
     58    else:
     59        raise ValueError(arg_type)
     60 
     61 
     62 def func_type_name(func_type):
     63    if "name" in func_type:
     64        return func_type["name"]
     65 
     66    # Autogenerate a name like `General_GeneralGeneral` if none is specified
     67    return f"{func_type['ret']}_{''.join(func_type['args'])}"
     68 
     69 
     70 def func_type_has_floats(func_type):
     71    for arg in func_type["args"]:
     72        if arg in {"Float32", "Float64"}:
     73            return True
     74    return False
     75 
     76 
     77 # Generate the ARM32 argument loading for a func type for when soft-FP is enabled
     78 def arm32_soft_fp_args(func_type):
     79    # This must match ABIArgGenerator::softNext() in Assembler-arm.cpp
     80    contents = ""
     81    numIntArgRegs = 4
     82    intRegIndex = 0
     83    stackOffset = 0
     84    for i, arg in enumerate(func_type["args"]):
     85        if i != 0:
     86            contents += ", "
     87 
     88        if arg == "General":
     89            if intRegIndex == numIntArgRegs:
     90                contents += f"stack_pointer[{stackOffset}]"
     91                stackOffset += 1
     92            else:
     93                contents += f"a{intRegIndex}"
     94                intRegIndex += 1
     95        elif arg == "Int32":
     96            if intRegIndex == numIntArgRegs:
     97                contents += f"stack_pointer[{stackOffset}]"
     98                stackOffset += 1
     99            else:
    100                contents += f"a{intRegIndex}"
    101                intRegIndex += 1
    102        elif arg == "Int64":
    103            intRegIndex += intRegIndex % 2
    104            if intRegIndex == numIntArgRegs:
    105                stackOffset += stackOffset % 2
    106                contents += f"MakeInt64(stack_pointer[{stackOffset}], stack_pointer[{stackOffset + 1}])"
    107                stackOffset += 2
    108            else:
    109                contents += f"MakeInt64(a{intRegIndex}, a{intRegIndex + 1})"
    110                intRegIndex += 2
    111        elif arg == "Float32":
    112            if intRegIndex == numIntArgRegs:
    113                contents += f"mozilla::BitwiseCast<float>(stack_pointer[{stackOffset}])"
    114                stackOffset += 1
    115            else:
    116                contents += f"mozilla::BitwiseCast<float>(a{intRegIndex})"
    117                intRegIndex += 1
    118        elif arg == "Float64":
    119            intRegIndex += intRegIndex % 2
    120            if intRegIndex == numIntArgRegs:
    121                stackOffset += stackOffset % 2
    122                contents += f"mozilla::BitwiseCast<double>(MakeInt64(stack_pointer[{stackOffset}], stack_pointer[{stackOffset + 1}]))"
    123                stackOffset += 2
    124            else:
    125                contents += f"mozilla::BitwiseCast<double>(MakeInt64(a{intRegIndex}, a{intRegIndex + 1}))"
    126                intRegIndex += 2
    127    assert intRegIndex <= numIntArgRegs
    128    return contents
    129 
    130 
    131 # Generate the ARM32 argument loading for a func type for when hard-FP is enabled
    132 def arm32_hard_fp_args(func_type):
    133    # This must match ABIArgGenerator::hardNext() in Assembler-arm.cpp
    134    contents = ""
    135    numIntArgRegs = 4
    136    numFloatArgRegs = 16
    137    intRegIndex = 0
    138    floatRegIndex = 0
    139    stackOffset = 0
    140    for i, arg in enumerate(func_type["args"]):
    141        if i != 0:
    142            contents += ", "
    143 
    144        if arg == "General":
    145            if intRegIndex == numIntArgRegs:
    146                contents += f"stack_pointer[{stackOffset}]"
    147                stackOffset += 1
    148            else:
    149                contents += f"a{intRegIndex}"
    150                intRegIndex += 1
    151        elif arg == "Int32":
    152            if intRegIndex == numIntArgRegs:
    153                contents += f"stack_pointer[{stackOffset}]"
    154                stackOffset += 1
    155            else:
    156                contents += f"a{intRegIndex}"
    157                intRegIndex += 1
    158        elif arg == "Int64":
    159            intRegIndex += intRegIndex % 2
    160            if intRegIndex == numIntArgRegs:
    161                stackOffset += stackOffset % 2
    162                contents += f"MakeInt64(stack_pointer[{stackOffset}], stack_pointer[{stackOffset + 1}])"
    163                stackOffset += 2
    164            else:
    165                contents += f"MakeInt64(a{intRegIndex}, a{intRegIndex + 1})"
    166                intRegIndex += 2
    167        elif arg == "Float32":
    168            if floatRegIndex == numFloatArgRegs:
    169                contents += f"mozilla::BitwiseCast<float>(stack_pointer[{stackOffset}])"
    170                stackOffset += 1
    171            else:
    172                contents += f"s{floatRegIndex}"
    173                floatRegIndex += 1
    174        elif arg == "Float64":
    175            floatRegIndex += floatRegIndex % 2
    176            if floatRegIndex == numFloatArgRegs:
    177                stackOffset += stackOffset % 2
    178                contents += f"mozilla::BitwiseCast<double>(MakeInt64(stack_pointer[{stackOffset}], stack_pointer[{stackOffset + 1}]))"
    179                stackOffset += 2
    180            else:
    181                contents += f"d{round(floatRegIndex / 2)}"
    182                floatRegIndex += 2
    183    assert intRegIndex <= numIntArgRegs
    184    assert floatRegIndex <= numFloatArgRegs
    185    return contents
    186 
    187 
    188 def arm32_simulator_dispatch(func_types):
    189    contents = ""
    190    for func_type in func_types:
    191        hard_fp_args = arm32_hard_fp_args(func_type)
    192        soft_fp_args = arm32_soft_fp_args(func_type)
    193        ret = func_type["ret"]
    194        has_ret = ret != "Void"
    195        ret_setter = "ret = " if has_ret else ""
    196 
    197        contents += f"case js::jit::Args_{func_type_name(func_type)}: {{\\\n"
    198        contents += f"  auto target = reinterpret_cast<Prototype_{func_type_name(func_type)}>(external);\\\n"
    199        if has_ret:
    200            contents += f"  {cpp_arg_type(ret)} ret;\\\n"
    201        if func_type_has_floats(func_type):
    202            contents += "  if (ARMFlags::UseHardFpABI()) {\\\n"
    203            contents += f"    {ret_setter}target({hard_fp_args});\\\n"
    204            contents += "  } else {\\\n"
    205            contents += f"    {ret_setter}target({soft_fp_args});\\\n"
    206            contents += "  }\\\n"
    207        else:
    208            # No float args means we don't need to check the float ABI and
    209            # either generated args will do.
    210            contents += f"  {ret_setter}target({soft_fp_args});\\\n"
    211        contents += "  scratchVolatileRegisters((void*)target);\\\n"
    212        if ret in {"General", "Int32", "Int64"}:
    213            contents += "  setCallResult(ret);\\\n"
    214        elif ret == "Float32":
    215            contents += "  setCallResultFloat(ret);\\\n"
    216        elif ret == "Float64":
    217            contents += "  setCallResultDouble(ret);\\\n"
    218        contents += "  break;\\\n"
    219        contents += "}\\\n"
    220    return contents
    221 
    222 
    223 # Generate the ARM64 argument loading for a func type
    224 def arm64_args(func_type):
    225    # This must match ABIArgGenerator::next() in Assembler-arm64.cpp
    226    contents = ""
    227    numIntArgRegs = 8
    228    numFloatArgRegs = 8
    229    intRegIndex = 0
    230    floatRegIndex = 0
    231    stackOffset = 0
    232    for i, arg in enumerate(func_type["args"]):
    233        if i != 0:
    234            contents += ", "
    235 
    236        if arg == "General":
    237            if intRegIndex == numIntArgRegs:
    238                contents += f"sp[{stackOffset}]"
    239                stackOffset += 1
    240            else:
    241                contents += f"x{intRegIndex}"
    242                intRegIndex += 1
    243        elif arg == "Int32":
    244            if intRegIndex == numIntArgRegs:
    245                contents += f"sp[{stackOffset}]"
    246                stackOffset += 1
    247            else:
    248                contents += f"x{intRegIndex}"
    249                intRegIndex += 1
    250        elif arg == "Int64":
    251            if intRegIndex == numIntArgRegs:
    252                contents += f"sp[{stackOffset}]"
    253                stackOffset += 1
    254            else:
    255                contents += f"x{intRegIndex}"
    256                intRegIndex += 1
    257        elif arg == "Float32":
    258            if floatRegIndex == numFloatArgRegs:
    259                contents += f"mozilla::BitwiseCast<float>(sp[{stackOffset}])"
    260                stackOffset += 1
    261            else:
    262                contents += f"s{floatRegIndex}"
    263                floatRegIndex += 1
    264        elif arg == "Float64":
    265            if floatRegIndex == numFloatArgRegs:
    266                contents += f"mozilla::BitwiseCast<double>(sp[{stackOffset}])"
    267                stackOffset += 1
    268            else:
    269                contents += f"d{floatRegIndex}"
    270                floatRegIndex += 1
    271    assert intRegIndex <= numIntArgRegs
    272    assert floatRegIndex <= numFloatArgRegs
    273    return contents
    274 
    275 
    276 def arm64_simulator_dispatch(func_types):
    277    contents = ""
    278    for func_type in func_types:
    279        args = arm64_args(func_type)
    280        contents += f"case js::jit::Args_{func_type_name(func_type)}: {{\\\n"
    281        contents += f"  auto target = reinterpret_cast<Prototype_{func_type_name(func_type)}>(nativeFn);\\\n"
    282        ret = func_type["ret"]
    283        if ret == "Void":
    284            contents += f"  target({args});\\\n"
    285        else:
    286            contents += f"  auto ret = target({args});\\\n"
    287        if ret == "General":
    288            contents += "  setGPR64Result(ret);\\\n"
    289        elif ret == "Int32":
    290            contents += "  setGPR32Result(ret);\\\n"
    291        elif ret == "Int64":
    292            contents += "  setGPR64Result(ret);\\\n"
    293        elif ret == "Float32":
    294            contents += "  setFP32Result(ret);\\\n"
    295        elif ret == "Float64":
    296            contents += "  setFP64Result(ret);\\\n"
    297        contents += "  break;\\\n"
    298        contents += "}\\\n"
    299    return contents
    300 
    301 
    302 # Generate the LoongArch64 argument loading for a func type
    303 def loongarch64_args(func_type):
    304    # This must match ABIArgGenerator::next() in Assembler-loong64.cpp
    305    contents = ""
    306    numIntArgRegs = 8
    307    numFloatArgRegs = 8
    308    intRegIndex = 0
    309    floatRegIndex = 0
    310    stackOffset = 0
    311    for i, arg in enumerate(func_type["args"]):
    312        if i != 0:
    313            contents += ", "
    314 
    315        if arg == "General":
    316            if intRegIndex == numIntArgRegs:
    317                contents += f"sp_[{stackOffset}]"
    318                stackOffset += 1
    319            else:
    320                contents += f"a{intRegIndex}_"
    321                intRegIndex += 1
    322        elif arg == "Int32":
    323            if intRegIndex == numIntArgRegs:
    324                contents += f"I32(sp_[{stackOffset}])"
    325                stackOffset += 1
    326            else:
    327                contents += f"I32(a{intRegIndex}_)"
    328                intRegIndex += 1
    329        elif arg == "Int64":
    330            if intRegIndex == numIntArgRegs:
    331                contents += f"sp_[{stackOffset}]"
    332                stackOffset += 1
    333            else:
    334                contents += f"a{intRegIndex}_"
    335                intRegIndex += 1
    336        elif arg == "Float32":
    337            if floatRegIndex == numFloatArgRegs:
    338                contents += f"*mozilla::BitwiseCast<float*>(sp_[{stackOffset}])"
    339                stackOffset += 1
    340            else:
    341                contents += f"f{floatRegIndex}_s"
    342                floatRegIndex += 1
    343        elif arg == "Float64":
    344            if floatRegIndex == numFloatArgRegs:
    345                contents += f"mozilla::BitwiseCast<double>(sp_[{stackOffset}])"
    346                stackOffset += 1
    347            else:
    348                contents += f"f{floatRegIndex}_d"
    349                floatRegIndex += 1
    350    assert intRegIndex <= numIntArgRegs
    351    assert floatRegIndex <= numFloatArgRegs
    352    return contents
    353 
    354 
    355 def loongarch64_simulator_dispatch(func_types):
    356    contents = ""
    357    for func_type in func_types:
    358        args = loongarch64_args(func_type)
    359        contents += f"case js::jit::Args_{func_type_name(func_type)}: {{\\\n"
    360        contents += f"  auto target = reinterpret_cast<Prototype_{func_type_name(func_type)}>(nativeFn);\\\n"
    361        ret = func_type["ret"]
    362        if ret == "Void":
    363            contents += f"  target({args});\\\n"
    364        else:
    365            contents += f"  auto ret = target({args});\\\n"
    366        if ret == "General":
    367            contents += "  setCallResult(ret);\\\n"
    368        elif ret == "Int32":
    369            contents += "  setCallResult(I64(ret));\\\n"
    370        elif ret == "Int64":
    371            contents += "  setCallResult(ret);\\\n"
    372        elif ret == "Float32":
    373            contents += "  setCallResultFloat(ret);\\\n"
    374        elif ret == "Float64":
    375            contents += "  setCallResultDouble(ret);\\\n"
    376        contents += "  break;\\\n"
    377        contents += "}\\\n"
    378    return contents
    379 
    380 
    381 # Generate the MIPS64 argument loading for a func type
    382 def mips64_args(func_type):
    383    # This must match ABIArgGenerator::next() in Assembler-mips64.cpp
    384    contents = ""
    385    numIntArgRegs = 8
    386    numFloatArgRegs = 8
    387    regIndex = 0
    388    stackOffset = 0
    389    for i, arg in enumerate(func_type["args"]):
    390        if i != 0:
    391            contents += ", "
    392 
    393        if arg == "General":
    394            if regIndex == numIntArgRegs:
    395                contents += f"sp_[{stackOffset}]"
    396                stackOffset += 1
    397            else:
    398                contents += f"a{regIndex}_"
    399                regIndex += 1
    400        elif arg == "Int32":
    401            if regIndex == numIntArgRegs:
    402                contents += f"I32(sp_[{stackOffset}])"
    403                stackOffset += 1
    404            else:
    405                contents += f"I32(a{regIndex}_)"
    406                regIndex += 1
    407        elif arg == "Int64":
    408            if regIndex == numIntArgRegs:
    409                contents += f"sp_[{stackOffset}]"
    410                stackOffset += 1
    411            else:
    412                contents += f"a{regIndex}_"
    413                regIndex += 1
    414        elif arg == "Float32":
    415            if regIndex == numFloatArgRegs:
    416                contents += f"*mozilla::BitwiseCast<float*>(sp_[{stackOffset}])"
    417                stackOffset += 1
    418            else:
    419                contents += f"f{regIndex + 12}_s"
    420                regIndex += 1
    421        elif arg == "Float64":
    422            if regIndex == numFloatArgRegs:
    423                contents += f"mozilla::BitwiseCast<double>(sp_[{stackOffset}])"
    424                stackOffset += 1
    425            else:
    426                contents += f"f{regIndex + 12}_d"
    427                regIndex += 1
    428    assert regIndex <= numIntArgRegs
    429    assert numIntArgRegs == numFloatArgRegs
    430    return contents
    431 
    432 
    433 def mips64_simulator_dispatch(func_types):
    434    contents = ""
    435    for func_type in func_types:
    436        args = mips64_args(func_type)
    437        contents += f"case js::jit::Args_{func_type_name(func_type)}: {{\\\n"
    438        contents += f"  auto target = reinterpret_cast<Prototype_{func_type_name(func_type)}>(nativeFn);\\\n"
    439        ret = func_type["ret"]
    440        if ret == "Void":
    441            contents += f"  target({args});\\\n"
    442        else:
    443            contents += f"  auto ret = target({args});\\\n"
    444        if ret == "General":
    445            contents += "  setCallResult(ret);\\\n"
    446        elif ret == "Int32":
    447            contents += "  setCallResult(I64(ret));\\\n"
    448        elif ret == "Int64":
    449            contents += "  setCallResult(ret);\\\n"
    450        elif ret == "Float32":
    451            contents += "  setCallResultFloat(ret);\\\n"
    452        elif ret == "Float64":
    453            contents += "  setCallResultDouble(ret);\\\n"
    454        contents += "  break;\\\n"
    455        contents += "}\\\n"
    456    return contents
    457 
    458 
    459 def riscv64_args(func_type):
    460    # This must match ABIArgGenerator::next() in Assembler-riscv64.cpp
    461    contents = ""
    462    numIntArgRegs = 8
    463    numFloatArgRegs = 8
    464    regIndex = 0
    465    floatRegIndex = 0
    466    stackOffset = 0
    467    for i, arg in enumerate(func_type["args"]):
    468        if i != 0:
    469            contents += ", "
    470 
    471        if arg == "General":
    472            if regIndex == numIntArgRegs:
    473                contents += f"sp_[{stackOffset}]"
    474                stackOffset += 1
    475            else:
    476                contents += f"arg{regIndex}"
    477                regIndex += 1
    478        elif arg == "Int32":
    479            if regIndex == numIntArgRegs:
    480                contents += f"I32(sp_[{stackOffset}])"
    481                stackOffset += 1
    482            else:
    483                contents += f"I32(arg{regIndex})"
    484                regIndex += 1
    485        elif arg == "Int64":
    486            if regIndex == numIntArgRegs:
    487                contents += f"sp_[{stackOffset}]"
    488                stackOffset += 1
    489            else:
    490                contents += f"arg{regIndex}"
    491                regIndex += 1
    492        elif arg == "Float32":
    493            if floatRegIndex == numFloatArgRegs:
    494                contents += f"mozilla::BitwiseCast<float>(static_cast<uint32_t>(sp_[{stackOffset}]))"
    495                stackOffset += 1
    496            else:
    497                contents += f"getFpuRegisterFloat(fa{floatRegIndex})"
    498                floatRegIndex += 1
    499        elif arg == "Float64":
    500            if floatRegIndex == numFloatArgRegs:
    501                contents += f"mozilla::BitwiseCast<double>(static_cast<uint64_t>(sp_[{stackOffset}]))"
    502                stackOffset += 1
    503            else:
    504                contents += f"getFpuRegisterDouble(fa{floatRegIndex})"
    505                floatRegIndex += 1
    506        else:
    507            raise ValueError(f"Unknown arg type: {arg}")
    508    return contents
    509 
    510 
    511 def riscv64_simulator_dispatch(func_types):
    512    contents = ""
    513    for func_type in func_types:
    514        args = riscv64_args(func_type)
    515        contents += f"case js::jit::Args_{func_type_name(func_type)}: {{\\\n"
    516        contents += f"  auto target = reinterpret_cast<Prototype_{func_type_name(func_type)}>(nativeFn);\\\n"
    517        ret = func_type["ret"]
    518        if ret == "Void":
    519            contents += f"  target({args});\\\n"
    520        else:
    521            contents += f"  auto ret = target({args});\\\n"
    522        if ret == "Void":
    523            pass
    524        elif ret == "General":
    525            contents += "  setCallResult(ret);\\\n"
    526        elif ret == "Int32":
    527            contents += "  setCallResult(I64(ret));\\\n"
    528        elif ret == "Int64":
    529            contents += "  setCallResult(ret);\\\n"
    530        elif ret == "Float32":
    531            contents += "  setCallResultFloat(ret);\\\n"
    532        elif ret == "Float64":
    533            contents += "  setCallResultDouble(ret);\\\n"
    534        else:
    535            raise ValueError(f"Unknown ret type: {ret}")
    536        contents += "  break;\\\n"
    537        contents += "}\\\n"
    538    return contents
    539 
    540 
    541 def main(c_out, yaml_path):
    542    func_types = load_yaml(yaml_path)
    543 
    544    # Define the ABIFunctionType enum
    545    contents = "#define ABI_FUNCTION_TYPE_ENUM \\\n"
    546    for func_type in func_types:
    547        name = "Args_" + func_type_name(func_type)
    548        args = ", ".join(f"ABIType::{p}" for p in func_type["args"])
    549        ret = f"ABIType::{func_type['ret']}"
    550 
    551        contents += f"    {name} = detail::MakeABIFunctionType({ret}, {{{args}}}),\\\n"
    552    contents += "\n"
    553 
    554    # Define the prototypes of the types
    555    contents += "#define ABI_FUNCTION_TYPE_SIM_PROTOTYPES \\\n"
    556    for func_type in func_types:
    557        name = "Prototype_" + func_type_name(func_type)
    558        args = ", ".join(cpp_arg_type(p) for p in func_type["args"])
    559        ret = cpp_arg_type(func_type["ret"])
    560 
    561        contents += f"    typedef {ret} (*{name})({args});\\\n"
    562    contents += "\n"
    563 
    564    contents += "#define ABI_FUNCTION_TYPE_ARM64_SIM_DISPATCH \\\n"
    565    contents += arm64_simulator_dispatch(func_types)
    566    contents += "\n"
    567 
    568    contents += "#define ABI_FUNCTION_TYPE_ARM32_SIM_DISPATCH \\\n"
    569    contents += arm32_simulator_dispatch(func_types)
    570    contents += "\n"
    571 
    572    contents += "#define ABI_FUNCTION_TYPE_LOONGARCH64_SIM_DISPATCH \\\n"
    573    contents += loongarch64_simulator_dispatch(func_types)
    574    contents += "\n"
    575 
    576    contents += "#define ABI_FUNCTION_TYPE_MIPS64_SIM_DISPATCH \\\n"
    577    contents += mips64_simulator_dispatch(func_types)
    578    contents += "\n"
    579 
    580    contents += "#define ABI_FUNCTION_TYPE_RISCV64_SIM_DISPATCH \\\n"
    581    contents += riscv64_simulator_dispatch(func_types)
    582    contents += "\n"
    583 
    584    generate_header(c_out, "jit_ABIFunctionTypeGenerated_h", contents)