diff --git a/js/src/jsobj.c b/js/src/jsobj.c index 7de2b9a8e6e..415d4461cda 100644 --- a/js/src/jsobj.c +++ b/js/src/jsobj.c @@ -79,6 +79,10 @@ #include "jsxml.h" #endif +#if JS_HAS_XDR +#include "jsxdrapi.h" +#endif + #ifdef JS_THREADSAFE #define NATIVE_DROP_PROPERTY js_DropProperty @@ -1973,14 +1977,159 @@ block_setProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) return JS_TRUE; } +#if JS_HAS_XDR + +#define NO_PARENT_INDEX (jsatomid)-1 + +jsatomid +FindObjectAtomIndex(JSAtomMap *map, JSObject *obj) +{ + size_t i; + JSAtom *atom; + + for (i = 0; i < map->length; i++) { + atom = map->vector[i]; + if (ATOM_KEY(atom) == OBJECT_TO_JSVAL(obj)) + return i; + } + + return NO_PARENT_INDEX; +} + +static JSBool +block_xdrObject(JSXDRState *xdr, JSObject **objp) +{ + JSContext *cx; + jsatomid parentId; + JSAtomMap *atomMap; + JSObject *parent; + uint16 depth, count, i; + uint32 tmp; + JSTempValueRooter tvr; + JSScopeProperty *sprop; + jsid propid; + JSAtom *atom; + int16 shortid; + JSBool ok; + + cx = xdr->cx; + + atomMap = &xdr->script->atomMap; + if (xdr->mode == JSXDR_ENCODE) { + parent = OBJ_GET_PARENT(cx, *objp); + parentId = FindObjectAtomIndex(atomMap, parent); + depth = OBJ_BLOCK_DEPTH(cx, *objp); + count = OBJ_BLOCK_COUNT(cx, *objp); + tmp = (uint32)(depth << 16) | count; + } + + /* First, XDR the parent atomid. */ + if (!JS_XDRUint32(xdr, &parentId)) + return JS_FALSE; + + if (xdr->mode == JSXDR_DECODE) { + *objp = js_NewBlockObject(cx); + if (!*objp) + return JS_FALSE; + + /* + * If there's a parent id, then get the parent out of our script's + * atomMap. We know that we XDR block object in outer-to-inner order, + * which means that getting the parent now will work. + */ + if (parentId != NO_PARENT_INDEX) { + atom = js_GetAtom(cx, atomMap, parentId); + JS_ASSERT(ATOM_IS_OBJECT(atom)); + parent = ATOM_TO_OBJECT(atom); + OBJ_SET_PARENT(cx, *objp, parent); + } + } + + JS_PUSH_SINGLE_TEMP_ROOT(cx, OBJECT_TO_JSVAL(*objp), &tvr); + + if (!JS_XDRUint32(xdr, &tmp)) { + JS_POP_TEMP_ROOT(cx, &tvr); + return JS_FALSE; + } + + if (xdr->mode == JSXDR_DECODE) { + depth = (uint16)(tmp >> 16); + count = (uint16)tmp; + OBJ_SET_BLOCK_DEPTH(cx, *objp, depth); + } + + /* + * XDR the block object's properties. We know that there are 'count' + * properties to XDR, stored as id/shortid pairs. We do not XDR any + * non-native properties, only those that the compiler created. + */ + sprop = NULL; + ok = JS_TRUE; + for (i = 0; i < count; i++) { + if (xdr->mode == JSXDR_ENCODE) { + /* Find a property to XDR. */ + do { + /* If sprop is NULL, this is the first property. */ + sprop = sprop ? sprop->parent : OBJ_SCOPE(*objp)->lastProp; + } while (!(sprop->flags & SPROP_HAS_SHORTID)); + + JS_ASSERT(sprop->getter == js_BlockClass.getProperty); + propid = sprop->id; + JS_ASSERT(JSID_IS_ATOM(propid)); + atom = JSID_TO_ATOM(propid); + shortid = sprop->shortid; + JS_ASSERT(shortid >= 0); + } + + /* XDR the real id, then the shortid. */ + if (!js_XDRStringAtom(xdr, &atom) || + !JS_XDRUint16(xdr, (uint16 *)&shortid)) { + ok = JS_FALSE; + break; + } + + if (xdr->mode == JSXDR_DECODE) { + if (!js_DefineNativeProperty(cx, *objp, ATOM_TO_JSID(atom), + JSVAL_VOID, NULL, NULL, + JSPROP_ENUMERATE | JSPROP_PERMANENT, + SPROP_HAS_SHORTID, shortid, NULL)) { + ok = JS_FALSE; + break; + } + } + } + + JS_POP_TEMP_ROOT(cx, &tvr); + return ok; +} + +#else +# define block_xdrObject NULL +#endif + JSClass js_BlockClass = { "Block", - JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_IS_ANONYMOUS, + JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(1) | + JSCLASS_IS_ANONYMOUS | JSCLASS_HAS_CACHED_PROTO(JSProto_Block), JS_PropertyStub, JS_PropertyStub, block_getProperty, block_setProperty, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub, - JSCLASS_NO_OPTIONAL_MEMBERS + NULL, NULL, NULL, NULL, block_xdrObject, NULL, NULL, NULL }; +JSObject* +js_InitBlockClass(JSContext *cx, JSObject* obj) +{ + JSObject *proto; + + proto = JS_InitClass(cx, obj, NULL, &js_BlockClass, NULL, 0, NULL, + NULL, NULL, NULL); + if (!proto) + return NULL; + + OBJ_SET_PROTO(cx, proto, NULL); + return proto; +} + JSObject * js_InitObjectClass(JSContext *cx, JSObject *obj) { @@ -4383,8 +4532,6 @@ js_TryMethod(JSContext *cx, JSObject *obj, JSAtom *atom, #if JS_HAS_XDR -#include "jsxdrapi.h" - JSBool js_XDRObject(JSXDRState *xdr, JSObject **objp) { diff --git a/js/src/jsobj.h b/js/src/jsobj.h index 2b6e10e7c32..69dcbb430f5 100644 --- a/js/src/jsobj.h +++ b/js/src/jsobj.h @@ -331,6 +331,9 @@ extern JSBool js_HasOwnPropertyHelper(JSContext *cx, JSObject *obj, JSLookupPropOp lookup, uintN argc, jsval *argv, jsval *rval); +extern JSObject* +js_InitBlockClass(JSContext *cx, JSObject* obj); + extern JSObject * js_InitObjectClass(JSContext *cx, JSObject *obj); diff --git a/js/src/jsopcode.c b/js/src/jsopcode.c index 2af6cd9c9b8..8978b5dd0ec 100644 --- a/js/src/jsopcode.c +++ b/js/src/jsopcode.c @@ -1443,9 +1443,12 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb) return JS_FALSE; } - for (i = argc, sprop = OBJ_SCOPE(obj)->lastProp; --i >= 0; + for (sprop = OBJ_SCOPE(obj)->lastProp; sprop; sprop = sprop->parent) { - atomv[i] = JSID_TO_ATOM(sprop->id); + if (!(sprop->flags & SPROP_HAS_SHORTID)) + continue; + JS_ASSERT(sprop->shortid < argc); + atomv[sprop->shortid] = JSID_TO_ATOM(sprop->id); } ok = JS_TRUE; for (i = 0; i < argc; i++) { diff --git a/js/src/jsproto.tbl b/js/src/jsproto.tbl index 81dc116ff42..8d7887f10ac 100644 --- a/js/src/jsproto.tbl +++ b/js/src/jsproto.tbl @@ -38,6 +38,38 @@ #include "jsconfig.h" +#if JS_HAS_SCRIPT_OBJECT +# define SCRIPT_INIT js_InitScriptClass +#else +# define SCRIPT_INIT js_InitNullClass +#endif + +#if JS_HAS_XML_SUPPORT +# define XML_INIT js_InitXMLClass +# define NAMESPACE_INIT js_InitNamespaceClass +# define QNAME_INIT js_InitQNameClass +# define ANYNAME_INIT js_InitAnyNameClass +# define ATTRIBUTE_INIT js_InitAttributeNameClass +#else +# define XML_INIT js_InitNullClass +# define NAMESPACE_INIT js_InitNullClass +# define QNAME_INIT js_InitNullClass +# define ANYNAME_INIT js_InitNullClass +# define ATTRIBUTE_INIT js_InitNullClass +#endif + +#if JS_HAS_GENERATORS +# define GENERATOR_INIT js_InitIteratorClasses +#else +# define GENERATOR_INIT js_InitNullClass +#endif + +#if JS_HAS_FILE_OBJECT +# define FILE_INIT js_InitFileClass +#else +# define FILE_INIT js_InitNullClass +#endif + /* * Enumerator codes in the second column must not change -- they are part of * the JS XDR API. @@ -53,16 +85,12 @@ JS_PROTO(Math, 7, js_InitMathClass) JS_PROTO(Number, 8, js_InitNumberClass) JS_PROTO(String, 9, js_InitStringClass) JS_PROTO(RegExp, 10, js_InitRegExpClass) -#if JS_HAS_SCRIPT_OBJECT -JS_PROTO(Script, 11, js_InitScriptClass) -#endif -#if JS_HAS_XML_SUPPORT -JS_PROTO(XML, 12, js_InitXMLClass) -JS_PROTO(Namespace, 13, js_InitNamespaceClass) -JS_PROTO(QName, 14, js_InitQNameClass) -JS_PROTO(AnyName, 15, js_InitAnyNameClass) -JS_PROTO(AttributeName, 16, js_InitAttributeNameClass) -#endif +JS_PROTO(Script, 11, SCRIPT_INIT) +JS_PROTO(XML, 12, XML_INIT) +JS_PROTO(Namespace, 13, NAMESPACE_INIT) +JS_PROTO(QName, 14, QNAME_INIT) +JS_PROTO(AnyName, 15, ANYNAME_INIT) +JS_PROTO(AttributeName, 16, ATTRIBUTE_INIT) JS_PROTO(Error, 17, js_InitExceptionClasses) JS_PROTO(InternalError, 18, js_InitExceptionClasses) JS_PROTO(EvalError, 19, js_InitExceptionClasses) @@ -71,12 +99,18 @@ JS_PROTO(ReferenceError, 21, js_InitExceptionClasses) JS_PROTO(SyntaxError, 22, js_InitExceptionClasses) JS_PROTO(TypeError, 23, js_InitExceptionClasses) JS_PROTO(URIError, 24, js_InitExceptionClasses) -#if JS_HAS_GENERATORS -JS_PROTO(Generator, 25, js_InitIteratorClasses) -#endif +JS_PROTO(Generator, 25, GENERATOR_INIT) JS_PROTO(Iterator, 26, js_InitIteratorClasses) JS_PROTO(StopIteration, 27, js_InitIteratorClasses) JS_PROTO(GeneratorExit, 28, js_InitIteratorClasses) -#if JS_HAS_FILE_OBJECT -JS_PROTO(File, 29, js_InitFileClass) -#endif +JS_PROTO(File, 29, FILE_INIT) +JS_PROTO(Block, 30, js_InitBlockClass) + +#undef SCRIPT_INIT +#undef XML_INIT +#undef NAMESPACE_INIT +#undef QNAME_INIT +#undef ANYNAME_INIT +#undef ATTRIBUTE_INIT +#undef GENERATOR_INIT +#undef FILE_INIT diff --git a/js/src/jsscript.c b/js/src/jsscript.c index 0b090422dd5..974ec5286d5 100644 --- a/js/src/jsscript.c +++ b/js/src/jsscript.c @@ -1,5 +1,5 @@ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: set ts=8 sw=4 et tw=80: + * vim: set ts=8 sw=4 et tw=78: * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 @@ -359,6 +359,9 @@ XDRAtomMap(JSXDRState *xdr, JSAtomMap *map) memset(atoms, 0, (size_t)natoms * sizeof *atoms); #endif } + + map->vector = atoms; + map->length = natoms; } for (i = 0; i != natoms; ++i) { @@ -377,15 +380,15 @@ XDRAtomMap(JSXDRState *xdr, JSAtomMap *map) goto bad; } - if (xdr->mode == JSXDR_DECODE) { - map->vector = atoms; - map->length = natoms; - } return JS_TRUE; bad: - if (xdr->mode == JSXDR_DECODE) + if (xdr->mode == JSXDR_DECODE) { JS_free(cx, atoms); + map->vector = NULL; + map->length = 0; + } + return JS_FALSE; } @@ -393,7 +396,7 @@ JSBool js_XDRScript(JSXDRState *xdr, JSScript **scriptp, JSBool *hasMagic) { JSContext *cx; - JSScript *script, *newscript; + JSScript *script, *newscript, *oldscript; uint32 length, lineno, depth, magic, nsrcnotes, ntrynotes; uint32 prologLength, version; JSBool filenameWasSaved; @@ -504,6 +507,8 @@ js_XDRScript(JSXDRState *xdr, JSScript **scriptp, JSBool *hasMagic) * in the (DECODE and magic < _4) case must point at a temporary vector * allocated just below. */ + oldscript = xdr->script; + xdr->script = script; if (!JS_XDRBytes(xdr, (char *)script->code, length * sizeof(jsbytecode)) || !XDRAtomMap(xdr, &script->atomMap)) { goto error; @@ -631,6 +636,8 @@ js_XDRScript(JSXDRState *xdr, JSScript **scriptp, JSBool *hasMagic) tn->length = (ptrdiff_t) catchLength; tn->catchStart = (ptrdiff_t) catchStart; } + + xdr->script = oldscript; return JS_TRUE; error: diff --git a/js/src/jsxdrapi.c b/js/src/jsxdrapi.c index ca79822f0b6..2855c608e92 100644 --- a/js/src/jsxdrapi.c +++ b/js/src/jsxdrapi.c @@ -233,6 +233,7 @@ JS_XDRInitBase(JSXDRState *xdr, JSXDRMode mode, JSContext *cx) xdr->numclasses = xdr->maxclasses = 0; xdr->reghash = NULL; xdr->userdata = NULL; + xdr->script = NULL; } JS_PUBLIC_API(JSXDRState *) diff --git a/js/src/jsxdrapi.h b/js/src/jsxdrapi.h index fd06849114a..12aa9b906d4 100644 --- a/js/src/jsxdrapi.h +++ b/js/src/jsxdrapi.h @@ -114,6 +114,7 @@ struct JSXDRState { uintN maxclasses; void *reghash; void *userdata; + JSScript *script; }; extern JS_PUBLIC_API(void)