1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 : * vim: set ts=8 sw=4 et tw=99:
3 : *
4 : * ***** BEGIN LICENSE BLOCK *****
5 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 : *
7 : * The contents of this file are subject to the Mozilla Public License Version
8 : * 1.1 (the "License"); you may not use this file except in compliance with
9 : * the License. You may obtain a copy of the License at
10 : * http://www.mozilla.org/MPL/
11 : *
12 : * Software distributed under the License is distributed on an "AS IS" basis,
13 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14 : * for the specific language governing rights and limitations under the
15 : * License.
16 : *
17 : * The Original Code is SpiderMonkey arguments object code.
18 : *
19 : * The Initial Developer of the Original Code is
20 : * the Mozilla Foundation.
21 : * Portions created by the Initial Developer are Copyright (C) 2012
22 : * the Initial Developer. All Rights Reserved.
23 : *
24 : * Contributor(s):
25 : * Luke Wagner <luke@mozilla.com>
26 : *
27 : * Alternatively, the contents of this file may be used under the terms of
28 : * either of the GNU General Public License Version 2 or later (the "GPL"),
29 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30 : * in which case the provisions of the GPL or the LGPL are applicable instead
31 : * of those above. If you wish to allow use of your version of this file only
32 : * under the terms of either the GPL or the LGPL, and not to allow others to
33 : * use your version of this file under the terms of the MPL, indicate your
34 : * decision by deleting the provisions above and replace them with the notice
35 : * and other provisions required by the GPL or the LGPL. If you do not delete
36 : * the provisions above, a recipient may use your version of this file under
37 : * the terms of any one of the MPL, the GPL or the LGPL.
38 : *
39 : * ***** END LICENSE BLOCK ***** */
40 :
41 : #include "jsgc.h"
42 : #include "jsinfer.h"
43 : #include "jsinterp.h"
44 :
45 : #include "vm/GlobalObject.h"
46 : #include "vm/MethodGuard.h"
47 : #include "vm/Stack.h"
48 : #include "vm/Xdr.h"
49 :
50 : #include "jsobjinlines.h"
51 :
52 : #include "gc/Barrier-inl.h"
53 : #include "vm/ArgumentsObject-inl.h"
54 :
55 : using namespace js;
56 : using namespace js::gc;
57 :
58 : struct PutArg
59 : {
60 362278 : PutArg(JSCompartment *comp, ArgumentsObject &argsobj)
61 362278 : : compartment(comp), argsobj(argsobj), dst(argsobj.data()->slots) {}
62 : JSCompartment *compartment;
63 : ArgumentsObject &argsobj;
64 : HeapValue *dst;
65 1171279 : bool operator()(unsigned i, Value *src) {
66 1171279 : JS_ASSERT(dst->isUndefined());
67 1171279 : if (!argsobj.isElementDeleted(i))
68 1170928 : dst->set(compartment, *src);
69 1171279 : ++dst;
70 1171279 : return true;
71 : }
72 : };
73 :
74 : void
75 361711 : js_PutArgsObject(StackFrame *fp)
76 : {
77 361711 : ArgumentsObject &argsobj = fp->argsObj();
78 361711 : if (argsobj.isNormalArguments()) {
79 356716 : JS_ASSERT(argsobj.maybeStackFrame() == fp);
80 356716 : JSCompartment *comp = fp->scopeChain().compartment();
81 356716 : fp->forEachCanonicalActualArg(PutArg(comp, argsobj));
82 356716 : argsobj.setStackFrame(NULL);
83 : } else {
84 4995 : JS_ASSERT(!argsobj.maybeStackFrame());
85 : }
86 361711 : }
87 :
88 : ArgumentsObject *
89 362440 : ArgumentsObject::create(JSContext *cx, uint32_t argc, JSObject &callee)
90 : {
91 362440 : JS_ASSERT(argc <= StackSpace::ARGS_LENGTH_MAX);
92 :
93 362440 : JSObject *proto = callee.global().getOrCreateObjectPrototype(cx);
94 362440 : if (!proto)
95 0 : return NULL;
96 :
97 724880 : RootedVarTypeObject type(cx);
98 :
99 362440 : type = proto->getNewType(cx);
100 362440 : if (!type)
101 0 : return NULL;
102 :
103 362440 : bool strict = callee.toFunction()->inStrictMode();
104 362440 : Class *clasp = strict ? &StrictArgumentsObjectClass : &NormalArgumentsObjectClass;
105 :
106 724880 : RootedVarShape emptyArgumentsShape(cx);
107 : emptyArgumentsShape =
108 : EmptyShape::getInitialShape(cx, clasp, proto,
109 : proto->getParent(), FINALIZE_KIND,
110 362440 : BaseShape::INDEXED);
111 362440 : if (!emptyArgumentsShape)
112 0 : return NULL;
113 :
114 362440 : unsigned numDeletedWords = NumWordsForBitArrayOfLength(argc);
115 : unsigned numBytes = offsetof(ArgumentsData, slots) +
116 : numDeletedWords * sizeof(size_t) +
117 362440 : argc * sizeof(Value);
118 :
119 362440 : ArgumentsData *data = (ArgumentsData *)cx->malloc_(numBytes);
120 362440 : if (!data)
121 0 : return NULL;
122 :
123 362440 : data->callee.init(ObjectValue(callee));
124 1533719 : for (HeapValue *vp = data->slots; vp != data->slots + argc; vp++)
125 1171279 : vp->init(UndefinedValue());
126 362440 : data->deletedBits = (size_t *)(data->slots + argc);
127 362440 : ClearAllBitArrayElements(data->deletedBits, numDeletedWords);
128 :
129 : /* We have everything needed to fill in the object, so make the object. */
130 362440 : JSObject *obj = JSObject::create(cx, FINALIZE_KIND, emptyArgumentsShape, type, NULL);
131 362440 : if (!obj)
132 0 : return NULL;
133 :
134 362440 : ArgumentsObject &argsobj = obj->asArguments();
135 :
136 362440 : JS_ASSERT(UINT32_MAX > (uint64_t(argc) << PACKED_BITS_COUNT));
137 362440 : argsobj.initInitialLength(argc);
138 362440 : argsobj.initData(data);
139 362440 : argsobj.setStackFrame(NULL);
140 :
141 362440 : JS_ASSERT(argsobj.numFixedSlots() >= NormalArgumentsObject::RESERVED_SLOTS);
142 362440 : JS_ASSERT(argsobj.numFixedSlots() >= StrictArgumentsObject::RESERVED_SLOTS);
143 :
144 362440 : return &argsobj;
145 : }
146 :
147 : bool
148 361882 : ArgumentsObject::create(JSContext *cx, StackFrame *fp)
149 : {
150 361882 : JS_ASSERT(fp->script()->needsArgsObj());
151 361882 : JS_ASSERT(!fp->hasCallObj());
152 :
153 361882 : ArgumentsObject *argsobj = ArgumentsObject::create(cx, fp->numActualArgs(), fp->callee());
154 361882 : if (!argsobj)
155 0 : return NULL;
156 :
157 : /*
158 : * Strict mode functions have arguments objects that copy the initial
159 : * actual parameter values. Non-strict mode arguments use the frame pointer
160 : * to retrieve up-to-date parameter values.
161 : */
162 361882 : if (argsobj->isStrictArguments())
163 5004 : fp->forEachCanonicalActualArg(PutArg(cx->compartment, *argsobj));
164 : else
165 356878 : argsobj->setStackFrame(fp);
166 :
167 361882 : fp->initArgsObj(*argsobj);
168 361882 : return argsobj;
169 : }
170 :
171 : ArgumentsObject *
172 558 : ArgumentsObject::createUnexpected(JSContext *cx, StackFrame *fp)
173 : {
174 558 : ArgumentsObject *argsobj = create(cx, fp->numActualArgs(), fp->callee());
175 558 : if (!argsobj)
176 0 : return NULL;
177 :
178 558 : fp->forEachCanonicalActualArg(PutArg(cx->compartment, *argsobj));
179 558 : return argsobj;
180 : }
181 :
182 : static JSBool
183 846 : args_delProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp)
184 : {
185 846 : ArgumentsObject &argsobj = obj->asArguments();
186 846 : if (JSID_IS_INT(id)) {
187 414 : unsigned arg = unsigned(JSID_TO_INT(id));
188 414 : if (arg < argsobj.initialLength() && !argsobj.isElementDeleted(arg)) {
189 414 : argsobj.setElement(arg, UndefinedValue());
190 414 : argsobj.markElementDeleted(arg);
191 : }
192 432 : } else if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) {
193 432 : argsobj.markLengthOverridden();
194 0 : } else if (JSID_IS_ATOM(id, cx->runtime->atomState.calleeAtom)) {
195 0 : argsobj.asNormalArguments().clearCallee();
196 : }
197 846 : return true;
198 : }
199 :
200 : static JSBool
201 2503 : ArgGetter(JSContext *cx, JSObject *obj, jsid id, Value *vp)
202 : {
203 2503 : if (!obj->isNormalArguments())
204 0 : return true;
205 :
206 2503 : NormalArgumentsObject &argsobj = obj->asNormalArguments();
207 2503 : if (JSID_IS_INT(id)) {
208 : /*
209 : * arg can exceed the number of arguments if a script changed the
210 : * prototype to point to another Arguments object with a bigger argc.
211 : */
212 1108 : unsigned arg = unsigned(JSID_TO_INT(id));
213 1108 : if (arg < argsobj.initialLength() && !argsobj.isElementDeleted(arg)) {
214 1099 : if (StackFrame *fp = argsobj.maybeStackFrame())
215 990 : *vp = fp->canonicalActualArg(arg);
216 : else
217 109 : *vp = argsobj.element(arg);
218 : }
219 1395 : } else if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) {
220 27 : if (!argsobj.hasOverriddenLength())
221 27 : vp->setInt32(argsobj.initialLength());
222 : } else {
223 1368 : JS_ASSERT(JSID_IS_ATOM(id, cx->runtime->atomState.calleeAtom));
224 1368 : const Value &v = argsobj.callee();
225 1368 : if (!v.isMagic(JS_OVERWRITTEN_CALLEE))
226 1368 : *vp = v;
227 : }
228 2503 : return true;
229 : }
230 :
231 : static JSBool
232 909 : ArgSetter(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp)
233 : {
234 909 : if (!obj->isNormalArguments())
235 0 : return true;
236 :
237 909 : NormalArgumentsObject &argsobj = obj->asNormalArguments();
238 :
239 909 : if (JSID_IS_INT(id)) {
240 504 : unsigned arg = unsigned(JSID_TO_INT(id));
241 504 : if (arg < argsobj.initialLength()) {
242 504 : if (StackFrame *fp = argsobj.maybeStackFrame()) {
243 468 : JSScript *script = fp->functionScript();
244 468 : JS_ASSERT(script->needsArgsObj());
245 468 : if (arg < fp->numFormalArgs())
246 297 : types::TypeScript::SetArgument(cx, script, arg, *vp);
247 468 : fp->canonicalActualArg(arg) = *vp;
248 468 : return true;
249 : }
250 : }
251 : } else {
252 405 : JS_ASSERT(JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom) ||
253 405 : JSID_IS_ATOM(id, cx->runtime->atomState.calleeAtom));
254 : }
255 :
256 : /*
257 : * For simplicity we use delete/define to replace the property with one
258 : * backed by the default Object getter and setter. Note that we rely on
259 : * args_delProperty to clear the corresponding reserved slot so the GC can
260 : * collect its value. Note also that we must define the property instead
261 : * of setting it in case the user has changed the prototype to an object
262 : * that has a setter for this id.
263 : */
264 882 : AutoValueRooter tvr(cx);
265 441 : return js_DeleteGeneric(cx, &argsobj, id, tvr.addr(), false) &&
266 441 : js_DefineProperty(cx, &argsobj, id, vp, NULL, NULL, JSPROP_ENUMERATE);
267 : }
268 :
269 : static JSBool
270 5442 : args_resolve(JSContext *cx, JSObject *obj, jsid id, unsigned flags,
271 : JSObject **objp)
272 : {
273 5442 : *objp = NULL;
274 :
275 5442 : NormalArgumentsObject &argsobj = obj->asNormalArguments();
276 :
277 5442 : unsigned attrs = JSPROP_SHARED | JSPROP_SHADOWABLE;
278 5442 : if (JSID_IS_INT(id)) {
279 4044 : uint32_t arg = uint32_t(JSID_TO_INT(id));
280 4044 : if (arg >= argsobj.initialLength() || argsobj.isElementDeleted(arg))
281 2610 : return true;
282 :
283 1434 : attrs |= JSPROP_ENUMERATE;
284 1398 : } else if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) {
285 572 : if (argsobj.hasOverriddenLength())
286 27 : return true;
287 : } else {
288 826 : if (!JSID_IS_ATOM(id, cx->runtime->atomState.calleeAtom))
289 340 : return true;
290 :
291 486 : if (argsobj.callee().isMagic(JS_OVERWRITTEN_CALLEE))
292 0 : return true;
293 : }
294 :
295 2465 : Value undef = UndefinedValue();
296 2465 : if (!js_DefineProperty(cx, &argsobj, id, &undef, ArgGetter, ArgSetter, attrs))
297 0 : return JS_FALSE;
298 :
299 2465 : *objp = &argsobj;
300 2465 : return true;
301 : }
302 :
303 : bool
304 95906 : NormalArgumentsObject::optimizedGetElem(JSContext *cx, StackFrame *fp, const Value &elem, Value *vp)
305 : {
306 95906 : JS_ASSERT(!fp->hasArgsObj());
307 :
308 : /* Fast path: no need to convert to id when elem is already an int in range. */
309 95906 : if (elem.isInt32()) {
310 95786 : int32_t i = elem.toInt32();
311 95786 : if (i >= 0 && uint32_t(i) < fp->numActualArgs()) {
312 93401 : *vp = fp->canonicalActualArg(i);
313 93401 : return true;
314 : }
315 : }
316 :
317 : /* Slow path: create and canonicalize an id, then emulate args_resolve. */
318 :
319 : jsid id;
320 2505 : if (!ValueToId(cx, elem, &id))
321 0 : return false;
322 2505 : id = js_CheckForStringIndex(id);
323 :
324 2505 : if (JSID_IS_INT(id)) {
325 2475 : int32_t i = JSID_TO_INT(id);
326 2475 : if (i >= 0 && uint32_t(i) < fp->numActualArgs()) {
327 90 : *vp = fp->canonicalActualArg(i);
328 90 : return true;
329 : }
330 : }
331 :
332 2415 : if (id == ATOM_TO_JSID(cx->runtime->atomState.lengthAtom)) {
333 0 : *vp = Int32Value(fp->numActualArgs());
334 0 : return true;
335 : }
336 :
337 2415 : if (id == ATOM_TO_JSID(cx->runtime->atomState.calleeAtom)) {
338 0 : *vp = ObjectValue(fp->callee());
339 0 : return true;
340 : }
341 :
342 2415 : JSObject *proto = fp->scopeChain().global().getOrCreateObjectPrototype(cx);
343 2415 : if (!proto)
344 0 : return false;
345 :
346 2415 : return proto->getGeneric(cx, id, vp);
347 : }
348 :
349 : static JSBool
350 180 : args_enumerate(JSContext *cx, JSObject *obj)
351 : {
352 180 : NormalArgumentsObject &argsobj = obj->asNormalArguments();
353 :
354 : /*
355 : * Trigger reflection in args_resolve using a series of js_LookupProperty
356 : * calls.
357 : */
358 180 : int argc = int(argsobj.initialLength());
359 540 : for (int i = -2; i != argc; i++) {
360 : jsid id = (i == -2)
361 180 : ? ATOM_TO_JSID(cx->runtime->atomState.lengthAtom)
362 : : (i == -1)
363 180 : ? ATOM_TO_JSID(cx->runtime->atomState.calleeAtom)
364 720 : : INT_TO_JSID(i);
365 :
366 : JSObject *pobj;
367 : JSProperty *prop;
368 360 : if (!js_LookupProperty(cx, &argsobj, id, &pobj, &prop))
369 0 : return false;
370 : }
371 180 : return true;
372 : }
373 :
374 : static JSBool
375 207 : StrictArgGetter(JSContext *cx, JSObject *obj, jsid id, Value *vp)
376 : {
377 207 : if (!obj->isStrictArguments())
378 0 : return true;
379 :
380 207 : StrictArgumentsObject &argsobj = obj->asStrictArguments();
381 :
382 207 : if (JSID_IS_INT(id)) {
383 : /*
384 : * arg can exceed the number of arguments if a script changed the
385 : * prototype to point to another Arguments object with a bigger argc.
386 : */
387 207 : unsigned arg = unsigned(JSID_TO_INT(id));
388 207 : if (arg < argsobj.initialLength() && !argsobj.isElementDeleted(arg))
389 207 : *vp = argsobj.element(arg);
390 : } else {
391 0 : JS_ASSERT(JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom));
392 0 : if (!argsobj.hasOverriddenLength())
393 0 : vp->setInt32(argsobj.initialLength());
394 : }
395 207 : return true;
396 : }
397 :
398 : static JSBool
399 279 : StrictArgSetter(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp)
400 : {
401 279 : if (!obj->isStrictArguments())
402 0 : return true;
403 :
404 279 : StrictArgumentsObject &argsobj = obj->asStrictArguments();
405 :
406 279 : if (JSID_IS_INT(id)) {
407 279 : unsigned arg = unsigned(JSID_TO_INT(id));
408 279 : if (arg < argsobj.initialLength()) {
409 279 : argsobj.setElement(arg, *vp);
410 279 : return true;
411 : }
412 : } else {
413 0 : JS_ASSERT(JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom));
414 : }
415 :
416 : /*
417 : * For simplicity we use delete/set to replace the property with one
418 : * backed by the default Object getter and setter. Note that we rely on
419 : * args_delProperty to clear the corresponding reserved slot so the GC can
420 : * collect its value.
421 : */
422 0 : AutoValueRooter tvr(cx);
423 0 : return js_DeleteGeneric(cx, &argsobj, id, tvr.addr(), strict) &&
424 0 : js_SetPropertyHelper(cx, &argsobj, id, 0, vp, strict);
425 : }
426 :
427 : static JSBool
428 1142 : strictargs_resolve(JSContext *cx, JSObject *obj, jsid id, unsigned flags, JSObject **objp)
429 : {
430 1142 : *objp = NULL;
431 :
432 1142 : StrictArgumentsObject &argsobj = obj->asStrictArguments();
433 :
434 1142 : unsigned attrs = JSPROP_SHARED | JSPROP_SHADOWABLE;
435 1142 : PropertyOp getter = StrictArgGetter;
436 1142 : StrictPropertyOp setter = StrictArgSetter;
437 :
438 1142 : if (JSID_IS_INT(id)) {
439 1094 : uint32_t arg = uint32_t(JSID_TO_INT(id));
440 1094 : if (arg >= argsobj.initialLength() || argsobj.isElementDeleted(arg))
441 603 : return true;
442 :
443 491 : attrs |= JSPROP_ENUMERATE;
444 48 : } else if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) {
445 48 : if (argsobj.hasOverriddenLength())
446 0 : return true;
447 : } else {
448 0 : if (!JSID_IS_ATOM(id, cx->runtime->atomState.calleeAtom) &&
449 0 : !JSID_IS_ATOM(id, cx->runtime->atomState.callerAtom)) {
450 0 : return true;
451 : }
452 :
453 0 : attrs = JSPROP_PERMANENT | JSPROP_GETTER | JSPROP_SETTER | JSPROP_SHARED;
454 0 : getter = CastAsPropertyOp(argsobj.global().getThrowTypeError());
455 0 : setter = CastAsStrictPropertyOp(argsobj.global().getThrowTypeError());
456 : }
457 :
458 539 : Value undef = UndefinedValue();
459 539 : if (!js_DefineProperty(cx, &argsobj, id, &undef, getter, setter, attrs))
460 0 : return false;
461 :
462 539 : *objp = &argsobj;
463 539 : return true;
464 : }
465 :
466 : static JSBool
467 0 : strictargs_enumerate(JSContext *cx, JSObject *obj)
468 : {
469 0 : StrictArgumentsObject *argsobj = &obj->asStrictArguments();
470 :
471 : /*
472 : * Trigger reflection in strictargs_resolve using a series of
473 : * js_LookupProperty calls.
474 : */
475 : JSObject *pobj;
476 : JSProperty *prop;
477 :
478 : // length
479 0 : if (!js_LookupProperty(cx, argsobj, ATOM_TO_JSID(cx->runtime->atomState.lengthAtom), &pobj, &prop))
480 0 : return false;
481 :
482 : // callee
483 0 : if (!js_LookupProperty(cx, argsobj, ATOM_TO_JSID(cx->runtime->atomState.calleeAtom), &pobj, &prop))
484 0 : return false;
485 :
486 : // caller
487 0 : if (!js_LookupProperty(cx, argsobj, ATOM_TO_JSID(cx->runtime->atomState.callerAtom), &pobj, &prop))
488 0 : return false;
489 :
490 0 : for (uint32_t i = 0, argc = argsobj->initialLength(); i < argc; i++) {
491 0 : if (!js_LookupProperty(cx, argsobj, INT_TO_JSID(i), &pobj, &prop))
492 0 : return false;
493 : }
494 :
495 0 : return true;
496 : }
497 :
498 : static void
499 362440 : args_finalize(FreeOp *fop, JSObject *obj)
500 : {
501 362440 : fop->free_(reinterpret_cast<void *>(obj->asArguments().data()));
502 362440 : }
503 :
504 : static void
505 1311 : args_trace(JSTracer *trc, JSObject *obj)
506 : {
507 1311 : ArgumentsObject &argsobj = obj->asArguments();
508 1311 : ArgumentsData *data = argsobj.data();
509 1311 : MarkValue(trc, &data->callee, js_callee_str);
510 1311 : MarkValueRange(trc, argsobj.initialLength(), data->slots, js_arguments_str);
511 :
512 : /*
513 : * If a generator's arguments or call object escapes, and the generator
514 : * frame is not executing, the generator object needs to be marked because
515 : * it is not otherwise reachable. An executing generator is rooted by its
516 : * invocation. To distinguish the two cases (which imply different access
517 : * paths to the generator object), we use the JSFRAME_FLOATING_GENERATOR
518 : * flag, which is only set on the StackFrame kept in the generator object's
519 : * JSGenerator.
520 : */
521 : #if JS_HAS_GENERATORS
522 1311 : StackFrame *fp = argsobj.maybeStackFrame();
523 1311 : if (fp && fp->isFloatingGenerator())
524 350 : MarkObject(trc, &js_FloatingFrameToGenerator(fp)->obj, "generator object");
525 : #endif
526 1311 : }
527 :
528 : /*
529 : * The classes below collaborate to lazily reflect and synchronize actual
530 : * argument values, argument count, and callee function object stored in a
531 : * StackFrame with their corresponding property values in the frame's
532 : * arguments object.
533 : */
534 : Class js::NormalArgumentsObjectClass = {
535 : "Arguments",
536 : JSCLASS_NEW_RESOLVE | JSCLASS_IMPLEMENTS_BARRIERS |
537 : JSCLASS_HAS_RESERVED_SLOTS(NormalArgumentsObject::RESERVED_SLOTS) |
538 : JSCLASS_HAS_CACHED_PROTO(JSProto_Object) |
539 : JSCLASS_FOR_OF_ITERATION,
540 : JS_PropertyStub, /* addProperty */
541 : args_delProperty,
542 : JS_PropertyStub, /* getProperty */
543 : JS_StrictPropertyStub, /* setProperty */
544 : args_enumerate,
545 : reinterpret_cast<JSResolveOp>(args_resolve),
546 : JS_ConvertStub,
547 : args_finalize, /* finalize */
548 : NULL, /* checkAccess */
549 : NULL, /* call */
550 : NULL, /* construct */
551 : NULL, /* hasInstance */
552 : args_trace,
553 : {
554 : NULL, /* equality */
555 : NULL, /* outerObject */
556 : NULL, /* innerObject */
557 : JS_ElementIteratorStub,
558 : NULL, /* unused */
559 : false, /* isWrappedNative */
560 : }
561 : };
562 :
563 : /*
564 : * Strict mode arguments is significantly less magical than non-strict mode
565 : * arguments, so it is represented by a different class while sharing some
566 : * functionality.
567 : */
568 : Class js::StrictArgumentsObjectClass = {
569 : "Arguments",
570 : JSCLASS_NEW_RESOLVE | JSCLASS_IMPLEMENTS_BARRIERS |
571 : JSCLASS_HAS_RESERVED_SLOTS(StrictArgumentsObject::RESERVED_SLOTS) |
572 : JSCLASS_HAS_CACHED_PROTO(JSProto_Object) |
573 : JSCLASS_FOR_OF_ITERATION,
574 : JS_PropertyStub, /* addProperty */
575 : args_delProperty,
576 : JS_PropertyStub, /* getProperty */
577 : JS_StrictPropertyStub, /* setProperty */
578 : strictargs_enumerate,
579 : reinterpret_cast<JSResolveOp>(strictargs_resolve),
580 : JS_ConvertStub,
581 : args_finalize, /* finalize */
582 : NULL, /* checkAccess */
583 : NULL, /* call */
584 : NULL, /* construct */
585 : NULL, /* hasInstance */
586 : args_trace,
587 : {
588 : NULL, /* equality */
589 : NULL, /* outerObject */
590 : NULL, /* innerObject */
591 : JS_ElementIteratorStub,
592 : NULL, /* unused */
593 : false, /* isWrappedNative */
594 : }
595 : };
|