Differential Revision: https://phabricator.services.mozilla.com/D289126
437 lines
17 KiB
C++
437 lines
17 KiB
C++
/* 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
|
|
* fmt::ptr(this\) file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
#include "mozilla/dom/Tensor.h"
|
|
|
|
#include "js/ArrayBuffer.h"
|
|
#include "js/BigInt.h"
|
|
#include "js/Value.h"
|
|
#include "mozilla/Assertions.h"
|
|
#include "mozilla/Logging.h"
|
|
#include "mozilla/PodOperations.h"
|
|
#include "mozilla/RefPtr.h"
|
|
#include "mozilla/dom/BindingUtils.h"
|
|
#include "mozilla/dom/ONNXBinding.h"
|
|
#include "mozilla/dom/Promise.h"
|
|
#include "mozilla/dom/ScriptSettings.h"
|
|
#include "mozilla/dom/ToJSValue.h"
|
|
#include "mozilla/dom/TypedArray.h"
|
|
#include "nsContentUtils.h"
|
|
#include "nsStringFwd.h"
|
|
#include "nsTArray.h"
|
|
|
|
extern mozilla::LazyLogModule gONNXLog;
|
|
#define LOGD(fmt, ...) \
|
|
MOZ_LOG_FMT(gONNXLog, LogLevel::Debug, fmt, ##__VA_ARGS__)
|
|
|
|
namespace mozilla::dom {
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(Tensor, mGlobal)
|
|
NS_IMPL_CYCLE_COLLECTING_ADDREF(Tensor)
|
|
NS_IMPL_CYCLE_COLLECTING_RELEASE(Tensor)
|
|
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Tensor)
|
|
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
|
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
|
NS_INTERFACE_MAP_END
|
|
|
|
Tensor::Tensor(const GlobalObject& aGlobal, const nsACString& aType,
|
|
const ArrayBufferView& aData, const Sequence<int32_t>& aDims)
|
|
: mType(aType) {
|
|
LOGD("{}", __PRETTY_FUNCTION__);
|
|
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
|
|
mGlobal = global;
|
|
if (!aData.AppendDataTo(mData)) {
|
|
size_t len = aData.ProcessFixedData(
|
|
[&](const Span<uint8_t>& aData) -> size_t { return aData.Length(); });
|
|
LOGD("{} OOM (size: {})", __PRETTY_FUNCTION__, len);
|
|
}
|
|
mDims.AppendElements(aDims);
|
|
}
|
|
|
|
Tensor::Tensor(const GlobalObject& aGlobal, const nsACString& aType,
|
|
const nsTArray<uint8_t>& aData, const Sequence<int32_t>& aDims)
|
|
: mType(aType) {
|
|
LOGD("{} type: {} len: {}", __PRETTY_FUNCTION__, aType, aData.Length());
|
|
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
|
|
mGlobal = std::move(global);
|
|
// Cast to uint8_t. Type is held in mType
|
|
mData.AppendElements(aData);
|
|
mDims.AppendElements(aDims);
|
|
}
|
|
|
|
Tensor::Tensor(const GlobalObject& aGlobal, ONNXTensorElementDataType aType,
|
|
nsTArray<uint8_t> aData, nsTArray<int64_t> aDims)
|
|
: mType(ONNXTypeToString(aType)) {
|
|
LOGD("Output tensor: {} type: {} len: {}", __PRETTY_FUNCTION__,
|
|
ONNXTypeToString(aType), aData.Length());
|
|
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
|
|
mGlobal = std::move(global);
|
|
mData = std::move(aData);
|
|
mDims.AppendElements(aDims);
|
|
}
|
|
|
|
static double ToDouble(const JS::Value& aValue) { return aValue.toDouble(); }
|
|
|
|
static int64_t ToBigInt64(const JS::Value& aValue) {
|
|
return JS::ToBigInt64(aValue.toBigInt());
|
|
}
|
|
|
|
static uint64_t ToBigUint64(const JS::Value& aValue) {
|
|
return JS::ToBigUint64(aValue.toBigInt());
|
|
}
|
|
|
|
static uint8_t ToBoolean(const JS::Value& aValue) { return aValue.toBoolean(); }
|
|
|
|
already_AddRefed<Tensor> Tensor::Constructor(
|
|
const GlobalObject& global, const nsACString& type,
|
|
const ArrayBufferViewOrAnySequence& data, const Sequence<int32_t>& dims,
|
|
ErrorResult& aRv) {
|
|
if (data.IsAnySequence()) {
|
|
const auto& sequence = data.GetAsAnySequence();
|
|
nsTArray<uint8_t> valuesAsBytes;
|
|
#define CASE(onnx_type, c_type, checkfn, conversionfn) \
|
|
case onnx_type: { \
|
|
valuesAsBytes.SetCapacity(sequence.Length() * sizeof(c_type)); \
|
|
for (const auto& element : sequence) { \
|
|
if (!element.checkfn()) { \
|
|
aRv.ThrowTypeError( \
|
|
"Inconsistency between type and value in second argument"); \
|
|
return nullptr; \
|
|
} \
|
|
auto value = conversionfn(element); \
|
|
if (std::numeric_limits<c_type>::lowest() > value || \
|
|
std::numeric_limits<c_type>::max() < value) { \
|
|
aRv.ThrowTypeError("Value out of range in arg 2"); \
|
|
return nullptr; \
|
|
} \
|
|
auto v = c_type(value); \
|
|
valuesAsBytes.AppendElements(reinterpret_cast<uint8_t*>(&v), \
|
|
sizeof(c_type)); \
|
|
} \
|
|
break; \
|
|
}
|
|
|
|
// Assume constant type, lock on the type of the first element.
|
|
switch (StringToONNXDataType(type)) {
|
|
CASE(ONNX_TENSOR_ELEMENT_DATA_TYPE_UNDEFINED, uint8_t, isNumber, ToDouble)
|
|
CASE(ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT, float, isNumber, ToDouble)
|
|
CASE(ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT8, uint8_t, isNumber, ToDouble)
|
|
CASE(ONNX_TENSOR_ELEMENT_DATA_TYPE_INT8, int8_t, isNumber, ToDouble)
|
|
CASE(ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT16, uint16_t, isNumber, ToDouble)
|
|
CASE(ONNX_TENSOR_ELEMENT_DATA_TYPE_INT16, int16_t, isNumber, ToDouble)
|
|
CASE(ONNX_TENSOR_ELEMENT_DATA_TYPE_INT32, int32_t, isNumber, ToDouble)
|
|
CASE(ONNX_TENSOR_ELEMENT_DATA_TYPE_STRING, int8_t, isNumber, ToDouble)
|
|
CASE(ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT16, int16_t, isNumber, ToDouble);
|
|
CASE(ONNX_TENSOR_ELEMENT_DATA_TYPE_DOUBLE, double, isNumber, ToDouble);
|
|
CASE(ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT32, uint32_t, isNumber, ToDouble);
|
|
CASE(ONNX_TENSOR_ELEMENT_DATA_TYPE_INT64, int64_t, isBigInt, ToBigInt64);
|
|
CASE(ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT64, uint64_t, isBigInt,
|
|
ToBigUint64);
|
|
CASE(ONNX_TENSOR_ELEMENT_DATA_TYPE_BOOL, uint8_t, isBoolean, ToBoolean);
|
|
case ONNX_TENSOR_ELEMENT_DATA_TYPE_COMPLEX64:
|
|
case ONNX_TENSOR_ELEMENT_DATA_TYPE_COMPLEX128:
|
|
case ONNX_TENSOR_ELEMENT_DATA_TYPE_BFLOAT16:
|
|
case ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT8E4M3FN:
|
|
case ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT8E4M3FNUZ:
|
|
case ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT8E5M2:
|
|
case ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT8E5M2FNUZ:
|
|
case ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT4:
|
|
case ONNX_TENSOR_ELEMENT_DATA_TYPE_INT4:
|
|
MOZ_CRASH("Not handled");
|
|
break;
|
|
}
|
|
|
|
auto rv = MakeRefPtr<Tensor>(global, type, valuesAsBytes, dims);
|
|
|
|
LOGD("Tensor from sequence<any>: {}", rv->ToString().get());
|
|
|
|
return rv.forget();
|
|
}
|
|
|
|
auto rv = MakeRefPtr<Tensor>(global, type, data.GetAsArrayBufferView(), dims);
|
|
LOGD("Tensor from TypedArray: {}", rv->ToString().get());
|
|
return rv.forget();
|
|
} // namespace mozilla::dom
|
|
|
|
#undef CASE
|
|
#undef CASE_BIGINT
|
|
|
|
void Tensor::Dispose() { mData.Clear(); }
|
|
|
|
void Tensor::SetDims(const nsTArray<int32_t>& aVal) {
|
|
mDims.Clear();
|
|
mDims.AppendElements(aVal);
|
|
}
|
|
|
|
void Tensor::GetDims(nsTArray<int32_t>& aRetVal) {
|
|
aRetVal.AppendElements(mDims);
|
|
}
|
|
|
|
void Tensor::GetType(nsCString& aRetVal) const { aRetVal.Assign(mType); }
|
|
|
|
void Tensor::GetData(JSContext* aCx,
|
|
JS::MutableHandle<JSObject*> aRetVal) const {
|
|
LOGD("{} {} type: {} size: {}", __PRETTY_FUNCTION__, fmt::ptr(this),
|
|
mType.get(), mData.Length());
|
|
|
|
#define CASE(onnx_type, typed_array_type, c_type) \
|
|
case ONNX_TENSOR_ELEMENT_DATA_TYPE_##onnx_type: { \
|
|
nsTArray<c_type> tmp((c_type*)mData.Elements(), \
|
|
mData.Length() / sizeof(c_type)); \
|
|
dom::TypedArrayCreator<typed_array_type> creator(std::move(tmp)); \
|
|
aRetVal.set(creator.Create(aCx)); \
|
|
break; \
|
|
}
|
|
|
|
switch (Type()) {
|
|
CASE(INT8, Int8Array, int8_t)
|
|
CASE(UINT8, Uint8Array, uint8_t)
|
|
CASE(INT16, Int16Array, int16_t)
|
|
CASE(UINT16, Uint16Array, uint16_t)
|
|
CASE(INT32, Int32Array, int32_t)
|
|
CASE(UINT32, Uint32Array, uint32_t)
|
|
CASE(INT64, BigInt64Array, int64_t)
|
|
CASE(UINT64, BigUint64Array, uint64_t)
|
|
CASE(BOOL, Uint8Array, uint8_t)
|
|
CASE(DOUBLE, Float64Array, double)
|
|
CASE(FLOAT, Float32Array, float)
|
|
CASE(STRING, Uint8Array, uint8_t) // hmmm
|
|
case ONNX_TENSOR_ELEMENT_DATA_TYPE_BFLOAT16:
|
|
case ONNX_TENSOR_ELEMENT_DATA_TYPE_COMPLEX128:
|
|
case ONNX_TENSOR_ELEMENT_DATA_TYPE_COMPLEX64:
|
|
case ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT16:
|
|
case ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT8E4M3FN:
|
|
case ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT8E4M3FNUZ:
|
|
case ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT8E5M2:
|
|
case ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT8E5M2FNUZ:
|
|
case ONNX_TENSOR_ELEMENT_DATA_TYPE_INT4:
|
|
case ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT4:
|
|
case ONNX_TENSOR_ELEMENT_DATA_TYPE_UNDEFINED:
|
|
MOZ_CRASH("Missing ONNX data type to js value");
|
|
break;
|
|
}
|
|
|
|
#undef CASE
|
|
} // namespace mozilla::dom
|
|
|
|
TensorDataLocation Tensor::Location() const {
|
|
LOGD("{} {}", __PRETTY_FUNCTION__, fmt::ptr(this));
|
|
return TensorDataLocation::Cpu;
|
|
}
|
|
|
|
already_AddRefed<Promise> Tensor::GetData(const Optional<bool>& releaseData) {
|
|
LOGD("{} {} type: {} size: {}", __PRETTY_FUNCTION__, fmt::ptr(this),
|
|
mType.get(), mData.Length());
|
|
|
|
AutoJSContext ctx;
|
|
|
|
RefPtr<Promise> p = Promise::CreateInfallible(mGlobal);
|
|
|
|
if (releaseData.WasPassed() && releaseData.Value()) {
|
|
size_t lengthBytes = mData.Length();
|
|
UniquePtr<uint8_t[], JS::FreePolicy> tensorData(
|
|
js_pod_arena_malloc<uint8_t>(js::ArrayBufferContentsArena,
|
|
lengthBytes));
|
|
PodCopy(tensorData.get(), mData.Elements(), lengthBytes);
|
|
JS::Rooted<JSObject*> data(
|
|
ctx, JS::NewArrayBufferWithContents(ctx, lengthBytes,
|
|
std::move(tensorData)));
|
|
JS::Rooted<JS::Value> value(ctx, JS::ObjectValue(*data));
|
|
p->MaybeResolve(value);
|
|
mData.Clear();
|
|
} else {
|
|
size_t lengthBytes = mData.Length();
|
|
UniquePtr<uint8_t[], JS::FreePolicy> tensorData(
|
|
js_pod_arena_malloc<uint8_t>(js::ArrayBufferContentsArena,
|
|
lengthBytes));
|
|
PodCopy(tensorData.get(), mData.Elements(), lengthBytes);
|
|
JS::Rooted<JSObject*> data(
|
|
ctx, JS::NewArrayBufferWithContents(ctx, lengthBytes,
|
|
std::move(tensorData)));
|
|
JS::Rooted<JS::Value> value(ctx, JS::ObjectValue(*data));
|
|
p->MaybeResolve(value);
|
|
}
|
|
|
|
return p.forget();
|
|
}
|
|
|
|
nsCString Tensor::TypeString() const { return ONNXTypeToString(Type()); }
|
|
|
|
ONNXTensorElementDataType Tensor::StringToONNXDataType(
|
|
const nsACString& aString) {
|
|
#define CASE(string, suffix) \
|
|
do { \
|
|
if (aString.EqualsASCII(#string)) { \
|
|
return ONNX_TENSOR_ELEMENT_DATA_TYPE_##suffix; \
|
|
} \
|
|
} while (0);
|
|
|
|
CASE(int4, INT4);
|
|
CASE(uint4, UINT4);
|
|
CASE(int8, INT8);
|
|
CASE(uint8, UINT8);
|
|
CASE(int16, INT16);
|
|
CASE(uint16, UINT16);
|
|
CASE(int32, INT32);
|
|
CASE(uint32, UINT32);
|
|
CASE(int64, INT64);
|
|
CASE(uint64, UINT64);
|
|
CASE(float16, FLOAT16);
|
|
CASE(float32, FLOAT);
|
|
CASE(float64, DOUBLE);
|
|
CASE(bool, BOOL);
|
|
|
|
MOZ_CRASH("Missing string to ONNX data type value");
|
|
|
|
#undef CASE
|
|
}
|
|
|
|
ONNXTensorElementDataType Tensor::Type() const {
|
|
return StringToONNXDataType(mType);
|
|
}
|
|
|
|
nsLiteralCString Tensor::ONNXTypeToString(
|
|
ONNXTensorElementDataType aType) const {
|
|
switch (aType) {
|
|
case ONNX_TENSOR_ELEMENT_DATA_TYPE_UNDEFINED:
|
|
return "undefined"_ns;
|
|
case ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT4:
|
|
return "uint4"_ns;
|
|
case ONNX_TENSOR_ELEMENT_DATA_TYPE_INT4:
|
|
return "int4"_ns;
|
|
case ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT8:
|
|
return "uint8"_ns;
|
|
case ONNX_TENSOR_ELEMENT_DATA_TYPE_INT8:
|
|
return "int8"_ns;
|
|
case ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT16:
|
|
return "uint16"_ns;
|
|
case ONNX_TENSOR_ELEMENT_DATA_TYPE_INT16:
|
|
return "int16"_ns;
|
|
case ONNX_TENSOR_ELEMENT_DATA_TYPE_INT32:
|
|
return "int32"_ns;
|
|
case ONNX_TENSOR_ELEMENT_DATA_TYPE_INT64:
|
|
return "int64"_ns;
|
|
case ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT32:
|
|
return "uint32"_ns;
|
|
case ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT64:
|
|
return "uint64"_ns;
|
|
case ONNX_TENSOR_ELEMENT_DATA_TYPE_STRING:
|
|
return "string"_ns;
|
|
case ONNX_TENSOR_ELEMENT_DATA_TYPE_BOOL:
|
|
return "bool"_ns;
|
|
case ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT16:
|
|
return "float16"_ns;
|
|
case ONNX_TENSOR_ELEMENT_DATA_TYPE_BFLOAT16:
|
|
return "bfloat16"_ns;
|
|
case ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT:
|
|
return "float32"_ns;
|
|
case ONNX_TENSOR_ELEMENT_DATA_TYPE_DOUBLE:
|
|
return "double"_ns;
|
|
case ONNX_TENSOR_ELEMENT_DATA_TYPE_COMPLEX64:
|
|
case ONNX_TENSOR_ELEMENT_DATA_TYPE_COMPLEX128:
|
|
case ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT8E4M3FN:
|
|
case ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT8E4M3FNUZ:
|
|
case ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT8E5M2:
|
|
case ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT8E5M2FNUZ:
|
|
MOZ_CRASH("Missing ONNX data type value to string");
|
|
break;
|
|
}
|
|
return ""_ns;
|
|
}
|
|
|
|
nsCString Tensor::ToString() const {
|
|
nsCString rv;
|
|
size_t count = mData.Length() / DataTypeSize(Type());
|
|
rv.AppendFmt("{} {} elements, {} bytes, {} dims", mType, count,
|
|
mData.Length(), mDims.Length());
|
|
|
|
if (MOZ_LOG_TEST(gONNXLog, LogLevel::Verbose)) {
|
|
rv.AppendFmt("Dims:\n");
|
|
rv.AppendFmt("{}\n", fmt::join(mDims, ","));
|
|
rv.AppendFmt("Values:\n");
|
|
|
|
#define CASE(onnx_type, c_type) \
|
|
case onnx_type: { \
|
|
rv.AppendFmt("{}\n", \
|
|
fmt::join(Span((c_type*)mData.Elements(), count), ",")); \
|
|
break; \
|
|
}
|
|
|
|
switch (Type()) {
|
|
CASE(ONNX_TENSOR_ELEMENT_DATA_TYPE_UNDEFINED, uint8_t)
|
|
CASE(ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT, float)
|
|
CASE(ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT8, uint8_t)
|
|
CASE(ONNX_TENSOR_ELEMENT_DATA_TYPE_INT8, int8_t)
|
|
CASE(ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT16, uint16_t)
|
|
CASE(ONNX_TENSOR_ELEMENT_DATA_TYPE_INT16, int16_t)
|
|
CASE(ONNX_TENSOR_ELEMENT_DATA_TYPE_INT32, int32_t)
|
|
CASE(ONNX_TENSOR_ELEMENT_DATA_TYPE_INT64, int64_t)
|
|
CASE(ONNX_TENSOR_ELEMENT_DATA_TYPE_STRING, int8_t)
|
|
CASE(ONNX_TENSOR_ELEMENT_DATA_TYPE_BOOL, int8_t)
|
|
CASE(ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT16, int16_t);
|
|
CASE(ONNX_TENSOR_ELEMENT_DATA_TYPE_DOUBLE, double);
|
|
CASE(ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT32, uint32_t);
|
|
CASE(ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT64, uint64_t);
|
|
case ONNX_TENSOR_ELEMENT_DATA_TYPE_COMPLEX64:
|
|
case ONNX_TENSOR_ELEMENT_DATA_TYPE_COMPLEX128:
|
|
case ONNX_TENSOR_ELEMENT_DATA_TYPE_BFLOAT16:
|
|
case ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT8E4M3FN:
|
|
case ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT8E4M3FNUZ:
|
|
case ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT8E5M2:
|
|
case ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT8E5M2FNUZ:
|
|
case ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT4:
|
|
case ONNX_TENSOR_ELEMENT_DATA_TYPE_INT4:
|
|
MOZ_CRASH("Not handled");
|
|
break;
|
|
}
|
|
#undef CASE
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
size_t Tensor::DataTypeSize(ONNXTensorElementDataType aType) {
|
|
#define CASE(onnx_type, c_type) \
|
|
do { \
|
|
case onnx_type: \
|
|
return sizeof(c_type); \
|
|
} while (0);
|
|
|
|
switch (aType) {
|
|
CASE(ONNX_TENSOR_ELEMENT_DATA_TYPE_UNDEFINED, uint8_t)
|
|
CASE(ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT, float)
|
|
CASE(ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT8, uint8_t)
|
|
CASE(ONNX_TENSOR_ELEMENT_DATA_TYPE_INT8, int8_t)
|
|
CASE(ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT16, uint16_t)
|
|
CASE(ONNX_TENSOR_ELEMENT_DATA_TYPE_INT16, int16_t)
|
|
CASE(ONNX_TENSOR_ELEMENT_DATA_TYPE_INT32, int32_t)
|
|
CASE(ONNX_TENSOR_ELEMENT_DATA_TYPE_INT64, int64_t)
|
|
CASE(ONNX_TENSOR_ELEMENT_DATA_TYPE_STRING, int8_t)
|
|
CASE(ONNX_TENSOR_ELEMENT_DATA_TYPE_BOOL, int8_t)
|
|
CASE(ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT16, int16_t);
|
|
CASE(ONNX_TENSOR_ELEMENT_DATA_TYPE_DOUBLE, double);
|
|
CASE(ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT32, uint32_t);
|
|
CASE(ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT64, uint64_t);
|
|
case ONNX_TENSOR_ELEMENT_DATA_TYPE_COMPLEX64:
|
|
case ONNX_TENSOR_ELEMENT_DATA_TYPE_COMPLEX128:
|
|
case ONNX_TENSOR_ELEMENT_DATA_TYPE_BFLOAT16:
|
|
case ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT8E4M3FN:
|
|
case ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT8E4M3FNUZ:
|
|
case ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT8E5M2:
|
|
case ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT8E5M2FNUZ:
|
|
case ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT4:
|
|
case ONNX_TENSOR_ELEMENT_DATA_TYPE_INT4:
|
|
MOZ_CRASH("Not handled");
|
|
break;
|
|
}
|
|
#undef CASE
|
|
return 0;
|
|
}
|
|
|
|
JSObject* Tensor::WrapObject(JSContext* aCx,
|
|
JS::Handle<JSObject*> aGivenProto) {
|
|
return Tensor_Binding::Wrap(aCx, this, aGivenProto);
|
|
}
|
|
|
|
} // namespace mozilla::dom
|