Commit 7ce7945c authored by Ryan Hunt's avatar Ryan Hunt
Browse files

Bug 1561521 - Add non-nullable references. r=lth

This commit adds decoding, validation, and JS-API type-checking for
non-nullable references.

Differential Revision: https://phabricator.services.mozilla.com/D85068
parent f6c4069d
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -442,6 +442,7 @@ MSG_DEF(JSMSG_WASM_BAD_ELEMENT, 0, JSEXN_TYPEERR, "\"element\" proper
MSG_DEF(JSMSG_WASM_BAD_ELEMENT_GENERALIZED, 0, JSEXN_TYPEERR, "\"element\" property of table descriptor must be \"funcref\" or \"externref\"")
MSG_DEF(JSMSG_WASM_BAD_ELEMENT_GENERALIZED, 0, JSEXN_TYPEERR, "\"element\" property of table descriptor must be \"funcref\" or \"externref\"")
MSG_DEF(JSMSG_WASM_BAD_IMPORT_ARG,     0, JSEXN_TYPEERR,     "second argument must be an object")
MSG_DEF(JSMSG_WASM_BAD_IMPORT_ARG,     0, JSEXN_TYPEERR,     "second argument must be an object")
MSG_DEF(JSMSG_WASM_BAD_IMPORT_FIELD,   1, JSEXN_TYPEERR,     "import object field '{0}' is not an Object")
MSG_DEF(JSMSG_WASM_BAD_IMPORT_FIELD,   1, JSEXN_TYPEERR,     "import object field '{0}' is not an Object")
MSG_DEF(JSMSG_WASM_BAD_REF_NONNULLABLE_VALUE,  0, JSEXN_TYPEERR,     "cannot pass null to non-nullable WebAssembly reference")
MSG_DEF(JSMSG_WASM_BAD_FUNCREF_VALUE,  0, JSEXN_TYPEERR,     "can only pass WebAssembly exported functions to funcref")
MSG_DEF(JSMSG_WASM_BAD_FUNCREF_VALUE,  0, JSEXN_TYPEERR,     "can only pass WebAssembly exported functions to funcref")
MSG_DEF(JSMSG_WASM_BAD_VAL_TYPE,       0, JSEXN_TYPEERR,     "cannot pass v128 to or from JS")
MSG_DEF(JSMSG_WASM_BAD_VAL_TYPE,       0, JSEXN_TYPEERR,     "cannot pass v128 to or from JS")
MSG_DEF(JSMSG_WASM_BAD_GLOBAL_TYPE,    0, JSEXN_TYPEERR,     "bad type for a WebAssembly.Global")
MSG_DEF(JSMSG_WASM_BAD_GLOBAL_TYPE,    0, JSEXN_TYPEERR,     "bad type for a WebAssembly.Global")
+10 −2
Original line number Original line Diff line number Diff line
@@ -65,8 +65,11 @@ enum class TypeCode {
  // A reference to any host value.
  // A reference to any host value.
  ExternRef = 0x6f,  // SLEB128(-0x11)
  ExternRef = 0x6f,  // SLEB128(-0x11)


  // Type constructor for reference types.
  // Type constructor for nullable reference types.
  OptRef = 0x6c,
  NullableRef = 0x6c,  // SLEB128(-0x14)

  // Type constructor for non-nullable reference types.
  Ref = 0x6b,  // SLEB128(-0x15)


  // Type constructor for function types
  // Type constructor for function types
  Func = 0x60,  // SLEB128(-0x20)
  Func = 0x60,  // SLEB128(-0x20)
@@ -91,6 +94,11 @@ static constexpr TypeCode LowestPrimitiveTypeCode = TypeCode::V128;


static constexpr TypeCode AbstractReferenceTypeCode = TypeCode::ExternRef;
static constexpr TypeCode AbstractReferenceTypeCode = TypeCode::ExternRef;


// A type code used to represent (ref null? typeindex) whether or not the type
// is encoded with 'Ref' or 'NullableRef'.

static constexpr TypeCode AbstractReferenceTypeIndexCode = TypeCode::Ref;

enum class FuncTypeIdDescKind { None, Immediate, Global };
enum class FuncTypeIdDescKind { None, Immediate, Global };


// A wasm::Trap represents a wasm-defined trap that can occur during execution
// A wasm::Trap represents a wasm-defined trap that can occur during execution
+1 −1
Original line number Original line Diff line number Diff line
@@ -608,7 +608,7 @@ BD_ConstantValue global_constantValue(const GlobalDesc* global) {
    case TypeCode::F64:
    case TypeCode::F64:
      v.u.f64 = value.f64();
      v.u.f64 = value.f64();
      break;
      break;
    case TypeCode::OptRef:
    case TypeCode::NullableRef:
      v.u.r = value.ref().forCompiledCode();
      v.u.r = value.ref().forCompiledCode();
      break;
      break;
    default:
    default:
+9 −0
Original line number Original line Diff line number Diff line
@@ -200,6 +200,15 @@ static bool ToWebAssemblyValue(JSContext* cx, HandleValue val, ValType type,
    case ValType::V128:
    case ValType::V128:
      MOZ_CRASH("unexpected v128 in ToWebAssemblyValue");
      MOZ_CRASH("unexpected v128 in ToWebAssemblyValue");
    case ValType::Ref:
    case ValType::Ref:
#ifdef ENABLE_WASM_GC
      if (!type.isNullable() && val.isNull()) {
        JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr,
                                 JSMSG_WASM_BAD_REF_NONNULLABLE_VALUE);
        return false;
      }
#else
      MOZ_ASSERT(type.isNullable());
#endif
      switch (type.refTypeKind()) {
      switch (type.refTypeKind()) {
        case RefType::Func:
        case RefType::Func:
          return ToWebAssemblyValue_funcref<Debug>(cx, val, (void**)loc);
          return ToWebAssemblyValue_funcref<Debug>(cx, val, (void**)loc);
+13 −6
Original line number Original line Diff line number Diff line
@@ -431,10 +431,15 @@ bool wasm::CodeCachingAvailable(JSContext* cx) {
  return StreamingCompilationAvailable(cx) && IonAvailable(cx);
  return StreamingCompilationAvailable(cx) && IonAvailable(cx);
}
}


bool wasm::CheckRefType(JSContext* cx, RefType::Kind targetTypeKind,
bool wasm::CheckRefType(JSContext* cx, RefType targetType, HandleValue v,
                        HandleValue v, MutableHandleFunction fnval,
                        MutableHandleFunction fnval,
                        MutableHandleAnyRef refval) {
                        MutableHandleAnyRef refval) {
  switch (targetTypeKind) {
  if (!targetType.isNullable() && v.isNull()) {
    JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr,
                             JSMSG_WASM_BAD_REF_NONNULLABLE_VALUE);
    return false;
  }
  switch (targetType.kind()) {
    case RefType::Func:
    case RefType::Func:
      if (!CheckFuncRefValue(cx, v, fnval)) {
      if (!CheckFuncRefValue(cx, v, fnval)) {
        return false;
        return false;
@@ -489,7 +494,7 @@ static bool ToWebAssemblyValue(JSContext* cx, ValType targetType, HandleValue v,
    case ValType::Ref: {
    case ValType::Ref: {
      RootedFunction fun(cx);
      RootedFunction fun(cx);
      RootedAnyRef any(cx, AnyRef::null());
      RootedAnyRef any(cx, AnyRef::null());
      if (!CheckRefType(cx, targetType.refTypeKind(), v, &fun, &any)) {
      if (!CheckRefType(cx, targetType.refType(), v, &fun, &any)) {
        return false;
        return false;
      }
      }
      switch (targetType.refTypeKind()) {
      switch (targetType.refTypeKind()) {
@@ -2695,7 +2700,7 @@ bool WasmTableObject::setImpl(JSContext* cx, const CallArgs& args) {
  RootedValue fillValue(cx, args[1]);
  RootedValue fillValue(cx, args[1]);
  RootedFunction fun(cx);
  RootedFunction fun(cx);
  RootedAnyRef any(cx, AnyRef::null());
  RootedAnyRef any(cx, AnyRef::null());
  if (!CheckRefType(cx, table.elemType().kind(), fillValue, &fun, &any)) {
  if (!CheckRefType(cx, table.elemType(), fillValue, &fun, &any)) {
    return false;
    return false;
  }
  }
  switch (table.elemType().kind()) {
  switch (table.elemType().kind()) {
@@ -2706,6 +2711,8 @@ bool WasmTableObject::setImpl(JSContext* cx, const CallArgs& args) {
    case RefType::Extern:
    case RefType::Extern:
      table.fillAnyRef(index, 1, any);
      table.fillAnyRef(index, 1, any);
      break;
      break;
    case RefType::TypeIndex:
      MOZ_CRASH("Ref NYI");
  }
  }


  args.rval().setUndefined();
  args.rval().setUndefined();
@@ -2755,7 +2762,7 @@ bool WasmTableObject::growImpl(JSContext* cx, const CallArgs& args) {
  if (!fillValue.isNull()) {
  if (!fillValue.isNull()) {
    RootedFunction fun(cx);
    RootedFunction fun(cx);
    RootedAnyRef any(cx, AnyRef::null());
    RootedAnyRef any(cx, AnyRef::null());
    if (!CheckRefType(cx, table.elemType().kind(), fillValue, &fun, &any)) {
    if (!CheckRefType(cx, table.elemType(), fillValue, &fun, &any)) {
      return false;
      return false;
    }
    }
    switch (table.repr()) {
    switch (table.repr()) {
Loading