static nsresult
ToStringHelper(const char* aSeverity, const nsString& aMessage,
               const nsString& aSourceName, const nsString* aSourceLine,
               uint32_t aLineNumber, uint32_t aColumnNumber,
               nsACString& /*UTF8*/ aResult)
{
    static const char format0[] =
        "[%s: \"%s\" {file: \"%s\" line: %d column: %d source: \"%s\"}]";
    static const char format1[] =
        "[%s: \"%s\" {file: \"%s\" line: %d}]";
    static const char format2[] =
        "[%s: \"%s\"]";

    UniqueChars temp;
    char* tempMessage = nullptr;
    char* tempSourceName = nullptr;
    char* tempSourceLine = nullptr;

    if (!aMessage.IsEmpty())
        tempMessage = ToNewUTF8String(aMessage);
    if (!aSourceName.IsEmpty())
        // Use at most 512 characters from mSourceName.
        tempSourceName = ToNewUTF8String(StringHead(aSourceName, 512));
    if (aSourceLine && !aSourceLine->IsEmpty())
        // Use at most 512 characters from mSourceLine.
        tempSourceLine = ToNewUTF8String(StringHead(*aSourceLine, 512));

    if (nullptr != tempSourceName && nullptr != tempSourceLine) {
        temp = JS_smprintf(format0,
                           aSeverity,
                           tempMessage,
                           tempSourceName,
                           aLineNumber,
                           aColumnNumber,
                           tempSourceLine);
    } else if (!aSourceName.IsEmpty()) {
        temp = JS_smprintf(format1,
                           aSeverity,
                           tempMessage,
                           tempSourceName,
                           aLineNumber);
    } else {
        temp = JS_smprintf(format2,
                           aSeverity,
                           tempMessage);
    }

    if (nullptr != tempMessage)
        free(tempMessage);
    if (nullptr != tempSourceName)
        free(tempSourceName);
    if (nullptr != tempSourceLine)
        free(tempSourceLine);

    if (!temp)
        return NS_ERROR_OUT_OF_MEMORY;

    aResult.Assign(temp.get());
    return NS_OK;
}
Example #2
0
template<size_t N> inline bool
Error(JSContext* cx, const char (&input)[N], uint32_t expectedLine,
      uint32_t expectedColumn)
{
    AutoInflatedString str(cx);
    RootedValue dummy(cx);
    str = input;

    bool ok = JS_ParseJSON(cx, str.chars(), str.length(), &dummy);
    CHECK(!ok);

    RootedValue exn(cx);
    CHECK(JS_GetPendingException(cx, &exn));
    JS_ClearPendingException(cx);

    js::ErrorReport report(cx);
    CHECK(report.init(cx, exn, js::ErrorReport::WithSideEffects));
    CHECK(report.report()->errorNumber == JSMSG_JSON_BAD_PARSE);

    UniqueChars lineAndColumnASCII = JS_smprintf("line %d column %d", expectedLine, expectedColumn);
    CHECK(strstr(report.toStringResult().c_str(), lineAndColumnASCII.get()) != nullptr);

    /* We do not execute JS, so there should be no exception thrown. */
    CHECK(!JS_IsExceptionPending(cx));

    return true;
}
void
Statistics::printStats()
{
    if (aborted) {
        if (fullFormat)
            fprintf(fp, "OOM during GC statistics collection. The report is unavailable for this GC.\n");
        fflush(fp);
        return;
    }

    if (fullFormat) {
        UniqueChars msg = formatDetailedMessage();
        if (msg)
            fprintf(fp, "GC(T+%.3fs) %s\n", t(slices[0].start - startupTime) / 1000.0, msg.get());
    } else {
        int64_t total, longest;
        gcDuration(&total, &longest);

        int64_t markTotal = SumPhase(PHASE_MARK, phaseTimes);
        fprintf(fp, "%f %f %f\n",
                t(total),
                t(markTotal),
                t(phaseTimes[PHASE_DAG_NONE][PHASE_SWEEP]));
        MOZ_ASSERT(phaseExtra[PHASE_SWEEP].dagSlot == PHASE_DAG_NONE);
    }
    fflush(fp);
}
Example #4
0
/*
 * Serializes the script/function pair into a "descriptive string" which is
 * allowed to fail. This function cannot trigger a GC because it could finalize
 * some scripts, resize the hash table of profile strings, and invalidate the
 * AddPtr held while invoking allocProfileString.
 */
UniqueChars
SPSProfiler::allocProfileString(JSScript* script, JSFunction* maybeFun)
{
    // Note: this profiler string is regexp-matched by
    // devtools/client/profiler/cleopatra/js/parserWorker.js.

    // Get the function name, if any.
    JSAtom* atom = maybeFun ? maybeFun->displayAtom() : nullptr;

    // Get the script filename, if any, and its length.
    const char* filename = script->filename();
    if (filename == nullptr)
        filename = "<unknown>";
    size_t lenFilename = strlen(filename);

    // Get the line number and its length as a string.
    uint64_t lineno = script->lineno();
    size_t lenLineno = 1;
    for (uint64_t i = lineno; i /= 10; lenLineno++);

    // Determine the required buffer size.
    size_t len = lenFilename + lenLineno + 1; // +1 for the ":" separating them.
    if (atom) {
        len += JS::GetDeflatedUTF8StringLength(atom) + 3; // +3 for the " (" and ")" it adds.
    }

    // Allocate the buffer.
    UniqueChars cstr(js_pod_malloc<char>(len + 1));
    if (!cstr)
        return nullptr;

    // Construct the descriptive string.
    DebugOnly<size_t> ret;
    if (atom) {
        UniqueChars atomStr = StringToNewUTF8CharsZ(nullptr, *atom);
        if (!atomStr)
            return nullptr;

        ret = snprintf(cstr.get(), len + 1, "%s (%s:%" PRIu64 ")", atomStr.get(), filename, lineno);
    } else {
        ret = snprintf(cstr.get(), len + 1, "%s:%" PRIu64, filename, lineno);
    }

    MOZ_ASSERT(ret == len, "Computed length should match actual length!");

    return cstr;
}
Example #5
0
/**
 * Returns a new UPluralRules with the locale and type options of the given
 * PluralRules.
 */
static UPluralRules* NewUPluralRules(JSContext* cx,
                                     Handle<PluralRulesObject*> pluralRules) {
  RootedObject internals(cx, intl::GetInternalsObject(cx, pluralRules));
  if (!internals) {
    return nullptr;
  }

  RootedValue value(cx);

  if (!GetProperty(cx, internals, internals, cx->names().locale, &value)) {
    return nullptr;
  }
  UniqueChars locale = intl::EncodeLocale(cx, value.toString());
  if (!locale) {
    return nullptr;
  }

  if (!GetProperty(cx, internals, internals, cx->names().type, &value)) {
    return nullptr;
  }

  UPluralType category;
  {
    JSLinearString* type = value.toString()->ensureLinear(cx);
    if (!type) {
      return nullptr;
    }

    if (StringEqualsAscii(type, "cardinal")) {
      category = UPLURAL_TYPE_CARDINAL;
    } else {
      MOZ_ASSERT(StringEqualsAscii(type, "ordinal"));
      category = UPLURAL_TYPE_ORDINAL;
    }
  }

  UErrorCode status = U_ZERO_ERROR;
  UPluralRules* pr =
      uplrules_openForType(IcuLocale(locale.get()), category, &status);
  if (U_FAILURE(status)) {
    intl::ReportInternalError(cx);
    return nullptr;
  }
  return pr;
}
Example #6
0
UniqueChars
Statistics::formatJsonPhaseTimes(const PhaseTimeTable phaseTimes)
{
    FragmentVector fragments;
    char buffer[128];
    for (AllPhaseIterator iter(phaseTimes); !iter.done(); iter.advance()) {
        Phase phase;
        size_t dagSlot;
        iter.get(&phase, &dagSlot);

        UniqueChars name = FilterJsonKey(phases[phase].name);
        int64_t ownTime = phaseTimes[dagSlot][phase];
        JS_snprintf(buffer, sizeof(buffer), "\"%s\":%llu.%03llu",
                    name.get(), ownTime / 1000, ownTime % 1000);

        if (!fragments.append(DuplicateString(buffer)))
            return UniqueChars(nullptr);
    }
    return Join(fragments, ",");
}
Example #7
0
static UniqueChars
DecodeFieldName(JSContext* cx, Decoder& d, CStringSet* dupSet)
{
    UniqueChars fieldName = d.readCString();
    if (!fieldName) {
        Fail(cx, d, "expected export external name string");
        return nullptr;
    }

    CStringSet::AddPtr p = dupSet->lookupForAdd(fieldName.get());
    if (p) {
        Fail(cx, d, "duplicate export");
        return nullptr;
    }

    if (!dupSet->add(p, fieldName.get()))
        return nullptr;

    return Move(fieldName);
}
Example #8
0
void
Statistics::printStats()
{
    if (aborted) {
        fprintf(fp, "OOM during GC statistics collection. The report is unavailable for this GC.\n");
    } else {
        UniqueChars msg = formatDetailedMessage();
        if (msg)
            fprintf(fp, "GC(T+%.3fs) %s\n", t(slices[0].start - startupTime) / 1000.0, msg.get());
    }
    fflush(fp);
}
Example #9
0
// ES6 draft rev34 (2015/02/20) 19.1.2.2 Object.create(O [, Properties])
bool
js::obj_create(JSContext* cx, unsigned argc, Value* vp)
{
    CallArgs args = CallArgsFromVp(argc, vp);

    // Step 1.
    if (args.length() == 0) {
        JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_MORE_ARGS_NEEDED,
                             "Object.create", "0", "s");
        return false;
    }

    if (!args[0].isObjectOrNull()) {
        RootedValue v(cx, args[0]);
        UniqueChars bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, v, nullptr);
        if (!bytes)
            return false;
        JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_UNEXPECTED_TYPE,
                             bytes.get(), "not an object or null");
        return false;
    }

    // Step 2.
    RootedObject proto(cx, args[0].toObjectOrNull());
    RootedPlainObject obj(cx, ObjectCreateImpl(cx, proto));
    if (!obj)
        return false;

    // Step 3.
    if (args.hasDefined(1)) {
        RootedValue val(cx, args[1]);
        RootedObject props(cx, ToObject(cx, val));
        if (!props || !DefineProperties(cx, obj, props))
            return false;
    }

    // Step 4.
    args.rval().setObject(*obj);
    return true;
}
Example #10
0
static char*
FormatWasmFrame(JSContext* cx, const FrameIter& iter, char* buf, int num, bool showArgs)
{
    JSAtom* functionDisplayAtom = iter.functionDisplayAtom();
    UniqueChars nameStr;
    if (functionDisplayAtom)
        nameStr = StringToNewUTF8CharsZ(cx, *functionDisplayAtom);

    buf = sprintf_append(cx, buf, "%d %s()",
                         num,
                         nameStr ? nameStr.get() : "<wasm-function>");
    if (!buf)
        return nullptr;
    const char* filename = iter.filename();
    uint32_t lineno = iter.computeLine();
    buf = sprintf_append(cx, buf, " [\"%s\":%d]\n",
                         filename ? filename : "<unknown>",
                         lineno);

    MOZ_ASSERT(!cx->isExceptionPending());
    return buf;
}
Example #11
0
static PerfMeasurement*
GetPM(JSContext* cx, JS::HandleValue value, const char* fname)
{
    if (!value.isObject()) {
        UniqueChars bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, value, nullptr);
        if (!bytes)
            return nullptr;
        JS_ReportErrorNumber(cx, GetErrorMessage, 0, JSMSG_NOT_NONNULL_OBJECT, bytes.get());
        return nullptr;
    }
    RootedObject obj(cx, &value.toObject());
    PerfMeasurement* p = (PerfMeasurement*)
        JS_GetInstancePrivate(cx, obj, &pm_class, nullptr);
    if (p)
        return p;

    // JS_GetInstancePrivate only sets an exception if its last argument
    // is nonzero, so we have to do it by hand.
    JS_ReportErrorNumber(cx, GetErrorMessage, 0, JSMSG_INCOMPATIBLE_PROTO,
                         pm_class.name, fname, JS_GetClass(obj)->name);
    return nullptr;
}
Example #12
0
MOZ_ALWAYS_INLINE bool
WeakMap_set_impl(JSContext* cx, const CallArgs& args)
{
    MOZ_ASSERT(IsWeakMap(args.thisv()));

    if (!args.get(0).isObject()) {
        UniqueChars bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, args.get(0), nullptr);
        if (!bytes)
            return false;
        JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_NOT_NONNULL_OBJECT, bytes.get());
        return false;
    }

    RootedObject key(cx, &args[0].toObject());
    Rooted<JSObject*> thisObj(cx, &args.thisv().toObject());
    Rooted<WeakMapObject*> map(cx, &thisObj->as<WeakMapObject>());

    if (!SetWeakMapEntryInternal(cx, map, key, args.get(1)))
        return false;
    args.rval().set(args.thisv());
    return true;
}
Example #13
0
static bool
DecodeImport(JSContext* cx, Decoder& d, ModuleGeneratorData* init, ImportNameVector* importNames)
{
    const DeclaredSig* sig;
    if (!DecodeSignatureIndex(cx, d, *init, &sig))
        return false;

    if (!init->imports.emplaceBack(sig))
        return false;

    UniqueChars moduleName = d.readCString();
    if (!moduleName)
        return Fail(cx, d, "expected import module name");

    if (!*moduleName.get())
        return Fail(cx, d, "module name cannot be empty");

    UniqueChars funcName = d.readCString();
    if (!funcName)
        return Fail(cx, d, "expected import func name");

    return importNames->emplaceBack(Move(moduleName), Move(funcName));
}
Example #14
0
static bool
WasmTextToBinary(JSContext* cx, unsigned argc, Value* vp)
{
    CallArgs args = CallArgsFromVp(argc, vp);
    RootedObject callee(cx, &args.callee());

    if (args.length() != 1) {
        ReportUsageError(cx, callee, "Wrong number of arguments");
        return false;
    }

    if (!args[0].isString()) {
        ReportUsageError(cx, callee, "First argument must be a String");
        return false;
    }

    AutoStableStringChars twoByteChars(cx);
    if (!twoByteChars.initTwoByte(cx, args[0].toString()))
        return false;

    UniqueChars error;
    wasm::UniqueBytecode bytes = wasm::TextToBinary(twoByteChars.twoByteChars(), &error);
    if (!bytes) {
        JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_WASM_TEXT_FAIL,
                             error.get() ? error.get() : "out of memory");
        return false;
    }

    Rooted<ArrayBufferObject*> buffer(cx, ArrayBufferObject::create(cx, bytes->length()));
    if (!buffer)
        return false;

    memcpy(buffer->dataPointer(), bytes->begin(), bytes->length());

    args.rval().setObject(*buffer);
    return true;
}
Example #15
0
static bool
DecodeUnknownSection(JSContext* cx, Decoder& d)
{
    UniqueChars sectionName = d.readCString();
    if (!sectionName)
        return Fail(cx, d, "failed to read section name");

    if (!strcmp(sectionName.get(), SigLabel) ||
        !strcmp(sectionName.get(), ImportLabel) ||
        !strcmp(sectionName.get(), DeclLabel) ||
        !strcmp(sectionName.get(), TableLabel) ||
        !strcmp(sectionName.get(), MemoryLabel) ||
        !strcmp(sectionName.get(), ExportLabel) ||
        !strcmp(sectionName.get(), FuncLabel) ||
        !strcmp(sectionName.get(), DataLabel))
    {
        return Fail(cx, d, "known section out of order");
    }

    if (!d.skipSection())
        return Fail(cx, d, "unable to skip unknown section");

    return true;
}
Example #16
0
static bool
PrintSingleError(JSContext* cx, FILE* file, JS::ConstUTF8CharsZ toStringResult,
                 T* report, PrintErrorKind kind)
{
    UniqueChars prefix;
    if (report->filename)
        prefix = JS_smprintf("%s:", report->filename);

    if (report->lineno) {
        prefix = JS_smprintf("%s%u:%u ", prefix ? prefix.get() : "", report->lineno,
                                        report->column);
    }

    if (kind != PrintErrorKind::Error) {
        const char* kindPrefix = nullptr;
        switch (kind) {
          case PrintErrorKind::Error:
            MOZ_CRASH("unreachable");
          case PrintErrorKind::Warning:
            kindPrefix = "warning";
            break;
          case PrintErrorKind::StrictWarning:
            kindPrefix = "strict warning";
            break;
          case PrintErrorKind::Note:
            kindPrefix = "note";
            break;
        }

        prefix = JS_smprintf("%s%s: ", prefix ? prefix.get() : "", kindPrefix);
    }

    const char* message = toStringResult ? toStringResult.c_str() : report->message().c_str();

    /* embedded newlines -- argh! */
    const char* ctmp;
    while ((ctmp = strchr(message, '\n')) != 0) {
        ctmp++;
        if (prefix)
            fputs(prefix.get(), file);
        mozilla::Unused << fwrite(message, 1, ctmp - message, file);
        message = ctmp;
    }

    /* If there were no filename or lineno, the prefix might be empty */
    if (prefix)
        fputs(prefix.get(), file);
    fputs(message, file);

    PrintErrorLine(file, prefix.get(), report);
    fputc('\n', file);

    fflush(file);
    return true;
}
Example #17
0
void
Statistics::printStats()
{
    if (fullFormat) {
        UniqueChars msg = formatDetailedMessage();
        if (msg)
            fprintf(fp, "GC(T+%.3fs) %s\n", t(slices[0].start - startupTime) / 1000.0, msg.get());
    } else {
        int64_t total, longest;
        gcDuration(&total, &longest);

        fprintf(fp, "%f %f %f\n",
                t(total),
                t(phaseTimes[PHASE_MARK]),
                t(phaseTimes[PHASE_SWEEP]));
    }
    fflush(fp);
}
Example #18
0
static bool
WeakMap_construct(JSContext* cx, unsigned argc, Value* vp)
{
    CallArgs args = CallArgsFromVp(argc, vp);

    // ES6 draft rev 31 (15 Jan 2015) 23.3.1.1 step 1.
    if (!ThrowIfNotConstructing(cx, args, "WeakMap"))
        return false;

    RootedObject newTarget(cx, &args.newTarget().toObject());
    RootedObject obj(cx, CreateThis(cx, &WeakMapObject::class_, newTarget));
    if (!obj)
        return false;

    // Steps 5-6, 11.
    if (!args.get(0).isNullOrUndefined()) {
        // Steps 7a-b.
        RootedValue adderVal(cx);
        if (!GetProperty(cx, obj, obj, cx->names().set, &adderVal))
            return false;

        // Step 7c.
        if (!IsCallable(adderVal))
            return ReportIsNotFunction(cx, adderVal);

        bool isOriginalAdder = IsNativeFunction(adderVal, WeakMap_set);
        RootedValue mapVal(cx, ObjectValue(*obj));
        FastCallGuard fig(cx, adderVal);
        InvokeArgs& args2 = fig.args();

        // Steps 7d-e.
        JS::ForOfIterator iter(cx);
        if (!iter.init(args[0]))
            return false;

        RootedValue pairVal(cx);
        RootedObject pairObject(cx);
        RootedValue keyVal(cx);
        RootedObject keyObject(cx);
        RootedValue val(cx);
        RootedValue dummy(cx);
        while (true) {
            // Steps 12a-e.
            bool done;
            if (!iter.next(&pairVal, &done))
                return false;
            if (done)
                break;

            // Step 12f.
            if (!pairVal.isObject()) {
                JS_ReportErrorNumber(cx, GetErrorMessage, nullptr,
                                     JSMSG_INVALID_MAP_ITERABLE, "WeakMap");
                return false;
            }

            pairObject = &pairVal.toObject();
            if (!pairObject)
                return false;

            // Steps 12g-h.
            if (!GetElement(cx, pairObject, pairObject, 0, &keyVal))
                return false;

            // Steps 12i-j.
            if (!GetElement(cx, pairObject, pairObject, 1, &val))
                return false;

            // Steps 12k-l.
            if (isOriginalAdder) {
                if (keyVal.isPrimitive()) {
                    UniqueChars bytes =
                        DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, keyVal, nullptr);
                    if (!bytes)
                        return false;
                    JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_NOT_NONNULL_OBJECT, bytes.get());
                    return false;
                }

                keyObject = &keyVal.toObject();
                if (!SetWeakMapEntry(cx, obj, keyObject, val))
                    return false;
            } else {
                if (!args2.init(cx, 2))
                    return false;

                args2[0].set(keyVal);
                args2[1].set(val);

                if (!fig.call(cx, adderVal, mapVal, &dummy))
                    return false;
            }
        }
    }

    args.rval().setObject(*obj);
    return true;
}
bool
ForOfIterator::init(HandleValue iterable, NonIterableBehavior nonIterableBehavior)
{
    JSContext* cx = cx_;
    RootedObject iterableObj(cx, ToObject(cx, iterable));
    if (!iterableObj)
        return false;

    MOZ_ASSERT(index == NOT_ARRAY);

    // Check the PIC first for a match.
    if (iterableObj->is<ArrayObject>()) {
        ForOfPIC::Chain* stubChain = ForOfPIC::getOrCreate(cx);
        if (!stubChain)
            return false;

        bool optimized;
        if (!stubChain->tryOptimizeArray(cx, iterableObj.as<ArrayObject>(), &optimized))
            return false;

        if (optimized) {
            // Got optimized stub.  Array is optimizable.
            index = 0;
            iterator = iterableObj;
            return true;
        }
    }

    MOZ_ASSERT(index == NOT_ARRAY);

    RootedValue callee(cx);
    RootedId iteratorId(cx, SYMBOL_TO_JSID(cx->wellKnownSymbols().iterator));
    if (!GetProperty(cx, iterableObj, iterableObj, iteratorId, &callee))
        return false;

    // If obj[@@iterator] is undefined and we were asked to allow non-iterables,
    // bail out now without setting iterator.  This will make valueIsIterable(),
    // which our caller should check, return false.
    if (nonIterableBehavior == AllowNonIterable && callee.isUndefined())
        return true;

    // Throw if obj[@@iterator] isn't callable.
    // js::Invoke is about to check for this kind of error anyway, but it would
    // throw an inscrutable error message about |method| rather than this nice
    // one about |obj|.
    if (!callee.isObject() || !callee.toObject().isCallable()) {
        UniqueChars bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, iterable, nullptr);
        if (!bytes)
            return false;
        JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr, JSMSG_NOT_ITERABLE, bytes.get());
        return false;
    }

    RootedValue res(cx);
    if (!js::Call(cx, callee, iterable, &res))
        return false;

    if (!res.isObject())
        return ThrowCheckIsObject(cx, CheckIsObjectKind::GetIterator);

    iterator = &res.toObject();
    return true;
}
Example #20
0
/**
 * This creates new UNumberFormat with calculated digit formatting
 * properties for PluralRules.
 *
 * This is similar to NewUNumberFormat but doesn't allow for currency or
 * percent types.
 */
static UNumberFormat* NewUNumberFormatForPluralRules(
    JSContext* cx, Handle<PluralRulesObject*> pluralRules) {
  RootedObject internals(cx, intl::GetInternalsObject(cx, pluralRules));
  if (!internals) {
    return nullptr;
  }

  RootedValue value(cx);

  if (!GetProperty(cx, internals, internals, cx->names().locale, &value)) {
    return nullptr;
  }
  UniqueChars locale = intl::EncodeLocale(cx, value.toString());
  if (!locale) {
    return nullptr;
  }

  uint32_t uMinimumIntegerDigits = 1;
  uint32_t uMinimumFractionDigits = 0;
  uint32_t uMaximumFractionDigits = 3;
  int32_t uMinimumSignificantDigits = -1;
  int32_t uMaximumSignificantDigits = -1;

  bool hasP;
  if (!HasProperty(cx, internals, cx->names().minimumSignificantDigits,
                   &hasP)) {
    return nullptr;
  }

  if (hasP) {
    if (!GetProperty(cx, internals, internals,
                     cx->names().minimumSignificantDigits, &value)) {
      return nullptr;
    }
    uMinimumSignificantDigits = value.toInt32();

    if (!GetProperty(cx, internals, internals,
                     cx->names().maximumSignificantDigits, &value)) {
      return nullptr;
    }
    uMaximumSignificantDigits = value.toInt32();
  } else {
    if (!GetProperty(cx, internals, internals, cx->names().minimumIntegerDigits,
                     &value)) {
      return nullptr;
    }
    uMinimumIntegerDigits = AssertedCast<uint32_t>(value.toInt32());

    if (!GetProperty(cx, internals, internals,
                     cx->names().minimumFractionDigits, &value)) {
      return nullptr;
    }
    uMinimumFractionDigits = AssertedCast<uint32_t>(value.toInt32());

    if (!GetProperty(cx, internals, internals,
                     cx->names().maximumFractionDigits, &value)) {
      return nullptr;
    }
    uMaximumFractionDigits = AssertedCast<uint32_t>(value.toInt32());
  }

  UErrorCode status = U_ZERO_ERROR;
  UNumberFormat* nf = unum_open(UNUM_DECIMAL, nullptr, 0,
                                IcuLocale(locale.get()), nullptr, &status);
  if (U_FAILURE(status)) {
    intl::ReportInternalError(cx);
    return nullptr;
  }
  ScopedICUObject<UNumberFormat, unum_close> toClose(nf);

  if (uMinimumSignificantDigits != -1) {
    unum_setAttribute(nf, UNUM_SIGNIFICANT_DIGITS_USED, true);
    unum_setAttribute(nf, UNUM_MIN_SIGNIFICANT_DIGITS,
                      uMinimumSignificantDigits);
    unum_setAttribute(nf, UNUM_MAX_SIGNIFICANT_DIGITS,
                      uMaximumSignificantDigits);
  } else {
    unum_setAttribute(nf, UNUM_MIN_INTEGER_DIGITS, uMinimumIntegerDigits);
    unum_setAttribute(nf, UNUM_MIN_FRACTION_DIGITS, uMinimumFractionDigits);
    unum_setAttribute(nf, UNUM_MAX_FRACTION_DIGITS, uMaximumFractionDigits);
  }

  return toClose.forget();
}