1 |
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- |
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- |
2 |
* vim: set ts=8 sw=4 et tw=99: |
* vim: set ts=8 sw=4 et tw=99: |
3 |
* |
* |
4 |
* ***** BEGIN LICENSE BLOCK ***** |
* ***** BEGIN LICENSE BLOCK ***** |
41 |
/* |
/* |
42 |
* JS function support. |
* JS function support. |
43 |
*/ |
*/ |
|
#include "jsstddef.h" |
|
44 |
#include <string.h> |
#include <string.h> |
45 |
#include "jstypes.h" |
#include "jstypes.h" |
46 |
|
#include "jsstdint.h" |
47 |
#include "jsbit.h" |
#include "jsbit.h" |
48 |
#include "jsutil.h" /* Added by JSIFY */ |
#include "jsutil.h" /* Added by JSIFY */ |
49 |
#include "jsapi.h" |
#include "jsapi.h" |
50 |
#include "jsarray.h" |
#include "jsarray.h" |
51 |
#include "jsatom.h" |
#include "jsatom.h" |
52 |
|
#include "jsbool.h" |
53 |
#include "jsbuiltins.h" |
#include "jsbuiltins.h" |
54 |
#include "jscntxt.h" |
#include "jscntxt.h" |
55 |
#include "jsversion.h" |
#include "jsversion.h" |
69 |
#include "jsstr.h" |
#include "jsstr.h" |
70 |
#include "jsexn.h" |
#include "jsexn.h" |
71 |
#include "jsstaticcheck.h" |
#include "jsstaticcheck.h" |
72 |
|
#include "jstracer.h" |
73 |
|
|
74 |
#if JS_HAS_GENERATORS |
#if JS_HAS_GENERATORS |
75 |
# include "jsiter.h" |
# include "jsiter.h" |
79 |
# include "jsxdrapi.h" |
# include "jsxdrapi.h" |
80 |
#endif |
#endif |
81 |
|
|
82 |
/* Generic function/call/arguments tinyids -- also reflected bit numbers. */ |
#include "jsatominlines.h" |
|
enum { |
|
|
CALL_ARGUMENTS = -1, /* predefined arguments local variable */ |
|
|
ARGS_LENGTH = -2, /* number of actual args, arity if inactive */ |
|
|
ARGS_CALLEE = -3, /* reference from arguments to active funobj */ |
|
|
FUN_ARITY = -4, /* number of formal parameters; desired argc */ |
|
|
FUN_NAME = -5, /* function name, "" if anonymous */ |
|
|
FUN_CALLER = -6 /* Function.prototype.caller, backward compat */ |
|
|
}; |
|
83 |
|
|
84 |
#if JSFRAME_OVERRIDE_BITS < 8 |
static inline void |
85 |
# error "not enough override bits in JSStackFrame.flags!" |
SetOverriddenArgsLength(JSObject *obj) |
86 |
#endif |
{ |
87 |
|
JS_ASSERT(STOBJ_GET_CLASS(obj) == &js_ArgumentsClass); |
88 |
|
|
89 |
|
jsval v = obj->fslots[JSSLOT_ARGS_LENGTH]; |
90 |
|
v = INT_TO_JSVAL(JSVAL_TO_INT(v) | 1); |
91 |
|
JS_ASSERT(JSVAL_IS_INT(v)); |
92 |
|
obj->fslots[JSSLOT_ARGS_LENGTH] = v; |
93 |
|
} |
94 |
|
|
95 |
|
static inline void |
96 |
|
InitArgsLengthSlot(JSObject *obj, uint32 argc) |
97 |
|
{ |
98 |
|
JS_ASSERT(STOBJ_GET_CLASS(obj) == &js_ArgumentsClass); |
99 |
|
JS_ASSERT(argc <= JS_ARGS_LENGTH_MAX); |
100 |
|
JS_ASSERT(obj->fslots[JSSLOT_ARGS_LENGTH] == JSVAL_VOID); |
101 |
|
obj->fslots[JSSLOT_ARGS_LENGTH] = INT_TO_JSVAL(argc << 1); |
102 |
|
JS_ASSERT(!js_IsOverriddenArgsLength(obj)); |
103 |
|
} |
104 |
|
|
105 |
|
static inline uint32 |
106 |
|
GetArgsLength(JSObject *obj) |
107 |
|
{ |
108 |
|
JS_ASSERT(STOBJ_GET_CLASS(obj) == &js_ArgumentsClass); |
109 |
|
|
110 |
#define TEST_OVERRIDE_BIT(fp, tinyid) \ |
uint32 argc = uint32(JSVAL_TO_INT(obj->fslots[JSSLOT_ARGS_LENGTH])) >> 1; |
111 |
((fp)->flags & JS_BIT(JSFRAME_OVERRIDE_SHIFT - ((tinyid) + 1))) |
JS_ASSERT(argc <= JS_ARGS_LENGTH_MAX); |
112 |
|
return argc; |
113 |
|
} |
114 |
|
|
115 |
#define SET_OVERRIDE_BIT(fp, tinyid) \ |
static inline void |
116 |
((fp)->flags |= JS_BIT(JSFRAME_OVERRIDE_SHIFT - ((tinyid) + 1))) |
SetArgsPrivateNative(JSObject *argsobj, js_ArgsPrivateNative *apn) |
117 |
|
{ |
118 |
|
JS_ASSERT(STOBJ_GET_CLASS(argsobj) == &js_ArgumentsClass); |
119 |
|
uintptr_t p = (uintptr_t) apn; |
120 |
|
argsobj->setPrivate((void*) (p | 2)); |
121 |
|
} |
122 |
|
|
123 |
JSBool |
JSBool |
124 |
js_GetArgsValue(JSContext *cx, JSStackFrame *fp, jsval *vp) |
js_GetArgsValue(JSContext *cx, JSStackFrame *fp, jsval *vp) |
125 |
{ |
{ |
126 |
JSObject *argsobj; |
JSObject *argsobj; |
127 |
|
|
128 |
if (TEST_OVERRIDE_BIT(fp, CALL_ARGUMENTS)) { |
if (fp->flags & JSFRAME_OVERRIDE_ARGS) { |
129 |
JS_ASSERT(fp->callobj); |
JS_ASSERT(fp->callobj); |
130 |
return OBJ_GET_PROPERTY(cx, fp->callobj, |
jsid id = ATOM_TO_JSID(cx->runtime->atomState.argumentsAtom); |
131 |
ATOM_TO_JSID(cx->runtime->atomState |
return fp->callobj->getProperty(cx, id, vp); |
|
.argumentsAtom), |
|
|
vp); |
|
132 |
} |
} |
133 |
argsobj = js_GetArgsObject(cx, fp); |
argsobj = js_GetArgsObject(cx, fp); |
134 |
if (!argsobj) |
if (!argsobj) |
137 |
return JS_TRUE; |
return JS_TRUE; |
138 |
} |
} |
139 |
|
|
|
static JSBool |
|
|
MarkArgDeleted(JSContext *cx, JSStackFrame *fp, uintN slot) |
|
|
{ |
|
|
JSObject *argsobj; |
|
|
jsval bmapval, bmapint; |
|
|
size_t nbits, nbytes; |
|
|
jsbitmap *bitmap; |
|
|
|
|
|
argsobj = fp->argsobj; |
|
|
(void) JS_GetReservedSlot(cx, argsobj, 0, &bmapval); |
|
|
nbits = fp->argc; |
|
|
JS_ASSERT(slot < nbits); |
|
|
if (JSVAL_IS_VOID(bmapval)) { |
|
|
if (nbits <= JSVAL_INT_BITS) { |
|
|
bmapint = 0; |
|
|
bitmap = (jsbitmap *) &bmapint; |
|
|
} else { |
|
|
nbytes = JS_HOWMANY(nbits, JS_BITS_PER_WORD) * sizeof(jsbitmap); |
|
|
bitmap = (jsbitmap *) JS_malloc(cx, nbytes); |
|
|
if (!bitmap) |
|
|
return JS_FALSE; |
|
|
memset(bitmap, 0, nbytes); |
|
|
bmapval = PRIVATE_TO_JSVAL(bitmap); |
|
|
JS_SetReservedSlot(cx, argsobj, 0, bmapval); |
|
|
} |
|
|
} else { |
|
|
if (nbits <= JSVAL_INT_BITS) { |
|
|
bmapint = JSVAL_TO_INT(bmapval); |
|
|
bitmap = (jsbitmap *) &bmapint; |
|
|
} else { |
|
|
bitmap = (jsbitmap *) JSVAL_TO_PRIVATE(bmapval); |
|
|
} |
|
|
} |
|
|
JS_SET_BIT(bitmap, slot); |
|
|
if (bitmap == (jsbitmap *) &bmapint) { |
|
|
bmapval = INT_TO_JSVAL(bmapint); |
|
|
JS_SetReservedSlot(cx, argsobj, 0, bmapval); |
|
|
} |
|
|
return JS_TRUE; |
|
|
} |
|
|
|
|
|
/* NB: Infallible predicate, false does not mean error/exception. */ |
|
|
static JSBool |
|
|
ArgWasDeleted(JSContext *cx, JSStackFrame *fp, uintN slot) |
|
|
{ |
|
|
JSObject *argsobj; |
|
|
jsval bmapval, bmapint; |
|
|
jsbitmap *bitmap; |
|
|
|
|
|
argsobj = fp->argsobj; |
|
|
(void) JS_GetReservedSlot(cx, argsobj, 0, &bmapval); |
|
|
if (JSVAL_IS_VOID(bmapval)) |
|
|
return JS_FALSE; |
|
|
if (fp->argc <= JSVAL_INT_BITS) { |
|
|
bmapint = JSVAL_TO_INT(bmapval); |
|
|
bitmap = (jsbitmap *) &bmapint; |
|
|
} else { |
|
|
bitmap = (jsbitmap *) JSVAL_TO_PRIVATE(bmapval); |
|
|
} |
|
|
return JS_TEST_BIT(bitmap, slot) != 0; |
|
|
} |
|
|
|
|
140 |
JSBool |
JSBool |
141 |
js_GetArgsProperty(JSContext *cx, JSStackFrame *fp, jsid id, jsval *vp) |
js_GetArgsProperty(JSContext *cx, JSStackFrame *fp, jsid id, jsval *vp) |
142 |
{ |
{ |
143 |
jsval val; |
if (fp->flags & JSFRAME_OVERRIDE_ARGS) { |
|
JSObject *obj; |
|
|
uintN slot; |
|
|
|
|
|
if (TEST_OVERRIDE_BIT(fp, CALL_ARGUMENTS)) { |
|
144 |
JS_ASSERT(fp->callobj); |
JS_ASSERT(fp->callobj); |
145 |
if (!OBJ_GET_PROPERTY(cx, fp->callobj, |
|
146 |
ATOM_TO_JSID(cx->runtime->atomState |
jsid argumentsid = ATOM_TO_JSID(cx->runtime->atomState.argumentsAtom); |
147 |
.argumentsAtom), |
jsval v; |
148 |
&val)) { |
if (!fp->callobj->getProperty(cx, argumentsid, &v)) |
149 |
return JS_FALSE; |
return false; |
150 |
} |
|
151 |
if (JSVAL_IS_PRIMITIVE(val)) { |
JSObject *obj; |
152 |
obj = js_ValueToNonNullObject(cx, val); |
if (JSVAL_IS_PRIMITIVE(v)) { |
153 |
|
obj = js_ValueToNonNullObject(cx, v); |
154 |
if (!obj) |
if (!obj) |
155 |
return JS_FALSE; |
return false; |
156 |
} else { |
} else { |
157 |
obj = JSVAL_TO_OBJECT(val); |
obj = JSVAL_TO_OBJECT(v); |
158 |
} |
} |
159 |
return OBJ_GET_PROPERTY(cx, obj, id, vp); |
return obj->getProperty(cx, id, vp); |
160 |
} |
} |
161 |
|
|
162 |
*vp = JSVAL_VOID; |
*vp = JSVAL_VOID; |
163 |
if (JSID_IS_INT(id)) { |
if (JSID_IS_INT(id)) { |
164 |
slot = (uintN) JSID_TO_INT(id); |
uint32 arg = uint32(JSID_TO_INT(id)); |
165 |
if (slot < fp->argc) { |
JSObject *argsobj = JSVAL_TO_OBJECT(fp->argsobj); |
166 |
if (fp->argsobj && ArgWasDeleted(cx, fp, slot)) |
if (arg < fp->argc) { |
167 |
return OBJ_GET_PROPERTY(cx, fp->argsobj, id, vp); |
if (argsobj) { |
168 |
*vp = fp->argv[slot]; |
jsval v = OBJ_GET_SLOT(cx, argsobj, JSSLOT_ARGS_COPY_START+arg); |
169 |
|
if (v == JSVAL_HOLE) |
170 |
|
return argsobj->getProperty(cx, id, vp); |
171 |
|
} |
172 |
|
*vp = fp->argv[arg]; |
173 |
} else { |
} else { |
174 |
/* |
/* |
175 |
* Per ECMA-262 Ed. 3, 10.1.8, last bulleted item, do not share |
* Per ECMA-262 Ed. 3, 10.1.8, last bulleted item, do not share |
183 |
* is null at this point, as it would be in the example, return |
* is null at this point, as it would be in the example, return |
184 |
* undefined in *vp. |
* undefined in *vp. |
185 |
*/ |
*/ |
186 |
if (fp->argsobj) |
if (argsobj) |
187 |
return OBJ_GET_PROPERTY(cx, fp->argsobj, id, vp); |
return argsobj->getProperty(cx, id, vp); |
|
} |
|
|
} else { |
|
|
if (id == ATOM_TO_JSID(cx->runtime->atomState.lengthAtom)) { |
|
|
if (fp->argsobj && TEST_OVERRIDE_BIT(fp, ARGS_LENGTH)) |
|
|
return OBJ_GET_PROPERTY(cx, fp->argsobj, id, vp); |
|
|
*vp = INT_TO_JSVAL((jsint) fp->argc); |
|
188 |
} |
} |
189 |
|
} else if (id == ATOM_TO_JSID(cx->runtime->atomState.lengthAtom)) { |
190 |
|
JSObject *argsobj = JSVAL_TO_OBJECT(fp->argsobj); |
191 |
|
if (argsobj && js_IsOverriddenArgsLength(argsobj)) |
192 |
|
return argsobj->getProperty(cx, id, vp); |
193 |
|
*vp = INT_TO_JSVAL(jsint(fp->argc)); |
194 |
} |
} |
195 |
return JS_TRUE; |
return true; |
196 |
|
} |
197 |
|
|
198 |
|
static JSObject * |
199 |
|
NewArguments(JSContext *cx, JSObject *parent, uint32 argc, JSObject *callee) |
200 |
|
{ |
201 |
|
JSObject *argsobj = js_NewObject(cx, &js_ArgumentsClass, NULL, parent, 0); |
202 |
|
if (!argsobj || !js_EnsureReservedSlots(cx, argsobj, argc)) |
203 |
|
return NULL; |
204 |
|
|
205 |
|
argsobj->fslots[JSSLOT_ARGS_CALLEE] = OBJECT_TO_JSVAL(callee); |
206 |
|
InitArgsLengthSlot(argsobj, argc); |
207 |
|
return argsobj; |
208 |
} |
} |
209 |
|
|
210 |
|
static void |
211 |
|
PutArguments(JSContext *cx, JSObject *argsobj, jsval *args) |
212 |
|
{ |
213 |
|
uint32 argc = GetArgsLength(argsobj); |
214 |
|
JS_LOCK_OBJ(cx, argsobj); |
215 |
|
for (uint32 i = 0; i != argc; ++i) { |
216 |
|
jsval v = STOBJ_GET_SLOT(argsobj, JSSLOT_ARGS_COPY_START + i); |
217 |
|
if (v != JSVAL_HOLE) |
218 |
|
STOBJ_SET_SLOT(argsobj, JSSLOT_ARGS_COPY_START + i, args[i]); |
219 |
|
} |
220 |
|
JS_UNLOCK_OBJ(cx, argsobj); |
221 |
|
} |
222 |
|
|
223 |
|
#ifdef OJI |
224 |
|
JS_BEGIN_EXTERN_C |
225 |
|
JS_EXPORT_API(JSObject *) |
226 |
|
#else |
227 |
JSObject * |
JSObject * |
228 |
|
#endif |
229 |
js_GetArgsObject(JSContext *cx, JSStackFrame *fp) |
js_GetArgsObject(JSContext *cx, JSStackFrame *fp) |
230 |
{ |
{ |
|
JSObject *argsobj, *global, *parent; |
|
|
|
|
231 |
/* |
/* |
232 |
* We must be in a function activation; the function must be lightweight |
* We must be in a function activation; the function must be lightweight |
233 |
* or else fp must have a variable object. |
* or else fp must have a variable object. |
239 |
fp = fp->down; |
fp = fp->down; |
240 |
|
|
241 |
/* Create an arguments object for fp only if it lacks one. */ |
/* Create an arguments object for fp only if it lacks one. */ |
242 |
argsobj = fp->argsobj; |
JSObject *argsobj = JSVAL_TO_OBJECT(fp->argsobj); |
243 |
if (argsobj) |
if (argsobj) |
244 |
return argsobj; |
return argsobj; |
245 |
|
|
|
/* Link the new object to fp so it can get actual argument values. */ |
|
|
argsobj = js_NewObject(cx, &js_ArgumentsClass, NULL, NULL, 0); |
|
|
if (!argsobj || !JS_SetPrivate(cx, argsobj, fp)) { |
|
|
cx->weakRoots.newborn[GCX_OBJECT] = NULL; |
|
|
return NULL; |
|
|
} |
|
|
|
|
246 |
/* |
/* |
247 |
* Give arguments an intrinsic scope chain link to fp's global object. |
* Give arguments an intrinsic scope chain link to fp's global object. |
248 |
* Since the arguments object lacks a prototype because js_ArgumentsClass |
* Since the arguments object lacks a prototype because js_ArgumentsClass |
254 |
* js_GetClassPrototype not being able to find a global object containing |
* js_GetClassPrototype not being able to find a global object containing |
255 |
* the standard prototype by starting from arguments and following parent. |
* the standard prototype by starting from arguments and following parent. |
256 |
*/ |
*/ |
257 |
global = fp->scopeChain; |
JSObject *parent, *global = fp->scopeChain; |
258 |
while ((parent = OBJ_GET_PARENT(cx, global)) != NULL) |
while ((parent = OBJ_GET_PARENT(cx, global)) != NULL) |
259 |
global = parent; |
global = parent; |
260 |
STOBJ_SET_PARENT(argsobj, global); |
|
261 |
fp->argsobj = argsobj; |
JS_ASSERT(fp->argv); |
262 |
|
argsobj = NewArguments(cx, global, fp->argc, JSVAL_TO_OBJECT(fp->argv[-2])); |
263 |
|
if (!argsobj) |
264 |
|
return argsobj; |
265 |
|
|
266 |
|
/* Link the new object to fp so it can get actual argument values. */ |
267 |
|
argsobj->setPrivate(fp); |
268 |
|
fp->argsobj = OBJECT_TO_JSVAL(argsobj); |
269 |
return argsobj; |
return argsobj; |
270 |
} |
} |
271 |
|
|
272 |
static JSBool |
#ifdef OJI |
273 |
args_enumerate(JSContext *cx, JSObject *obj); |
JS_EXPORT_API(void) |
274 |
|
#else |
275 |
JS_FRIEND_API(JSBool) |
void |
276 |
|
#endif |
277 |
js_PutArgsObject(JSContext *cx, JSStackFrame *fp) |
js_PutArgsObject(JSContext *cx, JSStackFrame *fp) |
278 |
{ |
{ |
279 |
JSObject *argsobj; |
JSObject *argsobj = JSVAL_TO_OBJECT(fp->argsobj); |
280 |
jsval bmapval, rval; |
JS_ASSERT(argsobj->getPrivate() == fp); |
281 |
JSBool ok; |
PutArguments(cx, argsobj, fp->argv); |
282 |
JSRuntime *rt; |
argsobj->setPrivate(NULL); |
283 |
|
fp->argsobj = JSVAL_NULL; |
284 |
|
} |
285 |
|
#ifdef OJI |
286 |
|
JS_END_EXTERN_C |
287 |
|
#endif |
288 |
|
|
289 |
/* |
/* |
290 |
* Reuse args_enumerate here to reflect fp's actual arguments as indexed |
* Traced versions of js_GetArgsObject and js_PutArgsObject. |
291 |
* elements of argsobj. Do this first, before clearing and freeing the |
*/ |
|
* deleted argument slot bitmap, because args_enumerate depends on that. |
|
|
*/ |
|
|
argsobj = fp->argsobj; |
|
|
ok = args_enumerate(cx, argsobj); |
|
292 |
|
|
293 |
/* |
#ifdef JS_TRACER |
294 |
* Now clear the deleted argument number bitmap slot and free the bitmap, |
JSObject * JS_FASTCALL |
295 |
* if one was actually created due to 'delete arguments[0]' or similar. |
js_Arguments(JSContext *cx, JSObject *parent, uint32 argc, JSObject *callee, |
296 |
*/ |
double *argv, js_ArgsPrivateNative *apn) |
297 |
(void) JS_GetReservedSlot(cx, argsobj, 0, &bmapval); |
{ |
298 |
if (!JSVAL_IS_VOID(bmapval)) { |
JSObject *argsobj = NewArguments(cx, parent, argc, callee); |
299 |
JS_SetReservedSlot(cx, argsobj, 0, JSVAL_VOID); |
if (!argsobj) |
300 |
if (fp->argc > JSVAL_INT_BITS) |
return NULL; |
301 |
JS_free(cx, JSVAL_TO_PRIVATE(bmapval)); |
apn->argv = argv; |
302 |
} |
SetArgsPrivateNative(argsobj, apn); |
303 |
|
return argsobj; |
304 |
|
} |
305 |
|
#endif |
306 |
|
|
307 |
/* |
JS_DEFINE_CALLINFO_6(extern, OBJECT, js_Arguments, CONTEXT, OBJECT, UINT32, OBJECT, |
308 |
* Now get the prototype properties so we snapshot fp->fun and fp->argc |
DOUBLEPTR, APNPTR, 0, 0) |
|
* before fp goes away. |
|
|
*/ |
|
|
rt = cx->runtime; |
|
|
ok &= js_GetProperty(cx, argsobj, ATOM_TO_JSID(rt->atomState.calleeAtom), |
|
|
&rval); |
|
|
ok &= js_SetProperty(cx, argsobj, ATOM_TO_JSID(rt->atomState.calleeAtom), |
|
|
&rval); |
|
|
ok &= js_GetProperty(cx, argsobj, ATOM_TO_JSID(rt->atomState.lengthAtom), |
|
|
&rval); |
|
|
ok &= js_SetProperty(cx, argsobj, ATOM_TO_JSID(rt->atomState.lengthAtom), |
|
|
&rval); |
|
309 |
|
|
310 |
/* |
/* FIXME change the return type to void. */ |
311 |
* Clear the private pointer to fp, which is about to go away (js_Invoke). |
JSBool JS_FASTCALL |
312 |
* Do this last because the args_enumerate and js_GetProperty calls above |
js_PutArguments(JSContext *cx, JSObject *argsobj, jsval *args) |
313 |
* need to follow the private slot to find fp. |
{ |
314 |
*/ |
JS_ASSERT(js_GetArgsPrivateNative(argsobj)); |
315 |
ok &= JS_SetPrivate(cx, argsobj, NULL); |
PutArguments(cx, argsobj, args); |
316 |
fp->argsobj = NULL; |
argsobj->setPrivate(NULL); |
317 |
return ok; |
return true; |
318 |
} |
} |
319 |
|
|
320 |
|
JS_DEFINE_CALLINFO_3(extern, BOOL, js_PutArguments, CONTEXT, OBJECT, JSVALPTR, 0, 0) |
321 |
|
|
322 |
static JSBool |
static JSBool |
323 |
args_delProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) |
args_delProperty(JSContext *cx, JSObject *obj, jsval idval, jsval *vp) |
324 |
{ |
{ |
325 |
jsint slot; |
JS_ASSERT(STOBJ_GET_CLASS(obj) == &js_ArgumentsClass); |
|
JSStackFrame *fp; |
|
326 |
|
|
327 |
if (!JSVAL_IS_INT(id)) |
if (JSVAL_IS_INT(idval)) { |
328 |
return JS_TRUE; |
uintN arg = uintN(JSVAL_TO_INT(idval)); |
329 |
fp = (JSStackFrame *) |
if (arg < GetArgsLength(obj)) |
330 |
JS_GetInstancePrivate(cx, obj, &js_ArgumentsClass, NULL); |
OBJ_SET_SLOT(cx, obj, JSSLOT_ARGS_COPY_START + arg, JSVAL_HOLE); |
331 |
if (!fp) |
} else if (idval == ATOM_KEY(cx->runtime->atomState.lengthAtom)) { |
332 |
return JS_TRUE; |
SetOverriddenArgsLength(obj); |
333 |
JS_ASSERT(fp->argsobj); |
} else if (idval == ATOM_KEY(cx->runtime->atomState.calleeAtom)) { |
334 |
|
obj->fslots[JSSLOT_ARGS_CALLEE] = JSVAL_HOLE; |
|
slot = JSVAL_TO_INT(id); |
|
|
switch (slot) { |
|
|
case ARGS_CALLEE: |
|
|
case ARGS_LENGTH: |
|
|
SET_OVERRIDE_BIT(fp, slot); |
|
|
break; |
|
|
|
|
|
default: |
|
|
if ((uintN)slot < fp->argc && !MarkArgDeleted(cx, fp, slot)) |
|
|
return JS_FALSE; |
|
|
break; |
|
335 |
} |
} |
336 |
return JS_TRUE; |
return true; |
337 |
} |
} |
338 |
|
|
339 |
static JS_REQUIRES_STACK JSObject * |
static JS_REQUIRES_STACK JSObject * |
355 |
return NULL; |
return NULL; |
356 |
|
|
357 |
JSObject *wfunobj = js_NewObjectWithGivenProto(cx, &js_FunctionClass, |
JSObject *wfunobj = js_NewObjectWithGivenProto(cx, &js_FunctionClass, |
358 |
funobj, scopeChain, 0); |
funobj, scopeChain); |
359 |
if (!wfunobj) |
if (!wfunobj) |
360 |
return NULL; |
return NULL; |
361 |
JSAutoTempValueRooter tvr(cx, wfunobj); |
JSAutoTempValueRooter tvr(cx, wfunobj); |
362 |
|
|
363 |
JSFunction *wfun = (JSFunction *) wfunobj; |
JSFunction *wfun = (JSFunction *) wfunobj; |
364 |
wfunobj->fslots[JSSLOT_PRIVATE] = PRIVATE_TO_JSVAL(wfun); |
wfunobj->setPrivate(wfun); |
365 |
wfun->nargs = 0; |
wfun->nargs = 0; |
366 |
wfun->flags = fun->flags | JSFUN_HEAVYWEIGHT; |
wfun->flags = fun->flags | JSFUN_HEAVYWEIGHT; |
367 |
wfun->u.i.nvars = 0; |
wfun->u.i.nvars = 0; |
405 |
} |
} |
406 |
|
|
407 |
JSScript *script = fun->u.i.script; |
JSScript *script = fun->u.i.script; |
408 |
jssrcnote *snbase = SCRIPT_NOTES(script); |
jssrcnote *snbase = script->notes(); |
409 |
jssrcnote *sn = snbase; |
jssrcnote *sn = snbase; |
410 |
while (!SN_IS_TERMINATOR(sn)) |
while (!SN_IS_TERMINATOR(sn)) |
411 |
sn = SN_NEXT(sn); |
sn = SN_NEXT(sn); |
415 |
JSScript *wscript = js_NewScript(cx, script->length, nsrcnotes, |
JSScript *wscript = js_NewScript(cx, script->length, nsrcnotes, |
416 |
script->atomMap.length, |
script->atomMap.length, |
417 |
(script->objectsOffset != 0) |
(script->objectsOffset != 0) |
418 |
? JS_SCRIPT_OBJECTS(script)->length |
? script->objects()->length |
419 |
: 0, |
: 0, |
420 |
fun->u.i.nupvars, |
fun->u.i.nupvars, |
421 |
(script->regexpsOffset != 0) |
(script->regexpsOffset != 0) |
422 |
? JS_SCRIPT_REGEXPS(script)->length |
? script->regexps()->length |
423 |
: 0, |
: 0, |
424 |
(script->trynotesOffset != 0) |
(script->trynotesOffset != 0) |
425 |
? JS_SCRIPT_TRYNOTES(script)->length |
? script->trynotes()->length |
426 |
: 0); |
: 0); |
427 |
if (!wscript) |
if (!wscript) |
428 |
return NULL; |
return NULL; |
430 |
memcpy(wscript->code, script->code, script->length); |
memcpy(wscript->code, script->code, script->length); |
431 |
wscript->main = wscript->code + (script->main - script->code); |
wscript->main = wscript->code + (script->main - script->code); |
432 |
|
|
433 |
memcpy(SCRIPT_NOTES(wscript), snbase, nsrcnotes); |
memcpy(wscript->notes(), snbase, nsrcnotes * sizeof(jssrcnote)); |
434 |
memcpy(wscript->atomMap.vector, script->atomMap.vector, |
memcpy(wscript->atomMap.vector, script->atomMap.vector, |
435 |
wscript->atomMap.length * sizeof(JSAtom *)); |
wscript->atomMap.length * sizeof(JSAtom *)); |
436 |
if (script->objectsOffset != 0) { |
if (script->objectsOffset != 0) { |
437 |
memcpy(JS_SCRIPT_OBJECTS(wscript)->vector, JS_SCRIPT_OBJECTS(script)->vector, |
memcpy(wscript->objects()->vector, script->objects()->vector, |
438 |
JS_SCRIPT_OBJECTS(wscript)->length * sizeof(JSObject *)); |
wscript->objects()->length * sizeof(JSObject *)); |
439 |
} |
} |
440 |
if (script->regexpsOffset != 0) { |
if (script->regexpsOffset != 0) { |
441 |
memcpy(JS_SCRIPT_REGEXPS(wscript)->vector, JS_SCRIPT_REGEXPS(script)->vector, |
memcpy(wscript->regexps()->vector, script->regexps()->vector, |
442 |
JS_SCRIPT_REGEXPS(wscript)->length * sizeof(JSObject *)); |
wscript->regexps()->length * sizeof(JSObject *)); |
443 |
} |
} |
444 |
if (script->trynotesOffset != 0) { |
if (script->trynotesOffset != 0) { |
445 |
memcpy(JS_SCRIPT_TRYNOTES(wscript)->vector, JS_SCRIPT_TRYNOTES(script)->vector, |
memcpy(wscript->trynotes()->vector, script->trynotes()->vector, |
446 |
JS_SCRIPT_TRYNOTES(wscript)->length * sizeof(JSTryNote)); |
wscript->trynotes()->length * sizeof(JSTryNote)); |
447 |
} |
} |
448 |
|
|
449 |
if (wfun->u.i.nupvars != 0) { |
if (wfun->u.i.nupvars != 0) { |
450 |
JS_ASSERT(wfun->u.i.nupvars == JS_SCRIPT_UPVARS(wscript)->length); |
JS_ASSERT(wfun->u.i.nupvars == wscript->upvars()->length); |
451 |
memcpy(JS_SCRIPT_UPVARS(wscript)->vector, JS_SCRIPT_UPVARS(script)->vector, |
memcpy(wscript->upvars()->vector, script->upvars()->vector, |
452 |
wfun->u.i.nupvars * sizeof(uint32)); |
wfun->u.i.nupvars * sizeof(uint32)); |
453 |
} |
} |
454 |
|
|
505 |
} |
} |
506 |
|
|
507 |
static JSBool |
static JSBool |
508 |
args_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) |
ArgGetter(JSContext *cx, JSObject *obj, jsval idval, jsval *vp) |
509 |
{ |
{ |
510 |
jsint slot; |
if (!JS_InstanceOf(cx, obj, &js_ArgumentsClass, NULL)) |
511 |
JSStackFrame *fp; |
return true; |
512 |
|
|
513 |
if (!JSVAL_IS_INT(id)) |
if (JSVAL_IS_INT(idval)) { |
514 |
return JS_TRUE; |
/* |
515 |
fp = (JSStackFrame *) |
* arg can exceed the number of arguments if a script changed the |
516 |
JS_GetInstancePrivate(cx, obj, &js_ArgumentsClass, NULL); |
* prototype to point to another Arguments object with a bigger argc. |
517 |
if (!fp) |
*/ |
518 |
return JS_TRUE; |
uintN arg = uintN(JSVAL_TO_INT(idval)); |
519 |
JS_ASSERT(fp->argsobj); |
if (arg < GetArgsLength(obj)) { |
520 |
|
#ifdef JS_TRACER |
521 |
|
js_ArgsPrivateNative *argp = js_GetArgsPrivateNative(obj); |
522 |
|
if (argp) { |
523 |
|
if (js_NativeToValue(cx, *vp, argp->typemap()[arg], &argp->argv[arg])) |
524 |
|
return true; |
525 |
|
js_LeaveTrace(cx); |
526 |
|
return false; |
527 |
|
} |
528 |
|
#endif |
529 |
|
|
530 |
slot = JSVAL_TO_INT(id); |
JSStackFrame *fp = (JSStackFrame *) obj->getPrivate(); |
531 |
switch (slot) { |
if (fp) { |
532 |
case ARGS_CALLEE: |
*vp = fp->argv[arg]; |
533 |
if (!TEST_OVERRIDE_BIT(fp, slot)) { |
} else { |
534 |
|
jsval v = OBJ_GET_SLOT(cx, obj, JSSLOT_ARGS_COPY_START + arg); |
535 |
|
if (v != JSVAL_HOLE) |
536 |
|
*vp = v; |
537 |
|
} |
538 |
|
} |
539 |
|
} else if (idval == ATOM_KEY(cx->runtime->atomState.lengthAtom)) { |
540 |
|
if (!js_IsOverriddenArgsLength(obj)) |
541 |
|
*vp = INT_TO_JSVAL(GetArgsLength(obj)); |
542 |
|
} else { |
543 |
|
JS_ASSERT(idval == ATOM_KEY(cx->runtime->atomState.calleeAtom)); |
544 |
|
jsval v = obj->fslots[JSSLOT_ARGS_CALLEE]; |
545 |
|
if (v != JSVAL_HOLE) { |
546 |
/* |
/* |
547 |
* If this function or one in it needs upvars that reach above it |
* If this function or one in it needs upvars that reach above it |
548 |
* in the scope chain, it must not be a null closure (it could be a |
* in the scope chain, it must not be a null closure (it could be a |
551 |
* to reduce code size and tell debugger users the truth instead of |
* to reduce code size and tell debugger users the truth instead of |
552 |
* passing off a fibbing wrapper. |
* passing off a fibbing wrapper. |
553 |
*/ |
*/ |
554 |
if (fp->fun->needsWrapper()) { |
if (GET_FUNCTION_PRIVATE(cx, JSVAL_TO_OBJECT(v))->needsWrapper()) { |
555 |
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, |
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, |
556 |
JSMSG_OPTIMIZED_CLOSURE_LEAK); |
JSMSG_OPTIMIZED_CLOSURE_LEAK); |
557 |
return JS_FALSE; |
return false; |
558 |
} |
} |
559 |
*vp = OBJECT_TO_JSVAL(fp->callee); |
*vp = v; |
560 |
} |
} |
|
break; |
|
|
|
|
|
case ARGS_LENGTH: |
|
|
if (!TEST_OVERRIDE_BIT(fp, slot)) |
|
|
*vp = INT_TO_JSVAL((jsint)fp->argc); |
|
|
break; |
|
|
|
|
|
default: |
|
|
if ((uintN)slot < fp->argc && !ArgWasDeleted(cx, fp, slot)) |
|
|
*vp = fp->argv[slot]; |
|
|
break; |
|
561 |
} |
} |
562 |
return JS_TRUE; |
return true; |
563 |
} |
} |
564 |
|
|
565 |
static JSBool |
static JSBool |
566 |
args_setProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) |
ArgSetter(JSContext *cx, JSObject *obj, jsval idval, jsval *vp) |
567 |
{ |
{ |
568 |
JSStackFrame *fp; |
#ifdef JS_TRACER |
569 |
jsint slot; |
// To be able to set a property here on trace, we would have to make |
570 |
|
// sure any updates also get written back to the trace native stack. |
571 |
if (!JSVAL_IS_INT(id)) |
// For simplicity, we just leave trace, since this is presumably not |
572 |
return JS_TRUE; |
// a common operation. |
573 |
fp = (JSStackFrame *) |
if (JS_ON_TRACE(cx)) { |
574 |
JS_GetInstancePrivate(cx, obj, &js_ArgumentsClass, NULL); |
js_DeepBail(cx); |
575 |
if (!fp) |
return false; |
576 |
return JS_TRUE; |
} |
577 |
JS_ASSERT(fp->argsobj); |
#endif |
|
|
|
|
slot = JSVAL_TO_INT(id); |
|
|
switch (slot) { |
|
|
case ARGS_CALLEE: |
|
|
case ARGS_LENGTH: |
|
|
SET_OVERRIDE_BIT(fp, slot); |
|
|
break; |
|
578 |
|
|
579 |
default: |
if (!JS_InstanceOf(cx, obj, &js_ArgumentsClass, NULL)) |
580 |
if (FUN_INTERPRETED(fp->fun) && |
return true; |
581 |
(uintN)slot < fp->argc && |
|
582 |
!ArgWasDeleted(cx, fp, slot)) { |
if (JSVAL_IS_INT(idval)) { |
583 |
fp->argv[slot] = *vp; |
uintN arg = uintN(JSVAL_TO_INT(idval)); |
584 |
|
if (arg < GetArgsLength(obj)) { |
585 |
|
JSStackFrame *fp = (JSStackFrame *) obj->getPrivate(); |
586 |
|
if (fp) { |
587 |
|
fp->argv[arg] = *vp; |
588 |
|
return true; |
589 |
|
} |
590 |
} |
} |
591 |
break; |
} else { |
592 |
|
JS_ASSERT(idval == ATOM_KEY(cx->runtime->atomState.lengthAtom) || |
593 |
|
idval == ATOM_KEY(cx->runtime->atomState.calleeAtom)); |
594 |
} |
} |
595 |
return JS_TRUE; |
|
596 |
|
/* |
597 |
|
* For simplicity we use delete/set to replace the property with one |
598 |
|
* backed by the default Object getter and setter. Note the we rely on |
599 |
|
* args_delete to clear the corresponding reserved slot so the GC can |
600 |
|
* collect its value. |
601 |
|
*/ |
602 |
|
jsid id; |
603 |
|
if (!JS_ValueToId(cx, idval, &id)) |
604 |
|
return false; |
605 |
|
|
606 |
|
JSAutoTempValueRooter tvr(cx); |
607 |
|
return js_DeleteProperty(cx, obj, id, tvr.addr()) && |
608 |
|
js_SetProperty(cx, obj, id, vp); |
609 |
} |
} |
610 |
|
|
611 |
static JSBool |
static JSBool |
612 |
args_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags, |
args_resolve(JSContext *cx, JSObject *obj, jsval idval, uintN flags, |
613 |
JSObject **objp) |
JSObject **objp) |
614 |
{ |
{ |
615 |
JSStackFrame *fp; |
JS_ASSERT(STOBJ_GET_CLASS(obj) == &js_ArgumentsClass); |
|
uintN slot; |
|
|
JSString *str; |
|
|
JSAtom *atom; |
|
|
intN tinyid; |
|
|
jsval value; |
|
616 |
|
|
617 |
*objp = NULL; |
*objp = NULL; |
618 |
fp = (JSStackFrame *) |
jsid id = 0; |
619 |
JS_GetInstancePrivate(cx, obj, &js_ArgumentsClass, NULL); |
if (JSVAL_IS_INT(idval)) { |
620 |
if (!fp) |
uint32 arg = uint32(JSVAL_TO_INT(idval)); |
621 |
return JS_TRUE; |
if (arg < GetArgsLength(obj) && |
622 |
JS_ASSERT(fp->argsobj); |
OBJ_GET_SLOT(cx, obj, JSSLOT_ARGS_COPY_START + arg) != JSVAL_HOLE) { |
623 |
|
id = INT_JSVAL_TO_JSID(idval); |
624 |
if (JSVAL_IS_INT(id)) { |
} |
625 |
slot = JSVAL_TO_INT(id); |
} else if (idval == ATOM_KEY(cx->runtime->atomState.lengthAtom)) { |
626 |
if (slot < fp->argc && !ArgWasDeleted(cx, fp, slot)) { |
if (!js_IsOverriddenArgsLength(obj)) |
627 |
/* XXX ECMA specs DontEnum, contrary to other array-like objects */ |
id = ATOM_TO_JSID(cx->runtime->atomState.lengthAtom); |
628 |
if (!js_DefineProperty(cx, obj, INT_JSVAL_TO_JSID(id), |
|
629 |
fp->argv[slot], |
} else if (idval == ATOM_KEY(cx->runtime->atomState.calleeAtom)) { |
630 |
args_getProperty, args_setProperty, |
if (obj->fslots[JSSLOT_ARGS_CALLEE] != JSVAL_HOLE) |
631 |
0, NULL)) { |
id = ATOM_TO_JSID(cx->runtime->atomState.calleeAtom); |
|
return JS_FALSE; |
|
|
} |
|
|
*objp = obj; |
|
|
} |
|
|
} else if (JSVAL_IS_STRING(id)) { |
|
|
str = JSVAL_TO_STRING(id); |
|
|
atom = cx->runtime->atomState.lengthAtom; |
|
|
if (str == ATOM_TO_STRING(atom)) { |
|
|
tinyid = ARGS_LENGTH; |
|
|
value = INT_TO_JSVAL(fp->argc); |
|
|
} else { |
|
|
atom = cx->runtime->atomState.calleeAtom; |
|
|
if (str == ATOM_TO_STRING(atom)) { |
|
|
tinyid = ARGS_CALLEE; |
|
|
value = OBJECT_TO_JSVAL(fp->callee); |
|
|
} else { |
|
|
atom = NULL; |
|
|
|
|
|
/* Quell GCC overwarnings. */ |
|
|
tinyid = 0; |
|
|
value = JSVAL_NULL; |
|
|
} |
|
|
} |
|
|
|
|
|
if (atom && !TEST_OVERRIDE_BIT(fp, tinyid)) { |
|
|
if (!js_DefineNativeProperty(cx, obj, ATOM_TO_JSID(atom), value, |
|
|
args_getProperty, args_setProperty, 0, |
|
|
SPROP_HAS_SHORTID, tinyid, NULL)) { |
|
|
return JS_FALSE; |
|
|
} |
|
|
*objp = obj; |
|
|
} |
|
632 |
} |
} |
633 |
|
|
634 |
return JS_TRUE; |
if (id != 0) { |
635 |
|
/* |
636 |
|
* XXX ECMA specs DontEnum even for indexed properties, contrary to |
637 |
|
* other array-like objects. |
638 |
|
*/ |
639 |
|
if (!js_DefineProperty(cx, obj, id, JSVAL_VOID, ArgGetter, ArgSetter, JSPROP_SHARED)) |
640 |
|
return JS_FALSE; |
641 |
|
*objp = obj; |
642 |
|
} |
643 |
|
return true; |
644 |
} |
} |
645 |
|
|
646 |
static JSBool |
static JSBool |
647 |
args_enumerate(JSContext *cx, JSObject *obj) |
args_enumerate(JSContext *cx, JSObject *obj) |
648 |
{ |
{ |
649 |
JSStackFrame *fp; |
JS_ASSERT(STOBJ_GET_CLASS(obj) == &js_ArgumentsClass); |
|
JSObject *pobj; |
|
|
JSProperty *prop; |
|
|
uintN slot, argc; |
|
|
|
|
|
fp = (JSStackFrame *) |
|
|
JS_GetInstancePrivate(cx, obj, &js_ArgumentsClass, NULL); |
|
|
if (!fp) |
|
|
return JS_TRUE; |
|
|
JS_ASSERT(fp->argsobj); |
|
650 |
|
|
651 |
/* |
/* |
652 |
* Trigger reflection with value snapshot in args_resolve using a series |
* Trigger reflection in args_resolve using a series of js_LookupProperty |
653 |
* of js_LookupProperty calls. We handle length, callee, and the indexed |
* calls. |
|
* argument properties. We know that args_resolve covers all these cases |
|
|
* and creates direct properties of obj, but that it may fail to resolve |
|
|
* length or callee if overridden. |
|
654 |
*/ |
*/ |
655 |
if (!js_LookupProperty(cx, obj, |
int argc = int(GetArgsLength(obj)); |
656 |
ATOM_TO_JSID(cx->runtime->atomState.lengthAtom), |
for (int i = -2; i != argc; i++) { |
657 |
&pobj, &prop)) { |
jsid id = (i == -2) |
658 |
return JS_FALSE; |
? ATOM_TO_JSID(cx->runtime->atomState.lengthAtom) |
659 |
} |
: (i == -1) |
660 |
if (prop) |
? ATOM_TO_JSID(cx->runtime->atomState.calleeAtom) |
661 |
OBJ_DROP_PROPERTY(cx, pobj, prop); |
: INT_JSVAL_TO_JSID(INT_TO_JSVAL(i)); |
662 |
|
|
663 |
if (!js_LookupProperty(cx, obj, |
JSObject *pobj; |
664 |
ATOM_TO_JSID(cx->runtime->atomState.calleeAtom), |
JSProperty *prop; |
665 |
&pobj, &prop)) { |
if (!js_LookupProperty(cx, obj, id, &pobj, &prop)) |
666 |
return JS_FALSE; |
return false; |
|
} |
|
|
if (prop) |
|
|
OBJ_DROP_PROPERTY(cx, pobj, prop); |
|
667 |
|
|
668 |
argc = fp->argc; |
/* prop is null when the property was deleted. */ |
|
for (slot = 0; slot < argc; slot++) { |
|
|
if (!js_LookupProperty(cx, obj, INT_TO_JSID((jsint)slot), &pobj, &prop)) |
|
|
return JS_FALSE; |
|
669 |
if (prop) |
if (prop) |
670 |
OBJ_DROP_PROPERTY(cx, pobj, prop); |
pobj->dropProperty(cx, prop); |
671 |
} |
} |
672 |
return JS_TRUE; |
return true; |
673 |
} |
} |
674 |
|
|
675 |
#if JS_HAS_GENERATORS |
#if JS_HAS_GENERATORS |
680 |
static void |
static void |
681 |
args_or_call_trace(JSTracer *trc, JSObject *obj) |
args_or_call_trace(JSTracer *trc, JSObject *obj) |
682 |
{ |
{ |
683 |
JSStackFrame *fp; |
JS_ASSERT(STOBJ_GET_CLASS(obj) == &js_ArgumentsClass || |
684 |
|
STOBJ_GET_CLASS(obj) == &js_CallClass); |
685 |
|
if (STOBJ_GET_CLASS(obj) == &js_ArgumentsClass && js_GetArgsPrivateNative(obj)) |
686 |
|
return; |
687 |
|
|
688 |
fp = (JSStackFrame *) JS_GetPrivate(trc->context, obj); |
JSStackFrame *fp = (JSStackFrame *) obj->getPrivate(); |
689 |
if (fp && (fp->flags & JSFRAME_GENERATOR)) { |
if (fp && (fp->flags & JSFRAME_GENERATOR)) { |
690 |
JS_CALL_OBJECT_TRACER(trc, FRAME_TO_GENERATOR(fp)->obj, |
JS_CALL_OBJECT_TRACER(trc, FRAME_TO_GENERATOR(fp)->obj, |
691 |
"FRAME_TO_GENERATOR(fp)->obj"); |
"FRAME_TO_GENERATOR(fp)->obj"); |
695 |
# define args_or_call_trace NULL |
# define args_or_call_trace NULL |
696 |
#endif |
#endif |
697 |
|
|
698 |
|
static uint32 |
699 |
|
args_reserveSlots(JSContext *cx, JSObject *obj) |
700 |
|
{ |
701 |
|
JS_ASSERT(STOBJ_GET_CLASS(obj) == &js_ArgumentsClass); |
702 |
|
return GetArgsLength(obj); |
703 |
|
} |
704 |
|
|
705 |
/* |
/* |
706 |
* The Arguments class is not initialized via JS_InitClass, and must not be, |
* The Arguments class is not initialized via JS_InitClass, and must not be, |
707 |
* because its name is "Object". Per ECMA, that causes instances of it to |
* because its name is "Object". Per ECMA, that causes instances of it to |
715 |
*/ |
*/ |
716 |
JSClass js_ArgumentsClass = { |
JSClass js_ArgumentsClass = { |
717 |
js_Object_str, |
js_Object_str, |
718 |
JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE | JSCLASS_HAS_RESERVED_SLOTS(1) | |
JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE | |
719 |
|
JSCLASS_HAS_RESERVED_SLOTS(ARGS_CLASS_FIXED_RESERVED_SLOTS) | |
720 |
JSCLASS_MARK_IS_TRACE | JSCLASS_HAS_CACHED_PROTO(JSProto_Object), |
JSCLASS_MARK_IS_TRACE | JSCLASS_HAS_CACHED_PROTO(JSProto_Object), |
721 |
JS_PropertyStub, args_delProperty, |
JS_PropertyStub, args_delProperty, |
722 |
args_getProperty, args_setProperty, |
JS_PropertyStub, JS_PropertyStub, |
723 |
args_enumerate, (JSResolveOp) args_resolve, |
args_enumerate, (JSResolveOp) args_resolve, |
724 |
JS_ConvertStub, JS_FinalizeStub, |
JS_ConvertStub, NULL, |
725 |
NULL, NULL, |
NULL, NULL, |
726 |
NULL, NULL, |
NULL, NULL, |
727 |
NULL, NULL, |
NULL, NULL, |
728 |
JS_CLASS_TRACE(args_or_call_trace), NULL |
JS_CLASS_TRACE(args_or_call_trace), args_reserveSlots |
729 |
}; |
}; |
730 |
|
|
731 |
#define JSSLOT_CALLEE (JSSLOT_PRIVATE + 1) |
const uint32 JSSLOT_CALLEE = JSSLOT_PRIVATE + 1; |
732 |
#define JSSLOT_CALL_ARGUMENTS (JSSLOT_PRIVATE + 2) |
const uint32 JSSLOT_CALL_ARGUMENTS = JSSLOT_PRIVATE + 2; |
733 |
#define CALL_CLASS_FIXED_RESERVED_SLOTS 2 |
const uint32 CALL_CLASS_FIXED_RESERVED_SLOTS = 2; |
734 |
|
|
735 |
/* |
/* |
736 |
* A Declarative Environment object stores its active JSStackFrame pointer in |
* A Declarative Environment object stores its active JSStackFrame pointer in |
740 |
js_Object_str, |
js_Object_str, |
741 |
JSCLASS_HAS_PRIVATE | JSCLASS_HAS_CACHED_PROTO(JSProto_Object), |
JSCLASS_HAS_PRIVATE | JSCLASS_HAS_CACHED_PROTO(JSProto_Object), |
742 |
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, |
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, |
743 |
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub, |
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, NULL, |
744 |
JSCLASS_NO_OPTIONAL_MEMBERS |
JSCLASS_NO_OPTIONAL_MEMBERS |
745 |
}; |
}; |
746 |
|
|
747 |
static JS_REQUIRES_STACK JSBool |
static JSBool |
748 |
CheckForEscapingClosure(JSContext *cx, JSObject *obj, jsval *vp) |
CheckForEscapingClosure(JSContext *cx, JSObject *obj, jsval *vp) |
749 |
{ |
{ |
750 |
JS_ASSERT(STOBJ_GET_CLASS(obj) == &js_CallClass || |
JS_ASSERT(STOBJ_GET_CLASS(obj) == &js_CallClass || |
763 |
* still has an active stack frame associated with it. |
* still has an active stack frame associated with it. |
764 |
*/ |
*/ |
765 |
if (fun->needsWrapper()) { |
if (fun->needsWrapper()) { |
766 |
JSStackFrame *fp = (JSStackFrame *) JS_GetPrivate(cx, obj); |
js_LeaveTrace(cx); |
767 |
|
|
768 |
|
JSStackFrame *fp = (JSStackFrame *) obj->getPrivate(); |
769 |
if (fp) { |
if (fp) { |
770 |
JSObject *wrapper = WrapEscapingClosure(cx, fp, funobj, fun); |
JSObject *wrapper = WrapEscapingClosure(cx, fp, funobj, fun); |
771 |
if (!wrapper) |
if (!wrapper) |
782 |
return true; |
return true; |
783 |
} |
} |
784 |
|
|
785 |
static JS_REQUIRES_STACK JSBool |
static JSBool |
786 |
CalleeGetter(JSContext *cx, JSObject *obj, jsval id, jsval *vp) |
CalleeGetter(JSContext *cx, JSObject *obj, jsval id, jsval *vp) |
787 |
{ |
{ |
788 |
return CheckForEscapingClosure(cx, obj, vp); |
return CheckForEscapingClosure(cx, obj, vp); |
803 |
/* A call object should be a frame's outermost scope chain element. */ |
/* A call object should be a frame's outermost scope chain element. */ |
804 |
JSClass *classp = OBJ_GET_CLASS(cx, fp->scopeChain); |
JSClass *classp = OBJ_GET_CLASS(cx, fp->scopeChain); |
805 |
if (classp == &js_WithClass || classp == &js_BlockClass || classp == &js_CallClass) |
if (classp == &js_WithClass || classp == &js_BlockClass || classp == &js_CallClass) |
806 |
JS_ASSERT(OBJ_GET_PRIVATE(cx, fp->scopeChain) != fp); |
JS_ASSERT(fp->scopeChain->getPrivate() != fp); |
807 |
#endif |
#endif |
808 |
|
|
809 |
/* |
/* |
815 |
JSAtom *lambdaName = (fp->fun->flags & JSFUN_LAMBDA) ? fp->fun->atom : NULL; |
JSAtom *lambdaName = (fp->fun->flags & JSFUN_LAMBDA) ? fp->fun->atom : NULL; |
816 |
if (lambdaName) { |
if (lambdaName) { |
817 |
JSObject *env = js_NewObjectWithGivenProto(cx, &js_DeclEnvClass, NULL, |
JSObject *env = js_NewObjectWithGivenProto(cx, &js_DeclEnvClass, NULL, |
818 |
fp->scopeChain, 0); |
fp->scopeChain); |
819 |
if (!env) |
if (!env) |
820 |
return NULL; |
return NULL; |
821 |
env->fslots[JSSLOT_PRIVATE] = PRIVATE_TO_JSVAL(fp); |
env->setPrivate(fp); |
822 |
|
|
823 |
/* Root env before js_DefineNativeProperty (-> JSClass.addProperty). */ |
/* Root env before js_DefineNativeProperty (-> JSClass.addProperty). */ |
824 |
fp->scopeChain = env; |
fp->scopeChain = env; |
825 |
|
JS_ASSERT(fp->argv); |
826 |
if (!js_DefineNativeProperty(cx, fp->scopeChain, ATOM_TO_JSID(lambdaName), |
if (!js_DefineNativeProperty(cx, fp->scopeChain, ATOM_TO_JSID(lambdaName), |
827 |
OBJECT_TO_JSVAL(fp->callee), |
fp->argv[-2], |
828 |
CalleeGetter, NULL, |
CalleeGetter, NULL, |
829 |
JSPROP_PERMANENT | JSPROP_READONLY, |
JSPROP_PERMANENT | JSPROP_READONLY, |
830 |
0, 0, NULL)) { |
0, 0, NULL)) { |
832 |
} |
} |
833 |
} |
} |
834 |
|
|
835 |
callobj = js_NewObjectWithGivenProto(cx, &js_CallClass, NULL, |
callobj = js_NewObjectWithGivenProto(cx, &js_CallClass, NULL, fp->scopeChain); |
836 |
fp->scopeChain, 0); |
if (!callobj || |
837 |
if (!callobj) |
!js_EnsureReservedSlots(cx, callobj, fp->fun->countArgsAndVars())) { |
838 |
return NULL; |
return NULL; |
839 |
|
} |
840 |
|
|
841 |
JS_SetPrivate(cx, callobj, fp); |
callobj->setPrivate(fp); |
842 |
JS_ASSERT(fp->fun == GET_FUNCTION_PRIVATE(cx, fp->callee)); |
JS_ASSERT(fp->argv); |
843 |
STOBJ_SET_SLOT(callobj, JSSLOT_CALLEE, OBJECT_TO_JSVAL(fp->callee)); |
JS_ASSERT(fp->fun == GET_FUNCTION_PRIVATE(cx, JSVAL_TO_OBJECT(fp->argv[-2]))); |
844 |
|
STOBJ_SET_SLOT(callobj, JSSLOT_CALLEE, fp->argv[-2]); |
845 |
fp->callobj = callobj; |
fp->callobj = callobj; |
846 |
|
|
847 |
/* |
/* |
853 |
return callobj; |
return callobj; |
854 |
} |
} |
855 |
|
|
856 |
static JSFunction * |
JSFunction * |
857 |
GetCallObjectFunction(JSObject *obj) |
js_GetCallObjectFunction(JSObject *obj) |
858 |
{ |
{ |
859 |
jsval v; |
jsval v; |
860 |
|
|
868 |
return GET_FUNCTION_PRIVATE(cx, JSVAL_TO_OBJECT(v)); |
return GET_FUNCTION_PRIVATE(cx, JSVAL_TO_OBJECT(v)); |
869 |
} |
} |
870 |
|
|
871 |
JS_FRIEND_API(JSBool) |
#ifdef OJI |
872 |
|
JS_BEGIN_EXTERN_C |
873 |
|
JS_EXPORT_API(void) |
874 |
|
#else |
875 |
|
void |
876 |
|
#endif |
877 |
js_PutCallObject(JSContext *cx, JSStackFrame *fp) |
js_PutCallObject(JSContext *cx, JSStackFrame *fp) |
878 |
{ |
{ |
879 |
JSObject *callobj; |
JSObject *callobj = fp->callobj; |
880 |
JSBool ok; |
JS_ASSERT(callobj); |
881 |
JSFunction *fun; |
|
882 |
uintN n; |
/* Get the arguments object to snapshot fp's actual argument values. */ |
883 |
JSScope *scope; |
if (fp->argsobj) { |
884 |
|
if (!(fp->flags & JSFRAME_OVERRIDE_ARGS)) |
885 |
|
STOBJ_SET_SLOT(callobj, JSSLOT_CALL_ARGUMENTS, fp->argsobj); |
886 |
|
js_PutArgsObject(cx, fp); |
887 |
|
} |
888 |
|
|
889 |
|
JSFunction *fun = fp->fun; |
890 |
|
JS_ASSERT(fun == js_GetCallObjectFunction(callobj)); |
891 |
|
uintN n = fun->countArgsAndVars(); |
892 |
|
|
893 |
/* |
/* |
894 |
* Since for a call object all fixed slots happen to be taken, we can copy |
* Since for a call object all fixed slots happen to be taken, we can copy |
896 |
*/ |
*/ |
897 |
JS_STATIC_ASSERT(JS_INITIAL_NSLOTS - JSSLOT_PRIVATE == |
JS_STATIC_ASSERT(JS_INITIAL_NSLOTS - JSSLOT_PRIVATE == |
898 |
1 + CALL_CLASS_FIXED_RESERVED_SLOTS); |
1 + CALL_CLASS_FIXED_RESERVED_SLOTS); |
|
|
|
|
callobj = fp->callobj; |
|
|
if (!callobj) |
|
|
return JS_TRUE; |
|
|
|
|
|
/* |
|
|
* Get the arguments object to snapshot fp's actual argument values. |
|
|
*/ |
|
|
ok = JS_TRUE; |
|
|
if (fp->argsobj) { |
|
|
if (!TEST_OVERRIDE_BIT(fp, CALL_ARGUMENTS)) { |
|
|
STOBJ_SET_SLOT(callobj, JSSLOT_CALL_ARGUMENTS, |
|
|
OBJECT_TO_JSVAL(fp->argsobj)); |
|
|
} |
|
|
ok &= js_PutArgsObject(cx, fp); |
|
|
} |
|
|
|
|
|
fun = fp->fun; |
|
|
JS_ASSERT(fun == GetCallObjectFunction(callobj)); |
|
|
n = fun->countArgsAndVars(); |
|
899 |
if (n != 0) { |
if (n != 0) { |
900 |
JS_LOCK_OBJ(cx, callobj); |
JS_ASSERT(STOBJ_NSLOTS(callobj) >= JS_INITIAL_NSLOTS + n); |
901 |
n += JS_INITIAL_NSLOTS; |
n += JS_INITIAL_NSLOTS; |
902 |
if (n > STOBJ_NSLOTS(callobj)) |
JS_LOCK_OBJ(cx, callobj); |
903 |
ok &= js_ReallocSlots(cx, callobj, n, JS_TRUE); |
memcpy(callobj->dslots, fp->argv, fun->nargs * sizeof(jsval)); |
904 |
scope = OBJ_SCOPE(callobj); |
memcpy(callobj->dslots + fun->nargs, fp->slots, |
905 |
if (ok) { |
fun->u.i.nvars * sizeof(jsval)); |
906 |
memcpy(callobj->dslots, fp->argv, fun->nargs * sizeof(jsval)); |
JS_UNLOCK_OBJ(cx, callobj); |
|
memcpy(callobj->dslots + fun->nargs, fp->slots, |
|
|
fun->u.i.nvars * sizeof(jsval)); |
|
|
if (scope->object == callobj && n > scope->freeslot) |
|
|
scope->freeslot = n; |
|
|
} |
|
|
JS_UNLOCK_SCOPE(cx, scope); |
|
907 |
} |
} |
908 |
|
|
909 |
/* |
/* Clear private pointers to fp, which is about to go away (js_Invoke). */ |
|
* Clear private pointers to fp, which is about to go away (js_Invoke). |
|
|
* Do this last because js_GetProperty calls above need to follow the |
|
|
* call object's private slot to find fp. |
|
|
*/ |
|
910 |
if ((fun->flags & JSFUN_LAMBDA) && fun->atom) { |
if ((fun->flags & JSFUN_LAMBDA) && fun->atom) { |
911 |
JSObject *env = STOBJ_GET_PARENT(callobj); |
JSObject *env = STOBJ_GET_PARENT(callobj); |
912 |
|
|
913 |
JS_ASSERT(STOBJ_GET_CLASS(env) == &js_DeclEnvClass); |
JS_ASSERT(STOBJ_GET_CLASS(env) == &js_DeclEnvClass); |
914 |
JS_ASSERT(STOBJ_GET_PRIVATE(env) == fp); |
JS_ASSERT(env->getPrivate() == fp); |
915 |
JS_SetPrivate(cx, env, NULL); |
env->setPrivate(NULL); |
916 |
} |
} |
917 |
|
|
918 |
JS_SetPrivate(cx, callobj, NULL); |
callobj->setPrivate(NULL); |
919 |
fp->callobj = NULL; |
fp->callobj = NULL; |
|
return ok; |
|
920 |
} |
} |
921 |
|
#ifdef OJI |
922 |
|
JS_END_EXTERN_C |
923 |
|
#endif |
924 |
|
|
925 |
static JSBool |
static JSBool |
926 |
call_enumerate(JSContext *cx, JSObject *obj) |
call_enumerate(JSContext *cx, JSObject *obj) |
934 |
JSObject *pobj; |
JSObject *pobj; |
935 |
JSProperty *prop; |
JSProperty *prop; |
936 |
|
|
937 |
fun = GetCallObjectFunction(obj); |
fun = js_GetCallObjectFunction(obj); |
938 |
n = fun ? fun->countArgsAndVars() : 0; |
n = fun ? fun->countArgsAndVars() : 0; |
939 |
if (n == 0) |
if (n == 0) |
940 |
return JS_TRUE; |
return JS_TRUE; |
968 |
*/ |
*/ |
969 |
JS_ASSERT(prop); |
JS_ASSERT(prop); |
970 |
JS_ASSERT(pobj == obj); |
JS_ASSERT(pobj == obj); |
971 |
OBJ_DROP_PROPERTY(cx, pobj, prop); |
pobj->dropProperty(cx, prop); |
972 |
} |
} |
973 |
ok = JS_TRUE; |
ok = JS_TRUE; |
974 |
|
|
995 |
if (STOBJ_GET_CLASS(obj) != &js_CallClass) |
if (STOBJ_GET_CLASS(obj) != &js_CallClass) |
996 |
return JS_TRUE; |
return JS_TRUE; |
997 |
|
|
998 |
fun = GetCallObjectFunction(obj); |
fun = js_GetCallObjectFunction(obj); |
999 |
fp = (JSStackFrame *) JS_GetPrivate(cx, obj); |
fp = (JSStackFrame *) obj->getPrivate(); |
1000 |
|
|
1001 |
if (kind == JSCPK_ARGUMENTS) { |
if (kind == JSCPK_ARGUMENTS) { |
1002 |
if (setter) { |
if (setter) { |
1003 |
if (fp) |
if (fp) |
1004 |
SET_OVERRIDE_BIT(fp, CALL_ARGUMENTS); |
fp->flags |= JSFRAME_OVERRIDE_ARGS; |
1005 |
STOBJ_SET_SLOT(obj, JSSLOT_CALL_ARGUMENTS, *vp); |
STOBJ_SET_SLOT(obj, JSSLOT_CALL_ARGUMENTS, *vp); |
1006 |
} else { |
} else { |
1007 |
if (fp && !TEST_OVERRIDE_BIT(fp, CALL_ARGUMENTS)) { |
if (fp && !(fp->flags & JSFRAME_OVERRIDE_ARGS)) { |
1008 |
JSObject *argsobj; |
JSObject *argsobj; |
1009 |
|
|
1010 |
argsobj = js_GetArgsObject(cx, fp); |
argsobj = js_GetArgsObject(cx, fp); |
1067 |
return CallPropertyOp(cx, obj, id, vp, JSCPK_ARG, JS_FALSE); |
return CallPropertyOp(cx, obj, id, vp, JSCPK_ARG, JS_FALSE); |
1068 |
} |
} |
1069 |
|
|
1070 |
static JSBool |
JSBool |
1071 |
SetCallArg(JSContext *cx, JSObject *obj, jsid id, jsval *vp) |
SetCallArg(JSContext *cx, JSObject *obj, jsid id, jsval *vp) |
1072 |
{ |
{ |
1073 |
return CallPropertyOp(cx, obj, id, vp, JSCPK_ARG, JS_TRUE); |
return CallPropertyOp(cx, obj, id, vp, JSCPK_ARG, JS_TRUE); |
1088 |
return CheckForEscapingClosure(cx, obj, vp); |
return CheckForEscapingClosure(cx, obj, vp); |
1089 |
} |
} |
1090 |
|
|
1091 |
static JSBool |
JSBool |
1092 |
SetCallVar(JSContext *cx, JSObject *obj, jsid id, jsval *vp) |
SetCallVar(JSContext *cx, JSObject *obj, jsid id, jsval *vp) |
1093 |
{ |
{ |
1094 |
return CallPropertyOp(cx, obj, id, vp, JSCPK_VAR, JS_TRUE); |
return CallPropertyOp(cx, obj, id, vp, JSCPK_VAR, JS_TRUE); |
1095 |
} |
} |
1096 |
|
|
1097 |
|
JSBool JS_FASTCALL |
1098 |
|
js_SetCallArg(JSContext *cx, JSObject *obj, jsid id, jsval v) |
1099 |
|
{ |
1100 |
|
return CallPropertyOp(cx, obj, id, &v, JSCPK_ARG, JS_TRUE); |
1101 |
|
} |
1102 |
|
|
1103 |
|
JSBool JS_FASTCALL |
1104 |
|
js_SetCallVar(JSContext *cx, JSObject *obj, jsid id, jsval v) |
1105 |
|
{ |
1106 |
|
return CallPropertyOp(cx, obj, id, &v, JSCPK_VAR, JS_TRUE); |
1107 |
|
} |
1108 |
|
|
1109 |
|
JS_DEFINE_CALLINFO_4(extern, BOOL, js_SetCallArg, CONTEXT, OBJECT, JSID, JSVAL, 0, 0) |
1110 |
|
JS_DEFINE_CALLINFO_4(extern, BOOL, js_SetCallVar, CONTEXT, OBJECT, JSID, JSVAL, 0, 0) |
1111 |
|
|
1112 |
static JSBool |
static JSBool |
1113 |
call_resolve(JSContext *cx, JSObject *obj, jsval idval, uintN flags, |
call_resolve(JSContext *cx, JSObject *obj, jsval idval, uintN flags, |
1114 |
JSObject **objp) |
JSObject **objp) |
1210 |
static JSBool |
static JSBool |
1211 |
call_convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp) |
call_convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp) |
1212 |
{ |
{ |
|
JSStackFrame *fp; |
|
|
|
|
1213 |
if (type == JSTYPE_FUNCTION) { |
if (type == JSTYPE_FUNCTION) { |
1214 |
fp = (JSStackFrame *) JS_GetPrivate(cx, obj); |
JSStackFrame *fp = (JSStackFrame *) obj->getPrivate(); |
1215 |
if (fp) { |
if (fp) { |
1216 |
JS_ASSERT(fp->fun); |
JS_ASSERT(fp->fun); |
1217 |
*vp = OBJECT_TO_JSVAL(fp->callee); |
JS_ASSERT(fp->argv); |
1218 |
|
*vp = fp->argv[-2]; |
1219 |
} |
} |
1220 |
} |
} |
1221 |
return JS_TRUE; |
return JS_TRUE; |
1226 |
{ |
{ |
1227 |
JSFunction *fun; |
JSFunction *fun; |
1228 |
|
|
1229 |
fun = GetCallObjectFunction(obj); |
fun = js_GetCallObjectFunction(obj); |
1230 |
return fun->countArgsAndVars(); |
return fun->countArgsAndVars(); |
1231 |
} |
} |
1232 |
|
|
1238 |
JS_PropertyStub, JS_PropertyStub, |
JS_PropertyStub, JS_PropertyStub, |
1239 |
JS_PropertyStub, JS_PropertyStub, |
JS_PropertyStub, JS_PropertyStub, |
1240 |
call_enumerate, (JSResolveOp)call_resolve, |
call_enumerate, (JSResolveOp)call_resolve, |
1241 |
call_convert, JS_FinalizeStub, |
call_convert, NULL, |
1242 |
NULL, NULL, |
NULL, NULL, |
1243 |
NULL, NULL, |
NULL, NULL, |
1244 |
NULL, NULL, |
NULL, NULL, |
1245 |
JS_CLASS_TRACE(args_or_call_trace), call_reserveSlots |
JS_CLASS_TRACE(args_or_call_trace), call_reserveSlots |
1246 |
}; |
}; |
1247 |
|
|
1248 |
|
/* Generic function tinyids. */ |
1249 |
|
enum { |
1250 |
|
FUN_ARGUMENTS = -1, /* predefined arguments local variable */ |
1251 |
|
FUN_LENGTH = -2, /* number of actual args, arity if inactive */ |
1252 |
|
FUN_ARITY = -3, /* number of formal parameters; desired argc */ |
1253 |
|
FUN_NAME = -4, /* function name, "" if anonymous */ |
1254 |
|
FUN_CALLER = -5 /* Function.prototype.caller, backward compat */ |
1255 |
|
}; |
1256 |
|
|
1257 |
static JSBool |
static JSBool |
1258 |
fun_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) |
fun_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) |
1259 |
{ |
{ |
1268 |
|
|
1269 |
/* |
/* |
1270 |
* Loop because getter and setter can be delegated from another class, |
* Loop because getter and setter can be delegated from another class, |
1271 |
* but loop only for ARGS_LENGTH because we must pretend that f.length |
* but loop only for FUN_LENGTH because we must pretend that f.length |
1272 |
* is in each function instance f, per ECMA-262, instead of only in the |
* is in each function instance f, per ECMA-262, instead of only in the |
1273 |
* Function.prototype object (we use JSPROP_PERMANENT with JSPROP_SHARED |
* Function.prototype object (we use JSPROP_PERMANENT with JSPROP_SHARED |
1274 |
* to make it appear so). |
* to make it appear so). |
1278 |
* |
* |
1279 |
* It's important to allow delegating objects, even though they inherit |
* It's important to allow delegating objects, even though they inherit |
1280 |
* this getter (fun_getProperty), to override arguments, arity, caller, |
* this getter (fun_getProperty), to override arguments, arity, caller, |
1281 |
* and name. If we didn't return early for slot != ARGS_LENGTH, we would |
* and name. If we didn't return early for slot != FUN_LENGTH, we would |
1282 |
* clobber *vp with the native property value, instead of letting script |
* clobber *vp with the native property value, instead of letting script |
1283 |
* override that value in delegating objects. |
* override that value in delegating objects. |
1284 |
* |
* |
1288 |
*/ |
*/ |
1289 |
while (!(fun = (JSFunction *) |
while (!(fun = (JSFunction *) |
1290 |
JS_GetInstancePrivate(cx, obj, &js_FunctionClass, NULL))) { |
JS_GetInstancePrivate(cx, obj, &js_FunctionClass, NULL))) { |
1291 |
if (slot != ARGS_LENGTH) |
if (slot != FUN_LENGTH) |
1292 |
return JS_TRUE; |
return JS_TRUE; |
1293 |
obj = OBJ_GET_PROTO(cx, obj); |
obj = OBJ_GET_PROTO(cx, obj); |
1294 |
if (!obj) |
if (!obj) |
1303 |
} |
} |
1304 |
|
|
1305 |
switch (slot) { |
switch (slot) { |
1306 |
case CALL_ARGUMENTS: |
case FUN_ARGUMENTS: |
1307 |
/* Warn if strict about f.arguments or equivalent unqualified uses. */ |
/* Warn if strict about f.arguments or equivalent unqualified uses. */ |
1308 |
if (!JS_ReportErrorFlagsAndNumber(cx, |
if (!JS_ReportErrorFlagsAndNumber(cx, |
1309 |
JSREPORT_WARNING | JSREPORT_STRICT, |
JSREPORT_WARNING | JSREPORT_STRICT, |
1320 |
} |
} |
1321 |
break; |
break; |
1322 |
|
|
1323 |
case ARGS_LENGTH: |
case FUN_LENGTH: |
1324 |
case FUN_ARITY: |
case FUN_ARITY: |
1325 |
*vp = INT_TO_JSVAL((jsint)fun->nargs); |
*vp = INT_TO_JSVAL((jsint)fun->nargs); |
1326 |
break; |
break; |
1348 |
return JS_TRUE; |
return JS_TRUE; |
1349 |
} |
} |
1350 |
|
|
1351 |
*vp = OBJECT_TO_JSVAL(fp->down->callee); |
JS_ASSERT(fp->down->argv); |
1352 |
|
*vp = fp->down->argv[-2]; |
1353 |
} else { |
} else { |
1354 |
*vp = JSVAL_NULL; |
*vp = JSVAL_NULL; |
1355 |
} |
} |
1390 |
#define LENGTH_PROP_ATTRS (JSPROP_READONLY|JSPROP_PERMANENT|JSPROP_SHARED) |
#define LENGTH_PROP_ATTRS (JSPROP_READONLY|JSPROP_PERMANENT|JSPROP_SHARED) |
1391 |
|
|
1392 |
static JSPropertySpec function_props[] = { |
static JSPropertySpec function_props[] = { |
1393 |
{js_length_str, ARGS_LENGTH, LENGTH_PROP_ATTRS, fun_getProperty, JS_PropertyStub}, |
{js_length_str, FUN_LENGTH, LENGTH_PROP_ATTRS, fun_getProperty, JS_PropertyStub}, |
1394 |
{0,0,0,0,0} |
{0,0,0,0,0} |
1395 |
}; |
}; |
1396 |
|
|
1402 |
|
|
1403 |
/* NB: no sentinel at the end -- use JS_ARRAY_LENGTH to bound loops. */ |
/* NB: no sentinel at the end -- use JS_ARRAY_LENGTH to bound loops. */ |
1404 |
static LazyFunctionProp lazy_function_props[] = { |
static LazyFunctionProp lazy_function_props[] = { |
1405 |
{ATOM_OFFSET(arguments), CALL_ARGUMENTS, JSPROP_PERMANENT}, |
{ATOM_OFFSET(arguments), FUN_ARGUMENTS, JSPROP_PERMANENT}, |
1406 |
{ATOM_OFFSET(arity), FUN_ARITY, JSPROP_PERMANENT}, |
{ATOM_OFFSET(arity), FUN_ARITY, JSPROP_PERMANENT}, |
1407 |
{ATOM_OFFSET(caller), FUN_CALLER, JSPROP_PERMANENT}, |
{ATOM_OFFSET(caller), FUN_CALLER, JSPROP_PERMANENT}, |
1408 |
{ATOM_OFFSET(name), FUN_NAME, JSPROP_PERMANENT}, |
{ATOM_OFFSET(name), FUN_NAME, JSPROP_PERMANENT}, |
1416 |
JSProperty *prop; |
JSProperty *prop; |
1417 |
|
|
1418 |
prototypeId = ATOM_TO_JSID(cx->runtime->atomState.classPrototypeAtom); |
prototypeId = ATOM_TO_JSID(cx->runtime->atomState.classPrototypeAtom); |
1419 |
if (!OBJ_LOOKUP_PROPERTY(cx, obj, prototypeId, &pobj, &prop)) |
if (!obj->lookupProperty(cx, prototypeId, &pobj, &prop)) |
1420 |
return JS_FALSE; |
return JS_FALSE; |
1421 |
if (prop) |
if (prop) |
1422 |
OBJ_DROP_PROPERTY(cx, pobj, prop); |
pobj->dropProperty(cx, prop); |
1423 |
return JS_TRUE; |
return JS_TRUE; |
1424 |
} |
} |
1425 |
|
|
1461 |
* Make the prototype object to have the same parent as the function |
* Make the prototype object to have the same parent as the function |
1462 |
* object itself. |
* object itself. |
1463 |
*/ |
*/ |
1464 |
proto = js_NewObject(cx, &js_ObjectClass, NULL, OBJ_GET_PARENT(cx, obj), |
proto = js_NewObject(cx, &js_ObjectClass, NULL, OBJ_GET_PARENT(cx, obj)); |
|
0); |
|
1465 |
if (!proto) |
if (!proto) |
1466 |
return JS_FALSE; |
return JS_FALSE; |
1467 |
|
|
1472 |
* set the former here in fun_resolve, but eagerly define the latter |
* set the former here in fun_resolve, but eagerly define the latter |
1473 |
* in JS_InitClass, with the right attributes. |
* in JS_InitClass, with the right attributes. |
1474 |
*/ |
*/ |
1475 |
if (!js_SetClassPrototype(cx, obj, proto, |
if (!js_SetClassPrototype(cx, obj, proto, JSPROP_PERMANENT)) |
|
JSPROP_ENUMERATE | JSPROP_PERMANENT)) { |
|
|
cx->weakRoots.newborn[GCX_OBJECT] = NULL; |
|
1476 |
return JS_FALSE; |
return JS_FALSE; |
1477 |
} |
|
1478 |
*objp = obj; |
*objp = obj; |
1479 |
return JS_TRUE; |
return JS_TRUE; |
1480 |
} |
} |
1721 |
fun_hasInstance(JSContext *cx, JSObject *obj, jsval v, JSBool *bp) |
fun_hasInstance(JSContext *cx, JSObject *obj, jsval v, JSBool *bp) |
1722 |
{ |
{ |
1723 |
jsval pval; |
jsval pval; |
1724 |
|
jsid id = ATOM_TO_JSID(cx->runtime->atomState.classPrototypeAtom); |
1725 |
if (!OBJ_GET_PROPERTY(cx, obj, |
if (!obj->getProperty(cx, id, &pval)) |
|
ATOM_TO_JSID(cx->runtime->atomState |
|
|
.classPrototypeAtom), |
|
|
&pval)) { |
|
1726 |
return JS_FALSE; |
return JS_FALSE; |
|
} |
|
1727 |
|
|
1728 |
if (JSVAL_IS_PRIMITIVE(pval)) { |
if (JSVAL_IS_PRIMITIVE(pval)) { |
1729 |
/* |
/* |
1747 |
static void |
static void |
1748 |
fun_trace(JSTracer *trc, JSObject *obj) |
fun_trace(JSTracer *trc, JSObject *obj) |
1749 |
{ |
{ |
|
JSFunction *fun; |
|
|
|
|
1750 |
/* A newborn function object may have a not yet initialized private slot. */ |
/* A newborn function object may have a not yet initialized private slot. */ |
1751 |
fun = (JSFunction *) JS_GetPrivate(trc->context, obj); |
JSFunction *fun = (JSFunction *) obj->getPrivate(); |
1752 |
if (!fun) |
if (!fun) |
1753 |
return; |
return; |
1754 |
|
|
1769 |
static void |
static void |
1770 |
fun_finalize(JSContext *cx, JSObject *obj) |
fun_finalize(JSContext *cx, JSObject *obj) |
1771 |
{ |
{ |
|
JSFunction *fun; |
|
|
|
|
1772 |
/* Ignore newborn and cloned function objects. */ |
/* Ignore newborn and cloned function objects. */ |
1773 |
fun = (JSFunction *) JS_GetPrivate(cx, obj); |
JSFunction *fun = (JSFunction *) obj->getPrivate(); |
1774 |
if (!fun || FUN_OBJECT(fun) != obj) |
if (!fun || FUN_OBJECT(fun) != obj) |
1775 |
return; |
return; |
1776 |
|
|
1785 |
} |
} |
1786 |
} |
} |
1787 |
|
|
1788 |
|
uint32 |
1789 |
|
JSFunction::countInterpretedReservedSlots() const |
1790 |
|
{ |
1791 |
|
JS_ASSERT(FUN_INTERPRETED(this)); |
1792 |
|
|
1793 |
|
uint32 nslots = (u.i.nupvars == 0) |
1794 |
|
? 0 |
1795 |
|
: u.i.script->upvars()->length; |
1796 |
|
if (u.i.script->regexpsOffset != 0) |
1797 |
|
nslots += u.i.script->regexps()->length; |
1798 |
|
return nslots; |
1799 |
|
} |
1800 |
|
|
1801 |
static uint32 |
static uint32 |
1802 |
fun_reserveSlots(JSContext *cx, JSObject *obj) |
fun_reserveSlots(JSContext *cx, JSObject *obj) |
1803 |
{ |
{ |
|
JSFunction *fun; |
|
|
uint32 nslots; |
|
|
|
|
1804 |
/* |
/* |
1805 |
* We use JS_GetPrivate and not GET_FUNCTION_PRIVATE because during |
* We use getPrivate and not GET_FUNCTION_PRIVATE because during |
1806 |
* js_InitFunctionClass invocation the function is called before the |
* js_InitFunctionClass invocation the function is called before the |
1807 |
* private slot of the function object is set. |
* private slot of the function object is set. |
1808 |
*/ |
*/ |
1809 |
fun = (JSFunction *) JS_GetPrivate(cx, obj); |
JSFunction *fun = (JSFunction *) obj->getPrivate(); |
1810 |
nslots = 0; |
return (fun && FUN_INTERPRETED(fun)) |
1811 |
if (fun && FUN_INTERPRETED(fun) && fun->u.i.script) { |
? fun->countInterpretedReservedSlots() |
1812 |
if (fun->u.i.nupvars != 0) |
: 0; |
|
nslots = JS_SCRIPT_UPVARS(fun->u.i.script)->length; |
|
|
if (fun->u.i.script->regexpsOffset != 0) |
|
|
nslots += JS_SCRIPT_REGEXPS(fun->u.i.script)->length; |
|
|
} |
|
|
return nslots; |
|
1813 |
} |
} |
1814 |
|
|
1815 |
/* |
/* |
1897 |
} |
} |
1898 |
#endif |
#endif |
1899 |
|
|
1900 |
JS_REQUIRES_STACK JSBool |
JSBool |
1901 |
js_fun_call(JSContext *cx, uintN argc, jsval *vp) |
js_fun_call(JSContext *cx, uintN argc, jsval *vp) |
1902 |
{ |
{ |
1903 |
JSObject *obj; |
JSObject *obj; |
1906 |
void *mark; |
void *mark; |
1907 |
JSBool ok; |
JSBool ok; |
1908 |
|
|
1909 |
|
js_LeaveTrace(cx); |
1910 |
|
|
1911 |
obj = JS_THIS_OBJECT(cx, vp); |
obj = JS_THIS_OBJECT(cx, vp); |
1912 |
if (!obj || !OBJ_DEFAULT_VALUE(cx, obj, JSTYPE_FUNCTION, &vp[1])) |
if (!obj || !obj->defaultValue(cx, JSTYPE_FUNCTION, &vp[1])) |
1913 |
return JS_FALSE; |
return JS_FALSE; |
1914 |
fval = vp[1]; |
fval = vp[1]; |
1915 |
|
|
1958 |
return ok; |
return ok; |
1959 |
} |
} |
1960 |
|
|
1961 |
JS_REQUIRES_STACK JSBool |
JSBool |
1962 |
js_fun_apply(JSContext *cx, uintN argc, jsval *vp) |
js_fun_apply(JSContext *cx, uintN argc, jsval *vp) |
1963 |
{ |
{ |
1964 |
JSObject *obj, *aobj; |
JSObject *obj, *aobj; |
1974 |
return js_fun_call(cx, argc, vp); |
return js_fun_call(cx, argc, vp); |
1975 |
} |
} |
1976 |
|
|
1977 |
|
js_LeaveTrace(cx); |
1978 |
|
|
1979 |
obj = JS_THIS_OBJECT(cx, vp); |
obj = JS_THIS_OBJECT(cx, vp); |
1980 |
if (!obj || !OBJ_DEFAULT_VALUE(cx, obj, JSTYPE_FUNCTION, &vp[1])) |
if (!obj || !obj->defaultValue(cx, JSTYPE_FUNCTION, &vp[1])) |
1981 |
return JS_FALSE; |
return JS_FALSE; |
1982 |
fval = vp[1]; |
fval = vp[1]; |
1983 |
|
|
2027 |
return JS_FALSE; |
return JS_FALSE; |
2028 |
|
|
2029 |
/* Allocate stack space for fval, obj, and the args. */ |
/* Allocate stack space for fval, obj, and the args. */ |
2030 |
argc = (uintN)JS_MIN(length, ARRAY_INIT_LIMIT - 1); |
argc = (uintN)JS_MIN(length, JS_ARGS_LENGTH_MAX); |
2031 |
invokevp = js_AllocStack(cx, 2 + argc, &mark); |
invokevp = js_AllocStack(cx, 2 + argc, &mark); |
2032 |
if (!invokevp) |
if (!invokevp) |
2033 |
return JS_FALSE; |
return JS_FALSE; |
2072 |
if (!js_GetLengthProperty(cx, aobj, &length)) |
if (!js_GetLengthProperty(cx, aobj, &length)) |
2073 |
return JS_FALSE; |
return JS_FALSE; |
2074 |
|
|
2075 |
if (length >= ARRAY_INIT_LIMIT) |
if (length > JS_ARGS_LENGTH_MAX) |
2076 |
length = ARRAY_INIT_LIMIT - 1; |
length = JS_ARGS_LENGTH_MAX; |
2077 |
invokevp = js_AllocStack(cx, 2 + length, &mark); |
invokevp = js_AllocStack(cx, 2 + length, &mark); |
2078 |
if (!invokevp) |
if (!invokevp) |
2079 |
return JS_FALSE; |
return JS_FALSE; |
2120 |
const char *filename; |
const char *filename; |
2121 |
JSBool ok; |
JSBool ok; |
2122 |
JSString *str, *arg; |
JSString *str, *arg; |
2123 |
JSTokenStream ts; |
JSTokenStream ts(cx); |
2124 |
JSPrincipals *principals; |
JSPrincipals *principals; |
2125 |
jschar *collected_args, *cp; |
jschar *collected_args, *cp; |
2126 |
void *mark; |
void *mark; |
2128 |
JSTokenType tt; |
JSTokenType tt; |
2129 |
|
|
2130 |
if (!JS_IsConstructing(cx)) { |
if (!JS_IsConstructing(cx)) { |
2131 |
obj = js_NewObject(cx, &js_FunctionClass, NULL, NULL, 0); |
obj = js_NewObject(cx, &js_FunctionClass, NULL, NULL); |
2132 |
if (!obj) |
if (!obj) |
2133 |
return JS_FALSE; |
return JS_FALSE; |
2134 |
*rval = OBJECT_TO_JSVAL(obj); |
*rval = OBJECT_TO_JSVAL(obj); |
2135 |
} else { |
} else { |
2136 |
/* |
/* |
2137 |
* The constructor is called before the private slot is initialized so |
* The constructor is called before the private slot is initialized so |
2138 |
* we must use JS_GetPrivate, not GET_FUNCTION_PRIVATE here. |
* we must use getPrivate, not GET_FUNCTION_PRIVATE here. |
2139 |
*/ |
*/ |
2140 |
if (JS_GetPrivate(cx, obj)) |
if (obj->getPrivate()) |
2141 |
return JS_TRUE; |
return JS_TRUE; |
2142 |
} |
} |
2143 |
|
|
2212 |
* JSString length fits in 2 fewer bits than size_t has. |
* JSString length fits in 2 fewer bits than size_t has. |
2213 |
*/ |
*/ |
2214 |
old_args_length = args_length; |
old_args_length = args_length; |
2215 |
args_length = old_args_length + JSSTRING_LENGTH(arg); |
args_length = old_args_length + arg->length(); |
2216 |
if (args_length < old_args_length) { |
if (args_length < old_args_length) { |
2217 |
js_ReportAllocationOverflow(cx); |
js_ReportAllocationOverflow(cx); |
2218 |
return JS_FALSE; |
return JS_FALSE; |
2247 |
*/ |
*/ |
2248 |
for (i = 0; i < n; i++) { |
for (i = 0; i < n; i++) { |
2249 |
arg = JSVAL_TO_STRING(argv[i]); |
arg = JSVAL_TO_STRING(argv[i]); |
2250 |
arg_length = JSSTRING_LENGTH(arg); |
arg_length = arg->length(); |
2251 |
(void) js_strncpy(cp, JSSTRING_CHARS(arg), arg_length); |
(void) js_strncpy(cp, arg->chars(), arg_length); |
2252 |
cp += arg_length; |
cp += arg_length; |
2253 |
|
|
2254 |
/* Add separating comma or terminating 0. */ |
/* Add separating comma or terminating 0. */ |
2256 |
} |
} |
2257 |
|
|
2258 |
/* Initialize a tokenstream that reads from the given string. */ |
/* Initialize a tokenstream that reads from the given string. */ |
2259 |
if (!js_InitTokenStream(cx, &ts, collected_args, args_length, |
if (!ts.init(cx, collected_args, args_length, NULL, filename, lineno)) { |
|
NULL, filename, lineno)) { |
|
2260 |
JS_ARENA_RELEASE(&cx->tempPool, mark); |
JS_ARENA_RELEASE(&cx->tempPool, mark); |
2261 |
return JS_FALSE; |
return JS_FALSE; |
2262 |
} |
} |
2319 |
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, |
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, |
2320 |
JSMSG_BAD_FORMAL); |
JSMSG_BAD_FORMAL); |
2321 |
} |
} |
2322 |
js_CloseTokenStream(cx, &ts); |
ts.close(cx); |
2323 |
JS_ARENA_RELEASE(&cx->tempPool, mark); |
JS_ARENA_RELEASE(&cx->tempPool, mark); |
2324 |
if (state != OK) |
if (state != OK) |
2325 |
return JS_FALSE; |
return JS_FALSE; |
2335 |
} |
} |
2336 |
|
|
2337 |
return JSCompiler::compileFunctionBody(cx, fun, principals, |
return JSCompiler::compileFunctionBody(cx, fun, principals, |
2338 |
JSSTRING_CHARS(str), JSSTRING_LENGTH(str), |
str->chars(), str->length(), |
2339 |
filename, lineno); |
filename, lineno); |
2340 |
} |
} |
2341 |
|
|
2351 |
return NULL; |
return NULL; |
2352 |
fun = js_NewFunction(cx, proto, NULL, 0, JSFUN_INTERPRETED, obj, NULL); |
fun = js_NewFunction(cx, proto, NULL, 0, JSFUN_INTERPRETED, obj, NULL); |
2353 |
if (!fun) |
if (!fun) |
2354 |
goto bad; |
return NULL; |
2355 |
fun->u.i.script = js_NewScript(cx, 1, 1, 0, 0, 0, 0, 0); |
fun->u.i.script = js_NewScript(cx, 1, 1, 0, 0, 0, 0, 0); |
2356 |
if (!fun->u.i.script) |
if (!fun->u.i.script) |
2357 |
goto bad; |
return NULL; |
2358 |
fun->u.i.script->code[0] = JSOP_STOP; |
fun->u.i.script->code[0] = JSOP_STOP; |
2359 |
*SCRIPT_NOTES(fun->u.i.script) = SRC_NULL; |
*fun->u.i.script->notes() = SRC_NULL; |
2360 |
#ifdef CHECK_SCRIPT_OWNER |
#ifdef CHECK_SCRIPT_OWNER |
2361 |
fun->u.i.script->owner = NULL; |
fun->u.i.script->owner = NULL; |
2362 |
#endif |
#endif |
2363 |
return proto; |
return proto; |
|
|
|
|
bad: |
|
|
cx->weakRoots.newborn[GCX_OBJECT] = NULL; |
|
|
return NULL; |
|
2364 |
} |
} |
2365 |
|
|
2366 |
JSFunction * |
JSFunction * |
2373 |
JS_ASSERT(HAS_FUNCTION_CLASS(funobj)); |
JS_ASSERT(HAS_FUNCTION_CLASS(funobj)); |
2374 |
OBJ_SET_PARENT(cx, funobj, parent); |
OBJ_SET_PARENT(cx, funobj, parent); |
2375 |
} else { |
} else { |
2376 |
funobj = js_NewObject(cx, &js_FunctionClass, NULL, parent, 0); |
funobj = js_NewObject(cx, &js_FunctionClass, NULL, parent); |
2377 |
if (!funobj) |
if (!funobj) |
2378 |
return NULL; |
return NULL; |
2379 |
} |
} |
2380 |
JS_ASSERT(JSVAL_IS_VOID(funobj->fslots[JSSLOT_PRIVATE])); |
JS_ASSERT(!funobj->getPrivate()); |
2381 |
fun = (JSFunction *) funobj; |
fun = (JSFunction *) funobj; |
2382 |
|
|
2383 |
/* Initialize all function members. */ |
/* Initialize all function members. */ |
2384 |
fun->nargs = nargs; |
fun->nargs = nargs; |
2385 |
fun->flags = flags & (JSFUN_FLAGS_MASK | JSFUN_KINDMASK | JSFUN_TRACEABLE); |
fun->flags = flags & (JSFUN_FLAGS_MASK | JSFUN_KINDMASK | JSFUN_TRCINFO); |
2386 |
if ((flags & JSFUN_KINDMASK) >= JSFUN_INTERPRETED) { |
if ((flags & JSFUN_KINDMASK) >= JSFUN_INTERPRETED) { |
2387 |
JS_ASSERT(!native); |
JS_ASSERT(!native); |
2388 |
JS_ASSERT(nargs == 0); |
JS_ASSERT(nargs == 0); |
2398 |
fun->u.n.extra = 0; |
fun->u.n.extra = 0; |
2399 |
fun->u.n.spare = 0; |
fun->u.n.spare = 0; |
2400 |
fun->u.n.clasp = NULL; |
fun->u.n.clasp = NULL; |
2401 |
if (flags & JSFUN_TRACEABLE) { |
if (flags & JSFUN_TRCINFO) { |
2402 |
#ifdef JS_TRACER |
#ifdef JS_TRACER |
2403 |
JSTraceableNative *trcinfo = |
JSNativeTraceInfo *trcinfo = |
2404 |
JS_FUNC_TO_DATA_PTR(JSTraceableNative *, native); |
JS_FUNC_TO_DATA_PTR(JSNativeTraceInfo *, native); |
2405 |
fun->u.n.native = (JSNative) trcinfo->native; |
fun->u.n.native = (JSNative) trcinfo->native; |
2406 |
fun->u.n.trcinfo = trcinfo; |
fun->u.n.trcinfo = trcinfo; |
2407 |
#else |
#else |
2416 |
fun->atom = atom; |
fun->atom = atom; |
2417 |
|
|
2418 |
/* Set private to self to indicate non-cloned fully initialized function. */ |
/* Set private to self to indicate non-cloned fully initialized function. */ |
2419 |
FUN_OBJECT(fun)->fslots[JSSLOT_PRIVATE] = PRIVATE_TO_JSVAL(fun); |
FUN_OBJECT(fun)->setPrivate(fun); |
2420 |
return fun; |
return fun; |
2421 |
} |
} |
2422 |
|
|
2427 |
* The cloned function object does not need the extra JSFunction members |
* The cloned function object does not need the extra JSFunction members |
2428 |
* beyond JSObject as it points to fun via the private slot. |
* beyond JSObject as it points to fun via the private slot. |
2429 |
*/ |
*/ |
2430 |
JSObject *clone = js_NewObject(cx, &js_FunctionClass, NULL, parent, |
JSObject *clone = js_NewObject(cx, &js_FunctionClass, NULL, parent, sizeof(JSObject)); |
|
sizeof(JSObject)); |
|
2431 |
if (!clone) |
if (!clone) |
2432 |
return NULL; |
return NULL; |
2433 |
clone->fslots[JSSLOT_PRIVATE] = PRIVATE_TO_JSVAL(fun); |
clone->setPrivate(fun); |
2434 |
return clone; |
return clone; |
2435 |
} |
} |
2436 |
|
|
2437 |
JSObject * |
/* |
2438 |
js_NewFlatClosure(JSContext *cx, JSFunction *fun) |
* Create a new flat closure, but don't initialize the imported upvar |
2439 |
|
* values. The tracer calls this function and then initializes the upvar |
2440 |
|
* slots on trace. |
2441 |
|
*/ |
2442 |
|
JSObject * JS_FASTCALL |
2443 |
|
js_AllocFlatClosure(JSContext *cx, JSFunction *fun, JSObject *scopeChain) |
2444 |
{ |
{ |
2445 |
JS_ASSERT(FUN_FLAT_CLOSURE(fun)); |
JS_ASSERT(FUN_FLAT_CLOSURE(fun)); |
2446 |
|
JS_ASSERT((fun->u.i.script->upvarsOffset |
2447 |
|
? fun->u.i.script->upvars()->length |
2448 |
|
: 0) == fun->u.i.nupvars); |
2449 |
|
|
2450 |
JSObject *closure = js_CloneFunctionObject(cx, fun, cx->fp->scopeChain); |
JSObject *closure = js_CloneFunctionObject(cx, fun, scopeChain); |
2451 |
if (!closure || fun->u.i.script->upvarsOffset == 0) |
if (!closure) |
2452 |
return closure; |
return closure; |
2453 |
|
|
2454 |
uint32 nslots = JSSLOT_FREE(&js_FunctionClass); |
uint32 nslots = fun->countInterpretedReservedSlots(); |
2455 |
JS_ASSERT(nslots == JS_INITIAL_NSLOTS); |
if (!nslots) |
2456 |
nslots += fun_reserveSlots(cx, closure); |
return closure; |
2457 |
if (!js_ReallocSlots(cx, closure, nslots, JS_TRUE)) |
if (!js_EnsureReservedSlots(cx, closure, nslots)) |
2458 |
return NULL; |
return NULL; |
2459 |
|
|
2460 |
JSUpvarArray *uva = JS_SCRIPT_UPVARS(fun->u.i.script); |
return closure; |
2461 |
|
} |
2462 |
|
|
2463 |
|
JS_DEFINE_CALLINFO_3(extern, OBJECT, js_AllocFlatClosure, |
2464 |
|
CONTEXT, FUNCTION, OBJECT, 0, 0) |
2465 |
|
|
2466 |
|
JSObject * |
2467 |
|
js_NewFlatClosure(JSContext *cx, JSFunction *fun) |
2468 |
|
{ |
2469 |
|
JSObject *closure = js_AllocFlatClosure(cx, fun, cx->fp->scopeChain); |
2470 |
|
if (!closure || fun->u.i.nupvars == 0) |
2471 |
|
return closure; |
2472 |
|
|
2473 |
|
JSUpvarArray *uva = fun->u.i.script->upvars(); |
2474 |
JS_ASSERT(uva->length <= size_t(closure->dslots[-1])); |
JS_ASSERT(uva->length <= size_t(closure->dslots[-1])); |
2475 |
|
|
2476 |
uintN level = fun->u.i.script->staticLevel; |
uintN level = fun->u.i.script->staticLevel; |
2511 |
fun = js_NewFunction(cx, NULL, native, nargs, attrs, obj, atom); |
fun = js_NewFunction(cx, NULL, native, nargs, attrs, obj, atom); |
2512 |
if (!fun) |
if (!fun) |
2513 |
return NULL; |
return NULL; |
2514 |
if (!OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_JSID(atom), |
if (!obj->defineProperty(cx, ATOM_TO_JSID(atom), OBJECT_TO_JSVAL(FUN_OBJECT(fun)), |
2515 |
OBJECT_TO_JSVAL(FUN_OBJECT(fun)), |
gsop, gsop, attrs & ~JSFUN_FLAGS_MASK)) { |
|
gsop, gsop, |
|
|
attrs & ~JSFUN_FLAGS_MASK, NULL)) { |
|
2516 |
return NULL; |
return NULL; |
2517 |
} |
} |
2518 |
return fun; |
return fun; |
2533 |
if (JSVAL_IS_OBJECT(v)) { |
if (JSVAL_IS_OBJECT(v)) { |
2534 |
obj = JSVAL_TO_OBJECT(v); |
obj = JSVAL_TO_OBJECT(v); |
2535 |
if (obj && OBJ_GET_CLASS(cx, obj) != &js_FunctionClass) { |
if (obj && OBJ_GET_CLASS(cx, obj) != &js_FunctionClass) { |
2536 |
if (!OBJ_DEFAULT_VALUE(cx, obj, JSTYPE_FUNCTION, &v)) |
if (!obj->defaultValue(cx, JSTYPE_FUNCTION, &v)) |
2537 |
return NULL; |
return NULL; |
2538 |
obj = VALUE_IS_FUNCTION(cx, v) ? JSVAL_TO_OBJECT(v) : NULL; |
obj = VALUE_IS_FUNCTION(cx, v) ? JSVAL_TO_OBJECT(v) : NULL; |
2539 |
} |
} |
2604 |
if (flags & JSV2F_ITERATOR) { |
if (flags & JSV2F_ITERATOR) { |
2605 |
error = JSMSG_BAD_ITERATOR; |
error = JSMSG_BAD_ITERATOR; |
2606 |
name = js_iterator_str; |
name = js_iterator_str; |
2607 |
tvr.u.string = js_ValueToSource(cx, *vp); |
JSString *src = js_ValueToSource(cx, *vp); |
2608 |
if (!tvr.u.string) |
if (!src) |
2609 |
goto out; |
goto out; |
2610 |
tvr.u.string = js_QuoteString(cx, tvr.u.string, 0); |
tvr.u.value = STRING_TO_JSVAL(src); |
2611 |
if (!tvr.u.string) |
JSString *qsrc = js_QuoteString(cx, src, 0); |
2612 |
|
if (!qsrc) |
2613 |
goto out; |
goto out; |
2614 |
source = js_GetStringBytes(cx, tvr.u.string); |
tvr.u.value = STRING_TO_JSVAL(qsrc); |
2615 |
|
source = js_GetStringBytes(cx, qsrc); |
2616 |
if (!source) |
if (!source) |
2617 |
goto out; |
goto out; |
2618 |
} else if (flags & JSV2F_CONSTRUCT) { |
} else if (flags & JSV2F_CONSTRUCT) { |
2682 |
|
|
2683 |
for (dup = map->lastdup; dup; dup = next) { |
for (dup = map->lastdup; dup; dup = next) { |
2684 |
next = dup->link; |
next = dup->link; |
2685 |
JS_free(cx, dup); |
cx->free(dup); |
2686 |
} |
} |
2687 |
JS_DHashTableFinish(&map->names); |
JS_DHashTableFinish(&map->names); |
2688 |
JS_free(cx, map); |
cx->free(map); |
2689 |
} |
} |
2690 |
|
|
2691 |
static JSBool |
static JSBool |
2712 |
} |
} |
2713 |
if (entry->name) { |
if (entry->name) { |
2714 |
JS_ASSERT(entry->name == name); |
JS_ASSERT(entry->name == name); |
2715 |
JS_ASSERT(entry->localKind == JSLOCAL_ARG); |
JS_ASSERT(entry->localKind == JSLOCAL_ARG && localKind == JSLOCAL_ARG); |
2716 |
dup = (JSNameIndexPair *) JS_malloc(cx, sizeof *dup); |
dup = (JSNameIndexPair *) cx->malloc(sizeof *dup); |
2717 |
if (!dup) |
if (!dup) |
2718 |
return JS_FALSE; |
return JS_FALSE; |
2719 |
dup->name = entry->name; |
dup->name = entry->name; |
2759 |
if (n > 1) { |
if (n > 1) { |
2760 |
array = fun->u.i.names.array; |
array = fun->u.i.names.array; |
2761 |
} else { |
} else { |
2762 |
array = (jsuword *) JS_malloc(cx, MAX_ARRAY_LOCALS * sizeof *array); |
array = (jsuword *) cx->malloc(MAX_ARRAY_LOCALS * sizeof *array); |
2763 |
if (!array) |
if (!array) |
2764 |
return JS_FALSE; |
return JS_FALSE; |
2765 |
array[0] = fun->u.i.names.taggedAtom; |
array[0] = fun->u.i.names.taggedAtom; |
2784 |
} |
} |
2785 |
} else if (n == MAX_ARRAY_LOCALS) { |
} else if (n == MAX_ARRAY_LOCALS) { |
2786 |
array = fun->u.i.names.array; |
array = fun->u.i.names.array; |
2787 |
map = (JSLocalNameMap *) JS_malloc(cx, sizeof *map); |
map = (JSLocalNameMap *) cx->malloc(sizeof *map); |
2788 |
if (!map) |
if (!map) |
2789 |
return JS_FALSE; |
return JS_FALSE; |
2790 |
if (!JS_DHashTableInit(&map->names, JS_DHashGetStubOps(), |
if (!JS_DHashTableInit(&map->names, JS_DHashGetStubOps(), |
2792 |
JS_DHASH_DEFAULT_CAPACITY(MAX_ARRAY_LOCALS |
JS_DHASH_DEFAULT_CAPACITY(MAX_ARRAY_LOCALS |
2793 |
* 2))) { |
* 2))) { |
2794 |
JS_ReportOutOfMemory(cx); |
JS_ReportOutOfMemory(cx); |
2795 |
JS_free(cx, map); |
cx->free(map); |
2796 |
return JS_FALSE; |
return JS_FALSE; |
2797 |
} |
} |
2798 |
|
|
2825 |
* to replace fun->u.i.names with the built map. |
* to replace fun->u.i.names with the built map. |
2826 |
*/ |
*/ |
2827 |
fun->u.i.names.map = map; |
fun->u.i.names.map = map; |
2828 |
JS_free(cx, array); |
cx->free(array); |
2829 |
} else { |
} else { |
2830 |
if (*indexp == JS_BITMASK(16)) { |
if (*indexp == JS_BITMASK(16)) { |
2831 |
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, |
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, |
2936 |
return JS_DHASH_NEXT; |
return JS_DHASH_NEXT; |
2937 |
} |
} |
2938 |
|
|
2939 |
jsuword * |
JS_FRIEND_API(jsuword *) |
2940 |
js_GetLocalNameArray(JSContext *cx, JSFunction *fun, JSArenaPool *pool) |
js_GetLocalNameArray(JSContext *cx, JSFunction *fun, JSArenaPool *pool) |
2941 |
{ |
{ |
2942 |
uintN n; |
uintN n; |
3047 |
if (n <= 1) |
if (n <= 1) |
3048 |
return; |
return; |
3049 |
if (n <= MAX_ARRAY_LOCALS) |
if (n <= MAX_ARRAY_LOCALS) |
3050 |
JS_free(cx, fun->u.i.names.array); |
cx->free(fun->u.i.names.array); |
3051 |
else |
else |
3052 |
FreeLocalNameHash(cx, fun->u.i.names.map); |
FreeLocalNameHash(cx, fun->u.i.names.map); |
3053 |
} |
} |
3063 |
n = fun->nargs + fun->u.i.nvars + fun->u.i.nupvars; |
n = fun->nargs + fun->u.i.nvars + fun->u.i.nupvars; |
3064 |
if (2 <= n && n < MAX_ARRAY_LOCALS) { |
if (2 <= n && n < MAX_ARRAY_LOCALS) { |
3065 |
/* Shrink over-allocated array ignoring realloc failures. */ |
/* Shrink over-allocated array ignoring realloc failures. */ |
3066 |
array = (jsuword *) JS_realloc(cx, fun->u.i.names.array, |
array = (jsuword *) cx->realloc(fun->u.i.names.array, |
3067 |
n * sizeof *array); |
n * sizeof *array); |
3068 |
if (array) |
if (array) |
3069 |
fun->u.i.names.array = array; |
fun->u.i.names.array = array; |
3070 |
} |
} |
3071 |
#ifdef DEBUG |
#ifdef DEBUG |
3072 |
// XXX no JS_DHashMarkTableImmutable on 1.9.1 |
if (n > MAX_ARRAY_LOCALS) |
3073 |
// if (n > MAX_ARRAY_LOCALS) |
JS_DHashMarkTableImmutable(&fun->u.i.names.map->names); |
|
// JS_DHashMarkTableImmutable(&fun->u.i.names.map->names); |
|
3074 |
#endif |
#endif |
3075 |
} |
} |