// Copyright 2022 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef V8_COMMON_C_SIGNATURE_H_ #define V8_COMMON_C_SIGNATURE_H_ #ifdef V8_USE_SIMULATOR_WITH_GENERIC_C_CALLS #include "include/v8-fast-api-calls.h" #endif // V8_USE_SIMULATOR_WITH_GENERIC_C_CALLS #include "src/codegen/machine-type.h" namespace v8 { namespace internal { namespace compiler { #define FOREACH_CTYPE_MACHINE_TYPE_MAPPING(V) \ V(void, MachineType::None()) \ V(bool, MachineType::Uint8()) \ V(int8_t, MachineType::Int8()) \ V(uint8_t, MachineType::Uint8()) \ V(int16_t, MachineType::Int16()) \ V(uint16_t, MachineType::Uint16()) \ V(int32_t, MachineType::Int32()) \ V(uint32_t, MachineType::Uint32()) \ V(int64_t, MachineType::Int64()) \ V(uint64_t, MachineType::Uint64()) \ V(float, MachineType::Float32()) \ V(double, MachineType::Float64()) \ V(void*, MachineType::Pointer()) \ V(int*, MachineType::Pointer()) template inline constexpr MachineType MachineTypeForC() { static_assert(std::is_convertible::value, "all non-specialized types must be convertible to Object"); return MachineType::AnyTagged(); } #define DECLARE_TEMPLATE_SPECIALIZATION(ctype, mtype) \ template <> \ inline MachineType constexpr MachineTypeForC() { \ return mtype; \ } FOREACH_CTYPE_MACHINE_TYPE_MAPPING(DECLARE_TEMPLATE_SPECIALIZATION) #undef DECLARE_TEMPLATE_SPECIALIZATION #ifdef V8_USE_SIMULATOR_WITH_GENERIC_C_CALLS template <> inline MachineType constexpr MachineTypeForC() { return MachineType::Int64(); } #endif // V8_USE_SIMULATOR_WITH_GENERIC_C_CALLS // Helper for building machine signatures from C types. class CSignature : public MachineSignature { protected: CSignature(size_t return_count, size_t parameter_count, MachineType* reps) : MachineSignature(return_count, parameter_count, reps) {} public: friend Zone; template static void VerifyParams(MachineSignature* sig) { // Verifies the C signature against the machine types. std::array params{ {MachineTypeForC()...}}; for (size_t p = 0; p < params.size(); ++p) { CHECK_EQ(sig->GetParam(p), params[p]); } } static CSignature* FromMachine(Zone* zone, MachineSignature* msig) { return reinterpret_cast(msig); } template static CSignature* New(Zone* zone, MachineType ret, ParamMachineTypes... params) { constexpr size_t param_count = sizeof...(params); std::array param_arr{{params...}}; const size_t buffer_size = param_count + (ret == MachineType::None() ? 0 : 1); MachineType* buffer = zone->NewArray(buffer_size); size_t pos = 0; size_t return_count = 0; if (ret != MachineType::None()) { buffer[pos++] = ret; return_count++; } for (MachineType p : param_arr) { // Check that there are no MachineType::None()'s in the parameters. CHECK_NE(MachineType::None(), p); buffer[pos++] = p; } DCHECK_EQ(buffer_size, pos); return zone->New(return_count, param_count, buffer); } }; // Helper classes for instantiating Signature objects to be callable from C. template class CSignatureOf : public CSignature { public: CSignatureOf() : CSignature(kReturnCount, kParamCount, storage_) { constexpr std::array param_types{ MachineTypeForC()...}; if (kReturnCount == 1) storage_[0] = MachineTypeForC(); static_assert( std::is_same::value, "type mismatch, cannot memcpy"); if (kParamCount > 0) { #if V8_CC_GNU #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wnonnull" #endif memcpy(storage_ + kReturnCount, param_types.data(), sizeof(*storage_) * kParamCount); #if V8_CC_GNU #pragma GCC diagnostic pop #endif } } private: static constexpr size_t kReturnCount = MachineTypeForC() == MachineType::None() ? 0 : 1; static constexpr size_t kParamCount = sizeof...(Params); MachineType storage_[kReturnCount + kParamCount]; }; using CSignature_i_ii = CSignatureOf; using CSignature_u_uu = CSignatureOf; using CSignature_f_ff = CSignatureOf; using CSignature_d_dd = CSignatureOf; using CSignature_o_oo = CSignatureOf; } // namespace compiler } // namespace internal } // namespace v8 #endif // V8_COMMON_C_SIGNATURE_H_