/*
* Copyright 2021 Mozilla Foundation
*
* Licensed under the Apache License , Version 2 . 0 ( the " License " ) ;
* you may not use this file except in compliance with the License .
* You may obtain a copy of the License at
*
* http : //www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing , software
* distributed under the License is distributed on an " AS IS " BASIS ,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied .
* See the License for the specific language governing permissions and
* limitations under the License .
*/
#include "wasm/WasmValue.h"
#include "builtin/Math.h"
#include "js/friend/ErrorMessages.h" // JSMSG_*
#include "js/Printf.h"
#include "js/Value.h"
#include "vm/BigIntType.h"
#include "vm/GlobalObject.h"
#include "vm/JSContext.h"
#include "vm/JSFunction.h"
#include "vm/JSObject.h"
#include "vm/StringType.h"
#include "wasm/WasmGcObject.h"
#include "wasm/WasmJS.h"
#include "wasm/WasmLog.h"
#include "wasm/WasmStacks.h"
#include "wasm/WasmTypeDef.h"
#include "vm/JSObject-inl.h"
using namespace js;
using namespace js::wasm;
Val::Val(const LitVal& val) {
type_ = val.type();
switch (type_.kind()) {
case ValType::I32:
cell_.i32_ = val.i32();
return ;
case ValType::F32:
cell_.f32_ = val.f32();
return ;
case ValType::I64:
cell_.i64_ = val.i64();
return ;
case ValType::F64:
cell_.f64_ = val.f64();
return ;
case ValType::V128:
cell_.v128_ = val.v128();
return ;
case ValType::Ref:
cell_.ref_ = val.ref();
return ;
}
MOZ_CRASH();
}
void Val::initFromRootedLocation(ValType type, const void * loc) {
MOZ_ASSERT(!type_.isValid());
type_ = type;
memset(&cell_, 0 , sizeof (Cell));
memcpy(&cell_, loc, type_.size());
}
void Val::initFromHeapLocation(ValType type, const void * loc) {
MOZ_ASSERT(!type_.isValid());
type_ = type;
memset(&cell_, 0 , sizeof (Cell));
readFromHeapLocation(loc);
}
void Val::writeToRootedLocation(void * loc, bool mustWrite64) const {
memcpy(loc, &cell_, type_.size());
if (mustWrite64 && type_.size() == 4 ) {
memset((uint8_t*)(loc) + 4 , 0 , 4 );
}
}
void Val::readFromHeapLocation(const void * loc) {
memcpy(&cell_, loc, type_.size());
}
void Val::writeToHeapLocation(gc::Cell* owner, void * loc) const {
if (isAnyRef()) {
BarrieredSet(owner, loc, toAnyRef());
return ;
}
memcpy(loc, &cell_, type_.size());
}
void Val::writeToTenuredHeapLocation(void * loc) const {
if (isAnyRef()) {
BarrieredSet(false , loc, toAnyRef());
return ;
}
memcpy(loc, &cell_, type_.size());
}
bool Val::fromJSValue(JSContext* cx, ValType targetType, HandleValue val,
MutableHandleVal rval) {
rval.get().type_ = targetType;
// No pre/post barrier needed as rval is rooted
return ToWebAssemblyValue(cx, val, targetType, &rval.get().cell_,
targetType.size() == 8 );
}
bool Val::toJSValue(JSContext* cx, MutableHandleValue rval) const {
return ToJSValue(cx, &cell_, type_, rval);
}
void Val::trace(JSTracer* trc) const {
if (isAnyRef()) {
TraceManuallyBarrieredEdge(trc, &toAnyRef(), "anyref" );
}
}
bool CheckFuncRefValue(JSContext* cx, HandleValue v, MutableHandleAnyRef vp) {
if (v.isNull()) {
vp.set(AnyRef::null());
return true ;
}
if (v.isObject()) {
JSObject& obj = v.toObject();
if (obj.is<JSFunction>()) {
JSFunction* f = &obj.as<JSFunction>();
if (f->isWasm()) {
vp.set(AnyRef::fromJSObject(*f));
return true ;
}
}
}
JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr,
JSMSG_WASM_BAD_FUNCREF_VALUE);
return false ;
}
bool CheckAnyRefValue(JSContext* cx, HandleValue v, MutableHandleAnyRef vp) {
if (!AnyRef::fromJSValue(cx, v, vp)) {
MOZ_ASSERT(cx->isThrowingOutOfMemory());
return false ;
}
return true ;
}
bool CheckNullFuncRefValue(JSContext* cx, HandleValue v,
MutableHandleAnyRef vp) {
if (!v.isNull()) {
JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr,
JSMSG_WASM_BAD_NULL_FUNCREF_VALUE);
return false ;
}
vp.set(AnyRef::null());
return true ;
}
bool CheckNullExnRefValue(JSContext* cx, HandleValue v,
MutableHandleAnyRef vp) {
if (!v.isNull()) {
JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr,
JSMSG_WASM_BAD_NULL_EXNREF_VALUE);
return false ;
}
vp.set(AnyRef::null());
return true ;
}
#ifdef ENABLE_WASM_JSPI
bool CheckNullContRefValue(JSContext* cx, HandleValue v,
MutableHandleAnyRef vp) {
if (!v.isNull()) {
JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr,
JSMSG_WASM_BAD_NULL_CONTREF_VALUE);
return false ;
}
vp.set(AnyRef::null());
return true ;
}
#endif // ENABLE_WASM_JSPI
bool CheckNullExternRefValue(JSContext* cx, HandleValue v,
MutableHandleAnyRef vp) {
if (!v.isNull()) {
JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr,
JSMSG_WASM_BAD_NULL_EXTERNREF_VALUE);
return false ;
}
vp.set(AnyRef::null());
return true ;
}
bool CheckNullRefValue(JSContext* cx, HandleValue v, MutableHandleAnyRef vp) {
if (!v.isNull()) {
JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr,
JSMSG_WASM_BAD_NULL_ANYREF_VALUE);
return false ;
}
vp.set(AnyRef::null());
return true ;
}
bool CheckEqRefValue(JSContext* cx, HandleValue v, MutableHandleAnyRef vp) {
if (!AnyRef::fromJSValue(cx, v, vp)) {
MOZ_ASSERT(cx->isThrowingOutOfMemory());
return false ;
}
if (vp.isNull() || vp.isI31() ||
(vp.isJSObject() && vp.toJSObject().is<WasmGcObject>())) {
return true ;
}
JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr,
JSMSG_WASM_BAD_EQREF_VALUE);
return false ;
}
bool CheckI31RefValue(JSContext* cx, HandleValue v, MutableHandleAnyRef vp) {
if (!AnyRef::fromJSValue(cx, v, vp)) {
MOZ_ASSERT(cx->isThrowingOutOfMemory());
return false ;
}
if (vp.isNull() || vp.isI31()) {
return true ;
}
JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr,
JSMSG_WASM_BAD_I31REF_VALUE);
return false ;
}
bool CheckStructRefValue(JSContext* cx, HandleValue v, MutableHandleAnyRef vp) {
if (v.isNull()) {
vp.set(AnyRef::null());
return true ;
}
if (v.isObject()) {
JSObject& obj = v.toObject();
if (obj.is<WasmStructObject>()) {
vp.set(AnyRef::fromJSObject(obj.as<WasmStructObject>()));
return true ;
}
}
JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr,
JSMSG_WASM_BAD_STRUCTREF_VALUE);
return false ;
}
bool CheckArrayRefValue(JSContext* cx, HandleValue v, MutableHandleAnyRef vp) {
if (v.isNull()) {
vp.set(AnyRef::null());
return true ;
}
if (v.isObject()) {
JSObject& obj = v.toObject();
if (obj.is<WasmArrayObject>()) {
vp.set(AnyRef::fromJSObject(obj.as<WasmArrayObject>()));
return true ;
}
}
JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr,
JSMSG_WASM_BAD_ARRAYREF_VALUE);
return false ;
}
bool CheckTypeRefValue(JSContext* cx, const TypeDef * typeDef , HandleValue v,
MutableHandleAnyRef vp) {
if (v.isNull()) {
vp.set(AnyRef::null());
return true ;
}
if (v.isObject()) {
JSObject& obj = v.toObject();
if (obj.is<WasmGcObject>() &&
obj.as<WasmGcObject>().isRuntimeSubtypeOf(typeDef )) {
vp.set(AnyRef::fromJSObject(obj.as<WasmGcObject>()));
return true ;
}
if (obj.is<JSFunction>() && obj.as<JSFunction>().isWasm()) {
JSFunction& funcObj = obj.as<JSFunction>();
if (TypeDef ::isSubTypeOf(funcObj.wasmTypeDef(), typeDef )) {
vp.set(AnyRef::fromJSObject(funcObj));
return true ;
}
}
#ifdef ENABLE_WASM_JSPI
if (obj.is<wasm::ContObject>() && typeDef ->isContType()) {
// TODO: skipping type check to get JS-PI working.
vp.set(AnyRef::fromJSObject(obj));
return true ;
}
#endif
}
JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr,
JSMSG_WASM_BAD_TYPEREF_VALUE);
return false ;
}
bool wasm::CheckRefType(JSContext* cx, RefType targetType, HandleValue v,
MutableHandleAnyRef vp) {
if (!targetType.isNullable() && v.isNull()) {
JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr,
JSMSG_WASM_BAD_REF_NONNULLABLE_VALUE);
return false ;
}
switch (targetType.kind()) {
case RefType::Func:
return CheckFuncRefValue(cx, v, vp);
case RefType::Extern :
return AnyRef::fromJSValue(cx, v, vp);
case RefType::Exn:
// Break to the non-exposable case
break ;
#ifdef ENABLE_WASM_JSPI
case RefType::Cont:
// Break to the non-exposable case
break ;
#endif
case RefType::Any:
return CheckAnyRefValue(cx, v, vp);
case RefType::NoFunc:
return CheckNullFuncRefValue(cx, v, vp);
case RefType::NoExn:
return CheckNullExnRefValue(cx, v, vp);
#ifdef ENABLE_WASM_JSPI
case RefType::NoCont:
return CheckNullContRefValue(cx, v, vp);
#endif
case RefType::NoExtern:
return CheckNullExternRefValue(cx, v, vp);
case RefType::None:
return CheckNullRefValue(cx, v, vp);
case RefType::Eq:
return CheckEqRefValue(cx, v, vp);
case RefType::I31:
return CheckI31RefValue(cx, v, vp);
case RefType::Struct :
return CheckStructRefValue(cx, v, vp);
case RefType::Array:
return CheckArrayRefValue(cx, v, vp);
case RefType::TypeRef:
return CheckTypeRefValue(cx, targetType.typeDef (), v, vp);
}
MOZ_ASSERT(!ValType(targetType).isExposable());
JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr,
JSMSG_WASM_BAD_VAL_TYPE);
return false ;
}
bool wasm::CheckRefType(JSContext* cx, RefType targetType, HandleValue v) {
RootedAnyRef any(cx, AnyRef::null());
return CheckRefType(cx, targetType, v, &any);
}
class wasm::NoDebug {
public :
template <typename T>
static void print(T v) {}
};
class wasm::DebugCodegenVal {
template <typename T>
static void print(const char * fmt, T v) {
DebugCodegen(DebugChannel::Function, fmt, v);
}
public :
static void print(int32_t v) { print(" i32(%d)" , v); }
static void print(int64_t v) { print(" i64(%" PRId64 ")" , v); }
static void print(float v) { print(" f32(%f)" , v); }
static void print(double v) { print(" f64(%lf)" , v); }
static void print(void * v) { print(" ptr(%p)" , v); }
};
template bool wasm::ToJSValue<NoDebug>(JSContext* cx, const void * src,
StorageType type, MutableHandleValue dst,
CoercionLevel level);
template bool wasm::ToJSValue<DebugCodegenVal>(JSContext* cx, const void * src,
StorageType type,
MutableHandleValue dst,
CoercionLevel level);
template bool wasm::ToJSValueMayGC<NoDebug>(StorageType type);
template bool wasm::ToJSValueMayGC<DebugCodegenVal>(StorageType type);
template bool wasm::ToWebAssemblyValue<NoDebug>(JSContext* cx, HandleValue val,
ValType type, void * loc,
bool mustWrite64,
CoercionLevel level);
template bool wasm::ToWebAssemblyValue<DebugCodegenVal>(JSContext* cx,
HandleValue val,
ValType type, void * loc,
bool mustWrite64,
CoercionLevel level);
template bool wasm::ToJSValue<NoDebug>(JSContext* cx, const void * src,
ValType type, MutableHandleValue dst,
CoercionLevel level);
template bool wasm::ToJSValue<DebugCodegenVal>(JSContext* cx, const void * src,
ValType type,
MutableHandleValue dst,
CoercionLevel level);
template bool wasm::ToJSValueMayGC<NoDebug>(ValType type);
template bool wasm::ToJSValueMayGC<DebugCodegenVal>(ValType type);
template <typename Debug = NoDebug>
bool ToWebAssemblyValue_i32(JSContext* cx, HandleValue val, int32_t* loc,
bool mustWrite64) {
bool ok = ToInt32(cx, val, loc);
if (ok && mustWrite64) {
#if defined (JS_CODEGEN_MIPS64) || defined (JS_CODEGEN_LOONG64) || \
defined (JS_CODEGEN_RISCV64)
loc[1 ] = loc[0 ] >> 31 ;
#else
loc[1 ] = 0 ;
#endif
}
Debug::print(*loc);
return ok;
}
template <typename Debug = NoDebug>
bool ToWebAssemblyValue_i64(JSContext* cx, HandleValue val, int64_t* loc,
bool mustWrite64) {
MOZ_ASSERT(mustWrite64);
JS_TRY_VAR_OR_RETURN_FALSE(cx, *loc, ToBigInt64(cx, val));
Debug::print(*loc);
return true ;
}
template <typename Debug = NoDebug>
bool ToWebAssemblyValue_f32(JSContext* cx, HandleValue val, float * loc,
bool mustWrite64) {
bool ok = RoundFloat32(cx, val, loc);
if (ok && mustWrite64) {
loc[1 ] = 0 .0 ;
}
Debug::print(*loc);
return ok;
}
template <typename Debug = NoDebug>
bool ToWebAssemblyValue_f64(JSContext* cx, HandleValue val, double * loc,
bool mustWrite64) {
MOZ_ASSERT(mustWrite64);
bool ok = ToNumber(cx, val, loc);
Debug::print(*loc);
return ok;
}
template <typename Debug = NoDebug>
bool ToWebAssemblyValue_externref(JSContext* cx, HandleValue val, void ** loc,
bool mustWrite64) {
RootedAnyRef result(cx, AnyRef::null());
if (!AnyRef::fromJSValue(cx, val, &result)) {
return false ;
}
loc[0 ] = result.get().forCompiledCode();
#ifndef JS_64BIT
if (mustWrite64) {
loc[1 ] = nullptr;
}
#endif
Debug::print(*loc);
return true ;
}
template <typename Debug = NoDebug>
bool ToWebAssemblyValue_nullexnref(JSContext* cx, HandleValue val, void ** loc,
bool mustWrite64) {
RootedAnyRef result(cx, AnyRef::null());
if (!CheckNullExnRefValue(cx, val, &result)) {
return false ;
}
loc[0 ] = result.get().forCompiledCode();
#ifndef JS_64BIT
if (mustWrite64) {
loc[1 ] = nullptr;
}
#endif
Debug::print(*loc);
return true ;
}
#ifdef ENABLE_WASM_JSPI
template <typename Debug = NoDebug>
bool ToWebAssemblyValue_nullcontref(JSContext* cx, HandleValue val, void ** loc,
bool mustWrite64) {
RootedAnyRef result(cx, AnyRef::null());
if (!CheckNullContRefValue(cx, val, &result)) {
return false ;
}
loc[0 ] = result.get().forCompiledCode();
# ifndef JS_64BIT
if (mustWrite64) {
loc[1 ] = nullptr;
}
# endif
Debug::print(*loc);
return true ;
}
#endif
template <typename Debug = NoDebug>
bool ToWebAssemblyValue_nullexternref(JSContext* cx, HandleValue val,
void ** loc, bool mustWrite64) {
RootedAnyRef result(cx, AnyRef::null());
if (!CheckNullExternRefValue(cx, val, &result)) {
return false ;
}
loc[0 ] = result.get().forCompiledCode();
#ifndef JS_64BIT
if (mustWrite64) {
loc[1 ] = nullptr;
}
#endif
Debug::print(*loc);
return true ;
}
template <typename Debug = NoDebug>
bool ToWebAssemblyValue_funcref(JSContext* cx, HandleValue val, void ** loc,
bool mustWrite64) {
RootedAnyRef result(cx, AnyRef::null());
if (!CheckFuncRefValue(cx, val, &result)) {
return false ;
}
loc[0 ] = result.get().forCompiledCode();
#ifndef JS_64BIT
if (mustWrite64) {
loc[1 ] = nullptr;
}
#endif
Debug::print(*loc);
return true ;
}
template <typename Debug = NoDebug>
bool ToWebAssemblyValue_nullfuncref(JSContext* cx, HandleValue val, void ** loc,
bool mustWrite64) {
RootedAnyRef result(cx, AnyRef::null());
if (!CheckNullFuncRefValue(cx, val, &result)) {
return false ;
}
loc[0 ] = result.get().forCompiledCode();
#ifndef JS_64BIT
if (mustWrite64) {
loc[1 ] = nullptr;
}
#endif
Debug::print(*loc);
return true ;
}
template <typename Debug = NoDebug>
bool ToWebAssemblyValue_anyref(JSContext* cx, HandleValue val, void ** loc,
bool mustWrite64) {
RootedAnyRef result(cx, AnyRef::null());
if (!CheckAnyRefValue(cx, val, &result)) {
return false ;
}
loc[0 ] = result.get().forCompiledCode();
#ifndef JS_64BIT
if (mustWrite64) {
loc[1 ] = nullptr;
}
#endif
Debug::print(*loc);
return true ;
}
template <typename Debug = NoDebug>
bool ToWebAssemblyValue_nullref(JSContext* cx, HandleValue val, void ** loc,
bool mustWrite64) {
RootedAnyRef result(cx, AnyRef::null());
if (!CheckNullRefValue(cx, val, &result)) {
return false ;
}
loc[0 ] = result.get().forCompiledCode();
#ifndef JS_64BIT
if (mustWrite64) {
loc[1 ] = nullptr;
}
#endif
Debug::print(*loc);
return true ;
}
template <typename Debug = NoDebug>
bool ToWebAssemblyValue_eqref(JSContext* cx, HandleValue val, void ** loc,
bool mustWrite64) {
RootedAnyRef result(cx, AnyRef::null());
if (!CheckEqRefValue(cx, val, &result)) {
return false ;
}
loc[0 ] = result.get().forCompiledCode();
#ifndef JS_64BIT
if (mustWrite64) {
loc[1 ] = nullptr;
}
#endif
Debug::print(*loc);
return true ;
}
template <typename Debug = NoDebug>
bool ToWebAssemblyValue_i31ref(JSContext* cx, HandleValue val, void ** loc,
bool mustWrite64) {
RootedAnyRef result(cx, AnyRef::null());
if (!CheckI31RefValue(cx, val, &result)) {
return false ;
}
loc[0 ] = result.get().forCompiledCode();
#ifndef JS_64BIT
if (mustWrite64) {
loc[1 ] = nullptr;
}
#endif
Debug::print(*loc);
return true ;
}
template <typename Debug = NoDebug>
bool ToWebAssemblyValue_structref(JSContext* cx, HandleValue val, void ** loc,
bool mustWrite64) {
RootedAnyRef result(cx, AnyRef::null());
if (!CheckStructRefValue(cx, val, &result)) {
return false ;
}
loc[0 ] = result.get().forCompiledCode();
#ifndef JS_64BIT
if (mustWrite64) {
loc[1 ] = nullptr;
}
#endif
Debug::print(*loc);
return true ;
}
template <typename Debug = NoDebug>
bool ToWebAssemblyValue_arrayref(JSContext* cx, HandleValue val, void ** loc,
bool mustWrite64) {
RootedAnyRef result(cx, AnyRef::null());
if (!CheckArrayRefValue(cx, val, &result)) {
return false ;
}
loc[0 ] = result.get().forCompiledCode();
#ifndef JS_64BIT
if (mustWrite64) {
loc[1 ] = nullptr;
}
#endif
Debug::print(*loc);
return true ;
}
template <typename Debug = NoDebug>
bool ToWebAssemblyValue_typeref(JSContext* cx, const TypeDef * typeDef ,
HandleValue val, void ** loc, bool mustWrite64) {
RootedAnyRef result(cx, AnyRef::null());
if (!CheckTypeRefValue(cx, typeDef , val, &result)) {
return false ;
}
loc[0 ] = result.get().forCompiledCode();
#ifndef JS_64BIT
if (mustWrite64) {
loc[1 ] = nullptr;
}
#endif
Debug::print(*loc);
return true ;
}
bool ToWebAssemblyValue_lossless(JSContext* cx, HandleValue val, ValType type,
void * loc, bool mustWrite64) {
if (!val.isObject() || !val.toObject().is<WasmGlobalObject>()) {
return false ;
}
Rooted<WasmGlobalObject*> srcVal(cx, &val.toObject().as<WasmGlobalObject>());
if (srcVal->type() != type) {
return false ;
}
srcVal->val().get().writeToRootedLocation(loc, mustWrite64);
return true ;
}
template <typename Debug>
bool wasm::ToWebAssemblyValue(JSContext* cx, HandleValue val, ValType type,
void * loc, bool mustWrite64,
CoercionLevel level) {
if (level == CoercionLevel::Lossless &&
ToWebAssemblyValue_lossless(cx, val, type.valType(), (void *)loc,
mustWrite64)) {
return true ;
}
switch (type.kind()) {
case ValType::I32:
return ToWebAssemblyValue_i32<Debug>(cx, val, (int32_t*)loc, mustWrite64);
case ValType::I64:
return ToWebAssemblyValue_i64<Debug>(cx, val, (int64_t*)loc, mustWrite64);
case ValType::F32:
return ToWebAssemblyValue_f32<Debug>(cx, val, (float *)loc, mustWrite64);
case ValType::F64:
return ToWebAssemblyValue_f64<Debug>(cx, val, (double *)loc, mustWrite64);
case ValType::V128:
break ;
case ValType::Ref:
if (!type.isNullable() && val.isNull()) {
JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr,
JSMSG_WASM_BAD_REF_NONNULLABLE_VALUE);
return false ;
}
switch (type.refTypeKind()) {
case RefType::Func:
return ToWebAssemblyValue_funcref<Debug>(cx, val, (void **)loc,
mustWrite64);
case RefType::Extern :
return ToWebAssemblyValue_externref<Debug>(cx, val, (void **)loc,
mustWrite64);
case RefType::Exn:
// Break to the non-exposable case
break ;
#ifdef ENABLE_WASM_JSPI
case RefType::Cont:
// Break to the non-exposable case
break ;
#endif
case RefType::Any:
return ToWebAssemblyValue_anyref<Debug>(cx, val, (void **)loc,
mustWrite64);
case RefType::NoFunc:
return ToWebAssemblyValue_nullfuncref<Debug>(cx, val, (void **)loc,
mustWrite64);
case RefType::NoExn:
return ToWebAssemblyValue_nullexnref<Debug>(cx, val, (void **)loc,
mustWrite64);
#ifdef ENABLE_WASM_JSPI
case RefType::NoCont:
return ToWebAssemblyValue_nullcontref<Debug>(cx, val, (void **)loc,
mustWrite64);
#endif
case RefType::NoExtern:
return ToWebAssemblyValue_nullexternref<Debug>(cx, val, (void **)loc,
mustWrite64);
case RefType::None:
return ToWebAssemblyValue_nullref<Debug>(cx, val, (void **)loc,
mustWrite64);
case RefType::Eq:
return ToWebAssemblyValue_eqref<Debug>(cx, val, (void **)loc,
mustWrite64);
case RefType::I31:
return ToWebAssemblyValue_i31ref<Debug>(cx, val, (void **)loc,
mustWrite64);
case RefType::Struct :
return ToWebAssemblyValue_structref<Debug>(cx, val, (void **)loc,
mustWrite64);
case RefType::Array:
return ToWebAssemblyValue_arrayref<Debug>(cx, val, (void **)loc,
mustWrite64);
case RefType::TypeRef:
return ToWebAssemblyValue_typeref<Debug>(cx, type.typeDef (), val,
(void **)loc, mustWrite64);
}
}
MOZ_ASSERT(!type.isExposable());
JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr,
JSMSG_WASM_BAD_VAL_TYPE);
return false ;
}
template <typename Debug = NoDebug>
bool ToJSValue_i8(JSContext* cx, int8_t src, MutableHandleValue dst) {
dst.set(Int32Value(src));
Debug::print(src);
return true ;
}
template <typename Debug = NoDebug>
bool ToJSValue_i16(JSContext* cx, int16_t src, MutableHandleValue dst) {
dst.set(Int32Value(src));
Debug::print(src);
return true ;
}
template <typename Debug = NoDebug>
bool ToJSValue_i32(JSContext* cx, int32_t src, MutableHandleValue dst) {
dst.set(Int32Value(src));
Debug::print(src);
return true ;
}
template <typename Debug = NoDebug>
bool ToJSValue_i64(JSContext* cx, int64_t src, MutableHandleValue dst) {
// If bi is manipulated other than test & storing, it would need
// to be rooted here.
BigInt* bi = BigInt::createFromInt64(cx, src);
if (!bi) {
return false ;
}
dst.set(BigIntValue(bi));
Debug::print(src);
return true ;
}
template <typename Debug = NoDebug>
bool ToJSValue_f32(JSContext* cx, float src, MutableHandleValue dst) {
dst.set(JS::CanonicalizedDoubleValue(src));
Debug::print(src);
return true ;
}
template <typename Debug = NoDebug>
bool ToJSValue_f64(JSContext* cx, double src, MutableHandleValue dst) {
dst.set(JS::CanonicalizedDoubleValue(src));
Debug::print(src);
return true ;
}
template <typename Debug = NoDebug>
bool ToJSValue_funcref(JSContext* cx, void * src, MutableHandleValue dst) {
dst.set(UnboxFuncRef(FuncRef::fromCompiledCode(src)));
Debug::print(src);
return true ;
}
template <typename Debug = NoDebug>
bool ToJSValue_externref(JSContext* cx, void * src, MutableHandleValue dst) {
dst.set(AnyRef::fromCompiledCode(src).toJSValue());
Debug::print(src);
return true ;
}
template <typename Debug = NoDebug>
bool ToJSValue_anyref(JSContext* cx, void * src, MutableHandleValue dst) {
dst.set(AnyRef::fromCompiledCode(src).toJSValue());
Debug::print(src);
return true ;
}
template <typename Debug = NoDebug>
bool ToJSValue_lossless(JSContext* cx, const void * src, MutableHandleValue dst,
ValType type) {
RootedVal srcVal(cx);
srcVal.get().initFromRootedLocation(type, src);
RootedObject prototype(
cx, GlobalObject::getOrCreatePrototype(cx, JSProto_WasmGlobal));
Rooted<WasmGlobalObject*> srcGlobal(
cx, WasmGlobalObject::create(cx, srcVal, false , prototype));
if (!srcGlobal) {
return false ;
}
dst.set(ObjectValue(*srcGlobal.get()));
return true ;
}
template <typename Debug>
bool wasm::ToJSValue(JSContext* cx, const void * src, StorageType type,
MutableHandleValue dst, CoercionLevel level) {
if (level == CoercionLevel::Lossless) {
MOZ_ASSERT(type.isValType());
return ToJSValue_lossless(cx, src, dst, type.valType());
}
switch (type.kind()) {
case StorageType::I8:
return ToJSValue_i8<Debug>(cx, *reinterpret_cast <const int8_t*>(src),
dst);
case StorageType::I16:
return ToJSValue_i16<Debug>(cx, *reinterpret_cast <const int16_t*>(src),
dst);
case StorageType::I32:
return ToJSValue_i32<Debug>(cx, *reinterpret_cast <const int32_t*>(src),
dst);
case StorageType::I64:
return ToJSValue_i64<Debug>(cx, *reinterpret_cast <const int64_t*>(src),
dst);
case StorageType::F32:
return ToJSValue_f32<Debug>(cx, *reinterpret_cast <const float *>(src),
dst);
case StorageType::F64:
return ToJSValue_f64<Debug>(cx, *reinterpret_cast <const double *>(src),
dst);
case StorageType::V128:
break ;
case StorageType::Ref:
switch (type.refType().hierarchy()) {
case RefTypeHierarchy::Func:
return ToJSValue_funcref<Debug>(
cx, *reinterpret_cast <void * const *>(src), dst);
case RefTypeHierarchy::Exn:
// Break to the non-exposable case
break ;
#ifdef ENABLE_WASM_JSPI
case RefTypeHierarchy::Cont:
// Break to the non-exposable case
break ;
#endif // ENABLE_WASM_JSPI
case RefTypeHierarchy::Extern :
return ToJSValue_externref<Debug>(
cx, *reinterpret_cast <void * const *>(src), dst);
case RefTypeHierarchy::Any:
return ToJSValue_anyref<Debug>(
cx, *reinterpret_cast <void * const *>(src), dst);
break ;
}
}
MOZ_ASSERT(!type.isExposable());
Debug::print(nullptr);
dst.setUndefined();
return true ;
}
template <typename Debug>
bool wasm::ToJSValueMayGC(StorageType type) {
return type.kind() == StorageType::I64;
}
template <typename Debug>
bool wasm::ToJSValue(JSContext* cx, const void * src, ValType type,
MutableHandleValue dst, CoercionLevel level) {
return wasm::ToJSValue(cx, src, StorageType(type.packed()), dst, level);
}
template <typename Debug>
bool wasm::ToJSValueMayGC(ValType type) {
return wasm::ToJSValueMayGC(StorageType(type.packed()));
}
/* static */
wasm::FuncRef wasm::FuncRef::fromAnyRefUnchecked(AnyRef p) {
if (p.isNull()) {
return FuncRef::null();
}
MOZ_ASSERT(p.isJSObject() && p.toJSObject().is<JSFunction>());
return FuncRef(&p.toJSObject().as<JSFunction>());
}
void wasm::FuncRef::trace(JSTracer* trc) const {
if (value_) {
TraceManuallyBarrieredEdge(trc, &value_, "wasm funcref referent" );
}
}
Value wasm::UnboxFuncRef(FuncRef val) {
JSFunction* fn = val.asJSFunction();
Value result;
MOZ_ASSERT_IF(fn, fn->is<JSFunction>());
result.setObjectOrNull(fn);
return result;
}
#ifdef DEBUG
void wasm::AssertEdgeSourceNotInsideNursery(void * vp) {
JSContext* cx = TlsContext.get();
if (cx) {
// We can't check this when called off thread.
Nursery& nursery = cx->runtime()->gc.nursery();
MOZ_ASSERT(!nursery.isInside(vp));
}
}
#endif
Messung V0.5 in Prozent C=99 H=100 G=99
¤ Dauer der Verarbeitung: 0.20 Sekunden
(vorverarbeitet am 2026-09-28)
¤
*© Formatika GbR, Deutschland