Bug 739808: Remove method cloning optimization and method barrier, r=luke

--HG--
extra : rebase_source : d383c3704c3efd08f9fbf1324433a94fc4a8dbb8
This commit is contained in:
David Mandelin 2012-03-23 17:59:56 -07:00
Родитель 0f7e28d9b2
Коммит 0fb86f4f13
44 изменённых файлов: 127 добавлений и 1154 удалений

Просмотреть файл

@ -4565,43 +4565,6 @@ EmitWith(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
return PopStatementBCE(cx, bce); return PopStatementBCE(cx, bce);
} }
static bool
SetMethodFunction(JSContext *cx, FunctionBox *funbox, JSAtom *atom)
{
RootedVarObject parent(cx);
parent = funbox->function()->getParent();
/*
* Replace a boxed function with a new one with a method atom. Methods
* require a function with the extended size finalize kind, which normal
* functions don't have. We don't eagerly allocate functions with the
* expanded size for boxed functions, as most functions are not methods.
*/
JSFunction *fun = js_NewFunction(cx, NULL, NULL,
funbox->function()->nargs,
funbox->function()->flags,
parent,
funbox->function()->atom,
JSFunction::ExtendedFinalizeKind);
if (!fun)
return false;
JSScript *script = funbox->function()->script();
if (script) {
fun->setScript(script);
if (!script->typeSetFunction(cx, fun))
return false;
}
JS_ASSERT(funbox->function()->joinable());
fun->setJoinable();
fun->setMethodAtom(atom);
funbox->object = fun;
return true;
}
static bool static bool
EmitForIn(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn, ptrdiff_t top) EmitForIn(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn, ptrdiff_t top)
{ {
@ -5371,23 +5334,6 @@ EmitStatement(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
} }
#endif #endif
if (op != JSOP_NOP) { if (op != JSOP_NOP) {
/*
* Specialize JSOP_SETPROP to JSOP_SETMETHOD to defer or
* avoid null closure cloning. Do this only for assignment
* statements that are not completion values wanted by a
* script evaluator, to ensure that the joined function
* can't escape directly.
*/
if (!wantval &&
pn2->isKind(PNK_ASSIGN) &&
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 false;
pn2->pn_left->setOp(JSOP_SETMETHOD);
}
if (!EmitTree(cx, bce, pn2)) if (!EmitTree(cx, bce, pn2))
return false; return false;
if (Emit1(cx, bce, op) < 0) if (Emit1(cx, bce, op) < 0)
@ -5894,28 +5840,13 @@ EmitObject(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
if (!bce->makeAtomIndex(pn3->pn_atom, &index)) if (!bce->makeAtomIndex(pn3->pn_atom, &index))
return false; return false;
/* Check whether we can optimize to JSOP_INITMETHOD. */ /*
ParseNode *init = pn2->pn_right; * Disable NEWOBJECT on initializers that set __proto__, which has
bool lambda = init->isOp(JSOP_LAMBDA); * a non-standard setter on objects.
if (lambda) */
++methodInits; if (pn3->pn_atom == cx->runtime->atomState.protoAtom)
if (op == JSOP_INITPROP && lambda && init->pn_funbox->joinable()) {
obj = NULL; obj = NULL;
op = JSOP_INITMETHOD; op = JSOP_INITPROP;
if (!SetMethodFunction(cx, init->pn_funbox, pn3->pn_atom))
return JS_FALSE;
pn2->setOp(op);
} else {
/*
* Disable NEWOBJECT on initializers that set __proto__, which has
* a non-standard setter on objects.
*/
if (pn3->pn_atom == cx->runtime->atomState.protoAtom)
obj = NULL;
op = JSOP_INITPROP;
if (lambda)
++slowMethodInits;
}
if (obj) { if (obj) {
JS_ASSERT(!obj->inDictionaryMode()); JS_ASSERT(!obj->inDictionaryMode());

Просмотреть файл

@ -108,15 +108,6 @@ ParseNode::clear()
pn_parens = false; pn_parens = false;
} }
bool
FunctionBox::joinable() const
{
return function()->isNullClosure() &&
(tcflags & (TCF_FUN_USES_ARGUMENTS |
TCF_FUN_USES_OWN_NAME |
TCF_COMPILE_N_GO)) == TCF_COMPILE_N_GO;
}
bool bool
FunctionBox::inAnyDynamicScope() const FunctionBox::inAnyDynamicScope() const
{ {

Просмотреть файл

@ -1554,8 +1554,6 @@ struct FunctionBox : public ObjectBox
JSFunction *function() const { return (JSFunction *) object; } JSFunction *function() const { return (JSFunction *) object; }
bool joinable() const;
/* /*
* True if this function is inside the scope of a with-statement, an E4X * True if this function is inside the scope of a with-statement, an E4X
* filter-expression, or a function that uses direct eval. * filter-expression, or a function that uses direct eval.

Просмотреть файл

@ -1069,8 +1069,6 @@ LeaveFunction(ParseNode *fn, TreeContext *funtc, PropertyName *funName = NULL,
dn->setOp(JSOP_CALLEE); dn->setOp(JSOP_CALLEE);
dn->pn_cookie.set(funtc->staticLevel, UpvarCookie::CALLEE_SLOT); dn->pn_cookie.set(funtc->staticLevel, UpvarCookie::CALLEE_SLOT);
dn->pn_dflags |= PND_BOUND; dn->pn_dflags |= PND_BOUND;
funbox->tcflags |= TCF_FUN_USES_OWN_NAME;
foundCallee = 1; foundCallee = 1;
continue; continue;
} }
@ -2049,7 +2047,7 @@ DefineGlobal(ParseNode *pn, BytecodeEmitter *bce, PropertyName *name)
globalObj != holder || globalObj != holder ||
shape->configurable() || shape->configurable() ||
!shape->hasSlot() || !shape->hasSlot() ||
!shape->hasDefaultGetterOrIsMethod() || !shape->hasDefaultGetter() ||
!shape->hasDefaultSetter()) { !shape->hasDefaultSetter()) {
return true; return true;
} }

Просмотреть файл

@ -217,9 +217,6 @@ SetFunctionKinds(FunctionBox *funbox, uint32_t *tcflags, bool isDirectEval)
FlagHeavyweights(lexdep, funbox, tcflags); FlagHeavyweights(lexdep, funbox, tcflags);
} }
} }
if (funbox->joinable())
fun->setJoinable();
} }
} }

Просмотреть файл

@ -1,51 +0,0 @@
var shapes = {};
function stringify(a) {
assertEq(shapes[shapeOf(a)], undefined);
shapes[shapeOf(a)] = 1;
var b = "";
for (var c in a) {
b += c + ":";
if (typeof a[c] == "function")
b += "function,";
else
b += a[c] + ",";
}
return b;
}
function test1() {
return stringify({a: 0, b: 1, a: function() {} });
}
for (var i = 0; i < 3; i++)
assertEq(test1(), "a:function,b:1,");
// This does not cause the object to go to dictionary mode, unlike the above.
function test2() {
return stringify({a: 0, b: 1, a: 2, b: 3});
}
assertEq(test2(), "a:2,b:3,");
function test3() {
return stringify({
aa:0,ab:1,ac:2,ad:3,ae:4,af:5,ag:6,ah:7,ai:8,aj:9,
ba:0,bb:1,bc:2,bd:3,be:4,bf:5,bg:6,bh:7,bi:8,bj:9,
ca:0,cb:1,cc:2,cd:3,ce:4,cf:5,cg:6,ch:7,ci:8,cj:9,
da:0,db:1,dc:2,dd:3,de:4,df:5,dg:6,dh:7,di:8,dj:9,
ea:0,eb:1,ec:2,ed:3,ee:4,ef:5,eg:6,eh:7,ei:8,ej:9,
fa:0,fb:1,fc:2,fd:3,fe:4,ff:5,fg:6,fh:7,fi:8,fj:9,
ga:0,gb:1,gc:2,gd:3,ge:4,gf:5,gg:6,gh:7,gi:8,gj:9,
ha:0,hb:1,hc:2,hd:3,he:4,hf:5,hg:6,hh:7,hi:8,hj:9,
ia:0,ib:1,ic:2,id:3,ie:4,if:5,ig:6,ih:7,ii:8,ij:9,
ja:0,jb:1,jc:2,jd:3,je:4,jf:5,jg:6,jh:7,ji:8,jj:9,
ka:0,kb:1,kc:2,kd:3,ke:4,kf:5,kg:6,kh:7,ki:8,kj:9,
la:0,lb:1,lc:2,ld:3,le:4,lf:5,lg:6,lh:7,li:8,lj:9,
ma:0,mb:1,mc:2,md:3,me:4,mf:5,mg:6,mh:7,mi:8,mj:9,
na:0,nb:1,nc:2,nd:3,ne:4,nf:5,ng:6,nh:7,ni:8,nj:9,
oa:0,ob:1,oc:2,od:3,oe:4,of:5,og:6,oh:7,oi:8,oj:9,
pa:0,pb:1,pc:2,pd:3,pe:4,pf:5,pg:6,ph:7,pi:8,pj:9,
});
}
for (var i = 0; i < 10; i++)
assertEq(test3(), "aa:0,ab:1,ac:2,ad:3,ae:4,af:5,ag:6,ah:7,ai:8,aj:9,ba:0,bb:1,bc:2,bd:3,be:4,bf:5,bg:6,bh:7,bi:8,bj:9,ca:0,cb:1,cc:2,cd:3,ce:4,cf:5,cg:6,ch:7,ci:8,cj:9,da:0,db:1,dc:2,dd:3,de:4,df:5,dg:6,dh:7,di:8,dj:9,ea:0,eb:1,ec:2,ed:3,ee:4,ef:5,eg:6,eh:7,ei:8,ej:9,fa:0,fb:1,fc:2,fd:3,fe:4,ff:5,fg:6,fh:7,fi:8,fj:9,ga:0,gb:1,gc:2,gd:3,ge:4,gf:5,gg:6,gh:7,gi:8,gj:9,ha:0,hb:1,hc:2,hd:3,he:4,hf:5,hg:6,hh:7,hi:8,hj:9,ia:0,ib:1,ic:2,id:3,ie:4,if:5,ig:6,ih:7,ii:8,ij:9,ja:0,jb:1,jc:2,jd:3,je:4,jf:5,jg:6,jh:7,ji:8,jj:9,ka:0,kb:1,kc:2,kd:3,ke:4,kf:5,kg:6,kh:7,ki:8,kj:9,la:0,lb:1,lc:2,ld:3,le:4,lf:5,lg:6,lh:7,li:8,lj:9,ma:0,mb:1,mc:2,md:3,me:4,mf:5,mg:6,mh:7,mi:8,mj:9,na:0,nb:1,nc:2,nd:3,ne:4,nf:5,ng:6,nh:7,ni:8,nj:9,oa:0,ob:1,oc:2,od:3,oe:4,of:5,og:6,oh:7,oi:8,oj:9,pa:0,pb:1,pc:2,pd:3,pe:4,pf:5,pg:6,ph:7,pi:8,pj:9,");

Просмотреть файл

@ -617,11 +617,9 @@ ScriptAnalysis::analyzeBytecode(JSContext *cx)
case JSOP_NEWARRAY: case JSOP_NEWARRAY:
case JSOP_NEWOBJECT: case JSOP_NEWOBJECT:
case JSOP_ENDINIT: case JSOP_ENDINIT:
case JSOP_INITMETHOD:
case JSOP_INITPROP: case JSOP_INITPROP:
case JSOP_INITELEM: case JSOP_INITELEM:
case JSOP_SETPROP: case JSOP_SETPROP:
case JSOP_SETMETHOD:
case JSOP_IN: case JSOP_IN:
case JSOP_INSTANCEOF: case JSOP_INSTANCEOF:
case JSOP_LINENO: case JSOP_LINENO:
@ -1522,7 +1520,6 @@ ScriptAnalysis::analyzeSSA(JSContext *cx)
break; break;
case JSOP_INITPROP: case JSOP_INITPROP:
case JSOP_INITMETHOD:
stack[stackDepth - 1].v = code->poppedValues[1]; stack[stackDepth - 1].v = code->poppedValues[1];
break; break;

Просмотреть файл

@ -28,7 +28,6 @@ BEGIN_TEST(testLookup_bug522590)
JSObject *funobj = JSVAL_TO_OBJECT(r); JSObject *funobj = JSVAL_TO_OBJECT(r);
CHECK(funobj->isFunction()); CHECK(funobj->isFunction());
CHECK(!js::IsInternalFunctionObject(funobj)); CHECK(!js::IsInternalFunctionObject(funobj));
CHECK(funobj->toFunction()->isClonedMethod());
return true; return true;
} }

Просмотреть файл

@ -3455,11 +3455,6 @@ LookupResult(JSContext *cx, JSObject *obj, JSObject *obj2, jsid id,
if (obj2->isNative()) { if (obj2->isNative()) {
Shape *shape = (Shape *) prop; Shape *shape = (Shape *) prop;
if (shape->isMethod()) {
vp->setObject(*obj2->nativeGetMethod(shape));
return !!obj2->methodReadBarrier(cx, *shape, vp);
}
/* Peek at the native property's slot value, without doing a Get. */ /* Peek at the native property's slot value, without doing a Get. */
if (shape->hasSlot()) { if (shape->hasSlot()) {
*vp = obj2->nativeGetSlot(shape->slot()); *vp = obj2->nativeGetSlot(shape->slot());
@ -3855,19 +3850,12 @@ GetPropertyDescriptorById(JSContext *cx, JSObject *obj, jsid id, unsigned flags,
if (obj2->isNative()) { if (obj2->isNative()) {
Shape *shape = (Shape *) prop; Shape *shape = (Shape *) prop;
desc->attrs = shape->attributes(); desc->attrs = shape->attributes();
desc->getter = shape->getter();
if (shape->isMethod()) { desc->setter = shape->setter();
desc->getter = JS_PropertyStub; if (shape->hasSlot())
desc->setter = JS_StrictPropertyStub; desc->value = obj2->nativeGetSlot(shape->slot());
desc->value.setObject(*obj2->nativeGetMethod(shape)); else
} else { desc->value.setUndefined();
desc->getter = shape->getter();
desc->setter = shape->setter();
if (shape->hasSlot())
desc->value = obj2->nativeGetSlot(shape->slot());
else
desc->value.setUndefined();
}
} else { } else {
if (obj2->isProxy()) { if (obj2->isProxy()) {
JSAutoResolveFlags rf(cx, flags); JSAutoResolveFlags rf(cx, flags);
@ -3968,8 +3956,9 @@ SetPropertyAttributesById(JSContext *cx, JSObject *obj, jsid id, unsigned attrs,
*foundp = false; *foundp = false;
return true; return true;
} }
Shape *shape = (Shape *) prop;
JSBool ok = obj->isNative() JSBool ok = obj->isNative()
? js_SetNativeAttributes(cx, obj, (Shape *) prop, attrs) ? obj->changePropertyAttributes(cx, shape, attrs)
: obj->setGenericAttributes(cx, id, &attrs); : obj->setGenericAttributes(cx, id, &attrs);
if (ok) if (ok)
*foundp = true; *foundp = true;
@ -4072,7 +4061,7 @@ JS_GetMethodById(JSContext *cx, JSObject *obj, jsid id, JSObject **objp, jsval *
AssertNoGC(cx); AssertNoGC(cx);
CHECK_REQUEST(cx); CHECK_REQUEST(cx);
assertSameCompartment(cx, obj, id); assertSameCompartment(cx, obj, id);
if (!js_GetMethod(cx, obj, id, JSGET_METHOD_BARRIER, vp)) if (!js_GetMethod(cx, obj, id, 0, vp))
return JS_FALSE; return JS_FALSE;
if (objp) if (objp)
*objp = obj; *objp = obj;
@ -5366,7 +5355,7 @@ JS_CallFunctionName(JSContext *cx, JSObject *obj, const char *name, unsigned arg
Value v; Value v;
JSAtom *atom = js_Atomize(cx, name, strlen(name)); JSAtom *atom = js_Atomize(cx, name, strlen(name));
return atom && return atom &&
js_GetMethod(cx, obj, ATOM_TO_JSID(atom), JSGET_NO_METHOD_BARRIER, &v) && js_GetMethod(cx, obj, ATOM_TO_JSID(atom), 0, &v) &&
Invoke(cx, ObjectOrNullValue(obj), v, argc, argv, rval); Invoke(cx, ObjectOrNullValue(obj), v, argc, argv, rval);
} }

Просмотреть файл

@ -644,17 +644,6 @@ JS_GetFrameCalleeObject(JSContext *cx, JSStackFrame *fp)
return Valueify(fp)->maybeCalleev().toObjectOrNull(); return Valueify(fp)->maybeCalleev().toObjectOrNull();
} }
JS_PUBLIC_API(JSBool)
JS_GetValidFrameCalleeObject(JSContext *cx, JSStackFrame *fp, jsval *vp)
{
Value v;
if (!Valueify(fp)->getValidCalleeObject(cx, &v))
return false;
*vp = v.isObject() ? v : JSVAL_VOID;
return true;
}
JS_PUBLIC_API(JSBool) JS_PUBLIC_API(JSBool)
JS_IsDebuggerFrame(JSContext *cx, JSStackFrame *fp) JS_IsDebuggerFrame(JSContext *cx, JSStackFrame *fp)
{ {

Просмотреть файл

@ -292,39 +292,10 @@ JS_SetFrameReturnValue(JSContext *cx, JSStackFrame *fp, jsval rval);
* Return fp's callee function object (fp->callee) if it has one. Note that * Return fp's callee function object (fp->callee) if it has one. Note that
* this API cannot fail. A null return means "no callee": fp is a global or * this API cannot fail. A null return means "no callee": fp is a global or
* eval-from-global frame, not a call frame. * eval-from-global frame, not a call frame.
*
* This API began life as an infallible getter, but now it can return either:
*
* 1. An optimized closure that was compiled assuming the function could not
* escape and be called from sites the compiler could not see.
*
* 2. A "joined function object", an optimization whereby SpiderMonkey avoids
* creating fresh function objects for every evaluation of a function
* expression that is used only once by a consumer that either promises to
* clone later when asked for the value or that cannot leak the value.
*
* Because Mozilla's Gecko embedding of SpiderMonkey (and no doubt other
* embeddings) calls this API in potentially performance-sensitive ways (e.g.
* in nsContentUtils::GetDocumentFromCaller), we are leaving this API alone. It
* may now return an unwrapped non-escaping optimized closure, or a joined
* function object. Such optimized objects may work well if called from the
* correct context, never mutated or compared for identity, etc.
*
* However, if you really need to get the same callee object that JS code would
* see, which means undoing the optimizations, where an undo attempt can fail,
* then use JS_GetValidFrameCalleeObject.
*/ */
extern JS_PUBLIC_API(JSObject *) extern JS_PUBLIC_API(JSObject *)
JS_GetFrameCalleeObject(JSContext *cx, JSStackFrame *fp); JS_GetFrameCalleeObject(JSContext *cx, JSStackFrame *fp);
/**
* Return fp's callee function object after running the deferred closure
* cloning "method read barrier". This API can fail! If the frame has no
* callee, this API returns true with JSVAL_IS_VOID(*vp).
*/
extern JS_PUBLIC_API(JSBool)
JS_GetValidFrameCalleeObject(JSContext *cx, JSStackFrame *fp, jsval *vp);
/************************************************************************/ /************************************************************************/
extern JS_PUBLIC_API(const char *) extern JS_PUBLIC_API(const char *)

Просмотреть файл

@ -97,107 +97,6 @@ using namespace js;
using namespace js::gc; using namespace js::gc;
using namespace js::types; using namespace js::types;
bool
StackFrame::getValidCalleeObject(JSContext *cx, Value *vp)
{
if (!isFunctionFrame()) {
vp->setNull();
return true;
}
JSFunction *fun = this->callee().toFunction();
vp->setObject(*fun);
/*
* Check for an escape attempt by a joined function object, which must go
* through the frame's |this| object's method read barrier for the method
* atom by which it was uniquely associated with a property.
*/
const Value &thisv = functionThis();
if (thisv.isObject() && fun->methodAtom() && !fun->isClonedMethod()) {
JSObject *thisp = &thisv.toObject();
JSObject *first_barriered_thisp = NULL;
do {
/*
* While a non-native object is responsible for handling its
* entire prototype chain, notable non-natives including dense
* and typed arrays have native prototypes, so keep going.
*/
if (!thisp->isNative())
continue;
const Shape *shape = thisp->nativeLookup(cx, ATOM_TO_JSID(fun->methodAtom()));
if (shape) {
/*
* Two cases follow: the method barrier was not crossed
* yet, so we cross it here; the method barrier *was*
* crossed but after the call, in which case we fetch
* and validate the cloned (unjoined) funobj from the
* method property's slot.
*
* In either case we must allow for the method property
* to have been replaced, or its value overwritten.
*/
if (shape->isMethod() && thisp->nativeGetMethod(shape) == fun) {
if (!thisp->methodReadBarrier(cx, *shape, vp))
return false;
overwriteCallee(vp->toObject());
return true;
}
if (shape->hasSlot()) {
Value v = thisp->getSlot(shape->slot());
JSFunction *clone;
if (IsFunctionObject(v, &clone) &&
clone->isInterpreted() &&
clone->script() == fun->script() &&
clone->methodObj() == thisp) {
/*
* N.B. If the method barrier was on a function
* with singleton type, then while crossing the
* method barrier CloneFunctionObject will have
* ignored the attempt to clone the function.
*/
JS_ASSERT_IF(!clone->hasSingletonType(), clone != fun);
*vp = v;
overwriteCallee(*clone);
return true;
}
}
}
if (!first_barriered_thisp)
first_barriered_thisp = thisp;
} while ((thisp = thisp->getProto()) != NULL);
if (!first_barriered_thisp)
return true;
/*
* At this point, we couldn't find an already-existing clone (or
* force to exist a fresh clone) created via thisp's method read
* barrier, so we must clone fun and store it in fp's callee to
* avoid re-cloning upon repeated foo.caller access.
*
* This must mean the code in js_DeleteGeneric could not find this
* stack frame on the stack when the method was deleted. We've lost
* track of the method, so we associate it with the first barriered
* object found starting from thisp on the prototype chain.
*/
JSFunction *newfunobj = CloneFunctionObject(cx, fun);
if (!newfunobj)
return false;
newfunobj->setMethodObj(*first_barriered_thisp);
overwriteCallee(*newfunobj);
vp->setObject(*newfunobj);
return true;
}
return true;
}
static JSBool static JSBool
fun_getProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp) fun_getProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp)
{ {
@ -227,10 +126,7 @@ fun_getProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp)
for (; fp; fp = fp->prev()) { for (; fp; fp = fp->prev()) {
if (!fp->isFunctionFrame() || fp->isEvalFrame()) if (!fp->isFunctionFrame() || fp->isEvalFrame())
continue; continue;
Value callee; if (fp->callee().toFunction() == fun)
if (!fp->getValidCalleeObject(cx, &callee))
return false;
if (&callee.toObject() == fun)
break; break;
} }
if (!fp) if (!fp)
@ -277,14 +173,13 @@ fun_getProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp)
while (frame && frame->isDummyFrame()) while (frame && frame->isDummyFrame())
frame = frame->prev(); frame = frame->prev();
if (frame && !frame->getValidCalleeObject(cx, vp)) if (!frame || !frame->isFunctionFrame()) {
return false;
if (!vp->isObject()) {
JS_ASSERT(vp->isNull()); JS_ASSERT(vp->isNull());
return true; return true;
} }
vp->setObject(frame->callee());
/* Censor the caller if it is from another compartment. */ /* Censor the caller if it is from another compartment. */
JSObject &caller = vp->toObject(); JSObject &caller = vp->toObject();
if (caller.compartment() != cx->compartment) { if (caller.compartment() != cx->compartment) {
@ -1263,7 +1158,6 @@ LookupInterpretedFunctionPrototype(JSContext *cx, JSObject *funobj)
JS_ASSERT(!shape->configurable()); JS_ASSERT(!shape->configurable());
JS_ASSERT(shape->isDataDescriptor()); JS_ASSERT(shape->isDataDescriptor());
JS_ASSERT(shape->hasSlot()); JS_ASSERT(shape->hasSlot());
JS_ASSERT(!shape->isMethod());
return shape; return shape;
} }

Просмотреть файл

@ -67,10 +67,6 @@
* move to u.i.script->flags. For now we use function flag bits to minimize * move to u.i.script->flags. For now we use function flag bits to minimize
* pointer-chasing. * pointer-chasing.
*/ */
#define JSFUN_JOINABLE 0x0001 /* function is null closure that does not
appear to call itself via its own name
or arguments.callee */
#define JSFUN_PROTOTYPE 0x0800 /* function is Function.prototype for some #define JSFUN_PROTOTYPE 0x0800 /* function is Function.prototype for some
global object */ global object */
@ -129,14 +125,6 @@ struct JSFunction : public JSObject
#define JS_LOCAL_NAME_TO_ATOM(nameWord) ((JSAtom *) ((nameWord) & ~uintptr_t(1))) #define JS_LOCAL_NAME_TO_ATOM(nameWord) ((JSAtom *) ((nameWord) & ~uintptr_t(1)))
#define JS_LOCAL_NAME_IS_CONST(nameWord) ((((nameWord) & uintptr_t(1))) != 0) #define JS_LOCAL_NAME_IS_CONST(nameWord) ((((nameWord) & uintptr_t(1))) != 0)
bool mightEscape() const {
return isInterpreted() && isNullClosure();
}
bool joinable() const {
return flags & JSFUN_JOINABLE;
}
/* /*
* For an interpreted function, accessors for the initial scope object of * For an interpreted function, accessors for the initial scope object of
* activations (stack frames) of the function. * activations (stack frames) of the function.
@ -147,8 +135,6 @@ struct JSFunction : public JSObject
static inline size_t offsetOfEnvironment() { return offsetof(JSFunction, u.i.env_); } static inline size_t offsetOfEnvironment() { return offsetof(JSFunction, u.i.env_); }
inline void setJoinable();
js::HeapPtrScript &script() const { js::HeapPtrScript &script() const {
JS_ASSERT(isInterpreted()); JS_ASSERT(isInterpreted());
return *(js::HeapPtrScript *)&u.i.script_; return *(js::HeapPtrScript *)&u.i.script_;
@ -218,33 +204,10 @@ struct JSFunction : public JSObject
public: public:
/* Accessors for data stored in extended functions. */ /* Accessors for data stored in extended functions. */
inline void initializeExtended(); inline void initializeExtended();
inline void setExtendedSlot(size_t which, const js::Value &val); inline void setExtendedSlot(size_t which, const js::Value &val);
inline const js::Value &getExtendedSlot(size_t which) const; inline const js::Value &getExtendedSlot(size_t which) const;
/* Slot holding associated method property, needed for foo.caller handling. */
static const uint32_t METHOD_PROPERTY_SLOT = 0;
/* For cloned methods, slot holding the object this was cloned as a property from. */
static const uint32_t METHOD_OBJECT_SLOT = 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 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.
* This is set on both the original and cloned function.
*/
inline JSAtom *methodAtom() const;
inline void setMethodAtom(JSAtom *atom);
private: private:
/* /*
* These member functions are inherited from JSObject, but should never be applied to * These member functions are inherited from JSObject, but should never be applied to

Просмотреть файл

@ -84,48 +84,6 @@ JSFunction::initializeExtended()
toExtended()->extendedSlots[1].init(js::UndefinedValue()); toExtended()->extendedSlots[1].init(js::UndefinedValue());
} }
inline void
JSFunction::setJoinable()
{
JS_ASSERT(isInterpreted());
flags |= JSFUN_JOINABLE;
}
inline bool
JSFunction::isClonedMethod() const
{
return joinable() && isExtended() && getExtendedSlot(METHOD_OBJECT_SLOT).isObject();
}
inline JSAtom *
JSFunction::methodAtom() const
{
return (joinable() && isExtended() && getExtendedSlot(METHOD_PROPERTY_SLOT).isString())
? (JSAtom *) getExtendedSlot(METHOD_PROPERTY_SLOT).toString()
: NULL;
}
inline void
JSFunction::setMethodAtom(JSAtom *atom)
{
JS_ASSERT(joinable());
setExtendedSlot(METHOD_PROPERTY_SLOT, js::StringValue(atom));
}
inline JSObject *
JSFunction::methodObj() const
{
JS_ASSERT(joinable());
return isClonedMethod() ? &getExtendedSlot(METHOD_OBJECT_SLOT).toObject() : NULL;
}
inline void
JSFunction::setMethodObj(JSObject& obj)
{
JS_ASSERT(joinable());
setExtendedSlot(METHOD_OBJECT_SLOT, js::ObjectValue(obj));
}
inline void inline void
JSFunction::setExtendedSlot(size_t which, const js::Value &val) JSFunction::setExtendedSlot(size_t which, const js::Value &val)
{ {
@ -288,10 +246,10 @@ inline JSFunction *
CloneFunctionObjectIfNotSingleton(JSContext *cx, JSFunction *fun, JSObject *parent) CloneFunctionObjectIfNotSingleton(JSContext *cx, JSFunction *fun, JSObject *parent)
{ {
/* /*
* For attempts to clone functions at a function definition opcode or from * For attempts to clone functions at a function definition opcode,
* a method barrier, don't perform the clone if the function has singleton * don't perform the clone if the function has singleton type. This
* type. This was called pessimistically, and we need to preserve the * was called pessimistically, and we need to preserve the type's
* type's property that if it is singleton there is only a single object * property that if it is singleton there is only a single object
* with its type in existence. * with its type in existence.
*/ */
if (fun->hasSingletonType()) { if (fun->hasSingletonType()) {

Просмотреть файл

@ -800,7 +800,7 @@ static inline const Shape *
GetSingletonShape(JSContext *cx, JSObject *obj, jsid id) GetSingletonShape(JSContext *cx, JSObject *obj, jsid id)
{ {
const Shape *shape = obj->nativeLookup(cx, id); const Shape *shape = obj->nativeLookup(cx, id);
if (shape && shape->hasDefaultGetterOrIsMethod() && shape->hasSlot()) if (shape && shape->hasDefaultGetter() && shape->hasSlot())
return shape; return shape;
return NULL; return NULL;
} }
@ -2739,7 +2739,7 @@ UpdatePropertyType(JSContext *cx, TypeSet *types, JSObject *obj, const Shape *sh
if (shape->hasGetterValue() || shape->hasSetterValue()) { if (shape->hasGetterValue() || shape->hasSetterValue()) {
types->setOwnProperty(cx, true); types->setOwnProperty(cx, true);
types->addType(cx, Type::UnknownType()); types->addType(cx, Type::UnknownType());
} else if (shape->hasDefaultGetterOrIsMethod() && shape->hasSlot()) { } else if (shape->hasDefaultGetter() && shape->hasSlot()) {
const Value &value = obj->nativeGetSlot(shape->slot()); const Value &value = obj->nativeGetSlot(shape->slot());
/* /*
@ -3667,8 +3667,7 @@ ScriptAnalysis::analyzeTypesBytecode(JSContext *cx, unsigned offset,
pushed[0].addType(cx, Type::LazyArgsType()); pushed[0].addType(cx, Type::LazyArgsType());
break; break;
case JSOP_SETPROP: case JSOP_SETPROP: {
case JSOP_SETMETHOD: {
jsid id = GetAtomId(cx, script, pc, 0); jsid id = GetAtomId(cx, script, pc, 0);
poppedTypes(pc, 1)->addSetProperty(cx, script, pc, poppedTypes(pc, 0), id); poppedTypes(pc, 1)->addSetProperty(cx, script, pc, poppedTypes(pc, 0), id);
poppedTypes(pc, 0)->addSubset(cx, &pushed[0]); poppedTypes(pc, 0)->addSubset(cx, &pushed[0]);
@ -3875,8 +3874,7 @@ ScriptAnalysis::analyzeTypesBytecode(JSContext *cx, unsigned offset,
state.hasHole = true; state.hasHole = true;
break; break;
case JSOP_INITPROP: case JSOP_INITPROP: {
case JSOP_INITMETHOD: {
const SSAValue &objv = poppedValue(pc, 1); const SSAValue &objv = poppedValue(pc, 1);
jsbytecode *initpc = script->code + objv.pushedOffset(); jsbytecode *initpc = script->code + objv.pushedOffset();
TypeObject *initializer = GetInitializerType(cx, script, initpc); TypeObject *initializer = GetInitializerType(cx, script, initpc);

Просмотреть файл

@ -369,7 +369,7 @@ js::OnUnknownMethod(JSContext *cx, JSObject *obj, Value idval, Value *vp)
{ {
jsid id = ATOM_TO_JSID(cx->runtime->atomState.noSuchMethodAtom); jsid id = ATOM_TO_JSID(cx->runtime->atomState.noSuchMethodAtom);
AutoValueRooter tvr(cx); AutoValueRooter tvr(cx);
if (!js_GetMethod(cx, obj, id, JSGET_NO_METHOD_BARRIER, tvr.addr())) if (!js_GetMethod(cx, obj, id, 0, tvr.addr()))
return false; return false;
TypeScript::MonitorUnknown(cx, cx->fp()->script(), cx->regs().pc); TypeScript::MonitorUnknown(cx, cx->fp()->script(), cx->regs().pc);
@ -1215,11 +1215,9 @@ JS_STATIC_ASSERT(JSOP_XMLNAME_LENGTH == JSOP_CALLXMLNAME_LENGTH);
/* /*
* Same for JSOP_SETNAME and JSOP_SETPROP, which differ only slightly but * Same for JSOP_SETNAME and JSOP_SETPROP, which differ only slightly but
* remain distinct for the decompiler. Likewise for JSOP_INIT{PROP,METHOD}. * remain distinct for the decompiler.
*/ */
JS_STATIC_ASSERT(JSOP_SETNAME_LENGTH == JSOP_SETPROP_LENGTH); JS_STATIC_ASSERT(JSOP_SETNAME_LENGTH == JSOP_SETPROP_LENGTH);
JS_STATIC_ASSERT(JSOP_SETNAME_LENGTH == JSOP_SETMETHOD_LENGTH);
JS_STATIC_ASSERT(JSOP_INITPROP_LENGTH == JSOP_INITMETHOD_LENGTH);
/* See TRY_BRANCH_AFTER_COND. */ /* See TRY_BRANCH_AFTER_COND. */
JS_STATIC_ASSERT(JSOP_IFNE_LENGTH == JSOP_IFEQ_LENGTH); JS_STATIC_ASSERT(JSOP_IFNE_LENGTH == JSOP_IFEQ_LENGTH);
@ -1714,6 +1712,8 @@ ADD_EMPTY_CASE(JSOP_UNUSED25)
ADD_EMPTY_CASE(JSOP_UNUSED26) ADD_EMPTY_CASE(JSOP_UNUSED26)
ADD_EMPTY_CASE(JSOP_UNUSED27) ADD_EMPTY_CASE(JSOP_UNUSED27)
ADD_EMPTY_CASE(JSOP_UNUSED28) ADD_EMPTY_CASE(JSOP_UNUSED28)
ADD_EMPTY_CASE(JSOP_UNUSED29)
ADD_EMPTY_CASE(JSOP_UNUSED30)
ADD_EMPTY_CASE(JSOP_CONDSWITCH) ADD_EMPTY_CASE(JSOP_CONDSWITCH)
ADD_EMPTY_CASE(JSOP_TRY) ADD_EMPTY_CASE(JSOP_TRY)
#if JS_HAS_XML_SUPPORT #if JS_HAS_XML_SUPPORT
@ -2585,7 +2585,6 @@ END_CASE(JSOP_GETPROP)
BEGIN_CASE(JSOP_SETGNAME) BEGIN_CASE(JSOP_SETGNAME)
BEGIN_CASE(JSOP_SETNAME) BEGIN_CASE(JSOP_SETNAME)
BEGIN_CASE(JSOP_SETPROP) BEGIN_CASE(JSOP_SETPROP)
BEGIN_CASE(JSOP_SETMETHOD)
{ {
const Value &rval = regs.sp[-1]; const Value &rval = regs.sp[-1];
const Value &lval = regs.sp[-2]; const Value &lval = regs.sp[-2];
@ -3159,73 +3158,6 @@ BEGIN_CASE(JSOP_LAMBDA)
JSObject *parent; JSObject *parent;
if (fun->isNullClosure()) { if (fun->isNullClosure()) {
parent = &regs.fp()->scopeChain(); parent = &regs.fp()->scopeChain();
if (fun->joinable()) {
jsbytecode *pc2 = regs.pc + JSOP_LAMBDA_LENGTH;
JSOp op2 = JSOp(*pc2);
/*
* Optimize var obj = {method: function () { ... }, ...},
* this.method = function () { ... }; and other significant
* single-use-of-null-closure bytecode sequences.
*/
if (op2 == JSOP_INITMETHOD) {
#ifdef DEBUG
const Value &lref = regs.sp[-1];
JS_ASSERT(lref.isObject());
JSObject *obj2 = &lref.toObject();
JS_ASSERT(obj2->isObject());
#endif
JS_ASSERT(fun->methodAtom() ==
script->getAtom(GET_UINT32_INDEX(regs.pc + JSOP_LAMBDA_LENGTH)));
break;
}
if (op2 == JSOP_SETMETHOD) {
#ifdef DEBUG
op2 = JSOp(pc2[JSOP_SETMETHOD_LENGTH]);
JS_ASSERT(op2 == JSOP_POP || op2 == JSOP_POPV);
#endif
const Value &lref = regs.sp[-1];
if (lref.isObject() && lref.toObject().canHaveMethodBarrier()) {
JS_ASSERT(fun->methodAtom() ==
script->getAtom(GET_UINT32_INDEX(regs.pc + JSOP_LAMBDA_LENGTH)));
break;
}
} else if (op2 == JSOP_CALL) {
/*
* Array.prototype.sort and String.prototype.replace are
* optimized as if they are special form. We know that they
* won't leak the joined function object in obj, therefore
* we don't need to clone that compiler-created function
* object for identity/mutation reasons.
*/
int iargc = GET_ARGC(pc2);
/*
* Note that we have not yet pushed obj as the final argument,
* so regs.sp[1 - (iargc + 2)], and not regs.sp[-(iargc + 2)],
* is the callee for this JSOP_CALL.
*/
const Value &cref = regs.sp[1 - (iargc + 2)];
JSFunction *fun;
if (IsFunctionObject(cref, &fun)) {
if (Native native = fun->maybeNative()) {
if ((iargc == 1 && native == array_sort) ||
(iargc == 2 && native == str_replace)) {
break;
}
}
}
} else if (op2 == JSOP_NULL) {
pc2 += JSOP_NULL_LENGTH;
op2 = JSOp(*pc2);
if (op2 == JSOP_CALL && GET_ARGC(pc2) == 0)
break;
}
}
} else { } else {
parent = GetScopeChain(cx, regs.fp()); parent = GetScopeChain(cx, regs.fp());
if (!parent) if (!parent)
@ -3405,7 +3337,6 @@ BEGIN_CASE(JSOP_ENDINIT)
END_CASE(JSOP_ENDINIT) END_CASE(JSOP_ENDINIT)
BEGIN_CASE(JSOP_INITPROP) BEGIN_CASE(JSOP_INITPROP)
BEGIN_CASE(JSOP_INITMETHOD)
{ {
/* Load the property's initial value into rval. */ /* Load the property's initial value into rval. */
JS_ASSERT(regs.sp - regs.fp()->base() >= 2); JS_ASSERT(regs.sp - regs.fp()->base() >= 2);
@ -3419,11 +3350,10 @@ BEGIN_CASE(JSOP_INITMETHOD)
LOAD_ATOM(0, atom); LOAD_ATOM(0, atom);
jsid id = ATOM_TO_JSID(atom); jsid id = ATOM_TO_JSID(atom);
unsigned defineHow = (op == JSOP_INITMETHOD) ? DNP_SET_METHOD : 0;
if (JS_UNLIKELY(atom == cx->runtime->atomState.protoAtom) if (JS_UNLIKELY(atom == cx->runtime->atomState.protoAtom)
? !js_SetPropertyHelper(cx, obj, id, defineHow, &rval, script->strictModeCode) ? !js_SetPropertyHelper(cx, obj, id, 0, &rval, script->strictModeCode)
: !DefineNativeProperty(cx, obj, id, rval, NULL, NULL, : !DefineNativeProperty(cx, obj, id, rval, NULL, NULL,
JSPROP_ENUMERATE, 0, 0, defineHow)) { JSPROP_ENUMERATE, 0, 0, 0)) {
goto error; goto error;
} }

Просмотреть файл

@ -244,17 +244,13 @@ GetPropertyOperation(JSContext *cx, jsbytecode *pc, const Value &lval, Value *vp
if (!obj) if (!obj)
return false; return false;
unsigned flags = (op == JSOP_CALLPROP)
? JSGET_CACHE_RESULT | JSGET_NO_METHOD_BARRIER
: JSGET_CACHE_RESULT | JSGET_METHOD_BARRIER;
PropertyCacheEntry *entry; PropertyCacheEntry *entry;
JSObject *obj2; JSObject *obj2;
PropertyName *name; PropertyName *name;
JS_PROPERTY_CACHE(cx).test(cx, pc, obj, obj2, entry, name); JS_PROPERTY_CACHE(cx).test(cx, pc, obj, obj2, entry, name);
if (!name) { if (!name) {
AssertValidPropertyCacheHit(cx, obj, obj2, entry); AssertValidPropertyCacheHit(cx, obj, obj2, entry);
if (!NativeGet(cx, obj, obj2, entry->prop, flags, vp)) if (!NativeGet(cx, obj, obj2, entry->prop, JSGET_CACHE_RESULT, vp))
return false; return false;
return true; return true;
} }
@ -265,7 +261,7 @@ GetPropertyOperation(JSContext *cx, jsbytecode *pc, const Value &lval, Value *vp
if (!GetPropertyGenericMaybeCallXML(cx, op, obj, id, vp)) if (!GetPropertyGenericMaybeCallXML(cx, op, obj, id, vp))
return false; return false;
} else { } else {
if (!GetPropertyHelper(cx, obj, id, flags, vp)) if (!GetPropertyHelper(cx, obj, id, JSGET_CACHE_RESULT, vp))
return false; return false;
} }
@ -289,7 +285,6 @@ SetPropertyOperation(JSContext *cx, jsbytecode *pc, const Value &lval, const Val
if (!obj) if (!obj)
return false; return false;
JS_ASSERT_IF(*pc == JSOP_SETMETHOD, IsFunctionObject(rval));
JS_ASSERT_IF(*pc == JSOP_SETNAME || *pc == JSOP_SETGNAME, lval.isObject()); JS_ASSERT_IF(*pc == JSOP_SETNAME || *pc == JSOP_SETGNAME, lval.isObject());
JS_ASSERT_IF(*pc == JSOP_SETGNAME, obj == &cx->fp()->scopeChain().global()); JS_ASSERT_IF(*pc == JSOP_SETGNAME, obj == &cx->fp()->scopeChain().global());
@ -322,7 +317,7 @@ SetPropertyOperation(JSContext *cx, jsbytecode *pc, const Value &lval, const Val
} }
#endif #endif
if (shape->hasDefaultSetter() && shape->hasSlot() && !shape->isMethod()) { if (shape->hasDefaultSetter() && shape->hasSlot()) {
/* Fast path for, e.g., plain Object instance properties. */ /* Fast path for, e.g., plain Object instance properties. */
obj->nativeSetSlotWithType(cx, shape, rval); obj->nativeSetSlotWithType(cx, shape, rval);
} else { } else {
@ -344,13 +339,9 @@ SetPropertyOperation(JSContext *cx, jsbytecode *pc, const Value &lval, const Val
jsid id = ATOM_TO_JSID(name); jsid id = ATOM_TO_JSID(name);
if (JS_LIKELY(!obj->getOps()->setProperty)) { if (JS_LIKELY(!obj->getOps()->setProperty)) {
unsigned defineHow; unsigned defineHow = (op == JSOP_SETNAME)
if (op == JSOP_SETMETHOD) ? DNP_CACHE_RESULT | DNP_UNQUALIFIED
defineHow = DNP_CACHE_RESULT | DNP_SET_METHOD; : DNP_CACHE_RESULT;
else if (op == JSOP_SETNAME)
defineHow = DNP_CACHE_RESULT | DNP_UNQUALIFIED;
else
defineHow = DNP_CACHE_RESULT;
if (!js_SetPropertyHelper(cx, obj, id, defineHow, &rref, strict)) if (!js_SetPropertyHelper(cx, obj, id, defineHow, &rref, strict))
return false; return false;
} else { } else {
@ -384,7 +375,7 @@ NameOperation(JSContext *cx, jsbytecode *pc, Value *vp)
JS_PROPERTY_CACHE(cx).test(cx, pc, obj, obj2, entry, name); JS_PROPERTY_CACHE(cx).test(cx, pc, obj, obj2, entry, name);
if (!name) { if (!name) {
AssertValidPropertyCacheHit(cx, obj, obj2, entry); AssertValidPropertyCacheHit(cx, obj, obj2, entry);
if (!NativeGet(cx, obj, obj2, entry->prop, JSGET_METHOD_BARRIER, vp)) if (!NativeGet(cx, obj, obj2, entry->prop, 0, vp))
return false; return false;
return true; return true;
} }
@ -416,7 +407,7 @@ NameOperation(JSContext *cx, jsbytecode *pc, Value *vp)
JSObject *normalized = obj; JSObject *normalized = obj;
if (normalized->getClass() == &WithClass && !shape->hasDefaultGetter()) if (normalized->getClass() == &WithClass && !shape->hasDefaultGetter())
normalized = &normalized->asWith().object(); normalized = &normalized->asWith().object();
if (!NativeGet(cx, normalized, obj2, shape, JSGET_METHOD_BARRIER, vp)) if (!NativeGet(cx, normalized, obj2, shape, 0, vp))
return false; return false;
} }

Просмотреть файл

@ -459,7 +459,7 @@ GetCustomIterator(JSContext *cx, JSObject *obj, unsigned flags, Value *vp)
/* Check whether we have a valid __iterator__ method. */ /* Check whether we have a valid __iterator__ method. */
JSAtom *atom = cx->runtime->atomState.iteratorAtom; JSAtom *atom = cx->runtime->atomState.iteratorAtom;
if (!js_GetMethod(cx, obj, ATOM_TO_JSID(atom), JSGET_NO_METHOD_BARRIER, vp)) if (!js_GetMethod(cx, obj, ATOM_TO_JSID(atom), 0, vp))
return false; return false;
/* If there is no custom __iterator__ method, we are done here. */ /* If there is no custom __iterator__ method, we are done here. */
@ -1242,7 +1242,7 @@ js_IteratorMore(JSContext *cx, JSObject *iterobj, Value *rval)
} else { } else {
/* Call the iterator object's .next method. */ /* Call the iterator object's .next method. */
jsid id = ATOM_TO_JSID(cx->runtime->atomState.nextAtom); jsid id = ATOM_TO_JSID(cx->runtime->atomState.nextAtom);
if (!js_GetMethod(cx, iterobj, id, JSGET_METHOD_BARRIER, rval)) if (!js_GetMethod(cx, iterobj, id, 0, rval))
return false; return false;
if (!Invoke(cx, ObjectValue(*iterobj), *rval, 0, NULL, rval)) { if (!Invoke(cx, ObjectValue(*iterobj), *rval, 0, NULL, rval)) {
/* Check for StopIteration. */ /* Check for StopIteration. */

Просмотреть файл

@ -1963,7 +1963,7 @@ DefinePropertyOnObject(JSContext *cx, JSObject *obj, const jsid &id, const PropD
return Reject(cx, JSMSG_CANT_REDEFINE_PROP, throwError, id, rval); return Reject(cx, JSMSG_CANT_REDEFINE_PROP, throwError, id, rval);
} }
if (!js_NativeGet(cx, obj, obj2, shape, JSGET_NO_METHOD_BARRIER, &v)) if (!js_NativeGet(cx, obj, obj2, shape, 0, &v))
return JS_FALSE; return JS_FALSE;
} }
@ -2092,14 +2092,8 @@ DefinePropertyOnObject(JSContext *cx, JSObject *obj, const jsid &id, const PropD
changed |= JSPROP_ENUMERATE; changed |= JSPROP_ENUMERATE;
attrs = (shape->attributes() & ~changed) | (desc.attrs & changed); attrs = (shape->attributes() & ~changed) | (desc.attrs & changed);
if (shape->isMethod()) { getter = shape->getter();
JS_ASSERT(!(attrs & (JSPROP_GETTER | JSPROP_SETTER))); setter = shape->setter();
getter = JS_PropertyStub;
setter = JS_StrictPropertyStub;
} else {
getter = shape->getter();
setter = shape->setter();
}
} else if (desc.isDataDescriptor()) { } else if (desc.isDataDescriptor()) {
unsigned unchanged = 0; unsigned unchanged = 0;
if (!desc.hasConfigurable) if (!desc.hasConfigurable)
@ -2126,8 +2120,6 @@ DefinePropertyOnObject(JSContext *cx, JSObject *obj, const jsid &id, const PropD
if (!CheckAccess(cx, obj2, id, JSACC_WATCH, &dummy, &attrs)) if (!CheckAccess(cx, obj2, id, JSACC_WATCH, &dummy, &attrs))
return JS_FALSE; return JS_FALSE;
JS_ASSERT_IF(shape->isMethod(), !(attrs & (JSPROP_GETTER | JSPROP_SETTER)));
/* 8.12.9 step 12. */ /* 8.12.9 step 12. */
unsigned changed = 0; unsigned changed = 0;
if (desc.hasConfigurable) if (desc.hasConfigurable)
@ -2143,7 +2135,7 @@ DefinePropertyOnObject(JSContext *cx, JSObject *obj, const jsid &id, const PropD
if (desc.hasGet) { if (desc.hasGet) {
getter = desc.getter(); getter = desc.getter();
} else { } else {
getter = (shape->isMethod() || (shape->hasDefaultGetter() && !shape->hasGetterValue())) getter = (shape->hasDefaultGetter() && !shape->hasGetterValue())
? JS_PropertyStub ? JS_PropertyStub
: shape->getter(); : shape->getter();
} }
@ -4399,8 +4391,6 @@ js_AddNativeProperty(JSContext *cx, JSObject *obj, jsid id,
PropertyOp getter, StrictPropertyOp setter, uint32_t slot, PropertyOp getter, StrictPropertyOp setter, uint32_t slot,
unsigned attrs, unsigned flags, int shortid) unsigned attrs, unsigned flags, int shortid)
{ {
JS_ASSERT(!(flags & Shape::METHOD));
/* Convert string indices to integers if appropriate. */ /* Convert string indices to integers if appropriate. */
id = js_CheckForStringIndex(id); id = js_CheckForStringIndex(id);
@ -4415,26 +4405,6 @@ js_AddNativeProperty(JSContext *cx, JSObject *obj, jsid id,
return obj->putProperty(cx, id, getter, setter, slot, attrs, flags, shortid); return obj->putProperty(cx, id, getter, setter, slot, attrs, flags, shortid);
} }
Shape *
js_ChangeNativePropertyAttrs(JSContext *cx, JSObject *obj,
Shape *shape, unsigned attrs, unsigned mask,
PropertyOp getter, StrictPropertyOp setter)
{
/*
* Check for freezing an object with shape-memoized methods here, on a
* shape-by-shape basis.
*/
if ((attrs & JSPROP_READONLY) && shape->isMethod()) {
Value v = ObjectValue(*obj->nativeGetMethod(shape));
shape = obj->methodReadBarrier(cx, *shape, &v);
if (!shape)
return NULL;
}
return obj->changeProperty(cx, shape, attrs, mask, getter, setter);
}
JSBool JSBool
js_DefineProperty(JSContext *cx, JSObject *obj, jsid id, const Value *value, js_DefineProperty(JSContext *cx, JSObject *obj, jsid id, const Value *value,
PropertyOp getter, StrictPropertyOp setter, unsigned attrs) PropertyOp getter, StrictPropertyOp setter, unsigned attrs)
@ -4482,15 +4452,12 @@ DefineNativeProperty(JSContext *cx, JSObject *obj, jsid id, const Value &value_,
unsigned flags, int shortid, unsigned defineHow /* = 0 */) unsigned flags, int shortid, unsigned defineHow /* = 0 */)
{ {
JS_ASSERT((defineHow & ~(DNP_CACHE_RESULT | DNP_DONT_PURGE | JS_ASSERT((defineHow & ~(DNP_CACHE_RESULT | DNP_DONT_PURGE |
DNP_SET_METHOD | DNP_SKIP_TYPE)) == 0); DNP_SKIP_TYPE)) == 0);
RootObject objRoot(cx, &obj); RootObject objRoot(cx, &obj);
RootId idRoot(cx, &id); RootId idRoot(cx, &id);
/* /* Make a local copy of value so addProperty can mutate its inout parameter. */
* Make a local copy of value, in case a method barrier needs to update the
* value to define, and just so addProperty can mutate its inout parameter.
*/
RootedVarValue value(cx); RootedVarValue value(cx);
value = value_; value = value_;
@ -4549,15 +4516,12 @@ DefineNativeProperty(JSContext *cx, JSObject *obj, jsid id, const Value &value_,
/* Use the object's class getter and setter by default. */ /* Use the object's class getter and setter by default. */
Class *clasp = obj->getClass(); Class *clasp = obj->getClass();
if (!(defineHow & DNP_SET_METHOD)) { if (!getter && !(attrs & JSPROP_GETTER))
if (!getter && !(attrs & JSPROP_GETTER)) getter = clasp->getProperty;
getter = clasp->getProperty; if (!setter && !(attrs & JSPROP_SETTER))
if (!setter && !(attrs & JSPROP_SETTER)) setter = clasp->setProperty;
setter = clasp->setProperty;
}
if (((defineHow & DNP_SET_METHOD) || getter == JS_PropertyStub) && if ((getter == JS_PropertyStub) && !(defineHow & DNP_SKIP_TYPE)) {
!(defineHow & DNP_SKIP_TYPE)) {
/* /*
* Type information for normal native properties should reflect the * Type information for normal native properties should reflect the
* initial value of the property. * initial value of the property.
@ -4568,32 +4532,6 @@ DefineNativeProperty(JSContext *cx, JSObject *obj, jsid id, const Value &value_,
} }
if (!shape) { if (!shape) {
/* Add a new property, or replace an existing one of the same id. */
if (defineHow & DNP_SET_METHOD) {
JS_ASSERT(clasp == &ObjectClass);
JS_ASSERT(IsFunctionObject(value));
JS_ASSERT(!(attrs & (JSPROP_GETTER | JSPROP_SETTER)));
JS_ASSERT(!getter && !setter);
JSObject *funobj = &value.raw().toObject();
if (!funobj->toFunction()->isClonedMethod())
flags |= Shape::METHOD;
}
if (const Shape *existingShape = obj->nativeLookup(cx, id)) {
if (existingShape->isMethod() &&
ObjectValue(*obj->nativeGetMethod(existingShape)) == value)
{
/*
* Redefining an existing shape-memoized method object without
* changing the property's value, perhaps to change attributes.
* Clone now via the method read barrier.
*/
if (!obj->methodReadBarrier(cx, *existingShape, value.address()))
return NULL;
}
}
shape = obj->putProperty(cx, id, getter, setter, SHAPE_INVALID_SLOT, shape = obj->putProperty(cx, id, getter, setter, SHAPE_INVALID_SLOT,
attrs, flags, shortid); attrs, flags, shortid);
if (!shape) if (!shape)
@ -4970,7 +4908,7 @@ js_NativeGetInline(JSContext *cx, JSObject *receiver, JSObject *obj, JSObject *p
if (shape->hasSlot()) { if (shape->hasSlot()) {
*vp = pobj->nativeGetSlot(shape->slot()); *vp = pobj->nativeGetSlot(shape->slot());
JS_ASSERT(!vp->isMagic()); JS_ASSERT(!vp->isMagic());
JS_ASSERT_IF(!pobj->hasSingletonType() && shape->hasDefaultGetterOrIsMethod(), JS_ASSERT_IF(!pobj->hasSingletonType() && shape->hasDefaultGetter(),
js::types::TypeHasProperty(cx, pobj->type(), shape->propid(), *vp)); js::types::TypeHasProperty(cx, pobj->type(), shape->propid(), *vp));
} else { } else {
vp->setUndefined(); vp->setUndefined();
@ -4978,9 +4916,6 @@ js_NativeGetInline(JSContext *cx, JSObject *receiver, JSObject *obj, JSObject *p
if (shape->hasDefaultGetter()) if (shape->hasDefaultGetter())
return true; return true;
if (JS_UNLIKELY(shape->isMethod()) && (getHow & JSGET_NO_METHOD_BARRIER))
return true;
jsbytecode *pc; jsbytecode *pc;
JSScript *script = cx->stack.currentScript(&pc); JSScript *script = cx->stack.currentScript(&pc);
if (script && script->hasAnalysis()) { if (script && script->hasAnalysis()) {
@ -4993,11 +4928,8 @@ js_NativeGetInline(JSContext *cx, JSObject *receiver, JSObject *obj, JSObject *p
return false; return false;
/* Update slotful shapes according to the value produced by the getter. */ /* Update slotful shapes according to the value produced by the getter. */
if (shape->hasSlot() && pobj->nativeContains(cx, *shape)) { if (shape->hasSlot() && pobj->nativeContains(cx, *shape))
/* Method shapes were removed by methodReadBarrier under shape->get(). */
JS_ASSERT(!shape->isMethod());
pobj->nativeSetSlot(shape->slot(), *vp); pobj->nativeSetSlot(shape->slot(), *vp);
}
return true; return true;
} }
@ -5021,10 +4953,6 @@ js_NativeSet(JSContext *cx, JSObject *obj, const Shape *shape, bool added, bool
/* If shape has a stub setter, just store *vp. */ /* If shape has a stub setter, just store *vp. */
if (shape->hasDefaultSetter()) { if (shape->hasDefaultSetter()) {
if (!added) {
if (shape->isMethod() && !obj->methodShapeChange(cx, *shape))
return false;
}
obj->nativeSetSlot(slot, *vp); obj->nativeSetSlot(slot, *vp);
return true; return true;
} }
@ -5162,7 +5090,7 @@ JSBool
js_GetProperty(JSContext *cx, JSObject *obj, JSObject *receiver, jsid id, Value *vp) js_GetProperty(JSContext *cx, JSObject *obj, JSObject *receiver, jsid id, Value *vp)
{ {
/* This call site is hot -- use the always-inlined variant of js_GetPropertyHelper(). */ /* This call site is hot -- use the always-inlined variant of js_GetPropertyHelper(). */
return js_GetPropertyHelperInline(cx, obj, receiver, id, JSGET_METHOD_BARRIER, vp); return js_GetPropertyHelperInline(cx, obj, receiver, id, 0, vp);
} }
JSBool JSBool
@ -5173,7 +5101,7 @@ js_GetElement(JSContext *cx, JSObject *obj, JSObject *receiver, uint32_t index,
return false; return false;
/* This call site is hot -- use the always-inlined variant of js_GetPropertyHelper(). */ /* This call site is hot -- use the always-inlined variant of js_GetPropertyHelper(). */
return js_GetPropertyHelperInline(cx, obj, receiver, id, JSGET_METHOD_BARRIER, vp); return js_GetPropertyHelperInline(cx, obj, receiver, id, 0, vp);
} }
JSBool JSBool
@ -5261,25 +5189,10 @@ bool
JSObject::callMethod(JSContext *cx, jsid id, unsigned argc, Value *argv, Value *vp) JSObject::callMethod(JSContext *cx, jsid id, unsigned argc, Value *argv, Value *vp)
{ {
Value fval; Value fval;
return js_GetMethod(cx, this, id, JSGET_NO_METHOD_BARRIER, &fval) && return js_GetMethod(cx, this, id, 0, &fval) &&
Invoke(cx, ObjectValue(*this), fval, argc, argv, vp); Invoke(cx, ObjectValue(*this), fval, argc, argv, vp);
} }
static bool
CloneFunctionForSetMethod(JSContext *cx, Value *vp)
{
JSFunction *fun = vp->toObject().toFunction();
/* Clone the fun unless it already has been. */
if (!fun->isClonedMethod()) {
fun = CloneFunctionObject(cx, fun);
if (!fun)
return false;
vp->setObject(*fun);
}
return true;
}
JSBool JSBool
js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, unsigned defineHow, js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, unsigned defineHow,
Value *vp, JSBool strict) Value *vp, JSBool strict)
@ -5294,7 +5207,7 @@ js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, unsigned defineHow,
StrictPropertyOp setter; StrictPropertyOp setter;
bool added; bool added;
JS_ASSERT((defineHow & ~(DNP_CACHE_RESULT | DNP_SET_METHOD | DNP_UNQUALIFIED)) == 0); JS_ASSERT((defineHow & ~(DNP_CACHE_RESULT | DNP_UNQUALIFIED)) == 0);
/* Convert string indices to integers if appropriate. */ /* Convert string indices to integers if appropriate. */
id = js_CheckForStringIndex(id); id = js_CheckForStringIndex(id);
@ -5304,9 +5217,6 @@ js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, unsigned defineHow,
WatchpointMap *wpmap = cx->compartment->watchpointMap; WatchpointMap *wpmap = cx->compartment->watchpointMap;
if (wpmap && !wpmap->triggerWatchpoint(cx, obj, id, vp)) if (wpmap && !wpmap->triggerWatchpoint(cx, obj, id, vp))
return false; return false;
/* A watchpoint handler may set *vp to a non-function value. */
defineHow &= ~DNP_SET_METHOD;
} }
if (!LookupPropertyWithFlags(cx, obj, id, cx->resolveFlags, &pobj, &prop)) if (!LookupPropertyWithFlags(cx, obj, id, cx->resolveFlags, &pobj, &prop))
@ -5381,12 +5291,6 @@ js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, unsigned defineHow,
* We found id in a prototype object: prepare to share or shadow. * We found id in a prototype object: prepare to share or shadow.
*/ */
if (!shape->shadowable()) { if (!shape->shadowable()) {
if (defineHow & DNP_SET_METHOD) {
JS_ASSERT(!shape->isMethod());
if (!CloneFunctionForSetMethod(cx, vp))
return false;
}
if (defineHow & DNP_CACHE_RESULT) if (defineHow & DNP_CACHE_RESULT)
JS_PROPERTY_CACHE(cx).fill(cx, obj, 0, pobj, shape); JS_PROPERTY_CACHE(cx).fill(cx, obj, 0, pobj, shape);
@ -5412,7 +5316,6 @@ js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, unsigned defineHow,
* about to create in obj. * about to create in obj.
*/ */
if (!shape->hasSlot()) { if (!shape->hasSlot()) {
defineHow &= ~DNP_SET_METHOD;
if (shape->hasShortID()) { if (shape->hasShortID()) {
flags = Shape::HAS_SHORTID; flags = Shape::HAS_SHORTID;
shortid = shape->shortid(); shortid = shape->shortid();
@ -5431,26 +5334,6 @@ js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, unsigned defineHow,
*/ */
shape = NULL; shape = NULL;
} }
if (shape && (defineHow & DNP_SET_METHOD)) {
/*
* JSOP_SETMETHOD is assigning to an existing own property. If it
* is an identical method property, do nothing. Otherwise downgrade
* to ordinary assignment. Either way, do not fill the property
* cache, as the interpreter has no fast path for these unusual
* cases.
*/
if (shape->isMethod()) {
if (obj->nativeGetMethod(shape) == &vp->toObject())
return true;
shape = obj->methodShapeChange(cx, *shape);
if (!shape)
return false;
}
if (!CloneFunctionForSetMethod(cx, vp))
return false;
return js_NativeSet(cx, obj, shape, false, strict, vp);
}
} }
added = false; added = false;
@ -5471,19 +5354,6 @@ js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, unsigned defineHow,
if (!js_PurgeScopeChain(cx, obj, id)) if (!js_PurgeScopeChain(cx, obj, id))
return JS_FALSE; return JS_FALSE;
/*
* Check for Object class here to avoid defining a method on a class
* with magic resolve, addProperty, getProperty, etc. hooks.
*/
if ((defineHow & DNP_SET_METHOD) && obj->canHaveMethodBarrier()) {
JS_ASSERT(IsFunctionObject(*vp));
JS_ASSERT(!(attrs & (JSPROP_GETTER | JSPROP_SETTER)));
JSObject *funobj = &vp->toObject();
if (!funobj->toFunction()->isClonedMethod())
flags |= Shape::METHOD;
}
shape = obj->putProperty(cx, id, getter, setter, SHAPE_INVALID_SLOT, shape = obj->putProperty(cx, id, getter, setter, SHAPE_INVALID_SLOT,
attrs, flags, shortid); attrs, flags, shortid);
if (!shape) if (!shape)
@ -5557,14 +5427,6 @@ js_GetElementAttributes(JSContext *cx, JSObject *obj, uint32_t index, unsigned *
return true; return true;
} }
JSBool
js_SetNativeAttributes(JSContext *cx, JSObject *obj, Shape *shape, unsigned attrs)
{
JS_ASSERT(obj->isNative());
return !!js_ChangeNativePropertyAttrs(cx, obj, shape, attrs, 0,
shape->getter(), shape->setter());
}
JSBool JSBool
js_SetAttributes(JSContext *cx, JSObject *obj, jsid id, unsigned *attrsp) js_SetAttributes(JSContext *cx, JSObject *obj, jsid id, unsigned *attrsp)
{ {
@ -5574,7 +5436,7 @@ js_SetAttributes(JSContext *cx, JSObject *obj, jsid id, unsigned *attrsp)
if (!prop) if (!prop)
return true; return true;
return obj->isNative() return obj->isNative()
? js_SetNativeAttributes(cx, obj, (Shape *) prop, *attrsp) ? obj->changePropertyAttributes(cx, (Shape *) prop, *attrsp)
: obj->setGenericAttributes(cx, id, attrsp); : obj->setGenericAttributes(cx, id, attrsp);
} }
@ -5587,7 +5449,7 @@ js_SetElementAttributes(JSContext *cx, JSObject *obj, uint32_t index, unsigned *
if (!prop) if (!prop)
return true; return true;
return obj->isNative() return obj->isNative()
? js_SetNativeAttributes(cx, obj, (Shape *) prop, *attrsp) ? obj->changePropertyAttributes(cx, (Shape *) prop, *attrsp)
: obj->setElementAttributes(cx, index, attrsp); : obj->setElementAttributes(cx, index, attrsp);
} }
@ -5624,35 +5486,6 @@ js_DeleteGeneric(JSContext *cx, JSObject *obj, jsid id, Value *rval, JSBool stri
if (shape->hasSlot()) { if (shape->hasSlot()) {
const Value &v = obj->nativeGetSlot(shape->slot()); const Value &v = obj->nativeGetSlot(shape->slot());
GCPoke(cx->runtime, v); GCPoke(cx->runtime, v);
/*
* Delete is rare enough that we can take the hit of checking for an
* active cloned method function object that must be homed to a callee
* slot on the active stack frame before this delete completes, in case
* someone saved the clone and checks it against foo.caller for a foo
* called from the active method.
*
* We do not check suspended frames. They can't be reached via caller,
* so the only way they could have the method's joined function object
* as callee is through an API abusage. We break any such edge case.
*/
JSFunction *fun;
if (IsFunctionObject(v, &fun) && fun->isClonedMethod()) {
for (StackFrame *fp = cx->maybefp(); fp; fp = fp->prev()) {
if (fp->isFunctionFrame() &&
fp->fun()->script() == fun->script() &&
fp->thisValue().isObject())
{
JSObject *tmp = &fp->thisValue().toObject();
do {
if (tmp == obj) {
fp->overwriteCallee(*fun);
break;
}
} while ((tmp = tmp->getProto()) != NULL);
}
}
}
} }
if (!CallJSPropertyOp(cx, obj->getClass()->delProperty, obj, shape->getUserId(), rval)) if (!CallJSPropertyOp(cx, obj->getClass()->delProperty, obj, shape->getUserId(), rval))
@ -5691,7 +5524,7 @@ HasDataProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp)
{ {
JS_ASSERT(id == js_CheckForStringIndex(id)); JS_ASSERT(id == js_CheckForStringIndex(id));
if (const Shape *shape = obj->nativeLookup(cx, id)) { if (const Shape *shape = obj->nativeLookup(cx, id)) {
if (shape->hasDefaultGetterOrIsMethod() && shape->hasSlot()) { if (shape->hasDefaultGetter() && shape->hasSlot()) {
*vp = obj->nativeGetSlot(shape->slot()); *vp = obj->nativeGetSlot(shape->slot());
return true; return true;
} }
@ -5711,7 +5544,7 @@ HasDataProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp)
static bool static bool
MaybeCallMethod(JSContext *cx, JSObject *obj, jsid id, Value *vp) MaybeCallMethod(JSContext *cx, JSObject *obj, jsid id, Value *vp)
{ {
if (!js_GetMethod(cx, obj, id, JSGET_NO_METHOD_BARRIER, vp)) if (!js_GetMethod(cx, obj, id, 0, vp))
return false; return false;
if (!js_IsCallable(*vp)) { if (!js_IsCallable(*vp)) {
*vp = ObjectValue(*obj); *vp = ObjectValue(*obj);
@ -6221,7 +6054,6 @@ DumpProperty(JSObject *obj, const Shape &shape)
if (attrs & JSPROP_READONLY) fprintf(stderr, "readonly "); if (attrs & JSPROP_READONLY) fprintf(stderr, "readonly ");
if (attrs & JSPROP_PERMANENT) fprintf(stderr, "permanent "); if (attrs & JSPROP_PERMANENT) fprintf(stderr, "permanent ");
if (attrs & JSPROP_SHARED) fprintf(stderr, "shared "); if (attrs & JSPROP_SHARED) fprintf(stderr, "shared ");
if (shape.isMethod()) fprintf(stderr, "method ");
if (shape.hasGetterValue()) if (shape.hasGetterValue())
fprintf(stderr, "getterValue=%p ", (void *) shape.getterObject()); fprintf(stderr, "getterValue=%p ", (void *) shape.getterObject());

Просмотреть файл

@ -509,19 +509,8 @@ struct JSObject : public js::ObjectImpl
public: public:
inline bool nativeEmpty() const; inline bool nativeEmpty() const;
js::Shape *methodShapeChange(JSContext *cx, const js::Shape &shape);
bool shadowingShapeChange(JSContext *cx, const js::Shape &shape); bool shadowingShapeChange(JSContext *cx, const js::Shape &shape);
/*
* Read barrier to clone a joined function object stored as a method.
* Defined in jsobjinlines.h, but not declared inline per standard style in
* order to avoid gcc warnings.
*/
js::Shape *methodReadBarrier(JSContext *cx, const js::Shape &shape, js::Value *vp);
/* Whether method shapes can be added to this object. */
inline bool canHaveMethodBarrier() const;
/* Whether there may be indexed properties on this object. */ /* Whether there may be indexed properties on this object. */
inline bool isIndexed() const; inline bool isIndexed() const;
@ -573,8 +562,6 @@ struct JSObject : public js::ObjectImpl
void rollbackProperties(JSContext *cx, uint32_t slotSpan); void rollbackProperties(JSContext *cx, uint32_t slotSpan);
inline JSFunction *nativeGetMethod(const js::Shape *shape) const;
inline void nativeSetSlot(unsigned slot, const js::Value &value); inline void nativeSetSlot(unsigned slot, const js::Value &value);
inline void nativeSetSlotWithType(JSContext *cx, const js::Shape *shape, const js::Value &value); inline void nativeSetSlotWithType(JSContext *cx, const js::Shape *shape, const js::Value &value);
@ -940,6 +927,8 @@ struct JSObject : public js::ObjectImpl
js::Shape *changeProperty(JSContext *cx, js::Shape *shape, unsigned attrs, unsigned mask, js::Shape *changeProperty(JSContext *cx, js::Shape *shape, unsigned attrs, unsigned mask,
JSPropertyOp getter, JSStrictPropertyOp setter); JSPropertyOp getter, JSStrictPropertyOp setter);
inline bool changePropertyAttributes(JSContext *cx, js::Shape *shape, unsigned attrs);
/* Remove the property named by id from this object. */ /* Remove the property named by id from this object. */
bool removeProperty(JSContext *cx, jsid id); bool removeProperty(JSContext *cx, jsid id);
@ -1351,16 +1340,6 @@ js_AddNativeProperty(JSContext *cx, JSObject *obj, jsid id,
JSPropertyOp getter, JSStrictPropertyOp setter, uint32_t slot, JSPropertyOp getter, JSStrictPropertyOp setter, uint32_t slot,
unsigned attrs, unsigned flags, int shortid); unsigned attrs, unsigned flags, int shortid);
/*
* Change shape to have the given attrs, getter, and setter in scope, morphing
* it into a potentially new js::Shape. Return a pointer to the changed
* or identical property.
*/
extern js::Shape *
js_ChangeNativePropertyAttrs(JSContext *cx, JSObject *obj,
js::Shape *shape, unsigned attrs, unsigned mask,
JSPropertyOp getter, JSStrictPropertyOp setter);
extern JSBool extern JSBool
js_DefineOwnProperty(JSContext *cx, JSObject *obj, jsid id, js_DefineOwnProperty(JSContext *cx, JSObject *obj, jsid id,
const js::Value &descriptor, JSBool *bp); const js::Value &descriptor, JSBool *bp);
@ -1372,13 +1351,10 @@ namespace js {
*/ */
const unsigned DNP_CACHE_RESULT = 1; /* an interpreter call from JSOP_INITPROP */ const unsigned DNP_CACHE_RESULT = 1; /* an interpreter call from JSOP_INITPROP */
const unsigned DNP_DONT_PURGE = 2; /* suppress js_PurgeScopeChain */ const unsigned DNP_DONT_PURGE = 2; /* suppress js_PurgeScopeChain */
const unsigned DNP_SET_METHOD = 4; /* DefineNativeProperty,js_SetPropertyHelper const unsigned DNP_UNQUALIFIED = 4; /* Unqualified property set. Only used in
must pass the js::Shape::METHOD
flag on to JSObject::{add,put}Property */
const unsigned DNP_UNQUALIFIED = 8; /* Unqualified property set. Only used in
the defineHow argument of the defineHow argument of
js_SetPropertyHelper. */ js_SetPropertyHelper. */
const unsigned DNP_SKIP_TYPE = 0x10; /* Don't update type information */ const unsigned DNP_SKIP_TYPE = 8; /* Don't update type information */
/* /*
* Return successfully added or changed shape or NULL on error. * Return successfully added or changed shape or NULL on error.
@ -1460,22 +1436,8 @@ FindIdentifierBase(JSContext *cx, JSObject *scopeChain, PropertyName *name);
extern JSObject * extern JSObject *
js_FindVariableScope(JSContext *cx, JSFunction **funp); js_FindVariableScope(JSContext *cx, JSFunction **funp);
/* /* JSGET_CACHE_RESULT is the analogue of DNP_CACHE_RESULT for js_GetMethod. */
* JSGET_CACHE_RESULT is the analogue of JSDNP_CACHE_RESULT for js_GetMethod. const unsigned JSGET_CACHE_RESULT = 1; // from a caching interpreter opcode
*
* JSGET_METHOD_BARRIER (the default, hence 0 but provided for documentation)
* enables a read barrier that preserves standard function object semantics (by
* default we assume our caller won't leak a joined callee to script, where it
* would create hazardous mutable object sharing as well as observable identity
* according to == and ===.
*
* JSGET_NO_METHOD_BARRIER avoids the performance overhead of the method read
* barrier, which is not needed when invoking a lambda that otherwise does not
* leak its callee reference (via arguments.callee or its name).
*/
const unsigned JSGET_METHOD_BARRIER = 0; // get can leak joined function object
const unsigned JSGET_NO_METHOD_BARRIER = 1; // call to joined function can't leak
const unsigned JSGET_CACHE_RESULT = 2; // from a caching interpreter opcode
/* /*
* NB: js_NativeGet and js_NativeSet are called with the scope containing shape * NB: js_NativeGet and js_NativeSet are called with the scope containing shape
@ -1526,14 +1488,6 @@ GetMethod(JSContext *cx, JSObject *obj, PropertyName *name, unsigned getHow, Val
} /* namespace js */ } /* namespace js */
/*
* Change attributes for the given native property. The caller must ensure
* that obj is locked and this function always unlocks obj on return.
*/
extern JSBool
js_SetNativeAttributes(JSContext *cx, JSObject *obj, js::Shape *shape,
unsigned attrs);
namespace js { namespace js {
/* /*

Просмотреть файл

@ -170,6 +170,12 @@ JSObject::setSpecialAttributes(JSContext *cx, js::SpecialId sid, unsigned *attrs
return setGenericAttributes(cx, SPECIALID_TO_JSID(sid), attrsp); return setGenericAttributes(cx, SPECIALID_TO_JSID(sid), attrsp);
} }
inline bool
JSObject::changePropertyAttributes(JSContext *cx, js::Shape *shape, unsigned attrs)
{
return !!changeProperty(cx, shape, attrs, 0, shape->getter(), shape->setter());
}
inline JSBool inline JSBool
JSObject::getGeneric(JSContext *cx, JSObject *receiver, jsid id, js::Value *vp) JSObject::getGeneric(JSContext *cx, JSObject *receiver, jsid id, js::Value *vp)
{ {
@ -265,50 +271,6 @@ JSObject::enclosingScope()
return isScope() ? &asScope().enclosingScope() : getParent(); return isScope() ? &asScope().enclosingScope() : getParent();
} }
/*
* Property read barrier for deferred cloning of compiler-created function
* objects optimized as typically non-escaping, ad-hoc methods in obj.
*/
inline js::Shape *
JSObject::methodReadBarrier(JSContext *cx, const js::Shape &shape, js::Value *vp)
{
JS_ASSERT(nativeContains(cx, shape));
JS_ASSERT(shape.isMethod());
JS_ASSERT(shape.hasSlot());
JS_ASSERT(shape.hasDefaultSetter());
JS_ASSERT(!isGlobal()); /* i.e. we are not changing the global shape */
JSFunction *fun = vp->toObject().toFunction();
JS_ASSERT(!fun->isClonedMethod());
JS_ASSERT(fun->isNullClosure());
fun = js::CloneFunctionObject(cx, fun);
if (!fun)
return NULL;
fun->setMethodObj(*this);
/*
* Replace the method property with an ordinary data property. This is
* equivalent to this->setProperty(cx, shape.id, vp) except that any
* watchpoint on the property is not triggered.
*/
uint32_t slot = shape.slot();
js::Shape *newshape = methodShapeChange(cx, shape);
if (!newshape)
return NULL;
JS_ASSERT(!newshape->isMethod());
JS_ASSERT(newshape->slot() == slot);
vp->setObject(*fun);
nativeSetSlot(slot, *vp);
return newshape;
}
inline bool
JSObject::canHaveMethodBarrier() const
{
return isObject() || isFunction() || isPrimitive() || isDate();
}
inline bool inline bool
JSObject::isFixedSlot(size_t slot) JSObject::isFixedSlot(size_t slot)
{ {
@ -964,22 +926,6 @@ JSObject::principals(JSContext *cx)
return cx->compartment ? cx->compartment->principals : NULL; return cx->compartment ? cx->compartment->principals : NULL;
} }
inline JSFunction *
JSObject::nativeGetMethod(const js::Shape *shape) const
{
/*
* For method shapes, this object must have an uncloned function object in
* the shape's slot.
*/
JS_ASSERT(shape->isMethod());
#ifdef DEBUG
JSObject *obj = &nativeGetSlot(shape->slot()).toObject();
JS_ASSERT(obj->isFunction() && !obj->toFunction()->isClonedMethod());
#endif
return static_cast<JSFunction *>(&nativeGetSlot(shape->slot()).toObject());
}
inline void inline void
JSObject::nativeSetSlot(unsigned slot, const js::Value &value) JSObject::nativeSetSlot(unsigned slot, const js::Value &value)
{ {

Просмотреть файл

@ -312,7 +312,7 @@ PreprocessValue(JSContext *cx, JSObject *holder, KeyType key, Value *vp, Stringi
if (vp->isObject()) { if (vp->isObject()) {
Value toJSON; Value toJSON;
jsid id = ATOM_TO_JSID(cx->runtime->atomState.toJSONAtom); jsid id = ATOM_TO_JSID(cx->runtime->atomState.toJSONAtom);
if (!js_GetMethod(cx, &vp->toObject(), id, JSGET_NO_METHOD_BARRIER, &toJSON)) if (!js_GetMethod(cx, &vp->toObject(), id, 0, &toJSON))
return false; return false;
if (js_IsCallable(toJSON)) { if (js_IsCallable(toJSON)) {

Просмотреть файл

@ -4515,7 +4515,6 @@ Decompile(SprintStack *ss, jsbytecode *pc, int nb)
break; break;
case JSOP_SETPROP: case JSOP_SETPROP:
case JSOP_SETMETHOD:
{ {
LOAD_ATOM(0); LOAD_ATOM(0);
GET_QUOTE_AND_FMT("[%s] %s= ", ".%s %s= ", xval); GET_QUOTE_AND_FMT("[%s] %s= ", ".%s %s= ", xval);
@ -5120,7 +5119,6 @@ Decompile(SprintStack *ss, jsbytecode *pc, int nb)
break; break;
case JSOP_INITPROP: case JSOP_INITPROP:
case JSOP_INITMETHOD:
LOAD_ATOM(0); LOAD_ATOM(0);
xval = QuoteString(&ss->sprinter, atom, jschar(IsIdentifier(atom) ? 0 : '\'')); xval = QuoteString(&ss->sprinter, atom, jschar(IsIdentifier(atom) ? 0 : '\''));
if (!xval) if (!xval)

Просмотреть файл

@ -569,7 +569,7 @@ class OpcodeCounts
* Access ops include all name, element and property reads, as well as * Access ops include all name, element and property reads, as well as
* SETELEM and SETPROP (for ElementCounts/PropertyCounts alignment). * SETELEM and SETPROP (for ElementCounts/PropertyCounts alignment).
*/ */
if (op == JSOP_SETELEM || op == JSOP_SETPROP || op == JSOP_SETMETHOD) if (op == JSOP_SETELEM || op == JSOP_SETPROP)
return true; return true;
int format = js_CodeSpec[op].format; int format = js_CodeSpec[op].format;
return !!(format & (JOF_NAME | JOF_GNAME | JOF_ELEM | JOF_PROP)) return !!(format & (JOF_NAME | JOF_GNAME | JOF_ELEM | JOF_PROP))

Просмотреть файл

@ -532,15 +532,10 @@ OPDEF(JSOP_LENGTH, 217, "length", NULL, 5, 1, 1, 18, JOF_ATOM|J
OPDEF(JSOP_HOLE, 218, "hole", NULL, 1, 0, 1, 0, JOF_BYTE) OPDEF(JSOP_HOLE, 218, "hole", NULL, 1, 0, 1, 0, JOF_BYTE)
OPDEF(JSOP_UNUSED17, 219,"unused17", NULL, 1, 0, 0, 0, JOF_BYTE) OPDEF(JSOP_UNUSED17, 219,"unused17", NULL, 1, 0, 0, 0, JOF_BYTE)
OPDEF(JSOP_UNUSED24, 220,"unused18", NULL, 1, 0, 0, 0, JOF_BYTE) OPDEF(JSOP_UNUSED24, 220,"unused24", NULL, 1, 0, 0, 0, JOF_BYTE)
OPDEF(JSOP_UNUSED25, 221,"unused19", NULL, 1, 0, 0, 0, JOF_BYTE) OPDEF(JSOP_UNUSED25, 221,"unused25", NULL, 1, 0, 0, 0, JOF_BYTE)
OPDEF(JSOP_UNUSED29, 222,"unused29", NULL, 1, 0, 0, 0, JOF_BYTE)
/* OPDEF(JSOP_UNUSED30, 223,"unused30", NULL, 1, 0, 0, 0, JOF_BYTE)
* Joined function object as method optimization support.
*/
OPDEF(JSOP_SETMETHOD, 222,"setmethod", NULL, 5, 2, 1, 3, JOF_ATOM|JOF_PROP|JOF_SET|JOF_DETECTING)
OPDEF(JSOP_INITMETHOD, 223,"initmethod", NULL, 5, 2, 1, 3, JOF_ATOM|JOF_PROP|JOF_SET|JOF_DETECTING)
OPDEF(JSOP_UNUSED16, 224,"unused16", NULL, 1, 0, 0, 0, JOF_BYTE) OPDEF(JSOP_UNUSED16, 224,"unused16", NULL, 1, 0, 0, 0, JOF_BYTE)
/* Pop the stack, convert to a jsid (int or string), and push back. */ /* Pop the stack, convert to a jsid (int or string), and push back. */

Просмотреть файл

@ -297,7 +297,6 @@ Shape::dump(JSContext *cx, FILE *fp) const
fputs("(", fp); fputs("(", fp);
#define DUMP_FLAG(name, display) if (flags & name) fputs(&(" " #display)[first], fp), first = 0 #define DUMP_FLAG(name, display) if (flags & name) fputs(&(" " #display)[first], fp), first = 0
DUMP_FLAG(HAS_SHORTID, has_shortid); DUMP_FLAG(HAS_SHORTID, has_shortid);
DUMP_FLAG(METHOD, method);
DUMP_FLAG(IN_DICTIONARY, in_dictionary); DUMP_FLAG(IN_DICTIONARY, in_dictionary);
#undef DUMP_FLAG #undef DUMP_FLAG
fputs(") ", fp); fputs(") ", fp);

Просмотреть файл

@ -498,16 +498,9 @@ NormalizeGetterAndSetter(JSContext *cx, JSObject *obj,
JS_ASSERT(!(attrs & JSPROP_SETTER)); JS_ASSERT(!(attrs & JSPROP_SETTER));
setter = NULL; setter = NULL;
} }
if (flags & Shape::METHOD) { if (getter == JS_PropertyStub) {
JS_ASSERT_IF(getter, getter == JS_PropertyStub); JS_ASSERT(!(attrs & JSPROP_GETTER));
JS_ASSERT(!setter);
JS_ASSERT(!(attrs & (JSPROP_GETTER | JSPROP_SETTER)));
getter = NULL; getter = NULL;
} else {
if (getter == JS_PropertyStub) {
JS_ASSERT(!(attrs & JSPROP_GETTER));
getter = NULL;
}
} }
return true; return true;
@ -808,9 +801,6 @@ JSObject::changeProperty(JSContext *cx, Shape *shape, unsigned attrs, unsigned m
JS_ASSERT(!((attrs ^ shape->attrs) & JSPROP_SHARED) || JS_ASSERT(!((attrs ^ shape->attrs) & JSPROP_SHARED) ||
!(attrs & JSPROP_SHARED)); !(attrs & JSPROP_SHARED));
/* Don't allow method properties to be changed to have a getter or setter. */
JS_ASSERT_IF(shape->isMethod(), !getter && !setter);
types::MarkTypePropertyConfigured(cx, this, shape->propid()); types::MarkTypePropertyConfigured(cx, this, shape->propid());
if (attrs & (JSPROP_GETTER | JSPROP_SETTER)) if (attrs & (JSPROP_GETTER | JSPROP_SETTER))
types::AddTypePropertyId(cx, this, shape->propid(), types::Type::UnknownType()); types::AddTypePropertyId(cx, this, shape->propid(), types::Type::UnknownType());
@ -1041,44 +1031,6 @@ JSObject::replaceWithNewEquivalentShape(JSContext *cx, Shape *oldShape, Shape *n
return newShape; return newShape;
} }
Shape *
JSObject::methodShapeChange(JSContext *cx, const Shape &shape)
{
JS_ASSERT(shape.isMethod());
if (!inDictionaryMode() && !toDictionaryMode(cx))
return NULL;
Shape *spare = js_NewGCShape(cx);
if (!spare)
return NULL;
new (spare) Shape(shape.base()->unowned(), 0);
#ifdef DEBUG
JS_ASSERT(canHaveMethodBarrier());
JS_ASSERT(!shape.setter());
JS_ASSERT(!shape.hasShortID());
#endif
/*
* Clear Shape::METHOD from flags as we are despecializing from a
* method memoized in the property tree to a plain old function-valued
* property.
*/
Shape *result =
putProperty(cx, shape.propid(), NULL, NULL, shape.slot(),
shape.attrs,
shape.getFlags() & ~Shape::METHOD,
0);
if (!result)
return NULL;
if (result != lastProperty())
JS_ALWAYS_TRUE(generateOwnShape(cx, spare));
return result;
}
bool bool
JSObject::shadowingShapeChange(JSContext *cx, const Shape &shape) JSObject::shadowingShapeChange(JSContext *cx, const Shape &shape)
{ {

Просмотреть файл

@ -649,43 +649,15 @@ struct Shape : public js::gc::Cell
/* Public bits stored in shape->flags. */ /* Public bits stored in shape->flags. */
enum { enum {
HAS_SHORTID = 0x40, HAS_SHORTID = 0x40,
METHOD = 0x80, PUBLIC_FLAGS = HAS_SHORTID
PUBLIC_FLAGS = HAS_SHORTID | METHOD
}; };
bool inDictionary() const { return (flags & IN_DICTIONARY) != 0; } bool inDictionary() const { return (flags & IN_DICTIONARY) != 0; }
unsigned getFlags() const { return flags & PUBLIC_FLAGS; } unsigned getFlags() const { return flags & PUBLIC_FLAGS; }
bool hasShortID() const { return (flags & HAS_SHORTID) != 0; } bool hasShortID() const { return (flags & HAS_SHORTID) != 0; }
/*
* A shape has a method barrier when some compiler-created "null closure"
* function objects (functions that do not use lexical bindings above their
* scope, only free variable names) that have a correct JSSLOT_PARENT value
* thanks to the COMPILE_N_GO optimization are stored in objects without
* cloning.
*
* The de-facto standard JS language requires each evaluation of such a
* closure to result in a unique (according to === and observable effects)
* function object. When storing a function to a property, we use method
* shapes to speculate that these effects will never be observed: the
* property will only be used in calls, and f.callee will not be used
* to get a handle on the object.
*
* If either a non-call use or callee access occurs, then the function is
* cloned and the object is reshaped with a non-method property.
*
* Note that method shapes do not imply the object has a particular
* uncloned function, just that the object has *some* uncloned function
* in the shape's slot.
*/
bool isMethod() const {
JS_ASSERT_IF(flags & METHOD, !base()->rawGetter);
return (flags & METHOD) != 0;
}
PropertyOp getter() const { return base()->rawGetter; } PropertyOp getter() const { return base()->rawGetter; }
bool hasDefaultGetterOrIsMethod() const { return !base()->rawGetter; } bool hasDefaultGetter() const { return !base()->rawGetter; }
bool hasDefaultGetter() const { return !base()->rawGetter && !isMethod(); }
PropertyOp getterOp() const { JS_ASSERT(!hasGetterValue()); return base()->rawGetter; } PropertyOp getterOp() const { JS_ASSERT(!hasGetterValue()); return base()->rawGetter; }
JSObject *getterObject() const { JS_ASSERT(hasGetterValue()); return base()->getterObj; } JSObject *getterObject() const { JS_ASSERT(hasGetterValue()); return base()->getterObj; }

Просмотреть файл

@ -282,16 +282,10 @@ Shape::get(JSContext* cx, JSObject *receiver, JSObject* obj, JSObject *pobj, js:
JS_ASSERT(!hasDefaultGetter()); JS_ASSERT(!hasDefaultGetter());
if (hasGetterValue()) { if (hasGetterValue()) {
JS_ASSERT(!isMethod());
js::Value fval = getterValue(); js::Value fval = getterValue();
return js::InvokeGetterOrSetter(cx, receiver, fval, 0, 0, vp); return js::InvokeGetterOrSetter(cx, receiver, fval, 0, 0, vp);
} }
if (isMethod()) {
vp->setObject(*pobj->nativeGetMethod(this));
return pobj->methodReadBarrier(cx, *this, vp);
}
/* /*
* |with (it) color;| ends up here, as do XML filter-expressions. * |with (it) color;| ends up here, as do XML filter-expressions.
* Avoid exposing the With object to native getters. * Avoid exposing the With object to native getters.

Просмотреть файл

@ -3312,7 +3312,7 @@ js_ValueToSource(JSContext *cx, const Value &v)
Value rval = NullValue(); Value rval = NullValue();
Value fval; Value fval;
jsid id = ATOM_TO_JSID(cx->runtime->atomState.toSourceAtom); jsid id = ATOM_TO_JSID(cx->runtime->atomState.toSourceAtom);
if (!js_GetMethod(cx, &v.toObject(), id, JSGET_NO_METHOD_BARRIER, &fval)) if (!js_GetMethod(cx, &v.toObject(), id, 0, &fval))
return NULL; return NULL;
if (js_IsCallable(fval)) { if (js_IsCallable(fval)) {
if (!Invoke(cx, v, fval, 0, NULL, &rval)) if (!Invoke(cx, v, fval, 0, NULL, &rval))

Просмотреть файл

@ -149,26 +149,8 @@ WatchpointMap::triggerWatchpoint(JSContext *cx, JSObject *obj, jsid id, Value *v
old.setUndefined(); old.setUndefined();
if (obj->isNative()) { if (obj->isNative()) {
if (const Shape *shape = obj->nativeLookup(cx, id)) { if (const Shape *shape = obj->nativeLookup(cx, id)) {
if (shape->hasSlot()) { if (shape->hasSlot())
if (shape->isMethod()) { old = obj->nativeGetSlot(shape->slot());
/*
* The existing watched property is a method. Trip
* the method read barrier in order to avoid
* passing an uncloned function object to the
* handler.
*/
old = UndefinedValue();
Value method = ObjectValue(*obj->nativeGetMethod(shape));
if (!obj->methodReadBarrier(cx, *shape, &method))
return false;
shape = obj->nativeLookup(cx, id);
JS_ASSERT(shape->isDataDescriptor());
JS_ASSERT(!shape->isMethod());
old = method;
} else {
old = obj->nativeGetSlot(shape->slot());
}
}
} }
} }

Просмотреть файл

@ -1715,8 +1715,7 @@ mjit::Compiler::finishThisUp()
jitPics[i].shapeRegHasBaseShape = true; jitPics[i].shapeRegHasBaseShape = true;
jitPics[i].pc = pics[i].pc; jitPics[i].pc = pics[i].pc;
if (pics[i].kind == ic::PICInfo::SET || if (pics[i].kind == ic::PICInfo::SET) {
pics[i].kind == ic::PICInfo::SETMETHOD) {
jitPics[i].u.vr = pics[i].vr; jitPics[i].u.vr = pics[i].vr;
} else if (pics[i].kind != ic::PICInfo::NAME) { } else if (pics[i].kind != ic::PICInfo::NAME) {
if (pics[i].hasTypeCheck) { if (pics[i].hasTypeCheck) {
@ -2900,11 +2899,6 @@ mjit::Compiler::generateMethod()
BEGIN_CASE(JSOP_ENDINIT) BEGIN_CASE(JSOP_ENDINIT)
END_CASE(JSOP_ENDINIT) END_CASE(JSOP_ENDINIT)
BEGIN_CASE(JSOP_INITMETHOD)
jsop_initmethod();
frame.pop();
END_CASE(JSOP_INITMETHOD)
BEGIN_CASE(JSOP_INITPROP) BEGIN_CASE(JSOP_INITPROP)
jsop_initprop(); jsop_initprop();
frame.pop(); frame.pop();
@ -2971,7 +2965,6 @@ mjit::Compiler::generateMethod()
END_CASE(JSOP_SETPROP) END_CASE(JSOP_SETPROP)
BEGIN_CASE(JSOP_SETNAME) BEGIN_CASE(JSOP_SETNAME)
BEGIN_CASE(JSOP_SETMETHOD)
{ {
jsbytecode *next = &PC[JSOP_SETNAME_LENGTH]; jsbytecode *next = &PC[JSOP_SETNAME_LENGTH];
bool pop = JSOp(*next) == JSOP_POP && !analysis->jumpTarget(next); bool pop = JSOp(*next) == JSOP_POP && !analysis->jumpTarget(next);
@ -3078,29 +3071,6 @@ mjit::Compiler::generateMethod()
JSObjStubFun stub = stubs::Lambda; JSObjStubFun stub = stubs::Lambda;
uint32_t uses = 0; uint32_t uses = 0;
jsbytecode *pc2 = NULL;
if (fun->joinable()) {
pc2 = PC + JSOP_LAMBDA_LENGTH;
JSOp next = JSOp(*pc2);
if (next == JSOP_INITMETHOD) {
stub = stubs::LambdaJoinableForInit;
} else if (next == JSOP_SETMETHOD) {
stub = stubs::LambdaJoinableForSet;
uses = 1;
} else if (next == JSOP_CALL) {
int iargc = GET_ARGC(pc2);
if (iargc == 1 || iargc == 2) {
stub = stubs::LambdaJoinableForCall;
uses = frame.frameSlots();
}
} else if (next == JSOP_NULL) {
pc2 += JSOP_NULL_LENGTH;
if (JSOp(*pc2) == JSOP_CALL && GET_ARGC(pc2) == 0)
stub = stubs::LambdaJoinableForNull;
}
}
prepareStubCall(Uses(uses)); prepareStubCall(Uses(uses));
masm.move(ImmPtr(fun), Registers::ArgReg1); masm.move(ImmPtr(fun), Registers::ArgReg1);
@ -3249,7 +3219,7 @@ mjit::Compiler::generateMethod()
/* Update information about the result type of access operations. */ /* Update information about the result type of access operations. */
if (OpcodeCounts::accessOp(op) && if (OpcodeCounts::accessOp(op) &&
op != JSOP_SETPROP && op != JSOP_SETMETHOD && op != JSOP_SETELEM) { op != JSOP_SETPROP && op != JSOP_SETELEM) {
FrameEntry *fe = (GetDefCount(script, lastPC - script->code) == 1) FrameEntry *fe = (GetDefCount(script, lastPC - script->code) == 1)
? frame.peek(-1) ? frame.peek(-1)
: frame.peek(-2); : frame.peek(-2);
@ -5267,7 +5237,7 @@ mjit::Compiler::testSingletonProperty(JSObject *obj, jsid id)
return false; return false;
if (holder->getSlot(shape->slot()).isUndefined()) if (holder->getSlot(shape->slot()).isUndefined())
return false; return false;
} else if (!shape->isMethod()) { } else {
return false; return false;
} }
@ -5600,10 +5570,7 @@ mjit::Compiler::jsop_setprop(PropertyName *name, bool popGuaranteed)
} }
#endif #endif
ic::PICInfo::Kind kind = (op == JSOP_SETMETHOD) PICGenInfo pic(ic::PICInfo::SET, op);
? ic::PICInfo::SETMETHOD
: ic::PICInfo::SET;
PICGenInfo pic(kind, op);
pic.name = name; pic.name = name;
if (monitored(PC)) { if (monitored(PC)) {
@ -6374,7 +6341,7 @@ mjit::Compiler::jsop_getgname(uint32_t index)
* reallocation of the global object's slots. * reallocation of the global object's slots.
*/ */
const js::Shape *shape = globalObj->nativeLookup(cx, ATOM_TO_JSID(name)); const js::Shape *shape = globalObj->nativeLookup(cx, ATOM_TO_JSID(name));
if (shape && shape->hasDefaultGetterOrIsMethod() && shape->hasSlot()) { if (shape && shape->hasDefaultGetter() && shape->hasSlot()) {
HeapSlot *value = &globalObj->getSlotRef(shape->slot()); HeapSlot *value = &globalObj->getSlotRef(shape->slot());
if (!value->isUndefined() && if (!value->isUndefined() &&
!propertyTypes->isOwnProperty(cx, globalObj->getType(cx), true)) { !propertyTypes->isOwnProperty(cx, globalObj->getType(cx), true)) {
@ -6497,7 +6464,7 @@ mjit::Compiler::jsop_setgname(PropertyName *name, bool popGuaranteed)
if (!types) if (!types)
return; return;
const js::Shape *shape = globalObj->nativeLookup(cx, ATOM_TO_JSID(name)); const js::Shape *shape = globalObj->nativeLookup(cx, ATOM_TO_JSID(name));
if (shape && !shape->isMethod() && shape->hasDefaultSetter() && if (shape && shape->hasDefaultSetter() &&
shape->writable() && shape->hasSlot() && shape->writable() && shape->hasSlot() &&
!types->isOwnProperty(cx, globalObj->getType(cx), true)) { !types->isOwnProperty(cx, globalObj->getType(cx), true)) {
watchGlobalReallocation(); watchGlobalReallocation();

Просмотреть файл

@ -262,7 +262,7 @@ class Compiler : public BaseCompiler
return getPropLabels_; return getPropLabels_;
} }
ic::SetPropLabels &setPropLabels() { ic::SetPropLabels &setPropLabels() {
JS_ASSERT(kind == ic::PICInfo::SET || kind == ic::PICInfo::SETMETHOD); JS_ASSERT(kind == ic::PICInfo::SET);
return setPropLabels_; return setPropLabels_;
} }
ic::BindNameLabels &bindNameLabels() { ic::BindNameLabels &bindNameLabels() {

Просмотреть файл

@ -2658,22 +2658,6 @@ mjit::Compiler::jsop_pos()
stubcc.rejoin(Changes(1)); stubcc.rejoin(Changes(1));
} }
void
mjit::Compiler::jsop_initmethod()
{
#ifdef DEBUG
FrameEntry *obj = frame.peek(-2);
#endif
JSAtom *atom = script->getAtom(GET_UINT32_INDEX(PC));
/* Initializers with INITMETHOD are not fast yet. */
JS_ASSERT(!frame.extra(obj).initObject);
prepareStubCall(Uses(2));
masm.move(ImmPtr(atom), Registers::ArgReg1);
INLINE_STUBCALL(stubs::InitMethod, REJOIN_FALLTHROUGH);
}
void void
mjit::Compiler::jsop_initprop() mjit::Compiler::jsop_initprop()
{ {

Просмотреть файл

@ -1869,8 +1869,7 @@ LoopState::analyzeLoopBody(unsigned frame)
break; break;
} }
case JSOP_SETPROP: case JSOP_SETPROP: {
case JSOP_SETMETHOD: {
JSAtom *atom = script->getAtom(GET_UINT32_INDEX(pc)); JSAtom *atom = script->getAtom(GET_UINT32_INDEX(pc));
jsid id = MakeTypeId(cx, ATOM_TO_JSID(atom)); jsid id = MakeTypeId(cx, ATOM_TO_JSID(atom));

Просмотреть файл

@ -99,7 +99,7 @@ ic::GetGlobalName(VMFrame &f, ic::GetGlobalNameIC *ic)
} }
if (!shape || if (!shape ||
!shape->hasDefaultGetterOrIsMethod() || !shape->hasDefaultGetter() ||
!shape->hasSlot()) !shape->hasSlot())
{ {
if (shape) if (shape)
@ -165,8 +165,7 @@ UpdateSetGlobalName(VMFrame &f, ic::SetGlobalNameIC *ic, JSObject *obj, const Sh
if (!shape) if (!shape)
return Lookup_Uncacheable; return Lookup_Uncacheable;
if (shape->isMethod() || if (!shape->hasDefaultSetter() ||
!shape->hasDefaultSetter() ||
!shape->writable() || !shape->writable() ||
!shape->hasSlot() || !shape->hasSlot() ||
obj->watched()) obj->watched())

Просмотреть файл

@ -350,23 +350,6 @@ class SetPropCompiler : public PICStubCompiler
lastReg = pic.shapeReg; lastReg = pic.shapeReg;
} }
if (pic.kind == ic::PICInfo::SETMETHOD) {
/*
* Guard that the value is equal to the shape's method.
* We already know it is a function, so test the payload.
*/
JS_ASSERT(shape->isMethod());
JSObject *funobj = obj->nativeGetMethod(shape);
if (pic.u.vr.isConstant()) {
JS_ASSERT(funobj == &pic.u.vr.value().toObject());
} else {
Jump mismatchedFunction =
masm.branchPtr(Assembler::NotEqual, pic.u.vr.dataReg(), ImmPtr(funobj));
if (!slowExits.append(mismatchedFunction))
return error();
}
}
if (obj->isFixedSlot(shape->slot())) { if (obj->isFixedSlot(shape->slot())) {
Address address(pic.objReg, Address address(pic.objReg,
JSObject::getFixedSlotOffset(shape->slot())); JSObject::getFixedSlotOffset(shape->slot()));
@ -389,7 +372,6 @@ class SetPropCompiler : public PICStubCompiler
/* Write the object's new shape. */ /* Write the object's new shape. */
masm.storePtr(ImmPtr(shape), Address(pic.objReg, JSObject::offsetOfShape())); masm.storePtr(ImmPtr(shape), Address(pic.objReg, JSObject::offsetOfShape()));
} else if (shape->hasDefaultSetter()) { } else if (shape->hasDefaultSetter()) {
JS_ASSERT(!shape->isMethod());
Address address = masm.objPropAddress(obj, pic.objReg, shape->slot()); Address address = masm.objPropAddress(obj, pic.objReg, shape->slot());
masm.storeValue(pic.u.vr, address); masm.storeValue(pic.u.vr, address);
} else { } else {
@ -585,17 +567,6 @@ class SetPropCompiler : public PICStubCompiler
unsigned flags = 0; unsigned flags = 0;
PropertyOp getter = clasp->getProperty; PropertyOp getter = clasp->getProperty;
if (pic.kind == ic::PICInfo::SETMETHOD) {
if (!obj->canHaveMethodBarrier())
return disable("can't have method barrier");
JSObject *funobj = &f.regs.sp[-1].toObject();
if (funobj->toFunction()->isClonedMethod())
return disable("mismatched function");
flags |= Shape::METHOD;
}
/* /*
* Define the property but do not set it yet. For setmethod, * Define the property but do not set it yet. For setmethod,
* populate the slot to satisfy the method invariant (in case we * populate the slot to satisfy the method invariant (in case we
@ -606,8 +577,6 @@ class SetPropCompiler : public PICStubCompiler
SHAPE_INVALID_SLOT, JSPROP_ENUMERATE, flags, 0); SHAPE_INVALID_SLOT, JSPROP_ENUMERATE, flags, 0);
if (!shape) if (!shape)
return error(); return error();
if (flags & Shape::METHOD)
obj->nativeSetSlot(shape->slot(), f.regs.sp[-1]);
if (monitor.recompiled()) if (monitor.recompiled())
return Lookup_Uncacheable; return Lookup_Uncacheable;
@ -647,13 +616,8 @@ class SetPropCompiler : public PICStubCompiler
} }
const Shape *shape = (const Shape *) prop; const Shape *shape = (const Shape *) prop;
if (pic.kind == ic::PICInfo::SETMETHOD && !shape->isMethod())
return disable("set method on non-method shape");
if (!shape->writable()) if (!shape->writable())
return disable("readonly"); return disable("readonly");
if (shape->isMethod())
return disable("method");
if (shape->hasDefaultSetter()) { if (shape->hasDefaultSetter()) {
if (!shape->hasSlot()) if (!shape->hasSlot())
return disable("invalid slot"); return disable("invalid slot");
@ -789,27 +753,22 @@ struct GetPropHelper {
LookupStatus testForGet() { LookupStatus testForGet() {
if (!shape->hasDefaultGetter()) { if (!shape->hasDefaultGetter()) {
if (shape->isMethod()) { if (shape->hasGetterValue())
if (JSOp(*f.pc()) != JSOP_CALLPROP) return ic.disable(f, "getter value shape");
return ic.disable(f, "method valued shape"); if (shape->hasSlot() && holder != obj)
} else { return ic.disable(f, "slotful getter hook through prototype");
if (shape->hasGetterValue()) if (!ic.canCallHook)
return ic.disable(f, "getter value shape"); return ic.disable(f, "can't call getter hook");
if (shape->hasSlot() && holder != obj) if (f.regs.inlined()) {
return ic.disable(f, "slotful getter hook through prototype"); /*
if (!ic.canCallHook) * As with native stubs, getter hook stubs can't be
return ic.disable(f, "can't call getter hook"); * generated for inline frames. Mark the inner function
if (f.regs.inlined()) { * as uninlineable and recompile.
/* */
* As with native stubs, getter hook stubs can't be f.script()->uninlineable = true;
* generated for inline frames. Mark the inner function MarkTypeObjectFlags(cx, f.script()->function(),
* as uninlineable and recompile. types::OBJECT_FLAG_UNINLINEABLE);
*/ return Lookup_Uncacheable;
f.script()->uninlineable = true;
MarkTypeObjectFlags(cx, f.script()->function(),
types::OBJECT_FLAG_UNINLINEABLE);
return Lookup_Uncacheable;
}
} }
} else if (!shape->hasSlot()) { } else if (!shape->hasSlot()) {
return ic.disable(f, "no slot"); return ic.disable(f, "no slot");
@ -962,7 +921,7 @@ class GetPropCompiler : public PICStubCompiler
return status; return status;
if (getprop.obj != getprop.holder) if (getprop.obj != getprop.holder)
return disable("proto walk on String.prototype"); return disable("proto walk on String.prototype");
if (!getprop.shape->hasDefaultGetterOrIsMethod()) if (!getprop.shape->hasDefaultGetter())
return disable("getter hook on String.prototype"); return disable("getter hook on String.prototype");
if (hadGC()) if (hadGC())
return Lookup_Uncacheable; return Lookup_Uncacheable;
@ -1239,7 +1198,7 @@ class GetPropCompiler : public PICStubCompiler
pic.secondShapeGuard = 0; pic.secondShapeGuard = 0;
} }
if (!shape->hasDefaultGetterOrIsMethod()) { if (!shape->hasDefaultGetter()) {
generateGetterStub(masm, shape, start, shapeMismatches); generateGetterStub(masm, shape, start, shapeMismatches);
if (setStubShapeOffset) if (setStubShapeOffset)
pic.getPropLabels().setStubShapeJump(masm, start, stubShapeJumpLabel); pic.getPropLabels().setStubShapeJump(masm, start, stubShapeJumpLabel);
@ -1327,7 +1286,7 @@ class GetPropCompiler : public PICStubCompiler
return Lookup_Uncacheable; return Lookup_Uncacheable;
if (obj == getprop.holder && if (obj == getprop.holder &&
getprop.shape->hasDefaultGetterOrIsMethod() && getprop.shape->hasDefaultGetter() &&
!pic.inlinePathPatched) { !pic.inlinePathPatched) {
return patchInline(getprop.holder, getprop.shape); return patchInline(getprop.holder, getprop.shape);
} }
@ -1675,7 +1634,7 @@ class ScopeNameCompiler : public PICStubCompiler
JSObject *normalized = obj; JSObject *normalized = obj;
if (obj->isWith() && !shape->hasDefaultGetter()) if (obj->isWith() && !shape->hasDefaultGetter())
normalized = &obj->asWith().object(); normalized = &obj->asWith().object();
NATIVE_GET(cx, normalized, holder, shape, JSGET_METHOD_BARRIER, vp, return false); NATIVE_GET(cx, normalized, holder, shape, 0, vp, return false);
return true; return true;
} }
}; };

Просмотреть файл

@ -384,7 +384,6 @@ struct PICInfo : public BasePolyIC {
{ {
GET, // JSOP_GETPROP GET, // JSOP_GETPROP
SET, // JSOP_SETPROP, JSOP_SETNAME SET, // JSOP_SETPROP, JSOP_SETNAME
SETMETHOD, // JSOP_SETMETHOD
NAME, // JSOP_NAME NAME, // JSOP_NAME
BIND, // JSOP_BINDNAME BIND, // JSOP_BINDNAME
XNAME // JSOP_GETXPROP XNAME // JSOP_GETXPROP
@ -461,7 +460,7 @@ struct PICInfo : public BasePolyIC {
types::TypeSet *rhsTypes; types::TypeSet *rhsTypes;
inline bool isSet() const { inline bool isSet() const {
return kind == SET || kind == SETMETHOD; return kind == SET;
} }
inline bool isGet() const { inline bool isGet() const {
return kind == GET; return kind == GET;

Просмотреть файл

@ -998,69 +998,6 @@ stubs::RegExp(VMFrame &f, JSObject *regex)
f.regs.sp[0].setObject(*obj); f.regs.sp[0].setObject(*obj);
} }
JSObject * JS_FASTCALL
stubs::LambdaJoinableForInit(VMFrame &f, JSFunction *fun)
{
JS_ASSERT(fun->joinable());
DebugOnly<jsbytecode*> nextpc = f.regs.pc + JSOP_LAMBDA_LENGTH;
JS_ASSERT(fun->methodAtom() == f.script()->getAtom(GET_UINT32_INDEX(nextpc)));
return fun;
}
JSObject * JS_FASTCALL
stubs::LambdaJoinableForSet(VMFrame &f, JSFunction *fun)
{
JS_ASSERT(fun->joinable());
const Value &lref = f.regs.sp[-1];
if (lref.isObject() && lref.toObject().canHaveMethodBarrier()) {
DebugOnly<jsbytecode*> nextpc = f.regs.pc + JSOP_LAMBDA_LENGTH;
JS_ASSERT(fun->methodAtom() == f.script()->getAtom(GET_UINT32_INDEX(nextpc)));
return fun;
}
return Lambda(f, fun);
}
JSObject * JS_FASTCALL
stubs::LambdaJoinableForCall(VMFrame &f, JSFunction *fun)
{
JS_ASSERT(fun->joinable());
/*
* Array.prototype.sort and String.prototype.replace are optimized as if
* they are special form. We know that they won't leak the joined function
* object fun, therefore we don't need to clone that compiler-created
* function object for identity/mutation reasons.
*/
int iargc = GET_ARGC(f.regs.pc + JSOP_LAMBDA_LENGTH);
/*
* Note that we have not yet pushed fun as the final argument, so
* regs.sp[1 - (iargc + 2)], and not regs.sp[-(iargc + 2)], is the callee
* for this JSOP_CALL.
*/
const Value &cref = f.regs.sp[1 - (iargc + 2)];
JSFunction *callee;
if (IsFunctionObject(cref, &callee)) {
Native native = callee->maybeNative();
if (native) {
if (iargc == 1 && native == array_sort)
return fun;
if (iargc == 2 && native == str_replace)
return fun;
}
}
return Lambda(f, fun);
}
JSObject * JS_FASTCALL
stubs::LambdaJoinableForNull(VMFrame &f, JSFunction *fun)
{
JS_ASSERT(fun->joinable());
return fun;
}
JSObject * JS_FASTCALL JSObject * JS_FASTCALL
stubs::Lambda(VMFrame &f, JSFunction *fun) stubs::Lambda(VMFrame &f, JSFunction *fun)
{ {
@ -1141,11 +1078,10 @@ InitPropOrMethod(VMFrame &f, PropertyName *name, JSOp op)
/* Get the immediate property name into id. */ /* Get the immediate property name into id. */
jsid id = ATOM_TO_JSID(name); jsid id = ATOM_TO_JSID(name);
unsigned defineHow = (op == JSOP_INITMETHOD) ? DNP_SET_METHOD : 0;
if (JS_UNLIKELY(name == cx->runtime->atomState.protoAtom) if (JS_UNLIKELY(name == cx->runtime->atomState.protoAtom)
? !js_SetPropertyHelper(cx, obj, id, defineHow, &rval, false) ? !js_SetPropertyHelper(cx, obj, id, 0, &rval, false)
: !DefineNativeProperty(cx, obj, id, rval, NULL, NULL, : !DefineNativeProperty(cx, obj, id, rval, NULL, NULL,
JSPROP_ENUMERATE, 0, 0, defineHow)) { JSPROP_ENUMERATE, 0, 0, 0)) {
THROW(); THROW();
} }
} }
@ -1156,12 +1092,6 @@ stubs::InitProp(VMFrame &f, PropertyName *name)
InitPropOrMethod(f, name, JSOP_INITPROP); InitPropOrMethod(f, name, JSOP_INITPROP);
} }
void JS_FASTCALL
stubs::InitMethod(VMFrame &f, PropertyName *name)
{
InitPropOrMethod(f, name, JSOP_INITMETHOD);
}
void JS_FASTCALL void JS_FASTCALL
stubs::IterNext(VMFrame &f, int32_t offset) stubs::IterNext(VMFrame &f, int32_t offset)
{ {

Просмотреть файл

@ -62,7 +62,6 @@ void JS_FASTCALL Interrupt(VMFrame &f, jsbytecode *pc);
void JS_FASTCALL RecompileForInline(VMFrame &f); void JS_FASTCALL RecompileForInline(VMFrame &f);
void JS_FASTCALL InitElem(VMFrame &f, uint32_t last); void JS_FASTCALL InitElem(VMFrame &f, uint32_t last);
void JS_FASTCALL InitProp(VMFrame &f, PropertyName *name); void JS_FASTCALL InitProp(VMFrame &f, PropertyName *name);
void JS_FASTCALL InitMethod(VMFrame &f, PropertyName *name);
void JS_FASTCALL HitStackQuota(VMFrame &f); void JS_FASTCALL HitStackQuota(VMFrame &f);
void * JS_FASTCALL FixupArity(VMFrame &f, uint32_t argc); void * JS_FASTCALL FixupArity(VMFrame &f, uint32_t argc);
@ -137,10 +136,6 @@ void JS_FASTCALL SetConst(VMFrame &f, PropertyName *name);
template<JSBool strict> void JS_FASTCALL DefFun(VMFrame &f, JSFunction *fun); template<JSBool strict> void JS_FASTCALL DefFun(VMFrame &f, JSFunction *fun);
void JS_FASTCALL RegExp(VMFrame &f, JSObject *regex); void JS_FASTCALL RegExp(VMFrame &f, JSObject *regex);
JSObject * JS_FASTCALL Lambda(VMFrame &f, JSFunction *fun); JSObject * JS_FASTCALL Lambda(VMFrame &f, JSFunction *fun);
JSObject * JS_FASTCALL LambdaJoinableForInit(VMFrame &f, JSFunction *fun);
JSObject * JS_FASTCALL LambdaJoinableForSet(VMFrame &f, JSFunction *fun);
JSObject * JS_FASTCALL LambdaJoinableForCall(VMFrame &f, JSFunction *fun);
JSObject * JS_FASTCALL LambdaJoinableForNull(VMFrame &f, JSFunction *fun);
JSObject * JS_FASTCALL FlatLambda(VMFrame &f, JSFunction *fun); JSObject * JS_FASTCALL FlatLambda(VMFrame &f, JSFunction *fun);
void JS_FASTCALL Arguments(VMFrame &f); void JS_FASTCALL Arguments(VMFrame &f);
void JS_FASTCALL EnterBlock(VMFrame &f, JSObject *obj); void JS_FASTCALL EnterBlock(VMFrame &f, JSObject *obj);

Просмотреть файл

@ -2170,8 +2170,7 @@ DumpStack(JSContext *cx, unsigned argc, Value *vp)
Value v; Value v;
if (iter.isScript()) { if (iter.isScript()) {
if (iter.fp()->isNonEvalFunctionFrame()) { if (iter.fp()->isNonEvalFunctionFrame()) {
if (!iter.fp()->getValidCalleeObject(cx, &v)) v = ObjectValue(iter.fp()->callee());
return false;
} else if (iter.fp()->isEvalFrame()) { } else if (iter.fp()->isEvalFrame()) {
v = StringValue(evalStr); v = StringValue(evalStr);
} else { } else {
@ -2782,11 +2781,7 @@ CopyProperty(JSContext *cx, JSObject *obj, JSObject *referent, jsid id,
return true; return true;
const Shape *shape = (Shape *) prop; const Shape *shape = (Shape *) prop;
if (shape->isMethod()) { if (shape->hasSlot()) {
shape = referent->methodReadBarrier(cx, *shape, &desc.value);
if (!shape)
return false;
} else if (shape->hasSlot()) {
desc.value = referent->nativeGetSlot(shape->slot()); desc.value = referent->nativeGetSlot(shape->slot());
} else { } else {
desc.value.setUndefined(); desc.value.setUndefined();

Просмотреть файл

@ -925,7 +925,7 @@ CallMethodIfPresent(JSContext *cx, JSObject *obj, const char *name, int argc, Va
JSAtom *atom = js_Atomize(cx, name, strlen(name)); JSAtom *atom = js_Atomize(cx, name, strlen(name));
Value fval; Value fval;
return atom && return atom &&
js_GetMethod(cx, obj, ATOM_TO_JSID(atom), JSGET_NO_METHOD_BARRIER, &fval) && js_GetMethod(cx, obj, ATOM_TO_JSID(atom), 0, &fval) &&
(!js_IsCallable(fval) || (!js_IsCallable(fval) ||
Invoke(cx, ObjectValue(*obj), fval, argc, argv, rval)); Invoke(cx, ObjectValue(*obj), fval, argc, argv, rval));
} }

Просмотреть файл

@ -189,13 +189,6 @@ StackFrame::initFixupFrame(StackFrame *prev, StackFrame::Flags flags, void *ncod
u.nactual = nactual; u.nactual = nactual;
} }
inline void
StackFrame::overwriteCallee(JSObject &newCallee)
{
JS_ASSERT(callee().toFunction()->script() == newCallee.toFunction()->script());
mutableCalleev().setObject(newCallee);
}
inline Value & inline Value &
StackFrame::canonicalActualArg(unsigned i) const StackFrame::canonicalActualArg(unsigned i) const
{ {

Просмотреть файл

@ -818,13 +818,6 @@ class StackFrame
return calleev; return calleev;
} }
/*
* Beware! Ad hoc changes can corrupt the stack layout; the callee should
* only be changed to something that is equivalent to the current callee in
* terms of numFormalArgs etc. Prefer overwriteCallee since it checks.
*/
inline void overwriteCallee(JSObject &newCallee);
Value &mutableCalleev() const { Value &mutableCalleev() const {
JS_ASSERT(isFunctionFrame()); JS_ASSERT(isFunctionFrame());
if (isEvalFrame()) if (isEvalFrame())
@ -832,13 +825,6 @@ class StackFrame
return formalArgs()[-2]; return formalArgs()[-2];
} }
/*
* Compute the callee function for this stack frame, cloning if needed to
* implement the method read barrier. If this is not a function frame,
* set *vp to null.
*/
bool getValidCalleeObject(JSContext *cx, Value *vp);
CallReceiver callReceiver() const { CallReceiver callReceiver() const {
return CallReceiverFromArgv(formalArgs()); return CallReceiverFromArgv(formalArgs());
} }