diff --git a/config/check_spidermonkey_style.py b/config/check_spidermonkey_style.py index f310d06a4efbc..9428e5be9d097 100644 --- a/config/check_spidermonkey_style.py +++ b/config/check_spidermonkey_style.py @@ -123,6 +123,7 @@ "unicode/utypes.h", # ICU "unicode/uversion.h", # ICU "vtune/VTuneWrapper.h", # VTune + "wasm/WasmIntrinsicGenerated.h", # generated in $OBJDIR" "zydis/ZydisAPI.h", # Zydis ] ) diff --git a/js/src/wasm/GenerateIntrinsics.py b/js/src/wasm/GenerateIntrinsics.py new file mode 100644 index 0000000000000..d4461a8cbbe2c --- /dev/null +++ b/js/src/wasm/GenerateIntrinsics.py @@ -0,0 +1,85 @@ +import buildconfig +import yaml +import six +from collections import OrderedDict +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 wasm/GenerateInstrinsic.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) + + +def main(c_out, yaml_path): + data = load_yaml(yaml_path) + + # Interate for all defined intrinsics + contents = "#define FOR_EACH_INTRINSIC(M) \\\n" + for i in range(len(data)): + op = data[i] + sa = op["symbolic_address"] + contents += ( + f" M({op['op']}, \"{op['export']}\", " + f"{sa['name']}, {sa['type']}, {op['entry']}, {i})\\\n" + ) + contents += "\n" + + for op in data: + # Define DECLARE_INTRINSIC_SAS_PARAM_VALTYPES_ as: + # `{ValType::I32, ValType::I32, ...}`. + contents += ( + f"#define DECLARE_INTRINSIC_SAS_PARAM_VALTYPES_{op['op']} " + f"{{ValType::{', ValType::'.join(op['params'])}}}\n" + ) + # Define DECLARE_INTRINSIC_PARAM_TYPES_ as: + # `, {_PTR, _I32, ..., _PTR, _END}`. + sas_types = f"{{_PTR{''.join(', _' + p for p in op['params'])}, _PTR, _END}}" + num_types = len(op["params"]) + 2 + contents += f"#define DECLARE_INTRINSIC_PARAM_TYPES_{op['op']} {num_types}, {sas_types}\n" + + generate_header(c_out, "wasm_WasmIntrinsicGenerated_h", contents) diff --git a/js/src/wasm/WasmBuiltins.cpp b/js/src/wasm/WasmBuiltins.cpp index e30fe2eaa55eb..73bd5684e5730 100644 --- a/js/src/wasm/WasmBuiltins.cpp +++ b/js/src/wasm/WasmBuiltins.cpp @@ -253,12 +253,13 @@ const SymbolicAddressSignature SASigRefTest = { SymbolicAddress::RefTest, _I32, _Infallible, 3, {_PTR, _RoN, _RoN, _END}}; const SymbolicAddressSignature SASigRttSub = { SymbolicAddress::RttSub, _RoN, _FailOnNullPtr, 3, {_PTR, _RoN, _RoN, _END}}; -const SymbolicAddressSignature SASigIntrI8VecMul = { - SymbolicAddress::IntrI8VecMul, - _VOID, - _FailOnNegI32, - 6, - {_PTR, _I32, _I32, _I32, _I32, _PTR, _END}}; +#define DECL_SAS_FOR_INTRINSIC(op, export, sa_name, abitype, entry, idx) \ + const SymbolicAddressSignature SASig##sa_name = { \ + SymbolicAddress::sa_name, _VOID, _FailOnNegI32, \ + DECLARE_INTRINSIC_PARAM_TYPES_##op}; + +FOR_EACH_INTRINSIC(DECL_SAS_FOR_INTRINSIC) +#undef DECL_SAS_FOR_INTRINSIC } // namespace wasm } // namespace js @@ -1277,12 +1278,12 @@ void* wasm::AddressOf(SymbolicAddress imm, ABIFunctionType* abiType) { *abiType = Args_General1; return FuncCast(PrintText, *abiType); #endif - case SymbolicAddress::IntrI8VecMul: - *abiType = MakeABIFunctionType( - ArgType_Int32, {ArgType_General, ArgType_Int32, ArgType_Int32, - ArgType_Int32, ArgType_Int32, ArgType_General}); - MOZ_ASSERT(*abiType == ToABIType(SASigIntrI8VecMul)); - return FuncCast(Instance::intrI8VecMul, *abiType); +#define DECL_SAS_TYPE_AND_FN(op, export, sa_name, abitype, entry, idx) \ + case SymbolicAddress::sa_name: \ + *abiType = abitype; \ + return FuncCast(entry, *abiType); + FOR_EACH_INTRINSIC(DECL_SAS_TYPE_AND_FN) +#undef DECL_SAS_TYPE_AND_FN case SymbolicAddress::Limit: break; } @@ -1409,7 +1410,10 @@ bool wasm::NeedsBuiltinThunk(SymbolicAddress sym) { case SymbolicAddress::ArrayNew: case SymbolicAddress::RefTest: case SymbolicAddress::RttSub: - case SymbolicAddress::IntrI8VecMul: +#define OP(op, export, sa_name, abitype, entry, idx) \ + case SymbolicAddress::sa_name: + FOR_EACH_INTRINSIC(OP) +#undef OP return true; case SymbolicAddress::Limit: break; diff --git a/js/src/wasm/WasmBuiltins.h b/js/src/wasm/WasmBuiltins.h index 2a3e226fe08a8..fcda615eb0275 100644 --- a/js/src/wasm/WasmBuiltins.h +++ b/js/src/wasm/WasmBuiltins.h @@ -20,6 +20,7 @@ #define wasm_builtins_h #include "jit/IonTypes.h" +#include "wasm/WasmIntrinsicGenerated.h" namespace js { namespace jit { @@ -123,9 +124,11 @@ enum class SymbolicAddress { #if defined(JS_CODEGEN_MIPS32) js_jit_gAtomic64Lock, #endif - IntrI8VecMul, +#define DECL_INTRINSIC_SA(op, export, sa_name, abitype, entry, idx) sa_name, + FOR_EACH_INTRINSIC(DECL_INTRINSIC_SA) +#undef DECL_INTRINSIC_SA #ifdef WASM_CODEGEN_DEBUG - PrintI32, + PrintI32, PrintPtr, PrintF32, PrintF64, diff --git a/js/src/wasm/WasmConstants.h b/js/src/wasm/WasmConstants.h index e258b994fcf84..78919d2803f11 100644 --- a/js/src/wasm/WasmConstants.h +++ b/js/src/wasm/WasmConstants.h @@ -21,6 +21,8 @@ #include +#include "wasm/WasmIntrinsicGenerated.h" + namespace js { namespace wasm { @@ -939,17 +941,16 @@ enum class ThreadOp { }; enum class IntrinsicOp { - // ------------------------------------------------------------------------ - // These operators are emitted internally when compiling intrinsic modules - // and are rejected by wasm validation. They are prefixed by - // IntrinsicPrefix. - - // i8vecmul(dest: i32, src1: i32, src2: i32, len: i32) - // Performs pairwise multiplication of two i8 vectors of 'len' specified at - // 'src1' and 'src2'. Output is written to 'dest'. This is used as a - // basic self-test for intrinsics. - I8VecMul = 0x0, - +// ------------------------------------------------------------------------ +// These operators are emitted internally when compiling intrinsic modules +// and are rejected by wasm validation. They are prefixed by +// IntrinsicPrefix. See wasm/WasmIntrinsic.yaml for the list. +#define DECL_INTRINSIC_OP(op, export, sa_name, abitype, entry, idx) \ + op = idx, // NOLINT + FOR_EACH_INTRINSIC(DECL_INTRINSIC_OP) +#undef DECL_INTRINSIC_OP + + // Op limit. Limit }; diff --git a/js/src/wasm/WasmFrameIter.cpp b/js/src/wasm/WasmFrameIter.cpp index 19d2306c95feb..45c957f79b444 100644 --- a/js/src/wasm/WasmFrameIter.cpp +++ b/js/src/wasm/WasmFrameIter.cpp @@ -23,6 +23,7 @@ #include "vm/JSContext.h" #include "wasm/WasmDebugFrame.h" #include "wasm/WasmInstance.h" +#include "wasm/WasmIntrinsicGenerated.h" #include "wasm/WasmStubs.h" #include "wasm/WasmTlsData.h" @@ -1527,8 +1528,11 @@ static const char* ThunkedNativeToDescription(SymbolicAddress func) { case SymbolicAddress::js_jit_gAtomic64Lock: MOZ_CRASH(); #endif - case SymbolicAddress::IntrI8VecMul: - return "call to native i8 vector multiplication intrinsic (in wasm)"; +#define OP(op, export, sa_name, abitype, entry, idx) \ + case SymbolicAddress::sa_name: \ + return "call to native " #op " intrinsic (in wasm)"; + FOR_EACH_INTRINSIC(OP) +#undef OP #ifdef WASM_CODEGEN_DEBUG case SymbolicAddress::PrintI32: case SymbolicAddress::PrintPtr: diff --git a/js/src/wasm/WasmIntrinsic.cpp b/js/src/wasm/WasmIntrinsic.cpp index 020fe28a622b7..22e48e9aa3320 100644 --- a/js/src/wasm/WasmIntrinsic.cpp +++ b/js/src/wasm/WasmIntrinsic.cpp @@ -22,6 +22,7 @@ #include "vm/GlobalObject.h" #include "wasm/WasmGenerator.h" +#include "wasm/WasmIntrinsicGenerated.h" #include "wasm/WasmJS.h" #include "wasm/WasmModule.h" #include "wasm/WasmOpIter.h" @@ -30,13 +31,18 @@ using namespace js; using namespace js::wasm; -static const ValType IntrinsicI8VecMul_Params[] = {ValType::I32, ValType::I32, - ValType::I32, ValType::I32}; -const Intrinsic IntrinsicI8VecMul = { - "i8vecmul", - mozilla::Span(IntrinsicI8VecMul_Params), - SASigIntrI8VecMul, -}; +#define INTR_DECL(op, export, sa_name, abitype, entry, idx) \ + static const ValType Intrinsic##op##_Params[] = \ + DECLARE_INTRINSIC_SAS_PARAM_VALTYPES_##op; \ + \ + const Intrinsic Intrinsic##op = { \ + export, \ + mozilla::Span(Intrinsic##op##_Params), \ + SASig##sa_name, \ + }; + +FOR_EACH_INTRINSIC(INTR_DECL) +#undef INTR_DECL bool Intrinsic::funcType(FuncType* type) const { ValTypeVector paramVec; @@ -50,8 +56,11 @@ bool Intrinsic::funcType(FuncType* type) const { /* static */ const Intrinsic& Intrinsic::getFromOp(IntrinsicOp op) { switch (op) { - case IntrinsicOp::I8VecMul: - return IntrinsicI8VecMul; +#define OP(op, export, sa_name, abitype, entry, idx) \ + case IntrinsicOp::op: \ + return Intrinsic##op; + FOR_EACH_INTRINSIC(OP) +#undef OP default: MOZ_CRASH("unexpected intrinsic"); } @@ -113,8 +122,8 @@ bool wasm::CompileIntrinsicModule(JSContext* cx, // Add (type (func (params ...))) for each intrinsic. The function types will // be deduplicated by the runtime - for (uint32_t funcIndex = 0; funcIndex < ops.size(); funcIndex++) { - const Intrinsic& intrinsic = Intrinsic::getFromOp(ops[funcIndex]); + for (const IntrinsicOp& op : ops) { + const Intrinsic& intrinsic = Intrinsic::getFromOp(op); FuncType type; if (!intrinsic.funcType(&type) || diff --git a/js/src/wasm/WasmIntrinsic.yaml b/js/src/wasm/WasmIntrinsic.yaml new file mode 100644 index 0000000000000..07a59674cc707 --- /dev/null +++ b/js/src/wasm/WasmIntrinsic.yaml @@ -0,0 +1,17 @@ +# The file contains information need to define wasm intrinsic operations. + +# i8vecmul(dest: i32, src1: i32, src2: i32, len: i32) +# Performs pairwise multiplication of two i8 vectors of 'len' specified at +# 'src1' and 'src2'. Output is written to 'dest'. This is used as a +# basic self-test for intrinsics. +- op: I8VecMul + symbolic_address: + name: IntrI8VecMul + type: Args_Int32_GeneralInt32Int32Int32Int32General + entry: Instance::intrI8VecMul + export: i8vecmul + params: + - I32 + - I32 + - I32 + - I32 diff --git a/js/src/wasm/moz.build b/js/src/wasm/moz.build index 12c5fce3e5318..c234e5dc16101 100644 --- a/js/src/wasm/moz.build +++ b/js/src/wasm/moz.build @@ -54,6 +54,13 @@ UNIFIED_SOURCES += [ "WasmValue.cpp", ] +# Generate wasm/WasmIntrinsicGenerated.h from wasm/WasmIntrinsic.yaml +GeneratedFile( + "WasmIntrinsicGenerated.h", + script="GenerateIntrinsics.py", + inputs=["WasmIntrinsic.yaml"], +) + # We don't support signals for wasi yet. if CONFIG["OS_ARCH"] != "WASI": UNIFIED_SOURCES += ["WasmSignalHandlers.cpp"]