js_Atomize(JSContext *cx, const char *bytes, size_t length, uintN flags) { jschar *chars; JSString *str; JSAtom *atom; #if PR_ALIGN_OF_DOUBLE == 8 union { jsdouble d; JSString s; } u; str = &u.s; #else char alignbuf[16]; str = (JSString *)&alignbuf[8 - ((pruword)&alignbuf & 7)]; #endif chars = js_InflateString(cx, bytes, length); if (!chars) return NULL; str->chars = chars; str->length = length; atom = js_AtomizeString(cx, str, ATOM_TMPSTR | ATOM_NOCOPY | flags); if (!atom || ATOM_TO_STRING(atom)->chars != chars) JS_free(cx, chars); return atom; }
/* * The arguments from ap need to be packaged up into an array and stored * into the report struct. * * The format string addressed by the error number may contain operands * identified by the format {N}, where N is a decimal digit. Each of these * is to be replaced by the Nth argument from the va_list. The complete * message is placed into reportp->ucmessage converted to a JSString. * * Returns true if the expansion succeeds (can fail if out of memory). */ JSBool js_ExpandErrorArguments(JSContext *cx, JSErrorCallback callback, void *userRef, const uintN errorNumber, char **messagep, JSErrorReport *reportp, JSBool *warningp, JSBool charArgs, va_list ap) { const JSErrorFormatString *efs; int i; int argCount; *warningp = JSREPORT_IS_WARNING(reportp->flags); if (*warningp && JS_HAS_WERROR_OPTION(cx)) { reportp->flags &= ~JSREPORT_WARNING; *warningp = JS_FALSE; } *messagep = NULL; /* Most calls supply js_GetErrorMessage; if this is so, assume NULL. */ if (!callback || callback == js_GetErrorMessage) efs = js_GetLocalizedErrorMessage(cx, userRef, NULL, errorNumber); else efs = callback(userRef, NULL, errorNumber); if (efs) { size_t totalArgsLength = 0; size_t argLengths[10]; /* only {0} thru {9} supported */ argCount = efs->argCount; JS_ASSERT(argCount <= 10); if (argCount > 0) { /* * Gather the arguments into an array, and accumulate * their sizes. We allocate 1 more than necessary and * null it out to act as the caboose when we free the * pointers later. */ reportp->messageArgs = (const jschar **) JS_malloc(cx, sizeof(jschar *) * (argCount + 1)); if (!reportp->messageArgs) return JS_FALSE; reportp->messageArgs[argCount] = NULL; for (i = 0; i < argCount; i++) { if (charArgs) { char *charArg = va_arg(ap, char *); size_t charArgLength = strlen(charArg); reportp->messageArgs[i] = js_InflateString(cx, charArg, &charArgLength); if (!reportp->messageArgs[i]) goto error; } else { reportp->messageArgs[i] = va_arg(ap, jschar *); } argLengths[i] = js_strlen(reportp->messageArgs[i]); totalArgsLength += argLengths[i]; } /* NULL-terminate for easy copying. */ reportp->messageArgs[i] = NULL; }
PRHashEntry * js_EnterSharpObject(JSContext *cx, JSObject *obj, jschar **sp) { JSSharpObjectMap *map; PRHashTable *table; PRHashNumber hash; PRHashEntry *he; jsatomid sharpid; char buf[20]; size_t len; map = &cx->sharpObjectMap; table = map->table; if (!table) { table = PR_NewHashTable(8, js_hash_object, PR_CompareValues, PR_CompareValues, NULL, NULL); if (!table) { JS_ReportOutOfMemory(cx); return NULL; } map->table = table; } if (map->depth == 0) { he = MarkSharpObjects(cx, obj); if (!he) return NULL; } else { hash = js_hash_object(obj); he = *PR_HashTableRawLookup(table, hash, obj); PR_ASSERT(he); } sharpid = (jsatomid) he->value; if (sharpid == 0) { *sp = NULL; } else { len = PR_snprintf(buf, sizeof buf, "#%u%c", sharpid >> 1, (sharpid & SHARP_BIT) ? '#' : '='); *sp = js_InflateString(cx, buf, len); if (!*sp) return NULL; } if ((sharpid & SHARP_BIT) == 0) map->depth++; return he; }
JS_EvaluateInStackFrame(JSContext *cx, JSStackFrame *fp, const char *bytes, uintN length, const char *filename, uintN lineno, jsval *rval) { jschar *chars; JSBool ok; chars = js_InflateString(cx, bytes, length); if (!chars) return JS_FALSE; ok = JS_EvaluateUCInStackFrame(cx, fp, chars, length, filename, lineno, rval); JS_free(cx, chars); return ok; }
JSBool js_ReportErrorVA(JSContext *cx, uintN flags, const char *format, va_list ap) { char *message; jschar *ucmessage; size_t messagelen; JSStackFrame *fp; JSErrorReport report; JSBool warning; if ((flags & JSREPORT_STRICT) && !JS_HAS_STRICT_OPTION(cx)) return JS_TRUE; message = JS_vsmprintf(format, ap); if (!message) return JS_FALSE; messagelen = strlen(message); memset(&report, 0, sizeof (struct JSErrorReport)); report.flags = flags; report.errorNumber = JSMSG_USER_DEFINED_ERROR; report.ucmessage = ucmessage = js_InflateString(cx, message, &messagelen); /* Find the top-most active script frame, for best line number blame. */ for (fp = cx->fp; fp; fp = fp->down) { if (fp->regs) { report.filename = fp->script->filename; report.lineno = js_PCToLineNumber(cx, fp->script, fp->regs->pc); break; } } warning = JSREPORT_IS_WARNING(report.flags); if (warning && JS_HAS_WERROR_OPTION(cx)) { report.flags &= ~JSREPORT_WARNING; warning = JS_FALSE; } ReportError(cx, message, &report); free(message); JS_free(cx, ucmessage); return warning; }
js_Atomize(JSContext *cx, const char *bytes, size_t length, uintN flags) { jschar *chars; JSString *str; JSAtom *atom; char buf[2 * ALIGNMENT(JSString)]; /* * Avoiding the malloc in js_InflateString on shorter strings saves us * over 20,000 malloc calls on mozilla browser startup. This compares to * only 131 calls where the string is longer than a 31 char (net) buffer. * The vast majority of atomized strings are already in the hashtable. So * js_AtomizeString rarely has to copy the temp string we make. */ #define ATOMIZE_BUF_MAX 32 jschar inflated[ATOMIZE_BUF_MAX]; size_t inflatedLength = ATOMIZE_BUF_MAX - 1; if (length < ATOMIZE_BUF_MAX) { js_InflateStringToBuffer(cx, bytes, length, inflated, &inflatedLength); inflated[inflatedLength] = 0; chars = inflated; } else { inflatedLength = length; chars = js_InflateString(cx, bytes, &inflatedLength); if (!chars) return NULL; flags |= ATOM_NOCOPY; } str = ALIGN(buf, JSString); str->chars = chars; str->length = inflatedLength; atom = js_AtomizeString(cx, str, ATOM_TMPSTR | flags); if (chars != inflated && (!atom || ATOM_TO_STRING(atom)->chars != chars)) JS_free(cx, chars); return atom; }
/* * The arguments from ap need to be packaged up into an array and stored * into the report struct. * * The format string addressed by the error number may contain operands * identified by the format {N}, where N is a decimal digit. Each of these * is to be replaced by the Nth argument from the va_list. The complete * message is placed into reportp->ucmessage converted to a JSString. * * Returns true if the expansion succeeds (can fail if out of memory). */ JSBool js_ExpandErrorArguments(JSContext *cx, JSErrorCallback callback, void *userRef, const uintN errorNumber, char **messagep, JSErrorReport *reportp, JSBool *warningp, JSBool charArgs, va_list ap) { const JSErrorFormatString *efs; int i; int argCount; *warningp = JSREPORT_IS_WARNING(reportp->flags); if (*warningp && JS_HAS_WERROR_OPTION(cx)) { reportp->flags &= ~JSREPORT_WARNING; *warningp = JS_FALSE; } *messagep = NULL; if (callback) { efs = callback(userRef, NULL, errorNumber); if (efs) { size_t totalArgsLength = 0; size_t argLengths[10]; /* only {0} thru {9} supported */ argCount = efs->argCount; JS_ASSERT(argCount <= 10); if (argCount > 0) { /* * Gather the arguments into an array, and accumulate * their sizes. We allocate 1 more than necessary and * null it out to act as the caboose when we free the * pointers later. */ reportp->messageArgs = (const jschar **) JS_malloc(cx, sizeof(jschar *) * (argCount + 1)); if (!reportp->messageArgs) return JS_FALSE; reportp->messageArgs[argCount] = NULL; for (i = 0; i < argCount; i++) { if (charArgs) { char *charArg = va_arg(ap, char *); reportp->messageArgs[i] = js_InflateString(cx, charArg, strlen(charArg)); if (!reportp->messageArgs[i]) goto error; } else reportp->messageArgs[i] = va_arg(ap, jschar *); argLengths[i] = js_strlen(reportp->messageArgs[i]); totalArgsLength += argLengths[i]; } /* NULL-terminate for easy copying. */ reportp->messageArgs[i] = NULL; } /* * Parse the error format, substituting the argument X * for {X} in the format. */ if (argCount > 0) { if (efs->format) { const char *fmt; const jschar *arg; jschar *out; int expandedArgs = 0; size_t expandedLength = strlen(efs->format) - (3 * argCount) /* exclude the {n} */ + totalArgsLength; /* * Note - the above calculation assumes that each argument * is used once and only once in the expansion !!! */ reportp->ucmessage = out = (jschar *) JS_malloc(cx, (expandedLength + 1) * sizeof(jschar)); if (!out) goto error; fmt = efs->format; while (*fmt) { if (*fmt == '{') { if (isdigit(fmt[1])) { int d = JS7_UNDEC(fmt[1]); JS_ASSERT(expandedArgs < argCount); arg = reportp->messageArgs[d]; js_strncpy(out, arg, argLengths[d]); out += argLengths[d]; fmt += 3; expandedArgs++; continue; } } /* * is this kosher? */ *out++ = (unsigned char)(*fmt++); } JS_ASSERT(expandedArgs == argCount); *out = 0; *messagep = js_DeflateString(cx, reportp->ucmessage, (size_t)(out - reportp->ucmessage)); if (!*messagep) goto error; } } else { /* * Zero arguments: the format string (if it exists) is the * entire message. */ if (efs->format) { *messagep = JS_strdup(cx, efs->format); if (!*messagep) goto error; reportp->ucmessage = js_InflateString(cx, *messagep, strlen(*messagep)); if (!reportp->ucmessage) goto error; } } }
template<size_t N> void operator=(const char (&str)[N]) { length_ = N - 1; chars_ = js_InflateString(cx, str, &length_); if (!chars_) abort(); }