mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Remove JSFunction fixed slots and unused fields, bug 697537.
This commit is contained in:
parent
f90413cb77
commit
a9c68ac54d
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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>();
|
||||
|
@ -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;
|
||||
|
@ -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.
|
||||
|
@ -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)
|
||||
{
|
||||
|
165
js/src/jsfun.cpp
165
js/src/jsfun.cpp
@ -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;
|
||||
|
||||
|
176
js/src/jsfun.h
176
js/src/jsfun.h
@ -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);
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -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
|
||||
|
@ -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 */
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
@ -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, ®s.fp()->scopeChain(), true);
|
||||
obj = CloneFunctionObjectIfNotSingleton(cx, fun, ®s.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);
|
||||
|
@ -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));
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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]
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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],
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user