jsobj.c
来自「一个基于alice开发的机器人」· C语言 代码 · 共 2,081 行 · 第 1/5 页
C
2,081 行
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Communicator client code, released
* March 31, 1998.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1998
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
/*
* JS object implementation.
*/
#include "jsstddef.h"
#include <stdlib.h>
#include <string.h>
#include "jstypes.h"
#include "jsarena.h" /* Added by JSIFY */
#include "jsutil.h" /* Added by JSIFY */
#include "jshash.h" /* Added by JSIFY */
#include "jsdhash.h"
#include "jsprf.h"
#include "jsapi.h"
#include "jsarray.h"
#include "jsatom.h"
#include "jsbool.h"
#include "jscntxt.h"
#include "jsconfig.h"
#include "jsfun.h"
#include "jsgc.h"
#include "jsinterp.h"
#include "jslock.h"
#include "jsnum.h"
#include "jsobj.h"
#include "jsscope.h"
#include "jsscript.h"
#include "jsstr.h"
#include "jsopcode.h"
#include "jsdbgapi.h" /* whether or not JS_HAS_OBJ_WATCHPOINT */
#ifdef JS_THREADSAFE
#define NATIVE_DROP_PROPERTY js_DropProperty
extern void
js_DropProperty(JSContext *cx, JSObject *obj, JSProperty *prop);
#else
#define NATIVE_DROP_PROPERTY NULL
#endif
#ifdef XP_MAC
#pragma export on
#endif
JS_FRIEND_DATA(JSObjectOps) js_ObjectOps = {
js_NewObjectMap, js_DestroyObjectMap,
#if defined JS_THREADSAFE && defined DEBUG
_js_LookupProperty, js_DefineProperty,
#else
js_LookupProperty, js_DefineProperty,
#endif
js_GetProperty, js_SetProperty,
js_GetAttributes, js_SetAttributes,
js_DeleteProperty, js_DefaultValue,
js_Enumerate, js_CheckAccess,
NULL, NATIVE_DROP_PROPERTY,
js_Call, js_Construct,
NULL, js_HasInstance,
js_SetProtoOrParent, js_SetProtoOrParent,
js_Mark, js_Clear,
js_GetRequiredSlot, js_SetRequiredSlot
};
#ifdef XP_MAC
#pragma export off
#endif
JSClass js_ObjectClass = {
js_Object_str,
0,
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub,
JSCLASS_NO_OPTIONAL_MEMBERS
};
#if JS_HAS_OBJ_PROTO_PROP
static JSBool
obj_getSlot(JSContext *cx, JSObject *obj, jsval id, jsval *vp);
static JSBool
obj_setSlot(JSContext *cx, JSObject *obj, jsval id, jsval *vp);
static JSBool
obj_getCount(JSContext *cx, JSObject *obj, jsval id, jsval *vp);
static JSPropertySpec object_props[] = {
/* These two must come first; see object_props[slot].name usage below. */
{js_proto_str, JSSLOT_PROTO, JSPROP_PERMANENT|JSPROP_SHARED,
obj_getSlot, obj_setSlot},
{js_parent_str,JSSLOT_PARENT,JSPROP_READONLY|JSPROP_PERMANENT|JSPROP_SHARED,
obj_getSlot, obj_setSlot},
{js_count_str, 0, JSPROP_PERMANENT,obj_getCount, obj_getCount},
{0,0,0,0,0}
};
/* NB: JSSLOT_PROTO and JSSLOT_PARENT are already indexes into object_props. */
#define JSSLOT_COUNT 2
static JSBool
ReportStrictSlot(JSContext *cx, uint32 slot)
{
if (slot == JSSLOT_PROTO)
return JS_TRUE;
return JS_ReportErrorFlagsAndNumber(cx,
JSREPORT_WARNING | JSREPORT_STRICT,
js_GetErrorMessage, NULL,
JSMSG_DEPRECATED_USAGE,
object_props[slot].name);
}
static JSBool
obj_getSlot(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
{
uint32 slot;
JSAccessMode mode;
uintN attrs;
slot = (uint32) JSVAL_TO_INT(id);
if (JS_HAS_STRICT_OPTION(cx) && !ReportStrictSlot(cx, slot))
return JS_FALSE;
if (id == INT_TO_JSVAL(JSSLOT_PROTO)) {
id = (jsid)cx->runtime->atomState.protoAtom;
mode = JSACC_PROTO;
} else {
id = (jsid)cx->runtime->atomState.parentAtom;
mode = JSACC_PARENT;
}
if (!OBJ_CHECK_ACCESS(cx, obj, id, mode, vp, &attrs))
return JS_FALSE;
*vp = OBJ_GET_SLOT(cx, obj, slot);
return JS_TRUE;
}
static JSBool
obj_setSlot(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
{
JSObject *pobj;
uint32 slot;
uintN attrs;
if (!JSVAL_IS_OBJECT(*vp))
return JS_TRUE;
pobj = JSVAL_TO_OBJECT(*vp);
slot = (uint32) JSVAL_TO_INT(id);
if (JS_HAS_STRICT_OPTION(cx) && !ReportStrictSlot(cx, slot))
return JS_FALSE;
/* __parent__ is readonly and permanent, only __proto__ may be set. */
if (!OBJ_CHECK_ACCESS(cx, obj, id, JSACC_PROTO | JSACC_WRITE, vp, &attrs))
return JS_FALSE;
return js_SetProtoOrParent(cx, obj, slot, pobj);
}
static JSBool
obj_getCount(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
{
jsval iter_state;
jsid num_properties;
JSBool ok;
if (JS_HAS_STRICT_OPTION(cx) && !ReportStrictSlot(cx, JSSLOT_COUNT))
return JS_FALSE;
/* Get the number of properties to enumerate. */
iter_state = JSVAL_NULL;
ok = OBJ_ENUMERATE(cx, obj, JSENUMERATE_INIT, &iter_state, &num_properties);
if (!ok)
goto out;
if (!JSVAL_IS_INT(num_properties)) {
JS_ASSERT(0);
*vp = JSVAL_ZERO;
goto out;
}
*vp = num_properties;
out:
if (iter_state != JSVAL_NULL)
ok = OBJ_ENUMERATE(cx, obj, JSENUMERATE_DESTROY, &iter_state, 0);
return ok;
}
#else /* !JS_HAS_OBJ_PROTO_PROP */
#define object_props NULL
#endif /* !JS_HAS_OBJ_PROTO_PROP */
JSBool
js_SetProtoOrParent(JSContext *cx, JSObject *obj, uint32 slot, JSObject *pobj)
{
JSRuntime *rt;
JSObject *obj2, *oldproto;
JSScope *scope, *newscope;
/*
* Serialize all proto and parent setting in order to detect cycles.
* We nest locks in this function, and only here, in the following orders:
*
* (1) rt->setSlotLock < pobj's scope lock;
* rt->setSlotLock < pobj's proto-or-parent's scope lock;
* rt->setSlotLock < pobj's grand-proto-or-parent's scope lock;
* etc...
* (2) rt->setSlotLock < obj's scope lock < pobj's scope lock.
*
* We avoid AB-BA deadlock by restricting obj from being on pobj's parent
* or proto chain (pobj may already be on obj's parent or proto chain; it
* could be moving up or down). We finally order obj with respect to pobj
* at the bottom of this routine (just before releasing rt->setSlotLock),
* by making pobj be obj's prototype or parent.
*
* After we have set the slot and released rt->setSlotLock, another call
* to js_SetProtoOrParent could nest locks according to the first order
* list above, but it cannot deadlock with any other thread. For there
* to be a deadlock, other parts of the engine would have to nest scope
* locks in the opposite order. XXXbe ensure they don't!
*/
rt = cx->runtime;
#ifdef JS_THREADSAFE
JS_ACQUIRE_LOCK(rt->setSlotLock);
while (rt->setSlotBusy) {
jsrefcount saveDepth;
/* Take pains to avoid nesting rt->gcLock inside rt->setSlotLock! */
JS_RELEASE_LOCK(rt->setSlotLock);
saveDepth = JS_SuspendRequest(cx);
JS_ACQUIRE_LOCK(rt->setSlotLock);
if (rt->setSlotBusy)
JS_WAIT_CONDVAR(rt->setSlotDone, JS_NO_TIMEOUT);
JS_RELEASE_LOCK(rt->setSlotLock);
JS_ResumeRequest(cx, saveDepth);
JS_ACQUIRE_LOCK(rt->setSlotLock);
}
rt->setSlotBusy = JS_TRUE;
JS_RELEASE_LOCK(rt->setSlotLock);
#define SET_SLOT_DONE(rt) \
JS_BEGIN_MACRO \
JS_ACQUIRE_LOCK((rt)->setSlotLock); \
(rt)->setSlotBusy = JS_FALSE; \
JS_NOTIFY_ALL_CONDVAR((rt)->setSlotDone); \
JS_RELEASE_LOCK((rt)->setSlotLock); \
JS_END_MACRO
#else
#define SET_SLOT_DONE(rt) /* nothing */
#endif
obj2 = pobj;
while (obj2) {
if (obj2 == obj) {
SET_SLOT_DONE(rt);
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
JSMSG_CYCLIC_VALUE,
#if JS_HAS_OBJ_PROTO_PROP
object_props[slot].name
#else
(slot == JSSLOT_PROTO) ? js_proto_str
: js_parent_str
#endif
);
return JS_FALSE;
}
obj2 = JSVAL_TO_OBJECT(OBJ_GET_SLOT(cx, obj2, slot));
}
if (slot == JSSLOT_PROTO && OBJ_IS_NATIVE(obj)) {
/* Check to see whether obj shares its prototype's scope. */
JS_LOCK_OBJ(cx, obj);
scope = OBJ_SCOPE(obj);
oldproto = JSVAL_TO_OBJECT(LOCKED_OBJ_GET_SLOT(obj, JSSLOT_PROTO));
if (oldproto && OBJ_SCOPE(oldproto) == scope) {
/* Either obj needs a new empty scope, or it should share pobj's. */
if (!pobj ||
!OBJ_IS_NATIVE(pobj) ||
OBJ_GET_CLASS(cx, pobj) != LOCKED_OBJ_GET_CLASS(oldproto)) {
/*
* With no proto and no scope of its own, obj is truly empty.
*
* If pobj is not native, obj needs its own empty scope -- it
* should not continue to share oldproto's scope once oldproto
* is not on obj's prototype chain. That would put properties
* from oldproto's scope ahead of properties defined by pobj,
* in lookup order.
*
* If pobj's class differs from oldproto's, we may need a new
* scope to handle differences in private and reserved slots,
* so we suboptimally but safely make one.
*/
scope = js_GetMutableScope(cx, obj);
if (!scope) {
JS_UNLOCK_OBJ(cx, obj);
SET_SLOT_DONE(rt);
return JS_FALSE;
}
} else if (OBJ_SCOPE(pobj) != scope) {
#ifdef JS_THREADSAFE
/*
* We are about to nest scope locks. Help jslock.c:ShareScope
* keep scope->u.count balanced for the JS_UNLOCK_SCOPE, while
* avoiding deadlock, by recording scope in rt->setSlotScope.
*/
if (scope->ownercx) {
JS_ASSERT(scope->ownercx == cx);
rt->setSlotScope = scope;
}
#endif
/* We can't deadlock because we checked for cycles above (2). */
JS_LOCK_OBJ(cx, pobj);
newscope = (JSScope *) js_HoldObjectMap(cx, pobj->map);
obj->map = &newscope->map;
js_DropObjectMap(cx, &scope->map, obj);
JS_TRANSFER_SCOPE_LOCK(cx, scope, newscope);
scope = newscope;
#ifdef JS_THREADSAFE
rt->setSlotScope = NULL;
#endif
}
}
LOCKED_OBJ_SET_SLOT(obj, JSSLOT_PROTO, OBJECT_TO_JSVAL(pobj));
JS_UNLOCK_SCOPE(cx, scope);
} else {
OBJ_SET_SLOT(cx, obj, slot, OBJECT_TO_JSVAL(pobj));
}
SET_SLOT_DONE(rt);
return JS_TRUE;
#undef SET_SLOT_DONE
}
JS_STATIC_DLL_CALLBACK(JSHashNumber)
js_hash_object(const void *key)
{
return (JSHashNumber)key >> JSVAL_TAGBITS;
}
static JSHashEntry *
MarkSharpObjects(JSContext *cx, JSObject *obj, JSIdArray **idap)
{
JSSharpObjectMap *map;
JSHashTable *table;
JSHashNumber hash;
JSHashEntry **hep, *he;
jsatomid sharpid;
JSIdArray *ida;
JSBool ok;
jsint i, length;
jsid id;
#if JS_HAS_GETTER_SETTER
JSObject *obj2;
JSProperty *prop;
uintN attrs;
#endif
jsval val;
map = &cx->sharpObjectMap;
table = map->table;
hash = js_hash_object(obj);
hep = JS_HashTableRawLookup(table, hash, obj);
he = *hep;
if (!he) {
sharpid = 0;
he = JS_HashTableRawAdd(table, hep, hash, obj, (void *)sharpid);
if (!he) {
JS_ReportOutOfMemory(cx);
return NULL;
}
ida = JS_Enumerate(cx, obj);
if (!ida)
return NULL;
ok = JS_TRUE;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?