Backed out changeset d53c38086d1b (bug 1853454) for causing spidermonkey build bustag...
[gecko.git] / js / src / wasm / WasmValType.cpp
blob3ac14044dc7f70fd7262cc2bc1b14b5bc0a64524
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:
4 * Copyright 2021 Mozilla Foundation
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
10 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include "wasm/WasmValType.h"
21 #include "js/Conversions.h"
22 #include "js/ErrorReport.h"
23 #include "js/friend/ErrorMessages.h" // JSMSG_*
24 #include "js/Printf.h"
25 #include "js/Value.h"
27 #include "vm/JSAtomUtils.h" // Atomize
28 #include "vm/JSObject.h"
29 #include "vm/StringType.h"
30 #include "wasm/WasmFeatures.h"
31 #include "wasm/WasmJS.h"
33 #include "vm/JSAtomUtils-inl.h" // AtomToId
34 #include "vm/JSObject-inl.h"
36 using namespace js;
37 using namespace js::wasm;
39 RefType RefType::topType() const {
40 switch (kind()) {
41 case RefType::Any:
42 case RefType::Eq:
43 case RefType::I31:
44 case RefType::Array:
45 case RefType::Struct:
46 case RefType::None:
47 return RefType::any();
48 case RefType::Func:
49 case RefType::NoFunc:
50 return RefType::func();
51 case RefType::Extern:
52 case RefType::NoExtern:
53 return RefType::extern_();
54 case RefType::TypeRef:
55 switch (typeDef()->kind()) {
56 case TypeDefKind::Array:
57 case TypeDefKind::Struct:
58 return RefType::any();
59 case TypeDefKind::Func:
60 return RefType::func();
61 case TypeDefKind::None:
62 MOZ_CRASH("should not see TypeDefKind::None at this point");
65 MOZ_CRASH("switch is exhaustive");
68 TypeDefKind RefType::typeDefKind() const {
69 switch (kind()) {
70 case RefType::Struct:
71 return TypeDefKind::Struct;
72 case RefType::Array:
73 return TypeDefKind::Array;
74 case RefType::Func:
75 return TypeDefKind::Func;
76 default:
77 return TypeDefKind::None;
79 MOZ_CRASH("switch is exhaustive");
82 static bool ToRefType(JSContext* cx, JSLinearString* typeLinearStr,
83 RefType* out) {
84 if (StringEqualsLiteral(typeLinearStr, "anyfunc") ||
85 StringEqualsLiteral(typeLinearStr, "funcref")) {
86 // The JS API uses "anyfunc" uniformly as the external name of funcref. We
87 // also allow "funcref" for compatibility with code we've already shipped.
88 *out = RefType::func();
89 return true;
91 if (StringEqualsLiteral(typeLinearStr, "externref")) {
92 *out = RefType::extern_();
93 return true;
95 #ifdef ENABLE_WASM_GC
96 if (GcAvailable(cx)) {
97 if (StringEqualsLiteral(typeLinearStr, "anyref")) {
98 *out = RefType::any();
99 return true;
101 if (StringEqualsLiteral(typeLinearStr, "eqref")) {
102 *out = RefType::eq();
103 return true;
105 if (StringEqualsLiteral(typeLinearStr, "i31ref")) {
106 *out = RefType::i31();
107 return true;
109 if (StringEqualsLiteral(typeLinearStr, "structref")) {
110 *out = RefType::struct_();
111 return true;
113 if (StringEqualsLiteral(typeLinearStr, "arrayref")) {
114 *out = RefType::array();
115 return true;
117 if (StringEqualsLiteral(typeLinearStr, "nullfuncref")) {
118 *out = RefType::nofunc();
119 return true;
121 if (StringEqualsLiteral(typeLinearStr, "nullexternref")) {
122 *out = RefType::noextern();
123 return true;
125 if (StringEqualsLiteral(typeLinearStr, "nullref")) {
126 *out = RefType::none();
127 return true;
130 #endif
132 JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr,
133 JSMSG_WASM_BAD_STRING_VAL_TYPE);
134 return false;
137 enum class RefTypeResult {
138 Failure,
139 Parsed,
140 Unparsed,
143 static RefTypeResult MaybeToRefType(JSContext* cx, HandleObject obj,
144 RefType* out) {
145 #ifdef ENABLE_WASM_FUNCTION_REFERENCES
146 if (!wasm::FunctionReferencesAvailable(cx)) {
147 return RefTypeResult::Unparsed;
150 JSAtom* refAtom = Atomize(cx, "ref", strlen("ref"));
151 if (!refAtom) {
152 return RefTypeResult::Failure;
154 RootedId refId(cx, AtomToId(refAtom));
156 RootedValue refVal(cx);
157 if (!GetProperty(cx, obj, obj, refId, &refVal)) {
158 return RefTypeResult::Failure;
161 RootedString typeStr(cx, ToString(cx, refVal));
162 if (!typeStr) {
163 return RefTypeResult::Failure;
166 Rooted<JSLinearString*> typeLinearStr(cx, typeStr->ensureLinear(cx));
167 if (!typeLinearStr) {
168 return RefTypeResult::Failure;
171 if (StringEqualsLiteral(typeLinearStr, "func")) {
172 *out = RefType::func();
173 } else if (StringEqualsLiteral(typeLinearStr, "extern")) {
174 *out = RefType::extern_();
175 # ifdef ENABLE_WASM_GC
176 } else if (GcAvailable(cx) && StringEqualsLiteral(typeLinearStr, "any")) {
177 *out = RefType::any();
178 } else if (GcAvailable(cx) && StringEqualsLiteral(typeLinearStr, "eq")) {
179 *out = RefType::eq();
180 } else if (GcAvailable(cx) && StringEqualsLiteral(typeLinearStr, "i31")) {
181 *out = RefType::i31();
182 } else if (GcAvailable(cx) && StringEqualsLiteral(typeLinearStr, "struct")) {
183 *out = RefType::struct_();
184 } else if (GcAvailable(cx) && StringEqualsLiteral(typeLinearStr, "array")) {
185 *out = RefType::array();
186 # endif
187 } else {
188 return RefTypeResult::Unparsed;
191 JSAtom* nullableAtom = Atomize(cx, "nullable", strlen("nullable"));
192 if (!nullableAtom) {
193 return RefTypeResult::Failure;
195 RootedId nullableId(cx, AtomToId(nullableAtom));
196 RootedValue nullableVal(cx);
197 if (!GetProperty(cx, obj, obj, nullableId, &nullableVal)) {
198 return RefTypeResult::Failure;
201 bool nullable = ToBoolean(nullableVal);
202 if (!nullable) {
203 *out = out->asNonNullable();
205 MOZ_ASSERT(out->isNullable() == nullable);
206 return RefTypeResult::Parsed;
207 #else
208 return RefTypeResult::Unparsed;
209 #endif
212 bool wasm::ToValType(JSContext* cx, HandleValue v, ValType* out) {
213 if (v.isObject()) {
214 RootedObject obj(cx, &v.toObject());
215 RefType refType;
216 switch (MaybeToRefType(cx, obj, &refType)) {
217 case RefTypeResult::Failure:
218 return false;
219 case RefTypeResult::Parsed:
220 *out = ValType(refType);
221 return true;
222 case RefTypeResult::Unparsed:
223 break;
227 RootedString typeStr(cx, ToString(cx, v));
228 if (!typeStr) {
229 return false;
232 Rooted<JSLinearString*> typeLinearStr(cx, typeStr->ensureLinear(cx));
233 if (!typeLinearStr) {
234 return false;
237 if (StringEqualsLiteral(typeLinearStr, "i32")) {
238 *out = ValType::I32;
239 } else if (StringEqualsLiteral(typeLinearStr, "i64")) {
240 *out = ValType::I64;
241 } else if (StringEqualsLiteral(typeLinearStr, "f32")) {
242 *out = ValType::F32;
243 } else if (StringEqualsLiteral(typeLinearStr, "f64")) {
244 *out = ValType::F64;
245 #ifdef ENABLE_WASM_SIMD
246 } else if (SimdAvailable(cx) && StringEqualsLiteral(typeLinearStr, "v128")) {
247 *out = ValType::V128;
248 #endif
249 } else {
250 RefType rt;
251 if (ToRefType(cx, typeLinearStr, &rt)) {
252 *out = ValType(rt);
253 } else {
254 // ToRefType will report an error when it fails, just return false
255 return false;
259 return true;
262 bool wasm::ToRefType(JSContext* cx, HandleValue v, RefType* out) {
263 if (v.isObject()) {
264 RootedObject obj(cx, &v.toObject());
265 switch (MaybeToRefType(cx, obj, out)) {
266 case RefTypeResult::Failure:
267 return false;
268 case RefTypeResult::Parsed:
269 return true;
270 case RefTypeResult::Unparsed:
271 break;
275 RootedString typeStr(cx, ToString(cx, v));
276 if (!typeStr) {
277 return false;
280 Rooted<JSLinearString*> typeLinearStr(cx, typeStr->ensureLinear(cx));
281 if (!typeLinearStr) {
282 return false;
285 return ToRefType(cx, typeLinearStr, out);
288 UniqueChars wasm::ToString(RefType type, const TypeContext* types) {
289 // Try to emit a shorthand version first
290 if (type.isNullable() && !type.isTypeRef()) {
291 const char* literal = nullptr;
292 switch (type.kind()) {
293 case RefType::Func:
294 literal = "funcref";
295 break;
296 case RefType::Extern:
297 literal = "externref";
298 break;
299 case RefType::Any:
300 literal = "anyref";
301 break;
302 case RefType::NoFunc:
303 literal = "nullfuncref";
304 break;
305 case RefType::NoExtern:
306 literal = "nullexternref";
307 break;
308 case RefType::None:
309 literal = "nullref";
310 break;
311 case RefType::Eq:
312 literal = "eqref";
313 break;
314 case RefType::I31:
315 literal = "i31ref";
316 break;
317 case RefType::Struct:
318 literal = "structref";
319 break;
320 case RefType::Array:
321 literal = "arrayref";
322 break;
323 case RefType::TypeRef: {
324 MOZ_CRASH("type ref should not be possible here");
327 return DuplicateString(literal);
330 // Emit the full reference type with heap type
331 const char* heapType = nullptr;
332 switch (type.kind()) {
333 case RefType::Func:
334 heapType = "func";
335 break;
336 case RefType::Extern:
337 heapType = "extern";
338 break;
339 case RefType::Any:
340 heapType = "any";
341 break;
342 case RefType::NoFunc:
343 heapType = "nofunc";
344 break;
345 case RefType::NoExtern:
346 heapType = "noextern";
347 break;
348 case RefType::None:
349 heapType = "none";
350 break;
351 case RefType::Eq:
352 heapType = "eq";
353 break;
354 case RefType::I31:
355 heapType = "i31";
356 break;
357 case RefType::Struct:
358 heapType = "struct";
359 break;
360 case RefType::Array:
361 heapType = "array";
362 break;
363 case RefType::TypeRef: {
364 if (types) {
365 uint32_t typeIndex = types->indexOf(*type.typeDef());
366 return JS_smprintf("(ref %s%d)", type.isNullable() ? "null " : "",
367 typeIndex);
369 return JS_smprintf("(ref %s?)", type.isNullable() ? "null " : "");
372 return JS_smprintf("(ref %s%s)", type.isNullable() ? "null " : "", heapType);
375 UniqueChars wasm::ToString(ValType type, const TypeContext* types) {
376 return ToString(type.fieldType(), types);
379 UniqueChars wasm::ToString(FieldType type, const TypeContext* types) {
380 const char* literal = nullptr;
381 switch (type.kind()) {
382 case FieldType::I8:
383 literal = "i8";
384 break;
385 case FieldType::I16:
386 literal = "i16";
387 break;
388 case FieldType::I32:
389 literal = "i32";
390 break;
391 case FieldType::I64:
392 literal = "i64";
393 break;
394 case FieldType::V128:
395 literal = "v128";
396 break;
397 case FieldType::F32:
398 literal = "f32";
399 break;
400 case FieldType::F64:
401 literal = "f64";
402 break;
403 case FieldType::Ref:
404 return ToString(type.refType(), types);
406 return DuplicateString(literal);
409 UniqueChars wasm::ToString(const Maybe<ValType>& type,
410 const TypeContext* types) {
411 return type ? ToString(type.ref(), types) : JS_smprintf("%s", "void");