From 57f904f8b2686155ed5770a0c0a5d6a3e6b493d7 Mon Sep 17 00:00:00 2001 From: Jason Orendorff Date: Tue, 31 Mar 2009 09:02:20 -0500 Subject: [PATCH 01/11] Bug 483473 - Make JSObjectOps private. r=brendan. --HG-- extra : rebase_source : 3240cb1f5c047dc92f8d1b525963bcb27e0a3521 --- js/src/jsapi.h | 45 --------- js/src/jsobj.h | 45 +++++++++ js/src/jsprvtd.h | 131 ++++++++++++++++++++++++++ js/src/jspubtd.h | 146 +---------------------------- js/src/liveconnect/jsj_JavaArray.c | 1 + js/src/liveconnect/jsj_JavaClass.c | 1 + 6 files changed, 180 insertions(+), 189 deletions(-) diff --git a/js/src/jsapi.h b/js/src/jsapi.h index 1bf930ba2f6e..2aafa6eb8739 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -1399,51 +1399,6 @@ struct JSExtendedClass { #define JSCLASS_NO_OPTIONAL_MEMBERS 0,0,0,0,0,0,0,0 #define JSCLASS_NO_RESERVED_MEMBERS 0,0,0 -/* For detailed comments on these function pointer types, see jspubtd.h. */ -struct JSObjectOps { - /* Mandatory non-null function pointer members. */ - JSNewObjectMapOp newObjectMap; - JSObjectMapOp destroyObjectMap; - JSLookupPropOp lookupProperty; - JSDefinePropOp defineProperty; - JSPropertyIdOp getProperty; - JSPropertyIdOp setProperty; - JSAttributesOp getAttributes; - JSAttributesOp setAttributes; - JSPropertyIdOp deleteProperty; - JSConvertOp defaultValue; - JSNewEnumerateOp enumerate; - JSCheckAccessIdOp checkAccess; - - /* Optionally non-null members start here. */ - JSObjectOp thisObject; - JSPropertyRefOp dropProperty; - JSNative call; - JSNative construct; - JSXDRObjectOp xdrObject; - JSHasInstanceOp hasInstance; - JSSetObjectSlotOp setProto; - JSSetObjectSlotOp setParent; - JSTraceOp trace; - JSFinalizeOp clear; - JSGetRequiredSlotOp getRequiredSlot; - JSSetRequiredSlotOp setRequiredSlot; -}; - -/* - * Classes that expose JSObjectOps via a non-null getObjectOps class hook may - * derive a property structure from this struct, return a pointer to it from - * lookupProperty and defineProperty, and use the pointer to avoid rehashing - * in getAttributes and setAttributes. - * - * The jsid type contains either an int jsval (see JSVAL_IS_INT above), or an - * internal pointer that is opaque to users of this API, but which users may - * convert from and to a jsval using JS_ValueToId and JS_IdToValue. - */ -struct JSProperty { - jsid id; -}; - struct JSIdArray { jsint length; jsid vector[1]; /* actually, length jsid words */ diff --git a/js/src/jsobj.h b/js/src/jsobj.h index 3bacddee28f8..e1eb0178e967 100644 --- a/js/src/jsobj.h +++ b/js/src/jsobj.h @@ -54,6 +54,51 @@ JS_BEGIN_EXTERN_C +/* For detailed comments on these function pointer types, see jsprvtd.h. */ +struct JSObjectOps { + /* Mandatory non-null function pointer members. */ + JSNewObjectMapOp newObjectMap; + JSObjectMapOp destroyObjectMap; + JSLookupPropOp lookupProperty; + JSDefinePropOp defineProperty; + JSPropertyIdOp getProperty; + JSPropertyIdOp setProperty; + JSAttributesOp getAttributes; + JSAttributesOp setAttributes; + JSPropertyIdOp deleteProperty; + JSConvertOp defaultValue; + JSNewEnumerateOp enumerate; + JSCheckAccessIdOp checkAccess; + + /* Optionally non-null members start here. */ + JSObjectOp thisObject; + JSPropertyRefOp dropProperty; + JSNative call; + JSNative construct; + JSXDRObjectOp xdrObject; + JSHasInstanceOp hasInstance; + JSSetObjectSlotOp setProto; + JSSetObjectSlotOp setParent; + JSTraceOp trace; + JSFinalizeOp clear; + JSGetRequiredSlotOp getRequiredSlot; + JSSetRequiredSlotOp setRequiredSlot; +}; + +/* + * Classes that expose JSObjectOps via a non-null getObjectOps class hook may + * derive a property structure from this struct, return a pointer to it from + * lookupProperty and defineProperty, and use the pointer to avoid rehashing + * in getAttributes and setAttributes. + * + * The jsid type contains either an int jsval (see JSVAL_IS_INT above), or an + * internal pointer that is opaque to users of this API, but which users may + * convert from and to a jsval using JS_ValueToId and JS_IdToValue. + */ +struct JSProperty { + jsid id; +}; + struct JSObjectMap { jsrefcount nrefs; /* count of all referencing objects */ JSObjectOps *ops; /* high level object operation vtable */ diff --git a/js/src/jsprvtd.h b/js/src/jsprvtd.h index 36f70a526023..651be0957045 100644 --- a/js/src/jsprvtd.h +++ b/js/src/jsprvtd.h @@ -253,6 +253,137 @@ struct JSTempValueRooter { JSTempValueUnion u; }; +/* JSObjectOps function pointer typedefs. */ + +/* + * Create a new subclass of JSObjectMap (see jsobj.h), with the nrefs and ops + * members initialized from the same-named parameters, and with the nslots and + * freeslot members initialized according to ops and clasp. Return null on + * error, non-null on success. + * + * JSObjectMaps are reference-counted by generic code in the engine. Usually, + * the nrefs parameter to JSObjectOps.newObjectMap will be 1, to count the ref + * returned to the caller on success. After a successful construction, some + * number of js_HoldObjectMap and js_DropObjectMap calls ensue. When nrefs + * reaches 0 due to a js_DropObjectMap call, JSObjectOps.destroyObjectMap will + * be called to dispose of the map. + */ +typedef JSObjectMap * +(* JSNewObjectMapOp)(JSContext *cx, jsrefcount nrefs, JSObjectOps *ops, + JSClass *clasp, JSObject *obj); + +/* + * Generic type for an infallible JSObjectMap operation, used currently by + * JSObjectOps.destroyObjectMap. + */ +typedef void +(* JSObjectMapOp)(JSContext *cx, JSObjectMap *map); + +/* + * Look for id in obj and its prototype chain, returning false on error or + * exception, true on success. On success, return null in *propp if id was + * not found. If id was found, return the first object searching from obj + * along its prototype chain in which id names a direct property in *objp, and + * return a non-null, opaque property pointer in *propp. + * + * If JSLookupPropOp succeeds and returns with *propp non-null, that pointer + * may be passed as the prop parameter to a JSAttributesOp, as a short-cut + * that bypasses id re-lookup. In any case, a non-null *propp result after a + * successful lookup must be dropped via JSObjectOps.dropProperty. + * + * NB: successful return with non-null *propp means the implementation may + * have locked *objp and added a reference count associated with *propp, so + * callers should not risk deadlock by nesting or interleaving other lookups + * or any obj-bearing ops before dropping *propp. + */ +typedef JSBool +(* JSLookupPropOp)(JSContext *cx, JSObject *obj, jsid id, JSObject **objp, + JSProperty **propp); + +/* + * Define obj[id], a direct property of obj named id, having the given initial + * value, with the specified getter, setter, and attributes. If the propp out + * param is non-null, *propp on successful return contains an opaque property + * pointer usable as a speedup hint with JSAttributesOp. But note that propp + * may be null, indicating that the caller is not interested in recovering an + * opaque pointer to the newly-defined property. + * + * If propp is non-null and JSDefinePropOp succeeds, its caller must be sure + * to drop *propp using JSObjectOps.dropProperty in short order, just as with + * JSLookupPropOp. + */ +typedef JSBool +(* JSDefinePropOp)(JSContext *cx, JSObject *obj, jsid id, jsval value, + JSPropertyOp getter, JSPropertyOp setter, uintN attrs, + JSProperty **propp); + +/* + * Get, set, or delete obj[id], returning false on error or exception, true + * on success. If getting or setting, the new value is returned in *vp on + * success. If deleting without error, *vp will be JSVAL_FALSE if obj[id] is + * permanent, and JSVAL_TRUE if id named a direct property of obj that was in + * fact deleted, or if id names no direct property of obj (id could name a + * prototype property, or no property in obj or its prototype chain). + */ +typedef JSBool +(* JSPropertyIdOp)(JSContext *cx, JSObject *obj, jsid id, jsval *vp); + +/* + * Get or set attributes of the property obj[id]. Return false on error or + * exception, true with current attributes in *attrsp. If prop is non-null, + * it must come from the *propp out parameter of a prior JSDefinePropOp or + * JSLookupPropOp call. + */ +typedef JSBool +(* JSAttributesOp)(JSContext *cx, JSObject *obj, jsid id, JSProperty *prop, + uintN *attrsp); + +/* + * JSObjectOps.checkAccess type: check whether obj[id] may be accessed per + * mode, returning false on error/exception, true on success with obj[id]'s + * last-got value in *vp, and its attributes in *attrsp. + */ +typedef JSBool +(* JSCheckAccessIdOp)(JSContext *cx, JSObject *obj, jsid id, JSAccessMode mode, + jsval *vp, uintN *attrsp); + +/* + * A generic type for functions taking a context, object, and property, with + * no return value. Used by JSObjectOps.dropProperty currently (see above, + * JSDefinePropOp and JSLookupPropOp, for the object-locking protocol in which + * dropProperty participates). + */ +typedef void +(* JSPropertyRefOp)(JSContext *cx, JSObject *obj, JSProperty *prop); + +/* + * Function pointer type for JSObjectOps.setProto and JSObjectOps.setParent. + * These hooks must check for cycles without deadlocking, and otherwise take + * special steps. See jsobj.c and jsgc.c for details. + */ +typedef JSBool +(* JSSetObjectSlotOp)(JSContext *cx, JSObject *obj, uint32 slot, + JSObject *pobj); + +/* + * Get and set a required slot, one that should already have been allocated. + * These operations are infallible, so required slots must be pre-allocated, + * or implementations must suppress out-of-memory errors. The native ops + * (js_ObjectOps, see jsobj.c) access slots reserved by including a call to + * the JSCLASS_HAS_RESERVED_SLOTS(n) macro in the JSClass.flags initializer. + * + * NB: the slot parameter is a zero-based index into obj slots, unlike the + * index parameter to the JS_GetReservedSlot and JS_SetReservedSlot API entry + * points, which is a zero-based index into the JSCLASS_RESERVED_SLOTS(clasp) + * reserved slots that come after the initial well-known slots: proto, parent, + * class, and optionally, the private data slot. + */ +typedef jsval +(* JSGetRequiredSlotOp)(JSContext *cx, JSObject *obj, uint32 slot); + +typedef JSBool +(* JSSetRequiredSlotOp)(JSContext *cx, JSObject *obj, uint32 slot, jsval v); + /* * The following determines whether JS_EncodeCharacters and JS_DecodeBytes * treat char[] as utf-8 or simply as bytes that need to be inflated/deflated. diff --git a/js/src/jspubtd.h b/js/src/jspubtd.h index b43e7926ff56..954fd59024ad 100644 --- a/js/src/jspubtd.h +++ b/js/src/jspubtd.h @@ -414,99 +414,10 @@ typedef void typedef uint32 (* JSReserveSlotsOp)(JSContext *cx, JSObject *obj); -/* JSObjectOps function pointer typedefs. */ +/* JSExtendedClass function pointer typedefs. */ -/* - * Create a new subclass of JSObjectMap (see jsobj.h), with the nrefs and ops - * members initialized from the same-named parameters, and with the nslots and - * freeslot members initialized according to ops and clasp. Return null on - * error, non-null on success. - * - * JSObjectMaps are reference-counted by generic code in the engine. Usually, - * the nrefs parameter to JSObjectOps.newObjectMap will be 1, to count the ref - * returned to the caller on success. After a successful construction, some - * number of js_HoldObjectMap and js_DropObjectMap calls ensue. When nrefs - * reaches 0 due to a js_DropObjectMap call, JSObjectOps.destroyObjectMap will - * be called to dispose of the map. - */ -typedef JSObjectMap * -(* JSNewObjectMapOp)(JSContext *cx, jsrefcount nrefs, JSObjectOps *ops, - JSClass *clasp, JSObject *obj); - -/* - * Generic type for an infallible JSObjectMap operation, used currently by - * JSObjectOps.destroyObjectMap. - */ -typedef void -(* JSObjectMapOp)(JSContext *cx, JSObjectMap *map); - -/* - * Look for id in obj and its prototype chain, returning false on error or - * exception, true on success. On success, return null in *propp if id was - * not found. If id was found, return the first object searching from obj - * along its prototype chain in which id names a direct property in *objp, and - * return a non-null, opaque property pointer in *propp. - * - * If JSLookupPropOp succeeds and returns with *propp non-null, that pointer - * may be passed as the prop parameter to a JSAttributesOp, as a short-cut - * that bypasses id re-lookup. In any case, a non-null *propp result after a - * successful lookup must be dropped via JSObjectOps.dropProperty. - * - * NB: successful return with non-null *propp means the implementation may - * have locked *objp and added a reference count associated with *propp, so - * callers should not risk deadlock by nesting or interleaving other lookups - * or any obj-bearing ops before dropping *propp. - */ typedef JSBool -(* JSLookupPropOp)(JSContext *cx, JSObject *obj, jsid id, JSObject **objp, - JSProperty **propp); - -/* - * Define obj[id], a direct property of obj named id, having the given initial - * value, with the specified getter, setter, and attributes. If the propp out - * param is non-null, *propp on successful return contains an opaque property - * pointer usable as a speedup hint with JSAttributesOp. But note that propp - * may be null, indicating that the caller is not interested in recovering an - * opaque pointer to the newly-defined property. - * - * If propp is non-null and JSDefinePropOp succeeds, its caller must be sure - * to drop *propp using JSObjectOps.dropProperty in short order, just as with - * JSLookupPropOp. - */ -typedef JSBool -(* JSDefinePropOp)(JSContext *cx, JSObject *obj, jsid id, jsval value, - JSPropertyOp getter, JSPropertyOp setter, uintN attrs, - JSProperty **propp); - -/* - * Get, set, or delete obj[id], returning false on error or exception, true - * on success. If getting or setting, the new value is returned in *vp on - * success. If deleting without error, *vp will be JSVAL_FALSE if obj[id] is - * permanent, and JSVAL_TRUE if id named a direct property of obj that was in - * fact deleted, or if id names no direct property of obj (id could name a - * prototype property, or no property in obj or its prototype chain). - */ -typedef JSBool -(* JSPropertyIdOp)(JSContext *cx, JSObject *obj, jsid id, jsval *vp); - -/* - * Get or set attributes of the property obj[id]. Return false on error or - * exception, true with current attributes in *attrsp. If prop is non-null, - * it must come from the *propp out parameter of a prior JSDefinePropOp or - * JSLookupPropOp call. - */ -typedef JSBool -(* JSAttributesOp)(JSContext *cx, JSObject *obj, jsid id, JSProperty *prop, - uintN *attrsp); - -/* - * JSObjectOps.checkAccess type: check whether obj[id] may be accessed per - * mode, returning false on error/exception, true on success with obj[id]'s - * last-got value in *vp, and its attributes in *attrsp. - */ -typedef JSBool -(* JSCheckAccessIdOp)(JSContext *cx, JSObject *obj, jsid id, JSAccessMode mode, - jsval *vp, uintN *attrsp); +(* JSEqualityOp)(JSContext *cx, JSObject *obj, jsval v, JSBool *bp); /* * A generic type for functions mapping an object to another object, or null @@ -523,59 +434,6 @@ typedef JSObject * typedef JSObject * (* JSIteratorOp)(JSContext *cx, JSObject *obj, JSBool keysonly); -/* - * A generic type for functions taking a context, object, and property, with - * no return value. Used by JSObjectOps.dropProperty currently (see above, - * JSDefinePropOp and JSLookupPropOp, for the object-locking protocol in which - * dropProperty participates). - */ -typedef void -(* JSPropertyRefOp)(JSContext *cx, JSObject *obj, JSProperty *prop); - -/* - * Function pointer type for JSObjectOps.setProto and JSObjectOps.setParent. - * These hooks must check for cycles without deadlocking, and otherwise take - * special steps. See jsobj.c and jsgc.c for details. - */ -typedef JSBool -(* JSSetObjectSlotOp)(JSContext *cx, JSObject *obj, uint32 slot, - JSObject *pobj); - -/* - * Get and set a required slot, one that should already have been allocated. - * These operations are infallible, so required slots must be pre-allocated, - * or implementations must suppress out-of-memory errors. The native ops - * (js_ObjectOps, see jsobj.c) access slots reserved by including a call to - * the JSCLASS_HAS_RESERVED_SLOTS(n) macro in the JSClass.flags initializer. - * - * NB: the slot parameter is a zero-based index into obj slots, unlike the - * index parameter to the JS_GetReservedSlot and JS_SetReservedSlot API entry - * points, which is a zero-based index into the JSCLASS_RESERVED_SLOTS(clasp) - * reserved slots that come after the initial well-known slots: proto, parent, - * class, and optionally, the private data slot. - */ -typedef jsval -(* JSGetRequiredSlotOp)(JSContext *cx, JSObject *obj, uint32 slot); - -typedef JSBool -(* JSSetRequiredSlotOp)(JSContext *cx, JSObject *obj, uint32 slot, jsval v); - -typedef JSObject * -(* JSGetMethodOp)(JSContext *cx, JSObject *obj, jsid id, jsval *vp); - -typedef JSBool -(* JSSetMethodOp)(JSContext *cx, JSObject *obj, jsid id, jsval *vp); - -typedef JSBool -(* JSEnumerateValuesOp)(JSContext *cx, JSObject *obj, JSIterateOp enum_op, - jsval *statep, jsid *idp, jsval *vp); - -typedef JSBool -(* JSEqualityOp)(JSContext *cx, JSObject *obj, jsval v, JSBool *bp); - -typedef JSBool -(* JSConcatenateOp)(JSContext *cx, JSObject *obj, jsval v, jsval *vp); - /* Typedef for native functions called by the JS VM. */ typedef JSBool diff --git a/js/src/liveconnect/jsj_JavaArray.c b/js/src/liveconnect/jsj_JavaArray.c index 4082a1905cb8..410e4ea2ebbf 100644 --- a/js/src/liveconnect/jsj_JavaArray.c +++ b/js/src/liveconnect/jsj_JavaArray.c @@ -48,6 +48,7 @@ #include #include "jsj_private.h" /* LiveConnect internals */ +#include "jsobj.h" /* Shorthands for ASCII (7-bit) decimal and hex conversion. */ #define JS7_ISDEC(c) (((c) >= '0') && ((c) <= '9')) diff --git a/js/src/liveconnect/jsj_JavaClass.c b/js/src/liveconnect/jsj_JavaClass.c index 77a8b5549b2a..4dd201fdd165 100644 --- a/js/src/liveconnect/jsj_JavaClass.c +++ b/js/src/liveconnect/jsj_JavaClass.c @@ -57,6 +57,7 @@ #include #include "jsj_private.h" /* LiveConnect internals */ +#include "jsobj.h" static JSBool JavaClass_convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp) From c711d85ee928e0e944ca7362ce907e630b0baa0e Mon Sep 17 00:00:00 2001 From: Andreas Gal Date: Tue, 31 Mar 2009 11:43:30 -0700 Subject: [PATCH 02/11] maintain globalShape in VMFragment only (486049, r=graydon). --- js/src/jstracer.cpp | 37 +++++++++++++++++++++---------------- js/src/jstracer.h | 5 +---- 2 files changed, 22 insertions(+), 20 deletions(-) diff --git a/js/src/jstracer.cpp b/js/src/jstracer.cpp index 1bf065cf9c96..30838398aef0 100644 --- a/js/src/jstracer.cpp +++ b/js/src/jstracer.cpp @@ -512,7 +512,7 @@ getVMFragment(JSTraceMonitor* tm, const void *ip, uint32 globalShape) return vf; } -static Fragment* +static VMFragment* getLoop(JSTraceMonitor* tm, const void *ip, uint32 globalShape) { return getVMFragment(tm, ip, globalShape); @@ -2536,7 +2536,7 @@ TraceRecorder::closeLoop(JSTraceMonitor* tm, bool& demote) LIns* exitIns; Fragment* peer; VMSideExit* exit; - Fragment* peer_root; + VMFragment* peer_root; Fragmento* fragmento = tm->fragmento; exitIns = snapshot(UNSTABLE_LOOP_EXIT); @@ -2551,7 +2551,8 @@ TraceRecorder::closeLoop(JSTraceMonitor* tm, bool& demote) JS_ASSERT(exit->numStackSlots == treeInfo->nStackTypes); - peer_root = getLoop(traceMonitor, fragment->root->ip, treeInfo->globalShape); + VMFragment* root = (VMFragment*)fragment->root; + peer_root = getLoop(traceMonitor, root->ip, root->globalShape); JS_ASSERT(peer_root != NULL); stable = deduceTypeStability(peer_root, &peer, demote); @@ -2628,7 +2629,7 @@ TraceRecorder::closeLoop(JSTraceMonitor* tm, bool& demote) } JS_REQUIRES_STACK void -TraceRecorder::joinEdgesToEntry(Fragmento* fragmento, Fragment* peer_root) +TraceRecorder::joinEdgesToEntry(Fragmento* fragmento, VMFragment* peer_root) { if (fragment->kind == LoopTrace) { TreeInfo* ti; @@ -2703,7 +2704,7 @@ TraceRecorder::joinEdgesToEntry(Fragmento* fragmento, Fragment* peer_root) } } - debug_only_v(js_DumpPeerStability(traceMonitor, peer_root->ip, treeInfo->globalShape);) + debug_only_v(js_DumpPeerStability(traceMonitor, peer_root->ip, peer_root->globalShape);) } /* Emit an always-exit guard and compile the tree (used for break statements. */ @@ -2725,7 +2726,8 @@ TraceRecorder::endLoop(JSTraceMonitor* tm) if (tm->fragmento->assm()->error() != nanojit::None) return; - joinEdgesToEntry(tm->fragmento, getLoop(tm, fragment->root->ip, treeInfo->globalShape)); + VMFragment* root = (VMFragment*)fragment->root; + joinEdgesToEntry(tm->fragmento, getLoop(tm, root->ip, root->globalShape)); /* Note: this must always be done, in case we added new globals on trace and haven't yet propagated those to linked and dependent trees. */ @@ -3026,12 +3028,13 @@ js_CheckGlobalObjectShape(JSContext* cx, JSTraceMonitor* tm, JSObject* globalObj uint32 globalShape = OBJ_SHAPE(globalObj); if (tm->recorder) { + VMFragment* root = (VMFragment*)tm->recorder->getFragment()->root; TreeInfo* ti = tm->recorder->getTreeInfo(); /* Check the global shape matches the recorder's treeinfo's shape. */ - if (globalShape != ti->globalShape) { + if (globalShape != root->globalShape) { AUDIT(globalShapeMismatchAtEntry); debug_only_v(printf("Global shape mismatch (%u vs. %u), flushing cache.\n", - globalShape, ti->globalShape);) + globalShape, root->globalShape);) return false; } if (shape) @@ -3332,7 +3335,7 @@ js_RecordTree(JSContext* cx, JSTraceMonitor* tm, Fragment* f, jsbytecode* outer, JS_ASSERT(!f->code() && !f->vmprivate); /* setup the VM-private treeInfo structure for this fragment */ - TreeInfo* ti = new (&gc) TreeInfo(f, globalShape, globalSlots); + TreeInfo* ti = new (&gc) TreeInfo(f, globalSlots); /* capture the coerced type of each active slot in the type map */ ti->typeMap.captureTypes(cx, *globalSlots, 0/*callDepth*/); @@ -3388,7 +3391,7 @@ JS_REQUIRES_STACK static bool js_AttemptToStabilizeTree(JSContext* cx, VMSideExit* exit, jsbytecode* outer) { JSTraceMonitor* tm = &JS_TRACE_MONITOR(cx); - Fragment* from = exit->from->root; + VMFragment* from = (VMFragment*)exit->from->root; TreeInfo* from_ti = (TreeInfo*)from->vmprivate; JS_ASSERT(exit->from->root->code()); @@ -3466,7 +3469,7 @@ js_AttemptToStabilizeTree(JSContext* cx, VMSideExit* exit, jsbytecode* outer) tail = &uexit->next; } JS_ASSERT(bound); - debug_only_v(js_DumpPeerStability(tm, f->ip, from_ti->globalShape);) + debug_only_v(js_DumpPeerStability(tm, f->ip, from->globalShape);) break; } else if (undemote) { /* The original tree is unconnectable, so trash it. */ @@ -3478,7 +3481,8 @@ js_AttemptToStabilizeTree(JSContext* cx, VMSideExit* exit, jsbytecode* outer) if (bound) return false; - return js_RecordTree(cx, tm, from->first, outer, from_ti->globalShape, from_ti->globalSlots); + return js_RecordTree(cx, tm, from->first, outer, ((VMFragment*)from->root)->globalShape, + from_ti->globalSlots); } static JS_REQUIRES_STACK bool @@ -3552,7 +3556,6 @@ js_RecordLoopEdge(JSContext* cx, TraceRecorder* r, uintN& inlineCallCount) #endif JSTraceMonitor* tm = &JS_TRACE_MONITOR(cx); - TreeInfo* ti = r->getTreeInfo(); /* Process deep abort requests. */ if (r->wasDeepAborted()) { @@ -3561,9 +3564,10 @@ js_RecordLoopEdge(JSContext* cx, TraceRecorder* r, uintN& inlineCallCount) } JS_ASSERT(r->getFragment() && !r->getFragment()->lastIns); + VMFragment* root = (VMFragment*)r->getFragment()->root; /* Does this branch go to an inner loop? */ - Fragment* f = getLoop(&JS_TRACE_MONITOR(cx), cx->fp->regs->pc, ti->globalShape); + Fragment* f = getLoop(&JS_TRACE_MONITOR(cx), cx->fp->regs->pc, root->globalShape); if (!f) { /* Not an inner loop we can call, abort trace. */ AUDIT(returnToDifferentLoopHeader); @@ -3852,7 +3856,7 @@ static JS_REQUIRES_STACK VMSideExit* js_ExecuteTree(JSContext* cx, Fragment* f, uintN& inlineCallCount, VMSideExit** innermostNestedGuardp) { - JS_ASSERT(f->code() && f->vmprivate); + JS_ASSERT(f->root == f && f->code() && f->vmprivate); JS_ASSERT(cx->builtinStatus == 0); JSTraceMonitor* tm = &JS_TRACE_MONITOR(cx); @@ -3863,7 +3867,8 @@ js_ExecuteTree(JSContext* cx, Fragment* f, uintN& inlineCallCount, unsigned globalFrameSize = STOBJ_NSLOTS(globalObj); /* Make sure the global object is sane. */ - JS_ASSERT(!ngslots || (OBJ_SHAPE(JS_GetGlobalForObject(cx, cx->fp->scopeChain)) == ti->globalShape)); + JS_ASSERT(!ngslots || (OBJ_SHAPE(JS_GetGlobalForObject(cx, cx->fp->scopeChain)) == + ((VMFragment*)f)->globalShape)); /* Make sure our caller replenished the double pool. */ JS_ASSERT(tm->reservedDoublePoolPtr >= tm->reservedDoublePool + MAX_NATIVE_STACK_SLOTS); diff --git a/js/src/jstracer.h b/js/src/jstracer.h index 7e44a54052ee..82589e600fdd 100644 --- a/js/src/jstracer.h +++ b/js/src/jstracer.h @@ -298,7 +298,6 @@ public: unsigned maxCallDepth; TypeMap typeMap; unsigned nStackTypes; - uint32 globalShape; SlotList* globalSlots; /* Dependent trees must be trashed if this tree dies, and updated on missing global types */ Queue dependentTrees; @@ -314,7 +313,6 @@ public: #endif TreeInfo(nanojit::Fragment* _fragment, - uint32 _globalShape, SlotList* _globalSlots) : fragment(_fragment), script(NULL), @@ -322,7 +320,6 @@ public: nativeStackBase(0), maxCallDepth(0), nStackTypes(0), - globalShape(_globalShape), globalSlots(_globalSlots), branchCount(0), unstableExits(NULL) @@ -572,7 +569,7 @@ public: JS_REQUIRES_STACK void closeLoop(JSTraceMonitor* tm, bool& demote); JS_REQUIRES_STACK void endLoop(JSTraceMonitor* tm); JS_REQUIRES_STACK void joinEdgesToEntry(nanojit::Fragmento* fragmento, - nanojit::Fragment* peer_root); + VMFragment* peer_root); void blacklist() { fragment->blacklist(); } JS_REQUIRES_STACK bool adjustCallerTypes(nanojit::Fragment* f); JS_REQUIRES_STACK nanojit::Fragment* findNestedCompatiblePeer(nanojit::Fragment* f, From 6b2f7b1e063e5f9978f762fcd232e769b93be441 Mon Sep 17 00:00:00 2001 From: Andreas Gal Date: Tue, 31 Mar 2009 11:49:44 -0700 Subject: [PATCH 03/11] specialize code for a specific global object, not just a global object shape (480905, r=graydon). --- js/src/jscntxt.h | 1 + js/src/jstracer.cpp | 85 ++++++++++++++++++++++++--------------------- js/src/jstracer.h | 2 -- 3 files changed, 47 insertions(+), 41 deletions(-) diff --git a/js/src/jscntxt.h b/js/src/jscntxt.h index 011b375f6aa4..27a290177ecc 100644 --- a/js/src/jscntxt.h +++ b/js/src/jscntxt.h @@ -111,6 +111,7 @@ struct VMFragment; #define MONITOR_N_GLOBAL_STATES 4 struct GlobalState { + JSObject* globalObj; uint32 globalShape; CLS(SlotList) globalSlots; }; diff --git a/js/src/jstracer.cpp b/js/src/jstracer.cpp index 30838398aef0..c6f0aa7933e0 100644 --- a/js/src/jstracer.cpp +++ b/js/src/jstracer.cpp @@ -236,7 +236,7 @@ static avmplus::AvmCore* core = &s_core; #ifdef JS_JIT_SPEW void -js_DumpPeerStability(JSTraceMonitor* tm, const void* ip, uint32 globalShape); +js_DumpPeerStability(JSTraceMonitor* tm, const void* ip, JSObject* globalObj, uint32 globalShape); #endif /* We really need a better way to configure the JIT. Shaver, where is my fancy JIT object? */ @@ -480,32 +480,36 @@ js_Backoff(Fragment* tree, const jsbytecode* where) } static inline size_t -fragmentHash(const void *ip, uint32 globalShape) +fragmentHash(const void *ip, JSObject* globalObj, uint32 globalShape) { uintptr_t h = HASH_SEED; hash_accum(h, uintptr_t(ip), FRAGMENT_TABLE_MASK); + hash_accum(h, uintptr_t(globalObj), FRAGMENT_TABLE_MASK); hash_accum(h, uintptr_t(globalShape), FRAGMENT_TABLE_MASK); return size_t(h); } struct VMFragment : public Fragment { - VMFragment(const void* _ip, uint32 _globalShape) : + VMFragment(const void* _ip, JSObject* _globalObj, uint32 _globalShape) : Fragment(_ip), next(NULL), + globalObj(_globalObj), globalShape(_globalShape) {} VMFragment* next; + JSObject* globalObj; uint32 globalShape; }; static VMFragment* -getVMFragment(JSTraceMonitor* tm, const void *ip, uint32 globalShape) +getVMFragment(JSTraceMonitor* tm, const void *ip, JSObject* globalObj, uint32 globalShape) { - size_t h = fragmentHash(ip, globalShape); + size_t h = fragmentHash(ip, globalObj, globalShape); VMFragment* vf = tm->vmfragments[h]; while (vf && - ! (vf->globalShape == globalShape && + ! (vf->globalObj == globalObj && + vf->globalShape == globalShape && vf->ip == ip)) { vf = vf->next; } @@ -513,18 +517,18 @@ getVMFragment(JSTraceMonitor* tm, const void *ip, uint32 globalShape) } static VMFragment* -getLoop(JSTraceMonitor* tm, const void *ip, uint32 globalShape) +getLoop(JSTraceMonitor* tm, const void *ip, JSObject* globalObj, uint32 globalShape) { - return getVMFragment(tm, ip, globalShape); + return getVMFragment(tm, ip, globalObj, globalShape); } static Fragment* -getAnchor(JSTraceMonitor* tm, const void *ip, uint32 globalShape) +getAnchor(JSTraceMonitor* tm, const void *ip, JSObject* globalObj, uint32 globalShape) { - VMFragment *f = new (&gc) VMFragment(ip, globalShape); + VMFragment *f = new (&gc) VMFragment(ip, globalObj, globalShape); JS_ASSERT(f); - Fragment *p = getVMFragment(tm, ip, globalShape); + Fragment *p = getVMFragment(tm, ip, globalObj, globalShape); if (p) { f->first = p; @@ -536,7 +540,7 @@ getAnchor(JSTraceMonitor* tm, const void *ip, uint32 globalShape) } else { /* this is the first fragment */ f->first = f; - size_t h = fragmentHash(ip, globalShape); + size_t h = fragmentHash(ip, globalObj, globalShape); f->next = tm->vmfragments[h]; tm->vmfragments[h] = f; } @@ -558,7 +562,7 @@ js_AttemptCompilation(JSTraceMonitor* tm, JSObject* globalObj, jsbytecode* pc) /* * Breath new live into all peer fragments at the designated loop header. */ - Fragment* f = (VMFragment*)getLoop(tm, pc, OBJ_SHAPE(globalObj)); + Fragment* f = (VMFragment*)getLoop(tm, pc, globalObj, OBJ_SHAPE(globalObj)); if (!f) { /* * If the global object's shape changed, we can't easily find the @@ -1260,7 +1264,6 @@ TraceRecorder::TraceRecorder(JSContext* cx, VMSideExit* _anchor, Fragment* _frag cx_ins = addName(lir->insLoad(LIR_ldp, lirbuf->state, offsetof(InterpState, cx)), "cx"); eos_ins = addName(lir->insLoad(LIR_ldp, lirbuf->state, offsetof(InterpState, eos)), "eos"); eor_ins = addName(lir->insLoad(LIR_ldp, lirbuf->state, offsetof(InterpState, eor)), "eor"); - globalObj_ins = addName(lir->insLoad(LIR_ldp, lirbuf->state, offsetof(InterpState, globalObj)), "globalObj"); /* If we came from exit, we might not have enough global types. */ if (ti->globalSlots->length() > ti->nGlobalTypes()) @@ -2552,7 +2555,7 @@ TraceRecorder::closeLoop(JSTraceMonitor* tm, bool& demote) JS_ASSERT(exit->numStackSlots == treeInfo->nStackTypes); VMFragment* root = (VMFragment*)fragment->root; - peer_root = getLoop(traceMonitor, root->ip, root->globalShape); + peer_root = getLoop(traceMonitor, root->ip, root->globalObj, root->globalShape); JS_ASSERT(peer_root != NULL); stable = deduceTypeStability(peer_root, &peer, demote); @@ -2704,7 +2707,8 @@ TraceRecorder::joinEdgesToEntry(Fragmento* fragmento, VMFragment* peer_root) } } - debug_only_v(js_DumpPeerStability(traceMonitor, peer_root->ip, peer_root->globalShape);) + debug_only_v(js_DumpPeerStability(traceMonitor, peer_root->ip, + peer_root->globalObj, peer_root->globalShape);) } /* Emit an always-exit guard and compile the tree (used for break statements. */ @@ -2727,7 +2731,7 @@ TraceRecorder::endLoop(JSTraceMonitor* tm) return; VMFragment* root = (VMFragment*)fragment->root; - joinEdgesToEntry(tm->fragmento, getLoop(tm, root->ip, root->globalShape)); + joinEdgesToEntry(tm->fragmento, getLoop(tm, root->ip, root->globalObj, root->globalShape)); /* Note: this must always be done, in case we added new globals on trace and haven't yet propagated those to linked and dependent trees. */ @@ -3031,10 +3035,10 @@ js_CheckGlobalObjectShape(JSContext* cx, JSTraceMonitor* tm, JSObject* globalObj VMFragment* root = (VMFragment*)tm->recorder->getFragment()->root; TreeInfo* ti = tm->recorder->getTreeInfo(); /* Check the global shape matches the recorder's treeinfo's shape. */ - if (globalShape != root->globalShape) { + if (globalObj != root->globalObj || globalShape != root->globalShape) { AUDIT(globalShapeMismatchAtEntry); - debug_only_v(printf("Global shape mismatch (%u vs. %u), flushing cache.\n", - globalShape, root->globalShape);) + debug_only_v(printf("Global object/shape mismatch (%p/%u vs. %p/%u), flushing cache.\n", + globalObj, globalShape, root->globalObj, root->globalShape);) return false; } if (shape) @@ -3049,12 +3053,13 @@ js_CheckGlobalObjectShape(JSContext* cx, JSTraceMonitor* tm, JSObject* globalObj GlobalState &state = tm->globalStates[i]; if (state.globalShape == (uint32) -1) { + state.globalObj = globalObj; state.globalShape = globalShape; JS_ASSERT(state.globalSlots); JS_ASSERT(state.globalSlots->length() == 0); } - if (tm->globalStates[i].globalShape == globalShape) { + if (state.globalObj == globalObj && state.globalShape == globalShape) { if (shape) *shape = globalShape; if (slots) @@ -3299,12 +3304,11 @@ js_SynthesizeFrame(JSContext* cx, const FrameInfo& fi) JS_REQUIRES_STACK bool js_RecordTree(JSContext* cx, JSTraceMonitor* tm, Fragment* f, jsbytecode* outer, - uint32 globalShape, SlotList* globalSlots) + JSObject* globalObj, uint32 globalShape, SlotList* globalSlots) { JS_ASSERT(f->root == f); /* Make sure the global type map didn't change on us. */ - JSObject* globalObj = JS_GetGlobalForObject(cx, cx->fp->scopeChain); if (!js_CheckGlobalObjectShape(cx, tm, globalObj)) { js_FlushJITCache(cx); return false; @@ -3316,7 +3320,7 @@ js_RecordTree(JSContext* cx, JSTraceMonitor* tm, Fragment* f, jsbytecode* outer, while (f->code() && f->peer) f = f->peer; if (f->code()) - f = getAnchor(&JS_TRACE_MONITOR(cx), f->root->ip, globalShape); + f = getAnchor(&JS_TRACE_MONITOR(cx), f->root->ip, globalObj, globalShape); if (!f) { js_FlushJITCache(cx); @@ -3345,7 +3349,8 @@ js_RecordTree(JSContext* cx, JSTraceMonitor* tm, Fragment* f, jsbytecode* outer, since we are trying to stabilize something without properly connecting peer edges. */ #ifdef DEBUG TreeInfo* ti_other; - for (Fragment* peer = getLoop(tm, f->root->ip, globalShape); peer != NULL; peer = peer->peer) { + for (Fragment* peer = getLoop(tm, f->root->ip, globalObj, globalShape); peer != NULL; + peer = peer->peer) { if (!peer->code() || peer == f) continue; ti_other = (TreeInfo*)peer->vmprivate; @@ -3469,7 +3474,7 @@ js_AttemptToStabilizeTree(JSContext* cx, VMSideExit* exit, jsbytecode* outer) tail = &uexit->next; } JS_ASSERT(bound); - debug_only_v(js_DumpPeerStability(tm, f->ip, from->globalShape);) + debug_only_v(js_DumpPeerStability(tm, f->ip, from->globalObj, from->globalShape);) break; } else if (undemote) { /* The original tree is unconnectable, so trash it. */ @@ -3481,7 +3486,8 @@ js_AttemptToStabilizeTree(JSContext* cx, VMSideExit* exit, jsbytecode* outer) if (bound) return false; - return js_RecordTree(cx, tm, from->first, outer, ((VMFragment*)from->root)->globalShape, + VMFragment* root = (VMFragment*)from->root; + return js_RecordTree(cx, tm, from->first, outer, root->globalObj, root->globalShape, from_ti->globalSlots); } @@ -3567,7 +3573,8 @@ js_RecordLoopEdge(JSContext* cx, TraceRecorder* r, uintN& inlineCallCount) VMFragment* root = (VMFragment*)r->getFragment()->root; /* Does this branch go to an inner loop? */ - Fragment* f = getLoop(&JS_TRACE_MONITOR(cx), cx->fp->regs->pc, root->globalShape); + Fragment* f = getLoop(&JS_TRACE_MONITOR(cx), cx->fp->regs->pc, + root->globalObj, root->globalShape); if (!f) { /* Not an inner loop we can call, abort trace. */ AUDIT(returnToDifferentLoopHeader); @@ -3623,13 +3630,13 @@ js_RecordLoopEdge(JSContext* cx, TraceRecorder* r, uintN& inlineCallCount) f = empty; if (!f) { - f = getAnchor(tm, cx->fp->regs->pc, globalShape); + f = getAnchor(tm, cx->fp->regs->pc, globalObj, globalShape); if (!f) { js_FlushJITCache(cx); return false; } } - return js_RecordTree(cx, tm, f, outer, globalShape, globalSlots); + return js_RecordTree(cx, tm, f, outer, globalObj, globalShape, globalSlots); } r->prepareTreeCall(f); @@ -3879,7 +3886,6 @@ js_ExecuteTree(JSContext* cx, Fragment* f, uintN& inlineCallCount, /* Setup the interpreter state block, which is followed by the native global frame. */ InterpState* state = (InterpState*)alloca(sizeof(InterpState) + (globalFrameSize+1)*sizeof(double)); state->cx = cx; - state->globalObj = globalObj; state->inlineCallCountp = &inlineCallCount; state->innermostNestedGuardp = innermostNestedGuardp; state->outermostTree = ti; @@ -4154,7 +4160,8 @@ LeaveTree(InterpState& state, VMSideExit* lr) /* write back interned globals */ double* global = (double*)(&state + 1); FlushNativeGlobalFrame(cx, ngslots, gslots, globalTypeMap, global); - JS_ASSERT(*(uint64*)&global[STOBJ_NSLOTS(state.globalObj)] == 0xdeadbeefdeadbeefLL); + JS_ASSERT(*(uint64*)&global[STOBJ_NSLOTS(JS_GetGlobalForObject(cx, cx->fp->scopeChain))] == + 0xdeadbeefdeadbeefLL); /* write back native stack frame */ #ifdef DEBUG @@ -4230,9 +4237,9 @@ js_MonitorLoopEdge(JSContext* cx, uintN& inlineCallCount) jsbytecode* pc = cx->fp->regs->pc; - Fragment* f = getLoop(tm, pc, globalShape); + Fragment* f = getLoop(tm, pc, globalObj, globalShape); if (!f) - f = getAnchor(tm, pc, globalShape); + f = getAnchor(tm, pc, globalObj, globalShape); if (!f) { js_FlushJITCache(cx); @@ -4247,7 +4254,7 @@ js_MonitorLoopEdge(JSContext* cx, uintN& inlineCallCount) return false; /* We can give RecordTree the root peer. If that peer is already taken, it will walk the peer list and find us a free slot or allocate a new tree if needed. */ - return js_RecordTree(cx, tm, f->first, NULL, globalShape, globalSlots); + return js_RecordTree(cx, tm, f->first, NULL, globalObj, globalShape, globalSlots); } debug_only_v(printf("Looking for compat peer %d@%d, from %p (ip: %p)\n", @@ -6126,7 +6133,7 @@ TraceRecorder::guardNotGlobalObject(JSObject* obj, LIns* obj_ins) { if (obj == globalObj) ABORT_TRACE("reference aliases global object"); - guard(false, lir->ins2(LIR_eq, obj_ins, globalObj_ins), MISMATCH_EXIT); + guard(false, lir->ins2(LIR_eq, obj_ins, INS_CONSTPTR(globalObj)), MISMATCH_EXIT); return true; } @@ -7540,7 +7547,7 @@ TraceRecorder::record_JSOP_CALLNAME() if (!activeCallOrGlobalSlot(obj, vp)) return false; stack(0, get(vp)); - stack(1, globalObj_ins); + stack(1, INS_CONSTPTR(globalObj)); return true; } @@ -9686,14 +9693,14 @@ TraceRecorder::record_JSOP_LOOP() #ifdef JS_JIT_SPEW /* Prints information about entry typemaps and unstable exits for all peers at a PC */ void -js_DumpPeerStability(JSTraceMonitor* tm, const void* ip, uint32 globalShape) +js_DumpPeerStability(JSTraceMonitor* tm, const void* ip, JSObject* globalObj, uint32 globalShape) { Fragment* f; TreeInfo* ti; bool looped = false; unsigned length = 0; - for (f = getLoop(tm, ip, globalShape); f != NULL; f = f->peer) { + for (f = getLoop(tm, ip, globalObj, globalShape); f != NULL; f = f->peer) { if (!f->vmprivate) continue; printf("fragment %p:\nENTRY: ", (void*)f); diff --git a/js/src/jstracer.h b/js/src/jstracer.h index 82589e600fdd..f313af515354 100644 --- a/js/src/jstracer.h +++ b/js/src/jstracer.h @@ -353,7 +353,6 @@ struct InterpState // call exit guard mismatched void* rpAtLastTreeCall; // value of rp at innermost tree call guard TreeInfo* outermostTree; // the outermost tree we initially invoked - JSObject* globalObj; // pointer to the global object double* stackBase; // native stack base FrameInfo** callstackBase; // call stack base uintN* inlineCallCountp; // inline call count counter @@ -398,7 +397,6 @@ class TraceRecorder : public avmplus::GCObject { nanojit::LIns* cx_ins; nanojit::LIns* eos_ins; nanojit::LIns* eor_ins; - nanojit::LIns* globalObj_ins; nanojit::LIns* rval_ins; nanojit::LIns* inner_sp_ins; nanojit::LIns* invokevp_ins; From f105b4a343b7b78826a79bf49acc51c4ef0a9657 Mon Sep 17 00:00:00 2001 From: Igor Bukanov Date: Tue, 31 Mar 2009 21:42:31 +0200 Subject: [PATCH 04/11] bug 486106 - restoring JS*Lookup API compatibility with fast arrays. r=shaver --- js/src/jsapi.cpp | 2 ++ js/src/jsarray.cpp | 17 +++++++++++++++++ js/src/jsarray.h | 6 ++++++ 3 files changed, 25 insertions(+) diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 8b62ac0c3ea6..0e629bc02b8b 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -3237,6 +3237,8 @@ LookupResult(JSContext *cx, JSObject *obj, JSObject *obj2, JSProperty *prop) rval = SPROP_HAS_VALID_SLOT(sprop, OBJ_SCOPE(obj2)) ? LOCKED_OBJ_GET_SLOT(obj2, sprop->slot) : JSVAL_TRUE; + } else if (OBJ_IS_DENSE_ARRAY(cx, obj2)) { + rval = js_GetDenseArrayElementValue(obj2, prop); } else { /* XXX bad API: no way to return "defined but value unknown" */ rval = JSVAL_TRUE; diff --git a/js/src/jsarray.cpp b/js/src/jsarray.cpp index 7fa5b39f26d7..5afa3b1f8cd2 100644 --- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -739,6 +739,23 @@ array_dropProperty(JSContext *cx, JSObject *obj, JSProperty *prop) #endif } +jsval +js_GetDenseArrayElementValue(JSObject *obj, JSProperty *prop) +{ + /* OBJ_IS_DENSE_ARRAY does not use the cx argument. */ + JS_ASSERT(OBJ_IS_DENSE_ARRAY(cx, obj)); + JS_ASSERT((void *) prop == + (void *) &(obj->fslots[JSSLOT_ARRAY_LOOKUP_HOLDER])); + JS_ASSERT((jsval) prop->id == obj->fslots[JSSLOT_ARRAY_LOOKUP_HOLDER]); + JS_ASSERT(JSVAL_IS_INT(prop->id)); + + jsint i = JSID_TO_INT(prop->id); + JS_ASSERT(i >= 0); + jsval v = obj->dslots[i]; + JS_ASSERT(v != JSVAL_HOLE); + return v; +} + static JSBool array_getProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp) { diff --git a/js/src/jsarray.h b/js/src/jsarray.h index 058932195f55..47c3f30333cd 100644 --- a/js/src/jsarray.h +++ b/js/src/jsarray.h @@ -223,6 +223,12 @@ js_ArrayToJSDoubleBuffer(JSContext *cx, JSObject *obj, jsuint offset, jsuint cou JSBool js_PrototypeHasIndexedProperties(JSContext *cx, JSObject *obj); +/* + * Utility to access the value from the id returned by array_lookupProperty. + */ +jsval +js_GetDenseArrayElementValue(JSObject *obj, JSProperty *prop); + JS_END_EXTERN_C #endif /* jsarray_h___ */ From 4e3de55d77af9bb8bc5062202a1e14144067a928 Mon Sep 17 00:00:00 2001 From: Jeff Walden Date: Tue, 31 Mar 2009 14:24:01 -0700 Subject: [PATCH 05/11] Bug 484751 - TM: "Assertion failure: !OBJ_GET_CLASS(cx, proto)->getObjectOps, at ../jsobj.cpp". r=mrbkap --- js/src/jsobj.cpp | 93 +++++++++++++++++++++++++------------------- js/src/trace-test.js | 17 ++++++++ 2 files changed, 69 insertions(+), 41 deletions(-) diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index f12238b73a62..bb34c9d36113 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -2012,6 +2012,52 @@ js_Object(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) return JS_TRUE; } +static inline bool +CreateMapForObject(JSContext* cx, JSObject* obj, JSObject* proto, JSObjectOps* ops) +{ + JSObjectMap* map; + JSClass* protoclasp; + JSClass* clasp = OBJ_GET_CLASS(cx, obj); + + /* + * Share proto's map only if it has the same JSObjectOps, and only if + * proto's class has the same private and reserved slots as obj's map + * and class have. We assume that if prototype and object are of the + * same class, they always have the same number of computed reserved + * slots (returned via clasp->reserveSlots); otherwise, prototype and + * object classes must have the same (null or not) reserveSlots hook. + */ + if (proto && + ((map = proto->map)->ops == ops && + ((protoclasp = OBJ_GET_CLASS(cx, proto)) == clasp || + (!((protoclasp->flags ^ clasp->flags) & + (JSCLASS_HAS_PRIVATE | + (JSCLASS_RESERVED_SLOTS_MASK << JSCLASS_RESERVED_SLOTS_SHIFT))) && + protoclasp->reserveSlots == clasp->reserveSlots)))) + { + /* Share the given prototype's map. */ + obj->map = js_HoldObjectMap(cx, map); + obj->dslots = NULL; + return true; + } + + map = ops->newObjectMap(cx, 1, ops, clasp, obj); + if (!map) + return false; + obj->map = map; + + /* Let ops->newObjectMap set freeslot so as to reserve slots. */ + uint32 nslots = map->freeslot; + JS_ASSERT(nslots >= JSSLOT_PRIVATE); + if (nslots > JS_INITIAL_NSLOTS && + !js_ReallocSlots(cx, obj, nslots, JS_TRUE)) { + js_DropObjectMap(cx, map, obj); + return false; + } + + return true; +} + #ifdef JS_TRACER static inline JSObject* @@ -2028,10 +2074,9 @@ NewNativeObject(JSContext* cx, JSObject* proto, JSObject *parent) for (unsigned i = JSSLOT_PRIVATE; i < JS_INITIAL_NSLOTS; ++i) obj->fslots[i] = JSVAL_VOID; - JS_ASSERT(!OBJ_GET_CLASS(cx, proto)->getObjectOps); - JS_ASSERT(proto->map->ops == &js_ObjectOps); - obj->map = js_HoldObjectMap(cx, proto->map); - obj->dslots = NULL; + if (!CreateMapForObject(cx, obj, proto, &js_ObjectOps)) + return NULL; + return obj; } @@ -3051,9 +3096,7 @@ js_NewObjectWithGivenProto(JSContext *cx, JSClass *clasp, JSObject *proto, { JSObject *obj; JSObjectOps *ops; - JSObjectMap *map; - JSClass *protoclasp; - uint32 nslots, i; + uint32 i; JSTempValueRooter tvr; #ifdef INCLUDE_MOZILLA_DTRACE @@ -3128,40 +3171,8 @@ js_NewObjectWithGivenProto(JSContext *cx, JSClass *clasp, JSObject *proto, if (proto && !parent) STOBJ_SET_PARENT(obj, OBJ_GET_PARENT(cx, proto)); - /* - * Share proto's map only if it has the same JSObjectOps, and only if - * proto's class has the same private and reserved slots as obj's map - * and class have. We assume that if prototype and object are of the - * same class, they always have the same number of computed reserved - * slots (returned via clasp->reserveSlots); otherwise, prototype and - * object classes must have the same (null or not) reserveSlots hook. - */ - if (proto && - (map = proto->map)->ops == ops && - ((protoclasp = OBJ_GET_CLASS(cx, proto)) == clasp || - (!((protoclasp->flags ^ clasp->flags) & - (JSCLASS_HAS_PRIVATE | - (JSCLASS_RESERVED_SLOTS_MASK << JSCLASS_RESERVED_SLOTS_SHIFT))) && - protoclasp->reserveSlots == clasp->reserveSlots))) - { - /* Share the given prototype's map. */ - obj->map = js_HoldObjectMap(cx, map); - } else { - map = ops->newObjectMap(cx, 1, ops, clasp, obj); - if (!map) - goto bad; - obj->map = map; - - /* Let ops->newObjectMap set freeslot so as to reserve slots. */ - nslots = map->freeslot; - JS_ASSERT(nslots >= JSSLOT_PRIVATE); - if (nslots > JS_INITIAL_NSLOTS && - !js_ReallocSlots(cx, obj, nslots, JS_TRUE)) { - js_DropObjectMap(cx, map, obj); - obj->map = NULL; - goto bad; - } - } + if (!CreateMapForObject(cx, obj, proto, ops)) + goto bad; /* * Do not call debug hooks on trace, because we might be in a non-_FAIL diff --git a/js/src/trace-test.js b/js/src/trace-test.js index 5571a2fe03f2..ff32d6cfb383 100644 --- a/js/src/trace-test.js +++ b/js/src/trace-test.js @@ -4774,6 +4774,23 @@ function testDenseArrayProp() testDenseArrayProp.expected = "ok"; test(testDenseArrayProp); +function testNewWithNonNativeProto() +{ + function f() { } + var a = f.prototype = []; + for (var i = 0; i < 5; i++) + var o = new f(); + return Object.getPrototypeOf(o) === a && o.splice === Array.prototype.splice; +} +testNewWithNonNativeProto.expected = true; +testNewWithNonNativeProto.jitstats = { + recorderStarted: 1, + recorderAborted: 0, + sideExitIntoInterpreter: 1 +}; +test(testNewWithNonNativeProto); + + /***************************************************************************** * * * _____ _ _ _____ ______ _____ _______ * From 1d29fe03f449fe893502a3a7d577319a015dd15a Mon Sep 17 00:00:00 2001 From: Blake Kaplan Date: Tue, 31 Mar 2009 18:38:28 -0700 Subject: [PATCH 06/11] printf warning police --- js/src/jstracer.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/js/src/jstracer.cpp b/js/src/jstracer.cpp index c6f0aa7933e0..08c89cc815de 100644 --- a/js/src/jstracer.cpp +++ b/js/src/jstracer.cpp @@ -3038,7 +3038,8 @@ js_CheckGlobalObjectShape(JSContext* cx, JSTraceMonitor* tm, JSObject* globalObj if (globalObj != root->globalObj || globalShape != root->globalShape) { AUDIT(globalShapeMismatchAtEntry); debug_only_v(printf("Global object/shape mismatch (%p/%u vs. %p/%u), flushing cache.\n", - globalObj, globalShape, root->globalObj, root->globalShape);) + (void*)globalObj, globalShape, (void*)root->globalObj, + root->globalShape);) return false; } if (shape) From db4fc5fa680007173d58c8489eeabe4c104e6086 Mon Sep 17 00:00:00 2001 From: Graydon Hoare Date: Tue, 31 Mar 2009 19:34:32 -0700 Subject: [PATCH 07/11] Bug 484751 - Followup patch to fix crash in initial checkin, r=mrbkap. --- js/src/jsobj.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index bb34c9d36113..703c351f340a 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -2037,7 +2037,6 @@ CreateMapForObject(JSContext* cx, JSObject* obj, JSObject* proto, JSObjectOps* o { /* Share the given prototype's map. */ obj->map = js_HoldObjectMap(cx, map); - obj->dslots = NULL; return true; } @@ -2076,6 +2075,7 @@ NewNativeObject(JSContext* cx, JSObject* proto, JSObject *parent) if (!CreateMapForObject(cx, obj, proto, &js_ObjectOps)) return NULL; + obj->dslots = NULL; return obj; } From 4ef0a7a1ec63b74b040960fc260d8151547a4fcb Mon Sep 17 00:00:00 2001 From: Graydon Hoare Date: Tue, 31 Mar 2009 17:55:43 -0700 Subject: [PATCH 08/11] Bug 479553 - Property tree forking heuristic improvement, r=brendan. --- js/src/jsscope.cpp | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/js/src/jsscope.cpp b/js/src/jsscope.cpp index b269983962fc..92ff873ae77f 100644 --- a/js/src/jsscope.cpp +++ b/js/src/jsscope.cpp @@ -1129,15 +1129,30 @@ js_AddScopeProperty(JSContext *cx, JSScope *scope, jsid id, JS_ASSERT(scope->table); CHECK_ANCESTOR_LINE(scope, JS_TRUE); - JSBool conflicts = JS_FALSE; + /* + * Our forking heuristic tries to balance the desire to avoid + * over-compacting (over-forking) against the desire to + * *periodically* fork anyways, in order to prevent paying scan + * penalties on each insert indefinitely, on a lineage with only + * a few old middle-deletions. So we fork if either: + * + * - A quick scan finds a true conflict. + * - We are passing through a doubling-threshold in size and + * have accumulated a nonzero count of uncompacted deletions. + */ + + bool conflicts = false; + uint32 count = 0; + uint32 threshold = JS_BIT(JS_CeilingLog2(scope->entryCount)); for (sprop = SCOPE_LAST_PROP(scope); sprop; sprop = sprop->parent) { + ++count; if (sprop->id == id) { - conflicts = JS_TRUE; + conflicts = true; break; } } - if (conflicts) { + if (conflicts || count > threshold) { /* * Enumerate live entries in scope->table using a temporary * vector, by walking the (possibly sparse, due to deletions) From 750ab370ba52aa1fbeacc19c3663103132c88c24 Mon Sep 17 00:00:00 2001 From: Graydon Hoare Date: Tue, 31 Mar 2009 20:51:01 -0700 Subject: [PATCH 09/11] Bug 474529 - Avoid artificial OOM conditions, r=gal. --- js/src/jsregexp.cpp | 6 +++- js/src/jstracer.cpp | 59 ++++++++++++++++++++++++++++++++---- js/src/jstracer.h | 3 ++ js/src/nanojit/Fragmento.cpp | 2 +- 4 files changed, 62 insertions(+), 8 deletions(-) diff --git a/js/src/jsregexp.cpp b/js/src/jsregexp.cpp index fcae5a976b1f..eaba283af5f6 100644 --- a/js/src/jsregexp.cpp +++ b/js/src/jsregexp.cpp @@ -71,6 +71,9 @@ #include "jstracer.h" using namespace avmplus; using namespace nanojit; + +/* Amount of memory in the RE fragmento before flushing. */ +#define MAX_MEM_IN_RE_FRAGMENTO (1 << 20) #endif typedef enum REOp { @@ -2438,7 +2441,8 @@ class RegExpNativeCompiler { #endif return JS_TRUE; fail: - if (lirbuf->outOMem() || oom) { + if (lirbuf->outOMem() || oom || + js_OverfullFragmento(fragmento, MAX_MEM_IN_RE_FRAGMENTO)) { fragmento->clearFrags(); lirbuf->rewind(); } else { diff --git a/js/src/jstracer.cpp b/js/src/jstracer.cpp index 08c89cc815de..70aea8cb3cc4 100644 --- a/js/src/jstracer.cpp +++ b/js/src/jstracer.cpp @@ -132,6 +132,9 @@ static const char tagChar[] = "OIDISIBI"; (MAX_NATIVE_STACK_SLOTS * sizeof(jsval) + \ MAX_CALL_STACK_ENTRIES * sizeof(JSInlineFrame)) +/* Amount of memory in the main fragmento before flushing. */ +#define MAX_MEM_IN_MAIN_FRAGMENTO (1 << 24) + /* Max number of branches per tree. */ #define MAX_BRANCHES 32 @@ -3009,7 +3012,8 @@ js_DeleteRecorder(JSContext* cx) /* * If we ran out of memory, flush the code cache. */ - if (JS_TRACE_MONITOR(cx).fragmento->assm()->error() == OutOMem) { + if (JS_TRACE_MONITOR(cx).fragmento->assm()->error() == OutOMem + || js_OverfullFragmento(tm->fragmento, MAX_MEM_IN_MAIN_FRAGMENTO)) { js_FlushJITCache(cx); return false; } @@ -3331,7 +3335,8 @@ js_RecordTree(JSContext* cx, JSTraceMonitor* tm, Fragment* f, jsbytecode* outer, f->root = f; f->lirbuf = tm->lirbuf; - if (f->lirbuf->outOMem()) { + if (f->lirbuf->outOMem() || + js_OverfullFragmento(tm->fragmento, MAX_MEM_IN_MAIN_FRAGMENTO)) { js_FlushJITCache(cx); debug_only_v(printf("Out of memory recording new tree, flushing cache.\n");) return false; @@ -4356,7 +4361,9 @@ TraceRecorder::monitorRecording(JSContext* cx, TraceRecorder* tr, JSOp op) return JSMRS_STOP; } - if (tr->lirbuf->outOMem()) { + if (tr->lirbuf->outOMem() || + js_OverfullFragmento(JS_TRACE_MONITOR(cx).fragmento, + MAX_MEM_IN_MAIN_FRAGMENTO)) { js_AbortRecording(cx, "no more LIR memory"); js_FlushJITCache(cx); return JSMRS_STOP; @@ -4608,7 +4615,7 @@ js_InitJIT(JSTraceMonitor *tm) if (!tm->fragmento) { JS_ASSERT(!tm->reservedDoublePool); - Fragmento* fragmento = new (&gc) Fragmento(core, 24); + Fragmento* fragmento = new (&gc) Fragmento(core, 32); verbose_only(fragmento->labels = new (&gc) LabelMap(core, NULL);) tm->fragmento = fragmento; tm->lirbuf = new (&gc) LirBuffer(fragmento, NULL); @@ -4624,7 +4631,7 @@ js_InitJIT(JSTraceMonitor *tm) memset(tm->vmfragments, 0, sizeof(tm->vmfragments)); } if (!tm->reFragmento) { - Fragmento* fragmento = new (&gc) Fragmento(core, 20); + Fragmento* fragmento = new (&gc) Fragmento(core, 32); verbose_only(fragmento->labels = new (&gc) LabelMap(core, NULL);) tm->reFragmento = fragmento; tm->reLirBuf = new (&gc) LirBuffer(fragmento, NULL); @@ -4739,6 +4746,46 @@ js_PurgeScriptFragments(JSContext* cx, JSScript* script) } } +bool +js_OverfullFragmento(Fragmento *frago, size_t maxsz) +{ + /* + * You might imagine the outOMem flag on the lirbuf is sufficient + * to model the notion of "running out of memory", but there are actually + * two separate issues involved: + * + * 1. The process truly running out of memory: malloc() or mmap() + * failed. + * + * 2. The limit we put on the "intended size" of the tracemonkey code + * cache, in pages, has been exceeded. + * + * Condition 1 doesn't happen very often, but we're obliged to try to + * safely shut down and signal the rest of spidermonkey when it + * does. Condition 2 happens quite regularly. + * + * Presently, the code in this file doesn't check the outOMem condition + * often enough, and frequently misuses the unchecked results of + * lirbuffer insertions on the asssumption that it will notice the + * outOMem flag "soon enough" when it returns to the monitorRecording + * function. This turns out to be a false assumption if we use outOMem + * to signal condition 2: we regularly provoke "passing our intended + * size" and regularly fail to notice it in time to prevent writing + * over the end of an artificially self-limited LIR buffer. + * + * To mitigate, though not completely solve, this problem, we're + * modeling the two forms of memory exhaustion *separately* for the + * time being: condition 1 is handled by the outOMem flag inside + * nanojit, and condition 2 is being handled independently *here*. So + * we construct our fragmentos to use all available memory they like, + * and only report outOMem to us when there is literally no OS memory + * left. Merely purging our cache when we hit our highwater mark is + * handled by the (few) callers of this function. + * + */ + return (frago->_stats.pages > (maxsz >> NJ_LOG2_PAGE_SIZE)); +} + JS_REQUIRES_STACK void js_FlushJITCache(JSContext* cx) { @@ -6695,7 +6742,7 @@ TraceRecorder::newArray(JSObject *ctor, uint32 argc, jsval *argv, jsval *rval) // arr->dslots[i] = box_jsval(vp[i]); for i in 0..argc LIns *dslots_ins = NULL; - for (uint32 i = 0; i < argc; i++) { + for (uint32 i = 0; i < argc && !lirbuf->outOMem(); i++) { LIns *elt_ins = get(argv + i); box_jsval(argv[i], elt_ins); stobj_set_dslot(arr_ins, i, dslots_ins, elt_ins, "set_array_elt"); diff --git a/js/src/jstracer.h b/js/src/jstracer.h index f313af515354..5393bd3dfb05 100644 --- a/js/src/jstracer.h +++ b/js/src/jstracer.h @@ -636,6 +636,9 @@ js_FinishJIT(JSTraceMonitor *tm); extern void js_PurgeScriptFragments(JSContext* cx, JSScript* script); +extern bool +js_OverfullFragmento(nanojit::Fragmento *frago, size_t maxsz); + extern void js_FlushJITCache(JSContext* cx); diff --git a/js/src/nanojit/Fragmento.cpp b/js/src/nanojit/Fragmento.cpp index cb10713bbc01..32170cb6b461 100644 --- a/js/src/nanojit/Fragmento.cpp +++ b/js/src/nanojit/Fragmento.cpp @@ -50,7 +50,7 @@ namespace nanojit static uint32_t calcSaneCacheSize(uint32_t in) { if (in < uint32_t(NJ_LOG2_PAGE_SIZE)) return NJ_LOG2_PAGE_SIZE; // at least 1 page - if (in > 30) return 30; // 1GB should be enough for anyone + if (in > 32) return 32; // 4GB should be enough for anyone return in; } From ab05dfaaab737641732665dd7260a7f527d63b35 Mon Sep 17 00:00:00 2001 From: Igor Bukanov Date: Wed, 1 Apr 2009 10:33:43 +0200 Subject: [PATCH 10/11] bug 486124 - removal of unused TCF_HAS_DEFXMLNS. r=mrbkap --- js/src/jsemit.h | 7 +++---- js/src/jsparse.cpp | 5 ++--- js/src/jsxml.cpp | 1 - 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/js/src/jsemit.h b/js/src/jsemit.h index 9b7cafeb2bfe..db25abff75bb 100644 --- a/js/src/jsemit.h +++ b/js/src/jsemit.h @@ -191,10 +191,9 @@ struct JSTreeContext { /* tree context for semantic checks */ #define TCF_FUN_USES_NONLOCALS 0x20 /* function refers to non-local names */ #define TCF_FUN_HEAVYWEIGHT 0x40 /* function needs Call object per call */ #define TCF_FUN_IS_GENERATOR 0x80 /* parsed yield statement in function */ -#define TCF_HAS_DEFXMLNS 0x100 /* default xml namespace = ...; parsed */ -#define TCF_HAS_FUNCTION_STMT 0x200 /* block contains a function statement */ -#define TCF_GENEXP_LAMBDA 0x400 /* flag lambda from generator expression */ -#define TCF_COMPILE_N_GO 0x800 /* compiler-and-go mode of script, can +#define TCF_HAS_FUNCTION_STMT 0x100 /* block contains a function statement */ +#define TCF_GENEXP_LAMBDA 0x200 /* flag lambda from generator expression */ +#define TCF_COMPILE_N_GO 0x400 /* compiler-and-go mode of script, can optimize name references based on scope chain */ /* diff --git a/js/src/jsparse.cpp b/js/src/jsparse.cpp index e2801b757ced..b669ecf405f6 100644 --- a/js/src/jsparse.cpp +++ b/js/src/jsparse.cpp @@ -906,7 +906,7 @@ FunctionBody(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) } } - tc->flags = oldflags | (tc->flags & (TCF_FUN_FLAGS | TCF_HAS_DEFXMLNS)); + tc->flags = oldflags | (tc->flags & TCF_FUN_FLAGS); return pn; } @@ -1453,7 +1453,7 @@ FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, pn->pn_funpob = funpob; pn->pn_op = op; pn->pn_body = body; - pn->pn_flags = funtc.flags & (TCF_FUN_FLAGS | TCF_HAS_DEFXMLNS | TCF_COMPILE_N_GO); + pn->pn_flags = funtc.flags & (TCF_FUN_FLAGS | TCF_COMPILE_N_GO); TREE_CONTEXT_FINISH(cx, &funtc); return result; } @@ -3505,7 +3505,6 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) pn->pn_op = JSOP_DEFXMLNS; pn->pn_pos.end = pn2->pn_pos.end; pn->pn_kid = pn2; - tc->flags |= TCF_HAS_DEFXMLNS; break; #endif diff --git a/js/src/jsxml.cpp b/js/src/jsxml.cpp index 9676dcef6f13..adbe6cdd38dd 100644 --- a/js/src/jsxml.cpp +++ b/js/src/jsxml.cpp @@ -82,7 +82,6 @@ * - XXXbe patrol * - Fuse objects and their JSXML* private data into single GC-things * - fix function::foo vs. x.(foo == 42) collision using proper namespacing - * - fix the !TCF_HAS_DEFXMLNS optimization in js_FoldConstants * - JSCLASS_DOCUMENT_OBSERVER support -- live two-way binding to Gecko's DOM! * - JS_TypeOfValue sure could use a cleaner interface to "types" */ From 9752bd3059e6e6998b92619e8790cdc1de6d77ca Mon Sep 17 00:00:00 2001 From: Igor Bukanov Date: Wed, 1 Apr 2009 14:32:51 +0200 Subject: [PATCH 11/11] bug 484861 - removal of unsed fields from JSObjectOps. r=mrbkap --- js/src/jsarray.cpp | 7 +++---- js/src/jsobj.cpp | 14 ++++++-------- js/src/jsobj.h | 3 --- js/src/jsprvtd.h | 9 --------- js/src/jsxml.cpp | 7 +++---- js/src/liveconnect/jsj_JavaArray.c | 5 +---- js/src/liveconnect/jsj_JavaClass.c | 5 +---- js/src/liveconnect/jsj_JavaObject.c | 5 +---- 8 files changed, 15 insertions(+), 40 deletions(-) diff --git a/js/src/jsarray.cpp b/js/src/jsarray.cpp index 5afa3b1f8cd2..9c9cdfb2194d 100644 --- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -1222,10 +1222,9 @@ JSObjectOps js_ArrayObjectOps = { array_enumerate, js_CheckAccess, NULL, array_dropProperty, NULL, NULL, - NULL, js_HasInstance, - js_SetProtoOrParent, js_SetProtoOrParent, - array_trace, NULL, - NULL, NULL + js_HasInstance, array_trace, + NULL, NULL, + NULL }; static JSObjectOps * diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index 703c351f340a..3e17d500e58d 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -110,10 +110,9 @@ JS_FRIEND_DATA(JSObjectOps) js_ObjectOps = { js_Enumerate, js_CheckAccess, NULL, NATIVE_DROP_PROPERTY, js_Call, js_Construct, - NULL, js_HasInstance, - js_SetProtoOrParent, js_SetProtoOrParent, - js_TraceObject, js_Clear, - js_GetRequiredSlot, js_SetRequiredSlot + js_HasInstance, js_TraceObject, + js_Clear, js_GetRequiredSlot, + js_SetRequiredSlot }; JSClass js_ObjectClass = { @@ -2353,10 +2352,9 @@ JS_FRIEND_DATA(JSObjectOps) js_WithObjectOps = { with_Enumerate, with_CheckAccess, with_ThisObject, NATIVE_DROP_PROPERTY, NULL, NULL, - NULL, NULL, - js_SetProtoOrParent, js_SetProtoOrParent, - js_TraceObject, js_Clear, - NULL, NULL + NULL, js_TraceObject, + js_Clear, NULL, + NULL }; static JSObjectOps * diff --git a/js/src/jsobj.h b/js/src/jsobj.h index e1eb0178e967..5f868d9499cf 100644 --- a/js/src/jsobj.h +++ b/js/src/jsobj.h @@ -75,10 +75,7 @@ struct JSObjectOps { JSPropertyRefOp dropProperty; JSNative call; JSNative construct; - JSXDRObjectOp xdrObject; JSHasInstanceOp hasInstance; - JSSetObjectSlotOp setProto; - JSSetObjectSlotOp setParent; JSTraceOp trace; JSFinalizeOp clear; JSGetRequiredSlotOp getRequiredSlot; diff --git a/js/src/jsprvtd.h b/js/src/jsprvtd.h index 651be0957045..0ce5ce8869f3 100644 --- a/js/src/jsprvtd.h +++ b/js/src/jsprvtd.h @@ -356,15 +356,6 @@ typedef JSBool typedef void (* JSPropertyRefOp)(JSContext *cx, JSObject *obj, JSProperty *prop); -/* - * Function pointer type for JSObjectOps.setProto and JSObjectOps.setParent. - * These hooks must check for cycles without deadlocking, and otherwise take - * special steps. See jsobj.c and jsgc.c for details. - */ -typedef JSBool -(* JSSetObjectSlotOp)(JSContext *cx, JSObject *obj, uint32 slot, - JSObject *pobj); - /* * Get and set a required slot, one that should already have been allocated. * These operations are infallible, so required slots must be pre-allocated, diff --git a/js/src/jsxml.cpp b/js/src/jsxml.cpp index adbe6cdd38dd..4aa801ca190b 100644 --- a/js/src/jsxml.cpp +++ b/js/src/jsxml.cpp @@ -5438,10 +5438,9 @@ JS_FRIEND_DATA(JSObjectOps) js_XMLObjectOps = { xml_enumerate, js_CheckAccess, NULL, NULL, NULL, NULL, - NULL, xml_hasInstance, - js_SetProtoOrParent, js_SetProtoOrParent, - js_TraceObject, xml_clear, - NULL, NULL + xml_hasInstance, js_TraceObject, + xml_clear, NULL, + NULL }; static JSObjectOps * diff --git a/js/src/liveconnect/jsj_JavaArray.c b/js/src/liveconnect/jsj_JavaArray.c index 410e4ea2ebbf..b235cb151360 100644 --- a/js/src/liveconnect/jsj_JavaArray.c +++ b/js/src/liveconnect/jsj_JavaArray.c @@ -424,11 +424,8 @@ JSObjectOps JavaArray_ops = { NULL, /* dropProperty */ NULL, /* call */ NULL, /* construct */ - NULL, /* xdrObject */ NULL, /* hasInstance */ - NULL, /* setProto */ - NULL, /* setParent */ - NULL, /* mark */ + NULL, /* trace */ NULL, /* clear */ jsj_wrapper_getRequiredSlot, /* getRequiredSlot */ jsj_wrapper_setRequiredSlot /* setRequiredSlot */ diff --git a/js/src/liveconnect/jsj_JavaClass.c b/js/src/liveconnect/jsj_JavaClass.c index 4dd201fdd165..2fe80c49476a 100644 --- a/js/src/liveconnect/jsj_JavaClass.c +++ b/js/src/liveconnect/jsj_JavaClass.c @@ -549,11 +549,8 @@ JSObjectOps JavaClass_ops = { NULL, /* dropProperty */ jsj_JavaConstructorWrapper, /* call */ jsj_JavaConstructorWrapper, /* construct */ - NULL, /* xdrObject */ JavaClass_hasInstance, /* hasInstance */ - NULL, /* setProto */ - NULL, /* setParent */ - NULL, /* mark */ + NULL, /* trace */ NULL, /* clear */ jsj_wrapper_getRequiredSlot, /* getRequiredSlot */ jsj_wrapper_setRequiredSlot /* setRequiredSlot */ diff --git a/js/src/liveconnect/jsj_JavaObject.c b/js/src/liveconnect/jsj_JavaObject.c index c062c99336e8..ffa9bee15495 100644 --- a/js/src/liveconnect/jsj_JavaObject.c +++ b/js/src/liveconnect/jsj_JavaObject.c @@ -1057,11 +1057,8 @@ JSObjectOps JavaObject_ops = { NULL, /* dropProperty */ NULL, /* call */ NULL, /* construct */ - NULL, /* xdrObject */ NULL, /* hasInstance */ - NULL, /* setProto */ - NULL, /* setParent */ - NULL, /* mark */ + NULL, /* trace */ NULL, /* clear */ jsj_wrapper_getRequiredSlot, /* getRequiredSlot */ jsj_wrapper_setRequiredSlot /* setRequiredSlot */