JSBool js_XDRAtom(JSXDRState *xdr, JSAtom **atomp) { jsval v; uint32 type; if (xdr->mode == JSXDR_ENCODE) { v = ATOM_KEY(*atomp); return JS_XDRValue(xdr, &v); } /* * Inline JS_XDRValue when decoding to avoid ceation of GC things when * then corresponding atom already exists. See bug 321985. */ if (!JS_XDRUint32(xdr, &type)) return JS_FALSE; if (type == JSVAL_STRING) return js_XDRStringAtom(xdr, atomp); if (type == JSVAL_DOUBLE) { jsdouble d = 0; if (!XDRDoubleValue(xdr, &d)) return JS_FALSE; *atomp = js_AtomizeDouble(xdr->cx, d); return *atomp != NULL; } return XDRValueBody(xdr, type, &v) && js_AtomizePrimitiveValue(xdr->cx, v, atomp); }
static JSBool math_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { *rval = ATOM_KEY(cx->runtime->atomState.MathAtom); return JS_TRUE; }
js_DropAtom(JSContext *cx, JSAtom *atom) { #ifdef DEBUG_DUPLICATE_ATOMS jsval key; PRHashNumber keyHash; PRHashEntry *he, **hep; key = ATOM_KEY(atom); keyHash = js_hash_atom_key((void *)key); hep = PR_HashTableRawLookup(cx->runtime->atomState.table, keyHash, (void*)key); he = *hep; PR_ASSERT(atom == (JSAtom *)he); #endif PR_ASSERT(JS_IS_LOCKED(cx)); PR_ASSERT(atom->nrefs > 0); if (atom->nrefs <= 0) return NULL; if (--atom->nrefs == 0) { PR_HashTableRemove(cx->runtime->atomState.table, atom->entry.key); #ifdef DEBUG_DUPLICATE_ATOMS hep = PR_HashTableRawLookup(cx->runtime->atomState.table, keyHash, (void *)key); he = *hep; PR_ASSERT(he == NULL); #endif atom = NULL; } return atom; }
void js_TryValueOf(JSContext *cx, JSObject *obj, JSType type, jsval *rval) { #if JS_HAS_VALUEOF_HINT jsval argv[1]; argv[0] = ATOM_KEY(cx->runtime->atomState.typeAtoms[type]); js_TryMethod(cx, obj, cx->runtime->atomState.valueOfAtom, 1, argv, rval); #else js_TryMethod(cx, obj, cx->runtime->atomState.valueOfAtom, 0, NULL, rval); #endif }
JSBool JS_DLL_CALLBACK js_watch_set_wrapper(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { JSObject *funobj; JSFunction *wrapper; jsval userid; funobj = JSVAL_TO_OBJECT(argv[-2]); wrapper = (JSFunction *) JS_GetPrivate(cx, funobj); userid = ATOM_KEY(wrapper->atom); *rval = argv[0]; return js_watch_set(cx, obj, userid, rval); }
js_atom_marker(JSHashEntry *he, intN i, void *arg) { JSAtom *atom; MarkArgs *args; jsval key; atom = (JSAtom *)he; args = (MarkArgs *)arg; if ((atom->flags & (ATOM_PINNED | ATOM_INTERNED)) || (args->gcflags & GC_KEEP_ATOMS)) { atom->flags |= ATOM_MARK; key = ATOM_KEY(atom); if (JSVAL_IS_GCTHING(key)) args->mark(JSVAL_TO_GCTHING(key), args->data); } return HT_ENUMERATE_NEXT; }
JSAtom * js_HoldAtom(JSContext *cx, JSAtom *atom) { #ifdef DEBUG_DUPLICATE_ATOMS jsval key; PRHashNumber keyHash; PRHashEntry *he, **hep; key = ATOM_KEY(atom); keyHash = js_hash_atom_key((void *)key); hep = PR_HashTableRawLookup(cx->runtime->atomState.table, keyHash, (void*)key); he = *hep; PR_ASSERT(atom == (JSAtom *)he); #endif PR_ASSERT(JS_IS_LOCKED(cx)); atom->nrefs++; PR_ASSERT(atom->nrefs > 0); return atom; }
js_atom_key_marker(PRHashEntry *he, intN i, void *arg) { JSAtom *atom; jsval key; MarkAtomArgs *args; atom = (JSAtom *)he; if (atom->nrefs == 0) { /* * Unreferenced atom, probably from the scanner atomizing a name, * number, or string that the parser did not save in an atom map * (because it was a syntax error, e.g.). */ return HT_ENUMERATE_REMOVE; } key = ATOM_KEY(atom); if (JSVAL_IS_GCTHING(key)) { args = arg; args->mark(args->runtime, JSVAL_TO_GCTHING(key)); } return HT_ENUMERATE_NEXT; }
JSBool js_XDRAtom(JSXDRState *xdr, JSAtom **atomp) { jsval v; uint32 type; jsdouble d; JSAtom *atom; if (xdr->mode == JSXDR_ENCODE) { v = ATOM_KEY(*atomp); return JS_XDRValue(xdr, &v); } /* * Inline JS_XDRValue when decoding to avoid ceation of GC things when * then corresponding atom already exists. See bug 321985. */ if (!JS_XDRUint32(xdr, &type)) return JS_FALSE; if (type == JSVAL_STRING) return js_XDRStringAtom(xdr, atomp); if (type == JSVAL_DOUBLE) { if (!XDRDoubleValue(xdr, &d)) return JS_FALSE; atom = js_AtomizeDouble(xdr->cx, d, 0); } else { if (!XDRValueBody(xdr, type, &v)) return JS_FALSE; atom = js_AtomizeValue(xdr->cx, v, 0); } if (!atom) return JS_FALSE; *atomp = atom; return JS_TRUE; }
jsval get_opcode_arg(JSContext *cx, JSScript *script, jsbytecode *pc) { JSOp op; const JSCodeSpec *cs; ptrdiff_t len; uint32 type; JSAtom *atom; jsval v; op = (JSOp)*pc; if (op >= JSOP_LIMIT) { char numBuf1[12], numBuf2[12]; JS_snprintf(numBuf1, sizeof numBuf1, "%d", op); JS_snprintf(numBuf2, sizeof numBuf2, "%d", JSOP_LIMIT); fprintf(stderr,"ERROR in get_opcode_arg: unknown bytecode %s %s\n",numBuf1,numBuf2); return 0; } cs = &js_CodeSpec[op]; len = (ptrdiff_t) cs->length; type = cs->format & JOF_TYPEMASK; switch (type) { case JOF_CONST: atom = GET_ATOM(cx, script, pc); v = ATOM_KEY(atom); return v; break; default: { char numBuf[12]; JS_snprintf(numBuf, sizeof numBuf, "%lx", (unsigned long) cs->format); fprintf(stderr,"ERROR in get_opcode_arg: Unknown format %s\n",numBuf); return 0; } } }
const char * js_AtomToPrintableString(JSContext *cx, JSAtom *atom) { return js_ValueToPrintableString(cx, ATOM_KEY(atom)); }
static JSBool math_toSource(JSContext *cx, uintN argc, jsval *vp) { *vp = ATOM_KEY(CLASS_ATOM(cx, Math)); return JS_TRUE; }
static JSBool InitExceptionObject(JSContext *cx, JSObject *obj, JSString *message, JSString *filename, uintN lineno) { JSCheckAccessOp checkAccess; JSErrorReporter older; JSExceptionState *state; jschar *stackbuf; size_t stacklen, stackmax; JSStackFrame *fp; jsval callerid, v; JSBool ok; JSString *argsrc, *stack; uintN i, ulineno; const char *cp; char ulnbuf[11]; if (!JS_DefineProperty(cx, obj, js_message_str, STRING_TO_JSVAL(message), NULL, NULL, JSPROP_ENUMERATE)) { return JS_FALSE; } if (!JS_DefineProperty(cx, obj, js_filename_str, STRING_TO_JSVAL(filename), NULL, NULL, JSPROP_ENUMERATE)) { return JS_FALSE; } if (!JS_DefineProperty(cx, obj, js_lineno_str, INT_TO_JSVAL(lineno), NULL, NULL, JSPROP_ENUMERATE)) { return JS_FALSE; } /* * Set the 'stack' property. * * First, set aside any error reporter for cx and save its exception state * so we can suppress any checkAccess failures. Such failures should stop * the backtrace procedure, not result in a failure of this constructor. */ checkAccess = cx->runtime->checkObjectAccess; if (checkAccess) { older = JS_SetErrorReporter(cx, NULL); state = JS_SaveExceptionState(cx); } #ifdef __GNUC__ /* suppress bogus gcc warnings */ else { older = NULL; state = NULL; } #endif callerid = ATOM_KEY(cx->runtime->atomState.callerAtom); /* * Prepare to allocate a jschar buffer at stackbuf, where stacklen indexes * the next free jschar slot, and with room for at most stackmax non-null * jschars. If stackbuf is non-null, it always contains an extra slot for * the null terminator we'll store at the end, as a backstop. * * All early returns must goto done after this point, till the after-loop * cleanup code has run! */ stackbuf = NULL; stacklen = stackmax = 0; ok = JS_TRUE; #define APPEND_CHAR_TO_STACK(c) \ JS_BEGIN_MACRO \ if (stacklen == stackmax) { \ void *ptr_; \ stackmax = stackmax ? 2 * stackmax : 64; \ ptr_ = JS_realloc(cx, stackbuf, (stackmax+1) * sizeof(jschar)); \ if (!ptr_) { \ ok = JS_FALSE; \ goto done; \ } \ stackbuf = ptr_; \ } \ stackbuf[stacklen++] = (c); \ JS_END_MACRO #define APPEND_STRING_TO_STACK(str) \ JS_BEGIN_MACRO \ JSString *str_ = str; \ size_t length_ = JSSTRING_LENGTH(str_); \ if (stacklen + length_ > stackmax) { \ void *ptr_; \ stackmax = JS_BIT(JS_CeilingLog2(stacklen + length_)); \ ptr_ = JS_realloc(cx, stackbuf, (stackmax+1) * sizeof(jschar)); \ if (!ptr_) { \ ok = JS_FALSE; \ goto done; \ } \ stackbuf = ptr_; \ } \ js_strncpy(stackbuf + stacklen, JSSTRING_CHARS(str_), length_); \ stacklen += length_; \ JS_END_MACRO for (fp = cx->fp; fp; fp = fp->down) { if (checkAccess) { v = (fp->fun && fp->argv) ? fp->argv[-2] : JSVAL_NULL; if (!JSVAL_IS_PRIMITIVE(v)) { ok = checkAccess(cx, fp->fun->object, callerid, JSACC_READ, &v); if (!ok) { ok = JS_TRUE; break; } } } if (fp->fun) { if (fp->fun->atom) APPEND_STRING_TO_STACK(ATOM_TO_STRING(fp->fun->atom)); APPEND_CHAR_TO_STACK('('); for (i = 0; i < fp->argc; i++) { argsrc = js_ValueToSource(cx, fp->argv[i]); if (!argsrc) { ok = JS_FALSE; goto done; } if (i > 0) APPEND_CHAR_TO_STACK(','); APPEND_STRING_TO_STACK(argsrc); } APPEND_CHAR_TO_STACK(')'); } APPEND_CHAR_TO_STACK('@'); if (fp->script && fp->script->filename) { for (cp = fp->script->filename; *cp; cp++) APPEND_CHAR_TO_STACK(*cp); } APPEND_CHAR_TO_STACK(':'); if (fp->script && fp->pc) { ulineno = js_PCToLineNumber(fp->script, fp->pc); JS_snprintf(ulnbuf, sizeof ulnbuf, "%u", ulineno); for (cp = ulnbuf; *cp; cp++) APPEND_CHAR_TO_STACK(*cp); } else { APPEND_CHAR_TO_STACK('0'); } APPEND_CHAR_TO_STACK('\n'); } #undef APPEND_CHAR_TO_STACK #undef APPEND_STRING_TO_STACK done: if (checkAccess) { if (ok) JS_RestoreExceptionState(cx, state); else JS_DropExceptionState(cx, state); JS_SetErrorReporter(cx, older); } if (!ok) { JS_free(cx, stackbuf); return JS_FALSE; } if (!stackbuf) { stack = cx->runtime->emptyString; } else { /* NB: if stackbuf was allocated, it has room for the terminator. */ JS_ASSERT(stacklen <= stackmax); if (stacklen < stackmax) { /* * Realloc can fail when shrinking on some FreeBSD versions, so * don't use JS_realloc here; simply let the oversized allocation * be owned by the string in that rare case. */ void *shrunk = realloc(stackbuf, (stacklen+1) * sizeof(jschar)); if (shrunk) stackbuf = shrunk; } stackbuf[stacklen] = 0; stack = js_NewString(cx, stackbuf, stacklen, 0); if (!stack) { JS_free(cx, stackbuf); return JS_FALSE; } } return JS_DefineProperty(cx, obj, js_stack_str, STRING_TO_JSVAL(stack), NULL, NULL, JSPROP_ENUMERATE); }
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; }
// convert a readable to a JSString, copying string data // static jsval XPCStringConvert::ReadableToJSVal(JSContext *cx, const nsAString &readable) { JSString *str; PRUint32 length = readable.Length(); JSAtom *atom; if (length == 0 && (atom = cx->runtime->atomState.emptyAtom)) { NS_ASSERTION(ATOM_IS_STRING(atom), "What kind of atom is this?"); return ATOM_KEY(atom); } nsStringBuffer *buf = nsStringBuffer::FromString(readable); if (buf) { // yay, we can share the string's buffer! if (sDOMStringFinalizerIndex == -1) { sDOMStringFinalizerIndex = JS_AddExternalStringFinalizer(DOMStringFinalizer); if (sDOMStringFinalizerIndex == -1) return JSVAL_NULL; } str = JS_NewExternalString(cx, reinterpret_cast<jschar *>(buf->Data()), length, sDOMStringFinalizerIndex); if (str) buf->AddRef(); } else { // blech, have to copy. jschar *chars = reinterpret_cast<jschar *> (JS_malloc(cx, (length + 1) * sizeof(jschar))); if (!chars) return JSVAL_NULL; if (length && !CopyUnicodeTo(readable, 0, reinterpret_cast<PRUnichar *>(chars), length)) { JS_free(cx, chars); return JSVAL_NULL; } chars[length] = 0; str = JS_NewUCString(cx, chars, length); if (!str) JS_free(cx, chars); } return STRING_TO_JSVAL(str); }
static JSBool InitExnPrivate(JSContext *cx, JSObject *exnObject, JSString *message, JSString *filename, uintN lineno, JSErrorReport *report) { JSCheckAccessOp checkAccess; JSErrorReporter older; JSExceptionState *state; jsval callerid, v; JSStackFrame *fp, *fpstop; size_t stackDepth, valueCount, size; JSBool overflow; JSExnPrivate *priv; JSStackTraceElem *elem; jsval *values; JS_ASSERT(OBJ_GET_CLASS(cx, exnObject) == &js_ErrorClass); /* * Prepare stack trace data. * * Set aside any error reporter for cx and save its exception state * so we can suppress any checkAccess failures. Such failures should stop * the backtrace procedure, not result in a failure of this constructor. */ checkAccess = cx->runtime->checkObjectAccess; older = JS_SetErrorReporter(cx, NULL); state = JS_SaveExceptionState(cx); callerid = ATOM_KEY(cx->runtime->atomState.callerAtom); stackDepth = 0; valueCount = 0; for (fp = cx->fp; fp; fp = fp->down) { if (fp->fun && fp->argv) { v = JSVAL_NULL; if (checkAccess && !checkAccess(cx, fp->callee, callerid, JSACC_READ, &v)) { break; } valueCount += fp->argc; } ++stackDepth; } JS_RestoreExceptionState(cx, state); JS_SetErrorReporter(cx, older); fpstop = fp; size = offsetof(JSExnPrivate, stackElems); overflow = (stackDepth > ((size_t)-1 - size) / sizeof(JSStackTraceElem)); size += stackDepth * sizeof(JSStackTraceElem); overflow |= (valueCount > ((size_t)-1 - size) / sizeof(jsval)); size += valueCount * sizeof(jsval); if (overflow) { js_ReportAllocationOverflow(cx); return JS_FALSE; } priv = (JSExnPrivate *)JS_malloc(cx, size); if (!priv) return JS_FALSE; /* * We initialize errorReport with a copy of report after setting the * private slot, to prevent GC accessing a junk value we clear the field * here. */ priv->errorReport = NULL; priv->message = message; priv->filename = filename; priv->lineno = lineno; priv->stackDepth = stackDepth; values = GetStackTraceValueBuffer(priv); elem = priv->stackElems; for (fp = cx->fp; fp != fpstop; fp = fp->down) { if (!fp->fun) { elem->funName = NULL; elem->argc = 0; } else { elem->funName = fp->fun->atom ? ATOM_TO_STRING(fp->fun->atom) : cx->runtime->emptyString; elem->argc = fp->argc; memcpy(values, fp->argv, fp->argc * sizeof(jsval)); values += fp->argc; } elem->ulineno = 0; elem->filename = NULL; if (fp->script) { elem->filename = fp->script->filename; if (fp->regs) elem->ulineno = js_PCToLineNumber(cx, fp->script, fp->regs->pc); } ++elem; } JS_ASSERT(priv->stackElems + stackDepth == elem); JS_ASSERT(GetStackTraceValueBuffer(priv) + valueCount == values); STOBJ_SET_SLOT(exnObject, JSSLOT_PRIVATE, PRIVATE_TO_JSVAL(priv)); if (report) { /* * Construct a new copy of the error report struct. We can't use the * error report struct that was passed in, because it's allocated on * the stack, and also because it may point to transient data in the * JSTokenStream. */ priv->errorReport = CopyErrorReport(cx, report); if (!priv->errorReport) { /* The finalizer realeases priv since it is in the private slot. */ return JS_FALSE; } } return JS_TRUE; }
static JSBool json_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *vp, jsval* rval) { *rval = ATOM_KEY(CLASS_ATOM(cx, JSON)); return JS_TRUE; }
static JSBool json_toSource(JSContext *cx, uintN argc, jsval *vp) { *vp = ATOM_KEY(CLASS_ATOM(cx, JSON)); return JS_TRUE; }