WasmAnyRef.cpp (3557B)
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 2023 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/WasmAnyRef.h" 20 21 #include "vm/JSContext.h" 22 #include "vm/JSObject.h" 23 #include "vm/NativeObject.h" 24 25 #include "vm/JSObject-inl.h" 26 27 using namespace js; 28 using namespace js::wasm; 29 30 class WasmValueBox : public NativeObject { 31 public: 32 static const unsigned VALUE_SLOT = 0; 33 static const unsigned RESERVED_SLOTS = 1; 34 static const JSClass class_; 35 36 static WasmValueBox* create(JSContext* cx, HandleValue value); 37 Value value() const { return getFixedSlot(VALUE_SLOT); } 38 }; 39 40 const JSClass WasmValueBox::class_ = { 41 "WasmValueBox", 42 JSCLASS_HAS_RESERVED_SLOTS(RESERVED_SLOTS), 43 }; 44 45 WasmValueBox* WasmValueBox::create(JSContext* cx, HandleValue value) { 46 WasmValueBox* obj = NewObjectWithGivenProto<WasmValueBox>(cx, nullptr); 47 if (!obj) { 48 return nullptr; 49 } 50 obj->initFixedSlot(VALUE_SLOT, value); 51 return obj; 52 } 53 54 const JSClass* AnyRef::valueBoxClass() { return &WasmValueBox::class_; } 55 56 size_t AnyRef::valueBoxOffsetOfValue() { 57 return NativeObject::getFixedSlotOffset(WasmValueBox::VALUE_SLOT); 58 } 59 60 bool AnyRef::fromJSValue(JSContext* cx, HandleValue value, 61 MutableHandleAnyRef result) { 62 if (value.isNull()) { 63 result.set(AnyRef::null()); 64 return true; 65 } 66 67 if (value.isString()) { 68 JSString* string = value.toString(); 69 result.set(AnyRef::fromJSString(string)); 70 return true; 71 } 72 73 if (value.isObject()) { 74 JSObject& obj = value.toObject(); 75 MOZ_ASSERT(!obj.is<WasmValueBox>()); 76 MOZ_ASSERT(obj.compartment() == cx->compartment()); 77 result.set(AnyRef::fromJSObject(obj)); 78 return true; 79 } 80 81 if (value.isInt32() && !int32NeedsBoxing(value.toInt32())) { 82 result.set(AnyRef::fromInt32(value.toInt32())); 83 return true; 84 } 85 86 if (value.isDouble()) { 87 double doubleValue = value.toDouble(); 88 int32_t intValue; 89 if (mozilla::NumberEqualsInt32(doubleValue, &intValue) && 90 !int32NeedsBoxing(intValue)) { 91 result.set(AnyRef::fromInt32(intValue)); 92 return true; 93 } 94 } 95 96 JSObject* box = AnyRef::boxValue(cx, value); 97 if (!box) { 98 return false; 99 } 100 result.set(AnyRef::fromJSObject(*box)); 101 return true; 102 } 103 104 JSObject* AnyRef::boxValue(JSContext* cx, HandleValue value) { 105 MOZ_ASSERT(AnyRef::valueNeedsBoxing(value)); 106 return WasmValueBox::create(cx, value); 107 } 108 109 Value wasm::AnyRef::toJSValue() const { 110 // If toJSValue needs to allocate then we need a more complicated API, and 111 // we need to root the value in the callers, see comments in callExport(). 112 Value value; 113 if (isNull()) { 114 value.setNull(); 115 } else if (isJSString()) { 116 value.setString(toJSString()); 117 } else if (isI31()) { 118 value.setInt32(toI31()); 119 } else { 120 JSObject& obj = toJSObject(); 121 if (obj.is<WasmValueBox>()) { 122 value = obj.as<WasmValueBox>().value(); 123 } else { 124 value.setObject(obj); 125 } 126 } 127 return value; 128 }