Remove JSFunction fixed slots and unused fields, bug 697537.

This commit is contained in:
Brian Hackett 2011-10-26 13:02:57 -07:00
parent f90413cb77
commit a9c68ac54d
35 changed files with 490 additions and 381 deletions

View File

@ -2378,7 +2378,6 @@ BindNameToSlot(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
JS_ASSERT(cg->inFunction());
JS_ASSERT_IF(cookie.slot() != UpvarCookie::CALLEE_SLOT, cg->roLexdeps->lookup(atom));
JS_ASSERT(JOF_OPTYPE(op) == JOF_ATOM);
JS_ASSERT(cg->fun()->u.i.skipmin <= skip);
/*
* If op is a mutating opcode, this upvar's lookup skips too many levels,
@ -5595,6 +5594,36 @@ EmitWith(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn, JSBool &ok)
return true;
}
static bool
SetMethodFunction(JSContext *cx, JSFunctionBox *funbox, JSAtom *atom)
{
/* Replace a boxed function with a new one with a method atom. */
JSFunction *fun = js_NewFunction(cx, NULL, NULL,
funbox->function()->nargs,
funbox->function()->flags,
funbox->function()->getParent(),
funbox->function()->atom,
JSFunction::ExtendedFinalizeKind);
if (!fun)
return false;
JSScript *script = funbox->function()->script();
if (script) {
fun->setScript(funbox->function()->script());
if (!fun->script()->typeSetFunction(cx, fun))
return false;
}
JS_ASSERT(funbox->function()->joinable());
fun->setJoinable();
fun->setMethodAtom(atom);
funbox->object = fun;
return true;
}
JSBool
js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
{
@ -6464,6 +6493,8 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
pn2->pn_left->isOp(JSOP_SETPROP) &&
pn2->pn_right->isOp(JSOP_LAMBDA) &&
pn2->pn_right->pn_funbox->joinable()) {
if (!SetMethodFunction(cx, pn2->pn_right->pn_funbox, pn2->pn_left->pn_atom))
return JS_FALSE;
pn2->pn_left->setOp(JSOP_SETMETHOD);
}
if (!js_EmitTree(cx, cg, pn2))
@ -7228,6 +7259,8 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
obj = NULL;
op = JSOP_INITMETHOD;
pn2->setOp(op);
if (!SetMethodFunction(cx, init->pn_funbox, pn3->pn_atom))
return JS_FALSE;
} else {
/*
* Disable NEWOBJECT on initializers that set __proto__, which has

View File

@ -1097,7 +1097,6 @@ FindFunArgs(JSFunctionBox *funbox, int level, JSFunctionBoxQueue *queue)
do {
JSParseNode *fn = funbox->node;
JS_ASSERT(fn->isArity(PN_FUNC));
JSFunction *fun = funbox->function();
int fnlevel = level;
/*
@ -1178,12 +1177,10 @@ FindFunArgs(JSFunctionBox *funbox, int level, JSFunctionBoxQueue *queue)
/*
* Finally, after we've traversed all of the current function's kids,
* minimize fun's skipmin against our accumulated skipmin. Do likewise
* with allskipmin, but minimize across funbox and all of its siblings,
* to compute our return value.
* minimize allskipmin against our accumulated skipmin. Minimize across
* funbox and all of its siblings, to compute our return value.
*/
if (skipmin != UpvarCookie::FREE_LEVEL) {
fun->u.i.skipmin = skipmin;
if (skipmin < allskipmin)
allskipmin = skipmin;
}

View File

@ -4290,7 +4290,12 @@ JS_NewFunctionById(JSContext *cx, JSNative native, uintN nargs, uintN flags, JSO
CHECK_REQUEST(cx);
assertSameCompartment(cx, parent);
return js_NewFunction(cx, NULL, native, nargs, flags, parent, JSID_TO_ATOM(id));
/* Allow natives created through this interface to use {Get,Set}FunctionNativeReserved. */
AllocKind kind = native
? (AllocKind) JSFunction::ExtendedFinalizeKind
: (AllocKind) JSFunction::FinalizeKind;
return js_NewFunction(cx, NULL, native, nargs, flags, parent, JSID_TO_ATOM(id), kind);
}
JS_PUBLIC_API(JSObject *)
@ -4318,7 +4323,7 @@ JS_CloneFunctionObject(JSContext *cx, JSObject *funobj, JSObject *parent)
JSFunction *fun = funobj->toFunction();
if (!fun->isInterpreted())
return CloneFunctionObject(cx, fun, parent);
return CloneFunctionObject(cx, fun, parent, fun->getAllocKind());
if (fun->script()->compileAndGo) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
@ -4327,7 +4332,7 @@ JS_CloneFunctionObject(JSContext *cx, JSObject *funobj, JSObject *parent)
}
if (!fun->isFlatClosure())
return CloneFunctionObject(cx, fun, parent);
return CloneFunctionObject(cx, fun, parent, fun->getAllocKind());
/*
* A flat closure carries its own environment, so why clone it? In case
@ -4364,7 +4369,7 @@ JS_CloneFunctionObject(JSContext *cx, JSObject *funobj, JSObject *parent)
Value v;
if (!obj->getGeneric(cx, r.front().propid(), &v))
return NULL;
clone->getFlatClosureUpvars()[i] = v;
clone->toFunction()->getFlatClosureUpvars()[i] = v;
}
return clone;
@ -4418,7 +4423,8 @@ JS_IsNativeFunction(JSObject *funobj, JSNative call)
JSBool
js_generic_native_method_dispatcher(JSContext *cx, uintN argc, Value *vp)
{
JSFunctionSpec *fs = (JSFunctionSpec *) vp->toObject().getReservedSlot(0).toPrivate();
JSFunctionSpec *fs = (JSFunctionSpec *)
vp->toObject().toFunction()->getNativeReserved(0).toPrivate();
JS_ASSERT((fs->flags & JSFUN_GENERIC_NATIVE) != 0);
if (argc < 1) {
@ -4480,7 +4486,8 @@ JS_DefineFunctions(JSContext *cx, JSObject *obj, JSFunctionSpec *fs)
fun = js_DefineFunction(cx, ctor, ATOM_TO_JSID(atom),
js_generic_native_method_dispatcher,
fs->nargs + 1,
flags & ~JSFUN_TRCINFO);
flags & ~JSFUN_TRCINFO,
JSFunction::ExtendedFinalizeKind);
if (!fun)
return JS_FALSE;
@ -4488,9 +4495,7 @@ JS_DefineFunctions(JSContext *cx, JSObject *obj, JSFunctionSpec *fs)
* As jsapi.h notes, fs must point to storage that lives as long
* as fun->object lives.
*/
Value priv = PrivateValue(fs);
if (!js_SetReservedSlot(cx, fun, 0, priv))
return JS_FALSE;
fun->setNativeReserved(0, PrivateValue(fs));
}
fun = js_DefineFunction(cx, obj, ATOM_TO_JSID(atom), fs->call, fs->nargs, flags);

View File

@ -620,12 +620,10 @@ JS_DECLARE_CALLINFO(js_BooleanIntToString)
JS_DECLARE_CALLINFO(js_NewNullClosure)
/* Defined in jsfun.cpp. */
JS_DECLARE_CALLINFO(js_AllocFlatClosure)
JS_DECLARE_CALLINFO(js_PutArgumentsOnTrace)
JS_DECLARE_CALLINFO(js_PutCallObjectOnTrace)
JS_DECLARE_CALLINFO(js_SetCallVar)
JS_DECLARE_CALLINFO(js_SetCallArg)
JS_DECLARE_CALLINFO(js_CloneFunctionObject)
JS_DECLARE_CALLINFO(js_CreateCallObjectOnTrace)
JS_DECLARE_CALLINFO(js_NewArgumentsOnTrace)

View File

@ -65,8 +65,6 @@ enum AllocKind {
FINALIZE_OBJECT16,
FINALIZE_OBJECT16_BACKGROUND,
FINALIZE_OBJECT_LAST = FINALIZE_OBJECT16_BACKGROUND,
FINALIZE_FUNCTION,
FINALIZE_FUNCTION_AND_OBJECT_LAST = FINALIZE_FUNCTION,
FINALIZE_SCRIPT,
FINALIZE_SHAPE,
FINALIZE_BASE_SHAPE,

View File

@ -473,7 +473,7 @@ JSCompartment::markTypes(JSTracer *trc)
}
for (size_t thingKind = FINALIZE_OBJECT0;
thingKind <= FINALIZE_FUNCTION_AND_OBJECT_LAST;
thingKind <= FINALIZE_OBJECT_LAST;
thingKind++) {
for (CellIterUnderGC i(this, AllocKind(thingKind)); !i.done(); i.next()) {
JSObject *object = i.get<JSObject>();

View File

@ -696,10 +696,6 @@ FilenameToString(JSContext *cx, const char *filename)
return JS_NewStringCopyZ(cx, filename);
}
enum {
JSSLOT_ERROR_EXNTYPE = 0
};
static JSBool
Exception(JSContext *cx, uintN argc, Value *vp)
{
@ -768,7 +764,7 @@ Exception(JSContext *cx, uintN argc, Value *vp)
lineno = iter.done() ? 0 : js_FramePCToLineNumber(cx, iter.fp(), iter.pc());
}
intN exnType = args.callee().getReservedSlot(JSSLOT_ERROR_EXNTYPE).toInt32();
intN exnType = args.callee().toFunction()->getNativeReserved(0).toInt32();
if (!InitExnPrivate(cx, obj, message, filename, lineno, NULL, exnType))
return false;
@ -1031,10 +1027,11 @@ InitErrorClass(JSContext *cx, GlobalObject *global, intN type, JSObject &proto)
}
/* Create the corresponding constructor. */
JSFunction *ctor = global->createConstructor(cx, Exception, &ErrorClass, name, 1);
JSFunction *ctor = global->createConstructor(cx, Exception, &ErrorClass, name, 1,
JSFunction::ExtendedFinalizeKind);
if (!ctor)
return NULL;
ctor->setReservedSlot(JSSLOT_ERROR_EXNTYPE, Int32Value(int32(type)));
ctor->setNativeReserved(0, Int32Value(int32(type)));
if (!LinkConstructorAndPrototype(cx, ctor, errorProto))
return NULL;

View File

@ -207,6 +207,18 @@ js::IsOriginalScriptFunction(JSFunction *fun)
return fun->script()->function() == fun;
}
JS_FRIEND_API(const Value &)
js::GetFunctionNativeReserved(JSObject *fun, size_t which)
{
return fun->toFunction()->getNativeReserved(which);
}
JS_FRIEND_API(void)
js::SetFunctionNativeReserved(JSObject *fun, size_t which, const Value &val)
{
fun->toFunction()->setNativeReserved(which, val);
}
/*
* The below code is for temporary telemetry use. It can be removed when
* sufficient data has been harvested.

View File

@ -276,6 +276,12 @@ GetObjectGlobal(JSObject *obj);
JS_FRIEND_API(bool)
IsOriginalScriptFunction(JSFunction *fun);
JS_FRIEND_API(const Value &)
GetFunctionNativeReserved(JSObject *fun, size_t which);
JS_FRIEND_API(void)
SetFunctionNativeReserved(JSObject *fun, size_t which, const Value &val);
inline JSObject *
GetObjectProto(const JSObject *obj)
{

View File

@ -1027,7 +1027,7 @@ GetCallUpvar(JSContext *cx, JSObject *obj, jsid id, Value *vp)
JS_ASSERT((int16) JSID_TO_INT(id) == JSID_TO_INT(id));
uintN i = (uint16) JSID_TO_INT(id);
*vp = callobj.getCallee()->getFlatClosureUpvar(i);
*vp = callobj.getCallee()->toFunction()->getFlatClosureUpvar(i);
return true;
}
@ -1038,7 +1038,7 @@ SetCallUpvar(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp)
JS_ASSERT((int16) JSID_TO_INT(id) == JSID_TO_INT(id));
uintN i = (uint16) JSID_TO_INT(id);
callobj.getCallee()->setFlatClosureUpvar(i, *vp);
callobj.getCallee()->toFunction()->setFlatClosureUpvar(i, *vp);
return true;
}
@ -1240,7 +1240,7 @@ StackFrame::getValidCalleeObject(JSContext *cx, Value *vp)
if (IsFunctionObject(v, &clone) &&
clone->script() == fun->script() &&
clone->hasMethodObj(*thisp)) {
clone->methodObj() == thisp) {
/*
* N.B. If the method barrier was on a function
* with singleton type, then while crossing the
@ -1572,7 +1572,7 @@ js_XDRFunctionObject(JSXDRState *xdr, JSObject **objp)
}
return false;
}
firstword = (fun->u.i.skipmin << 2) | !!fun->atom;
firstword = !!fun->atom;
flagsword = (fun->nargs << 16) | fun->flags;
} else {
fun = js_NewFunction(cx, NULL, NULL, 0, JSFUN_INTERPRETED, NULL, NULL);
@ -1597,7 +1597,6 @@ js_XDRFunctionObject(JSXDRState *xdr, JSObject **objp)
fun->nargs = flagsword >> 16;
JS_ASSERT((flagsword & JSFUN_KINDMASK) >= JSFUN_INTERPRETED);
fun->flags = uint16(flagsword);
fun->u.i.skipmin = uint16(firstword >> 2);
}
/*
@ -1637,7 +1636,7 @@ fun_hasInstance(JSContext *cx, JSObject *obj, const Value *v, JSBool *bp)
while (obj->isFunction()) {
if (!obj->isBoundFunction())
break;
obj = obj->getBoundFunctionTarget();
obj = obj->toFunction()->getBoundFunctionTarget();
}
Value pval;
@ -1657,32 +1656,53 @@ fun_hasInstance(JSContext *cx, JSObject *obj, const Value *v, JSBool *bp)
return JS_TRUE;
}
inline void
JSFunction::trace(JSTracer *trc)
{
if (isFlatClosure() && isExtended() && script()->bindings.hasUpvars()) {
Value *upvars = getFlatClosureUpvars();
if (upvars)
MarkValueRange(trc, script()->bindings.countUpvars(), upvars, "upvars");
}
if (joinable()) {
JSAtom *atom = methodAtom();
if (atom)
MarkString(trc, atom, "methodAtom");
JSObject *obj = methodObj();
if (obj)
MarkObject(trc, *obj, "methodObj");
}
if (isNative() && isExtended()) {
MarkValueRange(trc, JS_ARRAY_LENGTH(toExtended()->extu.nativeReserved),
toExtended()->extu.nativeReserved, "nativeReserved");
}
if (atom)
MarkString(trc, atom, "atom");
if (isInterpreted()) {
if (script())
MarkScript(trc, script(), "script");
if (callScope())
MarkObject(trc, *callScope(), "fun_callscope");
}
}
static void
fun_trace(JSTracer *trc, JSObject *obj)
{
JSFunction *fun = obj->toFunction();
if (fun->isFlatClosure() && fun->script()->bindings.hasUpvars()) {
Value *upvars = obj->getFlatClosureUpvars();
if (upvars)
MarkValueRange(trc, fun->script()->bindings.countUpvars(), upvars, "upvars");
}
if (fun->atom)
MarkString(trc, fun->atom, "atom");
if (fun->isInterpreted()) {
if (fun->script())
MarkScript(trc, fun->script(), "script");
if (fun->callScope())
MarkObject(trc, *fun->callScope(), "fun_callscope");
}
obj->toFunction()->trace(trc);
}
static void
fun_finalize(JSContext *cx, JSObject *obj)
{
obj->finalizeUpvarsIfFlatClosure();
if (obj->toFunction()->isFlatClosure())
obj->toFunction()->finalizeUpvars();
}
/*
@ -1693,7 +1713,6 @@ fun_finalize(JSContext *cx, JSObject *obj)
JS_FRIEND_DATA(Class) js::FunctionClass = {
js_Function_str,
JSCLASS_NEW_RESOLVE |
JSCLASS_HAS_RESERVED_SLOTS(JSFunction::CLASS_RESERVED_SLOTS) |
JSCLASS_HAS_CACHED_PROTO(JSProto_Function),
JS_PropertyStub, /* addProperty */
JS_PropertyStub, /* delProperty */
@ -1895,35 +1914,40 @@ CallOrConstructBoundFunction(JSContext *cx, uintN argc, Value *vp);
}
static const uint32 JSSLOT_BOUND_FUNCTION_THIS = 0;
static const uint32 JSSLOT_BOUND_FUNCTION_ARGS_COUNT = 1;
static const uint32 BOUND_FUNCTION_RESERVED_SLOTS = 2;
inline bool
JSObject::initBoundFunction(JSContext *cx, const Value &thisArg,
const Value *args, uintN argslen)
JSFunction::initBoundFunction(JSContext *cx, const Value &thisArg,
const Value *args, uintN argslen)
{
JS_ASSERT(isFunction());
setSlot(JSSLOT_BOUND_FUNCTION_THIS, thisArg);
setSlot(JSSLOT_BOUND_FUNCTION_ARGS_COUNT, PrivateUint32Value(argslen));
/*
* Convert to a dictionary to set the BOUND_FUNCTION flag and increase
* the slot span to cover the arguments.
* the slot span to cover the arguments and additional slots for the 'this'
* value and arguments count.
*/
if (!toDictionaryMode(cx))
return false;
lastProperty()->base()->setObjectFlag(BaseShape::BOUND_FUNCTION);
JS_ASSERT(slotSpan() == JSSLOT_FREE(&FunctionClass));
if (!setSlotSpan(cx, slotSpan() + argslen))
if (!setSlotSpan(cx, BOUND_FUNCTION_RESERVED_SLOTS + argslen))
return false;
copySlotRange(FUN_CLASS_RESERVED_SLOTS, args, argslen);
setSlot(JSSLOT_BOUND_FUNCTION_THIS, thisArg);
setSlot(JSSLOT_BOUND_FUNCTION_ARGS_COUNT, PrivateUint32Value(argslen));
copySlotRange(BOUND_FUNCTION_RESERVED_SLOTS, args, argslen);
return true;
}
inline JSObject *
JSObject::getBoundFunctionTarget() const
JSFunction::getBoundFunctionTarget() const
{
JS_ASSERT(isFunction());
JS_ASSERT(isBoundFunction());
@ -1933,7 +1957,7 @@ JSObject::getBoundFunctionTarget() const
}
inline const js::Value &
JSObject::getBoundFunctionThis() const
JSFunction::getBoundFunctionThis() const
{
JS_ASSERT(isFunction());
JS_ASSERT(isBoundFunction());
@ -1942,17 +1966,17 @@ JSObject::getBoundFunctionThis() const
}
inline const js::Value &
JSObject::getBoundFunctionArgument(uintN which) const
JSFunction::getBoundFunctionArgument(uintN which) const
{
JS_ASSERT(isFunction());
JS_ASSERT(isBoundFunction());
JS_ASSERT(which < getBoundFunctionArgumentCount());
return getSlot(FUN_CLASS_RESERVED_SLOTS + which);
return getSlot(BOUND_FUNCTION_RESERVED_SLOTS + which);
}
inline size_t
JSObject::getBoundFunctionArgumentCount() const
JSFunction::getBoundFunctionArgumentCount() const
{
JS_ASSERT(isFunction());
JS_ASSERT(isBoundFunction());
@ -1966,14 +1990,13 @@ namespace js {
JSBool
CallOrConstructBoundFunction(JSContext *cx, uintN argc, Value *vp)
{
JSObject *obj = &vp[0].toObject();
JS_ASSERT(obj->isFunction());
JS_ASSERT(obj->isBoundFunction());
JSFunction *fun = vp[0].toObject().toFunction();
JS_ASSERT(fun->isBoundFunction());
bool constructing = IsConstructing(vp);
/* 15.3.4.5.1 step 1, 15.3.4.5.2 step 3. */
uintN argslen = obj->getBoundFunctionArgumentCount();
uintN argslen = fun->getBoundFunctionArgumentCount();
if (argc + argslen > StackSpace::ARGS_LENGTH_MAX) {
js_ReportAllocationOverflow(cx);
@ -1981,10 +2004,10 @@ CallOrConstructBoundFunction(JSContext *cx, uintN argc, Value *vp)
}
/* 15.3.4.5.1 step 3, 15.3.4.5.2 step 1. */
JSObject *target = obj->getBoundFunctionTarget();
JSObject *target = fun->getBoundFunctionTarget();
/* 15.3.4.5.1 step 2. */
const Value &boundThis = obj->getBoundFunctionThis();
const Value &boundThis = fun->getBoundFunctionThis();
InvokeArgsGuard args;
if (!cx->stack.pushInvokeArgs(cx, argc + argslen, &args))
@ -1992,7 +2015,7 @@ CallOrConstructBoundFunction(JSContext *cx, uintN argc, Value *vp)
/* 15.3.4.5.1, 15.3.4.5.2 step 4. */
for (uintN i = 0; i < argslen; i++)
args[i] = obj->getBoundFunctionArgument(i);
args[i] = fun->getBoundFunctionArgument(i);
memcpy(args.array() + argslen, vp + 2, argc * sizeof(Value));
/* 15.3.4.5.1, 15.3.4.5.2 step 5. */
@ -2080,7 +2103,7 @@ fun_bind(JSContext *cx, uintN argc, Value *vp)
/* Steps 7-9. */
Value thisArg = args.length() >= 1 ? args[0] : UndefinedValue();
if (!funobj->initBoundFunction(cx, thisArg, boundArgs, argslen))
if (!funobj->toFunction()->initBoundFunction(cx, thisArg, boundArgs, argslen))
return false;
/* Steps 17, 19-21 are handled by fun_resolve. */
@ -2324,7 +2347,7 @@ LookupInterpretedFunctionPrototype(JSContext *cx, JSObject *funobj)
JSFunction *
js_NewFunction(JSContext *cx, JSObject *funobj, Native native, uintN nargs,
uintN flags, JSObject *parent, JSAtom *atom)
uintN flags, JSObject *parent, JSAtom *atom, js::gc::AllocKind kind)
{
JSFunction *fun;
@ -2332,7 +2355,7 @@ js_NewFunction(JSContext *cx, JSObject *funobj, Native native, uintN nargs,
JS_ASSERT(funobj->isFunction());
JS_ASSERT(funobj->getParent() == parent);
} else {
funobj = NewFunction(cx, SkipScopeParent(parent));
funobj = NewFunction(cx, SkipScopeParent(parent), kind);
if (!funobj)
return NULL;
if (native && !funobj->setSingletonType(cx))
@ -2342,11 +2365,13 @@ js_NewFunction(JSContext *cx, JSObject *funobj, Native native, uintN nargs,
/* Initialize all function members. */
fun->nargs = uint16(nargs);
fun->flags = flags & (JSFUN_FLAGS_MASK | JSFUN_KINDMASK | JSFUN_TRCINFO);
fun->flags = flags & (JSFUN_FLAGS_MASK | JSFUN_KINDMASK);
if (kind == JSFunction::ExtendedFinalizeKind) {
fun->flags |= JSFUN_EXTENDED;
fun->clearExtended();
}
if ((flags & JSFUN_KINDMASK) >= JSFUN_INTERPRETED) {
JS_ASSERT(!native);
JS_ASSERT(nargs == 0);
fun->u.i.skipmin = 0;
fun->u.i.script_ = NULL;
fun->setCallScope(parent);
} else {
@ -2356,13 +2381,9 @@ js_NewFunction(JSContext *cx, JSObject *funobj, Native native, uintN nargs,
JSNativeTraceInfo *trcinfo =
JS_FUNC_TO_DATA_PTR(JSNativeTraceInfo *, native);
fun->u.n.native = (Native) trcinfo->native;
fun->u.n.trcinfo = trcinfo;
#else
fun->u.n.trcinfo = NULL;
#endif
} else {
fun->u.n.native = native;
fun->u.n.trcinfo = NULL;
}
JS_ASSERT(fun->u.n.native);
}
@ -2373,20 +2394,25 @@ js_NewFunction(JSContext *cx, JSObject *funobj, Native native, uintN nargs,
JSFunction * JS_FASTCALL
js_CloneFunctionObject(JSContext *cx, JSFunction *fun, JSObject *parent,
JSObject *proto)
JSObject *proto, gc::AllocKind kind)
{
JS_ASSERT(parent);
JS_ASSERT(proto);
JSFunction *clone = NewFunction(cx, SkipScopeParent(parent));
JSFunction *clone = NewFunction(cx, SkipScopeParent(parent), kind);
if (!clone)
return NULL;
clone->nargs = fun->nargs;
clone->flags = fun->flags;
clone->flags = fun->flags & ~JSFUN_EXTENDED;
clone->u = fun->toFunction()->u;
clone->atom = fun->atom;
if (kind == JSFunction::ExtendedFinalizeKind) {
clone->flags |= JSFUN_EXTENDED;
clone->clearExtended();
}
if (clone->isInterpreted())
clone->setCallScope(parent);
@ -2428,17 +2454,12 @@ js_CloneFunctionObject(JSContext *cx, JSFunction *fun, JSObject *parent,
return clone;
}
#ifdef JS_TRACER
JS_DEFINE_CALLINFO_4(extern, FUNCTION, js_CloneFunctionObject, CONTEXT, FUNCTION, OBJECT, OBJECT, 0,
nanojit::ACCSET_STORE_ANY)
#endif
/*
* Create a new flat closure, but don't initialize the imported upvar
* values. The tracer calls this function and then initializes the upvar
* slots on trace.
*/
JSObject * JS_FASTCALL
JSFunction * JS_FASTCALL
js_AllocFlatClosure(JSContext *cx, JSFunction *fun, JSObject *scopeChain)
{
JS_ASSERT(fun->isFlatClosure());
@ -2447,7 +2468,7 @@ js_AllocFlatClosure(JSContext *cx, JSFunction *fun, JSObject *scopeChain)
JS_ASSERT_IF(JSScript::isValidOffset(fun->script()->upvarsOffset),
fun->script()->upvars()->length == fun->script()->bindings.countUpvars());
JSObject *closure = CloneFunctionObject(cx, fun, scopeChain, true);
JSFunction *closure = CloneFunctionObject(cx, fun, scopeChain, JSFunction::ExtendedFinalizeKind);
if (!closure)
return closure;
@ -2463,10 +2484,7 @@ js_AllocFlatClosure(JSContext *cx, JSFunction *fun, JSObject *scopeChain)
return closure;
}
JS_DEFINE_CALLINFO_3(extern, OBJECT, js_AllocFlatClosure,
CONTEXT, FUNCTION, OBJECT, 0, nanojit::ACCSET_STORE_ANY)
JSObject *
JSFunction *
js_NewFlatClosure(JSContext *cx, JSFunction *fun, JSOp op, size_t oplen)
{
/*
@ -2481,7 +2499,7 @@ js_NewFlatClosure(JSContext *cx, JSFunction *fun, JSOp op, size_t oplen)
VOUCH_DOES_NOT_REQUIRE_STACK();
JSObject *scopeChain = &cx->fp()->scopeChain();
JSObject *closure = js_AllocFlatClosure(cx, fun, scopeChain);
JSFunction *closure = js_AllocFlatClosure(cx, fun, scopeChain);
if (!closure || !fun->script()->bindings.hasUpvars())
return closure;
@ -2497,7 +2515,7 @@ js_NewFlatClosure(JSContext *cx, JSFunction *fun, JSOp op, size_t oplen)
JSFunction *
js_DefineFunction(JSContext *cx, JSObject *obj, jsid id, Native native,
uintN nargs, uintN attrs)
uintN nargs, uintN attrs, AllocKind kind)
{
PropertyOp gop;
StrictPropertyOp sop;
@ -2521,7 +2539,8 @@ js_DefineFunction(JSContext *cx, JSObject *obj, jsid id, Native native,
fun = js_NewFunction(cx, NULL, native, nargs,
attrs & (JSFUN_FLAGS_MASK | JSFUN_TRCINFO),
obj,
JSID_IS_ATOM(id) ? JSID_TO_ATOM(id) : NULL);
JSID_IS_ATOM(id) ? JSID_TO_ATOM(id) : NULL,
kind);
if (!fun)
return NULL;

View File

@ -92,18 +92,17 @@
global object */
#define JSFUN_EXPR_CLOSURE 0x1000 /* expression closure: function(x) x*x */
/* 0x2000 is JSFUN_TRCINFO:
u.n.trcinfo is non-null */
#define JSFUN_EXTENDED 0x2000 /* structure is FunctionExtended */
#define JSFUN_INTERPRETED 0x4000 /* use u.i if kind >= this value else u.n */
#define JSFUN_FLAT_CLOSURE 0x8000 /* flat (aka "display") closure */
#define JSFUN_NULL_CLOSURE 0xc000 /* null closure entrains no scope chain */
#define JSFUN_KINDMASK 0xc000 /* encode interp vs. native and closure
optimization level -- see above */
struct JSFunction : public JSObject_Slots2
{
/* Functions always have two fixed slots (FUN_CLASS_RESERVED_SLOTS). */
namespace js { class FunctionExtended; }
struct JSFunction : public JSObject
{
uint16 nargs; /* maximum number of specified arguments,
reflected as f.length/f.arity */
uint16 flags; /* flags, see JSFUN_* below and in jsapi.h */
@ -112,14 +111,10 @@ struct JSFunction : public JSObject_Slots2
js::Native native; /* native method pointer or null */
js::Class *clasp; /* class of objects constructed
by this function */
JSNativeTraceInfo *trcinfo;
} n;
struct Scripted {
JSScript *script_; /* interpreted bytecode descriptor or null;
use the setter! */
uint16 skipmin; /* net skip amount up (toward zero) from
script_->staticLevel to nearest upvar,
including upvars in nested functions */
JSObject *scope; /* scope to use when calling this function */
} i;
void *nativeOrScript;
@ -174,34 +169,6 @@ struct JSFunction : public JSObject_Slots2
static inline size_t offsetOfCallScope() { return offsetof(JSFunction, u.i.scope); }
/*
* FunctionClass reserves two slots, which are free in JSObject::fslots
* without requiring dslots allocation. Null closures that can be joined to
* a compiler-created function object use the first one to hold a mutable
* methodAtom() state variable, needed for correct foo.caller handling.
*/
static const uint32 JSSLOT_FUN_METHOD_ATOM = 0;
static const uint32 JSSLOT_FUN_METHOD_OBJ = 1;
/* Whether this is a function cloned from a method. */
inline bool isClonedMethod() const;
/* For a cloned method, pointer to the object the method was cloned for. */
inline bool hasMethodObj(const JSObject& obj) const;
inline void setMethodObj(JSObject& obj);
/*
* Method name imputed from property uniquely assigned to or initialized,
* where the function does not need to be cloned to carry a scope chain or
* flattened upvars. This is set on both the original and cloned function.
*/
JSAtom *methodAtom() const {
return (joinable() && getSlot(JSSLOT_FUN_METHOD_ATOM).isString())
? &getSlot(JSSLOT_FUN_METHOD_ATOM).toString()->asAtom()
: NULL;
}
inline void setMethodAtom(JSAtom *atom);
inline void setJoinable();
JSScript *script() const {
@ -234,10 +201,6 @@ struct JSFunction : public JSObject_Slots2
return offsetof(JSFunction, u.nativeOrScript);
}
/* Number of extra fixed function object slots. */
static const uint32 CLASS_RESERVED_SLOTS = JSObject::FUN_CLASS_RESERVED_SLOTS;
js::Class *getConstructorClass() const {
JS_ASSERT(isNative());
return u.n.clasp;
@ -248,11 +211,67 @@ struct JSFunction : public JSObject_Slots2
u.n.clasp = clasp;
}
JSNativeTraceInfo *getTraceInfo() const {
JS_ASSERT(isNative());
JS_ASSERT(flags & JSFUN_TRCINFO);
return u.n.trcinfo;
#if JS_BITS_PER_WORD == 32
static const js::gc::AllocKind FinalizeKind = js::gc::FINALIZE_OBJECT2;
static const js::gc::AllocKind ExtendedFinalizeKind = js::gc::FINALIZE_OBJECT4;
#else
static const js::gc::AllocKind FinalizeKind = js::gc::FINALIZE_OBJECT4;
static const js::gc::AllocKind ExtendedFinalizeKind = js::gc::FINALIZE_OBJECT8;
#endif
inline void trace(JSTracer *trc);
private:
inline js::FunctionExtended *toExtended();
inline const js::FunctionExtended *toExtended() const;
inline bool isExtended() const {
JS_STATIC_ASSERT(FinalizeKind != ExtendedFinalizeKind);
JS_ASSERT(!!(flags & JSFUN_EXTENDED) == (getAllocKind() == ExtendedFinalizeKind));
return !!(flags & JSFUN_EXTENDED);
}
public:
/* Accessors for data stored in extended functions. */
inline void clearExtended();
inline void setNativeReserved(size_t which, const js::Value &val);
inline const js::Value &getNativeReserved(size_t which);
static inline size_t getFlatClosureUpvarsOffset();
inline js::Value *getFlatClosureUpvars() const;
inline js::Value getFlatClosureUpvar(uint32 i) const;
inline const js::Value &getFlatClosureUpvar(uint32 i);
inline void setFlatClosureUpvar(uint32 i, const js::Value &v);
inline void setFlatClosureUpvars(js::Value *upvars);
/* See comments in fun_finalize. */
inline void finalizeUpvars();
inline bool initBoundFunction(JSContext *cx, const js::Value &thisArg,
const js::Value *args, uintN argslen);
inline JSObject *getBoundFunctionTarget() const;
inline const js::Value &getBoundFunctionThis() const;
inline const js::Value &getBoundFunctionArgument(uintN which) const;
inline size_t getBoundFunctionArgumentCount() const;
/* Whether this is a function cloned from a method. */
inline bool isClonedMethod() const;
/* For a cloned method, pointer to the object the method was cloned for. */
inline JSObject *methodObj() const;
inline void setMethodObj(JSObject& obj);
/*
* Method name imputed from property uniquely assigned to or initialized,
* where the function does not need to be cloned to carry a scope chain or
* flattened upvars. This is set on both the original and cloned function.
*/
inline JSAtom *methodAtom() const;
inline void setMethodAtom(JSAtom *atom);
};
inline JSFunction *
@ -289,24 +308,26 @@ fun_toStringHelper(JSContext *cx, JSObject *obj, uintN indent);
extern JSFunction *
js_NewFunction(JSContext *cx, JSObject *funobj, JSNative native, uintN nargs,
uintN flags, JSObject *parent, JSAtom *atom);
uintN flags, JSObject *parent, JSAtom *atom,
js::gc::AllocKind kind = JSFunction::FinalizeKind);
extern void
js_FinalizeFunction(JSContext *cx, JSFunction *fun);
extern JSFunction * JS_FASTCALL
js_CloneFunctionObject(JSContext *cx, JSFunction *fun, JSObject *parent,
JSObject *proto);
js_CloneFunctionObject(JSContext *cx, JSFunction *fun, JSObject *parent, JSObject *proto,
js::gc::AllocKind kind = JSFunction::FinalizeKind);
extern JSObject * JS_FASTCALL
extern JSFunction * JS_FASTCALL
js_AllocFlatClosure(JSContext *cx, JSFunction *fun, JSObject *scopeChain);
extern JSObject *
extern JSFunction *
js_NewFlatClosure(JSContext *cx, JSFunction *fun, JSOp op, size_t oplen);
extern JSFunction *
js_DefineFunction(JSContext *cx, JSObject *obj, jsid id, JSNative native,
uintN nargs, uintN flags);
uintN nargs, uintN flags,
js::gc::AllocKind kind = JSFunction::FinalizeKind);
/*
* Flags for js_ValueToFunction and js_ReportIsNotFunction.
@ -359,8 +380,61 @@ SetCallVar(JSContext *cx, JSObject *obj, jsid id, JSBool strict, js::Value *vp);
extern JSBool
SetCallUpvar(JSContext *cx, JSObject *obj, jsid id, JSBool strict, js::Value *vp);
/*
* Function extended with extra fields used by specific kinds of functions.
* Most functions do not have these extensions, but enough are that efficient
* storage is required (no malloc'ed reserved slots).
*/
class FunctionExtended : public JSFunction
{
friend struct JSFunction;
union {
/* Reserved slots available for storage by particular native functions. */
Value nativeReserved[2];
/*
* Flat closures with one or more upvars snapshot the upvars' values
* into a vector of js::Values referenced from here.
*/
Value *flatClosureUpvars;
/* State for original and cloned method functions. */
struct {
/* Associated method property, needed for foo.caller handling. */
JSAtom *property;
/* If this is a clone, the object this was cloned as a property from. */
JSObject *obj;
} methodFunction;
} extu;
};
} // namespace js
inline js::FunctionExtended *
JSFunction::toExtended()
{
JS_ASSERT(isExtended());
return static_cast<js::FunctionExtended *>(this);
}
inline const js::FunctionExtended *
JSFunction::toExtended() const
{
JS_ASSERT(isExtended());
return static_cast<const js::FunctionExtended *>(this);
}
inline void
JSFunction::clearExtended()
{
JS_ASSERT(isExtended());
memset((char *)&this[1], 0, sizeof(js::FunctionExtended) - sizeof(JSFunction));
}
extern JSBool
js_GetArgsValue(JSContext *cx, js::StackFrame *fp, js::Value *vp);

View File

@ -67,34 +67,118 @@ inline void
JSFunction::setJoinable()
{
JS_ASSERT(isInterpreted());
setSlot(JSSLOT_FUN_METHOD_ATOM, js::NullValue());
flags |= JSFUN_JOINABLE;
}
inline bool
JSFunction::isClonedMethod() const
{
return getFixedSlot(JSSLOT_FUN_METHOD_OBJ).isObject();
return joinable() && isExtended() && toExtended()->extu.methodFunction.obj != NULL;
}
inline JSAtom *
JSFunction::methodAtom() const
{
return (joinable() && isExtended()) ? toExtended()->extu.methodFunction.property : NULL;
}
inline void
JSFunction::setMethodAtom(JSAtom *atom)
{
JS_ASSERT(joinable());
setSlot(JSSLOT_FUN_METHOD_ATOM, js::StringValue(atom));
toExtended()->extu.methodFunction.property = atom;
}
inline bool
JSFunction::hasMethodObj(const JSObject& obj) const
inline JSObject *
JSFunction::methodObj() const
{
return getFixedSlot(JSSLOT_FUN_METHOD_OBJ).isObject() &&
getFixedSlot(JSSLOT_FUN_METHOD_OBJ).toObject() == obj;
JS_ASSERT(joinable());
return isExtended() ? toExtended()->extu.methodFunction.obj : NULL;
}
inline void
JSFunction::setMethodObj(JSObject& obj)
{
setFixedSlot(JSSLOT_FUN_METHOD_OBJ, js::ObjectValue(obj));
JS_ASSERT(joinable());
toExtended()->extu.methodFunction.obj = &obj;
}
inline void
JSFunction::setNativeReserved(size_t which, const js::Value &val)
{
JS_ASSERT(isNative());
JS_ASSERT(which < JS_ARRAY_LENGTH(toExtended()->extu.nativeReserved));
toExtended()->extu.nativeReserved[which] = val;
}
inline const js::Value &
JSFunction::getNativeReserved(size_t which)
{
JS_ASSERT(isNative());
JS_ASSERT(which < JS_ARRAY_LENGTH(toExtended()->extu.nativeReserved));
return toExtended()->extu.nativeReserved[which];
}
inline js::Value *
JSFunction::getFlatClosureUpvars() const
{
JS_ASSERT(isFlatClosure());
JS_ASSERT(script()->bindings.countUpvars() == script()->upvars()->length);
return toExtended()->extu.flatClosureUpvars;
}
inline void
JSFunction::finalizeUpvars()
{
/*
* Cloned function objects may be flat closures with upvars to free.
*
* We must not access JSScript here that is stored in JSFunction. The
* script can be finalized before the function or closure instances. So we
* just check if JSSLOT_FLAT_CLOSURE_UPVARS holds a private value encoded
* as a double. We must also ignore newborn closures that do not have the
* private pointer set.
*
* FIXME bug 648320 - allocate upvars on the GC heap to avoid doing it
* here explicitly.
*/
JS_ASSERT(isFlatClosure());
if (isExtended() && toExtended()->extu.flatClosureUpvars)
js::Foreground::free_(toExtended()->extu.flatClosureUpvars);
}
inline js::Value
JSFunction::getFlatClosureUpvar(uint32 i) const
{
JS_ASSERT(i < script()->bindings.countUpvars());
return getFlatClosureUpvars()[i];
}
inline const js::Value &
JSFunction::getFlatClosureUpvar(uint32 i)
{
JS_ASSERT(i < script()->bindings.countUpvars());
return getFlatClosureUpvars()[i];
}
inline void
JSFunction::setFlatClosureUpvar(uint32 i, const js::Value &v)
{
JS_ASSERT(i < script()->bindings.countUpvars());
getFlatClosureUpvars()[i] = v;
}
inline void
JSFunction::setFlatClosureUpvars(js::Value *upvars)
{
JS_ASSERT(isFlatClosure());
toExtended()->extu.flatClosureUpvars = upvars;
}
/* static */ inline size_t
JSFunction::getFlatClosureUpvarsOffset()
{
return offsetof(js::FunctionExtended, extu.flatClosureUpvars);
}
namespace js {
@ -249,29 +333,34 @@ SkipScopeParent(JSObject *parent)
inline JSFunction *
CloneFunctionObject(JSContext *cx, JSFunction *fun, JSObject *parent,
bool ignoreSingletonClone = false)
gc::AllocKind kind = JSFunction::FinalizeKind)
{
JS_ASSERT(parent);
JSObject *proto;
if (!js_GetClassPrototype(cx, parent, JSProto_Function, &proto))
return NULL;
return js_CloneFunctionObject(cx, fun, parent, proto, kind);
}
inline JSFunction *
CloneFunctionObjectIfNotSingleton(JSContext *cx, JSFunction *fun, JSObject *parent)
{
/*
* For attempts to clone functions at a function definition opcode or from
* a method barrier, don't perform the clone if the function has singleton
* type. CloneFunctionObject was called pessimistically, and we need to
* preserve the type's property that if it is singleton there is only a
* single object with its type in existence.
* type. This was called pessimistically, and we need to preserve the
* type's property that if it is singleton there is only a single object
* with its type in existence.
*/
if (ignoreSingletonClone && fun->hasSingletonType()) {
JS_ASSERT(fun->getProto() == proto);
if (fun->hasSingletonType()) {
if (!fun->setParent(cx, SkipScopeParent(parent)))
return NULL;
fun->setCallScope(parent);
return fun;
}
return js_CloneFunctionObject(cx, fun, parent, proto);
return CloneFunctionObject(cx, fun, parent);
}
inline JSFunction *
@ -289,7 +378,8 @@ CloneFunctionObject(JSContext *cx, JSFunction *fun)
if (fun->hasSingletonType())
return fun;
return js_CloneFunctionObject(cx, fun, fun->callScope(), fun->getProto());
return js_CloneFunctionObject(cx, fun, fun->callScope(), fun->getProto(),
JSFunction::ExtendedFinalizeKind);
}
} /* namespace js */

View File

@ -135,7 +135,6 @@ const uint32 Arena::ThingSizes[] = {
sizeof(JSObject_Slots12), /* FINALIZE_OBJECT12_BACKGROUND */
sizeof(JSObject_Slots16), /* FINALIZE_OBJECT16 */
sizeof(JSObject_Slots16), /* FINALIZE_OBJECT16_BACKGROUND */
sizeof(JSFunction), /* FINALIZE_FUNCTION */
sizeof(JSScript), /* FINALIZE_SCRIPT */
sizeof(Shape), /* FINALIZE_SHAPE */
sizeof(BaseShape), /* FINALIZE_BASE_SHAPE */
@ -163,7 +162,6 @@ const uint32 Arena::FirstThingOffsets[] = {
OFFSET(JSObject_Slots12), /* FINALIZE_OBJECT12_BACKGROUND */
OFFSET(JSObject_Slots16), /* FINALIZE_OBJECT16 */
OFFSET(JSObject_Slots16), /* FINALIZE_OBJECT16_BACKGROUND */
OFFSET(JSFunction), /* FINALIZE_FUNCTION */
OFFSET(JSScript), /* FINALIZE_SCRIPT */
OFFSET(Shape), /* FINALIZE_SHAPE */
OFFSET(BaseShape), /* FINALIZE_BASE_SHAPE */
@ -388,7 +386,6 @@ FinalizeArenas(JSContext *cx, ArenaLists::ArenaList *al, AllocKind thingKind, bo
case FINALIZE_OBJECT12_BACKGROUND:
case FINALIZE_OBJECT16:
case FINALIZE_OBJECT16_BACKGROUND:
case FINALIZE_FUNCTION:
FinalizeTypedArenas<JSObject>(cx, al, thingKind, background);
break;
case FINALIZE_SCRIPT:
@ -1380,7 +1377,6 @@ ArenaLists::finalizeLater(JSContext *cx, AllocKind thingKind)
thingKind == FINALIZE_OBJECT8_BACKGROUND ||
thingKind == FINALIZE_OBJECT12_BACKGROUND ||
thingKind == FINALIZE_OBJECT16_BACKGROUND ||
thingKind == FINALIZE_FUNCTION ||
thingKind == FINALIZE_SHORT_STRING ||
thingKind == FINALIZE_STRING);
@ -1484,13 +1480,6 @@ ArenaLists::finalizeObjects(JSContext *cx)
finalizeLater(cx, FINALIZE_OBJECT16_BACKGROUND);
#endif
/*
* We must finalize Function instances after finalizing any other objects
* even if we use the background finalization for the latter. See comments
* in JSObject::finalizeUpvarsIfFlatClosure.
*/
finalizeLater(cx, FINALIZE_FUNCTION);
#if JS_HAS_XML_SUPPORT
finalizeNow(cx, FINALIZE_XML);
#endif

View File

@ -873,7 +873,6 @@ MapAllocToTraceKind(AllocKind thingKind)
JSTRACE_OBJECT, /* FINALIZE_OBJECT12_BACKGROUND */
JSTRACE_OBJECT, /* FINALIZE_OBJECT16 */
JSTRACE_OBJECT, /* FINALIZE_OBJECT16_BACKGROUND */
JSTRACE_OBJECT, /* FINALIZE_FUNCTION */
JSTRACE_SCRIPT, /* FINALIZE_SCRIPT */
JSTRACE_SHAPE, /* FINALIZE_SHAPE */
JSTRACE_BASE_SHAPE, /* FINALIZE_BASE_SHAPE */

View File

@ -81,7 +81,7 @@ static inline AllocKind
GetGCObjectKind(Class *clasp)
{
if (clasp == &FunctionClass)
return FINALIZE_FUNCTION;
return JSFunction::FinalizeKind;
uint32 nslots = JSCLASS_RESERVED_SLOTS(clasp);
if (clasp->flags & JSCLASS_HAS_PRIVATE)
nslots++;
@ -118,7 +118,7 @@ GetGCObjectFixedSlotsKind(size_t numFixedSlots)
static inline bool
IsBackgroundAllocKind(AllocKind kind)
{
JS_ASSERT(kind <= FINALIZE_FUNCTION);
JS_ASSERT(kind <= FINALIZE_OBJECT_LAST);
return kind % 2 == 1;
}
@ -154,7 +154,6 @@ GetGCKindSlots(AllocKind thingKind)
return 0;
case FINALIZE_OBJECT2:
case FINALIZE_OBJECT2_BACKGROUND:
case FINALIZE_FUNCTION:
return 2;
case FINALIZE_OBJECT4:
case FINALIZE_OBJECT4_BACKGROUND:
@ -178,10 +177,20 @@ static inline size_t
GetGCKindSlots(AllocKind thingKind, Class *clasp)
{
size_t nslots = GetGCKindSlots(thingKind);
/* An object's private data uses the space taken by its last fixed slot. */
if (clasp->flags & JSCLASS_HAS_PRIVATE) {
JS_ASSERT(nslots > 0);
nslots--;
}
/*
* Functions have a larger finalize kind than FINALIZE_OBJECT to reserve
* space for the extra fields in JSFunction, but have no fixed slots.
*/
if (clasp == &FunctionClass)
nslots = 0;
return nslots;
}
@ -392,7 +401,7 @@ NewGCThing(JSContext *cx, js::gc::AllocKind kind, size_t thingSize)
inline JSObject *
js_NewGCObject(JSContext *cx, js::gc::AllocKind kind)
{
JS_ASSERT(kind >= js::gc::FINALIZE_OBJECT0 && kind <= js::gc::FINALIZE_FUNCTION);
JS_ASSERT(kind >= js::gc::FINALIZE_OBJECT0 && kind <= js::gc::FINALIZE_OBJECT_LAST);
JSObject *obj = NewGCThing<JSObject>(cx, kind, js::gc::Arena::thingSize(kind));
if (obj)
obj->earlyInit();

View File

@ -6300,7 +6300,7 @@ JS_GetTypeInferenceObjectStats(void *object_, TypeInferenceMemoryStats *stats)
}
if (object->emptyShapes)
stats->emptyShapes += sizeof(EmptyShape*) * gc::FINALIZE_FUNCTION_AND_OBJECT_LAST;
stats->emptyShapes += sizeof(EmptyShape*) * gc::FINALIZE_OBJECT_LAST;
size_t bytes = object->dynamicSize();
stats->objects += bytes;

View File

@ -4261,8 +4261,7 @@ BEGIN_CASE(JSOP_CALLFCSLOT)
uintN index = GET_UINT16(regs.pc);
JSObject *obj = &argv[-2].toObject();
JS_ASSERT(index < obj->toFunction()->script()->bindings.countUpvars());
PUSH_COPY(obj->getFlatClosureUpvar(index));
PUSH_COPY(obj->toFunction()->getFlatClosureUpvar(index));
TypeScript::Monitor(cx, script, regs.pc, regs.sp[-1]);
if (op == JSOP_CALLFCSLOT)
PUSH_UNDEFINED();
@ -4357,7 +4356,7 @@ BEGIN_CASE(JSOP_DEFFUN)
* requests in server-side JS.
*/
if (obj->toFunction()->callScope() != obj2) {
obj = CloneFunctionObject(cx, fun, obj2, true);
obj = CloneFunctionObjectIfNotSingleton(cx, fun, obj2);
if (!obj)
goto error;
JS_ASSERT_IF(script->hasGlobal(), obj->getProto() == fun->getProto());
@ -4475,7 +4474,7 @@ BEGIN_CASE(JSOP_DEFLOCALFUN)
JSObject *obj = fun;
if (fun->isNullClosure()) {
obj = CloneFunctionObject(cx, fun, &regs.fp()->scopeChain(), true);
obj = CloneFunctionObjectIfNotSingleton(cx, fun, &regs.fp()->scopeChain());
if (!obj)
goto error;
} else {
@ -4489,7 +4488,7 @@ BEGIN_CASE(JSOP_DEFLOCALFUN)
if (TRACE_RECORDER(cx))
AbortRecording(cx, "DEFLOCALFUN for closure");
#endif
obj = CloneFunctionObject(cx, fun, parent, true);
obj = CloneFunctionObjectIfNotSingleton(cx, fun, parent);
if (!obj)
goto error;
}
@ -4553,8 +4552,7 @@ BEGIN_CASE(JSOP_LAMBDA)
JSObject *obj2 = &lref.toObject();
JS_ASSERT(obj2->isObject());
#endif
fun->setMethodAtom(script->getAtom(GET_FULL_INDEX(pc2 - regs.pc)));
JS_ASSERT(fun->methodAtom() == script->getAtom(GET_FULL_INDEX(pc2 - regs.pc)));
break;
}
@ -4565,7 +4563,7 @@ BEGIN_CASE(JSOP_LAMBDA)
#endif
const Value &lref = regs.sp[-1];
if (lref.isObject() && lref.toObject().canHaveMethodBarrier()) {
fun->setMethodAtom(script->getAtom(GET_FULL_INDEX(pc2 - regs.pc)));
JS_ASSERT(fun->methodAtom() == script->getAtom(GET_FULL_INDEX(pc2 - regs.pc)));
break;
}
} else if (op2 == JSOP_CALL) {
@ -4608,7 +4606,7 @@ BEGIN_CASE(JSOP_LAMBDA)
goto error;
}
obj = CloneFunctionObject(cx, fun, parent, true);
obj = CloneFunctionObjectIfNotSingleton(cx, fun, parent);
if (!obj)
goto error;
} while (0);

View File

@ -4545,31 +4545,13 @@ JSObject::updateSlotsForSpan(size_t oldSpan, size_t newSpan)
invalidateSlotRange(newSpan, oldSpan - newSpan);
}
#ifdef DEBUG
size_t
JSObject::numFixedSlotsFromAllocationKind(Class *clasp) const
{
/*
* For checking that the fixed slot information in a shape is consistent
* with the allocation kind of this object.
*/
gc::AllocKind kind = getAllocKind();
size_t slots = gc::GetGCKindSlots(kind);
if (clasp->flags & JSCLASS_HAS_PRIVATE) {
JS_ASSERT(slots > 0);
slots--;
}
return slots;
}
#endif
bool
JSObject::setInitialProperty(JSContext *cx, const js::Shape *shape)
{
JS_ASSERT(isNewborn());
JS_ASSERT(shape->compartment() == compartment());
JS_ASSERT(!shape->inDictionary());
JS_ASSERT(numFixedSlotsFromAllocationKind(shape->getObjectClass()) == shape->numFixedSlots());
JS_ASSERT(gc::GetGCKindSlots(getAllocKind(), shape->getObjectClass()) == shape->numFixedSlots());
size_t span = shape->slotSpan();
@ -4595,7 +4577,7 @@ JSObject::setInitialPropertyInfallible(const js::Shape *shape)
JS_ASSERT(isNewborn());
JS_ASSERT(shape->compartment() == compartment());
JS_ASSERT(!shape->inDictionary());
JS_ASSERT(numFixedSlotsFromAllocationKind(shape->getObjectClass()) == shape->numFixedSlots());
JS_ASSERT(gc::GetGCKindSlots(getAllocKind(), shape->getObjectClass()) == shape->numFixedSlots());
JS_ASSERT_IF(shape->getObjectClass()->ext.equality && !hasSingletonType(),
type()->hasAnyFlags(js::types::OBJECT_FLAG_SPECIAL_EQUALITY));

View File

@ -623,10 +623,6 @@ struct JSObject : js::gc::Cell
inline size_t numFixedSlots() const;
#ifdef DEBUG
size_t numFixedSlotsFromAllocationKind(js::Class *clasp) const;
#endif
static const uint32 MAX_FIXED_SLOTS = 16;
private:
@ -1048,50 +1044,11 @@ struct JSObject : js::gc::Cell
* Function-specific getters and setters.
*/
private:
friend struct JSFunction;
/*
* Flat closures with one or more upvars snapshot the upvars' values into a
* vector of js::Values referenced from this slot.
*/
static const uint32 JSSLOT_FLAT_CLOSURE_UPVARS = 0;
/*
* Null closures set or initialized as methods have these slots. See the
* "method barrier" comments and methods.
*/
static const uint32 JSSLOT_BOUND_FUNCTION_THIS = 0;
static const uint32 JSSLOT_BOUND_FUNCTION_ARGS_COUNT = 1;
public:
static const uint32 FUN_CLASS_RESERVED_SLOTS = 2;
static size_t getFlatClosureUpvarsOffset() {
return getFixedSlotOffset(JSSLOT_FLAT_CLOSURE_UPVARS);
}
inline JSFunction *toFunction();
inline const JSFunction *toFunction() const;
inline js::Value *getFlatClosureUpvars() const;
inline js::Value getFlatClosureUpvar(uint32 i) const;
inline const js::Value &getFlatClosureUpvar(uint32 i);
inline void setFlatClosureUpvar(uint32 i, const js::Value &v);
inline void setFlatClosureUpvars(js::Value *upvars);
/* See comments in fun_finalize. */
inline void finalizeUpvarsIfFlatClosure();
inline bool initBoundFunction(JSContext *cx, const js::Value &thisArg,
const js::Value *args, uintN argslen);
inline JSObject *getBoundFunctionTarget() const;
inline const js::Value &getBoundFunctionThis() const;
inline const js::Value &getBoundFunctionArgument(uintN which) const;
inline size_t getBoundFunctionArgumentCount() const;
public:
/*
* Iterator-specific getters and setters.

View File

@ -692,69 +692,6 @@ JSObject::setDateUTCTime(const js::Value &time)
setFixedSlot(JSSLOT_DATE_UTC_TIME, time);
}
inline js::Value *
JSObject::getFlatClosureUpvars() const
{
#ifdef DEBUG
const JSFunction *fun = toFunction();
JS_ASSERT(fun->isFlatClosure());
JS_ASSERT(fun->script()->bindings.countUpvars() == fun->script()->upvars()->length);
#endif
const js::Value &slot = getFixedSlot(JSSLOT_FLAT_CLOSURE_UPVARS);
return (js::Value *) (slot.isUndefined() ? NULL : slot.toPrivate());
}
inline void
JSObject::finalizeUpvarsIfFlatClosure()
{
/*
* Cloned function objects may be flat closures with upvars to free.
*
* We must not access JSScript here that is stored in JSFunction. The
* script can be finalized before the function or closure instances. So we
* just check if JSSLOT_FLAT_CLOSURE_UPVARS holds a private value encoded
* as a double. We must also ignore newborn closures that do not have the
* private pointer set.
*
* FIXME bug 648320 - allocate upvars on the GC heap to avoid doing it
* here explicitly.
*/
if (toFunction()->isFlatClosure()) {
const js::Value &v = getSlot(JSSLOT_FLAT_CLOSURE_UPVARS);
if (v.isDouble())
js::Foreground::free_(v.toPrivate());
}
}
inline js::Value
JSObject::getFlatClosureUpvar(uint32 i) const
{
JS_ASSERT(i < toFunction()->script()->bindings.countUpvars());
return getFlatClosureUpvars()[i];
}
inline const js::Value &
JSObject::getFlatClosureUpvar(uint32 i)
{
JS_ASSERT(i < toFunction()->script()->bindings.countUpvars());
return getFlatClosureUpvars()[i];
}
inline void
JSObject::setFlatClosureUpvar(uint32 i, const js::Value &v)
{
JS_ASSERT(i < toFunction()->script()->bindings.countUpvars());
getFlatClosureUpvars()[i] = v;
}
inline void
JSObject::setFlatClosureUpvars(js::Value *upvars)
{
JS_ASSERT(isFunction());
JS_ASSERT(toFunction()->isFlatClosure());
setFixedSlot(JSSLOT_FLAT_CLOSURE_UPVARS, js::PrivateValue(upvars));
}
inline js::NativeIterator *
JSObject::getNativeIterator() const
{
@ -1477,7 +1414,7 @@ static inline bool
CanBeFinalizedInBackground(gc::AllocKind kind, Class *clasp)
{
#ifdef JS_THREADSAFE
JS_ASSERT(kind <= gc::FINALIZE_FUNCTION);
JS_ASSERT(kind <= gc::FINALIZE_OBJECT_LAST);
/* If the class has no finalizer or a finalizer that is safe to call on
* a different thread, we change the finalize kind. For example,
* FINALIZE_OBJECT0 calls the finalizer on the main thread,
@ -1668,7 +1605,8 @@ NewObject(JSContext *cx, js::Class *clasp, JSObject *proto, JSObject *parent,
* The should be specialized by the template.
*/
JS_ASSERT((clasp == &FunctionClass) == (kind == gc::FINALIZE_FUNCTION));
JS_ASSERT_IF(clasp == &FunctionClass,
kind == JSFunction::FinalizeKind || kind == JSFunction::ExtendedFinalizeKind);
if (CanBeFinalizedInBackground(kind, clasp))
kind = GetBackgroundAllocKind(kind);
@ -1706,10 +1644,9 @@ NewObject(JSContext *cx, js::Class *clasp, JSObject *proto, JSObject *parent)
}
static JS_ALWAYS_INLINE JSFunction *
NewFunction(JSContext *cx, JSObject *parent)
NewFunction(JSContext *cx, JSObject *parent, gc::AllocKind kind)
{
JSObject *obj = NewObject<WithProto::Class>(cx, &FunctionClass, NULL, parent,
gc::FINALIZE_FUNCTION);
JSObject *obj = NewObject<WithProto::Class>(cx, &FunctionClass, NULL, parent, kind);
return static_cast<JSFunction *>(obj);
}

View File

@ -233,7 +233,7 @@ FunctionClassname(const JSFunction *fun)
{
if (!fun || fun->isInterpreted())
return Probes::nullName;
if (!(fun->flags & JSFUN_TRCINFO) && fun->getConstructorClass())
if (fun->getConstructorClass())
return fun->getConstructorClass()->name;
return Probes::nullName;
}

View File

@ -953,13 +953,12 @@ class ShapeKindArray
{
public:
static const uint32 SHAPE_COUNT =
((js::gc::FINALIZE_FUNCTION - js::gc::FINALIZE_OBJECT0) / 2) + 1;
((js::gc::FINALIZE_OBJECT_LAST - js::gc::FINALIZE_OBJECT0) / 2) + 1;
ShapeKindArray() { PodZero(this); }
Shape *&get(gc::AllocKind kind) {
JS_ASSERT(kind >= gc::FINALIZE_OBJECT0 &&
kind <= gc::FINALIZE_FUNCTION_AND_OBJECT_LAST);
JS_ASSERT(kind >= gc::FINALIZE_OBJECT0 && kind <= gc::FINALIZE_OBJECT_LAST);
int i = (kind - gc::FINALIZE_OBJECT0) / 2;
return shapes[i];
}
@ -974,7 +973,6 @@ class ShapeKindArray
void staticAsserts() {
JS_STATIC_ASSERT(gc::FINALIZE_OBJECT0 % 2 == 0);
JS_STATIC_ASSERT(gc::FINALIZE_FUNCTION == gc::FINALIZE_OBJECT_LAST + 1);
}
};

View File

@ -308,7 +308,7 @@ CheckScript(JSScript *script, JSScript *prev)
void
CheckScriptOwner(JSScript *script, JSObject *owner)
{
JS_OPT_ASSERT(script->ownerObject == owner);
// JS_OPT_ASSERT(script->ownerObject == owner);
if (owner != JS_NEW_SCRIPT && owner != JS_CACHED_SCRIPT)
JS_OPT_ASSERT(script->compartment() == owner->compartment());
}
@ -1231,10 +1231,16 @@ JSScript::NewScriptFromCG(JSContext *cx, JSCodeGenerator *cg)
if (cg->flags & TCF_FUN_HEAVYWEIGHT)
fun->flags |= JSFUN_HEAVYWEIGHT;
/* Watch for scripts whose functions will not be cloned. These are singletons. */
/*
* Mark functions which will only be executed once as singletons.
* Skip this for flat closures, which must be copied on executing.
*/
bool singleton =
cx->typeInferenceEnabled() && cg->parent && cg->parent->compiling() &&
cg->parent->asCodeGenerator()->checkSingletonContext();
cx->typeInferenceEnabled() &&
cg->parent &&
cg->parent->compiling() &&
cg->parent->asCodeGenerator()->checkSingletonContext() &&
!fun->isFlatClosure();
if (!script->typeSetFunction(cx, fun, singleton))
return NULL;

View File

@ -2174,7 +2174,7 @@ js::str_replace(JSContext *cx, uintN argc, Value *vp)
Value table = UndefinedValue();
if (JSOp(*pc) == JSOP_GETFCSLOT) {
table = rdata.lambda->getFlatClosureUpvar(GET_UINT16(pc));
table = fun->getFlatClosureUpvar(GET_UINT16(pc));
pc += JSOP_GETFCSLOT_LENGTH;
}

View File

@ -11460,6 +11460,8 @@ TraceRecorder::callNative(uintN argc, JSOp mode)
break;
}
JS_NOT_REACHED("FIXME");
#if 0
if (fun->flags & JSFUN_TRCINFO) {
JSNativeTraceInfo *trcinfo = fun->getTraceInfo();
JS_ASSERT(trcinfo && fun->u.n.native == trcinfo->native);
@ -11471,6 +11473,7 @@ TraceRecorder::callNative(uintN argc, JSOp mode)
return status;
}
}
#endif
if (native == js_fun_apply || native == js_fun_call)
RETURN_STOP("trying to call native apply or call");
@ -13416,6 +13419,8 @@ TraceRecorder::stackLoad(Address addr, uint8 type)
JS_REQUIRES_STACK AbortableRecordingStatus
TraceRecorder::record_JSOP_GETFCSLOT()
{
JS_NOT_REACHED("FIXME");
#if 0
JSObject& callee = cx->fp()->callee();
LIns* callee_ins = get(&cx->fp()->calleev());
@ -13426,6 +13431,7 @@ TraceRecorder::record_JSOP_GETFCSLOT()
FCSlotsAddress(upvars_ins, index),
snapshot(BRANCH_EXIT));
stack(0, v_ins);
#endif
return ARECORD_CONTINUE;
}
@ -15383,13 +15389,13 @@ TraceRecorder::record_JSOP_LAMBDA()
CHECK_STATUS_A(getClassPrototype(JSProto_Function, proto_ins));
LIns* scopeChain_ins = scopeChain();
JS_ASSERT(scopeChain_ins);
LIns* args[] = { proto_ins, scopeChain_ins, w.nameImmpNonGC(fun), cx_ins };
LIns* call_ins = w.call(&js_CloneFunctionObject_ci, args);
//LIns* args[] = { proto_ins, scopeChain_ins, w.nameImmpNonGC(fun), cx_ins };
LIns* call_ins = NULL; // w.call(&js_CloneFunctionObject_ci, args);
guard(false,
w.name(w.eqp0(call_ins), "guard(js_CloneFunctionObject)"),
OOM_EXIT);
stack(0, call_ins);
return ARECORD_CONTINUE;
}
@ -15405,8 +15411,8 @@ TraceRecorder::record_JSOP_LAMBDA_FC()
if (GetBlockChainFast(cx, cx->fp(), JSOP_LAMBDA_FC, JSOP_LAMBDA_FC_LENGTH))
RETURN_STOP_A("Unable to trace creating lambda in let");
LIns* args[] = { scopeChain(), w.immpFunGC(fun), cx_ins };
LIns* closure_ins = w.call(&js_AllocFlatClosure_ci, args);
// LIns* args[] = { scopeChain(), w.immpFunGC(fun), cx_ins };
LIns* closure_ins = NULL; // w.call(&js_AllocFlatClosure_ci, args);
guard(false,
w.name(w.eqp(closure_ins, w.immpNull()), "guard(js_AllocFlatClosure)"),
OOM_EXIT);
@ -15414,8 +15420,8 @@ TraceRecorder::record_JSOP_LAMBDA_FC()
JSScript *script = fun->script();
if (script->bindings.hasUpvars()) {
JSUpvarArray *uva = script->upvars();
LIns* upvars_ins = w.getObjPrivatizedSlot(closure_ins,
JSObject::JSSLOT_FLAT_CLOSURE_UPVARS);
LIns* upvars_ins = NULL; // w.getObjPrivatizedSlot(closure_ins,
// JSObject::JSSLOT_FLAT_CLOSURE_UPVARS);
for (uint32 i = 0, n = uva->length; i < n; i++) {
Value v;

View File

@ -2656,7 +2656,7 @@ mjit::Compiler::generateMethod()
frame.pop();
// obj->getFlatClosureUpvars()
Address upvarAddress(reg, JSObject::getFlatClosureUpvarsOffset());
Address upvarAddress(reg, JSFunction::getFlatClosureUpvarsOffset());
masm.loadPrivate(upvarAddress, reg);
// push ((Value *) reg)[index]

View File

@ -694,7 +694,7 @@ stubs::DefFun(VMFrame &f, JSFunction *fun)
* requests in server-side JS.
*/
if (obj->toFunction()->callScope() != obj2) {
obj = CloneFunctionObject(cx, fun, obj2, true);
obj = CloneFunctionObjectIfNotSingleton(cx, fun, obj2);
if (!obj)
THROW();
JS_ASSERT_IF(f.script()->compileAndGo, obj->getGlobal() == fun->getGlobal());
@ -1329,7 +1329,7 @@ stubs::DefLocalFun(VMFrame &f, JSFunction *fun)
JSObject *obj = fun;
if (fun->isNullClosure()) {
obj = CloneFunctionObject(f.cx, fun, &f.fp()->scopeChain(), true);
obj = CloneFunctionObjectIfNotSingleton(f.cx, fun, &f.fp()->scopeChain());
if (!obj)
THROWV(NULL);
} else {
@ -1339,7 +1339,7 @@ stubs::DefLocalFun(VMFrame &f, JSFunction *fun)
THROWV(NULL);
if (obj->toFunction()->callScope() != parent) {
obj = CloneFunctionObject(f.cx, fun, parent, true);
obj = CloneFunctionObjectIfNotSingleton(f.cx, fun, parent);
if (!obj)
THROWV(NULL);
}
@ -1385,7 +1385,7 @@ stubs::LambdaJoinableForInit(VMFrame &f, JSFunction *fun)
{
jsbytecode *nextpc = (jsbytecode *) f.scratch;
JS_ASSERT(fun->joinable());
fun->setMethodAtom(f.fp()->script()->getAtom(GET_SLOTNO(nextpc)));
JS_ASSERT(fun->methodAtom() == f.script()->getAtom(GET_SLOTNO(nextpc)));
return fun;
}
@ -1396,7 +1396,7 @@ stubs::LambdaJoinableForSet(VMFrame &f, JSFunction *fun)
jsbytecode *nextpc = (jsbytecode *) f.scratch;
const Value &lref = f.regs.sp[-1];
if (lref.isObject() && lref.toObject().canHaveMethodBarrier()) {
fun->setMethodAtom(f.fp()->script()->getAtom(GET_SLOTNO(nextpc)));
JS_ASSERT(fun->methodAtom() == f.script()->getAtom(GET_SLOTNO(nextpc)));
return fun;
}
return Lambda(f, fun);
@ -1456,7 +1456,7 @@ stubs::Lambda(VMFrame &f, JSFunction *fun)
THROWV(NULL);
}
JSObject *obj = CloneFunctionObject(f.cx, fun, parent, true);
JSObject *obj = CloneFunctionObjectIfNotSingleton(f.cx, fun, parent);
if (!obj)
THROWV(NULL);

View File

@ -557,7 +557,7 @@ void ValidateWriter::checkAccSet(LOpcode op, LIns *base, int32_t disp, AccSet ac
//
// base = <const private ptr slots[JSSLOT_FLAT_CLOSURE_UPVARS]>
// ins = {ld,st}X.fcslots base[...]
ok = isConstPrivatePtr(base, JSObject::JSSLOT_FLAT_CLOSURE_UPVARS);
ok = false; // isConstPrivatePtr(base, JSObject::JSSLOT_FLAT_CLOSURE_UPVARS);
break;
case ACCSET_ARGS_DATA:

View File

@ -2526,7 +2526,7 @@ static JSBool
DebuggerArguments_getArg(JSContext *cx, uintN argc, Value *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
int32 i = args.callee().getReservedSlot(0).toInt32();
int32 i = (int32) args.callee().toFunction()->getNativeReserved(0).toInt32();
/* Check that the this value is an Arguments object. */
if (!args.thisv().isObject()) {
@ -2599,16 +2599,17 @@ DebuggerFrame_getArguments(JSContext *cx, uintN argc, Value *vp)
}
for (int32 i = 0; i < fargc; i++) {
JSObject *getobj =
js_NewFunction(cx, NULL, DebuggerArguments_getArg, 0, 0, global, NULL);
JSFunction *getobj =
js_NewFunction(cx, NULL, DebuggerArguments_getArg, 0, 0, global, NULL,
JSFunction::ExtendedFinalizeKind);
if (!getobj ||
!js_SetReservedSlot(cx, getobj, 0, Int32Value(i)) ||
!DefineNativeProperty(cx, argsobj, INT_TO_JSID(i), UndefinedValue(),
JS_DATA_TO_FUNC_PTR(PropertyOp, getobj), NULL,
JSPROP_ENUMERATE | JSPROP_SHARED | JSPROP_GETTER, 0, 0))
{
return false;
}
getobj->setNativeReserved(0, Int32Value(i));
}
} else {
argsobj = NULL;

View File

@ -360,9 +360,9 @@ GlobalObject::isRuntimeCodeGenEnabled(JSContext *cx)
JSFunction *
GlobalObject::createConstructor(JSContext *cx, Native ctor, Class *clasp, JSAtom *name,
uintN length)
uintN length, gc::AllocKind kind)
{
JSFunction *fun = js_NewFunction(cx, NULL, ctor, length, JSFUN_CONSTRUCTOR, this, name);
JSFunction *fun = js_NewFunction(cx, NULL, ctor, length, JSFUN_CONSTRUCTOR, this, name, kind);
if (!fun)
return NULL;

View File

@ -167,7 +167,8 @@ class GlobalObject : public ::JSObject {
* ctor, a method which creates objects with the given class.
*/
JSFunction *
createConstructor(JSContext *cx, JSNative ctor, Class *clasp, JSAtom *name, uintN length);
createConstructor(JSContext *cx, JSNative ctor, Class *clasp, JSAtom *name, uintN length,
gc::AllocKind kind = JSFunction::FinalizeKind);
/*
* Create an object to serve as [[Prototype]] for instances of the given

View File

@ -3869,9 +3869,7 @@ nsXPCComponents_Utils::CreateObjectIn(const jsval &vobj, JSContext *cx, jsval *r
JSBool
FunctionWrapper(JSContext *cx, uintN argc, jsval *vp)
{
jsval v;
if (!JS_GetReservedSlot(cx, JSVAL_TO_OBJECT(JS_CALLEE(cx, vp)), 0, &v))
return JS_FALSE;
jsval v = js::GetFunctionNativeReserved(JSVAL_TO_OBJECT(JS_CALLEE(cx, vp)), 0);
NS_ASSERTION(JSVAL_IS_OBJECT(v), "weird function");
return JS_CallFunctionValue(cx, JS_THIS_OBJECT(cx, vp), v,
@ -3887,8 +3885,7 @@ WrapCallable(JSContext *cx, JSObject *obj, jsid id, JSObject *propobj, jsval *vp
return JS_FALSE;
JSObject *funobj = JS_GetFunctionObject(fun);
if (!JS_SetReservedSlot(cx, funobj, 0, OBJECT_TO_JSVAL(propobj)))
return JS_FALSE;
js::SetFunctionNativeReserved(funobj, 0, OBJECT_TO_JSVAL(propobj));
*vp = OBJECT_TO_JSVAL(funobj);
return JS_TRUE;
}

View File

@ -1664,6 +1664,13 @@ ReportCompartmentStats(const CompartmentStats &stats,
"property accesses fast.",
callback, closure);
ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
"gc-heap/base-shapes"),
JS_GC_HEAP_KIND, stats.gcHeapKinds[JSTRACE_BASE_SHAPE],
"Memory on the compartment's garbage-collected JavaScript heap that collates "
"data common to many shapes.",
callback, closure);
ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
"gc-heap/type-objects"),
JS_GC_HEAP_KIND, stats.gcHeapKinds[JSTRACE_TYPE_OBJECT],

View File

@ -148,15 +148,13 @@ PropertyOpForwarder(JSContext *cx, uintN argc, jsval *vp)
JSObject *obj = JS_THIS_OBJECT(cx, vp);
if (!obj)
return JS_FALSE;
jsval v;
if (!JS_GetReservedSlot(cx, callee, 0, &v))
return JS_FALSE;
jsval v = js::GetFunctionNativeReserved(callee, 0);
JSObject *ptrobj = JSVAL_TO_OBJECT(v);
Op *popp = static_cast<Op *>(JS_GetPrivate(cx, ptrobj));
if (!JS_GetReservedSlot(cx, callee, 1, &v))
return JS_FALSE;
v = js::GetFunctionNativeReserved(callee, 1);
jsval argval = (argc > 0) ? JS_ARGV(cx, vp)[0] : JSVAL_VOID;
jsid id;
@ -207,8 +205,8 @@ GeneratePropertyOp(JSContext *cx, JSObject *obj, jsid id, uintN argc, Op pop)
*popp = pop;
JS_SetPrivate(cx, ptrobj, popp);
JS_SetReservedSlot(cx, funobj, 0, OBJECT_TO_JSVAL(ptrobj));
JS_SetReservedSlot(cx, funobj, 1, js::IdToJsval(id));
js::SetFunctionNativeReserved(funobj, 0, OBJECT_TO_JSVAL(ptrobj));
js::SetFunctionNativeReserved(funobj, 1, js::IdToJsval(id));
return funobj;
}

View File

@ -72,14 +72,10 @@ xpc_CloneJSFunction(XPCCallContext &ccx, JSObject *funobj, JSObject *parent)
JS_SetPrototype(ccx, clone, scope->GetPrototypeJSFunction());
// Copy the reserved slots to the clone.
jsval ifaceVal, memberVal;
if (!JS_GetReservedSlot(ccx, funobj, 0, &ifaceVal) ||
!JS_GetReservedSlot(ccx, funobj, 1, &memberVal))
return nsnull;
if (!JS_SetReservedSlot(ccx, clone, 0, ifaceVal) ||
!JS_SetReservedSlot(ccx, clone, 1, memberVal))
return nsnull;
jsval ifaceVal = js::GetFunctionNativeReserved(funobj, 0);
jsval memberVal = js::GetFunctionNativeReserved(funobj, 1);
js::SetFunctionNativeReserved(clone, 0, ifaceVal);
js::SetFunctionNativeReserved(clone, 1, memberVal);
return clone;
}
@ -94,8 +90,8 @@ XPCNativeMember::GetCallInfo(XPCCallContext& ccx,
XPCNativeMember** pMember)
{
funobj = js::UnwrapObject(funobj);
jsval ifaceVal = js::GetReservedSlot(funobj, 0);
jsval memberVal = js::GetReservedSlot(funobj, 1);
jsval ifaceVal = js::GetFunctionNativeReserved(funobj, 0);
jsval memberVal = js::GetFunctionNativeReserved(funobj, 1);
*pInterface = (XPCNativeInterface*) JSVAL_TO_PRIVATE(ifaceVal);
*pMember = (XPCNativeMember*) JSVAL_TO_PRIVATE(memberVal);
@ -172,9 +168,8 @@ XPCNativeMember::Resolve(XPCCallContext& ccx, XPCNativeInterface* iface,
if (!funobj)
return JS_FALSE;
if (!JS_SetReservedSlot(ccx, funobj, 0, PRIVATE_TO_JSVAL(iface))||
!JS_SetReservedSlot(ccx, funobj, 1, PRIVATE_TO_JSVAL(this)))
return JS_FALSE;
js::SetFunctionNativeReserved(funobj, 0, PRIVATE_TO_JSVAL(iface));
js::SetFunctionNativeReserved(funobj, 1, PRIVATE_TO_JSVAL(this));
*vp = OBJECT_TO_JSVAL(funobj);