mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-20 16:55:40 +00:00
Eliminate JSClass::reserveSlots and streamline new-object paths (535416, r=gal).
This commit is contained in:
parent
1ddbd48078
commit
b73234dea0
@ -1415,7 +1415,7 @@ struct JSClass {
|
||||
JSXDRObjectOp xdrObject;
|
||||
JSHasInstanceOp hasInstance;
|
||||
JSMarkOp mark;
|
||||
JSReserveSlotsOp reserveSlots;
|
||||
void (*reserved0)(void);
|
||||
};
|
||||
|
||||
struct JSExtendedClass {
|
||||
|
@ -3068,6 +3068,12 @@ static JSFunctionSpec array_static_methods[] = {
|
||||
JS_FS_END
|
||||
};
|
||||
|
||||
static inline JSObject *
|
||||
NewDenseArrayObject(JSContext *cx)
|
||||
{
|
||||
return NewObject(cx, &js_ArrayClass, NULL, NULL);
|
||||
}
|
||||
|
||||
JSBool
|
||||
js_Array(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
||||
{
|
||||
@ -3076,7 +3082,7 @@ js_Array(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
||||
|
||||
/* If called without new, replace obj with a new Array object. */
|
||||
if (!JS_IsConstructing(cx)) {
|
||||
obj = NewObject(cx, &js_ArrayClass, NULL, NULL);
|
||||
obj = NewDenseArrayObject(cx);
|
||||
if (!obj)
|
||||
return JS_FALSE;
|
||||
*rval = OBJECT_TO_JSVAL(obj);
|
||||
@ -3168,7 +3174,7 @@ js_InitArrayClass(JSContext *cx, JSObject *obj)
|
||||
JSObject *
|
||||
js_NewArrayObject(JSContext *cx, jsuint length, const jsval *vector, bool holey)
|
||||
{
|
||||
JSObject *obj = NewObject(cx, &js_ArrayClass, NULL, NULL);
|
||||
JSObject *obj = NewDenseArrayObject(cx);
|
||||
if (!obj)
|
||||
return NULL;
|
||||
|
||||
|
@ -216,7 +216,7 @@ AddPropertyHelper(JSContext* cx, JSObject* obj, JSScopeProperty* sprop, bool isD
|
||||
}
|
||||
|
||||
if (!scope->table) {
|
||||
if (slot < obj->numSlots() && !obj->getClass()->reserveSlots) {
|
||||
if (slot < obj->numSlots()) {
|
||||
JS_ASSERT(JSVAL_IS_VOID(obj->getSlot(scope->freeslot)));
|
||||
++scope->freeslot;
|
||||
} else {
|
||||
|
@ -1413,9 +1413,16 @@ struct JSRuntime {
|
||||
/* Literal table maintained by jsatom.c functions. */
|
||||
JSAtomState atomState;
|
||||
|
||||
/*
|
||||
* Runtime-shared empty scopes for well-known built-in objects that lack
|
||||
* class prototypes (the usual locus of an emptyScope). Mnemonic: ABCDEW
|
||||
*/
|
||||
JSEmptyScope *emptyArgumentsScope;
|
||||
JSEmptyScope *emptyBlockScope;
|
||||
JSEmptyScope *emptyCallScope;
|
||||
JSEmptyScope *emptyDeclEnvScope;
|
||||
JSEmptyScope *emptyEnumeratorScope;
|
||||
JSEmptyScope *emptyWithScope;
|
||||
|
||||
/*
|
||||
* Various metering fields are defined at the end of JSRuntime. In this
|
||||
|
@ -2343,7 +2343,7 @@ js_InitDateClass(JSContext *cx, JSObject *obj)
|
||||
JS_FRIEND_API(JSObject *)
|
||||
js_NewDateObjectMsec(JSContext *cx, jsdouble msec_time)
|
||||
{
|
||||
JSObject *obj = NewObject(cx, &js_DateClass, NULL, NULL);
|
||||
JSObject *obj = NewBuiltinClassInstance(cx, &js_DateClass);
|
||||
if (!obj || !SetUTCTime(cx, obj, msec_time))
|
||||
return NULL;
|
||||
return obj;
|
||||
|
@ -65,11 +65,13 @@
|
||||
#include "jsregexp.h"
|
||||
#include "jsscan.h"
|
||||
#include "jsscope.h"
|
||||
#include "jsscopeinlines.h"
|
||||
#include "jsscript.h"
|
||||
#include "jsautooplen.h" // generated headers last
|
||||
#include "jsstaticcheck.h"
|
||||
|
||||
#include "jsobjinlines.h"
|
||||
#include "jsscopeinlines.h"
|
||||
|
||||
/* Allocation chunk counts, must be powers of two in general. */
|
||||
#define BYTECODE_CHUNK 256 /* code allocation increment */
|
||||
#define SRCNOTE_CHUNK 64 /* initial srcnote allocation increment */
|
||||
@ -1845,9 +1847,8 @@ EmitEnterBlock(JSContext *cx, JSParseNode *pn, JSCodeGenerator *cg)
|
||||
if (depth < 0)
|
||||
return false;
|
||||
|
||||
for (uintN slot = JSSLOT_FREE(&js_BlockClass),
|
||||
limit = slot + OBJ_BLOCK_COUNT(cx, blockObj);
|
||||
slot < limit; slot++) {
|
||||
uintN base = JSSLOT_FREE(&js_BlockClass);
|
||||
for (uintN slot = base, limit = base + OBJ_BLOCK_COUNT(cx, blockObj); slot < limit; slot++) {
|
||||
jsval v = blockObj->getSlot(slot);
|
||||
|
||||
/* Beware the empty destructuring dummy. */
|
||||
@ -1869,8 +1870,8 @@ EmitEnterBlock(JSContext *cx, JSParseNode *pn, JSCodeGenerator *cg)
|
||||
#endif
|
||||
}
|
||||
|
||||
blockObj->scope()->freeslot = JSSLOT_FREE(&js_BlockClass);
|
||||
return blockObj->growSlots(cx, JSSLOT_FREE(&js_BlockClass));
|
||||
blockObj->scope()->freeslot = base;
|
||||
return blockObj->growSlots(cx, base);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -695,8 +695,8 @@ Exception(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
||||
* ECMA ed. 3, 15.11.1 requires Error, etc., to construct even when
|
||||
* called as functions, without operator new. But as we do not give
|
||||
* each constructor a distinct JSClass, whose .name member is used by
|
||||
* NewObject to find the class prototype, we must get the class
|
||||
* prototype ourselves.
|
||||
* NewNativeClassInstance to find the class prototype, we must get the
|
||||
* class prototype ourselves.
|
||||
*/
|
||||
if (!JSVAL_TO_OBJECT(argv[-2])->getProperty(cx,
|
||||
ATOM_TO_JSID(cx->runtime->atomState
|
||||
@ -704,7 +704,8 @@ Exception(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
||||
rval)) {
|
||||
return JS_FALSE;
|
||||
}
|
||||
obj = NewObject(cx, &js_ErrorClass, JSVAL_TO_OBJECT(*rval), NULL);
|
||||
JSObject *errProto = JSVAL_TO_OBJECT(*rval);
|
||||
obj = NewNativeClassInstance(cx, &js_ErrorClass, errProto, errProto->getParent());
|
||||
if (!obj)
|
||||
return JS_FALSE;
|
||||
*rval = OBJECT_TO_JSVAL(obj);
|
||||
@ -1159,7 +1160,7 @@ js_ErrorToException(JSContext *cx, const char *message, JSErrorReport *reportp,
|
||||
goto out;
|
||||
tv[0] = OBJECT_TO_JSVAL(errProto);
|
||||
|
||||
errObject = NewObject(cx, &js_ErrorClass, errProto, NULL);
|
||||
errObject = NewNativeClassInstance(cx, &js_ErrorClass, errProto, errProto->getParent());
|
||||
if (!errObject) {
|
||||
ok = JS_FALSE;
|
||||
goto out;
|
||||
|
@ -223,22 +223,8 @@ js_GetArgsObject(JSContext *cx, JSStackFrame *fp)
|
||||
if (argsobj)
|
||||
return argsobj;
|
||||
|
||||
/*
|
||||
* Give arguments an intrinsic scope chain link to fp's global object.
|
||||
* Since the arguments object lacks a prototype because js_ArgumentsClass
|
||||
* is not initialized, NewObject won't assign a default parent to it.
|
||||
*
|
||||
* Therefore if arguments is used as the head of an eval scope chain (via
|
||||
* a direct or indirect call to eval(program, arguments)), any reference
|
||||
* to a standard class object in the program will fail to resolve due to
|
||||
* js_GetClassPrototype not being able to find a global object containing
|
||||
* the standard prototype by starting from arguments and following parent.
|
||||
*/
|
||||
JSObject *global = fp->scopeChain;
|
||||
while (JSObject *parent = global->getParent())
|
||||
global = parent;
|
||||
|
||||
JS_ASSERT(fp->argv);
|
||||
/* Compute the arguments object's parent slot from fp's scope chain. */
|
||||
JSObject *global = fp->scopeChain->getGlobal();
|
||||
argsobj = NewArguments(cx, global, fp->argc, JSVAL_TO_OBJECT(fp->argv[-2]));
|
||||
if (!argsobj)
|
||||
return argsobj;
|
||||
@ -328,6 +314,11 @@ WrapEscapingClosure(JSContext *cx, JSStackFrame *fp, JSObject *funobj, JSFunctio
|
||||
if (!scopeChain)
|
||||
return NULL;
|
||||
|
||||
/*
|
||||
* We must wrap funobj with a JSFunction, so use NewObjectWithGivenProto.
|
||||
* This helper has a special case for js_FunctionClass, triggered here and
|
||||
* also possibly via the JS_NewObjectForGivenProto and JS_NewObject APIs.
|
||||
*/
|
||||
JSObject *wfunobj = NewObjectWithGivenProto(cx, &js_FunctionClass,
|
||||
funobj, scopeChain);
|
||||
if (!wfunobj)
|
||||
@ -674,12 +665,6 @@ args_or_call_trace(JSTracer *trc, JSObject *obj)
|
||||
# define args_or_call_trace NULL
|
||||
#endif
|
||||
|
||||
static uint32
|
||||
args_reserveSlots(JSContext *cx, JSObject *obj)
|
||||
{
|
||||
return obj->getArgsLength();
|
||||
}
|
||||
|
||||
/*
|
||||
* The Arguments class is not initialized via JS_InitClass, and must not be,
|
||||
* because its name is "Object". Per ECMA, that causes instances of it to
|
||||
@ -703,7 +688,7 @@ JSClass js_ArgumentsClass = {
|
||||
NULL, NULL,
|
||||
NULL, NULL,
|
||||
NULL, NULL,
|
||||
JS_CLASS_TRACE(args_or_call_trace), args_reserveSlots
|
||||
JS_CLASS_TRACE(args_or_call_trace), NULL
|
||||
};
|
||||
|
||||
const uint32 JSSLOT_CALLEE = JSSLOT_PRIVATE + 1;
|
||||
@ -775,7 +760,6 @@ NewCallObject(JSContext *cx, JSFunction *fun, JSObject *scopeChain)
|
||||
|
||||
/* Init immediately to avoid GC seeing a half-init'ed object. */
|
||||
callobj->init(&js_CallClass, NULL, scopeChain, JSVAL_NULL);
|
||||
|
||||
callobj->map = cx->runtime->emptyCallScope->hold();
|
||||
|
||||
/* This must come after callobj->map has been set. */
|
||||
@ -784,6 +768,19 @@ NewCallObject(JSContext *cx, JSFunction *fun, JSObject *scopeChain)
|
||||
return callobj;
|
||||
}
|
||||
|
||||
static inline JSObject *
|
||||
NewDeclEnvObject(JSContext *cx, JSStackFrame *fp)
|
||||
{
|
||||
JSObject *envobj = js_NewGCObject(cx);
|
||||
if (!envobj)
|
||||
return NULL;
|
||||
|
||||
/* Init immediately to avoid GC seeing a half-init'ed object. */
|
||||
envobj->init(&js_DeclEnvClass, NULL, fp->scopeChain, reinterpret_cast<jsval>(fp));
|
||||
envobj->map = cx->runtime->emptyDeclEnvScope->hold();
|
||||
return envobj;
|
||||
}
|
||||
|
||||
JSObject *
|
||||
js_GetCallObject(JSContext *cx, JSStackFrame *fp)
|
||||
{
|
||||
@ -812,14 +809,12 @@ js_GetCallObject(JSContext *cx, JSStackFrame *fp)
|
||||
*/
|
||||
JSAtom *lambdaName = (fp->fun->flags & JSFUN_LAMBDA) ? fp->fun->atom : NULL;
|
||||
if (lambdaName) {
|
||||
JSObject *env = NewObjectWithGivenProto(cx, &js_DeclEnvClass, NULL,
|
||||
fp->scopeChain);
|
||||
if (!env)
|
||||
JSObject *envobj = NewDeclEnvObject(cx, fp);
|
||||
if (!envobj)
|
||||
return NULL;
|
||||
env->setPrivate(fp);
|
||||
|
||||
/* Root env before js_DefineNativeProperty (-> JSClass.addProperty). */
|
||||
fp->scopeChain = env;
|
||||
/* Root envobj before js_DefineNativeProperty (-> JSClass.addProperty). */
|
||||
fp->scopeChain = envobj;
|
||||
JS_ASSERT(fp->argv);
|
||||
if (!js_DefineNativeProperty(cx, fp->scopeChain, ATOM_TO_JSID(lambdaName),
|
||||
fp->calleeValue(),
|
||||
@ -1264,15 +1259,6 @@ call_resolve(JSContext *cx, JSObject *obj, jsval idval, uintN flags,
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
static uint32
|
||||
call_reserveSlots(JSContext *cx, JSObject *obj)
|
||||
{
|
||||
JSFunction *fun;
|
||||
|
||||
fun = js_GetCallObjectFunction(obj);
|
||||
return fun->countArgsAndVars();
|
||||
}
|
||||
|
||||
JS_FRIEND_DATA(JSClass) js_CallClass = {
|
||||
"Call",
|
||||
JSCLASS_HAS_PRIVATE |
|
||||
@ -1285,7 +1271,7 @@ JS_FRIEND_DATA(JSClass) js_CallClass = {
|
||||
NULL, NULL,
|
||||
NULL, NULL,
|
||||
NULL, NULL,
|
||||
JS_CLASS_TRACE(args_or_call_trace), call_reserveSlots
|
||||
JS_CLASS_TRACE(args_or_call_trace), NULL
|
||||
};
|
||||
|
||||
/* Generic function tinyids. */
|
||||
@ -1463,10 +1449,14 @@ fun_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags,
|
||||
return JS_TRUE;
|
||||
|
||||
/*
|
||||
* Make the prototype object to have the same parent as the function
|
||||
* object itself.
|
||||
* Make the prototype object an instance of Object with the same parent
|
||||
* as the function object itself.
|
||||
*/
|
||||
JSObject *proto = NewObject(cx, &js_ObjectClass, NULL, obj->getParent());
|
||||
JSObject *parent = obj->getParent();
|
||||
JSObject *proto;
|
||||
if (!js_GetClassPrototype(cx, parent, JSProto_Object, &proto))
|
||||
return JS_FALSE;
|
||||
proto = NewNativeClassInstance(cx, &js_ObjectClass, proto, parent);
|
||||
if (!proto)
|
||||
return JS_FALSE;
|
||||
|
||||
@ -1809,20 +1799,6 @@ JSFunction::countInterpretedReservedSlots() const
|
||||
return (u.i.nupvars == 0) ? 0 : u.i.script->upvars()->length;
|
||||
}
|
||||
|
||||
static uint32
|
||||
fun_reserveSlots(JSContext *cx, JSObject *obj)
|
||||
{
|
||||
/*
|
||||
* We use getPrivate and not GET_FUNCTION_PRIVATE because during
|
||||
* js_InitFunctionClass invocation the function is called before the
|
||||
* private slot of the function object is set.
|
||||
*/
|
||||
JSFunction *fun = (JSFunction *) obj->getPrivate();
|
||||
return (fun && FUN_INTERPRETED(fun))
|
||||
? fun->countInterpretedReservedSlots()
|
||||
: 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reserve two slots in all function objects for XPConnect. Note that this
|
||||
* does not bloat every instance, only those on which reserved slots are set,
|
||||
@ -1839,7 +1815,7 @@ JS_FRIEND_DATA(JSClass) js_FunctionClass = {
|
||||
NULL, NULL,
|
||||
NULL, NULL,
|
||||
js_XDRFunctionObject, fun_hasInstance,
|
||||
JS_CLASS_TRACE(fun_trace), fun_reserveSlots
|
||||
JS_CLASS_TRACE(fun_trace), NULL
|
||||
};
|
||||
|
||||
static JSBool
|
||||
@ -2441,8 +2417,7 @@ js_CloneFunctionObject(JSContext *cx, JSFunction *fun, JSObject *parent,
|
||||
* The cloned function object does not need the extra JSFunction members
|
||||
* beyond JSObject as it points to fun via the private slot.
|
||||
*/
|
||||
JSObject *clone = NewObjectWithGivenProto(cx, &js_FunctionClass, proto,
|
||||
parent, sizeof(JSObject));
|
||||
JSObject *clone = NewNativeClassInstance(cx, &js_FunctionClass, proto, parent);
|
||||
if (!clone)
|
||||
return NULL;
|
||||
clone->setPrivate(fun);
|
||||
@ -2472,7 +2447,7 @@ js_AllocFlatClosure(JSContext *cx, JSFunction *fun, JSObject *scopeChain)
|
||||
return closure;
|
||||
|
||||
uint32 nslots = fun->countInterpretedReservedSlots();
|
||||
if (!nslots)
|
||||
if (nslots == 0)
|
||||
return closure;
|
||||
if (!js_EnsureReservedSlots(cx, closure, nslots))
|
||||
return NULL;
|
||||
|
@ -355,10 +355,18 @@ js_OnUnknownMethod(JSContext *cx, jsval *vp)
|
||||
vp[0] = ID_TO_VALUE(id);
|
||||
}
|
||||
#endif
|
||||
obj = NewObjectWithGivenProto(cx, &js_NoSuchMethodClass, NULL, NULL);
|
||||
obj = js_NewGCObject(cx);
|
||||
if (!obj)
|
||||
return false;
|
||||
obj->fslots[JSSLOT_FOUND_FUNCTION] = tvr.value();
|
||||
|
||||
/*
|
||||
* Null map to cause prompt and safe crash if this object were to
|
||||
* escape due to a bug. This will make the object appear to be a
|
||||
* stillborn instance that needs no finalization, which is sound:
|
||||
* NoSuchMethod helper objects own no manually allocated resources.
|
||||
*/
|
||||
obj->map = NULL;
|
||||
obj->init(&js_NoSuchMethodClass, NULL, NULL, tvr.value());
|
||||
obj->fslots[JSSLOT_SAVED_ID] = vp[0];
|
||||
vp[0] = OBJECT_TO_JSVAL(obj);
|
||||
}
|
||||
|
@ -388,12 +388,27 @@ Compare(T *a, T *b, size_t c)
|
||||
return true;
|
||||
}
|
||||
|
||||
static JSObject *
|
||||
static inline JSObject *
|
||||
NewIteratorObject(JSContext *cx, uintN flags)
|
||||
{
|
||||
return !(flags & JSITER_ENUMERATE)
|
||||
? NewObject(cx, &js_IteratorClass.base, NULL, NULL)
|
||||
: NewObjectWithGivenProto(cx, &js_IteratorClass.base, NULL, NULL);
|
||||
if (flags & JSITER_ENUMERATE) {
|
||||
/*
|
||||
* Non-escaping native enumerator objects do not need map, proto, or
|
||||
* parent. However, code in jstracer.cpp and elsewhere may find such a
|
||||
* native enumerator object via the stack and (as for all objects that
|
||||
* are not stillborn, with the exception of "NoSuchMethod" internal
|
||||
* helper objects) expect it to have a non-null map pointer, so we
|
||||
* share an empty Enumerator scope in the runtime.
|
||||
*/
|
||||
JSObject *obj = js_NewGCObject(cx);
|
||||
if (!obj)
|
||||
return false;
|
||||
obj->map = cx->runtime->emptyEnumeratorScope->hold();
|
||||
obj->init(&js_IteratorClass.base, NULL, NULL, JSVAL_NULL);
|
||||
return obj;
|
||||
}
|
||||
|
||||
return NewBuiltinClassInstance(cx, &js_IteratorClass.base);
|
||||
}
|
||||
|
||||
static inline void
|
||||
@ -912,7 +927,7 @@ JSExtendedClass js_GeneratorClass = {
|
||||
JS_REQUIRES_STACK JSObject *
|
||||
js_NewGenerator(JSContext *cx)
|
||||
{
|
||||
JSObject *obj = NewObject(cx, &js_GeneratorClass.base, NULL, NULL);
|
||||
JSObject *obj = NewBuiltinClassInstance(cx, &js_GeneratorClass.base);
|
||||
if (!obj)
|
||||
return NULL;
|
||||
|
||||
|
216
js/src/jsobj.cpp
216
js/src/jsobj.cpp
@ -316,7 +316,6 @@ js_EnterSharpObject(JSContext *cx, JSObject *obj, JSIdArray **idap,
|
||||
map->table = table;
|
||||
JS_KEEP_ATOMS(cx->runtime);
|
||||
}
|
||||
|
||||
|
||||
/* From this point the control must flow either through out: or bad:. */
|
||||
ida = NULL;
|
||||
@ -1738,10 +1737,11 @@ obj_getPrototypeOf(JSContext *cx, uintN argc, jsval *vp)
|
||||
}
|
||||
|
||||
extern JSBool
|
||||
js_NewPropertyDescriptorObject(JSContext *cx, jsid id, uintN attrs, jsval getter, jsval setter, jsval value, jsval *vp)
|
||||
js_NewPropertyDescriptorObject(JSContext *cx, jsid id, uintN attrs, jsval getter, jsval setter,
|
||||
jsval value, jsval *vp)
|
||||
{
|
||||
/* We have our own property, so start creating the descriptor. */
|
||||
JSObject *desc = NewObject(cx, &js_ObjectClass, NULL, NULL);
|
||||
JSObject *desc = NewBuiltinClassInstance(cx, &js_ObjectClass);
|
||||
if (!desc)
|
||||
return false;
|
||||
*vp = OBJECT_TO_JSVAL(desc); /* Root and return. */
|
||||
@ -2501,7 +2501,7 @@ obj_create(JSContext *cx, uintN argc, jsval *vp)
|
||||
}
|
||||
|
||||
jsval v = vp[2];
|
||||
if (!JSVAL_IS_OBJECT(vp[2])) {
|
||||
if (!JSVAL_IS_OBJECT(v)) {
|
||||
char *bytes = js_DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, v, NULL);
|
||||
if (!bytes)
|
||||
return JS_FALSE;
|
||||
@ -2512,11 +2512,11 @@ obj_create(JSContext *cx, uintN argc, jsval *vp)
|
||||
}
|
||||
|
||||
/*
|
||||
* It's plausible that it's safe to just use the context's global object,
|
||||
* but since we're not completely sure, better safe than sorry.
|
||||
* Use the callee's global as the parent of the new object to avoid dynamic
|
||||
* scoping (i.e., using the caller's global).
|
||||
*/
|
||||
JSObject *obj =
|
||||
NewObjectWithGivenProto(cx, &js_ObjectClass, JSVAL_TO_OBJECT(v), JS_GetScopeChain(cx));
|
||||
JSObject *obj = NewObjectWithGivenProto(cx, &js_ObjectClass, JSVAL_TO_OBJECT(v),
|
||||
JSVAL_TO_OBJECT(*vp)->getGlobal());
|
||||
if (!obj)
|
||||
return JS_FALSE;
|
||||
*vp = OBJECT_TO_JSVAL(obj); /* Root and prepare for eventual return. */
|
||||
@ -2612,7 +2612,7 @@ js_Object(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
||||
JS_ASSERT(!argc || JSVAL_IS_NULL(argv[0]) || JSVAL_IS_VOID(argv[0]));
|
||||
if (JS_IsConstructing(cx))
|
||||
return JS_TRUE;
|
||||
obj = NewObject(cx, &js_ObjectClass, NULL, NULL);
|
||||
obj = NewBuiltinClassInstance(cx, &js_ObjectClass);
|
||||
if (!obj)
|
||||
return JS_FALSE;
|
||||
}
|
||||
@ -2673,23 +2673,10 @@ js_NonEmptyObject(JSContext* cx, JSObject* proto)
|
||||
JS_DEFINE_CALLINFO_2(extern, CONSTRUCTOR_RETRY, js_NonEmptyObject, CONTEXT, CALLEE_PROTOTYPE, 0,
|
||||
nanojit::ACC_STORE_ANY)
|
||||
|
||||
|
||||
static inline JSObject*
|
||||
NewNativeObject(JSContext* cx, JSClass* clasp, JSObject* proto,
|
||||
JSObject *parent, jsval privateSlotValue)
|
||||
{
|
||||
JS_ASSERT(JS_ON_TRACE(cx));
|
||||
JSObject* obj = js_NewGCObject(cx);
|
||||
if (!obj)
|
||||
return NULL;
|
||||
|
||||
obj->init(clasp, proto, parent, privateSlotValue);
|
||||
return InitScopeForObject(cx, obj, clasp, proto, &js_ObjectOps) ? obj : NULL;
|
||||
}
|
||||
|
||||
JSObject* FASTCALL
|
||||
js_NewInstance(JSContext *cx, JSClass *clasp, JSObject *ctor)
|
||||
{
|
||||
JS_ASSERT(JS_ON_TRACE(cx));
|
||||
JS_ASSERT(ctor->isFunction());
|
||||
|
||||
JSAtom *atom = cx->runtime->atomState.classPrototypeAtom;
|
||||
@ -2708,27 +2695,37 @@ js_NewInstance(JSContext *cx, JSClass *clasp, JSObject *ctor)
|
||||
JSScopeProperty *sprop = scope->lookup(ATOM_TO_JSID(atom));
|
||||
jsval pval = sprop ? ctor->getSlot(sprop->slot) : JSVAL_HOLE;
|
||||
|
||||
JSObject *parent = ctor->getParent();
|
||||
JSObject *proto;
|
||||
if (!JSVAL_IS_PRIMITIVE(pval)) {
|
||||
/* An object in ctor.prototype, let's use it as the new instance's proto. */
|
||||
proto = JSVAL_TO_OBJECT(pval);
|
||||
} else if (pval == JSVAL_HOLE) {
|
||||
/* No ctor.prototype yet, inline and optimize fun_resolve's prototype code. */
|
||||
proto = NewObject(cx, clasp, NULL, ctor->getParent());
|
||||
if (!proto)
|
||||
return NULL;
|
||||
if (!js_SetClassPrototype(cx, ctor, proto, JSPROP_ENUMERATE | JSPROP_PERMANENT))
|
||||
return NULL;
|
||||
} else {
|
||||
/* Primitive value in .prototype means we use Object.prototype for proto. */
|
||||
if (!js_GetClassPrototype(cx, JSVAL_TO_OBJECT(ctor->fslots[JSSLOT_PARENT]),
|
||||
JSProto_Object, &proto)) {
|
||||
/* A hole or a primitive: either way, we need to get Object.prototype. */
|
||||
if (!js_GetClassPrototype(cx, parent, JSProto_Object, &proto))
|
||||
return NULL;
|
||||
|
||||
if (pval == JSVAL_HOLE) {
|
||||
/*
|
||||
* No ctor.prototype was set, so we inline-expand and optimize
|
||||
* fun_resolve's prototype creation code.
|
||||
*/
|
||||
proto = NewNativeClassInstance(cx, clasp, proto, parent);
|
||||
if (!proto)
|
||||
return NULL;
|
||||
if (!js_SetClassPrototype(cx, ctor, proto, JSPROP_ENUMERATE | JSPROP_PERMANENT))
|
||||
return NULL;
|
||||
} else {
|
||||
/*
|
||||
* A primitive value in .prototype means to use Object.prototype
|
||||
* for proto. See ES5 13.2.2 step 7.
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
return NewNativeObject(cx, clasp, proto, ctor->getParent(),
|
||||
JSObject::defaultPrivate(clasp));
|
||||
if (proto->isNative())
|
||||
return NewNativeClassInstance(cx, clasp, proto, parent);
|
||||
return NewObjectWithGivenProto(cx, clasp, proto, parent);
|
||||
}
|
||||
|
||||
JS_DEFINE_CALLINFO_3(extern, CONSTRUCTOR_RETRY, js_NewInstance, CONTEXT, CLASS, OBJECT, 0,
|
||||
@ -2954,11 +2951,13 @@ js_NewWithObject(JSContext *cx, JSObject *proto, JSObject *parent, jsint depth)
|
||||
{
|
||||
JSObject *obj;
|
||||
|
||||
obj = NewObject(cx, &js_WithClass, proto, parent);
|
||||
obj = js_NewGCObject(cx);
|
||||
if (!obj)
|
||||
return NULL;
|
||||
obj->setPrivate(js_FloatingFrameIfGenerator(cx, cx->fp));
|
||||
obj->init(&js_WithClass, proto, parent,
|
||||
reinterpret_cast<jsval>(js_FloatingFrameIfGenerator(cx, cx->fp)));
|
||||
OBJ_SET_BLOCK_DEPTH(cx, obj, depth);
|
||||
obj->map = cx->runtime->emptyWithScope->hold();
|
||||
|
||||
AutoObjectRooter tvr(cx, obj);
|
||||
JSObject *thisp = proto->thisObject(cx);
|
||||
@ -2976,8 +2975,11 @@ js_NewBlockObject(JSContext *cx)
|
||||
* Null obj's proto slot so that Object.prototype.* does not pollute block
|
||||
* scopes and to give the block object its own scope.
|
||||
*/
|
||||
JSObject *blockObj = NewObjectWithGivenProto(cx, &js_BlockClass, NULL, NULL);
|
||||
JS_ASSERT_IF(blockObj, !OBJ_IS_CLONED_BLOCK(blockObj));
|
||||
JSObject *blockObj = js_NewGCObject(cx);
|
||||
if (!blockObj)
|
||||
return NULL;
|
||||
blockObj->init(&js_BlockClass, NULL, NULL, JSVAL_NULL);
|
||||
blockObj->map = cx->runtime->emptyBlockScope->hold();
|
||||
return blockObj;
|
||||
}
|
||||
|
||||
@ -2999,6 +3001,9 @@ js_CloneBlockObject(JSContext *cx, JSObject *proto, JSStackFrame *fp)
|
||||
JS_ASSERT(cx->runtime->emptyBlockScope->freeslot == JSSLOT_BLOCK_DEPTH + 1);
|
||||
clone->map = cx->runtime->emptyBlockScope->hold();
|
||||
JS_ASSERT(OBJ_IS_CLONED_BLOCK(clone));
|
||||
|
||||
if (!js_EnsureReservedSlots(cx, clone, OBJ_BLOCK_COUNT(cx, proto)))
|
||||
return NULL;
|
||||
return clone;
|
||||
}
|
||||
|
||||
@ -3022,12 +3027,12 @@ js_PutBlockObject(JSContext *cx, JSBool normalUnwind)
|
||||
*/
|
||||
JS_ASSERT(obj->scope()->object != obj);
|
||||
|
||||
/* Block objects should not have reserved slots before they are put. */
|
||||
JS_ASSERT(obj->numSlots() == JS_INITIAL_NSLOTS);
|
||||
/* Block objects should have all reserved slots allocated early. */
|
||||
uintN count = OBJ_BLOCK_COUNT(cx, obj);
|
||||
JS_ASSERT(obj->numSlots() == JSSLOT_BLOCK_DEPTH + 1 + count);
|
||||
|
||||
/* The block and its locals must be on the current stack for GC safety. */
|
||||
uintN depth = OBJ_BLOCK_DEPTH(cx, obj);
|
||||
uintN count = OBJ_BLOCK_COUNT(cx, obj);
|
||||
JS_ASSERT(depth <= (size_t) (cx->regs->sp - StackBase(fp)));
|
||||
JS_ASSERT(count <= (size_t) (cx->regs->sp - StackBase(fp) - depth));
|
||||
|
||||
@ -3038,12 +3043,7 @@ js_PutBlockObject(JSContext *cx, JSBool normalUnwind)
|
||||
obj->fslots[JSSLOT_BLOCK_DEPTH + 1] = fp->slots()[depth];
|
||||
if (normalUnwind && count > 1) {
|
||||
--count;
|
||||
JS_LOCK_OBJ(cx, obj);
|
||||
if (!obj->allocSlots(cx, JS_INITIAL_NSLOTS + count))
|
||||
normalUnwind = JS_FALSE;
|
||||
else
|
||||
memcpy(obj->dslots, fp->slots() + depth + 1, count * sizeof(jsval));
|
||||
JS_UNLOCK_OBJ(cx, obj);
|
||||
memcpy(obj->dslots, fp->slots() + depth + 1, count * sizeof(jsval));
|
||||
}
|
||||
|
||||
/* We must clear the private slot even with errors. */
|
||||
@ -3288,18 +3288,12 @@ js_XDRBlockObject(JSXDRState *xdr, JSObject **objp)
|
||||
|
||||
#endif
|
||||
|
||||
static uint32
|
||||
block_reserveSlots(JSContext *cx, JSObject *obj)
|
||||
{
|
||||
return OBJ_IS_CLONED_BLOCK(obj) ? OBJ_BLOCK_COUNT(cx, obj) : 0;
|
||||
}
|
||||
|
||||
JSClass js_BlockClass = {
|
||||
"Block",
|
||||
JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_IS_ANONYMOUS,
|
||||
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
|
||||
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, NULL,
|
||||
NULL, NULL, NULL, NULL, NULL, NULL, NULL, block_reserveSlots
|
||||
JSCLASS_NO_OPTIONAL_MEMBERS
|
||||
};
|
||||
|
||||
JSObject *
|
||||
@ -3407,7 +3401,27 @@ js_InitClass(JSContext *cx, JSObject *obj, JSObject *parent_proto,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Create a prototype object for this class. */
|
||||
/*
|
||||
* Create a prototype object for this class.
|
||||
*
|
||||
* FIXME: lazy standard (built-in) class initialization and even older
|
||||
* eager boostrapping code rely on all of these properties:
|
||||
*
|
||||
* 1. NewObject attempting to compute a default prototype object when
|
||||
* passed null for proto; and
|
||||
*
|
||||
* 2. NewObject tolerating no default prototype (null proto slot value)
|
||||
* due to this js_InitClass call coming from js_InitFunctionClass on an
|
||||
* otherwise-uninitialized global.
|
||||
*
|
||||
* 3. NewObject allocating a JSFunction-sized GC-thing when clasp is
|
||||
* &js_FunctionClass, not a JSObject-sized (smaller) GC-thing.
|
||||
*
|
||||
* The JS_NewObjectForGivenProto and JS_NewObject APIs also allow clasp to
|
||||
* be &js_FunctionClass (we could break compatibility easily). But fixing
|
||||
* (3) is not enough without addressing the bootstrapping dependency on (1)
|
||||
* and (2).
|
||||
*/
|
||||
proto = NewObject(cx, clasp, parent_proto, obj);
|
||||
if (!proto)
|
||||
return NULL;
|
||||
@ -3911,12 +3925,6 @@ js_AllocSlot(JSContext *cx, JSObject *obj, uint32 *slotp)
|
||||
JSScope *scope = obj->scope();
|
||||
JS_ASSERT(scope->object == obj);
|
||||
|
||||
JSClass *clasp = obj->getClass();
|
||||
if (scope->freeslot == JSSLOT_FREE(clasp) && clasp->reserveSlots) {
|
||||
/* Adjust scope->freeslot to include computed reserved slots, if any. */
|
||||
scope->freeslot += clasp->reserveSlots(cx, obj);
|
||||
}
|
||||
|
||||
if (scope->freeslot >= obj->numSlots() &&
|
||||
!obj->growSlots(cx, scope->freeslot + 1)) {
|
||||
return JS_FALSE;
|
||||
@ -5690,6 +5698,28 @@ js_IsDelegate(JSContext *cx, JSObject *obj, jsval v, JSBool *bp)
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
bool
|
||||
js::FindClassPrototype(JSContext *cx, JSObject *scope, JSProtoKey protoKey, JSObject **protop,
|
||||
JSClass *clasp)
|
||||
{
|
||||
jsval v;
|
||||
if (!js_FindClassObject(cx, scope, protoKey, &v, clasp))
|
||||
return false;
|
||||
|
||||
if (VALUE_IS_FUNCTION(cx, v)) {
|
||||
JSObject *ctor = JSVAL_TO_OBJECT(v);
|
||||
if (!ctor->getProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.classPrototypeAtom), &v))
|
||||
return false;
|
||||
}
|
||||
|
||||
*protop = JSVAL_IS_OBJECT(v) ? JSVAL_TO_OBJECT(v) : NULL;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* The first part of this function has been hand-expanded and optimized into
|
||||
* NewBuiltinClassInstance in jsobjinlines.h.
|
||||
*/
|
||||
JSBool
|
||||
js_GetClassPrototype(JSContext *cx, JSObject *scope, JSProtoKey protoKey,
|
||||
JSObject **protop, JSClass *clasp)
|
||||
@ -5720,29 +5750,7 @@ js_GetClassPrototype(JSContext *cx, JSObject *scope, JSProtoKey protoKey,
|
||||
}
|
||||
}
|
||||
|
||||
jsval v;
|
||||
if (!js_FindClassObject(cx, scope, protoKey, &v, clasp))
|
||||
return JS_FALSE;
|
||||
if (VALUE_IS_FUNCTION(cx, v)) {
|
||||
JSObject *ctor = JSVAL_TO_OBJECT(v);
|
||||
if (!ctor->getProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.classPrototypeAtom), &v))
|
||||
return JS_FALSE;
|
||||
if (!JSVAL_IS_PRIMITIVE(v)) {
|
||||
/*
|
||||
* Set the newborn root in case v is otherwise unreferenced.
|
||||
* It's ok to overwrite newborn roots here, since the getter
|
||||
* called just above could have. Unlike the common GC rooting
|
||||
* model, our callers do not have to protect protop thanks to
|
||||
* this newborn root, since they all immediately create a new
|
||||
* instance that delegates to this object, or just query the
|
||||
* prototype for its class.
|
||||
*/
|
||||
cx->weakRoots.finalizableNewborns[FINALIZE_OBJECT] =
|
||||
JSVAL_TO_OBJECT(v);
|
||||
}
|
||||
}
|
||||
*protop = JSVAL_IS_OBJECT(v) ? JSVAL_TO_OBJECT(v) : NULL;
|
||||
return JS_TRUE;
|
||||
return FindClassPrototype(cx, scope, protoKey, protop, clasp);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -5830,7 +5838,7 @@ js_PrimitiveToObject(JSContext *cx, jsval *vp)
|
||||
JS_ASSERT(!JSVAL_IS_OBJECT(*vp));
|
||||
JS_ASSERT(!JSVAL_IS_VOID(*vp));
|
||||
clasp = PrimitiveClasses[JSVAL_TAG(*vp) - 1];
|
||||
obj = NewObject(cx, clasp, NULL, NULL);
|
||||
obj = NewBuiltinClassInstance(cx, clasp);
|
||||
if (!obj)
|
||||
return JS_FALSE;
|
||||
obj->setPrimitiveThis(*vp);
|
||||
@ -6162,25 +6170,6 @@ js_Clear(JSContext *cx, JSObject *obj)
|
||||
JS_UNLOCK_OBJ(cx, obj);
|
||||
}
|
||||
|
||||
/* On failure the function unlocks the object. */
|
||||
static bool
|
||||
ReservedSlotIndexOK(JSContext *cx, JSObject *obj, JSClass *clasp,
|
||||
uint32 index, uint32 limit)
|
||||
{
|
||||
JS_ASSERT(JS_IS_OBJ_LOCKED(cx, obj));
|
||||
|
||||
/* Check the computed, possibly per-instance, upper bound. */
|
||||
if (clasp->reserveSlots)
|
||||
limit += clasp->reserveSlots(cx, obj);
|
||||
if (index >= limit) {
|
||||
JS_UNLOCK_OBJ(cx, obj);
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
||||
JSMSG_RESERVED_SLOT_RANGE);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
js_GetReservedSlot(JSContext *cx, JSObject *obj, uint32 index, jsval *vp)
|
||||
{
|
||||
@ -6189,14 +6178,8 @@ js_GetReservedSlot(JSContext *cx, JSObject *obj, uint32 index, jsval *vp)
|
||||
return true;
|
||||
}
|
||||
|
||||
JSClass *clasp = obj->getClass();
|
||||
uint32 limit = JSCLASS_RESERVED_SLOTS(clasp);
|
||||
|
||||
uint32 slot = JSSLOT_START(obj->getClass()) + index;
|
||||
JS_LOCK_OBJ(cx, obj);
|
||||
if (index >= limit && !ReservedSlotIndexOK(cx, obj, clasp, index, limit))
|
||||
return false;
|
||||
|
||||
uint32 slot = JSSLOT_START(clasp) + index;
|
||||
*vp = (slot < obj->numSlots()) ? obj->getSlot(slot) : JSVAL_VOID;
|
||||
JS_UNLOCK_OBJ(cx, obj);
|
||||
return true;
|
||||
@ -6209,14 +6192,9 @@ js_SetReservedSlot(JSContext *cx, JSObject *obj, uint32 index, jsval v)
|
||||
return true;
|
||||
|
||||
JSClass *clasp = obj->getClass();
|
||||
uint32 slot = JSSLOT_START(clasp) + index;
|
||||
|
||||
JS_LOCK_OBJ(cx, obj);
|
||||
#ifdef DEBUG
|
||||
uint32 limit = JSCLASS_RESERVED_SLOTS(clasp);
|
||||
JS_ASSERT(index < limit || ReservedSlotIndexOK(cx, obj, clasp, index, limit));
|
||||
#endif
|
||||
|
||||
uint32 slot = JSSLOT_START(clasp) + index;
|
||||
if (slot >= obj->numSlots()) {
|
||||
/*
|
||||
* At this point, obj may or may not own scope, and we may or may not
|
||||
@ -6224,8 +6202,6 @@ js_SetReservedSlot(JSContext *cx, JSObject *obj, uint32 index, jsval v)
|
||||
* be accurate for obj (see comment below).
|
||||
*/
|
||||
uint32 nslots = JSSLOT_FREE(clasp);
|
||||
if (clasp->reserveSlots)
|
||||
nslots += clasp->reserveSlots(cx, obj);
|
||||
JS_ASSERT(slot < nslots);
|
||||
if (!obj->allocSlots(cx, nslots)) {
|
||||
JS_UNLOCK_OBJ(cx, obj);
|
||||
|
@ -986,9 +986,7 @@ js_FreeSlot(JSContext *cx, JSObject *obj, uint32 slot);
|
||||
* Ensure that the object has at least JSCLASS_RESERVED_SLOTS(clasp)+nreserved
|
||||
* slots. The function can be called only for native objects just created with
|
||||
* js_NewObject or its forms. In particular, the object should not be shared
|
||||
* between threads and its dslots array must be null. nreserved must match the
|
||||
* value that JSClass.reserveSlots (if any) would return after the object is
|
||||
* fully initialized.
|
||||
* between threads and its dslots array must be null.
|
||||
*/
|
||||
bool
|
||||
js_EnsureReservedSlots(JSContext *cx, JSObject *obj, size_t nreserved);
|
||||
|
@ -46,6 +46,7 @@
|
||||
#include "jsiter.h"
|
||||
#include "jsobj.h"
|
||||
#include "jsscope.h"
|
||||
#include "jsstaticcheck.h"
|
||||
#include "jsxml.h"
|
||||
|
||||
#include "jsdtracef.h"
|
||||
@ -594,14 +595,15 @@ InitScopeForObject(JSContext* cx, JSObject* obj, JSClass *clasp, JSObject* proto
|
||||
scope = JSScope::create(cx, ops, clasp, obj, js_GenerateShape(cx, false));
|
||||
if (!scope)
|
||||
goto bad;
|
||||
|
||||
/* Let JSScope::create set freeslot so as to reserve slots. */
|
||||
JS_ASSERT(scope->freeslot >= JSSLOT_PRIVATE);
|
||||
if (scope->freeslot > JS_INITIAL_NSLOTS &&
|
||||
!obj->allocSlots(cx, scope->freeslot)) {
|
||||
scope->destroy(cx);
|
||||
uint32 freeslot = JSSLOT_FREE(clasp);
|
||||
JS_ASSERT(freeslot >= scope->freeslot);
|
||||
if (freeslot > JS_INITIAL_NSLOTS && !obj->allocSlots(cx, freeslot))
|
||||
goto bad;
|
||||
}
|
||||
scope->freeslot = freeslot;
|
||||
#ifdef DEBUG
|
||||
if (freeslot < obj->numSlots())
|
||||
obj->setSlot(freeslot, JSVAL_VOID);
|
||||
#endif
|
||||
}
|
||||
|
||||
obj->map = scope;
|
||||
@ -613,9 +615,105 @@ InitScopeForObject(JSContext* cx, JSObject* obj, JSClass *clasp, JSObject* proto
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Helper optimized for creating a native instance of the given class (not the
|
||||
* class's prototype object). Use this in preference to NewObjectWithGivenProto
|
||||
* and NewObject, but use NewBuiltinClassInstance if you need the default class
|
||||
* prototype as proto, and its parent global as parent.
|
||||
*/
|
||||
static inline JSObject *
|
||||
NewObjectWithGivenProto(JSContext *cx, JSClass *clasp, JSObject *proto,
|
||||
JSObject *parent, size_t objectSize = 0)
|
||||
NewNativeClassInstance(JSContext *cx, JSClass *clasp, JSObject *proto, JSObject *parent)
|
||||
{
|
||||
JS_ASSERT(proto);
|
||||
JS_ASSERT(proto->isNative());
|
||||
JS_ASSERT(parent);
|
||||
|
||||
DTrace::ObjectCreationScope objectCreationScope(cx, cx->fp, clasp);
|
||||
|
||||
/*
|
||||
* Allocate an object from the GC heap and initialize all its fields before
|
||||
* doing any operation that can potentially trigger GC. Functions have a
|
||||
* larger non-standard allocation size.
|
||||
*/
|
||||
JSObject* obj = js_NewGCObject(cx);
|
||||
if (obj) {
|
||||
/*
|
||||
* Default parent to the parent of the prototype, which was set from
|
||||
* the parent of the prototype's constructor.
|
||||
*/
|
||||
obj->init(clasp, proto, parent, JSObject::defaultPrivate(clasp));
|
||||
|
||||
JS_LOCK_OBJ(cx, proto);
|
||||
JSScope *scope = proto->scope();
|
||||
JS_ASSERT(scope->canProvideEmptyScope(&js_ObjectOps, clasp));
|
||||
scope = scope->getEmptyScope(cx, clasp);
|
||||
JS_UNLOCK_OBJ(cx, proto);
|
||||
|
||||
if (!scope) {
|
||||
obj = NULL;
|
||||
} else {
|
||||
obj->map = scope;
|
||||
|
||||
/*
|
||||
* Do not call debug hooks on trace, because we might be in a non-_FAIL
|
||||
* builtin. See bug 481444.
|
||||
*/
|
||||
if (cx->debugHooks->objectHook && !JS_ON_TRACE(cx)) {
|
||||
AutoValueRooter tvr(cx, obj);
|
||||
AutoKeepAtoms keep(cx->runtime);
|
||||
cx->debugHooks->objectHook(cx, obj, JS_TRUE,
|
||||
cx->debugHooks->objectHookData);
|
||||
cx->weakRoots.finalizableNewborns[FINALIZE_OBJECT] = obj;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
objectCreationScope.handleCreation(obj);
|
||||
return obj;
|
||||
}
|
||||
|
||||
bool
|
||||
FindClassPrototype(JSContext *cx, JSObject *scope, JSProtoKey protoKey, JSObject **protop,
|
||||
JSClass *clasp);
|
||||
|
||||
/*
|
||||
* Helper used to create Boolean, Date, RegExp, etc. instances of built-in
|
||||
* classes with class prototypes of the same JSClass. See, e.g., jsdate.cpp,
|
||||
* jsregexp.cpp, and js_PrimitiveToObject in jsobj.cpp. Use this to get the
|
||||
* right default proto and parent for clasp in cx.
|
||||
*/
|
||||
static inline JSObject *
|
||||
NewBuiltinClassInstance(JSContext *cx, JSClass *clasp)
|
||||
{
|
||||
VOUCH_DOES_NOT_REQUIRE_STACK();
|
||||
|
||||
JSProtoKey protoKey = JSCLASS_CACHED_PROTO_KEY(clasp);
|
||||
JS_ASSERT(protoKey != JSProto_Null);
|
||||
|
||||
/* NB: inline-expanded and specialized version of js_GetClassPrototype. */
|
||||
JSObject *global = cx->fp ? cx->fp->scopeChain->getGlobal() : cx->globalObject;
|
||||
JS_ASSERT(global->getClass()->flags & JSCLASS_IS_GLOBAL);
|
||||
|
||||
jsval v = global->getReservedSlot(JSProto_LIMIT + protoKey);
|
||||
JSObject *proto;
|
||||
if (!JSVAL_IS_PRIMITIVE(v)) {
|
||||
proto = JSVAL_TO_OBJECT(v);
|
||||
JS_ASSERT(proto->getParent() == global);
|
||||
} else {
|
||||
if (!FindClassPrototype(cx, global, protoKey, &proto, clasp))
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return NewNativeClassInstance(cx, clasp, proto, global);
|
||||
}
|
||||
|
||||
/*
|
||||
* Like NewObject but with exactly the given proto. A null parent defaults to
|
||||
* proto->getParent() if proto is non-null (else to null). NB: only this helper
|
||||
* and NewObject can be used to construct full-sized JSFunction instances.
|
||||
*/
|
||||
static inline JSObject *
|
||||
NewObjectWithGivenProto(JSContext *cx, JSClass *clasp, JSObject *proto, JSObject *parent)
|
||||
{
|
||||
DTrace::ObjectCreationScope objectCreationScope(cx, cx->fp, clasp);
|
||||
|
||||
@ -630,7 +728,7 @@ NewObjectWithGivenProto(JSContext *cx, JSClass *clasp, JSObject *proto,
|
||||
* larger non-standard allocation size.
|
||||
*/
|
||||
JSObject* obj;
|
||||
if (clasp == &js_FunctionClass && !objectSize) {
|
||||
if (clasp == &js_FunctionClass) {
|
||||
obj = (JSObject*) js_NewGCFunction(cx);
|
||||
#ifdef DEBUG
|
||||
if (obj) {
|
||||
@ -639,7 +737,6 @@ NewObjectWithGivenProto(JSContext *cx, JSClass *clasp, JSObject *proto,
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
JS_ASSERT(!objectSize || objectSize == sizeof(JSObject));
|
||||
obj = js_NewGCObject(cx);
|
||||
}
|
||||
if (!obj)
|
||||
@ -692,24 +789,30 @@ GetClassProtoKey(JSClass *clasp)
|
||||
return JSProto_Null;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create an instance of any class, native or not, JSFunction-sized or not.
|
||||
*
|
||||
* If proto is null, use the memoized original value of the class constructor
|
||||
* .prototype property object for a built-in class, else the current value of
|
||||
* .prototype if available, else Object.prototype.
|
||||
*
|
||||
* Default parent is null to proto's parent (null if proto is null too).
|
||||
*/
|
||||
static inline JSObject *
|
||||
NewObject(JSContext *cx, JSClass *clasp, JSObject *proto,
|
||||
JSObject *parent, size_t objectSize = 0)
|
||||
NewObject(JSContext *cx, JSClass *clasp, JSObject *proto, JSObject *parent)
|
||||
{
|
||||
/* Bootstrap the ur-object, and make it the default prototype object. */
|
||||
if (!proto) {
|
||||
JSProtoKey protoKey = GetClassProtoKey(clasp);
|
||||
if (!js_GetClassPrototype(cx, parent, protoKey, &proto, clasp))
|
||||
return NULL;
|
||||
if (!proto &&
|
||||
!js_GetClassPrototype(cx, parent, JSProto_Object, &proto)) {
|
||||
if (!proto && !js_GetClassPrototype(cx, parent, JSProto_Object, &proto))
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return NewObjectWithGivenProto(cx, clasp, proto, parent, objectSize);
|
||||
return NewObjectWithGivenProto(cx, clasp, proto, parent);
|
||||
}
|
||||
|
||||
}
|
||||
} /* namespace js */
|
||||
|
||||
#endif /* jsobjinlines_h___ */
|
||||
|
@ -518,7 +518,7 @@ js_Stringify(JSContext *cx, jsval *vp, JSObject *replacer, jsval space,
|
||||
if (!InitializeGap(cx, space, scx.gap))
|
||||
return JS_FALSE;
|
||||
|
||||
JSObject *obj = NewObject(cx, &js_ObjectClass, NULL, NULL);
|
||||
JSObject *obj = NewBuiltinClassInstance(cx, &js_ObjectClass);
|
||||
if (!obj)
|
||||
return JS_FALSE;
|
||||
|
||||
@ -610,7 +610,7 @@ static bool
|
||||
Revive(JSContext *cx, jsval reviver, jsval *vp)
|
||||
{
|
||||
|
||||
JSObject *obj = NewObject(cx, &js_ObjectClass, NULL, NULL);
|
||||
JSObject *obj = NewBuiltinClassInstance(cx, &js_ObjectClass);
|
||||
if (!obj)
|
||||
return false;
|
||||
|
||||
@ -802,7 +802,7 @@ PushObject(JSContext *cx, JSONParser *jp, JSObject *obj)
|
||||
static JSBool
|
||||
OpenObject(JSContext *cx, JSONParser *jp)
|
||||
{
|
||||
JSObject *obj = NewObject(cx, &js_ObjectClass, NULL, NULL);
|
||||
JSObject *obj = NewBuiltinClassInstance(cx, &js_ObjectClass);
|
||||
if (!obj)
|
||||
return JS_FALSE;
|
||||
|
||||
|
@ -1739,17 +1739,12 @@ BEGIN_CASE(JSOP_SETMETHOD)
|
||||
PCMETER(cache->pchits++);
|
||||
PCMETER(cache->addpchits++);
|
||||
|
||||
/*
|
||||
* Beware classes such as Function that use the
|
||||
* reserveSlots hook to allocate a number of reserved
|
||||
* slots that may vary with obj.
|
||||
*/
|
||||
if (slot < obj->numSlots() &&
|
||||
!obj->getClass()->reserveSlots) {
|
||||
if (slot < obj->numSlots()) {
|
||||
++scope->freeslot;
|
||||
} else {
|
||||
if (!js_AllocSlot(cx, obj, &slot))
|
||||
goto error;
|
||||
JS_ASSERT(slot + 1 == scope->freeslot);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1757,12 +1752,16 @@ BEGIN_CASE(JSOP_SETMETHOD)
|
||||
* if something created a hash table for scope, we must
|
||||
* pay the price of JSScope::putProperty.
|
||||
*
|
||||
* (A reserveSlots hook can cause scopes of the same
|
||||
* shape to have different freeslot values. This is
|
||||
* what causes the slot != sprop->slot case. See
|
||||
* js_GetMutableScope.)
|
||||
* (A built-in object with a pre-allocated but not fixed
|
||||
* population of reserved slots hook can cause scopes of the
|
||||
* same shape to have different freeslot values. Arguments,
|
||||
* Block, Call, and certain Function objects pre-allocate
|
||||
* reserveds lots this way. This is what causes the slot !=
|
||||
* sprop->slot case. See js_GetMutableScope. FIXME 558451)
|
||||
*/
|
||||
if (slot != sprop->slot || scope->table) {
|
||||
if (slot == sprop->slot && !scope->table) {
|
||||
scope->extend(cx, sprop);
|
||||
} else {
|
||||
JSScopeProperty *sprop2 =
|
||||
scope->putProperty(cx, sprop->id,
|
||||
sprop->getter(), sprop->setter(),
|
||||
@ -1773,8 +1772,6 @@ BEGIN_CASE(JSOP_SETMETHOD)
|
||||
goto error;
|
||||
}
|
||||
sprop = sprop2;
|
||||
} else {
|
||||
scope->extend(cx, sprop);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -3207,7 +3204,7 @@ BEGIN_CASE(JSOP_NEWINIT)
|
||||
if (!obj)
|
||||
goto error;
|
||||
} else {
|
||||
obj = NewObject(cx, &js_ObjectClass, NULL, NULL);
|
||||
obj = NewBuiltinClassInstance(cx, &js_ObjectClass);
|
||||
if (!obj)
|
||||
goto error;
|
||||
|
||||
@ -3252,7 +3249,6 @@ BEGIN_CASE(JSOP_INITMETHOD)
|
||||
lval = FETCH_OPND(-2);
|
||||
obj = JSVAL_TO_OBJECT(lval);
|
||||
JS_ASSERT(obj->isNative());
|
||||
JS_ASSERT(!obj->getClass()->reserveSlots);
|
||||
|
||||
JSScope *scope = obj->scope();
|
||||
PropertyCacheEntry *entry;
|
||||
|
@ -3148,14 +3148,14 @@ BindLet(JSContext *cx, BindData *data, JSAtom *atom, JSTreeContext *tc)
|
||||
: js_variable_str,
|
||||
name);
|
||||
}
|
||||
return JS_FALSE;
|
||||
return false;
|
||||
}
|
||||
|
||||
n = OBJ_BLOCK_COUNT(cx, blockObj);
|
||||
if (n == JS_BIT(16)) {
|
||||
ReportCompileErrorNumber(cx, TS(tc->parser), pn,
|
||||
JSREPORT_ERROR, data->let.overflow);
|
||||
return JS_FALSE;
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -3163,7 +3163,7 @@ BindLet(JSContext *cx, BindData *data, JSAtom *atom, JSTreeContext *tc)
|
||||
* This is balanced by PopStatement, defined immediately below.
|
||||
*/
|
||||
if (!Define(pn, atom, tc, true))
|
||||
return JS_FALSE;
|
||||
return false;
|
||||
|
||||
/*
|
||||
* Assign block-local index to pn->pn_cookie right away, encoding it as an
|
||||
@ -3177,11 +3177,11 @@ BindLet(JSContext *cx, BindData *data, JSAtom *atom, JSTreeContext *tc)
|
||||
pn->pn_dflags |= PND_LET | PND_BOUND;
|
||||
|
||||
/*
|
||||
* Define the let binding's property before storing pn in a reserved slot,
|
||||
* since block_reserveSlots depends on blockObj->scope()->entryCount.
|
||||
* Define the let binding's property before storing pn in reserved slot at
|
||||
* reserved slot index (NB: not slot number) n.
|
||||
*/
|
||||
if (!js_DefineBlockVariable(cx, blockObj, ATOM_TO_JSID(atom), n))
|
||||
return JS_FALSE;
|
||||
return false;
|
||||
|
||||
/*
|
||||
* Store pn temporarily in what would be reserved slots in a cloned block
|
||||
@ -3190,13 +3190,11 @@ BindLet(JSContext *cx, BindData *data, JSAtom *atom, JSTreeContext *tc)
|
||||
* slots in jsemit.cpp:EmitEnterBlock.
|
||||
*/
|
||||
uintN slot = JSSLOT_FREE(&js_BlockClass) + n;
|
||||
if (slot >= blockObj->numSlots() &&
|
||||
!blockObj->growSlots(cx, slot + 1)) {
|
||||
return JS_FALSE;
|
||||
}
|
||||
if (slot >= blockObj->numSlots() && !blockObj->growSlots(cx, slot + 1))
|
||||
return false;
|
||||
blockObj->scope()->freeslot = slot + 1;
|
||||
blockObj->setSlot(slot, PRIVATE_TO_JSVAL(pn));
|
||||
return JS_TRUE;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -48,6 +48,7 @@
|
||||
#include "jsscope.h"
|
||||
|
||||
#include "jsnum.h"
|
||||
#include "jsobjinlines.h"
|
||||
#include "jsscopeinlines.h"
|
||||
|
||||
using namespace js;
|
||||
|
@ -968,9 +968,16 @@ proxy_Construct(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rv
|
||||
*/
|
||||
if (!JSProxy::get(cx, proxy, obj, ATOM_TO_JSID(ATOM(classPrototype)), rval))
|
||||
return false;
|
||||
JSObject *proto = !JSVAL_IS_PRIMITIVE(*rval) ? JSVAL_TO_OBJECT(*rval) : NULL;
|
||||
|
||||
JSObject *newobj = NewObject(cx, &js_ObjectClass, proto, NULL);
|
||||
JSObject *proto;
|
||||
if (!JSVAL_IS_PRIMITIVE(*rval)) {
|
||||
proto = JSVAL_TO_OBJECT(*rval);
|
||||
} else {
|
||||
if (!js_GetClassPrototype(cx, NULL, JSProto_Object, &proto))
|
||||
return false;
|
||||
}
|
||||
|
||||
JSObject *newobj = NewNativeClassInstance(cx, &js_ObjectClass, proto, proto->getParent());
|
||||
*rval = OBJECT_TO_JSVAL(newobj);
|
||||
|
||||
/* If the call returns an object, return that, otherwise the original newobj. */
|
||||
@ -1210,9 +1217,16 @@ callable_Construct(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval
|
||||
/* callable is the constructor, so get callable.prototype is the proto of the new object. */
|
||||
if (!callable->getProperty(cx, ATOM_TO_JSID(ATOM(classPrototype)), rval))
|
||||
return false;
|
||||
JSObject *proto = !JSVAL_IS_PRIMITIVE(*rval) ? JSVAL_TO_OBJECT(*rval) : NULL;
|
||||
|
||||
JSObject *newobj = NewObject(cx, &js_ObjectClass, proto, NULL);
|
||||
JSObject *proto;
|
||||
if (!JSVAL_IS_PRIMITIVE(*rval)) {
|
||||
proto = JSVAL_TO_OBJECT(*rval);
|
||||
} else {
|
||||
if (!js_GetClassPrototype(cx, NULL, JSProto_Object, &proto))
|
||||
return false;
|
||||
}
|
||||
|
||||
JSObject *newobj = NewNativeClassInstance(cx, &js_ObjectClass, proto, proto->getParent());
|
||||
*rval = OBJECT_TO_JSVAL(newobj);
|
||||
|
||||
/* If the call returns an object, return that, otherwise the original newobj. */
|
||||
@ -1309,5 +1323,5 @@ js_InitProxyClass(JSContext *cx, JSObject *obj)
|
||||
}
|
||||
if (!JS_DefineFunctions(cx, module, static_methods))
|
||||
return NULL;
|
||||
return obj;
|
||||
return module;
|
||||
}
|
||||
|
@ -397,21 +397,6 @@ typedef void
|
||||
typedef void
|
||||
(* JSTraceNamePrinter)(JSTracer *trc, char *buf, size_t bufsize);
|
||||
|
||||
/*
|
||||
* The optional JSClass.reserveSlots hook allows a class to make computed
|
||||
* per-instance object slots reservations, in addition to or instead of using
|
||||
* JSCLASS_HAS_RESERVED_SLOTS(n) in the JSClass.flags initializer to reserve
|
||||
* a constant-per-class number of slots. Implementations of this hook should
|
||||
* return the number of slots to reserve, not including any reserved by using
|
||||
* JSCLASS_HAS_RESERVED_SLOTS(n) in JSClass.flags.
|
||||
*
|
||||
* NB: called with obj locked by the JSObjectOps-specific mutual exclusion
|
||||
* mechanism appropriate for obj, so don't nest other operations that might
|
||||
* also lock obj.
|
||||
*/
|
||||
typedef uint32
|
||||
(* JSReserveSlotsOp)(JSContext *cx, JSObject *obj);
|
||||
|
||||
/* JSExtendedClass function pointer typedefs. */
|
||||
|
||||
typedef JSBool
|
||||
|
@ -5367,7 +5367,7 @@ js_XDRRegExpObject(JSXDRState *xdr, JSObject **objp)
|
||||
return JS_FALSE;
|
||||
}
|
||||
if (xdr->mode == JSXDR_DECODE) {
|
||||
obj = NewObject(xdr->cx, &js_RegExpClass, NULL, NULL);
|
||||
obj = NewBuiltinClassInstance(xdr->cx, &js_RegExpClass);
|
||||
if (!obj)
|
||||
return JS_FALSE;
|
||||
obj->clearParent();
|
||||
@ -5733,7 +5733,7 @@ RegExp(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
||||
}
|
||||
|
||||
/* Otherwise, replace obj with a new RegExp object. */
|
||||
obj = NewObject(cx, &js_RegExpClass, NULL, NULL);
|
||||
obj = NewBuiltinClassInstance(cx, &js_RegExpClass);
|
||||
if (!obj)
|
||||
return JS_FALSE;
|
||||
|
||||
@ -5788,7 +5788,7 @@ js_NewRegExpObject(JSContext *cx, TokenStream *ts,
|
||||
re = js_NewRegExp(cx, ts, str, flags, JS_FALSE);
|
||||
if (!re)
|
||||
return NULL;
|
||||
obj = NewObject(cx, &js_RegExpClass, NULL, NULL);
|
||||
obj = NewBuiltinClassInstance(cx, &js_RegExpClass);
|
||||
if (!obj) {
|
||||
js_DestroyRegExp(cx, re);
|
||||
return NULL;
|
||||
@ -5804,7 +5804,7 @@ js_CloneRegExpObject(JSContext *cx, JSObject *obj, JSObject *proto)
|
||||
JS_ASSERT(obj->getClass() == &js_RegExpClass);
|
||||
JS_ASSERT(proto);
|
||||
JS_ASSERT(proto->getClass() == &js_RegExpClass);
|
||||
JSObject *clone = NewObjectWithGivenProto(cx, &js_RegExpClass, proto, NULL);
|
||||
JSObject *clone = NewNativeClassInstance(cx, &js_RegExpClass, proto, proto->getParent());
|
||||
if (!clone)
|
||||
return NULL;
|
||||
JSRegExp *re = static_cast<JSRegExp *>(obj->getPrivate());
|
||||
|
@ -63,6 +63,7 @@
|
||||
#include "jsstr.h"
|
||||
#include "jstracer.h"
|
||||
|
||||
#include "jsobjinlines.h"
|
||||
#include "jsscopeinlines.h"
|
||||
|
||||
using namespace js;
|
||||
@ -93,21 +94,12 @@ js_GenerateShape(JSContext *cx, bool gcLocked)
|
||||
JSScope *
|
||||
js_GetMutableScope(JSContext *cx, JSObject *obj)
|
||||
{
|
||||
JSScope *scope, *newscope;
|
||||
JSClass *clasp;
|
||||
uint32 freeslot;
|
||||
|
||||
scope = obj->scope();
|
||||
JSScope *scope = obj->scope();
|
||||
JS_ASSERT(JS_IS_SCOPE_LOCKED(cx, scope));
|
||||
if (!scope->isSharedEmpty())
|
||||
return scope;
|
||||
|
||||
/*
|
||||
* Compile-time block objects each have their own scope, created at
|
||||
* birth, and runtime clone of a block objects are never mutated.
|
||||
*/
|
||||
JS_ASSERT(obj->getClass() != &js_BlockClass);
|
||||
newscope = JSScope::create(cx, scope->ops, obj->getClass(), obj, scope->shape);
|
||||
JSScope *newscope = JSScope::create(cx, scope->ops, obj->getClass(), obj, scope->shape);
|
||||
if (!newscope)
|
||||
return NULL;
|
||||
|
||||
@ -116,21 +108,33 @@ js_GetMutableScope(JSContext *cx, JSObject *obj)
|
||||
JS_ASSERT(JS_IS_SCOPE_LOCKED(cx, newscope));
|
||||
obj->map = newscope;
|
||||
|
||||
JS_ASSERT(newscope->freeslot == JSSLOT_FREE(obj->getClass()));
|
||||
clasp = obj->getClass();
|
||||
if (clasp->reserveSlots) {
|
||||
/*
|
||||
* FIXME: Here we change obj->scope()->freeslot without changing
|
||||
* obj->shape(). If we strengthen the shape guarantees to cover
|
||||
* freeslot, we can eliminate a check in JSOP_SETPROP and in
|
||||
* js_AddProperty. See bug 535416.
|
||||
*/
|
||||
freeslot = JSSLOT_FREE(clasp) + clasp->reserveSlots(cx, obj);
|
||||
if (freeslot > obj->numSlots())
|
||||
freeslot = obj->numSlots();
|
||||
if (newscope->freeslot < freeslot)
|
||||
newscope->freeslot = freeslot;
|
||||
/*
|
||||
* Subtle dependency on objects that call js_EnsureReservedSlots either:
|
||||
* (a) never escaping anywhere an ad-hoc property could be set on them;
|
||||
* (b) having at least JSSLOT_FREE(obj->getClass()) >= JS_INITIAL_NSLOTS.
|
||||
* Note that (b) depends on fine-tuning of JS_INITIAL_NSLOTS (5).
|
||||
*
|
||||
* Block objects fall into (a); Argument, Call, and Function objects (flat
|
||||
* closures only) fall into (b). All of this goes away soon (FIXME 558451).
|
||||
*/
|
||||
JS_ASSERT(newscope->freeslot >= JSSLOT_START(obj->getClass()) &&
|
||||
newscope->freeslot <= JSSLOT_FREE(obj->getClass()));
|
||||
newscope->freeslot = JSSLOT_FREE(obj->getClass());
|
||||
|
||||
uint32 nslots = obj->numSlots();
|
||||
if (newscope->freeslot > nslots && !obj->allocSlots(cx, newscope->freeslot)) {
|
||||
newscope->destroy(cx);
|
||||
obj->map = scope;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (nslots > JS_INITIAL_NSLOTS && nslots > newscope->freeslot)
|
||||
newscope->freeslot = nslots;
|
||||
#ifdef DEBUG
|
||||
if (newscope->freeslot < nslots)
|
||||
obj->setSlot(newscope->freeslot, JSVAL_VOID);
|
||||
#endif
|
||||
|
||||
JS_DROP_ALL_EMPTY_SCOPE_LOCKS(cx, scope);
|
||||
static_cast<JSEmptyScope *>(scope)->drop(cx);
|
||||
return newscope;
|
||||
@ -217,7 +221,7 @@ JSScope::create(JSContext *cx, const JSObjectOps *ops, JSClass *clasp,
|
||||
if (!scope)
|
||||
return NULL;
|
||||
|
||||
scope->freeslot = JSSLOT_FREE(clasp);
|
||||
scope->freeslot = JSSLOT_START(clasp);
|
||||
scope->flags = cx->runtime->gcRegenShapesScopeFlag;
|
||||
scope->initMinimal(cx, shape);
|
||||
|
||||
@ -238,7 +242,7 @@ JSEmptyScope::JSEmptyScope(JSContext *cx, const JSObjectOps *ops,
|
||||
* getEmptyScope, also promises to incref on behalf of its caller.
|
||||
*/
|
||||
nrefs = 2;
|
||||
freeslot = JSSLOT_FREE(clasp);
|
||||
freeslot = JSSLOT_START(clasp);
|
||||
flags = OWN_SHAPE | cx->runtime->gcRegenShapesScopeFlag;
|
||||
initMinimal(cx, js_GenerateShape(cx, false));
|
||||
|
||||
@ -283,12 +287,23 @@ JSScope::initRuntimeState(JSContext *cx)
|
||||
{
|
||||
JSRuntime *rt = cx->runtime;
|
||||
|
||||
rt->emptyArgumentsScope = cx->create<JSEmptyScope>(cx, &js_ObjectOps, &js_ArgumentsClass);
|
||||
if (!rt->emptyArgumentsScope)
|
||||
return false;
|
||||
JS_ASSERT(rt->emptyArgumentsScope->shape == JSScope::EMPTY_ARGUMENTS_SHAPE);
|
||||
JS_ASSERT(rt->emptyArgumentsScope->nrefs == 2);
|
||||
rt->emptyArgumentsScope->nrefs = 1;
|
||||
#define SCOPE(Name) rt->empty##Name##Scope
|
||||
#define CLASP(Name) &js_##Name##Class
|
||||
|
||||
#define INIT_EMPTY_SCOPE(Name,NAME,ops) \
|
||||
INIT_EMPTY_SCOPE_WITH_CLASS(Name, NAME, ops, CLASP(Name))
|
||||
|
||||
#define INIT_EMPTY_SCOPE_WITH_CLASS(Name,NAME,ops,clasp) \
|
||||
INIT_EMPTY_SCOPE_WITH_FREESLOT(Name, NAME, ops, clasp, JSSLOT_FREE(clasp))
|
||||
|
||||
#define INIT_EMPTY_SCOPE_WITH_FREESLOT(Name,NAME,ops,clasp,slot) \
|
||||
SCOPE(Name) = cx->create<JSEmptyScope>(cx, ops, clasp); \
|
||||
if (!SCOPE(Name)) \
|
||||
return false; \
|
||||
JS_ASSERT(SCOPE(Name)->shape == JSScope::EMPTY_##NAME##_SHAPE); \
|
||||
JS_ASSERT(SCOPE(Name)->nrefs == 2); \
|
||||
SCOPE(Name)->nrefs = 1; \
|
||||
SCOPE(Name)->freeslot = slot
|
||||
|
||||
/*
|
||||
* NewArguments allocates dslots to have enough room for the argc of the
|
||||
@ -308,25 +323,10 @@ JSScope::initRuntimeState(JSContext *cx)
|
||||
* arguments objects. This helps ensure that any arguments object needing
|
||||
* its own mutable scope (with unique shape) is a rare event.
|
||||
*/
|
||||
rt->emptyArgumentsScope->freeslot = JS_INITIAL_NSLOTS + JS_ARGS_LENGTH_MAX;
|
||||
INIT_EMPTY_SCOPE_WITH_FREESLOT(Arguments, ARGUMENTS, &js_ObjectOps, CLASP(Arguments),
|
||||
JS_INITIAL_NSLOTS + JS_ARGS_LENGTH_MAX);
|
||||
|
||||
rt->emptyBlockScope = cx->create<JSEmptyScope>(cx, &js_ObjectOps, &js_BlockClass);
|
||||
if (!rt->emptyBlockScope) {
|
||||
JSScope::finishRuntimeState(cx);
|
||||
return false;
|
||||
}
|
||||
JS_ASSERT(rt->emptyBlockScope->shape == JSScope::EMPTY_BLOCK_SHAPE);
|
||||
JS_ASSERT(rt->emptyBlockScope->nrefs == 2);
|
||||
rt->emptyBlockScope->nrefs = 1;
|
||||
|
||||
rt->emptyCallScope = cx->create<JSEmptyScope>(cx, &js_ObjectOps, &js_CallClass);
|
||||
if (!rt->emptyCallScope) {
|
||||
JSScope::finishRuntimeState(cx);
|
||||
return false;
|
||||
}
|
||||
JS_ASSERT(rt->emptyCallScope->shape == JSScope::EMPTY_CALL_SHAPE);
|
||||
JS_ASSERT(rt->emptyCallScope->nrefs == 2);
|
||||
rt->emptyCallScope->nrefs = 1;
|
||||
INIT_EMPTY_SCOPE(Block, BLOCK, &js_ObjectOps);
|
||||
|
||||
/*
|
||||
* Initialize the shared scope for all empty Call objects so gets for args
|
||||
@ -335,7 +335,23 @@ JSScope::initRuntimeState(JSContext *cx)
|
||||
*
|
||||
* See comment above for rt->emptyArgumentsScope->freeslot initialization.
|
||||
*/
|
||||
rt->emptyCallScope->freeslot = JS_INITIAL_NSLOTS + JSFunction::MAX_ARGS_AND_VARS;
|
||||
INIT_EMPTY_SCOPE_WITH_FREESLOT(Call, CALL, &js_ObjectOps, CLASP(Call),
|
||||
JS_INITIAL_NSLOTS + JSFunction::MAX_ARGS_AND_VARS);
|
||||
|
||||
/* A DeclEnv object holds the name binding for a named function expression. */
|
||||
INIT_EMPTY_SCOPE(DeclEnv, DECL_ENV, &js_ObjectOps);
|
||||
|
||||
/* Non-escaping native enumerator objects share this empty scope. */
|
||||
INIT_EMPTY_SCOPE_WITH_CLASS(Enumerator, ENUMERATOR, &js_ObjectOps, &js_IteratorClass.base);
|
||||
|
||||
/* Same drill for With objects. */
|
||||
INIT_EMPTY_SCOPE(With, WITH, &js_WithObjectOps);
|
||||
|
||||
#undef SCOPE
|
||||
#undef CLASP
|
||||
#undef INIT_EMPTY_SCOPE
|
||||
#undef INIT_EMPTY_SCOPE_WITH_CLASS
|
||||
#undef INIT_EMPTY_SCOPE_WITH_FREESLOT
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -345,18 +361,22 @@ void
|
||||
JSScope::finishRuntimeState(JSContext *cx)
|
||||
{
|
||||
JSRuntime *rt = cx->runtime;
|
||||
if (rt->emptyArgumentsScope) {
|
||||
rt->emptyArgumentsScope->drop(cx);
|
||||
rt->emptyArgumentsScope = NULL;
|
||||
}
|
||||
if (rt->emptyBlockScope) {
|
||||
rt->emptyBlockScope->drop(cx);
|
||||
rt->emptyBlockScope = NULL;
|
||||
}
|
||||
if (rt->emptyCallScope) {
|
||||
rt->emptyCallScope->drop(cx);
|
||||
rt->emptyCallScope = NULL;
|
||||
|
||||
#define FINISH_EMPTY_SCOPE(Name) \
|
||||
if (rt->empty##Name##Scope) { \
|
||||
rt->empty##Name##Scope->drop(cx); \
|
||||
rt->empty##Name##Scope = NULL; \
|
||||
}
|
||||
|
||||
/* Mnemonic: ABCDEW */
|
||||
FINISH_EMPTY_SCOPE(Arguments);
|
||||
FINISH_EMPTY_SCOPE(Block);
|
||||
FINISH_EMPTY_SCOPE(Call);
|
||||
FINISH_EMPTY_SCOPE(DeclEnv);
|
||||
FINISH_EMPTY_SCOPE(Enumerator);
|
||||
FINISH_EMPTY_SCOPE(With);
|
||||
|
||||
#undef FINISH_EMPTY_SCOPE
|
||||
}
|
||||
|
||||
JS_STATIC_ASSERT(sizeof(JSHashNumber) == 4);
|
||||
|
@ -515,10 +515,13 @@ struct JSScope : public JSObjectMap
|
||||
static void finishRuntimeState(JSContext *cx);
|
||||
|
||||
enum {
|
||||
EMPTY_ARGUMENTS_SHAPE = 1,
|
||||
EMPTY_BLOCK_SHAPE = 2,
|
||||
EMPTY_CALL_SHAPE = 3,
|
||||
LAST_RESERVED_SHAPE = 3
|
||||
EMPTY_ARGUMENTS_SHAPE = 1,
|
||||
EMPTY_BLOCK_SHAPE = 2,
|
||||
EMPTY_CALL_SHAPE = 3,
|
||||
EMPTY_DECL_ENV_SHAPE = 4,
|
||||
EMPTY_ENUMERATOR_SHAPE = 5,
|
||||
EMPTY_WITH_SHAPE = 6,
|
||||
LAST_RESERVED_SHAPE = 6
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -108,7 +108,7 @@ ArrayBuffer::class_constructor(JSContext *cx, JSObject *obj,
|
||||
uintN argc, jsval *argv, jsval *rval)
|
||||
{
|
||||
if (!JS_IsConstructing(cx)) {
|
||||
obj = NewObject(cx, &ArrayBuffer::jsclass, NULL, NULL);
|
||||
obj = NewBuiltinClassInstance(cx, &ArrayBuffer::jsclass);
|
||||
if (!obj)
|
||||
return false;
|
||||
*rval = OBJECT_TO_JSVAL(obj);
|
||||
@ -122,7 +122,7 @@ ArrayBuffer::create(JSContext *cx, JSObject *obj,
|
||||
uintN argc, jsval *argv, jsval *rval)
|
||||
{
|
||||
if (!obj) {
|
||||
obj = NewObject(cx, &ArrayBuffer::jsclass, NULL, NULL);
|
||||
obj = NewBuiltinClassInstance(cx, &ArrayBuffer::jsclass);
|
||||
if (!obj)
|
||||
return false;
|
||||
*rval = OBJECT_TO_JSVAL(obj);
|
||||
@ -717,7 +717,7 @@ class TypedArrayTemplate
|
||||
//
|
||||
|
||||
if (!JS_IsConstructing(cx)) {
|
||||
obj = NewObject(cx, slowClass(), NULL, NULL);
|
||||
obj = NewBuiltinClassInstance(cx, slowClass());
|
||||
if (!obj)
|
||||
return false;
|
||||
*rval = OBJECT_TO_JSVAL(obj);
|
||||
@ -730,7 +730,7 @@ class TypedArrayTemplate
|
||||
create(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
||||
{
|
||||
if (!obj) {
|
||||
obj = NewObject(cx, slowClass(), NULL, NULL);
|
||||
obj = NewBuiltinClassInstance(cx, slowClass());
|
||||
if (!obj)
|
||||
return false;
|
||||
*rval = OBJECT_TO_JSVAL(obj);
|
||||
|
@ -281,7 +281,7 @@ NewXMLNamespace(JSContext *cx, JSString *prefix, JSString *uri, JSBool declared)
|
||||
{
|
||||
JSObject *obj;
|
||||
|
||||
obj = NewObject(cx, &js_NamespaceClass.base, NULL, NULL);
|
||||
obj = NewBuiltinClassInstance(cx, &js_NamespaceClass.base);
|
||||
if (!obj)
|
||||
return JS_FALSE;
|
||||
JS_ASSERT(JSVAL_IS_VOID(obj->getNamePrefix()));
|
||||
@ -471,7 +471,7 @@ static JSObject *
|
||||
NewXMLQName(JSContext *cx, JSString *uri, JSString *prefix, JSString *localName,
|
||||
JSClass *clasp = &js_QNameClass.base)
|
||||
{
|
||||
JSObject *obj = NewObject(cx, clasp, NULL, NULL);
|
||||
JSObject *obj = NewBuiltinClassInstance(cx, clasp);
|
||||
if (!obj)
|
||||
return NULL;
|
||||
JS_ASSERT(obj->isQName());
|
||||
@ -584,7 +584,7 @@ NamespaceHelper(JSContext *cx, JSObject *obj, intN argc, jsval *argv,
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
obj = NewObject(cx, &js_NamespaceClass.base, NULL, NULL);
|
||||
obj = NewBuiltinClassInstance(cx, &js_NamespaceClass.base);
|
||||
if (!obj)
|
||||
return JS_FALSE;
|
||||
*rval = OBJECT_TO_JSVAL(obj);
|
||||
@ -691,7 +691,7 @@ QNameHelper(JSContext *cx, JSObject *obj, JSClass *clasp, intN argc,
|
||||
* Create and return a new QName or AttributeName object exactly as if
|
||||
* constructed.
|
||||
*/
|
||||
obj = NewObject(cx, clasp, NULL, NULL);
|
||||
obj = NewBuiltinClassInstance(cx, clasp);
|
||||
if (!obj)
|
||||
return JS_FALSE;
|
||||
*rval = OBJECT_TO_JSVAL(obj);
|
||||
@ -7305,8 +7305,7 @@ js_GetAnyName(JSContext *cx, jsval *vp)
|
||||
return JS_FALSE;
|
||||
|
||||
do {
|
||||
obj = NewObjectWithGivenProto(cx, &js_AnyNameClass, NULL,
|
||||
NULL);
|
||||
obj = NewObjectWithGivenProto(cx, &js_AnyNameClass, NULL, NULL);
|
||||
if (!obj) {
|
||||
ok = JS_FALSE;
|
||||
break;
|
||||
@ -7589,8 +7588,7 @@ js_StepXMLListFilter(JSContext *cx, JSBool initialized)
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
filterobj = NewObjectWithGivenProto(cx, &js_XMLFilterClass,
|
||||
NULL, NULL);
|
||||
filterobj = NewObjectWithGivenProto(cx, &js_XMLFilterClass, NULL, NULL);
|
||||
if (!filterobj)
|
||||
return JS_FALSE;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user