WasmValue.cpp (27702B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- 2 * vim: set ts=8 sts=2 et sw=2 tw=80: 3 * 4 * Copyright 2021 Mozilla Foundation 5 * 6 * Licensed under the Apache License, Version 2.0 (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 */ 18 19 #include "wasm/WasmValue.h" 20 21 #include "jsmath.h" 22 #include "js/friend/ErrorMessages.h" // JSMSG_* 23 #include "js/Printf.h" 24 #include "js/Value.h" 25 #include "vm/BigIntType.h" 26 #include "vm/GlobalObject.h" 27 #include "vm/JSContext.h" 28 #include "vm/JSFunction.h" 29 #include "vm/JSObject.h" 30 #include "vm/StringType.h" 31 #include "wasm/WasmGcObject.h" 32 #include "wasm/WasmJS.h" 33 #include "wasm/WasmLog.h" 34 #include "wasm/WasmTypeDef.h" 35 36 #include "vm/JSObject-inl.h" 37 38 using namespace js; 39 using namespace js::wasm; 40 41 Val::Val(const LitVal& val) { 42 type_ = val.type(); 43 switch (type_.kind()) { 44 case ValType::I32: 45 cell_.i32_ = val.i32(); 46 return; 47 case ValType::F32: 48 cell_.f32_ = val.f32(); 49 return; 50 case ValType::I64: 51 cell_.i64_ = val.i64(); 52 return; 53 case ValType::F64: 54 cell_.f64_ = val.f64(); 55 return; 56 case ValType::V128: 57 cell_.v128_ = val.v128(); 58 return; 59 case ValType::Ref: 60 cell_.ref_ = val.ref(); 61 return; 62 } 63 MOZ_CRASH(); 64 } 65 66 void Val::initFromRootedLocation(ValType type, const void* loc) { 67 MOZ_ASSERT(!type_.isValid()); 68 type_ = type; 69 memset(&cell_, 0, sizeof(Cell)); 70 memcpy(&cell_, loc, type_.size()); 71 } 72 73 void Val::initFromHeapLocation(ValType type, const void* loc) { 74 MOZ_ASSERT(!type_.isValid()); 75 type_ = type; 76 memset(&cell_, 0, sizeof(Cell)); 77 readFromHeapLocation(loc); 78 } 79 80 void Val::writeToRootedLocation(void* loc, bool mustWrite64) const { 81 memcpy(loc, &cell_, type_.size()); 82 if (mustWrite64 && type_.size() == 4) { 83 memset((uint8_t*)(loc) + 4, 0, 4); 84 } 85 } 86 87 void Val::readFromHeapLocation(const void* loc) { 88 memcpy(&cell_, loc, type_.size()); 89 } 90 91 void Val::writeToHeapLocation(void* loc) const { 92 if (isAnyRef()) { 93 *((GCPtr<AnyRef>*)loc) = toAnyRef(); 94 return; 95 } 96 memcpy(loc, &cell_, type_.size()); 97 } 98 99 bool Val::fromJSValue(JSContext* cx, ValType targetType, HandleValue val, 100 MutableHandleVal rval) { 101 rval.get().type_ = targetType; 102 // No pre/post barrier needed as rval is rooted 103 return ToWebAssemblyValue(cx, val, targetType, &rval.get().cell_, 104 targetType.size() == 8); 105 } 106 107 bool Val::toJSValue(JSContext* cx, MutableHandleValue rval) const { 108 return ToJSValue(cx, &cell_, type_, rval); 109 } 110 111 void Val::trace(JSTracer* trc) const { 112 if (isAnyRef()) { 113 TraceManuallyBarrieredEdge(trc, &toAnyRef(), "anyref"); 114 } 115 } 116 117 bool CheckFuncRefValue(JSContext* cx, HandleValue v, MutableHandleAnyRef vp) { 118 if (v.isNull()) { 119 vp.set(AnyRef::null()); 120 return true; 121 } 122 123 if (v.isObject()) { 124 JSObject& obj = v.toObject(); 125 if (obj.is<JSFunction>()) { 126 JSFunction* f = &obj.as<JSFunction>(); 127 if (f->isWasm()) { 128 vp.set(AnyRef::fromJSObject(*f)); 129 return true; 130 } 131 } 132 } 133 134 JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, 135 JSMSG_WASM_BAD_FUNCREF_VALUE); 136 return false; 137 } 138 139 bool CheckAnyRefValue(JSContext* cx, HandleValue v, MutableHandleAnyRef vp) { 140 if (!AnyRef::fromJSValue(cx, v, vp)) { 141 MOZ_ASSERT(cx->isThrowingOutOfMemory()); 142 return false; 143 } 144 return true; 145 } 146 147 bool CheckNullFuncRefValue(JSContext* cx, HandleValue v, 148 MutableHandleAnyRef vp) { 149 if (!v.isNull()) { 150 JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, 151 JSMSG_WASM_BAD_NULL_FUNCREF_VALUE); 152 return false; 153 } 154 vp.set(AnyRef::null()); 155 return true; 156 } 157 158 bool CheckNullExnRefValue(JSContext* cx, HandleValue v, 159 MutableHandleAnyRef vp) { 160 if (!v.isNull()) { 161 JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, 162 JSMSG_WASM_BAD_NULL_EXNREF_VALUE); 163 return false; 164 } 165 166 vp.set(AnyRef::null()); 167 return true; 168 } 169 170 bool CheckNullExternRefValue(JSContext* cx, HandleValue v, 171 MutableHandleAnyRef vp) { 172 if (!v.isNull()) { 173 JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, 174 JSMSG_WASM_BAD_NULL_EXTERNREF_VALUE); 175 return false; 176 } 177 178 vp.set(AnyRef::null()); 179 return true; 180 } 181 182 bool CheckNullRefValue(JSContext* cx, HandleValue v, MutableHandleAnyRef vp) { 183 if (!v.isNull()) { 184 JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, 185 JSMSG_WASM_BAD_NULL_ANYREF_VALUE); 186 return false; 187 } 188 189 vp.set(AnyRef::null()); 190 return true; 191 } 192 193 bool CheckEqRefValue(JSContext* cx, HandleValue v, MutableHandleAnyRef vp) { 194 if (!AnyRef::fromJSValue(cx, v, vp)) { 195 MOZ_ASSERT(cx->isThrowingOutOfMemory()); 196 return false; 197 } 198 199 if (vp.isNull() || vp.isI31() || 200 (vp.isJSObject() && vp.toJSObject().is<WasmGcObject>())) { 201 return true; 202 } 203 204 JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, 205 JSMSG_WASM_BAD_EQREF_VALUE); 206 return false; 207 } 208 209 bool CheckI31RefValue(JSContext* cx, HandleValue v, MutableHandleAnyRef vp) { 210 if (!AnyRef::fromJSValue(cx, v, vp)) { 211 MOZ_ASSERT(cx->isThrowingOutOfMemory()); 212 return false; 213 } 214 215 if (vp.isNull() || vp.isI31()) { 216 return true; 217 } 218 219 JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, 220 JSMSG_WASM_BAD_I31REF_VALUE); 221 return false; 222 } 223 224 bool CheckStructRefValue(JSContext* cx, HandleValue v, MutableHandleAnyRef vp) { 225 if (v.isNull()) { 226 vp.set(AnyRef::null()); 227 return true; 228 } 229 230 if (v.isObject()) { 231 JSObject& obj = v.toObject(); 232 if (obj.is<WasmStructObject>()) { 233 vp.set(AnyRef::fromJSObject(obj.as<WasmStructObject>())); 234 return true; 235 } 236 } 237 238 JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, 239 JSMSG_WASM_BAD_STRUCTREF_VALUE); 240 return false; 241 } 242 243 bool CheckArrayRefValue(JSContext* cx, HandleValue v, MutableHandleAnyRef vp) { 244 if (v.isNull()) { 245 vp.set(AnyRef::null()); 246 return true; 247 } 248 249 if (v.isObject()) { 250 JSObject& obj = v.toObject(); 251 if (obj.is<WasmArrayObject>()) { 252 vp.set(AnyRef::fromJSObject(obj.as<WasmArrayObject>())); 253 return true; 254 } 255 } 256 257 JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, 258 JSMSG_WASM_BAD_ARRAYREF_VALUE); 259 return false; 260 } 261 262 bool CheckTypeRefValue(JSContext* cx, const TypeDef* typeDef, HandleValue v, 263 MutableHandleAnyRef vp) { 264 if (v.isNull()) { 265 vp.set(AnyRef::null()); 266 return true; 267 } 268 269 if (v.isObject()) { 270 JSObject& obj = v.toObject(); 271 if (obj.is<WasmGcObject>() && 272 obj.as<WasmGcObject>().isRuntimeSubtypeOf(typeDef)) { 273 vp.set(AnyRef::fromJSObject(obj.as<WasmGcObject>())); 274 return true; 275 } 276 if (obj.is<JSFunction>() && obj.as<JSFunction>().isWasm()) { 277 JSFunction& funcObj = obj.as<JSFunction>(); 278 if (TypeDef::isSubTypeOf(funcObj.wasmTypeDef(), typeDef)) { 279 vp.set(AnyRef::fromJSObject(funcObj)); 280 return true; 281 } 282 } 283 } 284 285 JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, 286 JSMSG_WASM_BAD_TYPEREF_VALUE); 287 return false; 288 } 289 290 bool wasm::CheckRefType(JSContext* cx, RefType targetType, HandleValue v, 291 MutableHandleAnyRef vp) { 292 if (!targetType.isNullable() && v.isNull()) { 293 JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, 294 JSMSG_WASM_BAD_REF_NONNULLABLE_VALUE); 295 return false; 296 } 297 298 switch (targetType.kind()) { 299 case RefType::Func: 300 return CheckFuncRefValue(cx, v, vp); 301 case RefType::Extern: 302 return AnyRef::fromJSValue(cx, v, vp); 303 case RefType::Exn: 304 // Break to the non-exposable case 305 break; 306 case RefType::Any: 307 return CheckAnyRefValue(cx, v, vp); 308 case RefType::NoFunc: 309 return CheckNullFuncRefValue(cx, v, vp); 310 case RefType::NoExn: 311 return CheckNullExnRefValue(cx, v, vp); 312 case RefType::NoExtern: 313 return CheckNullExternRefValue(cx, v, vp); 314 case RefType::None: 315 return CheckNullRefValue(cx, v, vp); 316 case RefType::Eq: 317 return CheckEqRefValue(cx, v, vp); 318 case RefType::I31: 319 return CheckI31RefValue(cx, v, vp); 320 case RefType::Struct: 321 return CheckStructRefValue(cx, v, vp); 322 case RefType::Array: 323 return CheckArrayRefValue(cx, v, vp); 324 case RefType::TypeRef: 325 return CheckTypeRefValue(cx, targetType.typeDef(), v, vp); 326 } 327 328 MOZ_ASSERT(!ValType(targetType).isExposable()); 329 JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, 330 JSMSG_WASM_BAD_VAL_TYPE); 331 return false; 332 } 333 334 bool wasm::CheckRefType(JSContext* cx, RefType targetType, HandleValue v) { 335 RootedAnyRef any(cx, AnyRef::null()); 336 return CheckRefType(cx, targetType, v, &any); 337 } 338 339 class wasm::NoDebug { 340 public: 341 template <typename T> 342 static void print(T v) {} 343 }; 344 345 class wasm::DebugCodegenVal { 346 template <typename T> 347 static void print(const char* fmt, T v) { 348 DebugCodegen(DebugChannel::Function, fmt, v); 349 } 350 351 public: 352 static void print(int32_t v) { print(" i32(%d)", v); } 353 static void print(int64_t v) { print(" i64(%" PRId64 ")", v); } 354 static void print(float v) { print(" f32(%f)", v); } 355 static void print(double v) { print(" f64(%lf)", v); } 356 static void print(void* v) { print(" ptr(%p)", v); } 357 }; 358 359 template bool wasm::ToJSValue<NoDebug>(JSContext* cx, const void* src, 360 StorageType type, MutableHandleValue dst, 361 CoercionLevel level); 362 template bool wasm::ToJSValue<DebugCodegenVal>(JSContext* cx, const void* src, 363 StorageType type, 364 MutableHandleValue dst, 365 CoercionLevel level); 366 template bool wasm::ToJSValueMayGC<NoDebug>(StorageType type); 367 template bool wasm::ToJSValueMayGC<DebugCodegenVal>(StorageType type); 368 369 template bool wasm::ToWebAssemblyValue<NoDebug>(JSContext* cx, HandleValue val, 370 ValType type, void* loc, 371 bool mustWrite64, 372 CoercionLevel level); 373 template bool wasm::ToWebAssemblyValue<DebugCodegenVal>(JSContext* cx, 374 HandleValue val, 375 ValType type, void* loc, 376 bool mustWrite64, 377 CoercionLevel level); 378 template bool wasm::ToJSValue<NoDebug>(JSContext* cx, const void* src, 379 ValType type, MutableHandleValue dst, 380 CoercionLevel level); 381 template bool wasm::ToJSValue<DebugCodegenVal>(JSContext* cx, const void* src, 382 ValType type, 383 MutableHandleValue dst, 384 CoercionLevel level); 385 template bool wasm::ToJSValueMayGC<NoDebug>(ValType type); 386 template bool wasm::ToJSValueMayGC<DebugCodegenVal>(ValType type); 387 388 template <typename Debug = NoDebug> 389 bool ToWebAssemblyValue_i32(JSContext* cx, HandleValue val, int32_t* loc, 390 bool mustWrite64) { 391 bool ok = ToInt32(cx, val, loc); 392 if (ok && mustWrite64) { 393 #if defined(JS_CODEGEN_MIPS64) 394 loc[1] = loc[0] >> 31; 395 #else 396 loc[1] = 0; 397 #endif 398 } 399 Debug::print(*loc); 400 return ok; 401 } 402 403 template <typename Debug = NoDebug> 404 bool ToWebAssemblyValue_i64(JSContext* cx, HandleValue val, int64_t* loc, 405 bool mustWrite64) { 406 MOZ_ASSERT(mustWrite64); 407 JS_TRY_VAR_OR_RETURN_FALSE(cx, *loc, ToBigInt64(cx, val)); 408 Debug::print(*loc); 409 return true; 410 } 411 412 template <typename Debug = NoDebug> 413 bool ToWebAssemblyValue_f32(JSContext* cx, HandleValue val, float* loc, 414 bool mustWrite64) { 415 bool ok = RoundFloat32(cx, val, loc); 416 if (ok && mustWrite64) { 417 loc[1] = 0.0; 418 } 419 Debug::print(*loc); 420 return ok; 421 } 422 423 template <typename Debug = NoDebug> 424 bool ToWebAssemblyValue_f64(JSContext* cx, HandleValue val, double* loc, 425 bool mustWrite64) { 426 MOZ_ASSERT(mustWrite64); 427 bool ok = ToNumber(cx, val, loc); 428 Debug::print(*loc); 429 return ok; 430 } 431 432 template <typename Debug = NoDebug> 433 bool ToWebAssemblyValue_externref(JSContext* cx, HandleValue val, void** loc, 434 bool mustWrite64) { 435 RootedAnyRef result(cx, AnyRef::null()); 436 if (!AnyRef::fromJSValue(cx, val, &result)) { 437 return false; 438 } 439 loc[0] = result.get().forCompiledCode(); 440 #ifndef JS_64BIT 441 if (mustWrite64) { 442 loc[1] = nullptr; 443 } 444 #endif 445 Debug::print(*loc); 446 return true; 447 } 448 449 template <typename Debug = NoDebug> 450 bool ToWebAssemblyValue_nullexnref(JSContext* cx, HandleValue val, void** loc, 451 bool mustWrite64) { 452 RootedAnyRef result(cx, AnyRef::null()); 453 if (!CheckNullExnRefValue(cx, val, &result)) { 454 return false; 455 } 456 loc[0] = result.get().forCompiledCode(); 457 #ifndef JS_64BIT 458 if (mustWrite64) { 459 loc[1] = nullptr; 460 } 461 #endif 462 Debug::print(*loc); 463 return true; 464 } 465 466 template <typename Debug = NoDebug> 467 bool ToWebAssemblyValue_nullexternref(JSContext* cx, HandleValue val, 468 void** loc, bool mustWrite64) { 469 RootedAnyRef result(cx, AnyRef::null()); 470 if (!CheckNullExternRefValue(cx, val, &result)) { 471 return false; 472 } 473 loc[0] = result.get().forCompiledCode(); 474 #ifndef JS_64BIT 475 if (mustWrite64) { 476 loc[1] = nullptr; 477 } 478 #endif 479 Debug::print(*loc); 480 return true; 481 } 482 483 template <typename Debug = NoDebug> 484 bool ToWebAssemblyValue_funcref(JSContext* cx, HandleValue val, void** loc, 485 bool mustWrite64) { 486 RootedAnyRef result(cx, AnyRef::null()); 487 if (!CheckFuncRefValue(cx, val, &result)) { 488 return false; 489 } 490 loc[0] = result.get().forCompiledCode(); 491 #ifndef JS_64BIT 492 if (mustWrite64) { 493 loc[1] = nullptr; 494 } 495 #endif 496 Debug::print(*loc); 497 return true; 498 } 499 500 template <typename Debug = NoDebug> 501 bool ToWebAssemblyValue_nullfuncref(JSContext* cx, HandleValue val, void** loc, 502 bool mustWrite64) { 503 RootedAnyRef result(cx, AnyRef::null()); 504 if (!CheckNullFuncRefValue(cx, val, &result)) { 505 return false; 506 } 507 loc[0] = result.get().forCompiledCode(); 508 #ifndef JS_64BIT 509 if (mustWrite64) { 510 loc[1] = nullptr; 511 } 512 #endif 513 Debug::print(*loc); 514 return true; 515 } 516 517 template <typename Debug = NoDebug> 518 bool ToWebAssemblyValue_anyref(JSContext* cx, HandleValue val, void** loc, 519 bool mustWrite64) { 520 RootedAnyRef result(cx, AnyRef::null()); 521 if (!CheckAnyRefValue(cx, val, &result)) { 522 return false; 523 } 524 loc[0] = result.get().forCompiledCode(); 525 #ifndef JS_64BIT 526 if (mustWrite64) { 527 loc[1] = nullptr; 528 } 529 #endif 530 Debug::print(*loc); 531 return true; 532 } 533 534 template <typename Debug = NoDebug> 535 bool ToWebAssemblyValue_nullref(JSContext* cx, HandleValue val, void** loc, 536 bool mustWrite64) { 537 RootedAnyRef result(cx, AnyRef::null()); 538 if (!CheckNullRefValue(cx, val, &result)) { 539 return false; 540 } 541 loc[0] = result.get().forCompiledCode(); 542 #ifndef JS_64BIT 543 if (mustWrite64) { 544 loc[1] = nullptr; 545 } 546 #endif 547 Debug::print(*loc); 548 return true; 549 } 550 551 template <typename Debug = NoDebug> 552 bool ToWebAssemblyValue_eqref(JSContext* cx, HandleValue val, void** loc, 553 bool mustWrite64) { 554 RootedAnyRef result(cx, AnyRef::null()); 555 if (!CheckEqRefValue(cx, val, &result)) { 556 return false; 557 } 558 loc[0] = result.get().forCompiledCode(); 559 #ifndef JS_64BIT 560 if (mustWrite64) { 561 loc[1] = nullptr; 562 } 563 #endif 564 Debug::print(*loc); 565 return true; 566 } 567 568 template <typename Debug = NoDebug> 569 bool ToWebAssemblyValue_i31ref(JSContext* cx, HandleValue val, void** loc, 570 bool mustWrite64) { 571 RootedAnyRef result(cx, AnyRef::null()); 572 if (!CheckI31RefValue(cx, val, &result)) { 573 return false; 574 } 575 loc[0] = result.get().forCompiledCode(); 576 #ifndef JS_64BIT 577 if (mustWrite64) { 578 loc[1] = nullptr; 579 } 580 #endif 581 Debug::print(*loc); 582 return true; 583 } 584 585 template <typename Debug = NoDebug> 586 bool ToWebAssemblyValue_structref(JSContext* cx, HandleValue val, void** loc, 587 bool mustWrite64) { 588 RootedAnyRef result(cx, AnyRef::null()); 589 if (!CheckStructRefValue(cx, val, &result)) { 590 return false; 591 } 592 loc[0] = result.get().forCompiledCode(); 593 #ifndef JS_64BIT 594 if (mustWrite64) { 595 loc[1] = nullptr; 596 } 597 #endif 598 Debug::print(*loc); 599 return true; 600 } 601 602 template <typename Debug = NoDebug> 603 bool ToWebAssemblyValue_arrayref(JSContext* cx, HandleValue val, void** loc, 604 bool mustWrite64) { 605 RootedAnyRef result(cx, AnyRef::null()); 606 if (!CheckArrayRefValue(cx, val, &result)) { 607 return false; 608 } 609 loc[0] = result.get().forCompiledCode(); 610 #ifndef JS_64BIT 611 if (mustWrite64) { 612 loc[1] = nullptr; 613 } 614 #endif 615 Debug::print(*loc); 616 return true; 617 } 618 619 template <typename Debug = NoDebug> 620 bool ToWebAssemblyValue_typeref(JSContext* cx, const TypeDef* typeDef, 621 HandleValue val, void** loc, bool mustWrite64) { 622 RootedAnyRef result(cx, AnyRef::null()); 623 if (!CheckTypeRefValue(cx, typeDef, val, &result)) { 624 return false; 625 } 626 loc[0] = result.get().forCompiledCode(); 627 #ifndef JS_64BIT 628 if (mustWrite64) { 629 loc[1] = nullptr; 630 } 631 #endif 632 Debug::print(*loc); 633 return true; 634 } 635 636 bool ToWebAssemblyValue_lossless(JSContext* cx, HandleValue val, ValType type, 637 void* loc, bool mustWrite64) { 638 if (!val.isObject() || !val.toObject().is<WasmGlobalObject>()) { 639 return false; 640 } 641 Rooted<WasmGlobalObject*> srcVal(cx, &val.toObject().as<WasmGlobalObject>()); 642 643 if (srcVal->type() != type) { 644 return false; 645 } 646 647 srcVal->val().get().writeToRootedLocation(loc, mustWrite64); 648 return true; 649 } 650 651 template <typename Debug> 652 bool wasm::ToWebAssemblyValue(JSContext* cx, HandleValue val, ValType type, 653 void* loc, bool mustWrite64, 654 CoercionLevel level) { 655 if (level == CoercionLevel::Lossless && 656 ToWebAssemblyValue_lossless(cx, val, type.valType(), (void*)loc, 657 mustWrite64)) { 658 return true; 659 } 660 661 switch (type.kind()) { 662 case ValType::I32: 663 return ToWebAssemblyValue_i32<Debug>(cx, val, (int32_t*)loc, mustWrite64); 664 case ValType::I64: 665 return ToWebAssemblyValue_i64<Debug>(cx, val, (int64_t*)loc, mustWrite64); 666 case ValType::F32: 667 return ToWebAssemblyValue_f32<Debug>(cx, val, (float*)loc, mustWrite64); 668 case ValType::F64: 669 return ToWebAssemblyValue_f64<Debug>(cx, val, (double*)loc, mustWrite64); 670 case ValType::V128: 671 break; 672 case ValType::Ref: 673 if (!type.isNullable() && val.isNull()) { 674 JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, 675 JSMSG_WASM_BAD_REF_NONNULLABLE_VALUE); 676 return false; 677 } 678 switch (type.refTypeKind()) { 679 case RefType::Func: 680 return ToWebAssemblyValue_funcref<Debug>(cx, val, (void**)loc, 681 mustWrite64); 682 case RefType::Extern: 683 return ToWebAssemblyValue_externref<Debug>(cx, val, (void**)loc, 684 mustWrite64); 685 case RefType::Exn: 686 // Break to the non-exposable case 687 break; 688 case RefType::Any: 689 return ToWebAssemblyValue_anyref<Debug>(cx, val, (void**)loc, 690 mustWrite64); 691 case RefType::NoFunc: 692 return ToWebAssemblyValue_nullfuncref<Debug>(cx, val, (void**)loc, 693 mustWrite64); 694 case RefType::NoExn: 695 return ToWebAssemblyValue_nullexnref<Debug>(cx, val, (void**)loc, 696 mustWrite64); 697 case RefType::NoExtern: 698 return ToWebAssemblyValue_nullexternref<Debug>(cx, val, (void**)loc, 699 mustWrite64); 700 case RefType::None: 701 return ToWebAssemblyValue_nullref<Debug>(cx, val, (void**)loc, 702 mustWrite64); 703 case RefType::Eq: 704 return ToWebAssemblyValue_eqref<Debug>(cx, val, (void**)loc, 705 mustWrite64); 706 case RefType::I31: 707 return ToWebAssemblyValue_i31ref<Debug>(cx, val, (void**)loc, 708 mustWrite64); 709 case RefType::Struct: 710 return ToWebAssemblyValue_structref<Debug>(cx, val, (void**)loc, 711 mustWrite64); 712 case RefType::Array: 713 return ToWebAssemblyValue_arrayref<Debug>(cx, val, (void**)loc, 714 mustWrite64); 715 case RefType::TypeRef: 716 return ToWebAssemblyValue_typeref<Debug>(cx, type.typeDef(), val, 717 (void**)loc, mustWrite64); 718 } 719 } 720 721 MOZ_ASSERT(!type.isExposable()); 722 JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, 723 JSMSG_WASM_BAD_VAL_TYPE); 724 return false; 725 } 726 727 template <typename Debug = NoDebug> 728 bool ToJSValue_i8(JSContext* cx, int8_t src, MutableHandleValue dst) { 729 dst.set(Int32Value(src)); 730 Debug::print(src); 731 return true; 732 } 733 734 template <typename Debug = NoDebug> 735 bool ToJSValue_i16(JSContext* cx, int16_t src, MutableHandleValue dst) { 736 dst.set(Int32Value(src)); 737 Debug::print(src); 738 return true; 739 } 740 741 template <typename Debug = NoDebug> 742 bool ToJSValue_i32(JSContext* cx, int32_t src, MutableHandleValue dst) { 743 dst.set(Int32Value(src)); 744 Debug::print(src); 745 return true; 746 } 747 748 template <typename Debug = NoDebug> 749 bool ToJSValue_i64(JSContext* cx, int64_t src, MutableHandleValue dst) { 750 // If bi is manipulated other than test & storing, it would need 751 // to be rooted here. 752 BigInt* bi = BigInt::createFromInt64(cx, src); 753 if (!bi) { 754 return false; 755 } 756 dst.set(BigIntValue(bi)); 757 Debug::print(src); 758 return true; 759 } 760 761 template <typename Debug = NoDebug> 762 bool ToJSValue_f32(JSContext* cx, float src, MutableHandleValue dst) { 763 dst.set(JS::CanonicalizedDoubleValue(src)); 764 Debug::print(src); 765 return true; 766 } 767 768 template <typename Debug = NoDebug> 769 bool ToJSValue_f64(JSContext* cx, double src, MutableHandleValue dst) { 770 dst.set(JS::CanonicalizedDoubleValue(src)); 771 Debug::print(src); 772 return true; 773 } 774 775 template <typename Debug = NoDebug> 776 bool ToJSValue_funcref(JSContext* cx, void* src, MutableHandleValue dst) { 777 dst.set(UnboxFuncRef(FuncRef::fromCompiledCode(src))); 778 Debug::print(src); 779 return true; 780 } 781 782 template <typename Debug = NoDebug> 783 bool ToJSValue_externref(JSContext* cx, void* src, MutableHandleValue dst) { 784 dst.set(AnyRef::fromCompiledCode(src).toJSValue()); 785 Debug::print(src); 786 return true; 787 } 788 789 template <typename Debug = NoDebug> 790 bool ToJSValue_anyref(JSContext* cx, void* src, MutableHandleValue dst) { 791 dst.set(AnyRef::fromCompiledCode(src).toJSValue()); 792 Debug::print(src); 793 return true; 794 } 795 796 template <typename Debug = NoDebug> 797 bool ToJSValue_lossless(JSContext* cx, const void* src, MutableHandleValue dst, 798 ValType type) { 799 RootedVal srcVal(cx); 800 srcVal.get().initFromRootedLocation(type, src); 801 RootedObject prototype( 802 cx, GlobalObject::getOrCreatePrototype(cx, JSProto_WasmGlobal)); 803 Rooted<WasmGlobalObject*> srcGlobal( 804 cx, WasmGlobalObject::create(cx, srcVal, false, prototype)); 805 if (!srcGlobal) { 806 return false; 807 } 808 dst.set(ObjectValue(*srcGlobal.get())); 809 return true; 810 } 811 812 template <typename Debug> 813 bool wasm::ToJSValue(JSContext* cx, const void* src, StorageType type, 814 MutableHandleValue dst, CoercionLevel level) { 815 if (level == CoercionLevel::Lossless) { 816 MOZ_ASSERT(type.isValType()); 817 return ToJSValue_lossless(cx, src, dst, type.valType()); 818 } 819 820 switch (type.kind()) { 821 case StorageType::I8: 822 return ToJSValue_i8<Debug>(cx, *reinterpret_cast<const int8_t*>(src), 823 dst); 824 case StorageType::I16: 825 return ToJSValue_i16<Debug>(cx, *reinterpret_cast<const int16_t*>(src), 826 dst); 827 case StorageType::I32: 828 return ToJSValue_i32<Debug>(cx, *reinterpret_cast<const int32_t*>(src), 829 dst); 830 case StorageType::I64: 831 return ToJSValue_i64<Debug>(cx, *reinterpret_cast<const int64_t*>(src), 832 dst); 833 case StorageType::F32: 834 return ToJSValue_f32<Debug>(cx, *reinterpret_cast<const float*>(src), 835 dst); 836 case StorageType::F64: 837 return ToJSValue_f64<Debug>(cx, *reinterpret_cast<const double*>(src), 838 dst); 839 case StorageType::V128: 840 break; 841 case StorageType::Ref: 842 switch (type.refType().hierarchy()) { 843 case RefTypeHierarchy::Func: 844 return ToJSValue_funcref<Debug>( 845 cx, *reinterpret_cast<void* const*>(src), dst); 846 case RefTypeHierarchy::Exn: 847 // Break to the non-exposable case 848 break; 849 case RefTypeHierarchy::Extern: 850 return ToJSValue_externref<Debug>( 851 cx, *reinterpret_cast<void* const*>(src), dst); 852 case RefTypeHierarchy::Any: 853 return ToJSValue_anyref<Debug>( 854 cx, *reinterpret_cast<void* const*>(src), dst); 855 break; 856 } 857 } 858 MOZ_ASSERT(!type.isExposable()); 859 Debug::print(nullptr); 860 dst.setUndefined(); 861 return true; 862 } 863 864 template <typename Debug> 865 bool wasm::ToJSValueMayGC(StorageType type) { 866 return type.kind() == StorageType::I64; 867 } 868 869 template <typename Debug> 870 bool wasm::ToJSValue(JSContext* cx, const void* src, ValType type, 871 MutableHandleValue dst, CoercionLevel level) { 872 return wasm::ToJSValue(cx, src, StorageType(type.packed()), dst, level); 873 } 874 875 template <typename Debug> 876 bool wasm::ToJSValueMayGC(ValType type) { 877 return wasm::ToJSValueMayGC(StorageType(type.packed())); 878 } 879 880 /* static */ 881 wasm::FuncRef wasm::FuncRef::fromAnyRefUnchecked(AnyRef p) { 882 if (p.isNull()) { 883 return FuncRef::null(); 884 } 885 886 MOZ_ASSERT(p.isJSObject() && p.toJSObject().is<JSFunction>()); 887 return FuncRef(&p.toJSObject().as<JSFunction>()); 888 } 889 890 void wasm::FuncRef::trace(JSTracer* trc) const { 891 if (value_) { 892 TraceManuallyBarrieredEdge(trc, &value_, "wasm funcref referent"); 893 } 894 } 895 896 Value wasm::UnboxFuncRef(FuncRef val) { 897 JSFunction* fn = val.asJSFunction(); 898 Value result; 899 MOZ_ASSERT_IF(fn, fn->is<JSFunction>()); 900 result.setObjectOrNull(fn); 901 return result; 902 } 903 904 #ifdef DEBUG 905 void wasm::AssertEdgeSourceNotInsideNursery(void* vp) { 906 Nursery& nursery = TlsContext.get()->runtime()->gc.nursery(); 907 MOZ_ASSERT(!nursery.isInside(vp)); 908 } 909 #endif