static void TestArgFormatter(JSContext* jscontext, JSObject* glob, nsIXPConnect* xpc) { JSBool ok = JS_TRUE; const char* a_in = "some string"; nsCOMPtr<nsITestXPCFoo> b_in = new nsTestXPCFoo(); nsCOMPtr<nsIWritableVariant> c_in = do_CreateInstance("@mozilla.org/variant;1"); static NS_NAMED_LITERAL_STRING(d_in, "foo bar"); const char* e_in = "another meaningless chunck of text"; JSBool a_match; nsCOMPtr<nsISupports> b_out; nsCOMPtr<nsIVariant> c_out; nsAutoString d_out; JSBool e_match; nsCOMPtr<nsITestXPCFoo> specified; PRInt32 val; printf("ArgumentFormatter test: "); if(!b_in || !c_in || NS_FAILED(c_in->SetAsInt32(5))) { printf(" failed to construct test objects -- FAILED!\n"); return; } do { JSAutoRequest ar(jscontext); // Prepare an array of arguments for JS_ConvertArguments jsval argv[5]; js::AutoArrayRooter tvr(jscontext, JS_ARRAY_LENGTH(argv), argv); if (!PushArguments(jscontext, 5, argv, "s %ip %iv %is s", a_in, &NS_GET_IID(nsITestXPCFoo2), b_in.get(), c_in.get(), static_cast<const nsAString*>(&d_in), e_in)) { printf(" could not convert from native to JS -- FAILED!\n"); return; } JSString *a_out, *e_out; ok = JS_ConvertArguments(jscontext, 5, argv, "S %ip %iv %is S", &a_out, static_cast<nsISupports**>(getter_AddRefs(b_out)), static_cast<nsIVariant**>(getter_AddRefs(c_out)), static_cast<nsAString*>(&d_out), &e_out); TAF_CHECK(ok, " could not convert from JS to native -- FAILED!\n"); TAF_CHECK(b_out, " JS to native for %%ip returned NULL -- FAILED!\n"); specified = do_QueryInterface(b_out); TAF_CHECK(specified, " could not QI value JS to native returned -- FAILED!\n"); ok = specified.get() == b_in.get(); TAF_CHECK(ok, " JS to native returned wrong value -- FAILED!\n"); TAF_CHECK(c_out, " JS to native for %%iv returned NULL -- FAILED!\n"); TAF_CHECK(NS_SUCCEEDED(c_out->GetAsInt32(&val)) && val == 5, " JS to native for %%iv holds wrong value -- FAILED!\n"); TAF_CHECK(d_in.Equals(d_out), " JS to native for %%is returned the wrong value -- FAILED!\n"); TAF_CHECK(JS_StringEqualsAscii(jscontext, a_out, a_in, &a_match), " oom -- FAILED!\n"); TAF_CHECK(JS_StringEqualsAscii(jscontext, e_out, e_in, &e_match), " oom -- FAILED!\n"); } while (0); if (!ok) return; if(a_match && e_match) printf("passed\n"); else printf(" conversion OK, but surrounding was mangled -- FAILED!\n"); }
js_star_str, /* starAtom */ js_starQualifier_str, /* starQualifierAtom */ js_tagc_str, /* tagcAtom */ js_xml_str, /* xmlAtom */ #endif #ifdef NARCISSUS js___call___str, /* __call__Atom */ js___construct___str, /* __construct__Atom */ js___hasInstance___str, /* __hasInstance__Atom */ js_ExecutionContext_str, /* ExecutionContextAtom */ js_current_str, /* currentAtom */ #endif }; JS_STATIC_ASSERT(JS_ARRAY_LENGTH(js_common_atom_names) * sizeof(JSAtom *) == LAZY_ATOM_OFFSET_START - ATOM_OFFSET_START); /* * Interpreter macros called by the trace recorder assume common atom indexes * fit in one byte of immediate operand. */ JS_STATIC_ASSERT(JS_ARRAY_LENGTH(js_common_atom_names) < 256); const size_t js_common_atom_count = JS_ARRAY_LENGTH(js_common_atom_names); const char js_anonymous_str[] = "anonymous"; const char js_apply_str[] = "apply"; const char js_arguments_str[] = "arguments"; const char js_arity_str[] = "arity"; const char js_call_str[] = "call";
JSBool js_ReportUncaughtException(JSContext *cx) { jsval exn; JSObject *exnObject; jsval roots[5]; JSTempValueRooter tvr; JSErrorReport *reportp, report; JSString *str; const char *bytes; JSBool ok; if (!JS_IsExceptionPending(cx)) return JS_TRUE; if (!JS_GetPendingException(cx, &exn)) return JS_FALSE; memset(roots, 0, sizeof roots); JS_PUSH_TEMP_ROOT(cx, JS_ARRAY_LENGTH(roots), roots, &tvr); /* * Because js_ValueToString below could error and an exception object * could become unrooted, we must root exnObject. Later, if exnObject is * non-null, we need to root other intermediates, so allocate an operand * stack segment to protect all of these values. */ if (JSVAL_IS_PRIMITIVE(exn)) { exnObject = NULL; } else { exnObject = JSVAL_TO_OBJECT(exn); roots[0] = exn; } JS_ClearPendingException(cx); reportp = js_ErrorFromException(cx, exn); /* XXX L10N angels cry once again (see also jsemit.c, /L10N gaffes/) */ str = js_ValueToString(cx, exn); if (!str) { bytes = "unknown (can't convert to string)"; } else { roots[1] = STRING_TO_JSVAL(str); bytes = js_GetStringBytes(cx, str); if (!bytes) { ok = JS_FALSE; goto out; } } ok = JS_TRUE; if (!reportp && exnObject && OBJ_GET_CLASS(cx, exnObject) == &js_ErrorClass) { const char *filename; uint32 lineno; ok = JS_GetProperty(cx, exnObject, js_message_str, &roots[2]); if (!ok) goto out; if (JSVAL_IS_STRING(roots[2])) { bytes = js_GetStringBytes(cx, JSVAL_TO_STRING(roots[2])); if (!bytes) { ok = JS_FALSE; goto out; } } ok = JS_GetProperty(cx, exnObject, js_fileName_str, &roots[3]); if (!ok) goto out; str = js_ValueToString(cx, roots[3]); if (!str) { ok = JS_FALSE; goto out; } filename = StringToFilename(cx, str); if (!filename) { ok = JS_FALSE; goto out; } ok = JS_GetProperty(cx, exnObject, js_lineNumber_str, &roots[4]); if (!ok) goto out; lineno = js_ValueToECMAUint32 (cx, &roots[4]); ok = !JSVAL_IS_NULL(roots[4]); if (!ok) goto out; reportp = &report; memset(&report, 0, sizeof report); report.filename = filename; report.lineno = (uintN) lineno; } if (!reportp) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_UNCAUGHT_EXCEPTION, bytes); } else { /* Flag the error as an exception. */ reportp->flags |= JSREPORT_EXCEPTION; /* Pass the exception object. */ JS_SetPendingException(cx, exn); js_ReportErrorAgain(cx, bytes, reportp); JS_ClearPendingException(cx); } out: JS_POP_TEMP_ROOT(cx, &tvr); return ok; }
JSBool js_ErrorToException(JSContext *cx, const char *message, JSErrorReport *reportp) { JSErrNum errorNumber; const JSErrorFormatString *errorString; JSExnType exn; jsval tv[4]; JSTempValueRooter tvr; JSBool ok; JSObject *errProto, *errObject; JSString *messageStr, *filenameStr; /* * Tell our caller to report immediately if cx has no active frames, or if * this report is just a warning. */ JS_ASSERT(reportp); if (!cx->fp || JSREPORT_IS_WARNING(reportp->flags)) return JS_FALSE; /* Find the exception index associated with this error. */ errorNumber = (JSErrNum) reportp->errorNumber; errorString = js_GetLocalizedErrorMessage(cx, NULL, NULL, errorNumber); exn = errorString ? (JSExnType) errorString->exnType : JSEXN_NONE; JS_ASSERT(exn < JSEXN_LIMIT); #if defined( DEBUG_mccabe ) && defined ( PRINTNAMES ) /* Print the error name and the associated exception name to stderr */ fprintf(stderr, "%s\t%s\n", errortoexnname[errorNumber].name, errortoexnname[errorNumber].exception); #endif /* * Return false (no exception raised) if no exception is associated * with the given error number. */ if (exn == JSEXN_NONE) return JS_FALSE; /* * Prevent runaway recursion, via cx->generatingError. If an out-of-memory * error occurs, no exception object will be created, but we don't assume * that OOM is the only kind of error that subroutines of this function * called below might raise. */ if (cx->generatingError) return JS_FALSE; /* After this point the control must flow through the label out. */ cx->generatingError = JS_TRUE; /* Protect the newly-created strings below from nesting GCs. */ memset(tv, 0, sizeof tv); JS_PUSH_TEMP_ROOT(cx, JS_ARRAY_LENGTH(tv), tv, &tvr); /* * Try to get an appropriate prototype by looking up the corresponding * exception constructor name in the scope chain of the current context's * top stack frame, or in the global object if no frame is active. */ ok = js_GetClassPrototype(cx, NULL, INT_TO_JSID(exceptions[exn].key), &errProto); if (!ok) goto out; tv[0] = OBJECT_TO_JSVAL(errProto); errObject = js_NewObject(cx, &js_ErrorClass, errProto, NULL, 0); if (!errObject) { ok = JS_FALSE; goto out; } tv[1] = OBJECT_TO_JSVAL(errObject); messageStr = JS_NewStringCopyZ(cx, message); if (!messageStr) { ok = JS_FALSE; goto out; } tv[2] = STRING_TO_JSVAL(messageStr); filenameStr = JS_NewStringCopyZ(cx, reportp->filename); if (!filenameStr) { ok = JS_FALSE; goto out; } tv[3] = STRING_TO_JSVAL(filenameStr); ok = InitExnPrivate(cx, errObject, messageStr, filenameStr, reportp->lineno, reportp); if (!ok) goto out; JS_SetPendingException(cx, OBJECT_TO_JSVAL(errObject)); /* Flag the error report passed in to indicate an exception was raised. */ reportp->flags |= JSREPORT_EXCEPTION; out: JS_POP_TEMP_ROOT(cx, &tvr); cx->generatingError = JS_FALSE; return ok; }
"readline() Read a single line from stdin", "print([exp ...]) Evaluate and print expressions", "help([name ...]) Display usage and help messages", "quit() Quit the shell", #ifdef MOZ_SHARK "startShark() Start a Shark session.\n" " Shark must be running with programatic sampling.", "stopShark() Stop a running Shark session.", "connectShark() Connect to Shark.\n" " The -k switch does this automatically.", "disconnectShark() Disconnect from Shark.", #endif }; /* Help messages must match shell functions. */ JS_STATIC_ASSERT(JS_ARRAY_LENGTH(shell_help_messages) + 1 == JS_ARRAY_LENGTH(shell_functions)); #ifdef DEBUG static void CheckHelpMessages(void) { const char *const *m; const char *lp; /* Each message must begin with "function_name(" prefix. */ for (m = shell_help_messages; m != JS_ARRAY_END(shell_help_messages); ++m) { lp = strchr(*m, '('); JS_ASSERT(lp); JS_ASSERT(memcmp(shell_functions[m - shell_help_messages].name, *m, lp - *m) == 0);
namespace gc { #if defined(JS_DUMP_CONSERVATIVE_GC_ROOTS) || defined(JS_GCMETER) void ConservativeGCStats::dump(FILE *fp) { size_t words = 0; for (size_t i = 0; i != JS_ARRAY_LENGTH(counter); ++i) words += counter[i]; #define ULSTAT(x) ((unsigned long)(x)) fprintf(fp, "CONSERVATIVE STACK SCANNING:\n"); fprintf(fp, " number of stack words: %lu\n", ULSTAT(words)); fprintf(fp, " excluded, low bit set: %lu\n", ULSTAT(counter[CGCT_LOWBITSET])); fprintf(fp, " not withing a chunk: %lu\n", ULSTAT(counter[CGCT_NOTCHUNK])); fprintf(fp, " not within arena range: %lu\n", ULSTAT(counter[CGCT_NOTARENA])); fprintf(fp, " points to free arena: %lu\n", ULSTAT(counter[CGCT_FREEARENA])); fprintf(fp, " excluded, wrong tag: %lu\n", ULSTAT(counter[CGCT_WRONGTAG])); fprintf(fp, " excluded, not live: %lu\n", ULSTAT(counter[CGCT_NOTLIVE])); fprintf(fp, " valid GC things: %lu\n", ULSTAT(counter[CGCT_VALID])); fprintf(fp, " valid but not aligned: %lu\n", ULSTAT(unaligned)); #undef ULSTAT } #endif #ifdef JS_GCMETER void UpdateCompartmentGCStats(JSCompartment *comp, unsigned thingKind) { JSGCArenaStats *compSt = &comp->arenas[thingKind].stats; JSGCArenaStats *globSt = &comp->rt->globalArenaStats[thingKind]; JS_ASSERT(compSt->narenas >= compSt->livearenas); compSt->newarenas = compSt->narenas - compSt->livearenas; if (compSt->maxarenas < compSt->narenas) compSt->maxarenas = compSt->narenas; compSt->totalarenas += compSt->narenas; if (compSt->maxthings < compSt->nthings) compSt->maxthings = compSt->nthings; compSt->totalthings += compSt->nthings; globSt->newarenas += compSt->newarenas; globSt->narenas += compSt->narenas; globSt->livearenas += compSt->livearenas; globSt->totalarenas += compSt->totalarenas; globSt->nthings += compSt->nthings; globSt->totalthings += compSt->totalthings; if (globSt->maxarenas < compSt->maxarenas) globSt->maxarenas = compSt->maxarenas; if (globSt->maxthings < compSt->maxthings) globSt->maxthings = compSt->maxthings; } void UpdateAllCompartmentGCStats(JSCompartment *comp) { /* * The stats for the list arenas scheduled for the background finalization * are updated after that finishes. */ JS_ASSERT(comp->rt->gcRunning); for (unsigned i = 0; i != JS_ARRAY_LENGTH(comp->arenas); ++i) { #ifdef JS_THREADSAFE if (comp->arenas[i].willBeFinalizedLater()) continue; #endif UpdateCompartmentGCStats(comp, i); } } static const char *const GC_ARENA_NAMES[] = { "object_0", "object_0_background", "object_2", "object_2_background", "object_4", "object_4_background", "object_8", "object_8_background", "object_12", "object_12_background", "object_16", "object_16_background", "function", "shape", #if JS_HAS_XML_SUPPORT "xml", #endif "short string", "string", "external_string", }; JS_STATIC_ASSERT(JS_ARRAY_LENGTH(GC_ARENA_NAMES) == FINALIZE_LIMIT); template <typename T> static inline void GetSizeAndThings(size_t &thingSize, size_t &thingsPerArena) { thingSize = sizeof(T); thingsPerArena = Arena<T>::ThingsPerArena; } void GetSizeAndThingsPerArena(int thingKind, size_t &thingSize, size_t &thingsPerArena) { switch (thingKind) { case FINALIZE_OBJECT0: case FINALIZE_OBJECT0_BACKGROUND: GetSizeAndThings<JSObject>(thingSize, thingsPerArena); break; case FINALIZE_OBJECT2: case FINALIZE_OBJECT2_BACKGROUND: GetSizeAndThings<JSObject_Slots2>(thingSize, thingsPerArena); break; case FINALIZE_OBJECT4: case FINALIZE_OBJECT4_BACKGROUND: GetSizeAndThings<JSObject_Slots4>(thingSize, thingsPerArena); break; case FINALIZE_OBJECT8: case FINALIZE_OBJECT8_BACKGROUND: GetSizeAndThings<JSObject_Slots8>(thingSize, thingsPerArena); break; case FINALIZE_OBJECT12: case FINALIZE_OBJECT12_BACKGROUND: GetSizeAndThings<JSObject_Slots12>(thingSize, thingsPerArena); break; case FINALIZE_OBJECT16: case FINALIZE_OBJECT16_BACKGROUND: GetSizeAndThings<JSObject_Slots16>(thingSize, thingsPerArena); break; case FINALIZE_EXTERNAL_STRING: case FINALIZE_STRING: GetSizeAndThings<JSString>(thingSize, thingsPerArena); break; case FINALIZE_SHORT_STRING: GetSizeAndThings<JSShortString>(thingSize, thingsPerArena); break; case FINALIZE_FUNCTION: GetSizeAndThings<JSFunction>(thingSize, thingsPerArena); break; #if JS_HAS_XML_SUPPORT case FINALIZE_XML: GetSizeAndThings<JSXML>(thingSize, thingsPerArena); break; #endif default: JS_NOT_REACHED("wrong kind"); } } void DumpArenaStats(JSGCArenaStats *stp, FILE *fp) { size_t sumArenas = 0, sumTotalArenas = 0, sumThings =0, sumMaxThings = 0; size_t sumThingSize = 0, sumTotalThingSize = 0, sumArenaCapacity = 0; size_t sumTotalArenaCapacity = 0, sumAlloc = 0, sumLocalAlloc = 0; for (int i = 0; i < (int) FINALIZE_LIMIT; i++) { JSGCArenaStats *st = &stp[i]; if (st->maxarenas == 0) continue; size_t thingSize = 0, thingsPerArena = 0; GetSizeAndThingsPerArena(i, thingSize, thingsPerArena); fprintf(fp, "%s arenas (thing size %lu, %lu things per arena):\n", GC_ARENA_NAMES[i], UL(thingSize), UL(thingsPerArena)); fprintf(fp, " arenas before GC: %lu\n", UL(st->narenas)); fprintf(fp, " arenas after GC: %lu (%.1f%%)\n", UL(st->livearenas), PERCENT(st->livearenas, st->narenas)); fprintf(fp, " max arenas: %lu\n", UL(st->maxarenas)); fprintf(fp, " things: %lu\n", UL(st->nthings)); fprintf(fp, " GC cell utilization: %.1f%%\n", PERCENT(st->nthings, thingsPerArena * st->narenas)); fprintf(fp, " average cell utilization: %.1f%%\n", PERCENT(st->totalthings, thingsPerArena * st->totalarenas)); fprintf(fp, " max things: %lu\n", UL(st->maxthings)); fprintf(fp, " alloc attempts: %lu\n", UL(st->alloc)); fprintf(fp, " alloc without locks: %lu (%.1f%%)\n", UL(st->localalloc), PERCENT(st->localalloc, st->alloc)); sumArenas += st->narenas; sumTotalArenas += st->totalarenas; sumThings += st->nthings; sumMaxThings += st->maxthings; sumThingSize += thingSize * st->nthings; sumTotalThingSize += size_t(thingSize * st->totalthings); sumArenaCapacity += thingSize * thingsPerArena * st->narenas; sumTotalArenaCapacity += thingSize * thingsPerArena * st->totalarenas; sumAlloc += st->alloc; sumLocalAlloc += st->localalloc; putc('\n', fp); } fputs("Never used arenas:\n", fp); for (int i = 0; i < (int) FINALIZE_LIMIT; i++) { JSGCArenaStats *st = &stp[i]; if (st->maxarenas != 0) continue; fprintf(fp, "%s\n", GC_ARENA_NAMES[i]); } fprintf(fp, "\nTOTAL STATS:\n"); fprintf(fp, " total GC arenas: %lu\n", UL(sumArenas)); fprintf(fp, " total GC things: %lu\n", UL(sumThings)); fprintf(fp, " max total GC things: %lu\n", UL(sumMaxThings)); fprintf(fp, " GC cell utilization: %.1f%%\n", PERCENT(sumThingSize, sumArenaCapacity)); fprintf(fp, " average cell utilization: %.1f%%\n", PERCENT(sumTotalThingSize, sumTotalArenaCapacity)); fprintf(fp, " alloc attempts: %lu\n", UL(sumAlloc)); fprintf(fp, " alloc without locks: %lu (%.1f%%)\n", UL(sumLocalAlloc), PERCENT(sumLocalAlloc, sumAlloc)); } void DumpCompartmentStats(JSCompartment *comp, FILE *fp) { if (comp->rt->atomsCompartment == comp) fprintf(fp, "\n**** AtomsCompartment Allocation Statistics: %p ****\n\n", (void *) comp); else fprintf(fp, "\n**** Compartment Allocation Statistics: %p ****\n\n", (void *) comp); for (unsigned i = 0; i != FINALIZE_LIMIT; ++i) DumpArenaStats(&comp->arenas[i].stats, fp); } #endif } //gc
JSObject * js_InitExceptionClasses(JSContext *cx, JSObject *obj) { jsval roots[3]; JSObject *obj_proto, *error_proto; jsval empty; /* * If lazy class initialization occurs for any Error subclass, then all * classes are initialized, starting with Error. To avoid reentry and * redundant initialization, we must not pass a null proto parameter to * js_NewObject below, when called for the Error superclass. We need to * ensure that Object.prototype is the proto of Error.prototype. * * See the equivalent code to ensure that parent_proto is non-null when * JS_InitClass calls js_NewObject, in jsapi.c. */ if (!js_GetClassPrototype(cx, obj, INT_TO_JSID(JSProto_Object), &obj_proto)) { return NULL; } memset(roots, 0, sizeof(roots)); JSAutoTempValueRooter tvr(cx, JS_ARRAY_LENGTH(roots), roots); #ifdef __GNUC__ error_proto = NULL; /* quell GCC overwarning */ #endif /* Initialize the prototypes first. */ for (intN i = JSEXN_ERR; i != JSEXN_LIMIT; i++) { JSObject *proto; JSProtoKey protoKey; JSAtom *atom; JSFunction *fun; /* Make the prototype for the current constructor name. */ proto = js_NewObject(cx, &js_ErrorClass, (i != JSEXN_ERR) ? error_proto : obj_proto, obj); if (!proto) return NULL; if (i == JSEXN_ERR) { error_proto = proto; roots[0] = OBJECT_TO_JSVAL(proto); } else { // We cannot share the root for error_proto and other prototypes // as error_proto must be rooted until the function returns. roots[1] = OBJECT_TO_JSVAL(proto); } /* So exn_finalize knows whether to destroy private data. */ proto->setPrivate(NULL); /* Make a constructor function for the current name. */ protoKey = GetExceptionProtoKey(i); atom = cx->runtime->atomState.classAtoms[protoKey]; fun = js_DefineFunction(cx, obj, atom, Exception, 3, 0); if (!fun) return NULL; roots[2] = OBJECT_TO_JSVAL(FUN_OBJECT(fun)); /* Make this constructor make objects of class Exception. */ FUN_CLASP(fun) = &js_ErrorClass; /* Make the prototype and constructor links. */ if (!js_SetClassPrototype(cx, FUN_OBJECT(fun), proto, JSPROP_READONLY | JSPROP_PERMANENT)) { return NULL; } /* Add the name property to the prototype. */ if (!JS_DefineProperty(cx, proto, js_name_str, ATOM_KEY(atom), NULL, NULL, JSPROP_ENUMERATE)) { return NULL; } /* Finally, stash the constructor for later uses. */ if (!js_SetClassObject(cx, obj, protoKey, FUN_OBJECT(fun))) return NULL; } /* * Set default values and add methods. We do it only for Error.prototype * as the rest of exceptions delegate to it. */ empty = STRING_TO_JSVAL(cx->runtime->emptyString); if (!JS_DefineProperty(cx, error_proto, js_message_str, empty, NULL, NULL, JSPROP_ENUMERATE) || !JS_DefineProperty(cx, error_proto, js_fileName_str, empty, NULL, NULL, JSPROP_ENUMERATE) || !JS_DefineProperty(cx, error_proto, js_lineNumber_str, JSVAL_ZERO, NULL, NULL, JSPROP_ENUMERATE) || !JS_DefineFunctions(cx, error_proto, exception_methods)) { return NULL; } return error_proto; }