Bug 1511958 - part 5, WasmJS changes for BigInt<->I64 proposal draft
authorAsumu Takikawa <asumu@igalia.com>
Thu, 05 Dec 2019 02:49:18 +0000
changeset 2517402 b2e3c0d287eb9e7eae2755bf328c75339a7b775b
parent 2516758 32f84899fc000d95337a25c14a27470d0c52e3ee
child 2517403 0c144a90a99e7285405d81d672b16d5d420d9615
push id460515
push userreviewbot
push dateThu, 05 Dec 2019 02:49:40 +0000
treeherdertry@0c144a90a99e [default view] [failures only]
bugs1511958
milestone73.0a1
Bug 1511958 - part 5, WasmJS changes for BigInt<->I64 proposal This commit adds further Wasm to JS API changes from the BigInt to I64 proposal, mostly relating to globals. Differential Diff: PHID-DIFF-xktnwuszah5r4ktwq5jv
js/src/fuzz-tests/testWasm.cpp
js/src/wasm/WasmJS.cpp
js/src/wasm/WasmJS.h
--- a/js/src/fuzz-tests/testWasm.cpp
+++ b/js/src/fuzz-tests/testWasm.cpp
@@ -411,17 +411,17 @@ static int testWasmFuzz(const uint8_t* b
             rawMemByte += rawMemory[byteLen - 1];
           }
         }
 
         if (propObj->is<WasmGlobalObject>()) {
           Rooted<WasmGlobalObject*> global(gCx,
                                            &propObj->as<WasmGlobalObject>());
           if (global->type() != ValType::I64) {
-            lastReturnVal = global->value(gCx);
+            global->value(gCx, &lastReturnVal);
           }
         }
       }
     }
   }
 
   return 0;
 }
--- a/js/src/wasm/WasmJS.cpp
+++ b/js/src/wasm/WasmJS.cpp
@@ -215,40 +215,71 @@ static bool ToWebAssemblyValue(JSContext
     case ValType::AnyRef: {
       RootedAnyRef tmp(cx, AnyRef::null());
       if (!BoxAnyRef(cx, v, &tmp)) {
         return false;
       }
       val.set(Val(ValType::AnyRef, tmp));
       return true;
     }
+    case ValType::I64: {
+#ifdef ENABLE_WASM_BIGINT
+      if (HasI64BigIntSupport(cx)) {
+        BigInt* bigint = ToBigInt(cx, v);
+        if (!bigint) {
+          return false;
+        }
+        val.set(Val(BigInt::toUint64(bigint)));
+        return true;
+      }
+#endif
+      break;
+    }
     case ValType::Ref:
-    case ValType::NullRef:
-    case ValType::I64: {
+    case ValType::NullRef: {
       break;
     }
   }
   MOZ_CRASH("unexpected import value type, caller must guard");
 }
 
-static Value ToJSValue(const Val& val) {
+static bool ToJSValue(JSContext* cx, const Val& val, MutableHandleValue out) {
   switch (val.type().code()) {
     case ValType::I32:
-      return Int32Value(val.i32());
+      out.setInt32(val.i32());
+      return true;
     case ValType::F32:
-      return JS::CanonicalizedDoubleValue(double(val.f32()));
+      out.setDouble(JS::CanonicalizeNaN(double(val.f32())));
+      return true;
     case ValType::F64:
-      return JS::CanonicalizedDoubleValue(val.f64());
+      out.setDouble(JS::CanonicalizeNaN(val.f64()));
+      return true;
     case ValType::FuncRef:
-      return UnboxFuncRef(FuncRef::fromAnyRefUnchecked(val.ref()));
+      out.set(UnboxFuncRef(FuncRef::fromAnyRefUnchecked(val.ref())));
+      return true;
     case ValType::AnyRef:
-      return UnboxAnyRef(val.ref());
+      out.set(UnboxAnyRef(val.ref()));
+      return true;
+#ifdef ENABLE_WASM_BIGINT
+    case ValType::I64: {
+      if (HasI64BigIntSupport(cx)) {
+        BigInt* bi = BigInt::createFromInt64(cx, val.i64());
+        if (!bi) {
+          return false;
+        }
+        out.setBigInt(bi);
+        return true;
+      }
+      break;
+    }
+#else
+    case ValType::I64:
+#endif
     case ValType::Ref:
     case ValType::NullRef:
-    case ValType::I64:
       break;
   }
   MOZ_CRASH("unexpected type when translating to a JS value");
 }
 
 // ============================================================================
 // Imports
 
@@ -369,33 +400,39 @@ bool js::wasm::GetImports(JSContext* cx,
               !imports->globalObjs.resize(index + 1)) {
             ReportOutOfMemory(cx);
             return false;
           }
           imports->globalObjs[index] = obj;
           obj->val(&val);
         } else {
           if (IsNumberType(global.type())) {
-            if (!v.isNumber()) {
-              return ThrowBadImportType(cx, import.field.get(), "Number");
+            if (HasI64BigIntSupport(cx)) {
+              if (global.type() == ValType::I64 && v.isNumber()) {
+                return ThrowBadImportType(cx, import.field.get(), "BigInt");
+              } else if (global.type() != ValType::I64 && v.isBigInt()) {
+                return ThrowBadImportType(cx, import.field.get(), "Number");
+              }
+            } else {
+              if (!v.isNumber()) {
+                return ThrowBadImportType(cx, import.field.get(), "Number");
+              } else if (global.type() == ValType::I64) {
+                JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr,
+                                         JSMSG_WASM_BAD_I64_LINK);
+                return false;
+              }
             }
           } else {
             MOZ_ASSERT(global.type().isReference());
             if (!v.isNull() && !v.isObject() && global.type().isRef()) {
               return ThrowBadImportType(cx, import.field.get(),
                                         "Object-or-null");
             }
           }
 
-          if (global.type() == ValType::I64) {
-            JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr,
-                                     JSMSG_WASM_BAD_I64_LINK);
-            return false;
-          }
-
           if (global.isMutable()) {
             JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr,
                                      JSMSG_WASM_BAD_GLOB_MUT_LINK);
             return false;
           }
 
           if (!ToWebAssemblyValue(cx, global.type(), v, &val)) {
             return false;
@@ -2628,16 +2665,21 @@ bool WasmGlobalObject::construct(JSConte
   } else if (args.length() == 1 && StringEqualsLiteral(typeLinearStr, "i64")) {
     // For the time being, i64 is allowed only if there is not an
     // initializing value.
     globalType = ValType::I64;
   } else if (StringEqualsLiteral(typeLinearStr, "f32")) {
     globalType = ValType::F32;
   } else if (StringEqualsLiteral(typeLinearStr, "f64")) {
     globalType = ValType::F64;
+#ifdef ENABLE_WASM_BIGINT
+  } else if (StringEqualsAscii(typeLinearStr, "i64") &&
+             HasI64BigIntSupport(cx)) {
+    globalType = ValType::I64;
+#endif
 #ifdef ENABLE_WASM_REFTYPES
   } else if (HasReftypesSupport(cx) &&
              StringEqualsLiteral(typeLinearStr, "funcref")) {
     globalType = ValType::FuncRef;
   } else if (HasReftypesSupport(cx) &&
              StringEqualsLiteral(typeLinearStr, "anyref")) {
     globalType = ValType::AnyRef;
 #endif
@@ -2703,22 +2745,30 @@ static bool IsGlobal(HandleValue v) {
 /* static */
 bool WasmGlobalObject::valueGetterImpl(JSContext* cx, const CallArgs& args) {
   switch (args.thisv().toObject().as<WasmGlobalObject>().type().code()) {
     case ValType::I32:
     case ValType::F32:
     case ValType::F64:
     case ValType::FuncRef:
     case ValType::AnyRef:
-      args.rval().set(args.thisv().toObject().as<WasmGlobalObject>().value(cx));
-      return true;
-    case ValType::I64:
+      return args.thisv().toObject().as<WasmGlobalObject>().value(cx,
+                                                                  args.rval());
+    case ValType::I64: {
+#ifdef ENABLE_WASM_BIGINT
+      if (HasI64BigIntSupport(cx)) {
+        return args.thisv().toObject().as<WasmGlobalObject>().value(
+            cx, args.rval());
+      }
+#endif
+
       JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr,
                                JSMSG_WASM_BAD_I64_TYPE);
       return false;
+    }
     case ValType::Ref:
       MOZ_CRASH("Ref NYI");
     case ValType::NullRef:
       MOZ_CRASH("NullRef not expressible");
   }
   MOZ_CRASH();
 }
 
@@ -2737,17 +2787,17 @@ bool WasmGlobalObject::valueSetterImpl(J
   RootedWasmGlobalObject global(
       cx, &args.thisv().toObject().as<WasmGlobalObject>());
   if (!global->isMutable()) {
     JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr,
                              JSMSG_WASM_GLOBAL_IMMUTABLE);
     return false;
   }
 
-  if (global->type() == ValType::I64) {
+  if (global->type() == ValType::I64 && !HasI64BigIntSupport(cx)) {
     JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr,
                              JSMSG_WASM_BAD_I64_TYPE);
     return false;
   }
 
   RootedVal val(cx);
   if (!ToWebAssemblyValue(cx, global->type(), args.get(0), &val)) {
     return false;
@@ -2774,18 +2824,27 @@ bool WasmGlobalObject::valueSetterImpl(J
       cell->ref = val.get().ref();
       if (!cell->ref.isNull()) {
         JSObject::writeBarrierPost(cell->ref.asJSObjectAddress(),
                                    prevPtr.asJSObject(),
                                    cell->ref.asJSObject());
       }
       break;
     }
-    case ValType::I64:
+    case ValType::I64: {
+#ifdef ENABLE_WASM_BIGINT
+      if (!HasI64BigIntSupport(cx)) {
+        MOZ_CRASH("unexpected i64 when setting global's value");
+      }
+      cell->i64 = val.get().i64();
+      break;
+#else
       MOZ_CRASH("unexpected i64 when setting global's value");
+#endif
+    }
     case ValType::Ref:
       MOZ_CRASH("Ref NYI");
     case ValType::NullRef:
       MOZ_CRASH("NullRef not expressible");
   }
 
   args.rval().setUndefined();
   return true;
@@ -2841,21 +2900,20 @@ void WasmGlobalObject::val(MutableHandle
     case ValType::Ref:
       MOZ_CRASH("Ref NYI");
     case ValType::NullRef:
       MOZ_CRASH("NullRef not expressible");
   }
   MOZ_CRASH("unexpected Global type");
 }
 
-Value WasmGlobalObject::value(JSContext* cx) const {
-  // ToJSValue crashes on I64; this is desirable.
+bool WasmGlobalObject::value(JSContext* cx, MutableHandleValue out) {
   RootedVal result(cx);
   val(&result);
-  return ToJSValue(result.get());
+  return ToJSValue(cx, result.get(), out);
 }
 
 WasmGlobalObject::Cell* WasmGlobalObject::cell() const {
   return reinterpret_cast<Cell*>(getReservedSlot(CELL_SLOT).toPrivate());
 }
 
 // ============================================================================
 // WebAssembly class and static methods
--- a/js/src/wasm/WasmJS.h
+++ b/js/src/wasm/WasmJS.h
@@ -198,18 +198,17 @@ class WasmGlobalObject : public NativeOb
 
   static WasmGlobalObject* create(JSContext* cx, wasm::HandleVal value,
                                   bool isMutable);
   bool isNewborn() { return getReservedSlot(CELL_SLOT).isUndefined(); }
 
   wasm::ValType type() const;
   void val(wasm::MutableHandleVal outval) const;
   bool isMutable() const;
-  // value() will MOZ_CRASH if the type is int64
-  Value value(JSContext* cx) const;
+  bool value(JSContext* cx, MutableHandleValue out);
   Cell* cell() const;
 };
 
 // The class of WebAssembly.Instance. Each WasmInstanceObject owns a
 // wasm::Instance. These objects are used both as content-facing JS objects and
 // as internal implementation details of asm.js.
 
 class WasmInstanceObject : public NativeObject {