// 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; }
//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; }
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; }
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); }
// 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()); }
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; }