Esempio n. 1
0
// ES6 rev 25 (2014 May 22) 19.4.2.7
bool
SymbolObject::keyFor(JSContext *cx, unsigned argc, Value *vp)
{
    CallArgs args = CallArgsFromVp(argc, vp);

    // step 1
    HandleValue arg = args.get(0);
    if (!arg.isSymbol()) {
        js_ReportValueErrorFlags(cx, JSREPORT_ERROR, JSMSG_UNEXPECTED_TYPE, JSDVG_SEARCH_STACK,
                                 arg, js::NullPtr(), "not a symbol", nullptr);
        return false;
    }

    // step 2
    if (arg.toSymbol()->code() == JS::SymbolCode::InSymbolRegistry) {
#ifdef DEBUG
        RootedString desc(cx, arg.toSymbol()->description());
        MOZ_ASSERT(Symbol::for_(cx, desc) == arg.toSymbol());
#endif
        args.rval().setString(arg.toSymbol()->description());
        return true;
    }

    // step 3: omitted
    // step 4
    args.rval().setUndefined();
    return true;
}
Esempio n. 2
0
//ES6 rev 24 (2014 Apr 27) 19.4.3.2
bool
SymbolObject::toString_impl(JSContext *cx, CallArgs args)
{
    // steps 1-3
    HandleValue thisv = args.thisv();
    JS_ASSERT(IsSymbol(thisv));
    Rooted<Symbol*> sym(cx, thisv.isSymbol()
                            ? thisv.toSymbol()
                            : thisv.toObject().as<SymbolObject>().unbox());

    // steps 4-7
    StringBuffer sb(cx);
    if (!sb.append("Symbol("))
        return false;
    RootedString str(cx, sym->description());
    if (str) {
        if (!sb.append(str))
            return false;
    }
    if (!sb.append(')'))
        return false;

    // step 8
    str = sb.finishString();
    if (!str)
        return false;
    args.rval().setString(str);
    return true;
}
Esempio n. 3
0
static bool
CloneValue(JSContext *cx, HandleValue selfHostedValue, MutableHandleValue vp)
{
    if (selfHostedValue.isObject()) {
        RootedNativeObject selfHostedObject(cx, &selfHostedValue.toObject().as<NativeObject>());
        JSObject *clone = CloneObject(cx, selfHostedObject);
        if (!clone)
            return false;
        vp.setObject(*clone);
    } else if (selfHostedValue.isBoolean() || selfHostedValue.isNumber() || selfHostedValue.isNullOrUndefined()) {
        // Nothing to do here: these are represented inline in the value.
        vp.set(selfHostedValue);
    } else if (selfHostedValue.isString()) {
        if (!selfHostedValue.toString()->isFlat())
            MOZ_CRASH();
        JSFlatString *selfHostedString = &selfHostedValue.toString()->asFlat();
        JSString *clone = CloneString(cx, selfHostedString);
        if (!clone)
            return false;
        vp.setString(clone);
    } else if (selfHostedValue.isSymbol()) {
        // Well-known symbols are shared.
        mozilla::DebugOnly<JS::Symbol *> sym = selfHostedValue.toSymbol();
        MOZ_ASSERT(sym->isWellKnownSymbol());
        MOZ_ASSERT(cx->wellKnownSymbols().get(size_t(sym->code())) == sym);
        vp.set(selfHostedValue);
    } else {
        MOZ_CRASH("Self-hosting CloneValue can't clone given value.");
    }
    return true;
}
Esempio n. 4
0
Node::Node(HandleValue value)
{
    if (value.isObject())
        construct(&value.toObject());
    else if (value.isString())
        construct(value.toString());
    else if (value.isSymbol())
        construct(value.toSymbol());
    else
        construct<void>(nullptr);
}
Esempio n. 5
0
// ES6 rev 27 (2014 Aug 24) 19.4.3.2
bool
SymbolObject::toString_impl(JSContext *cx, CallArgs args)
{
    // steps 1-3
    HandleValue thisv = args.thisv();
    JS_ASSERT(IsSymbol(thisv));
    Rooted<Symbol*> sym(cx, thisv.isSymbol()
                            ? thisv.toSymbol()
                            : thisv.toObject().as<SymbolObject>().unbox());

    // step 4
    return SymbolDescriptiveString(cx, sym, args.rval());
}
Esempio n. 6
0
bool
ErrorReport::init(JSContext* cx, HandleValue exn,
                  SniffingBehavior sniffingBehavior)
{
    MOZ_ASSERT(!cx->isExceptionPending());
    MOZ_ASSERT(!reportp);

    if (exn.isObject()) {
        // Because ToString below could error and an exception object could become
        // unrooted, we must root our exception object, if any.
        exnObject = &exn.toObject();
        reportp = ErrorFromException(cx, exnObject);

        if (!reportp && sniffingBehavior == NoSideEffects) {
            JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
                                      JSMSG_ERR_DURING_THROW);
            return false;
        }

        // Let's see if the exception is from add-on code, if so, it should be reported
        // to telementry.
        ReportAddonExceptionToTelementry(cx);
    }


    // Be careful not to invoke ToString if we've already successfully extracted
    // an error report, since the exception might be wrapped in a security
    // wrapper, and ToString-ing it might throw.
    if (reportp) {
        str = ErrorReportToString(cx, reportp);
    } else if (exn.isSymbol()) {
        RootedValue strVal(cx);
        if (js::SymbolDescriptiveString(cx, exn.toSymbol(), &strVal))
            str = strVal.toString();
        else
            str = nullptr;
    } else {
        str = ToString<CanGC>(cx, exn);
    }

    if (!str)
        cx->clearPendingException();

    // If ErrorFromException didn't get us a JSErrorReport, then the object
    // was not an ErrorObject, security-wrapped or otherwise. However, it might
    // still quack like one. Give duck-typing a chance.  We start by looking for
    // "filename" (all lowercase), since that's where DOMExceptions store their
    // filename.  Then we check "fileName", which is where Errors store it.  We
    // have to do it in that order, because DOMExceptions have Error.prototype
    // on their proto chain, and hence also have a "fileName" property, but its
    // value is "".
    const char* filename_str = "filename";
    if (!reportp && exnObject && IsDuckTypedErrorObject(cx, exnObject, &filename_str))
    {
        // Temporary value for pulling properties off of duck-typed objects.
        RootedValue val(cx);

        RootedString name(cx);
        if (JS_GetProperty(cx, exnObject, js_name_str, &val) && val.isString())
            name = val.toString();
        else
            cx->clearPendingException();

        RootedString msg(cx);
        if (JS_GetProperty(cx, exnObject, js_message_str, &val) && val.isString())
            msg = val.toString();
        else
            cx->clearPendingException();

        // If we have the right fields, override the ToString we performed on
        // the exception object above with something built out of its quacks
        // (i.e. as much of |NameQuack: MessageQuack| as we can make).
        //
        // It would be nice to use ErrorReportToString here, but we can't quite
        // do it - mostly because we'd need to figure out what JSExnType |name|
        // corresponds to, which may not be any JSExnType at all.
        if (name && msg) {
            RootedString colon(cx, JS_NewStringCopyZ(cx, ": "));
            if (!colon)
                return false;
            RootedString nameColon(cx, ConcatStrings<CanGC>(cx, name, colon));
            if (!nameColon)
                return false;
            str = ConcatStrings<CanGC>(cx, nameColon, msg);
            if (!str)
                return false;
        } else if (name) {
            str = name;
        } else if (msg) {
            str = msg;
        }

        if (JS_GetProperty(cx, exnObject, filename_str, &val)) {
            RootedString tmp(cx, ToString<CanGC>(cx, val));
            if (tmp)
                filename.encodeUtf8(cx, tmp);
            else
                cx->clearPendingException();
        } else {
            cx->clearPendingException();
        }

        uint32_t lineno;
        if (!JS_GetProperty(cx, exnObject, js_lineNumber_str, &val) ||
            !ToUint32(cx, val, &lineno))
        {
            cx->clearPendingException();
            lineno = 0;
        }

        uint32_t column;
        if (!JS_GetProperty(cx, exnObject, js_columnNumber_str, &val) ||
            !ToUint32(cx, val, &column))
        {
            cx->clearPendingException();
            column = 0;
        }

        reportp = &ownedReport;
        new (reportp) JSErrorReport();
        ownedReport.filename = filename.ptr();
        ownedReport.lineno = lineno;
        ownedReport.exnType = JSEXN_INTERNALERR;
        ownedReport.column = column;
        if (str) {
            // Note that using |str| for |message_| here is kind of wrong,
            // because |str| is supposed to be of the format
            // |ErrorName: ErrorMessage|, and |message_| is supposed to
            // correspond to |ErrorMessage|. But this is what we've
            // historically done for duck-typed error objects.
            //
            // If only this stuff could get specced one day...
            char* utf8;
            if (str->ensureFlat(cx) &&
                strChars.initTwoByte(cx, str) &&
                (utf8 = JS::CharsToNewUTF8CharsZ(cx, strChars.twoByteRange()).c_str()))
            {
                ownedReport.initOwnedMessage(utf8);
            } else {
                cx->clearPendingException();
                str = nullptr;
            }
        }
    }

    const char* utf8Message = nullptr;
    if (str)
        utf8Message = toStringResultBytesStorage.encodeUtf8(cx, str);
    if (!utf8Message)
        utf8Message = "unknown (can't convert to string)";

    if (!reportp) {
        // This is basically an inlined version of
        //
        //   JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr,
        //                            JSMSG_UNCAUGHT_EXCEPTION, utf8Message);
        //
        // but without the reporting bits.  Instead it just puts all
        // the stuff we care about in our ownedReport and message_.
        if (!populateUncaughtExceptionReportUTF8(cx, utf8Message)) {
            // Just give up.  We're out of memory or something; not much we can
            // do here.
            return false;
        }
    } else {
        toStringResult_ = JS::ConstUTF8CharsZ(utf8Message, strlen(utf8Message));
        /* Flag the error as an exception. */
        reportp->flags |= JSREPORT_EXCEPTION;
    }

    return true;
}