зеркало из https://github.com/mozilla/gecko-dev.git
Merge tracemonkey to mozilla-central.
This commit is contained in:
Коммит
14165ff453
|
@ -3237,6 +3237,8 @@ LookupResult(JSContext *cx, JSObject *obj, JSObject *obj2, JSProperty *prop)
|
||||||
rval = SPROP_HAS_VALID_SLOT(sprop, OBJ_SCOPE(obj2))
|
rval = SPROP_HAS_VALID_SLOT(sprop, OBJ_SCOPE(obj2))
|
||||||
? LOCKED_OBJ_GET_SLOT(obj2, sprop->slot)
|
? LOCKED_OBJ_GET_SLOT(obj2, sprop->slot)
|
||||||
: JSVAL_TRUE;
|
: JSVAL_TRUE;
|
||||||
|
} else if (OBJ_IS_DENSE_ARRAY(cx, obj2)) {
|
||||||
|
rval = js_GetDenseArrayElementValue(obj2, prop);
|
||||||
} else {
|
} else {
|
||||||
/* XXX bad API: no way to return "defined but value unknown" */
|
/* XXX bad API: no way to return "defined but value unknown" */
|
||||||
rval = JSVAL_TRUE;
|
rval = JSVAL_TRUE;
|
||||||
|
|
|
@ -1399,51 +1399,6 @@ struct JSExtendedClass {
|
||||||
#define JSCLASS_NO_OPTIONAL_MEMBERS 0,0,0,0,0,0,0,0
|
#define JSCLASS_NO_OPTIONAL_MEMBERS 0,0,0,0,0,0,0,0
|
||||||
#define JSCLASS_NO_RESERVED_MEMBERS 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 {
|
struct JSIdArray {
|
||||||
jsint length;
|
jsint length;
|
||||||
jsid vector[1]; /* actually, length jsid words */
|
jsid vector[1]; /* actually, length jsid words */
|
||||||
|
|
|
@ -739,6 +739,23 @@ array_dropProperty(JSContext *cx, JSObject *obj, JSProperty *prop)
|
||||||
#endif
|
#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
|
static JSBool
|
||||||
array_getProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
|
array_getProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
|
||||||
{
|
{
|
||||||
|
@ -1205,10 +1222,9 @@ JSObjectOps js_ArrayObjectOps = {
|
||||||
array_enumerate, js_CheckAccess,
|
array_enumerate, js_CheckAccess,
|
||||||
NULL, array_dropProperty,
|
NULL, array_dropProperty,
|
||||||
NULL, NULL,
|
NULL, NULL,
|
||||||
NULL, js_HasInstance,
|
js_HasInstance, array_trace,
|
||||||
js_SetProtoOrParent, js_SetProtoOrParent,
|
NULL, NULL,
|
||||||
array_trace, NULL,
|
NULL
|
||||||
NULL, NULL
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static JSObjectOps *
|
static JSObjectOps *
|
||||||
|
|
|
@ -223,6 +223,12 @@ js_ArrayToJSDoubleBuffer(JSContext *cx, JSObject *obj, jsuint offset, jsuint cou
|
||||||
JSBool
|
JSBool
|
||||||
js_PrototypeHasIndexedProperties(JSContext *cx, JSObject *obj);
|
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
|
JS_END_EXTERN_C
|
||||||
|
|
||||||
#endif /* jsarray_h___ */
|
#endif /* jsarray_h___ */
|
||||||
|
|
|
@ -111,6 +111,7 @@ struct VMFragment;
|
||||||
|
|
||||||
#define MONITOR_N_GLOBAL_STATES 4
|
#define MONITOR_N_GLOBAL_STATES 4
|
||||||
struct GlobalState {
|
struct GlobalState {
|
||||||
|
JSObject* globalObj;
|
||||||
uint32 globalShape;
|
uint32 globalShape;
|
||||||
CLS(SlotList) globalSlots;
|
CLS(SlotList) globalSlots;
|
||||||
};
|
};
|
||||||
|
|
|
@ -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_USES_NONLOCALS 0x20 /* function refers to non-local names */
|
||||||
#define TCF_FUN_HEAVYWEIGHT 0x40 /* function needs Call object per call */
|
#define TCF_FUN_HEAVYWEIGHT 0x40 /* function needs Call object per call */
|
||||||
#define TCF_FUN_IS_GENERATOR 0x80 /* parsed yield statement in function */
|
#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 0x100 /* block contains a function statement */
|
||||||
#define TCF_HAS_FUNCTION_STMT 0x200 /* block contains a function statement */
|
#define TCF_GENEXP_LAMBDA 0x200 /* flag lambda from generator expression */
|
||||||
#define TCF_GENEXP_LAMBDA 0x400 /* flag lambda from generator expression */
|
#define TCF_COMPILE_N_GO 0x400 /* compiler-and-go mode of script, can
|
||||||
#define TCF_COMPILE_N_GO 0x800 /* compiler-and-go mode of script, can
|
|
||||||
optimize name references based on scope
|
optimize name references based on scope
|
||||||
chain */
|
chain */
|
||||||
/*
|
/*
|
||||||
|
|
105
js/src/jsobj.cpp
105
js/src/jsobj.cpp
|
@ -110,10 +110,9 @@ JS_FRIEND_DATA(JSObjectOps) js_ObjectOps = {
|
||||||
js_Enumerate, js_CheckAccess,
|
js_Enumerate, js_CheckAccess,
|
||||||
NULL, NATIVE_DROP_PROPERTY,
|
NULL, NATIVE_DROP_PROPERTY,
|
||||||
js_Call, js_Construct,
|
js_Call, js_Construct,
|
||||||
NULL, js_HasInstance,
|
js_HasInstance, js_TraceObject,
|
||||||
js_SetProtoOrParent, js_SetProtoOrParent,
|
js_Clear, js_GetRequiredSlot,
|
||||||
js_TraceObject, js_Clear,
|
js_SetRequiredSlot
|
||||||
js_GetRequiredSlot, js_SetRequiredSlot
|
|
||||||
};
|
};
|
||||||
|
|
||||||
JSClass js_ObjectClass = {
|
JSClass js_ObjectClass = {
|
||||||
|
@ -2012,6 +2011,51 @@ js_Object(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
||||||
return JS_TRUE;
|
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);
|
||||||
|
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
|
#ifdef JS_TRACER
|
||||||
|
|
||||||
static inline JSObject*
|
static inline JSObject*
|
||||||
|
@ -2028,10 +2072,10 @@ NewNativeObject(JSContext* cx, JSObject* proto, JSObject *parent)
|
||||||
for (unsigned i = JSSLOT_PRIVATE; i < JS_INITIAL_NSLOTS; ++i)
|
for (unsigned i = JSSLOT_PRIVATE; i < JS_INITIAL_NSLOTS; ++i)
|
||||||
obj->fslots[i] = JSVAL_VOID;
|
obj->fslots[i] = JSVAL_VOID;
|
||||||
|
|
||||||
JS_ASSERT(!OBJ_GET_CLASS(cx, proto)->getObjectOps);
|
if (!CreateMapForObject(cx, obj, proto, &js_ObjectOps))
|
||||||
JS_ASSERT(proto->map->ops == &js_ObjectOps);
|
return NULL;
|
||||||
obj->map = js_HoldObjectMap(cx, proto->map);
|
|
||||||
obj->dslots = NULL;
|
obj->dslots = NULL;
|
||||||
|
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2308,10 +2352,9 @@ JS_FRIEND_DATA(JSObjectOps) js_WithObjectOps = {
|
||||||
with_Enumerate, with_CheckAccess,
|
with_Enumerate, with_CheckAccess,
|
||||||
with_ThisObject, NATIVE_DROP_PROPERTY,
|
with_ThisObject, NATIVE_DROP_PROPERTY,
|
||||||
NULL, NULL,
|
NULL, NULL,
|
||||||
NULL, NULL,
|
NULL, js_TraceObject,
|
||||||
js_SetProtoOrParent, js_SetProtoOrParent,
|
js_Clear, NULL,
|
||||||
js_TraceObject, js_Clear,
|
NULL
|
||||||
NULL, NULL
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static JSObjectOps *
|
static JSObjectOps *
|
||||||
|
@ -3051,9 +3094,7 @@ js_NewObjectWithGivenProto(JSContext *cx, JSClass *clasp, JSObject *proto,
|
||||||
{
|
{
|
||||||
JSObject *obj;
|
JSObject *obj;
|
||||||
JSObjectOps *ops;
|
JSObjectOps *ops;
|
||||||
JSObjectMap *map;
|
uint32 i;
|
||||||
JSClass *protoclasp;
|
|
||||||
uint32 nslots, i;
|
|
||||||
JSTempValueRooter tvr;
|
JSTempValueRooter tvr;
|
||||||
|
|
||||||
#ifdef INCLUDE_MOZILLA_DTRACE
|
#ifdef INCLUDE_MOZILLA_DTRACE
|
||||||
|
@ -3128,40 +3169,8 @@ js_NewObjectWithGivenProto(JSContext *cx, JSClass *clasp, JSObject *proto,
|
||||||
if (proto && !parent)
|
if (proto && !parent)
|
||||||
STOBJ_SET_PARENT(obj, OBJ_GET_PARENT(cx, proto));
|
STOBJ_SET_PARENT(obj, OBJ_GET_PARENT(cx, proto));
|
||||||
|
|
||||||
/*
|
if (!CreateMapForObject(cx, obj, proto, ops))
|
||||||
* Share proto's map only if it has the same JSObjectOps, and only if
|
goto bad;
|
||||||
* 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Do not call debug hooks on trace, because we might be in a non-_FAIL
|
* Do not call debug hooks on trace, because we might be in a non-_FAIL
|
||||||
|
|
|
@ -54,6 +54,48 @@
|
||||||
|
|
||||||
JS_BEGIN_EXTERN_C
|
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;
|
||||||
|
JSHasInstanceOp hasInstance;
|
||||||
|
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 {
|
struct JSObjectMap {
|
||||||
jsrefcount nrefs; /* count of all referencing objects */
|
jsrefcount nrefs; /* count of all referencing objects */
|
||||||
JSObjectOps *ops; /* high level object operation vtable */
|
JSObjectOps *ops; /* high level object operation vtable */
|
||||||
|
|
|
@ -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;
|
return pn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1453,7 +1453,7 @@ FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
|
||||||
pn->pn_funpob = funpob;
|
pn->pn_funpob = funpob;
|
||||||
pn->pn_op = op;
|
pn->pn_op = op;
|
||||||
pn->pn_body = body;
|
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);
|
TREE_CONTEXT_FINISH(cx, &funtc);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -3505,7 +3505,6 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
||||||
pn->pn_op = JSOP_DEFXMLNS;
|
pn->pn_op = JSOP_DEFXMLNS;
|
||||||
pn->pn_pos.end = pn2->pn_pos.end;
|
pn->pn_pos.end = pn2->pn_pos.end;
|
||||||
pn->pn_kid = pn2;
|
pn->pn_kid = pn2;
|
||||||
tc->flags |= TCF_HAS_DEFXMLNS;
|
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
122
js/src/jsprvtd.h
122
js/src/jsprvtd.h
|
@ -253,6 +253,128 @@ struct JSTempValueRooter {
|
||||||
JSTempValueUnion u;
|
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);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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
|
* The following determines whether JS_EncodeCharacters and JS_DecodeBytes
|
||||||
* treat char[] as utf-8 or simply as bytes that need to be inflated/deflated.
|
* treat char[] as utf-8 or simply as bytes that need to be inflated/deflated.
|
||||||
|
|
146
js/src/jspubtd.h
146
js/src/jspubtd.h
|
@ -414,99 +414,10 @@ typedef void
|
||||||
typedef uint32
|
typedef uint32
|
||||||
(* JSReserveSlotsOp)(JSContext *cx, JSObject *obj);
|
(* 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
|
typedef JSBool
|
||||||
(* JSLookupPropOp)(JSContext *cx, JSObject *obj, jsid id, JSObject **objp,
|
(* JSEqualityOp)(JSContext *cx, JSObject *obj, jsval v, JSBool *bp);
|
||||||
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 mapping an object to another object, or null
|
* A generic type for functions mapping an object to another object, or null
|
||||||
|
@ -523,59 +434,6 @@ typedef JSObject *
|
||||||
typedef JSObject *
|
typedef JSObject *
|
||||||
(* JSIteratorOp)(JSContext *cx, JSObject *obj, JSBool keysonly);
|
(* 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 for native functions called by the JS VM. */
|
||||||
|
|
||||||
typedef JSBool
|
typedef JSBool
|
||||||
|
|
|
@ -71,6 +71,9 @@
|
||||||
#include "jstracer.h"
|
#include "jstracer.h"
|
||||||
using namespace avmplus;
|
using namespace avmplus;
|
||||||
using namespace nanojit;
|
using namespace nanojit;
|
||||||
|
|
||||||
|
/* Amount of memory in the RE fragmento before flushing. */
|
||||||
|
#define MAX_MEM_IN_RE_FRAGMENTO (1 << 20)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef enum REOp {
|
typedef enum REOp {
|
||||||
|
@ -2438,7 +2441,8 @@ class RegExpNativeCompiler {
|
||||||
#endif
|
#endif
|
||||||
return JS_TRUE;
|
return JS_TRUE;
|
||||||
fail:
|
fail:
|
||||||
if (lirbuf->outOMem() || oom) {
|
if (lirbuf->outOMem() || oom ||
|
||||||
|
js_OverfullFragmento(fragmento, MAX_MEM_IN_RE_FRAGMENTO)) {
|
||||||
fragmento->clearFrags();
|
fragmento->clearFrags();
|
||||||
lirbuf->rewind();
|
lirbuf->rewind();
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -1129,15 +1129,30 @@ js_AddScopeProperty(JSContext *cx, JSScope *scope, jsid id,
|
||||||
JS_ASSERT(scope->table);
|
JS_ASSERT(scope->table);
|
||||||
CHECK_ANCESTOR_LINE(scope, JS_TRUE);
|
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) {
|
for (sprop = SCOPE_LAST_PROP(scope); sprop; sprop = sprop->parent) {
|
||||||
|
++count;
|
||||||
if (sprop->id == id) {
|
if (sprop->id == id) {
|
||||||
conflicts = JS_TRUE;
|
conflicts = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (conflicts) {
|
if (conflicts || count > threshold) {
|
||||||
/*
|
/*
|
||||||
* Enumerate live entries in scope->table using a temporary
|
* Enumerate live entries in scope->table using a temporary
|
||||||
* vector, by walking the (possibly sparse, due to deletions)
|
* vector, by walking the (possibly sparse, due to deletions)
|
||||||
|
|
|
@ -132,6 +132,9 @@ static const char tagChar[] = "OIDISIBI";
|
||||||
(MAX_NATIVE_STACK_SLOTS * sizeof(jsval) + \
|
(MAX_NATIVE_STACK_SLOTS * sizeof(jsval) + \
|
||||||
MAX_CALL_STACK_ENTRIES * sizeof(JSInlineFrame))
|
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. */
|
/* Max number of branches per tree. */
|
||||||
#define MAX_BRANCHES 32
|
#define MAX_BRANCHES 32
|
||||||
|
|
||||||
|
@ -236,7 +239,7 @@ static avmplus::AvmCore* core = &s_core;
|
||||||
|
|
||||||
#ifdef JS_JIT_SPEW
|
#ifdef JS_JIT_SPEW
|
||||||
void
|
void
|
||||||
js_DumpPeerStability(JSTraceMonitor* tm, const void* ip, uint32 globalShape);
|
js_DumpPeerStability(JSTraceMonitor* tm, const void* ip, JSObject* globalObj, uint32 globalShape);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* We really need a better way to configure the JIT. Shaver, where is my fancy JIT object? */
|
/* We really need a better way to configure the JIT. Shaver, where is my fancy JIT object? */
|
||||||
|
@ -480,51 +483,55 @@ js_Backoff(Fragment* tree, const jsbytecode* where)
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline size_t
|
static inline size_t
|
||||||
fragmentHash(const void *ip, uint32 globalShape)
|
fragmentHash(const void *ip, JSObject* globalObj, uint32 globalShape)
|
||||||
{
|
{
|
||||||
uintptr_t h = HASH_SEED;
|
uintptr_t h = HASH_SEED;
|
||||||
hash_accum(h, uintptr_t(ip), FRAGMENT_TABLE_MASK);
|
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);
|
hash_accum(h, uintptr_t(globalShape), FRAGMENT_TABLE_MASK);
|
||||||
return size_t(h);
|
return size_t(h);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct VMFragment : public Fragment
|
struct VMFragment : public Fragment
|
||||||
{
|
{
|
||||||
VMFragment(const void* _ip, uint32 _globalShape) :
|
VMFragment(const void* _ip, JSObject* _globalObj, uint32 _globalShape) :
|
||||||
Fragment(_ip),
|
Fragment(_ip),
|
||||||
next(NULL),
|
next(NULL),
|
||||||
|
globalObj(_globalObj),
|
||||||
globalShape(_globalShape)
|
globalShape(_globalShape)
|
||||||
{}
|
{}
|
||||||
VMFragment* next;
|
VMFragment* next;
|
||||||
|
JSObject* globalObj;
|
||||||
uint32 globalShape;
|
uint32 globalShape;
|
||||||
};
|
};
|
||||||
|
|
||||||
static VMFragment*
|
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];
|
VMFragment* vf = tm->vmfragments[h];
|
||||||
while (vf &&
|
while (vf &&
|
||||||
! (vf->globalShape == globalShape &&
|
! (vf->globalObj == globalObj &&
|
||||||
|
vf->globalShape == globalShape &&
|
||||||
vf->ip == ip)) {
|
vf->ip == ip)) {
|
||||||
vf = vf->next;
|
vf = vf->next;
|
||||||
}
|
}
|
||||||
return vf;
|
return vf;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Fragment*
|
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*
|
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);
|
JS_ASSERT(f);
|
||||||
|
|
||||||
Fragment *p = getVMFragment(tm, ip, globalShape);
|
Fragment *p = getVMFragment(tm, ip, globalObj, globalShape);
|
||||||
|
|
||||||
if (p) {
|
if (p) {
|
||||||
f->first = p;
|
f->first = p;
|
||||||
|
@ -536,7 +543,7 @@ getAnchor(JSTraceMonitor* tm, const void *ip, uint32 globalShape)
|
||||||
} else {
|
} else {
|
||||||
/* this is the first fragment */
|
/* this is the first fragment */
|
||||||
f->first = f;
|
f->first = f;
|
||||||
size_t h = fragmentHash(ip, globalShape);
|
size_t h = fragmentHash(ip, globalObj, globalShape);
|
||||||
f->next = tm->vmfragments[h];
|
f->next = tm->vmfragments[h];
|
||||||
tm->vmfragments[h] = f;
|
tm->vmfragments[h] = f;
|
||||||
}
|
}
|
||||||
|
@ -558,7 +565,7 @@ js_AttemptCompilation(JSTraceMonitor* tm, JSObject* globalObj, jsbytecode* pc)
|
||||||
/*
|
/*
|
||||||
* Breath new live into all peer fragments at the designated loop header.
|
* 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 (!f) {
|
||||||
/*
|
/*
|
||||||
* If the global object's shape changed, we can't easily find the
|
* If the global object's shape changed, we can't easily find the
|
||||||
|
@ -1260,7 +1267,6 @@ TraceRecorder::TraceRecorder(JSContext* cx, VMSideExit* _anchor, Fragment* _frag
|
||||||
cx_ins = addName(lir->insLoad(LIR_ldp, lirbuf->state, offsetof(InterpState, cx)), "cx");
|
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");
|
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");
|
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 we came from exit, we might not have enough global types. */
|
||||||
if (ti->globalSlots->length() > ti->nGlobalTypes())
|
if (ti->globalSlots->length() > ti->nGlobalTypes())
|
||||||
|
@ -2536,7 +2542,7 @@ TraceRecorder::closeLoop(JSTraceMonitor* tm, bool& demote)
|
||||||
LIns* exitIns;
|
LIns* exitIns;
|
||||||
Fragment* peer;
|
Fragment* peer;
|
||||||
VMSideExit* exit;
|
VMSideExit* exit;
|
||||||
Fragment* peer_root;
|
VMFragment* peer_root;
|
||||||
Fragmento* fragmento = tm->fragmento;
|
Fragmento* fragmento = tm->fragmento;
|
||||||
|
|
||||||
exitIns = snapshot(UNSTABLE_LOOP_EXIT);
|
exitIns = snapshot(UNSTABLE_LOOP_EXIT);
|
||||||
|
@ -2551,7 +2557,8 @@ TraceRecorder::closeLoop(JSTraceMonitor* tm, bool& demote)
|
||||||
|
|
||||||
JS_ASSERT(exit->numStackSlots == treeInfo->nStackTypes);
|
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->globalObj, root->globalShape);
|
||||||
JS_ASSERT(peer_root != NULL);
|
JS_ASSERT(peer_root != NULL);
|
||||||
|
|
||||||
stable = deduceTypeStability(peer_root, &peer, demote);
|
stable = deduceTypeStability(peer_root, &peer, demote);
|
||||||
|
@ -2628,7 +2635,7 @@ TraceRecorder::closeLoop(JSTraceMonitor* tm, bool& demote)
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_REQUIRES_STACK void
|
JS_REQUIRES_STACK void
|
||||||
TraceRecorder::joinEdgesToEntry(Fragmento* fragmento, Fragment* peer_root)
|
TraceRecorder::joinEdgesToEntry(Fragmento* fragmento, VMFragment* peer_root)
|
||||||
{
|
{
|
||||||
if (fragment->kind == LoopTrace) {
|
if (fragment->kind == LoopTrace) {
|
||||||
TreeInfo* ti;
|
TreeInfo* ti;
|
||||||
|
@ -2703,7 +2710,8 @@ 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->globalObj, peer_root->globalShape);)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Emit an always-exit guard and compile the tree (used for break statements. */
|
/* Emit an always-exit guard and compile the tree (used for break statements. */
|
||||||
|
@ -2725,7 +2733,8 @@ TraceRecorder::endLoop(JSTraceMonitor* tm)
|
||||||
if (tm->fragmento->assm()->error() != nanojit::None)
|
if (tm->fragmento->assm()->error() != nanojit::None)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
joinEdgesToEntry(tm->fragmento, getLoop(tm, fragment->root->ip, treeInfo->globalShape));
|
VMFragment* root = (VMFragment*)fragment->root;
|
||||||
|
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
|
/* 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. */
|
propagated those to linked and dependent trees. */
|
||||||
|
@ -3003,7 +3012,8 @@ js_DeleteRecorder(JSContext* cx)
|
||||||
/*
|
/*
|
||||||
* If we ran out of memory, flush the code cache.
|
* 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);
|
js_FlushJITCache(cx);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -3026,12 +3036,14 @@ js_CheckGlobalObjectShape(JSContext* cx, JSTraceMonitor* tm, JSObject* globalObj
|
||||||
uint32 globalShape = OBJ_SHAPE(globalObj);
|
uint32 globalShape = OBJ_SHAPE(globalObj);
|
||||||
|
|
||||||
if (tm->recorder) {
|
if (tm->recorder) {
|
||||||
|
VMFragment* root = (VMFragment*)tm->recorder->getFragment()->root;
|
||||||
TreeInfo* ti = tm->recorder->getTreeInfo();
|
TreeInfo* ti = tm->recorder->getTreeInfo();
|
||||||
/* Check the global shape matches the recorder's treeinfo's shape. */
|
/* Check the global shape matches the recorder's treeinfo's shape. */
|
||||||
if (globalShape != ti->globalShape) {
|
if (globalObj != root->globalObj || globalShape != root->globalShape) {
|
||||||
AUDIT(globalShapeMismatchAtEntry);
|
AUDIT(globalShapeMismatchAtEntry);
|
||||||
debug_only_v(printf("Global shape mismatch (%u vs. %u), flushing cache.\n",
|
debug_only_v(printf("Global object/shape mismatch (%p/%u vs. %p/%u), flushing cache.\n",
|
||||||
globalShape, ti->globalShape);)
|
(void*)globalObj, globalShape, (void*)root->globalObj,
|
||||||
|
root->globalShape);)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (shape)
|
if (shape)
|
||||||
|
@ -3046,12 +3058,13 @@ js_CheckGlobalObjectShape(JSContext* cx, JSTraceMonitor* tm, JSObject* globalObj
|
||||||
GlobalState &state = tm->globalStates[i];
|
GlobalState &state = tm->globalStates[i];
|
||||||
|
|
||||||
if (state.globalShape == (uint32) -1) {
|
if (state.globalShape == (uint32) -1) {
|
||||||
|
state.globalObj = globalObj;
|
||||||
state.globalShape = globalShape;
|
state.globalShape = globalShape;
|
||||||
JS_ASSERT(state.globalSlots);
|
JS_ASSERT(state.globalSlots);
|
||||||
JS_ASSERT(state.globalSlots->length() == 0);
|
JS_ASSERT(state.globalSlots->length() == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tm->globalStates[i].globalShape == globalShape) {
|
if (state.globalObj == globalObj && state.globalShape == globalShape) {
|
||||||
if (shape)
|
if (shape)
|
||||||
*shape = globalShape;
|
*shape = globalShape;
|
||||||
if (slots)
|
if (slots)
|
||||||
|
@ -3296,12 +3309,11 @@ js_SynthesizeFrame(JSContext* cx, const FrameInfo& fi)
|
||||||
|
|
||||||
JS_REQUIRES_STACK bool
|
JS_REQUIRES_STACK bool
|
||||||
js_RecordTree(JSContext* cx, JSTraceMonitor* tm, Fragment* f, jsbytecode* outer,
|
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);
|
JS_ASSERT(f->root == f);
|
||||||
|
|
||||||
/* Make sure the global type map didn't change on us. */
|
/* 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)) {
|
if (!js_CheckGlobalObjectShape(cx, tm, globalObj)) {
|
||||||
js_FlushJITCache(cx);
|
js_FlushJITCache(cx);
|
||||||
return false;
|
return false;
|
||||||
|
@ -3313,7 +3325,7 @@ js_RecordTree(JSContext* cx, JSTraceMonitor* tm, Fragment* f, jsbytecode* outer,
|
||||||
while (f->code() && f->peer)
|
while (f->code() && f->peer)
|
||||||
f = f->peer;
|
f = f->peer;
|
||||||
if (f->code())
|
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) {
|
if (!f) {
|
||||||
js_FlushJITCache(cx);
|
js_FlushJITCache(cx);
|
||||||
|
@ -3323,7 +3335,8 @@ js_RecordTree(JSContext* cx, JSTraceMonitor* tm, Fragment* f, jsbytecode* outer,
|
||||||
f->root = f;
|
f->root = f;
|
||||||
f->lirbuf = tm->lirbuf;
|
f->lirbuf = tm->lirbuf;
|
||||||
|
|
||||||
if (f->lirbuf->outOMem()) {
|
if (f->lirbuf->outOMem() ||
|
||||||
|
js_OverfullFragmento(tm->fragmento, MAX_MEM_IN_MAIN_FRAGMENTO)) {
|
||||||
js_FlushJITCache(cx);
|
js_FlushJITCache(cx);
|
||||||
debug_only_v(printf("Out of memory recording new tree, flushing cache.\n");)
|
debug_only_v(printf("Out of memory recording new tree, flushing cache.\n");)
|
||||||
return false;
|
return false;
|
||||||
|
@ -3332,7 +3345,7 @@ js_RecordTree(JSContext* cx, JSTraceMonitor* tm, Fragment* f, jsbytecode* outer,
|
||||||
JS_ASSERT(!f->code() && !f->vmprivate);
|
JS_ASSERT(!f->code() && !f->vmprivate);
|
||||||
|
|
||||||
/* setup the VM-private treeInfo structure for this fragment */
|
/* 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 */
|
/* capture the coerced type of each active slot in the type map */
|
||||||
ti->typeMap.captureTypes(cx, *globalSlots, 0/*callDepth*/);
|
ti->typeMap.captureTypes(cx, *globalSlots, 0/*callDepth*/);
|
||||||
|
@ -3342,7 +3355,8 @@ js_RecordTree(JSContext* cx, JSTraceMonitor* tm, Fragment* f, jsbytecode* outer,
|
||||||
since we are trying to stabilize something without properly connecting peer edges. */
|
since we are trying to stabilize something without properly connecting peer edges. */
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
TreeInfo* ti_other;
|
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)
|
if (!peer->code() || peer == f)
|
||||||
continue;
|
continue;
|
||||||
ti_other = (TreeInfo*)peer->vmprivate;
|
ti_other = (TreeInfo*)peer->vmprivate;
|
||||||
|
@ -3388,7 +3402,7 @@ JS_REQUIRES_STACK static bool
|
||||||
js_AttemptToStabilizeTree(JSContext* cx, VMSideExit* exit, jsbytecode* outer)
|
js_AttemptToStabilizeTree(JSContext* cx, VMSideExit* exit, jsbytecode* outer)
|
||||||
{
|
{
|
||||||
JSTraceMonitor* tm = &JS_TRACE_MONITOR(cx);
|
JSTraceMonitor* tm = &JS_TRACE_MONITOR(cx);
|
||||||
Fragment* from = exit->from->root;
|
VMFragment* from = (VMFragment*)exit->from->root;
|
||||||
TreeInfo* from_ti = (TreeInfo*)from->vmprivate;
|
TreeInfo* from_ti = (TreeInfo*)from->vmprivate;
|
||||||
|
|
||||||
JS_ASSERT(exit->from->root->code());
|
JS_ASSERT(exit->from->root->code());
|
||||||
|
@ -3466,7 +3480,7 @@ js_AttemptToStabilizeTree(JSContext* cx, VMSideExit* exit, jsbytecode* outer)
|
||||||
tail = &uexit->next;
|
tail = &uexit->next;
|
||||||
}
|
}
|
||||||
JS_ASSERT(bound);
|
JS_ASSERT(bound);
|
||||||
debug_only_v(js_DumpPeerStability(tm, f->ip, from_ti->globalShape);)
|
debug_only_v(js_DumpPeerStability(tm, f->ip, from->globalObj, from->globalShape);)
|
||||||
break;
|
break;
|
||||||
} else if (undemote) {
|
} else if (undemote) {
|
||||||
/* The original tree is unconnectable, so trash it. */
|
/* The original tree is unconnectable, so trash it. */
|
||||||
|
@ -3478,7 +3492,9 @@ js_AttemptToStabilizeTree(JSContext* cx, VMSideExit* exit, jsbytecode* outer)
|
||||||
if (bound)
|
if (bound)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return js_RecordTree(cx, tm, from->first, outer, from_ti->globalShape, from_ti->globalSlots);
|
VMFragment* root = (VMFragment*)from->root;
|
||||||
|
return js_RecordTree(cx, tm, from->first, outer, root->globalObj, root->globalShape,
|
||||||
|
from_ti->globalSlots);
|
||||||
}
|
}
|
||||||
|
|
||||||
static JS_REQUIRES_STACK bool
|
static JS_REQUIRES_STACK bool
|
||||||
|
@ -3552,7 +3568,6 @@ js_RecordLoopEdge(JSContext* cx, TraceRecorder* r, uintN& inlineCallCount)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
JSTraceMonitor* tm = &JS_TRACE_MONITOR(cx);
|
JSTraceMonitor* tm = &JS_TRACE_MONITOR(cx);
|
||||||
TreeInfo* ti = r->getTreeInfo();
|
|
||||||
|
|
||||||
/* Process deep abort requests. */
|
/* Process deep abort requests. */
|
||||||
if (r->wasDeepAborted()) {
|
if (r->wasDeepAborted()) {
|
||||||
|
@ -3561,9 +3576,11 @@ js_RecordLoopEdge(JSContext* cx, TraceRecorder* r, uintN& inlineCallCount)
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_ASSERT(r->getFragment() && !r->getFragment()->lastIns);
|
JS_ASSERT(r->getFragment() && !r->getFragment()->lastIns);
|
||||||
|
VMFragment* root = (VMFragment*)r->getFragment()->root;
|
||||||
|
|
||||||
/* Does this branch go to an inner loop? */
|
/* 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->globalObj, root->globalShape);
|
||||||
if (!f) {
|
if (!f) {
|
||||||
/* Not an inner loop we can call, abort trace. */
|
/* Not an inner loop we can call, abort trace. */
|
||||||
AUDIT(returnToDifferentLoopHeader);
|
AUDIT(returnToDifferentLoopHeader);
|
||||||
|
@ -3619,13 +3636,13 @@ js_RecordLoopEdge(JSContext* cx, TraceRecorder* r, uintN& inlineCallCount)
|
||||||
|
|
||||||
f = empty;
|
f = empty;
|
||||||
if (!f) {
|
if (!f) {
|
||||||
f = getAnchor(tm, cx->fp->regs->pc, globalShape);
|
f = getAnchor(tm, cx->fp->regs->pc, globalObj, globalShape);
|
||||||
if (!f) {
|
if (!f) {
|
||||||
js_FlushJITCache(cx);
|
js_FlushJITCache(cx);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return js_RecordTree(cx, tm, f, outer, globalShape, globalSlots);
|
return js_RecordTree(cx, tm, f, outer, globalObj, globalShape, globalSlots);
|
||||||
}
|
}
|
||||||
|
|
||||||
r->prepareTreeCall(f);
|
r->prepareTreeCall(f);
|
||||||
|
@ -3852,7 +3869,7 @@ static JS_REQUIRES_STACK VMSideExit*
|
||||||
js_ExecuteTree(JSContext* cx, Fragment* f, uintN& inlineCallCount,
|
js_ExecuteTree(JSContext* cx, Fragment* f, uintN& inlineCallCount,
|
||||||
VMSideExit** innermostNestedGuardp)
|
VMSideExit** innermostNestedGuardp)
|
||||||
{
|
{
|
||||||
JS_ASSERT(f->code() && f->vmprivate);
|
JS_ASSERT(f->root == f && f->code() && f->vmprivate);
|
||||||
JS_ASSERT(cx->builtinStatus == 0);
|
JS_ASSERT(cx->builtinStatus == 0);
|
||||||
|
|
||||||
JSTraceMonitor* tm = &JS_TRACE_MONITOR(cx);
|
JSTraceMonitor* tm = &JS_TRACE_MONITOR(cx);
|
||||||
|
@ -3863,7 +3880,8 @@ js_ExecuteTree(JSContext* cx, Fragment* f, uintN& inlineCallCount,
|
||||||
unsigned globalFrameSize = STOBJ_NSLOTS(globalObj);
|
unsigned globalFrameSize = STOBJ_NSLOTS(globalObj);
|
||||||
|
|
||||||
/* Make sure the global object is sane. */
|
/* 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. */
|
/* Make sure our caller replenished the double pool. */
|
||||||
JS_ASSERT(tm->reservedDoublePoolPtr >= tm->reservedDoublePool + MAX_NATIVE_STACK_SLOTS);
|
JS_ASSERT(tm->reservedDoublePoolPtr >= tm->reservedDoublePool + MAX_NATIVE_STACK_SLOTS);
|
||||||
|
|
||||||
|
@ -3874,7 +3892,6 @@ js_ExecuteTree(JSContext* cx, Fragment* f, uintN& inlineCallCount,
|
||||||
/* Setup the interpreter state block, which is followed by the native global frame. */
|
/* Setup the interpreter state block, which is followed by the native global frame. */
|
||||||
InterpState* state = (InterpState*)alloca(sizeof(InterpState) + (globalFrameSize+1)*sizeof(double));
|
InterpState* state = (InterpState*)alloca(sizeof(InterpState) + (globalFrameSize+1)*sizeof(double));
|
||||||
state->cx = cx;
|
state->cx = cx;
|
||||||
state->globalObj = globalObj;
|
|
||||||
state->inlineCallCountp = &inlineCallCount;
|
state->inlineCallCountp = &inlineCallCount;
|
||||||
state->innermostNestedGuardp = innermostNestedGuardp;
|
state->innermostNestedGuardp = innermostNestedGuardp;
|
||||||
state->outermostTree = ti;
|
state->outermostTree = ti;
|
||||||
|
@ -4149,7 +4166,8 @@ LeaveTree(InterpState& state, VMSideExit* lr)
|
||||||
/* write back interned globals */
|
/* write back interned globals */
|
||||||
double* global = (double*)(&state + 1);
|
double* global = (double*)(&state + 1);
|
||||||
FlushNativeGlobalFrame(cx, ngslots, gslots, globalTypeMap, global);
|
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 */
|
/* write back native stack frame */
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
|
@ -4225,9 +4243,9 @@ js_MonitorLoopEdge(JSContext* cx, uintN& inlineCallCount)
|
||||||
|
|
||||||
jsbytecode* pc = cx->fp->regs->pc;
|
jsbytecode* pc = cx->fp->regs->pc;
|
||||||
|
|
||||||
Fragment* f = getLoop(tm, pc, globalShape);
|
Fragment* f = getLoop(tm, pc, globalObj, globalShape);
|
||||||
if (!f)
|
if (!f)
|
||||||
f = getAnchor(tm, pc, globalShape);
|
f = getAnchor(tm, pc, globalObj, globalShape);
|
||||||
|
|
||||||
if (!f) {
|
if (!f) {
|
||||||
js_FlushJITCache(cx);
|
js_FlushJITCache(cx);
|
||||||
|
@ -4242,7 +4260,7 @@ js_MonitorLoopEdge(JSContext* cx, uintN& inlineCallCount)
|
||||||
return false;
|
return false;
|
||||||
/* We can give RecordTree the root peer. If that peer is already taken, it will
|
/* 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. */
|
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",
|
debug_only_v(printf("Looking for compat peer %d@%d, from %p (ip: %p)\n",
|
||||||
|
@ -4343,7 +4361,9 @@ TraceRecorder::monitorRecording(JSContext* cx, TraceRecorder* tr, JSOp op)
|
||||||
return JSMRS_STOP;
|
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_AbortRecording(cx, "no more LIR memory");
|
||||||
js_FlushJITCache(cx);
|
js_FlushJITCache(cx);
|
||||||
return JSMRS_STOP;
|
return JSMRS_STOP;
|
||||||
|
@ -4595,7 +4615,7 @@ js_InitJIT(JSTraceMonitor *tm)
|
||||||
|
|
||||||
if (!tm->fragmento) {
|
if (!tm->fragmento) {
|
||||||
JS_ASSERT(!tm->reservedDoublePool);
|
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);)
|
verbose_only(fragmento->labels = new (&gc) LabelMap(core, NULL);)
|
||||||
tm->fragmento = fragmento;
|
tm->fragmento = fragmento;
|
||||||
tm->lirbuf = new (&gc) LirBuffer(fragmento, NULL);
|
tm->lirbuf = new (&gc) LirBuffer(fragmento, NULL);
|
||||||
|
@ -4611,7 +4631,7 @@ js_InitJIT(JSTraceMonitor *tm)
|
||||||
memset(tm->vmfragments, 0, sizeof(tm->vmfragments));
|
memset(tm->vmfragments, 0, sizeof(tm->vmfragments));
|
||||||
}
|
}
|
||||||
if (!tm->reFragmento) {
|
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);)
|
verbose_only(fragmento->labels = new (&gc) LabelMap(core, NULL);)
|
||||||
tm->reFragmento = fragmento;
|
tm->reFragmento = fragmento;
|
||||||
tm->reLirBuf = new (&gc) LirBuffer(fragmento, NULL);
|
tm->reLirBuf = new (&gc) LirBuffer(fragmento, NULL);
|
||||||
|
@ -4726,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_REQUIRES_STACK void
|
||||||
js_FlushJITCache(JSContext* cx)
|
js_FlushJITCache(JSContext* cx)
|
||||||
{
|
{
|
||||||
|
@ -6121,7 +6181,7 @@ TraceRecorder::guardNotGlobalObject(JSObject* obj, LIns* obj_ins)
|
||||||
{
|
{
|
||||||
if (obj == globalObj)
|
if (obj == globalObj)
|
||||||
ABORT_TRACE("reference aliases global object");
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6682,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
|
// arr->dslots[i] = box_jsval(vp[i]); for i in 0..argc
|
||||||
LIns *dslots_ins = NULL;
|
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);
|
LIns *elt_ins = get(argv + i);
|
||||||
box_jsval(argv[i], elt_ins);
|
box_jsval(argv[i], elt_ins);
|
||||||
stobj_set_dslot(arr_ins, i, dslots_ins, elt_ins, "set_array_elt");
|
stobj_set_dslot(arr_ins, i, dslots_ins, elt_ins, "set_array_elt");
|
||||||
|
@ -7535,7 +7595,7 @@ TraceRecorder::record_JSOP_CALLNAME()
|
||||||
if (!activeCallOrGlobalSlot(obj, vp))
|
if (!activeCallOrGlobalSlot(obj, vp))
|
||||||
return false;
|
return false;
|
||||||
stack(0, get(vp));
|
stack(0, get(vp));
|
||||||
stack(1, globalObj_ins);
|
stack(1, INS_CONSTPTR(globalObj));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9681,14 +9741,14 @@ TraceRecorder::record_JSOP_LOOP()
|
||||||
#ifdef JS_JIT_SPEW
|
#ifdef JS_JIT_SPEW
|
||||||
/* Prints information about entry typemaps and unstable exits for all peers at a PC */
|
/* Prints information about entry typemaps and unstable exits for all peers at a PC */
|
||||||
void
|
void
|
||||||
js_DumpPeerStability(JSTraceMonitor* tm, const void* ip, uint32 globalShape)
|
js_DumpPeerStability(JSTraceMonitor* tm, const void* ip, JSObject* globalObj, uint32 globalShape)
|
||||||
{
|
{
|
||||||
Fragment* f;
|
Fragment* f;
|
||||||
TreeInfo* ti;
|
TreeInfo* ti;
|
||||||
bool looped = false;
|
bool looped = false;
|
||||||
unsigned length = 0;
|
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)
|
if (!f->vmprivate)
|
||||||
continue;
|
continue;
|
||||||
printf("fragment %p:\nENTRY: ", (void*)f);
|
printf("fragment %p:\nENTRY: ", (void*)f);
|
||||||
|
|
|
@ -298,7 +298,6 @@ public:
|
||||||
unsigned maxCallDepth;
|
unsigned maxCallDepth;
|
||||||
TypeMap typeMap;
|
TypeMap typeMap;
|
||||||
unsigned nStackTypes;
|
unsigned nStackTypes;
|
||||||
uint32 globalShape;
|
|
||||||
SlotList* globalSlots;
|
SlotList* globalSlots;
|
||||||
/* Dependent trees must be trashed if this tree dies, and updated on missing global types */
|
/* Dependent trees must be trashed if this tree dies, and updated on missing global types */
|
||||||
Queue<nanojit::Fragment*> dependentTrees;
|
Queue<nanojit::Fragment*> dependentTrees;
|
||||||
|
@ -314,7 +313,6 @@ public:
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
TreeInfo(nanojit::Fragment* _fragment,
|
TreeInfo(nanojit::Fragment* _fragment,
|
||||||
uint32 _globalShape,
|
|
||||||
SlotList* _globalSlots)
|
SlotList* _globalSlots)
|
||||||
: fragment(_fragment),
|
: fragment(_fragment),
|
||||||
script(NULL),
|
script(NULL),
|
||||||
|
@ -322,7 +320,6 @@ public:
|
||||||
nativeStackBase(0),
|
nativeStackBase(0),
|
||||||
maxCallDepth(0),
|
maxCallDepth(0),
|
||||||
nStackTypes(0),
|
nStackTypes(0),
|
||||||
globalShape(_globalShape),
|
|
||||||
globalSlots(_globalSlots),
|
globalSlots(_globalSlots),
|
||||||
branchCount(0),
|
branchCount(0),
|
||||||
unstableExits(NULL)
|
unstableExits(NULL)
|
||||||
|
@ -356,7 +353,6 @@ struct InterpState
|
||||||
// call exit guard mismatched
|
// call exit guard mismatched
|
||||||
void* rpAtLastTreeCall; // value of rp at innermost tree call guard
|
void* rpAtLastTreeCall; // value of rp at innermost tree call guard
|
||||||
TreeInfo* outermostTree; // the outermost tree we initially invoked
|
TreeInfo* outermostTree; // the outermost tree we initially invoked
|
||||||
JSObject* globalObj; // pointer to the global object
|
|
||||||
double* stackBase; // native stack base
|
double* stackBase; // native stack base
|
||||||
FrameInfo** callstackBase; // call stack base
|
FrameInfo** callstackBase; // call stack base
|
||||||
uintN* inlineCallCountp; // inline call count counter
|
uintN* inlineCallCountp; // inline call count counter
|
||||||
|
@ -401,7 +397,6 @@ class TraceRecorder : public avmplus::GCObject {
|
||||||
nanojit::LIns* cx_ins;
|
nanojit::LIns* cx_ins;
|
||||||
nanojit::LIns* eos_ins;
|
nanojit::LIns* eos_ins;
|
||||||
nanojit::LIns* eor_ins;
|
nanojit::LIns* eor_ins;
|
||||||
nanojit::LIns* globalObj_ins;
|
|
||||||
nanojit::LIns* rval_ins;
|
nanojit::LIns* rval_ins;
|
||||||
nanojit::LIns* inner_sp_ins;
|
nanojit::LIns* inner_sp_ins;
|
||||||
nanojit::LIns* invokevp_ins;
|
nanojit::LIns* invokevp_ins;
|
||||||
|
@ -572,7 +567,7 @@ public:
|
||||||
JS_REQUIRES_STACK void closeLoop(JSTraceMonitor* tm, bool& demote);
|
JS_REQUIRES_STACK void closeLoop(JSTraceMonitor* tm, bool& demote);
|
||||||
JS_REQUIRES_STACK void endLoop(JSTraceMonitor* tm);
|
JS_REQUIRES_STACK void endLoop(JSTraceMonitor* tm);
|
||||||
JS_REQUIRES_STACK void joinEdgesToEntry(nanojit::Fragmento* fragmento,
|
JS_REQUIRES_STACK void joinEdgesToEntry(nanojit::Fragmento* fragmento,
|
||||||
nanojit::Fragment* peer_root);
|
VMFragment* peer_root);
|
||||||
void blacklist() { fragment->blacklist(); }
|
void blacklist() { fragment->blacklist(); }
|
||||||
JS_REQUIRES_STACK bool adjustCallerTypes(nanojit::Fragment* f);
|
JS_REQUIRES_STACK bool adjustCallerTypes(nanojit::Fragment* f);
|
||||||
JS_REQUIRES_STACK nanojit::Fragment* findNestedCompatiblePeer(nanojit::Fragment* f,
|
JS_REQUIRES_STACK nanojit::Fragment* findNestedCompatiblePeer(nanojit::Fragment* f,
|
||||||
|
@ -641,6 +636,9 @@ js_FinishJIT(JSTraceMonitor *tm);
|
||||||
extern void
|
extern void
|
||||||
js_PurgeScriptFragments(JSContext* cx, JSScript* script);
|
js_PurgeScriptFragments(JSContext* cx, JSScript* script);
|
||||||
|
|
||||||
|
extern bool
|
||||||
|
js_OverfullFragmento(nanojit::Fragmento *frago, size_t maxsz);
|
||||||
|
|
||||||
extern void
|
extern void
|
||||||
js_FlushJITCache(JSContext* cx);
|
js_FlushJITCache(JSContext* cx);
|
||||||
|
|
||||||
|
|
|
@ -82,7 +82,6 @@
|
||||||
* - XXXbe patrol
|
* - XXXbe patrol
|
||||||
* - Fuse objects and their JSXML* private data into single GC-things
|
* - Fuse objects and their JSXML* private data into single GC-things
|
||||||
* - fix function::foo vs. x.(foo == 42) collision using proper namespacing
|
* - 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!
|
* - JSCLASS_DOCUMENT_OBSERVER support -- live two-way binding to Gecko's DOM!
|
||||||
* - JS_TypeOfValue sure could use a cleaner interface to "types"
|
* - JS_TypeOfValue sure could use a cleaner interface to "types"
|
||||||
*/
|
*/
|
||||||
|
@ -5439,10 +5438,9 @@ JS_FRIEND_DATA(JSObjectOps) js_XMLObjectOps = {
|
||||||
xml_enumerate, js_CheckAccess,
|
xml_enumerate, js_CheckAccess,
|
||||||
NULL, NULL,
|
NULL, NULL,
|
||||||
NULL, NULL,
|
NULL, NULL,
|
||||||
NULL, xml_hasInstance,
|
xml_hasInstance, js_TraceObject,
|
||||||
js_SetProtoOrParent, js_SetProtoOrParent,
|
xml_clear, NULL,
|
||||||
js_TraceObject, xml_clear,
|
NULL
|
||||||
NULL, NULL
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static JSObjectOps *
|
static JSObjectOps *
|
||||||
|
|
|
@ -48,6 +48,7 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "jsj_private.h" /* LiveConnect internals */
|
#include "jsj_private.h" /* LiveConnect internals */
|
||||||
|
#include "jsobj.h"
|
||||||
|
|
||||||
/* Shorthands for ASCII (7-bit) decimal and hex conversion. */
|
/* Shorthands for ASCII (7-bit) decimal and hex conversion. */
|
||||||
#define JS7_ISDEC(c) (((c) >= '0') && ((c) <= '9'))
|
#define JS7_ISDEC(c) (((c) >= '0') && ((c) <= '9'))
|
||||||
|
@ -423,11 +424,8 @@ JSObjectOps JavaArray_ops = {
|
||||||
NULL, /* dropProperty */
|
NULL, /* dropProperty */
|
||||||
NULL, /* call */
|
NULL, /* call */
|
||||||
NULL, /* construct */
|
NULL, /* construct */
|
||||||
NULL, /* xdrObject */
|
|
||||||
NULL, /* hasInstance */
|
NULL, /* hasInstance */
|
||||||
NULL, /* setProto */
|
NULL, /* trace */
|
||||||
NULL, /* setParent */
|
|
||||||
NULL, /* mark */
|
|
||||||
NULL, /* clear */
|
NULL, /* clear */
|
||||||
jsj_wrapper_getRequiredSlot, /* getRequiredSlot */
|
jsj_wrapper_getRequiredSlot, /* getRequiredSlot */
|
||||||
jsj_wrapper_setRequiredSlot /* setRequiredSlot */
|
jsj_wrapper_setRequiredSlot /* setRequiredSlot */
|
||||||
|
|
|
@ -57,6 +57,7 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "jsj_private.h" /* LiveConnect internals */
|
#include "jsj_private.h" /* LiveConnect internals */
|
||||||
|
#include "jsobj.h"
|
||||||
|
|
||||||
static JSBool
|
static JSBool
|
||||||
JavaClass_convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp)
|
JavaClass_convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp)
|
||||||
|
@ -548,11 +549,8 @@ JSObjectOps JavaClass_ops = {
|
||||||
NULL, /* dropProperty */
|
NULL, /* dropProperty */
|
||||||
jsj_JavaConstructorWrapper, /* call */
|
jsj_JavaConstructorWrapper, /* call */
|
||||||
jsj_JavaConstructorWrapper, /* construct */
|
jsj_JavaConstructorWrapper, /* construct */
|
||||||
NULL, /* xdrObject */
|
|
||||||
JavaClass_hasInstance, /* hasInstance */
|
JavaClass_hasInstance, /* hasInstance */
|
||||||
NULL, /* setProto */
|
NULL, /* trace */
|
||||||
NULL, /* setParent */
|
|
||||||
NULL, /* mark */
|
|
||||||
NULL, /* clear */
|
NULL, /* clear */
|
||||||
jsj_wrapper_getRequiredSlot, /* getRequiredSlot */
|
jsj_wrapper_getRequiredSlot, /* getRequiredSlot */
|
||||||
jsj_wrapper_setRequiredSlot /* setRequiredSlot */
|
jsj_wrapper_setRequiredSlot /* setRequiredSlot */
|
||||||
|
|
|
@ -1057,11 +1057,8 @@ JSObjectOps JavaObject_ops = {
|
||||||
NULL, /* dropProperty */
|
NULL, /* dropProperty */
|
||||||
NULL, /* call */
|
NULL, /* call */
|
||||||
NULL, /* construct */
|
NULL, /* construct */
|
||||||
NULL, /* xdrObject */
|
|
||||||
NULL, /* hasInstance */
|
NULL, /* hasInstance */
|
||||||
NULL, /* setProto */
|
NULL, /* trace */
|
||||||
NULL, /* setParent */
|
|
||||||
NULL, /* mark */
|
|
||||||
NULL, /* clear */
|
NULL, /* clear */
|
||||||
jsj_wrapper_getRequiredSlot, /* getRequiredSlot */
|
jsj_wrapper_getRequiredSlot, /* getRequiredSlot */
|
||||||
jsj_wrapper_setRequiredSlot /* setRequiredSlot */
|
jsj_wrapper_setRequiredSlot /* setRequiredSlot */
|
||||||
|
|
|
@ -50,7 +50,7 @@ namespace nanojit
|
||||||
static uint32_t calcSaneCacheSize(uint32_t in)
|
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 < 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;
|
return in;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4774,6 +4774,23 @@ function testDenseArrayProp()
|
||||||
testDenseArrayProp.expected = "ok";
|
testDenseArrayProp.expected = "ok";
|
||||||
test(testDenseArrayProp);
|
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);
|
||||||
|
|
||||||
|
|
||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
* *
|
* *
|
||||||
* _____ _ _ _____ ______ _____ _______ *
|
* _____ _ _ _____ ______ _____ _______ *
|
||||||
|
|
Загрузка…
Ссылка в новой задаче