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