mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 739808: Remove method cloning optimization and method barrier, r=luke
--HG-- extra : rebase_source : d383c3704c3efd08f9fbf1324433a94fc4a8dbb8
This commit is contained in:
parent
15a66966a1
commit
5287c89131
@ -4565,43 +4565,6 @@ EmitWith(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
|
||||
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
|
||||
EmitForIn(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn, ptrdiff_t top)
|
||||
{
|
||||
@ -5371,23 +5334,6 @@ EmitStatement(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
|
||||
}
|
||||
#endif
|
||||
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))
|
||||
return false;
|
||||
if (Emit1(cx, bce, op) < 0)
|
||||
@ -5894,28 +5840,13 @@ EmitObject(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
|
||||
if (!bce->makeAtomIndex(pn3->pn_atom, &index))
|
||||
return false;
|
||||
|
||||
/* Check whether we can optimize to JSOP_INITMETHOD. */
|
||||
ParseNode *init = pn2->pn_right;
|
||||
bool lambda = init->isOp(JSOP_LAMBDA);
|
||||
if (lambda)
|
||||
++methodInits;
|
||||
if (op == JSOP_INITPROP && lambda && init->pn_funbox->joinable()) {
|
||||
/*
|
||||
* 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_INITMETHOD;
|
||||
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;
|
||||
}
|
||||
op = JSOP_INITPROP;
|
||||
|
||||
if (obj) {
|
||||
JS_ASSERT(!obj->inDictionaryMode());
|
||||
|
@ -108,15 +108,6 @@ ParseNode::clear()
|
||||
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
|
||||
FunctionBox::inAnyDynamicScope() const
|
||||
{
|
||||
|
@ -1554,8 +1554,6 @@ struct FunctionBox : public ObjectBox
|
||||
|
||||
JSFunction *function() const { return (JSFunction *) object; }
|
||||
|
||||
bool joinable() const;
|
||||
|
||||
/*
|
||||
* True if this function is inside the scope of a with-statement, an E4X
|
||||
* 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->pn_cookie.set(funtc->staticLevel, UpvarCookie::CALLEE_SLOT);
|
||||
dn->pn_dflags |= PND_BOUND;
|
||||
|
||||
funbox->tcflags |= TCF_FUN_USES_OWN_NAME;
|
||||
foundCallee = 1;
|
||||
continue;
|
||||
}
|
||||
@ -2049,7 +2047,7 @@ DefineGlobal(ParseNode *pn, BytecodeEmitter *bce, PropertyName *name)
|
||||
globalObj != holder ||
|
||||
shape->configurable() ||
|
||||
!shape->hasSlot() ||
|
||||
!shape->hasDefaultGetterOrIsMethod() ||
|
||||
!shape->hasDefaultGetter() ||
|
||||
!shape->hasDefaultSetter()) {
|
||||
return true;
|
||||
}
|
||||
|
@ -217,9 +217,6 @@ SetFunctionKinds(FunctionBox *funbox, uint32_t *tcflags, bool isDirectEval)
|
||||
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_NEWOBJECT:
|
||||
case JSOP_ENDINIT:
|
||||
case JSOP_INITMETHOD:
|
||||
case JSOP_INITPROP:
|
||||
case JSOP_INITELEM:
|
||||
case JSOP_SETPROP:
|
||||
case JSOP_SETMETHOD:
|
||||
case JSOP_IN:
|
||||
case JSOP_INSTANCEOF:
|
||||
case JSOP_LINENO:
|
||||
@ -1522,7 +1520,6 @@ ScriptAnalysis::analyzeSSA(JSContext *cx)
|
||||
break;
|
||||
|
||||
case JSOP_INITPROP:
|
||||
case JSOP_INITMETHOD:
|
||||
stack[stackDepth - 1].v = code->poppedValues[1];
|
||||
break;
|
||||
|
||||
|
@ -28,7 +28,6 @@ BEGIN_TEST(testLookup_bug522590)
|
||||
JSObject *funobj = JSVAL_TO_OBJECT(r);
|
||||
CHECK(funobj->isFunction());
|
||||
CHECK(!js::IsInternalFunctionObject(funobj));
|
||||
CHECK(funobj->toFunction()->isClonedMethod());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -3455,11 +3455,6 @@ LookupResult(JSContext *cx, JSObject *obj, JSObject *obj2, jsid id,
|
||||
if (obj2->isNative()) {
|
||||
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. */
|
||||
if (shape->hasSlot()) {
|
||||
*vp = obj2->nativeGetSlot(shape->slot());
|
||||
@ -3855,19 +3850,12 @@ GetPropertyDescriptorById(JSContext *cx, JSObject *obj, jsid id, unsigned flags,
|
||||
if (obj2->isNative()) {
|
||||
Shape *shape = (Shape *) prop;
|
||||
desc->attrs = shape->attributes();
|
||||
|
||||
if (shape->isMethod()) {
|
||||
desc->getter = JS_PropertyStub;
|
||||
desc->setter = JS_StrictPropertyStub;
|
||||
desc->value.setObject(*obj2->nativeGetMethod(shape));
|
||||
} else {
|
||||
desc->getter = shape->getter();
|
||||
desc->setter = shape->setter();
|
||||
if (shape->hasSlot())
|
||||
desc->value = obj2->nativeGetSlot(shape->slot());
|
||||
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 {
|
||||
if (obj2->isProxy()) {
|
||||
JSAutoResolveFlags rf(cx, flags);
|
||||
@ -3968,8 +3956,9 @@ SetPropertyAttributesById(JSContext *cx, JSObject *obj, jsid id, unsigned attrs,
|
||||
*foundp = false;
|
||||
return true;
|
||||
}
|
||||
Shape *shape = (Shape *) prop;
|
||||
JSBool ok = obj->isNative()
|
||||
? js_SetNativeAttributes(cx, obj, (Shape *) prop, attrs)
|
||||
? obj->changePropertyAttributes(cx, shape, attrs)
|
||||
: obj->setGenericAttributes(cx, id, &attrs);
|
||||
if (ok)
|
||||
*foundp = true;
|
||||
@ -4072,7 +4061,7 @@ JS_GetMethodById(JSContext *cx, JSObject *obj, jsid id, JSObject **objp, jsval *
|
||||
AssertNoGC(cx);
|
||||
CHECK_REQUEST(cx);
|
||||
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;
|
||||
if (objp)
|
||||
*objp = obj;
|
||||
@ -5366,7 +5355,7 @@ JS_CallFunctionName(JSContext *cx, JSObject *obj, const char *name, unsigned arg
|
||||
Value v;
|
||||
JSAtom *atom = js_Atomize(cx, name, strlen(name));
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -644,17 +644,6 @@ JS_GetFrameCalleeObject(JSContext *cx, JSStackFrame *fp)
|
||||
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_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
|
||||
* this API cannot fail. A null return means "no callee": fp is a global or
|
||||
* 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 *)
|
||||
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 *)
|
||||
|
114
js/src/jsfun.cpp
114
js/src/jsfun.cpp
@ -97,107 +97,6 @@ using namespace js;
|
||||
using namespace js::gc;
|
||||
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
|
||||
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()) {
|
||||
if (!fp->isFunctionFrame() || fp->isEvalFrame())
|
||||
continue;
|
||||
Value callee;
|
||||
if (!fp->getValidCalleeObject(cx, &callee))
|
||||
return false;
|
||||
if (&callee.toObject() == fun)
|
||||
if (fp->callee().toFunction() == fun)
|
||||
break;
|
||||
}
|
||||
if (!fp)
|
||||
@ -277,14 +173,13 @@ fun_getProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp)
|
||||
while (frame && frame->isDummyFrame())
|
||||
frame = frame->prev();
|
||||
|
||||
if (frame && !frame->getValidCalleeObject(cx, vp))
|
||||
return false;
|
||||
|
||||
if (!vp->isObject()) {
|
||||
if (!frame || !frame->isFunctionFrame()) {
|
||||
JS_ASSERT(vp->isNull());
|
||||
return true;
|
||||
}
|
||||
|
||||
vp->setObject(frame->callee());
|
||||
|
||||
/* Censor the caller if it is from another compartment. */
|
||||
JSObject &caller = vp->toObject();
|
||||
if (caller.compartment() != cx->compartment) {
|
||||
@ -1263,7 +1158,6 @@ LookupInterpretedFunctionPrototype(JSContext *cx, JSObject *funobj)
|
||||
JS_ASSERT(!shape->configurable());
|
||||
JS_ASSERT(shape->isDataDescriptor());
|
||||
JS_ASSERT(shape->hasSlot());
|
||||
JS_ASSERT(!shape->isMethod());
|
||||
return shape;
|
||||
}
|
||||
|
||||
|
@ -67,10 +67,6 @@
|
||||
* move to u.i.script->flags. For now we use function flag bits to minimize
|
||||
* 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
|
||||
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_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
|
||||
* 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_); }
|
||||
|
||||
inline void setJoinable();
|
||||
|
||||
js::HeapPtrScript &script() const {
|
||||
JS_ASSERT(isInterpreted());
|
||||
return *(js::HeapPtrScript *)&u.i.script_;
|
||||
@ -218,33 +204,10 @@ struct JSFunction : public JSObject
|
||||
|
||||
public:
|
||||
/* Accessors for data stored in extended functions. */
|
||||
|
||||
inline void initializeExtended();
|
||||
|
||||
inline void setExtendedSlot(size_t which, const js::Value &val);
|
||||
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:
|
||||
/*
|
||||
* 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());
|
||||
}
|
||||
|
||||
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
|
||||
JSFunction::setExtendedSlot(size_t which, const js::Value &val)
|
||||
{
|
||||
@ -288,10 +246,10 @@ inline JSFunction *
|
||||
CloneFunctionObjectIfNotSingleton(JSContext *cx, JSFunction *fun, JSObject *parent)
|
||||
{
|
||||
/*
|
||||
* For attempts to clone functions at a function definition opcode or from
|
||||
* a method barrier, don't perform the clone if the function has singleton
|
||||
* type. This was called pessimistically, and we need to preserve the
|
||||
* type's property that if it is singleton there is only a single object
|
||||
* For attempts to clone functions at a function definition opcode,
|
||||
* don't perform the clone if the function has singleton type. This
|
||||
* was called pessimistically, and we need to preserve the type's
|
||||
* property that if it is singleton there is only a single object
|
||||
* with its type in existence.
|
||||
*/
|
||||
if (fun->hasSingletonType()) {
|
||||
|
@ -800,7 +800,7 @@ static inline const Shape *
|
||||
GetSingletonShape(JSContext *cx, JSObject *obj, jsid id)
|
||||
{
|
||||
const Shape *shape = obj->nativeLookup(cx, id);
|
||||
if (shape && shape->hasDefaultGetterOrIsMethod() && shape->hasSlot())
|
||||
if (shape && shape->hasDefaultGetter() && shape->hasSlot())
|
||||
return shape;
|
||||
return NULL;
|
||||
}
|
||||
@ -2739,7 +2739,7 @@ UpdatePropertyType(JSContext *cx, TypeSet *types, JSObject *obj, const Shape *sh
|
||||
if (shape->hasGetterValue() || shape->hasSetterValue()) {
|
||||
types->setOwnProperty(cx, true);
|
||||
types->addType(cx, Type::UnknownType());
|
||||
} else if (shape->hasDefaultGetterOrIsMethod() && shape->hasSlot()) {
|
||||
} else if (shape->hasDefaultGetter() && shape->hasSlot()) {
|
||||
const Value &value = obj->nativeGetSlot(shape->slot());
|
||||
|
||||
/*
|
||||
@ -3667,8 +3667,7 @@ ScriptAnalysis::analyzeTypesBytecode(JSContext *cx, unsigned offset,
|
||||
pushed[0].addType(cx, Type::LazyArgsType());
|
||||
break;
|
||||
|
||||
case JSOP_SETPROP:
|
||||
case JSOP_SETMETHOD: {
|
||||
case JSOP_SETPROP: {
|
||||
jsid id = GetAtomId(cx, script, pc, 0);
|
||||
poppedTypes(pc, 1)->addSetProperty(cx, script, pc, poppedTypes(pc, 0), id);
|
||||
poppedTypes(pc, 0)->addSubset(cx, &pushed[0]);
|
||||
@ -3875,8 +3874,7 @@ ScriptAnalysis::analyzeTypesBytecode(JSContext *cx, unsigned offset,
|
||||
state.hasHole = true;
|
||||
break;
|
||||
|
||||
case JSOP_INITPROP:
|
||||
case JSOP_INITMETHOD: {
|
||||
case JSOP_INITPROP: {
|
||||
const SSAValue &objv = poppedValue(pc, 1);
|
||||
jsbytecode *initpc = script->code + objv.pushedOffset();
|
||||
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);
|
||||
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;
|
||||
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
|
||||
* 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_SETMETHOD_LENGTH);
|
||||
JS_STATIC_ASSERT(JSOP_INITPROP_LENGTH == JSOP_INITMETHOD_LENGTH);
|
||||
|
||||
/* See TRY_BRANCH_AFTER_COND. */
|
||||
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_UNUSED27)
|
||||
ADD_EMPTY_CASE(JSOP_UNUSED28)
|
||||
ADD_EMPTY_CASE(JSOP_UNUSED29)
|
||||
ADD_EMPTY_CASE(JSOP_UNUSED30)
|
||||
ADD_EMPTY_CASE(JSOP_CONDSWITCH)
|
||||
ADD_EMPTY_CASE(JSOP_TRY)
|
||||
#if JS_HAS_XML_SUPPORT
|
||||
@ -2585,7 +2585,6 @@ END_CASE(JSOP_GETPROP)
|
||||
BEGIN_CASE(JSOP_SETGNAME)
|
||||
BEGIN_CASE(JSOP_SETNAME)
|
||||
BEGIN_CASE(JSOP_SETPROP)
|
||||
BEGIN_CASE(JSOP_SETMETHOD)
|
||||
{
|
||||
const Value &rval = regs.sp[-1];
|
||||
const Value &lval = regs.sp[-2];
|
||||
@ -3159,73 +3158,6 @@ BEGIN_CASE(JSOP_LAMBDA)
|
||||
JSObject *parent;
|
||||
if (fun->isNullClosure()) {
|
||||
parent = ®s.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 {
|
||||
parent = GetScopeChain(cx, regs.fp());
|
||||
if (!parent)
|
||||
@ -3405,7 +3337,6 @@ BEGIN_CASE(JSOP_ENDINIT)
|
||||
END_CASE(JSOP_ENDINIT)
|
||||
|
||||
BEGIN_CASE(JSOP_INITPROP)
|
||||
BEGIN_CASE(JSOP_INITMETHOD)
|
||||
{
|
||||
/* Load the property's initial value into rval. */
|
||||
JS_ASSERT(regs.sp - regs.fp()->base() >= 2);
|
||||
@ -3419,11 +3350,10 @@ BEGIN_CASE(JSOP_INITMETHOD)
|
||||
LOAD_ATOM(0, atom);
|
||||
jsid id = ATOM_TO_JSID(atom);
|
||||
|
||||
unsigned defineHow = (op == JSOP_INITMETHOD) ? DNP_SET_METHOD : 0;
|
||||
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,
|
||||
JSPROP_ENUMERATE, 0, 0, defineHow)) {
|
||||
JSPROP_ENUMERATE, 0, 0, 0)) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
|
@ -244,17 +244,13 @@ GetPropertyOperation(JSContext *cx, jsbytecode *pc, const Value &lval, Value *vp
|
||||
if (!obj)
|
||||
return false;
|
||||
|
||||
unsigned flags = (op == JSOP_CALLPROP)
|
||||
? JSGET_CACHE_RESULT | JSGET_NO_METHOD_BARRIER
|
||||
: JSGET_CACHE_RESULT | JSGET_METHOD_BARRIER;
|
||||
|
||||
PropertyCacheEntry *entry;
|
||||
JSObject *obj2;
|
||||
PropertyName *name;
|
||||
JS_PROPERTY_CACHE(cx).test(cx, pc, obj, obj2, entry, name);
|
||||
if (!name) {
|
||||
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 true;
|
||||
}
|
||||
@ -265,7 +261,7 @@ GetPropertyOperation(JSContext *cx, jsbytecode *pc, const Value &lval, Value *vp
|
||||
if (!GetPropertyGenericMaybeCallXML(cx, op, obj, id, vp))
|
||||
return false;
|
||||
} else {
|
||||
if (!GetPropertyHelper(cx, obj, id, flags, vp))
|
||||
if (!GetPropertyHelper(cx, obj, id, JSGET_CACHE_RESULT, vp))
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -289,7 +285,6 @@ SetPropertyOperation(JSContext *cx, jsbytecode *pc, const Value &lval, const Val
|
||||
if (!obj)
|
||||
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_SETGNAME, obj == &cx->fp()->scopeChain().global());
|
||||
|
||||
@ -322,7 +317,7 @@ SetPropertyOperation(JSContext *cx, jsbytecode *pc, const Value &lval, const Val
|
||||
}
|
||||
#endif
|
||||
|
||||
if (shape->hasDefaultSetter() && shape->hasSlot() && !shape->isMethod()) {
|
||||
if (shape->hasDefaultSetter() && shape->hasSlot()) {
|
||||
/* Fast path for, e.g., plain Object instance properties. */
|
||||
obj->nativeSetSlotWithType(cx, shape, rval);
|
||||
} else {
|
||||
@ -344,13 +339,9 @@ SetPropertyOperation(JSContext *cx, jsbytecode *pc, const Value &lval, const Val
|
||||
|
||||
jsid id = ATOM_TO_JSID(name);
|
||||
if (JS_LIKELY(!obj->getOps()->setProperty)) {
|
||||
unsigned defineHow;
|
||||
if (op == JSOP_SETMETHOD)
|
||||
defineHow = DNP_CACHE_RESULT | DNP_SET_METHOD;
|
||||
else if (op == JSOP_SETNAME)
|
||||
defineHow = DNP_CACHE_RESULT | DNP_UNQUALIFIED;
|
||||
else
|
||||
defineHow = DNP_CACHE_RESULT;
|
||||
unsigned defineHow = (op == JSOP_SETNAME)
|
||||
? DNP_CACHE_RESULT | DNP_UNQUALIFIED
|
||||
: DNP_CACHE_RESULT;
|
||||
if (!js_SetPropertyHelper(cx, obj, id, defineHow, &rref, strict))
|
||||
return false;
|
||||
} else {
|
||||
@ -384,7 +375,7 @@ NameOperation(JSContext *cx, jsbytecode *pc, Value *vp)
|
||||
JS_PROPERTY_CACHE(cx).test(cx, pc, obj, obj2, entry, name);
|
||||
if (!name) {
|
||||
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 true;
|
||||
}
|
||||
@ -416,7 +407,7 @@ NameOperation(JSContext *cx, jsbytecode *pc, Value *vp)
|
||||
JSObject *normalized = obj;
|
||||
if (normalized->getClass() == &WithClass && !shape->hasDefaultGetter())
|
||||
normalized = &normalized->asWith().object();
|
||||
if (!NativeGet(cx, normalized, obj2, shape, JSGET_METHOD_BARRIER, vp))
|
||||
if (!NativeGet(cx, normalized, obj2, shape, 0, vp))
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -459,7 +459,7 @@ GetCustomIterator(JSContext *cx, JSObject *obj, unsigned flags, Value *vp)
|
||||
|
||||
/* Check whether we have a valid __iterator__ method. */
|
||||
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;
|
||||
|
||||
/* If there is no custom __iterator__ method, we are done here. */
|
||||
@ -1242,7 +1242,7 @@ js_IteratorMore(JSContext *cx, JSObject *iterobj, Value *rval)
|
||||
} else {
|
||||
/* Call the iterator object's .next method. */
|
||||
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;
|
||||
if (!Invoke(cx, ObjectValue(*iterobj), *rval, 0, NULL, rval)) {
|
||||
/* Check for StopIteration. */
|
||||
|
210
js/src/jsobj.cpp
210
js/src/jsobj.cpp
@ -1963,7 +1963,7 @@ DefinePropertyOnObject(JSContext *cx, JSObject *obj, const jsid &id, const PropD
|
||||
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;
|
||||
}
|
||||
|
||||
@ -2092,14 +2092,8 @@ DefinePropertyOnObject(JSContext *cx, JSObject *obj, const jsid &id, const PropD
|
||||
changed |= JSPROP_ENUMERATE;
|
||||
|
||||
attrs = (shape->attributes() & ~changed) | (desc.attrs & changed);
|
||||
if (shape->isMethod()) {
|
||||
JS_ASSERT(!(attrs & (JSPROP_GETTER | JSPROP_SETTER)));
|
||||
getter = JS_PropertyStub;
|
||||
setter = JS_StrictPropertyStub;
|
||||
} else {
|
||||
getter = shape->getter();
|
||||
setter = shape->setter();
|
||||
}
|
||||
getter = shape->getter();
|
||||
setter = shape->setter();
|
||||
} else if (desc.isDataDescriptor()) {
|
||||
unsigned unchanged = 0;
|
||||
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))
|
||||
return JS_FALSE;
|
||||
|
||||
JS_ASSERT_IF(shape->isMethod(), !(attrs & (JSPROP_GETTER | JSPROP_SETTER)));
|
||||
|
||||
/* 8.12.9 step 12. */
|
||||
unsigned changed = 0;
|
||||
if (desc.hasConfigurable)
|
||||
@ -2143,7 +2135,7 @@ DefinePropertyOnObject(JSContext *cx, JSObject *obj, const jsid &id, const PropD
|
||||
if (desc.hasGet) {
|
||||
getter = desc.getter();
|
||||
} else {
|
||||
getter = (shape->isMethod() || (shape->hasDefaultGetter() && !shape->hasGetterValue()))
|
||||
getter = (shape->hasDefaultGetter() && !shape->hasGetterValue())
|
||||
? JS_PropertyStub
|
||||
: shape->getter();
|
||||
}
|
||||
@ -4399,8 +4391,6 @@ js_AddNativeProperty(JSContext *cx, JSObject *obj, jsid id,
|
||||
PropertyOp getter, StrictPropertyOp setter, uint32_t slot,
|
||||
unsigned attrs, unsigned flags, int shortid)
|
||||
{
|
||||
JS_ASSERT(!(flags & Shape::METHOD));
|
||||
|
||||
/* Convert string indices to integers if appropriate. */
|
||||
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);
|
||||
}
|
||||
|
||||
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
|
||||
js_DefineProperty(JSContext *cx, JSObject *obj, jsid id, const Value *value,
|
||||
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 */)
|
||||
{
|
||||
JS_ASSERT((defineHow & ~(DNP_CACHE_RESULT | DNP_DONT_PURGE |
|
||||
DNP_SET_METHOD | DNP_SKIP_TYPE)) == 0);
|
||||
DNP_SKIP_TYPE)) == 0);
|
||||
|
||||
RootObject objRoot(cx, &obj);
|
||||
RootId idRoot(cx, &id);
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
/* Make a local copy of value so addProperty can mutate its inout parameter. */
|
||||
RootedVarValue value(cx);
|
||||
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. */
|
||||
Class *clasp = obj->getClass();
|
||||
if (!(defineHow & DNP_SET_METHOD)) {
|
||||
if (!getter && !(attrs & JSPROP_GETTER))
|
||||
getter = clasp->getProperty;
|
||||
if (!setter && !(attrs & JSPROP_SETTER))
|
||||
setter = clasp->setProperty;
|
||||
}
|
||||
if (!getter && !(attrs & JSPROP_GETTER))
|
||||
getter = clasp->getProperty;
|
||||
if (!setter && !(attrs & JSPROP_SETTER))
|
||||
setter = clasp->setProperty;
|
||||
|
||||
if (((defineHow & DNP_SET_METHOD) || getter == JS_PropertyStub) &&
|
||||
!(defineHow & DNP_SKIP_TYPE)) {
|
||||
if ((getter == JS_PropertyStub) && !(defineHow & DNP_SKIP_TYPE)) {
|
||||
/*
|
||||
* Type information for normal native properties should reflect the
|
||||
* initial value of the property.
|
||||
@ -4568,32 +4532,6 @@ DefineNativeProperty(JSContext *cx, JSObject *obj, jsid id, const Value &value_,
|
||||
}
|
||||
|
||||
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,
|
||||
attrs, flags, shortid);
|
||||
if (!shape)
|
||||
@ -4970,7 +4908,7 @@ js_NativeGetInline(JSContext *cx, JSObject *receiver, JSObject *obj, JSObject *p
|
||||
if (shape->hasSlot()) {
|
||||
*vp = pobj->nativeGetSlot(shape->slot());
|
||||
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));
|
||||
} else {
|
||||
vp->setUndefined();
|
||||
@ -4978,9 +4916,6 @@ js_NativeGetInline(JSContext *cx, JSObject *receiver, JSObject *obj, JSObject *p
|
||||
if (shape->hasDefaultGetter())
|
||||
return true;
|
||||
|
||||
if (JS_UNLIKELY(shape->isMethod()) && (getHow & JSGET_NO_METHOD_BARRIER))
|
||||
return true;
|
||||
|
||||
jsbytecode *pc;
|
||||
JSScript *script = cx->stack.currentScript(&pc);
|
||||
if (script && script->hasAnalysis()) {
|
||||
@ -4993,11 +4928,8 @@ js_NativeGetInline(JSContext *cx, JSObject *receiver, JSObject *obj, JSObject *p
|
||||
return false;
|
||||
|
||||
/* Update slotful shapes according to the value produced by the getter. */
|
||||
if (shape->hasSlot() && pobj->nativeContains(cx, *shape)) {
|
||||
/* Method shapes were removed by methodReadBarrier under shape->get(). */
|
||||
JS_ASSERT(!shape->isMethod());
|
||||
if (shape->hasSlot() && pobj->nativeContains(cx, *shape))
|
||||
pobj->nativeSetSlot(shape->slot(), *vp);
|
||||
}
|
||||
|
||||
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->hasDefaultSetter()) {
|
||||
if (!added) {
|
||||
if (shape->isMethod() && !obj->methodShapeChange(cx, *shape))
|
||||
return false;
|
||||
}
|
||||
obj->nativeSetSlot(slot, *vp);
|
||||
return true;
|
||||
}
|
||||
@ -5162,7 +5090,7 @@ JSBool
|
||||
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(). */
|
||||
return js_GetPropertyHelperInline(cx, obj, receiver, id, JSGET_METHOD_BARRIER, vp);
|
||||
return js_GetPropertyHelperInline(cx, obj, receiver, id, 0, vp);
|
||||
}
|
||||
|
||||
JSBool
|
||||
@ -5173,7 +5101,7 @@ js_GetElement(JSContext *cx, JSObject *obj, JSObject *receiver, uint32_t index,
|
||||
return false;
|
||||
|
||||
/* 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
|
||||
@ -5261,25 +5189,10 @@ bool
|
||||
JSObject::callMethod(JSContext *cx, jsid id, unsigned argc, Value *argv, Value *vp)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
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
|
||||
js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, unsigned defineHow,
|
||||
Value *vp, JSBool strict)
|
||||
@ -5294,7 +5207,7 @@ js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, unsigned defineHow,
|
||||
StrictPropertyOp setter;
|
||||
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. */
|
||||
id = js_CheckForStringIndex(id);
|
||||
@ -5304,9 +5217,6 @@ js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, unsigned defineHow,
|
||||
WatchpointMap *wpmap = cx->compartment->watchpointMap;
|
||||
if (wpmap && !wpmap->triggerWatchpoint(cx, obj, id, vp))
|
||||
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))
|
||||
@ -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.
|
||||
*/
|
||||
if (!shape->shadowable()) {
|
||||
if (defineHow & DNP_SET_METHOD) {
|
||||
JS_ASSERT(!shape->isMethod());
|
||||
if (!CloneFunctionForSetMethod(cx, vp))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (defineHow & DNP_CACHE_RESULT)
|
||||
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.
|
||||
*/
|
||||
if (!shape->hasSlot()) {
|
||||
defineHow &= ~DNP_SET_METHOD;
|
||||
if (shape->hasShortID()) {
|
||||
flags = Shape::HAS_SHORTID;
|
||||
shortid = shape->shortid();
|
||||
@ -5431,26 +5334,6 @@ js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, unsigned defineHow,
|
||||
*/
|
||||
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;
|
||||
@ -5471,19 +5354,6 @@ js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, unsigned defineHow,
|
||||
if (!js_PurgeScopeChain(cx, obj, id))
|
||||
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,
|
||||
attrs, flags, shortid);
|
||||
if (!shape)
|
||||
@ -5557,14 +5427,6 @@ js_GetElementAttributes(JSContext *cx, JSObject *obj, uint32_t index, unsigned *
|
||||
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
|
||||
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)
|
||||
return true;
|
||||
return obj->isNative()
|
||||
? js_SetNativeAttributes(cx, obj, (Shape *) prop, *attrsp)
|
||||
? obj->changePropertyAttributes(cx, (Shape *) prop, *attrsp)
|
||||
: obj->setGenericAttributes(cx, id, attrsp);
|
||||
}
|
||||
|
||||
@ -5587,7 +5449,7 @@ js_SetElementAttributes(JSContext *cx, JSObject *obj, uint32_t index, unsigned *
|
||||
if (!prop)
|
||||
return true;
|
||||
return obj->isNative()
|
||||
? js_SetNativeAttributes(cx, obj, (Shape *) prop, *attrsp)
|
||||
? obj->changePropertyAttributes(cx, (Shape *) prop, *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()) {
|
||||
const Value &v = obj->nativeGetSlot(shape->slot());
|
||||
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))
|
||||
@ -5691,7 +5524,7 @@ HasDataProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp)
|
||||
{
|
||||
JS_ASSERT(id == js_CheckForStringIndex(id));
|
||||
if (const Shape *shape = obj->nativeLookup(cx, id)) {
|
||||
if (shape->hasDefaultGetterOrIsMethod() && shape->hasSlot()) {
|
||||
if (shape->hasDefaultGetter() && shape->hasSlot()) {
|
||||
*vp = obj->nativeGetSlot(shape->slot());
|
||||
return true;
|
||||
}
|
||||
@ -5711,7 +5544,7 @@ HasDataProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp)
|
||||
static bool
|
||||
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;
|
||||
if (!js_IsCallable(*vp)) {
|
||||
*vp = ObjectValue(*obj);
|
||||
@ -6221,7 +6054,6 @@ DumpProperty(JSObject *obj, const Shape &shape)
|
||||
if (attrs & JSPROP_READONLY) fprintf(stderr, "readonly ");
|
||||
if (attrs & JSPROP_PERMANENT) fprintf(stderr, "permanent ");
|
||||
if (attrs & JSPROP_SHARED) fprintf(stderr, "shared ");
|
||||
if (shape.isMethod()) fprintf(stderr, "method ");
|
||||
|
||||
if (shape.hasGetterValue())
|
||||
fprintf(stderr, "getterValue=%p ", (void *) shape.getterObject());
|
||||
|
@ -509,19 +509,8 @@ struct JSObject : public js::ObjectImpl
|
||||
public:
|
||||
inline bool nativeEmpty() const;
|
||||
|
||||
js::Shape *methodShapeChange(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. */
|
||||
inline bool isIndexed() const;
|
||||
|
||||
@ -573,8 +562,6 @@ struct JSObject : public js::ObjectImpl
|
||||
|
||||
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 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,
|
||||
JSPropertyOp getter, JSStrictPropertyOp setter);
|
||||
|
||||
inline bool changePropertyAttributes(JSContext *cx, js::Shape *shape, unsigned attrs);
|
||||
|
||||
/* Remove the property named by id from this object. */
|
||||
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,
|
||||
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
|
||||
js_DefineOwnProperty(JSContext *cx, JSObject *obj, jsid id,
|
||||
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_DONT_PURGE = 2; /* suppress js_PurgeScopeChain */
|
||||
const unsigned DNP_SET_METHOD = 4; /* DefineNativeProperty,js_SetPropertyHelper
|
||||
must pass the js::Shape::METHOD
|
||||
flag on to JSObject::{add,put}Property */
|
||||
const unsigned DNP_UNQUALIFIED = 8; /* Unqualified property set. Only used in
|
||||
const unsigned DNP_UNQUALIFIED = 4; /* Unqualified property set. Only used in
|
||||
the defineHow argument of
|
||||
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.
|
||||
@ -1460,22 +1436,8 @@ FindIdentifierBase(JSContext *cx, JSObject *scopeChain, PropertyName *name);
|
||||
extern JSObject *
|
||||
js_FindVariableScope(JSContext *cx, JSFunction **funp);
|
||||
|
||||
/*
|
||||
* JSGET_CACHE_RESULT is the analogue of JSDNP_CACHE_RESULT for js_GetMethod.
|
||||
*
|
||||
* 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
|
||||
/* JSGET_CACHE_RESULT is the analogue of DNP_CACHE_RESULT for js_GetMethod. */
|
||||
const unsigned JSGET_CACHE_RESULT = 1; // from a caching interpreter opcode
|
||||
|
||||
/*
|
||||
* 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 */
|
||||
|
||||
/*
|
||||
* 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 {
|
||||
|
||||
/*
|
||||
|
@ -170,6 +170,12 @@ JSObject::setSpecialAttributes(JSContext *cx, js::SpecialId sid, unsigned *attrs
|
||||
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
|
||||
JSObject::getGeneric(JSContext *cx, JSObject *receiver, jsid id, js::Value *vp)
|
||||
{
|
||||
@ -265,50 +271,6 @@ JSObject::enclosingScope()
|
||||
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
|
||||
JSObject::isFixedSlot(size_t slot)
|
||||
{
|
||||
@ -964,22 +926,6 @@ JSObject::principals(JSContext *cx)
|
||||
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
|
||||
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()) {
|
||||
Value toJSON;
|
||||
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;
|
||||
|
||||
if (js_IsCallable(toJSON)) {
|
||||
|
@ -4515,7 +4515,6 @@ Decompile(SprintStack *ss, jsbytecode *pc, int nb)
|
||||
break;
|
||||
|
||||
case JSOP_SETPROP:
|
||||
case JSOP_SETMETHOD:
|
||||
{
|
||||
LOAD_ATOM(0);
|
||||
GET_QUOTE_AND_FMT("[%s] %s= ", ".%s %s= ", xval);
|
||||
@ -5120,7 +5119,6 @@ Decompile(SprintStack *ss, jsbytecode *pc, int nb)
|
||||
break;
|
||||
|
||||
case JSOP_INITPROP:
|
||||
case JSOP_INITMETHOD:
|
||||
LOAD_ATOM(0);
|
||||
xval = QuoteString(&ss->sprinter, atom, jschar(IsIdentifier(atom) ? 0 : '\''));
|
||||
if (!xval)
|
||||
|
@ -569,7 +569,7 @@ class OpcodeCounts
|
||||
* Access ops include all name, element and property reads, as well as
|
||||
* 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;
|
||||
int format = js_CodeSpec[op].format;
|
||||
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_UNUSED17, 219,"unused17", NULL, 1, 0, 0, 0, JOF_BYTE)
|
||||
OPDEF(JSOP_UNUSED24, 220,"unused18", NULL, 1, 0, 0, 0, JOF_BYTE)
|
||||
OPDEF(JSOP_UNUSED25, 221,"unused19", 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_UNUSED24, 220,"unused24", 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)
|
||||
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. */
|
||||
|
@ -297,7 +297,6 @@ Shape::dump(JSContext *cx, FILE *fp) const
|
||||
fputs("(", fp);
|
||||
#define DUMP_FLAG(name, display) if (flags & name) fputs(&(" " #display)[first], fp), first = 0
|
||||
DUMP_FLAG(HAS_SHORTID, has_shortid);
|
||||
DUMP_FLAG(METHOD, method);
|
||||
DUMP_FLAG(IN_DICTIONARY, in_dictionary);
|
||||
#undef DUMP_FLAG
|
||||
fputs(") ", fp);
|
||||
|
@ -498,16 +498,9 @@ NormalizeGetterAndSetter(JSContext *cx, JSObject *obj,
|
||||
JS_ASSERT(!(attrs & JSPROP_SETTER));
|
||||
setter = NULL;
|
||||
}
|
||||
if (flags & Shape::METHOD) {
|
||||
JS_ASSERT_IF(getter, getter == JS_PropertyStub);
|
||||
JS_ASSERT(!setter);
|
||||
JS_ASSERT(!(attrs & (JSPROP_GETTER | JSPROP_SETTER)));
|
||||
if (getter == JS_PropertyStub) {
|
||||
JS_ASSERT(!(attrs & JSPROP_GETTER));
|
||||
getter = NULL;
|
||||
} else {
|
||||
if (getter == JS_PropertyStub) {
|
||||
JS_ASSERT(!(attrs & JSPROP_GETTER));
|
||||
getter = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -808,9 +801,6 @@ JSObject::changeProperty(JSContext *cx, Shape *shape, unsigned attrs, unsigned m
|
||||
JS_ASSERT(!((attrs ^ shape->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());
|
||||
if (attrs & (JSPROP_GETTER | JSPROP_SETTER))
|
||||
types::AddTypePropertyId(cx, this, shape->propid(), types::Type::UnknownType());
|
||||
@ -1041,44 +1031,6 @@ JSObject::replaceWithNewEquivalentShape(JSContext *cx, Shape *oldShape, Shape *n
|
||||
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
|
||||
JSObject::shadowingShapeChange(JSContext *cx, const Shape &shape)
|
||||
{
|
||||
|
@ -649,43 +649,15 @@ struct Shape : public js::gc::Cell
|
||||
/* Public bits stored in shape->flags. */
|
||||
enum {
|
||||
HAS_SHORTID = 0x40,
|
||||
METHOD = 0x80,
|
||||
PUBLIC_FLAGS = HAS_SHORTID | METHOD
|
||||
PUBLIC_FLAGS = HAS_SHORTID
|
||||
};
|
||||
|
||||
bool inDictionary() const { return (flags & IN_DICTIONARY) != 0; }
|
||||
unsigned getFlags() const { return flags & PUBLIC_FLAGS; }
|
||||
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; }
|
||||
bool hasDefaultGetterOrIsMethod() const { return !base()->rawGetter; }
|
||||
bool hasDefaultGetter() const { return !base()->rawGetter && !isMethod(); }
|
||||
bool hasDefaultGetter() const { return !base()->rawGetter; }
|
||||
PropertyOp getterOp() const { JS_ASSERT(!hasGetterValue()); return base()->rawGetter; }
|
||||
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());
|
||||
|
||||
if (hasGetterValue()) {
|
||||
JS_ASSERT(!isMethod());
|
||||
js::Value fval = getterValue();
|
||||
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.
|
||||
* Avoid exposing the With object to native getters.
|
||||
|
@ -3312,7 +3312,7 @@ js_ValueToSource(JSContext *cx, const Value &v)
|
||||
Value rval = NullValue();
|
||||
Value fval;
|
||||
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;
|
||||
if (js_IsCallable(fval)) {
|
||||
if (!Invoke(cx, v, fval, 0, NULL, &rval))
|
||||
|
@ -149,26 +149,8 @@ WatchpointMap::triggerWatchpoint(JSContext *cx, JSObject *obj, jsid id, Value *v
|
||||
old.setUndefined();
|
||||
if (obj->isNative()) {
|
||||
if (const Shape *shape = obj->nativeLookup(cx, id)) {
|
||||
if (shape->hasSlot()) {
|
||||
if (shape->isMethod()) {
|
||||
/*
|
||||
* 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());
|
||||
}
|
||||
}
|
||||
if (shape->hasSlot())
|
||||
old = obj->nativeGetSlot(shape->slot());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1715,8 +1715,7 @@ mjit::Compiler::finishThisUp()
|
||||
jitPics[i].shapeRegHasBaseShape = true;
|
||||
jitPics[i].pc = pics[i].pc;
|
||||
|
||||
if (pics[i].kind == ic::PICInfo::SET ||
|
||||
pics[i].kind == ic::PICInfo::SETMETHOD) {
|
||||
if (pics[i].kind == ic::PICInfo::SET) {
|
||||
jitPics[i].u.vr = pics[i].vr;
|
||||
} else if (pics[i].kind != ic::PICInfo::NAME) {
|
||||
if (pics[i].hasTypeCheck) {
|
||||
@ -2900,11 +2899,6 @@ mjit::Compiler::generateMethod()
|
||||
BEGIN_CASE(JSOP_ENDINIT)
|
||||
END_CASE(JSOP_ENDINIT)
|
||||
|
||||
BEGIN_CASE(JSOP_INITMETHOD)
|
||||
jsop_initmethod();
|
||||
frame.pop();
|
||||
END_CASE(JSOP_INITMETHOD)
|
||||
|
||||
BEGIN_CASE(JSOP_INITPROP)
|
||||
jsop_initprop();
|
||||
frame.pop();
|
||||
@ -2971,7 +2965,6 @@ mjit::Compiler::generateMethod()
|
||||
END_CASE(JSOP_SETPROP)
|
||||
|
||||
BEGIN_CASE(JSOP_SETNAME)
|
||||
BEGIN_CASE(JSOP_SETMETHOD)
|
||||
{
|
||||
jsbytecode *next = &PC[JSOP_SETNAME_LENGTH];
|
||||
bool pop = JSOp(*next) == JSOP_POP && !analysis->jumpTarget(next);
|
||||
@ -3078,29 +3071,6 @@ mjit::Compiler::generateMethod()
|
||||
JSObjStubFun stub = stubs::Lambda;
|
||||
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));
|
||||
masm.move(ImmPtr(fun), Registers::ArgReg1);
|
||||
|
||||
@ -3249,7 +3219,7 @@ mjit::Compiler::generateMethod()
|
||||
|
||||
/* Update information about the result type of access operations. */
|
||||
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)
|
||||
? frame.peek(-1)
|
||||
: frame.peek(-2);
|
||||
@ -5267,7 +5237,7 @@ mjit::Compiler::testSingletonProperty(JSObject *obj, jsid id)
|
||||
return false;
|
||||
if (holder->getSlot(shape->slot()).isUndefined())
|
||||
return false;
|
||||
} else if (!shape->isMethod()) {
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -5600,10 +5570,7 @@ mjit::Compiler::jsop_setprop(PropertyName *name, bool popGuaranteed)
|
||||
}
|
||||
#endif
|
||||
|
||||
ic::PICInfo::Kind kind = (op == JSOP_SETMETHOD)
|
||||
? ic::PICInfo::SETMETHOD
|
||||
: ic::PICInfo::SET;
|
||||
PICGenInfo pic(kind, op);
|
||||
PICGenInfo pic(ic::PICInfo::SET, op);
|
||||
pic.name = name;
|
||||
|
||||
if (monitored(PC)) {
|
||||
@ -6374,7 +6341,7 @@ mjit::Compiler::jsop_getgname(uint32_t index)
|
||||
* reallocation of the global object's slots.
|
||||
*/
|
||||
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());
|
||||
if (!value->isUndefined() &&
|
||||
!propertyTypes->isOwnProperty(cx, globalObj->getType(cx), true)) {
|
||||
@ -6497,7 +6464,7 @@ mjit::Compiler::jsop_setgname(PropertyName *name, bool popGuaranteed)
|
||||
if (!types)
|
||||
return;
|
||||
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() &&
|
||||
!types->isOwnProperty(cx, globalObj->getType(cx), true)) {
|
||||
watchGlobalReallocation();
|
||||
|
@ -262,7 +262,7 @@ class Compiler : public BaseCompiler
|
||||
return getPropLabels_;
|
||||
}
|
||||
ic::SetPropLabels &setPropLabels() {
|
||||
JS_ASSERT(kind == ic::PICInfo::SET || kind == ic::PICInfo::SETMETHOD);
|
||||
JS_ASSERT(kind == ic::PICInfo::SET);
|
||||
return setPropLabels_;
|
||||
}
|
||||
ic::BindNameLabels &bindNameLabels() {
|
||||
|
@ -2658,22 +2658,6 @@ mjit::Compiler::jsop_pos()
|
||||
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
|
||||
mjit::Compiler::jsop_initprop()
|
||||
{
|
||||
|
@ -1869,8 +1869,7 @@ LoopState::analyzeLoopBody(unsigned frame)
|
||||
break;
|
||||
}
|
||||
|
||||
case JSOP_SETPROP:
|
||||
case JSOP_SETMETHOD: {
|
||||
case JSOP_SETPROP: {
|
||||
JSAtom *atom = script->getAtom(GET_UINT32_INDEX(pc));
|
||||
jsid id = MakeTypeId(cx, ATOM_TO_JSID(atom));
|
||||
|
||||
|
@ -99,7 +99,7 @@ ic::GetGlobalName(VMFrame &f, ic::GetGlobalNameIC *ic)
|
||||
}
|
||||
|
||||
if (!shape ||
|
||||
!shape->hasDefaultGetterOrIsMethod() ||
|
||||
!shape->hasDefaultGetter() ||
|
||||
!shape->hasSlot())
|
||||
{
|
||||
if (shape)
|
||||
@ -165,8 +165,7 @@ UpdateSetGlobalName(VMFrame &f, ic::SetGlobalNameIC *ic, JSObject *obj, const Sh
|
||||
if (!shape)
|
||||
return Lookup_Uncacheable;
|
||||
|
||||
if (shape->isMethod() ||
|
||||
!shape->hasDefaultSetter() ||
|
||||
if (!shape->hasDefaultSetter() ||
|
||||
!shape->writable() ||
|
||||
!shape->hasSlot() ||
|
||||
obj->watched())
|
||||
|
@ -350,23 +350,6 @@ class SetPropCompiler : public PICStubCompiler
|
||||
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())) {
|
||||
Address address(pic.objReg,
|
||||
JSObject::getFixedSlotOffset(shape->slot()));
|
||||
@ -389,7 +372,6 @@ class SetPropCompiler : public PICStubCompiler
|
||||
/* Write the object's new shape. */
|
||||
masm.storePtr(ImmPtr(shape), Address(pic.objReg, JSObject::offsetOfShape()));
|
||||
} else if (shape->hasDefaultSetter()) {
|
||||
JS_ASSERT(!shape->isMethod());
|
||||
Address address = masm.objPropAddress(obj, pic.objReg, shape->slot());
|
||||
masm.storeValue(pic.u.vr, address);
|
||||
} else {
|
||||
@ -585,17 +567,6 @@ class SetPropCompiler : public PICStubCompiler
|
||||
unsigned flags = 0;
|
||||
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,
|
||||
* 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);
|
||||
if (!shape)
|
||||
return error();
|
||||
if (flags & Shape::METHOD)
|
||||
obj->nativeSetSlot(shape->slot(), f.regs.sp[-1]);
|
||||
|
||||
if (monitor.recompiled())
|
||||
return Lookup_Uncacheable;
|
||||
@ -647,13 +616,8 @@ class SetPropCompiler : public PICStubCompiler
|
||||
}
|
||||
|
||||
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())
|
||||
return disable("readonly");
|
||||
if (shape->isMethod())
|
||||
return disable("method");
|
||||
|
||||
if (shape->hasDefaultSetter()) {
|
||||
if (!shape->hasSlot())
|
||||
return disable("invalid slot");
|
||||
@ -789,27 +753,22 @@ struct GetPropHelper {
|
||||
|
||||
LookupStatus testForGet() {
|
||||
if (!shape->hasDefaultGetter()) {
|
||||
if (shape->isMethod()) {
|
||||
if (JSOp(*f.pc()) != JSOP_CALLPROP)
|
||||
return ic.disable(f, "method valued shape");
|
||||
} else {
|
||||
if (shape->hasGetterValue())
|
||||
return ic.disable(f, "getter value shape");
|
||||
if (shape->hasSlot() && holder != obj)
|
||||
return ic.disable(f, "slotful getter hook through prototype");
|
||||
if (!ic.canCallHook)
|
||||
return ic.disable(f, "can't call getter hook");
|
||||
if (f.regs.inlined()) {
|
||||
/*
|
||||
* As with native stubs, getter hook stubs can't be
|
||||
* generated for inline frames. Mark the inner function
|
||||
* as uninlineable and recompile.
|
||||
*/
|
||||
f.script()->uninlineable = true;
|
||||
MarkTypeObjectFlags(cx, f.script()->function(),
|
||||
types::OBJECT_FLAG_UNINLINEABLE);
|
||||
return Lookup_Uncacheable;
|
||||
}
|
||||
if (shape->hasGetterValue())
|
||||
return ic.disable(f, "getter value shape");
|
||||
if (shape->hasSlot() && holder != obj)
|
||||
return ic.disable(f, "slotful getter hook through prototype");
|
||||
if (!ic.canCallHook)
|
||||
return ic.disable(f, "can't call getter hook");
|
||||
if (f.regs.inlined()) {
|
||||
/*
|
||||
* As with native stubs, getter hook stubs can't be
|
||||
* generated for inline frames. Mark the inner function
|
||||
* as uninlineable and recompile.
|
||||
*/
|
||||
f.script()->uninlineable = true;
|
||||
MarkTypeObjectFlags(cx, f.script()->function(),
|
||||
types::OBJECT_FLAG_UNINLINEABLE);
|
||||
return Lookup_Uncacheable;
|
||||
}
|
||||
} else if (!shape->hasSlot()) {
|
||||
return ic.disable(f, "no slot");
|
||||
@ -962,7 +921,7 @@ class GetPropCompiler : public PICStubCompiler
|
||||
return status;
|
||||
if (getprop.obj != getprop.holder)
|
||||
return disable("proto walk on String.prototype");
|
||||
if (!getprop.shape->hasDefaultGetterOrIsMethod())
|
||||
if (!getprop.shape->hasDefaultGetter())
|
||||
return disable("getter hook on String.prototype");
|
||||
if (hadGC())
|
||||
return Lookup_Uncacheable;
|
||||
@ -1239,7 +1198,7 @@ class GetPropCompiler : public PICStubCompiler
|
||||
pic.secondShapeGuard = 0;
|
||||
}
|
||||
|
||||
if (!shape->hasDefaultGetterOrIsMethod()) {
|
||||
if (!shape->hasDefaultGetter()) {
|
||||
generateGetterStub(masm, shape, start, shapeMismatches);
|
||||
if (setStubShapeOffset)
|
||||
pic.getPropLabels().setStubShapeJump(masm, start, stubShapeJumpLabel);
|
||||
@ -1327,7 +1286,7 @@ class GetPropCompiler : public PICStubCompiler
|
||||
return Lookup_Uncacheable;
|
||||
|
||||
if (obj == getprop.holder &&
|
||||
getprop.shape->hasDefaultGetterOrIsMethod() &&
|
||||
getprop.shape->hasDefaultGetter() &&
|
||||
!pic.inlinePathPatched) {
|
||||
return patchInline(getprop.holder, getprop.shape);
|
||||
}
|
||||
@ -1675,7 +1634,7 @@ class ScopeNameCompiler : public PICStubCompiler
|
||||
JSObject *normalized = obj;
|
||||
if (obj->isWith() && !shape->hasDefaultGetter())
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
@ -384,7 +384,6 @@ struct PICInfo : public BasePolyIC {
|
||||
{
|
||||
GET, // JSOP_GETPROP
|
||||
SET, // JSOP_SETPROP, JSOP_SETNAME
|
||||
SETMETHOD, // JSOP_SETMETHOD
|
||||
NAME, // JSOP_NAME
|
||||
BIND, // JSOP_BINDNAME
|
||||
XNAME // JSOP_GETXPROP
|
||||
@ -461,7 +460,7 @@ struct PICInfo : public BasePolyIC {
|
||||
types::TypeSet *rhsTypes;
|
||||
|
||||
inline bool isSet() const {
|
||||
return kind == SET || kind == SETMETHOD;
|
||||
return kind == SET;
|
||||
}
|
||||
inline bool isGet() const {
|
||||
return kind == GET;
|
||||
|
@ -998,69 +998,6 @@ stubs::RegExp(VMFrame &f, JSObject *regex)
|
||||
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
|
||||
stubs::Lambda(VMFrame &f, JSFunction *fun)
|
||||
{
|
||||
@ -1141,11 +1078,10 @@ InitPropOrMethod(VMFrame &f, PropertyName *name, JSOp op)
|
||||
/* Get the immediate property name into id. */
|
||||
jsid id = ATOM_TO_JSID(name);
|
||||
|
||||
unsigned defineHow = (op == JSOP_INITMETHOD) ? DNP_SET_METHOD : 0;
|
||||
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,
|
||||
JSPROP_ENUMERATE, 0, 0, defineHow)) {
|
||||
JSPROP_ENUMERATE, 0, 0, 0)) {
|
||||
THROW();
|
||||
}
|
||||
}
|
||||
@ -1156,12 +1092,6 @@ stubs::InitProp(VMFrame &f, PropertyName *name)
|
||||
InitPropOrMethod(f, name, JSOP_INITPROP);
|
||||
}
|
||||
|
||||
void JS_FASTCALL
|
||||
stubs::InitMethod(VMFrame &f, PropertyName *name)
|
||||
{
|
||||
InitPropOrMethod(f, name, JSOP_INITMETHOD);
|
||||
}
|
||||
|
||||
void JS_FASTCALL
|
||||
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 InitElem(VMFrame &f, uint32_t last);
|
||||
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 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);
|
||||
void JS_FASTCALL RegExp(VMFrame &f, JSObject *regex);
|
||||
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);
|
||||
void JS_FASTCALL Arguments(VMFrame &f);
|
||||
void JS_FASTCALL EnterBlock(VMFrame &f, JSObject *obj);
|
||||
|
@ -2170,8 +2170,7 @@ DumpStack(JSContext *cx, unsigned argc, Value *vp)
|
||||
Value v;
|
||||
if (iter.isScript()) {
|
||||
if (iter.fp()->isNonEvalFunctionFrame()) {
|
||||
if (!iter.fp()->getValidCalleeObject(cx, &v))
|
||||
return false;
|
||||
v = ObjectValue(iter.fp()->callee());
|
||||
} else if (iter.fp()->isEvalFrame()) {
|
||||
v = StringValue(evalStr);
|
||||
} else {
|
||||
@ -2782,11 +2781,7 @@ CopyProperty(JSContext *cx, JSObject *obj, JSObject *referent, jsid id,
|
||||
return true;
|
||||
|
||||
const Shape *shape = (Shape *) prop;
|
||||
if (shape->isMethod()) {
|
||||
shape = referent->methodReadBarrier(cx, *shape, &desc.value);
|
||||
if (!shape)
|
||||
return false;
|
||||
} else if (shape->hasSlot()) {
|
||||
if (shape->hasSlot()) {
|
||||
desc.value = referent->nativeGetSlot(shape->slot());
|
||||
} else {
|
||||
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));
|
||||
Value fval;
|
||||
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) ||
|
||||
Invoke(cx, ObjectValue(*obj), fval, argc, argv, rval));
|
||||
}
|
||||
|
@ -189,13 +189,6 @@ StackFrame::initFixupFrame(StackFrame *prev, StackFrame::Flags flags, void *ncod
|
||||
u.nactual = nactual;
|
||||
}
|
||||
|
||||
inline void
|
||||
StackFrame::overwriteCallee(JSObject &newCallee)
|
||||
{
|
||||
JS_ASSERT(callee().toFunction()->script() == newCallee.toFunction()->script());
|
||||
mutableCalleev().setObject(newCallee);
|
||||
}
|
||||
|
||||
inline Value &
|
||||
StackFrame::canonicalActualArg(unsigned i) const
|
||||
{
|
||||
|
@ -818,13 +818,6 @@ class StackFrame
|
||||
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 {
|
||||
JS_ASSERT(isFunctionFrame());
|
||||
if (isEvalFrame())
|
||||
@ -832,13 +825,6 @@ class StackFrame
|
||||
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 {
|
||||
return CallReceiverFromArgv(formalArgs());
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user