зеркало из https://github.com/mozilla/pjs.git
Fixed getter/setters, pave way for brutal sharing (15146, r=shaver@mozilla.org,rogerl@netscape.com)
This commit is contained in:
Родитель
7ffe77c49e
Коммит
f6243a48b1
|
@ -976,7 +976,7 @@ DumpScope(JSContext *cx, JSObject *obj, JSHashEnumerator dump, FILE *fp)
|
|||
int i;
|
||||
|
||||
fprintf(fp, "\n%s scope contents:\n", OBJ_GET_CLASS(cx, obj)->name);
|
||||
scope = (JSScope *)obj->map;
|
||||
scope = OBJ_SCOPE(obj);
|
||||
if (!MAP_IS_NATIVE(&scope->map))
|
||||
return;
|
||||
if (scope->ops == &js_list_scope_ops) {
|
||||
|
|
|
@ -1661,7 +1661,7 @@ JS_AliasProperty(JSContext *cx, JSObject *obj, const char *name,
|
|||
if (!atom) {
|
||||
ok = JS_FALSE;
|
||||
} else {
|
||||
scope = (JSScope *) obj->map;
|
||||
scope = OBJ_SCOPE(obj);
|
||||
ok = (scope->ops->add(cx, scope, (jsid)atom, (JSScopeProperty *)prop)
|
||||
!= NULL);
|
||||
}
|
||||
|
@ -2006,7 +2006,7 @@ JS_AliasElement(JSContext *cx, JSObject *obj, const char *name, jsint alias)
|
|||
numBuf, name, OBJ_GET_CLASS(cx, obj2)->name);
|
||||
return JS_FALSE;
|
||||
}
|
||||
scope = (JSScope *) obj->map;
|
||||
scope = OBJ_SCOPE(obj);
|
||||
ok = (scope->ops->add(cx, scope, INT_TO_JSVAL(alias),
|
||||
(JSScopeProperty *)prop)
|
||||
!= NULL);
|
||||
|
@ -2506,11 +2506,16 @@ JS_CompileUCFunctionForPrincipals(JSContext *cx, JSObject *obj,
|
|||
funAtom = NULL;
|
||||
goto out;
|
||||
}
|
||||
funAtom = js_Atomize(cx, name, strlen(name), 0);
|
||||
if (!funAtom) {
|
||||
fun = NULL;
|
||||
goto out;
|
||||
if (!name) {
|
||||
funAtom = NULL;
|
||||
} else {
|
||||
funAtom = js_Atomize(cx, name, strlen(name), 0);
|
||||
if (!funAtom) {
|
||||
fun = NULL;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
/* XXXbe new-function, bind name only on success */
|
||||
fun = js_DefineFunction(cx, obj, funAtom, NULL, nargs, 0);
|
||||
if (!fun)
|
||||
goto out;
|
||||
|
|
|
@ -251,9 +251,9 @@ DropWatchPoint(JSContext *cx, JSWatchPoint *wp)
|
|||
{
|
||||
if (--wp->nrefs != 0)
|
||||
return;
|
||||
wp->sprop->setter = wp->setter;
|
||||
SPROP_SETTER(wp->sprop, wp->object) = wp->setter;
|
||||
JS_LOCK_OBJ_VOID(cx, wp->object,
|
||||
js_DropScopeProperty(cx, (JSScope *)wp->object->map,
|
||||
js_DropScopeProperty(cx, OBJ_SCOPE(wp->object),
|
||||
wp->sprop));
|
||||
JS_REMOVE_LINK(&wp->links);
|
||||
js_RemoveRoot(cx->runtime, &wp->closure);
|
||||
|
@ -319,7 +319,7 @@ js_watch_set(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
|
|||
}
|
||||
symid = (jsid)atom;
|
||||
}
|
||||
scope = (JSScope *) obj->map;
|
||||
scope = OBJ_SCOPE(obj);
|
||||
JS_ASSERT(scope->props);
|
||||
ok = LOCKED_OBJ_GET_CLASS(obj)->addProperty(cx, obj, sprop->id,
|
||||
&value);
|
||||
|
@ -409,8 +409,8 @@ JS_SetWatchPoint(JSContext *cx, JSObject *obj, jsval id,
|
|||
return JS_FALSE;
|
||||
}
|
||||
}
|
||||
getter = sprop->getter;
|
||||
setter = sprop->setter;
|
||||
getter = SPROP_GETTER(sprop, pobj);
|
||||
setter = SPROP_SETTER(sprop, pobj);
|
||||
attrs = sprop->attrs;
|
||||
OBJ_DROP_PROPERTY(cx, pobj, (JSProperty *)sprop);
|
||||
|
||||
|
@ -434,9 +434,9 @@ JS_SetWatchPoint(JSContext *cx, JSObject *obj, jsval id,
|
|||
JS_APPEND_LINK(&wp->links, &rt->watchPointList);
|
||||
wp->object = obj;
|
||||
wp->userid = id;
|
||||
wp->sprop = js_HoldScopeProperty(cx, (JSScope *)obj->map, sprop);
|
||||
wp->setter = sprop->setter;
|
||||
sprop->setter = js_watch_set;
|
||||
wp->sprop = js_HoldScopeProperty(cx, OBJ_SCOPE(obj), sprop);
|
||||
wp->setter = SPROP_SETTER(sprop, obj);
|
||||
SPROP_SETTER(sprop, obj) = js_watch_set;
|
||||
wp->nrefs = 1;
|
||||
}
|
||||
wp->handler = handler;
|
||||
|
@ -732,7 +732,7 @@ JS_PropertyIterator(JSObject *obj, JSScopeProperty **iteratorp)
|
|||
JSScope *scope;
|
||||
|
||||
sprop = *iteratorp;
|
||||
scope = (JSScope *) obj->map;
|
||||
scope = OBJ_SCOPE(obj);
|
||||
sprop = (sprop == NULL) ? scope->props : sprop->next;
|
||||
*iteratorp = sprop;
|
||||
return sprop;
|
||||
|
@ -743,23 +743,25 @@ JS_GetPropertyDesc(JSContext *cx, JSObject *obj, JSScopeProperty *sprop,
|
|||
JSPropertyDesc *pd)
|
||||
{
|
||||
JSSymbol *sym;
|
||||
JSPropertyOp getter;
|
||||
|
||||
sym = sprop->symbols;
|
||||
pd->id = sym ? js_IdToValue(sym_id(sym)) : JSVAL_VOID;
|
||||
if (!sym || !js_GetProperty(cx, obj, sym_id(sym), &pd->value))
|
||||
pd->value = OBJ_GET_SLOT(cx, obj, sprop->slot);
|
||||
getter = SPROP_GETTER(sprop, obj);
|
||||
pd->flags = ((sprop->attrs & JSPROP_ENUMERATE) ? JSPD_ENUMERATE : 0)
|
||||
| ((sprop->attrs & JSPROP_READONLY) ? JSPD_READONLY : 0)
|
||||
| ((sprop->attrs & JSPROP_PERMANENT) ? JSPD_PERMANENT : 0)
|
||||
#if JS_HAS_CALL_OBJECT
|
||||
| ((sprop->getter == js_GetCallVariable) ? JSPD_VARIABLE : 0)
|
||||
| ((getter == js_GetCallVariable) ? JSPD_VARIABLE : 0)
|
||||
#endif /* JS_HAS_CALL_OBJECT */
|
||||
| ((sprop->getter == js_GetArgument) ? JSPD_ARGUMENT : 0)
|
||||
| ((sprop->getter == js_GetLocalVariable) ? JSPD_VARIABLE : 0);
|
||||
| ((getter == js_GetArgument) ? JSPD_ARGUMENT : 0)
|
||||
| ((getter == js_GetLocalVariable) ? JSPD_VARIABLE : 0);
|
||||
#if JS_HAS_CALL_OBJECT
|
||||
/* for Call Object 'real' getter isn't passed in to us */
|
||||
if (OBJ_GET_CLASS(cx, obj) == &js_CallClass &&
|
||||
sprop->getter == js_CallClass.getProperty) {
|
||||
getter == js_CallClass.getProperty) {
|
||||
pd->flags |= JSPD_ARGUMENT;
|
||||
}
|
||||
#endif /* JS_HAS_CALL_OBJECT */
|
||||
|
@ -795,10 +797,9 @@ JS_GetPropertyDescArray(JSContext *cx, JSObject *obj, JSPropertyDescArray *pda)
|
|||
return JS_FALSE;
|
||||
|
||||
/* have no props, or object's scope has not mutated from that of proto */
|
||||
scope = (JSScope *)obj->map;
|
||||
scope = OBJ_SCOPE(obj);
|
||||
if (!scope->props ||
|
||||
(OBJ_GET_PROTO(cx,obj) &&
|
||||
scope == (JSScope *)(OBJ_GET_PROTO(cx,obj)->map))) {
|
||||
(OBJ_GET_PROTO(cx,obj) && scope == OBJ_SCOPE(OBJ_GET_PROTO(cx,obj)))) {
|
||||
pda->length = 0;
|
||||
pda->array = NULL;
|
||||
return JS_TRUE;
|
||||
|
|
|
@ -469,9 +469,9 @@ call_enumerate(JSContext *cx, JSObject *obj)
|
|||
return JS_TRUE;
|
||||
|
||||
/* Reflect actual args for formal parameters, and all local variables. */
|
||||
scope = (JSScope *)fun->object->map;
|
||||
scope = OBJ_SCOPE(fun->object);
|
||||
for (sprop = scope->props; sprop; sprop = sprop->next) {
|
||||
getter = sprop->getter;
|
||||
getter = SPROP_GETTER_SCOPE(sprop, scope);
|
||||
if (getter != js_GetArgument && getter != js_GetLocalVariable)
|
||||
continue;
|
||||
|
||||
|
@ -518,7 +518,7 @@ call_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags,
|
|||
}
|
||||
|
||||
if (sprop) {
|
||||
getter = sprop->getter;
|
||||
getter = SPROP_GETTER(sprop, obj2);
|
||||
propid = sprop->id;
|
||||
symid = (jsid) sym_atom(sprop->symbols);
|
||||
OBJ_DROP_PROPERTY(cx, obj2, (JSProperty *)sprop);
|
||||
|
@ -804,7 +804,7 @@ fun_enumProperty(JSContext *cx, JSObject *obj)
|
|||
*/
|
||||
|
||||
JS_LOCK_OBJ(cx, obj);
|
||||
scope = (JSScope *) obj->map;
|
||||
scope = OBJ_SCOPE(obj);
|
||||
for (sprop = scope->props; sprop; sprop = sprop->next) {
|
||||
jsval id = sprop->id;
|
||||
if (!JSVAL_IS_INT(id)) {
|
||||
|
@ -1023,13 +1023,15 @@ fun_xdrObject(JSXDRState *xdr, JSObject **objp)
|
|||
/* do arguments and local vars */
|
||||
if (fun->object) {
|
||||
if (xdr->mode == JSXDR_ENCODE) {
|
||||
JSScope *scope = (JSScope *) fun->object->map;
|
||||
JSScope *scope = OBJ_SCOPE(fun->object);
|
||||
|
||||
for (sprop = scope->props; sprop; sprop = sprop->next) {
|
||||
if (sprop->getter == js_GetArgument) {
|
||||
JSPropertyOp getter = SPROP_GETTER_SCOPE(sprop, scope);
|
||||
|
||||
if (getter == js_GetArgument) {
|
||||
type = JSXDR_FUNARG;
|
||||
JS_ASSERT(nargs++ <= fun->nargs);
|
||||
} else if (sprop->getter == js_GetLocalVariable) {
|
||||
} else if (getter == js_GetLocalVariable) {
|
||||
type = JSXDR_FUNVAR;
|
||||
JS_ASSERT(nvars++ <= fun->nvars);
|
||||
} else {
|
||||
|
@ -1535,7 +1537,7 @@ Function(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
|||
}
|
||||
if (sprop && obj2 == obj) {
|
||||
#ifdef CHECK_ARGUMENT_HIDING
|
||||
JS_ASSERT(sprop->getter == js_GetArgument);
|
||||
JS_ASSERT(SPROP_GETTER(sprop, obj) == js_GetArgument);
|
||||
OBJ_DROP_PROPERTY(cx, obj2, (JSProperty *)sprop);
|
||||
JS_ReportErrorNumber(cx, JSREPORT_WARNING,
|
||||
JSMSG_SAME_FORMAL, ATOM_BYTES(atom));
|
||||
|
|
|
@ -502,7 +502,7 @@ gc_mark(JSRuntime *rt, void *thing)
|
|||
obj = thing;
|
||||
vp = obj->slots;
|
||||
if (vp) {
|
||||
scope = OBJ_IS_NATIVE(obj) ? (JSScope *) obj->map : NULL;
|
||||
scope = OBJ_IS_NATIVE(obj) ? OBJ_SCOPE(obj) : NULL;
|
||||
if (scope) {
|
||||
clasp = JSVAL_TO_PRIVATE(obj->slots[JSSLOT_CLASS]);
|
||||
|
||||
|
@ -550,7 +550,8 @@ gc_mark(JSRuntime *rt, void *thing)
|
|||
id, js_getter_str);
|
||||
#endif
|
||||
GC_MARK(rt,
|
||||
JSVAL_TO_GCTHING((jsval)sprop->getter),
|
||||
JSVAL_TO_GCTHING((jsval)
|
||||
SPROP_GETTER_SCOPE(sprop, scope)),
|
||||
buf,
|
||||
prev);
|
||||
}
|
||||
|
@ -560,7 +561,8 @@ gc_mark(JSRuntime *rt, void *thing)
|
|||
id, js_setter_str);
|
||||
#endif
|
||||
GC_MARK(rt,
|
||||
JSVAL_TO_GCTHING((jsval)sprop->setter),
|
||||
JSVAL_TO_GCTHING((jsval)
|
||||
SPROP_SETTER_SCOPE(sprop, scope)),
|
||||
buf,
|
||||
prev);
|
||||
}
|
||||
|
|
251
js/src/jslock.c
251
js/src/jslock.c
|
@ -70,11 +70,11 @@ js_UnlockGlobal(void *id)
|
|||
}
|
||||
|
||||
#define ReadWord(W) (W)
|
||||
#define AtomicAddBody(P,I)\
|
||||
jsword n;\
|
||||
do {\
|
||||
n = ReadWord(*(P));\
|
||||
} while (!js_CompareAndSwap(P, n, n + I));
|
||||
#define AtomicAddBody(P,I) \
|
||||
jsword n; \
|
||||
do { \
|
||||
n = ReadWord(*(P)); \
|
||||
} while (!js_CompareAndSwap(P, n, n + I))
|
||||
|
||||
/* Exclude Alpha NT. */
|
||||
#if defined(_WIN32) && defined(_M_IX86) && !defined(NSPR_LOCK)
|
||||
|
@ -112,10 +112,10 @@ static PRLock *_counter_lock;
|
|||
#define UsingCounterLock 1
|
||||
|
||||
#undef AtomicAddBody
|
||||
#define AtomicAddBody(P,I) \
|
||||
PR_Lock(_counter_lock);\
|
||||
*(P) += I;\
|
||||
PR_Unlock(_counter_lock);
|
||||
#define AtomicAddBody(P,I) \
|
||||
PR_Lock(_counter_lock); \
|
||||
*(P) += I; \
|
||||
PR_Unlock(_counter_lock)
|
||||
|
||||
#endif /* !ULTRA_SPARC */
|
||||
|
||||
|
@ -182,10 +182,10 @@ static PRLock *_counter_lock;
|
|||
#define UsingCounterLock 1
|
||||
|
||||
#undef AtomicAddBody
|
||||
#define AtomicAddBody(P,I) \
|
||||
PR_Lock(_counter_lock);\
|
||||
*(P) += I;\
|
||||
PR_Unlock(_counter_lock);
|
||||
#define AtomicAddBody(P,I) \
|
||||
PR_Lock(_counter_lock); \
|
||||
*(P) += I; \
|
||||
PR_Unlock(_counter_lock)
|
||||
|
||||
static PRLock *_compare_and_swap_lock;
|
||||
#define UsingCompareAndSwapLock 1
|
||||
|
@ -219,25 +219,25 @@ js_CurrentThreadId()
|
|||
}
|
||||
|
||||
void
|
||||
js_NewLock(JSThinLock *p)
|
||||
js_NewLock(JSThinLock *tl)
|
||||
{
|
||||
#ifdef NSPR_LOCK
|
||||
p->owner = 0;
|
||||
p->fat = (JSFatLock*)JS_NEW_LOCK();
|
||||
tl->owner = 0;
|
||||
tl->fat = (JSFatLock*)JS_NEW_LOCK();
|
||||
#else
|
||||
memset(p, 0, sizeof(JSThinLock));
|
||||
memset(tl, 0, sizeof(JSThinLock));
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
js_DestroyLock(JSThinLock *p)
|
||||
js_DestroyLock(JSThinLock *tl)
|
||||
{
|
||||
#ifdef NSPR_LOCK
|
||||
p->owner = 0xdeadbeef;
|
||||
JS_DESTROY_LOCK(((JSLock*)p->fat));
|
||||
tl->owner = 0xdeadbeef;
|
||||
JS_DESTROY_LOCK(((JSLock*)tl->fat));
|
||||
#else
|
||||
JS_ASSERT(p->owner == 0);
|
||||
JS_ASSERT(p->fat == NULL);
|
||||
JS_ASSERT(tl->owner == 0);
|
||||
JS_ASSERT(tl->fat == NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -248,27 +248,27 @@ js_GetSlotWhileLocked(JSContext *cx, JSObject *obj, uint32 slot)
|
|||
{
|
||||
jsval v;
|
||||
#ifndef NSPR_LOCK
|
||||
JSScope *scp = (JSScope *)obj->map;
|
||||
JSThinLock *p = &scp->lock;
|
||||
JSScope *scope = OBJ_SCOPE(obj);
|
||||
JSThinLock *tl = &scope->lock;
|
||||
jsword me = cx->thread;
|
||||
#endif
|
||||
|
||||
JS_ASSERT(obj->slots && slot < obj->map->freeslot);
|
||||
#ifndef NSPR_LOCK
|
||||
JS_ASSERT(me == CurrentThreadId());
|
||||
if (js_CompareAndSwap(&p->owner, 0, me)) {
|
||||
if (scp == (JSScope *)obj->map) {
|
||||
if (js_CompareAndSwap(&tl->owner, 0, me)) {
|
||||
if (scope == OBJ_SCOPE(obj)) {
|
||||
v = obj->slots[slot];
|
||||
if (!js_CompareAndSwap(&p->owner, me, 0)) {
|
||||
scp->count = 1;
|
||||
if (!js_CompareAndSwap(&tl->owner, me, 0)) {
|
||||
scope->count = 1;
|
||||
js_UnlockObj(cx,obj);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
if (!js_CompareAndSwap(&p->owner, me, 0))
|
||||
js_Dequeue(p);
|
||||
if (!js_CompareAndSwap(&tl->owner, me, 0))
|
||||
js_Dequeue(tl);
|
||||
}
|
||||
else if (Thin_RemoveWait(ReadWord(p->owner)) == me) {
|
||||
else if (Thin_RemoveWait(ReadWord(tl->owner)) == me) {
|
||||
return obj->slots[slot];
|
||||
}
|
||||
#endif
|
||||
|
@ -282,27 +282,27 @@ JS_INLINE void
|
|||
js_SetSlotWhileLocked(JSContext *cx, JSObject *obj, uint32 slot, jsval v)
|
||||
{
|
||||
#ifndef NSPR_LOCK
|
||||
JSScope *scp = (JSScope *)obj->map;
|
||||
JSThinLock *p = &scp->lock;
|
||||
JSScope *scope = OBJ_SCOPE(obj);
|
||||
JSThinLock *tl = &scope->lock;
|
||||
jsword me = cx->thread;
|
||||
#endif
|
||||
|
||||
JS_ASSERT(obj->slots && slot < obj->map->freeslot);
|
||||
#ifndef NSPR_LOCK
|
||||
JS_ASSERT(me == CurrentThreadId());
|
||||
if (js_CompareAndSwap(&p->owner, 0, me)) {
|
||||
if (scp == (JSScope *)obj->map) {
|
||||
if (js_CompareAndSwap(&tl->owner, 0, me)) {
|
||||
if (scope == OBJ_SCOPE(obj)) {
|
||||
obj->slots[slot] = v;
|
||||
if (!js_CompareAndSwap(&p->owner, me, 0)) {
|
||||
scp->count = 1;
|
||||
if (!js_CompareAndSwap(&tl->owner, me, 0)) {
|
||||
scope->count = 1;
|
||||
js_UnlockObj(cx,obj);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (!js_CompareAndSwap(&p->owner, me, 0))
|
||||
js_Dequeue(p);
|
||||
if (!js_CompareAndSwap(&tl->owner, me, 0))
|
||||
js_Dequeue(tl);
|
||||
}
|
||||
else if (Thin_RemoveWait(ReadWord(p->owner)) == me) {
|
||||
else if (Thin_RemoveWait(ReadWord(tl->owner)) == me) {
|
||||
obj->slots[slot] = v;
|
||||
return;
|
||||
}
|
||||
|
@ -316,7 +316,7 @@ static JSFatLock *
|
|||
mallocFatlock()
|
||||
{
|
||||
JSFatLock *fl = (JSFatLock *)malloc(sizeof(JSFatLock)); /* for now */
|
||||
JS_ASSERT(fl);
|
||||
if (!fl) return NULL;
|
||||
fl->susp = 0;
|
||||
fl->next = NULL;
|
||||
fl->prev = NULL;
|
||||
|
@ -338,13 +338,13 @@ listOfFatlocks(int l)
|
|||
{
|
||||
JSFatLock *m;
|
||||
JSFatLock *m0;
|
||||
int i;
|
||||
int i;
|
||||
|
||||
JS_ASSERT(l>0);
|
||||
m0 = m = mallocFatlock();
|
||||
for (i=1; i<l; i++) {
|
||||
m->next = mallocFatlock();
|
||||
m = m->next;
|
||||
m->next = mallocFatlock();
|
||||
m = m->next;
|
||||
}
|
||||
return m0;
|
||||
}
|
||||
|
@ -364,25 +364,25 @@ static JSFatLockTable* _fl_tables;
|
|||
static JSFatLock *
|
||||
allocateFatlock(void *id)
|
||||
{
|
||||
JSFatLock *m;
|
||||
JSFatLock *m;
|
||||
|
||||
int i = ((int)id/4)%_nr_of_globals;
|
||||
if (_fl_tables[i].free == NULL) {
|
||||
#ifdef DEBUG
|
||||
printf("Ran out of fat locks!\n");
|
||||
#endif
|
||||
_fl_tables[i].free = listOfFatlocks(10);
|
||||
}
|
||||
m = _fl_tables[i].free;
|
||||
_fl_tables[i].free = m->next;
|
||||
_fl_tables[i].free->prev = NULL;
|
||||
m->susp = 0;
|
||||
m->next = _fl_tables[i].taken;
|
||||
m->prev = NULL;
|
||||
if (_fl_tables[i].taken != NULL)
|
||||
_fl_tables[i].taken->prev = m;
|
||||
_fl_tables[i].taken = m;
|
||||
return m;
|
||||
int i = ((int)id/4)%_nr_of_globals;
|
||||
if (_fl_tables[i].free == NULL) {
|
||||
#ifdef DEBUG
|
||||
printf("Ran out of fat locks!\n");
|
||||
#endif
|
||||
_fl_tables[i].free = listOfFatlocks(10);
|
||||
}
|
||||
m = _fl_tables[i].free;
|
||||
_fl_tables[i].free = m->next;
|
||||
_fl_tables[i].free->prev = NULL;
|
||||
m->susp = 0;
|
||||
m->next = _fl_tables[i].taken;
|
||||
m->prev = NULL;
|
||||
if (_fl_tables[i].taken != NULL)
|
||||
_fl_tables[i].taken->prev = m;
|
||||
_fl_tables[i].taken = m;
|
||||
return m;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -508,93 +508,93 @@ js_InitContextForLocking(JSContext *cx)
|
|||
(ii) fl->susp >= 0
|
||||
*/
|
||||
static int
|
||||
js_SuspendThread(JSThinLock *p)
|
||||
js_SuspendThread(JSThinLock *tl)
|
||||
{
|
||||
JSFatLock *fl;
|
||||
JSStatus stat;
|
||||
|
||||
if (p->fat == NULL)
|
||||
fl = p->fat = allocateFatlock(p);
|
||||
|
||||
if (tl->fat == NULL)
|
||||
fl = tl->fat = allocateFatlock(tl);
|
||||
else
|
||||
fl = p->fat;
|
||||
fl = tl->fat;
|
||||
JS_ASSERT(fl->susp >= 0);
|
||||
fl->susp++;
|
||||
PR_Lock(fl->slock);
|
||||
js_UnlockGlobal(p);
|
||||
js_UnlockGlobal(tl);
|
||||
stat = (JSStatus)PR_WaitCondVar(fl->svar,PR_INTERVAL_NO_TIMEOUT);
|
||||
JS_ASSERT(stat != JS_FAILURE);
|
||||
PR_Unlock(fl->slock);
|
||||
js_LockGlobal(p);
|
||||
js_LockGlobal(tl);
|
||||
fl->susp--;
|
||||
if (fl->susp == 0) {
|
||||
deallocateFatlock(fl,p);
|
||||
p->fat = NULL;
|
||||
deallocateFatlock(fl,tl);
|
||||
tl->fat = NULL;
|
||||
}
|
||||
return p->fat == NULL;
|
||||
return tl->fat == NULL;
|
||||
}
|
||||
|
||||
/* (i) global lock is held
|
||||
/* (i) global lock is held
|
||||
(ii) fl->susp > 0
|
||||
*/
|
||||
static void
|
||||
js_ResumeThread(JSThinLock *p)
|
||||
js_ResumeThread(JSThinLock *tl)
|
||||
{
|
||||
JSFatLock *fl = p->fat;
|
||||
JSFatLock *fl = tl->fat;
|
||||
JSStatus stat;
|
||||
|
||||
JS_ASSERT(fl != NULL);
|
||||
JS_ASSERT(fl->susp > 0);
|
||||
PR_Lock(fl->slock);
|
||||
js_UnlockGlobal(p);
|
||||
js_UnlockGlobal(tl);
|
||||
stat = (JSStatus)PR_NotifyCondVar(fl->svar);
|
||||
JS_ASSERT(stat != JS_FAILURE);
|
||||
PR_Unlock(fl->slock);
|
||||
}
|
||||
|
||||
static void
|
||||
js_Enqueue(JSThinLock *p, jsword me)
|
||||
js_Enqueue(JSThinLock *tl, jsword me)
|
||||
{
|
||||
jsword o, n;
|
||||
|
||||
js_LockGlobal(p);
|
||||
js_LockGlobal(tl);
|
||||
while (1) {
|
||||
o = ReadWord(p->owner);
|
||||
o = ReadWord(tl->owner);
|
||||
n = Thin_SetWait(o);
|
||||
if (o != 0 && js_CompareAndSwap(&p->owner,o,n)) {
|
||||
if (js_SuspendThread(p))
|
||||
if (o != 0 && js_CompareAndSwap(&tl->owner,o,n)) {
|
||||
if (js_SuspendThread(tl))
|
||||
me = Thin_RemoveWait(me);
|
||||
else
|
||||
me = Thin_SetWait(me);
|
||||
}
|
||||
else if (js_CompareAndSwap(&p->owner,0,me)) {
|
||||
js_UnlockGlobal(p);
|
||||
else if (js_CompareAndSwap(&tl->owner,0,me)) {
|
||||
js_UnlockGlobal(tl);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
js_Dequeue(JSThinLock *p)
|
||||
js_Dequeue(JSThinLock *tl)
|
||||
{
|
||||
int o;
|
||||
|
||||
js_LockGlobal(p);
|
||||
o = ReadWord(p->owner);
|
||||
js_LockGlobal(tl);
|
||||
o = ReadWord(tl->owner);
|
||||
JS_ASSERT(Thin_GetWait(o) != 0);
|
||||
JS_ASSERT(p->fat != NULL);
|
||||
if (!js_CompareAndSwap(&p->owner,o,0)) /* release it */
|
||||
JS_ASSERT(tl->fat != NULL);
|
||||
if (!js_CompareAndSwap(&tl->owner,o,0)) /* release it */
|
||||
JS_ASSERT(0);
|
||||
js_ResumeThread(p);
|
||||
js_ResumeThread(tl);
|
||||
}
|
||||
|
||||
JS_INLINE void
|
||||
js_Lock(JSThinLock *p, jsword me)
|
||||
js_Lock(JSThinLock *tl, jsword me)
|
||||
{
|
||||
JS_ASSERT(me == CurrentThreadId());
|
||||
if (js_CompareAndSwap(&p->owner, 0, me))
|
||||
if (js_CompareAndSwap(&tl->owner, 0, me))
|
||||
return;
|
||||
if (Thin_RemoveWait(ReadWord(p->owner)) != me)
|
||||
js_Enqueue(p, me);
|
||||
if (Thin_RemoveWait(ReadWord(tl->owner)) != me)
|
||||
js_Enqueue(tl, me);
|
||||
#ifdef DEBUG
|
||||
else
|
||||
JS_ASSERT(0);
|
||||
|
@ -602,13 +602,13 @@ js_Lock(JSThinLock *p, jsword me)
|
|||
}
|
||||
|
||||
JS_INLINE void
|
||||
js_Unlock(JSThinLock *p, jsword me)
|
||||
js_Unlock(JSThinLock *tl, jsword me)
|
||||
{
|
||||
JS_ASSERT(me == CurrentThreadId());
|
||||
if (js_CompareAndSwap(&p->owner, me, 0))
|
||||
if (js_CompareAndSwap(&tl->owner, me, 0))
|
||||
return;
|
||||
if (Thin_RemoveWait(ReadWord(p->owner)) == me)
|
||||
js_Dequeue(p);
|
||||
if (Thin_RemoveWait(ReadWord(tl->owner)) == me)
|
||||
js_Dequeue(tl);
|
||||
#ifdef DEBUG
|
||||
else
|
||||
JS_ASSERT(0);
|
||||
|
@ -619,35 +619,35 @@ void
|
|||
js_LockRuntime(JSRuntime *rt)
|
||||
{
|
||||
jsword me = CurrentThreadId();
|
||||
JSThinLock *p;
|
||||
JSThinLock *tl;
|
||||
|
||||
JS_ASSERT(Thin_RemoveWait(ReadWord(rt->rtLock.owner)) != me);
|
||||
p = &rt->rtLock;
|
||||
JS_LOCK0(p,me);
|
||||
tl = &rt->rtLock;
|
||||
JS_LOCK0(tl,me);
|
||||
}
|
||||
|
||||
void
|
||||
js_UnlockRuntime(JSRuntime *rt)
|
||||
{
|
||||
jsword me = CurrentThreadId();
|
||||
JSThinLock *p;
|
||||
JSThinLock *tl;
|
||||
|
||||
JS_ASSERT(Thin_RemoveWait(ReadWord(rt->rtLock.owner)) == me);
|
||||
p = &rt->rtLock;
|
||||
JS_UNLOCK0(p,me);
|
||||
tl = &rt->rtLock;
|
||||
JS_UNLOCK0(tl,me);
|
||||
}
|
||||
|
||||
static JS_INLINE void
|
||||
js_LockScope1(JSContext *cx, JSScope *scope, jsword me)
|
||||
{
|
||||
JSThinLock *p;
|
||||
JSThinLock *tl;
|
||||
|
||||
if (Thin_RemoveWait(ReadWord(scope->lock.owner)) == me) {
|
||||
JS_ASSERT(scope->count > 0);
|
||||
scope->count++;
|
||||
} else {
|
||||
p = &scope->lock;
|
||||
JS_LOCK0(p,me);
|
||||
tl = &scope->lock;
|
||||
JS_LOCK0(tl,me);
|
||||
JS_ASSERT(scope->count == 0);
|
||||
scope->count = 1;
|
||||
}
|
||||
|
@ -664,7 +664,7 @@ void
|
|||
js_UnlockScope(JSContext *cx, JSScope *scope)
|
||||
{
|
||||
jsword me = cx->thread;
|
||||
JSThinLock *p;
|
||||
JSThinLock *tl;
|
||||
|
||||
JS_ASSERT(scope->count > 0);
|
||||
if (Thin_RemoveWait(ReadWord(scope->lock.owner)) != me) {
|
||||
|
@ -672,8 +672,8 @@ js_UnlockScope(JSContext *cx, JSScope *scope)
|
|||
return;
|
||||
}
|
||||
if (--scope->count == 0) {
|
||||
p = &scope->lock;
|
||||
JS_UNLOCK0(p,me);
|
||||
tl = &scope->lock;
|
||||
JS_UNLOCK0(tl,me);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -681,30 +681,32 @@ void
|
|||
js_TransferScopeLock(JSContext *cx, JSScope *oldscope, JSScope *newscope)
|
||||
{
|
||||
jsword me;
|
||||
JSThinLock *p;
|
||||
JSThinLock *tl;
|
||||
|
||||
JS_ASSERT(JS_IS_SCOPE_LOCKED(newscope));
|
||||
|
||||
/*
|
||||
* If the last reference to oldscope went away, newscope needs no lock
|
||||
* state update.
|
||||
*/
|
||||
if (!oldscope) {
|
||||
if (!oldscope)
|
||||
return;
|
||||
}
|
||||
JS_ASSERT(JS_IS_SCOPE_LOCKED(oldscope));
|
||||
|
||||
/*
|
||||
* Transfer oldscope's entry count to newscope, as it will be unlocked
|
||||
* now via JS_UNLOCK_OBJ(cx,obj) calls made while we unwind the C stack
|
||||
* from the current point (under js_GetMutableScope).
|
||||
*/
|
||||
newscope->count = oldscope->count;
|
||||
|
||||
/*
|
||||
* Reset oldscope's lock state so that it is completely unlocked.
|
||||
*/
|
||||
oldscope->count = 0;
|
||||
p = &oldscope->lock;
|
||||
tl = &oldscope->lock;
|
||||
me = cx->thread;
|
||||
JS_UNLOCK0(p,me);
|
||||
JS_UNLOCK0(tl,me);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -714,22 +716,22 @@ js_LockObj(JSContext *cx, JSObject *obj)
|
|||
jsword me = cx->thread;
|
||||
JS_ASSERT(me == CurrentThreadId());
|
||||
for (;;) {
|
||||
scope = (JSScope *) obj->map;
|
||||
js_LockScope1(cx, scope, me);
|
||||
scope = OBJ_SCOPE(obj);
|
||||
js_LockScope1(cx, scope, me);
|
||||
|
||||
/* If obj still has this scope, we're done. */
|
||||
if (scope == (JSScope *) obj->map)
|
||||
return;
|
||||
/* If obj still has this scope, we're done. */
|
||||
if (scope == OBJ_SCOPE(obj))
|
||||
return;
|
||||
|
||||
/* Lost a race with a mutator; retry with obj's new scope. */
|
||||
js_UnlockScope(cx, scope);
|
||||
/* Lost a race with a mutator; retry with obj's new scope. */
|
||||
js_UnlockScope(cx, scope);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
js_UnlockObj(JSContext *cx, JSObject *obj)
|
||||
{
|
||||
js_UnlockScope(cx, (JSScope *) obj->map);
|
||||
js_UnlockScope(cx, OBJ_SCOPE(obj));
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
|
@ -742,9 +744,10 @@ js_IsRuntimeLocked(JSRuntime *rt)
|
|||
JSBool
|
||||
js_IsObjLocked(JSObject *obj)
|
||||
{
|
||||
JSObjectMap *map = obj->map;
|
||||
JSScope *scope = OBJ_SCOPE(obj);
|
||||
|
||||
return MAP_IS_NATIVE(map) && CurrentThreadId() == Thin_RemoveWait(ReadWord(((JSScope *)map)->lock.owner));
|
||||
return MAP_IS_NATIVE(&scope->map) &&
|
||||
CurrentThreadId() == Thin_RemoveWait(ReadWord(scope->lock.owner));
|
||||
}
|
||||
|
||||
JSBool
|
||||
|
|
|
@ -87,7 +87,7 @@ typedef struct JSFatLockTable {
|
|||
#include "jsscope.h"
|
||||
|
||||
#define _SET_OBJ_INFO(obj,f,l) \
|
||||
_SET_SCOPE_INFO(((JSScope*)obj->map),f,l)
|
||||
_SET_SCOPE_INFO(OBJ_SCOPE(obj),f,l)
|
||||
|
||||
#define _SET_SCOPE_INFO(scope,f,l) \
|
||||
(JS_ASSERT(scope->count > 0 && scope->count <= 4), \
|
||||
|
|
|
@ -249,7 +249,7 @@ MarkSharpObjects(JSContext *cx, JSObject *obj, JSIdArray **idap)
|
|||
(attrs & (JSPROP_GETTER | JSPROP_SETTER))) {
|
||||
val = JSVAL_NULL;
|
||||
if (attrs & JSPROP_GETTER)
|
||||
val = (jsval) ((JSScopeProperty *)prop)->getter;
|
||||
val = (jsval)SPROP_GETTER((JSScopeProperty*)prop, obj2);
|
||||
if (attrs & JSPROP_SETTER) {
|
||||
if (val != JSVAL_NULL) {
|
||||
/* Mark the getter here, then set val to setter. */
|
||||
|
@ -257,7 +257,7 @@ MarkSharpObjects(JSContext *cx, JSObject *obj, JSIdArray **idap)
|
|||
NULL)
|
||||
!= NULL);
|
||||
}
|
||||
val = (jsval) ((JSScopeProperty *)prop)->setter;
|
||||
val = (jsval)SPROP_SETTER((JSScopeProperty*)prop, obj2);
|
||||
}
|
||||
} else {
|
||||
ok = OBJ_GET_PROPERTY(cx, obj, id, &val);
|
||||
|
@ -486,13 +486,15 @@ js_obj_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
|
|||
(attrs & (JSPROP_GETTER | JSPROP_SETTER))) {
|
||||
valcnt = 0;
|
||||
if (attrs & JSPROP_GETTER) {
|
||||
val[valcnt] = (jsval) ((JSScopeProperty *)prop)->getter;
|
||||
val[valcnt] = (jsval)
|
||||
SPROP_GETTER((JSScopeProperty *)prop, obj2);
|
||||
gsop[valcnt] =
|
||||
ATOM_TO_STRING(cx->runtime->atomState.getterAtom);
|
||||
valcnt++;
|
||||
}
|
||||
if (attrs & JSPROP_SETTER) {
|
||||
val[valcnt] = (jsval) ((JSScopeProperty *)prop)->setter;
|
||||
val[valcnt] = (jsval)
|
||||
SPROP_SETTER((JSScopeProperty *)prop, obj2);
|
||||
gsop[valcnt] =
|
||||
ATOM_TO_STRING(cx->runtime->atomState.setterAtom);
|
||||
valcnt++;
|
||||
|
@ -1516,9 +1518,9 @@ js_DefineProperty(JSContext *cx, JSObject *obj, jsid id, jsval value,
|
|||
(sprop->attrs & (JSPROP_GETTER | JSPROP_SETTER))) {
|
||||
sprop->attrs |= attrs;
|
||||
if (attrs & JSPROP_GETTER)
|
||||
sprop->getter = getter;
|
||||
SPROP_GETTER(sprop, pobj) = getter;
|
||||
else
|
||||
sprop->setter = setter;
|
||||
SPROP_SETTER(sprop, pobj) = setter;
|
||||
if (propp)
|
||||
*propp = (JSProperty *) sprop;
|
||||
#ifdef JS_THREADSAFE
|
||||
|
@ -1610,7 +1612,7 @@ js_LookupProperty(JSContext *cx, JSObject *obj, jsid id, JSObject **objp,
|
|||
for (;;) {
|
||||
JS_LOCK_OBJ(cx, obj);
|
||||
_SET_OBJ_INFO(obj, file, line);
|
||||
scope = (JSScope *)obj->map;
|
||||
scope = OBJ_SCOPE(obj);
|
||||
if (scope == prevscope)
|
||||
goto skip;
|
||||
sym = scope->ops->lookup(cx, scope, id, hash);
|
||||
|
@ -1635,7 +1637,7 @@ js_LookupProperty(JSContext *cx, JSObject *obj, jsid id, JSObject **objp,
|
|||
JS_LOCK_OBJ(cx, obj);
|
||||
_SET_OBJ_INFO(obj, file, line);
|
||||
if (obj2) {
|
||||
scope = (JSScope *)obj2->map;
|
||||
scope = OBJ_SCOPE(obj2);
|
||||
if (MAP_IS_NATIVE(&scope->map))
|
||||
sym = scope->ops->lookup(cx, scope, id, hash);
|
||||
}
|
||||
|
@ -1645,14 +1647,14 @@ js_LookupProperty(JSContext *cx, JSObject *obj, jsid id, JSObject **objp,
|
|||
return JS_FALSE;
|
||||
JS_LOCK_OBJ(cx, obj);
|
||||
_SET_OBJ_INFO(obj, file, line);
|
||||
scope = (JSScope *)obj->map;
|
||||
scope = OBJ_SCOPE(obj);
|
||||
if (MAP_IS_NATIVE(&scope->map))
|
||||
sym = scope->ops->lookup(cx, scope, id, hash);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (sym && (sprop = sym_property(sym)) != NULL) {
|
||||
JS_ASSERT((JSScope *)obj->map == scope);
|
||||
JS_ASSERT(OBJ_SCOPE(obj) == scope);
|
||||
*objp = scope->object; /* XXXbe hide in jsscope.[ch] */
|
||||
#ifdef JS_THREADSAFE
|
||||
js_HoldScopeProperty(cx, scope, sprop);
|
||||
|
@ -1924,7 +1926,7 @@ js_SetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
|
|||
JS_UNLOCK_OBJ(cx, obj);
|
||||
while (proto) {
|
||||
JS_LOCK_OBJ(cx, proto);
|
||||
protoscope = (JSScope *)proto->map;
|
||||
protoscope = OBJ_SCOPE(proto);
|
||||
if (MAP_IS_NATIVE(&protoscope->map)) {
|
||||
protosym = protoscope->ops->lookup(cx, protoscope, id, hash);
|
||||
if (protosym) {
|
||||
|
@ -1952,8 +1954,8 @@ js_SetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
|
|||
#endif /* JS_HAS_GETTER_SETTER */
|
||||
|
||||
protoid = protosprop->id;
|
||||
protogetter = protosprop->getter;
|
||||
protosetter = protosprop->setter;
|
||||
protogetter = SPROP_GETTER_SCOPE(protosprop,protoscope);
|
||||
protosetter = SPROP_SETTER_SCOPE(protosprop,protoscope);
|
||||
JS_UNLOCK_OBJ(cx, proto);
|
||||
break;
|
||||
}
|
||||
|
@ -2191,7 +2193,7 @@ js_DeleteProperty(JSContext *cx, JSObject *obj, jsid id, jsval *rval)
|
|||
}
|
||||
|
||||
GC_POKE(cx, LOCKED_OBJ_GET_SLOT(obj, sprop->slot));
|
||||
scope = (JSScope *)obj->map;
|
||||
scope = OBJ_SCOPE(obj);
|
||||
|
||||
/*
|
||||
* Purge cache only if prop is not about to be destroyed (since
|
||||
|
@ -2203,7 +2205,7 @@ js_DeleteProperty(JSContext *cx, JSObject *obj, jsid id, jsval *rval)
|
|||
}
|
||||
|
||||
#if JS_HAS_OBJ_WATCHPOINT
|
||||
if (sprop->setter == js_watch_set) {
|
||||
if (SPROP_SETTER_SCOPE(sprop, scope) == js_watch_set) {
|
||||
/*
|
||||
* Keep the symbol around with null value in case of re-set.
|
||||
* The watchpoint will hold the "deleted" property until it
|
||||
|
@ -2381,7 +2383,7 @@ js_Enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op,
|
|||
* deleted during the iteration.
|
||||
*/
|
||||
JS_LOCK_OBJ(cx, obj);
|
||||
scope = (JSScope *) obj->map;
|
||||
scope = OBJ_SCOPE(obj);
|
||||
|
||||
/*
|
||||
* If this object shares a scope with its prototype, don't enumerate
|
||||
|
@ -2389,7 +2391,7 @@ js_Enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op,
|
|||
* when the prototype object is enumerated.
|
||||
*/
|
||||
proto_obj = OBJ_GET_PROTO(cx, obj);
|
||||
if (proto_obj && (scope == (JSScope *)proto_obj->map)) {
|
||||
if (proto_obj && scope == OBJ_SCOPE(proto_obj)) {
|
||||
ida = js_NewIdArray(cx, 0);
|
||||
if (!ida) {
|
||||
JS_UNLOCK_OBJ(cx, obj);
|
||||
|
@ -2553,7 +2555,7 @@ js_IsDelegate(JSContext *cx, JSObject *obj, jsval v, JSBool *bp)
|
|||
void
|
||||
js_DropProperty(JSContext *cx, JSObject *obj, JSProperty *prop)
|
||||
{
|
||||
js_DropScopeProperty(cx, (JSScope *)obj->map, (JSScopeProperty *)prop);
|
||||
js_DropScopeProperty(cx, OBJ_SCOPE(obj), (JSScopeProperty *)prop);
|
||||
JS_UNLOCK_OBJ(cx, obj);
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -165,8 +165,8 @@ struct JSObject {
|
|||
|
||||
extern JS_FRIEND_DATA(JSObjectOps) js_ObjectOps;
|
||||
extern JS_FRIEND_DATA(JSObjectOps) js_WithObjectOps;
|
||||
extern JSClass js_ObjectClass;
|
||||
extern JSClass js_WithClass;
|
||||
extern JSClass js_ObjectClass;
|
||||
extern JSClass js_WithClass;
|
||||
|
||||
struct JSSharpObjectMap {
|
||||
jsrefcount depth;
|
||||
|
|
|
@ -451,7 +451,7 @@ js_NewPrinter(JSContext *cx, const char *name, uintN indent, JSBool pretty)
|
|||
if (fp && fp->scopeChain) {
|
||||
obj = fp->scopeChain;
|
||||
map = obj->map;
|
||||
if (map->ops == &js_ObjectOps) {
|
||||
if (MAP_IS_NATIVE(map)) {
|
||||
if (OBJ_GET_CLASS(cx, obj) == &js_CallClass) {
|
||||
obj = fp->fun ? fp->fun->object : NULL;
|
||||
if (obj)
|
||||
|
@ -747,7 +747,7 @@ GetSlotAtom(JSScope *scope, JSPropertyOp getter, uintN slot)
|
|||
if (!scope)
|
||||
return NULL;
|
||||
for (sprop = scope->props; sprop; sprop = sprop->next) {
|
||||
if (sprop->getter != getter)
|
||||
if (SPROP_GETTER_SCOPE(sprop, scope) != getter)
|
||||
continue;
|
||||
if ((uintN)JSVAL_TO_INT(sprop->id) == slot)
|
||||
return sym_atom(sprop->symbols);
|
||||
|
@ -2128,7 +2128,7 @@ js_DecompileFunctionBody(JSPrinter *jp, JSFunction *fun)
|
|||
js_printf(jp, native_code_str);
|
||||
return JS_TRUE;
|
||||
}
|
||||
scope = fun->object ? (JSScope *)fun->object->map : NULL;
|
||||
scope = fun->object ? OBJ_SCOPE(fun->object) : NULL;
|
||||
save = jp->scope;
|
||||
jp->scope = scope;
|
||||
ok = js_DecompileCode(jp, script, script->code, (uintN)script->length);
|
||||
|
@ -2171,10 +2171,10 @@ js_DecompileFunction(JSPrinter *jp, JSFunction *fun)
|
|||
for (i = 0; ; i++) {
|
||||
jsid id;
|
||||
atom = NULL;
|
||||
scope = (JSScope *)fun->object->map;
|
||||
scope = OBJ_SCOPE(fun->object);
|
||||
for (sprop = scope->props; sprop; sprop = snext) {
|
||||
snext = sprop->next;
|
||||
if (sprop->getter != js_GetArgument)
|
||||
if (SPROP_GETTER_SCOPE(sprop, scope) != js_GetArgument)
|
||||
continue;
|
||||
if (JSVAL_IS_INT(sprop->id) && JSVAL_TO_INT(sprop->id) == i) {
|
||||
atom = sym_atom(sprop->symbols);
|
||||
|
|
163
js/src/jsparse.c
163
js/src/jsparse.c
|
@ -110,21 +110,18 @@ static JSMemberParser MemberExpr;
|
|||
static JSParser PrimaryExpr;
|
||||
|
||||
/*
|
||||
* Insist that the next token be of type tt, or report err and throw or fail.
|
||||
* Insist that the next token be of type tt, or report errno and return null.
|
||||
* NB: this macro uses cx and ts from its lexical environment.
|
||||
*/
|
||||
|
||||
#define MUST_MATCH_TOKEN_THROW(tt, errno, throw) \
|
||||
#define MUST_MATCH_TOKEN(tt, errno) \
|
||||
JS_BEGIN_MACRO \
|
||||
if (js_GetToken(cx, ts) != tt) { \
|
||||
js_ReportCompileErrorNumber(cx, ts, JSREPORT_ERROR, errno); \
|
||||
throw; \
|
||||
return NULL; \
|
||||
} \
|
||||
JS_END_MACRO
|
||||
|
||||
#define MUST_MATCH_TOKEN(tt, errno) \
|
||||
MUST_MATCH_TOKEN_THROW(tt, errno, return NULL)
|
||||
|
||||
|
||||
/*
|
||||
* Allocate a JSParseNode from cx's temporary arena.
|
||||
|
@ -447,9 +444,12 @@ FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
|
|||
JSParseNode *pn, *pn2;
|
||||
JSOp op;
|
||||
JSAtom *funAtom, *argAtom;
|
||||
JSObject *parent;
|
||||
JSFunction *fun, *outerFun;
|
||||
JSBool ok, named;
|
||||
JSObject *parent;
|
||||
JSPropertyOp getter, setter;
|
||||
uintN attrs;
|
||||
JSBool named;
|
||||
jsval fval;
|
||||
JSObject *pobj;
|
||||
JSScopeProperty *sprop;
|
||||
JSTreeContext funtc;
|
||||
|
@ -471,74 +471,55 @@ FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
|
|||
if (!parent)
|
||||
return NULL;
|
||||
|
||||
/* Set up for ultimate OBJ_DEFINE_PROPERTY call, if not anonymous. */
|
||||
named = !lambda && funAtom && !InWithStatement(tc);
|
||||
getter = setter = NULL;
|
||||
attrs = JSPROP_ENUMERATE;
|
||||
|
||||
fun = js_NewFunction(cx, NULL, NULL, 0, 0, parent, funAtom);
|
||||
if (!fun)
|
||||
return NULL;
|
||||
|
||||
#if JS_HAS_GETTER_SETTER
|
||||
if (op != JSOP_NOP) {
|
||||
JSPropertyOp getter, setter;
|
||||
uintN attr;
|
||||
uintN gsattr;
|
||||
|
||||
fun = js_NewFunction(cx, NULL, NULL, 0, 0, parent, funAtom);
|
||||
if (!fun)
|
||||
return NULL;
|
||||
if (op == JSOP_GETTER) {
|
||||
getter = (JSPropertyOp) fun->object;
|
||||
setter = NULL;
|
||||
attr = JSPROP_GETTER;
|
||||
gsattr = JSPROP_GETTER;
|
||||
} else {
|
||||
getter = NULL;
|
||||
setter = (JSPropertyOp) fun->object;
|
||||
attr = JSPROP_SETTER;
|
||||
gsattr = JSPROP_SETTER;
|
||||
}
|
||||
fun->flags |= attr;
|
||||
fun->flags |= gsattr;
|
||||
attrs |= gsattr;
|
||||
|
||||
if (!lambda && funAtom && !InWithStatement(tc)) {
|
||||
if (!OBJ_DEFINE_PROPERTY(cx, parent, (jsid)funAtom, JSVAL_VOID,
|
||||
getter, setter, attr | JSPROP_ENUMERATE,
|
||||
NULL)) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
#if JS_HAS_LEXICAL_CLOSURE
|
||||
if (lambda || !funAtom || InWithStatement(tc)) {
|
||||
/* Don't name the function if enclosed by a with statement or equiv. */
|
||||
fun = js_NewFunction(cx, NULL, NULL, 0, 0, cx->fp->scopeChain,
|
||||
funAtom);
|
||||
named = JS_FALSE;
|
||||
fval = JSVAL_VOID;
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
/* Don't add the function to it's parent until the parse succeeds. */
|
||||
fun = js_NewFunction(cx, NULL, NULL, 0, 0, parent, funAtom);
|
||||
named = (fun != NULL);
|
||||
}
|
||||
if (!fun) {
|
||||
ok = JS_FALSE;
|
||||
goto out;
|
||||
fval = OBJECT_TO_JSVAL(fun->object);
|
||||
}
|
||||
|
||||
/* Now parse formal argument list and compute fun->nargs. */
|
||||
MUST_MATCH_TOKEN_THROW(TOK_LP, JSMSG_PAREN_BEFORE_FORMAL,
|
||||
ok = JS_FALSE; goto out);
|
||||
MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_FORMAL);
|
||||
if (!js_MatchToken(cx, ts, TOK_RP)) {
|
||||
do {
|
||||
MUST_MATCH_TOKEN_THROW(TOK_NAME, JSMSG_MISSING_FORMAL,
|
||||
ok = JS_FALSE; goto out);
|
||||
MUST_MATCH_TOKEN(TOK_NAME, JSMSG_MISSING_FORMAL);
|
||||
argAtom = CURRENT_TOKEN(ts).t_atom;
|
||||
pobj = NULL;
|
||||
ok = js_LookupProperty(cx, fun->object, (jsid)argAtom, &pobj,
|
||||
(JSProperty **)&sprop);
|
||||
if (!ok)
|
||||
goto out;
|
||||
if (!js_LookupProperty(cx, fun->object, (jsid)argAtom, &pobj,
|
||||
(JSProperty **)&sprop)) {
|
||||
return NULL;
|
||||
}
|
||||
if (sprop && pobj == fun->object) {
|
||||
if (sprop->getter == js_GetArgument) {
|
||||
if (SPROP_GETTER(sprop, pobj) == js_GetArgument) {
|
||||
#ifdef CHECK_ARGUMENT_HIDING
|
||||
OBJ_DROP_PROPERTY(cx, pobj, (JSProperty *)sprop);
|
||||
js_ReportCompileErrorNumber(cx, ts, JSREPORT_WARNING,
|
||||
JSMSG_DUPLICATE_FORMAL,
|
||||
ATOM_BYTES(argAtom));
|
||||
ok = JS_FALSE;
|
||||
goto out;
|
||||
return NULL;
|
||||
#else
|
||||
/*
|
||||
* A duplicate parameter name. We create a dummy symbol
|
||||
|
@ -549,13 +530,13 @@ FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
|
|||
jsid oldArgId = (jsid) sprop->id;
|
||||
OBJ_DROP_PROPERTY(cx, pobj, (JSProperty *)sprop);
|
||||
sprop = NULL;
|
||||
ok = js_DefineProperty(cx, fun->object,
|
||||
if (!js_DefineProperty(cx, fun->object,
|
||||
oldArgId, JSVAL_VOID,
|
||||
js_GetArgument, js_SetArgument,
|
||||
JSPROP_ENUMERATE | JSPROP_PERMANENT,
|
||||
(JSProperty **)&sprop);
|
||||
if (!ok)
|
||||
goto out;
|
||||
(JSProperty **)&sprop)) {
|
||||
return NULL;
|
||||
}
|
||||
sprop->id = (jsid) argAtom;
|
||||
#endif
|
||||
}
|
||||
|
@ -564,35 +545,30 @@ FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
|
|||
OBJ_DROP_PROPERTY(cx, pobj, (JSProperty *)sprop);
|
||||
sprop = NULL;
|
||||
}
|
||||
ok = js_DefineProperty(cx, fun->object,
|
||||
if (!js_DefineProperty(cx, fun->object,
|
||||
(jsid)argAtom, JSVAL_VOID,
|
||||
js_GetArgument, js_SetArgument,
|
||||
JSPROP_ENUMERATE | JSPROP_PERMANENT,
|
||||
(JSProperty **)&sprop);
|
||||
if (!ok)
|
||||
goto out;
|
||||
(JSProperty **)&sprop)) {
|
||||
return NULL;
|
||||
}
|
||||
JS_ASSERT(sprop);
|
||||
sprop->id = INT_TO_JSVAL(fun->nargs++);
|
||||
OBJ_DROP_PROPERTY(cx, fun->object, (JSProperty *)sprop);
|
||||
} while (js_MatchToken(cx, ts, TOK_COMMA));
|
||||
|
||||
MUST_MATCH_TOKEN_THROW(TOK_RP, JSMSG_PAREN_AFTER_FORMAL,
|
||||
ok = JS_FALSE; goto out);
|
||||
MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_FORMAL);
|
||||
}
|
||||
|
||||
MUST_MATCH_TOKEN_THROW(TOK_LC, JSMSG_CURLY_BEFORE_BODY,
|
||||
ok = JS_FALSE; goto out);
|
||||
MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_BODY);
|
||||
pn->pn_pos.begin = CURRENT_TOKEN(ts).pos.begin;
|
||||
|
||||
TREE_CONTEXT_INIT(&funtc);
|
||||
pn2 = FunctionBody(cx, ts, fun, &funtc);
|
||||
if (!pn2) {
|
||||
ok = JS_FALSE;
|
||||
goto out;
|
||||
}
|
||||
if (!pn2)
|
||||
return NULL;
|
||||
|
||||
MUST_MATCH_TOKEN_THROW(TOK_RC, JSMSG_CURLY_AFTER_BODY,
|
||||
ok = JS_FALSE; goto out);
|
||||
MUST_MATCH_TOKEN(TOK_RC, JSMSG_CURLY_AFTER_BODY);
|
||||
pn->pn_pos.end = CURRENT_TOKEN(ts).pos.end;
|
||||
|
||||
pn->pn_fun = fun;
|
||||
|
@ -608,15 +584,10 @@ FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
|
|||
#endif
|
||||
pn->pn_op = JSOP_NOP;
|
||||
|
||||
ok = JS_TRUE;
|
||||
if (named)
|
||||
if (!OBJ_DEFINE_PROPERTY(cx, parent, (jsid)funAtom, OBJECT_TO_JSVAL(fun->object),
|
||||
NULL, NULL, JSPROP_ENUMERATE, NULL)) {
|
||||
return NULL;
|
||||
}
|
||||
out:
|
||||
if (!ok) {
|
||||
return NULL;
|
||||
if (named &&
|
||||
!OBJ_DEFINE_PROPERTY(cx, parent, (jsid)funAtom, fval, getter, setter,
|
||||
attrs, NULL)) {
|
||||
return NULL;
|
||||
}
|
||||
return pn;
|
||||
}
|
||||
|
@ -1085,8 +1056,8 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
|||
/*
|
||||
* We can be sure that if it's a for/in loop, there's still an 'in'
|
||||
* keyword here, even if Javascript recognizes it as an operator,
|
||||
* because we've excluded it from parsing by setting the
|
||||
* TCF_IN_FOR_INIT flag on the JSTreeContext argument.
|
||||
* because we've excluded it from being parsed in RelExpr by setting
|
||||
* the TCF_IN_FOR_INIT flag in our JSTreeContext.
|
||||
*/
|
||||
if (pn1 && js_MatchToken(cx, ts, TOK_IN)) {
|
||||
stmtInfo.type = STMT_FOR_IN_LOOP;
|
||||
|
@ -1589,8 +1560,9 @@ Variables(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
|||
if (pobj == obj &&
|
||||
OBJ_IS_NATIVE(pobj) &&
|
||||
(sprop = (JSScopeProperty *)prop) != NULL) {
|
||||
if (sprop->getter == js_GetArgument) {
|
||||
currentGetter = sprop->getter;
|
||||
if (SPROP_GETTER(sprop, pobj) == js_GetArgument) {
|
||||
currentGetter = js_GetArgument;
|
||||
currentSetter = js_SetArgument;
|
||||
#ifdef CHECK_ARGUMENT_HIDING
|
||||
js_ReportCompileErrorNumber(cx, ts, JSREPORT_WARNING,
|
||||
JSMSG_VAR_HIDES_ARG,
|
||||
|
@ -1604,11 +1576,11 @@ Variables(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
|||
if (fun) {
|
||||
/* Not an argument, must be a redeclared local var. */
|
||||
if (clasp == &js_FunctionClass) {
|
||||
JS_ASSERT(sprop->getter == js_GetLocalVariable);
|
||||
JS_ASSERT(SPROP_GETTER(sprop,pobj) == js_GetLocalVariable);
|
||||
JS_ASSERT(JSVAL_IS_INT(sprop->id) &&
|
||||
JSVAL_TO_INT(sprop->id) < fun->nvars);
|
||||
} else if (clasp == &js_CallClass) {
|
||||
if (sprop->getter == js_GetCallVariable) {
|
||||
if (SPROP_GETTER(sprop, pobj) == js_GetCallVariable) {
|
||||
/*
|
||||
* Referencing a variable introduced by a var
|
||||
* statement in the enclosing function. Check
|
||||
|
@ -1622,16 +1594,16 @@ Variables(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
|||
* don't use the special getters and setters
|
||||
* since we can't allocate a slot in the frame.
|
||||
*/
|
||||
currentGetter = sprop->getter;
|
||||
currentSetter = sprop->setter;
|
||||
currentGetter = SPROP_GETTER(sprop, pobj);
|
||||
currentSetter = SPROP_SETTER(sprop, pobj);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* Global var: (re-)set id a la js_DefineProperty. */
|
||||
sprop->id = ATOM_KEY(atom);
|
||||
}
|
||||
sprop->getter = currentGetter;
|
||||
sprop->setter = currentSetter;
|
||||
SPROP_GETTER(sprop, pobj) = currentGetter;
|
||||
SPROP_SETTER(sprop, pobj) = currentSetter;
|
||||
sprop->attrs |= JSPROP_ENUMERATE | JSPROP_PERMANENT;
|
||||
sprop->attrs &= ~JSPROP_READONLY;
|
||||
}
|
||||
|
@ -1684,8 +1656,9 @@ Variables(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
|||
}
|
||||
}
|
||||
|
||||
if (ok && fun && (clasp == &js_FunctionClass ||
|
||||
clasp == &js_CallClass) &&
|
||||
if (ok &&
|
||||
fun &&
|
||||
(clasp == &js_FunctionClass || clasp == &js_CallClass) &&
|
||||
!InWithStatement(tc))
|
||||
{
|
||||
/* Depending on the value of the getter, change the
|
||||
|
@ -1764,11 +1737,13 @@ LookupArgOrVar(JSContext *cx, JSAtom *atom, JSTreeContext *tc,
|
|||
return JS_FALSE;
|
||||
*slotp = -1;
|
||||
if (sprop) {
|
||||
if (sprop->getter == js_GetArgument) {
|
||||
JSPropertyOp getter = SPROP_GETTER(sprop, pobj);
|
||||
|
||||
if (getter == js_GetArgument) {
|
||||
*opp = JSOP_GETARG;
|
||||
*slotp = JSVAL_TO_INT(sprop->id);
|
||||
} else if (sprop->getter == js_GetLocalVariable ||
|
||||
sprop->getter == js_GetCallVariable)
|
||||
} else if (getter == js_GetLocalVariable ||
|
||||
getter == js_GetCallVariable)
|
||||
{
|
||||
*opp = JSOP_GETVAR;
|
||||
*slotp = JSVAL_TO_INT(sprop->id);
|
||||
|
@ -1966,7 +1941,7 @@ RelExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
|||
(js_MatchToken(cx, ts, TOK_RELOP)
|
||||
#if JS_HAS_IN_OPERATOR
|
||||
/*
|
||||
* Only recognize the 'in' token as an operator if we're not
|
||||
* Recognize the 'in' token as an operator only if we're not
|
||||
* currently in the init expr of a for loop.
|
||||
*/
|
||||
|| (inForInitFlag == 0 && js_MatchToken(cx, ts, TOK_IN))
|
||||
|
|
|
@ -367,7 +367,7 @@ js_GetMutableScope(JSContext *cx, JSObject *obj)
|
|||
{
|
||||
JSScope *scope, *newscope;
|
||||
|
||||
scope = (JSScope *) obj->map;
|
||||
scope = OBJ_SCOPE(obj);
|
||||
JS_ASSERT(JS_IS_SCOPE_LOCKED(scope));
|
||||
if (scope->object == obj)
|
||||
return scope;
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
#include "jsprvtd.h"
|
||||
#include "jspubtd.h"
|
||||
|
||||
#ifndef JS_DOUBLE_HASHING
|
||||
struct JSScopeOps {
|
||||
JSSymbol * (*lookup)(JSContext *cx, JSScope *scope, jsid id,
|
||||
JSHashNumber hash);
|
||||
|
@ -51,16 +52,24 @@ struct JSScopeOps {
|
|||
JSBool (*remove)(JSContext *cx, JSScope *scope, jsid id);
|
||||
void (*clear)(JSContext *cx, JSScope *scope);
|
||||
};
|
||||
#endif
|
||||
|
||||
struct JSScope {
|
||||
JSObjectMap map; /* base class state */
|
||||
JSObject *object; /* object that owns this scope */
|
||||
JSScopeProperty *props; /* property list in definition order */
|
||||
JSScopeProperty **proptail; /* pointer to pointer to last prop */
|
||||
#ifdef JS_DOUBLE_HASHING
|
||||
uint32 tableLength;
|
||||
JSScopeProperty *table;
|
||||
uint32 gsTableLength; /* number of entries in gsTable */
|
||||
JSPropertyOp gsTable[1]; /* actually, gsTableLength ops */
|
||||
#else
|
||||
JSScopeOps *ops; /* virtual operations */
|
||||
void *data; /* private data specific to ops */
|
||||
#endif
|
||||
#ifdef JS_THREADSAFE
|
||||
JSThinLock lock; /* binary semaphore protecting scope */
|
||||
JSThinLock lock; /* binary semaphore protecting scope */
|
||||
int32 count; /* entry count for reentrancy */
|
||||
#ifdef DEBUG
|
||||
const char *file[4]; /* file where lock was (re-)taken */
|
||||
|
@ -69,6 +78,27 @@ struct JSScope {
|
|||
#endif
|
||||
};
|
||||
|
||||
#define OBJ_SCOPE(obj) ((JSScope *)(obj)->map)
|
||||
#define SPROP_GETTER(sprop,obj) SPROP_GETTER_SCOPE(sprop, OBJ_SCOPE(obj))
|
||||
#define SPROP_SETTER(sprop,obj) SPROP_SETTER_SCOPE(sprop, OBJ_SCOPE(obj))
|
||||
|
||||
#ifdef JS_DOUBLE_HASHING
|
||||
|
||||
struct JSScopeProperty {
|
||||
jsid id;
|
||||
uint32 slot; /* index in obj->slots vector */
|
||||
uint8 attrs; /* attributes, see jsapi.h JSPROP_ */
|
||||
uint8 getterIndex; /* getter and setter method indexes */
|
||||
uint8 setterIndex; /* in JSScope.gsTable[] */
|
||||
uint8 reserved;
|
||||
JSScopeProperty *next; /* singly-linked list linkage */
|
||||
};
|
||||
|
||||
#define SPROP_GETTER_SCOPE(sprop,scope) ((scope)->gsTable[(sprop)->getterIndex])
|
||||
#define SPROP_SETTER_SCOPE(sprop,scope) ((scope)->gsTable[(sprop)->setterIndex])
|
||||
|
||||
#else /* !JS_DOUBLE_HASHING */
|
||||
|
||||
struct JSSymbol {
|
||||
JSHashEntry entry; /* base class state */
|
||||
JSScope *scope; /* pointer to owning scope */
|
||||
|
@ -92,21 +122,28 @@ struct JSScopeProperty {
|
|||
JSScopeProperty **prevp;
|
||||
};
|
||||
|
||||
#define SPROP_GETTER_SCOPE(sprop,scope) ((sprop)->getter)
|
||||
#define SPROP_SETTER_SCOPE(sprop,scope) ((sprop)->setter)
|
||||
|
||||
#endif /* !JS_DOUBLE_HASHING */
|
||||
|
||||
/*
|
||||
* These macros are designed to decouple getter and setter from sprop, by
|
||||
* passing obj2 (in whose scope sprop lives, and in whose scope getter and
|
||||
* setter might be stored apart from sprop -- say in scope->opTable[i] for
|
||||
* setter might be stored apart from sprop -- say in scope->gsTable[i] for
|
||||
* a compressed getter or setter index i that is stored in sprop).
|
||||
*/
|
||||
#define SPROP_GET(cx,sprop,obj,obj2,vp) \
|
||||
(((sprop)->attrs & JSPROP_GETTER) \
|
||||
? js_InternalCall(cx, obj, OBJECT_TO_JSVAL(sprop->getter), 0, 0, vp) \
|
||||
: (sprop)->getter(cx, OBJ_THIS_OBJECT(cx,obj), sprop->id, vp))
|
||||
? js_InternalCall(cx, obj, OBJECT_TO_JSVAL(SPROP_GETTER(sprop,obj2)), \
|
||||
0, 0, vp) \
|
||||
: SPROP_GETTER(sprop,obj2)(cx, OBJ_THIS_OBJECT(cx,obj), sprop->id, vp))
|
||||
|
||||
#define SPROP_SET(cx,sprop,obj,obj2,vp) \
|
||||
(((sprop)->attrs & JSPROP_SETTER) \
|
||||
? js_InternalCall(cx, obj, OBJECT_TO_JSVAL(sprop->setter), 1, vp, vp) \
|
||||
: (sprop)->setter(cx, OBJ_THIS_OBJECT(cx,obj), sprop->id, vp))
|
||||
? js_InternalCall(cx, obj, OBJECT_TO_JSVAL(SPROP_SETTER(sprop,obj2)), \
|
||||
1, vp, vp) \
|
||||
: SPROP_SETTER(sprop,obj2)(cx, OBJ_THIS_OBJECT(cx,obj), sprop->id, vp))
|
||||
|
||||
extern JSScope *
|
||||
js_GetMutableScope(JSContext *cx, JSObject *obj);
|
||||
|
|
Загрузка…
Ссылка в новой задаче