Source code

Revision control

Copy as Markdown

Other Tools

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/GenerateABIFunctionType.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()
return yaml.safe_load(contents)
def cpp_arg_type(arg_type):
if arg_type == "General":
return "intptr_t"
elif arg_type == "Int32":
return "int32_t"
elif arg_type == "Int64":
return "int64_t"
elif arg_type == "Float32":
return "float"
elif arg_type == "Float64":
return "double"
else:
raise ValueError(arg_type)
def func_type_name(func_type):
if "name" in func_type:
return func_type["name"]
# Autogenerate a name like `General_GeneralGeneral` if none is specified
return f"{func_type['ret']}_{''.join(func_type['args'])}"
def func_type_has_floats(func_type):
for arg in func_type["args"]:
if arg == "Float32" or arg == "Float64":
return True
return False
# Generate the ARM32 argument loading for a func type for when soft-FP is enabled
def arm32_soft_fp_args(func_type):
# This must match ABIArgGenerator::softNext() in Assembler-arm.cpp
contents = ""
numIntArgRegs = 4
intRegIndex = 0
stackOffset = 0
for i, arg in enumerate(func_type["args"]):
if i != 0:
contents += ", "
if arg == "General":
if intRegIndex == numIntArgRegs:
contents += f"stack_pointer[{stackOffset}]"
stackOffset += 1
else:
contents += f"a{intRegIndex}"
intRegIndex += 1
elif arg == "Int32":
if intRegIndex == numIntArgRegs:
contents += f"stack_pointer[{stackOffset}]"
stackOffset += 1
else:
contents += f"a{intRegIndex}"
intRegIndex += 1
elif arg == "Int64":
intRegIndex += intRegIndex % 2
if intRegIndex == numIntArgRegs:
stackOffset += stackOffset % 2
contents += f"MakeInt64(stack_pointer[{stackOffset}], stack_pointer[{stackOffset + 1}])"
stackOffset += 2
else:
contents += f"MakeInt64(a{intRegIndex}, a{intRegIndex+1})"
intRegIndex += 2
elif arg == "Float32":
if intRegIndex == numIntArgRegs:
contents += f"mozilla::BitwiseCast<float>(stack_pointer[{stackOffset}])"
stackOffset += 1
else:
contents += f"mozilla::BitwiseCast<float>(a{intRegIndex})"
intRegIndex += 1
elif arg == "Float64":
intRegIndex += intRegIndex % 2
if intRegIndex == numIntArgRegs:
stackOffset += stackOffset % 2
contents += f"mozilla::BitwiseCast<double>(MakeInt64(stack_pointer[{stackOffset}], stack_pointer[{stackOffset + 1}]))"
stackOffset += 2
else:
contents += f"mozilla::BitwiseCast<double>(MakeInt64(a{intRegIndex}, a{intRegIndex + 1}))"
intRegIndex += 2
assert intRegIndex <= numIntArgRegs
return contents
# Generate the ARM32 argument loading for a func type for when hard-FP is enabled
def arm32_hard_fp_args(func_type):
# This must match ABIArgGenerator::hardNext() in Assembler-arm.cpp
contents = ""
numIntArgRegs = 4
numFloatArgRegs = 16
intRegIndex = 0
floatRegIndex = 0
stackOffset = 0
for i, arg in enumerate(func_type["args"]):
if i != 0:
contents += ", "
if arg == "General":
if intRegIndex == numIntArgRegs:
contents += f"stack_pointer[{stackOffset}]"
stackOffset += 1
else:
contents += f"a{intRegIndex}"
intRegIndex += 1
elif arg == "Int32":
if intRegIndex == numIntArgRegs:
contents += f"stack_pointer[{stackOffset}]"
stackOffset += 1
else:
contents += f"a{intRegIndex}"
intRegIndex += 1
elif arg == "Int64":
intRegIndex += intRegIndex % 2
if intRegIndex == numIntArgRegs:
stackOffset += stackOffset % 2
contents += f"MakeInt64(stack_pointer[{stackOffset}], stack_pointer[{stackOffset + 1}])"
stackOffset += 2
else:
contents += f"MakeInt64(a{intRegIndex}, a{intRegIndex+1})"
intRegIndex += 2
elif arg == "Float32":
if floatRegIndex == numFloatArgRegs:
contents += f"mozilla::BitwiseCast<float>(stack_pointer[{stackOffset}])"
stackOffset += 1
else:
contents += f"s{floatRegIndex}"
floatRegIndex += 1
elif arg == "Float64":
floatRegIndex += floatRegIndex % 2
if floatRegIndex == numFloatArgRegs:
stackOffset += stackOffset % 2
contents += f"mozilla::BitwiseCast<double>(MakeInt64(stack_pointer[{stackOffset}], stack_pointer[{stackOffset + 1}]))"
stackOffset += 2
else:
contents += f"d{round(floatRegIndex / 2)}"
floatRegIndex += 2
assert intRegIndex <= numIntArgRegs
assert floatRegIndex <= numFloatArgRegs
return contents
def arm32_simulator_dispatch(func_types):
contents = ""
for func_type in func_types:
hard_fp_args = arm32_hard_fp_args(func_type)
soft_fp_args = arm32_soft_fp_args(func_type)
ret = func_type["ret"]
contents += f"case js::jit::Args_{func_type_name(func_type)}: {{\\\n"
contents += f" auto target = reinterpret_cast<Prototype_{func_type_name(func_type)}>(external);\\\n"
contents += f" {cpp_arg_type(ret)} ret;\\\n"
if func_type_has_floats(func_type):
contents += " if (UseHardFpABI()) {\\\n"
contents += f" ret = target({hard_fp_args});\\\n"
contents += " } else {\\\n"
contents += f" ret = target({soft_fp_args});\\\n"
contents += " }\\\n"
else:
# No float args means we don't need to check the float ABI and
# either generated args will do.
contents += f" ret = target({soft_fp_args});\\\n"
contents += " scratchVolatileRegisters((void*)target);\\\n"
if ret == "General" or ret == "Int32" or ret == "Int64":
contents += " setCallResult(ret);\\\n"
elif ret == "Float32":
contents += " setCallResultFloat(ret);\\\n"
elif ret == "Float64":
contents += " setCallResultDouble(ret);\\\n"
contents += " break;\\\n"
contents += "}\\\n"
return contents
# Generate the ARM64 argument loading for a func type
def arm64_args(func_type):
# This must match ABIArgGenerator::next() in Assembler-arm64.cpp
contents = ""
numIntArgRegs = 8
numFloatArgRegs = 8
intRegIndex = 0
floatRegIndex = 0
stackOffset = 0
for i, arg in enumerate(func_type["args"]):
if i != 0:
contents += ", "
if arg == "General":
if intRegIndex == numIntArgRegs:
contents += f"sp[{stackOffset}]"
stackOffset += 1
else:
contents += f"x{intRegIndex}"
intRegIndex += 1
elif arg == "Int32":
if intRegIndex == numIntArgRegs:
contents += f"sp[{stackOffset}]"
stackOffset += 1
else:
contents += f"x{intRegIndex}"
intRegIndex += 1
elif arg == "Int64":
if intRegIndex == numIntArgRegs:
contents += f"sp[{stackOffset}]"
stackOffset += 1
else:
contents += f"x{intRegIndex}"
intRegIndex += 1
elif arg == "Float32":
if floatRegIndex == numFloatArgRegs:
contents += f"mozilla::BitwiseCast<float>(sp[{stackOffset}])"
stackOffset += 1
else:
contents += f"s{floatRegIndex}"
floatRegIndex += 1
elif arg == "Float64":
if floatRegIndex == numFloatArgRegs:
contents += f"mozilla::BitwiseCast<double>(sp[{stackOffset}])"
stackOffset += 1
else:
contents += f"d{floatRegIndex}"
floatRegIndex += 1
assert intRegIndex <= numIntArgRegs
assert floatRegIndex <= numFloatArgRegs
return contents
def arm64_simulator_dispatch(func_types):
contents = ""
for func_type in func_types:
args = arm64_args(func_type)
contents += f"case js::jit::Args_{func_type_name(func_type)}: {{\\\n"
contents += f" auto target = reinterpret_cast<Prototype_{func_type_name(func_type)}>(nativeFn);\\\n"
contents += f" auto ret = target({args});\\\n"
ret = func_type["ret"]
if ret == "General":
contents += " setGPR64Result(ret);\\\n"
elif ret == "Int32":
contents += " setGPR32Result(ret);\\\n"
elif ret == "Int64":
contents += " setGPR64Result(ret);\\\n"
elif ret == "Float32":
contents += " setFP32Result(ret);\\\n"
elif ret == "Float64":
contents += " setFP64Result(ret);\\\n"
contents += " break;\\\n"
contents += "}\\\n"
return contents
# Generate the LoongArch64 argument loading for a func type
def loongarch64_args(func_type):
# This must match ABIArgGenerator::next() in Assembler-loong64.cpp
contents = ""
numIntArgRegs = 8
numFloatArgRegs = 8
intRegIndex = 0
floatRegIndex = 0
stackOffset = 0
for i, arg in enumerate(func_type["args"]):
if i != 0:
contents += ", "
if arg == "General":
if intRegIndex == numIntArgRegs:
contents += f"sp_[{stackOffset}]"
stackOffset += 1
else:
contents += f"a{intRegIndex}_"
intRegIndex += 1
elif arg == "Int32":
if intRegIndex == numIntArgRegs:
contents += f"I32(sp_[{stackOffset}])"
stackOffset += 1
else:
contents += f"I32(a{intRegIndex}_)"
intRegIndex += 1
elif arg == "Int64":
if intRegIndex == numIntArgRegs:
contents += f"sp_[{stackOffset}]"
stackOffset += 1
else:
contents += f"a{intRegIndex}_"
intRegIndex += 1
elif arg == "Float32":
if floatRegIndex == numFloatArgRegs:
contents += f"*mozilla::BitwiseCast<float*>(sp_[{stackOffset}])"
stackOffset += 1
else:
contents += f"f{floatRegIndex}_s"
floatRegIndex += 1
elif arg == "Float64":
if floatRegIndex == numFloatArgRegs:
contents += f"mozilla::BitwiseCast<double>(sp_[{stackOffset}])"
stackOffset += 1
else:
contents += f"f{floatRegIndex}_d"
floatRegIndex += 1
assert intRegIndex <= numIntArgRegs
assert floatRegIndex <= numFloatArgRegs
return contents
def loongarch64_simulator_dispatch(func_types):
contents = ""
for func_type in func_types:
args = loongarch64_args(func_type)
contents += f"case js::jit::Args_{func_type_name(func_type)}: {{\\\n"
contents += f" auto target = reinterpret_cast<Prototype_{func_type_name(func_type)}>(nativeFn);\\\n"
contents += f" auto ret = target({args});\\\n"
ret = func_type["ret"]
if ret == "General":
contents += " setCallResult(ret);\\\n"
elif ret == "Int32":
contents += " setCallResult(I64(ret));\\\n"
elif ret == "Int64":
contents += " setCallResult(ret);\\\n"
elif ret == "Float32":
contents += " setCallResultFloat(ret);\\\n"
elif ret == "Float64":
contents += " setCallResultDouble(ret);\\\n"
contents += " break;\\\n"
contents += "}\\\n"
return contents
# Generate the MIPS64 argument loading for a func type
def mips64_args(func_type):
# This must match ABIArgGenerator::next() in Assembler-mips64.cpp
contents = ""
numIntArgRegs = 8
numFloatArgRegs = 8
regIndex = 0
stackOffset = 0
for i, arg in enumerate(func_type["args"]):
if i != 0:
contents += ", "
if arg == "General":
if regIndex == numIntArgRegs:
contents += f"sp_[{stackOffset}]"
stackOffset += 1
else:
contents += f"a{regIndex}_"
regIndex += 1
elif arg == "Int32":
if regIndex == numIntArgRegs:
contents += f"I32(sp_[{stackOffset}])"
stackOffset += 1
else:
contents += f"I32(a{regIndex}_)"
regIndex += 1
elif arg == "Int64":
if regIndex == numIntArgRegs:
contents += f"sp_[{stackOffset}]"
stackOffset += 1
else:
contents += f"a{regIndex}_"
regIndex += 1
elif arg == "Float32":
if regIndex == numFloatArgRegs:
contents += f"*mozilla::BitwiseCast<float*>(sp_[{stackOffset}])"
stackOffset += 1
else:
contents += f"f{regIndex + 12}_s"
regIndex += 1
elif arg == "Float64":
if regIndex == numFloatArgRegs:
contents += f"mozilla::BitwiseCast<double>(sp_[{stackOffset}])"
stackOffset += 1
else:
contents += f"f{regIndex + 12}_d"
regIndex += 1
assert regIndex <= numIntArgRegs
assert numIntArgRegs == numFloatArgRegs
return contents
def mips64_simulator_dispatch(func_types):
contents = ""
for func_type in func_types:
args = mips64_args(func_type)
contents += f"case js::jit::Args_{func_type_name(func_type)}: {{\\\n"
contents += f" auto target = reinterpret_cast<Prototype_{func_type_name(func_type)}>(nativeFn);\\\n"
contents += f" auto ret = target({args});\\\n"
ret = func_type["ret"]
if ret == "General":
contents += " setCallResult(ret);\\\n"
elif ret == "Int32":
contents += " setCallResult(I64(ret));\\\n"
elif ret == "Int64":
contents += " setCallResult(ret);\\\n"
elif ret == "Float32":
contents += " setCallResultFloat(ret);\\\n"
elif ret == "Float64":
contents += " setCallResultDouble(ret);\\\n"
contents += " break;\\\n"
contents += "}\\\n"
return contents
def main(c_out, yaml_path):
func_types = load_yaml(yaml_path)
# Define the ABIFunctionType enum
contents = "#define ABI_FUNCTION_TYPE_ENUM \\\n"
for func_type in func_types:
name = "Args_" + func_type_name(func_type)
args = ", ".join(f"ABIType::{p}" for p in func_type["args"])
ret = f"ABIType::{func_type['ret']}"
contents += f" {name} = detail::MakeABIFunctionType({ret}, {{{args}}}),\\\n"
contents += "\n"
# Define the prototypes of the types
contents += "#define ABI_FUNCTION_TYPE_SIM_PROTOTYPES \\\n"
for func_type in func_types:
name = "Prototype_" + func_type_name(func_type)
args = ", ".join(cpp_arg_type(p) for p in func_type["args"])
ret = cpp_arg_type(func_type["ret"])
contents += f" typedef {ret} (*{name})({args});\\\n"
contents += "\n"
contents += "#define ABI_FUNCTION_TYPE_ARM64_SIM_DISPATCH \\\n"
contents += arm64_simulator_dispatch(func_types)
contents += "\n"
contents += "#define ABI_FUNCTION_TYPE_ARM32_SIM_DISPATCH \\\n"
contents += arm32_simulator_dispatch(func_types)
contents += "\n"
contents += "#define ABI_FUNCTION_TYPE_LOONGARCH64_SIM_DISPATCH \\\n"
contents += loongarch64_simulator_dispatch(func_types)
contents += "\n"
contents += "#define ABI_FUNCTION_TYPE_MIPS64_SIM_DISPATCH \\\n"
contents += mips64_simulator_dispatch(func_types)
contents += "\n"
generate_header(c_out, "jit_ABIFunctionTypeGenerated_h", contents)